From b039eaaf8ae75fd8307e115bc1e75e5868f78fbc Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Thu, 10 Dec 2015 17:51:38 +0100 Subject: [PATCH] Imported Upstream version 1.5.0+dfsg1 --- AUTHORS.txt | 180 +- CONTRIBUTING.md | 32 +- Makefile.in | 2 +- README.md | 14 +- RELEASES.md | 276 +- configure | 41 +- man/rustc.1 | 7 +- mk/cfg/mips-unknown-linux-gnu.mk | 6 +- mk/cfg/mipsel-unknown-linux-gnu.mk | 10 +- mk/cfg/x86_64-rumprun-netbsd.mk | 24 + mk/cfg/x86_64-unknown-netbsd.mk | 1 + mk/crates.mk | 62 +- mk/dist.mk | 115 +- mk/grammar.mk | 6 +- mk/install.mk | 18 +- mk/llvm.mk | 4 +- mk/main.mk | 27 +- mk/platform.mk | 8 + mk/prepare.mk | 20 +- mk/tests.mk | 9 +- src/compiletest/compiletest.rs | 15 +- src/compiletest/procsrv.rs | 2 + src/compiletest/runtest.rs | 3 +- src/doc/README.md | 7 +- src/doc/complement-lang-faq.md | 2 +- src/doc/complement-project-faq.md | 2 +- src/doc/grammar.md | 10 +- src/doc/index.md | 1 + src/doc/nomicon/atomics.md | 10 +- src/doc/nomicon/casts.md | 4 +- src/doc/nomicon/concurrency.md | 2 +- src/doc/nomicon/destructors.md | 6 +- src/doc/nomicon/drop-flags.md | 2 +- src/doc/nomicon/dropck.md | 162 +- src/doc/nomicon/exotic-sizes.md | 4 +- src/doc/nomicon/leaking.md | 10 +- src/doc/nomicon/lifetime-mismatch.md | 2 +- src/doc/nomicon/lifetimes.md | 2 +- src/doc/nomicon/meet-safe-and-unsafe.md | 14 +- src/doc/nomicon/other-reprs.md | 6 +- src/doc/nomicon/ownership.md | 1 - src/doc/nomicon/races.md | 4 +- src/doc/nomicon/repr-rust.md | 4 +- src/doc/nomicon/safe-unsafe-meaning.md | 8 +- src/doc/nomicon/send-and-sync.md | 2 +- src/doc/nomicon/transmutes.md | 4 +- src/doc/nomicon/unbounded-lifetimes.md | 4 +- src/doc/nomicon/unchecked-uninit.md | 2 +- src/doc/nomicon/uninitialized.md | 4 +- src/doc/nomicon/unwinding.md | 2 +- src/doc/nomicon/vec-layout.md | 2 +- src/doc/nomicon/vec-push-pop.md | 2 +- src/doc/nomicon/vec-zsts.md | 4 +- src/doc/reference.md | 415 +- src/doc/rust.css | 15 +- src/doc/style/SUMMARY.md | 4 - src/doc/style/changing/README.md | 5 - src/doc/style/changing/post-1-0.md | 12 - src/doc/style/changing/pre-1-0.md | 17 - src/doc/style/changing/unclear.md | 28 - src/doc/style/errors/ergonomics.md | 2 +- src/doc/style/features/modules.md | 10 +- src/doc/style/features/traits/common.md | 8 +- src/doc/style/features/traits/generics.md | 4 +- src/doc/style/features/traits/reuse.md | 2 +- src/doc/style/style/comments.md | 17 + src/doc/trpl/README.md | 49 +- src/doc/trpl/SUMMARY.md | 2 + src/doc/trpl/advanced-linking.md | 6 +- src/doc/trpl/bibliography.md | 10 +- src/doc/trpl/casting-between-types.md | 2 +- src/doc/trpl/choosing-your-guarantees.md | 4 +- src/doc/trpl/closures.md | 76 +- src/doc/trpl/compiler-plugins.md | 30 +- src/doc/trpl/concurrency.md | 67 +- src/doc/trpl/conditional-compilation.md | 2 +- src/doc/trpl/crates-and-modules.md | 6 +- src/doc/trpl/custom-allocators.md | 170 + src/doc/trpl/dining-philosophers.md | 19 +- src/doc/trpl/documentation.md | 117 +- src/doc/trpl/error-handling.md | 95 +- src/doc/trpl/getting-started.md | 2 +- src/doc/trpl/glossary.md | 10 +- src/doc/trpl/guessing-game.md | 13 +- src/doc/trpl/hello-cargo.md | 92 +- src/doc/trpl/hello-world.md | 106 +- src/doc/trpl/if-let.md | 4 +- src/doc/trpl/installing-rust.md | 186 +- src/doc/trpl/iterators.md | 40 +- src/doc/trpl/lifetimes.md | 21 +- src/doc/trpl/method-syntax.md | 2 +- src/doc/trpl/mutability.md | 2 +- src/doc/trpl/no-stdlib.md | 38 +- src/doc/trpl/ownership.md | 16 +- src/doc/trpl/patterns.md | 27 +- src/doc/trpl/primitive-types.md | 11 +- src/doc/trpl/raw-pointers.md | 7 +- src/doc/trpl/references-and-borrowing.md | 12 +- src/doc/trpl/rust-inside-other-languages.md | 3 +- src/doc/trpl/strings.md | 4 +- src/doc/trpl/structs.md | 2 + src/doc/trpl/syntax-index.md | 229 + src/doc/trpl/testing.md | 11 +- src/doc/trpl/the-stack-and-the-heap.md | 174 +- src/doc/trpl/traits.md | 43 +- src/doc/trpl/variable-bindings.md | 99 +- src/doc/trpl/vectors.md | 29 + src/driver/driver.rs | 4 +- src/error-index-generator/main.rs | 16 +- src/etc/generate-deriving-span-tests.py | 2 +- src/etc/maketest.py | 12 +- src/etc/mklldeps.py | 5 +- src/etc/test-float-parse/runtests.py | 2 +- src/etc/unicode.py | 17 +- src/jemalloc/VERSION | 2 +- src/liballoc/arc.rs | 97 +- src/liballoc/boxed.rs | 124 +- src/liballoc/boxed_test.rs | 15 +- src/liballoc/heap.rs | 33 +- src/liballoc/lib.rs | 20 +- src/liballoc/raw_vec.rs | 75 +- src/liballoc/rc.rs | 90 +- src/liballoc_jemalloc/lib.rs | 52 +- src/liballoc_system/lib.rs | 77 +- src/libarena/lib.rs | 139 +- src/libbacktrace/ChangeLog.jit | 2 +- src/libbacktrace/Makefile.am | 4 +- src/libbacktrace/Makefile.in | 20 +- src/libbacktrace/alloc.c | 6 +- src/libbacktrace/atomic.c | 6 +- src/libbacktrace/backtrace-supported.h.in | 6 +- src/libbacktrace/backtrace.c | 6 +- src/libbacktrace/backtrace.h | 6 +- src/libbacktrace/btest.c | 8 +- src/libbacktrace/configure.ac | 6 +- src/libbacktrace/dwarf.c | 12 +- src/libbacktrace/dwarf2.def | 14 +- src/libbacktrace/dwarf2.h | 2 +- src/libbacktrace/elf.c | 6 +- src/libbacktrace/fileline.c | 6 +- src/libbacktrace/internal.h | 6 +- src/libbacktrace/mmap.c | 6 +- src/libbacktrace/mmapio.c | 6 +- src/libbacktrace/nounwind.c | 6 +- src/libbacktrace/posix.c | 6 +- src/libbacktrace/print.c | 6 +- src/libbacktrace/read.c | 6 +- src/libbacktrace/simple.c | 6 +- src/libbacktrace/sort.c | 6 +- src/libbacktrace/state.c | 6 +- src/libbacktrace/stest.c | 6 +- src/libbacktrace/unknown.c | 6 +- src/libcollections/binary_heap.rs | 73 +- src/libcollections/btree/map.rs | 14 +- src/libcollections/btree/node.rs | 14 +- src/libcollections/btree/set.rs | 10 +- src/libcollections/enum_set.rs | 11 +- src/libcollections/fmt.rs | 26 +- src/libcollections/lib.rs | 15 +- src/libcollections/linked_list.rs | 1 + src/libcollections/slice.rs | 11 +- src/libcollections/str.rs | 111 +- src/libcollections/string.rs | 172 +- src/libcollections/vec.rs | 127 +- src/libcollections/vec_deque.rs | 375 +- src/libcollectionstest/btree/map.rs | 53 + src/libcollectionstest/btree/set.rs | 12 +- src/libcollectionstest/lib.rs | 5 - src/libcollectionstest/str.rs | 96 +- src/libcollectionstest/string.rs | 2 +- src/libcollectionstest/vec_deque.rs | 8 +- src/libcore/array.rs | 13 +- src/libcore/cell.rs | 14 +- src/libcore/char.rs | 34 +- src/libcore/cmp.rs | 26 +- src/libcore/cmp_macros.rs | 8 +- src/libcore/convert.rs | 2 +- src/libcore/default.rs | 4 +- src/libcore/fmt/builders.rs | 62 +- src/libcore/fmt/mod.rs | 92 +- src/libcore/fmt/num.rs | 22 +- src/libcore/fmt/rt/v1.rs | 2 +- src/libcore/hash/mod.rs | 31 +- src/libcore/hash/sip.rs | 11 +- src/libcore/intrinsics.rs | 8 +- src/libcore/iter.rs | 957 ++- src/libcore/macros.rs | 36 +- src/libcore/marker.rs | 17 +- src/libcore/mem.rs | 32 +- src/libcore/nonzero.rs | 30 +- src/libcore/num/{flt2dec => }/bignum.rs | 22 +- src/libcore/num/dec2flt/algorithm.rs | 8 +- src/libcore/num/dec2flt/mod.rs | 3 - src/libcore/num/dec2flt/num.rs | 3 +- src/libcore/num/dec2flt/rawfp.rs | 4 +- src/libcore/num/diy_float.rs | 71 + src/libcore/num/f32.rs | 2 +- src/libcore/num/f64.rs | 2 +- src/libcore/num/flt2dec/mod.rs | 3 +- src/libcore/num/flt2dec/strategy/dragon.rs | 4 +- src/libcore/num/flt2dec/strategy/grisu.rs | 55 +- src/libcore/num/mod.rs | 152 +- src/libcore/ops.rs | 532 +- src/libcore/option.rs | 7 +- src/libcore/ptr.rs | 105 +- src/libcore/raw.rs | 2 +- src/libcore/result.rs | 4 +- src/libcore/slice.rs | 62 +- src/libcore/str/mod.rs | 168 +- src/libcore/sync/atomic.rs | 6 +- src/libcoretest/cell.rs | 23 +- src/libcoretest/clone.rs | 20 +- src/libcoretest/fmt/float.rs | 4 +- src/libcoretest/fmt/mod.rs | 3 +- src/libcoretest/intrinsics.rs | 2 +- src/libcoretest/lib.rs | 4 + src/libcoretest/num/{flt2dec => }/bignum.rs | 2 +- src/libcoretest/num/dec2flt/mod.rs | 2 +- src/libcoretest/num/dec2flt/rawfp.rs | 6 +- src/libcoretest/num/flt2dec/mod.rs | 1 - .../num/flt2dec/strategy/dragon.rs | 2 +- src/libcoretest/num/mod.rs | 49 + src/libflate/lib.rs | 21 +- src/libfmt_macros/lib.rs | 382 +- src/libgraphviz/lib.rs | 4 +- src/liblibc/lib.rs | 5120 +++++++++-------- src/liblog/directive.rs | 84 +- src/liblog/lib.rs | 119 +- src/librand/chacha.rs | 45 +- src/librand/distributions/exponential.rs | 20 +- src/librand/distributions/gamma.rs | 57 +- src/librand/distributions/mod.rs | 123 +- src/librand/distributions/normal.rs | 41 +- src/librand/distributions/range.rs | 12 +- src/librand/distributions/ziggurat_tables.rs | 4 + src/librand/isaac.rs | 103 +- src/librand/lib.rs | 36 +- src/librand/rand_impls.rs | 6 +- src/librand/reseeding.rs | 16 +- src/librbml/lib.rs | 84 +- src/librustc/diagnostics.rs | 200 +- src/librustc/front/check_attr.rs | 110 + src/librustc/front/map/blocks.rs | 18 +- src/librustc/front/map/collector.rs | 316 + src/librustc/front/map/definitions.rs | 263 + src/librustc/front/map/mod.rs | 380 +- src/librustc/lib.rs | 9 +- src/librustc/lint/builtin.rs | 13 +- src/librustc/lint/context.rs | 662 ++- src/librustc/lint/mod.rs | 138 +- src/librustc/metadata/common.rs | 74 +- src/librustc/metadata/creader.rs | 80 +- src/librustc/metadata/csearch.rs | 111 +- src/librustc/metadata/cstore.rs | 28 +- src/librustc/metadata/decoder.rs | 414 +- src/librustc/metadata/encoder.rs | 1010 ++-- src/librustc/metadata/index.rs | 245 +- src/librustc/metadata/loader.rs | 49 +- src/librustc/metadata/macro_import.rs | 21 +- src/librustc/metadata/tydecode.rs | 107 +- src/librustc/metadata/tyencode.rs | 63 +- src/librustc/middle/astconv_util.rs | 2 + src/librustc/middle/astencode.rs | 373 +- src/librustc/middle/cfg/construct.rs | 10 +- src/librustc/middle/check_const.rs | 60 +- src/librustc/middle/check_match.rs | 29 +- src/librustc/middle/check_no_asm.rs | 4 +- src/librustc/middle/check_static_recursion.rs | 71 +- src/librustc/middle/const_eval.rs | 310 +- src/librustc/middle/dataflow.rs | 3 +- src/librustc/middle/dead.rs | 110 +- src/librustc/middle/def.rs | 48 +- src/librustc/middle/def_id.rs | 74 +- src/librustc/middle/effect.rs | 6 +- src/librustc/middle/entry.rs | 6 +- src/librustc/middle/expr_use_visitor.rs | 59 +- src/librustc/middle/free_region.rs | 2 +- src/librustc/middle/infer/combine.rs | 6 +- src/librustc/middle/infer/equate.rs | 4 +- src/librustc/middle/infer/error_reporting.rs | 205 +- .../middle/infer/higher_ranked/mod.rs | 2 +- src/librustc/middle/infer/mod.rs | 21 +- .../middle/infer/region_inference/README.md | 92 +- .../middle/infer/region_inference/mod.rs | 380 +- src/librustc/middle/infer/sub.rs | 5 +- src/librustc/middle/infer/unify_key.rs | 2 +- src/librustc/middle/intrinsicck.rs | 2 +- src/librustc/middle/lang_items.rs | 45 +- src/librustc/middle/liveness.rs | 41 +- src/librustc/middle/mem_categorization.rs | 25 +- src/librustc/middle/pat_util.rs | 37 +- src/librustc/middle/reachable.rs | 62 +- src/librustc/middle/region.rs | 13 +- src/librustc/middle/resolve_lifetime.rs | 51 +- src/librustc/middle/stability.rs | 135 +- src/librustc/middle/traits/coherence.rs | 3 +- src/librustc/middle/traits/error_reporting.rs | 16 +- src/librustc/middle/traits/mod.rs | 1 + src/librustc/middle/traits/object_safety.rs | 40 +- src/librustc/middle/traits/select.rs | 10 +- src/librustc/middle/traits/util.rs | 2 +- src/librustc/middle/ty/adjustment.rs | 2 +- src/librustc/middle/ty/cast.rs | 2 +- src/librustc/middle/ty/contents.rs | 4 +- src/librustc/middle/ty/context.rs | 126 +- src/librustc/middle/ty/error.rs | 24 +- src/librustc/middle/ty/fast_reject.rs | 8 +- src/librustc/middle/ty/mod.rs | 127 +- src/librustc/middle/ty/structural_impls.rs | 4 +- src/librustc/middle/ty/sty.rs | 28 +- src/librustc/middle/ty/util.rs | 277 +- src/librustc/middle/weak_lang_items.rs | 3 +- src/librustc/plugin/build.rs | 2 +- src/librustc/plugin/load.rs | 12 +- src/librustc/plugin/registry.rs | 19 +- src/librustc/session/config.rs | 94 +- src/librustc/session/mod.rs | 19 +- src/librustc/util/ppaux.rs | 43 +- src/librustc_back/lib.rs | 3 +- .../javascript.rs => librustc_back/slice.rs} | 13 +- src/librustc_back/svh.rs | 44 +- src/librustc_back/target/aarch64_apple_ios.rs | 1 + .../target/aarch64_linux_android.rs | 1 + .../target/aarch64_unknown_linux_gnu.rs | 1 + src/librustc_back/target/apple_base.rs | 2 +- .../target/arm_linux_androideabi.rs | 1 + .../target/arm_unknown_linux_gnueabi.rs | 1 + .../target/arm_unknown_linux_gnueabihf.rs | 1 + src/librustc_back/target/armv7_apple_ios.rs | 1 + src/librustc_back/target/armv7s_apple_ios.rs | 1 + src/librustc_back/target/bitrig_base.rs | 2 +- src/librustc_back/target/dragonfly_base.rs | 2 +- src/librustc_back/target/freebsd_base.rs | 2 +- src/librustc_back/target/i386_apple_ios.rs | 1 + src/librustc_back/target/i686_apple_darwin.rs | 1 + .../target/i686_linux_android.rs | 1 + .../target/i686_pc_windows_gnu.rs | 1 + .../target/i686_pc_windows_msvc.rs | 1 + .../target/i686_unknown_dragonfly.rs | 1 + .../target/i686_unknown_freebsd.rs | 1 + .../target/i686_unknown_linux_gnu.rs | 1 + src/librustc_back/target/le32_unknown_nacl.rs | 41 + src/librustc_back/target/linux_base.rs | 2 +- .../target/mips_unknown_linux_gnu.rs | 1 + .../target/mipsel_unknown_linux_gnu.rs | 1 + src/librustc_back/target/mod.rs | 24 +- src/librustc_back/target/openbsd_base.rs | 2 +- .../target/powerpc_unknown_linux_gnu.rs | 1 + src/librustc_back/target/windows_base.rs | 6 +- src/librustc_back/target/windows_msvc_base.rs | 2 +- .../target/x86_64_apple_darwin.rs | 1 + src/librustc_back/target/x86_64_apple_ios.rs | 1 + .../target/x86_64_pc_windows_gnu.rs | 1 + .../target/x86_64_pc_windows_msvc.rs | 1 + .../target/x86_64_rumprun_netbsd.rs | 35 + .../target/x86_64_unknown_bitrig.rs | 1 + .../target/x86_64_unknown_dragonfly.rs | 1 + .../target/x86_64_unknown_freebsd.rs | 1 + .../target/x86_64_unknown_linux_gnu.rs | 1 + .../target/x86_64_unknown_linux_musl.rs | 1 + .../target/x86_64_unknown_netbsd.rs | 1 + .../target/x86_64_unknown_openbsd.rs | 1 + src/librustc_bitflags/lib.rs | 24 +- src/librustc_borrowck/borrowck/check_loans.rs | 92 +- src/librustc_borrowck/borrowck/fragments.rs | 8 +- .../borrowck/gather_loans/gather_moves.rs | 2 +- .../borrowck/gather_loans/move_error.rs | 31 +- src/librustc_borrowck/borrowck/mod.rs | 6 +- src/librustc_borrowck/diagnostics.rs | 42 +- src/librustc_driver/driver.rs | 159 +- src/librustc_driver/lib.rs | 13 +- src/librustc_driver/pretty.rs | 53 +- src/librustc_driver/test.rs | 37 +- src/librustc_front/attr.rs | 628 -- src/librustc_front/fold.rs | 870 +-- src/librustc_front/hir.rs | 478 +- src/librustc_front/lib.rs | 13 +- src/librustc_front/lowering.rs | 2006 ++++--- src/librustc_front/print/pp.rs | 686 --- src/librustc_front/print/pprust.rs | 1273 ++-- src/librustc_front/util.rs | 189 +- src/librustc_front/visit.rs | 741 ++- src/librustc_lint/bad_style.rs | 372 ++ src/librustc_lint/builtin.rs | 1910 +----- src/librustc_lint/lib.rs | 33 +- src/librustc_lint/types.rs | 676 +++ src/librustc_lint/unused.rs | 465 ++ src/librustc_llvm/lib.rs | 4 +- src/librustc_mir/build/block.rs | 9 +- src/librustc_mir/build/cfg.rs | 30 +- src/librustc_mir/build/expr/as_constant.rs | 110 +- src/librustc_mir/build/expr/as_lvalue.rs | 26 +- src/librustc_mir/build/expr/as_operand.rs | 29 +- src/librustc_mir/build/expr/as_rvalue.rs | 32 +- src/librustc_mir/build/expr/as_temp.rs | 34 +- src/librustc_mir/build/expr/category.rs | 6 +- src/librustc_mir/build/expr/into.rs | 34 +- src/librustc_mir/build/into.rs | 53 +- src/librustc_mir/build/matches/mod.rs | 277 +- src/librustc_mir/build/matches/simplify.rs | 28 +- src/librustc_mir/build/matches/test.rs | 111 +- src/librustc_mir/build/matches/util.rs | 52 +- src/librustc_mir/build/misc.rs | 53 +- src/librustc_mir/build/mod.rs | 65 +- src/librustc_mir/build/scope.rs | 89 +- src/librustc_mir/build/stmt.rs | 8 +- src/librustc_mir/graphviz/mod.rs | 39 +- src/librustc_mir/hair.rs | 466 +- src/librustc_mir/lib.rs | 7 +- src/librustc_mir/{dump.rs => mir_map.rs} | 166 +- src/librustc_mir/repr.rs | 258 +- src/librustc_mir/tcx/block.rs | 62 +- src/librustc_mir/tcx/expr.rs | 389 +- src/librustc_mir/tcx/mod.rs | 140 +- src/librustc_mir/tcx/pattern.rs | 121 +- src/librustc_mir/tcx/to_ref.rs | 56 +- src/librustc_privacy/lib.rs | 246 +- src/librustc_resolve/build_reduced_graph.rs | 159 +- src/librustc_resolve/diagnostics.rs | 24 +- src/librustc_resolve/lib.rs | 126 +- src/librustc_resolve/record_exports.rs | 6 +- src/librustc_resolve/resolve_imports.rs | 20 +- src/librustc_trans/back/archive.rs | 7 +- src/librustc_trans/back/link.rs | 123 +- src/librustc_trans/back/linker.rs | 22 +- src/librustc_trans/back/lto.rs | 13 +- src/librustc_trans/back/write.rs | 103 +- src/librustc_trans/diagnostics.rs | 122 + src/librustc_trans/lib.rs | 8 +- src/librustc_trans/save/dump_csv.rs | 346 +- src/librustc_trans/save/mod.rs | 172 +- src/librustc_trans/save/recorder.rs | 292 +- src/librustc_trans/save/span_utils.rs | 38 +- src/librustc_trans/trans/_match.rs | 73 +- src/librustc_trans/trans/adt.rs | 23 +- src/librustc_trans/trans/asm.rs | 5 +- src/librustc_trans/trans/attributes.rs | 7 +- src/librustc_trans/trans/base.rs | 99 +- src/librustc_trans/trans/cabi_x86_64.rs | 47 +- src/librustc_trans/trans/cabi_x86_win64.rs | 2 +- src/librustc_trans/trans/callee.rs | 116 +- src/librustc_trans/trans/closure.rs | 48 +- src/librustc_trans/trans/common.rs | 14 +- src/librustc_trans/trans/consts.rs | 360 +- src/librustc_trans/trans/context.rs | 1 - src/librustc_trans/trans/controlflow.rs | 13 +- .../trans/debuginfo/create_scope_map.rs | 9 +- src/librustc_trans/trans/debuginfo/gdb.rs | 21 +- .../trans/debuginfo/metadata.rs | 59 +- src/librustc_trans/trans/debuginfo/mod.rs | 15 +- .../trans/debuginfo/type_names.rs | 26 +- src/librustc_trans/trans/debuginfo/utils.rs | 17 +- src/librustc_trans/trans/expr.rs | 274 +- src/librustc_trans/trans/foreign.rs | 34 +- src/librustc_trans/trans/glue.rs | 6 +- src/librustc_trans/trans/inline.rs | 30 +- src/librustc_trans/trans/intrinsic.rs | 58 +- src/librustc_trans/trans/meth.rs | 65 +- src/librustc_trans/trans/monomorphize.rs | 43 +- src/librustc_trans/trans/tvec.rs | 7 +- src/librustc_trans/trans/type_.rs | 32 +- src/librustc_trans/trans/type_of.rs | 6 +- src/librustc_typeck/astconv.rs | 76 +- src/librustc_typeck/check/_match.rs | 50 +- src/librustc_typeck/check/callee.rs | 3 +- src/librustc_typeck/check/cast.rs | 5 +- src/librustc_typeck/check/closure.rs | 3 +- src/librustc_typeck/check/compare_method.rs | 8 +- src/librustc_typeck/check/dropck.rs | 88 +- src/librustc_typeck/check/intrinsic.rs | 30 +- src/librustc_typeck/check/method/confirm.rs | 23 +- src/librustc_typeck/check/method/mod.rs | 3 + src/librustc_typeck/check/method/probe.rs | 24 +- src/librustc_typeck/check/method/suggest.rs | 42 +- src/librustc_typeck/check/mod.rs | 305 +- src/librustc_typeck/check/op.rs | 143 +- src/librustc_typeck/check/regionck.rs | 18 +- src/librustc_typeck/check/upvar.rs | 19 +- src/librustc_typeck/check/wf.rs | 70 +- src/librustc_typeck/check/wfcheck.rs | 69 +- src/librustc_typeck/check/writeback.rs | 71 +- src/librustc_typeck/coherence/mod.rs | 190 +- src/librustc_typeck/coherence/orphan.rs | 30 +- src/librustc_typeck/coherence/overlap.rs | 15 +- src/librustc_typeck/coherence/unsafety.rs | 3 +- src/librustc_typeck/collect.rs | 359 +- src/librustc_typeck/diagnostics.rs | 187 +- src/librustc_typeck/lib.rs | 13 +- src/librustc_typeck/variance.rs | 30 +- src/librustc_unicode/char.rs | 547 +- src/librustc_unicode/lib.rs | 1 - src/librustc_unicode/u_str.rs | 62 +- src/librustdoc/clean/inline.rs | 16 +- src/librustdoc/clean/mod.rs | 270 +- src/librustdoc/core.rs | 41 +- src/librustdoc/doctree.rs | 68 +- src/librustdoc/html/format.rs | 6 +- src/librustdoc/html/markdown.rs | 111 +- src/librustdoc/html/render.rs | 233 +- src/librustdoc/html/static/COPYRIGHT.txt | 64 + src/librustdoc/html/static/LICENSE-APACHE.txt | 201 + src/librustdoc/html/static/LICENSE-MIT.txt | 23 + src/librustdoc/html/static/main.css | 22 +- src/librustdoc/html/static/main.js | 43 +- src/librustdoc/html/static/playpen.js | 4 +- src/librustdoc/html/toc.rs | 4 +- src/librustdoc/lib.rs | 3 +- src/librustdoc/passes.rs | 43 +- src/librustdoc/plugins.rs | 2 + src/librustdoc/test.rs | 27 +- src/librustdoc/visit_ast.rs | 56 +- src/libserialize/json.rs | 9 +- src/libstd/collections/hash/map.rs | 14 +- src/libstd/collections/hash/set.rs | 10 +- src/libstd/collections/hash/table.rs | 3 +- src/libstd/collections/mod.rs | 54 +- src/libstd/dynamic_lib.rs | 5 +- src/libstd/env.rs | 23 +- src/libstd/ffi/c_str.rs | 78 +- src/libstd/ffi/mod.rs | 2 +- src/libstd/fs.rs | 37 +- src/libstd/io/buffered.rs | 2 +- src/libstd/io/cursor.rs | 133 +- src/libstd/io/error.rs | 5 +- src/libstd/io/impls.rs | 8 +- src/libstd/io/mod.rs | 23 +- src/libstd/io/prelude.rs | 1 + src/libstd/io/stdio.rs | 6 +- src/libstd/lib.rs | 18 +- src/libstd/macros.rs | 10 +- src/libstd/net/ip.rs | 10 +- src/libstd/net/parser.rs | 68 +- src/libstd/net/tcp.rs | 55 +- src/libstd/net/test.rs | 4 +- src/libstd/net/udp.rs | 9 +- src/libstd/os/android/raw.rs | 2 + src/libstd/os/bitrig/raw.rs | 1 + src/libstd/os/dragonfly/raw.rs | 1 + src/libstd/os/freebsd/raw.rs | 3 +- src/libstd/os/ios/raw.rs | 1 + src/libstd/os/linux/raw.rs | 4 + src/libstd/os/macos/raw.rs | 1 + src/libstd/os/nacl/raw.rs | 4 + src/libstd/os/netbsd/raw.rs | 14 +- src/libstd/os/openbsd/raw.rs | 1 + src/libstd/panicking.rs | 73 +- src/libstd/path.rs | 82 +- src/libstd/prelude/mod.rs | 4 +- src/libstd/primitive_docs.rs | 2 +- src/libstd/process.rs | 17 +- src/libstd/sync/condvar.rs | 7 +- src/libstd/sync/mpsc/mod.rs | 2 +- src/libstd/sync/mutex.rs | 139 +- src/libstd/sync/rwlock.rs | 142 +- src/libstd/sys/common/libunwind.rs | 10 +- src/libstd/sys/common/unwind/mod.rs | 136 +- src/libstd/sys/common/wtf8.rs | 40 +- src/libstd/sys/unix/c.rs | 12 +- src/libstd/sys/unix/ext/fs.rs | 10 +- src/libstd/sys/unix/ext/process.rs | 2 +- src/libstd/sys/unix/fs.rs | 3 +- src/libstd/sys/unix/mod.rs | 2 +- src/libstd/sys/unix/os.rs | 17 +- src/libstd/sys/unix/process.rs | 34 +- src/libstd/sys/unix/stack_overflow.rs | 4 +- src/libstd/sys/unix/sync.rs | 66 +- src/libstd/sys/unix/thread.rs | 36 +- src/libstd/sys/unix/time.rs | 2 + src/libstd/sys/windows/backtrace.rs | 2 +- src/libstd/sys/windows/c.rs | 3 + src/libstd/sys/windows/fs.rs | 3 + src/libstd/sys/windows/mod.rs | 5 +- src/libstd/sys/windows/mutex.rs | 2 +- src/libstd/sys/windows/printing/gnu.rs | 2 + src/libstd/sys/windows/printing/msvc.rs | 2 + src/libstd/thread/mod.rs | 42 +- src/libstd/time/duration.rs | 2 +- src/libsyntax/ast.rs | 294 +- src/libsyntax/ast_util.rs | 65 +- src/libsyntax/attr.rs | 301 +- src/libsyntax/codemap.rs | 29 +- src/libsyntax/config.rs | 36 +- src/libsyntax/diagnostic.rs | 3 +- src/libsyntax/diagnostics/plugin.rs | 2 +- src/libsyntax/entry.rs | 2 +- src/libsyntax/ext/asm.rs | 5 +- src/libsyntax/ext/base.rs | 23 +- src/libsyntax/ext/build.rs | 42 +- .../ext/deriving/{show.rs => debug.rs} | 2 +- src/libsyntax/ext/deriving/generic/mod.rs | 78 +- src/libsyntax/ext/deriving/mod.rs | 6 +- src/libsyntax/ext/deriving/primitive.rs | 60 +- src/libsyntax/ext/expand.rs | 708 +-- src/libsyntax/ext/mtwt.rs | 68 +- src/libsyntax/ext/pushpop_safe.rs | 94 - src/libsyntax/ext/quote.rs | 19 +- src/libsyntax/ext/tt/macro_parser.rs | 12 +- src/libsyntax/ext/tt/macro_rules.rs | 10 +- src/libsyntax/ext/tt/transcribe.rs | 10 +- src/libsyntax/feature_gate.rs | 87 +- src/libsyntax/fold.rs | 69 +- src/libsyntax/lib.rs | 3 - src/libsyntax/owned_slice.rs | 9 + src/libsyntax/parse/attr.rs | 19 +- src/libsyntax/parse/lexer/comments.rs | 4 +- src/libsyntax/parse/lexer/mod.rs | 5 +- src/libsyntax/parse/mod.rs | 13 +- src/libsyntax/parse/parser.rs | 283 +- src/libsyntax/parse/token.rs | 14 +- src/libsyntax/print/pprust.rs | 838 +-- src/libsyntax/std_inject.rs | 2 +- src/libsyntax/util/interner.rs | 6 +- src/libsyntax/util/small_vector.rs | 3 +- src/libsyntax/visit.rs | 669 +-- src/libterm/lib.rs | 1 - src/libterm/terminfo/searcher.rs | 2 +- src/libtest/lib.rs | 2 +- src/rt/hoedown/bin/hoedown.c | 2 +- src/rt/hoedown/src/document.c | 2 +- src/rt/hoedown/src/version.h | 4 +- src/rt/rust_test_helpers.c | 4 + src/rustbook/build.rs | 42 +- src/rustbook/help.rs | 2 +- src/rustbook/main.rs | 3 - src/rustbook/static/rustbook.css | 74 +- src/rustbook/static/rustbook.js | 113 +- src/rustbook/subcommand.rs | 2 +- src/rustllvm/ArchiveWrapper.cpp | 8 + src/rustllvm/PassWrapper.cpp | 7 +- src/rustllvm/RustWrapper.cpp | 23 +- src/rustllvm/llvm-auto-clean-trigger | 2 +- src/test/auxiliary/augmented_assignments.rs | 22 + src/test/auxiliary/cross_crate_spans.rs | 1 + src/test/auxiliary/inherited_stability.rs | 2 +- src/test/auxiliary/issue-2380.rs | 2 +- src/test/auxiliary/issue-29181.rs | 15 + src/test/auxiliary/lint_for_crate.rs | 12 +- src/test/auxiliary/lint_group_plugin_test.rs | 10 +- src/test/auxiliary/lint_output_format.rs | 2 +- src/test/auxiliary/lint_plugin_test.rs | 15 +- src/test/auxiliary/lint_stability.rs | 34 +- src/test/auxiliary/lint_stability_fields.rs | 12 +- src/test/auxiliary/procedural_mbe_matching.rs | 2 +- src/test/auxiliary/sepcomp_cci_lib.rs | 3 +- src/test/auxiliary/xcrate_static_addresses.rs | 3 - src/test/bench/core-map.rs | 6 +- src/test/bench/shootout-fasta-redux.rs | 444 +- src/test/bench/shootout-fasta.rs | 392 +- src/test/bench/shootout-mandelbrot.rs | 2 +- src/test/bench/shootout-nbody.rs | 219 +- src/test/codegen/adjustments.rs | 39 + src/test/codegen/coercions.rs | 2 + src/test/codegen/consts.rs | 66 + src/test/codegen/extern-functions.rs | 1 + src/test/codegen/function-arguments.rs | 1 + src/test/codegen/gdb_debug_script_load.rs | 25 + src/test/codegen/link_section.rs | 2 + src/test/codegen/loads.rs | 2 + src/test/codegen/match.rs | 30 + src/test/codegen/refs.rs | 30 + src/test/codegen/stores.rs | 2 + .../assignment-operator-unimplemented.rs | 2 +- ...ted-types-invalid-trait-ref-issue-18865.rs | 2 +- src/test/compile-fail/attr-usage-inline.rs | 19 + src/test/compile-fail/attr-usage-repr.rs | 41 + ...ugmented-assignments-feature-gate-cross.rs | 25 + .../augmented-assignments-feature-gate.rs | 26 + .../augmented-assignments-trait.rs | 24 + .../compile-fail/augmented-assignments.rs | 33 + src/test/compile-fail/autoderef-full-lval.rs | 1 - src/test/compile-fail/borrow-tuple-fields.rs | 1 - src/test/compile-fail/borrowck-argument.rs | 43 + ...rrowck-borrow-overloaded-auto-deref-mut.rs | 3 - .../compile-fail/borrowck-closures-unique.rs | 2 +- .../compile-fail/borrowck-lend-flow-if.rs | 3 +- .../compile-fail/borrowck-lend-flow-loop.rs | 3 +- src/test/compile-fail/borrowck-lend-flow.rs | 3 +- .../borrowck-loan-in-overloaded-op.rs | 3 +- ...orrowck-loan-of-static-data-issue-27616.rs | 0 .../borrowck-mut-borrow-linear-errors.rs | 28 + .../compile-fail/borrowck-unboxed-closures.rs | 2 +- src/test/compile-fail/cast-as-bool.rs | 2 +- src/test/compile-fail/const-err.rs | 36 + src/test/compile-fail/const-eval-overflow.rs | 2 - src/test/compile-fail/const-eval-span.rs | 24 + .../const-fn-destructuring-arg.rs | 18 + .../const-fn-stability-calls-2.rs | 2 +- .../const-len-underflow-separate-spans.rs | 2 +- .../const-len-underflow-subspans.rs | 2 +- ...e-pushpop-unsafe.rs => const-slice-oob.rs} | 6 +- src/test/compile-fail/deriving-primitive.rs | 8 +- .../compile-fail/dropck_arr_cycle_checked.rs | 1 - .../dropck_tarena_cycle_checked.rs | 2 - .../dropck_tarena_unsound_drop.rs | 6 +- .../dropck_trait_cycle_checked.rs | 2 +- .../compile-fail/dropck_vec_cycle_checked.rs | 1 - .../{for-expn-2.rs => dupe-symbols-8.rs} | 11 +- src/test/compile-fail/empty-comment.rs | 17 + .../compile-fail/empty-struct-braces-expr.rs | 26 + .../empty-struct-braces-gate-1.rs | 23 + .../empty-struct-braces-gate-2.rs | 49 + .../compile-fail/empty-struct-braces-pat-1.rs | 33 + .../compile-fail/empty-struct-braces-pat-2.rs | 39 + .../compile-fail/empty-struct-unit-expr.rs | 24 + .../compile-fail/empty-struct-unit-pat.rs | 40 + .../compile-fail/feature-gate-box-expr.rs | 4 - .../feature-gate-cfg-target-vendor.rs | 21 + .../compile-fail/feature-gate-dropck-ugeh.rs | 40 + .../feature-gate-negate-unsigned.rs | 10 +- .../compile-fail/feature-gate-no-debug.rs | 12 + ...re-gate-omit-gdb-pretty-printer-section.rs | 12 + .../feature-gate-placement-expr.rs | 4 - .../feature-gated-feature-in-macro-arg.rs | 8 - src/test/compile-fail/for-loop-hygiene.rs | 2 - ...or-loop-refutable-pattern-error-message.rs | 4 +- .../compile-fail/invalid-path-in-const.rs | 14 + src/test/compile-fail/issue-14084.rs | 3 +- src/test/compile-fail/issue-15167.rs | 13 + src/test/compile-fail/issue-15381.rs | 6 +- src/test/compile-fail/issue-16819.rs | 18 + src/test/compile-fail/issue-17283.rs | 2 + src/test/compile-fail/issue-17337.rs | 4 +- src/test/compile-fail/issue-17904-2.rs | 2 +- src/test/compile-fail/issue-18959.rs | 1 + src/test/compile-fail/issue-1920-2.rs | 2 +- src/test/compile-fail/issue-21546.rs | 65 + src/test/compile-fail/issue-22599.rs | 20 + src/test/compile-fail/issue-22872.rs | 36 - src/test/compile-fail/issue-23046.rs | 4 +- src/test/compile-fail/issue-23543.rs | 21 + src/test/compile-fail/issue-23544.rs | 19 + src/test/compile-fail/issue-23729.rs | 2 +- src/test/compile-fail/issue-25145.rs | 22 + src/test/compile-fail/issue-26056.rs | 33 + src/test/compile-fail/issue-26459.rs | 16 + src/test/compile-fail/issue-26886.rs | 17 + src/test/compile-fail/issue-26905.rs | 34 + src/test/compile-fail/issue-27831.rs | 4 +- src/test/compile-fail/issue-27895.rs | 21 + src/test/compile-fail/issue-28075.rs | 25 + src/test/compile-fail/issue-28388-1.rs | 15 + src/test/compile-fail/issue-28388-2.rs | 19 + src/test/compile-fail/issue-28388-3.rs | 20 + src/test/compile-fail/issue-28433.rs | 21 + .../{issue-3993-2.rs => issue-28472.rs} | 19 +- src/test/compile-fail/issue-28576.rs | 22 + src/test/compile-fail/issue-28776.rs | 15 + src/test/compile-fail/issue-28837.rs | 60 + src/test/compile-fail/issue-29106.rs | 34 + src/test/compile-fail/issue-29161.rs | 26 + src/test/compile-fail/issue-29181.rs | 17 + .../issue-29184.rs} | 9 +- src/test/compile-fail/issue-6801.rs | 2 +- src/test/compile-fail/issue-8460-const.rs | 42 +- .../compile-fail/issue28498-reject-ex1.rs | 48 + .../issue28498-reject-lifetime-param.rs | 48 + .../issue28498-reject-passed-to-fn.rs | 50 + .../issue28498-reject-trait-bound.rs | 50 + src/test/compile-fail/lint-output-format.rs | 3 +- .../compile-fail/lint-stability-fields.rs | 12 +- src/test/compile-fail/lint-stability.rs | 26 +- .../lint-visible-private-types.rs | 1 - .../compile-fail/loop-does-not-diverge.rs | 2 +- .../compile-fail/moves-based-on-type-tuple.rs | 3 +- .../compile-fail/object-safety-issue-22040.rs | 7 +- .../object-safety-supertrait-mentions-Self.rs | 4 +- .../packed-struct-generic-transmute.rs | 2 +- .../compile-fail/packed-struct-transmute.rs | 2 +- .../compile-fail/placement-expr-unsafe.rs | 24 + .../compile-fail/placement-expr-unstable.rs | 27 + src/test/compile-fail/privacy-ufcs.rs | 24 + .../compile-fail/pushpop-unsafe-rejects.rs | 74 - ...ions-outlives-projection-container-hrtb.rs | 2 +- .../stability-attribute-sanity-2.rs | 25 + .../stability-attribute-sanity.rs | 31 +- .../struct-no-fields-enumlike.rs | 4 +- src/test/compile-fail/trait-not-accessible.rs | 28 + src/test/compile-fail/trait-test-2.rs | 1 + .../compile-fail/transmute-different-sizes.rs | 4 +- .../compile-fail/transmute-fat-pointers.rs | 8 +- src/test/compile-fail/transmute-impl.rs | 2 +- .../compile-fail/transmute-imut-to-mut.rs | 1 - ...oxed-closures-recursive-fn-using-fn-mut.rs | 2 +- src/test/compile-fail/unsafe-const-fn.rs | 24 + .../{useless-priv.rs => useless-pub.rs} | 1 - .../compile-fail/variance-regions-direct.rs | 2 +- .../compile-fail/variance-trait-bounds.rs | 1 - src/test/compile-fail/variance-types.rs | 1 - .../vec-must-not-hide-type-from-dropck.rs | 1 - .../wf-method-late-bound-regions.rs | 33 + .../wf-misc-methods-issue-28609.rs | 84 + src/test/compile-fail/wf-static-method.rs | 64 + src/test/debuginfo/associated-types.rs | 1 + .../debuginfo/basic-types-globals-metadata.rs | 1 + src/test/debuginfo/basic-types-globals.rs | 1 + src/test/debuginfo/basic-types-metadata.rs | 1 + src/test/debuginfo/basic-types-mut-globals.rs | 1 + src/test/debuginfo/basic-types.rs | 1 + src/test/debuginfo/borrowed-basic.rs | 1 + src/test/debuginfo/borrowed-c-style-enum.rs | 1 + src/test/debuginfo/borrowed-enum.rs | 1 + src/test/debuginfo/borrowed-struct.rs | 1 + src/test/debuginfo/borrowed-tuple.rs | 3 +- src/test/debuginfo/borrowed-unique-basic.rs | 1 + src/test/debuginfo/box.rs | 3 +- src/test/debuginfo/boxed-struct.rs | 1 + .../by-value-non-immediate-argument.rs | 1 + .../by-value-self-argument-in-trait-impl.rs | 1 + .../debuginfo/c-style-enum-in-composite.rs | 1 + src/test/debuginfo/c-style-enum.rs | 1 + .../debuginfo/closure-in-generic-function.rs | 1 + src/test/debuginfo/constant-debug-locs.rs | 1 + .../debuginfo/constant-in-match-pattern.rs | 1 + src/test/debuginfo/cross-crate-spans.rs | 5 +- .../debuginfo/destructured-fn-argument.rs | 3 +- .../destructured-for-loop-variable.rs | 1 + src/test/debuginfo/destructured-local.rs | 3 +- src/test/debuginfo/evec-in-struct.rs | 1 + src/test/debuginfo/extern-c-fn.rs | 1 + .../debuginfo/function-arg-initialization.rs | 1 + src/test/debuginfo/function-arguments.rs | 1 + ...nction-prologue-stepping-no-stack-check.rs | 1 + .../function-prologue-stepping-regular.rs | 1 + .../generic-enum-with-different-disr-sizes.rs | 1 + src/test/debuginfo/generic-function.rs | 1 + .../debuginfo/generic-functions-nested.rs | 1 + .../generic-method-on-generic-struct.rs | 1 + ...eneric-static-method-on-struct-and-enum.rs | 1 + .../debuginfo/generic-struct-style-enum.rs | 1 + src/test/debuginfo/generic-struct.rs | 1 + .../debuginfo/generic-tuple-style-enum.rs | 1 + src/test/debuginfo/include_string.rs | 1 + src/test/debuginfo/issue12886.rs | 3 +- src/test/debuginfo/issue22656.rs | 1 + .../debuginfo/lexical-scope-in-for-loop.rs | 1 + src/test/debuginfo/lexical-scope-in-if.rs | 1 + src/test/debuginfo/lexical-scope-in-match.rs | 1 + .../lexical-scope-in-stack-closure.rs | 1 + .../lexical-scope-in-unconditional-loop.rs | 1 + .../lexical-scope-in-unique-closure.rs | 1 + src/test/debuginfo/lexical-scope-in-while.rs | 1 + .../debuginfo/lexical-scope-with-macro.rs | 1 + .../lexical-scopes-in-block-expression.rs | 1 + src/test/debuginfo/limited-debuginfo.rs | 1 + src/test/debuginfo/method-on-enum.rs | 1 + .../debuginfo/method-on-generic-struct.rs | 1 + src/test/debuginfo/method-on-struct.rs | 1 + src/test/debuginfo/method-on-trait.rs | 1 + src/test/debuginfo/method-on-tuple-struct.rs | 1 + .../multiple-functions-equal-var-names.rs | 1 + src/test/debuginfo/multiple-functions.rs | 1 + .../name-shadowing-and-scope-nesting.rs | 1 + src/test/debuginfo/nil-enum.rs | 1 + src/test/debuginfo/no-debug-attribute.rs | 2 + src/test/debuginfo/option-like-enum.rs | 1 + .../packed-struct-with-destructor.rs | 1 + src/test/debuginfo/packed-struct.rs | 1 + src/test/debuginfo/recursive-enum.rs | 1 + src/test/debuginfo/recursive-struct.rs | 1 + src/test/debuginfo/self-in-default-method.rs | 1 + .../self-in-generic-default-method.rs | 1 + src/test/debuginfo/shadowed-argument.rs | 1 + src/test/debuginfo/shadowed-variable.rs | 1 + src/test/debuginfo/simd.rs | 1 + src/test/debuginfo/simple-lexical-scope.rs | 1 + src/test/debuginfo/simple-struct.rs | 1 + src/test/debuginfo/simple-tuple.rs | 1 + .../static-method-on-struct-and-enum.rs | 1 + src/test/debuginfo/struct-in-enum.rs | 1 + src/test/debuginfo/struct-in-struct.rs | 1 + src/test/debuginfo/struct-style-enum.rs | 1 + src/test/debuginfo/struct-with-destructor.rs | 1 + src/test/debuginfo/trait-pointers.rs | 1 + src/test/debuginfo/tuple-in-struct.rs | 1 + src/test/debuginfo/tuple-in-tuple.rs | 1 + src/test/debuginfo/tuple-struct.rs | 1 + src/test/debuginfo/tuple-style-enum.rs | 1 + src/test/debuginfo/type-names.rs | 1 + src/test/debuginfo/unique-enum.rs | 1 + src/test/debuginfo/unreachable-locals.rs | 1 + .../var-captured-in-nested-closure.rs | 1 + .../var-captured-in-sendable-closure.rs | 1 + .../var-captured-in-stack-closure.rs | 1 + src/test/debuginfo/vec-slices.rs | 1 + src/test/debuginfo/vec.rs | 1 + src/test/parse-fail/lifetime-in-pattern.rs | 16 + src/test/parse-fail/struct-no-fields-2.rs | 20 - src/test/parse-fail/struct-no-fields-3.rs | 20 - src/test/parse-fail/struct-no-fields-4.rs | 20 - src/test/parse-fail/struct-no-fields-5.rs | 20 - src/test/pretty/issue-4264.pp | 7 +- src/test/run-fail/issue-18576.rs | 2 +- src/test/run-fail/issue-28934.rs | 28 + src/test/run-fail/overflowing-add.rs | 4 +- src/test/run-fail/overflowing-lsh-1.rs | 5 +- src/test/run-fail/overflowing-lsh-2.rs | 5 +- src/test/run-fail/overflowing-lsh-3.rs | 5 +- src/test/run-fail/overflowing-lsh-4.rs | 5 +- src/test/run-fail/overflowing-mul.rs | 5 +- src/test/run-fail/overflowing-neg.rs | 5 +- src/test/run-fail/overflowing-rsh-1.rs | 5 +- src/test/run-fail/overflowing-rsh-2.rs | 5 +- src/test/run-fail/overflowing-rsh-3.rs | 5 +- src/test/run-fail/overflowing-rsh-4.rs | 5 +- src/test/run-fail/overflowing-sub.rs | 5 +- .../allow-non-lint-warnings-cmdline/1 | 0 .../allow-warnings-cmdline-stability/1 | 0 .../run-make/archive-duplicate-names/Makefile | 4 +- src/test/run-make/bare-outfile/Makefile | 4 +- src/test/run-make/c-dynamic-dylib/cfoo.c | 3 + src/test/run-make/c-dynamic-rlib/cfoo.c | 4 + .../run-make/c-link-to-rust-dylib/Makefile | 17 +- .../c-link-to-rust-staticlib/Makefile | 6 +- src/test/run-make/c-static-dylib/Makefile | 4 +- src/test/run-make/c-static-rlib/Makefile | 4 +- src/test/run-make/compile-stdin/Makefile | 5 + .../run-make/crate-name-priority/Makefile | 2 +- src/test/run-make/dep-info/Makefile | 10 +- .../{issue-12446/bar.rs => dep-info/lib2.rs} | 9 +- src/test/run-make/execution-engine/test.rs | 9 +- src/test/run-make/extern-fn-generic/Makefile | 8 +- src/test/run-make/extern-fn-mangle/Makefile | 6 +- .../extern-fn-struct-passing-abi/Makefile | 5 + .../extern-fn-struct-passing-abi/test.c | 260 + .../extern-fn-struct-passing-abi/test.rs | 98 + .../extern-fn-with-packed-struct/Makefile | 6 +- .../extern-fn-with-packed-struct/test.c | 10 + .../run-make/extern-fn-with-union/Makefile | 8 +- .../interdependent-c-libraries/Makefile | 2 +- src/test/run-make/invalid-staticlib/Makefile | 5 + src/test/run-make/issue-12446/Makefile | 6 - src/test/run-make/issue-12446/foo.c | 2 - src/test/run-make/issue-14500/Makefile | 2 +- src/test/run-make/issue-14698/Makefile | 4 + src/test/run-make/issue-14698/foo.rs | 11 + src/test/run-make/issue-15460/Makefile | 2 +- src/test/run-make/issue-15460/foo.c | 4 + src/test/run-make/issue-15460/foo.rs | 2 + src/test/run-make/issue-19371/foo.rs | 6 +- src/test/run-make/issue-25581/Makefile | 6 +- src/test/run-make/issue-26092/Makefile | 2 +- src/test/run-make/issue-28595/Makefile | 6 + src/test/run-make/issue-28595/a.c | 11 + src/test/run-make/issue-28595/a.rs | 16 + .../issue-28595/b.c} | 9 +- src/test/run-make/issue-28595/b.rs | 21 + src/test/run-make/link-path-order/Makefile | 8 +- .../run-make/linkage-attr-on-static/Makefile | 6 +- .../run-make/linkage-attr-on-static/bar.rs | 1 + .../run-make/linker-output-non-utf8/Makefile | 24 + .../run-make/linker-output-non-utf8/exec.rs | 16 + .../linker-output-non-utf8/library.rs | 20 + src/test/run-make/lto-smoke-c/Makefile | 4 +- src/test/run-make/no-duplicate-libs/Makefile | 5 + src/test/run-make/no-duplicate-libs/bar.c | 4 - src/test/run-make/no-duplicate-libs/foo.c | 2 - .../output-type-permutations/Makefile | 64 +- src/test/run-make/relocation-model/Makefile | 14 +- src/test/run-make/save-analysis/Makefile | 2 +- src/test/run-make/save-analysis/foo.rs | 19 + .../run-make/static-dylib-by-default/Makefile | 9 +- src/test/run-make/tools.mk | 46 +- .../run-pass-fulldeps/rename-directory.rs | 4 +- src/test/run-pass/arr_cycle.rs | 2 +- src/test/run-pass/augmented-assignments.rs | 164 + .../run-pass/autoderef-method-on-trait.rs | 2 +- src/test/run-pass/borrowck-rvalues-mutable.rs | 2 +- src/test/run-pass/cfg-target-vendor.rs | 19 + src/test/run-pass/const-adt-align-mismatch.rs | 2 +- src/test/run-pass/const-fn-const-eval.rs | 19 + src/test/run-pass/const-unsafe-fn.rs | 31 + src/test/run-pass/core-run-destroy.rs | 36 +- .../crate-method-reexport-grrrrrrr.rs | 2 +- src/test/run-pass/deprecated-derive.rs | 8 +- src/test/run-pass/dropck_legal_cycles.rs | 526 +- src/test/run-pass/dropck_tarena_sound_drop.rs | 2 +- src/test/run-pass/empty-struct-braces.rs | 88 + src/test/run-pass/ifmt.rs | 4 + .../run-pass/impl-inherent-non-conflict.rs | 2 +- src/test/run-pass/issue-10767.rs | 2 +- src/test/run-pass/issue-11047.rs | 35 + src/test/run-pass/issue-11577.rs | 1 - src/test/run-pass/issue-14919.rs | 2 +- src/test/run-pass/issue-16819.rs | 22 + src/test/run-pass/issue-17336.rs | 17 + src/test/run-pass/issue-21410.rs | 15 + src/test/run-pass/issue-21922.rs | 26 + src/test/run-pass/issue-22403.rs | 15 + src/test/run-pass/issue-22781.rs | 23 + src/test/run-pass/issue-22814.rs | 22 + src/test/run-pass/issue-23036.rs | 18 + src/test/run-pass/issue-23891.rs | 20 + src/test/run-pass/issue-24085.rs | 2 +- src/test/run-pass/issue-24389.rs | 20 + src/test/run-pass/issue-24533.rs | 32 + .../run-pass/issue-24805-dropck-itemless.rs | 7 +- src/test/run-pass/issue-24956.rs | 20 + src/test/run-pass/issue-24972.rs | 36 + src/test/run-pass/issue-25439.rs | 19 + src/test/run-pass/issue-25693.rs | 30 + src/test/run-pass/issue-26095.rs | 30 + src/test/run-pass/issue-26905.rs | 31 + src/test/run-pass/issue-27105.rs | 24 + src/test/run-pass/issue-27320.rs | 21 + src/test/run-pass/issue-28189.rs | 15 + src/test/run-pass/issue-28279.rs | 30 + src/test/run-pass/issue-28561.rs | 120 + src/test/run-pass/issue-28676.rs | 40 + .../foo.rs => run-pass/issue-28822.rs} | 11 +- src/test/run-pass/issue-28839.rs | 24 + src/test/run-pass/issue-28936.rs | 36 + src/test/run-pass/issue-28983.rs | 31 + src/test/run-pass/issue-28999.rs | 20 + src/test/run-pass/issue-29037.rs | 32 + .../issue-29048.rs} | 14 +- src/test/run-pass/issue-29166.rs | 30 + src/test/run-pass/issue-2935.rs | 2 +- src/test/run-pass/issue-29746.rs | 45 + .../issue-30081.rs} | 19 +- src/test/run-pass/issue-5060.rs | 3 +- src/test/run-pass/issue28498-must-work-ex1.rs | 27 + src/test/run-pass/issue28498-must-work-ex2.rs | 30 + src/test/run-pass/issue28498-ugeh-ex1.rs | 37 + .../issue28498-ugeh-with-lifetime-param.rs | 48 + .../issue28498-ugeh-with-passed-to-fn.rs | 56 + .../issue28498-ugeh-with-trait-bound.rs | 51 + src/test/run-pass/lambda-var-hygiene.rs | 2 - src/test/run-pass/new-box-syntax.rs | 6 +- src/test/run-pass/pushpop-unsafe-okay.rs | 56 - .../regions-early-bound-trait-param.rs | 2 +- src/test/run-pass/sepcomp-cci.rs | 12 +- src/test/run-pass/shift-near-oflo.rs | 43 +- .../sync-send-iterators-in-libcollections.rs | 3 +- src/test/run-pass/trait-object-generics.rs | 2 +- .../run-pass/unary-minus-suffix-inference.rs | 2 + src/test/run-pass/vec_cycle.rs | 2 +- src/test/run-pass/vec_cycle_wrapped.rs | 4 +- src/test/run-pass/wrapping-int-api.rs | 2 - src/test/run-pass/x86stdcall2.rs | 2 +- src/test/rustdoc/hidden-line.rs | 4 - 1040 files changed, 33241 insertions(+), 22447 deletions(-) create mode 100644 mk/cfg/x86_64-rumprun-netbsd.mk delete mode 100644 src/doc/style/changing/README.md delete mode 100644 src/doc/style/changing/post-1-0.md delete mode 100644 src/doc/style/changing/pre-1-0.md delete mode 100644 src/doc/style/changing/unclear.md create mode 100644 src/doc/trpl/custom-allocators.md create mode 100644 src/doc/trpl/syntax-index.md rename src/libcore/num/{flt2dec => }/bignum.rs (96%) create mode 100644 src/libcore/num/diy_float.rs rename src/libcoretest/num/{flt2dec => }/bignum.rs (99%) create mode 100644 src/librustc/front/check_attr.rs create mode 100644 src/librustc/front/map/collector.rs create mode 100644 src/librustc/front/map/definitions.rs rename src/{rustbook/javascript.rs => librustc_back/slice.rs} (69%) create mode 100644 src/librustc_back/target/le32_unknown_nacl.rs create mode 100644 src/librustc_back/target/x86_64_rumprun_netbsd.rs delete mode 100644 src/librustc_front/attr.rs delete mode 100644 src/librustc_front/print/pp.rs create mode 100644 src/librustc_lint/bad_style.rs create mode 100644 src/librustc_lint/types.rs create mode 100644 src/librustc_lint/unused.rs rename src/librustc_mir/{dump.rs => mir_map.rs} (57%) create mode 100644 src/librustc_trans/diagnostics.rs create mode 100644 src/librustdoc/html/static/COPYRIGHT.txt create mode 100644 src/librustdoc/html/static/LICENSE-APACHE.txt create mode 100644 src/librustdoc/html/static/LICENSE-MIT.txt rename src/libsyntax/ext/deriving/{show.rs => debug.rs} (99%) delete mode 100644 src/libsyntax/ext/pushpop_safe.rs create mode 100644 src/test/auxiliary/augmented_assignments.rs create mode 100644 src/test/auxiliary/issue-29181.rs create mode 100644 src/test/codegen/adjustments.rs create mode 100644 src/test/codegen/consts.rs create mode 100644 src/test/codegen/gdb_debug_script_load.rs create mode 100644 src/test/codegen/match.rs create mode 100644 src/test/codegen/refs.rs create mode 100644 src/test/compile-fail/attr-usage-inline.rs create mode 100644 src/test/compile-fail/attr-usage-repr.rs create mode 100644 src/test/compile-fail/augmented-assignments-feature-gate-cross.rs create mode 100644 src/test/compile-fail/augmented-assignments-feature-gate.rs create mode 100644 src/test/compile-fail/augmented-assignments-trait.rs create mode 100644 src/test/compile-fail/augmented-assignments.rs create mode 100644 src/test/compile-fail/borrowck-argument.rs rename src/test/{ => compile-fail}/borrowck-loan-of-static-data-issue-27616.rs (100%) create mode 100644 src/test/compile-fail/borrowck-mut-borrow-linear-errors.rs create mode 100644 src/test/compile-fail/const-err.rs create mode 100644 src/test/compile-fail/const-eval-span.rs create mode 100644 src/test/compile-fail/const-fn-destructuring-arg.rs rename src/test/compile-fail/{feature-gate-pushpop-unsafe.rs => const-slice-oob.rs} (74%) rename src/test/compile-fail/{for-expn-2.rs => dupe-symbols-8.rs} (78%) create mode 100644 src/test/compile-fail/empty-comment.rs create mode 100644 src/test/compile-fail/empty-struct-braces-expr.rs create mode 100644 src/test/compile-fail/empty-struct-braces-gate-1.rs create mode 100644 src/test/compile-fail/empty-struct-braces-gate-2.rs create mode 100644 src/test/compile-fail/empty-struct-braces-pat-1.rs create mode 100644 src/test/compile-fail/empty-struct-braces-pat-2.rs create mode 100644 src/test/compile-fail/empty-struct-unit-expr.rs create mode 100644 src/test/compile-fail/empty-struct-unit-pat.rs create mode 100644 src/test/compile-fail/feature-gate-cfg-target-vendor.rs create mode 100644 src/test/compile-fail/feature-gate-dropck-ugeh.rs rename src/test/{run-pass => compile-fail}/feature-gate-negate-unsigned.rs (67%) create mode 100644 src/test/compile-fail/feature-gate-no-debug.rs create mode 100644 src/test/compile-fail/feature-gate-omit-gdb-pretty-printer-section.rs create mode 100644 src/test/compile-fail/invalid-path-in-const.rs create mode 100644 src/test/compile-fail/issue-16819.rs create mode 100644 src/test/compile-fail/issue-21546.rs create mode 100644 src/test/compile-fail/issue-22599.rs delete mode 100644 src/test/compile-fail/issue-22872.rs create mode 100644 src/test/compile-fail/issue-23543.rs create mode 100644 src/test/compile-fail/issue-23544.rs create mode 100644 src/test/compile-fail/issue-25145.rs create mode 100644 src/test/compile-fail/issue-26056.rs create mode 100644 src/test/compile-fail/issue-26459.rs create mode 100644 src/test/compile-fail/issue-26886.rs create mode 100644 src/test/compile-fail/issue-26905.rs create mode 100644 src/test/compile-fail/issue-27895.rs create mode 100644 src/test/compile-fail/issue-28075.rs create mode 100644 src/test/compile-fail/issue-28388-1.rs create mode 100644 src/test/compile-fail/issue-28388-2.rs create mode 100644 src/test/compile-fail/issue-28388-3.rs create mode 100644 src/test/compile-fail/issue-28433.rs rename src/test/compile-fail/{issue-3993-2.rs => issue-28472.rs} (60%) create mode 100644 src/test/compile-fail/issue-28576.rs create mode 100644 src/test/compile-fail/issue-28776.rs create mode 100644 src/test/compile-fail/issue-28837.rs create mode 100644 src/test/compile-fail/issue-29106.rs create mode 100644 src/test/compile-fail/issue-29161.rs create mode 100644 src/test/compile-fail/issue-29181.rs rename src/test/{parse-fail/struct-no-fields.rs => compile-fail/issue-29184.rs} (77%) create mode 100644 src/test/compile-fail/issue28498-reject-ex1.rs create mode 100644 src/test/compile-fail/issue28498-reject-lifetime-param.rs create mode 100644 src/test/compile-fail/issue28498-reject-passed-to-fn.rs create mode 100644 src/test/compile-fail/issue28498-reject-trait-bound.rs create mode 100644 src/test/compile-fail/placement-expr-unsafe.rs create mode 100644 src/test/compile-fail/placement-expr-unstable.rs create mode 100644 src/test/compile-fail/privacy-ufcs.rs delete mode 100644 src/test/compile-fail/pushpop-unsafe-rejects.rs create mode 100644 src/test/compile-fail/stability-attribute-sanity-2.rs rename src/test/{parse-fail => compile-fail}/struct-no-fields-enumlike.rs (80%) create mode 100644 src/test/compile-fail/trait-not-accessible.rs create mode 100644 src/test/compile-fail/unsafe-const-fn.rs rename src/test/compile-fail/{useless-priv.rs => useless-pub.rs} (91%) create mode 100644 src/test/compile-fail/wf-method-late-bound-regions.rs create mode 100644 src/test/compile-fail/wf-misc-methods-issue-28609.rs create mode 100644 src/test/compile-fail/wf-static-method.rs create mode 100644 src/test/parse-fail/lifetime-in-pattern.rs delete mode 100644 src/test/parse-fail/struct-no-fields-2.rs delete mode 100644 src/test/parse-fail/struct-no-fields-3.rs delete mode 100644 src/test/parse-fail/struct-no-fields-4.rs delete mode 100644 src/test/parse-fail/struct-no-fields-5.rs create mode 100644 src/test/run-fail/issue-28934.rs delete mode 100644 src/test/run-make/allow-non-lint-warnings-cmdline/1 delete mode 100644 src/test/run-make/allow-warnings-cmdline-stability/1 create mode 100644 src/test/run-make/compile-stdin/Makefile rename src/test/run-make/{issue-12446/bar.rs => dep-info/lib2.rs} (85%) create mode 100644 src/test/run-make/extern-fn-struct-passing-abi/Makefile create mode 100644 src/test/run-make/extern-fn-struct-passing-abi/test.c create mode 100644 src/test/run-make/extern-fn-struct-passing-abi/test.rs create mode 100644 src/test/run-make/invalid-staticlib/Makefile delete mode 100644 src/test/run-make/issue-12446/Makefile delete mode 100644 src/test/run-make/issue-12446/foo.c create mode 100644 src/test/run-make/issue-14698/Makefile create mode 100644 src/test/run-make/issue-14698/foo.rs create mode 100644 src/test/run-make/issue-28595/Makefile create mode 100644 src/test/run-make/issue-28595/a.c create mode 100644 src/test/run-make/issue-28595/a.rs rename src/test/{run-pass/issue-14564.rs => run-make/issue-28595/b.c} (90%) create mode 100644 src/test/run-make/issue-28595/b.rs create mode 100644 src/test/run-make/linker-output-non-utf8/Makefile create mode 100644 src/test/run-make/linker-output-non-utf8/exec.rs create mode 100644 src/test/run-make/linker-output-non-utf8/library.rs delete mode 100644 src/test/run-make/no-duplicate-libs/bar.c delete mode 100644 src/test/run-make/no-duplicate-libs/foo.c create mode 100644 src/test/run-pass/augmented-assignments.rs create mode 100644 src/test/run-pass/cfg-target-vendor.rs create mode 100644 src/test/run-pass/const-fn-const-eval.rs create mode 100644 src/test/run-pass/const-unsafe-fn.rs create mode 100644 src/test/run-pass/empty-struct-braces.rs create mode 100644 src/test/run-pass/issue-11047.rs create mode 100644 src/test/run-pass/issue-16819.rs create mode 100644 src/test/run-pass/issue-17336.rs create mode 100644 src/test/run-pass/issue-21410.rs create mode 100644 src/test/run-pass/issue-21922.rs create mode 100644 src/test/run-pass/issue-22403.rs create mode 100644 src/test/run-pass/issue-22781.rs create mode 100644 src/test/run-pass/issue-22814.rs create mode 100644 src/test/run-pass/issue-23036.rs create mode 100644 src/test/run-pass/issue-23891.rs create mode 100644 src/test/run-pass/issue-24389.rs create mode 100644 src/test/run-pass/issue-24533.rs create mode 100644 src/test/run-pass/issue-24956.rs create mode 100644 src/test/run-pass/issue-24972.rs create mode 100644 src/test/run-pass/issue-25439.rs create mode 100644 src/test/run-pass/issue-25693.rs create mode 100644 src/test/run-pass/issue-26095.rs create mode 100644 src/test/run-pass/issue-26905.rs create mode 100644 src/test/run-pass/issue-27105.rs create mode 100644 src/test/run-pass/issue-27320.rs create mode 100644 src/test/run-pass/issue-28189.rs create mode 100644 src/test/run-pass/issue-28279.rs create mode 100644 src/test/run-pass/issue-28561.rs create mode 100644 src/test/run-pass/issue-28676.rs rename src/test/{run-make/issue-12446/foo.rs => run-pass/issue-28822.rs} (81%) create mode 100644 src/test/run-pass/issue-28839.rs create mode 100644 src/test/run-pass/issue-28936.rs create mode 100644 src/test/run-pass/issue-28983.rs create mode 100644 src/test/run-pass/issue-28999.rs create mode 100644 src/test/run-pass/issue-29037.rs rename src/test/{parse-fail/struct-variant-no-fields.rs => run-pass/issue-29048.rs} (66%) create mode 100644 src/test/run-pass/issue-29166.rs create mode 100644 src/test/run-pass/issue-29746.rs rename src/test/{parse-fail/parenthesized-box-expr-message.rs => run-pass/issue-30081.rs} (54%) create mode 100644 src/test/run-pass/issue28498-must-work-ex1.rs create mode 100644 src/test/run-pass/issue28498-must-work-ex2.rs create mode 100644 src/test/run-pass/issue28498-ugeh-ex1.rs create mode 100644 src/test/run-pass/issue28498-ugeh-with-lifetime-param.rs create mode 100644 src/test/run-pass/issue28498-ugeh-with-passed-to-fn.rs create mode 100644 src/test/run-pass/issue28498-ugeh-with-trait-bound.rs delete mode 100644 src/test/run-pass/pushpop-unsafe-okay.rs diff --git a/AUTHORS.txt b/AUTHORS.txt index 310a91b2d1..d5db7e3310 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -9,7 +9,9 @@ Aaron Todd Aaron Turon Aaron Weiss Abhishek Chanda +Adam Badawy Adam Bozanich +Adam Crume Adam Heins Adam Jacob Adam Roben @@ -30,8 +32,10 @@ Alan Cutter Alan Williams Aleksander Balicki Aleksandr Koshlo +Aleksey Kladov Alexander Artemenko Alexander Bliskovsky +Alexander Bulaev Alexander Campbell Alexander Chernyakhovsky Alexander Korolkov @@ -42,19 +46,25 @@ Alexandre Gagnon Alexandros Tasos Alex Burka Alex Crichton +AlexDenisov <1101.debian@gmail.com> Alexei Sholik Alex Gaynor Alexis Beingessner Alex Lyon Alex Newman +Alex Ozdemir Alex Quach Alex Rønne Petersen Alex Stokes Alex Whitney Alfie John +Alfie John Alisdair Owens Ali Smesseim Aljaž "g5pw" Srebrnič +Amanieu d'Antras +Amit Aryeh Levy +Amit Saha Amol Mundayoor Amy Unger Anatoly Ikorsky @@ -65,7 +75,9 @@ Andreas Gal Andreas Martens Andreas Neuhaus Andreas Ots +Andreas Sommer Andreas Tolfsen +Andre Bogus Andrei Formiga Andrei Oprea Andrew Barchuk @@ -82,14 +94,18 @@ Andrew Poelstra Andrew Seidl Andrew Straw Andrew Wagner +androm3da Andrzej Janik Andy Caldwell Andy Grover +angelsl Angus Lees Anthony Juckel Anton Löfgren Antti Keränen +aochagavia Aram Visser +arcnmx Arcterus Areski Belaid Ariel Ben-Yehuda @@ -99,9 +115,11 @@ Armin Preiml Armin Ronacher Arpad Borsos Artem +Artem Shitov Arthur Liao arthurprs arturo +Ashkan Kiani Ashok Gautham Augusto Hack auREAX @@ -113,8 +131,11 @@ Avdi Grimm awlnx Axel Viala Aydin Kim +b1nd bachm +Barosl LEE Barosl Lee +Bastien Dejean bcoopers Ben Alpert benaryorg @@ -133,19 +154,24 @@ Benjamin Peterson Ben Kelly Ben Noordhuis Ben Sago +benshu +Ben S Ben Striegel +Bhargav Patel Bheesham Persaud Bilal Husain Bill Fallon Bill Myers +billpmurphy Bill Wendling Birunthan Mohanathas Björn Steinbrink +blackbeam blake2-ppc Blake Loring -bluss bluss -Boris Egorov +bombless +Boris Egorov bors Bouke van der Bijl Brad King @@ -169,10 +195,14 @@ Brian Leibig Brian Quinlan Brody Holden Bruno de Oliveira Abinader +Bruno Tavares Bryan Dunsmore +Bryce Van Dyk Byron Williams Cadence Marseille +caipre Caitlin Potter +Cameron Sun Cameron Zwarich Camille Roussel Camille TJHOA @@ -180,18 +210,25 @@ Cam Jackson Carl-Anton Ingmarsson Carl Lerche Carlos Galarza +Carlos Liam +Carlos Carol (Nichols || Goulding) Carol Willing Carter Hinsley Carter Tazio Schonwald CarVac Caspar Krieger +Cesar Eduardo Barros +Charlotte Spencer Chase Southwood Ches Martin -chitra +chitra Chloe <5paceToast@users.noreply.github.com> +Chris C Cerami Chris Double +Chris Drake Chris Hellmuth +Chris Krycho Chris Morgan Chris Nixon Chris Peterson @@ -205,6 +242,7 @@ Christian Weinz Christoph Burgdorf Christopher Bergqvist Christopher Chambers +christopherdumas Christopher Kendell Chris Wong chromatic @@ -220,18 +258,25 @@ Cole Mickens Cole Reynolds Colin Davidson Colin Sherratt +Colin Wallace Colin Walters comex Conrad Kleinespel +corentih +Corentin Henry Corey Farwell Corey Ford Corey Richardson Cornel Punga +Craig Hills crhino Cristian Kubis Cristi Burcă +Cristi Cobzarenco critiqjo Cruz Julian Bishop +Daan Rijks +Dabo Ross Damian Gryski Damien Grassart Damien Radtke @@ -242,11 +287,13 @@ Dan Callahan Dan Connolly Daniel Albert Daniel Brooks +Daniel Carral Daniel Fagnan Daniel Farina Daniel Griffen Daniel Grunwald Daniel Hofstetter +Daniel Keep Daniel Lobato García Daniel Luz Daniel MacDougall @@ -255,9 +302,12 @@ Daniel Patterson Daniel Raloff Daniel Ralston Daniel Ramos +Daniel Rollins Daniel Rosenwasser +Daniel Trebbien Daniel Ursache Dogariu Daniil Smirnov +Danilo Bargen Dan Luu Dan Schatzberg Dan W. <1danwade@gmail.com> @@ -265,11 +315,13 @@ Dan Yang Darin Morrison darkf Darrell Hamilton +Dato Simó Dave Herman Dave Hodder Dave Huseby David Campbell David Creswick +David Elliott David Forsythe David Halperin David King @@ -279,17 +331,21 @@ David Manescu David Rajchenbach-Teller David Reid David Renshaw +David Ripton David Ross David Stygstra +David Szotten David Vazgenovich Shakaryan David Voit Davis Silverman defuz Denis Defreyne +DenisKolodin Derecho Derek Chiang Derek Guenther Derek Harland +Devon Hollowood dgoon diaphore Diego Giagio @@ -311,10 +367,13 @@ Dmitry Vasiliev Dominick Allen Dominic van Berkel Dominik Inführ +Dongie Agnir +Dong Zhou Do Nhat Minh donkopotamus Donovan Preston Don Petersen +Doug Goldstein Douglas Young Drew Crawford Drew Willcoxon @@ -322,8 +381,10 @@ Duane Edwards Duncan Regan Dylan Braithwaite Dylan Ede +Dylan McKay Dzmitry Malyshau Earl St Sauver +ebadf econoplas Eduard Bopp Eduard Burtescu @@ -339,12 +400,14 @@ Elliott Slaughter Elly Fong-Jones elszben emanueLczirai +Emanuel Czirai Emanuel Rylke Emeliov Dmitrii Emilio Cobos Álvarez Emily Dunham Eric Allen Eric Biggers +Eric Findlay Eric Holk Eric Holmes Eric Kidd @@ -354,6 +417,7 @@ Eric Martin Eric Platon Eric Reed Eric Ye +Erik Davidson Erik Lyon Erik Michaels-Ober Erik Price @@ -366,8 +430,9 @@ Eunchong Yu Eunji Jeong Evan Klitzke Evan McClanahan -Evgeny Sologubov +Evgeny Sologubov Fabian Deutsch +Fabiano Beselga Fabrice Desré FakeKane Falco Hirschenberger @@ -378,7 +443,7 @@ Felix S. Klock II fenduru Fenhl Filip Szczepański -Flaper Fesp +Flavio Percoco flo-l Florian Gilcher Florian Hahn @@ -418,11 +483,13 @@ Germano Gabbianelli Gil Cottle Gioele Barabucci github-monoculture +GlacJAY Gleb Kozyrev +glendc Glenn Willen Gonçalo Cabrita <_@gmcabrita.com> Grahame Bowland -Graham Fawcett +Graham Fawcett Graydon Hoare Greg Chapple Grigoriy @@ -447,6 +514,7 @@ Honza Strnad Huachao Huang Hugo Jobling Hugo van der Wijst +Hunan Rostomyan Huon Wilson Hyeon Kim Ian Connolly @@ -454,22 +522,30 @@ Ian Daniher Ian D. Bollinger Ignacio Corderi Igor Bukanov +Igor Shuvalov Igor Strebezhev Ilya Dmitrichenko Ilyong Cho Ingo Blechschmidt inrustwetrust +Irving A.J. Rivas Z. Isaac Aggrey Isaac Dupree Isaac Ge Ivan Enderlin +Ivan Ivaschenko +Ivan Jager +Ivan Kozik Ivano Coppola Ivan Petkov Ivan Radanov Ivanov +Ivan Stankovic Ivan Ukhov Iven Hsu +Jack Fransham Jack Heizer Jack Moffitt +Jack Wilson Jacob Edelman Jacob Harris Cryer Kragh Jacob Hegna @@ -481,14 +557,18 @@ Jake Hickey Jake Kaufman Jake Kerr Jake Scott +Jake Shadle +Jake Worth Jakub Bukaj Jakub Vrána Jakub Wieczorek +James Bell James Deng James Hurst James Lal James Laverack jamesluke +James McGlashan James Miller James Perry James Rowe @@ -518,6 +598,7 @@ Jay True J Bailey jbranchaud J.C. Moyer +Jean Maillard Jeaye Jed Davis Jed Estep @@ -527,6 +608,7 @@ Jeff Belgum Jeff Muizelaar Jeff Olson Jeff Parsons +Jeffrey Seyfried Jeffrey Yasskin Jelte Fennema Jens Nockert @@ -539,10 +621,11 @@ Jesse Ray Jesse Ruderman Jessy Diamond Exum Jesús Espino +Jethro Beekman jethrogb Jexell Jihyeok Seo -Jihyun Yu +Jihyun Yu Jim Apple Jim Blandy Jimmie Elvenmark @@ -554,13 +637,14 @@ J. J. Weber jmgrosen jmu303 João Oliveira +joaoxsouls Joe Pletcher Joe Schafer Johannes Hoff Johannes Löthberg Johannes Muenzel Johannes Oertel -Johann Hofmann +Johann Hofmann Johann Tuffe John Albietz John Barker @@ -575,10 +659,12 @@ John Louis Walker John Schmidt John Simon John Talling +John Thomas John Van Enk John Zhang joliv Jonas Hietala +Jonas Schievink Jonathan Bailey Jonathan Boyett Jonathan Hansford @@ -593,25 +679,32 @@ Joonas Javanainen Jordan Humphreys Jordan Woehr Jordi Boggiano -Jorge Aparicio +Jorge Aparicio Jorge Israel Peña Joris Rehm Jormundir +Jørn Lode Jose Narvaez +Joseph Caudle Joseph Crail Joseph Martin Joseph Rushton Wakeling +Josh Austin Josh Haberman Josh Matthews Josh Stone Josh Triplett Joshua Clark +Joshua Holmer Joshua Landau Joshua Wise Joshua Yanovski +jotomicron JP-Ellis JP Sugarbroad +jrburke jrincayc +J. Ryan Stinnett Julia Evans Julian Orth Julian Viereck @@ -640,12 +733,15 @@ Kevin Murphy Kevin Rauwolf Kevin Walter Kevin Yap +Kevin Yeh kgv +kickinbahk Kieran Hunt Kiet Tran Kim Røen kjpgit klutzy +Kohei Hasegawa KokaKiwi korenchkin Kornel Lesiński @@ -657,6 +753,8 @@ Kubilay Kocak kulakowski kwantam Kyeongwoon Lee +Kyle Mayes +Kyle Robinson Young Lai Jiangshan Lars Bergstrom Laurence Tratt @@ -666,6 +764,7 @@ Lawrence Velázquez Leah Hanson Lee Aronson Lee Jeffery +Lee Jenkins Lee Wondong Leif Arne Storset LemmingAvalanche @@ -678,6 +777,7 @@ Liam Monahan Liigo Zhuang Lindsey Kuper Lionel Flandrin +llogiq Logan Chien Loïc Damien Lorenz @@ -701,7 +801,10 @@ Makoto Kato Makoto Nakashima Manish Goregaokar Manuel Hoffmann +Marc-Antoine Perennou marcell +Marcello Seri +Marcell Pardavi Marcel Müller Marcel Rodrigues Marcus Klaas @@ -712,6 +815,7 @@ Mário Feroldi Mark Buer Mark Lacey <641@rudkx.com> Mark Mossberg +Marko Lalic Mark Rowe Mark Sinclair Markus Siemens @@ -721,9 +825,11 @@ Mark Vian Martin DeMello Martin Olsson Martin Pool +Martin WernstÃ¥l Marti Raudsepp Marvin Löbel masklinn +Matěj Grabovský Matej Lach Mateusz Czapliński Mathieu David @@ -740,7 +846,9 @@ Matthew Auld Matthew Iselin Matthew McPherrin Matthew O'Connor +Matthias Bussonnier Matthias Einwag +Matthias Kauer Matthijs Hofstra Matthijs van der Vleuten Matt McPherrin @@ -762,15 +870,18 @@ Michael Alexander Michael Arntzenius Michael Bebenita Michael Budde +Michael Choate Michael Dagitses Michael Darakananda Michael Fairley Michael Gehring +Michael Howell Michael Kainer Michael Layzell Michael Letterle Michael Macias Michael Matuzak +Michael McConville Michael Neumann Michael Pankov Michael Park @@ -790,10 +901,12 @@ Mickaël Raybaud-Roig Mickaël Salaün Mick Koch midinastasurazz +Mihaly Barasz Mihnea Dobrescu-Balaur Mike Boutin Mike Dilger Mike English +Mike Marcacci Mike Pedersen Mike Robinson Mike Sampson @@ -814,6 +927,7 @@ nathan dotz Nathan Froyd Nathaniel Herman Nathaniel Theis +Nathan Kleyn Nathan Long Nathan Stoddard Nathan Typanski @@ -822,9 +936,11 @@ Nathan Zadoks Neil Pankey Nelo Onyiah Nelson Chen +nham NiccosSystem Nicholas Bishop Nicholas Mazzuca +Nicholas Seckar Nick Cameron Nick Desaulniers Nick Fitzgerald @@ -839,9 +955,11 @@ Niels langager Ellegaard Nif Ward Nikita Pekin Niklas Koep +Nikolay Kondratyev Niko Matsakis Nils Liberg Nils Winter +Niranjan Padmanabhan noam Noam Yorav-Raphael NODA, Kai @@ -849,25 +967,31 @@ Noufal Ibrahim novalis nsf nwin +nxnfufunezn Oak OGINO Masanori OlegTsyba -Oliver Schneider +Ole Krüger +Oliver Middleton +Oliver Schneider Olivier Saut olivren Olle Jonsson olombard Or Brostovski Oren Hazi +Ori Avtalion Or Neeman Orphée Lafond-Lummis Orpheus Lummis osa1 O S K Chaitanya +Overmind JIANG Ožbolt Menegatti P1start Pablo Brasero Palmer Cox +panicbit Paolo Falabella Parker Moore Pascal Hertleif @@ -876,6 +1000,7 @@ Patrick Walton Patrick Yevsukov Patrik KÃ¥rlin Paul ADENOT +Paul A. Jungwirth Paul Banks Paul Collier Paul Collins @@ -898,6 +1023,7 @@ Peter Elmers Peter Hull Peter Marheine Peter Minten +Peter Reid Peter Schuller Peter Williams Peter Zotov @@ -907,8 +1033,11 @@ Phil Dawes Philip Munksgaard Philipp Brüschweiler Philipp Gesang +Philipp Matthias Schäfer +Philipp Oppermann Phil Ruffwind Pierre Baillet +pierzchalski Piotr Czarnecki Piotr Jawniak Piotr Szotkowski @@ -916,10 +1045,12 @@ Piotr Zolnierek Poga Po posixphreak Potpourri +Pradeep Kumar Prudhvi Krishna Surapaneni Przemysław Wesołek Pyfisch Pyry Kontio +Pythoner6 Q.P.Liu qwitwa Rafael Ávila de Espíndola @@ -933,6 +1064,7 @@ Raphael Catolino Raphael Nestler Raphael Speyer Raul Gutierrez S +Ravi Shankar Ray Clanan ray glover reedlepee @@ -942,20 +1074,25 @@ Rémi Audebert Remi Rampin Renato Alves Renato Riccieri Santos Zannon +Renato Zannon Reuben Morais reus +Reza Akhavan Ricardo Martins Ricardo M. Correia +Ricardo Signes Richard Diamond Rich Lane Richo Healey Rick Waldron Ricky Taylor +Rizky Luthfianto rjz Rob Arnold Robert Buonpastore Robert Clipsham Robert Foss +Robert Gardner Robert Gawdzik Robert Irelan Robert Knight @@ -973,6 +1110,7 @@ Ron Dahlgren Rory O’Kane Roy Crihfield Roy Frostig +Ruby Rüdiger Sonderfeld rundrop1 Russell Johnston @@ -986,6 +1124,7 @@ Ryan Riginding Ryan Scheel Ryman らいどっと +Ryo Munakata Sae-bom Kim Salem Talha saml @@ -1011,14 +1150,17 @@ Sean Patrick Santos Sean Stangl Sean T Allen Sebastian Gesemann +Sebastian Hahn Sebastian N. Fernandez Sebastian Rasmussen +Sebastian Wicki Sebastian Zaha Sébastien Chauvel Sébastien Crozet Sébastien Marie Sebastien Martini Sébastien Paolacci +Seeker14491 Seonghyun Kim Seo Sanghyeon Sergio Benitez @@ -1033,12 +1175,14 @@ SiegeLord Simonas Kazlauskas Simon Barber-Dueck Simon Kern +Simon Mazur Simon Persson Simon Sapin Simon Wollwage simplex Sindre Johansen sinkuu +skeleten Skyler smenardpw Son @@ -1047,6 +1191,7 @@ S Pradeep Kumar Squeaky startling Stefan Bucur +Stefan O'Rear Stefan Plantikow Stepan Koltsov Sterling Greene @@ -1072,7 +1217,9 @@ Taras Shpot tav Taylor Hutchison Ted Horst +Ted Mielczarek Tero Hänninen +Tero Hänninen th0114nd Thad Guidry Theo Belaire @@ -1092,8 +1239,11 @@ Till Hoeppner Tim Brooks Tim Chevalier Tim Cuthbertson +Tim Dumol +Tim JIANG Tim Joseph Dumol Tim Kuehn +Tim Neumann Timon Rapp Timothée Ravier Tim Parenti @@ -1131,6 +1281,7 @@ tynopex Ty Overby Ulrik Sverdrup Ulysse Carion +U-NOV2010\eugals User Jyyou Utkarsh Kukreti Uwe Dauernheim @@ -1138,6 +1289,7 @@ Vadim Chugunov Vadim Petrochenkov Valentin Tsatskin Valerii Hiora +Viacheslav Chimishuk Victor Berger Victor van den Elzen Victory @@ -1157,6 +1309,7 @@ Vladimir Rutsky Vladimir Smola Vojtech Kral Volker Mische +w00ns Wade Mealing Wangshan Lu WebeWizard @@ -1173,10 +1326,16 @@ Will Hipschman William Throwe William Ting Willson Mock +Will Speak Will +Willy Aguirre +Without Boats Wojciech Ogrodowczyk wonyong kim xales +Xavier Shay +xd1le +Xiao Chuan Yu Xuefeng Wu XuefengWu Xuefeng Wu @@ -1187,6 +1346,7 @@ Yazhong Liu Yehuda Katz Yongqian Li York Xiang +Yoshito Komatsu Young-il Choi Youngmin Yoo Youngsoo Son diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f81bb0bd69..515e6e18f7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -145,10 +145,15 @@ To save @bors some work, and to get small changes through more quickly, when the other rollup-eligible patches too, and they'll get tested and merged at the same time. -To find documentation-related issues, sort by the [A-docs label][adocs]. +To find documentation-related issues, sort by the [A-docs label][adocs]. [adocs]: https://github.com/rust-lang/rust/issues?q=is%3Aopen+is%3Aissue+label%3AA-docs +In many cases, you don't need a full `make doc`. You can use `rustdoc` directly +to check small fixes. For example, `rustdoc src/doc/reference.md` will render +reference to `doc/reference.html`. The CSS might be messed up, but you can +verify that HTML is right. + ## Issue Triage Sometimes, an issue will stay open, even though the bug has been fixed. And @@ -164,30 +169,30 @@ Contributors with sufficient permissions on the Rust repo can help by adding labels to triage issues: * Yellow, **A**-prefixed labels state which **area** of the project an issue - relates to. + relates to. -* Magenta, **B**-prefixed labels identify bugs which **belong** elsewhere. +* Magenta, **B**-prefixed labels identify bugs which **belong** elsewhere. * Green, **E**-prefixed labels explain the level of **experience** necessary to fix the issue. * Red, **I**-prefixed labels indicate the **importance** of the issue. The [I-nominated][inom] label indicates that an issue has been nominated for - prioritizing at the next triage meeting. + prioritizing at the next triage meeting. * Orange, **P**-prefixed labels indicate a bug's **priority**. These labels are only assigned during triage meetings, and replace the [I-nominated][inom] - label. + label. * Blue, **T**-prefixed bugs denote which **team** the issue belongs to. * Dark blue, **beta-** labels track changes which need to be backported into - the beta branches. - + the beta branches. + * The purple **metabug** label marks lists of bugs collected by other - categories. + categories. -If you're looking for somewhere to start, check out the [E-easy][eeasy] tag. +If you're looking for somewhere to start, check out the [E-easy][eeasy] tag. [inom]: https://github.com/rust-lang/rust/issues?q=is%3Aopen+is%3Aissue+label%3AI-nominated [eeasy]: https://github.com/rust-lang/rust/issues?q=is%3Aopen+is%3Aissue+label%3AE-easy @@ -221,18 +226,19 @@ are: * The [Rust Internals forum][rif], a place to ask questions and discuss Rust's internals * The [generated documentation for rust's compiler][gdfrustc] -* The [rust referance][rr], even though it doesn't specifically talk about Rust's internals, its a great reasource nontheless +* The [rust reference][rr], even though it doesn't specifically talk about Rust's internals, it's a great resource nonetheless * Although out of date, [Tom Lee's great blog article][tlgba] is very helpful * [rustaceans.org][ro] is helpful, but mostly dedicated to IRC * The [Rust Compiler Testing Docs][rctd] -* For @bors, [this cheetsheat][cheetsheat] is helpful (Remember to replace `@homu` with `@bors` in the commands that you use.) -* **Google**! +* For @bors, [this cheat sheet][cheatsheet] is helpful (Remember to replace `@homu` with `@bors` in the commands that you use.) +* **Google!** ([search only in Rust Documentation][gsearchdocs] to find types, traits, etc. quickly) * Don't be afraid to ask! The Rust community is friendly and helpful. [gdfrustc]: http://manishearth.github.io/rust-internals-docs/rustc/ +[gsearchdocs]: https://www.google.de/search?q=site:doc.rust-lang.org+your+query+here [rif]: http://internals.rust-lang.org [rr]: https://doc.rust-lang.org/book/README.html [tlgba]: http://tomlee.co/2014/04/03/a-more-detailed-tour-of-the-rust-compiler/ [ro]: http://www.rustaceans.org/ [rctd]: ./COMPILER_TESTS.md -[cheetsheat]: http://buildbot.rust-lang.org/homu/ +[cheatsheet]: http://buildbot.rust-lang.org/homu/ diff --git a/Makefile.in b/Makefile.in index 8968fabf1b..baa7e77394 100644 --- a/Makefile.in +++ b/Makefile.in @@ -26,7 +26,7 @@ # # * check - Run the complete test suite # -# * clean - Clean the build repertory. It is advised to run this +# * clean - Clean the build repository. It is advised to run this # command if you want to build Rust again, after an update # of the git repository. # diff --git a/README.md b/README.md index 67285da2e3..acd9cb6afc 100644 --- a/README.md +++ b/README.md @@ -67,11 +67,14 @@ Read ["Installing Rust"] from [The Book]. ```sh # Update package mirrors (may be needed if you have a fresh install of MSYS2) $ pacman -Sy pacman-mirrors - + # Choose one based on platform: $ pacman -S mingw-w64-i686-toolchain $ pacman -S mingw-w64-x86_64-toolchain + # Make git available in MSYS2 (if not already available on path) + $ pacman -S git + $ pacman -S base-devel ``` @@ -84,6 +87,13 @@ Read ["Installing Rust"] from [The Book]. $ ./configure $ make && make install ``` +> ***Note:*** gcc versions >= 5 currently have issues building LLVM on Windows +> resulting in a segmentation fault when building Rust. In order to avoid this +> it may be necessary to obtain an earlier version of gcc such as 4.9.x. +> Installers for earlier Windows builds of gcc are available at the +> [Mingw-Builds] project. For more information on this see issue #28260. + +[Mingw-Builds]: http://sourceforge.net/projects/mingw-w64/ ## Building Documentation @@ -98,7 +108,7 @@ Building the documentation requires building the compiler, so the above details will apply. Once you have the compiler built, you can ```sh -$ make docs NO_REBUILD=1 +$ make docs NO_REBUILD=1 ``` To make sure you don’t re-build the compiler because you made a change diff --git a/RELEASES.md b/RELEASES.md index 76246640ca..f867943133 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,5 +1,223 @@ -Version 1.4.0 (October 2015) -============================ +Version 1.5.0 (2015-12-10) +========================== + +* ~700 changes, numerous bugfixes + +Highlights +---------- + +* Stabilized APIs: + [`BinaryHeap::from`], [`BinaryHeap::into_sorted_vec`], + [`BinaryHeap::into_vec`], [`Condvar::wait_timeout`], + [`FileTypeExt::is_block_device`], [`FileTypeExt::is_char_device`], + [`FileTypeExt::is_fifo`], [`FileTypeExt::is_socket`], + [`FileTypeExt`], [`Formatter::alternate`], [`Formatter::fill`], + [`Formatter::precision`], [`Formatter::sign_aware_zero_pad`], + [`Formatter::sign_minus`], [`Formatter::sign_plus`], + [`Formatter::width`], [`Iterator::cmp`], [`Iterator::eq`], + [`Iterator::ge`], [`Iterator::gt`], [`Iterator::le`], + [`Iterator::lt`], [`Iterator::ne`], [`Iterator::partial_cmp`], + [`Path::canonicalize`], [`Path::exists`], [`Path::is_dir`], + [`Path::is_file`], [`Path::metadata`], [`Path::read_dir`], + [`Path::read_link`], [`Path::symlink_metadata`], + [`Utf8Error::valid_up_to`], [`Vec::resize`], + [`VecDeque::as_mut_slices`], [`VecDeque::as_slices`], + [`VecDeque::insert`], [`VecDeque::shrink_to_fit`], + [`VecDeque::swap_remove_back`], [`VecDeque::swap_remove_front`], + [`slice::split_first_mut`], [`slice::split_first`], + [`slice::split_last_mut`], [`slice::split_last`], + [`char::from_u32_unchecked`], [`fs::canonicalize`], + [`str::MatchIndices`], [`str::RMatchIndices`], + [`str::match_indices`], [`str::rmatch_indices`], + [`str::slice_mut_unchecked`], [`string::ParseError`]. +* Rust applications hosted on crates.io can be installed locally to + `~/.cargo/bin` with the [`cargo install`] command. Among other + things this makes it easier to augment Cargo with new subcommands: + when a binary named e.g. `cargo-foo` is found in `$PATH` it can be + invoked as `cargo foo`. +* Crates with wildcard (`*`) dependencies will [emit warnings when + published][1.5w]. In 1.6 it will no longer be possible to publish + crates with wildcard dependencies. + +Breaking Changes +---------------- + +* The rules determining when a particular lifetime must outlive + a particular value (known as '[dropck]') have been [modified + to not rely on parametricity][1.5p]. +* [Implementations of `AsRef` and `AsMut` were added to `Box`, `Rc`, + and `Arc`][1.5a]. Because these smart pointer types implement + `Deref`, this causes breakage in cases where the interior type + contains methods of the same name. +* [Correct a bug in Rc/Arc][1.5c] that caused [dropck] to be unaware + that they could drop their content. Soundness fix. +* All method invocations are [properly checked][1.5wf1] for + [well-formedness][1.5wf2]. Soundness fix. +* Traits whose supertraits contain `Self` are [not object + safe][1.5o]. Soundness fix. +* Target specifications support a [`no_default_libraries`][1.5nd] + setting that controls whether `-nodefaultlibs` is passed to the + linker, and in turn the `is_like_windows` setting no longer affects + the `-nodefaultlibs` flag. +* `#[derive(Show)]`, long-deprecated, [has been removed][1.5ds]. +* The `#[inline]` and `#[repr]` attributes [can only appear + in valid locations][1.5at]. +* Native libraries linked from the local crate are [passed to + the linker before native libraries from upstream crates][1.5nl]. +* Two rarely-used attributes, `#[no_debug]` and + `#[omit_gdb_pretty_printer_section]` [are feature gated][1.5fg]. +* Negation of unsigned integers, which has been a warning for + several releases, [is now behind a feature gate and will + generate errors][1.5nu]. +* The parser accidentally accepted visibility modifiers on + enum variants, a bug [which has been fixed][1.5ev]. +* [A bug was fixed that allowed `use` statements to import unstable + features][1.5use]. + +Language +-------- + +* When evaluating expressions at compile-time that are not + compile-time constants (const-evaluating expressions in non-const + contexts), incorrect code such as overlong bitshifts and arithmetic + overflow will [generate a warning instead of an error][1.5ce], + delaying the error until runtime. This will allow the + const-evaluator to be expanded in the future backwards-compatibly. +* The `improper_ctypes` lint [no longer warns about using `isize` and + `usize` in FFI][1.5ict]. + +Libraries +--------- + +* `Arc` and `Rc` are [covariant with respect to `T` instead of + invariant][1.5c]. +* `Default` is [implemented for mutable slices][1.5d]. +* `FromStr` is [implemented for `SockAddrV4` and `SockAddrV6`][1.5s]. +* There are now `From` conversions [between floating point + types][1.5f] where the conversions are lossless. +* Thera are now `From` conversions [between integer types][1.5i] where + the conversions are lossless. +* [`fs::Metadata` implements `Clone`][1.5fs]. +* The `parse` method [accepts a leading "+" when parsing + integers][1.5pi]. +* [`AsMut` is implemented for `Vec`][1.5am]. +* The `clone_from` implementations for `String` and `BinaryHeap` [have + been optimized][1.5cf] and no longer rely on the default impl. +* The `extern "Rust"`, `extern "C"`, `unsafe extern "Rust"` and + `unsafe extern "C"` function types now [implement `Clone`, + `PartialEq`, `Eq`, `PartialOrd`, `Ord`, `Hash`, `fmt::Pointer`, and + `fmt::Debug` for up to 12 arguments][1.5fp]. +* [Dropping `Vec`s is much faster in unoptimized builds when the + element types don't implement `Drop`][1.5dv]. +* A bug that caused in incorrect behavior when [combining `VecDeque` + with zero-sized types][1.5vdz] was resolved. +* [`PartialOrd` for slices is faster][1.5po]. + +Miscellaneous +------------- + +* [Crate metadata size was reduced by 20%][1.5md]. +* [Improvements to code generation reduced the size of libcore by 3.3 + MB and rustc's memory usage by 18MB][1.5m]. +* [Improvements to deref translation increased performance in + unoptimized builds][1.5dr]. +* Various errors in trait resolution [are deduplicated to only be + reported once][1.5te]. +* Rust has preliminary [support for rumprun kernels][1.5rr]. +* Rust has preliminary [support for NetBSD on amd64][1.5na]. + +[1.5use]: https://github.com/rust-lang/rust/pull/28364 +[1.5po]: https://github.com/rust-lang/rust/pull/28436 +[1.5ev]: https://github.com/rust-lang/rust/pull/28442 +[1.5nu]: https://github.com/rust-lang/rust/pull/28468 +[1.5dr]: https://github.com/rust-lang/rust/pull/28491 +[1.5vdz]: https://github.com/rust-lang/rust/pull/28494 +[1.5md]: https://github.com/rust-lang/rust/pull/28521 +[1.5fg]: https://github.com/rust-lang/rust/pull/28522 +[1.5dv]: https://github.com/rust-lang/rust/pull/28531 +[1.5na]: https://github.com/rust-lang/rust/pull/28543 +[1.5fp]: https://github.com/rust-lang/rust/pull/28560 +[1.5rr]: https://github.com/rust-lang/rust/pull/28593 +[1.5cf]: https://github.com/rust-lang/rust/pull/28602 +[1.5nl]: https://github.com/rust-lang/rust/pull/28605 +[1.5te]: https://github.com/rust-lang/rust/pull/28645 +[1.5at]: https://github.com/rust-lang/rust/pull/28650 +[1.5am]: https://github.com/rust-lang/rust/pull/28663 +[1.5m]: https://github.com/rust-lang/rust/pull/28778 +[1.5ict]: https://github.com/rust-lang/rust/pull/28779 +[1.5a]: https://github.com/rust-lang/rust/pull/28811 +[1.5pi]: https://github.com/rust-lang/rust/pull/28826 +[1.5ce]: https://github.com/rust-lang/rfcs/blob/master/text/1229-compile-time-asserts.md +[1.5p]: https://github.com/rust-lang/rfcs/blob/master/text/1238-nonparametric-dropck.md +[1.5i]: https://github.com/rust-lang/rust/pull/28921 +[1.5fs]: https://github.com/rust-lang/rust/pull/29021 +[1.5f]: https://github.com/rust-lang/rust/pull/29129 +[1.5ds]: https://github.com/rust-lang/rust/pull/29148 +[1.5s]: https://github.com/rust-lang/rust/pull/29190 +[1.5d]: https://github.com/rust-lang/rust/pull/29245 +[1.5o]: https://github.com/rust-lang/rust/pull/29259 +[1.5nd]: https://github.com/rust-lang/rust/pull/28578 +[1.5wf2]: https://github.com/rust-lang/rfcs/blob/master/text/1214-projections-lifetimes-and-wf.md +[1.5wf1]: https://github.com/rust-lang/rust/pull/28669 +[dropck]: https://doc.rust-lang.org/nightly/nomicon/dropck.html +[1.5c]: https://github.com/rust-lang/rust/pull/29110 +[1.5w]: https://github.com/rust-lang/rfcs/blob/master/text/1241-no-wildcard-deps.md +[`cargo install`]: https://github.com/rust-lang/rfcs/blob/master/text/1200-cargo-install.md +[`BinaryHeap::from`]: http://doc.rust-lang.org/nightly/std/convert/trait.From.html#method.from +[`BinaryHeap::into_sorted_vec`]: http://doc.rust-lang.org/nightly/std/collections/struct.BinaryHeap.html#method.into_sorted_vec +[`BinaryHeap::into_vec`]: http://doc.rust-lang.org/nightly/std/collections/struct.BinaryHeap.html#method.into_vec +[`Condvar::wait_timeout`]: http://doc.rust-lang.org/nightly/std/sync/struct.Condvar.html#method.wait_timeout +[`FileTypeExt::is_block_device`]: http://doc.rust-lang.org/nightly/std/os/unix/fs/trait.FileTypeExt.html#tymethod.is_block_device +[`FileTypeExt::is_char_device`]: http://doc.rust-lang.org/nightly/std/os/unix/fs/trait.FileTypeExt.html#tymethod.is_char_device +[`FileTypeExt::is_fifo`]: http://doc.rust-lang.org/nightly/std/os/unix/fs/trait.FileTypeExt.html#tymethod.is_fifo +[`FileTypeExt::is_socket`]: http://doc.rust-lang.org/nightly/std/os/unix/fs/trait.FileTypeExt.html#tymethod.is_socket +[`FileTypeExt`]: http://doc.rust-lang.org/nightly/std/os/unix/fs/trait.FileTypeExt.html +[`Formatter::alternate`]: http://doc.rust-lang.org/nightly/core/fmt/struct.Formatter.html#method.alternate +[`Formatter::fill`]: http://doc.rust-lang.org/nightly/core/fmt/struct.Formatter.html#method.fill +[`Formatter::precision`]: http://doc.rust-lang.org/nightly/core/fmt/struct.Formatter.html#method.precision +[`Formatter::sign_aware_zero_pad`]: http://doc.rust-lang.org/nightly/core/fmt/struct.Formatter.html#method.sign_aware_zero_pad +[`Formatter::sign_minus`]: http://doc.rust-lang.org/nightly/core/fmt/struct.Formatter.html#method.sign_minus +[`Formatter::sign_plus`]: http://doc.rust-lang.org/nightly/core/fmt/struct.Formatter.html#method.sign_plus +[`Formatter::width`]: http://doc.rust-lang.org/nightly/core/fmt/struct.Formatter.html#method.width +[`Iterator::cmp`]: http://doc.rust-lang.org/nightly/core/iter/trait.Iterator.html#method.cmp +[`Iterator::eq`]: http://doc.rust-lang.org/nightly/core/iter/trait.Iterator.html#method.eq +[`Iterator::ge`]: http://doc.rust-lang.org/nightly/core/iter/trait.Iterator.html#method.ge +[`Iterator::gt`]: http://doc.rust-lang.org/nightly/core/iter/trait.Iterator.html#method.gt +[`Iterator::le`]: http://doc.rust-lang.org/nightly/core/iter/trait.Iterator.html#method.le +[`Iterator::lt`]: http://doc.rust-lang.org/nightly/core/iter/trait.Iterator.html#method.lt +[`Iterator::ne`]: http://doc.rust-lang.org/nightly/core/iter/trait.Iterator.html#method.ne +[`Iterator::partial_cmp`]: http://doc.rust-lang.org/nightly/core/iter/trait.Iterator.html#method.partial_cmp +[`Path::canonicalize`]: http://doc.rust-lang.org/nightly/std/path/struct.Path.html#method.canonicalize +[`Path::exists`]: http://doc.rust-lang.org/nightly/std/path/struct.Path.html#method.exists +[`Path::is_dir`]: http://doc.rust-lang.org/nightly/std/path/struct.Path.html#method.is_dir +[`Path::is_file`]: http://doc.rust-lang.org/nightly/std/path/struct.Path.html#method.is_file +[`Path::metadata`]: http://doc.rust-lang.org/nightly/std/path/struct.Path.html#method.metadata +[`Path::read_dir`]: http://doc.rust-lang.org/nightly/std/path/struct.Path.html#method.read_dir +[`Path::read_link`]: http://doc.rust-lang.org/nightly/std/path/struct.Path.html#method.read_link +[`Path::symlink_metadata`]: http://doc.rust-lang.org/nightly/std/path/struct.Path.html#method.symlink_metadata +[`Utf8Error::valid_up_to`]: http://doc.rust-lang.org/nightly/core/str/struct.Utf8Error.html#method.valid_up_to +[`Vec::resize`]: http://doc.rust-lang.org/nightly/std/vec/struct.Vec.html#method.resize +[`VecDeque::as_mut_slices`]: http://doc.rust-lang.org/nightly/std/collections/struct.VecDeque.html#method.as_mut_slices +[`VecDeque::as_slices`]: http://doc.rust-lang.org/nightly/std/collections/struct.VecDeque.html#method.as_slices +[`VecDeque::insert`]: http://doc.rust-lang.org/nightly/std/collections/struct.VecDeque.html#method.insert +[`VecDeque::shrink_to_fit`]: http://doc.rust-lang.org/nightly/std/collections/struct.VecDeque.html#method.shrink_to_fit +[`VecDeque::swap_remove_back`]: http://doc.rust-lang.org/nightly/std/collections/struct.VecDeque.html#method.swap_remove_back +[`VecDeque::swap_remove_front`]: http://doc.rust-lang.org/nightly/std/collections/struct.VecDeque.html#method.swap_remove_front +[`slice::split_first_mut`]: http://doc.rust-lang.org/nightly/std/primitive.slice.html#method.split_first_mut +[`slice::split_first`]: http://doc.rust-lang.org/nightly/std/primitive.slice.html#method.split_first +[`slice::split_last_mut`]: http://doc.rust-lang.org/nightly/std/primitive.slice.html#method.split_last_mut +[`slice::split_last`]: http://doc.rust-lang.org/nightly/std/primitive.slice.html#method.split_last +[`char::from_u32_unchecked`]: http://doc.rust-lang.org/nightly/std/char/fn.from_u32_unchecked.html +[`fs::canonicalize`]: http://doc.rust-lang.org/nightly/std/fs/fn.canonicalize.html +[`str::MatchIndices`]: http://doc.rust-lang.org/nightly/std/str/struct.MatchIndices.html +[`str::RMatchIndices`]: http://doc.rust-lang.org/nightly/std/str/struct.RMatchIndices.html +[`str::match_indices`]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.match_indices +[`str::rmatch_indices`]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.rmatch_indices +[`str::slice_mut_unchecked`]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.slice_mut_unchecked +[`string::ParseError`]: http://doc.rust-lang.org/nightly/std/string/enum.ParseError.html + +Version 1.4.0 (2015-10-29) +========================== * ~1200 changes, numerous bugfixes @@ -20,6 +238,12 @@ Breaking Changes * [The `str::lines` and `BufRead::lines` iterators treat `\r\n` as line breaks in addition to `\n`][crlf]. * [Loans of `'static` lifetime extend to the end of a function][stat]. +* [`str::parse` no longer introduces avoidable rounding error when + parsing floating point numbers. Together with earlier changes to + float formatting/output, "round trips" like f.to_string().parse() + now preserve the value of f exactly. Additionally, leading plus + signs are now accepted][fp3]. + Language -------- @@ -68,19 +292,22 @@ Libraries prelude][pr]. * [`Extend` and `FromIterator` and - `Result<&T>`][into]. +* [`IntoIterator` is implemented for references to `Option` and + `Result`][into2]. * [`HashMap` and `HashSet` implement `Extend<&T>` where `T: - Copy`][ext] as part of [RFC 839]. + Copy`][ext] as part of [RFC 839]. This will cause type inferance + breakage in rare situations. * [`BinaryHeap` implements `Debug`][bh2]. * [`Borrow` and `BorrowMut` are implemented for fixed-size arrays][bm]. -* [`extern fn`s of with the "Rust" and "C" ABIs implement common +* [`extern fn`s with the "Rust" and "C" ABIs implement common traits including `Eq`, `Ord`, `Debug`, `Hash`][fp]. * [String comparison is faster][faststr]. -* `&mut T` where `T: Write` [also implements `Write`][mutw]. -* [A stable regression in `VecDec::push_back` that caused panics for - zero-sized types was fixed][vd]. +* `&mut T` where `T: std::fmt::Write` [also implements + `std::fmt::Write`][mutw]. +* [A stable regression in `VecDeque::push_back` and other + capicity-altering methods that caused panics for zero-sized types + was fixed][vd]. * [Function pointers implement traits for up to 12 parameters][fp2]. Miscellaneous @@ -151,8 +378,9 @@ Miscellaneous [ffi]: https://github.com/rust-lang/rust/pull/28779 [fp]: https://github.com/rust-lang/rust/pull/28268 [fp2]: https://github.com/rust-lang/rust/pull/28560 +[fp3]: https://github.com/rust-lang/rust/pull/27307 [i]: https://github.com/rust-lang/rust/pull/27451 -[into]: https://github.com/rust-lang/rust/pull/28039 +[into2]: https://github.com/rust-lang/rust/pull/28039 [it]: https://github.com/rust-lang/rust/pull/27652 [mm]: https://github.com/rust-lang/rust/pull/27338 [mutw]: https://github.com/rust-lang/rust/pull/28368 @@ -802,7 +1030,7 @@ Misc [path-normalize]: https://github.com/rust-lang/rust/pull/23229 -Version 1.0.0-alpha.2 (February 2015) +Version 1.0.0-alpha.2 (2015-02-20) ===================================== * ~1300 changes, numerous bugfixes @@ -901,7 +1129,7 @@ Version 1.0.0-alpha.2 (February 2015) [un]: https://github.com/rust-lang/rust/pull/22256 -Version 1.0.0-alpha (January 2015) +Version 1.0.0-alpha (2015-01-09) ================================== * ~2400 changes, numerous bugfixes @@ -1088,7 +1316,7 @@ Version 1.0.0-alpha (January 2015) [rbe]: http://rustbyexample.com/ -Version 0.12.0 (October 2014) +Version 0.12.0 (2014-10-09) ============================= * ~1900 changes, numerous bugfixes @@ -1211,7 +1439,7 @@ Version 0.12.0 (October 2014) kernels and distributions, built on CentOS 5.10. -Version 0.11.0 (July 2014) +Version 0.11.0 (2014-07-02) ========================== * ~1700 changes, numerous bugfixes @@ -1344,7 +1572,7 @@ Version 0.11.0 (July 2014) greatly improved. -Version 0.10 (April 2014) +Version 0.10 (2014-04-03) ========================= * ~1500 changes, numerous bugfixes @@ -1511,7 +1739,7 @@ Version 0.10 (April 2014) directory. -Version 0.9 (January 2014) +Version 0.9 (2014-01-09) ========================== * ~1800 changes, numerous bugfixes @@ -1677,7 +1905,7 @@ Version 0.9 (January 2014) build tools. -Version 0.8 (September 2013) +Version 0.8 (2013-09-26) ============================ * ~2200 changes, numerous bugfixes @@ -1833,7 +2061,7 @@ Version 0.8 (September 2013) still invoked through the normal `rustdoc` command. -Version 0.7 (July 2013) +Version 0.7 (2013-07-03) ======================= * ~2000 changes, numerous bugfixes @@ -1950,7 +2178,7 @@ Version 0.7 (July 2013) * Improvements to rustpkg (see the detailed release notes). -Version 0.6 (April 2013) +Version 0.6 (2013-04-03) ======================== * ~2100 changes, numerous bugfixes @@ -2053,7 +2281,7 @@ Version 0.6 (April 2013) * Inline assembler supported by new asm!() syntax extension. -Version 0.5 (December 2012) +Version 0.5 (2012-12-21) =========================== * ~900 changes, numerous bugfixes @@ -2110,7 +2338,7 @@ Version 0.5 (December 2012) * License changed from MIT to dual MIT/APL2 -Version 0.4 (October 2012) +Version 0.4 (2012-10-15) ========================== * ~2000 changes, numerous bugfixes @@ -2166,7 +2394,7 @@ Version 0.4 (October 2012) * All hash functions and tables converted to secure, randomized SipHash -Version 0.3 (July 2012) +Version 0.3 (2012-07-12) ======================== * ~1900 changes, numerous bugfixes @@ -2225,7 +2453,7 @@ Version 0.3 (July 2012) * Cargo automatically resolves dependencies -Version 0.2 (March 2012) +Version 0.2 (2012-03-29) ========================= * >1500 changes, numerous bugfixes @@ -2266,7 +2494,7 @@ Version 0.2 (March 2012) * Extensive cleanup, regularization in libstd, libcore -Version 0.1 (January 20, 2012) +Version 0.1 (2012-01-20) =============================== * Most language features work, including: diff --git a/configure b/configure index 2d03b5f6f4..60d366100f 100755 --- a/configure +++ b/configure @@ -578,6 +578,7 @@ opt ccache 0 "invoke gcc/clang via ccache to reuse object files between builds" opt local-rust 0 "use an installed rustc rather than downloading a snapshot" opt llvm-static-stdcpp 0 "statically link to libstdc++ for LLVM" opt rpath 0 "build rpaths into rustc itself" +opt stage0-landing-pads 1 "enable landing pads during bootstrap with stage0" # This is used by the automation to produce single-target nightlies opt dist-host-only 0 "only install bins for the host architecture" opt inject-std-version 1 "inject the current compiler version of libstd into programs" @@ -766,8 +767,6 @@ probe CFG_ANTLR4 antlr4 probe CFG_GRUN grun probe CFG_FLEX flex probe CFG_BISON bison -probe CFG_PANDOC pandoc -probe CFG_XELATEX xelatex probe CFG_GDB gdb probe CFG_LLDB lldb @@ -826,26 +825,6 @@ step_msg "looking for target specific programs" probe CFG_ADB adb -if [ -n "$CFG_PANDOC" ] -then - # Extract "MAJOR MINOR" from Pandoc's version number - PV_MAJOR_MINOR=$(pandoc --version | grep '^pandoc' | - sed -E 's/pandoc(.exe)? ([0-9]+)\.([0-9]+).*/\2 \3/') - - MIN_PV_MAJOR="1" - MIN_PV_MINOR="9" - - # these patterns are shell globs, *not* regexps - PV_MAJOR=${PV_MAJOR_MINOR% *} - PV_MINOR=${PV_MAJOR_MINOR#* } - - if [ "$PV_MAJOR" -lt "$MIN_PV_MAJOR" ] || [ "$PV_MINOR" -lt "$MIN_PV_MINOR" ] - then - step_msg "pandoc $PV_MAJOR.$PV_MINOR is too old. Need at least $MIN_PV_MAJOR.$MIN_PV_MINOR. Disabling" - BAD_PANDOC=1 - fi -fi - BIN_SUF= if [ "$CFG_OSTYPE" = "pc-windows-gnu" ] || [ "$CFG_OSTYPE" = "pc-windows-msvc" ] then @@ -1095,6 +1074,12 @@ envopt CPP envopt CFLAGS envopt CXXFLAGS +# stdc++ name in use +# used to manage non-standard name (on OpenBSD for example) +program_transform_name=$($CFG_CC -v 2>&1 | sed -n "s/.*--program-transform-name='\([^']*\)'.*/\1/p") +CFG_STDCPP_NAME=$(echo "stdc++" | sed "${program_transform_name}") +putvar CFG_STDCPP_NAME + # a little post-processing of various config values CFG_PREFIX=${CFG_PREFIX%/} CFG_MANDIR=${CFG_MANDIR%/} @@ -1289,6 +1274,12 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake putvar CFG_MSVC_LIB_PATH_${bits} ;; + *-rumprun-netbsd) + step_msg "targeting rumprun-netbsd, disabling jemalloc" + CFG_DISABLE_JEMALLOC=1 + putvar CFG_DISABLE_JEMALLOC + ;; + *) ;; esac @@ -1763,12 +1754,6 @@ then fi -if [ -n $BAD_PANDOC ] -then - CFG_PANDOC= - putvar CFG_PANDOC -fi - putvar CFG_LLVM_SRC_DIR for t in $CFG_HOST diff --git a/man/rustc.1 b/man/rustc.1 index 3ac79ecae6..56e3fe0515 100644 --- a/man/rustc.1 +++ b/man/rustc.1 @@ -53,7 +53,9 @@ Comma separated list of types of crates for the compiler to emit. Specify the name of the crate being built. .TP \fB\-\-emit\fR [asm|llvm\-bc|llvm\-ir|obj|link|dep\-info] -Configure the output that \fBrustc\fR will produce. +Configure the output that \fBrustc\fR will produce. Each option may also be of +the form KIND=PATH to specify the explicit output location for that particular +emission kind. .TP \fB\-\-print\fR [crate\-name|file\-names|sysroot] Comma separated list of compiler information to print on stdout. @@ -66,7 +68,8 @@ Equivalent to \fI\-C\ opt\-level=2\fR. .TP \fB\-o\fR \fIFILENAME\fR Write output to \fIFILENAME\fR. -Ignored if multiple \fI\-\-emit\fR outputs are specified. +Ignored if multiple \fI\-\-emit\fR outputs are specified which don't have an +explicit path otherwise. .TP \fB\-\-out\-dir\fR \fIDIR\fR Write output to compiler\[hy]chosen filename in \fIDIR\fR. diff --git a/mk/cfg/mips-unknown-linux-gnu.mk b/mk/cfg/mips-unknown-linux-gnu.mk index ba5f6d0e75..65b08774d4 100644 --- a/mk/cfg/mips-unknown-linux-gnu.mk +++ b/mk/cfg/mips-unknown-linux-gnu.mk @@ -7,8 +7,8 @@ CFG_LIB_NAME_mips-unknown-linux-gnu=lib$(1).so CFG_STATIC_LIB_NAME_mips-unknown-linux-gnu=lib$(1).a CFG_LIB_GLOB_mips-unknown-linux-gnu=lib$(1)-*.so CFG_LIB_DSYM_GLOB_mips-unknown-linux-gnu=lib$(1)-*.dylib.dSYM -CFG_JEMALLOC_CFLAGS_mips-unknown-linux-gnu := -mips32r2 -msoft-float -mabi=32 -mno-compact-eh $(CFLAGS) -CFG_GCCISH_CFLAGS_mips-unknown-linux-gnu := -Wall -g -fPIC -mips32r2 -msoft-float -mabi=32 -mno-compact-eh $(CFLAGS) +CFG_JEMALLOC_CFLAGS_mips-unknown-linux-gnu := -mips32r2 -msoft-float -mabi=32 $(CFLAGS) +CFG_GCCISH_CFLAGS_mips-unknown-linux-gnu := -Wall -g -fPIC -mips32r2 -msoft-float -mabi=32 $(CFLAGS) CFG_GCCISH_CXXFLAGS_mips-unknown-linux-gnu := -fno-rtti $(CXXFLAGS) CFG_GCCISH_LINK_FLAGS_mips-unknown-linux-gnu := -shared -fPIC -g -mips32r2 -msoft-float -mabi=32 CFG_GCCISH_DEF_FLAG_mips-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list= @@ -20,5 +20,5 @@ CFG_UNIXY_mips-unknown-linux-gnu := 1 CFG_LDPATH_mips-unknown-linux-gnu := CFG_RUN_mips-unknown-linux-gnu= CFG_RUN_TARG_mips-unknown-linux-gnu= -RUSTC_FLAGS_mips-unknown-linux-gnu := -C target-cpu=mips32r2 -C target-feature="+mips32r2,+o32" -C soft-float +RUSTC_FLAGS_mips-unknown-linux-gnu := -C target-cpu=mips32r2 -C target-feature="+mips32r2" -C soft-float CFG_GNU_TRIPLE_mips-unknown-linux-gnu := mips-unknown-linux-gnu diff --git a/mk/cfg/mipsel-unknown-linux-gnu.mk b/mk/cfg/mipsel-unknown-linux-gnu.mk index 539038c743..4dadfc275d 100644 --- a/mk/cfg/mipsel-unknown-linux-gnu.mk +++ b/mk/cfg/mipsel-unknown-linux-gnu.mk @@ -1,8 +1,8 @@ # mipsel-unknown-linux-gnu configuration -CC_mipsel-unknown-linux-gnu=mipsel-unknown-linux-gnu-gcc -CXX_mipsel-unknown-linux-gnu=mipsel-unknown-linux-gnu-g++ -CPP_mipsel-unknown-linux-gnu=mipsel-unknown-linux-gnu-gcc -AR_mipsel-unknown-linux-gnu=mipsel-unknown-linux-gnu-ar +CC_mipsel-unknown-linux-gnu=mipsel-linux-gnu-gcc +CXX_mipsel-unknown-linux-gnu=mipsel-linux-gnu-g++ +CPP_mipsel-unknown-linux-gnu=mipsel-linux-gnu-gcc +AR_mipsel-unknown-linux-gnu=mipsel-linux-gnu-ar CFG_LIB_NAME_mipsel-unknown-linux-gnu=lib$(1).so CFG_STATIC_LIB_NAME_mipsel-unknown-linux-gnu=lib$(1).a CFG_LIB_GLOB_mipsel-unknown-linux-gnu=lib$(1)-*.so @@ -20,5 +20,5 @@ CFG_UNIXY_mipsel-unknown-linux-gnu := 1 CFG_LDPATH_mipsel-unknown-linux-gnu := CFG_RUN_mipsel-unknown-linux-gnu= CFG_RUN_TARG_mipsel-unknown-linux-gnu= -RUSTC_FLAGS_mipsel-unknown-linux-gnu := -C target-cpu=mips32 -C target-feature="+mips32,+o32" +RUSTC_FLAGS_mipsel-unknown-linux-gnu := -C target-cpu=mips32 -C target-feature="+mips32" CFG_GNU_TRIPLE_mipsel-unknown-linux-gnu := mipsel-unknown-linux-gnu diff --git a/mk/cfg/x86_64-rumprun-netbsd.mk b/mk/cfg/x86_64-rumprun-netbsd.mk new file mode 100644 index 0000000000..5894805e3e --- /dev/null +++ b/mk/cfg/x86_64-rumprun-netbsd.mk @@ -0,0 +1,24 @@ +# x86_64-rumprun-netbsd configuration +CROSS_PREFIX_x86_64-rumprun-netbsd=x86_64-rumprun-netbsd- +CC_x86_64-rumprun-netbsd=gcc +CXX_x86_64-rumprun-netbsd=g++ +CPP_x86_64-rumprun-netbsd=gcc -E +AR_x86_64-rumprun-netbsd=ar +CFG_INSTALL_ONLY_RLIB_x86_64-rumprun-netbsd = 1 +CFG_LIB_NAME_x86_64-rumprun-netbsd=lib$(1).so +CFG_STATIC_LIB_NAME_x86_64-rumprun-netbsd=lib$(1).a +CFG_LIB_GLOB_x86_64-rumprun-netbsd=lib$(1)-*.so +CFG_JEMALLOC_CFLAGS_x86_64-rumprun-netbsd := -m64 +CFG_GCCISH_CFLAGS_x86_64-rumprun-netbsd := -Wall -Werror -g -fPIC -m64 +CFG_GCCISH_CXXFLAGS_x86_64-rumprun-netbsd := +CFG_GCCISH_LINK_FLAGS_x86_64-rumprun-netbsd := +CFG_GCCISH_DEF_FLAG_x86_64-rumprun-netbsd := +CFG_LLC_FLAGS_x86_64-rumprun-netbsd := +CFG_INSTALL_NAME_x86_64-rumprun-netbsd = +CFG_EXE_SUFFIX_x86_64-rumprun-netbsd = +CFG_WINDOWSY_x86_64-rumprun-netbsd := +CFG_UNIXY_x86_64-rumprun-netbsd := 1 +CFG_LDPATH_x86_64-rumprun-netbsd := +CFG_RUN_x86_64-rumprun-netbsd=$(2) +CFG_RUN_TARG_x86_64-rumprun-netbsd=$(call CFG_RUN_x86_64-rumprun-netbsd,,$(2)) +CFG_GNU_TRIPLE_x86_64-rumprun-netbsd := x86_64-rumprun-netbsd diff --git a/mk/cfg/x86_64-unknown-netbsd.mk b/mk/cfg/x86_64-unknown-netbsd.mk index 401b0fb7ab..a77c5fa542 100644 --- a/mk/cfg/x86_64-unknown-netbsd.mk +++ b/mk/cfg/x86_64-unknown-netbsd.mk @@ -1,4 +1,5 @@ # x86_64-unknown-netbsd configuration +CROSS_PREFIX_x86_64-unknown-netbsd=x86_64-unknown-netbsd- CC_x86_64-unknown-netbsd=$(CC) CXX_x86_64-unknown-netbsd=$(CXX) CPP_x86_64-unknown-netbsd=$(CPP) diff --git a/mk/crates.mk b/mk/crates.mk index b424c1d877..6673b9b28e 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -61,51 +61,55 @@ HOST_CRATES := syntax $(RUSTC_CRATES) rustdoc fmt_macros TOOLS := compiletest rustdoc rustc rustbook error-index-generator DEPS_core := +DEPS_alloc := core libc alloc_system +DEPS_alloc_system := core libc +DEPS_collections := core alloc rustc_unicode DEPS_libc := core +DEPS_rand := core +DEPS_rustc_bitflags := core DEPS_rustc_unicode := core -DEPS_alloc := core libc alloc_system + DEPS_std := core libc rand alloc collections rustc_unicode \ native:rust_builtin native:backtrace \ alloc_system +DEPS_arena := std +DEPS_glob := std +DEPS_flate := std native:miniz +DEPS_fmt_macros = std +DEPS_getopts := std DEPS_graphviz := std +DEPS_log := std +DEPS_num := std +DEPS_rbml := std log serialize +DEPS_serialize := std log +DEPS_term := std log +DEPS_test := std getopts serialize rbml term native:rust_test_helpers + DEPS_syntax := std term serialize log fmt_macros arena libc rustc_bitflags + +DEPS_rustc := syntax flate arena serialize getopts rbml rustc_front\ + log graphviz rustc_llvm rustc_back rustc_data_structures +DEPS_rustc_back := std syntax rustc_llvm rustc_front flate log libc +DEPS_rustc_borrowck := rustc rustc_front log graphviz syntax +DEPS_rustc_data_structures := std log serialize 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_front -DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back \ - log syntax serialize rustc_llvm rustc_front rustc_platform_intrinsics -DEPS_rustc_mir := rustc rustc_front syntax -DEPS_rustc_typeck := rustc syntax rustc_front rustc_platform_intrinsics -DEPS_rustc_borrowck := rustc rustc_front log graphviz syntax -DEPS_rustc_resolve := rustc rustc_front log syntax -DEPS_rustc_privacy := rustc rustc_front log syntax +DEPS_rustc_front := std syntax log serialize DEPS_rustc_lint := rustc log syntax -DEPS_rustc := syntax flate arena serialize getopts rbml \ - log graphviz rustc_llvm rustc_back rustc_data_structures DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags +DEPS_rustc_mir := rustc rustc_front syntax +DEPS_rustc_resolve := rustc rustc_front log syntax DEPS_rustc_platform_intrinsics := rustc rustc_llvm -DEPS_rustc_back := std syntax rustc_llvm rustc_front flate log libc -DEPS_rustc_front := std syntax log serialize -DEPS_rustc_data_structures := std log serialize +DEPS_rustc_privacy := rustc rustc_front log syntax +DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back \ + log syntax serialize rustc_llvm rustc_front rustc_platform_intrinsics +DEPS_rustc_typeck := rustc syntax rustc_front rustc_platform_intrinsics + DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \ test rustc_lint rustc_front -DEPS_rustc_bitflags := core -DEPS_flate := std native:miniz -DEPS_arena := std -DEPS_graphviz := std -DEPS_glob := std -DEPS_serialize := std log -DEPS_rbml := std log serialize -DEPS_term := std log -DEPS_getopts := std -DEPS_collections := core alloc rustc_unicode -DEPS_num := std -DEPS_test := std getopts serialize rbml term native:rust_test_helpers -DEPS_rand := core -DEPS_log := std -DEPS_fmt_macros = std -DEPS_alloc_system := core libc + TOOL_DEPS_compiletest := test getopts TOOL_DEPS_rustdoc := rustdoc diff --git a/mk/dist.mk b/mk/dist.mk index 0fc9100b85..4cdee8bda9 100644 --- a/mk/dist.mk +++ b/mk/dist.mk @@ -21,6 +21,7 @@ # * dist-docs - Stage docs for upload PKG_NAME := $(CFG_PACKAGE_NAME) +STD_PKG_NAME := rust-std-$(CFG_PACKAGE_VERS) DOC_PKG_NAME := rust-docs-$(CFG_PACKAGE_VERS) MINGW_PKG_NAME := rust-mingw-$(CFG_PACKAGE_VERS) @@ -77,6 +78,7 @@ $(PKG_TAR): $(PKG_FILES) -C $(S) \ --exclude-vcs \ --exclude=*~ \ + --exclude=*.pyc \ --exclude=*/llvm/test/*/*.ll \ --exclude=*/llvm/test/*/*.td \ --exclude=*/llvm/test/*/*.s \ @@ -111,19 +113,25 @@ distcheck-tar-src: dist-tar-src # Unix binary installer tarballs ###################################################################### -define DEF_INSTALLER +define DEF_START_INSTALLER +dist-install-dir-$(1)-%: PREPARE_DIR_CMD=$(DEFAULT_PREPARE_DIR_CMD) +dist-install-dir-$(1)-%: PREPARE_BIN_CMD=$(DEFAULT_PREPARE_BIN_CMD) +dist-install-dir-$(1)-%: PREPARE_LIB_CMD=$(DEFAULT_PREPARE_LIB_CMD) +dist-install-dir-$(1)-%: PREPARE_MAN_CMD=$(DEFAULT_PREPARE_MAN_CMD) +dist-install-dir-$(1)-%: PREPARE_CLEAN=true $$(eval $$(call DEF_PREPARE,dir-$(1))) +endef -dist-install-dir-$(1): PREPARE_HOST=$(1) -dist-install-dir-$(1): PREPARE_TARGETS=$(2) -dist-install-dir-$(1): PREPARE_DEST_DIR=tmp/dist/$$(PKG_NAME)-$(1)-image -dist-install-dir-$(1): PREPARE_DIR_CMD=$(DEFAULT_PREPARE_DIR_CMD) -dist-install-dir-$(1): PREPARE_BIN_CMD=$(DEFAULT_PREPARE_BIN_CMD) -dist-install-dir-$(1): PREPARE_LIB_CMD=$(DEFAULT_PREPARE_LIB_CMD) -dist-install-dir-$(1): PREPARE_MAN_CMD=$(DEFAULT_PREPARE_MAN_CMD) -dist-install-dir-$(1): PREPARE_CLEAN=true -dist-install-dir-$(1): prepare-base-dir-$(1) docs +$(foreach target,$(CFG_TARGET),\ + $(eval $(call DEF_START_INSTALLER,$(target)))) + +define DEF_INSTALLER + +dist-install-dir-$(1)-host: PREPARE_HOST=$(1) +dist-install-dir-$(1)-host: PREPARE_TARGETS=$(2) +dist-install-dir-$(1)-host: PREPARE_DEST_DIR=tmp/dist/$$(PKG_NAME)-$(1)-image +dist-install-dir-$(1)-host: prepare-base-dir-$(1)-host docs $$(Q)mkdir -p $$(PREPARE_DEST_DIR)/share/doc/rust $$(Q)$$(PREPARE_MAN_CMD) $$(S)COPYRIGHT $$(PREPARE_DEST_DIR)/share/doc/rust $$(Q)$$(PREPARE_MAN_CMD) $$(S)LICENSE-APACHE $$(PREPARE_DEST_DIR)/share/doc/rust @@ -140,14 +148,27 @@ prepare-overlay-$(1): # This tiny morsel of metadata is used by rust-packaging $$(Q)echo "$(CFG_VERSION)" > tmp/dist/$$(PKG_NAME)-$(1)-overlay/version -dist/$$(PKG_NAME)-$(1).tar.gz: dist-install-dir-$(1) prepare-overlay-$(1) +dist/$$(PKG_NAME)-$(1).tar.gz: dist-install-dir-$(1)-host prepare-overlay-$(1) @$(call E, build: $$@) -# Copy essential gcc components into installer -ifdef CFG_WINDOWSY_$(1) -ifeq ($$(findstring gnu,$(1)),gnu) +# On a MinGW target we've got a few runtime DLL dependencies that we need +# to include. THe first argument to `make-win-dist` is where to put these DLLs +# (the image we're creating) and the second argument is a junk directory to +# ignore all the other MinGW stuff the script creates. +ifeq ($$(findstring pc-windows-gnu,$(1)),pc-windows-gnu) $$(Q)rm -Rf tmp/dist/win-rust-gcc-$(1) - $$(Q)$$(CFG_PYTHON) $$(S)src/etc/make-win-dist.py tmp/dist/$$(PKG_NAME)-$(1)-image tmp/dist/win-rust-gcc-$(1) $(1) - $$(Q)cp -r $$(S)src/etc/third-party tmp/dist/$$(PKG_NAME)-$(1)-image/share/doc/ + $$(Q)$$(CFG_PYTHON) $$(S)src/etc/make-win-dist.py \ + tmp/dist/$$(PKG_NAME)-$(1)-image \ + tmp/dist/win-rust-gcc-$(1) $(1) +endif +# On 32-bit MinGW we're always including a DLL which needs some extra licenses +# to distribute. On 64-bit MinGW we don't actually distribute anything requiring +# us to distribute a license but it's likely that the install will *also* +# include the rust-mingw package down below, which also need licenses, so to be +# safe we just inlude it here in all MinGW packages. +ifdef CFG_WINDOWSY_$(1) +ifeq ($$(findstring $(1),gnu),gnu) + $$(Q)cp -r $$(S)src/etc/third-party \ + tmp/dist/$$(PKG_NAME)-$(1)-image/share/doc/ endif endif $$(Q)$$(S)src/rust-installer/gen-installer.sh \ @@ -182,11 +203,16 @@ dist/$$(DOC_PKG_NAME)-$(1).tar.gz: dist-doc-install-dir-$(1) --bulk-dirs=share/doc/rust/html $$(Q)rm -R tmp/dist/$$(DOC_PKG_NAME)-$(1)-image +# Creates the rust-mingw package, and the first argument to make-win-dist is a +# "temporary directory" which is just thrown away (this contains the runtime +# DLLs included in the rustc package above) and the second argument is where to +# place all the MinGW components (which is what we want). dist-mingw-install-dir-$(1): $$(Q)mkdir -p tmp/dist/rust-mingw-tmp-$(1)-image $$(Q)rm -Rf tmp/dist/$$(MINGW_PKG_NAME)-$(1)-image $$(Q)$$(CFG_PYTHON) $$(S)src/etc/make-win-dist.py \ - tmp/dist/rust-mingw-tmp-$(1)-image tmp/dist/$$(MINGW_PKG_NAME)-$(1)-image $(1) + tmp/dist/rust-mingw-tmp-$(1)-image \ + tmp/dist/$$(MINGW_PKG_NAME)-$(1)-image $(1) dist/$$(MINGW_PKG_NAME)-$(1).tar.gz: dist-mingw-install-dir-$(1) @$(call E, build: $$@) @@ -204,15 +230,52 @@ dist/$$(MINGW_PKG_NAME)-$(1).tar.gz: dist-mingw-install-dir-$(1) endef -ifneq ($(CFG_ENABLE_DIST_HOST_ONLY),) -$(foreach host,$(CFG_HOST),\ - $(eval $(call DEF_INSTALLER,$(host),$(host)))) -else +# $(1) - host +# $(2) - target +define DEF_INSTALLER_TARGETS + +dist-install-dir-$(2)-target: PREPARE_HOST=$(1) +dist-install-dir-$(2)-target: PREPARE_TARGETS=$(2) +dist-install-dir-$(2)-target: PREPARE_DEST_DIR=tmp/dist/$$(STD_PKG_NAME)-$(2)-image +dist-install-dir-$(2)-target: prepare-base-dir-$(2)-target + +dist/$$(STD_PKG_NAME)-$(2).tar.gz: dist-install-dir-$(2)-target + @$$(call E, build: $$@) + $$(Q)$$(S)src/rust-installer/gen-installer.sh \ + --product-name=Rust \ + --rel-manifest-dir=rustlib \ + --success-message=std-is-standing-at-the-ready. \ + --image-dir=tmp/dist/$$(STD_PKG_NAME)-$(2)-image \ + --work-dir=tmp/dist \ + --output-dir=dist \ + --package-name=$$(STD_PKG_NAME)-$(2) \ + --component-name=rust-std-$(2) \ + --legacy-manifest-dirs=rustlib,cargo + $$(Q)rm -R tmp/dist/$$(STD_PKG_NAME)-$(2)-image +endef + $(foreach host,$(CFG_HOST),\ - $(eval $(call DEF_INSTALLER,$(host),$(CFG_TARGET)))) -endif + $(eval $(call DEF_INSTALLER,$(host)))) -dist-install-dirs: $(foreach host,$(CFG_HOST),dist-install-dir-$(host)) +# When generating packages for the standard library, we've actually got a lot of +# artifacts to choose from. Each of the CFG_HOST compilers will have a copy of +# the standard library for each CFG_TARGET, but we only want to generate one +# standard library package. As a result, for each entry in CFG_TARGET we need to +# pick a CFG_HOST to get the standard library from. +# +# In theory it doesn't actually matter what host we choose as it should be the +# case that all hosts produce the same set of libraries for a target (regardless +# of the host itself). Currently there is a bug in the compiler, however, which +# means this is not the case (see #29228 and #29235). To solve the first of +# those bugs, we prefer to select a standard library from the host it was +# generated from, allowing plugins to work in more situations. +# +# For all CFG_TARGET entries in CFG_HOST, however, we just pick CFG_BUILD as the +# host we slurp up a standard library from. +$(foreach host,$(CFG_HOST),\ + $(eval $(call DEF_INSTALLER_TARGETS,$(host),$(host)))) +$(foreach target,$(filter-out $(CFG_HOST),$(CFG_TARGET)),\ + $(eval $(call DEF_INSTALLER_TARGETS,$(CFG_BUILD),$(target)))) ifdef CFG_WINDOWSY_$(CFG_BUILD) define BUILD_MINGW_TARBALL @@ -229,7 +292,9 @@ ifeq ($(CFG_DISABLE_DOCS),) MAYBE_DOC_TARBALLS=$(foreach host,$(CFG_HOST),dist/$(DOC_PKG_NAME)-$(host).tar.gz) endif -dist-tar-bins: $(foreach host,$(CFG_HOST),dist/$(PKG_NAME)-$(host).tar.gz) \ +dist-tar-bins: \ + $(foreach host,$(CFG_HOST),dist/$(PKG_NAME)-$(host).tar.gz) \ + $(foreach target,$(CFG_TARGET),dist/$(STD_PKG_NAME)-$(target).tar.gz) \ $(MAYBE_DOC_TARBALLS) $(MAYBE_MINGW_TARBALLS) # Just try to run the compiler for the build host diff --git a/mk/grammar.mk b/mk/grammar.mk index d9c66e282b..0d527bd068 100644 --- a/mk/grammar.mk +++ b/mk/grammar.mk @@ -58,17 +58,17 @@ check-lexer: $(BG) $(BG)RustLexer.class check-build-lexer-verifier $(Q)$(SG)check.sh $(S) "$(BG)" \ "$(CFG_GRUN)" "$(BG)verify" "$(BG)RustLexer.tokens" else -$(info cfg: grun not available, skipping lexer test...) +$(info cfg: lexer tooling not available, skipping lexer test...) check-lexer: endif else -$(info cfg: antlr4 not available, skipping lexer test...) +$(info cfg: lexer tooling not available, skipping lexer test...) check-lexer: endif else -$(info cfg: javac not available, skipping lexer test...) +$(info cfg: lexer tooling not available, skipping lexer test...) check-lexer: endif diff --git a/mk/install.mk b/mk/install.mk index cabc97a1e4..8b8170220c 100644 --- a/mk/install.mk +++ b/mk/install.mk @@ -8,6 +8,12 @@ # option. This file may not be copied, modified, or distributed # except according to those terms. +RUN_INSALLER = cd tmp/empty_dir && \ + sh ../../tmp/dist/$(1)/install.sh \ + --prefix="$(DESTDIR)$(CFG_PREFIX)" \ + --libdir="$(DESTDIR)$(CFG_LIBDIR)" \ + --mandir="$(DESTDIR)$(CFG_MANDIR)" + install: ifeq (root user, $(USER) $(patsubst %,user,$(SUDO_USER))) # Build the dist as the original user @@ -16,9 +22,11 @@ else $(Q)$(MAKE) prepare_install endif ifeq ($(CFG_DISABLE_DOCS),) - $(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(DOC_PKG_NAME)-$(CFG_BUILD)/install.sh --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)" + $(Q)$(call RUN_INSALLER,$(DOC_PKG_NAME)-$(CFG_BUILD)) --disable-ldconfig endif - $(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(PKG_NAME)-$(CFG_BUILD)/install.sh --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)" + $(Q)$(foreach target,$(CFG_TARGET),\ + ($(call RUN_INSALLER,$(STD_PKG_NAME)-$(target)) --disable-ldconfig);) + $(Q)$(call RUN_INSALLER,$(PKG_NAME)-$(CFG_BUILD)) # Remove tmp files because it's a decent amount of disk space $(Q)rm -R tmp/dist @@ -32,9 +40,11 @@ else $(Q)$(MAKE) prepare_uninstall endif ifeq ($(CFG_DISABLE_DOCS),) - $(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(DOC_PKG_NAME)-$(CFG_BUILD)/install.sh --uninstall --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)" + $(Q)$(call RUN_INSALLER,$(DOC_PKG_NAME)-$(CFG_BUILD)) --uninstall endif - $(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(PKG_NAME)-$(CFG_BUILD)/install.sh --uninstall --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)" + $(Q)$(call RUN_INSALLER,$(PKG_NAME)-$(CFG_BUILD)) --uninstall + $(Q)$(foreach target,$(CFG_TARGET),\ + ($(call RUN_INSALLER,$(STD_PKG_NAME)-$(target)) --uninstall);) # Remove tmp files because it's a decent amount of disk space $(Q)rm -R tmp/dist diff --git a/mk/llvm.mk b/mk/llvm.mk index d5b608e88d..1cbf4a9fb8 100644 --- a/mk/llvm.mk +++ b/mk/llvm.mk @@ -73,7 +73,7 @@ $$(LLVM_STAMP_$(1)): $(S)src/rustllvm/llvm-auto-clean-trigger ifeq ($$(CFG_ENABLE_LLVM_STATIC_STDCPP),1) LLVM_STDCPP_RUSTFLAGS_$(1) = -L "$$(dir $$(shell $$(CC_$(1)) $$(CFG_GCCISH_CFLAGS_$(1)) \ - -print-file-name=libstdc++.a))" + -print-file-name=lib$(CFG_STDCPP_NAME).a))" else LLVM_STDCPP_RUSTFLAGS_$(1) = endif @@ -83,7 +83,7 @@ endif LLVM_LINKAGE_PATH_$(1):=$$(abspath $$(RT_OUTPUT_DIR_$(1))/llvmdeps.rs) $$(LLVM_LINKAGE_PATH_$(1)): $(S)src/etc/mklldeps.py $$(LLVM_CONFIG_$(1)) $(Q)$(CFG_PYTHON) "$$<" "$$@" "$$(LLVM_COMPONENTS)" "$$(CFG_ENABLE_LLVM_STATIC_STDCPP)" \ - $$(LLVM_CONFIG_$(1)) + $$(LLVM_CONFIG_$(1)) "$(CFG_STDCPP_NAME)" endef $(foreach host,$(CFG_HOST), \ diff --git a/mk/main.mk b/mk/main.mk index f13355517d..34f8247966 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -13,12 +13,12 @@ ###################################################################### # The version number -CFG_RELEASE_NUM=1.4.0 +CFG_RELEASE_NUM=1.5.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=.4 +CFG_PRERELEASE_VERSION=.5 # Append a version-dependent hash to each library, so we can install different # versions in the same place @@ -132,7 +132,11 @@ endif ifdef CFG_ENABLE_DEBUGINFO $(info cfg: enabling debuginfo (CFG_ENABLE_DEBUGINFO)) - CFG_RUSTC_FLAGS += -g + # FIXME: Re-enable -g in stage0 after new snapshot + #CFG_RUSTC_FLAGS += -g + RUSTFLAGS_STAGE1 += -g + RUSTFLAGS_STAGE2 += -g + RUSTFLAGS_STAGE3 += -g endif ifdef SAVE_TEMPS @@ -170,19 +174,10 @@ RUST_LIB_FLAGS_ST3 += -C prefer-dynamic # Landing pads require a lot of codegen. We can get through bootstrapping faster # by not emitting them. -RUSTFLAGS_STAGE0 += -Z no-landing-pads - -# Enable MIR to "always build" for crates where this works. This is -# just temporary while MIR is being actively built up -- it's just a -# poor man's unit testing infrastructure. Anyway we only want this for -# stage1/stage2. -define ADD_MIR_FLAG -RUSTFLAGS1_$(1) += -Z always-build-mir -RUSTFLAGS2_$(1) += -Z always-build-mir -endef -$(foreach crate,$(TARGET_CRATES),$(eval $(call ADD_MIR_FLAG,$(crate)))) -$(foreach crate,$(RUSTC_CRATES),$(eval $(call ADD_MIR_FLAG,$(crate)))) -$(foreach crate,$(HOST_CRATES),$(eval $(call ADD_MIR_FLAG,$(crate)))) + +ifdef CFG_DISABLE_STAGE0_LANDING_PADS + RUSTFLAGS_STAGE0 += -Z no-landing-pads +endif # platform-specific auto-configuration include $(CFG_SRC_DIR)mk/platform.mk diff --git a/mk/platform.mk b/mk/platform.mk index fcb6a5b50d..856a22dc60 100644 --- a/mk/platform.mk +++ b/mk/platform.mk @@ -208,6 +208,14 @@ define CFG_MAKE_TOOLCHAIN ifeq ($$(findstring $(HOST_$(1)),arm aarch64 mips mipsel powerpc),) + # On OpenBSD, we need to pass the path of libstdc++.so to the linker + # (use path of libstdc++.a which is a known name for the same path) + ifeq ($(OSTYPE_$(1)),unknown-openbsd) + RUSTC_FLAGS_$(1)=-L "$$(dir $$(shell $$(CC_$(1)) $$(CFG_GCCISH_CFLAGS_$(1)) \ + -print-file-name=lib$(CFG_STDCPP_NAME).a))" \ + $(RUSTC_FLAGS_$(1)) + endif + # On Bitrig, we need the relocation model to be PIC for everything ifeq (,$(filter $(OSTYPE_$(1)),bitrig)) LLVM_MC_RELOCATION_MODEL="pic" diff --git a/mk/prepare.mk b/mk/prepare.mk index fe619cc7ca..e263a6d2e4 100644 --- a/mk/prepare.mk +++ b/mk/prepare.mk @@ -185,16 +185,16 @@ INSTALL_DEBUGGER_SCRIPT_COMMANDS=$(if $(findstring windows,$(1)),\ define DEF_PREPARE -prepare-base-$(1): PREPARE_SOURCE_DIR=$$(PREPARE_HOST)/stage$$(PREPARE_STAGE) -prepare-base-$(1): PREPARE_SOURCE_BIN_DIR=$$(PREPARE_SOURCE_DIR)/bin -prepare-base-$(1): PREPARE_SOURCE_LIB_DIR=$$(PREPARE_SOURCE_DIR)/$$(CFG_LIBDIR_RELATIVE) -prepare-base-$(1): PREPARE_SOURCE_MAN_DIR=$$(S)/man -prepare-base-$(1): PREPARE_DEST_BIN_DIR=$$(PREPARE_DEST_DIR)/bin -prepare-base-$(1): PREPARE_DEST_LIB_DIR=$$(PREPARE_DEST_DIR)/$$(CFG_LIBDIR_RELATIVE) -prepare-base-$(1): PREPARE_DEST_MAN_DIR=$$(PREPARE_DEST_DIR)/share/man/man1 -prepare-base-$(1): prepare-everything-$(1) +prepare-base-$(1)-%: PREPARE_SOURCE_DIR=$$(PREPARE_HOST)/stage$$(PREPARE_STAGE) +prepare-base-$(1)-%: PREPARE_SOURCE_BIN_DIR=$$(PREPARE_SOURCE_DIR)/bin +prepare-base-$(1)-%: PREPARE_SOURCE_LIB_DIR=$$(PREPARE_SOURCE_DIR)/$$(CFG_LIBDIR_RELATIVE) +prepare-base-$(1)-%: PREPARE_SOURCE_MAN_DIR=$$(S)/man +prepare-base-$(1)-%: PREPARE_DEST_BIN_DIR=$$(PREPARE_DEST_DIR)/bin +prepare-base-$(1)-%: PREPARE_DEST_LIB_DIR=$$(PREPARE_DEST_DIR)/$$(CFG_LIBDIR_RELATIVE) +prepare-base-$(1)-%: PREPARE_DEST_MAN_DIR=$$(PREPARE_DEST_DIR)/share/man/man1 -prepare-everything-$(1): prepare-host-$(1) prepare-targets-$(1) prepare-debugger-scripts-$(1) +prepare-base-$(1)-target: prepare-target-$(1) +prepare-base-$(1)-host: prepare-host-$(1) prepare-debugger-scripts-$(1) prepare-host-$(1): prepare-host-tools-$(1) @@ -222,7 +222,7 @@ $$(foreach lib,$$(CRATES), \ $$(foreach host,$$(CFG_HOST), \ $$(eval $$(call DEF_PREPARE_HOST_LIB,$$(lib),$$(PREPARE_STAGE),$$(host),$(1))))) -prepare-targets-$(1): \ +prepare-target-$(1): \ $$(foreach host,$$(CFG_HOST), \ $$(foreach target,$$(CFG_TARGET), \ prepare-target-$$(target)-host-$$(host)-$$(PREPARE_STAGE)-$(1))) diff --git a/mk/tests.mk b/mk/tests.mk index e0984cfe86..d004558d1b 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -1046,6 +1046,10 @@ $$(call TEST_OK_FILE,$(1),$(2),$(3),rmake): \ $$(RMAKE_TESTS:%=$(3)/test/run-make/%-$(1)-T-$(2)-H-$(3).ok) @touch $$@ +$(3)/test/run-make/%-$(1)-T-$(2)-H-$(3).ok: \ + export INCLUDE := $$(CFG_MSVC_INCLUDE_PATH_$$(HOST_$(3))) +$(3)/test/run-make/%-$(1)-T-$(2)-H-$(3).ok: \ + export LIB := $$(CFG_MSVC_LIB_PATH_$$(HOST_$(3))) $(3)/test/run-make/%-$(1)-T-$(2)-H-$(3).ok: \ $(S)src/test/run-make/%/Makefile \ $$(CSREQ$(1)_T_$(2)_H_$(3)) @@ -1056,7 +1060,7 @@ $(3)/test/run-make/%-$(1)-T-$(2)-H-$(3).ok: \ $$(MAKE) \ $$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \ $(3)/test/run-make/$$* \ - $$(CC_$(3)) \ + '$$(CC_$(3))' \ "$$(CFG_GCCISH_CFLAGS_$(3))" \ $$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \ "$$(TESTNAME)" \ @@ -1064,7 +1068,8 @@ $(3)/test/run-make/%-$(1)-T-$(2)-H-$(3).ok: \ "$$(LD_LIBRARY_PATH_ENV_HOSTDIR$(1)_T_$(2)_H_$(3))" \ "$$(LD_LIBRARY_PATH_ENV_TARGETDIR$(1)_T_$(2)_H_$(3))" \ $(1) \ - $$(S) + $$(S) \ + $(3) @touch -r $$@.start_time $$@ && rm $$@.start_time else # FIXME #11094 - The above rule doesn't work right for multiple targets diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index f508798a8b..dfd99a9bea 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -13,9 +13,7 @@ #![feature(box_syntax)] #![feature(dynamic_lib)] #![feature(libc)] -#![feature(path_ext)] #![feature(rustc_private)] -#![feature(slice_splits)] #![feature(str_char)] #![feature(test)] #![feature(vec_push_all)] @@ -92,7 +90,7 @@ pub fn parse_config(args: Vec ) -> Config { optflag("h", "help", "show this message")); let (argv0, args_) = args.split_first().unwrap(); - if args[1] == "-h" || args[1] == "--help" { + if args.len() == 1 || args[1] == "-h" || args[1] == "--help" { let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0); println!("{}", getopts::usage(&message, &groups)); println!(""); @@ -348,7 +346,7 @@ fn extract_gdb_version(full_version_line: Option) -> Option { if !full_version_line.trim().is_empty() => { let full_version_line = full_version_line.trim(); - // used to be a regex "(^|[^0-9])([0-9]\.[0-9])([^0-9]|$)" + // 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 } @@ -357,11 +355,12 @@ fn extract_gdb_version(full_version_line: Option) -> Option { if pos > 0 && full_version_line.char_at_reverse(pos).is_digit(10) { continue } - if pos + 3 < full_version_line.len() && - full_version_line.char_at(pos + 3).is_digit(10) { - continue + let mut end = pos + 3; + while end < full_version_line.len() && + full_version_line.char_at(end).is_digit(10) { + end += 1; } - return Some(full_version_line[pos..pos+3].to_owned()); + return Some(full_version_line[pos..end].to_owned()); } println!("Could not extract GDB version from line '{}'", full_version_line); diff --git a/src/compiletest/procsrv.rs b/src/compiletest/procsrv.rs index 66fa0dfecd..7c5397a1af 100644 --- a/src/compiletest/procsrv.rs +++ b/src/compiletest/procsrv.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(deprecated)] + use std::dynamic_lib::DynamicLibrary; use std::io::prelude::*; use std::path::PathBuf; diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index 12f560be45..8db6725f7a 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -1669,8 +1669,7 @@ fn compile_test_and_save_ir(config: &Config, props: &TestProps, // 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(), - "--crate-type=lib".to_owned()); + let llvm_args = vec!("--emit=llvm-ir".to_owned(),); link_args.extend(llvm_args); let args = make_compile_args(config, props, diff --git a/src/doc/README.md b/src/doc/README.md index c09f28ae4f..0882b073ea 100644 --- a/src/doc/README.md +++ b/src/doc/README.md @@ -2,9 +2,10 @@ ## Building -To generate all the docs, just run `make docs` from the root of the repository. -This will convert the distributed Markdown docs to HTML and generate HTML doc -for the 'std' and 'extra' libraries. +To generate all the docs, follow the "Building Documentation" instructions in +the README in the root of the repository. This will convert the distributed +Markdown docs to HTML and generate HTML doc for the books, 'std' and 'extra' +libraries. To generate HTML documentation from one source file/crate, do something like: diff --git a/src/doc/complement-lang-faq.md b/src/doc/complement-lang-faq.md index 8b9467589c..05c17606ce 100644 --- a/src/doc/complement-lang-faq.md +++ b/src/doc/complement-lang-faq.md @@ -76,7 +76,7 @@ Cleanup through RAII-style destructors is more likely to work than in catch bloc ## Why aren't modules type-parametric? -We want to maintain the option to parametrize at runtime. We may eventually change this limitation, but initially this is how type parameters were implemented. +We want to maintain the option to parameterize at runtime. We may eventually change this limitation, but initially this is how type parameters were implemented. ## Why aren't values type-parametric? Why only items? diff --git a/src/doc/complement-project-faq.md b/src/doc/complement-project-faq.md index bb1805d694..1ed961fd55 100644 --- a/src/doc/complement-project-faq.md +++ b/src/doc/complement-project-faq.md @@ -22,7 +22,7 @@ Existing languages at this level of abstraction and efficiency are unsatisfactor # Is any part of this thing production-ready? -No. Feel free to play around, but don't expect completeness or stability yet. Expect incompleteness and breakage. +Yes! # Is this a completely Mozilla-planned and orchestrated thing? diff --git a/src/doc/grammar.md b/src/doc/grammar.md index 3ae93b8f27..a400e70e97 100644 --- a/src/doc/grammar.md +++ b/src/doc/grammar.md @@ -9,7 +9,7 @@ provides only one kind of material: This document does not serve as an introduction to the language. Background familiarity with the language is assumed. A separate [guide] is available to -help acquire such background familiarity. +help acquire such background. This document also does not serve as a reference to the [standard] library included in the language distribution. Those libraries are documented @@ -258,8 +258,8 @@ symbol : "::" | "->" | ',' | ';' ; ``` -Symbols are a general class of printable [token](#tokens) that play structural -roles in a variety of grammar productions. They are catalogued here for +Symbols are a general class of printable [tokens](#tokens) that play structural +roles in a variety of grammar productions. They are cataloged here for completeness as the set of remaining miscellaneous printable tokens that do not otherwise appear as [unary operators](#unary-operator-expressions), [binary operators](#binary-operator-expressions), or [keywords](#keywords). @@ -436,7 +436,7 @@ meta_seq : meta_item [ ',' meta_seq ] ? ; ## Statements ```antlr -stmt : decl_stmt | expr_stmt ; +stmt : decl_stmt | expr_stmt | ';' ; ``` ### Declaration statements @@ -773,7 +773,7 @@ bound := path | lifetime ## Type kinds -**FIXME:** this this probably not relevant to the grammar... +**FIXME:** this is probably not relevant to the grammar... # Memory and concurrency models diff --git a/src/doc/index.md b/src/doc/index.md index 1e667d3600..992b6eef5e 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -98,3 +98,4 @@ languages: - [Korean](https://github.com/rust-kr/doc.rust-kr.org) - [Chinese](https://github.com/KaiserY/rust-book-chinese) - [Spanish](https://goyox86.github.io/elpr) +- [German](https://panicbit.github.io/rustbook-de) diff --git a/src/doc/nomicon/atomics.md b/src/doc/nomicon/atomics.md index 08f0de4f00..1efca08abd 100644 --- a/src/doc/nomicon/atomics.md +++ b/src/doc/nomicon/atomics.md @@ -1,11 +1,11 @@ % Atomics Rust pretty blatantly just inherits C11's memory model for atomics. This is not -due this model being particularly excellent or easy to understand. Indeed, this -model is quite complex and known to have [several flaws][C11-busted]. Rather, it -is a pragmatic concession to the fact that *everyone* is pretty bad at modeling -atomics. At very least, we can benefit from existing tooling and research around -C. +due to this model being particularly excellent or easy to understand. Indeed, +this model is quite complex and known to have [several flaws][C11-busted]. +Rather, it is a pragmatic concession to the fact that *everyone* is pretty bad +at modeling atomics. At very least, we can benefit from existing tooling and +research around C. Trying to fully explain the model in this book is fairly hopeless. It's defined in terms of madness-inducing causality graphs that require a full book to diff --git a/src/doc/nomicon/casts.md b/src/doc/nomicon/casts.md index 5f07709cf4..6cc41bd953 100644 --- a/src/doc/nomicon/casts.md +++ b/src/doc/nomicon/casts.md @@ -52,7 +52,7 @@ For numeric casts, there are quite a few cases to consider: * zero-extend if the source is unsigned * sign-extend if the source is signed * casting from a float to an integer will round the float towards zero - * **[NOTE: currently this will cause Undefined Behaviour if the rounded + * **[NOTE: currently this will cause Undefined Behavior if the rounded value cannot be represented by the target integer type][float-int]**. This includes Inf and NaN. This is a bug and will be fixed. * casting from an integer to float will produce the floating point @@ -61,7 +61,7 @@ For numeric casts, there are quite a few cases to consider: * casting from an f32 to an f64 is perfect and lossless * casting from an f64 to an f32 will produce the closest possible value (rounding strategy unspecified) - * **[NOTE: currently this will cause Undefined Behaviour if the value + * **[NOTE: currently this will cause Undefined Behavior if the value is finite but larger or smaller than the largest or smallest finite value representable by f32][float-float]**. This is a bug and will be fixed. diff --git a/src/doc/nomicon/concurrency.md b/src/doc/nomicon/concurrency.md index 802f3204cd..b93b303f0b 100644 --- a/src/doc/nomicon/concurrency.md +++ b/src/doc/nomicon/concurrency.md @@ -1,4 +1,4 @@ -% Concurrency and Paralellism +% Concurrency and Parallelism Rust as a language doesn't *really* have an opinion on how to do concurrency or parallelism. The standard library exposes OS threads and blocking sys-calls diff --git a/src/doc/nomicon/destructors.md b/src/doc/nomicon/destructors.md index 91abdab977..604370b636 100644 --- a/src/doc/nomicon/destructors.md +++ b/src/doc/nomicon/destructors.md @@ -17,7 +17,7 @@ boilerplate" to drop children. If a struct has no special logic for being dropped other than dropping its children, then it means `Drop` doesn't need to be implemented at all! -**There is no stable way to prevent this behaviour in Rust 1.0.** +**There is no stable way to prevent this behavior in Rust 1.0.** Note that taking `&mut self` means that even if you could suppress recursive Drop, Rust will prevent you from e.g. moving fields out of self. For most types, @@ -53,7 +53,7 @@ impl Drop for Box { and this works fine because when Rust goes to drop the `ptr` field it just sees a [Unique] that has no actual `Drop` implementation. Similarly nothing can -use-after-free the `ptr` because when drop exits, it becomes inacessible. +use-after-free the `ptr` because when drop exits, it becomes inaccessible. However this wouldn't work: @@ -101,7 +101,7 @@ After we deallocate the `box`'s ptr in SuperBox's destructor, Rust will happily proceed to tell the box to Drop itself and everything will blow up with use-after-frees and double-frees. -Note that the recursive drop behaviour applies to all structs and enums +Note that the recursive drop behavior applies to all structs and enums regardless of whether they implement Drop. Therefore something like ```rust diff --git a/src/doc/nomicon/drop-flags.md b/src/doc/nomicon/drop-flags.md index 5655c5d245..cfceafe1bd 100644 --- a/src/doc/nomicon/drop-flags.md +++ b/src/doc/nomicon/drop-flags.md @@ -40,7 +40,7 @@ y = x; // y was init; Drop y, overwrite it, and make x uninit! // x goes out of scope; x was uninit; do nothing. ``` -Similarly, branched code where all branches have the same behaviour with respect +Similarly, branched code where all branches have the same behavior with respect to initialization has static drop semantics: ```rust diff --git a/src/doc/nomicon/dropck.md b/src/doc/nomicon/dropck.md index 98d269ff76..ad7c65032c 100644 --- a/src/doc/nomicon/dropck.md +++ b/src/doc/nomicon/dropck.md @@ -6,7 +6,7 @@ interacted with the *outlives* relationship in an inclusive manner. That is, when we talked about `'a: 'b`, it was ok for `'a` to live *exactly* as long as `'b`. At first glance, this seems to be a meaningless distinction. Nothing ever gets dropped at the same time as another, right? This is why we used the -following desugarring of `let` statements: +following desugaring of `let` statements: ```rust,ignore let x; @@ -115,13 +115,163 @@ section: **For a generic type to soundly implement drop, its generics arguments must strictly outlive it.** -This rule is sufficient but not necessary to satisfy the drop checker. That is, -if your type obeys this rule then it's definitely sound to drop. However -there are special cases where you can fail to satisfy this, but still -successfully pass the borrow checker. These are the precise rules that are -currently up in the air. +Obeying this rule is (usually) necessary to satisfy the borrow +checker; obeying it is sufficient but not necessary to be +sound. That is, if your type obeys this rule then it's definitely +sound to drop. + +The reason that it is not always necessary to satisfy the above rule +is that some Drop implementations will not access borrowed data even +though their type gives them the capability for such access. + +For example, this variant of the above `Inspector` example will never +accessed borrowed data: + +```rust,ignore +struct Inspector<'a>(&'a u8, &'static str); + +impl<'a> Drop for Inspector<'a> { + fn drop(&mut self) { + println!("Inspector(_, {}) knows when *not* to inspect.", self.1); + } +} + +fn main() { + let (inspector, days); + days = Box::new(1); + inspector = Inspector(&days, "gadget"); + // Let's say `days` happens to get dropped first. + // Even when Inspector is dropped, its destructor will not access the + // borrowed `days`. +} +``` + +Likewise, this variant will also never access borrowed data: + +```rust,ignore +use std::fmt; + +struct Inspector(T, &'static str); + +impl Drop for Inspector { + fn drop(&mut self) { + println!("Inspector(_, {}) knows when *not* to inspect.", self.1); + } +} + +fn main() { + let (inspector, days): (Inspector<&u8>, Box); + days = Box::new(1); + inspector = Inspector(&days, "gadget"); + // Let's say `days` happens to get dropped first. + // Even when Inspector is dropped, its destructor will not access the + // borrowed `days`. +} +``` + +However, *both* of the above variants are rejected by the borrow +checker during the analysis of `fn main`, saying that `days` does not +live long enough. + +The reason is that the borrow checking analysis of `main` does not +know about the internals of each Inspector's Drop implementation. As +far as the borrow checker knows while it is analyzing `main`, the body +of an inspector's destructor might access that borrowed data. + +Therefore, the drop checker forces all borrowed data in a value to +strictly outlive that value. + +# An Escape Hatch + +The precise rules that govern drop checking may be less restrictive in +the future. + +The current analysis is deliberately conservative and trivial; it forces all +borrowed data in a value to outlive that value, which is certainly sound. + +Future versions of the language may make the analysis more precise, to +reduce the number of cases where sound code is rejected as unsafe. +This would help address cases such as the two Inspectors above that +know not to inspect during destruction. + +In the meantime, there is an unstable attribute that one can use to +assert (unsafely) that a generic type's destructor is *guaranteed* to +not access any expired data, even if its type gives it the capability +to do so. + +That attribute is called `unsafe_destructor_blind_to_params`. +To deploy it on the Inspector example from above, we would write: + +```rust,ignore +struct Inspector<'a>(&'a u8, &'static str); + +impl<'a> Drop for Inspector<'a> { + #[unsafe_destructor_blind_to_params] + fn drop(&mut self) { + println!("Inspector(_, {}) knows when *not* to inspect.", self.1); + } +} +``` + +This attribute has the word `unsafe` in it because the compiler is not +checking the implicit assertion that no potentially expired data +(e.g. `self.0` above) is accessed. + +It is sometimes obvious that no such access can occur, like the case above. +However, when dealing with a generic type parameter, such access can +occur indirectly. Examples of such indirect access are: + + * invoking a callback, + * via a trait method call. + +(Future changes to the language, such as impl specialization, may add +other avenues for such indirect access.) + +Here is an example of invoking a callback: + +```rust,ignore +struct Inspector(T, &'static str, Box fn(&'r T) -> String>); + +impl Drop for Inspector { + fn drop(&mut self) { + // The `self.2` call could access a borrow e.g. if `T` is `&'a _`. + println!("Inspector({}, {}) unwittingly inspects expired data.", + (self.2)(&self.0), self.1); + } +} +``` + +Here is an example of a trait method call: + +```rust,ignore +use std::fmt; + +struct Inspector(T, &'static str); + +impl Drop for Inspector { + fn drop(&mut self) { + // There is a hidden call to `::fmt` below, which + // could access a borrow e.g. if `T` is `&'a _` + println!("Inspector({}, {}) unwittingly inspects expired data.", + self.0, self.1); + } +} +``` + +And of course, all of these accesses could be further hidden within +some other method invoked by the destructor, rather than being written +directly within it. + +In all of the above cases where the `&'a u8` is accessed in the +destructor, adding the `#[unsafe_destructor_blind_to_params]` +attribute makes the type vulnerable to misuse that the borrower +checker will not catch, inviting havoc. It is better to avoid adding +the attribute. + +# Is that all about drop checker? It turns out that when writing unsafe code, we generally don't need to worry at all about doing the right thing for the drop checker. However there is one special case that you need to worry about, which we will look at in the next section. + diff --git a/src/doc/nomicon/exotic-sizes.md b/src/doc/nomicon/exotic-sizes.md index e8637e38ac..052e3c5fdd 100644 --- a/src/doc/nomicon/exotic-sizes.md +++ b/src/doc/nomicon/exotic-sizes.md @@ -20,7 +20,7 @@ information that "completes" them (more on this below). There are two major DSTs exposed by the language: trait objects, and slices. A trait object represents some type that implements the traits it specifies. -The exact original type is *erased* in favour of runtime reflection +The exact original type is *erased* in favor of runtime reflection with a vtable containing all the information necessary to use the type. This is the information that completes a trait object: a pointer to its vtable. @@ -128,7 +128,7 @@ But neither of these tricks work today, so all Void types get you is the ability to be confident that certain situations are statically impossible. One final subtle detail about empty types is that raw pointers to them are -actually valid to construct, but dereferencing them is Undefined Behaviour +actually valid to construct, but dereferencing them is Undefined Behavior because that doesn't actually make sense. That is, you could model C's `void *` type with `*const Void`, but this doesn't necessarily gain anything over using e.g. `*const ()`, which *is* safe to randomly dereference. diff --git a/src/doc/nomicon/leaking.md b/src/doc/nomicon/leaking.md index 0441db2752..a5d5742a4c 100644 --- a/src/doc/nomicon/leaking.md +++ b/src/doc/nomicon/leaking.md @@ -90,16 +90,16 @@ let mut vec = vec![Box::new(0); 4]; println!("{}", vec[0]); ``` -This is pretty clearly Not Good. Unfortunately, we're kind've stuck between a +This is pretty clearly Not Good. Unfortunately, we're kind of stuck between a rock and a hard place: maintaining consistent state at every step has an enormous cost (and would negate any benefits of the API). Failing to maintain -consistent state gives us Undefined Behaviour in safe code (making the API +consistent state gives us Undefined Behavior in safe code (making the API unsound). So what can we do? Well, we can pick a trivially consistent state: set the Vec's len to be 0 when we start the iteration, and fix it up if necessary in the destructor. That way, if everything executes like normal we get the desired -behaviour with minimal overhead. But if someone has the *audacity* to +behavior with minimal overhead. But if someone has the *audacity* to mem::forget us in the middle of the iteration, all that does is *leak even more* (and possibly leave the Vec in an unexpected but otherwise consistent state). Since we've accepted that mem::forget is safe, this is definitely safe. We call @@ -135,7 +135,7 @@ impl Rc { fn new(data: T) -> Self { unsafe { // Wouldn't it be nice if heap::allocate worked like this? - let ptr = heap::allocate>(); + let ptr = heap::allocate::>(); ptr::write(ptr, RcBox { data: data, ref_count: 1, @@ -248,4 +248,4 @@ let mut data = Box::new(0); ``` Dang. Here the destructor running was pretty fundamental to the API, and it had -to be scrapped in favour of a completely different design. +to be scrapped in favor of a completely different design. diff --git a/src/doc/nomicon/lifetime-mismatch.md b/src/doc/nomicon/lifetime-mismatch.md index 8b01616ee0..0ad8a78880 100644 --- a/src/doc/nomicon/lifetime-mismatch.md +++ b/src/doc/nomicon/lifetime-mismatch.md @@ -78,4 +78,4 @@ TODO: other common problems? SEME regions stuff, mostly? -[ex2]: lifetimes.html#example-2:-aliasing-a-mutable-reference +[ex2]: lifetimes.html#example-aliasing-a-mutable-reference diff --git a/src/doc/nomicon/lifetimes.md b/src/doc/nomicon/lifetimes.md index 58272a1bc3..e48d5f852f 100644 --- a/src/doc/nomicon/lifetimes.md +++ b/src/doc/nomicon/lifetimes.md @@ -195,7 +195,7 @@ println!("{}", x); The problem here is is bit more subtle and interesting. We want Rust to reject this program for the following reason: We have a live shared reference `x` -to a descendent of `data` when we try to take a mutable reference to `data` +to a descendant of `data` when we try to take a mutable reference to `data` to `push`. This would create an aliased mutable reference, which would violate the *second* rule of references. diff --git a/src/doc/nomicon/meet-safe-and-unsafe.md b/src/doc/nomicon/meet-safe-and-unsafe.md index 52582e8750..978d051872 100644 --- a/src/doc/nomicon/meet-safe-and-unsafe.md +++ b/src/doc/nomicon/meet-safe-and-unsafe.md @@ -26,7 +26,7 @@ do some really crazy unsafe things. Safe Rust is the *true* Rust programming language. If all you do is write Safe Rust, you will never have to worry about type-safety or memory-safety. You will -never endure a null or dangling pointer, or any of that Undefined Behaviour +never endure a null or dangling pointer, or any of that Undefined Behavior nonsense. *That's totally awesome.* @@ -52,11 +52,11 @@ The only things that are different in Unsafe Rust are that you can: * Mutate statics That's it. The reason these operations are relegated to Unsafe is that misusing -any of these things will cause the ever dreaded Undefined Behaviour. Invoking -Undefined Behaviour gives the compiler full rights to do arbitrarily bad things -to your program. You definitely *should not* invoke Undefined Behaviour. +any of these things will cause the ever dreaded Undefined Behavior. Invoking +Undefined Behavior gives the compiler full rights to do arbitrarily bad things +to your program. You definitely *should not* invoke Undefined Behavior. -Unlike C, Undefined Behaviour is pretty limited in scope in Rust. All the core +Unlike C, Undefined Behavior is pretty limited in scope in Rust. All the core language cares about is preventing the following things: * Dereferencing null or dangling pointers @@ -71,9 +71,9 @@ language cares about is preventing the following things: * Unwinding into another language * Causing a [data race][race] -That's it. That's all the causes of Undefined Behaviour baked into Rust. Of +That's it. That's all the causes of Undefined Behavior baked into Rust. Of course, unsafe functions and traits are free to declare arbitrary other -constraints that a program must maintain to avoid Undefined Behaviour. However, +constraints that a program must maintain to avoid Undefined Behavior. However, generally violations of these constraints will just transitively lead to one of the above problems. Some additional constraints may also derive from compiler intrinsics that make special assumptions about how code can be optimized. diff --git a/src/doc/nomicon/other-reprs.md b/src/doc/nomicon/other-reprs.md index 71da743f35..e361fbb7ae 100644 --- a/src/doc/nomicon/other-reprs.md +++ b/src/doc/nomicon/other-reprs.md @@ -19,8 +19,8 @@ kept in mind. Due to its dual purpose as "for FFI" and "for layout control", `repr(C)` can be applied to types that will be nonsensical or problematic if passed through the FFI boundary. -* ZSTs are still zero-sized, even though this is not a standard behaviour in -C, and is explicitly contrary to the behaviour of an empty type in C++, which +* ZSTs are still zero-sized, even though this is not a standard behavior in +C, and is explicitly contrary to the behavior of an empty type in C++, which still consumes a byte of space. * DSTs, tuples, and tagged unions are not a concept in C and as such are never @@ -65,7 +65,7 @@ compiler might be able to paper over alignment issues with shifts and masks. However if you take a reference to a packed field, it's unlikely that the compiler will be able to emit code to avoid an unaligned load. -**[As of Rust 1.0 this can cause undefined behaviour.][ub loads]** +**[As of Rust 1.0 this can cause undefined behavior.][ub loads]** `repr(packed)` is not to be used lightly. Unless you have extreme requirements, this should not be used. diff --git a/src/doc/nomicon/ownership.md b/src/doc/nomicon/ownership.md index e80c64c354..6be8d3b702 100644 --- a/src/doc/nomicon/ownership.md +++ b/src/doc/nomicon/ownership.md @@ -64,4 +64,3 @@ does in fact live as long as we needed. However it was *changed* while we had a reference into it. This is why Rust requires any references to freeze the referent and its owners. - diff --git a/src/doc/nomicon/races.md b/src/doc/nomicon/races.md index 3b47502ebf..f0732cf265 100644 --- a/src/doc/nomicon/races.md +++ b/src/doc/nomicon/races.md @@ -6,7 +6,7 @@ Safe Rust guarantees an absence of data races, which are defined as: * one of them is a write * one of them is unsynchronized -A data race has Undefined Behaviour, and is therefore impossible to perform +A data race has Undefined Behavior, and is therefore impossible to perform in Safe Rust. Data races are *mostly* prevented through rust's ownership system: it's impossible to alias a mutable reference, so it's impossible to perform a data race. Interior mutability makes this more complicated, which is largely why @@ -53,7 +53,7 @@ thread::spawn(move || { // bounds checked, and there's no chance of the value getting changed // in the middle. However our program may panic if the thread we spawned // managed to increment before this ran. A race condition because correct -// program execution (panicing is rarely correct) depends on order of +// program execution (panicking is rarely correct) depends on order of // thread execution. println!("{}", data[idx.load(Ordering::SeqCst)]); ``` diff --git a/src/doc/nomicon/repr-rust.md b/src/doc/nomicon/repr-rust.md index e038ae5639..effeaf872b 100644 --- a/src/doc/nomicon/repr-rust.md +++ b/src/doc/nomicon/repr-rust.md @@ -6,7 +6,7 @@ value of alignment `n` must only be stored at an address that is a multiple of `n`. So alignment 2 means you must be stored at an even address, and 1 means that you can be stored anywhere. Alignment is at least 1, and always a power of 2. Most primitives are generally aligned to their size, although this is -platform-specific behaviour. In particular, on x86 `u64` and `f64` may be only +platform-specific behavior. In particular, on x86 `u64` and `f64` may be only aligned to 32 bits. A type's size must always be a multiple of its alignment. This ensures that an @@ -151,4 +151,4 @@ use fairly elaborate algorithms to cache bits throughout nested types with special constrained representations. As such it is *especially* desirable that we leave enum layout unspecified today. -[dst]: exotic-sizes.html#dynamically-sized-types-(dsts) +[dst]: exotic-sizes.html#dynamically-sized-types-dsts diff --git a/src/doc/nomicon/safe-unsafe-meaning.md b/src/doc/nomicon/safe-unsafe-meaning.md index 3cb02d31b1..5fd61eb51d 100644 --- a/src/doc/nomicon/safe-unsafe-meaning.md +++ b/src/doc/nomicon/safe-unsafe-meaning.md @@ -41,8 +41,8 @@ Some examples of unsafe functions: * `slice::get_unchecked` will perform unchecked indexing, allowing memory safety to be freely violated. -* `ptr::offset` is an intrinsic that invokes Undefined Behaviour if it is - not "in bounds" as defined by LLVM. +* every raw pointer to sized type has intrinsic `offset` method that invokes + Undefined Behavior if it is not "in bounds" as defined by LLVM. * `mem::transmute` reinterprets some value as having the given type, bypassing type safety in arbitrary ways. (see [conversions] for details) * All FFI functions are `unsafe` because they can do arbitrary things. @@ -59,9 +59,9 @@ As of Rust 1.0 there are exactly two unsafe traits: The need for unsafe traits boils down to the fundamental property of safe code: **No matter how completely awful Safe code is, it can't cause Undefined -Behaviour.** +Behavior.** -This means that Unsafe Rust, **the royal vanguard of Undefined Behaviour**, has to be +This means that Unsafe Rust, **the royal vanguard of Undefined Behavior**, has to be *super paranoid* about generic safe code. To be clear, Unsafe Rust is totally free to trust specific safe code. Anything else would degenerate into infinite spirals of paranoid despair. In particular it's generally regarded as ok to trust the standard library diff --git a/src/doc/nomicon/send-and-sync.md b/src/doc/nomicon/send-and-sync.md index 9ab60d03fc..134e47f18d 100644 --- a/src/doc/nomicon/send-and-sync.md +++ b/src/doc/nomicon/send-and-sync.md @@ -15,7 +15,7 @@ implement, and other unsafe code can assume that they are correctly implemented. Since they're *marker traits* (they have no associated items like methods), correctly implemented simply means that they have the intrinsic properties an implementor should have. Incorrectly implementing Send or Sync can -cause Undefined Behaviour. +cause Undefined Behavior. Send and Sync are also automatically derived traits. This means that, unlike every other trait, if a type is composed entirely of Send or Sync types, then it diff --git a/src/doc/nomicon/transmutes.md b/src/doc/nomicon/transmutes.md index 2b34ad0a9f..f1478b7f66 100644 --- a/src/doc/nomicon/transmutes.md +++ b/src/doc/nomicon/transmutes.md @@ -8,7 +8,7 @@ horribly unsafe thing you can do in Rust. The railguards here are dental floss. `mem::transmute` takes a value of type `T` and reinterprets it to have type `U`. The only restriction is that the `T` and `U` are verified to have the -same size. The ways to cause Undefined Behaviour with this are mind boggling. +same size. The ways to cause Undefined Behavior with this are mind boggling. * First and foremost, creating an instance of *any* type with an invalid state is going to cause arbitrary chaos that can't really be predicted. @@ -26,7 +26,7 @@ same size. The ways to cause Undefined Behaviour with this are mind boggling. `mem::transmute_copy` somehow manages to be *even more* wildly unsafe than this. It copies `size_of` bytes out of an `&T` and interprets them as a `U`. The size check that `mem::transmute` has is gone (as it may be valid to copy -out a prefix), though it is Undefined Behaviour for `U` to be larger than `T`. +out a prefix), though it is Undefined Behavior for `U` to be larger than `T`. Also of course you can get most of the functionality of these functions using pointer casts. diff --git a/src/doc/nomicon/unbounded-lifetimes.md b/src/doc/nomicon/unbounded-lifetimes.md index b540ab4ed5..2c5ba79a50 100644 --- a/src/doc/nomicon/unbounded-lifetimes.md +++ b/src/doc/nomicon/unbounded-lifetimes.md @@ -2,7 +2,7 @@ Unsafe code can often end up producing references or lifetimes out of thin air. Such lifetimes come into the world as *unbounded*. The most common source of this -is derefencing a raw pointer, which produces a reference with an unbounded lifetime. +is dereferencing a raw pointer, which produces a reference with an unbounded lifetime. Such a lifetime becomes as big as context demands. This is in fact more powerful than simply becoming `'static`, because for instance `&'static &'a T` will fail to typecheck, but the unbound lifetime will perfectly mold into @@ -10,7 +10,7 @@ will fail to typecheck, but the unbound lifetime will perfectly mold into lifetime can be regarded as `'static`. Almost no reference is `'static`, so this is probably wrong. `transmute` and -`transmute_copy` are the two other primary offenders. One should endeavour to +`transmute_copy` are the two other primary offenders. One should endeavor to bound an unbounded lifetime as quick as possible, especially across function boundaries. diff --git a/src/doc/nomicon/unchecked-uninit.md b/src/doc/nomicon/unchecked-uninit.md index 5ae1818dc6..c72ed8a763 100644 --- a/src/doc/nomicon/unchecked-uninit.md +++ b/src/doc/nomicon/unchecked-uninit.md @@ -38,7 +38,7 @@ dropping the old value: `write`, `copy`, and `copy_nonoverlapping`. (this is equivalent to memcpy -- note that the argument order is reversed!) It should go without saying that these functions, if misused, will cause serious -havoc or just straight up Undefined Behaviour. The only things that these +havoc or just straight up Undefined Behavior. The only things that these functions *themselves* require is that the locations you want to read and write are allocated. However the ways writing arbitrary bits to arbitrary locations of memory can break things are basically uncountable! diff --git a/src/doc/nomicon/uninitialized.md b/src/doc/nomicon/uninitialized.md index 915ea86029..05615d89be 100644 --- a/src/doc/nomicon/uninitialized.md +++ b/src/doc/nomicon/uninitialized.md @@ -4,7 +4,7 @@ All runtime-allocated memory in a Rust program begins its life as *uninitialized*. In this state the value of the memory is an indeterminate pile of bits that may or may not even reflect a valid state for the type that is supposed to inhabit that location of memory. Attempting to interpret this memory -as a value of *any* type will cause Undefined Behaviour. Do Not Do This. +as a value of *any* type will cause Undefined Behavior. Do Not Do This. Rust provides mechanisms to work with uninitialized memory in checked (safe) and -unchecked (unsafe) ways. \ No newline at end of file +unchecked (unsafe) ways. diff --git a/src/doc/nomicon/unwinding.md b/src/doc/nomicon/unwinding.md index 3ad95dde39..e81f06b83b 100644 --- a/src/doc/nomicon/unwinding.md +++ b/src/doc/nomicon/unwinding.md @@ -42,7 +42,7 @@ should only panic for programming errors or *extreme* problems. Rust's unwinding strategy is not specified to be fundamentally compatible with any other language's unwinding. As such, unwinding into Rust from another -language, or unwinding into another language from Rust is Undefined Behaviour. +language, or unwinding into another language from Rust is Undefined Behavior. You must *absolutely* catch any panics at the FFI boundary! What you do at that point is up to you, but *something* must be done. If you fail to do this, at best, your application will crash and burn. At worst, your application *won't* diff --git a/src/doc/nomicon/vec-layout.md b/src/doc/nomicon/vec-layout.md index 3df63d5249..7ca369da0b 100644 --- a/src/doc/nomicon/vec-layout.md +++ b/src/doc/nomicon/vec-layout.md @@ -93,7 +93,7 @@ pub struct Vec { If you don't care about the null-pointer optimization, then you can use the stable code. However we will be designing the rest of the code around enabling the optimization. In particular, `Unique::new` is unsafe to call, because -putting `null` inside of it is Undefined Behaviour. Our stable Unique doesn't +putting `null` inside of it is Undefined Behavior. Our stable Unique doesn't need `new` to be unsafe because it doesn't make any interesting guarantees about its contents. diff --git a/src/doc/nomicon/vec-push-pop.md b/src/doc/nomicon/vec-push-pop.md index b518e8aa48..5e747a8c71 100644 --- a/src/doc/nomicon/vec-push-pop.md +++ b/src/doc/nomicon/vec-push-pop.md @@ -34,7 +34,7 @@ Easy! How about `pop`? Although this time the index we want to access is initialized, Rust won't just let us dereference the location of memory to move the value out, because that would leave the memory uninitialized! For this we need `ptr::read`, which just copies out the bits from the target address and -intrprets it as a value of type T. This will leave the memory at this address +interprets it as a value of type T. This will leave the memory at this address logically uninitialized, even though there is in fact a perfectly good instance of T there. diff --git a/src/doc/nomicon/vec-zsts.md b/src/doc/nomicon/vec-zsts.md index 72e8a34488..fb337a891a 100644 --- a/src/doc/nomicon/vec-zsts.md +++ b/src/doc/nomicon/vec-zsts.md @@ -1,11 +1,11 @@ % Handling Zero-Sized Types -It's time. We're going to fight the spectre that is zero-sized types. Safe Rust +It's time. We're going to fight the specter that is zero-sized types. Safe Rust *never* needs to care about this, but Vec is very intensive on raw pointers and raw allocations, which are exactly the two things that care about zero-sized types. We need to be careful of two things: -* The raw allocator API has undefined behaviour if you pass in 0 for an +* The raw allocator API has undefined behavior if you pass in 0 for an allocation size. * raw pointer offsets are no-ops for zero-sized types, which will break our C-style pointer iterator. diff --git a/src/doc/reference.md b/src/doc/reference.md index 717c99901d..037fb6a8d9 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -76,8 +76,16 @@ An identifier is any nonempty Unicode[^non_ascii_idents] string of the following [^non_ascii_idents]: Non-ASCII characters in identifiers are currently feature gated. This is expected to improve soon. -- The first character has property `XID_start` -- The remaining characters have property `XID_continue` +Either + + * The first character has property `XID_start` + * The remaining characters have property `XID_continue` + +Or + + * The first character is `_` + * The identifier is more than one character, `_` alone is not an identifier + * The remaining characters have property `XID_continue` that does _not_ occur in the set of [keywords][keywords]. @@ -410,11 +418,14 @@ The two values of the boolean type are written `true` and `false`. ### Symbols -Symbols are a general class of printable [token](#tokens) that play structural -roles in a variety of grammar productions. They are catalogued here for -completeness as the set of remaining miscellaneous printable tokens that do not +Symbols are a general class of printable [tokens](#tokens) that play structural +roles in a variety of grammar productions. They are a +set of remaining miscellaneous printable tokens that do not otherwise appear as [unary operators](#unary-operator-expressions), [binary operators](#binary-operator-expressions), or [keywords][keywords]. +They are catalogued in [the Symbols section][symbols] of the Grammar document. + +[symbols]: grammar.html#symbols ## Paths @@ -586,8 +597,8 @@ Rust syntax is restricted in two ways: # Crates and source files Although Rust, like any other language, can be implemented by an interpreter as -well as a compiler, the only existing implementation is a compiler — -from now on referred to as *the* Rust compiler — and the language has +well as a compiler, the only existing implementation is a compiler, +and the language has always been designed to be compiled. For these reasons, this section assumes a compiler. @@ -674,7 +685,7 @@ There are several kinds of item: * [modules](#modules) * [functions](#functions) * [type definitions](grammar.html#type-definitions) -* [structures](#structures) +* [structs](#structs) * [enumerations](#enumerations) * [constant items](#constant-items) * [static items](#static-items) @@ -881,7 +892,7 @@ mod foo { } use foo::example::iter; // good: foo is at crate root -// use example::iter; // bad: core is not at the crate root +// use example::iter; // bad: example is not at the crate root use self::baz::foobaz; // good: self refers to module 'foo' use foo::bar::foobar; // good: foo is at crate root @@ -900,9 +911,10 @@ fn main() {} ### Functions -A _function item_ defines a sequence of [statements](#statements) and an -optional final [expression](#expressions), along with a name and a set of -parameters. Functions are declared with the keyword `fn`. Functions declare a +A _function item_ defines a sequence of [statements](#statements) and a +final [expression](#expressions), along with a name and a set of +parameters. Other than a name, all these are optional. +Functions are declared with the keyword `fn`. Functions may declare a set of *input* [*variables*](#variables) as parameters, through which the caller passes arguments into the function, and the *output* [*type*](#types) of the value the function will return to its caller on completion. @@ -921,7 +933,7 @@ An example of a function: ``` fn add(x: i32, y: i32) -> i32 { - return x + y; + x + y } ``` @@ -975,99 +987,6 @@ The type parameters can also be explicitly supplied in a trailing there is not sufficient context to determine the type parameters. For example, `mem::size_of::() == 4`. -#### Unsafety - -Unsafe operations are those that potentially violate the memory-safety -guarantees of Rust's static semantics. - -The following language level features cannot be used in the safe subset of -Rust: - -- Dereferencing a [raw pointer](#pointer-types). -- Reading or writing a [mutable static variable](#mutable-statics). -- Calling an unsafe function (including an intrinsic or foreign function). - -##### Unsafe functions - -Unsafe functions are functions that are not safe in all contexts and/or for all -possible inputs. Such a function must be prefixed with the keyword `unsafe` and -can only be called from an `unsafe` block or another `unsafe` function. - -##### Unsafe blocks - -A block of code can be prefixed with the `unsafe` keyword, to permit calling -`unsafe` functions or dereferencing raw pointers within a safe function. - -When a programmer has sufficient conviction that a sequence of potentially -unsafe operations is actually safe, they can encapsulate that sequence (taken -as a whole) within an `unsafe` block. The compiler will consider uses of such -code safe, in the surrounding context. - -Unsafe blocks are used to wrap foreign libraries, make direct use of hardware -or implement features not directly present in the language. For example, Rust -provides the language features necessary to implement memory-safe concurrency -in the language but the implementation of threads and message passing is in the -standard library. - -Rust's type system is a conservative approximation of the dynamic safety -requirements, so in some cases there is a performance cost to using safe code. -For example, a doubly-linked list is not a tree structure and can only be -represented with reference-counted pointers in safe code. By using `unsafe` -blocks to represent the reverse links as raw pointers, it can be implemented -with only boxes. - -##### Behavior considered undefined - -The following is a list of behavior which is forbidden in all Rust code, -including within `unsafe` blocks and `unsafe` functions. Type checking provides -the guarantee that these issues are never caused by safe code. - -* Data races -* Dereferencing a null/dangling raw pointer -* Reads of [undef](http://llvm.org/docs/LangRef.html#undefined-values) - (uninitialized) memory -* Breaking the [pointer aliasing - rules](http://llvm.org/docs/LangRef.html#pointer-aliasing-rules) - with raw pointers (a subset of the rules used by C) -* `&mut` and `&` follow LLVM’s scoped [noalias] model, except if the `&T` - contains an `UnsafeCell`. Unsafe code must not violate these aliasing - guarantees. -* Mutating non-mutable data (that is, data reached through a shared reference or - data owned by a `let` binding), unless that data is contained within an `UnsafeCell`. -* Invoking undefined behavior via compiler intrinsics: - * Indexing outside of the bounds of an object with `std::ptr::offset` - (`offset` intrinsic), with - the exception of one byte past the end which is permitted. - * Using `std::ptr::copy_nonoverlapping_memory` (`memcpy32`/`memcpy64` - intrinsics) on overlapping buffers -* Invalid values in primitive types, even in private fields/locals: - * Dangling/null references or boxes - * A value other than `false` (0) or `true` (1) in a `bool` - * A discriminant in an `enum` not included in the type definition - * A value in a `char` which is a surrogate or above `char::MAX` - * Non-UTF-8 byte sequences in a `str` -* Unwinding into Rust from foreign code or unwinding from Rust into foreign - code. Rust's failure system is not compatible with exception handling in - other languages. Unwinding must be caught and handled at FFI boundaries. - -[noalias]: http://llvm.org/docs/LangRef.html#noalias - -##### Behavior not considered unsafe - -This is a list of behavior not considered *unsafe* in Rust terms, but that may -be undesired. - -* Deadlocks -* Leaks of memory and other resources -* Exiting without calling destructors -* Integer overflow - - Overflow is considered "unexpected" behavior and is always user-error, - unless the `wrapping` primitives are used. In non-optimized builds, the compiler - will insert debug checks that panic on overflow, but in optimized builds overflow - instead results in wrapped values. See [RFC 560] for the rationale and more details. - -[RFC 560]: https://github.com/rust-lang/rfcs/blob/master/text/0560-integer-overflow.md - #### Diverging functions A special kind of function can be declared with a `!` character where the @@ -1155,9 +1074,9 @@ type Point = (u8, u8); let p: Point = (41, 68); ``` -### Structures +### Structs -A _structure_ is a nominal [structure type](#structure-types) defined with the +A _struct_ is a nominal [struct type](#struct-types) defined with the keyword `struct`. An example of a `struct` item and its use: @@ -1168,7 +1087,7 @@ let p = Point {x: 10, y: 11}; let px: i32 = p.x; ``` -A _tuple structure_ is a nominal [tuple type](#tuple-types), also defined with +A _tuple struct_ is a nominal [tuple type](#tuple-types), also defined with the keyword `struct`. For example: ``` @@ -1177,15 +1096,26 @@ let p = Point(10, 11); let px: i32 = match p { Point(x, _) => x }; ``` -A _unit-like struct_ is a structure without any fields, defined by leaving off -the list of fields entirely. Such types will have a single value. For example: +A _unit-like struct_ is a struct without any fields, defined by leaving off +the list of fields entirely. Such a struct implicitly defines a constant of +its type with the same name. For example: ``` +# #![feature(braced_empty_structs)] struct Cookie; -let c = [Cookie, Cookie, Cookie, Cookie]; +let c = [Cookie, Cookie {}, Cookie, Cookie {}]; +``` + +is equivalent to + +``` +# #![feature(braced_empty_structs)] +struct Cookie {} +const Cookie: Cookie = Cookie {}; +let c = [Cookie, Cookie {}, Cookie, Cookie {}]; ``` -The precise memory layout of a structure is not specified. One can specify a +The precise memory layout of a struct is not specified. One can specify a particular layout using the [`repr` attribute](#ffi-attributes). ### Enumerations @@ -1508,11 +1438,11 @@ struct Foo; trait Shape { fn area(&self) -> f64; } trait Circle : Shape { fn radius(&self) -> f64; } -# impl Shape for Foo { -# fn area(&self) -> f64 { -# 0.0 -# } -# } +impl Shape for Foo { + fn area(&self) -> f64 { + 0.0 + } +} impl Circle for Foo { fn radius(&self) -> f64 { println!("calling area: {}", self.area()); @@ -1590,11 +1520,11 @@ impl Shape for Circle { ``` It is possible to define an implementation without referring to a trait. The -methods in such an implementation can only be used as direct calls on the -values of the type that the implementation targets. In such an implementation, -the trait type and `for` after `impl` are omitted. Such implementations are -limited to nominal types (enums, structs), and the implementation must appear -in the same crate as the `self` type: +methods in such an implementation can only be used as direct calls on the values +of the type that the implementation targets. In such an implementation, the +trait type and `for` after `impl` are omitted. Such implementations are limited +to nominal types (enums, structs, trait objects), and the implementation must +appear in the same crate as the `self` type: ``` struct Point {x: i32, y: i32} @@ -1977,7 +1907,7 @@ On `struct`s: list of names `#[macro_use(foo, bar)]` restricts the import to just those macros named. The `extern crate` must appear at the crate root, not inside `mod`, which ensures proper function of the [`$crate` macro - variable](book/macros.html#the-variable-$crate). + variable](book/macros.html#the-variable-crate). - `macro_reexport` on an `extern crate` — re-export the named macros. @@ -1987,7 +1917,7 @@ On `struct`s: link it into the output. See the [macros section of the -book](book/macros.html#scoping-and-macro-import/export) for more information on +book](book/macros.html#scoping-and-macro-importexport) for more information on macro scope. @@ -2002,6 +1932,20 @@ macro scope. - `simd` - on certain tuple structs, derive the arithmetic operators, which lower to the target's SIMD instructions, if any; the `simd` feature gate is necessary to use this attribute. +- `unsafe_destructor_blind_to_params` - on `Drop::drop` method, asserts that the + destructor code (and all potential specializations of that code) will + never attempt to read from nor write to any references with lifetimes + that come in via generic parameters. This is a constraint we cannot + currently express via the type system, and therefore we rely on the + programmer to assert that it holds. Adding this to a Drop impl causes + the associated destructor to be considered "uninteresting" by the + Drop-Check rule, and thus it can help sidestep data ordering + constraints that would otherwise be introduced by the Drop-Check + rule. Such sidestepping of the constraints, if done incorrectly, can + lead to undefined behavior (in the form of reading or writing to data + outside of its dynamic extent), and thus this attribute has the word + "unsafe" in its name. To use this, the + `unsafe_destructor_blind_to_params` feature gate must be enabled. - `unsafe_no_drop_flag` - on structs, remove the flag that prevents destructors from being run twice. Destructors might be run multiple times on the same object with this attribute. To use this, the `unsafe_no_drop_flag` feature @@ -2081,6 +2025,8 @@ The following configurations must be defined by the implementation: * `target_pointer_width = "..."` - Target pointer width in bits. This is set to `"32"` for targets with 32-bit pointers, and likewise set to `"64"` for 64-bit pointers. +* `target_vendor = "..."` - Vendor of the target, for example `apple`, `pc`, or + simply `"unknown"`. * `test` - Enabled when compiling the test harness (using the `--test` flag). * `unix` - See `target_family`. * `windows` - See `target_family`. @@ -2257,7 +2203,7 @@ The currently implemented features of the reference compiler are: * `advanced_slice_patterns` - See the [match expressions](#match-expressions) section for discussion; the exact semantics of slice patterns are subject to change, so some types - are still unstable. + are still unstable. * `slice_patterns` - OK, actually, slice patterns are just scary and completely unstable. @@ -2278,6 +2224,9 @@ The currently implemented features of the reference compiler are: * `box_syntax` - Allows use of `box` expressions, the exact semantics of which is subject to change. +* `cfg_target_vendor` - Allows conditional compilation using the `target_vendor` + matcher which is subject to change. + * `concat_idents` - Allows use of the `concat_idents` macro, which is in many ways insufficient for concatenating identifiers, and may be removed entirely for something more wholesome. @@ -2411,6 +2360,7 @@ The currently implemented features of the reference compiler are: terms of encapsulation). * - `default_type_parameter_fallback` - Allows type parameter defaults to influence type inference. +* - `braced_empty_structs` - Allows use of empty structs and enum variants with braces. If a feature is promoted to a language feature, then all existing programs will start to receive compilation warnings about `#![feature]` directives which enabled @@ -2454,7 +2404,7 @@ items. An _item declaration statement_ has a syntactic form identical to an [item](#items) declaration within a module. Declaring an item — a -function, enumeration, structure, type, static, trait, implementation or module +function, enumeration, struct, type, static, trait, implementation or module — locally within a statement block is simply a way of restricting its scope to a narrow region containing all of its uses; it is otherwise identical in meaning to declaring the item outside the statement block. @@ -2560,7 +2510,7 @@ Here are some examples: #### Moved and copied types When a [local variable](#variables) is used as an -[rvalue](#lvalues,-rvalues-and-temporaries), the variable will be copied +[rvalue](#lvalues-rvalues-and-temporaries), the variable will be copied if its type implements `Copy`. All others are moved. ### Literal expressions @@ -2579,7 +2529,7 @@ value, or the unit value. ### Path expressions A [path](#paths) used as an expression context denotes either a local variable -or an item. Path expressions are [lvalues](#lvalues,-rvalues-and-temporaries). +or an item. Path expressions are [lvalues](#lvalues-rvalues-and-temporaries). ### Tuple expressions @@ -2599,26 +2549,26 @@ comma: (0); // zero in parentheses ``` -### Structure expressions +### Struct expressions -There are several forms of structure expressions. A _structure expression_ -consists of the [path](#paths) of a [structure item](#structures), followed by +There are several forms of struct expressions. A _struct expression_ +consists of the [path](#paths) of a [struct item](#structs), followed by a brace-enclosed list of one or more comma-separated name-value pairs, -providing the field values of a new instance of the structure. A field name +providing the field values of a new instance of the struct. A field name can be any identifier, and is separated from its value expression by a colon. -The location denoted by a structure field is mutable if and only if the -enclosing structure is mutable. +The location denoted by a struct field is mutable if and only if the +enclosing struct is mutable. -A _tuple structure expression_ consists of the [path](#paths) of a [structure -item](#structures), followed by a parenthesized list of one or more -comma-separated expressions (in other words, the path of a structure item -followed by a tuple expression). The structure item must be a tuple structure +A _tuple struct expression_ consists of the [path](#paths) of a [struct +item](#structs), followed by a parenthesized list of one or more +comma-separated expressions (in other words, the path of a struct item +followed by a tuple expression). The struct item must be a tuple struct item. -A _unit-like structure expression_ consists only of the [path](#paths) of a -[structure item](#structures). +A _unit-like struct expression_ consists only of the [path](#paths) of a +[struct item](#structs). -The following are examples of structure expressions: +The following are examples of struct expressions: ``` # struct Point { x: f64, y: f64 } @@ -2631,14 +2581,14 @@ let u = game::User {name: "Joe", age: 35, score: 100_000}; some_fn::(Cookie); ``` -A structure expression forms a new value of the named structure type. Note -that for a given *unit-like* structure type, this will always be the same +A struct expression forms a new value of the named struct type. Note +that for a given *unit-like* struct type, this will always be the same value. -A structure expression can terminate with the syntax `..` followed by an +A struct expression can terminate with the syntax `..` followed by an expression to denote a functional update. The expression following `..` (the -base) must have the same structure type as the new structure type being formed. -The entire expression denotes the result of constructing a new structure (with +base) must have the same struct type as the new struct type being formed. +The entire expression denotes the result of constructing a new struct (with the same type as the base expression) with the given values for the fields that were explicitly specified and the values in the base expression for all other fields. @@ -2684,7 +2634,7 @@ the left-hand-side expression is an indirect [trait object](#trait-objects). A _field expression_ consists of an expression followed by a single dot and an identifier, when not immediately followed by a parenthesized expression-list (the latter is a [method call expression](#method-call-expressions)). A field -expression denotes a field of a [structure](#structure-types). +expression denotes a field of a [struct](#struct-types). ```{.ignore .field} mystruct.myfield; @@ -2692,7 +2642,7 @@ foo().x; (Struct {a: 10, b: 20}).a; ``` -A field access is an [lvalue](#lvalues,-rvalues-and-temporaries) referring to +A field access is an [lvalue](#lvalues-rvalues-and-temporaries) referring to the value of that field. When the type providing the field inherits mutability, it can be [assigned](#assignment-expressions) to. @@ -2703,7 +2653,7 @@ fewer autoderefs to more. ### Array expressions -An [array](#array,-and-slice-types) _expression_ is written by enclosing zero +An [array](#array-and-slice-types) _expression_ is written by enclosing zero or more comma-separated expressions of uniform type in square brackets. In the `[expr ';' expr]` form, the expression after the `';'` must be a @@ -2719,9 +2669,9 @@ constant expression that can be evaluated at compile time, such as a ### Index expressions -[Array](#array,-and-slice-types)-typed expressions can be indexed by +[Array](#array-and-slice-types)-typed expressions can be indexed by writing a square-bracket-enclosed expression (the index) after them. When the -array is mutable, the resulting [lvalue](#lvalues,-rvalues-and-temporaries) can +array is mutable, the resulting [lvalue](#lvalues-rvalues-and-temporaries) can be assigned to. Indices are zero-based, and may be of any integral type. Vector access is @@ -2762,7 +2712,7 @@ The following expressions are equivalent. let x = std::ops::Range {start: 0, end: 10}; let y = 0..10; -assert_eq!(x,y); +assert_eq!(x, y); ``` ### Unary operator expressions @@ -2775,7 +2725,7 @@ before the expression they apply to. * `*` : Dereference. When applied to a [pointer](#pointer-types) it denotes the pointed-to location. For pointers to mutable locations, the resulting - [lvalue](#lvalues,-rvalues-and-temporaries) can be assigned to. + [lvalue](#lvalues-rvalues-and-temporaries) can be assigned to. On non-pointer types, it calls the `deref` method of the `std::ops::Deref` trait, or the `deref_mut` method of the `std::ops::DerefMut` trait (if implemented by the type and required for an outer expression that will or @@ -2916,8 +2866,8 @@ surprising side-effects on the dynamic execution semantics. #### Assignment expressions An _assignment expression_ consists of an -[lvalue](#lvalues,-rvalues-and-temporaries) expression followed by an equals -sign (`=`) and an [rvalue](#lvalues,-rvalues-and-temporaries) expression. +[lvalue](#lvalues-rvalues-and-temporaries) expression followed by an equals +sign (`=`) and an [rvalue](#lvalues-rvalues-and-temporaries) expression. Evaluating an assignment expression [either copies or moves](#moved-and-copied-types) its right-hand operand to its left-hand @@ -3035,10 +2985,10 @@ A `loop` expression may optionally have a _label_. The label is written as a lifetime preceding the loop expression, as in `'foo: loop{ }`. If a label is present, then labeled `break` and `continue` expressions nested within this loop may exit out of this loop or return control to its head. -See [Break expressions](#break-expressions) and [Continue +See [break expressions](#break-expressions) and [continue expressions](#continue-expressions). -### Break expressions +### `break` expressions A `break` expression has an optional _label_. If the label is absent, then executing a `break` expression immediately terminates the innermost loop @@ -3046,7 +2996,7 @@ enclosing it. It is only permitted in the body of a loop. If the label is present, then `break 'foo` terminates the loop with label `'foo`, which need not be the innermost label enclosing the `break` expression, but must enclose it. -### Continue expressions +### `continue` expressions A `continue` expression has an optional _label_. If the label is absent, then executing a `continue` expression immediately terminates the current iteration @@ -3059,7 +3009,7 @@ innermost label enclosing the `break` expression, but must enclose it. A `continue` expression is only permitted in the body of a loop. -### While loops +### `while` loops A `while` loop begins by evaluating the boolean loop conditional expression. If the loop conditional expression evaluates to `true`, the loop body block @@ -3082,12 +3032,12 @@ Like `loop` expressions, `while` loops can be controlled with `break` or loops](#infinite-loops), [break expressions](#break-expressions), and [continue expressions](#continue-expressions) for more information. -### For expressions +### `for` expressions A `for` expression is a syntactic construct for looping over elements provided by an implementation of `std::iter::IntoIterator`. -An example of a for loop over the contents of an array: +An example of a `for` loop over the contents of an array: ``` # type Foo = i32; @@ -3117,7 +3067,7 @@ Like `loop` expressions, `for` loops can be controlled with `break` or loops](#infinite-loops), [break expressions](#break-expressions), and [continue expressions](#continue-expressions) for more information. -### If expressions +### `if` expressions An `if` expression is a conditional branch in program control. The form of an `if` expression is a condition expression, followed by a consequent block, any @@ -3129,11 +3079,11 @@ evaluates to `false`, the consequent block is skipped and any subsequent `else if` condition is evaluated. If all `if` and `else if` conditions evaluate to `false` then any `else` block is executed. -### Match expressions +### `match` expressions A `match` expression branches on a *pattern*. The exact form of matching that occurs depends on the pattern. Patterns consist of some combination of -literals, destructured arrays or enum constructors, structures and tuples, +literals, destructured arrays or enum constructors, structs and tuples, variable binding specifications, wildcards (`..`), and placeholders (`_`). A `match` expression has a *head expression*, which is the value to compare to the patterns. The type of the patterns must equal the type of the head @@ -3144,7 +3094,7 @@ stands for a *single* data field, whereas a wildcard `..` stands for *all* the fields of a particular variant. A `match` behaves differently depending on whether or not the head expression -is an [lvalue or an rvalue](#lvalues,-rvalues-and-temporaries). If the head +is an [lvalue or an rvalue](#lvalues-rvalues-and-temporaries). If the head expression is an rvalue, it is first evaluated into a temporary location, and the resulting value is sequentially compared to the patterns in the arms until a match is found. The first arm with a matching pattern is chosen as the branch @@ -3235,7 +3185,7 @@ let message = match maybe_digit { }; ``` -### If let expressions +### `if let` expressions An `if let` expression is semantically identical to an `if` expression but in place of a condition expression it expects a refutable let statement. If the value of the @@ -3256,7 +3206,7 @@ if let ("Ham", b) = dish { } ``` -### While let loops +### `while let` loops A `while let` loop is semantically identical to a `while` loop but in place of a condition expression it expects a refutable let statement. If the value of the @@ -3264,7 +3214,7 @@ expression on the right hand side of the let statement matches the pattern, the loop body block executes and control returns to the pattern matching statement. Otherwise, the while expression completes. -### Return expressions +### `return` expressions Return expressions are denoted with the keyword `return`. Evaluating a `return` expression moves its argument into the designated output location for the @@ -3403,17 +3353,17 @@ As you can see, the `vec!` macro allows you to create a `Vec` easily. The All in-bounds elements of arrays and slices are always initialized, and access to an array or slice is always bounds-checked. -### Structure types +### Struct types A `struct` *type* is a heterogeneous product of other types, called the *fields* of the type.[^structtype] [^structtype]: `struct` types are analogous to `struct` types in C, the *record* types of the ML family, - or the *structure* types of the Lisp family. + or the *struct* types of the Lisp family. New instances of a `struct` can be constructed with a [struct -expression](#structure-expressions). +expression](#struct-expressions). The memory layout of a `struct` is undefined by default to allow for compiler optimizations like field reordering, but it can be fixed with the @@ -3423,14 +3373,14 @@ have the same memory layout. The fields of a `struct` may be qualified by [visibility modifiers](#visibility-and-privacy), to allow access to data in a -structure outside a module. +struct outside a module. -A _tuple struct_ type is just like a structure type, except that the fields are +A _tuple struct_ type is just like a struct type, except that the fields are anonymous. -A _unit-like struct_ type is like a structure type, except that it has no -fields. The one value constructed by the associated [structure -expression](#structure-expressions) is the only value that inhabits such a +A _unit-like struct_ type is like a struct type, except that it has no +fields. The one value constructed by the associated [struct +expression](#struct-expressions) is the only value that inhabits such a type. ### Enumerated types @@ -3457,13 +3407,13 @@ named reference to an [`enum` item](#enumerations). ### Recursive types Nominal types — [enumerations](#enumerated-types) and -[structures](#structure-types) — may be recursive. That is, each `enum` +[structs](#struct-types) — may be recursive. That is, each `enum` constructor or `struct` field may refer, directly or indirectly, to the enclosing `enum` or `struct` type itself. Such recursion has restrictions: * Recursive types must include a nominal type in the recursion (not mere [type definitions](grammar.html#type-definitions), - or other structural types such as [arrays](#array,-and-slice-types) or [tuples](#tuple-types)). + or other structural types such as [arrays](#array-and-slice-types) or [tuples](#tuple-types)). * A recursive `enum` item must have at least one non-recursive constructor (in order to give the recursion a basis case). * The size of a recursive type must be finite; @@ -3485,7 +3435,7 @@ let a: List = List::Cons(7, Box::new(List::Cons(13, Box::new(List::Nil)))); ### Pointer types All pointers in Rust are explicit first-class values. They can be copied, -stored into data structures, and returned from functions. There are two +stored into data structs, and returned from functions. There are two varieties of pointer in Rust: * References (`&`) @@ -3759,7 +3709,7 @@ repeated sub-expression is a coercion site for coercion to type `U`. Each sub-expression is a coercion site to the respective type, e.g. the zeroth sub-expression is a coercion site to type `U_0`. -* Parenthesised sub-expressions (`(e)`): if the expression has type `U`, then +* Parenthesized sub-expressions (`(e)`): if the expression has type `U`, then the sub-expression is a coercion site to `U`. * Blocks: if a block has type `U`, then the last expression in the block (if @@ -3885,7 +3835,7 @@ references to boxes are dropped. ### Variables A _variable_ is a component of a stack frame, either a named function parameter, -an anonymous [temporary](#lvalues,-rvalues-and-temporaries), or a named local +an anonymous [temporary](#lvalues-rvalues-and-temporaries), or a named local variable. A _local variable_ (or *stack-local* allocation) holds a value directly, @@ -3919,11 +3869,11 @@ initialized; this is enforced by the compiler. The Rust compiler supports various methods to link crates together both statically and dynamically. This section will explore the various methods to link Rust crates together, and more information about native libraries can be -found in the [ffi section of the book][ffi]. +found in the [FFI section of the book][ffi]. In one session of compilation, the compiler can generate multiple artifacts through the usage of either command line flags or the `crate_type` attribute. -If one or more command line flag is specified, all `crate_type` attributes will +If one or more command line flags are specified, all `crate_type` attributes will be ignored in favor of only building the artifacts specified by command line. * `--crate-type=bin`, `#[crate_type = "bin"]` - A runnable executable will be @@ -3969,7 +3919,7 @@ Note that these outputs are stackable in the sense that if multiple are specified, then the compiler will produce each form of output at once without having to recompile. However, this only applies for outputs specified by the same method. If only `crate_type` attributes are specified, then they will all -be built, but if one or more `--crate-type` command line flag is specified, +be built, but if one or more `--crate-type` command line flags are specified, then only those outputs will be built. With all these different kinds of outputs, if crate A depends on crate B, then @@ -4024,9 +3974,98 @@ In general, `--crate-type=bin` or `--crate-type=lib` should be sufficient for all compilation needs, and the other options are just available if more fine-grained control is desired over the output format of a Rust crate. -# Appendix: Rationales and design trade-offs +# Unsafety + +Unsafe operations are those that potentially violate the memory-safety +guarantees of Rust's static semantics. + +The following language level features cannot be used in the safe subset of +Rust: + +- Dereferencing a [raw pointer](#pointer-types). +- Reading or writing a [mutable static variable](#mutable-statics). +- Calling an unsafe function (including an intrinsic or foreign function). + +## Unsafe functions + +Unsafe functions are functions that are not safe in all contexts and/or for all +possible inputs. Such a function must be prefixed with the keyword `unsafe` and +can only be called from an `unsafe` block or another `unsafe` function. + +## Unsafe blocks + +A block of code can be prefixed with the `unsafe` keyword, to permit calling +`unsafe` functions or dereferencing raw pointers within a safe function. + +When a programmer has sufficient conviction that a sequence of potentially +unsafe operations is actually safe, they can encapsulate that sequence (taken +as a whole) within an `unsafe` block. The compiler will consider uses of such +code safe, in the surrounding context. + +Unsafe blocks are used to wrap foreign libraries, make direct use of hardware +or implement features not directly present in the language. For example, Rust +provides the language features necessary to implement memory-safe concurrency +in the language but the implementation of threads and message passing is in the +standard library. + +Rust's type system is a conservative approximation of the dynamic safety +requirements, so in some cases there is a performance cost to using safe code. +For example, a doubly-linked list is not a tree structure and can only be +represented with reference-counted pointers in safe code. By using `unsafe` +blocks to represent the reverse links as raw pointers, it can be implemented +with only boxes. + +## Behavior considered undefined + +The following is a list of behavior which is forbidden in all Rust code, +including within `unsafe` blocks and `unsafe` functions. Type checking provides +the guarantee that these issues are never caused by safe code. -*TODO*. +* Data races +* Dereferencing a null/dangling raw pointer +* Reads of [undef](http://llvm.org/docs/LangRef.html#undefined-values) + (uninitialized) memory +* Breaking the [pointer aliasing + rules](http://llvm.org/docs/LangRef.html#pointer-aliasing-rules) + with raw pointers (a subset of the rules used by C) +* `&mut` and `&` follow LLVM’s scoped [noalias] model, except if the `&T` + contains an `UnsafeCell`. Unsafe code must not violate these aliasing + guarantees. +* Mutating non-mutable data (that is, data reached through a shared reference or + data owned by a `let` binding), unless that data is contained within an `UnsafeCell`. +* Invoking undefined behavior via compiler intrinsics: + * Indexing outside of the bounds of an object with `std::ptr::offset` + (`offset` intrinsic), with + the exception of one byte past the end which is permitted. + * Using `std::ptr::copy_nonoverlapping_memory` (`memcpy32`/`memcpy64` + intrinsics) on overlapping buffers +* Invalid values in primitive types, even in private fields/locals: + * Dangling/null references or boxes + * A value other than `false` (0) or `true` (1) in a `bool` + * A discriminant in an `enum` not included in the type definition + * A value in a `char` which is a surrogate or above `char::MAX` + * Non-UTF-8 byte sequences in a `str` +* Unwinding into Rust from foreign code or unwinding from Rust into foreign + code. Rust's failure system is not compatible with exception handling in + other languages. Unwinding must be caught and handled at FFI boundaries. + +[noalias]: http://llvm.org/docs/LangRef.html#noalias + +## Behavior not considered unsafe + +This is a list of behavior not considered *unsafe* in Rust terms, but that may +be undesired. + +* Deadlocks +* Leaks of memory and other resources +* Exiting without calling destructors +* Integer overflow + - Overflow is considered "unexpected" behavior and is always user-error, + unless the `wrapping` primitives are used. In non-optimized builds, the compiler + will insert debug checks that panic on overflow, but in optimized builds overflow + instead results in wrapped values. See [RFC 560] for the rationale and more details. + +[RFC 560]: https://github.com/rust-lang/rfcs/blob/master/text/0560-integer-overflow.md # Appendix: Influences @@ -4036,7 +4075,7 @@ that have since been removed): * SML, OCaml: algebraic data types, pattern matching, type inference, semicolon statement separation -* C++: references, RAII, smart pointers, move semantics, monomorphisation, +* C++: references, RAII, smart pointers, move semantics, monomorphization, memory model * ML Kit, Cyclone: region based memory management * Haskell (GHC): typeclasses, type families diff --git a/src/doc/rust.css b/src/doc/rust.css index 6204f38a37..874f697661 100644 --- a/src/doc/rust.css +++ b/src/doc/rust.css @@ -338,14 +338,17 @@ table th { .rusttest { display: none; } pre.rust { position: relative; } -.test-arrow { +a.test-arrow { display: inline-block; position: absolute; - top: 0; - right: 10px; - font-size: 150%; - -webkit-transform: scaleX(-1); - transform: scaleX(-1); + + background-color: #4e8bca; + color: #f5f5f5; + padding: 5px 10px 5px 10px; + border-radius: 5px; + font-size: 130%; + top: 5px; + right: 5px; } .unstable-feature { diff --git a/src/doc/style/SUMMARY.md b/src/doc/style/SUMMARY.md index 41bc08f229..508ede6c4a 100644 --- a/src/doc/style/SUMMARY.md +++ b/src/doc/style/SUMMARY.md @@ -48,7 +48,3 @@ * [Testing](testing/README.md) * [Unit testing](testing/unit.md) * [FFI, platform-specific code](platform.md) -* [APIs for a changing Rust](changing/README.md) - * [Pre-1.0 changes](changing/pre-1-0.md) - * [Post-1.0 changes](changing/post-1-0.md) - * [Timing unclear](changing/unclear.md) diff --git a/src/doc/style/changing/README.md b/src/doc/style/changing/README.md deleted file mode 100644 index 38e76f6970..0000000000 --- a/src/doc/style/changing/README.md +++ /dev/null @@ -1,5 +0,0 @@ -% API design for a changing Rust - -A number of planned Rust features will drastically affect the API design -story. This section collects some of the biggest features with concrete examples -of how the API will change. diff --git a/src/doc/style/changing/post-1-0.md b/src/doc/style/changing/post-1-0.md deleted file mode 100644 index 7ac1c837c0..0000000000 --- a/src/doc/style/changing/post-1-0.md +++ /dev/null @@ -1,12 +0,0 @@ -% Post-1.0 changes - -### Higher-kinded types - -* A trait encompassing both `Iterable` for some fixed `T` and - `FromIterator` for _all_ `U` (where HKT comes in). The train - could provide e.g. a default `map` method producing the same kind of - the container, but with a new type parameter. - -* **Monadic-generic programming**? Can we add this without deprecating - huge swaths of the API (including `Option::map`, `option::collect`, - `result::collect`, `try!` etc. diff --git a/src/doc/style/changing/pre-1-0.md b/src/doc/style/changing/pre-1-0.md deleted file mode 100644 index adadfe31a5..0000000000 --- a/src/doc/style/changing/pre-1-0.md +++ /dev/null @@ -1,17 +0,0 @@ -% Pre-1.0 changes - -### `std` facade - -We should revisit some APIs in `libstd` now that the facade effort is complete. - -For example, the treatment of environment variables in the new -`Command` API is waiting on access to hashtables before being -approved. - -### Trait reform - -Potential for standard conversion traits (`to`, `into`, `as`). - -Probably many other opportunities here. - -### Unboxed closures diff --git a/src/doc/style/changing/unclear.md b/src/doc/style/changing/unclear.md deleted file mode 100644 index e4b8a98e1a..0000000000 --- a/src/doc/style/changing/unclear.md +++ /dev/null @@ -1,28 +0,0 @@ -% Changes with unclear timing - -### Associated items - -* Many traits that currently take type parameters should instead use associated - types; this will _drastically_ simplify signatures in some cases. - -* Associated constants would be useful in a few places, e.g. traits for - numerics, traits for paths. - -### Anonymous, unboxed return types (aka `impl Trait` types) - -* See https://github.com/rust-lang/rfcs/pull/105 - -* Could affect API design in several places, e.g. the `Iterator` trait. - -### Default type parameters - -We are already using this in a few places (e.g. `HashMap`), but it's -feature-gated. - -### Compile-time function evaluation (CTFE) - -https://github.com/mozilla/rust/issues/11621 - -### Improved constant folding - -https://github.com/rust-lang/rust/issues/7834 diff --git a/src/doc/style/errors/ergonomics.md b/src/doc/style/errors/ergonomics.md index 0985475f56..a404d25bf3 100644 --- a/src/doc/style/errors/ergonomics.md +++ b/src/doc/style/errors/ergonomics.md @@ -57,7 +57,7 @@ fn write_info(info: &Info) -> Result<(), IoError> { ``` See -[the `result` module documentation](https://doc.rust-lang.org/stable/std/result/index.html#the-try!-macro) +[the `result` module documentation](https://doc.rust-lang.org/stable/std/result/index.html#the-try-macro) for more details. ### The `Result`-`impl` pattern [FIXME] diff --git a/src/doc/style/features/modules.md b/src/doc/style/features/modules.md index 23d8760f57..c55b38b915 100644 --- a/src/doc/style/features/modules.md +++ b/src/doc/style/features/modules.md @@ -17,12 +17,12 @@ Organize module headers as follows: Avoid using `#[path="..."]` directives; make the file system and module hierarchy match, instead. -### Use the module hirearchy to organize APIs into coherent sections. [FIXME] +### Use the module hierarchy to organize APIs into coherent sections. [FIXME] > **[FIXME]** Flesh this out with examples; explain what a "coherent > section" is with examples. > -> The module hirearchy defines both the public and internal API of your module. +> The module hierarchy defines both the public and internal API of your module. > Breaking related functionality into submodules makes it understandable to both > users and contributors to the module. @@ -82,7 +82,7 @@ io/mod.rs ``` While it is possible to define all of `io` within a single directory, -mirroring the module hirearchy in the directory structure makes +mirroring the module hierarchy in the directory structure makes submodules of `io::net` easier to find. ### Consider top-level definitions or reexports. [FIXME: needs RFC] @@ -104,13 +104,13 @@ while [`TcpStream`](https://doc.rust-lang.org/std/io/net/tcp/struct.TcpStream.html) is defined in `io/net/tcp.rs` and reexported in the `io` module. -### Use internal module hirearchies for organization. [FIXME: needs RFC] +### Use internal module hierarchies for organization. [FIXME: needs RFC] > **[FIXME]** > - Referencing internal modules from the standard library is subject to > becoming outdated. -Internal module hirearchies (i.e., private submodules) may be used to +Internal module hierarchies (i.e., private submodules) may be used to hide implementation details that are not part of the module's API. For example, in [`std::io`](https://doc.rust-lang.org/std/io/), `mod mem` diff --git a/src/doc/style/features/traits/common.md b/src/doc/style/features/traits/common.md index 48c37eabca..18346c0925 100644 --- a/src/doc/style/features/traits/common.md +++ b/src/doc/style/features/traits/common.md @@ -9,18 +9,18 @@ applicable, common traits. To see why, consider the following situation: -* Crate `std` defines trait `Show`. -* Crate `url` defines type `Url`, without implementing `Show`. +* Crate `std` defines trait `Debug`. +* Crate `url` defines type `Url`, without implementing `Debug`. * Crate `webapp` imports from both `std` and `url`, -There is no way for `webapp` to add `Show` to `url`, since it defines neither. +There is no way for `webapp` to add `Debug` to `url`, since it defines neither. (Note: the newtype pattern can provide an efficient, but inconvenient workaround; see [newtype for views](../types/newtype.md)) The most important common traits to implement from `std` are: ```rust -Clone, Show, Hash, Eq +Clone, Debug, Hash, Eq ``` #### When safe, derive or otherwise implement `Send` and `Share`. [FIXME] diff --git a/src/doc/style/features/traits/generics.md b/src/doc/style/features/traits/generics.md index 2d9356fc42..26ffda50ac 100644 --- a/src/doc/style/features/traits/generics.md +++ b/src/doc/style/features/traits/generics.md @@ -27,7 +27,7 @@ explicitly implement to be used by this generic function. * _Inference_. Since the type parameters to generic functions can usually be inferred, generic functions can help cut down on verbosity in code where explicit conversions or other method calls would usually be necessary. See the - [overloading/implicits use case](#use-case:-limited-overloading-and/or-implicit-conversions) + [overloading/implicits use case](#use-case-limited-overloading-andor-implicit-conversions) below. * _Precise types_. Because generics give a _name_ to the specific type implementing a trait, it is possible to be precise about places where that @@ -51,7 +51,7 @@ explicitly implement to be used by this generic function. a `Vec` contains elements of a single concrete type (and, indeed, the vector representation is specialized to lay these out in line). Sometimes heterogeneous collections are useful; see - [trait objects](#use-case:-trait-objects) below. + [trait objects](#use-case-trait-objects) below. * _Signature verbosity_. Heavy use of generics can bloat function signatures. **[Ed. note]** This problem may be mitigated by some language improvements; stay tuned. diff --git a/src/doc/style/features/traits/reuse.md b/src/doc/style/features/traits/reuse.md index 61f8db87cd..feedd3937f 100644 --- a/src/doc/style/features/traits/reuse.md +++ b/src/doc/style/features/traits/reuse.md @@ -5,7 +5,7 @@ > **[FIXME]** We probably want to discourage this, at least when used in a way > that is publicly exposed. -Traits that provide default implmentations for function can provide code reuse +Traits that provide default implementations for function can provide code reuse across types. For example, a `print` method can be defined across multiple types as follows: diff --git a/src/doc/style/style/comments.md b/src/doc/style/style/comments.md index b2d2d9ab6b..3851187b52 100644 --- a/src/doc/style/style/comments.md +++ b/src/doc/style/style/comments.md @@ -85,3 +85,20 @@ Use inner doc comments _only_ to document crates and file-level modules: //! //! The core library is a something something... ``` + +### Explain context. + +Rust doesn't have special constructors, only functions that return new +instances. These aren't visible in the automatically generated documentation +for a type, so you should specifically link to them: + +``` rust +/// An iterator that yields `None` forever after the underlying iterator +/// yields `None` once. +/// +/// These can be created through +/// [`iter.fuse()`](trait.Iterator.html#method.fuse). +pub struct Fuse { + // ... +} +``` diff --git a/src/doc/trpl/README.md b/src/doc/trpl/README.md index 0feaf9c6bb..6962f828e1 100644 --- a/src/doc/trpl/README.md +++ b/src/doc/trpl/README.md @@ -9,9 +9,8 @@ requirements, and writing low-level code, like device drivers and operating systems. It improves on current languages targeting this space by having a number of compile-time safety checks that produce no runtime overhead, while eliminating all data races. Rust also aims to achieve ‘zero-cost abstractions’ -even though some of these abstractions feel like those of a high-level -language. Even then, Rust still allows precise control like a low-level -language would. +even though some of these abstractions feel like those of a high-level language. +Even then, Rust still allows precise control like a low-level language would. [rust]: https://www.rust-lang.org @@ -34,15 +33,15 @@ is the first. After this: [gl]: glossary.html [bi]: bibliography.html -After reading this introduction, you’ll want to dive into either ‘Learn Rust’ -or ‘Syntax and Semantics’, depending on your preference: ‘Learn Rust’ if you -want to dive in with a project, or ‘Syntax and Semantics’ if you prefer to -start small, and learn a single concept thoroughly before moving onto the next. +After reading this introduction, you’ll want to dive into either ‘Learn Rust’ or +‘Syntax and Semantics’, depending on your preference: ‘Learn Rust’ if you want +to dive in with a project, or ‘Syntax and Semantics’ if you prefer to start +small, and learn a single concept thoroughly before moving onto the next. Copious cross-linking connects these parts together. ### Contributing -The source files from which this book is generated can be found on Github: +The source files from which this book is generated can be found on GitHub: [github.com/rust-lang/rust/tree/master/src/doc/trpl](https://github.com/rust-lang/rust/tree/master/src/doc/trpl) ## A brief introduction to Rust @@ -76,11 +75,11 @@ type inference to balance out the power of static typing with the verbosity of annotating types. Rust prefers stack allocation to heap allocation: `x` is placed directly on the -stack. However, the `Vec` type allocates space for the elements of the -vector on the heap. If you’re not familiar with this distinction, you can -ignore it for now, or check out [‘The Stack and the Heap’][heap]. As a systems -programming language, Rust gives you the ability to control how your memory is -allocated, but when we’re getting started, it’s less of a big deal. +stack. However, the `Vec` type allocates space for the elements of the vector +on the heap. If you’re not familiar with this distinction, you can ignore it for +now, or check out [‘The Stack and the Heap’][heap]. As a systems programming +language, Rust gives us the ability to control how our memory is allocated, but +when we’re getting started, it’s less of a big deal. [var]: variable-bindings.html [macro]: macros.html @@ -90,10 +89,10 @@ Earlier, we mentioned that ‘ownership’ is the key new concept in Rust. In Ru parlance, `x` is said to ‘own’ the vector. This means that when `x` goes out of scope, the vector’s memory will be de-allocated. This is done deterministically by the Rust compiler, rather than through a mechanism such as a garbage -collector. In other words, in Rust, you don’t call functions like `malloc` and -`free` yourself: the compiler statically determines when you need to allocate -or deallocate memory, and inserts those calls itself. To err is to be human, -but compilers never forget. +collector. In other words, in Rust, we don’t call functions like `malloc` and +`free` ourselves: the compiler statically determines when we need to allocate or +deallocate memory, and inserts those calls itself. To err is to be human, but +compilers never forget. Let’s add another line to our example: @@ -105,13 +104,13 @@ fn main() { } ``` -We’ve introduced another binding, `y`. In this case, `y` is a ‘reference’ to -the first element of the vector. Rust’s references are similar to pointers in -other languages, but with additional compile-time safety checks. References -interact with the ownership system by [‘borrowing’][borrowing] what they point -to, rather than owning it. The difference is, when the reference goes out of -scope, it will not deallocate the underlying memory. If it did, we’d -de-allocate twice, which is bad! +We’ve introduced another binding, `y`. In this case, `y` is a ‘reference’ to the +first element of the vector. Rust’s references are similar to pointers in other +languages, but with additional compile-time safety checks. References interact +with the ownership system by [‘borrowing’][borrowing] what they point to, rather +than owning it. The difference is, when the reference goes out of scope, it +won't deallocate the underlying memory. If it did, we’d de-allocate twice, which +is bad! [borrowing]: references-and-borrowing.html @@ -147,7 +146,7 @@ fn main() { Whew! The Rust compiler gives quite detailed errors at times, and this is one of those times. As the error explains, while we made our binding mutable, we -still cannot call `push`. This is because we already have a reference to an +still can't call `push`. This is because we already have a reference to an element of the vector, `y`. Mutating something while another reference exists is dangerous, because we may invalidate the reference. In this specific case, when we create the vector, we may have only allocated space for two elements. diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md index ae2416018c..2b5d1fa70a 100644 --- a/src/doc/trpl/SUMMARY.md +++ b/src/doc/trpl/SUMMARY.md @@ -68,5 +68,7 @@ * [Box Syntax and Patterns](box-syntax-and-patterns.md) * [Slice Patterns](slice-patterns.md) * [Associated Constants](associated-constants.md) + * [Custom Allocators](custom-allocators.md) * [Glossary](glossary.md) +* [Syntax Index](syntax-index.md) * [Bibliography](bibliography.md) diff --git a/src/doc/trpl/advanced-linking.md b/src/doc/trpl/advanced-linking.md index 03043f5f73..9ef6d5c2bf 100644 --- a/src/doc/trpl/advanced-linking.md +++ b/src/doc/trpl/advanced-linking.md @@ -26,7 +26,7 @@ shells out to the system linker (`gcc` on most systems, `link.exe` on MSVC), so it makes sense to provide extra command line arguments, but this will not always be the case. In the future `rustc` may use LLVM directly to link native libraries, in which case `link_args` will have no -meaning. You can achieve the same effect as the `link-args` attribute with the +meaning. You can achieve the same effect as the `link_args` attribute with the `-C link-args` argument to `rustc`. It is highly recommended to *not* use this attribute, and rather use the more @@ -71,7 +71,7 @@ Dynamic linking on Linux can be undesirable if you wish to use new library features on old systems or target systems which do not have the required dependencies for your program to run. -Static linking is supported via an alternative `libc`, `musl`. You can compile +Static linking is supported via an alternative `libc`, [`musl`](http://www.musl-libc.org). You can compile your own version of Rust with `musl` enabled and install it into a custom directory with the instructions below: @@ -94,8 +94,6 @@ $ # Build libunwind.a $ curl -O http://llvm.org/releases/3.7.0/llvm-3.7.0.src.tar.xz $ tar xf llvm-3.7.0.src.tar.xz $ cd llvm-3.7.0.src/projects/ -llvm-3.7.0.src/projects $ curl http://llvm.org/releases/3.7.0/libcxxabi-3.7.0.src.tar.xz | tar xJf - -llvm-3.7.0.src/projects $ mv libcxxabi-3.7.0.src libcxxabi llvm-3.7.0.src/projects $ curl http://llvm.org/releases/3.7.0/libunwind-3.7.0.src.tar.xz | tar xJf - llvm-3.7.0.src/projects $ mv libunwind-3.7.0.src libunwind llvm-3.7.0.src/projects $ mkdir libunwind/build diff --git a/src/doc/trpl/bibliography.md b/src/doc/trpl/bibliography.md index 9659fe4585..ba02053b6b 100644 --- a/src/doc/trpl/bibliography.md +++ b/src/doc/trpl/bibliography.md @@ -48,7 +48,7 @@ Systems Level Language](http://www.cs.indiana.edu/~eholk/papers/hips2013.pdf). Early GPU work by Eric Holk. * [Parallel closures: a new twist on an old idea](https://www.usenix.org/conference/hotpar12/parallel-closures-new-twist-old-idea) - - not exactly about rust, but by nmatsakis + - not exactly about Rust, but by nmatsakis * [Patina: A Formalization of the Rust Programming Language](ftp://ftp.cs.washington.edu/tr/2015/03/UW-CSE-15-03-02.pdf). Early formalization of a subset of the type system, by Eric Reed. @@ -61,8 +61,9 @@ Language](http://www.cs.indiana.edu/~eholk/papers/hips2013.pdf). Early GPU work Rust](http://scialex.github.io/reenix.pdf). Undergrad paper by Alex Light. * [Evaluation of performance and productivity metrics of potential - programming languages in the HPC environment](). Bachelor's thesis by - Florian Wilkens. Compares C, Go and Rust. + programming languages in the HPC environment] + (http://octarineparrot.com/assets/mrfloya-thesis-ba.pdf). + Bachelor's thesis by Florian Wilkens. Compares C, Go and Rust. * [Nom, a byte oriented, streaming, zero copy, parser combinators library in Rust](http://spw15.langsec.org/papers/couprie-nom.pdf). By Geoffroy Couprie, research for VLC. @@ -77,4 +78,5 @@ Language](http://www.cs.indiana.edu/~eholk/papers/hips2013.pdf). Early GPU work Farnstrand's master's thesis. * [Session Types for Rust](http://munksgaard.me/papers/laumann-munksgaard-larsen.pdf). Philip - Munksgaard's master's thesis. Research for Servo. \ No newline at end of file + Munksgaard's master's thesis. Research for Servo. +* [Ownership is Theft: Experiences Building an Embedded OS in Rust - Amit Levy, et. al.](http://amitlevy.com/papers/tock-plos2015.pdf) diff --git a/src/doc/trpl/casting-between-types.md b/src/doc/trpl/casting-between-types.md index dbacd40506..148c55e4b9 100644 --- a/src/doc/trpl/casting-between-types.md +++ b/src/doc/trpl/casting-between-types.md @@ -82,7 +82,7 @@ unsafe { with: ```text -error: transmute called on types with different sizes: [u8; 4] (32 bits) to u64 +error: transmute called with differently sized types: [u8; 4] (32 bits) to u64 (64 bits) ``` diff --git a/src/doc/trpl/choosing-your-guarantees.md b/src/doc/trpl/choosing-your-guarantees.md index b86ad47feb..d9e92de8d9 100644 --- a/src/doc/trpl/choosing-your-guarantees.md +++ b/src/doc/trpl/choosing-your-guarantees.md @@ -204,7 +204,7 @@ borrow checker. Generally we know that such mutations won't happen in a nested f to check. For large, complicated programs, it becomes useful to put some things in `RefCell`s to make things -simpler. For example, a lot of the maps in [the `ctxt` struct][ctxt] in the rust compiler internals +simpler. For example, a lot of the maps in [the `ctxt` struct][ctxt] in the Rust compiler internals are inside this wrapper. These are only modified once (during creation, which is not right after initialization) or a couple of times in well-separated places. However, since this struct is pervasively used everywhere, juggling mutable and immutable pointers would be hard (perhaps @@ -321,7 +321,7 @@ there's a lot of concurrent access happening. # Composition -A common gripe when reading Rust code is with types like `Rc>>` (or even more more +A common gripe when reading Rust code is with types like `Rc>>` (or even more complicated compositions of such types). It's not always clear what the composition does, or why the author chose one like this (and when one should be using such a composition in one's own code) diff --git a/src/doc/trpl/closures.md b/src/doc/trpl/closures.md index 161c4ce90b..7d4452a4c8 100644 --- a/src/doc/trpl/closures.md +++ b/src/doc/trpl/closures.md @@ -1,9 +1,10 @@ % Closures -Rust not only has named functions, but anonymous functions as well. Anonymous -functions that have an associated environment are called ‘closures’, because they -close over an environment. Rust has a really great implementation of them, as -we’ll see. +Sometimes it is useful to wrap up a function and _free variables_ for better +clarity and reuse. The free variables that can be used come from the +enclosing scope and are ‘closed over’ when used in the function. From this, we +get the name ‘closures’ and Rust provides a really great implementation of +them, as we’ll see. # Syntax @@ -34,7 +35,7 @@ assert_eq!(4, plus_two(2)); ``` You’ll notice a few things about closures that are a bit different from regular -functions defined with `fn`. The first is that we did not need to +named functions defined with `fn`. The first is that we did not need to annotate the types of arguments the closure takes or the values it returns. We can: @@ -44,14 +45,15 @@ let plus_one = |x: i32| -> i32 { x + 1 }; assert_eq!(2, plus_one(1)); ``` -But we don’t have to. Why is this? Basically, it was chosen for ergonomic reasons. -While specifying the full type for named functions is helpful with things like -documentation and type inference, the types of closures are rarely documented -since they’re anonymous, and they don’t cause the kinds of error-at-a-distance -problems that inferring named function types can. +But we don’t have to. Why is this? Basically, it was chosen for ergonomic +reasons. While specifying the full type for named functions is helpful with +things like documentation and type inference, the full type signatures of +closures are rarely documented since they’re anonymous, and they don’t cause +the kinds of error-at-a-distance problems that inferring named function types +can. -The second is that the syntax is similar, but a bit different. I’ve added spaces -here for easier comparison: +The second is that the syntax is similar, but a bit different. I’ve added +spaces here for easier comparison: ```rust fn plus_one_v1 (x: i32) -> i32 { x + 1 } @@ -63,8 +65,8 @@ Small differences, but they’re similar. # Closures and their environment -Closures are called such because they ‘close over their environment’. It -looks like this: +The environment for a closure can include bindings from its enclosing scope in +addition to parameters and local bindings. It looks like this: ```rust let num = 5; @@ -197,9 +199,10 @@ frame. Without `move`, a closure may be tied to the stack frame that created it, while a `move` closure is self-contained. This means that you cannot generally return a non-`move` closure from a function, for example. -But before we talk about taking and returning closures, we should talk some more -about the way that closures are implemented. As a systems language, Rust gives -you tons of control over what your code does, and closures are no different. +But before we talk about taking and returning closures, we should talk some +more about the way that closures are implemented. As a systems language, Rust +gives you tons of control over what your code does, and closures are no +different. # Closure implementation @@ -288,9 +291,9 @@ isn’t interesting. The next part is: # some_closure(1) } ``` -Because `Fn` is a trait, we can bound our generic with it. In this case, our closure -takes a `i32` as an argument and returns an `i32`, and so the generic bound we use -is `Fn(i32) -> i32`. +Because `Fn` is a trait, we can bound our generic with it. In this case, our +closure takes a `i32` as an argument and returns an `i32`, and so the generic +bound we use is `Fn(i32) -> i32`. There’s one other key point here: because we’re bounding a generic with a trait, this will get monomorphized, and therefore, we’ll be doing static @@ -411,8 +414,9 @@ fn factory() -> &(Fn(i32) -> i32) { ``` Right. Because we have a reference, we need to give it a lifetime. But -our `factory()` function takes no arguments, so elision doesn’t kick in -here. What lifetime can we choose? `'static`: +our `factory()` function takes no arguments, so +[elision](lifetimes.html#lifetime-elision) doesn’t kick in here. Then what +choices do we have? Try `'static`: ```rust,ignore fn factory() -> &'static (Fn(i32) -> i32) { @@ -432,7 +436,7 @@ But we get another error: ```text error: mismatched types: expected `&'static core::ops::Fn(i32) -> i32`, - found `[closure :7:9: 7:20]` + found `[closure@:7:9: 7:20]` (expected &-ptr, found closure) [E0308] |x| x + num @@ -441,21 +445,17 @@ error: mismatched types: ``` This error is letting us know that we don’t have a `&'static Fn(i32) -> i32`, -we have a `[closure :7:9: 7:20]`. Wait, what? +we have a `[closure@:7:9: 7:20]`. Wait, what? Because each closure generates its own environment `struct` and implementation of `Fn` and friends, these types are anonymous. They exist just solely for -this closure. So Rust shows them as `closure `, rather than some +this closure. So Rust shows them as `closure@`, rather than some autogenerated name. -But why doesn’t our closure implement `&'static Fn`? Well, as we discussed before, -closures borrow their environment. And in this case, our environment is based -on a stack-allocated `5`, the `num` variable binding. So the borrow has a lifetime -of the stack frame. So if we returned this closure, the function call would be -over, the stack frame would go away, and our closure is capturing an environment -of garbage memory! - -So what to do? This _almost_ works: +The error also points out that the return type is expected to be a reference, +but what we are trying to return is not. Further, we cannot directly assign a +`'static` lifetime to an object. So we'll take a different approach and return +a ‘trait object’ by `Box`ing up the `Fn`. This _almost_ works: ```rust,ignore fn factory() -> Box i32> { @@ -471,7 +471,7 @@ assert_eq!(6, answer); # } ``` -We use a trait object, by `Box`ing up the `Fn`. There’s just one last problem: +There’s just one last problem: ```text error: closure may outlive the current function, but it borrows `num`, @@ -480,8 +480,12 @@ Box::new(|x| x + num) ^~~~~~~~~~~ ``` -We still have a reference to the parent stack frame. With one last fix, we can -make this work: +Well, as we discussed before, closures borrow their environment. And in this +case, our environment is based on a stack-allocated `5`, the `num` variable +binding. So the borrow has a lifetime of the stack frame. So if we returned +this closure, the function call would be over, the stack frame would go away, +and our closure is capturing an environment of garbage memory! With one last +fix, we can make this work: ```rust fn factory() -> Box i32> { diff --git a/src/doc/trpl/compiler-plugins.md b/src/doc/trpl/compiler-plugins.md index ffa8be5ac0..e1c9825111 100644 --- a/src/doc/trpl/compiler-plugins.md +++ b/src/doc/trpl/compiler-plugins.md @@ -170,13 +170,25 @@ starting point for an improved quasiquote as an ordinary plugin library. Plugins can extend [Rust's lint infrastructure](../reference.html#lint-check-attributes) with additional checks for -code style, safety, etc. You can see -[`src/test/auxiliary/lint_plugin_test.rs`](https://github.com/rust-lang/rust/blob/master/src/test/auxiliary/lint_plugin_test.rs) -for a full example, the core of which is reproduced here: +code style, safety, etc. Now let's write a plugin [`lint_plugin_test.rs`](https://github.com/rust-lang/rust/blob/master/src/test/auxiliary/lint_plugin_test.rs) +that warns about any item named `lintme`. ```ignore -declare_lint!(TEST_LINT, Warn, - "Warn about items named 'lintme'"); +#![feature(plugin_registrar)] +#![feature(box_syntax, rustc_private)] + +extern crate syntax; + +// Load rustc as a plugin to get macros +#[macro_use] +extern crate rustc; + +use rustc::lint::{EarlyContext, LintContext, LintPass, EarlyLintPass, + EarlyLintPassObject, LintArray}; +use rustc::plugin::Registry; +use syntax::ast; + +declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'"); struct Pass; @@ -184,9 +196,11 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(TEST_LINT) } +} - fn check_item(&mut self, cx: &Context, it: &ast::Item) { - if it.ident.name == "lintme" { +impl EarlyLintPass for Pass { + fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) { + if it.ident.name.as_str() == "lintme" { cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'"); } } @@ -194,7 +208,7 @@ impl LintPass for Pass { #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { - reg.register_lint_pass(box Pass as LintPassObject); + reg.register_early_lint_pass(box Pass as EarlyLintPassObject); } ``` diff --git a/src/doc/trpl/concurrency.md b/src/doc/trpl/concurrency.md index e00fe75013..7b3f13a3ed 100644 --- a/src/doc/trpl/concurrency.md +++ b/src/doc/trpl/concurrency.md @@ -26,8 +26,8 @@ to help us make sense of code that can possibly be concurrent. ### `Send` The first trait we're going to talk about is -[`Send`](../std/marker/trait.Send.html). When a type `T` implements `Send`, it indicates -to the compiler that something of this type is able to have ownership transferred +[`Send`](../std/marker/trait.Send.html). When a type `T` implements `Send`, it +indicates that something of this type is able to have ownership transferred safely between threads. This is important to enforce certain restrictions. For example, if we have a @@ -35,20 +35,28 @@ channel connecting two threads, we would want to be able to send some data down the channel and to the other thread. Therefore, we'd ensure that `Send` was implemented for that type. -In the opposite way, if we were wrapping a library with FFI that isn't +In the opposite way, if we were wrapping a library with [FFI][ffi] that isn't threadsafe, we wouldn't want to implement `Send`, and so the compiler will help us enforce that it can't leave the current thread. +[ffi]: ffi.html + ### `Sync` The second of these traits is called [`Sync`](../std/marker/trait.Sync.html). -When a type `T` implements `Sync`, it indicates to the compiler that something +When a type `T` implements `Sync`, it indicates that something of this type has no possibility of introducing memory unsafety when used from -multiple threads concurrently. - -For example, sharing immutable data with an atomic reference count is -threadsafe. Rust provides a type like this, `Arc`, and it implements `Sync`, -so it is safe to share between threads. +multiple threads concurrently through shared references. This implies that +types which don't have [interior mutability](mutability.html) are inherently +`Sync`, which includes simple primitive types (like `u8`) and aggregate types +containing them. + +For sharing references across threads, Rust provides a wrapper type called +`Arc`. `Arc` implements `Send` and `Sync` if and only if `T` implements +both `Send` and `Sync`. For example, an object of type `Arc>` cannot +be transferred across threads because +[`RefCell`](choosing-your-guarantees.html#refcellt) does not implement +`Sync`, consequently `Arc>` would not implement `Send`. These two traits allow you to use the type system to make strong guarantees about the properties of your code under concurrency. Before we demonstrate @@ -70,7 +78,7 @@ fn main() { } ``` -The `thread::spawn()` method accepts a closure, which is executed in a +The `thread::spawn()` method accepts a [closure](closures.html), which is executed in a new thread. It returns a handle to the thread, that can be used to wait for the child thread to finish and extract its result: @@ -142,7 +150,7 @@ owners! So, we need some type that lets us have more than one reference to a value and that we can share between threads, that is it must implement `Sync`. -We'll use `Arc`, rust's standard atomic reference count type, which +We'll use `Arc`, Rust's standard atomic reference count type, which wraps a value up with some extra runtime bookkeeping which allows us to share the ownership of the value between multiple references at the same time. @@ -189,7 +197,7 @@ our value if it's immutable, but we want to be able to mutate it, so we need something else to persuade the borrow checker we know what we're doing. It looks like we need some type that allows us to safely mutate a shared value, -for example a type that that can ensure only one thread at a time is able to +for example a type that can ensure only one thread at a time is able to mutate the value inside it at any one time. For that, we can use the `Mutex` type! @@ -215,29 +223,18 @@ fn main() { } ``` +Note that the value of `i` is bound (copied) to the closure and not shared +among the threads. -If we'd tried to use `Mutex` without wrapping it in an `Arc` we would have -seen another error like: - -```text -error: the trait `core::marker::Send` is not implemented for the type `std::sync::mutex::MutexGuard<'_, collections::vec::Vec>` [E0277] - thread::spawn(move || { - ^~~~~~~~~~~~~ -note: `std::sync::mutex::MutexGuard<'_, collections::vec::Vec>` cannot be sent between threads safely - thread::spawn(move || { - ^~~~~~~~~~~~~ -``` - -You see, [`Mutex`](../std/sync/struct.Mutex.html) has a -[`lock`](../std/sync/struct.Mutex.html#method.lock) -method which has this signature: +Also note that [`lock`](../std/sync/struct.Mutex.html#method.lock) method of +[`Mutex`](../std/sync/struct.Mutex.html) has this signature: ```ignore fn lock(&self) -> LockResult> ``` -and because `Send` is not implemented for `MutexGuard`, we couldn't have -transferred the guard across thread boundaries on it's own. +and because `Send` is not implemented for `MutexGuard`, the guard cannot +cross thread boundaries, ensuring thread-locality of lock acquire and release. Let's examine the body of the thread more closely: @@ -317,22 +314,24 @@ use std::sync::mpsc; fn main() { let (tx, rx) = mpsc::channel(); - for _ in 0..10 { + for i in 0..10 { let tx = tx.clone(); thread::spawn(move || { - let answer = 42; + let answer = i * i; tx.send(answer); }); } - rx.recv().ok().expect("Could not receive answer"); + for _ in 0..10 { + println!("{}", rx.recv().unwrap()); + } } ``` -A `u32` is `Send` because we can make a copy. So we create a thread, ask it to calculate -the answer, and then it `send()`s us the answer over the channel. +Here we create 10 threads, asking each to calculate the square of a number (`i` +at the time of `spawn()`), and then `send()` back the answer over the channel. ## Panics diff --git a/src/doc/trpl/conditional-compilation.md b/src/doc/trpl/conditional-compilation.md index a944b852d2..a6ff75db89 100644 --- a/src/doc/trpl/conditional-compilation.md +++ b/src/doc/trpl/conditional-compilation.md @@ -34,7 +34,7 @@ These can nest arbitrarily: As for how to enable or disable these switches, if you’re using Cargo, they get set in the [`[features]` section][features] of your `Cargo.toml`: -[features]: http://doc.crates.io/manifest.html#the-%5Bfeatures%5D-section +[features]: http://doc.crates.io/manifest.html#the-features-section ```toml [features] diff --git a/src/doc/trpl/crates-and-modules.md b/src/doc/trpl/crates-and-modules.md index 1c5115117c..4a4648c7b5 100644 --- a/src/doc/trpl/crates-and-modules.md +++ b/src/doc/trpl/crates-and-modules.md @@ -563,8 +563,8 @@ What's going on here? First, both `extern crate` and `use` allow renaming the thing that is being imported. So the crate is still called "phrases", but here we will refer to it as "sayings". Similarly, the first `use` statement pulls in the -`japanese::farewells` module from the crate, but makes it available as -`jp_farewells` as opposed to simply `farewells`. This can help to avoid +`japanese::greetings` module from the crate, but makes it available as +`ja_greetings` as opposed to simply `greetings`. This can help to avoid ambiguity when importing similarly-named items from different places. The second `use` statement uses a star glob to bring in _all_ symbols from the @@ -576,11 +576,13 @@ The third `use` statement bears more explanation. It's using "brace expansion" globbing to compress three `use` statements into one (this sort of syntax may be familiar if you've written Linux shell scripts before). The uncompressed form of this statement would be: + ```rust,ignore use sayings::english; use sayings::english::greetings as en_greetings; use sayings::english::farewells as en_farewells; ``` + As you can see, the curly brackets compress `use` statements for several items under the same path, and in this context `self` just refers back to that path. Note: The curly brackets cannot be nested or mixed with star globbing. diff --git a/src/doc/trpl/custom-allocators.md b/src/doc/trpl/custom-allocators.md new file mode 100644 index 0000000000..c38d0dde51 --- /dev/null +++ b/src/doc/trpl/custom-allocators.md @@ -0,0 +1,170 @@ +% Custom Allocators + +Allocating memory isn't always the easiest thing to do, and while Rust generally +takes care of this by default it often becomes necessary to customize how +allocation occurs. The compiler and standard library currently allow switching +out the default global allocator in use at compile time. The design is currently +spelled out in [RFC 1183][rfc] but this will walk you through how to get your +own allocator up and running. + +[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1183-swap-out-jemalloc.md + +# Default Allocator + +The compiler currently ships two default allocators: `alloc_system` and +`alloc_jemalloc` (some targets don't have jemalloc, however). These allocators +are just normal Rust crates and contain an implementation of the routines to +allocate and deallocate memory. The standard library is not compiled assuming +either one, and the compiler will decide which allocator is in use at +compile-time depending on the type of output artifact being produced. + +Binaries generated by the compiler will use `alloc_jemalloc` by default (where +available). In this situation the compiler "controls the world" in the sense of +it has power over the final link. Primarily this means that the allocator +decision can be left up the compiler. + +Dynamic and static libraries, however, will use `alloc_system` by default. Here +Rust is typically a 'guest' in another application or another world where it +cannot authoritatively decide what allocator is in use. As a result it resorts +back to the standard APIs (e.g. `malloc` and `free`) for acquiring and releasing +memory. + +# Switching Allocators + +Although the compiler's default choices may work most of the time, it's often +necessary to tweak certain aspects. Overriding the compiler's decision about +which allocator is in use is done simply by linking to the desired allocator: + +```rust,no_run +#![feature(alloc_system)] + +extern crate alloc_system; + +fn main() { + let a = Box::new(4); // allocates from the system allocator + println!("{}", a); +} +``` + +In this example the binary generated will not link to jemalloc by default but +instead use the system allocator. Conversely to generate a dynamic library which +uses jemalloc by default one would write: + +```rust,ignore +#![feature(alloc_jemalloc)] +#![crate_type = "dylib"] + +extern crate alloc_jemalloc; + +pub fn foo() { + let a = Box::new(4); // allocates from jemalloc + println!("{}", a); +} +# fn main() {} +``` + +# Writing a custom allocator + +Sometimes even the choices of jemalloc vs the system allocator aren't enough and +an entirely new custom allocator is required. In this you'll write your own +crate which implements the allocator API (e.g. the same as `alloc_system` or +`alloc_jemalloc`). As an example, let's take a look at a simplified and +annotated version of `alloc_system` + +```rust,no_run +# // only needed for rustdoc --test down below +# #![feature(lang_items)] +// The compiler needs to be instructed that this crate is an allocator in order +// to realize that when this is linked in another allocator like jemalloc should +// not be linked in +#![feature(allocator)] +#![allocator] + +// Allocators are not allowed to depend on the standard library which in turn +// requires an allocator in order to avoid circular dependencies. This crate, +// however, can use all of libcore. +#![feature(no_std)] +#![no_std] + +// Let's give a unique name to our custom allocator +#![crate_name = "my_allocator"] +#![crate_type = "rlib"] + +// Our system allocator will use the in-tree libc crate for FFI bindings. Note +// that currently the external (crates.io) libc cannot be used because it links +// to the standard library (e.g. `#![no_std]` isn't stable yet), so that's why +// this specifically requires the in-tree version. +#![feature(libc)] +extern crate libc; + +// Listed below are the five allocation functions currently required by custom +// allocators. Their signatures and symbol names are not currently typechecked +// by the compiler, but this is a future extension and are required to match +// what is found below. +// +// Note that the standard `malloc` and `realloc` functions do not provide a way +// to communicate alignment so this implementation would need to be improved +// with respect to alignment in that aspect. + +#[no_mangle] +pub extern fn __rust_allocate(size: usize, _align: usize) -> *mut u8 { + unsafe { libc::malloc(size as libc::size_t) as *mut u8 } +} + +#[no_mangle] +pub extern fn __rust_deallocate(ptr: *mut u8, _old_size: usize, _align: usize) { + unsafe { libc::free(ptr as *mut libc::c_void) } +} + +#[no_mangle] +pub extern fn __rust_reallocate(ptr: *mut u8, _old_size: usize, size: usize, + _align: usize) -> *mut u8 { + unsafe { + libc::realloc(ptr as *mut libc::c_void, size as libc::size_t) as *mut u8 + } +} + +#[no_mangle] +pub extern fn __rust_reallocate_inplace(_ptr: *mut u8, old_size: usize, + _size: usize, _align: usize) -> usize { + old_size // this api is not supported by libc +} + +#[no_mangle] +pub extern fn __rust_usable_size(size: usize, _align: usize) -> usize { + size +} + +# // just needed to get rustdoc to test this +# fn main() {} +# #[lang = "panic_fmt"] fn panic_fmt() {} +# #[lang = "eh_personality"] fn eh_personality() {} +# #[lang = "eh_unwind_resume"] extern fn eh_unwind_resume() {} +``` + +After we compile this crate, it can be used as follows: + +```rust,ignore +extern crate my_allocator; + +fn main() { + let a = Box::new(8); // allocates memory via our custom allocator crate + println!("{}", a); +} +``` + +# Custom allocator limitations + +There are a few restrictions when working with custom allocators which may cause +compiler errors: + +* Any one artifact may only be linked to at most one allocator. Binaries, + dylibs, and staticlibs must link to exactly one allocator, and if none have + been explicitly chosen the compiler will choose one. On the other hand rlibs + do not need to link to an allocator (but still can). + +* A consumer of an allocator is tagged with `#![needs_allocator]` (e.g. the + `liballoc` crate currently) and an `#[allocator]` crate cannot transitively + depend on a crate which needs an allocator (e.g. circular dependencies are not + allowed). This basically means that allocators must restrict themselves to + libcore currently. diff --git a/src/doc/trpl/dining-philosophers.md b/src/doc/trpl/dining-philosophers.md index 9539cd3447..e81ae4648a 100644 --- a/src/doc/trpl/dining-philosophers.md +++ b/src/doc/trpl/dining-philosophers.md @@ -13,7 +13,7 @@ Hoare in 1985. > dining room, furnished with a circular table, surrounded by five chairs, each > labelled by the name of the philosopher who was to sit in it. They sat > anticlockwise around the table. To the left of each philosopher there was -> laid a golden fork, and in the centre stood a large bowl of spaghetti, which +> laid a golden fork, and in the center stood a large bowl of spaghetti, which > was constantly replenished. A philosopher was expected to spend most of > their time thinking; but when they felt hungry, they went to the dining > room, sat down in their own chair, picked up their own fork on their left, @@ -45,7 +45,7 @@ Now, let’s imagine this sequence of events: 6. ... ? All the forks are taken, but nobody can eat! There are different ways to solve this problem. We’ll get to our solution in -the tutorial itself. For now, let’s get started modelling the problem itself. +the tutorial itself. For now, let’s get started modeling the problem itself. We’ll start with the philosophers: ```rust @@ -434,7 +434,7 @@ ownership of the values it’s capturing. Primarily, the `p` variable of the Inside the thread, all we do is call `eat()` on `p`. Also note that the call to `thread::spawn` lacks a trailing semicolon, making this an expression. This distinction is important, yielding the correct return value. For more details, read [Expressions vs. Statements][es]. -[es]: functions.html#expressions-vs.-statements +[es]: functions.html#expressions-vs-statements ```rust,ignore }).collect(); @@ -512,6 +512,7 @@ impl Philosopher { fn eat(&self, table: &Table) { let _left = table.forks[self.left].lock().unwrap(); + thread::sleep_ms(150); let _right = table.forks[self.right].lock().unwrap(); println!("{} is eating.", self.name); @@ -597,6 +598,7 @@ We now need to construct those `left` and `right` values, so we add them to ```rust,ignore fn eat(&self, table: &Table) { let _left = table.forks[self.left].lock().unwrap(); + thread::sleep_ms(150); let _right = table.forks[self.right].lock().unwrap(); println!("{} is eating.", self.name); @@ -607,11 +609,14 @@ fn eat(&self, table: &Table) { } ``` -We have two new lines. We’ve also added an argument, `table`. We access the +We have three new lines. We’ve added an argument, `table`. We access the `Table`’s list of forks, and then use `self.left` and `self.right` to access the fork at that particular index. That gives us access to the `Mutex` at that index, and we call `lock()` on it. If the mutex is currently being accessed by -someone else, we’ll block until it becomes available. +someone else, we’ll block until it becomes available. We have also a call to +`thread::sleep_ms` between the moment first fork is picked and the moment the +second forked is picked, as the process of picking up the fork is not +immediate. The call to `lock()` might fail, and if it does, we want to crash. In this case, the error that could happen is that the mutex is [‘poisoned’][poison], @@ -660,7 +665,9 @@ We need to pass in our `left` and `right` values to the constructors for our you look at the pattern, it’s all consistent until the very end. Monsieur Foucault should have `4, 0` as arguments, but instead, has `0, 4`. This is what prevents deadlock, actually: one of our philosophers is left handed! This is -one way to solve the problem, and in my opinion, it’s the simplest. +one way to solve the problem, and in my opinion, it’s the simplest. If you +change the order of the parameters, you will be able to observe the deadlock +taking place. ```rust,ignore let handles: Vec<_> = philosophers.into_iter().map(|p| { diff --git a/src/doc/trpl/documentation.md b/src/doc/trpl/documentation.md index 0a471beb43..e101d4bc0d 100644 --- a/src/doc/trpl/documentation.md +++ b/src/doc/trpl/documentation.md @@ -45,7 +45,7 @@ Rust keeps track of these comments, and uses them when generating documentation. This is important when documenting things like enums: ```rust -/// The `Option` type. See [the module level documentation](../) for more. +/// The `Option` type. See [the module level documentation](index.html) for more. enum Option { /// No value None, @@ -57,7 +57,7 @@ enum Option { The above works, but this does not: ```rust,ignore -/// The `Option` type. See [the module level documentation](../) for more. +/// The `Option` type. See [the module level documentation](index.html) for more. enum Option { None, /// No value Some(T), /// Some value `T` @@ -73,7 +73,7 @@ hello.rs:4 } ``` This [unfortunate error](https://github.com/rust-lang/rust/issues/22547) is -correct: documentation comments apply to the thing after them, and there's +correct: documentation comments apply to the thing after them, and there's nothing after that last comment. [rc-new]: https://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.new @@ -213,7 +213,7 @@ Let's discuss our sample example documentation: ``` You'll notice that you don't need a `fn main()` or anything here. `rustdoc` will -automatically add a main() wrapper around your code, and in the right place. +automatically add a `main()` wrapper around your code, and in the right place. For example: ```rust @@ -234,7 +234,7 @@ fn main() { } ``` -Here's the full algorithm rustdoc uses to postprocess examples: +Here's the full algorithm rustdoc uses to preprocess examples: 1. Any leading `#![foo]` attributes are left intact as crate attributes. 2. Some common `allow` attributes are inserted, including @@ -269,45 +269,21 @@ documentation comment, I need to add a little function definition below it. At the same time, it's just there to satisfy the compiler, so hiding it makes the example more clear. You can use this technique to explain longer examples in detail, while still preserving the testability of your -documentation. For example, this code: - -```rust -let x = 5; -let y = 6; -println!("{}", x + y); -``` - -Here's an explanation, rendered: +documentation. -First, we set `x` to five: +For example, imagine that we wanted to document this code: ```rust let x = 5; -# let y = 6; -# println!("{}", x + y); -``` - -Next, we set `y` to six: - -```rust -# let x = 5; let y = 6; -# println!("{}", x + y); -``` - -Finally, we print the sum of `x` and `y`: - -```rust -# let x = 5; -# let y = 6; println!("{}", x + y); ``` -Here's the same explanation, in raw text: +We might want the documentation to end up looking like this: > First, we set `x` to five: > -> ```text +> ```rust > let x = 5; > # let y = 6; > # println!("{}", x + y); @@ -315,7 +291,7 @@ Here's the same explanation, in raw text: > > Next, we set `y` to six: > -> ```text +> ```rust > # let x = 5; > let y = 6; > # println!("{}", x + y); @@ -323,12 +299,42 @@ Here's the same explanation, in raw text: > > Finally, we print the sum of `x` and `y`: > -> ```text +> ```rust > # let x = 5; > # let y = 6; > println!("{}", x + y); > ``` +To keep each code block testable, we want the whole program in each block, but +we don't want the reader to see every line every time. Here's what we put in +our source code: + +```text + First, we set `x` to five: + + ```text + let x = 5; + # let y = 6; + # println!("{}", x + y); + ``` + + Next, we set `y` to six: + + ```text + # let x = 5; + let y = 6; + # println!("{}", x + y); + ``` + + Finally, we print the sum of `x` and `y`: + + ```text + # let x = 5; + # let y = 6; + println!("{}", x + y); + ``` +``` + By repeating all parts of the example, you can ensure that your example still compiles, while only showing the parts that are relevant to that part of your explanation. @@ -369,7 +375,7 @@ things, so they don’t show up in the output. ### Running documentation tests -To run the tests, either +To run the tests, either: ```bash $ rustdoc --test path/to/my/crate/root.rs @@ -494,7 +500,8 @@ This `%` line needs to be the very first line of the file. ## `doc` attributes -At a deeper level, documentation comments are sugar for documentation attributes: +At a deeper level, documentation comments are syntactic sugar for documentation +attributes: ```rust /// this @@ -509,7 +516,7 @@ are the same, as are these: ```rust //! this -#![doc="/// this"] +#![doc="this"] ``` You won't often see this attribute used for writing documentation, but it @@ -525,7 +532,7 @@ extern crate foo; pub use foo::bar; ``` -This will create documentation for bar both inside the documentation for the +This will create documentation for `bar` both inside the documentation for the crate `foo`, as well as the documentation for your crate. It will use the same documentation in both places. @@ -538,6 +545,38 @@ extern crate foo; pub use foo::bar; ``` +## Missing documentation + +Sometimes you want to make sure that every single public thing in your project +is documented, especially when you are working on a library. Rust allows you to +to generate warnings or errors, when an item is missing documentation. +To generate warnings you use `warn`: + +```rust +#![warn(missing_docs)] +``` + +And to generate errors you use `deny`: + +```rust,ignore +#![deny(missing_docs)] +``` + +There are cases where you want to disable these warnings/errors to explicitly +leave something undocumented. This is done by using `allow`: + +```rust +#[allow(missing_docs)] +struct Undocumented; +``` + +You might even want to hide items from the documentation completely: + +```rust +#[doc(hidden)] +struct Hidden; +``` + ### Controlling HTML You can control a few aspects of the HTML that `rustdoc` generates through the diff --git a/src/doc/trpl/error-handling.md b/src/doc/trpl/error-handling.md index 673dc950ec..56dfa17b4e 100644 --- a/src/doc/trpl/error-handling.md +++ b/src/doc/trpl/error-handling.md @@ -87,6 +87,8 @@ thread '
' panicked at 'Invalid number: 11', src/bin/panic-simple.rs:5 Here's another example that is slightly less contrived. A program that accepts an integer as an argument, doubles it and prints it. + + ```rust,should_panic use std::env; @@ -120,10 +122,9 @@ It would be better if we just showed the code for unwrapping because it is so simple, but to do that, we will first need to explore the `Option` and `Result` types. Both of these types have a method called `unwrap` defined on them. -## The `Option` type +### The `Option` type -The `Option` type is -[defined in the standard library][1]: +The `Option` type is [defined in the standard library][5]: ```rust enum Option { @@ -138,6 +139,8 @@ system is an important concept because it will cause the compiler to force the programmer to handle that absence. Let's take a look at an example that tries to find a character in a string: + + ```rust // Searches `haystack` for the Unicode character `needle`. If one is found, the // byte offset of the character is returned. Otherwise, `None` is returned. @@ -151,7 +154,7 @@ fn find(haystack: &str, needle: char) -> Option { } ``` -Notice that when this function finds a matching character, it doen't just +Notice that when this function finds a matching character, it doesn't just return the `offset`. Instead, it returns `Some(offset)`. `Some` is a variant or a *value constructor* for the `Option` type. You can think of it as a function with the type `fn(value: T) -> Option`. Correspondingly, `None` is also a @@ -179,10 +182,12 @@ analysis is the only way to get at the value stored inside an `Option`. This means that you, as the programmer, must handle the case when an `Option` is `None` instead of `Some(t)`. -But wait, what about `unwrap` used in [`unwrap-double`](#code-unwrap-double)? +But wait, what about `unwrap`,which we used [`previously`](#code-unwrap-double)? There was no case analysis there! Instead, the case analysis was put inside the `unwrap` method for you. You could define it yourself if you want: + + ```rust enum Option { None, @@ -206,7 +211,7 @@ that makes `unwrap` ergonomic to use. Unfortunately, that `panic!` means that ### Composing `Option` values -In [`option-ex-string-find`](#code-option-ex-string-find-2) +In an [example from before](#code-option-ex-string-find), we saw how to use `find` to discover the extension in a file name. Of course, not all file names have a `.` in them, so it's possible that the file name has no extension. This *possibility of absence* is encoded into the types using @@ -220,7 +225,7 @@ sense to put it into a function: ```rust # fn find(_: &str, _: char) -> Option { None } // Returns the extension of the given file name, where the extension is defined -// as all characters proceding the first `.`. +// as all characters proceeding the first `.`. // If `file_name` has no `.`, then `None` is returned. fn extension_explicit(file_name: &str) -> Option<&str> { match find(file_name, '.') { @@ -248,6 +253,8 @@ option is `None`, in which case, just return `None`. Rust has parametric polymorphism, so it is very easy to define a combinator that abstracts this pattern: + + ```rust fn map(option: Option, f: F) -> Option where F: FnOnce(T) -> A { match option { @@ -265,18 +272,18 @@ to get rid of the case analysis: ```rust # fn find(_: &str, _: char) -> Option { None } // Returns the extension of the given file name, where the extension is defined -// as all characters proceding the first `.`. +// as all characters proceeding the first `.`. // If `file_name` has no `.`, then `None` is returned. fn extension(file_name: &str) -> Option<&str> { find(file_name, '.').map(|i| &file_name[i+1..]) } ``` -One other pattern that we find is very common is assigning a default value to -the case when an `Option` value is `None`. For example, maybe your program -assumes that the extension of a file is `rs` even if none is present. As you -might imagine, the case analysis for this is not specific to file -extensions - it can work with any `Option`: +One other pattern we commonly find is assigning a default value to the case +when an `Option` value is `None`. For example, maybe your program assumes that +the extension of a file is `rs` even if none is present. As you might imagine, +the case analysis for this is not specific to file extensions - it can work +with any `Option`: ```rust fn unwrap_or(option: Option, default: T) -> T { @@ -387,6 +394,8 @@ remove choices because they will panic if `Option` is `None`. The `Result` type is also [defined in the standard library][6]: + + ```rust enum Result { Ok(T), @@ -553,7 +562,7 @@ combinators that affect only the error type, such as ### The `Result` type alias idiom In the standard library, you may frequently see types like -`Result`. But wait, [we defined `Result`](#code-result-def-1) to +`Result`. But wait, [we defined `Result`](#code-result-def) to have two type parameters. How can we get away with only specifying one? The key is to define a `Result` type alias that *fixes* one of the type parameters to a particular type. Usually the fixed type is @@ -663,6 +672,8 @@ with both an `Option` and a `Result`, the solution is *usually* to convert the (from `env::args()`) means the user didn't invoke the program correctly. We could just use a `String` to describe the error. Let's try: + + ```rust use std::env; @@ -744,7 +755,7 @@ fn main() { (N.B. The `AsRef` is used because those are the [same bounds used on `std::fs::File::open`](../std/fs/struct.File.html#method.open). -This makes it ergnomic to use any kind of string as a file path.) +This makes it ergonomic to use any kind of string as a file path.) There are three different errors that can occur here: @@ -829,7 +840,7 @@ example, the very last call to `map` multiplies the `Ok(...)` value (which is an `i32`) by `2`. If an error had occurred before that point, this operation would have been skipped because of how `map` is defined. -`map_err` is the trick the makes all of this work. `map_err` is just like +`map_err` is the trick that makes all of this work. `map_err` is just like `map`, except it applies a function to the `Err(...)` value of a `Result`. In this case, we want to convert all of our errors to one type: `String`. Since both `io::Error` and `num::ParseIntError` implement `ToString`, we can call the @@ -895,6 +906,8 @@ seen above. Here is a simplified definition of a `try!` macro: + + ```rust macro_rules! try { ($e:expr) => (match $e { @@ -1155,6 +1168,8 @@ The `std::convert::From` trait is [defined in the standard library](../std/convert/trait.From.html): + + ```rust trait From { fn from(T) -> Self; @@ -1208,7 +1223,7 @@ let err2: Box = From::from(parse_err); There is a really important pattern to recognize here. Both `err1` and `err2` have the *same type*. This is because they are existentially quantified types, -or trait objects. In particularly, their underlying type is *erased* from the +or trait objects. In particular, their underlying type is *erased* from the compiler's knowledge, so it truly sees `err1` and `err2` as exactly the same. Additionally, we constructed `err1` and `err2` using precisely the same function call: `From::from`. This is because `From::from` is overloaded on both @@ -1232,9 +1247,11 @@ macro_rules! try { } ``` -This is not it's real definition. It's real definition is +This is not its real definition. Its real definition is [in the standard library](../std/macro.try!.html): + + ```rust macro_rules! try { ($e:expr) => (match $e { @@ -1267,7 +1284,7 @@ fn file_double>(file_path: P) -> Result { Earlier, we promised that we could get rid of the `map_err` calls. Indeed, all we have to do is pick a type that `From` works with. As we saw in the previous -section, `From` has an impl that let's it convert any error type into a +section, `From` has an impl that lets it convert any error type into a `Box`: ```rust @@ -1498,7 +1515,7 @@ and [`rustc-serialize`](https://crates.io/crates/rustc-serialize) crates. We're not going to spend a lot of time on setting up a project with Cargo because it is already covered well in [the Cargo -chapter](../book/hello-cargo) and [Cargo's documentation][14]. +chapter](../book/hello-cargo.html) and [Cargo's documentation][14]. To get started from scratch, run `cargo new --bin city-pop` and make sure your `Cargo.toml` looks something like this: @@ -1528,14 +1545,14 @@ cargo build --release ## Argument parsing -Let's get argument parsing out of the way. we won't go into too much +Let's get argument parsing out of the way. We won't go into too much detail on Getopts, but there is [some good documentation][15] describing it. The short story is that Getopts generates an argument parser and a help message from a vector of options (The fact that it is a vector is hidden behind a struct and a set of methods). Once the parsing is done, we can decode the program arguments into a Rust struct. From there, we can get information about the flags, for -instance, wether they were passed in, and what arguments they +instance, whether they were passed in, and what arguments they had. Here's our program with the appropriate `extern crate` statements, and the basic argument setup for Getopts: @@ -1556,7 +1573,7 @@ fn main() { let mut opts = Options::new(); opts.optflag("h", "help", "Show this usage message."); - + let matches = match opts.parse(&args[1..]) { Ok(m) => { m } Err(e) => { panic!(e.to_string()) } @@ -1567,7 +1584,7 @@ fn main() { } let data_path = args[1].clone(); let city = args[2].clone(); - + // Do stuff with information } ``` @@ -1577,7 +1594,7 @@ then store the first one, knowing that it is our program's name. Once that's done, we set up our argument flags, in this case a simplistic help message flag. Once we have the argument flags set up, we use `Options.parse` to parse the argument vector (starting from index one, -becouse index 0 is the program name). If this was successful, we +because index 0 is the program name). If this was successful, we assign matches to the parsed object, if not, we panic. Once past that, we test if the user passed in the help flag, and if so print the usage message. The option help messages are constructed by Getopts, so all @@ -1630,27 +1647,27 @@ fn main() { let mut opts = Options::new(); opts.optflag("h", "help", "Show this usage message."); - + let matches = match opts.parse(&args[1..]) { Ok(m) => { m } Err(e) => { panic!(e.to_string()) } }; - + if matches.opt_present("h") { print_usage(&program, opts); return; } - + let data_file = args[1].clone(); let data_path = Path::new(&data_file); let city = args[2].clone(); - + let file = fs::File::open(data_path).unwrap(); let mut rdr = csv::Reader::from_reader(file); - + for row in rdr.decode::() { let row = row.unwrap(); - + if row.city == city { println!("{}, {}: {:?}", row.city, row.country, @@ -1756,7 +1773,7 @@ fn main() { print_usage(&program, opts); return; } - + let data_file = args[1].clone(); let data_path = Path::new(&data_file); let city = args[2].clone(); @@ -1838,7 +1855,7 @@ In our program, we accept a single file for input and do one pass over the data. This means we probably should be able to accept input on stdin. But maybe we like the current format too—so let's have both! -Adding support for stdin is actually quite easy. There are only two things we +Adding support for stdin is actually quite easy. There are only three things we have to do: 1. Tweak the program arguments so that a single parameter—the @@ -1865,7 +1882,7 @@ opts.optflag("h", "help", "Show this usage message."); ... let file = matches.opt_str("f"); let data_file = file.as_ref().map(Path::new); - + let city = if !matches.free.is_empty() { matches.free[0].clone() } else { @@ -1879,9 +1896,9 @@ for pop in search(&data_file, &city) { ... ``` -In this peice of code, we take `file` (which has the type +In this piece of code, we take `file` (which has the type `Option`), and convert it to a type that `search` can use, in -this case, `&Option>`. Do do this, we take a reference of +this case, `&Option>`. To do this, we take a reference of file, and map `Path::new` onto it. In this case, `as_ref()` converts the `Option` into an `Option<&str>`, and from there, we can execute `Path::new` to the content of the optional, and return the @@ -2040,14 +2057,14 @@ so. This can be a little clumsy, especially if you intend for the program to be used in shell scripts. So let's start by adding the flags. Like before, we need to tweak the usage -string and add a flag to the Option variable. Once were done that, Getopts does the rest: +string and add a flag to the Option variable. Once we've done that, Getopts does the rest: ```rust,ignore ... let mut opts = Options::new(); opts.optopt("f", "file", "Choose an input file, instead of using STDIN.", "NAME"); opts.optflag("h", "help", "Show this usage message."); -opts.optflag("q", "quit", "Silences errors and warnings."); +opts.optflag("q", "quiet", "Silences errors and warnings."); ... ``` @@ -2103,7 +2120,7 @@ heuristics! and [`Error`](../std/error/trait.Error.html) impls to make the [`try!`](../std/macro.try!.html) - macro more ergnomic. + macro more ergonomic. * If you're writing a library and your code can produce errors, define your own error type and implement the [`std::error::Error`](../std/error/trait.Error.html) diff --git a/src/doc/trpl/getting-started.md b/src/doc/trpl/getting-started.md index d0825e543f..549f8c3ca5 100644 --- a/src/doc/trpl/getting-started.md +++ b/src/doc/trpl/getting-started.md @@ -1,5 +1,5 @@ % Getting Started -This first section of the book will get you going with Rust and its tooling. +This first section of the book will get us going with Rust and its tooling. First, we’ll install Rust. Then, the classic ‘Hello World’ program. Finally, we’ll talk about Cargo, Rust’s build system and package manager. diff --git a/src/doc/trpl/glossary.md b/src/doc/trpl/glossary.md index 6a5a45fdb2..0956580ade 100644 --- a/src/doc/trpl/glossary.md +++ b/src/doc/trpl/glossary.md @@ -38,11 +38,19 @@ let z = (8, 2, 6); In the example above `x` and `y` have arity 2. `z` has arity 3. +### Bounds + +Bounds are constraints on a type or [trait][traits]. For example, if a bound +is placed on the argument a function takes, types passed to that function +must abide by that constraint. + +[traits]: traits.html + ### DST (Dynamically Sized Type) A type without a statically known size or alignment. ([more info][link]) -[link]: ../nomicon/exotic-sizes.html#dynamically-sized-types-(dsts) +[link]: ../nomicon/exotic-sizes.html#dynamically-sized-types-dsts ### Expression diff --git a/src/doc/trpl/guessing-game.md b/src/doc/trpl/guessing-game.md index 4a35022b03..db484a28cb 100644 --- a/src/doc/trpl/guessing-game.md +++ b/src/doc/trpl/guessing-game.md @@ -99,9 +99,12 @@ use std::io; We’ll need to take user input, and then print the result as output. As such, we need the `io` library from the standard library. Rust only imports a few things by default into every program, [the ‘prelude’][prelude]. If it’s not in the -prelude, you’ll have to `use` it directly. +prelude, you’ll have to `use` it directly. There is also a second ‘prelude’, the +[`io` prelude][ioprelude], which serves a similar function: you import it, and it +imports a number of useful, `io`-related things. [prelude]: ../std/prelude/index.html +[ioprelude]: ../std/io/prelude/index.html ```rust,ignore fn main() { @@ -147,7 +150,7 @@ a few tricks up their sleeves. For example, they’re [immutable][immutable] by default. That’s why our example uses `mut`: it makes a binding mutable, rather than immutable. `let` doesn’t -take a name on the left hand side, it actually accepts a +take a name on the left hand side of the assignment, it actually accepts a ‘[pattern][patterns]’. We’ll use patterns later. It’s easy enough to use for now: @@ -599,7 +602,7 @@ With this definition, anything of type `Foo` can be either a `Foo::Bar` or a `Foo::Baz`. We use the `::` to indicate the namespace for a particular `enum` variant. -The [`Ordering`][ordering] enum has three possible variants: `Less`, `Equal`, +The [`Ordering`][ordering] `enum` has three possible variants: `Less`, `Equal`, and `Greater`. The `match` statement takes a value of a type, and lets you create an ‘arm’ for each possible value. Since we have three types of `Ordering`, we have three arms: @@ -918,9 +921,9 @@ let guess: u32 = match guess.trim().parse() { This is how you generally move from ‘crash on error’ to ‘actually handle the error’, by switching from `ok().expect()` to a `match` statement. The `Result` -returned by `parse()` is an enum just like `Ordering`, but in this case, each +returned by `parse()` is an `enum` just like `Ordering`, but in this case, each variant has some data associated with it: `Ok` is a success, and `Err` is a -failure. Each contains more information: the successful parsed integer, or an +failure. Each contains more information: the successfully parsed integer, or an error type. In this case, we `match` on `Ok(num)`, which sets the inner value of the `Ok` to the name `num`, and then we just return it on the right-hand side. In the `Err` case, we don’t care what kind of error it is, so we just diff --git a/src/doc/trpl/hello-cargo.md b/src/doc/trpl/hello-cargo.md index 4bd7de23f0..b155a4287e 100644 --- a/src/doc/trpl/hello-cargo.md +++ b/src/doc/trpl/hello-cargo.md @@ -7,15 +7,16 @@ so it is assumed that Rust projects will use Cargo from the beginning. [cratesio]: http://doc.crates.io -Cargo manages three things: building your code, downloading the dependencies -your code needs, and building those dependencies. At first, your program doesn’t -have any dependencies, so we’ll only be using the first part of its -functionality. Eventually, we’ll add more. Since we started off by using Cargo, -it'll be easy to add later. +Cargo manages three things: building our code, downloading the dependencies our +code needs, and building those dependencies. At first, our program doesn’t have +any dependencies, so we’ll only be using the first part of its functionality. +Eventually, we’ll add more. Since we started off by using Cargo, it'll be easy +to add later. -If we installed Rust via the official installers we will also have Cargo. If we -installed Rust some other way, we may want to [check the Cargo -README][cargoreadme] for specific instructions about installing it. +If you installed Rust via the official installers you will also have Cargo. If +you installed Rust some other way, you may want to +[check the Cargo README][cargoreadme] for specific instructions about installing +it. [cargoreadme]: https://github.com/rust-lang/cargo#installing-cargo-from-nightlies @@ -30,29 +31,29 @@ old executable (`main.exe` on Windows, `main` everywhere else). Let's do that pa ```bash $ mkdir src $ mv main.rs src/main.rs -$ rm main # or main.exe on Windows +$ rm main # or 'rm main.exe' on Windows ``` -Note that since we're creating an executable, we retain `main.rs` as the source -filename. If we want to make a library instead, we should use `lib.rs`. This -convention is used by Cargo to successfully compile our projects, but it can be -overridden if we wish. Custom file locations for the entry point can be -specified with a [`[lib]` or `[[bin]]`][crates-custom] key in the TOML file. +> Note: since we're creating an executable, we retain `main.rs` as the source +> filename. If we want to make a library instead, we should use `lib.rs`. This +> convention is used by Cargo to successfully compile our projects, but it can +> be overridden if we wish. Custom file locations for the entry point can be +> specified with a [`[lib]` or `[[bin]]`][crates-custom] key in the TOML file. [crates-custom]: http://doc.crates.io/manifest.html#configuring-a-target -Cargo expects your source files to live inside a `src` directory. That leaves -the top level for other things, like READMEs, license information, and anything -not related to your code. Cargo helps us keep our projects nice and tidy. A -place for everything, and everything in its place. +Cargo expects our source files to live inside a `src` directory. That leaves the +top level for other things, like READMEs, license information, and anything not +related to our code. Cargo helps us keep our projects nice and tidy. A place for +everything, and everything in its place. Next, our configuration file: ```bash -$ editor Cargo.toml +$ editor Cargo.toml # or 'notepad Cargo.toml' on Windows ``` -Make sure to get this name right: you need the capital `C`! +Make sure to get this name right: we need the capital `C`! Put this inside: @@ -109,8 +110,8 @@ about the future: when our project gets more complex, we need to do more things to get all of the parts to properly compile. With Cargo, as our project grows, we can just run `cargo build`, and it’ll work the right way. -When your project is finally ready for release, you can use -`cargo build --release` to compile your project with optimizations. +When our project is finally ready for release, we can use `cargo build +--release` to compile our project with optimizations. You'll also notice that Cargo has created a new file: `Cargo.lock`. @@ -120,14 +121,14 @@ name = "hello_world" version = "0.0.1" ``` -The `Cargo.lock` file is used by Cargo to keep track of dependencies in your application. -Right now, we don’t have any, so it’s a bit sparse. You won't ever need -to touch this file yourself, just let Cargo handle it. +The `Cargo.lock` file is used by Cargo to keep track of dependencies in our +application. Right now, we don’t have any, so it’s a bit sparse. We won't ever +need to touch this file ourselves, just let Cargo handle it. That’s it! We’ve successfully built `hello_world` with Cargo. Even though our -program is simple, it’s using much of the real tooling that you’ll use for the -rest of your Rust career. You can expect to do this to get started with -virtually all Rust projects: +program is simple, it’s using much of the real tooling that we’ll use for the +rest of our Rust career. We can expect to do this to get started with virtually +all Rust projects: ```bash $ git clone someurl.com/foo @@ -137,17 +138,19 @@ $ cargo build ## A New Project -You don’t have to go through this whole process every time you want to start a -new project! Cargo has the ability to make a bare-bones project directory in -which you can start developing right away. +We don’t have to go through this whole process every time we want to start a new +project! Cargo has the ability to make a bare-bones project directory in which +we can start developing right away. -To start a new project with Cargo, use `cargo new`: +To start a new project with Cargo, we use `cargo new`: ```bash $ cargo new hello_world --bin ``` -We’re passing `--bin` because our goal is to get straight to making an executable application, as opposed to a library. Executables are often called ‘binaries.’ (as in `/usr/bin`, if you’re on a Unix system) +We’re passing `--bin` because our goal is to get straight to making an +executable application, as opposed to a library. Executables are often called +‘binaries.’ (as in `/usr/bin`, if we’re on a Unix system) Let's check out what Cargo has generated for us: @@ -162,7 +165,7 @@ $ tree . 1 directory, 2 files ``` -If you don't have the `tree` command, you can probably get it from your +If we don't have the `tree` command, we can probably get it from our distribution’s package manager. It’s not necessary, but it’s certainly useful. This is all we need to get started. First, let’s check out `Cargo.toml`: @@ -176,7 +179,7 @@ authors = ["Your Name "] ``` Cargo has populated this file with reasonable defaults based off the arguments -you gave it and your `git` global configuration. You may notice that Cargo has +we gave it and our `git` global configuration. You may notice that Cargo has also initialized the `hello_world` directory as a `git` repository. Here’s what’s in `src/main.rs`: @@ -187,20 +190,21 @@ fn main() { } ``` -Cargo has generated a "Hello World!" for us, and you’re ready to start coding! Cargo -has its own [guide][guide] which covers Cargo’s features in much more depth. +Cargo has generated a "Hello World!" for us, and we’re ready to start coding! +Cargo has its own [guide][guide] which covers Cargo’s features in much more +depth. [guide]: http://doc.crates.io/guide.html -Now that you’ve got the tools down, let’s actually learn more about the Rust -language itself. These are the basics that will serve you well through the rest -of your time with Rust. +Now that we’ve got the tools down, let’s actually learn more about the Rust +language itself. These are the basics that will serve us well through the rest +of our time with Rust. You have two options: Dive into a project with ‘[Learn Rust][learnrust]’, or -start from the bottom and work your way up with ‘[Syntax and -Semantics][syntax]’. More experienced systems programmers will probably prefer -‘Learn Rust’, while those from dynamic backgrounds may enjoy either. Different -people learn differently! Choose whatever’s right for you. +start from the bottom and work your way up with +‘[Syntax and Semantics][syntax]’. More experienced systems programmers will +probably prefer ‘Learn Rust’, while those from dynamic backgrounds may enjoy +either. Different people learn differently! Choose whatever’s right for you. [learnrust]: learn-rust.html [syntax]: syntax-and-semantics.html diff --git a/src/doc/trpl/hello-world.md b/src/doc/trpl/hello-world.md index cd4326a28d..2f9166751d 100644 --- a/src/doc/trpl/hello-world.md +++ b/src/doc/trpl/hello-world.md @@ -1,25 +1,25 @@ % Hello, world! -Now that you have Rust installed, let’s write your first Rust program. It’s -traditional to make your first program in any new language one that prints the +Now that we have Rust installed, let’s write our first Rust program. It’s +traditional to make our first program in any new language one that prints the text “Hello, world!” to the screen. The nice thing about starting with such a -simple program is that you can verify that your compiler isn’t just installed, -but also working properly. And printing information to the screen is a pretty -common thing to do. +simple program is that we can verify that our compiler isn’t just installed, but +also working properly. And printing information to the screen is a pretty common +thing to do. -The first thing that we need to do is make a file to put our code in. I like -to make a `projects` directory in my home directory, and keep all my projects -there. Rust does not care where your code lives. +The first thing that we need to do is make a file to put our code in. I like to +make a `projects` directory in my home directory, and keep all my projects +there. Rust doesn't care where our code lives. This actually leads to one other concern we should address: this guide will -assume that you have basic familiarity with the command line. Rust itself makes -no specific demands on your editing tooling, or where your code lives. If you -prefer an IDE to the command line, you may want to check out -[SolidOak][solidoak], or wherever plugins are for your favorite IDE. There are -a number of extensions of varying quality in development by the community. The -Rust team also ships [plugins for various editors][plugins]. Configuring your +assume that we have basic familiarity with the command line. Rust itself makes +no specific demands on our editing tooling, or where our code lives. If we +prefer an IDE to the command line, we may want to check out +[SolidOak][solidoak], or wherever plugins are for our favorite IDE. There are a +number of extensions of varying quality in development by the community. The +Rust team also ships [plugins for various editors][plugins]. Configuring our editor or IDE is out of the scope of this tutorial, so check the documentation -for your setup, specifically. +for our setup, specifically. [solidoak]: https://github.com/oakes/SolidOak [plugins]: https://github.com/rust-lang/rust/blob/master/src/etc/CONFIGS.md @@ -33,14 +33,15 @@ $ mkdir hello_world $ cd hello_world ``` -If you’re on Windows and not using PowerShell, the `~` may not work. Consult -the documentation for your shell for more details. +If we’re on Windows and not using PowerShell, the `~` may not work. Consult the +documentation for our shell for more details. Let’s make a new source file next. We’ll call our file `main.rs`. Rust files -always end in a `.rs` extension. If you’re using more than one word in your -filename, use an underscore: `hello_world.rs` rather than `helloworld.rs`. +always end in a `.rs` extension, and if we’re using more than one word in a +Rust filename, we use an underscore: for example, `linked_list.rs`, not +`linkedlist.rs` or `LinkedList.rs`. -Now that you’ve got your file open, type this in: +Now that we’ve got our file open, type this in: ```rust fn main() { @@ -48,7 +49,7 @@ fn main() { } ``` -Save the file, and then type this into your terminal window: +Save the file, and then type this into our terminal window: ```bash $ rustc main.rs @@ -72,9 +73,9 @@ we aren’t returning anything from this function, we can omit the return type entirely. We’ll get to it later. You’ll also note that the function is wrapped in curly braces (`{` and `}`). -Rust requires these around all function bodies. It is also considered good -style to put the opening curly brace on the same line as the function -declaration, with one space in between. +Rust requires these around all function bodies. It is also considered good style +to put the opening curly brace on the same line as the function declaration, +with one space in between. Next up is this line: @@ -85,29 +86,30 @@ Next up is this line: This line does all of the work in our little program. There are a number of details that are important here. The first is that it’s indented with four spaces, not tabs. Please configure your editor of choice to insert four spaces -with the tab key. We provide some [sample configurations for various -editors][configs]. +with the tab key. We provide some +[sample configurations for various editors][configs]. [configs]: https://github.com/rust-lang/rust/tree/master/src/etc/CONFIGS.md -The second point is the `println!()` part. This is calling a Rust [macro][macro], -which is how metaprogramming is done in Rust. If it were a function instead, it -would look like this: `println()`. For our purposes, we don’t need to worry -about this difference. Just know that sometimes, you’ll see a `!`, and that -means that you’re calling a macro instead of a normal function. Rust implements -`println!` as a macro rather than a function for good reasons, but that's an -advanced topic. One last thing to mention: Rust’s macros are significantly -different from C macros, if you’ve used those. Don’t be scared of using macros. -We’ll get to the details eventually, you’ll just have to trust us for now. +The second point is the `println!()` part. This is calling a Rust +[macro][macro], which is how metaprogramming is done in Rust. If it were a +function instead, it would look like this: `println()`. For our purposes, we +don’t need to worry about this difference. Just know that sometimes, we’ll see a +`!`, and that means that we’re calling a macro instead of a normal function. +Rust implements `println!` as a macro rather than a function for good reasons, +but that's an advanced topic. One last thing to mention: Rust’s macros are +significantly different from C macros, if you’ve used those. Don’t be scared of +using macros. We’ll get to the details eventually, you’ll just have to take it +on trust for now. [macro]: macros.html Next, `"Hello, world!"` is a ‘string’. Strings are a surprisingly complicated topic in a systems programming language, and this is a ‘statically allocated’ -string. If you want to read further about allocation, check out -[the stack and the heap][allocation], but you don’t need to right now if you -don’t want to. We pass this string as an argument to `println!`, which prints the -string to the screen. Easy enough! +string. If you want to read further about allocation, check out [the stack and +the heap][allocation], but you don’t need to right now if you don’t want to. We +pass this string as an argument to `println!`, which prints the string to the +screen. Easy enough! [allocation]: the-stack-and-the-heap.html @@ -126,8 +128,8 @@ compiler, `rustc`, by passing it the name of our source file: $ rustc main.rs ``` -This is similar to `gcc` or `clang`, if you come from a C or C++ background. Rust -will output a binary executable. You can see it with `ls`: +This is similar to `gcc` or `clang`, if you come from a C or C++ background. +Rust will output a binary executable. We can see it with `ls`: ```bash $ ls @@ -142,7 +144,7 @@ main.exe main.rs ``` There are now two files: our source code, with the `.rs` extension, and the -executable (`main.exe` on Windows, `main` everywhere else) +executable (`main.exe` on Windows, `main` everywhere else). ```bash $ ./main # or main.exe on Windows @@ -150,20 +152,20 @@ $ ./main # or main.exe on Windows This prints out our `Hello, world!` text to our terminal. -If you come from a dynamic language like Ruby, Python, or JavaScript, -you may not be used to these two steps being separate. Rust is an -‘ahead-of-time compiled language’, which means that you can compile a program, -give it to someone else, and they don't need to have Rust installed. If you -give someone a `.rb` or `.py` or `.js` file, they need to have a -Ruby/Python/JavaScript implementation installed, but you just need one command -to both compile and run your program. Everything is a tradeoff in language -design, and Rust has made its choice. +If you come from a dynamic language like Ruby, Python, or JavaScript, you may +not be used to these two steps being separate. Rust is an ‘ahead-of-time +compiled language’, which means that we can compile a program, give it to +someone else, and they don't need to have Rust installed. If we give someone a +`.rb` or `.py` or `.js` file, they need to have a Ruby/Python/JavaScript +implementation installed, but we just need one command to both compile and run +our program. Everything is a tradeoff in language design, and Rust has made its +choice. Congratulations! You have officially written a Rust program. That makes you a Rust programmer! Welcome. 🎊🎉👍 Next, I'd like to introduce you to another tool, Cargo, which is used to write real-world Rust programs. Just using `rustc` is nice for simple things, but as -your project grows, you'll want something to help you manage all of the options -that it has, and to make it easy to share your code with other people and +our project grows, we'll want something to help us manage all of the options +that it has, and to make it easy to share our code with other people and projects. diff --git a/src/doc/trpl/if-let.md b/src/doc/trpl/if-let.md index 4872ed6a77..faa922acb3 100644 --- a/src/doc/trpl/if-let.md +++ b/src/doc/trpl/if-let.md @@ -41,7 +41,7 @@ If a [pattern][patterns] matches successfully, it binds any appropriate parts of the value to the identifiers in the pattern, then evaluates the expression. If the pattern doesn’t match, nothing happens. -If you’d rather to do something else when the pattern does not match, you can +If you want to do something else when the pattern does not match, you can use `else`: ```rust @@ -65,7 +65,7 @@ loop as long as a value matches a certain pattern. It turns code like this: loop { match option { Some(x) => println!("{}", x), - _ => break, + None => break, } } ``` diff --git a/src/doc/trpl/installing-rust.md b/src/doc/trpl/installing-rust.md index f06005d55b..49ee5317c7 100644 --- a/src/doc/trpl/installing-rust.md +++ b/src/doc/trpl/installing-rust.md @@ -1,21 +1,21 @@ % Installing Rust The first step to using Rust is to install it! There are a number of ways to -install Rust, but the easiest is to use the `rustup` script. If you're on Linux -or a Mac, all you need to do is this: +install Rust, but the easiest is to use the `rustup` script. If we're on Linux +or a Mac, all we need to do is this: -> Note: you don't need to type in the `$`s, they just indicate the start of -> each command. You’ll see many tutorials and examples around the web that -> follow this convention: `$` for commands run as your regular user, and -> `#` for commands you should be running as an administrator. +> Note: we don't need to type in the `$`s, they are there to indicate the start of +> each command. We’ll see many tutorials and examples around the web that +> follow this convention: `$` for commands run as our regular user, and `#` for +> commands we should be running as an administrator. ```bash $ curl -sf -L https://static.rust-lang.org/rustup.sh | sh ``` -If you're concerned about the [potential insecurity][insecurity] of using `curl -| sh`, please keep reading and see our disclaimer below. And feel free to -use a two-step version of the installation and examine our installation script: +If we're concerned about the [potential insecurity][insecurity] of using `curl | +sh`, please keep reading and see our disclaimer below. And feel free to use a +two-step version of the installation and examine our installation script: ```bash $ curl -f -L https://static.rust-lang.org/rustup.sh -O @@ -25,11 +25,12 @@ $ sh rustup.sh [insecurity]: http://curlpipesh.tumblr.com If you're on Windows, please download the appropriate [installer][install-page]. -**NOTE:** By default, the Windows installer will not add Rust to the %PATH% -system variable. If this is the only version of Rust you are installing and you -want to be able to run it from the command line, click on "Advanced" on the -install dialog and on the "Product Features" page ensure "Add to PATH" is -installed on the local hard drive. + +> Note: By default, the Windows installer won't add Rust to the %PATH% system +> variable. If this is the only version of Rust we are installing and we want to +> be able to run it from the command line, click on "Advanced" on the install +> dialog and on the "Product Features" page ensure "Add to PATH" is installed on +> the local hard drive. [install-page]: https://www.rust-lang.org/install.html @@ -37,78 +38,145 @@ installed on the local hard drive. ## Uninstalling If you decide you don't want Rust anymore, we'll be a bit sad, but that's okay. -Not every programming language is great for everyone. Just run the uninstall -script: +Not every programming language is great for everyone. We can run the +uninstall script: ```bash $ sudo /usr/local/lib/rustlib/uninstall.sh ``` -If you used the Windows installer, just re-run the `.msi` and it will give you -an uninstall option. +If we used the Windows installer, we can re-run the `.msi` and it will give +us an uninstall option. ## That disclaimer we promised -Some people, and somewhat rightfully so, get very upset when we tell you to -`curl | sh`. Basically, when you do this, you are trusting that the good -people who maintain Rust aren't going to hack your computer and do bad things. -That's a good instinct! If you're one of those people, please check out the -documentation on [building Rust from Source][from-source], or [the official -binary downloads][install-page]. +Some people, and somewhat rightfully so, get very upset when we tell them to +`curl | sh`. Their concern is that `curl | sh` implicitly requires you to trust +that the good people who maintain Rust aren't going to hack your computer and +do bad things — and even having accepted that, there is still the possibility +that the Rust website has been hacked and the `rustup` script compromised. + +Being wary of such possibilities is a good instinct! If you're uncomfortable +using `curl | sh` for reasons like these, please check out the documentation on +[building Rust from Source][from-source], or +[the official binary downloads][install-page]. [from-source]: https://github.com/rust-lang/rust#building-from-source ## Platform support -Oh, we should also mention the officially supported platforms: - -* Windows (7, 8, Server 2008 R2) -* Linux (2.6.18 or later, various distributions), x86 and x86-64 -* OSX 10.7 (Lion) or greater, x86 and x86-64 - -We extensively test Rust on these platforms, and a few others, too, like -Android. But these are the ones most likely to work, as they have the most -testing. - -Finally, a comment about Windows. Rust considers Windows to be a first-class -platform upon release, but if we're honest, the Windows experience isn't as -integrated as the Linux/OS X experience is. We're working on it! If anything -does not work, it is a bug. Please let us know if that happens. Each and every -commit is tested against Windows just like any other platform. +The Rust compiler runs on, and compiles to, a great number of platforms, though +not all platforms are equally supported. Rust's support levels are organized +into three tiers, each with a different set of guarantees. + +Platforms are identified by their "target triple" which is the string to inform +the compiler what kind of output should be produced. The columns below indicate +whether the corresponding component works on the specified platform. + +### Tier 1 + +Tier 1 platforms can be thought of as "guaranteed to build and work". +Specifically they will each satisfy the following requirements: + +* Automated testing is set up to run tests for the platform. +* Landing changes to the `rust-lang/rust` repository's master branch is gated on + tests passing. +* Official release artifacts are provided for the platform. +* Documentation for how to use and how to build the platform is available. + +| Target | std |rustc|cargo| notes | +|-------------------------------|-----|-----|-----|----------------------------| +| `x86_64-pc-windows-msvc` | ✓ | ✓ | ✓ | 64-bit MSVC (Windows 7+) | +| `i686-pc-windows-gnu` | ✓ | ✓ | ✓ | 32-bit MinGW (Windows 7+) | +| `x86_64-pc-windows-gnu` | ✓ | ✓ | ✓ | 64-bit MinGW (Windows 7+) | +| `i686-apple-darwin` | ✓ | ✓ | ✓ | 32-bit OSX (10.7+, Lion+) | +| `x86_64-apple-darwin` | ✓ | ✓ | ✓ | 64-bit OSX (10.7+, Lion+) | +| `i686-unknown-linux-gnu` | ✓ | ✓ | ✓ | 32-bit Linux (2.6.18+) | +| `x86_64-unknown-linux-gnu` | ✓ | ✓ | ✓ | 64-bit Linux (2.6.18+) | + +### Tier 2 + +Tier 2 platforms can be thought of as "guaranteed to build". Automated tests are +not run so it's not guaranteed to produce a working build, but platforms often +work to quite a good degree and patches are always welcome! Specifically, these +platforms are required to have each of the following: + +* Automated building is set up, but may not be running tests. +* Landing changes to the `rust-lang/rust` repository's master branch is gated on + platforms **building**. Note that this means for some platforms only the + standard library is compiled, but for others the full bootstrap is run. +* Official release artifacts are provided for the platform. + +| Target | std |rustc|cargo| notes | +|-------------------------------|-----|-----|-----|----------------------------| +| `i686-pc-windows-msvc` | ✓ | ✓ | ✓ | 32-bit MSVC (Windows 7+) | + +### Tier 3 + +Tier 3 platforms are those which Rust has support for, but landing changes is +not gated on the platform either building or passing tests. Working builds for +these platforms may be spotty as their reliability is often defined in terms of +community contributions. Additionally, release artifacts and installers are not +provided, but there may be community infrastructure producing these in +unofficial locations. + +| Target | std |rustc|cargo| notes | +|-------------------------------|-----|-----|-----|----------------------------| +| `x86_64-unknown-linux-musl` | ✓ | | | 64-bit Linux with MUSL | +| `arm-linux-androideabi` | ✓ | | | ARM Android | +| `i686-linux-android` | ✓ | | | 32-bit x86 Android | +| `aarch64-linux-android` | ✓ | | | ARM64 Android | +| `arm-unknown-linux-gnueabi` | ✓ | ✓ | | ARM Linux (2.6.18+) | +| `arm-unknown-linux-gnueabihf` | ✓ | ✓ | | ARM Linux (2.6.18+) | +| `aarch64-unknown-linux-gnu` | ✓ | | | ARM64 Linux (2.6.18+) | +| `mips-unknown-linux-gnu` | ✓ | | | MIPS Linux (2.6.18+) | +| `mipsel-unknown-linux-gnu` | ✓ | | | MIPS (LE) Linux (2.6.18+) | +| `powerpc-unknown-linux-gnu` | ✓ | | | PowerPC Linux (2.6.18+) | +| `i386-apple-ios` | ✓ | | | 32-bit x86 iOS | +| `x86_64-apple-ios` | ✓ | | | 64-bit x86 iOS | +| `armv7-apple-ios` | ✓ | | | ARM iOS | +| `armv7s-apple-ios` | ✓ | | | ARM iOS | +| `aarch64-apple-ios` | ✓ | | | ARM64 iOS | +| `i686-unknown-freebsd` | ✓ | ✓ | | 32-bit FreeBSD | +| `x86_64-unknown-freebsd` | ✓ | ✓ | | 64-bit FreeBSD | +| `x86_64-unknown-openbsd` | ✓ | ✓ | | 64-bit OpenBSD | +| `x86_64-unknown-netbsd` | ✓ | ✓ | | 64-bit NetBSD | +| `x86_64-unknown-bitrig` | ✓ | ✓ | | 64-bit Bitrig | +| `x86_64-unknown-dragonfly` | ✓ | ✓ | | 64-bit DragonFlyBSD | +| `x86_64-rumprun-netbsd` | ✓ | | | 64-bit NetBSD Rump Kernel | +| `i686-pc-windows-msvc` (XP) | ✓ | | | Windows XP support | +| `x86_64-pc-windows-msvc` (XP) | ✓ | | | Windows XP support | + +Note that this table can be expanded over time, this isn't the exhaustive set of +tier 3 platforms that will ever be! ## After installation -If you've got Rust installed, you can open up a shell, and type this: +If we've got Rust installed, we can open up a shell, and type this: ```bash $ rustc --version ``` -You should see the version number, commit hash, and commit date. If you just -installed version 1.2.0, you should see: +You should see the version number, commit hash, and commit date. -```bash -rustc 1.2.0 (082e47636 2015-08-03) -``` +If you do, Rust has been installed successfully! Congrats! -If you did, Rust has been installed successfully! Congrats! - -If you didn't and you're on Windows, check that Rust is in your %PATH% system +If you don't and you're on Windows, check that Rust is in your %PATH% system variable. If it isn't, run the installer again, select "Change" on the "Change, repair, or remove installation" page and ensure "Add to PATH" is installed on the local hard drive. -This installer also installs a copy of the documentation locally, so you can -read it offline. On UNIX systems, `/usr/local/share/doc/rust` is the location. -On Windows, it's in a `share/doc` directory, inside wherever you installed Rust -to. - -If not, there are a number of places where you can get help. The easiest is -[the #rust IRC channel on irc.mozilla.org][irc], which you can access through -[Mibbit][mibbit]. Click that link, and you'll be chatting with other Rustaceans -(a silly nickname we call ourselves), and we can help you out. Other great -resources include [the user’s forum][users], and -[Stack Overflow][stackoverflow]. +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. + +If not, there are a number of places where we can get help. The easiest is +[the #rust IRC channel on irc.mozilla.org][irc], which we can access through +[Mibbit][mibbit]. Click that link, and 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]. [irc]: irc://irc.mozilla.org/#rust [mibbit]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust diff --git a/src/doc/trpl/iterators.md b/src/doc/trpl/iterators.md index 1c574f0209..c444f9f2fe 100644 --- a/src/doc/trpl/iterators.md +++ b/src/doc/trpl/iterators.md @@ -42,12 +42,12 @@ loop is just a handy way to write this `loop`/`match`/`break` construct. `for` loops aren't the only thing that uses iterators, however. Writing your own iterator involves implementing the `Iterator` trait. While doing that is outside of the scope of this guide, Rust provides a number of useful iterators -to accomplish various tasks. Before we talk about those, we should talk about a -Rust anti-pattern. And that's using ranges like this. +to accomplish various tasks. But first, a few notes about limitations of ranges. -Yes, we just talked about how ranges are cool. But ranges are also very -primitive. For example, if you needed to iterate over the contents of a vector, -you may be tempted to write this: +Ranges are very primitive, and we often can use better alternatives. Consider the +following Rust anti-pattern: using ranges to emulate a C-style `for` loop. Let’s +suppose you needed to iterate over the contents of a vector. You may be tempted +to write this: ```rust let nums = vec![1, 2, 3]; @@ -101,10 +101,10 @@ So, now that we've established that ranges are often not what you want, let's talk about what you do want instead. There are three broad classes of things that are relevant here: iterators, -*iterator adapters*, and *consumers*. Here's some definitions: +*iterator adaptors*, and *consumers*. Here's some definitions: * *iterators* give you a sequence of values. -* *iterator adapters* operate on an iterator, producing a new iterator with a +* *iterator adaptors* operate on an iterator, producing a new iterator with a different output sequence. * *consumers* operate on an iterator, producing some final set of values. @@ -150,15 +150,16 @@ let greater_than_forty_two = (0..100) .find(|x| *x > 42); match greater_than_forty_two { - Some(_) => println!("We got some numbers!"), - None => println!("No numbers found :("), + Some(_) => println!("Found a match!"), + None => println!("No match found :("), } ``` `find` takes a closure, and works on a reference to each element of an iterator. This closure returns `true` if the element is the element we're -looking for, and `false` otherwise. Because we might not find a matching -element, `find` returns an `Option` rather than the element itself. +looking for, and `false` otherwise. `find` returns the first element satisfying +the specified predicate. Because we might not find a matching element, `find` +returns an `Option` rather than the element itself. Another important consumer is `fold`. Here's what it looks like: @@ -245,12 +246,12 @@ for num in nums.iter() { These two basic iterators should serve you well. There are some more advanced iterators, including ones that are infinite. -That's enough about iterators. Iterator adapters are the last concept +That's enough about iterators. Iterator adaptors are the last concept we need to talk about with regards to iterators. Let's get to it! -## Iterator adapters +## Iterator adaptors -*Iterator adapters* take an iterator and modify it somehow, producing +*Iterator adaptors* take an iterator and modify it somehow, producing a new iterator. The simplest one is called `map`: ```rust,ignore @@ -279,10 +280,9 @@ doesn't print any numbers: If you are trying to execute a closure on an iterator for its side effects, just use `for` instead. -There are tons of interesting iterator adapters. `take(n)` will return an -iterator over the next `n` elements of the original iterator. Note that this -has no side effect on the original iterator. Let's try it out with our infinite -iterator from before: +There are tons of interesting iterator adaptors. `take(n)` will return an +iterator over the next `n` elements of the original iterator. Let's try it out +with an infinite iterator: ```rust for i in (1..).take(5) { @@ -302,7 +302,7 @@ This will print `filter()` is an adapter that takes a closure as an argument. This closure returns `true` or `false`. The new iterator `filter()` produces -only the elements that that closure returns `true` for: +only the elements that the closure returns `true` for: ```rust for i in (1..100).filter(|&x| x % 2 == 0) { @@ -329,7 +329,7 @@ a few times, and then consume the result. Check it out: This will give you a vector containing `6`, `12`, `18`, `24`, and `30`. -This is just a small taste of what iterators, iterator adapters, and consumers +This is just a small taste of what iterators, iterator adaptors, and consumers can help you with. There are a number of really useful iterators, and you can write your own as well. Iterators provide a safe, efficient way to manipulate all kinds of lists. They're a little unusual at first, but if you play with diff --git a/src/doc/trpl/lifetimes.md b/src/doc/trpl/lifetimes.md index 62270cb45b..13265ab1eb 100644 --- a/src/doc/trpl/lifetimes.md +++ b/src/doc/trpl/lifetimes.md @@ -1,6 +1,6 @@ % Lifetimes -This guide is one of three presenting Rust’s ownership system. This is one of +This guide is three of three presenting Rust’s ownership system. This is one of Rust’s most unique and compelling features, with which Rust developers should become quite acquainted. Ownership is how Rust achieves its largest goal, memory safety. There are a few distinct concepts, each with its own chapter: @@ -43,11 +43,11 @@ With that in mind, let’s learn about lifetimes. Lending out a reference to a resource that someone else owns can be complicated. For example, imagine this set of operations: -- I acquire a handle to some kind of resource. -- I lend you a reference to the resource. -- I decide I’m done with the resource, and deallocate it, while you still have +1. I acquire a handle to some kind of resource. +2. I lend you a reference to the resource. +3. I decide I’m done with the resource, and deallocate it, while you still have your reference. -- You decide to use the resource. +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. @@ -70,9 +70,12 @@ fn bar<'a>(x: &'a i32) { ``` The `'a` reads ‘the lifetime a’. Technically, every reference has some lifetime -associated with it, but the compiler lets you elide them in common cases. +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 + ```rust,ignore fn bar<'a>(...) ``` @@ -349,9 +352,9 @@ fn frob<'a, 'b>(s: &'a str, t: &'b str) -> &str; // Expanded: Output lifetime is fn get_mut(&mut self) -> &mut T; // elided fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded -fn args(&mut self, args: &[T]) -> &mut Command // elided -fn args<'a, 'b, T:ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command // expanded +fn args(&mut self, args: &[T]) -> &mut Command; // elided +fn args<'a, 'b, T:ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command; // expanded fn new(buf: &mut [u8]) -> BufWriter; // elided -fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> // expanded +fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a>; // expanded ``` diff --git a/src/doc/trpl/method-syntax.md b/src/doc/trpl/method-syntax.md index a2bdd66b0c..d31d823247 100644 --- a/src/doc/trpl/method-syntax.md +++ b/src/doc/trpl/method-syntax.md @@ -55,7 +55,7 @@ kinds of things `foo` could be: `self` if it’s just a value on the stack, `&self` if it’s a reference, and `&mut self` if it’s a mutable reference. Because we took the `&self` parameter to `area`, we can use it just like any other parameter. Because we know it’s a `Circle`, we can access the `radius` -just like we would with any other `struct`. +just like we would with any other `struct`. We should default to using `&self`, as you should prefer borrowing over taking ownership, as well as taking immutable references over mutable ones. Here’s an diff --git a/src/doc/trpl/mutability.md b/src/doc/trpl/mutability.md index 2c4316e651..71acb551e6 100644 --- a/src/doc/trpl/mutability.md +++ b/src/doc/trpl/mutability.md @@ -84,7 +84,7 @@ philosophy, memory safety, and the mechanism by which Rust guarantees it, the > You may have one or the other of these two kinds of borrows, but not both at > the same time: -> +> > * one or more references (`&T`) to a resource, > * exactly one mutable reference (`&mut T`). diff --git a/src/doc/trpl/no-stdlib.md b/src/doc/trpl/no-stdlib.md index 9abcd33098..5fca05d534 100644 --- a/src/doc/trpl/no-stdlib.md +++ b/src/doc/trpl/no-stdlib.md @@ -4,14 +4,6 @@ By default, `std` is linked to every Rust crate. In some contexts, this is undesirable, and can be avoided with the `#![no_std]` attribute attached to the crate. -```ignore -// a minimal library -#![crate_type="lib"] -#![feature(no_std)] -#![no_std] -# // fn main() {} tricked you, rustdoc! -``` - Obviously there's more to life than just libraries: one can use `#[no_std]` with an executable, controlling the entry point is possible in two ways: the `#[start]` attribute, or overriding the @@ -21,7 +13,10 @@ The function marked `#[start]` is passed the command line parameters in the same format as C: ```rust -#![feature(lang_items, start, no_std, libc)] +# #![feature(libc)] +#![feature(lang_items)] +#![feature(start)] +#![feature(no_std)] #![no_std] // Pull in the system libc library for what crt0.o likely requires @@ -47,11 +42,13 @@ with `#![no_main]` and then create the appropriate symbol with the correct ABI and the correct name, which requires overriding the compiler's name mangling too: -```ignore +```rust +# #![feature(libc)] #![feature(no_std)] +#![feature(lang_items)] +#![feature(start)] #![no_std] #![no_main] -#![feature(lang_items, start)] extern crate libc; @@ -92,19 +89,24 @@ instead. The core library has very few dependencies and is much more portable than the standard library itself. Additionally, the core library has most of the -necessary functionality for writing idiomatic and effective Rust code. +necessary functionality for writing idiomatic and effective Rust code. When +using `#![no_std]`, Rust will automatically inject the `core` crate, just like +we do for `std` when we’re using it. As an example, here is a program that will calculate the dot product of two vectors provided from C, using idiomatic Rust practices. -```ignore -#![feature(lang_items, start, no_std, core, libc)] +```rust +# #![feature(libc)] +#![feature(lang_items)] +#![feature(start)] +#![feature(no_std)] +#![feature(core)] +#![feature(core_slice_ext)] +#![feature(raw)] #![no_std] -# extern crate libc; -extern crate core; - -use core::prelude::*; +extern crate libc; use core::mem; diff --git a/src/doc/trpl/ownership.md b/src/doc/trpl/ownership.md index 5ddbdd6df0..d8ef44b782 100644 --- a/src/doc/trpl/ownership.md +++ b/src/doc/trpl/ownership.md @@ -42,7 +42,7 @@ With that in mind, let’s learn about ownership. # Ownership [Variable bindings][bindings] have a property in Rust: they ‘have ownership’ -of what they’re bound to. This means that when a binding goes out of scope, +of what they’re bound to. This means that when a binding goes out of scope, Rust will free the bound resources. For example: ```rust @@ -158,8 +158,8 @@ has no pointers to data somewhere else, copying it is a full copy. All primitive types implement the `Copy` trait and their ownership is therefore not moved like one would assume, following the ´ownership rules´. -To give an example, the two following snippets of code only compile because the -`i32` and `bool` types implement the `Copy` trait. +To give an example, the two following snippets of code only compile because the +`i32` and `bool` types implement the `Copy` trait. ```rust fn main() { @@ -236,13 +236,3 @@ complicated. Luckily, Rust offers a feature, borrowing, which helps us solve this problem. It’s the topic of the next section! - - - - - - - - - - diff --git a/src/doc/trpl/patterns.md b/src/doc/trpl/patterns.md index a365732fe9..8f4a7a4395 100644 --- a/src/doc/trpl/patterns.md +++ b/src/doc/trpl/patterns.md @@ -23,6 +23,31 @@ match x { This prints `one`. +There’s one pitfall with patterns: like anything that introduces a new binding, +they introduce shadowing. For example: + +```rust +let x = 'x'; +let c = 'c'; + +match c { + x => println!("x: {} c: {}", x, c), +} + +println!("x: {}", x) +``` + +This prints: + +```text +x: c c: c +x: x +``` + +In other words, `x =>` matches the pattern and introduces a new binding named +`x` that’s in scope for the match arm. Because we already have a binding named +`x`, this new `x` shadows it. + # Multiple patterns You can match multiple patterns with `|`: @@ -299,7 +324,7 @@ match x { ``` This prints `no`, because the `if` applies to the whole of `4 | 5`, and not to -just the `5`, In other words, the the precedence of `if` behaves like this: +just the `5`. In other words, the precedence of `if` behaves like this: ```text (4 | 5) if y => ... diff --git a/src/doc/trpl/primitive-types.md b/src/doc/trpl/primitive-types.md index 027909dd05..a8c7a7d415 100644 --- a/src/doc/trpl/primitive-types.md +++ b/src/doc/trpl/primitive-types.md @@ -162,13 +162,18 @@ A ‘slice’ is a reference to (or “view” into) another data structure. The useful for allowing safe, efficient access to a portion of an array without copying. For example, you might want to reference just one line of a file read into memory. By nature, a slice is not created directly, but from an existing -variable. Slices have a length, can be mutable or not, and in many ways behave -like arrays: +variable binding. Slices have a defined length, can be mutable or immutable. + +## Slicing syntax + +You can use a combo of `&` and `[]` to create a slice from various things. The +`&` indicates that slices are similar to references, and the `[]`s, with a +range, let you define the length of the slice: ```rust let a = [0, 1, 2, 3, 4]; -let middle = &a[1..4]; // A slice of a: just the elements 1, 2, and 3 let complete = &a[..]; // A slice containing all of the elements in a +let middle = &a[1..4]; // A slice of a: just the elements 1, 2, and 3 ``` Slices have type `&[T]`. We’ll talk about that `T` when we cover diff --git a/src/doc/trpl/raw-pointers.md b/src/doc/trpl/raw-pointers.md index 8a3b98b729..679f5489ea 100644 --- a/src/doc/trpl/raw-pointers.md +++ b/src/doc/trpl/raw-pointers.md @@ -98,16 +98,15 @@ these properties are true for any references, no matter how they are created, and so any conversion from raw pointers is asserting that they hold. The programmer *must* guarantee this. -The recommended method for the conversion is +The recommended method for the conversion is: ```rust -let i: u32 = 1; - // explicit cast +let i: u32 = 1; let p_imm: *const u32 = &i as *const u32; -let mut m: u32 = 2; // implicit coercion +let mut m: u32 = 2; let p_mut: *mut u32 = &mut m; unsafe { diff --git a/src/doc/trpl/references-and-borrowing.md b/src/doc/trpl/references-and-borrowing.md index 50297b266d..13cfecdf1a 100644 --- a/src/doc/trpl/references-and-borrowing.md +++ b/src/doc/trpl/references-and-borrowing.md @@ -1,6 +1,6 @@ % References and Borrowing -This guide is one of three presenting Rust’s ownership system. This is one of +This guide is two of three presenting Rust’s ownership system. This is one of Rust’s most unique and compelling features, with which Rust developers should become quite acquainted. Ownership is how Rust achieves its largest goal, memory safety. There are a few distinct concepts, each with its own @@ -233,7 +233,7 @@ So when we add the curly braces: ```rust let mut x = 5; -{ +{ let y = &mut x; // -+ &mut borrow starts here *y += 1; // | } // -+ ... and ends here @@ -306,7 +306,7 @@ which was invalid. For example: ```rust,ignore let y: &i32; -{ +{ let x = 5; y = &x; } @@ -323,7 +323,7 @@ error: `x` does not live long enough note: reference must be valid for the block suffix following statement 0 at 2:16... let y: &i32; -{ +{ let x = 5; y = &x; } @@ -363,7 +363,7 @@ note: reference must be valid for the block suffix following statement 0 at let y: &i32; let x = 5; y = &x; - + println!("{}", y); } @@ -371,7 +371,7 @@ note: ...but borrowed value is only valid for the block suffix following statement 1 at 3:14 let x = 5; y = &x; - + println!("{}", y); } ``` diff --git a/src/doc/trpl/rust-inside-other-languages.md b/src/doc/trpl/rust-inside-other-languages.md index 8dd2e365aa..5c0bde02f9 100644 --- a/src/doc/trpl/rust-inside-other-languages.md +++ b/src/doc/trpl/rust-inside-other-languages.md @@ -108,7 +108,7 @@ fn process() { let handles: Vec<_> = (0..10).map(|_| { thread::spawn(|| { let mut x = 0; - for _ in (0..5_000_000) { + for _ in 0..5_000_000 { x += 1 } x @@ -119,7 +119,6 @@ fn process() { println!("Thread finished with count={}", h.join().map_err(|_| "Could not join a thread!").unwrap()); } - println!("done!"); } ``` diff --git a/src/doc/trpl/strings.md b/src/doc/trpl/strings.md index aa1944a099..1848366498 100644 --- a/src/doc/trpl/strings.md +++ b/src/doc/trpl/strings.md @@ -102,8 +102,8 @@ println!(""); This prints: ```text -229, 191, 160, 231, 138, 172, 227, 131, 143, 227, 131, 129, 229, 133, 172, -忠, 犬, ハ, チ, 公, +229, 191, 160, 231, 138, 172, 227, 131, 143, 227, 131, 129, 229, 133, 172, +忠, 犬, ハ, チ, 公, ``` As you can see, there are more bytes than `char`s. diff --git a/src/doc/trpl/structs.md b/src/doc/trpl/structs.md index 85b11d0b6b..b51ad8e087 100644 --- a/src/doc/trpl/structs.md +++ b/src/doc/trpl/structs.md @@ -184,6 +184,8 @@ You can define a `struct` with no members at all: ```rust struct Electron; + +let x = Electron; ``` Such a `struct` is called ‘unit-like’ because it resembles the empty diff --git a/src/doc/trpl/syntax-index.md b/src/doc/trpl/syntax-index.md new file mode 100644 index 0000000000..7e03bb72ca --- /dev/null +++ b/src/doc/trpl/syntax-index.md @@ -0,0 +1,229 @@ +% Syntax Index + +## Keywords + +* `as`: primitive casting. See [Casting Between Types (`as`)]. +* `break`: break out of loop. See [Loops (Ending Iteration Early)]. +* `const`: constant items. See [`const` and `static`]. +* `continue`: continue to next loop iteration. See [Loops (Ending Iteration Early)]. +* `crate`: external crate linkage. See [Crates and Modules (Importing External Crates)]. +* `else`: fallback for `if` and `if let` constructs. See [`if`], [`if let`]. +* `enum`: defining enumeration. See [Enums]. +* `extern`: external crate, function, and variable linkage. See [Crates and Modules (Importing External Crates)], [Foreign Function Interface]. +* `false`: boolean false literal. See [Primitive Types (Booleans)]. +* `fn`: function definition and function pointer types. See [Functions]. +* `for`: iterator loop, part of trait `impl` syntax, and higher-ranked lifetime syntax. See [Loops (`for`)], [Method Syntax]. +* `if`: conditional branching. See [`if`], [`if let`]. +* `impl`: inherent and trait implementation blocks. See [Method Syntax]. +* `in`: part of `for` loop syntax. See [Loops (`for`)]. +* `let`: variable binding. See [Variable Bindings]. +* `loop`: unconditional, infinite loop. See [Loops (`loop`)]. +* `match`: pattern matching. See [Match]. +* `mod`: module declaration. See [Crates and Modules (Defining Modules)]. +* `move`: part of closure syntax. See [Closures (`move` closures)]. +* `mut`: denotes mutability in pointer types and pattern bindings. See [Mutability]. +* `pub`: denotes public visibility in `struct` fields, `impl` blocks, and modules. See [Crates and Modules (Exporting a Public Interface)]. +* `ref`: by-reference binding. See [Patterns (`ref` and `ref mut`)]. +* `return`: return from function. See [Functions (Early Returns)]. +* `Self`: implementor type alias. See [Traits]. +* `self`: method subject. See [Method Syntax (Method Calls)]. +* `static`: global variable. See [`const` and `static` (`static`)]. +* `struct`: structure definition. See [Structs]. +* `trait`: trait definition. See [Traits]. +* `true`: boolean true literal. See [Primitive Types (Booleans)]. +* `type`: type alias, and associated type definition. See [`type` Aliases], [Associated Types]. +* `unsafe`: denotes unsafe code, functions, traits, and implementations. See [Unsafe]. +* `use`: import symbols into scope. See [Crates and Modules (Importing Modules with `use`)]. +* `where`: type constraint clauses. See [Traits (`where` clause)]. +* `while`: conditional loop. See [Loops (`while`)]. + +## Operators and Symbols + +* `!` (`expr!(…)`, `expr!{…}`, `expr![…]`): denotes macro expansion. See [Macros]. +* `!` (`!expr`): bitwise or logical complement. Overloadable (`Not`). +* `%` (`expr % expr`): arithmetic remainder. Overloadable (`Rem`). +* `%=` (`var %= expr`): arithmetic remainder & assignment. +* `&` (`expr & expr`): bitwise and. Overloadable (`BitAnd`). +* `&` (`&expr`): borrow. See [References and Borrowing]. +* `&` (`&type`, `&mut type`, `&'a type`, `&'a mut type`): borrowed pointer type. See [References and Borrowing]. +* `&=` (`var &= expr`): bitwise and & assignment. +* `&&` (`expr && expr`): logical and. +* `*` (`expr * expr`): arithmetic multiplication. Overloadable (`Mul`). +* `*` (`*expr`): dereference. +* `*` (`*const type`, `*mut type`): raw pointer. See [Raw Pointers]. +* `*=` (`var *= expr`): arithmetic multiplication & assignment. +* `+` (`expr + expr`): arithmetic addition. Overloadable (`Add`). +* `+` (`trait + trait`, `'a + trait`): compound type constraint. See [Traits (Multiple Trait Bounds)]. +* `+=` (`var += expr`): arithmetic addition & assignment. +* `,`: argument and element separator. See [Attributes], [Functions], [Structs], [Generics], [Match], [Closures], [Crates and Modules (Importing Modules with `use`)]. +* `-` (`expr - expr`): arithmetic subtraction. Overloadable (`Sub`). +* `-` (`- expr`): arithmetic negation. Overloadable (`Neg`). +* `-=` (`var -= expr`): arithmetic subtraction & assignment. +* `->` (`fn(…) -> type`, `|…| -> type`): function and closure return type. See [Functions], [Closures]. +* `.` (`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)]. +* `..` (`variant(x, ..)`, `struct_type { x, .. }`): "and the rest" pattern binding. See [Patterns (Ignoring bindings)]. +* `...` (`expr ... expr`): inclusive range pattern. See [Patterns (Ranges)]. +* `/` (`expr / expr`): arithmetic division. Overloadable (`Div`). +* `/=` (`var /= expr`): arithmetic division & assignment. +* `:` (`pat: type`, `ident: type`): constraints. See [Variable Bindings], [Functions], [Structs], [Traits]. +* `:` (`ident: expr`): struct field initializer. See [Structs]. +* `:` (`'a: loop {…}`): loop label. See [Loops (Loops Labels)]. +* `;`: statement and item terminator. +* `;` (`[…; len]`): part of fixed-size array syntax. See [Primitive Types (Arrays)]. +* `<<` (`expr << expr`): left-shift. Overloadable (`Shl`). +* `<<=` (`var <<= expr`): left-shift & assignment. +* `<` (`expr < expr`): less-than comparison. Overloadable (`Cmp`, `PartialCmp`). +* `<=` (`var <= expr`): less-than or equal-to comparison. Overloadable (`Cmp`, `PartialCmp`). +* `=` (`var = expr`, `ident = type`): assignment/equivalence. See [Variable Bindings], [`type` Aliases], generic parameter defaults. +* `==` (`var == expr`): comparison. Overloadable (`Eq`, `PartialEq`). +* `=>` (`pat => expr`): part of match arm syntax. See [Match]. +* `>` (`expr > expr`): greater-than comparison. Overloadable (`Cmp`, `PartialCmp`). +* `>=` (`var >= expr`): greater-than or equal-to comparison. Overloadable (`Cmp`, `PartialCmp`). +* `>>` (`expr >> expr`): right-shift. Overloadable (`Shr`). +* `>>=` (`var >>= expr`): right-shift & assignment. +* `@` (`ident @ pat`): pattern binding. See [Patterns (Bindings)]. +* `^` (`expr ^ expr`): bitwise exclusive or. Overloadable (`BitXor`). +* `^=` (`var ^= expr`): bitwise exclusive or & assignment. +* `|` (`expr | expr`): bitwise or. Overloadable (`BitOr`). +* `|` (`pat | pat`): pattern alternatives. See [Patterns (Multiple patterns)]. +* `|=` (`var |= expr`): bitwise or & assignment. +* `||` (`expr || expr`): logical or. +* `_`: "ignored" pattern binding. See [Patterns (Ignoring bindings)]. + +## Other Syntax + + + +* `'ident`: named lifetime or loop label. See [Lifetimes], [Loops (Loops Labels)]. +* `…u8`, `…i32`, `…f64`, `…usize`, …: numeric literal of specific type. +* `"…"`: string literal. See [Strings]. +* `r"…"`, `r#"…"#`, `r##"…"##`, …: raw string literal. +* `b"…"`: byte string literal. +* `rb"…"`, `rb#"…"#`, `rb##"…"##`, …: raw byte string literal. +* `'…'`: character literal. See [Primitive Types (`char`)]. +* `b'…'`: ASCII byte literal. + + + +* `ident::ident`: path. See [Crates and Modules (Defining Modules)]. +* `::path`: path relative to the crate root (*i.e.* an explicitly absolute path). See [Crates and Modules (Re-exporting with `pub use`)]. +* `self::path`: path relative to the current module (*i.e.* an explicitly relative path). See [Crates and Modules (Re-exporting with `pub use`)]. +* `super::path`: path relative to the parent of the current module. See [Crates and Modules (Re-exporting with `pub use`)]. +* `type::ident`: associated constants, functions, and types. See [Associated Types]. +* `::…`: associated item for a type which cannot be directly named (*e.g.* `<&T>::…`, `<[T]>::…`, *etc.*). See [Associated Types]. + + + +* `path<…>` (*e.g.* `Vec`): specifies parameters to generic type *in a type*. See [Generics]. +* `path::<…>`, `method::<…>` (*e.g.* `"42".parse::()`): specifies parameters to generic type, function, or method *in an expression*. +* `fn ident<…> …`: define generic function. See [Generics]. +* `struct ident<…> …`: define generic structure. See [Generics]. +* `enum ident<…> …`: define generic enumeration. See [Generics]. +* `impl<…> …`: define generic implementation. +* `for<…> type`: higher-ranked lifetime bounds. +* `type` (*e.g.* `Iterator`): a generic type where one or more associated types have specific assignments. See [Associated Types]. + + + +* `T: U`: generic parameter `T` constrained to types that implement `U`. See [Traits]. +* `T: 'a`: generic type `T` must outlive lifetime `'a`. +* `'b: 'a`: generic lifetime `'b` must outlive lifetime `'a`. +* `T: ?Sized`: allow generic type parameter to be a dynamically-sized type. See [Unsized Types (`?Sized`)]. +* `'a + trait`, `trait + trait`: compound type constraint. See [Traits (Multiple Trait Bounds)]. + + + +* `#[meta]`: outer attribute. See [Attributes]. +* `#![meta]`: inner attribute. See [Attributes]. +* `$ident`: macro substitution. See [Macros]. +* `$ident:kind`: macro capture. See [Macros]. +* `$(…)…`: macro repetition. See [Macros]. + + + +* `//`: line comment. See [Comments]. +* `//!`: inner line doc comment. See [Comments]. +* `///`: outer line doc comment. See [Comments]. +* `/*…*/`: block comment. See [Comments]. +* `/*!…*/`: inner block doc comment. See [Comments]. +* `/**…*/`: outer block doc comment. See [Comments]. + + + +* `()`: empty tuple (*a.k.a.* unit), both literal and type. +* `(expr)`: parenthesized expression. +* `(expr,)`: single-element tuple expression. See [Primitive Types (Tuples)]. +* `(type,)`: single-element tuple type. See [Primitive Types (Tuples)]. +* `(expr, …)`: tuple expression. See [Primitive Types (Tuples)]. +* `(type, …)`: tuple type. See [Primitive Types (Tuples)]. +* `expr(expr, …)`: function call expression. Also used to initialize tuple `struct`s and tuple `enum` variants. See [Functions]. +* `ident!(…)`, `ident!{…}`, `ident![…]`: macro invocation. See [Macros]. +* `expr.0`, `expr.1`, …: tuple indexing. See [Primitive Types (Tuple Indexing)]. + + + +* `{…}`: block expression. +* `Type {…}`: `struct` literal. See [Structs]. + + + +* `[…]`: array literal. See [Primitive Types (Arrays)]. +* `[expr; len]`: array literal containing `len` copies of `expr`. See [Primitive Types (Arrays)]. +* `[type; len]`: array type containing `len` instances of `type`. See [Primitive Types (Arrays)]. + +[`const` and `static` (`static`)]: const-and-static.html#static +[`const` and `static`]: const-and-static.html +[`if let`]: if-let.html +[`if`]: if.html +[`type` Aliases]: type-aliases.html +[Associated Types]: associated-types.html +[Attributes]: attributes.html +[Casting Between Types (`as`)]: casting-between-types.html#as +[Closures (`move` closures)]: closures.html#move-closures +[Closures]: closures.html +[Comments]: comments.html +[Crates and Modules (Defining Modules)]: crates-and-modules.html#defining-modules +[Crates and Modules (Exporting a Public Interface)]: crates-and-modules.html#exporting-a-public-interface +[Crates and Modules (Importing External Crates)]: crates-and-modules.html#importing-external-crates +[Crates and Modules (Importing Modules with `use`)]: crates-and-modules.html#importing-modules-with-use +[Crates and Modules (Re-exporting with `pub use`)]: crates-and-modules.html#re-exporting-with-pub-use +[Enums]: enums.html +[Foreign Function Interface]: ffi.html +[Functions (Early Returns)]: functions.html#early-returns +[Functions]: functions.html +[Generics]: generics.html +[Lifetimes]: lifetimes.html +[Loops (`for`)]: loops.html#for +[Loops (`loop`)]: loops.html#loop +[Loops (`while`)]: loops.html#while +[Loops (Ending Iteration Early)]: loops.html#ending-iteration-early +[Loops (Loops Labels)]: loops.html#loop-labels +[Macros]: macros.html +[Match]: match.html +[Method Syntax (Method Calls)]: method-syntax.html#method-calls +[Method Syntax]: method-syntax.html +[Mutability]: mutability.html +[Operators and Overloading]: operators-and-overloading.html +[Patterns (`ref` and `ref mut`)]: patterns.html#ref-and-ref-mut +[Patterns (Bindings)]: patterns.html#bindings +[Patterns (Ignoring bindings)]: patterns.html#ignoring-bindings +[Patterns (Multiple patterns)]: patterns.html#multiple-patterns +[Patterns (Ranges)]: patterns.html#ranges +[Primitive Types (`char`)]: primitive-types.html#char +[Primitive Types (Arrays)]: primitive-types.html#arrays +[Primitive Types (Booleans)]: primitive-types.html#booleans +[Primitive Types (Tuple Indexing)]: primitive-types.html#tuple-indexing +[Primitive Types (Tuples)]: primitive-types.html#tuples +[Raw Pointers]: raw-pointers.html +[References and Borrowing]: references-and-borrowing.html +[Strings]: strings.html +[Structs (Update syntax)]: structs.html#update-syntax +[Structs]: structs.html +[Traits (`where` clause)]: traits.html#where-clause +[Traits (Multiple Trait Bounds)]: traits.html#multiple-trait-bounds +[Traits]: traits.html +[Unsafe]: unsafe.html +[Unsized Types (`?Sized`)]: unsized-types.html#?sized +[Variable Bindings]: variable-bindings.html diff --git a/src/doc/trpl/testing.md b/src/doc/trpl/testing.md index 587f60343c..c6aeb86f7d 100644 --- a/src/doc/trpl/testing.md +++ b/src/doc/trpl/testing.md @@ -82,7 +82,7 @@ fn it_works() { ``` `assert!` is a macro provided by Rust which takes one argument: if the argument -is `true`, nothing happens. If the argument is false, it `panic!`s. Let's run +is `true`, nothing happens. If the argument is `false`, it `panic!`s. Let's run our tests again: ```bash @@ -289,7 +289,7 @@ running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured ``` -The `--ignored` argument is an argument to the test binary, and not to cargo, +The `--ignored` argument is an argument to the test binary, and not to Cargo, which is why the command is `cargo test -- --ignored`. # The `tests` module @@ -367,7 +367,7 @@ It works! The current convention is to use the `tests` module to hold your "unit-style" tests. Anything that just tests one small bit of functionality makes sense to go here. But what about "integration-style" tests instead? For that, we have -the `tests` directory +the `tests` directory. # The `tests` directory @@ -502,3 +502,8 @@ documentation tests: the `_0` is generated for the module test, and `add_two_0` for the function test. These will auto increment with names like `add_two_1` as you add more examples. +We haven’t covered all of the details with writing documentation tests. For more, +please see the [Documentation chapter](documentation.html) + +One final note: Tests *cannot* be run on a binary file. To see more on file arrangement see the [Crates and Modules](crates-and-modules.html) section. + diff --git a/src/doc/trpl/the-stack-and-the-heap.md b/src/doc/trpl/the-stack-and-the-heap.md index fb778b59a3..f30dacc485 100644 --- a/src/doc/trpl/the-stack-and-the-heap.md +++ b/src/doc/trpl/the-stack-and-the-heap.md @@ -41,8 +41,8 @@ and just consider the local variables we’re allocating. So in this case, when This is automatically handled for you, as you can see; we didn’t have to write any special Rust code or anything. -When the function is over, its stack frame gets deallocated. This happens -automatically, we didn’t have to do anything special here. +When the function exits, its stack frame gets deallocated. This happens +automatically as well. That’s all there is for this simple program. The key thing to understand here is that stack allocation is very, very fast. Since we know all the local @@ -217,18 +217,18 @@ on the heap. The actual value of the box is a structure which has a pointer to it allocates some memory for the heap, and puts `5` there. The memory now looks like this: -| Address | Name | Value | -|-----------------|------|------------------| -| 230 | | 5 | -| ... | ... | ... | -| 1 | y | 42 | -| 0 | x | → 230 | +| Address | Name | Value | +|----------------------|------|------------------------| +| (230) - 1 | | 5 | +| ... | ... | ... | +| 1 | y | 42 | +| 0 | x | → (230) - 1 | -We have 230 in our hypothetical computer with 1GB of RAM. And since +We have (230) - 1 addresses in our hypothetical computer with 1GB of RAM. And since our stack grows from zero, the easiest place to allocate memory is from the other end. So our first value is at the highest place in memory. And the value of the struct at `x` has a [raw pointer][rawpointer] to the place we’ve -allocated on the heap, so the value of `x` is 230, the memory +allocated on the heap, so the value of `x` is (230) - 1, the memory location we’ve asked for. [rawpointer]: raw-pointers.html @@ -244,18 +244,18 @@ layout of a program which has been running for a while now: | Address | Name | Value | |----------------------|------|------------------------| -| 230 | | 5 | -| (230) - 1 | | | +| (230) - 1 | | 5 | | (230) - 2 | | | -| (230) - 3 | | 42 | +| (230) - 3 | | | +| (230) - 4 | | 42 | | ... | ... | ... | -| 3 | y | → (230) - 3 | +| 3 | y | → (230) - 4 | | 2 | y | 42 | | 1 | y | 42 | -| 0 | x | → 230 | +| 0 | x | → (230) - 1 | In this case, we’ve allocated four things on the heap, but deallocated two of -them. There’s a gap between 230 and (230) - 3 which isn’t +them. There’s a gap between (230) - 1 and (230) - 4 which isn’t currently being used. The specific details of how and why this happens depends on what kind of strategy you use to manage the heap. Different programs can use different ‘memory allocators’, which are libraries that manage this for you. @@ -366,29 +366,29 @@ fn main() { First, we call `main()`: -| Address | Name | Value | -|-----------------|------|------------------| -| 230 | | 20 | -| ... | ... | ... | -| 2 | j | → 0 | -| 1 | i | → 230 | -| 0 | h | 3 | +| Address | Name | Value | +|----------------------|------|------------------------| +| (230) - 1 | | 20 | +| ... | ... | ... | +| 2 | j | → 0 | +| 1 | i | → (230) - 1 | +| 0 | h | 3 | We allocate memory for `j`, `i`, and `h`. `i` is on the heap, and so has a value pointing there. Next, at the end of `main()`, `foo()` gets called: -| Address | Name | Value | -|-----------------|------|-----------------| -| 230 | | 20 | -| ... | ... | ... | -| 5 | z | → 4 | -| 4 | y | 10 | -| 3 | x | → 0 | -| 2 | j | → 0 | -| 1 | i | → 230| -| 0 | h | 3 | +| Address | Name | Value | +|----------------------|------|------------------------| +| (230) - 1 | | 20 | +| ... | ... | ... | +| 5 | z | → 4 | +| 4 | y | 10 | +| 3 | x | → 0 | +| 2 | j | → 0 | +| 1 | i | → (230) - 1 | +| 0 | h | 3 | Space gets allocated for `x`, `y`, and `z`. The argument `x` has the same value as `j`, since that’s what we passed it in. It’s a pointer to the `0` address, @@ -396,42 +396,42 @@ since `j` points at `h`. Next, `foo()` calls `baz()`, passing `z`: -| Address | Name | Value | -|-----------------|------|------------------| -| 230 | | 20 | -| ... | ... | ... | -| 7 | g | 100 | -| 6 | f | → 4 | -| 5 | z | → 4 | -| 4 | y | 10 | -| 3 | x | → 0 | -| 2 | j | → 0 | -| 1 | i | → 230 | -| 0 | h | 3 | +| Address | Name | Value | +|----------------------|------|------------------------| +| (230) - 1 | | 20 | +| ... | ... | ... | +| 7 | g | 100 | +| 6 | f | → 4 | +| 5 | z | → 4 | +| 4 | y | 10 | +| 3 | x | → 0 | +| 2 | j | → 0 | +| 1 | i | → (230) - 1 | +| 0 | h | 3 | We’ve allocated memory for `f` and `g`. `baz()` is very short, so when it’s over, we get rid of its stack frame: -| Address | Name | Value | -|-----------------|------|------------------| -| 230 | | 20 | -| ... | ... | ... | -| 5 | z | → 4 | -| 4 | y | 10 | -| 3 | x | → 0 | -| 2 | j | → 0 | -| 1 | i | → 230 | -| 0 | h | 3 | +| Address | Name | Value | +|----------------------|------|------------------------| +| (230) - 1 | | 20 | +| ... | ... | ... | +| 5 | z | → 4 | +| 4 | y | 10 | +| 3 | x | → 0 | +| 2 | j | → 0 | +| 1 | i | → (230) - 1 | +| 0 | h | 3 | Next, `foo()` calls `bar()` with `x` and `z`: | Address | Name | Value | |----------------------|------|------------------------| -| 230 | | 20 | -| (230) - 1 | | 5 | +| (230) - 1 | | 20 | +| (230) - 2 | | 5 | | ... | ... | ... | | 10 | e | → 9 | -| 9 | d | → (230) - 1 | +| 9 | d | → (230) - 2 | | 8 | c | 5 | | 7 | b | → 4 | | 6 | a | → 0 | @@ -439,24 +439,24 @@ Next, `foo()` calls `bar()` with `x` and `z`: | 4 | y | 10 | | 3 | x | → 0 | | 2 | j | → 0 | -| 1 | i | → 230 | +| 1 | i | → (230) - 1 | | 0 | h | 3 | We end up allocating another value on the heap, and so we have to subtract one -from 230. It’s easier to just write that than `1,073,741,823`. In any +from (230) - 1. It’s easier to just write that than `1,073,741,822`. In any case, we set up the variables as usual. At the end of `bar()`, it calls `baz()`: | Address | Name | Value | |----------------------|------|------------------------| -| 230 | | 20 | -| (230) - 1 | | 5 | +| (230) - 1 | | 20 | +| (230) - 2 | | 5 | | ... | ... | ... | | 12 | g | 100 | | 11 | f | → 9 | | 10 | e | → 9 | -| 9 | d | → (230) - 1 | +| 9 | d | → (230) - 2 | | 8 | c | 5 | | 7 | b | → 4 | | 6 | a | → 0 | @@ -464,7 +464,7 @@ At the end of `bar()`, it calls `baz()`: | 4 | y | 10 | | 3 | x | → 0 | | 2 | j | → 0 | -| 1 | i | → 230 | +| 1 | i | → (230) - 1 | | 0 | h | 3 | With this, we’re at our deepest point! Whew! Congrats for following along this @@ -474,11 +474,11 @@ After `baz()` is over, we get rid of `f` and `g`: | Address | Name | Value | |----------------------|------|------------------------| -| 230 | | 20 | -| (230) - 1 | | 5 | +| (230) - 1 | | 20 | +| (230) - 2 | | 5 | | ... | ... | ... | | 10 | e | → 9 | -| 9 | d | → (230) - 1 | +| 9 | d | → (230) - 2 | | 8 | c | 5 | | 7 | b | → 4 | | 6 | a | → 0 | @@ -486,32 +486,32 @@ After `baz()` is over, we get rid of `f` and `g`: | 4 | y | 10 | | 3 | x | → 0 | | 2 | j | → 0 | -| 1 | i | → 230 | +| 1 | i | → (230) - 1 | | 0 | h | 3 | Next, we return from `bar()`. `d` in this case is a `Box`, so it also frees -what it points to: (230) - 1. - -| Address | Name | Value | -|-----------------|------|------------------| -| 230 | | 20 | -| ... | ... | ... | -| 5 | z | → 4 | -| 4 | y | 10 | -| 3 | x | → 0 | -| 2 | j | → 0 | -| 1 | i | → 230 | -| 0 | h | 3 | +what it points to: (230) - 2. + +| Address | Name | Value | +|----------------------|------|------------------------| +| (230) - 1 | | 20 | +| ... | ... | ... | +| 5 | z | → 4 | +| 4 | y | 10 | +| 3 | x | → 0 | +| 2 | j | → 0 | +| 1 | i | → (230) - 1 | +| 0 | h | 3 | And after that, `foo()` returns: -| Address | Name | Value | -|-----------------|------|------------------| -| 230 | | 20 | -| ... | ... | ... | -| 2 | j | → 0 | -| 1 | i | → 230 | -| 0 | h | 3 | +| Address | Name | Value | +|----------------------|------|------------------------| +| (230) - 1 | | 20 | +| ... | ... | ... | +| 2 | j | → 0 | +| 1 | i | → (230) - 1 | +| 0 | h | 3 | And then, finally, `main()`, which cleans the rest up. When `i` is `Drop`ped, it will clean up the last of the heap too. diff --git a/src/doc/trpl/traits.md b/src/doc/trpl/traits.md index 0870a6ef34..7b6d0b730a 100644 --- a/src/doc/trpl/traits.md +++ b/src/doc/trpl/traits.md @@ -47,12 +47,14 @@ As you can see, the `trait` block looks very similar to the `impl` block, but we don’t define a body, just a type signature. When we `impl` a trait, we use `impl Trait for Item`, rather than just `impl Item`. -## Traits bounds for generic functions +## Trait bounds on generic functions Traits are useful because they allow a type to make certain promises about its -behavior. Generic functions can exploit this to constrain the types they +behavior. Generic functions can exploit this to constrain, or [bound][bounds], the types they accept. Consider this function, which does not compile: +[bounds]: glossary.html#bounds + ```rust,ignore fn print_area(shape: T) { println!("This shape has an area of {}", shape.area()); @@ -66,7 +68,7 @@ error: no method named `area` found for type `T` in the current scope ``` Because `T` can be any type, we can’t be sure that it implements the `area` -method. But we can add a ‘trait constraint’ to our generic `T`, ensuring +method. But we can add a trait bound to our generic `T`, ensuring that it does: ```rust @@ -155,10 +157,10 @@ We get a compile-time error: error: the trait `HasArea` is not implemented for the type `_` [E0277] ``` -## Traits bounds for generic structs +## Trait bounds on generic structs -Your generic structs can also benefit from trait constraints. All you need to -do is append the constraint when you declare type parameters. Here is a new +Your generic structs can also benefit from trait bounds. All you need to +do is append the bound when you declare type parameters. Here is a new type `Rectangle` and its operation `is_square()`: ```rust @@ -492,3 +494,32 @@ If we forget to implement `Foo`, Rust will tell us: ```text error: the trait `main::Foo` is not implemented for the type `main::Baz` [E0277] ``` + +# Deriving + +Implementing traits like `Debug` and `Default` over and over again can become +quite tedious. For that reason, Rust provides an [attribute][attributes] that +allows you to let Rust automatically implement traits for you: + +```rust +#[derive(Debug)] +struct Foo; + +fn main() { + println!("{:?}", Foo); +} +``` + +[attributes]: attributes.html + +However, deriving is limited to a certain set of traits: + +- [`Clone`](../core/clone/trait.Clone.html) +- [`Copy`](../core/marker/trait.Copy.html) +- [`Debug`](../core/fmt/trait.Debug.html) +- [`Default`](../core/default/trait.Default.html) +- [`Eq`](../core/cmp/trait.Eq.html) +- [`Hash`](../core/hash/trait.Hash.html) +- [`Ord`](../core/cmp/trait.Ord.html) +- [`PartialEq`](../core/cmp/trait.PartialEq.html) +- [`PartialOrd`](../core/cmp/trait.PartialOrd.html) diff --git a/src/doc/trpl/variable-bindings.md b/src/doc/trpl/variable-bindings.md index 2166c04689..f3a5d1dd88 100644 --- a/src/doc/trpl/variable-bindings.md +++ b/src/doc/trpl/variable-bindings.md @@ -1,7 +1,8 @@ % Variable Bindings Virtually every non-'Hello World’ Rust program uses *variable bindings*. They -look like this: +bind some value to a name, so it can be used later. `let` is +used to introduce a binding, just like this: ```rust fn main() { @@ -13,10 +14,12 @@ Putting `fn main() {` in each example is a bit tedious, so we’ll leave that ou in the future. If you’re following along, make sure to edit your `main()` function, rather than leaving it off. Otherwise, you’ll get an error. -In many languages, this is called a *variable*, but Rust’s variable bindings -have a few tricks up their sleeves. For example the left-hand side of a `let` -expression is a ‘[pattern][pattern]’, not just a variable name. This means we -can do things like: +# Patterns + +In many languages, a variable binding would be called a *variable*, but Rust’s +variable bindings have a few tricks up their sleeves. For example the +left-hand side of a `let` expression is a ‘[pattern][pattern]’, not just a +variable name. This means we can do things like: ```rust let (x, y) = (1, 2); @@ -29,6 +32,8 @@ of our minds as we go forward. [pattern]: patterns.html +# Type annotations + Rust is a statically typed language, which means that we specify our types up front, and they’re checked at compile time. So why does our first example compile? Well, Rust has this thing called ‘type inference’. If it can figure @@ -63,6 +68,8 @@ Note the similarities between this annotation and the syntax you use with occasionally include them to help you understand what the types that Rust infers are. +# Mutability + By default, bindings are *immutable*. This code will not compile: ```rust,ignore @@ -97,9 +104,11 @@ out of the scope of this guide. In general, you can often avoid explicit mutation, and so it is preferable in Rust. That said, sometimes, mutation is what you need, so it’s not verboten. -Let’s get back to bindings. Rust variable bindings have one more aspect that -differs from other languages: bindings are required to be initialized with a -value before you're allowed to use them. +# Initializing bindings + +Rust variable bindings have one more aspect that differs from other languages: +bindings are required to be initialized with a value before you're allowed to +use them. Let’s try it out. Change your `src/main.rs` file to look like this: @@ -167,3 +176,77 @@ For now, we'll just stick to the default: integers aren't very complicated to print. [format]: ../std/fmt/index.html + +# Scope and shadowing + +Let’s get back to bindings. Variable bindings have a scope - they are +constrained to live in a block they were defined in. A block is a collection +of statements enclosed by `{` and `}`. Function definitions are also blocks! +In the following example we define two variable bindings, `x` and `y`, which +live in different blocks. `x` can be accessed from inside the `fn main() {}` +block, while `y` can be accessed only from inside the inner block: + +```rust,ignore +fn main() { + let x: i32 = 17; + { + let y: i32 = 3; + println!("The value of x is {} and value of y is {}", x, y); + } + println!("The value of x is {} and value of y is {}", x, y); // This won't work +} +``` + +The first `println!` would print "The value of x is 17 and the value of y is +3", but this example cannot be compiled successfully, because the second +`println!` cannot access the value of `y`, since it is not in scope anymore. +Instead we get this error: + +```bash +$ cargo build + Compiling hello v0.1.0 (file:///home/you/projects/hello_world) +main.rs:7:62: 7:63 error: unresolved name `y`. Did you mean `x`? [E0425] +main.rs:7 println!("The value of x is {} and value of y is {}", x, y); // This won't work + ^ +note: in expansion of format_args! +:2:25: 2:56 note: expansion site +:1:1: 2:62 note: in expansion of print! +:3:1: 3:54 note: expansion site +:1:1: 3:58 note: in expansion of println! +main.rs:7:5: 7:65 note: expansion site +main.rs:7:62: 7:63 help: run `rustc --explain E0425` to see a detailed explanation +error: aborting due to previous error +Could not compile `hello`. + +To learn more, run the command again with --verbose. +``` + +Additionally, variable bindings can be shadowed. This means that a later +variable binding with the same name as another binding, that's currently in +scope, will override the previous binding. + +```rust +let x: i32 = 8; +{ + println!("{}", x); // Prints "8" + let x = 12; + println!("{}", x); // Prints "12" +} +println!("{}", x); // Prints "8" +let x = 42; +println!("{}", x); // Prints "42" +``` + +Shadowing and mutable bindings may appear as two sides of the same coin, but +they are two distinct concepts that can't always be used interchangeably. For +one, shadowing enables us to rebind a name to a value of a different type. It +is also possible to change the mutability of a binding. + +```rust +let mut x: i32 = 1; +x = 7; +let x = x; // x is now immutable and is bound to 7 + +let y = 4; +let y = "I can also be bound to text!"; // y is now of a different type +``` diff --git a/src/doc/trpl/vectors.md b/src/doc/trpl/vectors.md index d8b894a2f6..7b826f08ae 100644 --- a/src/doc/trpl/vectors.md +++ b/src/doc/trpl/vectors.md @@ -32,6 +32,35 @@ println!("The third element of v is {}", v[2]); The indices count from `0`, so the third element is `v[2]`. +It’s also important to note that you must index with the `usize` type: + +```ignore +let v = vec![1, 2, 3, 4, 5]; + +let i: usize = 0; +let j: i32 = 0; + +// works +v[i]; + +// doesn’t +v[j]; +``` + +Indexing with a non-`usize` type gives an error that looks like this: + +```text +error: the trait `core::ops::Index` is not implemented for the type +`collections::vec::Vec<_>` [E0277] +v[j]; +^~~~ +note: the type `collections::vec::Vec<_>` cannot be indexed by `i32` +error: aborting due to previous error +``` + +There’s a lot of punctuation in that message, but the core of it makes sense: +you cannot index with an `i32`. + ## Iterating Once you have a vector, you can iterate through its elements with `for`. There diff --git a/src/driver/driver.rs b/src/driver/driver.rs index c5c58bb49a..e74652d85d 100644 --- a/src/driver/driver.rs +++ b/src/driver/driver.rs @@ -17,4 +17,6 @@ extern crate rustdoc as this; #[cfg(rustc)] extern crate rustc_driver as this; -fn main() { this::main() } +fn main() { + this::main() +} diff --git a/src/error-index-generator/main.rs b/src/error-index-generator/main.rs index cbb67014e2..4b10b02f2d 100644 --- a/src/error-index-generator/main.rs +++ b/src/error-index-generator/main.rs @@ -34,10 +34,7 @@ fn load_all_errors(metadata_dir: &Path) -> Result> let path = try!(entry).path(); let mut metadata_str = String::new(); - try!( - File::open(&path).and_then(|mut f| - f.read_to_string(&mut metadata_str)) - ); + try!(File::open(&path).and_then(|mut f| f.read_to_string(&mut metadata_str))); let some_errors: ErrorMetadataMap = try!(json::decode(&metadata_str)); @@ -78,24 +75,23 @@ r##" // Enclose each error in a div so they can be shown/hidden en masse. let desc_desc = match info.description { Some(_) => "error-described", - None => "error-undescribed" + None => "error-undescribed", }; let use_desc = match info.use_site { Some(_) => "error-used", - None => "error-unused" + None => "error-unused", }; try!(write!(&mut output_file, "
", desc_desc, use_desc)); // Error title (with self-link). try!(write!(&mut output_file, - "

{0}

\n", - err_code - )); + "

{0}

\n", + err_code)); // Description rendered as markdown. match info.description { Some(ref desc) => try!(write!(&mut output_file, "{}", Markdown(desc))), - None => try!(write!(&mut output_file, "

No description.

\n")) + None => try!(write!(&mut output_file, "

No description.

\n")), } try!(write!(&mut output_file, "
\n")); diff --git a/src/etc/generate-deriving-span-tests.py b/src/etc/generate-deriving-span-tests.py index a8a62358d3..790fc89428 100755 --- a/src/etc/generate-deriving-span-tests.py +++ b/src/etc/generate-deriving-span-tests.py @@ -119,7 +119,7 @@ for (trait, supers, errs) in [('Clone', [], 1), ('PartialOrd', ['PartialEq'], 8), ('Eq', ['PartialEq'], 1), ('Ord', ['Eq', 'PartialOrd', 'PartialEq'], 1), - ('Show', [], 1), + ('Debug', [], 1), ('Hash', [], 1)]: traits[trait] = (ALL, supers, errs) diff --git a/src/etc/maketest.py b/src/etc/maketest.py index 04bf81a96a..c2958caddc 100644 --- a/src/etc/maketest.py +++ b/src/etc/maketest.py @@ -12,6 +12,7 @@ import subprocess import os import sys +target_triple = sys.argv[14] def normalize_path(v): """msys1/msys2 automatically converts `/abs/path1:/abs/path2` into @@ -22,8 +23,11 @@ def normalize_path(v): windows paths so it is really error-prone. revert it for peace.""" v = v.replace('\\', '/') # c:/path -> /c/path - if ':/' in v: - v = '/' + v.replace(':/', '/') + # "c:/path" -> "/c/path" + start = v.find(':/') + while start != -1: + v = v[:start - 1] + '/' + v[start - 1:start] + v[start + 1:] + start = v.find(':/') return v @@ -50,6 +54,10 @@ putenv('TARGET_RPATH_DIR', os.path.abspath(sys.argv[11])) putenv('RUST_BUILD_STAGE', sys.argv[12]) putenv('S', os.path.abspath(sys.argv[13])) putenv('PYTHON', sys.executable) +os.putenv('TARGET', target_triple) + +if 'msvc' in target_triple: + os.putenv('IS_MSVC', '1') if filt not in sys.argv[1]: sys.exit(0) diff --git a/src/etc/mklldeps.py b/src/etc/mklldeps.py index 1cc65406b2..215fa1cdd1 100644 --- a/src/etc/mklldeps.py +++ b/src/etc/mklldeps.py @@ -17,6 +17,7 @@ f = open(sys.argv[1], 'wb') components = sys.argv[2].split() # splits on whitespace enable_static = sys.argv[3] llvm_config = sys.argv[4] +stdcpp_name = sys.argv[5] f.write("""// Copyright 2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at @@ -77,7 +78,7 @@ for lib in out.strip().split(' '): out = run([llvm_config, '--cxxflags']) if enable_static == '1': assert('stdlib=libc++' not in out) - f.write("#[link(name = \"stdc++\", kind = \"static\")]\n") + f.write("#[link(name = \"" + stdcpp_name + "\", kind = \"static\")]\n") else: # Note that we use `cfg_attr` here because on MSVC the C++ standard library # is not c++ or stdc++, but rather the linker takes care of linking the @@ -85,7 +86,7 @@ else: if 'stdlib=libc++' in out: f.write("#[cfg_attr(not(target_env = \"msvc\"), link(name = \"c++\"))]\n") else: - f.write("#[cfg_attr(not(target_env = \"msvc\"), link(name = \"stdc++\"))]\n") + f.write("#[cfg_attr(not(target_env = \"msvc\"), link(name = \"" + stdcpp_name + "\"))]\n") # Attach everything to an extern block f.write("extern {}\n") diff --git a/src/etc/test-float-parse/runtests.py b/src/etc/test-float-parse/runtests.py index 17a1b769bd..27af63a587 100644 --- a/src/etc/test-float-parse/runtests.py +++ b/src/etc/test-float-parse/runtests.py @@ -71,7 +71,7 @@ The output on stdout is treated as (f64, f32, decimal) record, encoded thusly: Incomplete records are an error. Not-a-Number bit patterns are invalid too. -The tests run serially but the validaition for a a single test is parallelized +The tests run serially but the validation for a single test is parallelized with ``multiprocessing``. Each test is launched as a subprocess. One thread supervises it: Accepts and enqueues records to validate, observe stderr, and waits for the process to exit. A set of worker processes perform diff --git a/src/etc/unicode.py b/src/etc/unicode.py index 2c14741947..3eeb1ac472 100755 --- a/src/etc/unicode.py +++ b/src/etc/unicode.py @@ -313,14 +313,19 @@ def escape_char(c): def emit_bsearch_range_table(f): f.write(""" -fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool { +fn bsearch_range_table(c: char, r: &'static [(char, char)]) -> bool { use core::cmp::Ordering::{Equal, Less, Greater}; use core::slice::SliceExt; - r.binary_search_by(|&(lo,hi)| { - if lo <= c && c <= hi { Equal } - else if hi < c { Less } - else { Greater } - }).is_ok() + r.binary_search_by(|&(lo, hi)| { + if lo <= c && c <= hi { + Equal + } else if hi < c { + Less + } else { + Greater + } + }) + .is_ok() }\n """) diff --git a/src/jemalloc/VERSION b/src/jemalloc/VERSION index 8259d8ea67..ffdc2b0397 100644 --- a/src/jemalloc/VERSION +++ b/src/jemalloc/VERSION @@ -1 +1 @@ -0.12.0-13461-g8ab8581f6921bc7a8e3fa4defffd2814372dcb15 +0.12.0-14610-g3d7cd77e442ce34eaac8a176ae8be17669498ebc diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 78821403de..33ca80ba37 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -79,9 +79,8 @@ use core::cmp::Ordering; use core::mem::{align_of_val, size_of_val}; use core::intrinsics::{drop_in_place, abort}; use core::mem; -use core::nonzero::NonZero; use core::ops::{Deref, CoerceUnsized}; -use core::ptr; +use core::ptr::{self, Shared}; use core::marker::Unsize; use core::hash::{Hash, Hasher}; use core::{usize, isize}; @@ -93,7 +92,7 @@ const MAX_REFCOUNT: usize = (isize::MAX) as usize; /// /// # Examples /// -/// In this example, a large vector of floats is shared between several threads. +/// In this example, a large vector is shared between several threads. /// With simple pipes, without `Arc`, a copy would have to be made for each /// thread. /// @@ -124,12 +123,13 @@ const MAX_REFCOUNT: usize = (isize::MAX) as usize; pub struct Arc { // FIXME #12808: strange name to try to avoid interfering with // field accesses of the contained type via Deref - _ptr: NonZero<*mut ArcInner>, + _ptr: Shared>, } unsafe impl Send for Arc { } unsafe impl Sync for Arc { } +#[cfg(not(stage0))] // remove cfg after new snapshot impl, U: ?Sized> CoerceUnsized> for Arc {} /// A weak pointer to an `Arc`. @@ -141,12 +141,13 @@ impl, U: ?Sized> CoerceUnsized> for Arc {} pub struct Weak { // FIXME #12808: strange name to try to avoid interfering with // field accesses of the contained type via Deref - _ptr: NonZero<*mut ArcInner>, + _ptr: Shared>, } unsafe impl Send for Weak { } unsafe impl Sync for Weak { } +#[cfg(not(stage0))] // remove cfg after new snapshot impl, U: ?Sized> CoerceUnsized> for Weak {} #[stable(feature = "rust1", since = "1.0.0")] @@ -190,7 +191,7 @@ impl Arc { weak: atomic::AtomicUsize::new(1), data: data, }; - Arc { _ptr: unsafe { NonZero::new(Box::into_raw(x)) } } + Arc { _ptr: unsafe { Shared::new(Box::into_raw(x)) } } } /// Unwraps the contained value if the `Arc` has only one strong reference. @@ -214,7 +215,9 @@ impl Arc { #[stable(feature = "arc_unique", since = "1.4.0")] pub fn try_unwrap(this: Self) -> Result { // See `drop` for why all these atomics are like this - if this.inner().strong.compare_and_swap(1, 0, Release) != 1 { return Err(this) } + if this.inner().strong.compare_and_swap(1, 0, Release) != 1 { + return Err(this) + } atomic::fence(Acquire); @@ -251,7 +254,9 @@ impl Arc { let cur = this.inner().weak.load(Relaxed); // check if the weak counter is currently "locked"; if so, spin. - if cur == usize::MAX { continue } + if cur == usize::MAX { + continue + } // NOTE: this code currently ignores the possibility of overflow // into usize::MAX; in general both Rc and Arc need to be adjusted @@ -348,7 +353,9 @@ impl Clone for Arc { // We abort because such a program is incredibly degenerate, and we // don't care to support it. if old_size > MAX_REFCOUNT { - unsafe { abort(); } + unsafe { + abort(); + } } Arc { _ptr: self._ptr } @@ -542,6 +549,7 @@ impl Drop for Arc { /// /// } // implicit drop /// ``` + #[unsafe_destructor_blind_to_params] #[inline] fn drop(&mut self) { // This structure has #[unsafe_no_drop_flag], so this drop glue may run @@ -556,7 +564,9 @@ impl Drop for Arc { // Because `fetch_sub` is already atomic, we do not need to synchronize // with other threads unless we are going to delete the object. This // same logic applies to the below `fetch_sub` to the `weak` count. - if self.inner().strong.fetch_sub(1, Release) != 1 { return } + if self.inner().strong.fetch_sub(1, Release) != 1 { + return + } // This fence is needed to prevent reordering of use of the data and // deletion of the data. Because it is marked `Release`, the decreasing @@ -578,7 +588,7 @@ impl Drop for Arc { atomic::fence(Acquire); unsafe { - self.drop_slow() + self.drop_slow(); } } } @@ -613,11 +623,15 @@ impl Weak { // "stale" read of 0 is fine), and any other value is // confirmed via the CAS below. let n = inner.strong.load(Relaxed); - if n == 0 { return None } + if n == 0 { + return None + } // Relaxed is valid for the same reason it is on Arc's Clone impl let old = inner.strong.compare_and_swap(n, n + 1, Relaxed); - if old == n { return Some(Arc { _ptr: self._ptr }) } + if old == n { + return Some(Arc { _ptr: self._ptr }) + } } } @@ -653,7 +667,9 @@ impl Clone for Weak { // See comments in Arc::clone() for why we do this (for mem::forget). if old_size > MAX_REFCOUNT { - unsafe { abort(); } + unsafe { + abort(); + } } return Weak { _ptr: self._ptr } @@ -705,9 +721,7 @@ impl Drop for Weak { // ref, which can only happen after the lock is released. if self.inner().weak.fetch_sub(1, Release) == 1 { atomic::fence(Acquire); - unsafe { deallocate(ptr as *mut u8, - size_of_val(&*ptr), - align_of_val(&*ptr)) } + unsafe { deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr)) } } } } @@ -727,7 +741,9 @@ impl PartialEq for Arc { /// /// five == Arc::new(5); /// ``` - fn eq(&self, other: &Arc) -> bool { *(*self) == *(*other) } + fn eq(&self, other: &Arc) -> bool { + *(*self) == *(*other) + } /// Inequality for two `Arc`s. /// @@ -742,7 +758,9 @@ impl PartialEq for Arc { /// /// five != Arc::new(5); /// ``` - fn ne(&self, other: &Arc) -> bool { *(*self) != *(*other) } + fn ne(&self, other: &Arc) -> bool { + *(*self) != *(*other) + } } #[stable(feature = "rust1", since = "1.0.0")] impl PartialOrd for Arc { @@ -776,7 +794,9 @@ impl PartialOrd for Arc { /// /// five < Arc::new(5); /// ``` - fn lt(&self, other: &Arc) -> bool { *(*self) < *(*other) } + fn lt(&self, other: &Arc) -> bool { + *(*self) < *(*other) + } /// 'Less-than or equal to' comparison for two `Arc`s. /// @@ -791,7 +811,9 @@ impl PartialOrd for Arc { /// /// five <= Arc::new(5); /// ``` - fn le(&self, other: &Arc) -> bool { *(*self) <= *(*other) } + fn le(&self, other: &Arc) -> bool { + *(*self) <= *(*other) + } /// Greater-than comparison for two `Arc`s. /// @@ -806,7 +828,9 @@ impl PartialOrd for Arc { /// /// five > Arc::new(5); /// ``` - fn gt(&self, other: &Arc) -> bool { *(*self) > *(*other) } + fn gt(&self, other: &Arc) -> bool { + *(*self) > *(*other) + } /// 'Greater-than or equal to' comparison for two `Arc`s. /// @@ -821,11 +845,15 @@ impl PartialOrd for Arc { /// /// five >= Arc::new(5); /// ``` - fn ge(&self, other: &Arc) -> bool { *(*self) >= *(*other) } + fn ge(&self, other: &Arc) -> bool { + *(*self) >= *(*other) + } } #[stable(feature = "rust1", since = "1.0.0")] impl Ord for Arc { - fn cmp(&self, other: &Arc) -> Ordering { (**self).cmp(&**other) } + fn cmp(&self, other: &Arc) -> Ordering { + (**self).cmp(&**other) + } } #[stable(feature = "rust1", since = "1.0.0")] impl Eq for Arc {} @@ -854,7 +882,9 @@ impl fmt::Pointer for Arc { #[stable(feature = "rust1", since = "1.0.0")] impl Default for Arc { #[stable(feature = "rust1", since = "1.0.0")] - fn default() -> Arc { Arc::new(Default::default()) } + fn default() -> Arc { + Arc::new(Default::default()) + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1015,7 +1045,7 @@ mod tests { #[test] fn weak_self_cyclic() { struct Cycle { - x: Mutex>> + x: Mutex>>, } let a = Arc::new(Cycle { x: Mutex::new(None) }); @@ -1095,7 +1125,9 @@ mod tests { // Make sure deriving works with Arc #[derive(Eq, Ord, PartialEq, PartialOrd, Clone, Debug, Default)] - struct Foo { inner: Arc } + struct Foo { + inner: Arc, + } #[test] fn test_unsized() { @@ -1108,5 +1140,14 @@ mod tests { } impl borrow::Borrow for Arc { - fn borrow(&self) -> &T { &**self } + fn borrow(&self) -> &T { + &**self + } +} + +#[stable(since = "1.5.0", feature = "smart_ptr_as_ref")] +impl AsRef for Arc { + fn as_ref(&self) -> &T { + &**self + } } diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 4293b4765e..4783b4339d 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -66,7 +66,7 @@ use core::mem; use core::ops::{CoerceUnsized, Deref, DerefMut}; use core::ops::{Placer, Boxed, Place, InPlace, BoxPlace}; use core::ptr::{self, Unique}; -use core::raw::{TraitObject}; +use core::raw::TraitObject; /// A value that represents the heap. This is the default place that the `box` /// keyword allocates into when no place is supplied. @@ -80,11 +80,10 @@ use core::raw::{TraitObject}; /// use std::boxed::HEAP; /// /// fn main() { -/// let foo = box(HEAP) 5; +/// let foo: Box = in HEAP { 5 }; /// let foo = box 5; /// } /// ``` -#[lang = "exchange_heap"] #[unstable(feature = "box_heap", reason = "may be renamed; uncertain about custom allocator design", issue = "27779")] @@ -96,7 +95,9 @@ pub const HEAP: ExchangeHeapSingleton = reason = "may be renamed; uncertain about custom allocator design", issue = "27779")] #[derive(Copy, Clone)] -pub struct ExchangeHeapSingleton { _force_singleton: () } +pub struct ExchangeHeapSingleton { + _force_singleton: (), +} /// A pointer type for heap allocation. /// @@ -127,7 +128,7 @@ pub struct Box(Unique); #[unstable(feature = "placement_in", reason = "placement box design is still being worked out.", issue = "27779")] -pub struct IntermediateBox{ +pub struct IntermediateBox { ptr: *mut u8, size: usize, align: usize, @@ -136,7 +137,7 @@ pub struct IntermediateBox{ impl Place for IntermediateBox { fn pointer(&mut self) -> *mut T { - unsafe { ::core::mem::transmute(self.ptr) } + self.ptr as *mut T } } @@ -153,31 +154,40 @@ fn make_place() -> IntermediateBox { let p = if size == 0 { heap::EMPTY as *mut u8 } else { - let p = unsafe { - heap::allocate(size, align) - }; + let p = unsafe { heap::allocate(size, align) }; if p.is_null() { panic!("Box make_place allocation failure."); } p }; - IntermediateBox { ptr: p, size: size, align: align, marker: marker::PhantomData } + IntermediateBox { + ptr: p, + size: size, + align: align, + marker: marker::PhantomData, + } } impl BoxPlace for IntermediateBox { - fn make_place() -> IntermediateBox { make_place() } + fn make_place() -> IntermediateBox { + make_place() + } } impl InPlace for IntermediateBox { type Owner = Box; - unsafe fn finalize(self) -> Box { finalize(self) } + unsafe fn finalize(self) -> Box { + finalize(self) + } } impl Boxed for Box { type Data = T; type Place = IntermediateBox; - unsafe fn finalize(b: IntermediateBox) -> Box { finalize(b) } + unsafe fn finalize(b: IntermediateBox) -> Box { + finalize(b) + } } impl Placer for ExchangeHeapSingleton { @@ -191,9 +201,7 @@ impl Placer for ExchangeHeapSingleton { impl Drop for IntermediateBox { fn drop(&mut self) { if self.size > 0 { - unsafe { - heap::deallocate(self.ptr, self.size, self.align) - } + unsafe { heap::deallocate(self.ptr, self.size, self.align) } } } } @@ -257,13 +265,17 @@ impl Box { #[stable(feature = "rust1", since = "1.0.0")] impl Default for Box { #[stable(feature = "rust1", since = "1.0.0")] - fn default() -> Box { box Default::default() } + fn default() -> Box { + box Default::default() + } } #[stable(feature = "rust1", since = "1.0.0")] impl Default for Box<[T]> { #[stable(feature = "rust1", since = "1.0.0")] - fn default() -> Box<[T]> { Box::<[T; 0]>::new([]) } + fn default() -> Box<[T]> { + Box::<[T; 0]>::new([]) + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -276,8 +288,11 @@ impl Clone for Box { /// let x = Box::new(5); /// let y = x.clone(); /// ``` + #[rustfmt_skip] #[inline] - fn clone(&self) -> Box { box {(**self).clone()} } + fn clone(&self) -> Box { + box { (**self).clone() } + } /// Copies `source`'s contents into `self` without creating a new allocation. /// /// # Examples @@ -312,9 +327,13 @@ impl Clone for Box { #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for Box { #[inline] - fn eq(&self, other: &Box) -> bool { PartialEq::eq(&**self, &**other) } + fn eq(&self, other: &Box) -> bool { + PartialEq::eq(&**self, &**other) + } #[inline] - fn ne(&self, other: &Box) -> bool { PartialEq::ne(&**self, &**other) } + fn ne(&self, other: &Box) -> bool { + PartialEq::ne(&**self, &**other) + } } #[stable(feature = "rust1", since = "1.0.0")] impl PartialOrd for Box { @@ -323,13 +342,21 @@ impl PartialOrd for Box { PartialOrd::partial_cmp(&**self, &**other) } #[inline] - fn lt(&self, other: &Box) -> bool { PartialOrd::lt(&**self, &**other) } + fn lt(&self, other: &Box) -> bool { + PartialOrd::lt(&**self, &**other) + } #[inline] - fn le(&self, other: &Box) -> bool { PartialOrd::le(&**self, &**other) } + fn le(&self, other: &Box) -> bool { + PartialOrd::le(&**self, &**other) + } #[inline] - fn ge(&self, other: &Box) -> bool { PartialOrd::ge(&**self, &**other) } + fn ge(&self, other: &Box) -> bool { + PartialOrd::ge(&**self, &**other) + } #[inline] - fn gt(&self, other: &Box) -> bool { PartialOrd::gt(&**self, &**other) } + fn gt(&self, other: &Box) -> bool { + PartialOrd::gt(&**self, &**other) + } } #[stable(feature = "rust1", since = "1.0.0")] impl Ord for Box { @@ -357,8 +384,7 @@ impl Box { unsafe { // Get the raw representation of the trait object let raw = Box::into_raw(self); - let to: TraitObject = - mem::transmute::<*mut Any, TraitObject>(raw); + let to: TraitObject = mem::transmute::<*mut Any, TraitObject>(raw); // Extract the data pointer Ok(Box::from_raw(to.data as *mut T)) @@ -409,23 +435,33 @@ impl fmt::Pointer for Box { impl Deref for Box { type Target = T; - fn deref(&self) -> &T { &**self } + fn deref(&self) -> &T { + &**self + } } #[stable(feature = "rust1", since = "1.0.0")] impl DerefMut for Box { - fn deref_mut(&mut self) -> &mut T { &mut **self } + fn deref_mut(&mut self) -> &mut T { + &mut **self + } } #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for Box { type Item = I::Item; - fn next(&mut self) -> Option { (**self).next() } - fn size_hint(&self) -> (usize, Option) { (**self).size_hint() } + fn next(&mut self) -> Option { + (**self).next() + } + fn size_hint(&self) -> (usize, Option) { + (**self).size_hint() + } } #[stable(feature = "rust1", since = "1.0.0")] impl DoubleEndedIterator for Box { - fn next_back(&mut self) -> Option { (**self).next_back() } + fn next_back(&mut self) -> Option { + (**self).next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Box {} @@ -509,7 +545,7 @@ impl Clone for Box<[T]> { fn clone(&self) -> Self { let mut new = BoxBuilder { data: RawVec::with_capacity(self.len()), - len: 0 + len: 0, }; let mut target = new.data.ptr(); @@ -556,9 +592,27 @@ impl Clone for Box<[T]> { } impl borrow::Borrow for Box { - fn borrow(&self) -> &T { &**self } + fn borrow(&self) -> &T { + &**self + } } impl borrow::BorrowMut for Box { - fn borrow_mut(&mut self) -> &mut T { &mut **self } + fn borrow_mut(&mut self) -> &mut T { + &mut **self + } +} + +#[stable(since = "1.5.0", feature = "smart_ptr_as_ref")] +impl AsRef for Box { + fn as_ref(&self) -> &T { + &**self + } +} + +#[stable(since = "1.5.0", feature = "smart_ptr_as_ref")] +impl AsMut for Box { + fn as_mut(&mut self) -> &mut T { + &mut **self + } } diff --git a/src/liballoc/boxed_test.rs b/src/liballoc/boxed_test.rs index 2ef23b26a5..7f3dadcf24 100644 --- a/src/liballoc/boxed_test.rs +++ b/src/liballoc/boxed_test.rs @@ -34,12 +34,16 @@ fn any_move() { let b = Box::new(Test) as Box; match a.downcast::() { - Ok(a) => { assert!(a == Box::new(8)); } - Err(..) => panic!() + Ok(a) => { + assert!(a == Box::new(8)); + } + Err(..) => panic!(), } match b.downcast::() { - Ok(a) => { assert!(a == Box::new(Test)); } - Err(..) => panic!() + Ok(a) => { + assert!(a == Box::new(Test)); + } + Err(..) => panic!(), } let a = Box::new(8) as Box; @@ -70,7 +74,8 @@ fn test_show() { #[test] fn deref() { - fn homura>(_: T) { } + fn homura>(_: T) { + } homura(Box::new(765)); } diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index 10cb84d1da..6961702cbc 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -22,18 +22,24 @@ extern { #[allocator] fn __rust_allocate(size: usize, align: usize) -> *mut u8; fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize); - fn __rust_reallocate(ptr: *mut u8, old_size: usize, size: usize, - align: usize) -> *mut u8; - fn __rust_reallocate_inplace(ptr: *mut u8, old_size: usize, size: usize, - align: usize) -> usize; + fn __rust_reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8; + fn __rust_reallocate_inplace(ptr: *mut u8, + old_size: usize, + size: usize, + align: usize) + -> usize; fn __rust_usable_size(size: usize, align: usize) -> usize; } #[inline(always)] fn check_size_and_alignment(size: usize, align: usize) { debug_assert!(size != 0); - debug_assert!(size <= isize::MAX as usize, "Tried to allocate too much: {} bytes", size); - debug_assert!(usize::is_power_of_two(align), "Invalid alignment of allocation: {}", align); + debug_assert!(size <= isize::MAX as usize, + "Tried to allocate too much: {} bytes", + size); + debug_assert!(usize::is_power_of_two(align), + "Invalid alignment of allocation: {}", + align); } // FIXME: #13996: mark the `allocate` and `reallocate` return value as `noalias` @@ -84,8 +90,11 @@ pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usiz /// create the allocation referenced by `ptr`. The `old_size` parameter may be /// any value in range_inclusive(requested_size, usable_size). #[inline] -pub unsafe fn reallocate_inplace(ptr: *mut u8, old_size: usize, size: usize, - align: usize) -> usize { +pub unsafe fn reallocate_inplace(ptr: *mut u8, + old_size: usize, + size: usize, + align: usize) + -> usize { check_size_and_alignment(size, align); __rust_reallocate_inplace(ptr, old_size, size, align) } @@ -124,7 +133,9 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { EMPTY as *mut u8 } else { let ptr = allocate(size, align); - if ptr.is_null() { ::oom() } + if ptr.is_null() { + ::oom() + } ptr } } @@ -148,7 +159,9 @@ mod tests { unsafe { let size = 4000; let ptr = heap::allocate(size, 8); - if ptr.is_null() { ::oom() } + if ptr.is_null() { + ::oom() + } let ret = heap::reallocate_inplace(ptr, size, size, 8); heap::deallocate(ptr, size, 8); assert_eq!(ret, heap::usable_size(size, 8)); diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 1beb015364..c78ebdf434 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -90,25 +90,35 @@ #![feature(placement_in_syntax)] #![feature(placement_new_protocol)] #![feature(raw)] +#![feature(shared)] #![feature(staged_api)] #![feature(unboxed_closures)] #![feature(unique)] #![feature(unsafe_no_drop_flag, filling_drop)] +// SNAP 1af31d4 +#![allow(unused_features)] +// SNAP 1af31d4 +#![allow(unused_attributes)] +#![feature(dropck_parametricity)] #![feature(unsize)] #![feature(core_slice_ext)] #![feature(core_str_ext)] #![cfg_attr(stage0, feature(alloc_system))] #![cfg_attr(not(stage0), feature(needs_allocator))] -#![cfg_attr(test, feature(test, rustc_private))] +#![cfg_attr(test, feature(test, rustc_private, box_heap))] #[cfg(stage0)] extern crate alloc_system; // Allow testing this library -#[cfg(test)] #[macro_use] extern crate std; -#[cfg(test)] #[macro_use] extern crate log; +#[cfg(test)] +#[macro_use] +extern crate std; +#[cfg(test)] +#[macro_use] +extern crate log; // Heaps provided for low-level allocation strategies @@ -123,7 +133,9 @@ pub mod heap; #[cfg(not(test))] pub mod boxed; #[cfg(test)] -mod boxed { pub use std::boxed::{Box, HEAP}; } +mod boxed { + pub use std::boxed::{Box, HEAP}; +} #[cfg(test)] mod boxed_test; pub mod arc; diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 97acd0db52..996a590043 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -58,10 +58,17 @@ 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 { ptr: Unique::new(heap::EMPTY as *mut T), cap: cap } + RawVec { + ptr: Unique::new(heap::EMPTY as *mut T), + cap: cap, + } } } @@ -92,23 +99,31 @@ impl RawVec { } else { let align = mem::align_of::(); let ptr = heap::allocate(alloc_size, align); - if ptr.is_null() { oom() } + if ptr.is_null() { + oom() + } ptr }; - RawVec { ptr: Unique::new(ptr as *mut _), cap: cap } + RawVec { + ptr: Unique::new(ptr as *mut _), + cap: cap, + } } } /// Reconstitutes a RawVec from a pointer and capacity. /// - /// # Undefined Behaviour + /// # Undefined Behavior /// /// The ptr must be allocated, and with the given capacity. The /// capacity cannot exceed `isize::MAX` (only a concern on 32-bit systems). /// If the ptr and capacity come from a RawVec, then this is guaranteed. pub unsafe fn from_raw_parts(ptr: *mut T, cap: usize) -> Self { - RawVec { ptr: Unique::new(ptr), cap: cap } + RawVec { + ptr: Unique::new(ptr), + cap: cap, + } } /// Converts a `Box<[T]>` into a `RawVec`. @@ -133,7 +148,11 @@ impl RawVec { /// /// This will always be `usize::MAX` if `T` is zero-sized. pub fn cap(&self) -> usize { - if mem::size_of::() == 0 { !0 } else { self.cap } + if mem::size_of::() == 0 { + !0 + } else { + self.cap + } } /// Doubles the size of the type's backing allocation. This is common enough @@ -190,7 +209,11 @@ 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 { @@ -207,7 +230,9 @@ impl RawVec { }; // If allocate or reallocate fail, we'll get `null` back - if ptr.is_null() { oom() } + if ptr.is_null() { + oom() + } self.ptr = Unique::new(ptr as *mut _); self.cap = new_cap; @@ -223,7 +248,7 @@ impl RawVec { /// /// If `used_cap` exceeds `self.cap()`, this may fail to actually allocate /// the requested space. This is not really unsafe, but the unsafe - /// code *you* write that relies on the behaviour of this function may break. + /// code *you* write that relies on the behavior of this function may break. /// /// # Panics /// @@ -246,7 +271,9 @@ impl RawVec { // Don't actually need any more capacity. // Wrapping in case they gave a bad `used_cap`. - if self.cap().wrapping_sub(used_cap) >= needed_extra_cap { return; } + if self.cap().wrapping_sub(used_cap) >= needed_extra_cap { + return; + } // Nothing we can really do about these checks :( let new_cap = used_cap.checked_add(needed_extra_cap).expect("capacity overflow"); @@ -263,7 +290,9 @@ impl RawVec { }; // If allocate or reallocate fail, we'll get `null` back - if ptr.is_null() { oom() } + if ptr.is_null() { + oom() + } self.ptr = Unique::new(ptr as *mut _); self.cap = new_cap; @@ -273,12 +302,12 @@ impl RawVec { /// Ensures that the buffer contains at least enough space to hold /// `used_cap + needed_extra_cap` elements. If it doesn't already have /// enough capacity, will reallocate enough space plus comfortable slack - /// space to get amortized `O(1)` behaviour. Will limit this behaviour + /// space to get amortized `O(1)` behavior. Will limit this behavior /// if it would needlessly cause itself to panic. /// /// If `used_cap` exceeds `self.cap()`, this may fail to actually allocate /// the requested space. This is not really unsafe, but the unsafe - /// code *you* write that relies on the behaviour of this function may break. + /// code *you* write that relies on the behavior of this function may break. /// /// This is ideal for implementing a bulk-push operation like `extend`. /// @@ -326,7 +355,9 @@ impl RawVec { // Don't actually need any more capacity. // Wrapping in case they give a bas `used_cap` - if self.cap().wrapping_sub(used_cap) >= needed_extra_cap { return; } + if self.cap().wrapping_sub(used_cap) >= needed_extra_cap { + return; + } // Nothing we can really do about these checks :( let new_cap = used_cap.checked_add(needed_extra_cap) @@ -346,7 +377,9 @@ impl RawVec { }; // If allocate or reallocate fail, we'll get `null` back - if ptr.is_null() { oom() } + if ptr.is_null() { + oom() + } self.ptr = Unique::new(ptr as *mut _); self.cap = new_cap; @@ -386,7 +419,9 @@ impl RawVec { self.cap * elem_size, amount * elem_size, align); - if ptr.is_null() { oom() } + if ptr.is_null() { + oom() + } self.ptr = Unique::new(ptr as *mut _); } self.cap = amount; @@ -395,7 +430,7 @@ impl RawVec { /// Converts the entire buffer into `Box<[T]>`. /// - /// While it is not *strictly* Undefined Behaviour to call + /// While it is not *strictly* Undefined Behavior to call /// this procedure while some of the RawVec is unintialized, /// it cetainly makes it trivial to trigger it. /// @@ -418,6 +453,7 @@ impl RawVec { } impl Drop for RawVec { + #[unsafe_destructor_blind_to_params] /// Frees the memory owned by the RawVec *without* trying to Drop its contents. fn drop(&mut self) { let elem_size = mem::size_of::(); @@ -446,6 +482,7 @@ impl Drop for RawVec { #[inline] fn alloc_guard(alloc_size: usize) { if core::usize::BITS < 64 { - assert!(alloc_size <= ::core::isize::MAX as usize, "capacity overflow"); + assert!(alloc_size <= ::core::isize::MAX as usize, + "capacity overflow"); } } diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 4fe474cef0..d695c0edd1 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -163,9 +163,8 @@ use core::hash::{Hasher, Hash}; use core::intrinsics::{assume, drop_in_place, abort}; use core::marker::{self, Unsize}; use core::mem::{self, align_of_val, size_of_val, forget}; -use core::nonzero::NonZero; use core::ops::{CoerceUnsized, Deref}; -use core::ptr; +use core::ptr::{self, Shared}; use heap::deallocate; @@ -184,12 +183,13 @@ struct RcBox { pub struct Rc { // FIXME #12808: strange names to try to avoid interfering with field // accesses of the contained type via Deref - _ptr: NonZero<*mut RcBox>, + _ptr: Shared>, } impl !marker::Send for Rc {} impl !marker::Sync for Rc {} +#[cfg(not(stage0))] // remove cfg after new snapshot impl, U: ?Sized> CoerceUnsized> for Rc {} impl Rc { @@ -210,10 +210,10 @@ impl Rc { // pointers, which ensures that the weak destructor never frees // the allocation while the strong destructor is running, even // if the weak pointer is stored inside the strong one. - _ptr: NonZero::new(Box::into_raw(box RcBox { + _ptr: Shared::new(Box::into_raw(box RcBox { strong: Cell::new(1), weak: Cell::new(1), - value: value + value: value, })), } } @@ -290,13 +290,17 @@ impl Rc { #[inline] #[unstable(feature = "rc_counts", reason = "not clearly useful", issue = "28356")] - pub fn weak_count(this: &Self) -> usize { this.weak() - 1 } + pub fn weak_count(this: &Self) -> usize { + this.weak() - 1 + } /// Get the number of strong references to this value. #[inline] #[unstable(feature = "rc_counts", reason = "not clearly useful", issue = "28356")] - pub fn strong_count(this: &Self) -> usize { this.strong() } + pub fn strong_count(this: &Self) -> usize { + this.strong() + } /// Returns true if there are no other `Rc` or `Weak` values that share /// the same inner value. @@ -447,11 +451,12 @@ impl Drop for Rc { /// /// } // implicit drop /// ``` + #[unsafe_destructor_blind_to_params] fn drop(&mut self) { unsafe { let ptr = *self._ptr; if !(*(&ptr as *const _ as *const *const ())).is_null() && - ptr as *const () as usize != mem::POST_DROP_USIZE { + ptr as *const () as usize != mem::POST_DROP_USIZE { self.dec_strong(); if self.strong() == 0 { // destroy the contained object @@ -462,9 +467,7 @@ impl Drop for Rc { self.dec_weak(); if self.weak() == 0 { - deallocate(ptr as *mut u8, - size_of_val(&*ptr), - align_of_val(&*ptr)) + deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr)) } } } @@ -530,7 +533,9 @@ impl PartialEq for Rc { /// five == Rc::new(5); /// ``` #[inline(always)] - fn eq(&self, other: &Rc) -> bool { **self == **other } + fn eq(&self, other: &Rc) -> bool { + **self == **other + } /// Inequality for two `Rc`s. /// @@ -546,7 +551,9 @@ impl PartialEq for Rc { /// five != Rc::new(5); /// ``` #[inline(always)] - fn ne(&self, other: &Rc) -> bool { **self != **other } + fn ne(&self, other: &Rc) -> bool { + **self != **other + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -586,7 +593,9 @@ impl PartialOrd for Rc { /// five < Rc::new(5); /// ``` #[inline(always)] - fn lt(&self, other: &Rc) -> bool { **self < **other } + fn lt(&self, other: &Rc) -> bool { + **self < **other + } /// 'Less-than or equal to' comparison for two `Rc`s. /// @@ -602,7 +611,9 @@ impl PartialOrd for Rc { /// five <= Rc::new(5); /// ``` #[inline(always)] - fn le(&self, other: &Rc) -> bool { **self <= **other } + fn le(&self, other: &Rc) -> bool { + **self <= **other + } /// Greater-than comparison for two `Rc`s. /// @@ -618,7 +629,9 @@ impl PartialOrd for Rc { /// five > Rc::new(5); /// ``` #[inline(always)] - fn gt(&self, other: &Rc) -> bool { **self > **other } + fn gt(&self, other: &Rc) -> bool { + **self > **other + } /// 'Greater-than or equal to' comparison for two `Rc`s. /// @@ -634,7 +647,9 @@ impl PartialOrd for Rc { /// five >= Rc::new(5); /// ``` #[inline(always)] - fn ge(&self, other: &Rc) -> bool { **self >= **other } + fn ge(&self, other: &Rc) -> bool { + **self >= **other + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -653,7 +668,9 @@ impl Ord for Rc { /// five.partial_cmp(&Rc::new(5)); /// ``` #[inline] - fn cmp(&self, other: &Rc) -> Ordering { (**self).cmp(&**other) } + fn cmp(&self, other: &Rc) -> Ordering { + (**self).cmp(&**other) + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -695,12 +712,13 @@ impl fmt::Pointer for Rc { pub struct Weak { // FIXME #12808: strange names to try to avoid interfering with // field accesses of the contained type via Deref - _ptr: NonZero<*mut RcBox>, + _ptr: Shared>, } impl !marker::Send for Weak {} impl !marker::Sync for Weak {} +#[cfg(not(stage0))] // remove cfg after new snapshot impl, U: ?Sized> CoerceUnsized> for Weak {} impl Weak { @@ -764,13 +782,12 @@ impl Drop for Weak { unsafe { let ptr = *self._ptr; if !(*(&ptr as *const _ as *const *const ())).is_null() && - ptr as *const () as usize != mem::POST_DROP_USIZE { + ptr as *const () as usize != mem::POST_DROP_USIZE { self.dec_weak(); // the weak count starts at 1, and will only go to zero if all // the strong pointers have disappeared. if self.weak() == 0 { - deallocate(ptr as *mut u8, size_of_val(&*ptr), - align_of_val(&*ptr)) + deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr)) } } } @@ -821,7 +838,9 @@ trait RcBoxPtr { fn inner(&self) -> &RcBox; #[inline] - fn strong(&self) -> usize { self.inner().strong.get() } + fn strong(&self) -> usize { + self.inner().strong.get() + } #[inline] fn inc_strong(&self) { @@ -829,10 +848,14 @@ trait RcBoxPtr { } #[inline] - fn dec_strong(&self) { self.inner().strong.set(self.strong() - 1); } + fn dec_strong(&self) { + self.inner().strong.set(self.strong() - 1); + } #[inline] - fn weak(&self) -> usize { self.inner().weak.get() } + fn weak(&self) -> usize { + self.inner().weak.get() + } #[inline] fn inc_weak(&self) { @@ -840,7 +863,9 @@ trait RcBoxPtr { } #[inline] - fn dec_weak(&self) { self.inner().weak.set(self.weak() - 1); } + fn dec_weak(&self) { + self.inner().weak.set(self.weak() - 1); + } } impl RcBoxPtr for Rc { @@ -928,7 +953,7 @@ mod tests { #[test] fn weak_self_cyclic() { struct Cycle { - x: RefCell>> + x: RefCell>>, } let a = Rc::new(Cycle { x: RefCell::new(None) }); @@ -1086,5 +1111,14 @@ mod tests { } impl borrow::Borrow for Rc { - fn borrow(&self) -> &T { &**self } + fn borrow(&self) -> &T { + &**self + } +} + +#[stable(since = "1.5.0", feature = "smart_ptr_as_ref")] +impl AsRef for Rc { + fn as_ref(&self) -> &T { + &**self + } } diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index 4179cbe8a7..f46b12e80c 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -27,23 +27,27 @@ extern crate libc; use libc::{c_int, c_void, size_t}; +// 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"))] extern { fn je_mallocx(size: size_t, flags: c_int) -> *mut c_void; fn je_rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void; - fn je_xallocx(ptr: *mut c_void, size: size_t, extra: size_t, - flags: c_int) -> size_t; + fn je_xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t; fn je_sdallocx(ptr: *mut c_void, size: size_t, flags: c_int); fn je_nallocx(size: size_t, flags: c_int) -> size_t; } -// -lpthread needs to occur after -ljemalloc, the earlier argument isn't enough -#[cfg(all(not(windows), - not(target_os = "android"), - not(target_env = "musl")))] -#[link(name = "pthread")] -extern {} - // 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. @@ -58,40 +62,52 @@ const MIN_ALIGN: usize = 8; const MIN_ALIGN: usize = 16; // MALLOCX_ALIGN(a) macro -fn mallocx_align(a: usize) -> c_int { a.trailing_zeros() as c_int } +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) } + if align <= MIN_ALIGN { + 0 + } else { + mallocx_align(align) + } } #[no_mangle] -pub extern fn __rust_allocate(size: usize, align: usize) -> *mut u8 { +pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 { let flags = align_to_flags(align); unsafe { je_mallocx(size as size_t, flags) as *mut u8 } } #[no_mangle] -pub extern fn __rust_reallocate(ptr: *mut u8, _old_size: usize, size: usize, - align: usize) -> *mut u8 { +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 { je_rallocx(ptr as *mut c_void, size as size_t, flags) as *mut u8 } } #[no_mangle] -pub extern fn __rust_reallocate_inplace(ptr: *mut u8, _old_size: usize, - size: usize, align: usize) -> usize { +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 { je_xallocx(ptr as *mut c_void, size as size_t, 0, flags) as usize } } #[no_mangle] -pub extern fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) { +pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) { let flags = align_to_flags(align); unsafe { je_sdallocx(ptr as *mut c_void, old_size as size_t, flags) } } #[no_mangle] -pub extern fn __rust_usable_size(size: usize, align: usize) -> usize { +pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize { let flags = align_to_flags(align); unsafe { je_nallocx(size as size_t, flags) as usize } } diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index aff4bea19e..c447dfbec4 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -39,29 +39,35 @@ const MIN_ALIGN: usize = 8; const MIN_ALIGN: usize = 16; #[no_mangle] -pub extern fn __rust_allocate(size: usize, align: usize) -> *mut u8 { +pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 { unsafe { imp::allocate(size, align) } } #[no_mangle] -pub extern fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) { +pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) { unsafe { imp::deallocate(ptr, old_size, align) } } #[no_mangle] -pub extern fn __rust_reallocate(ptr: *mut u8, old_size: usize, size: usize, - align: usize) -> *mut u8 { +pub extern "C" fn __rust_reallocate(ptr: *mut u8, + old_size: usize, + size: usize, + align: usize) + -> *mut u8 { unsafe { imp::reallocate(ptr, old_size, size, align) } } #[no_mangle] -pub extern fn __rust_reallocate_inplace(ptr: *mut u8, old_size: usize, - size: usize, align: usize) -> usize { +pub extern "C" fn __rust_reallocate_inplace(ptr: *mut u8, + old_size: usize, + size: usize, + align: usize) + -> usize { unsafe { imp::reallocate_inplace(ptr, old_size, size, align) } } #[no_mangle] -pub extern fn __rust_usable_size(size: usize, align: usize) -> usize { +pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize { imp::usable_size(size, align) } @@ -80,7 +86,8 @@ mod imp { #[cfg(not(target_os = "android"))] fn posix_memalign(memptr: *mut *mut libc::c_void, align: libc::size_t, - size: libc::size_t) -> libc::c_int; + size: libc::size_t) + -> libc::c_int; } pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 { @@ -94,9 +101,7 @@ mod imp { #[cfg(not(target_os = "android"))] unsafe fn more_aligned_malloc(size: usize, align: usize) -> *mut u8 { let mut out = ptr::null_mut(); - let ret = posix_memalign(&mut out, - align as libc::size_t, - size as libc::size_t); + let ret = posix_memalign(&mut out, align as libc::size_t, size as libc::size_t); if ret != 0 { ptr::null_mut() } else { @@ -107,8 +112,7 @@ mod imp { } } - pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, - align: usize) -> *mut u8 { + pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 { if align <= MIN_ALIGN { libc::realloc(ptr as *mut libc::c_void, size as libc::size_t) as *mut u8 } else { @@ -119,8 +123,11 @@ mod imp { } } - pub unsafe fn reallocate_inplace(_ptr: *mut u8, old_size: usize, _size: usize, - _align: usize) -> usize { + pub unsafe fn reallocate_inplace(_ptr: *mut u8, + old_size: usize, + _size: usize, + _align: usize) + -> usize { old_size } @@ -141,8 +148,7 @@ mod imp { extern "system" { fn GetProcessHeap() -> HANDLE; fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID; - fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, - 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; } @@ -165,32 +171,45 @@ mod imp { if align <= MIN_ALIGN { HeapAlloc(GetProcessHeap(), 0, size as SIZE_T) as *mut u8 } else { - let ptr = HeapAlloc(GetProcessHeap(), 0, - (size + align) as SIZE_T) as *mut u8; - if ptr.is_null() { return ptr } + let ptr = HeapAlloc(GetProcessHeap(), 0, (size + align) as SIZE_T) as *mut u8; + if ptr.is_null() { + return ptr + } align_ptr(ptr, align) } } - pub unsafe fn reallocate(ptr: *mut u8, _old_size: usize, size: usize, - align: usize) -> *mut u8 { + pub unsafe fn reallocate(ptr: *mut u8, _old_size: usize, size: usize, align: usize) -> *mut u8 { if align <= MIN_ALIGN { HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, size as SIZE_T) as *mut u8 } else { let header = get_header(ptr); - let new = HeapReAlloc(GetProcessHeap(), 0, header.0 as LPVOID, + let new = HeapReAlloc(GetProcessHeap(), + 0, + header.0 as LPVOID, (size + align) as SIZE_T) as *mut u8; - if new.is_null() { return new } + if new.is_null() { + return new + } align_ptr(new, align) } } - pub unsafe fn reallocate_inplace(ptr: *mut u8, old_size: usize, size: usize, - align: usize) -> usize { + pub unsafe fn reallocate_inplace(ptr: *mut u8, + old_size: usize, + size: usize, + align: usize) + -> usize { if align <= MIN_ALIGN { - let new = HeapReAlloc(GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY, - ptr as LPVOID, size as SIZE_T) as *mut u8; - if new.is_null() { old_size } else { size } + let new = HeapReAlloc(GetProcessHeap(), + HEAP_REALLOC_IN_PLACE_ONLY, + ptr as LPVOID, + size as SIZE_T) as *mut u8; + if new.is_null() { + old_size + } else { + size + } } else { old_size } diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index 57e82720e8..5bc1c44e1b 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -38,8 +38,14 @@ #![feature(ptr_as_ref)] #![feature(raw)] #![feature(staged_api)] +#![feature(dropck_parametricity)] #![cfg_attr(test, feature(test))] +// SNAP 1af31d4 +#![allow(unused_features)] +// SNAP 1af31d4 +#![allow(unused_attributes)] + extern crate alloc; use std::cell::{Cell, RefCell}; @@ -99,7 +105,7 @@ pub struct Arena<'longer_than_self> { head: RefCell, copy_head: RefCell, chunks: RefCell>, - _marker: marker::PhantomData<*mut &'longer_than_self()>, + _marker: marker::PhantomData<*mut &'longer_than_self ()>, } impl<'a> Arena<'a> { @@ -191,7 +197,7 @@ fn un_bitpack_tydesc_ptr(p: usize) -> (*const TyDesc, bool) { struct TyDesc { drop_glue: fn(*const i8), size: usize, - align: usize + align: usize, } trait AllTypes { fn dummy(&self) { } } @@ -218,8 +224,7 @@ impl<'longer_than_self> Arena<'longer_than_self> { let new_min_chunk_size = cmp::max(n_bytes, self.chunk_size()); self.chunks.borrow_mut().push(self.copy_head.borrow().clone()); - *self.copy_head.borrow_mut() = - chunk((new_min_chunk_size + 1).next_power_of_two(), true); + *self.copy_head.borrow_mut() = chunk((new_min_chunk_size + 1).next_power_of_two(), true); self.alloc_copy_inner(n_bytes, align) } @@ -236,16 +241,15 @@ impl<'longer_than_self> Arena<'longer_than_self> { let copy_head = self.copy_head.borrow(); copy_head.fill.set(end); - unsafe { - copy_head.as_ptr().offset(start as isize) - } + unsafe { copy_head.as_ptr().offset(start as isize) } } #[inline] - fn alloc_copy(&self, op: F) -> &mut T where F: FnOnce() -> T { + fn alloc_copy(&self, op: F) -> &mut T + where F: FnOnce() -> T + { unsafe { - let ptr = self.alloc_copy_inner(mem::size_of::(), - mem::align_of::()); + let ptr = self.alloc_copy_inner(mem::size_of::(), mem::align_of::()); let ptr = ptr as *mut T; ptr::write(&mut (*ptr), op()); &mut *ptr @@ -253,21 +257,18 @@ impl<'longer_than_self> Arena<'longer_than_self> { } // Functions for the non-POD part of the arena - fn alloc_noncopy_grow(&self, n_bytes: usize, - align: usize) -> (*const u8, *const u8) { + fn alloc_noncopy_grow(&self, n_bytes: usize, align: usize) -> (*const u8, *const u8) { // Allocate a new chunk. let new_min_chunk_size = cmp::max(n_bytes, self.chunk_size()); self.chunks.borrow_mut().push(self.head.borrow().clone()); - *self.head.borrow_mut() = - chunk((new_min_chunk_size + 1).next_power_of_two(), false); + *self.head.borrow_mut() = chunk((new_min_chunk_size + 1).next_power_of_two(), false); self.alloc_noncopy_inner(n_bytes, align) } #[inline] - fn alloc_noncopy_inner(&self, n_bytes: usize, - align: usize) -> (*const u8, *const u8) { + fn alloc_noncopy_inner(&self, n_bytes: usize, align: usize) -> (*const u8, *const u8) { // Be careful to not maintain any `head` borrows active, because // `alloc_noncopy_grow` borrows it mutably. let (start, end, tydesc_start, head_capacity) = { @@ -291,24 +292,25 @@ impl<'longer_than_self> Arena<'longer_than_self> { unsafe { let buf = head.as_ptr(); - (buf.offset(tydesc_start as isize), buf.offset(start as isize)) + (buf.offset(tydesc_start as isize), + buf.offset(start as isize)) } } #[inline] - fn alloc_noncopy(&self, op: F) -> &mut T where F: FnOnce() -> T { + fn alloc_noncopy(&self, op: F) -> &mut T + where F: FnOnce() -> T + { unsafe { let tydesc = get_tydesc::(); - let (ty_ptr, ptr) = - self.alloc_noncopy_inner(mem::size_of::(), - mem::align_of::()); + let (ty_ptr, ptr) = self.alloc_noncopy_inner(mem::size_of::(), mem::align_of::()); let ty_ptr = ty_ptr as *mut usize; let ptr = ptr as *mut T; // Write in our tydesc along with a bit indicating that it // has *not* been initialized yet. *ty_ptr = bitpack_tydesc_ptr(tydesc, false); // Actually initialize it - ptr::write(&mut(*ptr), op()); + ptr::write(&mut (*ptr), op()); // Now that we are done, update the tydesc to indicate that // the object is there. *ty_ptr = bitpack_tydesc_ptr(tydesc, true); @@ -320,7 +322,9 @@ impl<'longer_than_self> Arena<'longer_than_self> { /// Allocates a new item in the arena, using `op` to initialize the value, /// and returns a reference to it. #[inline] - pub fn alloc(&self, op: F) -> &mut T where F: FnOnce() -> T { + pub fn alloc(&self, op: F) -> &mut T + where F: FnOnce() -> T + { unsafe { if intrinsics::needs_drop::() { self.alloc_noncopy(op) @@ -352,10 +356,10 @@ fn test_arena_destructors_fail() { for i in 0..10 { // Arena allocate something with drop glue to make sure it // doesn't leak. - arena.alloc(|| { Rc::new(i) }); + arena.alloc(|| Rc::new(i)); // Allocate something with funny size and alignment, to keep // things interesting. - arena.alloc(|| { [0u8, 1, 2] }); + arena.alloc(|| [0u8, 1, 2]); } // Now, panic while allocating arena.alloc::, _>(|| { @@ -403,12 +407,13 @@ fn calculate_size(capacity: usize) -> usize { impl TypedArenaChunk { #[inline] - unsafe fn new(next: *mut TypedArenaChunk, capacity: usize) - -> *mut TypedArenaChunk { + unsafe fn new(next: *mut TypedArenaChunk, capacity: usize) -> *mut TypedArenaChunk { let size = calculate_size::(capacity); - let chunk = allocate(size, mem::align_of::>()) - as *mut TypedArenaChunk; - if chunk.is_null() { alloc::oom() } + let chunk = + allocate(size, mem::align_of::>()) as *mut TypedArenaChunk; + if chunk.is_null() { + alloc::oom() + } (*chunk).next = next; (*chunk).capacity = capacity; chunk @@ -431,7 +436,8 @@ impl TypedArenaChunk { let next = self.next; let size = calculate_size::(self.capacity); let self_ptr: *mut TypedArenaChunk = self; - deallocate(self_ptr as *mut u8, size, + deallocate(self_ptr as *mut u8, + size, mem::align_of::>()); if !next.is_null() { let capacity = (*next).capacity; @@ -443,9 +449,7 @@ impl TypedArenaChunk { #[inline] fn start(&self) -> *const u8 { let this: *const TypedArenaChunk = self; - unsafe { - round_up(this.offset(1) as usize, mem::align_of::()) as *const u8 - } + unsafe { round_up(this.offset(1) as usize, mem::align_of::()) as *const u8 } } // Returns a pointer to the end of the allocated space. @@ -510,6 +514,7 @@ impl TypedArena { } impl Drop for TypedArena { + #[unsafe_destructor_blind_to_params] fn drop(&mut self) { unsafe { // Determine how much was filled. @@ -538,14 +543,21 @@ mod tests { #[test] fn test_arena_alloc_nested() { - struct Inner { value: u8 } - struct Outer<'a> { inner: &'a Inner } - enum EI<'e> { I(Inner), O(Outer<'e>) } + struct Inner { + value: u8, + } + struct Outer<'a> { + inner: &'a Inner, + } + enum EI<'e> { + I(Inner), + O(Outer<'e>), + } struct Wrap<'a>(TypedArena>); impl<'a> Wrap<'a> { - fn alloc_inner Inner>(&self, f: F) -> &Inner { + fn alloc_inner Inner>(&self, f: F) -> &Inner { let r: &EI = self.0.alloc(EI::I(f())); if let &EI::I(ref i) = r { i @@ -553,7 +565,7 @@ mod tests { panic!("mismatch"); } } - fn alloc_outer Outer<'a>>(&self, f: F) -> &Outer { + fn alloc_outer Outer<'a>>(&self, f: F) -> &Outer { let r: &EI = self.0.alloc(EI::O(f())); if let &EI::O(ref o) = r { o @@ -565,8 +577,9 @@ 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); } @@ -575,49 +588,27 @@ mod tests { pub fn test_copy() { let arena = TypedArena::new(); for _ in 0..100000 { - arena.alloc(Point { - x: 1, - y: 2, - z: 3, - }); + arena.alloc(Point { x: 1, y: 2, z: 3 }); } } #[bench] pub fn bench_copy(b: &mut Bencher) { let arena = TypedArena::new(); - b.iter(|| { - arena.alloc(Point { - x: 1, - y: 2, - z: 3, - }) - }) + b.iter(|| arena.alloc(Point { x: 1, y: 2, z: 3 })) } #[bench] pub fn bench_copy_nonarena(b: &mut Bencher) { b.iter(|| { - let _: Box<_> = box Point { - x: 1, - y: 2, - z: 3, - }; + let _: Box<_> = box Point { x: 1, y: 2, z: 3 }; }) } #[bench] pub fn bench_copy_old_arena(b: &mut Bencher) { let arena = Arena::new(); - b.iter(|| { - arena.alloc(|| { - Point { - x: 1, - y: 2, - z: 3, - } - }) - }) + b.iter(|| arena.alloc(|| Point { x: 1, y: 2, z: 3 })) } #[allow(dead_code)] @@ -632,7 +623,7 @@ mod tests { for _ in 0..100000 { arena.alloc(Noncopy { string: "hello world".to_string(), - array: vec!( 1, 2, 3, 4, 5 ), + array: vec!(1, 2, 3, 4, 5), }); } } @@ -643,7 +634,7 @@ mod tests { b.iter(|| { arena.alloc(Noncopy { string: "hello world".to_string(), - array: vec!( 1, 2, 3, 4, 5 ), + array: vec!(1, 2, 3, 4, 5), }) }) } @@ -653,7 +644,7 @@ mod tests { b.iter(|| { let _: Box<_> = box Noncopy { string: "hello world".to_string(), - array: vec!( 1, 2, 3, 4, 5 ), + array: vec!(1, 2, 3, 4, 5), }; }) } @@ -662,9 +653,11 @@ mod tests { pub fn bench_noncopy_old_arena(b: &mut Bencher) { let arena = Arena::new(); b.iter(|| { - arena.alloc(|| Noncopy { - string: "hello world".to_string(), - array: vec!( 1, 2, 3, 4, 5 ), + arena.alloc(|| { + Noncopy { + string: "hello world".to_string(), + array: vec!(1, 2, 3, 4, 5), + } }) }) } diff --git a/src/libbacktrace/ChangeLog.jit b/src/libbacktrace/ChangeLog.jit index 6b60e3b3b0..5ab329c696 100644 --- a/src/libbacktrace/ChangeLog.jit +++ b/src/libbacktrace/ChangeLog.jit @@ -6,7 +6,7 @@ * configure.ac: Add --enable-host-shared. * configure: Regenerate. - + Copyright (C) 2013-2014 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, diff --git a/src/libbacktrace/Makefile.am b/src/libbacktrace/Makefile.am index c5f0dcbcf7..ea78c70163 100644 --- a/src/libbacktrace/Makefile.am +++ b/src/libbacktrace/Makefile.am @@ -6,12 +6,12 @@ # met: # (1) Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. +# notice, this list of conditions and the following disclaimer. # (2) Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the -# distribution. +# distribution. # (3) The name of the author may not be used to # endorse or promote products derived from this software without diff --git a/src/libbacktrace/Makefile.in b/src/libbacktrace/Makefile.in index b434d76edb..16b1a72712 100644 --- a/src/libbacktrace/Makefile.in +++ b/src/libbacktrace/Makefile.in @@ -23,12 +23,12 @@ # met: # (1) Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. +# notice, this list of conditions and the following disclaimer. # (2) Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the -# distribution. +# distribution. # (3) The name of the author may not be used to # endorse or promote products derived from this software without @@ -137,10 +137,10 @@ LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(libbacktrace_la_SOURCES) $(EXTRA_libbacktrace_la_SOURCES) \ $(btest_SOURCES) $(stest_SOURCES) -MULTISRCTOP = -MULTIBUILDTOP = -MULTIDIRS = -MULTISUBDIR = +MULTISRCTOP = +MULTIBUILDTOP = +MULTIDIRS = +MULTISUBDIR = MULTIDO = true MULTICLEAN = true am__can_run_installinfo = \ @@ -389,7 +389,7 @@ config.h: stamp-h1 stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status @rm -f stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status config.h -$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) +$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) rm -f stamp-h1 touch $@ @@ -407,7 +407,7 @@ clean-noinstLTLIBRARIES: echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done -libbacktrace.la: $(libbacktrace_la_OBJECTS) $(libbacktrace_la_DEPENDENCIES) $(EXTRA_libbacktrace_la_DEPENDENCIES) +libbacktrace.la: $(libbacktrace_la_OBJECTS) $(libbacktrace_la_DEPENDENCIES) $(EXTRA_libbacktrace_la_DEPENDENCIES) $(LINK) $(libbacktrace_la_OBJECTS) $(libbacktrace_la_LIBADD) $(LIBS) clean-checkPROGRAMS: @@ -418,10 +418,10 @@ clean-checkPROGRAMS: list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list -btest$(EXEEXT): $(btest_OBJECTS) $(btest_DEPENDENCIES) $(EXTRA_btest_DEPENDENCIES) +btest$(EXEEXT): $(btest_OBJECTS) $(btest_DEPENDENCIES) $(EXTRA_btest_DEPENDENCIES) @rm -f btest$(EXEEXT) $(btest_LINK) $(btest_OBJECTS) $(btest_LDADD) $(LIBS) -stest$(EXEEXT): $(stest_OBJECTS) $(stest_DEPENDENCIES) $(EXTRA_stest_DEPENDENCIES) +stest$(EXEEXT): $(stest_OBJECTS) $(stest_DEPENDENCIES) $(EXTRA_stest_DEPENDENCIES) @rm -f stest$(EXEEXT) $(LINK) $(stest_OBJECTS) $(stest_LDADD) $(LIBS) diff --git a/src/libbacktrace/alloc.c b/src/libbacktrace/alloc.c index 143ef68ca5..c9d6a1406b 100644 --- a/src/libbacktrace/alloc.c +++ b/src/libbacktrace/alloc.c @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/libbacktrace/atomic.c b/src/libbacktrace/atomic.c index fdd2490da7..40e4ff93cf 100644 --- a/src/libbacktrace/atomic.c +++ b/src/libbacktrace/atomic.c @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/libbacktrace/backtrace-supported.h.in b/src/libbacktrace/backtrace-supported.h.in index ab051a1689..976963e710 100644 --- a/src/libbacktrace/backtrace-supported.h.in +++ b/src/libbacktrace/backtrace-supported.h.in @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/libbacktrace/backtrace.c b/src/libbacktrace/backtrace.c index d352d27a40..8941375c6c 100644 --- a/src/libbacktrace/backtrace.c +++ b/src/libbacktrace/backtrace.c @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/libbacktrace/backtrace.h b/src/libbacktrace/backtrace.h index 50dcd40751..f16ee36cbc 100644 --- a/src/libbacktrace/backtrace.h +++ b/src/libbacktrace/backtrace.h @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/libbacktrace/btest.c b/src/libbacktrace/btest.c index 9821e34c0c..a950a704f0 100644 --- a/src/libbacktrace/btest.c +++ b/src/libbacktrace/btest.c @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. @@ -460,7 +460,7 @@ f23 (int f1line, int f2line) (unsigned int) bdata.index, j + 1); bdata.failed = 1; } - } + } check ("test3", 0, all, f3line, "f23", &bdata.failed); check ("test3", 1, all, f2line, "f22", &bdata.failed); diff --git a/src/libbacktrace/configure.ac b/src/libbacktrace/configure.ac index a0e487bb42..30d890ef14 100644 --- a/src/libbacktrace/configure.ac +++ b/src/libbacktrace/configure.ac @@ -6,13 +6,13 @@ # met: # (1) Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. +# notice, this list of conditions and the following disclaimer. # (2) Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the -# distribution. - +# distribution. + # (3) The name of the author may not be used to # endorse or promote products derived from this software without # specific prior written permission. diff --git a/src/libbacktrace/dwarf.c b/src/libbacktrace/dwarf.c index 54e5ace9b4..fd3beac01f 100644 --- a/src/libbacktrace/dwarf.c +++ b/src/libbacktrace/dwarf.c @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. @@ -1246,7 +1246,7 @@ add_unit_ranges (struct backtrace_state *state, uintptr_t base_address, static int find_address_ranges (struct backtrace_state *state, uintptr_t base_address, - struct dwarf_buf *unit_buf, + struct dwarf_buf *unit_buf, const unsigned char *dwarf_str, size_t dwarf_str_size, const unsigned char *dwarf_ranges, size_t dwarf_ranges_size, @@ -1605,7 +1605,7 @@ read_line_header (struct backtrace_state *state, struct unit *u, if (!advance (line_buf, hdrlen)) return 0; - + hdr->min_insn_len = read_byte (&hdr_buf); if (hdr->version < 4) hdr->max_ops_per_insn = 1; @@ -1614,7 +1614,7 @@ read_line_header (struct backtrace_state *state, struct unit *u, /* We don't care about default_is_stmt. */ read_byte (&hdr_buf); - + hdr->line_base = read_sbyte (&hdr_buf); hdr->line_range = read_byte (&hdr_buf); diff --git a/src/libbacktrace/dwarf2.def b/src/libbacktrace/dwarf2.def index 71a37b30c9..932ce86435 100644 --- a/src/libbacktrace/dwarf2.def +++ b/src/libbacktrace/dwarf2.def @@ -47,27 +47,27 @@ /* This file declares various DWARF-related constants using a set of macros which can be redefined by the including file. - + The macros are in sections. Each section corresponds to a single set of DWARF constants and has a corresponding key. The key is used in all the macro names. - + The sections are TAG (for DW_TAG_ constants), FORM (DW_FORM_), AT (DW_AT_), OP (DW_OP_), ATE (DW_ATE_), and CFA (DW_CFA_). - + Using TAG as an example, the following macros may be used for each key: - + DW_FIRST_TAG(name, value) - Introduce the first DW_TAG constant. - + DW_TAG(name, value) - Define a subsequent constant. - + DW_TAG_DUP(name, value) - Define a subsequent constant whose value is a duplicate of some other constant. Not all keys use the _DUP macro form. If more than one name shares a value, then the base (DW_TAG) form will be the preferred name and DW_TAG_DUP will hold any alternate names. - + DW_END_TAG - Invoked at the end of the DW_TAG constants. */ DW_FIRST_TAG (DW_TAG_padding, 0x00) diff --git a/src/libbacktrace/dwarf2.h b/src/libbacktrace/dwarf2.h index 120e2c16b4..c7d49ebb24 100644 --- a/src/libbacktrace/dwarf2.h +++ b/src/libbacktrace/dwarf2.h @@ -352,7 +352,7 @@ enum dwarf_macro_record_type DW_MACRO_GNU_lo_user = 0xe0, DW_MACRO_GNU_hi_user = 0xff }; - + /* @@@ For use with GNU frame unwind information. */ #define DW_EH_PE_absptr 0x00 diff --git a/src/libbacktrace/elf.c b/src/libbacktrace/elf.c index 3f14b11a43..f0709c9c35 100644 --- a/src/libbacktrace/elf.c +++ b/src/libbacktrace/elf.c @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/libbacktrace/fileline.c b/src/libbacktrace/fileline.c index 0acad0603e..c151147213 100644 --- a/src/libbacktrace/fileline.c +++ b/src/libbacktrace/fileline.c @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/libbacktrace/internal.h b/src/libbacktrace/internal.h index 30f99ca127..f6046ee605 100644 --- a/src/libbacktrace/internal.h +++ b/src/libbacktrace/internal.h @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/libbacktrace/mmap.c b/src/libbacktrace/mmap.c index 1ecf131191..610548a8a4 100644 --- a/src/libbacktrace/mmap.c +++ b/src/libbacktrace/mmap.c @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/libbacktrace/mmapio.c b/src/libbacktrace/mmapio.c index b5a787e0aa..45f81a8593 100644 --- a/src/libbacktrace/mmapio.c +++ b/src/libbacktrace/mmapio.c @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/libbacktrace/nounwind.c b/src/libbacktrace/nounwind.c index f53f906b5a..9952c0bcbf 100644 --- a/src/libbacktrace/nounwind.c +++ b/src/libbacktrace/nounwind.c @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/libbacktrace/posix.c b/src/libbacktrace/posix.c index 7fa7cd0d5d..f6260a0044 100644 --- a/src/libbacktrace/posix.c +++ b/src/libbacktrace/posix.c @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/libbacktrace/print.c b/src/libbacktrace/print.c index 90ecaf89ed..271f41c0c5 100644 --- a/src/libbacktrace/print.c +++ b/src/libbacktrace/print.c @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/libbacktrace/read.c b/src/libbacktrace/read.c index 299f77ba7c..70dd91ee97 100644 --- a/src/libbacktrace/read.c +++ b/src/libbacktrace/read.c @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/libbacktrace/simple.c b/src/libbacktrace/simple.c index 39c2e902ff..fc0f4f4980 100644 --- a/src/libbacktrace/simple.c +++ b/src/libbacktrace/simple.c @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/libbacktrace/sort.c b/src/libbacktrace/sort.c index bcc765e93a..01b1cb2b8a 100644 --- a/src/libbacktrace/sort.c +++ b/src/libbacktrace/sort.c @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/libbacktrace/state.c b/src/libbacktrace/state.c index a846378e90..373938865c 100644 --- a/src/libbacktrace/state.c +++ b/src/libbacktrace/state.c @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/libbacktrace/stest.c b/src/libbacktrace/stest.c index ec93e680e8..5107152918 100644 --- a/src/libbacktrace/stest.c +++ b/src/libbacktrace/stest.c @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/libbacktrace/unknown.c b/src/libbacktrace/unknown.c index e89cba96f7..953e96e510 100644 --- a/src/libbacktrace/unknown.c +++ b/src/libbacktrace/unknown.c @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index a3e32b59b7..30fc22e400 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -167,12 +167,22 @@ use vec::{self, Vec}; /// item's ordering relative to any other item, as determined by the `Ord` /// trait, changes while it is in the heap. This is normally only possible /// through `Cell`, `RefCell`, global state, I/O, or unsafe code. -#[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct BinaryHeap { data: Vec, } +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for BinaryHeap { + fn clone(&self) -> Self { + BinaryHeap { data: self.data.clone() } + } + + fn clone_from(&mut self, source: &Self) { + self.data.clone_from(&source.data); + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Default for BinaryHeap { #[inline] @@ -230,14 +240,9 @@ impl BinaryHeap { #[unstable(feature = "binary_heap_extras", reason = "needs to be audited", issue = "28147")] + #[deprecated(since = "1.5.0", reason = "use BinaryHeap::from instead")] pub fn from_vec(vec: Vec) -> BinaryHeap { - let mut heap = BinaryHeap { data: vec }; - let mut n = heap.len() / 2; - while n > 0 { - n -= 1; - heap.sift_down(n); - } - heap + BinaryHeap::from(vec) } /// Returns an iterator visiting all values in the underlying vector, in @@ -246,10 +251,8 @@ impl BinaryHeap { /// # Examples /// /// ``` - /// #![feature(binary_heap_extras)] - /// /// use std::collections::BinaryHeap; - /// let heap = BinaryHeap::from_vec(vec![1, 2, 3, 4]); + /// let heap = BinaryHeap::from(vec![1, 2, 3, 4]); /// /// // Print 1, 2, 3, 4 in arbitrary order /// for x in heap.iter() { @@ -352,10 +355,8 @@ impl BinaryHeap { /// # Examples /// /// ``` - /// #![feature(binary_heap_extras)] - /// /// use std::collections::BinaryHeap; - /// let mut heap = BinaryHeap::from_vec(vec![1, 3]); + /// let mut heap = BinaryHeap::from(vec![1, 3]); /// /// assert_eq!(heap.pop(), Some(3)); /// assert_eq!(heap.pop(), Some(1)); @@ -465,10 +466,8 @@ impl BinaryHeap { /// # Examples /// /// ``` - /// #![feature(binary_heap_extras)] - /// /// use std::collections::BinaryHeap; - /// let heap = BinaryHeap::from_vec(vec![1, 2, 3, 4, 5, 6, 7]); + /// let heap = BinaryHeap::from(vec![1, 2, 3, 4, 5, 6, 7]); /// let vec = heap.into_vec(); /// /// // Will print in some order @@ -476,10 +475,10 @@ impl BinaryHeap { /// println!("{}", x); /// } /// ``` - #[unstable(feature = "binary_heap_extras", - reason = "needs to be audited", - issue = "28147")] - pub fn into_vec(self) -> Vec { self.data } + #[stable(feature = "binary_heap_extras_15", since = "1.5.0")] + pub fn into_vec(self) -> Vec { + self.into() + } /// Consumes the `BinaryHeap` and returns a vector in sorted /// (ascending) order. @@ -487,20 +486,16 @@ impl BinaryHeap { /// # Examples /// /// ``` - /// #![feature(binary_heap_extras)] - /// /// use std::collections::BinaryHeap; /// - /// let mut heap = BinaryHeap::from_vec(vec![1, 2, 4, 5, 7]); + /// let mut heap = BinaryHeap::from(vec![1, 2, 4, 5, 7]); /// heap.push(6); /// heap.push(3); /// /// let vec = heap.into_sorted_vec(); /// assert_eq!(vec, [1, 2, 3, 4, 5, 6, 7]); /// ``` - #[unstable(feature = "binary_heap_extras", - reason = "needs to be audited", - issue = "28147")] + #[stable(feature = "binary_heap_extras_15", since = "1.5.0")] pub fn into_sorted_vec(mut self) -> Vec { let mut end = self.len(); while end > 1 { @@ -734,10 +729,28 @@ impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> {} +impl From> for BinaryHeap { + fn from(vec: Vec) -> BinaryHeap { + let mut heap = BinaryHeap { data: vec }; + let mut n = heap.len() / 2; + while n > 0 { + n -= 1; + heap.sift_down(n); + } + heap + } +} + +impl From> for Vec { + fn from(heap: BinaryHeap) -> Vec { + heap.data + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl FromIterator for BinaryHeap { fn from_iter>(iter: I) -> BinaryHeap { - BinaryHeap::from_vec(iter.into_iter().collect()) + BinaryHeap::from(iter.into_iter().collect::>()) } } @@ -753,10 +766,8 @@ impl IntoIterator for BinaryHeap { /// # Examples /// /// ``` - /// #![feature(binary_heap_extras)] - /// /// use std::collections::BinaryHeap; - /// let heap = BinaryHeap::from_vec(vec![1, 2, 3, 4]); + /// let heap = BinaryHeap::from(vec![1, 2, 3, 4]); /// /// // Print 1, 2, 3, 4 in arbitrary order /// for x in heap.into_iter() { diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index aedfbe546d..1ad836f9bd 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -315,8 +315,14 @@ impl BTreeMap { // 2) While ODS may potentially return the pair we *just* inserted after // the split, we will never do this. Again, this shouldn't effect the analysis. - /// Inserts a key-value pair into the map. If the key already had a value - /// present in the map, that value is returned. Otherwise, `None` is returned. + /// Inserts a key-value pair into the map. + /// + /// If the map did not have this key present, `None` is returned. + /// + /// If the map did have this key present, that value is returned, and the + /// entry is not updated. See the [module-level documentation] for more. + /// + /// [module-level documentation]: index.html#insert-and-complex-keys /// /// # Examples /// @@ -593,7 +599,7 @@ mod stack { top: node::Handle<*mut Node, Type, NodeType>, } - /// A `PartialSearchStack` that doesn't hold a a reference to the next node, and is just + /// A `PartialSearchStack` that doesn't hold a reference to the next node, and is just /// just waiting for a `Handle` to that next node to be pushed. See `PartialSearchStack::with` /// for more details. pub struct Pusher<'id, 'a, K:'a, V:'a> { @@ -949,7 +955,7 @@ impl<'a, K: Ord, Q: ?Sized, V> Index<&'a Q> for BTreeMap } } -/// Genericises over how to get the correct type of iterator from the correct type +/// Genericizes over how to get the correct type of iterator from the correct type /// of Node ownership. trait Traverse { fn traverse(node: N) -> Self; diff --git a/src/libcollections/btree/node.rs b/src/libcollections/btree/node.rs index d8f8ca6eae..4380f315ee 100644 --- a/src/libcollections/btree/node.rs +++ b/src/libcollections/btree/node.rs @@ -164,7 +164,12 @@ fn calculate_allocation_generic(capacity: usize, is_leaf: bool) -> (usize, let (keys_size, keys_align) = (capacity * mem::size_of::(), mem::align_of::()); let (vals_size, vals_align) = (capacity * mem::size_of::(), mem::align_of::()); let (edges_size, edges_align) = if is_leaf { - (0, 1) + // allocate one edge to ensure that we don't pass size 0 to `heap::allocate` + if mem::size_of::() == 0 && mem::size_of::() == 0 { + (1, mem::align_of::>()) + } else { + (0, 1) + } } else { ((capacity + 1) * mem::size_of::>(), mem::align_of::>()) }; @@ -270,12 +275,14 @@ impl DoubleEndedIterator for RawItems { } impl Drop for RawItems { + #[unsafe_destructor_blind_to_params] fn drop(&mut self) { - for _ in self.by_ref() {} + for _ in self {} } } impl Drop for Node { + #[unsafe_destructor_blind_to_params] fn drop(&mut self) { if self.keys.is_null() || (unsafe { self.keys.get() as *const K as usize == mem::POST_DROP_USIZE }) @@ -811,7 +818,7 @@ impl Handle where } } - /// Handle an underflow in this node's child. We favour handling "to the left" because we know + /// Handle an underflow in this node's child. We favor handling "to the left" because we know /// we're empty, but our neighbour can be full. Handling to the left means when we choose to /// steal, we pop off the end of our neighbour (always fast) and "unshift" ourselves /// (always slow, but at least faster since we know we're half-empty). @@ -1414,6 +1421,7 @@ impl TraversalImpl for MoveTraversalImpl { } impl Drop for MoveTraversalImpl { + #[unsafe_destructor_blind_to_params] fn drop(&mut self) { // We need to cleanup the stored values manually, as the RawItems destructor would run // after our deallocation. diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index eb2a6d5e08..3ca0aa377c 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -430,8 +430,14 @@ impl BTreeSet { other.is_subset(self) } - /// Adds a value to the set. Returns `true` if the value was not already - /// present in the set. + /// Adds a value to the set. + /// + /// If the set did not have a value present, `true` is returned. + /// + /// If the set did have this key present, that value is returned, and the + /// entry is not updated. See the [module-level documentation] for more. + /// + /// [module-level documentation]: index.html#insert-and-complex-keys /// /// # Examples /// diff --git a/src/libcollections/enum_set.rs b/src/libcollections/enum_set.rs index 7e7e8ba235..32cd4193d8 100644 --- a/src/libcollections/enum_set.rs +++ b/src/libcollections/enum_set.rs @@ -49,16 +49,7 @@ 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 { - try!(write!(fmt, "{{")); - let mut first = true; - for e in self { - if !first { - try!(write!(fmt, ", ")); - } - try!(write!(fmt, "{:?}", e)); - first = false; - } - write!(fmt, "}}") + fmt.debug_set().entries(self).finish() } } diff --git a/src/libcollections/fmt.rs b/src/libcollections/fmt.rs index d17bd5cccf..a31ad6c109 100644 --- a/src/libcollections/fmt.rs +++ b/src/libcollections/fmt.rs @@ -218,7 +218,7 @@ //! } //! ``` //! -//! ### fmt::Display vs fmt::Debug +//! ### `fmt::Display` vs `fmt::Debug` //! //! These two formatting traits have distinct purposes: //! @@ -358,24 +358,24 @@ //! to ensure padding is applied is to format your input, then use this //! resulting string to pad your output. //! -//! ## Sign/#/0 +//! ## Sign/`#`/`0` //! //! These can all be interpreted as flags for a particular formatter. //! -//! * '+' - This is intended for numeric types and indicates that the sign +//! * `+` - This is intended for numeric types and indicates that the sign //! should always be printed. Positive signs are never printed by //! default, and the negative sign is only printed by default for the -//! `Signed` trait. This flag indicates that the correct sign (+ or -) +//! `Signed` trait. This flag indicates that the correct sign (`+` or `-`) //! should always be printed. -//! * '-' - Currently not used -//! * '#' - This flag is indicates that the "alternate" form of printing should +//! * `-` - Currently not used +//! * `#` - This flag is indicates that the "alternate" form of printing should //! be used. The alternate forms are: //! * `#?` - pretty-print the `Debug` formatting -//! * `#x` - precedes the argument with a "0x" -//! * `#X` - precedes the argument with a "0x" -//! * `#b` - precedes the argument with a "0b" -//! * `#o` - precedes the argument with a "0o" -//! * '0' - This is used to indicate for integer formats that the padding should +//! * `#x` - precedes the argument with a `0x` +//! * `#X` - precedes the argument with a `0x` +//! * `#b` - precedes the argument with a `0b` +//! * `#o` - precedes the argument with a `0o` +//! * `0` - This is used to indicate for integer formats that the padding should //! both be done with a `0` character as well as be sign-aware. A format //! like `{:08}` would yield `00000001` for the integer `1`, while the //! same format would yield `-0000001` for the integer `-1`. Notice that @@ -390,8 +390,8 @@ //! //! The default fill/alignment for non-numerics is a space and left-aligned. The //! defaults for numeric formatters is also a space but with right-alignment. If -//! the '0' flag is specified for numerics, then the implicit fill character is -//! '0'. +//! the `0` flag is specified for numerics, then the implicit fill character is +//! `0`. //! //! The value for the width can also be provided as a `usize` in the list of //! parameters by using the `2$` syntax indicating that the second argument is a diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index fe06e3fb20..3bb8a11c6a 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -32,14 +32,20 @@ #![allow(trivial_casts)] #![cfg_attr(test, allow(deprecated))] // rand +// SNAP 1af31d4 +#![allow(unused_features)] +// SNAP 1af31d4 +#![allow(unused_attributes)] + #![feature(alloc)] #![feature(box_patterns)] #![feature(box_syntax)] #![feature(core_intrinsics)] #![feature(core_slice_ext)] #![feature(core_str_ext)] +#![feature(fmt_internals)] +#![feature(fmt_radix)] #![feature(heap_api)] -#![feature(iter_order)] #![feature(iter_arith)] #![feature(iter_arith)] #![feature(lang_items)] @@ -47,18 +53,19 @@ #![feature(oom)] #![feature(pattern)] #![feature(ptr_as_ref)] +#![feature(ref_slice)] +#![feature(slice_bytes)] #![feature(slice_patterns)] #![feature(staged_api)] #![feature(step_by)] #![feature(str_char)] -#![feature(str_match_indices)] #![feature(unboxed_closures)] #![feature(unicode)] #![feature(unique)] +#![feature(dropck_parametricity)] #![feature(unsafe_no_drop_flag, filling_drop)] #![feature(decode_utf16)] -#![feature(utf8_error)] -#![cfg_attr(test, feature(rand, test))] +#![cfg_attr(test, feature(clone_from_slice, rand, test))] #![feature(no_std)] #![no_std] diff --git a/src/libcollections/linked_list.rs b/src/libcollections/linked_list.rs index 891e8b7b2c..fca7d3b26f 100644 --- a/src/libcollections/linked_list.rs +++ b/src/libcollections/linked_list.rs @@ -655,6 +655,7 @@ impl LinkedList { #[stable(feature = "rust1", since = "1.0.0")] impl Drop for LinkedList { + #[unsafe_destructor_blind_to_params] fn drop(&mut self) { // Dissolve the linked_list in a loop. // Just dropping the list_head can lead to stack exhaustion diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 76bdd6dbea..ea4830fc3e 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -106,6 +106,7 @@ pub use core::slice::{Chunks, Windows}; pub use core::slice::{Iter, IterMut}; pub use core::slice::{SplitMut, ChunksMut, Split}; pub use core::slice::{SplitN, RSplitN, SplitNMut, RSplitNMut}; +#[allow(deprecated)] pub use core::slice::{bytes, mut_ref_slice, ref_slice}; pub use core::slice::{from_raw_parts, from_raw_parts_mut}; @@ -214,21 +215,21 @@ impl [T] { } /// Returns the first and all the rest of the elements of a slice. - #[unstable(feature = "slice_splits", reason = "new API", issue = "27742")] + #[stable(feature = "slice_splits", since = "1.5.0")] #[inline] pub fn split_first(&self) -> Option<(&T, &[T])> { core_slice::SliceExt::split_first(self) } /// Returns the first and all the rest of the elements of a slice. - #[unstable(feature = "slice_splits", reason = "new API", issue = "27742")] + #[stable(feature = "slice_splits", since = "1.5.0")] #[inline] pub fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> { core_slice::SliceExt::split_first_mut(self) } /// Returns the last and all the rest of the elements of a slice. - #[unstable(feature = "slice_splits", reason = "new API", issue = "27742")] + #[stable(feature = "slice_splits", since = "1.5.0")] #[inline] pub fn split_last(&self) -> Option<(&T, &[T])> { core_slice::SliceExt::split_last(self) @@ -236,7 +237,7 @@ impl [T] { } /// Returns the last and all the rest of the elements of a slice. - #[unstable(feature = "slice_splits", reason = "new API", issue = "27742")] + #[stable(feature = "slice_splits", since = "1.5.0")] #[inline] pub fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> { core_slice::SliceExt::split_last_mut(self) @@ -455,6 +456,8 @@ impl [T] { /// the index `mid` itself) and the second will contain all /// indices from `[mid, len)` (excluding the index `len` itself). /// + /// # Panics + /// /// Panics if `mid > len`. /// /// # Examples diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index fbb6c279bb..21406354d8 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -38,6 +38,7 @@ use slice::SliceConcatExt; use boxed::Box; pub use core::str::{FromStr, Utf8Error}; +#[allow(deprecated)] pub use core::str::{Lines, LinesAny, CharRange}; pub use core::str::{Split, RSplit}; pub use core::str::{SplitN, RSplitN}; @@ -101,7 +102,7 @@ impl> SliceConcatExt for [S] { } } -/// External iterator for a string's UTF16 codeunits. +/// External iterator for a string's UTF-16 code units. /// /// For use with the `std::iter` module. #[derive(Clone)] @@ -253,7 +254,7 @@ impl str { /// /// Returns the substring from [`begin`..`end`). /// - /// # Unsafety + /// # Safety /// /// Caller must check both UTF-8 sequence boundaries and the boundaries /// of the entire slice as well. @@ -276,8 +277,7 @@ impl str { /// Takes a bytewise mutable slice from a string. /// /// Same as `slice_unchecked`, but works with `&mut str` instead of `&str`. - #[unstable(feature = "str_slice_mut", reason = "recently added", - issue = "27793")] + #[stable(feature = "str_slice_mut", since = "1.5.0")] #[inline] pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str { core_str::StrExt::slice_mut_unchecked(self, begin, end) @@ -505,8 +505,6 @@ impl str { /// /// # Examples /// ``` - /// #![feature(str_split_at)] - /// /// let s = "Löwe 老虎 Léopard"; /// let first_space = s.find(' ').unwrap_or(s.len()); /// let (a, b) = s.split_at(first_space); @@ -714,8 +712,7 @@ impl str { /// Returns `None` if it doesn't exist. /// /// The pattern can be a simple `&str`, `char`, or a closure that - /// determines the - /// split. + /// determines if a character matches. /// /// # Examples /// @@ -759,7 +756,7 @@ impl str { /// Returns `None` if it doesn't exist. /// /// The pattern can be a simple `&str`, `char`, - /// or a closure that determines the split. + /// or a closure that determines if a character matches. /// /// # Examples /// @@ -869,6 +866,10 @@ impl str { /// ```rust,ignore /// assert_eq!(d, &["a", "b", "c"]); /// ``` + /// + /// Use [`.split_whitespace()`][split_whitespace] for this behavior. + /// + /// [split_whitespace]: #method.split_whitespace #[stable(feature = "rust1", since = "1.0.0")] pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> { core_str::StrExt::split(self, pat) @@ -1095,7 +1096,7 @@ impl str { /// An iterator over the matches of a pattern within `self`. /// /// The pattern can be a simple `&str`, `char`, or a closure that - /// determines the split. + /// determines if a character matches. /// Additional libraries might provide more complex patterns like /// regular expressions. /// @@ -1128,7 +1129,7 @@ impl str { /// reverse order. /// /// The pattern can be a simple `&str`, `char`, or a closure that - /// determines the split. + /// determines if a character matches. /// Additional libraries might provide more complex patterns like /// regular expressions. /// @@ -1157,26 +1158,21 @@ impl str { core_str::StrExt::rmatches(self, pat) } - /// An iterator over the start and end indices of the disjoint matches - /// of a pattern within `self`. + /// An iterator over the disjoint matches of a pattern within `self` as well + /// as the index that the match starts at. /// /// For matches of `pat` within `self` that overlap, only the indices - /// corresponding to the first - /// match are returned. + /// corresponding to the first match are returned. /// - /// The pattern can be a simple `&str`, `char`, or a closure that - /// determines - /// the split. - /// Additional libraries might provide more complex patterns like - /// regular expressions. + /// The pattern can be a simple `&str`, `char`, or a closure that determines + /// if a character matches. Additional libraries might provide more complex + /// patterns like regular expressions. /// /// # Iterator behavior /// /// The returned iterator will be double ended if the pattern allows a - /// reverse search - /// and forward/reverse search yields the same elements. This is true for, - /// eg, `char` but not - /// for `&str`. + /// reverse search and forward/reverse search yields the same elements. This + /// is true for, eg, `char` but not for `&str`. /// /// If the pattern allows a reverse search but its results might differ /// from a forward search, `rmatch_indices()` can be used. @@ -1186,43 +1182,34 @@ impl str { /// ``` /// #![feature(str_match_indices)] /// - /// let v: Vec<(usize, usize)> = "abcXXXabcYYYabc".match_indices("abc").collect(); - /// assert_eq!(v, [(0, 3), (6, 9), (12, 15)]); + /// let v: Vec<_> = "abcXXXabcYYYabc".match_indices("abc").collect(); + /// assert_eq!(v, [(0, "abc"), (6, "abc"), (12, "abc")]); /// - /// let v: Vec<(usize, usize)> = "1abcabc2".match_indices("abc").collect(); - /// assert_eq!(v, [(1, 4), (4, 7)]); + /// let v: Vec<_> = "1abcabc2".match_indices("abc").collect(); + /// assert_eq!(v, [(1, "abc"), (4, "abc")]); /// - /// let v: Vec<(usize, usize)> = "ababa".match_indices("aba").collect(); - /// assert_eq!(v, [(0, 3)]); // only the first `aba` + /// let v: Vec<_> = "ababa".match_indices("aba").collect(); + /// assert_eq!(v, [(0, "aba")]); // only the first `aba` /// ``` - #[unstable(feature = "str_match_indices", - reason = "might have its iterator type changed", - issue = "27743")] - // NB: Right now MatchIndices yields `(usize, usize)`, but it would - // be more consistent with `matches` and `char_indices` to return `(usize, &str)` + #[stable(feature = "str_match_indices", since = "1.5.0")] pub fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> { core_str::StrExt::match_indices(self, pat) } - /// An iterator over the start and end indices of the disjoint matches of - /// a pattern within - /// `self`, yielded in reverse order. + /// An iterator over the disjoint matches of a pattern within `self`, + /// yielded in reverse order along with the index of the match. /// /// For matches of `pat` within `self` that overlap, only the indices - /// corresponding to the last - /// match are returned. + /// corresponding to the last match are returned. /// - /// The pattern can be a simple `&str`, `char`, or a closure that - /// determines - /// the split. - /// Additional libraries might provide more complex patterns like - /// regular expressions. + /// The pattern can be a simple `&str`, `char`, or a closure that determines + /// if a character matches. Additional libraries might provide more complex + /// patterns like regular expressions. /// /// # Iterator behavior /// - /// The returned iterator requires that the pattern supports a - /// reverse search, - /// and it will be double ended if a forward/reverse search yields + /// The returned iterator requires that the pattern supports a reverse + /// search, and it will be double ended if a forward/reverse search yields /// the same elements. /// /// For iterating from the front, `match_indices()` can be used. @@ -1232,20 +1219,16 @@ impl str { /// ``` /// #![feature(str_match_indices)] /// - /// let v: Vec<(usize, usize)> = "abcXXXabcYYYabc".rmatch_indices("abc").collect(); - /// assert_eq!(v, [(12, 15), (6, 9), (0, 3)]); + /// let v: Vec<_> = "abcXXXabcYYYabc".rmatch_indices("abc").collect(); + /// assert_eq!(v, [(12, "abc"), (6, "abc"), (0, "abc")]); /// - /// let v: Vec<(usize, usize)> = "1abcabc2".rmatch_indices("abc").collect(); - /// assert_eq!(v, [(4, 7), (1, 4)]); + /// let v: Vec<_> = "1abcabc2".rmatch_indices("abc").collect(); + /// assert_eq!(v, [(4, "abc"), (1, "abc")]); /// - /// let v: Vec<(usize, usize)> = "ababa".rmatch_indices("aba").collect(); - /// assert_eq!(v, [(2, 5)]); // only the last `aba` + /// let v: Vec<_> = "ababa".rmatch_indices("aba").collect(); + /// assert_eq!(v, [(2, "aba")]); // only the last `aba` /// ``` - #[unstable(feature = "str_match_indices", - reason = "might have its iterator type changed", - issue = "27743")] - // NB: Right now RMatchIndices yields `(usize, usize)`, but it would - // be more consistent with `rmatches` and `char_indices` to return `(usize, &str)` + #[stable(feature = "str_match_indices", since = "1.5.0")] pub fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P> where P::Searcher: ReverseSearcher<'a> { @@ -1295,7 +1278,7 @@ impl str { /// repeatedly removed. /// /// The pattern can be a simple `char`, or a closure that determines - /// the split. + /// if a character matches. /// /// # Examples /// @@ -1325,7 +1308,7 @@ impl str { /// repeatedly removed. /// /// The pattern can be a simple `&str`, `char`, or a closure that - /// determines the split. + /// determines if a character matches. /// /// # Examples /// @@ -1345,7 +1328,7 @@ impl str { /// repeatedly removed. /// /// The pattern can be a simple `&str`, `char`, or a closure that - /// determines the split. + /// determines if a character matches. /// /// # Examples /// @@ -1418,10 +1401,10 @@ impl str { pub fn replace(&self, from: &str, to: &str) -> String { let mut result = String::new(); let mut last_end = 0; - for (start, end) in self.match_indices(from) { + for (start, part) in self.match_indices(from) { result.push_str(unsafe { self.slice_unchecked(last_end, start) }); result.push_str(to); - last_end = end; + last_end = start + part.len(); } result.push_str(unsafe { self.slice_unchecked(last_end, self.len()) }); result diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index bb65d7469a..96a28d3ee3 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -30,7 +30,7 @@ use vec::Vec; use boxed::Box; /// A growable string stored as a UTF-8 encoded buffer. -#[derive(Clone, PartialOrd, Eq, Ord)] +#[derive(PartialOrd, Eq, Ord)] #[stable(feature = "rust1", since = "1.0.0")] pub struct String { vec: Vec, @@ -92,26 +92,61 @@ impl String { panic!("not available with cfg(test)"); } - /// Returns the vector as a string buffer, if possible, taking care not to - /// copy it. + /// Converts a vector of bytes to a `String`. + /// + /// A string slice (`&str`) is made of bytes (`u8`), and a vector of bytes + /// (`Vec`) is made of bytes, so this function converts between the + /// two. Not all byte slices are valid `String`s, however: `String` + /// requires that it is valid UTF-8. `from_utf8()` checks to ensure that + /// the bytes are valid UTF-8, and then does the conversion. + /// + /// If you are sure that the byte slice is valid UTF-8, and you don't want + /// to incur the overhead of the validity check, there is an unsafe version + /// of this function, [`from_utf8_unchecked()`][fromutf8], which has the + /// same behavior but skips the check. + /// + /// [fromutf8]: struct.String.html#method.from_utf8_unchecked + /// + /// This method will take care to not copy the vector, for efficiency's + /// sake. + /// + /// If you need a `&str` instead of a `String`, consider + /// [`str::from_utf8()`][str]. + /// + /// [str]: ../str/fn.from_utf8.html /// /// # Failure /// - /// If the given vector is not valid UTF-8, then the original vector and the - /// corresponding error is returned. + /// Returns `Err` if the slice is not UTF-8 with a description as to why the + /// provided bytes are not UTF-8. The vector you moved in is also included. /// /// # Examples /// + /// Basic usage: + /// /// ``` - /// let hello_vec = vec![104, 101, 108, 108, 111]; - /// let s = String::from_utf8(hello_vec).unwrap(); - /// assert_eq!(s, "hello"); - /// - /// let invalid_vec = vec![240, 144, 128]; - /// let s = String::from_utf8(invalid_vec).err().unwrap(); - /// let err = s.utf8_error(); - /// assert_eq!(s.into_bytes(), [240, 144, 128]); + /// // some bytes, in a vector + /// let sparkle_heart = vec![240, 159, 146, 150]; + /// + /// // We know these bytes are valid, so just use `unwrap()`. + /// let sparkle_heart = String::from_utf8(sparkle_heart).unwrap(); + /// + /// assert_eq!("💖", sparkle_heart); + /// ``` + /// + /// Incorrect bytes: + /// /// ``` + /// // some invalid bytes, in a vector + /// let sparkle_heart = vec![0, 159, 146, 150]; + /// + /// assert!(String::from_utf8(sparkle_heart).is_err()); + /// ``` + /// + /// See the docs for [`FromUtf8Error`][error] for more details on what you + /// can do with this error. + /// + /// [error]: struct.FromUtf8Error.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn from_utf8(vec: Vec) -> Result { @@ -121,15 +156,49 @@ impl String { } } - /// Converts a vector of bytes to a new UTF-8 string. - /// Any invalid UTF-8 sequences are replaced with U+FFFD REPLACEMENT CHARACTER. + /// Converts a slice of bytes to a `String`, including invalid characters. + /// + /// A string slice (`&str`) is made of bytes (`u8`), and a slice of bytes + /// (`&[u8]`) is made of bytes, so this function converts between the two. + /// Not all byte slices are valid string slices, however: `&str` requires + /// that it is valid UTF-8. During this conversion, `from_utf8_lossy()` + /// will replace any invalid UTF-8 sequences with + /// `U+FFFD REPLACEMENT CHARACTER`, which looks like this: � + /// + /// If you are sure that the byte slice is valid UTF-8, and you don't want + /// to incur the overhead of the conversion, there is an unsafe version + /// of this function, [`from_utf8_unchecked()`][fromutf8], which has the + /// same behavior but skips the checks. + /// + /// [fromutf8]: struct.String.html#method.from_utf8_unchecked + /// + /// If you need a `&str` instead of a `String`, consider + /// [`str::from_utf8()`][str]. + /// + /// [str]: ../str/fn.from_utf8.html /// /// # Examples /// + /// Basic usage: + /// /// ``` + /// // some bytes, in a vector + /// let sparkle_heart = vec![240, 159, 146, 150]; + /// + /// // We know these bytes are valid, so just use `unwrap()`. + /// let sparkle_heart = String::from_utf8(sparkle_heart).unwrap(); + /// + /// assert_eq!("💖", sparkle_heart); + /// ``` + /// + /// Incorrect bytes: + /// + /// ``` + /// // some invalid bytes /// let input = b"Hello \xF0\x90\x80World"; /// let output = String::from_utf8_lossy(input); - /// assert_eq!(output, "Hello \u{FFFD}World"); + /// + /// assert_eq!("Hello �World", output); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn from_utf8_lossy<'a>(v: &'a [u8]) -> Cow<'a, str> { @@ -292,7 +361,7 @@ impl String { /// Creates a new `String` from a length, capacity, and pointer. /// - /// # Unsafety + /// # Safety /// /// This is _very_ unsafe because: /// @@ -309,9 +378,33 @@ impl String { } } - /// Converts a vector of bytes to a new `String` without checking if - /// it contains valid UTF-8. This is unsafe because it assumes that - /// the UTF-8-ness of the vector has already been validated. + /// Converts a vector of bytes to a `String` without checking that the + /// string contains valid UTF-8. + /// + /// See the safe version, [`from_utf8()`][fromutf8], for more. + /// + /// [fromutf8]: struct.String.html#method.from_utf8 + /// + /// # Safety + /// + /// This function is unsafe because it does not check that the bytes passed to + /// it are valid UTF-8. If this constraint is violated, undefined behavior + /// results, as the rest of Rust assumes that `String`s are valid UTF-8. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// // some bytes, in a vector + /// let sparkle_heart = vec![240, 159, 146, 150]; + /// + /// let sparkle_heart = unsafe { + /// String::from_utf8_unchecked(sparkle_heart) + /// }; + /// + /// assert_eq!("💖", sparkle_heart); + /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn from_utf8_unchecked(bytes: Vec) -> String { @@ -765,6 +858,17 @@ impl fmt::Display for FromUtf16Error { } } +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for String { + fn clone(&self) -> Self { + String { vec: self.vec.clone() } + } + + fn clone_from(&mut self, source: &Self) { + self.vec.clone_from(&source.vec); + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl FromIterator for String { fn from_iter>(iterable: I) -> String { @@ -1027,11 +1131,9 @@ impl ops::DerefMut for String { } /// Error returned from `String::from` -#[unstable(feature = "str_parse_error", reason = "may want to be replaced with \ - Void if it ever exists", - issue = "27734")] -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct ParseError(()); +#[stable(feature = "str_parse_error", since = "1.5.0")] +#[derive(Copy)] +pub enum ParseError {} #[stable(feature = "rust1", since = "1.0.0")] impl FromStr for String { @@ -1042,6 +1144,26 @@ impl FromStr for String { } } +impl Clone for ParseError { + fn clone(&self) -> ParseError { + match *self {} + } +} + +impl fmt::Debug for ParseError { + fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { + match *self {} + } +} + +impl PartialEq for ParseError { + fn eq(&self, _: &ParseError) -> bool { + match *self {} + } +} + +impl Eq for ParseError {} + /// A generic trait for converting a value to a string #[stable(feature = "rust1", since = "1.0.0")] pub trait ToString { diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index c99460a55c..897fea5309 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -65,7 +65,7 @@ use alloc::heap::EMPTY; use core::cmp::Ordering; use core::fmt; use core::hash::{self, Hash}; -use core::intrinsics::{arith_offset, assume, drop_in_place}; +use core::intrinsics::{arith_offset, assume, drop_in_place, needs_drop}; use core::iter::FromIterator; use core::mem; use core::ops::{Index, IndexMut, Deref}; @@ -148,6 +148,81 @@ use super::range::RangeArgument; /// 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` /// 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 +/// 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) +/// 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 +/// 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. +/// +/// 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. +/// +/// 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 +/// 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`. +/// +/// `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 +/// and it may prove desirable to use a non-constant growth factor. Whatever +/// 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 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 +/// 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 +/// (the order has changed in the past, and may change again). +/// #[unsafe_no_drop_flag] #[stable(feature = "rust1", since = "1.0.0")] pub struct Vec { @@ -209,7 +284,7 @@ impl Vec { /// Creates a `Vec` directly from the raw components of another vector. /// - /// # Unsafety + /// # Safety /// /// This is highly unsafe, due to the number of invariants that aren't /// checked: @@ -753,8 +828,6 @@ impl Vec { /// # Examples /// /// ``` - /// #![feature(split_off)] - /// /// let mut vec = vec![1,2,3]; /// let vec2 = vec.split_off(1); /// assert_eq!(vec, [1]); @@ -792,8 +865,6 @@ impl Vec { /// # Examples /// /// ``` - /// #![feature(vec_resize)] - /// /// let mut vec = vec!["hello"]; /// vec.resize(3, "world"); /// assert_eq!(vec, ["hello", "world", "world"]); @@ -802,9 +873,7 @@ impl Vec { /// vec.resize(2, 0); /// assert_eq!(vec, [1, 2]); /// ``` - #[unstable(feature = "vec_resize", - reason = "matches collection reform specification; waiting for dust to settle", - issue = "27790")] + #[stable(feature = "vec_resize", since = "1.5.0")] pub fn resize(&mut self, new_len: usize, value: T) { let len = self.len(); @@ -1007,19 +1076,15 @@ impl Clone for Vec { fn clone_from(&mut self, other: &Vec) { // drop anything in self that will not be overwritten - if self.len() > other.len() { - self.truncate(other.len()) - } + self.truncate(other.len()); + let len = self.len(); // reuse the contained values' allocations/resources. - for (place, thing) in self.iter_mut().zip(other) { - place.clone_from(thing) - } + self.clone_from_slice(&other[..len]); // self.len <= other.len due to the truncate above, so the // slice here is always in-bounds. - let slice = &other[self.len()..]; - self.push_all(slice); + self.push_all(&other[len..]); } } @@ -1316,14 +1381,21 @@ impl Ord for Vec { #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Vec { + #[unsafe_destructor_blind_to_params] fn drop(&mut self) { // NOTE: this is currently abusing the fact that ZSTs can't impl Drop. // Or rather, that impl'ing Drop makes them not zero-sized. This is // OK because exactly when this stops being a valid assumption, we // don't need unsafe_no_drop_flag shenanigans anymore. if self.buf.unsafe_no_drop_flag_needs_drop() { - for x in self.iter_mut() { - unsafe { drop_in_place(x); } + unsafe { + // The branch on needs_drop() is an -O1 performance optimization. + // Without the branch, dropping Vec takes linear time. + if needs_drop::() { + for x in self.iter_mut() { + drop_in_place(x); + } + } } } // RawVec handles deallocation @@ -1352,6 +1424,13 @@ impl AsRef> for Vec { } } +#[stable(feature = "vec_as_mut", since = "1.5.0")] +impl AsMut> for Vec { + fn as_mut(&mut self) -> &mut Vec { + self + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl AsRef<[T]> for Vec { fn as_ref(&self) -> &[T] { @@ -1359,6 +1438,13 @@ impl AsRef<[T]> for Vec { } } +#[stable(feature = "vec_as_mut", since = "1.5.0")] +impl AsMut<[T]> for Vec { + fn as_mut(&mut self) -> &mut [T] { + self + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T: Clone> From<&'a [T]> for Vec { #[cfg(not(test))] @@ -1487,9 +1573,10 @@ impl ExactSizeIterator for IntoIter {} #[stable(feature = "rust1", since = "1.0.0")] impl Drop for IntoIter { + #[unsafe_destructor_blind_to_params] fn drop(&mut self) { // destroy the remaining elements - for _x in self.by_ref() {} + for _x in self {} // RawVec handles deallocation } diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 4ee9787c9e..937ace00fd 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -32,16 +32,19 @@ use core::cmp; use alloc::raw_vec::RawVec; +use super::range::RangeArgument; + const INITIAL_CAPACITY: usize = 7; // 2^3 - 1 const MINIMUM_CAPACITY: usize = 1; // 2 - 1 const MAXIMUM_ZST_CAPACITY: usize = 1 << (usize::BITS - 1); // Largest possible power of two -/// `VecDeque` is a growable ring buffer, which can be used as a -/// double-ended queue efficiently. +/// `VecDeque` is a growable ring buffer, which can be used as a double-ended +/// queue efficiently. /// -/// The "default" usage of this type as a queue is to use `push_back` to add to the queue, and -/// `pop_front` to remove from the queue. `extend` and `append` push onto the back in this manner, -/// and iterating over `VecDeque` goes front to back. +/// The "default" usage of this type as a queue is to use `push_back` to add to +/// the queue, and `pop_front` to remove from the queue. `extend` and `append` +/// push onto the back in this manner, and iterating over `VecDeque` goes front +/// to back. #[stable(feature = "rust1", since = "1.0.0")] pub struct VecDeque { // tail and head are pointers into the buffer. Tail always points @@ -64,6 +67,7 @@ impl Clone for VecDeque { #[stable(feature = "rust1", since = "1.0.0")] impl Drop for VecDeque { + #[unsafe_destructor_blind_to_params] fn drop(&mut self) { self.clear(); // RawVec handles deallocation @@ -167,6 +171,117 @@ impl VecDeque { len); } + /// Copies a potentially wrapping block of memory len long from src to dest. + /// (abs(dst - src) + len) must be no larger than cap() (There must be at + /// most one continuous overlapping region between src and dest). + unsafe fn wrap_copy(&self, dst: usize, src: usize, len: usize) { + debug_assert!( + (if src <= dst { dst - src } else { src - dst }) + len <= self.cap(), + "dst={} src={} len={} cap={}", dst, src, len, self.cap()); + + if src == dst || len == 0 { return } + + let dst_after_src = self.wrap_sub(dst, src) < len; + + let src_pre_wrap_len = self.cap() - src; + let dst_pre_wrap_len = self.cap() - dst; + let src_wraps = src_pre_wrap_len < len; + let dst_wraps = dst_pre_wrap_len < len; + + match (dst_after_src, src_wraps, dst_wraps) { + (_, false, false) => { + // src doesn't wrap, dst doesn't wrap + // + // S . . . + // 1 [_ _ A A B B C C _] + // 2 [_ _ A A A A B B _] + // D . . . + // + self.copy(dst, src, len); + } + (false, false, true) => { + // dst before src, src doesn't wrap, dst wraps + // + // S . . . + // 1 [A A B B _ _ _ C C] + // 2 [A A B B _ _ _ A A] + // 3 [B B B B _ _ _ A A] + // . . D . + // + self.copy(dst, src, dst_pre_wrap_len); + self.copy(0, src + dst_pre_wrap_len, len - dst_pre_wrap_len); + } + (true, false, true) => { + // src before dst, src doesn't wrap, dst wraps + // + // S . . . + // 1 [C C _ _ _ A A B B] + // 2 [B B _ _ _ A A B B] + // 3 [B B _ _ _ A A A A] + // . . D . + // + self.copy(0, src + dst_pre_wrap_len, len - dst_pre_wrap_len); + self.copy(dst, src, dst_pre_wrap_len); + } + (false, true, false) => { + // dst before src, src wraps, dst doesn't wrap + // + // . . S . + // 1 [C C _ _ _ A A B B] + // 2 [C C _ _ _ B B B B] + // 3 [C C _ _ _ B B C C] + // D . . . + // + self.copy(dst, src, src_pre_wrap_len); + self.copy(dst + src_pre_wrap_len, 0, len - src_pre_wrap_len); + } + (true, true, false) => { + // src before dst, src wraps, dst doesn't wrap + // + // . . S . + // 1 [A A B B _ _ _ C C] + // 2 [A A A A _ _ _ C C] + // 3 [C C A A _ _ _ C C] + // D . . . + // + self.copy(dst + src_pre_wrap_len, 0, len - src_pre_wrap_len); + self.copy(dst, src, src_pre_wrap_len); + } + (false, true, true) => { + // dst before src, src wraps, dst wraps + // + // . . . S . + // 1 [A B C D _ E F G H] + // 2 [A B C D _ E G H H] + // 3 [A B C D _ E G H A] + // 4 [B C C D _ E G H A] + // . . D . . + // + debug_assert!(dst_pre_wrap_len > src_pre_wrap_len); + let delta = dst_pre_wrap_len - src_pre_wrap_len; + self.copy(dst, src, src_pre_wrap_len); + self.copy(dst + src_pre_wrap_len, 0, delta); + self.copy(0, delta, len - dst_pre_wrap_len); + } + (true, true, true) => { + // src before dst, src wraps, dst wraps + // + // . . S . . + // 1 [A B C D _ E F G H] + // 2 [A A B D _ E F G H] + // 3 [H A B D _ E F G H] + // 4 [H A B D _ E F F G] + // . . . D . + // + debug_assert!(src_pre_wrap_len > dst_pre_wrap_len); + let delta = src_pre_wrap_len - dst_pre_wrap_len; + self.copy(delta, 0, len - src_pre_wrap_len); + self.copy(0, self.cap() - delta, delta); + self.copy(dst, src, dst_pre_wrap_len); + } + } + } + /// Frobs the head and tail sections around to handle the fact that we /// just reallocated. Unsafe because it trusts old_cap. #[inline] @@ -385,8 +500,6 @@ impl VecDeque { /// # Examples /// /// ``` - /// #![feature(deque_extras)] - /// /// use std::collections::VecDeque; /// /// let mut buf = VecDeque::with_capacity(15); @@ -395,9 +508,7 @@ impl VecDeque { /// buf.shrink_to_fit(); /// assert!(buf.capacity() >= 4); /// ``` - #[unstable(feature = "deque_extras", - reason = "needs to be audited", - issue = "27788")] + #[stable(feature = "deque_extras_15", since = "1.5.0")] pub fn shrink_to_fit(&mut self) { // +1 since the ringbuffer always leaves one space empty // len + 1 can't overflow for an existing, well-formed ringbuffer. @@ -539,9 +650,7 @@ impl VecDeque { /// Returns a pair of slices which contain, in order, the contents of the /// `VecDeque`. #[inline] - #[unstable(feature = "deque_extras", - reason = "matches collection reform specification, waiting for dust to settle", - issue = "27788")] + #[stable(feature = "deque_extras_15", since = "1.5.0")] pub fn as_slices(&self) -> (&[T], &[T]) { unsafe { let contiguous = self.is_contiguous(); @@ -560,9 +669,7 @@ impl VecDeque { /// Returns a pair of slices which contain, in order, the contents of the /// `VecDeque`. #[inline] - #[unstable(feature = "deque_extras", - reason = "matches collection reform specification, waiting for dust to settle", - issue = "27788")] + #[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(); @@ -612,8 +719,18 @@ impl VecDeque { #[stable(feature = "rust1", since = "1.0.0")] pub fn is_empty(&self) -> bool { self.len() == 0 } - /// Creates a draining iterator that clears the `VecDeque` and iterates over - /// the removed items from start to end. + /// Create a draining iterator that removes the specified range in the + /// `VecDeque` and yields the removed items from start to end. The element + /// range is removed even if the iterator is not consumed until the end. + /// + /// Note: It is unspecified how many elements are removed from the deque, + /// if the `Drain` value is not dropped, but the borrow it holds expires + /// (eg. due to mem::forget). + /// + /// # Panics + /// + /// Panics if the starting point is greater than the end point or if + /// the end point is greater than the length of the vector. /// /// # Examples /// @@ -622,18 +739,66 @@ impl VecDeque { /// /// use std::collections::VecDeque; /// + /// // draining using `..` clears the whole deque. /// let mut v = VecDeque::new(); /// v.push_back(1); - /// assert_eq!(v.drain().next(), Some(1)); + /// assert_eq!(v.drain(..).next(), Some(1)); /// assert!(v.is_empty()); /// ``` #[inline] #[unstable(feature = "drain", reason = "matches collection reform specification, waiting for dust to settle", issue = "27711")] - pub fn drain(&mut self) -> Drain { + pub fn drain(&mut self, range: R) -> Drain where R: RangeArgument { + // Memory safety + // + // When the Drain is first created, the source deque is shortened to + // make sure no uninitialized or moved-from elements are accessible at + // all if the Drain's destructor never gets to run. + // + // Drain will ptr::read out the values to remove. + // When finished, the remaining data will be copied back to cover the hole, + // and the head/tail values will be restored correctly. + // + let len = self.len(); + let start = *range.start().unwrap_or(&0); + let end = *range.end().unwrap_or(&len); + assert!(start <= end, "drain lower bound was too large"); + assert!(end <= len, "drain upper bound was too large"); + + // The deque's elements are parted into three segments: + // * self.tail -> drain_tail + // * drain_tail -> drain_head + // * drain_head -> self.head + // + // T = self.tail; H = self.head; t = drain_tail; h = drain_head + // + // We store drain_tail as self.head, and drain_head and self.head as + // after_tail and after_head respectively on the Drain. This also + // truncates the effective array such that if the Drain is leaked, we + // have forgotten about the potentially moved values after the start of + // the drain. + // + // T t h H + // [. . . o o x x o o . . .] + // + let drain_tail = self.wrap_add(self.tail, start); + let drain_head = self.wrap_add(self.tail, end); + let head = self.head; + + // "forget" about the values after the start of the drain until after + // the drain is complete and the Drain destructor is run. + self.head = drain_tail; + Drain { - inner: self, + deque: self as *mut _, + after_tail: drain_head, + after_head: head, + iter: Iter { + tail: drain_tail, + head: drain_head, + ring: unsafe { self.buffer_as_mut_slice() }, + }, } } @@ -652,7 +817,7 @@ impl VecDeque { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn clear(&mut self) { - self.drain(); + self.drain(..); } /// Provides a reference to the front element, or `None` if the sequence is @@ -863,25 +1028,21 @@ impl VecDeque { /// # Examples /// /// ``` - /// #![feature(deque_extras)] - /// /// use std::collections::VecDeque; /// /// let mut buf = VecDeque::new(); - /// assert_eq!(buf.swap_back_remove(0), None); + /// assert_eq!(buf.swap_remove_back(0), None); /// buf.push_back(1); /// buf.push_back(2); /// buf.push_back(3); /// - /// assert_eq!(buf.swap_back_remove(0), Some(1)); + /// assert_eq!(buf.swap_remove_back(0), Some(1)); /// assert_eq!(buf.len(), 2); /// assert_eq!(buf[0], 3); /// assert_eq!(buf[1], 2); /// ``` - #[unstable(feature = "deque_extras", - reason = "the naming of this function may be altered", - issue = "27788")] - pub fn swap_back_remove(&mut self, index: usize) -> Option { + #[stable(feature = "deque_extras_15", since = "1.5.0")] + pub fn swap_remove_back(&mut self, index: usize) -> Option { let length = self.len(); if length > 0 && index < length - 1 { self.swap(index, length - 1); @@ -891,6 +1052,15 @@ impl VecDeque { self.pop_back() } + /// deprecated + #[unstable(feature = "deque_extras", + reason = "the naming of this function may be altered", + issue = "27788")] + #[deprecated(since = "1.5.0", reason = "renamed to swap_remove_back")] + pub fn swap_back_remove(&mut self, index: usize) -> Option { + self.swap_remove_back(index) + } + /// Removes an element from anywhere in the `VecDeque` and returns it, /// replacing it with the first element. /// @@ -901,25 +1071,21 @@ impl VecDeque { /// # Examples /// /// ``` - /// #![feature(deque_extras)] - /// /// use std::collections::VecDeque; /// /// let mut buf = VecDeque::new(); - /// assert_eq!(buf.swap_front_remove(0), None); + /// assert_eq!(buf.swap_remove_front(0), None); /// buf.push_back(1); /// buf.push_back(2); /// buf.push_back(3); /// - /// assert_eq!(buf.swap_front_remove(2), Some(3)); + /// assert_eq!(buf.swap_remove_front(2), Some(3)); /// assert_eq!(buf.len(), 2); /// assert_eq!(buf[0], 2); /// assert_eq!(buf[1], 1); /// ``` - #[unstable(feature = "deque_extras", - reason = "the naming of this function may be altered", - issue = "27788")] - pub fn swap_front_remove(&mut self, index: usize) -> Option { + #[stable(feature = "deque_extras_15", since = "1.5.0")] + pub fn swap_remove_front(&mut self, index: usize) -> Option { let length = self.len(); if length > 0 && index < length && index != 0 { self.swap(index, 0); @@ -929,6 +1095,15 @@ impl VecDeque { self.pop_front() } + /// deprecated + #[unstable(feature = "deque_extras", + reason = "the naming of this function may be altered", + issue = "27788")] + #[deprecated(since = "1.5.0", reason = "renamed to swap_remove_front")] + pub fn swap_front_remove(&mut self, index: usize) -> Option { + self.swap_remove_front(index) + } + /// Inserts an element at `index` within the `VecDeque`. Whichever /// end is closer to the insertion point will be moved to make room, /// and all the affected elements will be moved to new positions. @@ -939,8 +1114,6 @@ impl VecDeque { /// /// # Examples /// ``` - /// #![feature(deque_extras)] - /// /// use std::collections::VecDeque; /// /// let mut buf = VecDeque::new(); @@ -949,9 +1122,7 @@ impl VecDeque { /// buf.insert(1, 11); /// assert_eq!(Some(&11), buf.get(1)); /// ``` - #[unstable(feature = "deque_extras", - reason = "needs to be audited", - issue = "27788")] + #[stable(feature = "deque_extras_15", since = "1.5.0")] pub fn insert(&mut self, index: usize, value: T) { assert!(index <= self.len(), "index out of bounds"); if self.is_full() { @@ -1319,8 +1490,6 @@ impl VecDeque { /// # Examples /// /// ``` - /// #![feature(split_off)] - /// /// use std::collections::VecDeque; /// /// let mut buf: VecDeque<_> = vec![1,2,3].into_iter().collect(); @@ -1394,7 +1563,7 @@ impl VecDeque { #[stable(feature = "append", since = "1.4.0")] pub fn append(&mut self, other: &mut Self) { // naive impl - self.extend(other.drain()); + self.extend(other.drain(..)); } /// Retains only the elements specified by the predicate. @@ -1406,8 +1575,6 @@ impl VecDeque { /// # Examples /// /// ``` - /// #![feature(vec_deque_retain)] - /// /// use std::collections::VecDeque; /// /// let mut buf = VecDeque::new(); @@ -1630,15 +1797,59 @@ impl ExactSizeIterator for IntoIter {} reason = "matches collection reform specification, waiting for dust to settle", issue = "27711")] pub struct Drain<'a, T: 'a> { - inner: &'a mut VecDeque, + after_tail: usize, + after_head: usize, + iter: Iter<'a, T>, + deque: *mut VecDeque, } +unsafe impl<'a, T: Sync> Sync for Drain<'a, T> {} +unsafe impl<'a, T: Send> Send for Drain<'a, T> {} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T: 'a> Drop for Drain<'a, T> { fn drop(&mut self) { for _ in self.by_ref() {} - self.inner.head = 0; - self.inner.tail = 0; + + let source_deque = unsafe { &mut *self.deque }; + + // T = source_deque_tail; H = source_deque_head; t = drain_tail; h = drain_head + // + // T t h H + // [. . . o o x x o o . . .] + // + let orig_tail = source_deque.tail; + let drain_tail = source_deque.head; + let drain_head = self.after_tail; + let orig_head = self.after_head; + + let tail_len = count(orig_tail, drain_tail, source_deque.cap()); + let head_len = count(drain_head, orig_head, source_deque.cap()); + + // Restore the original head value + source_deque.head = orig_head; + + match (tail_len, head_len) { + (0, 0) => { + source_deque.head = 0; + source_deque.tail = 0; + } + (0, _) => { + source_deque.tail = drain_head; + } + (_, 0) => { + source_deque.head = drain_tail; + } + _ => unsafe { + if tail_len <= head_len { + source_deque.tail = source_deque.wrap_sub(drain_head, tail_len); + source_deque.wrap_copy(source_deque.tail, orig_tail, tail_len); + } else { + source_deque.head = source_deque.wrap_add(drain_tail, head_len); + source_deque.wrap_copy(drain_tail, drain_head, head_len); + } + } + } } } @@ -1648,13 +1859,16 @@ impl<'a, T: 'a> Iterator for Drain<'a, T> { #[inline] fn next(&mut self) -> Option { - self.inner.pop_front() + self.iter.next().map(|elt| + unsafe { + ptr::read(elt) + } + ) } #[inline] fn size_hint(&self) -> (usize, Option) { - let len = self.inner.len(); - (len, Some(len)) + self.iter.size_hint() } } @@ -1662,7 +1876,11 @@ impl<'a, T: 'a> Iterator for Drain<'a, T> { impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> { #[inline] fn next_back(&mut self) -> Option { - self.inner.pop_back() + self.iter.next_back().map(|elt| + unsafe { + ptr::read(elt) + } + ) } } @@ -1787,14 +2005,7 @@ impl<'a, T: 'a + Copy> Extend<&'a T> for VecDeque { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for VecDeque { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "[")); - - for (i, e) in self.iter().enumerate() { - if i != 0 { try!(write!(f, ", ")); } - try!(write!(f, "{:?}", *e)); - } - - write!(f, "]") + f.debug_list().entries(self).finish() } } @@ -1972,6 +2183,44 @@ mod tests { } } + #[test] + fn test_drain() { + let mut tester: VecDeque = VecDeque::with_capacity(7); + + let cap = tester.capacity(); + for len in 0..cap + 1 { + for tail in 0..cap + 1 { + for drain_start in 0..len + 1 { + for drain_end in drain_start..len + 1 { + tester.tail = tail; + tester.head = tail; + for i in 0..len { + tester.push_back(i); + } + + // Check that we drain the correct values + let drained: VecDeque<_> = + tester.drain(drain_start..drain_end).collect(); + let drained_expected: VecDeque<_> = + (drain_start..drain_end).collect(); + assert_eq!(drained, drained_expected); + + // We shouldn't have changed the capacity or made the + // head or tail out of bounds + assert_eq!(tester.capacity(), cap); + assert!(tester.tail < tester.cap()); + assert!(tester.head < tester.cap()); + + // We should see the correct values in the VecDeque + let expected: VecDeque<_> = + (0..drain_start).chain(drain_end..len).collect(); + assert_eq!(expected, tester); + } + } + } + } + } + #[test] fn test_shrink_to_fit() { // This test checks that every single combination of head and tail position, diff --git a/src/libcollectionstest/btree/map.rs b/src/libcollectionstest/btree/map.rs index 62b46433da..846353cc4e 100644 --- a/src/libcollectionstest/btree/map.rs +++ b/src/libcollectionstest/btree/map.rs @@ -294,6 +294,59 @@ fn test_extend_ref() { assert_eq!(a[&3], "three"); } +#[test] +fn test_zst() { + let mut m = BTreeMap::new(); + assert_eq!(m.len(), 0); + + assert_eq!(m.insert((), ()), None); + assert_eq!(m.len(), 1); + + assert_eq!(m.insert((), ()), Some(())); + assert_eq!(m.len(), 1); + assert_eq!(m.iter().count(), 1); + + m.clear(); + assert_eq!(m.len(), 0); + + for _ in 0..100 { + m.insert((), ()); + } + + assert_eq!(m.len(), 1); + assert_eq!(m.iter().count(), 1); +} + +// This test's only purpose is to ensure that zero-sized keys with nonsensical orderings +// do not cause segfaults when used with zero-sized values. All other map behavior is +// undefined. +#[test] +fn test_bad_zst() { + use std::cmp::Ordering; + + struct Bad; + + impl PartialEq for Bad { + fn eq(&self, _: &Self) -> bool { false } + } + + impl Eq for Bad {} + + impl PartialOrd for Bad { + fn partial_cmp(&self, _: &Self) -> Option { Some(Ordering::Less) } + } + + impl Ord for Bad { + fn cmp(&self, _: &Self) -> Ordering { Ordering::Less } + } + + let mut m = BTreeMap::new(); + + for _ in 0..100 { + m.insert(Bad, Bad); + } +} + mod bench { use std::collections::BTreeMap; use std::__rand::{Rng, thread_rng}; diff --git a/src/libcollectionstest/btree/set.rs b/src/libcollectionstest/btree/set.rs index e7593bfcfe..8fcfe97f42 100644 --- a/src/libcollectionstest/btree/set.rs +++ b/src/libcollectionstest/btree/set.rs @@ -148,15 +148,9 @@ fn test_zip() { let y = y; let mut z = x.iter().zip(&y); - // FIXME: #5801: this needs a type hint to compile... - let result: Option<(&usize, & &'static str)> = z.next(); - assert_eq!(result.unwrap(), (&5, &("bar"))); - - let result: Option<(&usize, & &'static str)> = z.next(); - assert_eq!(result.unwrap(), (&11, &("foo"))); - - let result: Option<(&usize, & &'static str)> = z.next(); - assert!(result.is_none()); + assert_eq!(z.next().unwrap(), (&5, &("bar"))); + assert_eq!(z.next().unwrap(), (&11, &("foo"))); + assert!(z.next().is_none()); } #[test] diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs index d84f5bdf10..63c7bc15c8 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollectionstest/lib.rs @@ -9,7 +9,6 @@ // except according to those terms. #![feature(ascii)] -#![feature(append)] #![feature(binary_heap_extras)] #![feature(box_syntax)] #![feature(btree_range)] @@ -29,18 +28,14 @@ #![feature(set_recovery)] #![feature(slice_bytes)] #![feature(slice_splits)] -#![feature(split_off)] #![feature(step_by)] #![feature(str_char)] #![feature(str_escape)] #![feature(str_match_indices)] -#![feature(str_split_at)] #![feature(str_utf16)] -#![feature(box_str)] #![feature(test)] #![feature(unboxed_closures)] #![feature(unicode)] -#![feature(vec_deque_retain)] #![feature(vec_push_all)] #[macro_use] extern crate log; diff --git a/src/libcollectionstest/str.rs b/src/libcollectionstest/str.rs index 7b481f6399..e22ff7ca54 100644 --- a/src/libcollectionstest/str.rs +++ b/src/libcollectionstest/str.rs @@ -41,10 +41,10 @@ fn test_rfind() { #[test] fn test_collect() { - let empty = String::from(""); + let empty = ""; let s: String = empty.chars().collect(); assert_eq!(empty, s); - let data = String::from("ประเทศไทย中"); + let data = "ประเทศไทย中"; let s: String = data.chars().collect(); assert_eq!(data, s); } @@ -86,7 +86,7 @@ fn test_find_str() { assert_eq!(data[43..86].find("iệt"), Some(77 - 43)); assert_eq!(data[43..86].find("Nam"), Some(83 - 43)); - // find every substring -- assert that it finds it, or an earlier occurence. + // find every substring -- assert that it finds it, or an earlier occurrence. let string = "Việt Namacbaabcaabaaba"; for (i, ci) in string.char_indices() { let ip = i + ci.len_utf8(); @@ -187,10 +187,8 @@ fn test_unsafe_slice() { rs } let letters = a_million_letter_a(); - assert!(half_a_million_letter_a() == - unsafe {String::from(letters.slice_unchecked( - 0, - 500000))}); + assert_eq!(half_a_million_letter_a(), + unsafe { letters.slice_unchecked(0, 500000)}); } #[test] @@ -224,13 +222,12 @@ fn test_is_empty() { #[test] fn test_replace() { let a = "a"; - assert_eq!("".replace(a, "b"), String::from("")); - assert_eq!("a".replace(a, "b"), String::from("b")); - assert_eq!("ab".replace(a, "b"), String::from("bb")); + assert_eq!("".replace(a, "b"), ""); + assert_eq!("a".replace(a, "b"), "b"); + assert_eq!("ab".replace(a, "b"), "bb"); let test = "test"; - assert!(" test test ".replace(test, "toast") == - String::from(" toast toast ")); - assert_eq!(" test test ".replace(test, ""), String::from(" ")); + assert_eq!(" test test ".replace(test, "toast"), " toast toast "); + assert_eq!(" test test ".replace(test, ""), " "); } #[test] @@ -304,8 +301,7 @@ fn test_slice() { rs } let letters = a_million_letter_x(); - assert!(half_a_million_letter_x() == - String::from(&letters[0..3 * 500000])); + assert_eq!(half_a_million_letter_x(), &letters[0..3 * 500000]); } #[test] @@ -676,49 +672,36 @@ fn test_split_at_boundscheck() { #[test] fn test_escape_unicode() { - assert_eq!("abc".escape_unicode(), - String::from("\\u{61}\\u{62}\\u{63}")); - assert_eq!("a c".escape_unicode(), - String::from("\\u{61}\\u{20}\\u{63}")); - assert_eq!("\r\n\t".escape_unicode(), - String::from("\\u{d}\\u{a}\\u{9}")); - assert_eq!("'\"\\".escape_unicode(), - String::from("\\u{27}\\u{22}\\u{5c}")); - assert_eq!("\x00\x01\u{fe}\u{ff}".escape_unicode(), - String::from("\\u{0}\\u{1}\\u{fe}\\u{ff}")); - assert_eq!("\u{100}\u{ffff}".escape_unicode(), - String::from("\\u{100}\\u{ffff}")); - assert_eq!("\u{10000}\u{10ffff}".escape_unicode(), - String::from("\\u{10000}\\u{10ffff}")); - assert_eq!("ab\u{fb00}".escape_unicode(), - String::from("\\u{61}\\u{62}\\u{fb00}")); - assert_eq!("\u{1d4ea}\r".escape_unicode(), - String::from("\\u{1d4ea}\\u{d}")); + assert_eq!("abc".escape_unicode(), "\\u{61}\\u{62}\\u{63}"); + assert_eq!("a c".escape_unicode(), "\\u{61}\\u{20}\\u{63}"); + assert_eq!("\r\n\t".escape_unicode(), "\\u{d}\\u{a}\\u{9}"); + assert_eq!("'\"\\".escape_unicode(), "\\u{27}\\u{22}\\u{5c}"); + assert_eq!("\x00\x01\u{fe}\u{ff}".escape_unicode(), "\\u{0}\\u{1}\\u{fe}\\u{ff}"); + assert_eq!("\u{100}\u{ffff}".escape_unicode(), "\\u{100}\\u{ffff}"); + assert_eq!("\u{10000}\u{10ffff}".escape_unicode(), "\\u{10000}\\u{10ffff}"); + assert_eq!("ab\u{fb00}".escape_unicode(), "\\u{61}\\u{62}\\u{fb00}"); + assert_eq!("\u{1d4ea}\r".escape_unicode(), "\\u{1d4ea}\\u{d}"); } #[test] fn test_escape_default() { - assert_eq!("abc".escape_default(), String::from("abc")); - assert_eq!("a c".escape_default(), String::from("a c")); - assert_eq!("\r\n\t".escape_default(), String::from("\\r\\n\\t")); - assert_eq!("'\"\\".escape_default(), String::from("\\'\\\"\\\\")); - assert_eq!("\u{100}\u{ffff}".escape_default(), - String::from("\\u{100}\\u{ffff}")); - assert_eq!("\u{10000}\u{10ffff}".escape_default(), - String::from("\\u{10000}\\u{10ffff}")); - assert_eq!("ab\u{fb00}".escape_default(), - String::from("ab\\u{fb00}")); - assert_eq!("\u{1d4ea}\r".escape_default(), - String::from("\\u{1d4ea}\\r")); + assert_eq!("abc".escape_default(), "abc"); + assert_eq!("a c".escape_default(), "a c"); + assert_eq!("\r\n\t".escape_default(), "\\r\\n\\t"); + assert_eq!("'\"\\".escape_default(), "\\'\\\"\\\\"); + assert_eq!("\u{100}\u{ffff}".escape_default(), "\\u{100}\\u{ffff}"); + assert_eq!("\u{10000}\u{10ffff}".escape_default(), "\\u{10000}\\u{10ffff}"); + assert_eq!("ab\u{fb00}".escape_default(), "ab\\u{fb00}"); + assert_eq!("\u{1d4ea}\r".escape_default(), "\\u{1d4ea}\\r"); } #[test] fn test_total_ord() { - "1234".cmp("123") == Greater; - "123".cmp("1234") == Less; - "1234".cmp("1234") == Equal; - "12345555".cmp("123456") == Less; - "22".cmp("1234") == Greater; + assert_eq!("1234".cmp("123"), Greater); + assert_eq!("123".cmp("1234"), Less); + assert_eq!("1234".cmp("1234"), Equal); + assert_eq!("12345555".cmp("123456"), Less); + assert_eq!("22".cmp("1234"), Greater); } #[test] @@ -1014,13 +997,10 @@ fn test_str_container() { v.iter().map(|x| x.len()).sum() } - let s = String::from("01234"); + let s = "01234"; assert_eq!(5, sum_len(&["012", "", "34"])); - assert_eq!(5, sum_len(&[&String::from("01"), - &String::from("2"), - &String::from("34"), - &String::from("")])); - assert_eq!(5, sum_len(&[&s])); + assert_eq!(5, sum_len(&["01", "2", "34", ""])); + assert_eq!(5, sum_len(&[s])); } #[test] @@ -1047,7 +1027,7 @@ fn test_pattern_deref_forward() { fn test_empty_match_indices() { let data = "aä中!"; let vec: Vec<_> = data.match_indices("").collect(); - assert_eq!(vec, [(0, 0), (1, 1), (3, 3), (6, 6), (7, 7)]); + assert_eq!(vec, [(0, ""), (1, ""), (3, ""), (6, ""), (7, "")]); } #[test] @@ -1477,7 +1457,7 @@ generate_iterator_test! { generate_iterator_test! { double_ended_match_indices { - ("a1b2c3", char::is_numeric) -> [(1, 2), (3, 4), (5, 6)]; + ("a1b2c3", char::is_numeric) -> [(1, "1"), (3, "2"), (5, "3")]; } with str::match_indices, str::rmatch_indices; } diff --git a/src/libcollectionstest/string.rs b/src/libcollectionstest/string.rs index 69553bff0e..89df77d074 100644 --- a/src/libcollectionstest/string.rs +++ b/src/libcollectionstest/string.rs @@ -264,7 +264,7 @@ fn test_str_add() { #[test] fn remove() { - let mut s = "ศไทย中华Việt Nam; foobar".to_string();; + let mut s = "ศไทย中华Việt Nam; foobar".to_string(); assert_eq!(s.remove(0), 'ศ'); assert_eq!(s.len(), 33); assert_eq!(s, "ไทย中华Việt Nam; foobar"); diff --git a/src/libcollectionstest/vec_deque.rs b/src/libcollectionstest/vec_deque.rs index 1931e372ae..5f587789bd 100644 --- a/src/libcollectionstest/vec_deque.rs +++ b/src/libcollectionstest/vec_deque.rs @@ -475,7 +475,7 @@ fn test_drain() { let mut d: VecDeque = VecDeque::new(); { - let mut iter = d.drain(); + let mut iter = d.drain(..); assert_eq!(iter.size_hint(), (0, Some(0))); assert_eq!(iter.next(), None); @@ -492,7 +492,7 @@ fn test_drain() { d.push_back(i); } - assert_eq!(d.drain().collect::>(), [0, 1, 2, 3, 4]); + assert_eq!(d.drain(..).collect::>(), [0, 1, 2, 3, 4]); assert!(d.is_empty()); } @@ -506,7 +506,7 @@ fn test_drain() { d.push_front(i); } - assert_eq!(d.drain().collect::>(), [8,7,6,0,1,2,3,4]); + assert_eq!(d.drain(..).collect::>(), [8,7,6,0,1,2,3,4]); assert!(d.is_empty()); } @@ -521,7 +521,7 @@ fn test_drain() { } { - let mut it = d.drain(); + let mut it = d.drain(..); assert_eq!(it.size_hint(), (8, Some(8))); assert_eq!(it.next(), Some(8)); assert_eq!(it.size_hint(), (7, Some(7))); diff --git a/src/libcore/array.rs b/src/libcore/array.rs index 8c785b1092..c986914440 100644 --- a/src/libcore/array.rs +++ b/src/libcore/array.rs @@ -35,14 +35,23 @@ use slice::{Iter, IterMut, SliceExt}; /// /// This trait can be used to implement other traits on fixed-size arrays /// without causing much metadata bloat. -pub trait FixedSizeArray { +/// +/// The trait is marked unsafe in order to restrict implementors to fixed-size +/// arrays. User of this trait can assume that implementors have the exact +/// layout in memory of a fixed size array (for example, for unsafe +/// initialization). +/// +/// Note that the traits AsRef and AsMut provide similar methods for types that +/// may not be fixed-size arrays. Implementors should prefer those traits +/// instead. +pub unsafe trait FixedSizeArray { /// Converts the array to immutable slice fn as_slice(&self) -> &[T]; /// Converts the array to mutable slice fn as_mut_slice(&mut self) -> &mut [T]; } -impl> FixedSizeArray for A { +unsafe impl> FixedSizeArray for A { #[inline] fn as_slice(&self) -> &[T] { self diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index d37f5169af..1dc989018a 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -214,7 +214,7 @@ impl Cell { /// Returns a reference to the underlying `UnsafeCell`. /// - /// # Unsafety + /// # Safety /// /// This function is `unsafe` because `UnsafeCell`'s field is public. /// @@ -598,7 +598,7 @@ impl<'b, T: ?Sized> Ref<'b, T> { } } - /// Make a new `Ref` for a optional component of the borrowed data, e.g. an + /// Make a new `Ref` for an optional component of the borrowed data, e.g. an /// enum variant. /// /// The `RefCell` is already immutably borrowed, so this cannot fail. @@ -668,7 +668,7 @@ impl<'b, T: ?Sized> RefMut<'b, T> { } } - /// Make a new `RefMut` for a optional component of the borrowed data, e.g. + /// Make a new `RefMut` for an optional component of the borrowed data, e.g. /// an enum variant. /// /// The `RefCell` is already mutably borrowed, so this cannot fail. @@ -784,9 +784,6 @@ impl<'b, T: ?Sized> DerefMut for RefMut<'b, T> { /// /// unsafe impl Sync for NotThreadSafe {} /// ``` -/// -/// **NOTE:** `UnsafeCell`'s fields are public to allow static initializers. It is not -/// recommended to access its fields directly, `get` should be used instead. #[lang = "unsafe_cell"] #[stable(feature = "rust1", since = "1.0.0")] pub struct UnsafeCell { @@ -799,8 +796,7 @@ impl UnsafeCell { /// Constructs a new instance of `UnsafeCell` which will wrap the specified /// value. /// - /// All access to the inner value through methods is `unsafe`, and it is highly discouraged to - /// access the fields directly. + /// All access to the inner value through methods is `unsafe`. /// /// # Examples /// @@ -817,7 +813,7 @@ impl UnsafeCell { /// Unwraps the value. /// - /// # Unsafety + /// # Safety /// /// This function is unsafe because this thread or another thread may currently be /// inspecting the inner value. diff --git a/src/libcore/char.rs b/src/libcore/char.rs index dfcbfd476b..21146f9836 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -91,8 +91,7 @@ pub fn from_u32(i: u32) -> Option { /// Converts a `u32` to an `char`, not checking whether it is a valid unicode /// codepoint. #[inline] -#[unstable(feature = "char_from_unchecked", reason = "recently added API", - issue = "27781")] +#[stable(feature = "char_from_unchecked", since = "1.5.0")] pub unsafe fn from_u32_unchecked(i: u32) -> char { transmute(i) } @@ -185,9 +184,7 @@ impl CharExt for char { '\t' => EscapeDefaultState::Backslash('t'), '\r' => EscapeDefaultState::Backslash('r'), '\n' => EscapeDefaultState::Backslash('n'), - '\\' => EscapeDefaultState::Backslash('\\'), - '\'' => EscapeDefaultState::Backslash('\''), - '"' => EscapeDefaultState::Backslash('"'), + '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self), '\x20' ... '\x7e' => EscapeDefaultState::Char(self), _ => EscapeDefaultState::Unicode(self.escape_unicode()) }; @@ -344,6 +341,22 @@ impl Iterator for EscapeUnicode { EscapeUnicodeState::Done => None, } } + + fn size_hint(&self) -> (usize, Option) { + let mut n = 0; + while (self.c as usize) >> (4 * (n + 1)) != 0 { + n += 1; + } + let n = match self.state { + EscapeUnicodeState::Backslash => n + 5, + EscapeUnicodeState::Type => n + 4, + EscapeUnicodeState::LeftBrace => n + 3, + EscapeUnicodeState::Value(offset) => offset + 2, + EscapeUnicodeState::RightBrace => 1, + EscapeUnicodeState::Done => 0, + }; + (n, Some(n)) + } } /// An iterator over the characters that represent a `char`, escaped @@ -377,7 +390,16 @@ impl Iterator for EscapeDefault { Some(c) } EscapeDefaultState::Done => None, - EscapeDefaultState::Unicode(ref mut iter) => iter.next() + EscapeDefaultState::Unicode(ref mut iter) => iter.next(), + } + } + + fn size_hint(&self) -> (usize, Option) { + match self.state { + EscapeDefaultState::Char(_) => (1, Some(1)), + EscapeDefaultState::Backslash(_) => (2, Some(2)), + EscapeDefaultState::Unicode(ref iter) => iter.size_hint(), + EscapeDefaultState::Done => (0, Some(0)), } } } diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index aea5feb4be..fa1f4727bc 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -218,7 +218,7 @@ impl PartialOrd for Ordering { /// /// The comparison must satisfy, for all `a`, `b` and `c`: /// -/// - antisymmetry: if `a < b` then `!(a > b)` and vice versa; and +/// - antisymmetry: if `a < b` then `!(a > b)`, as well as `a > b` implying `!(a < b)`; and /// - transitivity: `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. /// /// Note that these requirements mean that the trait itself must be implemented symmetrically and @@ -463,17 +463,33 @@ mod impls { } } - partial_ord_impl! { char usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } + partial_ord_impl! { f32 f64 } macro_rules! ord_impl { ($($t:ty)*) => ($( + #[stable(feature = "rust1", since = "1.0.0")] + impl PartialOrd for $t { + #[inline] + fn partial_cmp(&self, other: &$t) -> Option { + Some(self.cmp(other)) + } + #[inline] + fn lt(&self, other: &$t) -> bool { (*self) < (*other) } + #[inline] + fn le(&self, other: &$t) -> bool { (*self) <= (*other) } + #[inline] + fn ge(&self, other: &$t) -> bool { (*self) >= (*other) } + #[inline] + fn gt(&self, other: &$t) -> bool { (*self) > (*other) } + } + #[stable(feature = "rust1", since = "1.0.0")] impl Ord for $t { #[inline] fn cmp(&self, other: &$t) -> Ordering { - if *self < *other { Less } - else if *self > *other { Greater } - else { Equal } + if *self == *other { Equal } + else if *self < *other { Less } + else { Greater } } } )*) diff --git a/src/libcore/cmp_macros.rs b/src/libcore/cmp_macros.rs index 95dab3d165..3863f63265 100644 --- a/src/libcore/cmp_macros.rs +++ b/src/libcore/cmp_macros.rs @@ -21,9 +21,9 @@ macro_rules! __impl_slice_eq1 { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq { #[inline] - fn eq(&self, other: &$Rhs) -> bool { &self[..] == &other[..] } + fn eq(&self, other: &$Rhs) -> bool { self[..] == other[..] } #[inline] - fn ne(&self, other: &$Rhs) -> bool { &self[..] != &other[..] } + fn ne(&self, other: &$Rhs) -> bool { self[..] != other[..] } } } } @@ -39,9 +39,9 @@ macro_rules! __impl_slice_eq2 { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, 'b, A: $Bound, B> PartialEq<$Lhs> for $Rhs where B: PartialEq { #[inline] - fn eq(&self, other: &$Lhs) -> bool { &self[..] == &other[..] } + fn eq(&self, other: &$Lhs) -> bool { self[..] == other[..] } #[inline] - fn ne(&self, other: &$Lhs) -> bool { &self[..] != &other[..] } + fn ne(&self, other: &$Lhs) -> bool { self[..] != other[..] } } } } diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 7086880529..b02b2a06b7 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -95,7 +95,7 @@ pub trait Into: Sized { /// assert_eq!(string, other_string); /// ``` #[stable(feature = "rust1", since = "1.0.0")] -pub trait From { +pub trait From: Sized { /// Performs the conversion. #[stable(feature = "rust1", since = "1.0.0")] fn from(T) -> Self; diff --git a/src/libcore/default.rs b/src/libcore/default.rs index 0e318f204e..f7fda3d04f 100644 --- a/src/libcore/default.rs +++ b/src/libcore/default.rs @@ -78,6 +78,8 @@ #![stable(feature = "rust1", since = "1.0.0")] +use marker::Sized; + /// A trait for giving a type a useful default value. /// /// A struct can derive default implementations of `Default` for basic types using @@ -93,7 +95,7 @@ /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] -pub trait Default { +pub trait Default: Sized { /// Returns the "default value" for a type. /// /// Default values are often some kind of initial value, identity value, or anything else that diff --git a/src/libcore/fmt/builders.rs b/src/libcore/fmt/builders.rs index 764d12dd90..0d4c0bb648 100644 --- a/src/libcore/fmt/builders.rs +++ b/src/libcore/fmt/builders.rs @@ -61,7 +61,8 @@ pub struct DebugStruct<'a, 'b: 'a> { has_fields: bool, } -pub fn debug_struct_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) +pub fn debug_struct_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, + name: &str) -> DebugStruct<'a, 'b> { let result = fmt.write_str(name); DebugStruct { @@ -84,7 +85,8 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> { if self.is_pretty() { let mut writer = PadAdapter::new(self.fmt); - fmt::write(&mut writer, format_args!("{}\n{}: {:#?}", prefix, name, value)) + fmt::write(&mut writer, + format_args!("{}\n{}: {:#?}", prefix, name, value)) } else { write!(self.fmt, "{} {}: {:?}", prefix, name, value) } @@ -195,10 +197,18 @@ impl<'a, 'b: 'a> DebugInner<'a, 'b> { self.result = self.result.and_then(|_| { if self.is_pretty() { let mut writer = PadAdapter::new(self.fmt); - let prefix = if self.has_fields { "," } else { "" }; + let prefix = if self.has_fields { + "," + } else { + "" + }; fmt::write(&mut writer, format_args!("{}\n{:#?}", prefix, entry)) } else { - let prefix = if self.has_fields { ", " } else { "" }; + let prefix = if self.has_fields { + ", " + } else { + "" + }; write!(self.fmt, "{}{:?}", prefix, entry) } }); @@ -207,7 +217,11 @@ impl<'a, 'b: 'a> DebugInner<'a, 'b> { } pub fn finish(&mut self) { - let prefix = if self.is_pretty() && self.has_fields { "\n" } else { "" }; + let prefix = if self.is_pretty() && self.has_fields { + "\n" + } else { + "" + }; self.result = self.result.and_then(|_| self.fmt.write_str(prefix)); } @@ -232,7 +246,7 @@ pub fn debug_set_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugSet<'a, 'b fmt: fmt, result: result, has_fields: false, - } + }, } } @@ -247,7 +261,9 @@ impl<'a, 'b: 'a> DebugSet<'a, 'b> { /// Adds the contents of an iterator of entries to the set output. #[stable(feature = "debug_builders", since = "1.2.0")] pub fn entries(&mut self, entries: I) -> &mut DebugSet<'a, 'b> - where D: fmt::Debug, I: IntoIterator { + where D: fmt::Debug, + I: IntoIterator + { for entry in entries { self.entry(&entry); } @@ -278,7 +294,7 @@ pub fn debug_list_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugList<'a, fmt: fmt, result: result, has_fields: false, - } + }, } } @@ -293,7 +309,9 @@ impl<'a, 'b: 'a> DebugList<'a, 'b> { /// Adds the contents of an iterator of entries to the list output. #[stable(feature = "debug_builders", since = "1.2.0")] pub fn entries(&mut self, entries: I) -> &mut DebugList<'a, 'b> - where D: fmt::Debug, I: IntoIterator { + where D: fmt::Debug, + I: IntoIterator + { for entry in entries { self.entry(&entry); } @@ -335,10 +353,19 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> { self.result = self.result.and_then(|_| { if self.is_pretty() { let mut writer = PadAdapter::new(self.fmt); - let prefix = if self.has_fields { "," } else { "" }; - fmt::write(&mut writer, format_args!("{}\n{:#?}: {:#?}", prefix, key, value)) + let prefix = if self.has_fields { + "," + } else { + "" + }; + fmt::write(&mut writer, + format_args!("{}\n{:#?}: {:#?}", prefix, key, value)) } else { - let prefix = if self.has_fields { ", " } else { "" }; + let prefix = if self.has_fields { + ", " + } else { + "" + }; write!(self.fmt, "{}{:?}: {:?}", prefix, key, value) } }); @@ -350,7 +377,10 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> { /// Adds the contents of an iterator of entries to the map output. #[stable(feature = "debug_builders", since = "1.2.0")] pub fn entries(&mut self, entries: I) -> &mut DebugMap<'a, 'b> - where K: fmt::Debug, V: fmt::Debug, I: IntoIterator { + where K: fmt::Debug, + V: fmt::Debug, + I: IntoIterator + { for (k, v) in entries { self.entry(&k, &v); } @@ -360,7 +390,11 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> { /// Finishes output and returns any error encountered. #[stable(feature = "debug_builders", since = "1.2.0")] pub fn finish(&mut self) -> fmt::Result { - let prefix = if self.is_pretty() && self.has_fields { "\n" } else { "" }; + let prefix = if self.is_pretty() && self.has_fields { + "\n" + } else { + "" + }; self.result.and_then(|_| write!(self.fmt, "{}}}", prefix)) } diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index db7e6d3006..f850cdbbd6 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -94,7 +94,7 @@ pub trait Write { self.write_str(unsafe { str::from_utf8_unchecked(&utf_8[..bytes_written]) }) } - /// Glue for usage of the `write!` macro with implementers of this trait. + /// Glue for usage of the `write!` macro with implementors of this trait. /// /// This method should generally not be invoked manually, but rather through /// the `write!` macro itself. @@ -298,7 +298,7 @@ impl<'a> Display for Arguments<'a> { /// /// For more information on formatters, see [the module-level documentation][module]. /// -/// [module]: ../index.html +/// [module]: ../../std/fmt/index.html /// /// # Examples /// @@ -393,7 +393,7 @@ pub trait Debug { /// /// For more information on formatters, see [the module-level documentation][module]. /// -/// [module]: ../index.html +/// [module]: ../../std/fmt/index.html /// /// # Examples /// @@ -435,7 +435,7 @@ pub trait Display { /// /// For more information on formatters, see [the module-level documentation][module]. /// -/// [module]: ../index.html +/// [module]: ../../std/fmt/index.html /// /// # Examples /// @@ -482,7 +482,7 @@ pub trait Octal { /// /// For more information on formatters, see [the module-level documentation][module]. /// -/// [module]: ../index.html +/// [module]: ../../std/fmt/index.html /// /// # Examples /// @@ -523,14 +523,14 @@ pub trait Binary { /// Format trait for the `x` character. /// -/// The `LowerHex` trait should format its output as a number in hexidecimal, with `a` through `f` +/// The `LowerHex` trait should format its output as a number in hexadecimal, with `a` through `f` /// in lower case. /// /// The alternate flag, `#`, adds a `0x` in front of the output. /// /// For more information on formatters, see [the module-level documentation][module]. /// -/// [module]: ../index.html +/// [module]: ../../std/fmt/index.html /// /// # Examples /// @@ -571,14 +571,14 @@ pub trait LowerHex { /// Format trait for the `X` character. /// -/// The `UpperHex` trait should format its output as a number in hexidecimal, with `A` through `F` +/// The `UpperHex` trait should format its output as a number in hexadecimal, with `A` through `F` /// in upper case. /// /// The alternate flag, `#`, adds a `0x` in front of the output. /// /// For more information on formatters, see [the module-level documentation][module]. /// -/// [module]: ../index.html +/// [module]: ../../std/fmt/index.html /// /// # Examples /// @@ -620,11 +620,11 @@ pub trait UpperHex { /// Format trait for the `p` character. /// /// The `Pointer` trait should format its output as a memory location. This is commonly presented -/// as hexidecimal. +/// as hexadecimal. /// /// For more information on formatters, see [the module-level documentation][module]. /// -/// [module]: ../index.html +/// [module]: ../../std/fmt/index.html /// /// # Examples /// @@ -668,7 +668,7 @@ pub trait Pointer { /// /// For more information on formatters, see [the module-level documentation][module]. /// -/// [module]: ../index.html +/// [module]: ../../std/fmt/index.html /// /// # Examples /// @@ -711,7 +711,7 @@ pub trait LowerExp { /// /// For more information on formatters, see [the module-level documentation][module]. /// -/// [module]: ../index.html +/// [module]: ../../std/fmt/index.html /// /// # Examples /// @@ -865,12 +865,12 @@ impl<'a> Formatter<'a> { let mut sign = None; if !is_positive { sign = Some('-'); width += 1; - } else if self.flags & (1 << (FlagV1::SignPlus as u32)) != 0 { + } else if self.sign_plus() { sign = Some('+'); width += 1; } let mut prefixed = false; - if self.flags & (1 << (FlagV1::Alternate as u32)) != 0 { + if self.alternate() { prefixed = true; width += prefix.char_len(); } @@ -900,7 +900,7 @@ impl<'a> Formatter<'a> { } // The sign and prefix goes before the padding if the fill character // is zero - Some(min) if self.flags & (1 << (FlagV1::SignAwareZeroPad as u32)) != 0 => { + Some(min) if self.sign_aware_zero_pad() => { self.fill = '0'; try!(write_prefix(self)); self.with_padding(min - width, Alignment::Right, |f| { @@ -1013,7 +1013,7 @@ impl<'a> Formatter<'a> { let mut formatted = formatted.clone(); let mut align = self.align; let old_fill = self.fill; - if self.flags & (1 << (FlagV1::SignAwareZeroPad as u32)) != 0 { + if self.sign_aware_zero_pad() { // a sign always goes first let sign = unsafe { str::from_utf8_unchecked(formatted.sign) }; try!(self.buf.write_str(sign)); @@ -1098,25 +1098,40 @@ impl<'a> Formatter<'a> { pub fn flags(&self) -> u32 { self.flags } /// Character used as 'fill' whenever there is alignment - #[unstable(feature = "fmt_flags", reason = "method was just created", - issue = "27726")] + #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn fill(&self) -> char { self.fill } /// Flag indicating what form of alignment was requested - #[unstable(feature = "fmt_flags", reason = "method was just created", + #[unstable(feature = "fmt_flags_align", reason = "method was just created", issue = "27726")] pub fn align(&self) -> Alignment { self.align } /// Optionally specified integer width that the output should be - #[unstable(feature = "fmt_flags", reason = "method was just created", - issue = "27726")] + #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn width(&self) -> Option { self.width } /// Optionally specified precision for numeric types - #[unstable(feature = "fmt_flags", reason = "method was just created", - issue = "27726")] + #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn precision(&self) -> Option { self.precision } + /// Determines if the `+` flag was specified. + #[stable(feature = "fmt_flags", since = "1.5.0")] + pub fn sign_plus(&self) -> bool { self.flags & (1 << FlagV1::SignPlus as u32) != 0 } + + /// Determines if the `-` flag was specified. + #[stable(feature = "fmt_flags", since = "1.5.0")] + pub fn sign_minus(&self) -> bool { self.flags & (1 << FlagV1::SignMinus as u32) != 0 } + + /// Determines if the `#` flag was specified. + #[stable(feature = "fmt_flags", since = "1.5.0")] + pub fn alternate(&self) -> bool { self.flags & (1 << FlagV1::Alternate as u32) != 0 } + + /// Determines if the `0` flag was specified. + #[stable(feature = "fmt_flags", since = "1.5.0")] + pub fn sign_aware_zero_pad(&self) -> bool { + self.flags & (1 << FlagV1::SignAwareZeroPad as u32) != 0 + } + /// Creates a `DebugStruct` builder designed to assist with creation of /// `fmt::Debug` implementations for structs. /// @@ -1310,11 +1325,21 @@ impl Display for bool { #[stable(feature = "rust1", since = "1.0.0")] impl Debug for str { fn fmt(&self, f: &mut Formatter) -> Result { - try!(write!(f, "\"")); - for c in self.chars().flat_map(|c| c.escape_default()) { - try!(f.write_char(c)) + try!(f.write_char('"')); + let mut from = 0; + for (i, c) in self.char_indices() { + let esc = c.escape_default(); + // If char needs escaping, flush backlog so far and write, else skip + if esc.size_hint() != (1, Some(1)) { + try!(f.write_str(&self[from..i])); + for c in esc { + try!(f.write_char(c)); + } + from = i + c.len_utf8(); + } } - write!(f, "\"") + try!(f.write_str(&self[from..])); + f.write_char('"') } } @@ -1328,12 +1353,11 @@ impl Display for str { #[stable(feature = "rust1", since = "1.0.0")] impl Debug for char { fn fmt(&self, f: &mut Formatter) -> Result { - use char::CharExt; - try!(write!(f, "'")); + try!(f.write_char('\'')); for c in self.escape_default() { try!(f.write_char(c)) } - write!(f, "'") + f.write_char('\'') } } @@ -1361,7 +1385,7 @@ impl Pointer for *const T { // it denotes whether to prefix with 0x. We use it to work out whether // or not to zero extend, and then unconditionally set it to get the // prefix. - if f.flags & 1 << (FlagV1::Alternate as u32) > 0 { + if f.alternate() { f.flags |= 1 << (FlagV1::SignAwareZeroPad as u32); if let None = f.width { @@ -1410,7 +1434,7 @@ impl<'a, T> Pointer for &'a mut T { fn float_to_decimal_common(fmt: &mut Formatter, num: &T, negative_zero: bool) -> Result where T: flt2dec::DecodableFloat { - let force_sign = fmt.flags & (1 << (FlagV1::SignPlus as u32)) != 0; + let force_sign = fmt.sign_plus(); let sign = match (force_sign, negative_zero) { (false, false) => flt2dec::Sign::Minus, (false, true) => flt2dec::Sign::MinusRaw, @@ -1434,7 +1458,7 @@ fn float_to_decimal_common(fmt: &mut Formatter, num: &T, negative_zero: bool) fn float_to_exponential_common(fmt: &mut Formatter, num: &T, upper: bool) -> Result where T: flt2dec::DecodableFloat { - let force_sign = fmt.flags & (1 << (FlagV1::SignPlus as u32)) != 0; + let force_sign = fmt.sign_plus(); let sign = match force_sign { false => flt2dec::Sign::Minus, true => flt2dec::Sign::MinusPlus, diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index 022fe6711b..23642790a8 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -48,7 +48,9 @@ trait GenericRadix { fn base(&self) -> u8; /// A radix-specific prefix string. - fn prefix(&self) -> &'static str { "" } + fn prefix(&self) -> &'static str { + "" + } /// Converts an integer to corresponding radix digit. fn digit(&self, x: u8) -> u8; @@ -70,7 +72,10 @@ trait GenericRadix { x = x / base; // Deaccumulate the number. *byte = self.digit(n.to_u8()); // Store the digit in the buffer. curr -= 1; - if x == zero { break }; // No more digits left to accumulate. + if x == zero { + // No more digits left to accumulate. + break + }; } } else { // Do the same as above, but accounting for two's complement. @@ -79,7 +84,10 @@ trait GenericRadix { x = x / base; // Deaccumulate the number. *byte = self.digit(n.to_u8()); // Store the digit in the buffer. curr -= 1; - if x == zero { break }; // No more digits left to accumulate. + if x == zero { + // No more digits left to accumulate. + break + }; } } let buf = unsafe { str::from_utf8_unchecked(&buf[curr..]) }; @@ -141,13 +149,17 @@ pub struct Radix { impl Radix { fn new(base: u8) -> Radix { - assert!(2 <= base && base <= 36, "the base must be in the range of 2..36: {}", base); + assert!(2 <= base && base <= 36, + "the base must be in the range of 2..36: {}", + base); Radix { base: base } } } impl GenericRadix for Radix { - fn base(&self) -> u8 { self.base } + fn base(&self) -> u8 { + self.base + } fn digit(&self, x: u8) -> u8 { match x { x @ 0 ... 9 => b'0' + x, diff --git a/src/libcore/fmt/rt/v1.rs b/src/libcore/fmt/rt/v1.rs index 033834dd5a..f889045a3f 100644 --- a/src/libcore/fmt/rt/v1.rs +++ b/src/libcore/fmt/rt/v1.rs @@ -53,5 +53,5 @@ pub enum Count { #[derive(Copy, Clone)] pub enum Position { Next, - At(usize) + At(usize), } diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index 2a4c909d63..4e038f455e 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -100,7 +100,9 @@ pub trait Hash { /// Feeds a slice of this type into the state provided. #[stable(feature = "hash_slice", since = "1.3.0")] - fn hash_slice(data: &[Self], state: &mut H) where Self: Sized { + fn hash_slice(data: &[Self], state: &mut H) + where Self: Sized + { for piece in data { piece.hash(state); } @@ -121,7 +123,9 @@ pub trait 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]) } + fn write_u8(&mut self, i: u8) { + self.write(&[i]) + } /// Write a single `u16` into this hasher. #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] @@ -145,8 +149,7 @@ pub trait Hasher { #[stable(feature = "hasher_write", since = "1.3.0")] fn write_usize(&mut self, i: usize) { let bytes = unsafe { - ::slice::from_raw_parts(&i as *const usize as *const u8, - mem::size_of::()) + ::slice::from_raw_parts(&i as *const usize as *const u8, mem::size_of::()) }; self.write(bytes); } @@ -154,23 +157,33 @@ pub trait Hasher { /// Write 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) } + fn write_i8(&mut self, i: i8) { + self.write_u8(i as u8) + } /// Write 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) } + fn write_i16(&mut self, i: i16) { + self.write_u16(i as u16) + } /// Write 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) } + fn write_i32(&mut self, i: i32) { + self.write_u32(i as u32) + } /// Write 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) } + fn write_i64(&mut self, i: i64) { + self.write_u64(i as u64) + } /// Write a single `isize` into this hasher. #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] - fn write_isize(&mut self, i: isize) { self.write_usize(i as usize) } + fn write_isize(&mut self, i: isize) { + self.write_usize(i as usize) + } } ////////////////////////////////////////////////////////////////////////////// diff --git a/src/libcore/hash/sip.rs b/src/libcore/hash/sip.rs index 32a4f1e5bd..722d77a8a1 100644 --- a/src/libcore/hash/sip.rs +++ b/src/libcore/hash/sip.rs @@ -37,12 +37,12 @@ pub struct SipHasher { // and simd implementations of SipHash will use vectors // of v02 and v13. By placing them in this order in the struct, // the compiler can pick up on just a few simd optimizations by itself. - v0: u64, // hash state + v0: u64, // hash state v2: u64, v1: u64, v3: u64, tail: u64, // unprocessed bytes le - ntail: usize, // how many bytes in tail are valid + ntail: usize, // how many bytes in tail are valid } // sadly, these macro definitions can't appear later, @@ -80,8 +80,7 @@ macro_rules! u8to64_le { 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); + ptr::copy_nonoverlapping(buf.get_unchecked(i), &mut data as *mut _ as *mut u8, 8); data.to_le() } @@ -152,12 +151,12 @@ impl Hasher for SipHasher { if self.ntail != 0 { needed = 8 - self.ntail; if length < needed { - self.tail |= u8to64_le!(msg, 0, length) << 8*self.ntail; + self.tail |= u8to64_le!(msg, 0, length) << 8 * self.ntail; self.ntail += length; return } - let m = self.tail | u8to64_le!(msg, 0, needed) << 8*self.ntail; + let m = self.tail | u8to64_le!(msg, 0, needed) << 8 * self.ntail; self.v3 ^= m; compress!(self.v0, self.v1, self.v2, self.v3); diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index ece285a831..45b1c8a359 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -301,7 +301,7 @@ extern "rust-intrinsic" { /// # Safety /// /// Beyond requiring that the program must be allowed to access both regions - /// of memory, it is Undefined Behaviour for source and destination to + /// of memory, it is Undefined Behavior for source and destination to /// overlap. Care must also be taken with the ownership of `src` and /// `dst`. This method semantically moves the values of `src` into `dst`. /// However it does not drop the contents of `dst`, or prevent the contents @@ -373,20 +373,20 @@ extern "rust-intrinsic" { /// a size of `count` * `size_of::()` and an alignment of /// `min_align_of::()` /// - /// The volatile parameter parameter is set to `true`, so it will not be optimized out. + /// The volatile parameter is set to `true`, so it will not be optimized out. pub fn volatile_copy_nonoverlapping_memory(dst: *mut T, src: *const T, count: usize); /// Equivalent to the appropriate `llvm.memmove.p0i8.0i8.*` intrinsic, with /// a size of `count` * `size_of::()` and an alignment of /// `min_align_of::()` /// - /// The volatile parameter parameter is set to `true`, so it will not be optimized out. + /// The volatile parameter is set to `true`, so it will not be optimized out. pub fn volatile_copy_memory(dst: *mut T, src: *const T, count: usize); /// Equivalent to the appropriate `llvm.memset.p0i8.*` intrinsic, with a /// size of `count` * `size_of::()` and an alignment of /// `min_align_of::()`. /// - /// The volatile parameter parameter is set to `true`, so it will not be optimized out. + /// The volatile parameter is set to `true`, so it will not be optimized out. pub fn volatile_set_memory(dst: *mut T, val: u8, count: usize); /// Perform a volatile load from the `src` pointer. diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 97dcb2475a..5353fcaa3b 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -8,51 +8,293 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Composable external iterators +//! Composable external iteration //! -//! # The `Iterator` trait +//! If you've found yourself with a collection of some kind, and needed to +//! perform an operation on the elements of said collection, you'll quickly run +//! into 'iterators'. Iterators are heavily used in idiomatic Rust code, so +//! it's worth becoming familiar with them. //! -//! This module defines Rust's core iteration trait. The `Iterator` trait has -//! one unimplemented method, `next`. All other methods are derived through -//! default methods to perform operations such as `zip`, `chain`, `enumerate`, -//! and `fold`. +//! Before explaining more, let's talk about how this module is structured: //! -//! The goal of this module is to unify iteration across all containers in Rust. -//! An iterator can be considered as a state machine which is used to track -//! which element will be yielded next. +//! # Organization //! -//! There are various extensions also defined in this module to assist with -//! various types of iteration, such as the `DoubleEndedIterator` for iterating -//! in reverse, the `FromIterator` trait for creating a container from an -//! iterator, and much more. +//! This module is largely organized by type: //! -//! # Rust's `for` loop +//! * [Traits] are the core portion: these traits define what kind of iterators +//! exist and what you can do with them. The methods of these traits are worth +//! putting some extra study time into. +//! * [Functions] provide some helpful ways to create some basic iterators. +//! * [Structs] are often the return types of the various methods on this +//! module's traits. You'll usually want to look at the method that creates +//! the `struct`, rather than the `struct` itself. For more detail about why, +//! see '[Implementing Iterator](#implementing-iterator)'. //! -//! The special syntax used by rust's `for` loop is based around the -//! `IntoIterator` trait defined in this module. `for` loops can be viewed as a -//! syntactical expansion into a `loop`, for example, the `for` loop in this -//! example is essentially translated to the `loop` below. +//! [Traits]: #traits +//! [Functions]: #functions +//! [Structs]: #structs +//! +//! That's it! Let's dig into iterators. +//! +//! # Iterator +//! +//! The heart and soul of this module is the [`Iterator`] trait. The core of +//! [`Iterator`] looks like this: +//! +//! ``` +//! trait Iterator { +//! type Item; +//! fn next(&mut self) -> Option; +//! } +//! ``` +//! +//! An iterator has a method, [`next()`], which when called, returns an +//! [`Option`]``. [`next()`] will return `Some(Item)` as long as there +//! are elements, and once they've all been exhausted, will return `None` to +//! indicate that iteration is finished. Individual iterators may choose to +//! resume iteration, and so calling [`next()`] again may or may not eventually +//! start returning `Some(Item)` again at some point. +//! +//! [`Iterator`]'s full definition includes a number of other methods as well, +//! but they are default methods, built on top of [`next()`], and so you get +//! them for free. +//! +//! Iterators are also composable, and it's common to chain them together to do +//! more complex forms of processing. See the [Adapters](#adapters) section +//! below for more details. +//! +//! [`Iterator`]: trait.Iterator.html +//! [`next()`]: trait.Iterator.html#tymethod.next +//! [`Option`]: ../option/enum.Option.html +//! +//! # The three forms of iteration +//! +//! There are three common methods which can create iterators from a collection: +//! +//! * `iter()`, which iterates over `&T`. +//! * `iter_mut()`, which iterates over `&mut T`. +//! * `into_iter()`, which iterates over `T`. +//! +//! Various things in the standard library may implement one or more of the +//! three, where appropriate. +//! +//! # Implementing Iterator +//! +//! Creating an iterator of your own involves two steps: creating a `struct` to +//! hold the iterator's state, and then `impl`ementing [`Iterator`] for that +//! `struct`. This is why there are so many `struct`s in this module: there is +//! one for each iterator and iterator adapter. +//! +//! Let's make an iterator named `Counter` which counts from `1` to `5`: //! //! ``` -//! let values = vec![1, 2, 3]; +//! // First, the struct: +//! +//! /// An iterator which counts from one to five +//! struct Counter { +//! count: usize, +//! } +//! +//! // we want our count to start at one, so let's add a new() method to help. +//! // This isn't strictly necessary, but is convenient. Note that we start +//! // `count` at zero, we'll see why in `next()`'s implementation below. +//! impl Counter { +//! fn new() -> Counter { +//! Counter { count: 0 } +//! } +//! } +//! +//! // Then, we implement `Iterator` for our `Counter`: +//! +//! impl Iterator for Counter { +//! // we will be counting with usize +//! type Item = usize; +//! +//! // next() is the only required method +//! fn next(&mut self) -> Option { +//! // increment our count. This is why we started at zero. +//! self.count += 1; +//! +//! // check to see if we've finished counting or not. +//! if self.count < 6 { +//! Some(self.count) +//! } else { +//! None +//! } +//! } +//! } +//! +//! // And now we can use it! +//! +//! let mut counter = Counter::new(); +//! +//! let x = counter.next().unwrap(); +//! println!("{}", x); +//! +//! let x = counter.next().unwrap(); +//! println!("{}", x); +//! +//! let x = counter.next().unwrap(); +//! println!("{}", x); +//! +//! let x = counter.next().unwrap(); +//! println!("{}", x); +//! +//! let x = counter.next().unwrap(); +//! println!("{}", x); +//! ``` +//! +//! This will print `1` through `5`, each on their own line. +//! +//! Calling `next()` this way gets repetitive. Rust has a construct which can +//! call `next()` on your iterator, until it reaches `None`. Let's go over that +//! next. +//! +//! # for Loops and IntoIterator +//! +//! Rust's `for` loop syntax is actually sugar for iterators. Here's a basic +//! example of `for`: +//! +//! ``` +//! let values = vec![1, 2, 3, 4, 5]; //! //! for x in values { //! println!("{}", x); //! } +//! ``` //! -//! // Rough translation of the iteration without a `for` iterator. -//! # let values = vec![1, 2, 3]; -//! let mut it = values.into_iter(); -//! loop { -//! match it.next() { -//! Some(x) => println!("{}", x), -//! None => break, -//! } +//! This will print the numbers one through five, each on their own line. But +//! you'll notice something here: we never called anything on our vector to +//! produce an iterator. What gives? +//! +//! There's a trait in the standard library for converting something into an +//! iterator: [`IntoIterator`]. This trait has one method, [`into_iter()`], +//! which converts the thing implementing [`IntoIterator`] into an iterator. +//! Let's take a look at that `for` loop again, and what the compiler converts +//! it into: +//! +//! [`IntoIterator`]: trait.IntoIterator.html +//! [`into_iter()`]: trait.IntoIterator.html#tymethod.into_iter +//! +//! ``` +//! let values = vec![1, 2, 3, 4, 5]; +//! +//! for x in values { +//! println!("{}", x); //! } //! ``` //! -//! Because `Iterator`s implement `IntoIterator`, this `for` loop syntax can be -//! applied to any iterator over any type. +//! Rust de-sugars this into: +//! +//! ``` +//! let values = vec![1, 2, 3, 4, 5]; +//! { +//! let result = match values.into_iter() { +//! mut iter => loop { +//! match iter.next() { +//! Some(x) => { println!("{}", x); }, +//! None => break, +//! } +//! }, +//! }; +//! result +//! } +//! ``` +//! +//! First, we call `into_iter()` on the value. Then, we match on the iterator +//! that returns, calling [`next()`] over and over until we see a `None`. At +//! that point, we `break` out of the loop, and we're done iterating. +//! +//! There's one more subtle bit here: the standard library contains an +//! interesting implementation of [`IntoIterator`]: +//! +//! ```ignore +//! impl IntoIterator for I +//! ``` +//! +//! In other words, all [`Iterator`]s implement [`IntoIterator`], by just +//! returning themselves. This means two things: +//! +//! 1. If you're writing an [`Iterator`], you can use it with a `for` loop. +//! 2. If you're creating a collection, implementing [`IntoIterator`] for it +//! will allow your collection to be used with the `for` loop. +//! +//! # Adapters +//! +//! Functions which take an [`Iterator`] and return another [`Iterator`] are +//! often called 'iterator adapters', as they're a form of the 'adapter +//! pattern'. +//! +//! Common iterator adapters include [`map()`], [`take()`], and [`collect()`]. +//! For more, see their documentation. +//! +//! [`map()`]: trait.Iterator.html#method.map +//! [`take()`]: trait.Iterator.html#method.take +//! [`collect()`]: trait.Iterator.html#method.collect +//! +//! # Laziness +//! +//! Iterators (and iterator [adapters](#adapters)) are *lazy*. This means that +//! just creating an iterator doesn't _do_ a whole lot. Nothing really happens +//! until you call [`next()`]. This is sometimes a source of confusion when +//! creating an iterator solely for its side effects. For example, the [`map()`] +//! method calls a closure on each element it iterates over: +//! +//! ``` +//! let v = vec![1, 2, 3, 4, 5]; +//! v.iter().map(|x| println!("{}", x)); +//! ``` +//! +//! This will not print any values, as we only created an iterator, rather than +//! using it. The compiler will warn us about this kind of behavior: +//! +//! ```text +//! warning: unused result which must be used: iterator adaptors are lazy and +//! do nothing unless consumed +//! ``` +//! +//! The idiomatic way to write a [`map()`] for its side effects is to use a +//! `for` loop instead: +//! +//! ``` +//! let v = vec![1, 2, 3, 4, 5]; +//! +//! for x in &v { +//! println!("{}", x); +//! } +//! ``` +//! +//! [`map()`]: trait.Iterator.html#method.map +//! +//! The two most common ways to evaluate an iterator are to use a `for` loop +//! like this, or using the [`collect()`] adapter to produce a new collection. +//! +//! [`collect()`]: trait.Iterator.html#method.collect +//! +//! # Infinity +//! +//! Iterators do not have to be finite. As an example, an open-ended range is +//! an infinite iterator: +//! +//! ``` +//! let numbers = 0..; +//! ``` +//! +//! It is common to use the [`take()`] iterator adapter to turn an infinite +//! iterator into a finite one: +//! +//! ``` +//! let numbers = 0..; +//! let five_numbers = numbers.take(5); +//! +//! for number in five_numbers { +//! println!("{}", number); +//! } +//! ``` +//! +//! This will print the numbers `0` through `4`, each on their own line. +//! +//! [`take()`]: trait.Iterator.html#method.take #![stable(feature = "rust1", since = "1.0.0")] @@ -165,7 +407,7 @@ pub trait Iterator { #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn nth(&mut self, mut n: usize) -> Option where Self: Sized { - for x in self.by_ref() { + for x in self { if n == 0 { return Some(x) } n -= 1; } @@ -637,7 +879,7 @@ pub trait Iterator { fn all(&mut self, mut f: F) -> bool where Self: Sized, F: FnMut(Self::Item) -> bool { - for x in self.by_ref() { + for x in self { if !f(x) { return false; } @@ -664,7 +906,7 @@ pub trait Iterator { Self: Sized, F: FnMut(Self::Item) -> bool { - for x in self.by_ref() { + for x in self { if f(x) { return true; } @@ -689,7 +931,7 @@ pub trait Iterator { Self: Sized, P: FnMut(&Self::Item) -> bool, { - for x in self.by_ref() { + for x in self { if predicate(&x) { return Some(x) } } None @@ -725,7 +967,7 @@ pub trait Iterator { P: FnMut(Self::Item) -> bool, { // `enumerate` might overflow. - for (i, x) in self.by_ref().enumerate() { + for (i, x) in self.enumerate() { if predicate(x) { return Some(i); } @@ -935,7 +1177,7 @@ pub trait Iterator { /// Creates an iterator that clones the elements it yields. /// - /// This is useful for converting an Iterator<&T> to an Iterator, + /// This is useful for converting an `Iterator<&T>` to an`Iterator`, /// so it's a more convenient form of `map(|&x| x)`. /// /// # Examples @@ -1015,7 +1257,7 @@ pub trait Iterator { /// Lexicographically compares the elements of this `Iterator` with those /// of another. - #[unstable(feature = "iter_order", reason = "needs review and revision", issue = "27737")] + #[stable(feature = "iter_order", since = "1.5.0")] fn cmp(mut self, other: I) -> Ordering where I: IntoIterator, Self::Item: Ord, @@ -1038,7 +1280,7 @@ pub trait Iterator { /// Lexicographically compares the elements of this `Iterator` with those /// of another. - #[unstable(feature = "iter_order", reason = "needs review and revision", issue = "27737")] + #[stable(feature = "iter_order", since = "1.5.0")] fn partial_cmp(mut self, other: I) -> Option where I: IntoIterator, Self::Item: PartialOrd, @@ -1061,7 +1303,7 @@ pub trait Iterator { /// Determines if the elements of this `Iterator` are equal to those of /// another. - #[unstable(feature = "iter_order", reason = "needs review and revision", issue = "27737")] + #[stable(feature = "iter_order", since = "1.5.0")] fn eq(mut self, other: I) -> bool where I: IntoIterator, Self::Item: PartialEq, @@ -1080,7 +1322,7 @@ pub trait Iterator { /// Determines if the elements of this `Iterator` are unequal to those of /// another. - #[unstable(feature = "iter_order", reason = "needs review and revision", issue = "27737")] + #[stable(feature = "iter_order", since = "1.5.0")] fn ne(mut self, other: I) -> bool where I: IntoIterator, Self::Item: PartialEq, @@ -1099,7 +1341,7 @@ pub trait Iterator { /// Determines if the elements of this `Iterator` are lexicographically /// less than those of another. - #[unstable(feature = "iter_order", reason = "needs review and revision", issue = "27737")] + #[stable(feature = "iter_order", since = "1.5.0")] fn lt(mut self, other: I) -> bool where I: IntoIterator, Self::Item: PartialOrd, @@ -1126,7 +1368,7 @@ pub trait Iterator { /// Determines if the elements of this `Iterator` are lexicographically /// less or equal to those of another. - #[unstable(feature = "iter_order", reason = "needs review and revision", issue = "27737")] + #[stable(feature = "iter_order", since = "1.5.0")] fn le(mut self, other: I) -> bool where I: IntoIterator, Self::Item: PartialOrd, @@ -1153,7 +1395,7 @@ pub trait Iterator { /// Determines if the elements of this `Iterator` are lexicographically /// greater than those of another. - #[unstable(feature = "iter_order", reason = "needs review and revision", issue = "27737")] + #[stable(feature = "iter_order", since = "1.5.0")] fn gt(mut self, other: I) -> bool where I: IntoIterator, Self::Item: PartialOrd, @@ -1180,7 +1422,7 @@ pub trait Iterator { /// Determines if the elements of this `Iterator` are lexicographically /// greater than or equal to those of another. - #[unstable(feature = "iter_order", reason = "needs review and revision", issue = "27737")] + #[stable(feature = "iter_order", since = "1.5.0")] fn ge(mut self, other: I) -> bool where I: IntoIterator, Self::Item: PartialOrd, @@ -1211,7 +1453,7 @@ pub trait Iterator { /// /// This is an idiosyncratic helper to try to factor out the /// commonalities of {max,min}{,_by}. In particular, this avoids -/// having to implement optimisations several times. +/// having to implement optimizations several times. #[inline] fn select_fold1(mut it: I, mut f_proj: FProj, @@ -1244,11 +1486,11 @@ impl<'a, I: Iterator + ?Sized> Iterator for &'a mut I { fn size_hint(&self) -> (usize, Option) { (**self).size_hint() } } -/// Conversion from an `Iterator` +/// Conversion from an `Iterator`. #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented="a collection of type `{Self}` cannot be \ built from an iterator over elements of type `{A}`"] -pub trait FromIterator { +pub trait FromIterator: Sized { /// Builds a container with elements from something iterable. /// /// # Examples @@ -1276,21 +1518,90 @@ pub trait FromIterator { fn from_iter>(iterator: T) -> Self; } -/// Conversion into an `Iterator` +/// Conversion into an `Iterator`. +/// +/// By implementing `IntoIterator` for a type, you define how it will be +/// converted to an iterator. This is common for types which describe a +/// collection of some kind. +/// +/// One benefit of implementing `IntoIterator` is that your type will [work +/// with Rust's `for` loop syntax](index.html#for-loops-and-intoiterator). /// -/// Implementing this trait allows you to use your type with Rust's `for` loop. See -/// the [module level documentation](index.html) for more details. +/// # Examples +/// +/// Vectors implement `IntoIterator`: +/// +/// ``` +/// let v = vec![1, 2, 3]; +/// +/// let mut iter = v.into_iter(); +/// +/// let n = iter.next(); +/// assert_eq!(Some(1), n); +/// +/// let n = iter.next(); +/// assert_eq!(Some(2), n); +/// +/// let n = iter.next(); +/// assert_eq!(Some(3), n); +/// +/// let n = iter.next(); +/// assert_eq!(None, n); +/// ``` +/// +/// Implementing `IntoIterator` for your type: +/// +/// ``` +/// // A sample collection, that's just a wrapper over Vec +/// #[derive(Debug)] +/// struct MyCollection(Vec); +/// +/// // Let's give it some methods so we can create one and add things +/// // to it. +/// impl MyCollection { +/// fn new() -> MyCollection { +/// MyCollection(Vec::new()) +/// } +/// +/// fn add(&mut self, elem: i32) { +/// self.0.push(elem); +/// } +/// } +/// +/// // and we'll implement IntoIterator +/// impl IntoIterator for MyCollection { +/// type Item = i32; +/// type IntoIter = ::std::vec::IntoIter; +/// +/// fn into_iter(self) -> Self::IntoIter { +/// self.0.into_iter() +/// } +/// } +/// +/// // Now we can make a new collection... +/// let mut c = MyCollection::new(); +/// +/// // ... add some stuff to it ... +/// c.add(0); +/// c.add(1); +/// c.add(2); +/// +/// // ... and then turn it into an Iterator: +/// for (i, n) in c.into_iter().enumerate() { +/// assert_eq!(i as i32, n); +/// } +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait IntoIterator { - /// The type of the elements being iterated + /// The type of the elements being iterated over. #[stable(feature = "rust1", since = "1.0.0")] type Item; - /// A container for iterating over elements of type `Item` + /// Which kind of iterator are we turning this into? #[stable(feature = "rust1", since = "1.0.0")] type IntoIter: Iterator; - /// Consumes `Self` and returns an iterator over it + /// Consumes `Self` and returns an iterator over it. #[stable(feature = "rust1", since = "1.0.0")] fn into_iter(self) -> Self::IntoIter; } @@ -1305,23 +1616,164 @@ impl IntoIterator for I { } } -/// A type growable from an `Iterator` implementation +/// Extend a collection with the contents of an iterator. +/// +/// Iterators produce a series of values, and collections can also be thought +/// of as a series of values. The `Extend` trait bridges this gap, allowing you +/// to extend a collection by including the contents of that iterator. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// // You can extend a String with some chars: +/// let mut message = String::from("The first three letters are: "); +/// +/// message.extend(&['a', 'b', 'c']); +/// +/// assert_eq!("abc", &message[29..32]); +/// ``` +/// +/// Implementing `Extend`: +/// +/// ``` +/// // A sample collection, that's just a wrapper over Vec +/// #[derive(Debug)] +/// struct MyCollection(Vec); +/// +/// // Let's give it some methods so we can create one and add things +/// // to it. +/// impl MyCollection { +/// fn new() -> MyCollection { +/// MyCollection(Vec::new()) +/// } +/// +/// fn add(&mut self, elem: i32) { +/// self.0.push(elem); +/// } +/// } +/// +/// // since MyCollection has a list of i32s, we implement Extend for i32 +/// impl Extend for MyCollection { +/// +/// // This is a bit simpler with the concrete type signature: we can call +/// // extend on anything which can be turned into an Iterator which gives +/// // us i32s. Because we need i32s to put into MyCollection. +/// fn extend>(&mut self, iterable: T) { +/// +/// // The implementation is very straightforward: loop through the +/// // iterator, and add() each element to ourselves. +/// for elem in iterable { +/// self.add(elem); +/// } +/// } +/// } +/// +/// let mut c = MyCollection::new(); +/// +/// c.add(5); +/// c.add(6); +/// c.add(7); +/// +/// // let's extend our collection with three more numbers +/// c.extend(vec![1, 2, 3]); +/// +/// // we've added these elements onto the end +/// assert_eq!("MyCollection([5, 6, 7, 1, 2, 3])", format!("{:?}", c)); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait Extend { - /// Extends a container with the elements yielded by an arbitrary iterator + /// Extends a collection with the contents of an iterator. + /// + /// As this is the only method for this trait, the [trait-level] docs + /// contain more details. + /// + /// [trait-level]: trait.Extend.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// // You can extend a String with some chars: + /// let mut message = String::from("The first three letters are: "); + /// + /// message.extend(['a', 'b', 'c'].iter()); + /// + /// assert_eq!("abc", &message[29..32]); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn extend>(&mut self, iterable: T); } -/// A range iterator able to yield elements from both ends +/// An iterator able to yield elements from both ends. +/// +/// Something that implements `DoubleEndedIterator` has one extra capability +/// over something that implements [`Iterator`]: the ability to also take +/// `Item`s from the back, as well as the front. +/// +/// It is important to note that both back and forth work on the same range, +/// and do not cross: iteration is over when they meet in the middle. +/// +/// [`Iterator`]: trait.Iterator.html +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// let numbers = vec![1, 2, 3]; +/// +/// let mut iter = numbers.iter(); +/// +/// let n = iter.next(); +/// assert_eq!(Some(&1), n); +/// +/// let n = iter.next_back(); +/// assert_eq!(Some(&3), n); /// -/// A `DoubleEndedIterator` can be thought of as a deque in that `next()` and -/// `next_back()` exhaust elements from the *same* range, and do not work -/// independently of each other. +/// let n = iter.next_back(); +/// assert_eq!(Some(&2), n); +/// +/// let n = iter.next(); +/// assert_eq!(None, n); +/// +/// let n = iter.next_back(); +/// assert_eq!(None, n); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait DoubleEndedIterator: Iterator { - /// Yields an element from the end of the range, returning `None` if the - /// range is empty. + /// An iterator able to yield elements from both ends. + /// + /// As this is the only method for this trait, the [trait-level] docs + /// contain more details. + /// + /// [trait-level]: trait.DoubleEndedIterator.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let numbers = vec![1, 2, 3]; + /// + /// let mut iter = numbers.iter(); + /// + /// let n = iter.next(); + /// assert_eq!(Some(&1), n); + /// + /// let n = iter.next_back(); + /// assert_eq!(Some(&3), n); + /// + /// let n = iter.next_back(); + /// assert_eq!(Some(&2), n); + /// + /// let n = iter.next(); + /// assert_eq!(None, n); + /// + /// let n = iter.next_back(); + /// assert_eq!(None, n); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn next_back(&mut self) -> Option; } @@ -1331,18 +1783,98 @@ impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I { fn next_back(&mut self) -> Option { (**self).next_back() } } -/// An iterator that knows its exact length +/// An iterator that knows its exact length. +/// +/// Many [`Iterator`]s don't know how many times they will iterate, but some do. +/// If an iterator knows how many times it can iterate, providing access to +/// that information can be useful. For example, if you want to iterate +/// backwards, a good start is to know where the end is. /// -/// This trait is a helper for iterators like the vector iterator, so that -/// it can support double-ended enumeration. +/// When implementing an `ExactSizeIterator`, You must also implement +/// [`Iterator`]. When doing so, the implementation of [`size_hint()`] *must* +/// return the exact size of the iterator. /// -/// `Iterator::size_hint` *must* return the exact size of the iterator. -/// Note that the size must fit in `usize`. +/// [`Iterator`]: trait.Iterator.html +/// [`size_hint()`]: trait.Iterator.html#method.size_hint +/// +/// The [`len()`] method has a default implementation, so you usually shouldn't +/// implement it. However, you may be able to provide a more performant +/// implementation than the default, so overriding it in this case makes sense. +/// +/// [`len()`]: #method.len +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// // a finite range knows exactly how many times it will iterate +/// let five = (0..5); +/// +/// assert_eq!(5, five.len()); +/// ``` +/// +/// In the [module level docs][moddocs], we implemented an [`Iterator`], +/// `Counter`. Let's implement `ExactSizeIterator` for it as well: +/// +/// [moddocs]: index.html +/// +/// ``` +/// # struct Counter { +/// # count: usize, +/// # } +/// # impl Counter { +/// # fn new() -> Counter { +/// # Counter { count: 0 } +/// # } +/// # } +/// # impl Iterator for Counter { +/// # type Item = usize; +/// # fn next(&mut self) -> Option { +/// # self.count += 1; +/// # if self.count < 6 { +/// # Some(self.count) +/// # } else { +/// # None +/// # } +/// # } +/// # } +/// impl ExactSizeIterator for Counter { +/// // We already have the number of iterations, so we can use it directly. +/// fn len(&self) -> usize { +/// self.count +/// } +/// } +/// +/// // And now we can use it! +/// +/// let counter = Counter::new(); +/// +/// assert_eq!(0, counter.len()); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait ExactSizeIterator: Iterator { #[inline] #[stable(feature = "rust1", since = "1.0.0")] - /// Returns the exact length of the iterator. + /// Returns the exact number of times the iterator will iterate. + /// + /// This method has a default implementation, so you usually should not + /// implement it directly. However, if you can provide a more efficient + /// implementation, you can do so. See the [trait-level] docs for an + /// example. + /// + /// [trait-level]: trait.ExactSizeIterator.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// // a finite range knows exactly how many times it will iterate + /// let five = (0..5); + /// + /// assert_eq!(5, five.len()); + /// ``` fn len(&self) -> usize { let (lower, upper) = self.size_hint(); // Note: This assertion is overly defensive, but it checks the invariant @@ -1376,7 +1908,13 @@ impl ExactSizeIterator for Map where impl ExactSizeIterator for Zip where A: ExactSizeIterator, B: ExactSizeIterator {} -/// An double-ended iterator with the direction inverted +/// An double-ended iterator with the direction inverted. +/// +/// This `struct` is created by the [`rev()`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`rev()`]: trait.Iterator.html#method.rev +/// [`Iterator`]: trait.Iterator.html #[derive(Clone)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] @@ -1400,7 +1938,13 @@ impl DoubleEndedIterator for Rev where I: DoubleEndedIterator { fn next_back(&mut self) -> Option<::Item> { self.iter.next() } } -/// An iterator that clones the elements of an underlying iterator +/// An iterator that clones the elements of an underlying iterator. +/// +/// This `struct` is created by the [`cloned()`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`cloned()`]: trait.Iterator.html#method.cloned +/// [`Iterator`]: trait.Iterator.html #[stable(feature = "iter_cloned", since = "1.1.0")] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[derive(Clone)] @@ -1437,7 +1981,13 @@ impl<'a, I, T: 'a> ExactSizeIterator for Cloned where I: ExactSizeIterator, T: Clone {} -/// An iterator that repeats endlessly +/// An iterator that repeats endlessly. +/// +/// This `struct` is created by the [`cycle()`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`cycle()`]: trait.Iterator.html#method.cycle +/// [`Iterator`]: trait.Iterator.html #[derive(Clone)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] @@ -1469,7 +2019,13 @@ impl Iterator for Cycle where I: Clone + Iterator { } } -/// An iterator that strings two iterators together +/// An iterator that strings two iterators together. +/// +/// This `struct` is created by the [`chain()`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`chain()`]: trait.Iterator.html#method.chain +/// [`Iterator`]: trait.Iterator.html #[derive(Clone)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] @@ -1559,7 +2115,12 @@ impl Iterator for Chain where #[inline] fn last(self) -> Option { match self.state { - ChainState::Both => self.b.last().or(self.a.last()), + ChainState::Both => { + // Must exhaust a before b. + let a_last = self.a.last(); + let b_last = self.b.last(); + b_last.or(a_last) + }, ChainState::Front => self.a.last(), ChainState::Back => self.b.last() } @@ -1602,7 +2163,13 @@ impl DoubleEndedIterator for Chain where } } -/// An iterator that iterates two other iterators simultaneously +/// An iterator that iterates two other iterators simultaneously. +/// +/// This `struct` is created by the [`zip()`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`zip()`]: trait.Iterator.html#method.zip +/// [`Iterator`]: trait.Iterator.html #[derive(Clone)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] @@ -1668,7 +2235,13 @@ impl DoubleEndedIterator for Zip where } } -/// An iterator that maps the values of `iter` with `f` +/// An iterator that maps the values of `iter` with `f`. +/// +/// This `struct` is created by the [`map()`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`map()`]: trait.Iterator.html#method.map +/// [`Iterator`]: trait.Iterator.html #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] @@ -1702,7 +2275,13 @@ impl DoubleEndedIterator for Map where } } -/// An iterator that filters the elements of `iter` with `predicate` +/// An iterator that filters the elements of `iter` with `predicate`. +/// +/// This `struct` is created by the [`filter()`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`filter()`]: trait.Iterator.html#method.filter +/// [`Iterator`]: trait.Iterator.html #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] @@ -1747,7 +2326,13 @@ impl DoubleEndedIterator for Filter } } -/// An iterator that uses `f` to both filter and map elements from `iter` +/// An iterator that uses `f` to both filter and map elements from `iter`. +/// +/// This `struct` is created by the [`filter_map()`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`filter_map()`]: trait.Iterator.html#method.filter_map +/// [`Iterator`]: trait.Iterator.html #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] @@ -1794,7 +2379,13 @@ impl DoubleEndedIterator for FilterMap } } -/// An iterator that yields the current count and the element during iteration +/// An iterator that yields the current count and the element during iteration. +/// +/// This `struct` is created by the [`enumerate()`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`enumerate()`]: trait.Iterator.html#method.enumerate +/// [`Iterator`]: trait.Iterator.html #[derive(Clone)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] @@ -1861,7 +2452,15 @@ impl DoubleEndedIterator for Enumerate where } } -/// An iterator with a `peek()` that returns an optional reference to the next element. +/// An iterator with a `peek()` that returns an optional reference to the next +/// element. +/// +/// This `struct` is created by the [`peekable()`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`peekable()`]: trait.Iterator.html#method.peekable +/// [`Iterator`]: trait.Iterator.html +#[derive(Clone)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] pub struct Peekable { @@ -1869,15 +2468,6 @@ pub struct Peekable { peeked: Option, } -impl Clone for Peekable where I::Item: Clone { - fn clone(&self) -> Peekable { - Peekable { - iter: self.iter.clone(), - peeked: self.peeked.clone(), - } - } -} - #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for Peekable { type Item = I::Item; @@ -1951,7 +2541,13 @@ impl Peekable { } } -/// An iterator that rejects elements while `predicate` is true +/// An iterator that rejects elements while `predicate` is true. +/// +/// This `struct` is created by the [`skip_while()`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`skip_while()`]: trait.Iterator.html#method.skip_while +/// [`Iterator`]: trait.Iterator.html #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] @@ -1985,7 +2581,13 @@ impl Iterator for SkipWhile } } -/// An iterator that only accepts elements while `predicate` is true +/// An iterator that only accepts elements while `predicate` is true. +/// +/// This `struct` is created by the [`take_while()`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`take_while()`]: trait.Iterator.html#method.take_while +/// [`Iterator`]: trait.Iterator.html #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] @@ -2025,6 +2627,12 @@ impl Iterator for TakeWhile } /// An iterator that skips over `n` elements of `iter`. +/// +/// This `struct` is created by the [`skip()`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`skip()`]: trait.Iterator.html#method.skip +/// [`Iterator`]: trait.Iterator.html #[derive(Clone)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] @@ -2099,6 +2707,12 @@ impl Iterator for Skip where I: Iterator { impl ExactSizeIterator for Skip where I: ExactSizeIterator {} /// An iterator that only iterates over the first `n` iterations of `iter`. +/// +/// This `struct` is created by the [`take()`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`take()`]: trait.Iterator.html#method.take +/// [`Iterator`]: trait.Iterator.html #[derive(Clone)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] @@ -2154,7 +2768,13 @@ impl Iterator for Take where I: Iterator{ impl ExactSizeIterator for Take where I: ExactSizeIterator {} -/// An iterator to maintain state while iterating another iterator +/// An iterator to maintain state while iterating another iterator. +/// +/// This `struct` is created by the [`scan()`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`scan()`]: trait.Iterator.html#method.scan +/// [`Iterator`]: trait.Iterator.html #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] @@ -2183,9 +2803,14 @@ impl Iterator for Scan where } } -/// An iterator that maps each element to an iterator, -/// and yields the elements of the produced iterators +/// An iterator that maps each element to an iterator, and yields the elements +/// of the produced iterators. +/// +/// This `struct` is created by the [`flat_map()`] method on [`Iterator`]. See its +/// documentation for more. /// +/// [`flat_map()`]: trait.Iterator.html#method.flat_map +/// [`Iterator`]: trait.Iterator.html #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] @@ -2253,6 +2878,12 @@ impl DoubleEndedIterator for FlatMap wher /// An iterator that yields `None` forever after the underlying iterator /// yields `None` once. +/// +/// This `struct` is created by the [`fuse()`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`fuse()`]: trait.Iterator.html#method.fuse +/// [`Iterator`]: trait.Iterator.html #[derive(Clone)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] @@ -2332,8 +2963,14 @@ impl DoubleEndedIterator for Fuse where I: DoubleEndedIterator { #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Fuse where I: ExactSizeIterator {} -/// An iterator that calls a function with a reference to each -/// element before yielding it. +/// An iterator that calls a function with a reference to each element before +/// yielding it. +/// +/// This `struct` is created by the [`inspect()`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`inspect()`]: trait.Iterator.html#method.inspect +/// [`Iterator`]: trait.Iterator.html #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] @@ -2587,6 +3224,8 @@ impl Iterator for StepBy> where #[unstable(feature = "range_inclusive", reason = "likely to be replaced by range notation and adapters", issue = "27777")] +#[deprecated(since = "1.5.0", reason = "replaced with ... syntax")] +#[allow(deprecated)] pub struct RangeInclusive { range: ops::Range, done: bool, @@ -2597,6 +3236,8 @@ pub struct RangeInclusive { #[unstable(feature = "range_inclusive", reason = "likely to be replaced by range notation and adapters", issue = "27777")] +#[deprecated(since = "1.5.0", reason = "replaced with ... syntax")] +#[allow(deprecated)] pub fn range_inclusive(start: A, stop: A) -> RangeInclusive where A: Step + One + Clone { @@ -2609,6 +3250,8 @@ pub fn range_inclusive(start: A, stop: A) -> RangeInclusive #[unstable(feature = "range_inclusive", reason = "likely to be replaced by range notation and adapters", issue = "27777")] +#[deprecated(since = "1.5.0", reason = "replaced with ... syntax")] +#[allow(deprecated)] impl Iterator for RangeInclusive where A: PartialEq + Step + One + Clone, for<'a> &'a A: Add<&'a A, Output = A> @@ -2643,6 +3286,8 @@ impl Iterator for RangeInclusive where #[unstable(feature = "range_inclusive", reason = "likely to be replaced by range notation and adapters", issue = "27777")] +#[deprecated(since = "1.5.0", reason = "replaced with ... syntax")] +#[allow(deprecated)] impl DoubleEndedIterator for RangeInclusive where A: PartialEq + Step + One + Clone, for<'a> &'a A: Add<&'a A, Output = A>, @@ -2767,7 +3412,11 @@ impl Iterator for ops::RangeFrom where } } -/// An iterator that repeats an element endlessly +/// An iterator that repeats an element endlessly. +/// +/// This `struct` is created by the [`repeat()`] function. See its documentation for more. +/// +/// [`repeat()`]: fn.repeat.html #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Repeat { @@ -2790,7 +3439,52 @@ impl DoubleEndedIterator for Repeat { fn next_back(&mut self) -> Option { Some(self.element.clone()) } } -/// Creates a new iterator that endlessly repeats the element `elt`. +/// Creates a new iterator that endlessly repeats a single element. +/// +/// The `repeat()` function repeats a single value over and over and over and +/// over and over and 🔁. +/// +/// Infinite iterators like `repeat()` are often used with adapters like +/// [`take()`], in order to make them finite. +/// +/// [`take()`]: trait.Iterator.html#method.take +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::iter; +/// +/// // the number four 4ever: +/// let mut fours = iter::repeat(4); +/// +/// assert_eq!(Some(4), fours.next()); +/// assert_eq!(Some(4), fours.next()); +/// assert_eq!(Some(4), fours.next()); +/// assert_eq!(Some(4), fours.next()); +/// assert_eq!(Some(4), fours.next()); +/// +/// // yup, still four +/// assert_eq!(Some(4), fours.next()); +/// ``` +/// +/// Going finite with [`take()`]: +/// +/// ``` +/// use std::iter; +/// +/// // that last example was too many fours. Let's only have four fours. +/// let mut four_fours = iter::repeat(4).take(4); +/// +/// assert_eq!(Some(4), four_fours.next()); +/// assert_eq!(Some(4), four_fours.next()); +/// assert_eq!(Some(4), four_fours.next()); +/// assert_eq!(Some(4), four_fours.next()); +/// +/// // ... and now we're done +/// assert_eq!(None, four_fours.next()); +/// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn repeat(elt: T) -> Repeat { @@ -2798,6 +3492,10 @@ pub fn repeat(elt: T) -> Repeat { } /// An iterator that yields nothing. +/// +/// This `struct` is created by the [`empty()`] function. See its documentation for more. +/// +/// [`empty()`]: fn.empty.html #[stable(feature = "iter_empty", since = "1.2.0")] pub struct Empty(marker::PhantomData); @@ -2847,12 +3545,29 @@ impl Default for Empty { } /// Creates an iterator that yields nothing. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::iter; +/// +/// // this could have been an iterator over i32, but alas, it's just not. +/// let mut nope = iter::empty::(); +/// +/// assert_eq!(None, nope.next()); +/// ``` #[stable(feature = "iter_empty", since = "1.2.0")] pub fn empty() -> Empty { Empty(marker::PhantomData) } /// An iterator that yields an element exactly once. +/// +/// This `struct` is created by the [`once()`] function. See its documentation for more. +/// +/// [`once()`]: fn.once.html #[derive(Clone)] #[stable(feature = "iter_once", since = "1.2.0")] pub struct Once { @@ -2887,6 +3602,56 @@ impl ExactSizeIterator for Once { } /// Creates an iterator that yields an element exactly once. +/// +/// This is commonly used to adapt a single value into a [`chain()`] of other +/// kinds of iteration. Maybe you have an iterator that covers almost +/// everything, but you need an extra special case. Maybe you have a function +/// which works on iterators, but you only need to process one value. +/// +/// [`chain()`]: trait.Iterator.html#method.chain +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::iter; +/// +/// // one is the loneliest number +/// let mut one = iter::once(1); +/// +/// assert_eq!(Some(1), one.next()); +/// +/// // just one, that's all we get +/// assert_eq!(None, one.next()); +/// ``` +/// +/// Chaining together with another iterator. Let's say that we want to iterate +/// over each file of the `.foo` directory, but also a configuration file, +/// `.foorc`: +/// +/// ```no_run +/// use std::iter; +/// use std::fs; +/// use std::path::PathBuf; +/// +/// let dirs = fs::read_dir(".foo").unwrap(); +/// +/// // we need to convert from an iterator of DirEntry-s to an iterator of +/// // PathBufs, so we use map +/// let dirs = dirs.map(|file| file.unwrap().path()); +/// +/// // now, our iterator just for our config file +/// let config = iter::once(PathBuf::from(".foorc")); +/// +/// // chain the two iterators together into one big iterator +/// let files = dirs.chain(config); +/// +/// // this will give us all of the files in .foo as well as .foorc +/// for f in files { +/// println!("{:?}", f); +/// } +/// ``` #[stable(feature = "iter_once", since = "1.2.0")] pub fn once(value: T) -> Once { Once { inner: Some(value).into_iter() } @@ -2900,7 +3665,7 @@ pub fn once(value: T) -> Once { /// If two sequences are equal up until the point where one ends, /// the shorter sequence compares less. #[deprecated(since = "1.4.0", reason = "use the equivalent methods on `Iterator` instead")] -#[unstable(feature = "iter_order", reason = "needs review and revision", +#[unstable(feature = "iter_order_deprecated", reason = "needs review and revision", issue = "27737")] pub mod order { use cmp; diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 25ca33a3d5..bb112327ab 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -168,8 +168,14 @@ macro_rules! try { }) } -/// Use the `format!` syntax to write data into a buffer of type `&mut Write`. -/// See `std::fmt` for more information. +/// Use the `format!` syntax to write data into a buffer. +/// +/// This macro is typically used with a buffer of `&mut `[`Write`][write]. +/// +/// See [`std::fmt`][fmt] for more information on format syntax. +/// +/// [fmt]: fmt/index.html +/// [write]: io/trait.Write.html /// /// # Examples /// @@ -179,14 +185,34 @@ macro_rules! try { /// let mut w = Vec::new(); /// write!(&mut w, "test").unwrap(); /// write!(&mut w, "formatted {}", "arguments").unwrap(); +/// +/// assert_eq!(w, b"testformatted arguments"); /// ``` #[macro_export] macro_rules! write { ($dst:expr, $($arg:tt)*) => ($dst.write_fmt(format_args!($($arg)*))) } -/// Equivalent to the `write!` macro, except that a newline is appended after -/// the message is written. +/// Use the `format!` syntax to write data into a buffer, appending a newline. +/// +/// This macro is typically used with a buffer of `&mut `[`Write`][write]. +/// +/// See [`std::fmt`][fmt] for more information on format syntax. +/// +/// [fmt]: fmt/index.html +/// [write]: io/trait.Write.html +/// +/// # Examples +/// +/// ``` +/// use std::io::Write; +/// +/// let mut w = Vec::new(); +/// writeln!(&mut w, "test").unwrap(); +/// writeln!(&mut w, "formatted {}", "arguments").unwrap(); +/// +/// assert_eq!(&w[..], "test\nformatted arguments\n".as_bytes()); +/// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] macro_rules! writeln { @@ -253,7 +279,7 @@ macro_rules! unreachable { }); } -/// A standardised placeholder for marking unfinished code. It panics with the +/// A standardized placeholder for marking unfinished code. It panics with the /// message `"not yet implemented"` when executed. /// /// This can be useful if you are prototyping and are just looking to have your diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 35dde63e52..27d8af2e8a 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -36,6 +36,17 @@ impl !Send for *const T { } impl !Send for *mut T { } /// Types with a constant size known at compile-time. +/// +/// All type parameters which can be bounded have an implicit bound of `Sized`. The special syntax +/// `?Sized` can be used to remove this bound if it is not appropriate. +/// +/// ``` +/// struct Foo(T); +/// struct Bar(T); +/// +/// // struct FooUse(Foo<[i32]>); // error: Sized is not implemented for [i32] +/// struct BarUse(Bar<[i32]>); // OK +/// ``` #[stable(feature = "rust1", since = "1.0.0")] #[lang = "sized"] #[rustc_on_unimplemented = "`{Self}` does not have a constant size known at compile-time"] @@ -172,7 +183,7 @@ pub trait Copy : Clone { /// /// A somewhat surprising consequence of the definition is `&mut T` is /// `Sync` (if `T` is `Sync`) even though it seems that it might -/// provide unsynchronised mutation. The trick is a mutable reference +/// provide unsynchronized mutation. The trick is a mutable reference /// stored in an aliasable reference (that is, `& &mut T`) becomes /// read-only, as if it were a `& &T`, hence there is no risk of a data /// race. @@ -195,7 +206,7 @@ pub trait Copy : Clone { /// /// Any types with interior mutability must also use the `std::cell::UnsafeCell` /// wrapper around the value(s) which can be mutated when behind a `&` -/// reference; not doing this is undefined behaviour (for example, +/// reference; not doing this is undefined behavior (for example, /// `transmute`-ing from `&T` to `&mut T` is invalid). #[stable(feature = "rust1", since = "1.0.0")] #[lang = "sync"] @@ -381,7 +392,7 @@ mod impls { /// ``` /// /// Without the declaration `T:Reflect`, `foo` would not type check -/// (note: as a matter of style, it would be preferable to to write +/// (note: as a matter of style, it would be preferable to write /// `T:Any`, because `T:Any` implies `T:Reflect` and `T:'static`, but /// we use `Reflect` here to show how it works). The `Reflect` bound /// thus serves to alert `foo`'s caller to the fact that `foo` may diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 48d003c2cf..a87d135e42 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -37,7 +37,7 @@ pub use intrinsics::transmute; /// * You have two copies of a value (like when writing something like /// [`mem::swap`][swap]), but need the destructor to only run once to /// prevent a double `free`. -/// * Transferring resources across [FFI][ffi] boundries. +/// * Transferring resources across [FFI][ffi] boundaries. /// /// [swap]: fn.swap.html /// [ffi]: ../../book/ffi.html @@ -264,9 +264,9 @@ pub unsafe fn dropped() -> T { /// This is useful for FFI functions and initializing arrays sometimes, /// but should generally be avoided. /// -/// # Undefined Behaviour +/// # Undefined Behavior /// -/// It is Undefined Behaviour to read uninitialized memory. Even just an +/// It is Undefined Behavior to read uninitialized memory. Even just an /// uninitialized boolean. For instance, if you branch on the value of such /// a boolean your program may take one, both, or neither of the branches. /// @@ -303,7 +303,7 @@ pub unsafe fn dropped() -> T { /// /// // DANGER ZONE: if anything panics or otherwise /// // incorrectly reads the array here, we will have -/// // Undefined Behaviour. +/// // Undefined Behavior. /// /// // It's ok to mutably iterate the data, since this /// // doesn't involve reading it at all. @@ -340,7 +340,7 @@ pub unsafe fn uninitialized() -> T { intrinsics::uninit() } -/// Swap the values at two mutable locations of the same type, without deinitialising or copying +/// Swap the values at two mutable locations of the same type, without deinitializing or copying /// either one. /// /// # Examples @@ -376,7 +376,7 @@ pub fn swap(x: &mut T, y: &mut T) { } /// Replaces the value at a mutable location with a new one, returning the old value, without -/// deinitialising or copying either one. +/// deinitializing or copying either one. /// /// This is primarily used for transferring and swapping ownership of a value in a mutable /// location. @@ -434,6 +434,11 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// While this does call the argument's implementation of `Drop`, it will not /// release any borrows, as borrows are based on lexical scope. /// +/// This effectively does nothing for +/// [types which implement `Copy`](../../book/ownership.html#copy-types), +/// e.g. integers. Such values are copied and _then_ moved into the function, +/// so the value persists after this function call. +/// /// # Examples /// /// Basic usage: @@ -486,6 +491,21 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// let borrow = x.borrow(); /// println!("{}", *borrow); /// ``` +/// +/// Integers and other types implementing `Copy` are unaffected by `drop()` +/// +/// ``` +/// #[derive(Copy, Clone)] +/// struct Foo(u8); +/// +/// let x = 1; +/// let y = Foo(2); +/// drop(x); // a copy of `x` is moved and dropped +/// drop(y); // a copy of `y` is moved and dropped +/// +/// println!("x: {}, y: {}", x, y.0); // still available +/// ``` +/// #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn drop(_x: T) { } diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index c945e4e066..c4ca3fa384 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -38,13 +38,31 @@ unsafe impl Zeroable for u64 {} #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)] pub struct NonZero(T); +#[cfg(stage0)] +macro_rules! nonzero_new { + () => ( + /// Creates an instance of NonZero with the provided value. + /// You must indeed ensure that the value is actually "non-zero". + #[inline(always)] + pub unsafe fn new(inner: T) -> NonZero { + NonZero(inner) + } + ) +} +#[cfg(not(stage0))] +macro_rules! nonzero_new { + () => ( + /// Creates an instance of NonZero with the provided value. + /// You must indeed ensure that the value is actually "non-zero". + #[inline(always)] + pub const unsafe fn new(inner: T) -> NonZero { + NonZero(inner) + } + ) +} + impl NonZero { - /// Creates an instance of NonZero with the provided value. - /// You must indeed ensure that the value is actually "non-zero". - #[inline(always)] - pub unsafe fn new(inner: T) -> NonZero { - NonZero(inner) - } + nonzero_new!{} } impl Deref for NonZero { diff --git a/src/libcore/num/flt2dec/bignum.rs b/src/libcore/num/bignum.rs similarity index 96% rename from src/libcore/num/flt2dec/bignum.rs rename to src/libcore/num/bignum.rs index 091e9c889d..18b34e24fc 100644 --- a/src/libcore/num/flt2dec/bignum.rs +++ b/src/libcore/num/bignum.rs @@ -19,6 +19,12 @@ //! inputs, but we don't do so to avoid the code bloat. Each bignum is still //! tracked for the actual usages, so it normally doesn't matter. +// This module is only for dec2flt and flt2dec, and only public because of libcoretest. +// It is not intended to ever be stabilized. +#![doc(hidden)] +#![unstable(feature = "core_private_bignum", + reason = "internal routines only exposed for testing", + issue = "0")] #![macro_use] use prelude::v1::*; @@ -104,7 +110,7 @@ macro_rules! define_bignum { ($name:ident: type=$ty:ty, n=$n:expr) => ( /// Stack-allocated arbitrary-precision (up to certain limit) integer. /// - /// This is backed by an fixed-size array of given type ("digit"). + /// This is backed by a fixed-size array of given type ("digit"). /// While the array is not very large (normally some hundred bytes), /// copying it recklessly may result in the performance hit. /// Thus this is intentionally not `Copy`. @@ -194,7 +200,7 @@ macro_rules! define_bignum { /// Adds `other` to itself and returns its own mutable reference. pub fn add<'a>(&'a mut self, other: &$name) -> &'a mut $name { use cmp; - use num::flt2dec::bignum::FullOps; + use num::bignum::FullOps; let mut sz = cmp::max(self.size, other.size); let mut carry = false; @@ -212,7 +218,7 @@ macro_rules! define_bignum { } pub fn add_small(&mut self, other: $ty) -> &mut $name { - use num::flt2dec::bignum::FullOps; + use num::bignum::FullOps; let (mut carry, v) = self.base[0].full_add(other, false); self.base[0] = v; @@ -232,7 +238,7 @@ macro_rules! define_bignum { /// Subtracts `other` from itself and returns its own mutable reference. pub fn sub<'a>(&'a mut self, other: &$name) -> &'a mut $name { use cmp; - use num::flt2dec::bignum::FullOps; + use num::bignum::FullOps; let sz = cmp::max(self.size, other.size); let mut noborrow = true; @@ -249,7 +255,7 @@ macro_rules! define_bignum { /// Multiplies itself by a digit-sized `other` and returns its own /// mutable reference. pub fn mul_small(&mut self, other: $ty) -> &mut $name { - use num::flt2dec::bignum::FullOps; + use num::bignum::FullOps; let mut sz = self.size; let mut carry = 0; @@ -310,7 +316,7 @@ macro_rules! define_bignum { /// Multiplies itself by `5^e` and returns its own mutable reference. pub fn mul_pow5(&mut self, mut e: usize) -> &mut $name { use mem; - use num::flt2dec::bignum::SMALL_POW5; + use num::bignum::SMALL_POW5; // There are exactly n trailing zeros on 2^n, and the only relevant digit sizes // are consecutive powers of two, so this is well suited index for the table. @@ -341,7 +347,7 @@ macro_rules! define_bignum { pub fn mul_digits<'a>(&'a mut self, other: &[$ty]) -> &'a mut $name { // the internal routine. works best when aa.len() <= bb.len(). fn mul_inner(ret: &mut [$ty; $n], aa: &[$ty], bb: &[$ty]) -> usize { - use num::flt2dec::bignum::FullOps; + use num::bignum::FullOps; let mut retsz = 0; for (i, &a) in aa.iter().enumerate() { @@ -378,7 +384,7 @@ macro_rules! define_bignum { /// Divides itself by a digit-sized `other` and returns its own /// mutable reference *and* the remainder. pub fn div_rem_small(&mut self, other: $ty) -> (&mut $name, $ty) { - use num::flt2dec::bignum::FullOps; + use num::bignum::FullOps; assert!(other > 0); diff --git a/src/libcore/num/dec2flt/algorithm.rs b/src/libcore/num/dec2flt/algorithm.rs index f166bb9b3e..1f0f06d746 100644 --- a/src/libcore/num/dec2flt/algorithm.rs +++ b/src/libcore/num/dec2flt/algorithm.rs @@ -10,13 +10,13 @@ //! The various algorithms from the paper. -use num::flt2dec::strategy::grisu::Fp; use prelude::v1::*; use cmp::min; use cmp::Ordering::{Less, Equal, Greater}; -use super::table; -use super::rawfp::{self, Unpacked, RawFloat, fp_to_float, next_float, prev_float}; -use super::num::{self, Big}; +use num::diy_float::Fp; +use num::dec2flt::table; +use num::dec2flt::rawfp::{self, Unpacked, RawFloat, fp_to_float, next_float, prev_float}; +use num::dec2flt::num::{self, Big}; /// Number of significand bits in Fp const P: u32 = 64; diff --git a/src/libcore/num/dec2flt/mod.rs b/src/libcore/num/dec2flt/mod.rs index 4e6b6f04e9..55be4cd319 100644 --- a/src/libcore/num/dec2flt/mod.rs +++ b/src/libcore/num/dec2flt/mod.rs @@ -86,9 +86,6 @@ //! "such that the exponent +/- the number of decimal digits fits into a 64 bit integer". //! Larger exponents are accepted, but we don't do arithmetic with them, they are immediately //! turned into {positive,negative} {zero,infinity}. -//! -//! FIXME: this uses several things from core::num::flt2dec, which is nonsense. Those things -//! should be moved into core::num::. #![doc(hidden)] #![unstable(feature = "dec2flt", diff --git a/src/libcore/num/dec2flt/num.rs b/src/libcore/num/dec2flt/num.rs index dcba73d7c9..81e7856633 100644 --- a/src/libcore/num/dec2flt/num.rs +++ b/src/libcore/num/dec2flt/num.rs @@ -14,9 +14,8 @@ use prelude::v1::*; use cmp::Ordering::{self, Less, Equal, Greater}; -use num::flt2dec::bignum::Big32x40; -pub type Big = Big32x40; +pub use num::bignum::Big32x40 as Big; /// Test whether truncating all bits less significant than `ones_place` introduces /// a relative error less, equal, or greater than 0.5 ULP. diff --git a/src/libcore/num/dec2flt/rawfp.rs b/src/libcore/num/dec2flt/rawfp.rs index 830d2dad42..be61653c37 100644 --- a/src/libcore/num/dec2flt/rawfp.rs +++ b/src/libcore/num/dec2flt/rawfp.rs @@ -33,10 +33,10 @@ use cmp::Ordering::{Less, Equal, Greater}; use ops::{Mul, Div, Neg}; use fmt::{Debug, LowerExp}; use mem::transmute; -use num::flt2dec::strategy::grisu::Fp; +use num::diy_float::Fp; use num::FpCategory::{Infinite, Zero, Subnormal, Normal, Nan}; use num::Float; -use super::num::{self, Big}; +use num::dec2flt::num::{self, Big}; #[derive(Copy, Clone, Debug)] pub struct Unpacked { diff --git a/src/libcore/num/diy_float.rs b/src/libcore/num/diy_float.rs new file mode 100644 index 0000000000..7c369ee3b3 --- /dev/null +++ b/src/libcore/num/diy_float.rs @@ -0,0 +1,71 @@ +// 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. + +//! Extended precision "soft float", for internal use only. + +// This module is only for dec2flt and flt2dec, and only public because of libcoretest. +// It is not intended to ever be stabilized. +#![doc(hidden)] +#![unstable(feature = "core_private_diy_float", + reason = "internal routines only exposed for testing", + issue = "0")] + +/// A custom 64-bit floating point type, representing `f * 2^e`. +#[derive(Copy, Clone, Debug)] +#[doc(hidden)] +pub struct Fp { + /// The integer mantissa. + pub f: u64, + /// The exponent in base 2. + pub e: i16, +} + +impl Fp { + /// Returns a correctly rounded product of itself and `other`. + pub fn mul(&self, other: &Fp) -> Fp { + const MASK: u64 = 0xffffffff; + let a = self.f >> 32; + let b = self.f & MASK; + let c = other.f >> 32; + let d = other.f & MASK; + let ac = a * c; + let bc = b * c; + let ad = a * d; + let bd = b * d; + let tmp = (bd >> 32) + (ad & MASK) + (bc & MASK) + (1 << 31) /* round */; + let f = ac + (ad >> 32) + (bc >> 32) + (tmp >> 32); + let e = self.e + other.e + 64; + Fp { f: f, e: e } + } + + /// Normalizes itself so that the resulting mantissa is at least `2^63`. + 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; } + debug_assert!(f >= (1 >> 63)); + Fp { f: f, e: e } + } + + /// Normalizes itself to have the shared exponent. + /// It can only decrease the exponent (and thus increase the mantissa). + pub fn normalize_to(&self, e: i16) -> Fp { + let edelta = self.e - e; + assert!(edelta >= 0); + let edelta = edelta as usize; + assert_eq!(self.f << edelta >> edelta, self.f); + Fp { f: self.f << edelta, e: e } + } +} diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 1b7cbb050d..6185823d00 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -71,7 +71,7 @@ pub const INFINITY: f32 = 1.0_f32/0.0_f32; #[allow(missing_docs)] pub const NEG_INFINITY: f32 = -1.0_f32/0.0_f32; -/// Basic mathematial constants. +/// Basic mathematical constants. #[stable(feature = "rust1", since = "1.0.0")] pub mod consts { // FIXME: replace with mathematical constants from cmath. diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index a057e5fe51..f85f8c5bd1 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -71,7 +71,7 @@ pub const INFINITY: f64 = 1.0_f64/0.0_f64; #[allow(missing_docs)] pub const NEG_INFINITY: f64 = -1.0_f64/0.0_f64; -/// Basic mathematial constants. +/// Basic mathematical constants. #[stable(feature = "rust1", since = "1.0.0")] pub mod consts { // FIXME: replace with mathematical constants from cmath. diff --git a/src/libcore/num/flt2dec/mod.rs b/src/libcore/num/flt2dec/mod.rs index 700523e49a..57d4bccbfa 100644 --- a/src/libcore/num/flt2dec/mod.rs +++ b/src/libcore/num/flt2dec/mod.rs @@ -136,7 +136,6 @@ use slice::bytes; pub use self::decoder::{decode, DecodableFloat, FullDecoded, Decoded}; pub mod estimator; -pub mod bignum; pub mod decoder; /// Digit-generation algorithms. @@ -462,7 +461,7 @@ pub fn to_shortest_str<'a, T, F>(mut format_shortest: F, v: T, /// You probably would want `strategy::grisu::format_shortest` for this. /// /// The `dec_bounds` is a tuple `(lo, hi)` such that the number is formatted -/// as decimal only when `10^lo <= V < 10^hi`. Note that this is the *apparant* `V` +/// as decimal only when `10^lo <= V < 10^hi`. Note that this is the *apparent* `V` /// instead of the actual `v`! Thus any printed exponent in the exponential form /// cannot be in this range, avoiding any confusion. /// diff --git a/src/libcore/num/flt2dec/strategy/dragon.rs b/src/libcore/num/flt2dec/strategy/dragon.rs index 40aa2a527d..2d68c3a6d0 100644 --- a/src/libcore/num/flt2dec/strategy/dragon.rs +++ b/src/libcore/num/flt2dec/strategy/dragon.rs @@ -21,8 +21,8 @@ use cmp::Ordering; use num::flt2dec::{Decoded, MAX_SIG_DIGITS, round_up}; use num::flt2dec::estimator::estimate_scaling_factor; -use num::flt2dec::bignum::Digit32 as Digit; -use num::flt2dec::bignum::Big32x40 as Big; +use num::bignum::Digit32 as Digit; +use num::bignum::Big32x40 as Big; static POW10: [Digit; 10] = [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000]; diff --git a/src/libcore/num/flt2dec/strategy/grisu.rs b/src/libcore/num/flt2dec/strategy/grisu.rs index b0822ca76c..13e01d9a7f 100644 --- a/src/libcore/num/flt2dec/strategy/grisu.rs +++ b/src/libcore/num/flt2dec/strategy/grisu.rs @@ -18,60 +18,9 @@ Rust adaptation of Grisu3 algorithm described in [1]. It uses about use prelude::v1::*; +use num::diy_float::Fp; use num::flt2dec::{Decoded, MAX_SIG_DIGITS, round_up}; -/// A custom 64-bit floating point type, representing `f * 2^e`. -#[derive(Copy, Clone, Debug)] -#[doc(hidden)] -pub struct Fp { - /// The integer mantissa. - pub f: u64, - /// The exponent in base 2. - pub e: i16, -} - -impl Fp { - /// Returns a correctly rounded product of itself and `other`. - pub fn mul(&self, other: &Fp) -> Fp { - const MASK: u64 = 0xffffffff; - let a = self.f >> 32; - let b = self.f & MASK; - let c = other.f >> 32; - let d = other.f & MASK; - let ac = a * c; - let bc = b * c; - let ad = a * d; - let bd = b * d; - let tmp = (bd >> 32) + (ad & MASK) + (bc & MASK) + (1 << 31) /* round */; - let f = ac + (ad >> 32) + (bc >> 32) + (tmp >> 32); - let e = self.e + other.e + 64; - Fp { f: f, e: e } - } - - /// Normalizes itself so that the resulting mantissa is at least `2^63`. - 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; } - debug_assert!(f >= (1 >> 63)); - Fp { f: f, e: e } - } - - /// Normalizes itself to have the shared exponent. - /// It can only decrease the exponent (and thus increase the mantissa). - pub fn normalize_to(&self, e: i16) -> Fp { - let edelta = self.e - e; - assert!(edelta >= 0); - let edelta = edelta as usize; - assert_eq!(self.f << edelta >> edelta, self.f); - Fp { f: self.f << edelta, e: e } - } -} // see the comments in `format_shortest_opt` for the rationale. #[doc(hidden)] pub const ALPHA: i16 = -60; @@ -539,7 +488,7 @@ pub fn format_exact_opt(d: &Decoded, buf: &mut [u8], limit: i16) // but scaling `max_ten_kappa << e` by 10 can result in overflow. // thus we are being sloppy here and widen the error range by a factor of 10. // this will increase the false negative rate, but only very, *very* slightly; - // it can only matter noticably when the mantissa is bigger than 60 bits. + // it can only matter noticeably when the mantissa is bigger than 60 bits. return possibly_round(buf, 0, exp, limit, v.f / 10, (max_ten_kappa as u64) << e, err << e); } else if ((exp as i32 - limit as i32) as usize) < buf.len() { (exp - limit) as usize diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 127f8d3b5a..de56cf902a 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -17,6 +17,7 @@ use self::wrapping::OverflowingOps; use char::CharExt; use cmp::{Eq, PartialOrd}; +use convert::From; use fmt; use intrinsics; use marker::{Copy, Sized}; @@ -39,12 +40,16 @@ use slice::SliceExt; /// all standard arithmetic operations on the underlying value are /// intended to have wrapping semantics. #[stable(feature = "rust1", since = "1.0.0")] -#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)] +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug, Default)] pub struct Wrapping(#[stable(feature = "rust1", since = "1.0.0")] pub T); pub mod wrapping; + +// All these modules are technically private and only exposed for libcoretest: pub mod flt2dec; pub mod dec2flt; +pub mod bignum; +pub mod diy_float; /// Types that have a "zero" value. /// @@ -53,7 +58,7 @@ pub mod dec2flt; #[unstable(feature = "zero_one", reason = "unsure of placement, wants to use associated constants", issue = "27739")] -pub trait Zero { +pub trait Zero: Sized { /// The "zero" (usually, additive identity) for this type. fn zero() -> Self; } @@ -65,7 +70,7 @@ pub trait Zero { #[unstable(feature = "zero_one", reason = "unsure of placement, wants to use associated constants", issue = "27739")] -pub trait One { +pub trait One: Sized { /// The "one" (usually, multiplicative identity) for this type. fn one() -> Self; } @@ -399,12 +404,12 @@ macro_rules! int_impl { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn checked_div(self, v: Self) -> Option { - match v { - 0 => None, + pub fn checked_div(self, other: Self) -> Option { + match other { + 0 => None, -1 if self == Self::min_value() - => None, - v => Some(self / v), + => None, + other => Some(self / other), } } @@ -968,10 +973,10 @@ macro_rules! uint_impl { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn checked_div(self, v: Self) -> Option { - match v { + pub fn checked_div(self, other: Self) -> Option { + match other { 0 => None, - v => Some(self / v), + other => Some(self / other), } } @@ -1379,54 +1384,55 @@ fn from_str_radix(src: &str, radix: u32) // all valid digits are ascii, so we will just iterate over the utf8 bytes // and cast them to chars. .to_digit() will safely return None for anything - // other than a valid ascii digit for a the given radix, including the first-byte + // other than a valid ascii digit for the given radix, including the first-byte // of multi-byte sequences let src = src.as_bytes(); - match (src[0], &src[1..]) { - (b'-', digits) if digits.is_empty() => Err(PIE { kind: Empty }), - (b'-', digits) if is_signed_ty => { - // The number is negative - let mut result = T::from_u32(0); - for &c in digits { - let x = match (c as char).to_digit(radix) { - Some(x) => x, - None => return Err(PIE { kind: InvalidDigit }), - }; - result = match result.checked_mul(radix) { - Some(result) => result, - None => return Err(PIE { kind: Underflow }), - }; - result = match result.checked_sub(x) { - Some(result) => result, - None => return Err(PIE { kind: Underflow }), - }; - } - Ok(result) - }, - (c, digits) => { - // The number is signed - let mut result = match (c as char).to_digit(radix) { - Some(x) => T::from_u32(x), + let (is_positive, digits) = match src[0] { + b'+' => (true, &src[1..]), + b'-' if is_signed_ty => (false, &src[1..]), + _ => (true, src) + }; + + if digits.is_empty() { + return Err(PIE { kind: Empty }); + } + + let mut result = T::from_u32(0); + if is_positive { + // The number is positive + for &c in digits { + let x = match (c as char).to_digit(radix) { + Some(x) => x, None => return Err(PIE { kind: InvalidDigit }), }; - for &c in digits { - let x = match (c as char).to_digit(radix) { - Some(x) => x, - None => return Err(PIE { kind: InvalidDigit }), - }; - result = match result.checked_mul(radix) { - Some(result) => result, - None => return Err(PIE { kind: Overflow }), - }; - result = match result.checked_add(x) { - Some(result) => result, - None => return Err(PIE { kind: Overflow }), - }; - } - Ok(result) + result = match result.checked_mul(radix) { + Some(result) => result, + None => return Err(PIE { kind: Overflow }), + }; + result = match result.checked_add(x) { + Some(result) => result, + None => return Err(PIE { kind: Overflow }), + }; + } + } else { + // The number is negative + for &c in digits { + let x = match (c as char).to_digit(radix) { + Some(x) => x, + None => return Err(PIE { kind: InvalidDigit }), + }; + result = match result.checked_mul(radix) { + Some(result) => result, + None => return Err(PIE { kind: Underflow }), + }; + result = match result.checked_sub(x) { + Some(result) => result, + None => return Err(PIE { kind: Underflow }), + }; } } + Ok(result) } /// An error which can be returned when parsing an integer. @@ -1466,3 +1472,45 @@ impl fmt::Display for ParseIntError { } pub use num::dec2flt::ParseFloatError; + +// Conversion traits for primitive integer types +// Conversions T -> T are covered by a blanket impl and therefore excluded +// Some conversions from and to usize/isize are not implemented due to portability concerns +macro_rules! impl_from { + ($Small: ty, $Large: ty) => { + #[stable(feature = "lossless_int_conv", since = "1.5.0")] + impl From<$Small> for $Large { + #[stable(feature = "lossless_int_conv", since = "1.5.0")] + #[inline] + fn from(small: $Small) -> $Large { + small as $Large + } + } + } +} + +// Unsigned -> Unsigned +impl_from! { u8, u16 } +impl_from! { u8, u32 } +impl_from! { u8, u64 } +impl_from! { u8, usize } +impl_from! { u16, u32 } +impl_from! { u16, u64 } +impl_from! { u32, u64 } + +// Signed -> Signed +impl_from! { i8, i16 } +impl_from! { i8, i32 } +impl_from! { i8, i64 } +impl_from! { i8, isize } +impl_from! { i16, i32 } +impl_from! { i16, i64 } +impl_from! { i32, i64 } + +// Unsigned -> Signed +impl_from! { u8, i16 } +impl_from! { u8, i32 } +impl_from! { u8, i64 } +impl_from! { u16, i32 } +impl_from! { u16, i64 } +impl_from! { u32, i64 } diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 07de4d0761..582c091091 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -94,7 +94,7 @@ use fmt; #[lang = "drop"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Drop { - /// The `drop` method, called when the value goes out of scope. + /// A method called when the value goes out of scope. #[stable(feature = "rust1", since = "1.0.0")] fn drop(&mut self); } @@ -927,6 +927,534 @@ macro_rules! shr_impl_all { shr_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize } +/// The `AddAssign` trait is used to specify the functionality of `+=`. +/// +/// # Examples +/// +/// A trivial implementation of `AddAssign`. When `Foo += Foo` happens, it ends up +/// calling `add_assign`, and therefore, `main` prints `Adding!`. +/// +/// ``` +/// #![feature(augmented_assignments)] +/// #![feature(op_assign_traits)] +/// +/// use std::ops::AddAssign; +/// +/// #[derive(Copy, Clone)] +/// struct Foo; +/// +/// impl AddAssign for Foo { +/// fn add_assign(&mut self, _rhs: Foo) { +/// println!("Adding!"); +/// } +/// } +/// +/// fn main() { +/// let mut foo = Foo; +/// foo += Foo; +/// } +/// ``` +#[cfg(not(stage0))] +#[lang = "add_assign"] +#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")] +pub trait AddAssign { + /// The method for the `+=` operator + fn add_assign(&mut self, Rhs); +} + +#[cfg(not(stage0))] +macro_rules! add_assign_impl { + ($($t:ty)+) => ($( + #[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")] + impl AddAssign for $t { + #[inline] + fn add_assign(&mut self, other: $t) { *self += other } + } + )+) +} + +#[cfg(not(stage0))] +add_assign_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } + +/// The `SubAssign` trait is used to specify the functionality of `-=`. +/// +/// # Examples +/// +/// A trivial implementation of `SubAssign`. When `Foo -= Foo` happens, it ends up +/// calling `sub_assign`, and therefore, `main` prints `Subtracting!`. +/// +/// ``` +/// #![feature(augmented_assignments)] +/// #![feature(op_assign_traits)] +/// +/// use std::ops::SubAssign; +/// +/// #[derive(Copy, Clone)] +/// struct Foo; +/// +/// impl SubAssign for Foo { +/// fn sub_assign(&mut self, _rhs: Foo) { +/// println!("Subtracting!"); +/// } +/// } +/// +/// fn main() { +/// let mut foo = Foo; +/// foo -= Foo; +/// } +/// ``` +#[cfg(not(stage0))] +#[lang = "sub_assign"] +#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")] +pub trait SubAssign { + /// The method for the `-=` operator + fn sub_assign(&mut self, Rhs); +} + +#[cfg(not(stage0))] +macro_rules! sub_assign_impl { + ($($t:ty)+) => ($( + #[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")] + impl SubAssign for $t { + #[inline] + fn sub_assign(&mut self, other: $t) { *self -= other } + } + )+) +} + +#[cfg(not(stage0))] +sub_assign_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } + +/// The `MulAssign` trait is used to specify the functionality of `*=`. +/// +/// # Examples +/// +/// A trivial implementation of `MulAssign`. When `Foo *= Foo` happens, it ends up +/// calling `mul_assign`, and therefore, `main` prints `Multiplying!`. +/// +/// ``` +/// #![feature(augmented_assignments)] +/// #![feature(op_assign_traits)] +/// +/// use std::ops::MulAssign; +/// +/// #[derive(Copy, Clone)] +/// struct Foo; +/// +/// impl MulAssign for Foo { +/// fn mul_assign(&mut self, _rhs: Foo) { +/// println!("Multiplying!"); +/// } +/// } +/// +/// fn main() { +/// let mut foo = Foo; +/// foo *= Foo; +/// } +/// ``` +#[cfg(not(stage0))] +#[lang = "mul_assign"] +#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")] +pub trait MulAssign { + /// The method for the `*=` operator + fn mul_assign(&mut self, Rhs); +} + +#[cfg(not(stage0))] +macro_rules! mul_assign_impl { + ($($t:ty)+) => ($( + #[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")] + impl MulAssign for $t { + #[inline] + fn mul_assign(&mut self, other: $t) { *self *= other } + } + )+) +} + +#[cfg(not(stage0))] +mul_assign_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } + +/// The `DivAssign` trait is used to specify the functionality of `/=`. +/// +/// # Examples +/// +/// A trivial implementation of `DivAssign`. When `Foo /= Foo` happens, it ends up +/// calling `div_assign`, and therefore, `main` prints `Dividing!`. +/// +/// ``` +/// #![feature(augmented_assignments)] +/// #![feature(op_assign_traits)] +/// +/// use std::ops::DivAssign; +/// +/// #[derive(Copy, Clone)] +/// struct Foo; +/// +/// impl DivAssign for Foo { +/// fn div_assign(&mut self, _rhs: Foo) { +/// println!("Dividing!"); +/// } +/// } +/// +/// fn main() { +/// let mut foo = Foo; +/// foo /= Foo; +/// } +/// ``` +#[cfg(not(stage0))] +#[lang = "div_assign"] +#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")] +pub trait DivAssign { + /// The method for the `/=` operator + fn div_assign(&mut self, Rhs); +} + +#[cfg(not(stage0))] +macro_rules! div_assign_impl { + ($($t:ty)+) => ($( + #[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")] + impl DivAssign for $t { + #[inline] + fn div_assign(&mut self, other: $t) { *self /= other } + } + )+) +} + +#[cfg(not(stage0))] +div_assign_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } + +/// The `RemAssign` trait is used to specify the functionality of `%=`. +/// +/// # Examples +/// +/// A trivial implementation of `RemAssign`. When `Foo %= Foo` happens, it ends up +/// calling `rem_assign`, and therefore, `main` prints `Remainder-ing!`. +/// +/// ``` +/// #![feature(augmented_assignments)] +/// #![feature(op_assign_traits)] +/// +/// use std::ops::RemAssign; +/// +/// #[derive(Copy, Clone)] +/// struct Foo; +/// +/// impl RemAssign for Foo { +/// fn rem_assign(&mut self, _rhs: Foo) { +/// println!("Remainder-ing!"); +/// } +/// } +/// +/// fn main() { +/// let mut foo = Foo; +/// foo %= Foo; +/// } +/// ``` +#[cfg(not(stage0))] +#[lang = "rem_assign"] +#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")] +pub trait RemAssign { + /// The method for the `%=` operator + fn rem_assign(&mut self, Rhs); +} + +#[cfg(not(stage0))] +macro_rules! rem_assign_impl { + ($($t:ty)+) => ($( + #[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")] + impl RemAssign for $t { + #[inline] + fn rem_assign(&mut self, other: $t) { *self %= other } + } + )+) +} + +#[cfg(not(stage0))] +rem_assign_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } + +/// The `BitAndAssign` trait is used to specify the functionality of `&=`. +/// +/// # Examples +/// +/// A trivial implementation of `BitAndAssign`. When `Foo &= Foo` happens, it ends up +/// calling `bitand_assign`, and therefore, `main` prints `Bitwise And-ing!`. +/// +/// ``` +/// #![feature(augmented_assignments)] +/// #![feature(op_assign_traits)] +/// +/// use std::ops::BitAndAssign; +/// +/// #[derive(Copy, Clone)] +/// struct Foo; +/// +/// impl BitAndAssign for Foo { +/// fn bitand_assign(&mut self, _rhs: Foo) { +/// println!("Bitwise And-ing!"); +/// } +/// } +/// +/// fn main() { +/// let mut foo = Foo; +/// foo &= Foo; +/// } +/// ``` +#[cfg(not(stage0))] +#[lang = "bitand_assign"] +#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")] +pub trait BitAndAssign { + /// The method for the `&` operator + fn bitand_assign(&mut self, Rhs); +} + +#[cfg(not(stage0))] +macro_rules! bitand_assign_impl { + ($($t:ty)+) => ($( + #[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")] + impl BitAndAssign for $t { + #[inline] + fn bitand_assign(&mut self, other: $t) { *self &= other } + } + )+) +} + +#[cfg(not(stage0))] +bitand_assign_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 } + +/// The `BitOrAssign` trait is used to specify the functionality of `|=`. +/// +/// # Examples +/// +/// A trivial implementation of `BitOrAssign`. When `Foo |= Foo` happens, it ends up +/// calling `bitor_assign`, and therefore, `main` prints `Bitwise Or-ing!`. +/// +/// ``` +/// #![feature(augmented_assignments)] +/// #![feature(op_assign_traits)] +/// +/// use std::ops::BitOrAssign; +/// +/// #[derive(Copy, Clone)] +/// struct Foo; +/// +/// impl BitOrAssign for Foo { +/// fn bitor_assign(&mut self, _rhs: Foo) { +/// println!("Bitwise Or-ing!"); +/// } +/// } +/// +/// fn main() { +/// let mut foo = Foo; +/// foo |= Foo; +/// } +/// ``` +#[cfg(not(stage0))] +#[lang = "bitor_assign"] +#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")] +pub trait BitOrAssign { + /// The method for the `|=` operator + fn bitor_assign(&mut self, Rhs); +} + +#[cfg(not(stage0))] +macro_rules! bitor_assign_impl { + ($($t:ty)+) => ($( + #[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")] + impl BitOrAssign for $t { + #[inline] + fn bitor_assign(&mut self, other: $t) { *self |= other } + } + )+) +} + +#[cfg(not(stage0))] +bitor_assign_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 } + +/// The `BitXorAssign` trait is used to specify the functionality of `^=`. +/// +/// # Examples +/// +/// A trivial implementation of `BitXorAssign`. When `Foo ^= Foo` happens, it ends up +/// calling `bitxor_assign`, and therefore, `main` prints `Bitwise Xor-ing!`. +/// +/// ``` +/// #![feature(augmented_assignments)] +/// #![feature(op_assign_traits)] +/// +/// use std::ops::BitXorAssign; +/// +/// #[derive(Copy, Clone)] +/// struct Foo; +/// +/// impl BitXorAssign for Foo { +/// fn bitxor_assign(&mut self, _rhs: Foo) { +/// println!("Bitwise Xor-ing!"); +/// } +/// } +/// +/// fn main() { +/// let mut foo = Foo; +/// foo ^= Foo; +/// } +/// ``` +#[cfg(not(stage0))] +#[lang = "bitxor_assign"] +#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")] +pub trait BitXorAssign { + /// The method for the `^=` operator + fn bitxor_assign(&mut self, Rhs); +} + +#[cfg(not(stage0))] +macro_rules! bitxor_assign_impl { + ($($t:ty)+) => ($( + #[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")] + impl BitXorAssign for $t { + #[inline] + fn bitxor_assign(&mut self, other: $t) { *self ^= other } + } + )+) +} + +#[cfg(not(stage0))] +bitxor_assign_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 } + +/// The `ShlAssign` trait is used to specify the functionality of `<<=`. +/// +/// # Examples +/// +/// A trivial implementation of `ShlAssign`. When `Foo <<= Foo` happens, it ends up +/// calling `shl_assign`, and therefore, `main` prints `Shifting left!`. +/// +/// ``` +/// #![feature(augmented_assignments)] +/// #![feature(op_assign_traits)] +/// +/// use std::ops::ShlAssign; +/// +/// #[derive(Copy, Clone)] +/// struct Foo; +/// +/// impl ShlAssign for Foo { +/// fn shl_assign(&mut self, _rhs: Foo) { +/// println!("Shifting left!"); +/// } +/// } +/// +/// fn main() { +/// let mut foo = Foo; +/// foo <<= Foo; +/// } +/// ``` +#[cfg(not(stage0))] +#[lang = "shl_assign"] +#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")] +pub trait ShlAssign { + /// The method for the `<<=` operator + fn shl_assign(&mut self, Rhs); +} + +#[cfg(not(stage0))] +macro_rules! shl_assign_impl { + ($t:ty, $f:ty) => ( + #[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")] + impl ShlAssign<$f> for $t { + #[inline] + fn shl_assign(&mut self, other: $f) { + *self <<= other + } + } + ) +} + +#[cfg(not(stage0))] +macro_rules! shl_assign_impl_all { + ($($t:ty)*) => ($( + shl_assign_impl! { $t, u8 } + shl_assign_impl! { $t, u16 } + shl_assign_impl! { $t, u32 } + shl_assign_impl! { $t, u64 } + shl_assign_impl! { $t, usize } + + shl_assign_impl! { $t, i8 } + shl_assign_impl! { $t, i16 } + shl_assign_impl! { $t, i32 } + shl_assign_impl! { $t, i64 } + shl_assign_impl! { $t, isize } + )*) +} + +#[cfg(not(stage0))] +shl_assign_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize } + +/// The `ShrAssign` trait is used to specify the functionality of `>>=`. +/// +/// # Examples +/// +/// A trivial implementation of `ShrAssign`. When `Foo >>= Foo` happens, it ends up +/// calling `shr_assign`, and therefore, `main` prints `Shifting right!`. +/// +/// ``` +/// #![feature(augmented_assignments)] +/// #![feature(op_assign_traits)] +/// +/// use std::ops::ShrAssign; +/// +/// #[derive(Copy, Clone)] +/// struct Foo; +/// +/// impl ShrAssign for Foo { +/// fn shr_assign(&mut self, _rhs: Foo) { +/// println!("Shifting right!"); +/// } +/// } +/// +/// fn main() { +/// let mut foo = Foo; +/// foo >>= Foo; +/// } +/// ``` +#[cfg(not(stage0))] +#[lang = "shr_assign"] +#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")] +pub trait ShrAssign { + /// The method for the `>>=` operator + fn shr_assign(&mut self, Rhs); +} + +#[cfg(not(stage0))] +macro_rules! shr_assign_impl { + ($t:ty, $f:ty) => ( + #[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")] + impl ShrAssign<$f> for $t { + #[inline] + fn shr_assign(&mut self, other: $f) { + *self >>= other + } + } + ) +} + +#[cfg(not(stage0))] +macro_rules! shr_assign_impl_all { + ($($t:ty)*) => ($( + shr_assign_impl! { $t, u8 } + shr_assign_impl! { $t, u16 } + shr_assign_impl! { $t, u32 } + shr_assign_impl! { $t, u64 } + shr_assign_impl! { $t, usize } + + shr_assign_impl! { $t, i8 } + shr_assign_impl! { $t, i16 } + shr_assign_impl! { $t, i32 } + shr_assign_impl! { $t, i64 } + shr_assign_impl! { $t, isize } + )*) +} + +#[cfg(not(stage0))] +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. /// @@ -1100,7 +1628,7 @@ impl fmt::Debug for RangeTo { /// impl Deref for DerefExample { /// type Target = T; /// -/// fn deref<'a>(&'a self) -> &'a T { +/// fn deref(&self) -> &T { /// &self.value /// } /// } diff --git a/src/libcore/option.rs b/src/libcore/option.rs index a539ef81db..8fce64bd56 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -290,6 +290,7 @@ impl Option { reason = "waiting for mut conventions", issue = "27776")] #[deprecated(since = "1.4.0", reason = "niche API, unclear of usefulness")] + #[allow(deprecated)] pub fn as_mut_slice(&mut self) -> &mut [T] { match *self { Some(ref mut x) => { @@ -541,7 +542,7 @@ impl Option { /// ``` /// let mut x = Some(4); /// match x.iter_mut().next() { - /// Some(&mut ref mut v) => *v = 42, + /// Some(v) => *v = 42, /// None => {}, /// } /// assert_eq!(x, Some(42)); @@ -694,6 +695,7 @@ impl Option { #[unstable(feature = "as_slice", reason = "unsure of the utility here", issue = "27776")] #[deprecated(since = "1.4.0", reason = "niche API, unclear of usefulness")] + #[allow(deprecated)] pub fn as_slice(&self) -> &[T] { match *self { Some(ref x) => slice::ref_slice(x), @@ -706,7 +708,8 @@ impl Option { } impl<'a, T: Clone> Option<&'a T> { - /// Maps an Option<&T> to an Option by cloning the contents of the Option. + /// Maps an `Option<&T>` to an `Option` by cloning the contents of the + /// option. #[stable(feature = "rust1", since = "1.0.0")] pub fn cloned(self) -> Option { self.map(|t| t.clone()) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 831616293c..52a888d797 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -18,11 +18,11 @@ use clone::Clone; use intrinsics; -use ops::Deref; +use ops::{CoerceUnsized, Deref}; use fmt; use hash; use option::Option::{self, Some, None}; -use marker::{PhantomData, Send, Sized, Sync}; +use marker::{Copy, PhantomData, Send, Sized, Sync, Unsize}; use mem; use nonzero::NonZero; @@ -69,7 +69,7 @@ pub const fn null() -> *const T { 0 as *const T } pub const fn null_mut() -> *mut T { 0 as *mut T } /// Swaps the values at two mutable locations of the same type, without -/// deinitialising either. They may overlap, unlike `mem::swap` which is +/// deinitializing either. They may overlap, unlike `mem::swap` which is /// otherwise equivalent. /// /// # Safety @@ -145,9 +145,11 @@ pub unsafe fn read_and_drop(dest: *mut T) -> T { /// /// # Safety /// -/// Beyond accepting a raw pointer, this operation is unsafe because it does -/// not drop the contents of `dst`. This could leak allocations or resources, -/// so care must be taken not to overwrite an object that should be dropped. +/// This operation is marked unsafe because it accepts a raw pointer. +/// +/// It does not drop the contents of `dst`. This is safe, but it could leak +/// allocations or resources, so care must be taken not to overwrite an object +/// that should be dropped. /// /// This is appropriate for initializing uninitialized memory, or overwriting /// memory that has previously been `read` from. @@ -245,7 +247,7 @@ impl *mut T { /// # Safety /// /// The offset must be in-bounds of the object, or one-byte-past-the-end. - /// Otherwise `offset` invokes Undefined Behaviour, regardless of whether + /// Otherwise `offset` invokes Undefined Behavior, regardless of whether /// the pointer is used. #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -496,12 +498,28 @@ unsafe impl Send for Unique { } #[unstable(feature = "unique", issue = "27730")] unsafe impl Sync for Unique { } +#[cfg(stage0)] +macro_rules! unique_new { + () => ( + /// Creates a new `Unique`. + pub unsafe fn new(ptr: *mut T) -> Unique { + Unique { pointer: NonZero::new(ptr), _marker: PhantomData } + } + ) +} +#[cfg(not(stage0))] +macro_rules! unique_new { + () => ( + /// Creates a new `Unique`. + pub const unsafe fn new(ptr: *mut T) -> Unique { + Unique { pointer: NonZero::new(ptr), _marker: PhantomData } + } + ) +} + #[unstable(feature = "unique", issue = "27730")] impl Unique { - /// Creates a new `Unique`. - pub unsafe fn new(ptr: *mut T) -> Unique { - Unique { pointer: NonZero::new(ptr), _marker: PhantomData } - } + unique_new!{} /// Dereferences the content. pub unsafe fn get(&self) -> &T { @@ -530,3 +548,68 @@ impl fmt::Pointer for Unique { fmt::Pointer::fmt(&*self.pointer, f) } } + +/// A wrapper around a raw `*mut T` that indicates that the possessor +/// of this wrapper has shared ownership of the referent. Useful for +/// building abstractions like `Rc` or `Arc`, which internally +/// use raw pointers to manage the memory that they own. +#[unstable(feature = "shared", reason = "needs an RFC to flesh out design", + issue = "27730")] +pub struct Shared { + pointer: NonZero<*const T>, + // NOTE: this marker has no consequences for variance, but is necessary + // for dropck to understand that we logically own a `T`. + // + // For details, see: + // https://github.com/rust-lang/rfcs/blob/master/text/0769-sound-generic-drop.md#phantom-data + _marker: PhantomData, +} + +/// `Shared` pointers are not `Send` because the data they reference may be aliased. +// NB: This impl is unnecessary, but should provide better error messages. +#[unstable(feature = "shared", issue = "27730")] +impl !Send for Shared { } + +/// `Shared` pointers are not `Sync` because the data they reference may be aliased. +// NB: This impl is unnecessary, but should provide better error messages. +#[unstable(feature = "shared", issue = "27730")] +impl !Sync for Shared { } + +#[unstable(feature = "shared", issue = "27730")] +impl Shared { + /// Creates a new `Shared`. + pub unsafe fn new(ptr: *mut T) -> Self { + Shared { pointer: NonZero::new(ptr), _marker: PhantomData } + } +} + +#[unstable(feature = "shared", issue = "27730")] +impl Clone for Shared { + fn clone(&self) -> Self { + *self + } +} + +#[unstable(feature = "shared", issue = "27730")] +impl Copy for Shared { } + +#[cfg(not(stage0))] // remove cfg after new snapshot +#[unstable(feature = "shared", issue = "27730")] +impl CoerceUnsized> for Shared where T: Unsize { } + +#[unstable(feature = "shared", issue = "27730")] +impl Deref for Shared { + type Target = *mut T; + + #[inline] + fn deref(&self) -> &*mut T { + unsafe { mem::transmute(&*self.pointer) } + } +} + +#[unstable(feature = "shared", issue = "27730")] +impl fmt::Pointer for Shared { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Pointer::fmt(&*self.pointer, f) + } +} diff --git a/src/libcore/raw.rs b/src/libcore/raw.rs index 382fd0f378..84467be6ec 100644 --- a/src/libcore/raw.rs +++ b/src/libcore/raw.rs @@ -94,7 +94,7 @@ impl Clone for Slice { /// Synthesizing a trait object with mismatched types—one where the /// vtable does not correspond to the type of the value to which the /// data pointer points—is highly likely to lead to undefined -/// behaviour. +/// behavior. /// /// # Examples /// diff --git a/src/libcore/result.rs b/src/libcore/result.rs index e9a6719675..e48252fa6f 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -408,6 +408,7 @@ impl Result { #[unstable(feature = "as_slice", reason = "unsure of the utility here", issue = "27776")] #[deprecated(since = "1.4.0", reason = "niche API, unclear of usefulness")] + #[allow(deprecated)] pub fn as_slice(&self) -> &[T] { match *self { Ok(ref x) => slice::ref_slice(x), @@ -441,6 +442,7 @@ impl Result { reason = "waiting for mut conventions", issue = "27776")] #[deprecated(since = "1.4.0", reason = "niche API, unclear of usefulness")] + #[allow(deprecated)] pub fn as_mut_slice(&mut self) -> &mut [T] { match *self { Ok(ref mut x) => slice::mut_ref_slice(x), @@ -538,7 +540,7 @@ impl Result { /// ``` /// let mut x: Result = Ok(7); /// match x.iter_mut().next() { - /// Some(&mut ref mut x) => *x = 40, + /// Some(v) => *v = 40, /// None => {}, /// } /// assert_eq!(x, Ok(40)); diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 8d3d798afe..a49d91ca03 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -655,6 +655,11 @@ impl<'a, T> Default for &'a [T] { fn default() -> &'a [T] { &[] } } +#[stable(feature = "mut_slice_default", since = "1.5.0")] +impl<'a, T> Default for &'a mut [T] { + fn default() -> &'a mut [T] { &mut [] } +} + // // Iterators // @@ -1410,16 +1415,18 @@ impl<'a, T> ExactSizeIterator for ChunksMut<'a, T> {} // Free functions // -/// Converts a pointer to A into a slice of length 1 (without copying). +/// Converts a reference to A into a slice of length 1 (without copying). #[unstable(feature = "ref_slice", issue = "27774")] +#[deprecated(since = "1.5.0", reason = "unclear whether belongs in libstd")] pub fn ref_slice(s: &A) -> &[A] { unsafe { from_raw_parts(s, 1) } } -/// Converts a pointer to A into a slice of length 1 (without copying). +/// Converts a reference to A into a slice of length 1 (without copying). #[unstable(feature = "ref_slice", issue = "27774")] +#[deprecated(since = "1.5.0", reason = "unclear whether belongs in libstd")] pub fn mut_ref_slice(s: &mut A) -> &mut [A] { unsafe { from_raw_parts_mut(s, 1) @@ -1430,7 +1437,7 @@ pub fn mut_ref_slice(s: &mut A) -> &mut [A] { /// /// The `len` argument is the number of **elements**, not the number of bytes. /// -/// # Unsafety +/// # Safety /// /// This function is unsafe as there is no guarantee that the given pointer is /// valid for `len` elements, nor whether the lifetime inferred is a suitable @@ -1559,30 +1566,41 @@ impl Eq for [T] {} #[stable(feature = "rust1", since = "1.0.0")] impl Ord for [T] { fn cmp(&self, other: &[T]) -> Ordering { - self.iter().cmp(other.iter()) + let l = cmp::min(self.len(), other.len()); + + // Slice to the loop iteration range to enable bound check + // elimination in the compiler + let lhs = &self[..l]; + let rhs = &other[..l]; + + for i in 0..l { + match lhs[i].cmp(&rhs[i]) { + Ordering::Equal => (), + non_eq => return non_eq, + } + } + + self.len().cmp(&other.len()) } } #[stable(feature = "rust1", since = "1.0.0")] impl PartialOrd for [T] { - #[inline] fn partial_cmp(&self, other: &[T]) -> Option { - self.iter().partial_cmp(other.iter()) - } - #[inline] - fn lt(&self, other: &[T]) -> bool { - self.iter().lt(other.iter()) - } - #[inline] - fn le(&self, other: &[T]) -> bool { - self.iter().le(other.iter()) - } - #[inline] - fn ge(&self, other: &[T]) -> bool { - self.iter().ge(other.iter()) - } - #[inline] - fn gt(&self, other: &[T]) -> bool { - self.iter().gt(other.iter()) + let l = cmp::min(self.len(), other.len()); + + // Slice to the loop iteration range to enable bound check + // elimination in the compiler + let lhs = &self[..l]; + let rhs = &other[..l]; + + for i in 0..l { + match lhs[i].partial_cmp(&rhs[i]) { + Some(Ordering::Equal) => (), + non_eq => return non_eq, + } + } + + self.len().partial_cmp(&other.len()) } } diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 69ebcb1ab7..7a78460a84 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -48,6 +48,21 @@ pub trait FromStr: Sized { /// If parsing succeeds, return the value inside `Ok`, otherwise /// when the string is ill-formatted return an error specific to the /// inside `Err`. The error type is specific to implementation of the trait. + /// + /// # Examples + /// + /// Basic usage with [`i32`][ithirtytwo], a type that implements `FromStr`: + /// + /// [ithirtytwo]: ../primitive.i32.html + /// + /// ``` + /// use std::str::FromStr; + /// + /// let s = "5"; + /// let x = i32::from_str(s).unwrap(); + /// + /// assert_eq!(5, x); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn from_str(s: &str) -> Result; } @@ -104,7 +119,11 @@ impl fmt::Display for ParseBoolError { Section: Creating a string */ -/// Errors which can occur when attempting to interpret a byte slice as a `str`. +/// Errors which can occur when attempting to interpret a sequence of `u8` +/// as a string. +/// +/// As such, the `from_utf8` family of functions and methods for both `String`s +/// and `&str`s make use of this error, for example. #[derive(Copy, Eq, PartialEq, Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Utf8Error { @@ -115,23 +134,105 @@ impl Utf8Error { /// Returns the index in the given string up to which valid UTF-8 was /// verified. /// - /// Starting at the index provided, but not necessarily at it precisely, an - /// invalid UTF-8 encoding sequence was found. - #[unstable(feature = "utf8_error", reason = "method just added", - issue = "27734")] + /// It is the maximum index such that `from_utf8(input[..index])` + /// would return `Some(_)`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(utf8_error)] + /// + /// use std::str; + /// + /// // some invalid bytes, in a vector + /// let sparkle_heart = vec![0, 159, 146, 150]; + /// + /// // std::str::from_utf8 returns a Utf8Error + /// let error = str::from_utf8(&sparkle_heart).unwrap_err(); + /// + /// // the first byte is invalid here + /// assert_eq!(1, error.valid_up_to()); + /// ``` + #[stable(feature = "utf8_error", since = "1.5.0")] pub fn valid_up_to(&self) -> usize { self.valid_up_to } } -/// Converts a slice of bytes to a string slice without performing any -/// allocations. +/// Converts a slice of bytes to a string slice. /// -/// Once the slice has been validated as UTF-8, it is transmuted in-place and -/// returned as a '&str' instead of a '&[u8]' +/// A string slice (`&str`) is made of bytes (`u8`), and a byte slice (`&[u8]`) +/// is made of bytes, so this function converts between the two. Not all byte +/// slices are valid string slices, however: `&str` requires that it is valid +/// UTF-8. `from_utf8()` checks to ensure that the bytes are valid UTF-8, and +/// then does the conversion. +/// +/// If you are sure that the byte slice is valid UTF-8, and you don't want to +/// incur the overhead of the validity check, there is an unsafe version of +/// this function, [`from_utf8_unchecked()`][fromutf8], which has the same +/// behavior but skips the check. +/// +/// [fromutf8]: fn.from_utf8.html +/// +/// If you need a `String` instead of a `&str`, consider +/// [`String::from_utf8()`][string]. +/// +/// [string]: ../string/struct.String.html#method.from_utf8 +/// +/// Because you can stack-allocate a `[u8; N]`, and you can take a `&[u8]` of +/// it, this function is one way to have a stack-allocated string. There is +/// an example of this in the examples section below. /// /// # Failure /// /// Returns `Err` if the slice is not UTF-8 with a description as to why the /// provided slice is not UTF-8. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::str; +/// +/// // some bytes, in a vector +/// let sparkle_heart = vec![240, 159, 146, 150]; +/// +/// // We know these bytes are valid, so just use `unwrap()`. +/// let sparkle_heart = str::from_utf8(&sparkle_heart).unwrap(); +/// +/// assert_eq!("💖", sparkle_heart); +/// ``` +/// +/// Incorrect bytes: +/// +/// ``` +/// use std::str; +/// +/// // some invalid bytes, in a vector +/// let sparkle_heart = vec![0, 159, 146, 150]; +/// +/// assert!(str::from_utf8(&sparkle_heart).is_err()); +/// ``` +/// +/// See the docs for [`Utf8Error`][error] for more details on the kinds of +/// errors that can be returned. +/// +/// [error]: struct.Utf8Error.html +/// +/// A "stack allocated string": +/// +/// ``` +/// use std::str; +/// +/// // some bytes, in a stack-allocated array +/// let sparkle_heart = [240, 159, 146, 150]; +/// +/// // We know these bytes are valid, so just use `unwrap()`. +/// let sparkle_heart = str::from_utf8(&sparkle_heart).unwrap(); +/// +/// assert_eq!("💖", sparkle_heart); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { try!(run_utf8_validation_iterator(&mut v.iter())); @@ -140,6 +241,33 @@ pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { /// Converts a slice of bytes to a string slice without checking /// that the string contains valid UTF-8. +/// +/// See the safe version, [`from_utf8()`][fromutf8], for more. +/// +/// [fromutf8]: fn.from_utf8.html +/// +/// # Safety +/// +/// This function is unsafe because it does not check that the bytes passed to +/// it are valid UTF-8. If this constraint is violated, undefined behavior +/// results, as the rest of Rust assumes that `&str`s are valid UTF-8. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::str; +/// +/// // some bytes, in a vector +/// let sparkle_heart = vec![240, 159, 146, 150]; +/// +/// let sparkle_heart = unsafe { +/// str::from_utf8_unchecked(&sparkle_heart) +/// }; +/// +/// assert_eq!("💖", sparkle_heart); +/// ``` #[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { @@ -433,7 +561,7 @@ macro_rules! derive_pattern_clone { } /// This macro generates two public iterator structs -/// wrapping an private internal one that makes use of the `Pattern` API. +/// wrapping a private internal one that makes use of the `Pattern` API. /// /// For all patterns `P: Pattern<'a>` the following items will be /// generated (generics omitted): @@ -729,15 +857,19 @@ struct MatchIndicesInternal<'a, P: Pattern<'a>>(P::Searcher); impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> { #[inline] - fn next(&mut self) -> Option<(usize, usize)> { - self.0.next_match() + fn next(&mut self) -> Option<(usize, &'a str)> { + self.0.next_match().map(|(start, end)| unsafe { + (start, self.0.haystack().slice_unchecked(start, end)) + }) } #[inline] - fn next_back(&mut self) -> Option<(usize, usize)> + fn next_back(&mut self) -> Option<(usize, &'a str)> where P::Searcher: ReverseSearcher<'a> { - self.0.next_match_back() + self.0.next_match_back().map(|(start, end)| unsafe { + (start, self.0.haystack().slice_unchecked(start, end)) + }) } } @@ -749,11 +881,9 @@ generate_pattern_iterators! { /// Created with the method `.rmatch_indices()`. struct RMatchIndices; stability: - #[unstable(feature = "str_match_indices", - reason = "type may be removed or have its iterator impl changed", - issue = "27743")] + #[stable(feature = "str_match_indices", since = "1.5.0")] internal: - MatchIndicesInternal yielding ((usize, usize)); + MatchIndicesInternal yielding ((usize, &'a str)); delegate double ended; } @@ -832,7 +962,7 @@ impl<'a> DoubleEndedIterator for Lines<'a> { #[allow(deprecated)] pub struct LinesAny<'a>(Lines<'a>); -/// A nameable, clonable fn type +/// A nameable, cloneable fn type #[derive(Clone)] struct LinesAnyMap; diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 53952cdc90..7225b4f6e0 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -92,6 +92,7 @@ impl Default for AtomicBool { } } +// Send is implicitly implemented for AtomicBool. unsafe impl Sync for AtomicBool {} /// A signed integer type which can be safely shared between threads. @@ -106,6 +107,7 @@ impl Default for AtomicIsize { } } +// Send is implicitly implemented for AtomicIsize. unsafe impl Sync for AtomicIsize {} /// An unsigned integer type which can be safely shared between threads. @@ -120,6 +122,7 @@ impl Default for AtomicUsize { } } +// Send is implicitly implemented for AtomicUsize. unsafe impl Sync for AtomicUsize {} /// A raw pointer type which can be safely shared between threads. @@ -150,7 +153,8 @@ unsafe impl Sync for AtomicPtr {} #[stable(feature = "rust1", since = "1.0.0")] #[derive(Copy, Clone)] pub enum Ordering { - /// No ordering constraints, only atomic operations. + /// No ordering constraints, only atomic operations. Corresponds to LLVM's + /// `Monotonic` ordering. #[stable(feature = "rust1", since = "1.0.0")] Relaxed, /// When coupled with a store, all previous writes become visible diff --git a/src/libcoretest/cell.rs b/src/libcoretest/cell.rs index 20740a5e2c..309a3d51c7 100644 --- a/src/libcoretest/cell.rs +++ b/src/libcoretest/cell.rs @@ -248,15 +248,14 @@ fn unsafe_cell_unsized() { assert_eq!(unsafe { &mut *cell.get() }, comp); } -// FIXME(#25351) needs deeply nested coercions of DST structs. -// #[test] -// fn refcell_unsized() { -// let cell: &RefCell<[i32]> = &RefCell::new([1, 2, 3]); -// { -// let b = &mut *cell.borrow_mut(); -// b[0] = 4; -// b[2] = 5; -// } -// let comp: &mut [i32] = &mut [4, 2, 5]; -// assert_eq!(&*cell.borrow(), comp); -// } +#[test] +fn refcell_unsized() { + let cell: &RefCell<[i32]> = &RefCell::new([1, 2, 3]); + { + let b = &mut *cell.borrow_mut(); + b[0] = 4; + b[2] = 5; + } + let comp: &mut [i32] = &mut [4, 2, 5]; + assert_eq!(&*cell.borrow(), comp); +} diff --git a/src/libcoretest/clone.rs b/src/libcoretest/clone.rs index 5ab6ab27ba..91d68ba334 100644 --- a/src/libcoretest/clone.rs +++ b/src/libcoretest/clone.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -11,8 +11,8 @@ #[test] fn test_borrowed_clone() { let x = 5; - let y: &int = &x; - let z: &int = (&y).clone(); + let y: &i32 = &x; + let z: &i32 = (&y).clone(); assert_eq!(*z, 5); } @@ -23,17 +23,3 @@ fn test_clone_from() { b.clone_from(&a); assert_eq!(*b, 5); } - -#[test] -fn test_extern_fn_clone() { - trait Empty {} - impl Empty for int {} - - fn test_fn_a() -> f64 { 1.0 } - fn test_fn_b(x: T) -> T { x } - fn test_fn_c(_: int, _: f64, _: int, _: int, _: int) {} - - let _ = test_fn_a.clone(); - let _ = test_fn_b::.clone(); - let _ = test_fn_c.clone(); -} diff --git a/src/libcoretest/fmt/float.rs b/src/libcoretest/fmt/float.rs index 6b14fa8be8..16cd2feddc 100644 --- a/src/libcoretest/fmt/float.rs +++ b/src/libcoretest/fmt/float.rs @@ -13,5 +13,7 @@ fn test_format_float() { assert!("1" == format!("{:.0}", 1.0f64)); assert!("9" == format!("{:.0}", 9.4f64)); assert!("10" == format!("{:.0}", 9.9f64)); - assert!("9.9" == format!("{:.1}", 9.85f64)); + assert!("9.8" == format!("{:.1}", 9.849f64)); + assert!("9.9" == format!("{:.1}", 9.851f64)); + assert!("1" == format!("{:.0}", 0.5f64)); } diff --git a/src/libcoretest/fmt/mod.rs b/src/libcoretest/fmt/mod.rs index 42872589bb..99ea39c619 100644 --- a/src/libcoretest/fmt/mod.rs +++ b/src/libcoretest/fmt/mod.rs @@ -8,8 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -mod num; mod builders; +mod float; +mod num; #[test] fn test_format_flags() { diff --git a/src/libcoretest/intrinsics.rs b/src/libcoretest/intrinsics.rs index c99fb8c197..2b380abf63 100644 --- a/src/libcoretest/intrinsics.rs +++ b/src/libcoretest/intrinsics.rs @@ -12,7 +12,7 @@ use core::any::TypeId; #[test] fn test_typeid_sized_types() { - struct X; struct Y(uint); + struct X; struct Y(u32); assert_eq!(TypeId::of::(), TypeId::of::()); assert_eq!(TypeId::of::(), TypeId::of::()); diff --git a/src/libcoretest/lib.rs b/src/libcoretest/lib.rs index e87a179f58..96886c9104 100644 --- a/src/libcoretest/lib.rs +++ b/src/libcoretest/lib.rs @@ -15,6 +15,8 @@ #![feature(const_fn)] #![feature(core)] #![feature(core_float)] +#![feature(core_private_bignum)] +#![feature(core_private_diy_float)] #![feature(dec2flt)] #![feature(decode_utf16)] #![feature(fixed_size_array)] @@ -52,9 +54,11 @@ mod array; mod atomic; mod cell; mod char; +mod clone; mod cmp; mod fmt; mod hash; +mod intrinsics; mod iter; mod mem; mod nonzero; diff --git a/src/libcoretest/num/flt2dec/bignum.rs b/src/libcoretest/num/bignum.rs similarity index 99% rename from src/libcoretest/num/flt2dec/bignum.rs rename to src/libcoretest/num/bignum.rs index 31065b2898..58a9dd1b12 100644 --- a/src/libcoretest/num/flt2dec/bignum.rs +++ b/src/libcoretest/num/bignum.rs @@ -9,7 +9,7 @@ // except according to those terms. use std::prelude::v1::*; -use core::num::flt2dec::bignum::tests::Big8x3 as Big; +use core::num::bignum::tests::Big8x3 as Big; #[test] #[should_panic] diff --git a/src/libcoretest/num/dec2flt/mod.rs b/src/libcoretest/num/dec2flt/mod.rs index fb98e7e6f9..0c92b2fe2a 100644 --- a/src/libcoretest/num/dec2flt/mod.rs +++ b/src/libcoretest/num/dec2flt/mod.rs @@ -16,7 +16,7 @@ use test; mod parse; mod rawfp; -// Take an float literal, turn it into a string in various ways (that are all trusted +// Take a float literal, turn it into a string in various ways (that are all trusted // to be correct) and see if those strings are parsed back to the value of the literal. // Requires a *polymorphic literal*, i.e. one that can serve as f64 as well as f32. macro_rules! test_literal { diff --git a/src/libcoretest/num/dec2flt/rawfp.rs b/src/libcoretest/num/dec2flt/rawfp.rs index a40d360f10..4c0a403e57 100644 --- a/src/libcoretest/num/dec2flt/rawfp.rs +++ b/src/libcoretest/num/dec2flt/rawfp.rs @@ -9,14 +9,14 @@ // except according to those terms. use std::f64; -use core::num::flt2dec::strategy::grisu::Fp; +use core::num::diy_float::Fp; use core::num::dec2flt::rawfp::{fp_to_float, prev_float, next_float, round_normal}; #[test] fn fp_to_float_half_to_even() { fn is_normalized(sig: u64) -> bool { - // intentionally written without {min,max}_sig() as a sanity check - sig >> 52 == 1 && sig >> 53 == 0 + // intentionally written without {min,max}_sig() as a sanity check + sig >> 52 == 1 && sig >> 53 == 0 } fn conv(sig: u64) -> u64 { diff --git a/src/libcoretest/num/flt2dec/mod.rs b/src/libcoretest/num/flt2dec/mod.rs index 8ae33a4420..309bf6d819 100644 --- a/src/libcoretest/num/flt2dec/mod.rs +++ b/src/libcoretest/num/flt2dec/mod.rs @@ -23,7 +23,6 @@ use core::num::flt2dec::{to_shortest_str, to_shortest_exp_str, pub use test::Bencher; mod estimator; -mod bignum; mod strategy { mod dragon; mod grisu; diff --git a/src/libcoretest/num/flt2dec/strategy/dragon.rs b/src/libcoretest/num/flt2dec/strategy/dragon.rs index f3ddc370d1..79dcca7671 100644 --- a/src/libcoretest/num/flt2dec/strategy/dragon.rs +++ b/src/libcoretest/num/flt2dec/strategy/dragon.rs @@ -12,7 +12,7 @@ use std::prelude::v1::*; use std::{i16, f64}; use super::super::*; use core::num::flt2dec::*; -use core::num::flt2dec::bignum::Big32x40 as Big; +use core::num::bignum::Big32x40 as Big; use core::num::flt2dec::strategy::dragon::*; #[test] diff --git a/src/libcoretest/num/mod.rs b/src/libcoretest/num/mod.rs index 9f9d2a4ca1..5e2ec66bab 100644 --- a/src/libcoretest/num/mod.rs +++ b/src/libcoretest/num/mod.rs @@ -31,6 +31,7 @@ mod u64; mod flt2dec; mod dec2flt; +mod bignum; /// Helper function for testing numeric operations pub fn test_num(ten: T, two: T) where @@ -117,15 +118,63 @@ mod tests { assert_eq!("-9223372036854775809".parse::().ok(), None); } + #[test] + fn test_leading_plus() { + assert_eq!("+127".parse::().ok(), Some(127u8)); + assert_eq!("+9223372036854775807".parse::().ok(), Some(9223372036854775807i64)); + } + #[test] fn test_invalid() { assert_eq!("--129".parse::().ok(), None); + assert_eq!("++129".parse::().ok(), None); assert_eq!("Съешь".parse::().ok(), None); } #[test] fn test_empty() { assert_eq!("-".parse::().ok(), None); + assert_eq!("+".parse::().ok(), None); assert_eq!("".parse::().ok(), None); } + + macro_rules! test_impl_from { + ($fn_name: ident, $Small: ty, $Large: ty) => { + #[test] + fn $fn_name() { + let small_max = <$Small>::max_value(); + let small_min = <$Small>::min_value(); + let large_max: $Large = small_max.into(); + let large_min: $Large = small_min.into(); + assert_eq!(large_max as $Small, small_max); + assert_eq!(large_min as $Small, small_min); + } + } + } + + // Unsigned -> Unsigned + test_impl_from! { test_u8u16, u8, u16 } + test_impl_from! { test_u8u32, u8, u32 } + test_impl_from! { test_u8u64, u8, u64 } + test_impl_from! { test_u8usize, u8, usize } + test_impl_from! { test_u16u32, u16, u32 } + test_impl_from! { test_u16u64, u16, u64 } + test_impl_from! { test_u32u64, u32, u64 } + + // Signed -> Signed + test_impl_from! { test_i8i16, i8, i16 } + test_impl_from! { test_i8i32, i8, i32 } + test_impl_from! { test_i8i64, i8, i64 } + test_impl_from! { test_i8isize, i8, isize } + test_impl_from! { test_i16i32, i16, i32 } + test_impl_from! { test_i16i64, i16, i64 } + test_impl_from! { test_i32i64, i32, i64 } + + // Unsigned -> Signed + test_impl_from! { test_u8i16, u8, i16 } + test_impl_from! { test_u8i32, u8, i32 } + test_impl_from! { test_u8i64, u8, i64 } + test_impl_from! { test_u16i32, u16, i32 } + test_impl_from! { test_u16i64, u16, i64 } + test_impl_from! { test_u32i64, u32, i64 } } diff --git a/src/libflate/lib.rs b/src/libflate/lib.rs index d85f653937..521dddae78 100644 --- a/src/libflate/lib.rs +++ b/src/libflate/lib.rs @@ -30,7 +30,9 @@ #![feature(unique)] #![cfg_attr(test, feature(rustc_private, rand, vec_push_all))] -#[cfg(test)] #[macro_use] extern crate log; +#[cfg(test)] +#[macro_use] +extern crate log; extern crate libc; @@ -47,9 +49,7 @@ pub struct Error { impl Error { fn new() -> Error { - Error { - _unused: (), - } + Error { _unused: () } } } @@ -73,7 +73,9 @@ impl Deref for Bytes { impl Drop for Bytes { fn drop(&mut self) { - unsafe { libc::free(*self.ptr as *mut _); } + unsafe { + libc::free(*self.ptr as *mut _); + } } } @@ -123,7 +125,7 @@ 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 { +fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Result { unsafe { let mut outsz: size_t = 0; let res = tinfl_decompress_mem_to_heap(bytes.as_ptr() as *const _, @@ -142,12 +144,12 @@ 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 { +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 { +pub fn inflate_bytes_zlib(bytes: &[u8]) -> Result { inflate_bytes_internal(bytes, TINFL_FLAG_PARSE_ZLIB_HEADER) } @@ -176,7 +178,8 @@ mod tests { let cmp = deflate_bytes(&input); let out = inflate_bytes(&cmp).unwrap(); debug!("{} bytes deflated to {} ({:.1}% size)", - input.len(), cmp.len(), + input.len(), + cmp.len(), 100.0 * ((cmp.len() as f64) / (input.len() as f64))); assert_eq!(&*input, &*out); } diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index 9c02ccb08a..ed767ab1e5 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -75,7 +75,7 @@ pub struct FormatSpec<'a> { /// The descriptor string representing the name of the format desired for /// this argument, this can be empty or any number of characters, although /// it is required to be one word. - pub ty: &'a str + pub ty: &'a str, } /// Enum describing where an argument for a format can be located. @@ -135,7 +135,7 @@ pub enum Count<'a> { } /// The parser structure for interpreting the input format string. This is -/// modelled as an iterator over `Piece` structures to form a stream of tokens +/// modeled as an iterator over `Piece` structures to form a stream of tokens /// being output. /// /// This is a recursive-descent parser for the sake of simplicity, and if @@ -202,7 +202,12 @@ impl<'a> Parser<'a> { /// returned, otherwise the character is consumed and true is returned. fn consume(&mut self, c: char) -> bool { if let Some(&(_, maybe)) = self.cur.peek() { - if c == maybe { self.cur.next(); true } else { false } + if c == maybe { + self.cur.next(); + true + } else { + false + } } else { false } @@ -227,7 +232,11 @@ impl<'a> Parser<'a> { /// character fn ws(&mut self) { while let Some(&(_, c)) = self.cur.peek() { - if c.is_whitespace() { self.cur.next(); } else { break } + if c.is_whitespace() { + self.cur.next(); + } else { + break + } } } @@ -237,8 +246,12 @@ impl<'a> Parser<'a> { // we may not consume the character, peek the iterator while let Some(&(pos, c)) = self.cur.peek() { match c { - '{' | '}' => { return &self.input[start..pos]; } - _ => { self.cur.next(); } + '{' | '}' => { + return &self.input[start..pos]; + } + _ => { + self.cur.next(); + } } } &self.input[start..self.input.len()] @@ -263,7 +276,7 @@ impl<'a> Parser<'a> { Some(&(_, c)) if c.is_alphabetic() => { ArgumentNamed(self.word()) } - _ => ArgumentNext + _ => ArgumentNext, } } } @@ -279,7 +292,9 @@ impl<'a> Parser<'a> { width: CountImplied, ty: &self.input[..0], }; - if !self.consume(':') { return spec } + if !self.consume(':') { + return spec + } // fill character if let Some(&(_, c)) = self.cur.peek() { @@ -347,7 +362,11 @@ impl<'a> Parser<'a> { /// width. fn count(&mut self) -> Count<'a> { if let Some(i) = self.integer() { - if self.consume('$') { CountIsParam(i) } else { CountIs(i) } + if self.consume('$') { + CountIsParam(i) + } else { + CountIs(i) + } } else { let tmp = self.cur.clone(); let word = self.word(); @@ -370,8 +389,13 @@ impl<'a> Parser<'a> { /// characters. fn word(&mut self) -> &'a str { let start = match self.cur.peek() { - Some(&(pos, c)) if c.is_xid_start() => { self.cur.next(); pos } - _ => { return &self.input[..0]; } + Some(&(pos, c)) if c.is_xid_start() => { + self.cur.next(); + pos + } + _ => { + return &self.input[..0]; + } }; while let Some(&(pos, c)) = self.cur.peek() { if c.is_xid_continue() { @@ -397,7 +421,11 @@ impl<'a> Parser<'a> { break } } - if found { Some(cur) } else { None } + if found { + Some(cur) + } else { + None + } } } @@ -437,178 +465,210 @@ mod tests { same("\\}}", &[String("\\"), String("}")]); } - #[test] fn invalid01() { musterr("{") } - #[test] fn invalid02() { musterr("}") } - #[test] fn invalid04() { musterr("{3a}") } - #[test] fn invalid05() { musterr("{:|}") } - #[test] fn invalid06() { musterr("{:>>>}") } + #[test] + fn invalid01() { + musterr("{") + } + #[test] + fn invalid02() { + musterr("}") + } + #[test] + fn invalid04() { + musterr("{3a}") + } + #[test] + fn invalid05() { + musterr("{:|}") + } + #[test] + fn invalid06() { + musterr("{:>>>}") + } #[test] fn format_nothing() { - same("{}", &[NextArgument(Argument { - position: ArgumentNext, - format: fmtdflt(), - })]); + same("{}", + &[NextArgument(Argument { + position: ArgumentNext, + format: fmtdflt(), + })]); } #[test] fn format_position() { - same("{3}", &[NextArgument(Argument { - position: ArgumentIs(3), - format: fmtdflt(), - })]); + same("{3}", + &[NextArgument(Argument { + position: ArgumentIs(3), + format: fmtdflt(), + })]); } #[test] fn format_position_nothing_else() { - same("{3:}", &[NextArgument(Argument { - position: ArgumentIs(3), - format: fmtdflt(), - })]); + same("{3:}", + &[NextArgument(Argument { + position: ArgumentIs(3), + format: fmtdflt(), + })]); } #[test] fn format_type() { - same("{3:a}", &[NextArgument(Argument { - position: ArgumentIs(3), - format: FormatSpec { - fill: None, - align: AlignUnknown, - flags: 0, - precision: CountImplied, - width: CountImplied, - ty: "a", - }, - })]); + same("{3:a}", + &[NextArgument(Argument { + position: ArgumentIs(3), + format: FormatSpec { + fill: None, + align: AlignUnknown, + flags: 0, + precision: CountImplied, + width: CountImplied, + ty: "a", + }, + })]); } #[test] fn format_align_fill() { - same("{3:>}", &[NextArgument(Argument { - position: ArgumentIs(3), - format: FormatSpec { - fill: None, - align: AlignRight, - flags: 0, - precision: CountImplied, - width: CountImplied, - ty: "", - }, - })]); - same("{3:0<}", &[NextArgument(Argument { - position: ArgumentIs(3), - format: FormatSpec { - fill: Some('0'), - align: AlignLeft, - flags: 0, - precision: CountImplied, - width: CountImplied, - ty: "", - }, - })]); - same("{3:*}", + &[NextArgument(Argument { + position: ArgumentIs(3), + format: FormatSpec { + fill: None, + align: AlignRight, + flags: 0, + precision: CountImplied, + width: CountImplied, + ty: "", + }, + })]); + same("{3:0<}", + &[NextArgument(Argument { + position: ArgumentIs(3), + format: FormatSpec { + fill: Some('0'), + align: AlignLeft, + flags: 0, + precision: CountImplied, + width: CountImplied, + ty: "", + }, + })]); + same("{3:* { fn graph_id(&'a self) -> Id<'a>; /// Maps `n` to a unique identifier with respect to `self`. The - /// implementer is responsible for ensuring that the returned name + /// implementor is responsible for ensuring that the returned name /// is a valid DOT identifier. fn node_id(&'a self, n: &N) -> Id<'a>; @@ -594,7 +594,7 @@ pub type Edges<'a,E> = Cow<'a,[E]>; /// that is bound by the self lifetime `'a`. /// /// The `nodes` and `edges` method each return instantiations of -/// `Cow<[T]>` to leave implementers the freedom to create +/// `Cow<[T]>` to leave implementors the freedom to create /// entirely new vectors or to pass back slices into internally owned /// vectors. pub trait GraphWalk<'a, N: Clone, E: Clone> { diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index 95b5ccca75..13902d6743 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -24,6 +24,7 @@ html_playground_url = "https://play.rust-lang.org/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")] #![cfg_attr(test, feature(test))] +#![cfg_attr(not(feature = "cargo-build"), feature(cfg_target_vendor))] //! Bindings for the C standard library and other platform libraries //! @@ -79,10 +80,13 @@ #![allow(bad_style, raw_pointer_derive)] #![cfg_attr(target_os = "nacl", allow(unused_imports))] -#[cfg(feature = "cargo-build")] extern crate std as core; +#[cfg(feature = "cargo-build")] +extern crate std as core; -#[cfg(test)] extern crate std; -#[cfg(test)] extern crate test; +#[cfg(test)] +extern crate std; +#[cfg(test)] +extern crate test; // Explicit export lists for the intersection (provided here) mean that // you can write more-platform-agnostic code if you stick to just these @@ -127,46 +131,63 @@ pub use funcs::bsd43::*; // // So the following exports don't follow any particular plan. -#[cfg(unix)] pub use consts::os::sysconf::*; - -#[cfg(unix)] pub use funcs::posix88::mman::*; -#[cfg(unix)] pub use funcs::posix88::dirent::*; -#[cfg(unix)] pub use funcs::posix88::net::*; -#[cfg(unix)] pub use funcs::posix01::stat_::*; -#[cfg(unix)] pub use funcs::posix01::unistd::*; -#[cfg(unix)] pub use funcs::posix01::resource::*; - - -#[cfg(windows)] pub use funcs::extra::kernel32::*; -#[cfg(windows)] pub use funcs::extra::winsock::*; -#[cfg(windows)] pub use funcs::extra::msvcrt::*; +#[cfg(unix)] +pub use consts::os::sysconf::*; + +#[cfg(unix)] +pub use funcs::posix88::mman::*; +#[cfg(unix)] +pub use funcs::posix88::dirent::*; +#[cfg(unix)] +pub use funcs::posix88::net::*; +#[cfg(unix)] +pub use funcs::posix01::stat_::*; +#[cfg(unix)] +pub use funcs::posix01::unistd::*; +#[cfg(unix)] +pub use funcs::posix01::resource::*; + + +#[cfg(windows)] +pub use funcs::extra::kernel32::*; +#[cfg(windows)] +pub use funcs::extra::winsock::*; +#[cfg(windows)] +pub use funcs::extra::msvcrt::*; // On NaCl, these libraries are static. Thus it would be a Bad Idea to link them // in when creating a test crate. -#[cfg(not(any(windows, target_env = "musl", all(target_os = "nacl", test))))] +#[cfg(not(any(windows, + target_env = "musl", + all(target_os = "nacl", test), + all(target_os = "netbsd", target_vendor = "rumprun"))))] #[link(name = "c")] #[link(name = "m")] -extern {} +extern { +} // When compiling rust with musl, statically include libc.a in liblibc.rlib. // A cargo build of the libc crate will therefore automatically pick up the // libc.a symbols because liblibc is transitively linked to by the stdlib. #[cfg(all(target_env = "musl", not(feature = "cargo-build"), not(test)))] #[link(name = "c", kind = "static")] -extern {} +extern { +} #[cfg(all(windows, target_env = "msvc"))] #[link(name = "kernel32")] #[link(name = "shell32")] #[link(name = "msvcrt")] -extern {} +extern { +} // libnacl provides functions that require a trip through the IRT to work. // ie: _exit, mmap, nanosleep, etc. Anything that would otherwise require a trip // to the kernel. #[cfg(all(target_os = "nacl", not(feature = "cargo-build"), not(test)))] #[link(name = "nacl", kind = "static")] -extern {} +extern { +} // pnaclmm provides a number of functions that the toolchain's Clang emits calls // to when codegening atomic ops. All the functions within wrap various atomic @@ -176,7 +197,8 @@ extern {} // optimizations on the whole pnaclmm foreach binary built). #[cfg(all(target_os = "nacl", not(feature = "cargo-build"), not(test)))] #[link(name = "pnaclmm", kind = "static")] -extern {} +extern { +} pub mod types { @@ -222,9 +244,12 @@ pub mod types { pub enum DIR {} pub enum dirent_t {} } - pub mod posix01 {} - pub mod posix08 {} - pub mod bsd44 {} + pub mod posix01 { + } + pub mod posix08 { + } + pub mod bsd44 { + } } // Standard types that are scalar but vary by OS and arch. @@ -233,9 +258,8 @@ pub mod types { pub mod os { pub mod common { pub mod posix01 { - use types::common::c95::{c_void}; - use types::os::arch::c95::{c_char, c_ulong, size_t, - time_t, suseconds_t, c_long}; + use types::common::c95::c_void; + use types::os::arch::c95::{c_char, c_ulong, size_t, time_t, suseconds_t, c_long}; #[cfg(not(target_os = "nacl"))] pub type pthread_t = c_ulong; @@ -244,10 +268,11 @@ pub mod types { pub type rlim_t = u64; #[repr(C)] - #[derive(Copy, Clone)] pub struct glob_t { + #[derive(Copy, Clone)] + pub struct glob_t { pub gl_pathc: size_t, pub gl_pathv: *mut *mut c_char, - pub gl_offs: size_t, + pub gl_offs: size_t, pub __unused1: *mut c_void, pub __unused2: *mut c_void, @@ -257,13 +282,15 @@ pub mod types { } #[repr(C)] - #[derive(Copy, Clone)] pub struct timeval { + #[derive(Copy, Clone)] + pub struct timeval { pub tv_sec: time_t, pub tv_usec: suseconds_t, } #[repr(C)] - #[derive(Copy, Clone)] pub struct timespec { + #[derive(Copy, Clone)] + pub struct timespec { pub tv_sec: time_t, pub tv_nsec: c_long, } @@ -303,12 +330,12 @@ pub mod types { pub ru_msgrcv: c_long, pub ru_nsignals: c_long, pub ru_nvcsw: c_long, - pub ru_nivcsw: c_long + pub ru_nivcsw: c_long, } } pub mod bsd44 { - use types::common::c95::{c_void}; + use types::common::c95::c_void; use types::os::arch::c95::{c_char, c_int, c_uint}; pub type socklen_t = u32; @@ -316,12 +343,14 @@ pub mod types { pub type in_port_t = u16; pub type in_addr_t = u32; #[repr(C)] - #[derive(Copy, Clone)] pub struct sockaddr { + #[derive(Copy, Clone)] + pub struct sockaddr { pub sa_family: sa_family_t, pub sa_data: [u8; 14], } #[repr(C)] - #[derive(Copy)] pub struct sockaddr_storage { + #[derive(Copy)] + pub struct sockaddr_storage { pub ss_family: sa_family_t, pub __ss_align: isize, #[cfg(target_pointer_width = "32")] @@ -330,21 +359,26 @@ pub mod types { pub __ss_pad2: [u8; 128 - 2 * 8], } impl ::core::clone::Clone for sockaddr_storage { - fn clone(&self) -> sockaddr_storage { *self } + fn clone(&self) -> sockaddr_storage { + *self + } } #[repr(C)] - #[derive(Copy, Clone)] pub struct sockaddr_in { + #[derive(Copy, Clone)] + pub struct sockaddr_in { pub sin_family: sa_family_t, pub sin_port: in_port_t, pub sin_addr: in_addr, pub sin_zero: [u8; 8], } #[repr(C)] - #[derive(Copy, Clone)] pub struct in_addr { + #[derive(Copy, Clone)] + pub struct in_addr { pub s_addr: in_addr_t, } #[repr(C)] - #[derive(Copy, Clone)] pub struct sockaddr_in6 { + #[derive(Copy, Clone)] + pub struct sockaddr_in6 { pub sin6_family: sa_family_t, pub sin6_port: in_port_t, pub sin6_flowinfo: u32, @@ -352,21 +386,25 @@ pub mod types { pub sin6_scope_id: u32, } #[repr(C)] - #[derive(Copy, Clone)] pub struct in6_addr { - pub s6_addr: [u16; 8] + #[derive(Copy, Clone)] + pub struct in6_addr { + pub s6_addr: [u16; 8], } #[repr(C)] - #[derive(Copy, Clone)] pub struct ip_mreq { + #[derive(Copy, Clone)] + pub struct ip_mreq { pub imr_multiaddr: in_addr, pub imr_interface: in_addr, } #[repr(C)] - #[derive(Copy, Clone)] pub struct ip6_mreq { + #[derive(Copy, Clone)] + pub struct ip6_mreq { pub ipv6mr_multiaddr: in6_addr, pub ipv6mr_interface: c_uint, } #[repr(C)] - #[derive(Copy, Clone)] pub struct addrinfo { + #[derive(Copy, Clone)] + pub struct addrinfo { pub ai_flags: c_int, pub ai_family: c_int, pub ai_socktype: c_int, @@ -388,23 +426,27 @@ pub mod types { pub ai_next: *mut addrinfo, } #[repr(C)] - #[derive(Copy)] pub struct sockaddr_un { + #[derive(Copy)] + pub struct sockaddr_un { pub sun_family: sa_family_t, - pub sun_path: [c_char; 108] + pub sun_path: [c_char; 108], } impl ::core::clone::Clone for sockaddr_un { - fn clone(&self) -> sockaddr_un { *self } + fn clone(&self) -> sockaddr_un { + *self + } } #[repr(C)] - #[derive(Copy, Clone)] pub struct ifaddrs { + #[derive(Copy, Clone)] + pub struct ifaddrs { pub ifa_next: *mut ifaddrs, pub ifa_name: *mut c_char, pub ifa_flags: c_uint, pub ifa_addr: *mut sockaddr, pub ifa_netmask: *mut sockaddr, pub ifa_ifu: *mut sockaddr, // FIXME This should be a union - pub ifa_data: *mut c_void + pub ifa_data: *mut c_void, } } @@ -484,14 +526,15 @@ pub mod types { use types::os::arch::c95::{c_short, c_long, time_t}; use types::os::arch::posix88::{dev_t, gid_t, ino_t}; use types::os::arch::posix88::{mode_t, off_t}; - use types::os::arch::posix88::{uid_t}; + use types::os::arch::posix88::uid_t; pub type nlink_t = u32; pub type blksize_t = i32; pub type blkcnt_t = i32; #[repr(C)] - #[derive(Copy, Clone)] pub struct stat { + #[derive(Copy, Clone)] + pub struct stat { pub st_dev: dev_t, pub __pad1: c_short, pub st_ino: ino_t, @@ -515,14 +558,16 @@ pub mod types { } #[repr(C)] - #[derive(Copy, Clone)] pub struct utimbuf { + #[derive(Copy, Clone)] + pub struct utimbuf { pub actime: time_t, pub modtime: time_t, } #[repr(C)] - #[derive(Copy, Clone)] pub struct pthread_attr_t { - pub __size: [u32; 9] + #[derive(Copy, Clone)] + pub struct pthread_attr_t { + pub __size: [u32; 9], } } @@ -538,7 +583,8 @@ pub mod types { pub type blkcnt_t = u32; #[repr(C)] - #[derive(Copy, Clone)] pub struct stat { + #[derive(Copy, Clone)] + pub struct stat { pub st_dev: c_ulonglong, pub __pad0: [c_uchar; 4], pub __st_ino: c_long, @@ -561,14 +607,16 @@ pub mod types { } #[repr(C)] - #[derive(Copy, Clone)] pub struct utimbuf { + #[derive(Copy, Clone)] + pub struct utimbuf { pub actime: time_t, pub modtime: time_t, } #[repr(C)] - #[derive(Copy, Clone)] pub struct pthread_attr_t { - pub __size: [u32; 9] + #[derive(Copy, Clone)] + pub struct pthread_attr_t { + pub __size: [u32; 9], } } @@ -578,14 +626,15 @@ pub mod types { use types::os::arch::c95::{c_long, c_ulong, time_t}; use types::os::arch::posix88::{gid_t, ino_t}; use types::os::arch::posix88::{mode_t, off_t}; - use types::os::arch::posix88::{uid_t}; + use types::os::arch::posix88::uid_t; pub type nlink_t = u32; pub type blksize_t = i32; pub type blkcnt_t = i32; #[repr(C)] - #[derive(Copy, Clone)] pub struct stat { + #[derive(Copy, Clone)] + pub struct stat { pub st_dev: c_ulong, pub st_pad1: [c_long; 3], pub st_ino: ino_t, @@ -609,29 +658,34 @@ pub mod types { } #[repr(C)] - #[derive(Copy, Clone)] pub struct utimbuf { + #[derive(Copy, Clone)] + pub struct utimbuf { pub actime: time_t, pub modtime: time_t, } #[repr(C)] - #[derive(Copy, Clone)] pub struct pthread_attr_t { - pub __size: [u32; 9] + #[derive(Copy, Clone)] + pub struct pthread_attr_t { + pub __size: [u32; 9], } } - pub mod posix08 {} - pub mod bsd44 {} + pub mod posix08 { + } + pub mod bsd44 { + } pub mod extra { use types::os::arch::c95::{c_ushort, c_int, c_uchar}; #[repr(C)] - #[derive(Copy, Clone)] pub struct sockaddr_ll { + #[derive(Copy, Clone)] + pub struct sockaddr_ll { pub sll_family: c_ushort, pub sll_protocol: c_ushort, pub sll_ifindex: c_int, pub sll_hatype: c_ushort, pub sll_pkttype: c_uchar, pub sll_halen: c_uchar, - pub sll_addr: [c_uchar; 8] + pub sll_addr: [c_uchar; 8], } } @@ -689,14 +743,15 @@ pub mod types { use types::os::arch::c95::{c_int, c_long, time_t}; use types::os::arch::posix88::{dev_t, gid_t, ino_t}; use types::os::arch::posix88::{mode_t, off_t}; - use types::os::arch::posix88::{uid_t}; + use types::os::arch::posix88::uid_t; pub type nlink_t = u64; pub type blksize_t = i64; pub type blkcnt_t = i64; #[repr(C)] - #[derive(Copy, Clone)] pub struct stat { + #[derive(Copy, Clone)] + pub struct stat { pub st_dev: dev_t, pub st_ino: ino_t, pub st_nlink: nlink_t, @@ -718,14 +773,16 @@ pub mod types { } #[repr(C)] - #[derive(Copy, Clone)] pub struct utimbuf { + #[derive(Copy, Clone)] + pub struct utimbuf { pub actime: time_t, pub modtime: time_t, } #[repr(C)] - #[derive(Copy, Clone)] pub struct pthread_attr_t { - pub __size: [u64; 7] + #[derive(Copy, Clone)] + pub struct pthread_attr_t { + pub __size: [u64; 7], } } #[cfg(target_arch = "aarch64")] @@ -733,14 +790,15 @@ pub mod types { use types::os::arch::c95::{c_int, c_long, time_t}; use types::os::arch::posix88::{dev_t, gid_t, ino_t}; use types::os::arch::posix88::{mode_t, off_t}; - use types::os::arch::posix88::{uid_t}; + use types::os::arch::posix88::uid_t; pub type nlink_t = u32; pub type blksize_t = i32; pub type blkcnt_t = i64; #[repr(C)] - #[derive(Copy, Clone)] pub struct stat { + #[derive(Copy, Clone)] + pub struct stat { pub st_dev: dev_t, pub st_ino: ino_t, pub st_mode: mode_t, @@ -763,14 +821,16 @@ pub mod types { } #[repr(C)] - #[derive(Copy, Clone)] pub struct utimbuf { + #[derive(Copy, Clone)] + pub struct utimbuf { pub actime: time_t, pub modtime: time_t, } #[repr(C)] - #[derive(Copy, Clone)] pub struct pthread_attr_t { - pub __size: [u64; 8] + #[derive(Copy, Clone)] + pub struct pthread_attr_t { + pub __size: [u64; 8], } } pub mod posix08 { @@ -779,14 +839,15 @@ pub mod types { } pub mod extra { use types::os::arch::c95::{c_ushort, c_int, c_uchar}; - #[derive(Copy, Clone)] pub struct sockaddr_ll { + #[derive(Copy, Clone)] + pub struct sockaddr_ll { pub sll_family: c_ushort, pub sll_protocol: c_ushort, pub sll_ifindex: c_int, pub sll_hatype: c_ushort, pub sll_pkttype: c_uchar, pub sll_halen: c_uchar, - pub sll_addr: [c_uchar; 8] + pub sll_addr: [c_uchar; 8], } } @@ -797,21 +858,21 @@ pub mod types { pub mod os { pub mod common { pub mod posix01 { - use types::common::c95::{c_void}; - use types::os::arch::c95::{c_char, c_int, size_t, - time_t, suseconds_t, c_long}; - use types::os::arch::c99::{uintptr_t}; + use types::common::c95::c_void; + use types::os::arch::c95::{c_char, c_int, size_t, time_t, suseconds_t, c_long}; + use types::os::arch::c99::uintptr_t; pub type pthread_t = uintptr_t; pub type rlim_t = i64; #[repr(C)] - #[derive(Copy, Clone)] pub struct glob_t { - pub gl_pathc: size_t, + #[derive(Copy, Clone)] + pub struct glob_t { + pub gl_pathc: size_t, pub __unused1: size_t, - pub gl_offs: size_t, + pub gl_offs: size_t, pub __unused2: c_int, - pub gl_pathv: *mut *mut c_char, + pub gl_pathv: *mut *mut c_char, pub __unused3: *mut c_void, @@ -823,13 +884,15 @@ pub mod types { } #[repr(C)] - #[derive(Copy, Clone)] pub struct timeval { + #[derive(Copy, Clone)] + pub struct timeval { pub tv_sec: time_t, pub tv_usec: suseconds_t, } #[repr(C)] - #[derive(Copy, Clone)] pub struct timespec { + #[derive(Copy, Clone)] + pub struct timespec { pub tv_sec: time_t, pub tv_nsec: c_long, } @@ -867,12 +930,12 @@ pub mod types { pub ru_msgrcv: c_long, pub ru_nsignals: c_long, pub ru_nvcsw: c_long, - pub ru_nivcsw: c_long + pub ru_nivcsw: c_long, } } pub mod bsd44 { - use types::common::c95::{c_void}; + use types::common::c95::c_void; use types::os::arch::c95::{c_char, c_int, c_uint}; pub type socklen_t = u32; @@ -880,13 +943,15 @@ pub mod types { pub type in_port_t = u16; pub type in_addr_t = u32; #[repr(C)] - #[derive(Copy, Clone)] pub struct sockaddr { + #[derive(Copy, Clone)] + pub struct sockaddr { pub sa_len: u8, pub sa_family: sa_family_t, pub sa_data: [u8; 14], } #[repr(C)] - #[derive(Copy)] pub struct sockaddr_storage { + #[derive(Copy)] + pub struct sockaddr_storage { pub ss_len: u8, pub ss_family: sa_family_t, pub __ss_pad1: [u8; 6], @@ -894,10 +959,13 @@ pub mod types { pub __ss_pad2: [u8; 112], } impl ::core::clone::Clone for sockaddr_storage { - fn clone(&self) -> sockaddr_storage { *self } + fn clone(&self) -> sockaddr_storage { + *self + } } #[repr(C)] - #[derive(Copy, Clone)] pub struct sockaddr_in { + #[derive(Copy, Clone)] + pub struct sockaddr_in { pub sin_len: u8, pub sin_family: sa_family_t, pub sin_port: in_port_t, @@ -905,11 +973,13 @@ pub mod types { pub sin_zero: [u8; 8], } #[repr(C)] - #[derive(Copy, Clone)] pub struct in_addr { + #[derive(Copy, Clone)] + pub struct in_addr { pub s_addr: in_addr_t, } #[repr(C)] - #[derive(Copy, Clone)] pub struct sockaddr_in6 { + #[derive(Copy, Clone)] + pub struct sockaddr_in6 { pub sin6_len: u8, pub sin6_family: sa_family_t, pub sin6_port: in_port_t, @@ -918,21 +988,25 @@ pub mod types { pub sin6_scope_id: u32, } #[repr(C)] - #[derive(Copy, Clone)] pub struct in6_addr { - pub s6_addr: [u16; 8] + #[derive(Copy, Clone)] + pub struct in6_addr { + pub s6_addr: [u16; 8], } #[repr(C)] - #[derive(Copy, Clone)] pub struct ip_mreq { + #[derive(Copy, Clone)] + pub struct ip_mreq { pub imr_multiaddr: in_addr, pub imr_interface: in_addr, } #[repr(C)] - #[derive(Copy, Clone)] pub struct ip6_mreq { + #[derive(Copy, Clone)] + pub struct ip6_mreq { pub ipv6mr_multiaddr: in6_addr, pub ipv6mr_interface: c_uint, } #[repr(C)] - #[derive(Copy, Clone)] pub struct addrinfo { + #[derive(Copy, Clone)] + pub struct addrinfo { pub ai_flags: c_int, pub ai_family: c_int, pub ai_socktype: c_int, @@ -943,23 +1017,27 @@ pub mod types { pub ai_next: *mut addrinfo, } #[repr(C)] - #[derive(Copy)] pub struct sockaddr_un { + #[derive(Copy)] + pub struct sockaddr_un { pub sun_len: u8, pub sun_family: sa_family_t, - pub sun_path: [c_char; 104] + pub sun_path: [c_char; 104], } impl ::core::clone::Clone for sockaddr_un { - fn clone(&self) -> sockaddr_un { *self } + fn clone(&self) -> sockaddr_un { + *self + } } #[repr(C)] - #[derive(Copy, Clone)] pub struct ifaddrs { + #[derive(Copy, Clone)] + pub struct ifaddrs { pub ifa_next: *mut ifaddrs, pub ifa_name: *mut c_char, pub ifa_flags: c_uint, pub ifa_addr: *mut sockaddr, pub ifa_netmask: *mut sockaddr, pub ifa_dstaddr: *mut sockaddr, - pub ifa_data: *mut c_void + pub ifa_data: *mut c_void, } @@ -1007,19 +1085,20 @@ pub mod types { pub type ssize_t = i32; } pub mod posix01 { - use types::common::c95::{c_void}; + use types::common::c95::c_void; use types::common::c99::{uint32_t, int32_t}; use types::os::arch::c95::{c_long, time_t}; use types::os::arch::posix88::{dev_t, gid_t, ino_t}; use types::os::arch::posix88::{mode_t, off_t}; - use types::os::arch::posix88::{uid_t}; + use types::os::arch::posix88::uid_t; pub type nlink_t = u16; pub type blksize_t = u32; pub type blkcnt_t = i64; pub type fflags_t = u32; #[repr(C)] - #[derive(Copy, Clone)] pub struct stat { + #[derive(Copy, Clone)] + pub struct stat { pub st_dev: dev_t, pub st_ino: ino_t, pub st_mode: mode_t, @@ -1045,7 +1124,8 @@ pub mod types { } #[repr(C)] - #[derive(Copy, Clone)] pub struct utimbuf { + #[derive(Copy, Clone)] + pub struct utimbuf { pub actime: time_t, pub modtime: time_t, } @@ -1101,19 +1181,20 @@ pub mod types { pub type ssize_t = i64; } pub mod posix01 { - use types::common::c95::{c_void}; + use types::common::c95::c_void; use types::common::c99::{uint32_t, int32_t}; use types::os::arch::c95::{c_long, time_t}; use types::os::arch::posix88::{dev_t, gid_t, ino_t}; use types::os::arch::posix88::{mode_t, off_t}; - use types::os::arch::posix88::{uid_t}; + use types::os::arch::posix88::uid_t; pub type nlink_t = u16; pub type blksize_t = u32; pub type blkcnt_t = i64; pub type fflags_t = u32; #[repr(C)] - #[derive(Copy, Clone)] pub struct stat { + #[derive(Copy, Clone)] + pub struct stat { pub st_dev: dev_t, pub st_ino: ino_t, pub st_mode: mode_t, @@ -1138,7 +1219,8 @@ pub mod types { } #[repr(C)] - #[derive(Copy, Clone)] pub struct utimbuf { + #[derive(Copy, Clone)] + pub struct utimbuf { pub actime: time_t, pub modtime: time_t, } @@ -1158,21 +1240,21 @@ pub mod types { pub mod os { pub mod common { pub mod posix01 { - use types::common::c95::{c_void}; - use types::os::arch::c95::{c_char, c_int, size_t, - time_t, suseconds_t, c_long}; - use types::os::arch::c99::{uintptr_t}; + use types::common::c95::c_void; + use types::os::arch::c95::{c_char, c_int, size_t, time_t, suseconds_t, c_long}; + use types::os::arch::c99::uintptr_t; pub type pthread_t = uintptr_t; pub type rlim_t = i64; #[repr(C)] - #[derive(Copy, Clone)] pub struct glob_t { - pub gl_pathc: size_t, + #[derive(Copy, Clone)] + pub struct glob_t { + pub gl_pathc: size_t, pub __unused1: size_t, - pub gl_offs: size_t, + pub gl_offs: size_t, pub __unused2: c_int, - pub gl_pathv: *mut *mut c_char, + pub gl_pathv: *mut *mut c_char, pub __unused3: *mut c_void, @@ -1184,13 +1266,15 @@ pub mod types { } #[repr(C)] - #[derive(Copy, Clone)] pub struct timeval { + #[derive(Copy, Clone)] + pub struct timeval { pub tv_sec: time_t, pub tv_usec: suseconds_t, } #[repr(C)] - #[derive(Copy, Clone)] pub struct timespec { + #[derive(Copy, Clone)] + pub struct timespec { pub tv_sec: time_t, pub tv_nsec: c_long, } @@ -1228,12 +1312,12 @@ pub mod types { pub ru_msgrcv: c_long, pub ru_nsignals: c_long, pub ru_nvcsw: c_long, - pub ru_nivcsw: c_long + pub ru_nivcsw: c_long, } } pub mod bsd44 { - use types::common::c95::{c_void}; + use types::common::c95::c_void; use types::os::arch::c95::{c_char, c_int, c_uint}; pub type socklen_t = u32; @@ -1241,13 +1325,15 @@ pub mod types { pub type in_port_t = u16; pub type in_addr_t = u32; #[repr(C)] - #[derive(Copy, Clone)] pub struct sockaddr { + #[derive(Copy, Clone)] + pub struct sockaddr { pub sa_len: u8, pub sa_family: sa_family_t, pub sa_data: [u8; 14], } #[repr(C)] - #[derive(Copy)] pub struct sockaddr_storage { + #[derive(Copy)] + pub struct sockaddr_storage { pub ss_len: u8, pub ss_family: sa_family_t, pub __ss_pad1: [u8; 6], @@ -1255,10 +1341,13 @@ pub mod types { pub __ss_pad2: [u8; 112], } impl ::core::clone::Clone for sockaddr_storage { - fn clone(&self) -> sockaddr_storage { *self } + fn clone(&self) -> sockaddr_storage { + *self + } } #[repr(C)] - #[derive(Copy, Clone)] pub struct sockaddr_in { + #[derive(Copy, Clone)] + pub struct sockaddr_in { pub sin_len: u8, pub sin_family: sa_family_t, pub sin_port: in_port_t, @@ -1266,11 +1355,13 @@ pub mod types { pub sin_zero: [u8; 8], } #[repr(C)] - #[derive(Copy, Clone)] pub struct in_addr { + #[derive(Copy, Clone)] + pub struct in_addr { pub s_addr: in_addr_t, } #[repr(C)] - #[derive(Copy, Clone)] pub struct sockaddr_in6 { + #[derive(Copy, Clone)] + pub struct sockaddr_in6 { pub sin6_len: u8, pub sin6_family: sa_family_t, pub sin6_port: in_port_t, @@ -1279,21 +1370,25 @@ pub mod types { pub sin6_scope_id: u32, } #[repr(C)] - #[derive(Copy, Clone)] pub struct in6_addr { - pub s6_addr: [u16; 8] + #[derive(Copy, Clone)] + pub struct in6_addr { + pub s6_addr: [u16; 8], } #[repr(C)] - #[derive(Copy, Clone)] pub struct ip_mreq { + #[derive(Copy, Clone)] + pub struct ip_mreq { pub imr_multiaddr: in_addr, pub imr_interface: in_addr, } #[repr(C)] - #[derive(Copy, Clone)] pub struct ip6_mreq { + #[derive(Copy, Clone)] + pub struct ip6_mreq { pub ipv6mr_multiaddr: in6_addr, pub ipv6mr_interface: c_uint, } #[repr(C)] - #[derive(Copy, Clone)] pub struct addrinfo { + #[derive(Copy, Clone)] + pub struct addrinfo { pub ai_flags: c_int, pub ai_family: c_int, pub ai_socktype: c_int, @@ -1304,23 +1399,27 @@ pub mod types { pub ai_next: *mut addrinfo, } #[repr(C)] - #[derive(Copy)] pub struct sockaddr_un { + #[derive(Copy)] + pub struct sockaddr_un { pub sun_len: u8, pub sun_family: sa_family_t, - pub sun_path: [c_char; 104] + pub sun_path: [c_char; 104], } impl ::core::clone::Clone for sockaddr_un { - fn clone(&self) -> sockaddr_un { *self } + fn clone(&self) -> sockaddr_un { + *self + } } #[repr(C)] - #[derive(Copy, Clone)] pub struct ifaddrs { + #[derive(Copy, Clone)] + pub struct ifaddrs { pub ifa_next: *mut ifaddrs, pub ifa_name: *mut c_char, pub ifa_flags: c_uint, pub ifa_addr: *mut sockaddr, pub ifa_netmask: *mut sockaddr, pub ifa_dstaddr: *mut sockaddr, - pub ifa_data: *mut c_void + pub ifa_data: *mut c_void, } } @@ -1366,12 +1465,12 @@ pub mod types { pub type ssize_t = i64; } pub mod posix01 { - use types::common::c95::{c_void}; + use types::common::c95::c_void; use types::common::c99::{uint16_t, uint32_t, int32_t, uint64_t, int64_t}; use types::os::arch::c95::{c_long, time_t}; use types::os::arch::posix88::{dev_t, gid_t}; use types::os::arch::posix88::{mode_t, off_t}; - use types::os::arch::posix88::{uid_t}; + use types::os::arch::posix88::uid_t; pub type nlink_t = u16; pub type blksize_t = uint32_t; @@ -1380,7 +1479,8 @@ pub mod types { pub type fflags_t = u32; #[repr(C)] - #[derive(Copy, Clone)] pub struct stat { + #[derive(Copy, Clone)] + pub struct stat { pub st_ino: ino_t, pub st_nlink: nlink_t, pub st_dev: dev_t, @@ -1405,7 +1505,8 @@ pub mod types { pub st_qspare2: int64_t, } #[repr(C)] - #[derive(Copy, Clone)] pub struct utimbuf { + #[derive(Copy, Clone)] + pub struct utimbuf { pub actime: time_t, pub modtime: time_t, } @@ -1425,22 +1526,22 @@ pub mod types { pub mod os { pub mod common { pub mod posix01 { - use types::common::c95::{c_void}; - use types::os::arch::c95::{c_char, c_int, size_t, - time_t, suseconds_t, c_long}; - use types::os::arch::c99::{uintptr_t}; + use types::common::c95::c_void; + use types::os::arch::c95::{c_char, c_int, size_t, time_t, suseconds_t, c_long}; + use types::os::arch::c99::uintptr_t; pub type pthread_t = uintptr_t; pub type rlim_t = u64; #[cfg(target_os = "bitrig")] #[repr(C)] - #[derive(Copy, Clone)] pub struct glob_t { - pub gl_pathc: c_int, + #[derive(Copy, Clone)] + pub struct glob_t { + pub gl_pathc: c_int, pub gl_matchc: c_int, - pub gl_offs: c_int, - pub gl_flags: c_int, - pub gl_pathv: *mut *mut c_char, + pub gl_offs: c_int, + pub gl_flags: c_int, + pub gl_pathv: *mut *mut c_char, pub __unused1: *mut c_void, pub __unused2: *mut c_void, pub __unused3: *mut c_void, @@ -1450,14 +1551,32 @@ pub mod types { pub __unused7: *mut c_void, } - #[cfg(any(target_os = "netbsd", target_os="openbsd"))] + #[cfg(target_os = "netbsd")] + #[repr(C)] + #[derive(Copy, Clone)] + pub struct glob_t { + pub gl_pathc: size_t, + pub gl_matchc: size_t, + pub gl_offs: size_t, + pub gl_flags: c_int, + pub gl_pathv: *mut *mut c_char, + pub __unused1: *mut c_void, + pub __unused2: *mut c_void, + pub __unused3: *mut c_void, + pub __unused4: *mut c_void, + pub __unused5: *mut c_void, + pub __unused6: *mut c_void, + } + + #[cfg(target_os = "openbsd")] #[repr(C)] - #[derive(Copy, Clone)] pub struct glob_t { - pub gl_pathc: c_int, + #[derive(Copy, Clone)] + pub struct glob_t { + pub gl_pathc: c_int, pub __unused1: c_int, - pub gl_offs: c_int, + pub gl_offs: c_int, pub __unused2: c_int, - pub gl_pathv: *mut *mut c_char, + pub gl_pathv: *mut *mut c_char, pub __unused3: *mut c_void, @@ -1470,13 +1589,15 @@ pub mod types { } #[repr(C)] - #[derive(Copy, Clone)] pub struct timeval { + #[derive(Copy, Clone)] + pub struct timeval { pub tv_sec: time_t, pub tv_usec: suseconds_t, } #[repr(C)] - #[derive(Copy, Clone)] pub struct timespec { + #[derive(Copy, Clone)] + pub struct timespec { pub tv_sec: time_t, pub tv_nsec: c_long, } @@ -1514,12 +1635,12 @@ pub mod types { pub ru_msgrcv: c_long, pub ru_nsignals: c_long, pub ru_nvcsw: c_long, - pub ru_nivcsw: c_long + pub ru_nivcsw: c_long, } } pub mod bsd44 { - use types::common::c95::{c_void}; + use types::common::c95::c_void; use types::os::arch::c95::{c_char, c_int, c_uint}; pub type socklen_t = u32; @@ -1527,13 +1648,15 @@ pub mod types { pub type in_port_t = u16; pub type in_addr_t = u32; #[repr(C)] - #[derive(Copy, Clone)] pub struct sockaddr { + #[derive(Copy, Clone)] + pub struct sockaddr { pub sa_len: u8, pub sa_family: sa_family_t, pub sa_data: [u8; 14], } #[repr(C)] - #[derive(Copy)] pub struct sockaddr_storage { + #[derive(Copy)] + pub struct sockaddr_storage { pub ss_len: u8, pub ss_family: sa_family_t, pub __ss_pad1: [u8; 6], @@ -1541,10 +1664,13 @@ pub mod types { pub __ss_pad3: [u8; 240], } impl ::core::clone::Clone for sockaddr_storage { - fn clone(&self) -> sockaddr_storage { *self } + fn clone(&self) -> sockaddr_storage { + *self + } } #[repr(C)] - #[derive(Copy, Clone)] pub struct sockaddr_in { + #[derive(Copy, Clone)] + pub struct sockaddr_in { pub sin_len: u8, pub sin_family: sa_family_t, pub sin_port: in_port_t, @@ -1552,11 +1678,13 @@ pub mod types { pub sin_zero: [u8; 8], } #[repr(C)] - #[derive(Copy, Clone)] pub struct in_addr { + #[derive(Copy, Clone)] + pub struct in_addr { pub s_addr: in_addr_t, } #[repr(C)] - #[derive(Copy, Clone)] pub struct sockaddr_in6 { + #[derive(Copy, Clone)] + pub struct sockaddr_in6 { pub sin6_len: u8, pub sin6_family: sa_family_t, pub sin6_port: in_port_t, @@ -1565,21 +1693,26 @@ pub mod types { pub sin6_scope_id: u32, } #[repr(C)] - #[derive(Copy, Clone)] pub struct in6_addr { - pub s6_addr: [u16; 8] + #[derive(Copy, Clone)] + pub struct in6_addr { + pub s6_addr: [u16; 8], } #[repr(C)] - #[derive(Copy, Clone)] pub struct ip_mreq { + #[derive(Copy, Clone)] + pub struct ip_mreq { pub imr_multiaddr: in_addr, pub imr_interface: in_addr, } #[repr(C)] - #[derive(Copy, Clone)] pub struct ip6_mreq { + #[derive(Copy, Clone)] + pub struct ip6_mreq { pub ipv6mr_multiaddr: in6_addr, pub ipv6mr_interface: c_uint, } + #[cfg(not(target_os = "netbsd"))] #[repr(C)] - #[derive(Copy, Clone)] pub struct addrinfo { + #[derive(Copy, Clone)] + pub struct addrinfo { pub ai_flags: c_int, pub ai_family: c_int, pub ai_socktype: c_int, @@ -1589,24 +1722,41 @@ pub mod types { pub ai_canonname: *mut c_char, pub ai_next: *mut addrinfo, } + #[cfg(target_os = "netbsd")] + #[repr(C)] + #[derive(Copy, Clone)] + pub struct addrinfo { + pub ai_flags: c_int, + pub ai_family: c_int, + pub ai_socktype: c_int, + pub ai_protocol: c_int, + pub ai_addrlen: socklen_t, + pub ai_canonname: *mut c_char, + pub ai_addr: *mut sockaddr, + pub ai_next: *mut addrinfo, + } #[repr(C)] - #[derive(Copy)] pub struct sockaddr_un { + #[derive(Copy)] + pub struct sockaddr_un { pub sun_len: u8, pub sun_family: sa_family_t, - pub sun_path: [c_char; 104] + pub sun_path: [c_char; 104], } impl ::core::clone::Clone for sockaddr_un { - fn clone(&self) -> sockaddr_un { *self } + fn clone(&self) -> sockaddr_un { + *self + } } #[repr(C)] - #[derive(Copy, Clone)] pub struct ifaddrs { + #[derive(Copy, Clone)] + pub struct ifaddrs { pub ifa_next: *mut ifaddrs, pub ifa_name: *mut c_char, pub ifa_flags: c_uint, pub ifa_addr: *mut sockaddr, pub ifa_netmask: *mut sockaddr, pub ifa_dstaddr: *mut sockaddr, - pub ifa_data: *mut c_void + pub ifa_data: *mut c_void, } } } @@ -1641,7 +1791,7 @@ pub mod types { pub type uintmax_t = u64; } pub mod posix88 { - use types::os::arch::c95::{c_long}; + use types::os::arch::c95::c_long; pub type off_t = i64; pub type dev_t = i32; pub type pid_t = i32; @@ -1652,12 +1802,14 @@ pub mod types { pub type ssize_t = c_long; } pub mod posix01 { - use types::common::c95::{c_void}; + use types::common::c95::c_void; use types::common::c99::{uint32_t, uint64_t}; use types::os::arch::c95::{c_long, time_t}; use types::os::arch::posix88::{dev_t, gid_t}; use types::os::arch::posix88::{mode_t, off_t}; - use types::os::arch::posix88::{uid_t}; + use types::os::arch::posix88::uid_t; + #[cfg(target_os = "netbsd")] + use types::os::arch::c95::{c_int, c_uint}; pub type nlink_t = uint32_t; pub type blksize_t = uint32_t; @@ -1665,8 +1817,10 @@ pub mod types { pub type blkcnt_t = i64; pub type fflags_t = u32; // type not declared, but struct stat have u_int32_t + #[cfg(not(target_os = "netbsd"))] #[repr(C)] - #[derive(Copy, Clone)] pub struct stat { + #[derive(Copy, Clone)] + pub struct stat { pub st_mode: mode_t, pub st_dev: dev_t, pub st_ino: ino_t, @@ -1688,13 +1842,50 @@ pub mod types { pub st_birthtime: time_t, pub st_birthtime_nsec: c_long, } + #[cfg(target_os = "netbsd")] #[repr(C)] - #[derive(Copy, Clone)] pub struct utimbuf { + #[derive(Copy, Clone)] + pub struct stat { + pub st_mode: mode_t, + pub st_dev: dev_t, + pub st_ino: ino_t, + pub st_nlink: nlink_t, + pub st_uid: uid_t, + pub st_gid: gid_t, + pub st_rdev: dev_t, + pub st_atime: time_t, + pub st_atime_nsec: c_long, + pub st_mtime: time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: time_t, + pub st_ctime_nsec: c_long, + pub st_birthtime: time_t, + pub st_birthtime_nsec: c_long, + pub st_size: off_t, + pub st_blocks: blkcnt_t, + pub st_blksize: blksize_t, + pub st_flags: fflags_t, + pub st_gen: uint32_t, + st_spare: [uint32_t; 2], + } + + #[repr(C)] + #[derive(Copy, Clone)] + pub struct utimbuf { pub actime: time_t, pub modtime: time_t, } + #[cfg(not(target_os = "netbsd"))] pub type pthread_attr_t = *mut c_void; + #[cfg(target_os = "netbsd")] + #[repr(C)] + #[derive(Copy, Clone)] + pub struct pthread_attr_t { + pta_magic: c_uint, + pta_flags: c_int, + pta_private: *mut c_void, + } } pub mod posix08 { } @@ -1716,7 +1907,8 @@ pub mod types { // pub Note: this is the struct called stat64 in Windows. Not stat, // nor stati64. #[repr(C)] - #[derive(Copy, Clone)] pub struct stat { + #[derive(Copy, Clone)] + pub struct stat { pub st_dev: dev_t, pub st_ino: ino_t, pub st_mode: u16, @@ -1732,19 +1924,22 @@ pub mod types { // note that this is called utimbuf64 in Windows #[repr(C)] - #[derive(Copy, Clone)] pub struct utimbuf { + #[derive(Copy, Clone)] + pub struct utimbuf { pub actime: time64_t, pub modtime: time64_t, } #[repr(C)] - #[derive(Copy, Clone)] pub struct timeval { + #[derive(Copy, Clone)] + pub struct timeval { pub tv_sec: c_long, pub tv_usec: c_long, } #[repr(C)] - #[derive(Copy, Clone)] pub struct timespec { + #[derive(Copy, Clone)] + pub struct timespec { pub tv_sec: time_t, pub tv_nsec: c_long, } @@ -1762,33 +1957,40 @@ pub mod types { pub type in_port_t = u16; pub type in_addr_t = u32; #[repr(C)] - #[derive(Copy, Clone)] pub struct sockaddr { + #[derive(Copy, Clone)] + pub struct sockaddr { pub sa_family: sa_family_t, pub sa_data: [u8; 14], } #[repr(C)] - #[derive(Copy)] pub struct sockaddr_storage { + #[derive(Copy)] + pub struct sockaddr_storage { pub ss_family: sa_family_t, pub __ss_pad1: [u8; 6], pub __ss_align: i64, pub __ss_pad2: [u8; 112], } impl ::core::clone::Clone for sockaddr_storage { - fn clone(&self) -> sockaddr_storage { *self } + fn clone(&self) -> sockaddr_storage { + *self + } } #[repr(C)] - #[derive(Copy, Clone)] pub struct sockaddr_in { + #[derive(Copy, Clone)] + pub struct sockaddr_in { pub sin_family: sa_family_t, pub sin_port: in_port_t, pub sin_addr: in_addr, pub sin_zero: [u8; 8], } #[repr(C)] - #[derive(Copy, Clone)] pub struct in_addr { + #[derive(Copy, Clone)] + pub struct in_addr { pub s_addr: in_addr_t, } #[repr(C)] - #[derive(Copy, Clone)] pub struct sockaddr_in6 { + #[derive(Copy, Clone)] + pub struct sockaddr_in6 { pub sin6_family: sa_family_t, pub sin6_port: in_port_t, pub sin6_flowinfo: u32, @@ -1796,21 +1998,25 @@ pub mod types { pub sin6_scope_id: u32, } #[repr(C)] - #[derive(Copy, Clone)] pub struct in6_addr { - pub s6_addr: [u16; 8] + #[derive(Copy, Clone)] + pub struct in6_addr { + pub s6_addr: [u16; 8], } #[repr(C)] - #[derive(Copy, Clone)] pub struct ip_mreq { + #[derive(Copy, Clone)] + pub struct ip_mreq { pub imr_multiaddr: in_addr, pub imr_interface: in_addr, } #[repr(C)] - #[derive(Copy, Clone)] pub struct ip6_mreq { + #[derive(Copy, Clone)] + pub struct ip6_mreq { pub ipv6mr_multiaddr: in6_addr, pub ipv6mr_interface: c_uint, } #[repr(C)] - #[derive(Copy, Clone)] pub struct addrinfo { + #[derive(Copy, Clone)] + pub struct addrinfo { pub ai_flags: c_int, pub ai_family: c_int, pub ai_socktype: c_int, @@ -1821,12 +2027,15 @@ pub mod types { pub ai_next: *mut addrinfo, } #[repr(C)] - #[derive(Copy)] pub struct sockaddr_un { + #[derive(Copy)] + pub struct sockaddr_un { pub sun_family: sa_family_t, - pub sun_path: [c_char; 108] + pub sun_path: [c_char; 108], } impl ::core::clone::Clone for sockaddr_un { - fn clone(&self) -> sockaddr_un { *self } + fn clone(&self) -> sockaddr_un { + *self + } } } } @@ -1911,12 +2120,11 @@ pub mod types { pub mod bsd44 { } pub mod extra { - use consts::os::extra::{MAX_PROTOCOL_CHAIN, - WSAPROTOCOL_LEN}; + use consts::os::extra::{MAX_PROTOCOL_CHAIN, WSAPROTOCOL_LEN}; use types::common::c95::c_void; use types::os::arch::c95::{c_char, c_int, c_uint, size_t}; use types::os::arch::c95::{c_long, c_ulong}; - use types::os::arch::c95::{wchar_t}; + use types::os::arch::c95::wchar_t; use types::os::arch::c99::{c_ulonglong, c_longlong, uintptr_t}; pub type BOOL = c_int; @@ -1953,7 +2161,8 @@ pub mod types { pub type LPCH = *mut CHAR; #[repr(C)] - #[derive(Copy, Clone)] pub struct SECURITY_ATTRIBUTES { + #[derive(Copy, Clone)] + pub struct SECURITY_ATTRIBUTES { pub nLength: DWORD, pub lpSecurityDescriptor: LPVOID, pub bInheritHandle: BOOL, @@ -1977,7 +2186,8 @@ pub mod types { pub type int64 = i64; #[repr(C)] - #[derive(Copy, Clone)] pub struct STARTUPINFO { + #[derive(Copy, Clone)] + pub struct STARTUPINFO { pub cb: DWORD, pub lpReserved: LPWSTR, pub lpDesktop: LPWSTR, @@ -2000,7 +2210,8 @@ pub mod types { pub type LPSTARTUPINFO = *mut STARTUPINFO; #[repr(C)] - #[derive(Copy, Clone)] pub struct PROCESS_INFORMATION { + #[derive(Copy, Clone)] + pub struct PROCESS_INFORMATION { pub hProcess: HANDLE, pub hThread: HANDLE, pub dwProcessId: DWORD, @@ -2009,7 +2220,8 @@ pub mod types { pub type LPPROCESS_INFORMATION = *mut PROCESS_INFORMATION; #[repr(C)] - #[derive(Copy, Clone)] pub struct SYSTEM_INFO { + #[derive(Copy, Clone)] + pub struct SYSTEM_INFO { pub wProcessorArchitecture: WORD, pub wReserved: WORD, pub dwPageSize: DWORD, @@ -2025,7 +2237,8 @@ pub mod types { pub type LPSYSTEM_INFO = *mut SYSTEM_INFO; #[repr(C)] - #[derive(Copy, Clone)] pub struct MEMORY_BASIC_INFORMATION { + #[derive(Copy, Clone)] + pub struct MEMORY_BASIC_INFORMATION { pub BaseAddress: LPVOID, pub AllocationBase: LPVOID, pub AllocationProtect: DWORD, @@ -2037,7 +2250,8 @@ pub mod types { pub type LPMEMORY_BASIC_INFORMATION = *mut MEMORY_BASIC_INFORMATION; #[repr(C)] - #[derive(Copy, Clone)] pub struct OVERLAPPED { + #[derive(Copy, Clone)] + pub struct OVERLAPPED { pub Internal: *mut c_ulong, pub InternalHigh: *mut c_ulong, pub Offset: DWORD, @@ -2048,7 +2262,8 @@ pub mod types { pub type LPOVERLAPPED = *mut OVERLAPPED; #[repr(C)] - #[derive(Copy, Clone)] pub struct FILETIME { + #[derive(Copy, Clone)] + pub struct FILETIME { pub dwLowDateTime: DWORD, pub dwHighDateTime: DWORD, } @@ -2056,7 +2271,8 @@ pub mod types { pub type LPFILETIME = *mut FILETIME; #[repr(C)] - #[derive(Copy, Clone)] pub struct GUID { + #[derive(Copy, Clone)] + pub struct GUID { pub Data1: DWORD, pub Data2: WORD, pub Data3: WORD, @@ -2064,7 +2280,8 @@ pub mod types { } #[repr(C)] - #[derive(Copy, Clone)] pub struct WSAPROTOCOLCHAIN { + #[derive(Copy, Clone)] + pub struct WSAPROTOCOLCHAIN { pub ChainLen: c_int, pub ChainEntries: [DWORD; MAX_PROTOCOL_CHAIN as usize], } @@ -2072,7 +2289,8 @@ pub mod types { pub type LPWSAPROTOCOLCHAIN = *mut WSAPROTOCOLCHAIN; #[repr(C)] - #[derive(Copy)] pub struct WSAPROTOCOL_INFO { + #[derive(Copy)] + pub struct WSAPROTOCOL_INFO { pub dwServiceFlags1: DWORD, pub dwServiceFlags2: DWORD, pub dwServiceFlags3: DWORD, @@ -2092,10 +2310,12 @@ pub mod types { pub iSecurityScheme: c_int, pub dwMessageSize: DWORD, pub dwProviderReserved: DWORD, - pub szProtocol: [u8; WSAPROTOCOL_LEN as usize + 1], + pub szProtocol: [u8; (WSAPROTOCOL_LEN as usize) + 1], } impl ::core::clone::Clone for WSAPROTOCOL_INFO { - fn clone(&self) -> WSAPROTOCOL_INFO { *self } + fn clone(&self) -> WSAPROTOCOL_INFO { + *self + } } pub type LPWSAPROTOCOL_INFO = *mut WSAPROTOCOL_INFO; @@ -2103,7 +2323,8 @@ pub mod types { pub type GROUP = c_uint; #[repr(C)] - #[derive(Copy)] pub struct WIN32_FIND_DATAW { + #[derive(Copy)] + pub struct WIN32_FIND_DATAW { pub dwFileAttributes: DWORD, pub ftCreationTime: FILETIME, pub ftLastAccessTime: FILETIME, @@ -2116,7 +2337,9 @@ pub mod types { pub cAlternateFileName: [wchar_t; 14], } impl ::core::clone::Clone for WIN32_FIND_DATAW { - fn clone(&self) -> WIN32_FIND_DATAW { *self } + fn clone(&self) -> WIN32_FIND_DATAW { + *self + } } pub type LPWIN32_FIND_DATAW = *mut WIN32_FIND_DATAW; @@ -2131,18 +2354,19 @@ pub mod types { use types::common::c95::c_void; use types::os::arch::c95::{c_char, c_int, size_t, time_t}; use types::os::arch::c95::{suseconds_t, c_long}; - use types::os::arch::c99::{uintptr_t}; + use types::os::arch::c99::uintptr_t; pub type pthread_t = uintptr_t; pub type rlim_t = u64; #[repr(C)] - #[derive(Copy, Clone)] pub struct glob_t { - pub gl_pathc: size_t, + #[derive(Copy, Clone)] + pub struct glob_t { + pub gl_pathc: size_t, pub __unused1: c_int, - pub gl_offs: size_t, + pub gl_offs: size_t, pub __unused2: c_int, - pub gl_pathv: *mut *mut c_char, + pub gl_pathv: *mut *mut c_char, pub __unused3: *mut c_void, @@ -2154,13 +2378,15 @@ pub mod types { } #[repr(C)] - #[derive(Copy, Clone)] pub struct timeval { + #[derive(Copy, Clone)] + pub struct timeval { pub tv_sec: time_t, pub tv_usec: suseconds_t, } #[repr(C)] - #[derive(Copy, Clone)] pub struct timespec { + #[derive(Copy, Clone)] + pub struct timespec { pub tv_sec: time_t, pub tv_nsec: c_long, } @@ -2198,12 +2424,12 @@ pub mod types { pub ru_msgrcv: c_long, pub ru_nsignals: c_long, pub ru_nvcsw: c_long, - pub ru_nivcsw: c_long + pub ru_nivcsw: c_long, } } pub mod bsd44 { - use types::common::c95::{c_void}; + use types::common::c95::c_void; use types::os::arch::c95::{c_char, c_int, c_uint}; pub type socklen_t = u32; @@ -2211,14 +2437,16 @@ pub mod types { pub type in_port_t = u16; pub type in_addr_t = u32; #[repr(C)] - #[derive(Copy, Clone)] pub struct sockaddr { + #[derive(Copy, Clone)] + pub struct sockaddr { pub sa_len: u8, pub sa_family: sa_family_t, pub sa_data: [u8; 14], } #[repr(C)] - #[derive(Copy)] pub struct sockaddr_storage { + #[derive(Copy)] + pub struct sockaddr_storage { pub ss_len: u8, pub ss_family: sa_family_t, pub __ss_pad1: [u8; 6], @@ -2226,11 +2454,14 @@ pub mod types { pub __ss_pad2: [u8; 112], } impl ::core::clone::Clone for sockaddr_storage { - fn clone(&self) -> sockaddr_storage { *self } + fn clone(&self) -> sockaddr_storage { + *self + } } #[repr(C)] - #[derive(Copy, Clone)] pub struct sockaddr_in { + #[derive(Copy, Clone)] + pub struct sockaddr_in { pub sin_len: u8, pub sin_family: sa_family_t, pub sin_port: in_port_t, @@ -2239,12 +2470,14 @@ pub mod types { } #[repr(C)] - #[derive(Copy, Clone)] pub struct in_addr { + #[derive(Copy, Clone)] + pub struct in_addr { pub s_addr: in_addr_t, } #[repr(C)] - #[derive(Copy, Clone)] pub struct sockaddr_in6 { + #[derive(Copy, Clone)] + pub struct sockaddr_in6 { pub sin6_len: u8, pub sin6_family: sa_family_t, pub sin6_port: in_port_t, @@ -2254,24 +2487,28 @@ pub mod types { } #[repr(C)] - #[derive(Copy, Clone)] pub struct in6_addr { - pub s6_addr: [u16; 8] + #[derive(Copy, Clone)] + pub struct in6_addr { + pub s6_addr: [u16; 8], } #[repr(C)] - #[derive(Copy, Clone)] pub struct ip_mreq { + #[derive(Copy, Clone)] + pub struct ip_mreq { pub imr_multiaddr: in_addr, pub imr_interface: in_addr, } #[repr(C)] - #[derive(Copy, Clone)] pub struct ip6_mreq { + #[derive(Copy, Clone)] + pub struct ip6_mreq { pub ipv6mr_multiaddr: in6_addr, pub ipv6mr_interface: c_uint, } #[repr(C)] - #[derive(Copy, Clone)] pub struct addrinfo { + #[derive(Copy, Clone)] + pub struct addrinfo { pub ai_flags: c_int, pub ai_family: c_int, pub ai_socktype: c_int, @@ -2283,24 +2520,28 @@ pub mod types { } #[repr(C)] - #[derive(Copy)] pub struct sockaddr_un { + #[derive(Copy)] + pub struct sockaddr_un { pub sun_len: u8, pub sun_family: sa_family_t, - pub sun_path: [c_char; 104] + pub sun_path: [c_char; 104], } impl ::core::clone::Clone for sockaddr_un { - fn clone(&self) -> sockaddr_un { *self } + fn clone(&self) -> sockaddr_un { + *self + } } #[repr(C)] - #[derive(Copy, Clone)] pub struct ifaddrs { + #[derive(Copy, Clone)] + pub struct ifaddrs { pub ifa_next: *mut ifaddrs, pub ifa_name: *mut c_char, pub ifa_flags: c_uint, pub ifa_addr: *mut sockaddr, pub ifa_netmask: *mut sockaddr, pub ifa_dstaddr: *mut sockaddr, - pub ifa_data: *mut c_void + pub ifa_data: *mut c_void, } } } @@ -2350,15 +2591,15 @@ pub mod types { pub mod posix01 { use types::common::c99::{int32_t, int64_t, uint32_t}; use types::os::arch::c95::{c_char, c_long, time_t}; - use types::os::arch::posix88::{dev_t, gid_t, ino_t, - mode_t, off_t, uid_t}; + use types::os::arch::posix88::{dev_t, gid_t, ino_t, mode_t, off_t, uid_t}; pub type nlink_t = u16; pub type blksize_t = i32; pub type blkcnt_t = i64; #[repr(C)] - #[derive(Copy, Clone)] pub struct stat { + #[derive(Copy, Clone)] + pub struct stat { pub st_dev: dev_t, pub st_mode: mode_t, pub st_nlink: nlink_t, @@ -2384,18 +2625,22 @@ pub mod types { } #[repr(C)] - #[derive(Copy, Clone)] pub struct utimbuf { + #[derive(Copy, Clone)] + pub struct utimbuf { pub actime: time_t, pub modtime: time_t, } #[repr(C)] - #[derive(Copy)] pub struct pthread_attr_t { + #[derive(Copy)] + pub struct pthread_attr_t { pub __sig: c_long, - pub __opaque: [c_char; 36] + pub __opaque: [c_char; 36], } impl ::core::clone::Clone for pthread_attr_t { - fn clone(&self) -> pthread_attr_t { *self } + fn clone(&self) -> pthread_attr_t { + *self + } } } pub mod posix08 { @@ -2404,7 +2649,8 @@ pub mod types { } pub mod extra { #[repr(C)] - #[derive(Copy, Clone)] pub struct mach_timebase_info { + #[derive(Copy, Clone)] + pub struct mach_timebase_info { pub numer: u32, pub denom: u32, } @@ -2457,7 +2703,7 @@ pub mod types { } pub mod posix01 { use types::common::c99::{int32_t, int64_t}; - use types::common::c99::{uint32_t}; + use types::common::c99::uint32_t; use types::os::arch::c95::{c_char, c_long, time_t}; use types::os::arch::posix88::{dev_t, gid_t, ino_t}; use types::os::arch::posix88::{mode_t, off_t, uid_t}; @@ -2467,7 +2713,8 @@ pub mod types { pub type blkcnt_t = i64; #[repr(C)] - #[derive(Copy, Clone)] pub struct stat { + #[derive(Copy, Clone)] + pub struct stat { pub st_dev: dev_t, pub st_mode: mode_t, pub st_nlink: nlink_t, @@ -2493,18 +2740,22 @@ pub mod types { } #[repr(C)] - #[derive(Copy, Clone)] pub struct utimbuf { + #[derive(Copy, Clone)] + pub struct utimbuf { pub actime: time_t, pub modtime: time_t, } #[repr(C)] - #[derive(Copy)] pub struct pthread_attr_t { + #[derive(Copy)] + pub struct pthread_attr_t { pub __sig: c_long, - pub __opaque: [c_char; 56] + pub __opaque: [c_char; 56], } impl ::core::clone::Clone for pthread_attr_t { - fn clone(&self) -> pthread_attr_t { *self } + fn clone(&self) -> pthread_attr_t { + *self + } } } pub mod posix08 { @@ -2513,7 +2764,8 @@ pub mod types { } pub mod extra { #[repr(C)] - #[derive(Copy, Clone)] pub struct mach_timebase_info { + #[derive(Copy, Clone)] + pub struct mach_timebase_info { pub numer: u32, pub denom: u32, } @@ -2533,21 +2785,21 @@ pub mod consts { pub mod c95 { use types::os::arch::c95::{c_int, c_uint}; - pub const EXIT_FAILURE : c_int = 1; - pub const EXIT_SUCCESS : c_int = 0; - pub const RAND_MAX : c_int = 32767; - pub const EOF : c_int = -1; - pub const SEEK_SET : c_int = 0; - pub const SEEK_CUR : c_int = 1; - pub const SEEK_END : c_int = 2; - pub const _IOFBF : c_int = 0; - pub const _IONBF : c_int = 4; - pub const _IOLBF : c_int = 64; - pub const BUFSIZ : c_uint = 512; - pub const FOPEN_MAX : c_uint = 20; - pub const FILENAME_MAX : c_uint = 260; - pub const L_tmpnam : c_uint = 16; - pub const TMP_MAX : c_uint = 32767; + pub const EXIT_FAILURE: c_int = 1; + pub const EXIT_SUCCESS: c_int = 0; + pub const RAND_MAX: c_int = 32767; + pub const EOF: c_int = -1; + pub const SEEK_SET: c_int = 0; + pub const SEEK_CUR: c_int = 1; + pub const SEEK_END: c_int = 2; + pub const _IOFBF: c_int = 0; + pub const _IONBF: c_int = 4; + pub const _IOLBF: c_int = 64; + pub const BUFSIZ: c_uint = 512; + pub const FOPEN_MAX: c_uint = 20; + pub const FILENAME_MAX: c_uint = 260; + pub const L_tmpnam: c_uint = 16; + pub const TMP_MAX: c_uint = 32767; pub const WSAEINTR: c_int = 10004; pub const WSAEBADF: c_int = 10009; @@ -2608,43 +2860,43 @@ pub mod consts { use types::os::arch::c95::c_int; use types::os::arch::posix88::mode_t; - pub const O_RDONLY : c_int = 0; - pub const O_WRONLY : c_int = 1; - pub const O_RDWR : c_int = 2; - pub const O_APPEND : c_int = 8; - pub const O_CREAT : c_int = 256; - pub const O_EXCL : c_int = 1024; - pub const O_TRUNC : c_int = 512; - pub const S_IFIFO : c_int = 4096; - pub const S_IFCHR : c_int = 8192; - pub const S_IFBLK : c_int = 12288; - pub const S_IFDIR : c_int = 16384; - pub const S_IFREG : c_int = 32768; - pub const S_IFLNK : c_int = 40960; - pub const S_IFSOCK : mode_t = 49152; - pub const S_IFMT : c_int = 61440; - pub const S_IEXEC : c_int = 64; - pub const S_IWRITE : c_int = 128; - pub const S_IREAD : c_int = 256; - pub const S_IRWXU : c_int = 448; - pub const S_IXUSR : c_int = 64; - pub const S_IWUSR : c_int = 128; - pub const S_IRUSR : c_int = 256; - pub const S_IRWXG : mode_t = 56; - pub const S_IXGRP : mode_t = 8; - pub const S_IWGRP : mode_t = 16; - pub const S_IRGRP : mode_t = 32; - pub const S_IRWXO : mode_t = 7; - pub const S_IXOTH : mode_t = 1; - pub const S_IWOTH : mode_t = 2; - pub const S_IROTH : mode_t = 4; - pub const F_OK : c_int = 0; - pub const R_OK : c_int = 4; - pub const W_OK : c_int = 2; - pub const X_OK : c_int = 1; - pub const STDIN_FILENO : c_int = 0; - pub const STDOUT_FILENO : c_int = 1; - pub const STDERR_FILENO : c_int = 2; + pub const O_RDONLY: c_int = 0; + pub const O_WRONLY: c_int = 1; + pub const O_RDWR: c_int = 2; + pub const O_APPEND: c_int = 8; + pub const O_CREAT: c_int = 256; + pub const O_EXCL: c_int = 1024; + pub const O_TRUNC: c_int = 512; + pub const S_IFIFO: c_int = 4096; + pub const S_IFCHR: c_int = 8192; + pub const S_IFBLK: c_int = 12288; + pub const S_IFDIR: c_int = 16384; + pub const S_IFREG: c_int = 32768; + pub const S_IFLNK: c_int = 40960; + pub const S_IFSOCK: mode_t = 49152; + pub const S_IFMT: c_int = 61440; + pub const S_IEXEC: c_int = 64; + pub const S_IWRITE: c_int = 128; + pub const S_IREAD: c_int = 256; + pub const S_IRWXU: c_int = 448; + pub const S_IXUSR: c_int = 64; + pub const S_IWUSR: c_int = 128; + pub const S_IRUSR: c_int = 256; + pub const S_IRWXG: mode_t = 56; + pub const S_IXGRP: mode_t = 8; + pub const S_IWGRP: mode_t = 16; + pub const S_IRGRP: mode_t = 32; + pub const S_IRWXO: mode_t = 7; + pub const S_IXOTH: mode_t = 1; + pub const S_IWOTH: mode_t = 2; + pub const S_IROTH: mode_t = 4; + pub const F_OK: c_int = 0; + pub const R_OK: c_int = 4; + pub const W_OK: c_int = 2; + pub const X_OK: c_int = 1; + pub const STDIN_FILENO: c_int = 0; + pub const STDOUT_FILENO: c_int = 1; + pub const STDERR_FILENO: c_int = 2; } pub mod posix01 { } @@ -2702,121 +2954,121 @@ pub mod consts { use types::os::arch::c95::{c_int, c_long}; use types::os::arch::extra::{WORD, DWORD, BOOL, HANDLE}; - pub const TRUE : BOOL = 1; - pub const FALSE : BOOL = 0; + pub const TRUE: BOOL = 1; + pub const FALSE: BOOL = 0; - pub const O_TEXT : c_int = 16384; - pub const O_BINARY : c_int = 32768; + pub const O_TEXT: c_int = 16384; + pub const O_BINARY: c_int = 32768; pub const O_NOINHERIT: c_int = 128; - pub const ERROR_SUCCESS : c_int = 0; + pub const ERROR_SUCCESS: c_int = 0; pub const ERROR_INVALID_FUNCTION: c_int = 1; pub const ERROR_FILE_NOT_FOUND: c_int = 2; pub const ERROR_ACCESS_DENIED: c_int = 5; - pub const ERROR_INVALID_HANDLE : c_int = 6; + pub const ERROR_INVALID_HANDLE: c_int = 6; pub const ERROR_BROKEN_PIPE: c_int = 109; - pub const ERROR_DISK_FULL : c_int = 112; - pub const ERROR_CALL_NOT_IMPLEMENTED : c_int = 120; - pub const ERROR_INSUFFICIENT_BUFFER : c_int = 122; - pub const ERROR_INVALID_NAME : c_int = 123; - pub const ERROR_ALREADY_EXISTS : c_int = 183; + pub const ERROR_DISK_FULL: c_int = 112; + pub const ERROR_CALL_NOT_IMPLEMENTED: c_int = 120; + pub const ERROR_INSUFFICIENT_BUFFER: c_int = 122; + pub const ERROR_INVALID_NAME: c_int = 123; + pub const ERROR_ALREADY_EXISTS: c_int = 183; pub const ERROR_PIPE_BUSY: c_int = 231; pub const ERROR_NO_DATA: c_int = 232; - pub const ERROR_INVALID_ADDRESS : c_int = 487; + pub const ERROR_INVALID_ADDRESS: c_int = 487; pub const ERROR_PIPE_CONNECTED: c_int = 535; pub const ERROR_NOTHING_TO_TERMINATE: c_int = 758; pub const ERROR_OPERATION_ABORTED: c_int = 995; pub const ERROR_IO_PENDING: c_int = 997; - pub const ERROR_FILE_INVALID : c_int = 1006; + pub const ERROR_FILE_INVALID: c_int = 1006; pub const ERROR_NOT_FOUND: c_int = 1168; pub const INVALID_HANDLE_VALUE: HANDLE = !0 as HANDLE; - pub const DELETE : DWORD = 0x00010000; - pub const READ_CONTROL : DWORD = 0x00020000; - pub const SYNCHRONIZE : DWORD = 0x00100000; - pub const WRITE_DAC : DWORD = 0x00040000; - pub const WRITE_OWNER : DWORD = 0x00080000; - - pub const PROCESS_CREATE_PROCESS : DWORD = 0x0080; - pub const PROCESS_CREATE_THREAD : DWORD = 0x0002; - pub const PROCESS_DUP_HANDLE : DWORD = 0x0040; - pub const PROCESS_QUERY_INFORMATION : DWORD = 0x0400; - pub const PROCESS_QUERY_LIMITED_INFORMATION : DWORD = 0x1000; - pub const PROCESS_SET_INFORMATION : DWORD = 0x0200; - pub const PROCESS_SET_QUOTA : DWORD = 0x0100; - pub const PROCESS_SUSPEND_RESUME : DWORD = 0x0800; - pub const PROCESS_TERMINATE : DWORD = 0x0001; - pub const PROCESS_VM_OPERATION : DWORD = 0x0008; - pub const PROCESS_VM_READ : DWORD = 0x0010; - pub const PROCESS_VM_WRITE : DWORD = 0x0020; - - pub const STARTF_FORCEONFEEDBACK : DWORD = 0x00000040; - pub const STARTF_FORCEOFFFEEDBACK : DWORD = 0x00000080; - pub const STARTF_PREVENTPINNING : DWORD = 0x00002000; - pub const STARTF_RUNFULLSCREEN : DWORD = 0x00000020; - pub const STARTF_TITLEISAPPID : DWORD = 0x00001000; - pub const STARTF_TITLEISLINKNAME : DWORD = 0x00000800; - pub const STARTF_USECOUNTCHARS : DWORD = 0x00000008; - pub const STARTF_USEFILLATTRIBUTE : DWORD = 0x00000010; - pub const STARTF_USEHOTKEY : DWORD = 0x00000200; - pub const STARTF_USEPOSITION : DWORD = 0x00000004; - pub const STARTF_USESHOWWINDOW : DWORD = 0x00000001; - pub const STARTF_USESIZE : DWORD = 0x00000002; - pub const STARTF_USESTDHANDLES : DWORD = 0x00000100; - - pub const WAIT_ABANDONED : DWORD = 0x00000080; - pub const WAIT_OBJECT_0 : DWORD = 0x00000000; - pub const WAIT_TIMEOUT : DWORD = 0x00000102; - pub const WAIT_FAILED : DWORD = !0; - - pub const DUPLICATE_CLOSE_SOURCE : DWORD = 0x00000001; - pub const DUPLICATE_SAME_ACCESS : DWORD = 0x00000002; - - pub const INFINITE : DWORD = !0; - pub const STILL_ACTIVE : DWORD = 259; - - pub const MEM_COMMIT : DWORD = 0x00001000; - pub const MEM_RESERVE : DWORD = 0x00002000; - pub const MEM_DECOMMIT : DWORD = 0x00004000; - pub const MEM_RELEASE : DWORD = 0x00008000; - pub const MEM_RESET : DWORD = 0x00080000; - pub const MEM_RESET_UNDO : DWORD = 0x1000000; - pub const MEM_LARGE_PAGES : DWORD = 0x20000000; - pub const MEM_PHYSICAL : DWORD = 0x00400000; - pub const MEM_TOP_DOWN : DWORD = 0x00100000; - pub const MEM_WRITE_WATCH : DWORD = 0x00200000; - - pub const PAGE_EXECUTE : DWORD = 0x10; - pub const PAGE_EXECUTE_READ : DWORD = 0x20; - pub const PAGE_EXECUTE_READWRITE : DWORD = 0x40; - pub const PAGE_EXECUTE_WRITECOPY : DWORD = 0x80; - pub const PAGE_NOACCESS : DWORD = 0x01; - pub const PAGE_READONLY : DWORD = 0x02; - pub const PAGE_READWRITE : DWORD = 0x04; - pub const PAGE_WRITECOPY : DWORD = 0x08; - pub const PAGE_GUARD : DWORD = 0x100; - pub const PAGE_NOCACHE : DWORD = 0x200; - pub const PAGE_WRITECOMBINE : DWORD = 0x400; - - pub const SEC_COMMIT : DWORD = 0x8000000; - pub const SEC_IMAGE : DWORD = 0x1000000; - pub const SEC_IMAGE_NO_EXECUTE : DWORD = 0x11000000; - pub const SEC_LARGE_PAGES : DWORD = 0x80000000; - pub const SEC_NOCACHE : DWORD = 0x10000000; - pub const SEC_RESERVE : DWORD = 0x4000000; - pub const SEC_WRITECOMBINE : DWORD = 0x40000000; - - pub const FILE_MAP_ALL_ACCESS : DWORD = 0xf001f; - pub const FILE_MAP_READ : DWORD = 0x4; - pub const FILE_MAP_WRITE : DWORD = 0x2; - pub const FILE_MAP_COPY : DWORD = 0x1; - pub const FILE_MAP_EXECUTE : DWORD = 0x20; - - pub const PROCESSOR_ARCHITECTURE_INTEL : WORD = 0; - pub const PROCESSOR_ARCHITECTURE_ARM : WORD = 5; - pub const PROCESSOR_ARCHITECTURE_IA64 : WORD = 6; - pub const PROCESSOR_ARCHITECTURE_AMD64 : WORD = 9; - pub const PROCESSOR_ARCHITECTURE_UNKNOWN : WORD = 0xffff; + pub const DELETE: DWORD = 0x00010000; + pub const READ_CONTROL: DWORD = 0x00020000; + pub const SYNCHRONIZE: DWORD = 0x00100000; + pub const WRITE_DAC: DWORD = 0x00040000; + pub const WRITE_OWNER: DWORD = 0x00080000; + + pub const PROCESS_CREATE_PROCESS: DWORD = 0x0080; + pub const PROCESS_CREATE_THREAD: DWORD = 0x0002; + pub const PROCESS_DUP_HANDLE: DWORD = 0x0040; + pub const PROCESS_QUERY_INFORMATION: DWORD = 0x0400; + pub const PROCESS_QUERY_LIMITED_INFORMATION: DWORD = 0x1000; + pub const PROCESS_SET_INFORMATION: DWORD = 0x0200; + pub const PROCESS_SET_QUOTA: DWORD = 0x0100; + pub const PROCESS_SUSPEND_RESUME: DWORD = 0x0800; + pub const PROCESS_TERMINATE: DWORD = 0x0001; + pub const PROCESS_VM_OPERATION: DWORD = 0x0008; + pub const PROCESS_VM_READ: DWORD = 0x0010; + pub const PROCESS_VM_WRITE: DWORD = 0x0020; + + pub const STARTF_FORCEONFEEDBACK: DWORD = 0x00000040; + pub const STARTF_FORCEOFFFEEDBACK: DWORD = 0x00000080; + pub const STARTF_PREVENTPINNING: DWORD = 0x00002000; + pub const STARTF_RUNFULLSCREEN: DWORD = 0x00000020; + pub const STARTF_TITLEISAPPID: DWORD = 0x00001000; + pub const STARTF_TITLEISLINKNAME: DWORD = 0x00000800; + pub const STARTF_USECOUNTCHARS: DWORD = 0x00000008; + pub const STARTF_USEFILLATTRIBUTE: DWORD = 0x00000010; + pub const STARTF_USEHOTKEY: DWORD = 0x00000200; + pub const STARTF_USEPOSITION: DWORD = 0x00000004; + pub const STARTF_USESHOWWINDOW: DWORD = 0x00000001; + pub const STARTF_USESIZE: DWORD = 0x00000002; + pub const STARTF_USESTDHANDLES: DWORD = 0x00000100; + + pub const WAIT_ABANDONED: DWORD = 0x00000080; + pub const WAIT_OBJECT_0: DWORD = 0x00000000; + pub const WAIT_TIMEOUT: DWORD = 0x00000102; + pub const WAIT_FAILED: DWORD = !0; + + pub const DUPLICATE_CLOSE_SOURCE: DWORD = 0x00000001; + pub const DUPLICATE_SAME_ACCESS: DWORD = 0x00000002; + + pub const INFINITE: DWORD = !0; + pub const STILL_ACTIVE: DWORD = 259; + + pub const MEM_COMMIT: DWORD = 0x00001000; + pub const MEM_RESERVE: DWORD = 0x00002000; + pub const MEM_DECOMMIT: DWORD = 0x00004000; + pub const MEM_RELEASE: DWORD = 0x00008000; + pub const MEM_RESET: DWORD = 0x00080000; + pub const MEM_RESET_UNDO: DWORD = 0x1000000; + pub const MEM_LARGE_PAGES: DWORD = 0x20000000; + pub const MEM_PHYSICAL: DWORD = 0x00400000; + pub const MEM_TOP_DOWN: DWORD = 0x00100000; + pub const MEM_WRITE_WATCH: DWORD = 0x00200000; + + pub const PAGE_EXECUTE: DWORD = 0x10; + pub const PAGE_EXECUTE_READ: DWORD = 0x20; + pub const PAGE_EXECUTE_READWRITE: DWORD = 0x40; + pub const PAGE_EXECUTE_WRITECOPY: DWORD = 0x80; + pub const PAGE_NOACCESS: DWORD = 0x01; + pub const PAGE_READONLY: DWORD = 0x02; + pub const PAGE_READWRITE: DWORD = 0x04; + pub const PAGE_WRITECOPY: DWORD = 0x08; + pub const PAGE_GUARD: DWORD = 0x100; + pub const PAGE_NOCACHE: DWORD = 0x200; + pub const PAGE_WRITECOMBINE: DWORD = 0x400; + + pub const SEC_COMMIT: DWORD = 0x8000000; + pub const SEC_IMAGE: DWORD = 0x1000000; + pub const SEC_IMAGE_NO_EXECUTE: DWORD = 0x11000000; + pub const SEC_LARGE_PAGES: DWORD = 0x80000000; + pub const SEC_NOCACHE: DWORD = 0x10000000; + pub const SEC_RESERVE: DWORD = 0x4000000; + pub const SEC_WRITECOMBINE: DWORD = 0x40000000; + + pub const FILE_MAP_ALL_ACCESS: DWORD = 0xf001f; + pub const FILE_MAP_READ: DWORD = 0x4; + pub const FILE_MAP_WRITE: DWORD = 0x2; + pub const FILE_MAP_COPY: DWORD = 0x1; + pub const FILE_MAP_EXECUTE: DWORD = 0x20; + + pub const PROCESSOR_ARCHITECTURE_INTEL: WORD = 0; + pub const PROCESSOR_ARCHITECTURE_ARM: WORD = 5; + pub const PROCESSOR_ARCHITECTURE_IA64: WORD = 6; + pub const PROCESSOR_ARCHITECTURE_AMD64: WORD = 9; + pub const PROCESSOR_ARCHITECTURE_UNKNOWN: WORD = 0xffff; pub const MOVEFILE_COPY_ALLOWED: DWORD = 2; pub const MOVEFILE_CREATE_HARDLINK: DWORD = 16; @@ -2891,13 +3143,15 @@ pub mod consts { pub const STANDARD_RIGHTS_WRITE: DWORD = 0x20000; pub const FILE_WRITE_EA: DWORD = 0x00000010; pub const FILE_READ_EA: DWORD = 0x00000008; - pub const FILE_GENERIC_READ: DWORD = - STANDARD_RIGHTS_READ | FILE_READ_DATA | - FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE; - pub const FILE_GENERIC_WRITE: DWORD = - STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | - FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | - SYNCHRONIZE; + pub const FILE_GENERIC_READ: DWORD = STANDARD_RIGHTS_READ | FILE_READ_DATA | + FILE_READ_ATTRIBUTES | + FILE_READ_EA | + SYNCHRONIZE; + pub const FILE_GENERIC_WRITE: DWORD = STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | + FILE_WRITE_ATTRIBUTES | + FILE_WRITE_EA | + FILE_APPEND_DATA | + SYNCHRONIZE; pub const FILE_BEGIN: DWORD = 0; pub const FILE_CURRENT: DWORD = 1; @@ -2938,21 +3192,21 @@ pub mod consts { pub mod c95 { use types::os::arch::c95::{c_int, c_uint}; - pub const EXIT_FAILURE : c_int = 1; - pub const EXIT_SUCCESS : c_int = 0; - pub const RAND_MAX : c_int = 2147483647; - pub const EOF : c_int = -1; - pub const SEEK_SET : c_int = 0; - pub const SEEK_CUR : c_int = 1; - pub const SEEK_END : c_int = 2; - pub const _IOFBF : c_int = 0; - pub const _IONBF : c_int = 2; - pub const _IOLBF : c_int = 1; - pub const BUFSIZ : c_uint = 8192; - pub const FOPEN_MAX : c_uint = 16; - pub const FILENAME_MAX : c_uint = 4096; - pub const L_tmpnam : c_uint = 20; - pub const TMP_MAX : c_uint = 238328; + pub const EXIT_FAILURE: c_int = 1; + pub const EXIT_SUCCESS: c_int = 0; + pub const RAND_MAX: c_int = 2147483647; + pub const EOF: c_int = -1; + pub const SEEK_SET: c_int = 0; + pub const SEEK_CUR: c_int = 1; + pub const SEEK_END: c_int = 2; + pub const _IOFBF: c_int = 0; + pub const _IONBF: c_int = 2; + pub const _IOLBF: c_int = 1; + pub const BUFSIZ: c_uint = 8192; + pub const FOPEN_MAX: c_uint = 16; + pub const FILENAME_MAX: c_uint = 4096; + pub const L_tmpnam: c_uint = 20; + pub const TMP_MAX: c_uint = 238328; } pub mod c99 { } @@ -2967,114 +3221,114 @@ pub mod consts { use types::common::c95::c_void; use types::os::arch::posix88::mode_t; - pub const O_RDONLY : c_int = 0; - pub const O_WRONLY : c_int = 1; - pub const O_RDWR : c_int = 2; - pub const O_APPEND : c_int = 1024; - pub const O_CREAT : c_int = 64; - pub const O_EXCL : c_int = 128; - pub const O_NOCTTY : c_int = 256; - pub const O_TRUNC : c_int = 512; - pub const S_IFIFO : mode_t = 4096; - pub const S_IFCHR : mode_t = 8192; - pub const S_IFBLK : mode_t = 24576; - pub const S_IFDIR : mode_t = 16384; - pub const S_IFREG : mode_t = 32768; - pub const S_IFLNK : mode_t = 40960; - pub const S_IFSOCK : mode_t = 49152; - pub const S_IFMT : mode_t = 61440; - pub const S_IEXEC : mode_t = 64; - pub const S_IWRITE : mode_t = 128; - pub const S_IREAD : mode_t = 256; - pub const S_IRWXU : mode_t = 448; - pub const S_IXUSR : mode_t = 64; - pub const S_IWUSR : mode_t = 128; - pub const S_IRUSR : mode_t = 256; - pub const S_IRWXG : mode_t = 56; - pub const S_IXGRP : mode_t = 8; - pub const S_IWGRP : mode_t = 16; - pub const S_IRGRP : mode_t = 32; - pub const S_IRWXO : mode_t = 7; - pub const S_IXOTH : mode_t = 1; - pub const S_IWOTH : mode_t = 2; - pub const S_IROTH : mode_t = 4; - pub const F_OK : c_int = 0; - pub const R_OK : c_int = 4; - pub const W_OK : c_int = 2; - pub const X_OK : c_int = 1; - pub const STDIN_FILENO : c_int = 0; - pub const STDOUT_FILENO : c_int = 1; - pub const STDERR_FILENO : c_int = 2; - pub const F_LOCK : c_int = 1; - pub const F_TEST : c_int = 3; - pub const F_TLOCK : c_int = 2; - pub const F_ULOCK : c_int = 0; - pub const SIGHUP : c_int = 1; - pub const SIGINT : c_int = 2; - pub const SIGQUIT : c_int = 3; - pub const SIGILL : c_int = 4; - pub const SIGABRT : c_int = 6; - pub const SIGFPE : c_int = 8; - pub const SIGKILL : c_int = 9; - pub const SIGSEGV : c_int = 11; - pub const SIGPIPE : c_int = 13; - pub const SIGALRM : c_int = 14; - pub const SIGTERM : c_int = 15; - - pub const PROT_NONE : c_int = 0; - pub const PROT_READ : c_int = 1; - pub const PROT_WRITE : c_int = 2; - pub const PROT_EXEC : c_int = 4; - - pub const MAP_FILE : c_int = 0x0000; - pub const MAP_SHARED : c_int = 0x0001; - pub const MAP_PRIVATE : c_int = 0x0002; - pub const MAP_FIXED : c_int = 0x0010; - pub const MAP_ANON : c_int = 0x0020; - - pub const MAP_FAILED : *mut c_void = !0 as *mut c_void; - - pub const MCL_CURRENT : c_int = 0x0001; - pub const MCL_FUTURE : c_int = 0x0002; - - pub const MS_ASYNC : c_int = 0x0001; - pub const MS_INVALIDATE : c_int = 0x0002; - pub const MS_SYNC : c_int = 0x0004; - - pub const EPERM : c_int = 1; - pub const ENOENT : c_int = 2; - pub const ESRCH : c_int = 3; - pub const EINTR : c_int = 4; - pub const EIO : c_int = 5; - pub const ENXIO : c_int = 6; - pub const E2BIG : c_int = 7; - pub const ENOEXEC : c_int = 8; - pub const EBADF : c_int = 9; - pub const ECHILD : c_int = 10; - pub const EAGAIN : c_int = 11; - pub const ENOMEM : c_int = 12; - pub const EACCES : c_int = 13; - pub const EFAULT : c_int = 14; - pub const ENOTBLK : c_int = 15; - pub const EBUSY : c_int = 16; - pub const EEXIST : c_int = 17; - pub const EXDEV : c_int = 18; - pub const ENODEV : c_int = 19; - pub const ENOTDIR : c_int = 20; - pub const EISDIR : c_int = 21; - pub const EINVAL : c_int = 22; - pub const ENFILE : c_int = 23; - pub const EMFILE : c_int = 24; - pub const ENOTTY : c_int = 25; - pub const ETXTBSY : c_int = 26; - pub const EFBIG : c_int = 27; - pub const ENOSPC : c_int = 28; - pub const ESPIPE : c_int = 29; - pub const EROFS : c_int = 30; - pub const EMLINK : c_int = 31; - pub const EPIPE : c_int = 32; - pub const EDOM : c_int = 33; - pub const ERANGE : c_int = 34; + pub const O_RDONLY: c_int = 0; + pub const O_WRONLY: c_int = 1; + pub const O_RDWR: c_int = 2; + pub const O_APPEND: c_int = 1024; + pub const O_CREAT: c_int = 64; + pub const O_EXCL: c_int = 128; + pub const O_NOCTTY: c_int = 256; + pub const O_TRUNC: c_int = 512; + pub const S_IFIFO: mode_t = 4096; + pub const S_IFCHR: mode_t = 8192; + pub const S_IFBLK: mode_t = 24576; + pub const S_IFDIR: mode_t = 16384; + pub const S_IFREG: mode_t = 32768; + pub const S_IFLNK: mode_t = 40960; + pub const S_IFSOCK: mode_t = 49152; + pub const S_IFMT: mode_t = 61440; + pub const S_IEXEC: mode_t = 64; + pub const S_IWRITE: mode_t = 128; + pub const S_IREAD: mode_t = 256; + pub const S_IRWXU: mode_t = 448; + pub const S_IXUSR: mode_t = 64; + pub const S_IWUSR: mode_t = 128; + pub const S_IRUSR: mode_t = 256; + pub const S_IRWXG: mode_t = 56; + pub const S_IXGRP: mode_t = 8; + pub const S_IWGRP: mode_t = 16; + pub const S_IRGRP: mode_t = 32; + pub const S_IRWXO: mode_t = 7; + pub const S_IXOTH: mode_t = 1; + pub const S_IWOTH: mode_t = 2; + pub const S_IROTH: mode_t = 4; + pub const F_OK: c_int = 0; + pub const R_OK: c_int = 4; + pub const W_OK: c_int = 2; + pub const X_OK: c_int = 1; + pub const STDIN_FILENO: c_int = 0; + pub const STDOUT_FILENO: c_int = 1; + pub const STDERR_FILENO: c_int = 2; + pub const F_LOCK: c_int = 1; + pub const F_TEST: c_int = 3; + pub const F_TLOCK: c_int = 2; + pub const F_ULOCK: c_int = 0; + pub const SIGHUP: c_int = 1; + pub const SIGINT: c_int = 2; + pub const SIGQUIT: c_int = 3; + pub const SIGILL: c_int = 4; + pub const SIGABRT: c_int = 6; + pub const SIGFPE: c_int = 8; + pub const SIGKILL: c_int = 9; + pub const SIGSEGV: c_int = 11; + pub const SIGPIPE: c_int = 13; + pub const SIGALRM: c_int = 14; + pub const SIGTERM: c_int = 15; + + pub const PROT_NONE: c_int = 0; + pub const PROT_READ: c_int = 1; + pub const PROT_WRITE: c_int = 2; + pub const PROT_EXEC: c_int = 4; + + pub const MAP_FILE: c_int = 0x0000; + pub const MAP_SHARED: c_int = 0x0001; + pub const MAP_PRIVATE: c_int = 0x0002; + pub const MAP_FIXED: c_int = 0x0010; + pub const MAP_ANON: c_int = 0x0020; + + pub const MAP_FAILED: *mut c_void = !0 as *mut c_void; + + pub const MCL_CURRENT: c_int = 0x0001; + pub const MCL_FUTURE: c_int = 0x0002; + + pub const MS_ASYNC: c_int = 0x0001; + pub const MS_INVALIDATE: c_int = 0x0002; + pub const MS_SYNC: c_int = 0x0004; + + pub const EPERM: c_int = 1; + pub const ENOENT: c_int = 2; + pub const ESRCH: c_int = 3; + pub const EINTR: c_int = 4; + pub const EIO: c_int = 5; + pub const ENXIO: c_int = 6; + pub const E2BIG: c_int = 7; + pub const ENOEXEC: c_int = 8; + pub const EBADF: c_int = 9; + pub const ECHILD: c_int = 10; + pub const EAGAIN: c_int = 11; + pub const ENOMEM: c_int = 12; + pub const EACCES: c_int = 13; + pub const EFAULT: c_int = 14; + pub const ENOTBLK: c_int = 15; + pub const EBUSY: c_int = 16; + pub const EEXIST: c_int = 17; + pub const EXDEV: c_int = 18; + pub const ENODEV: c_int = 19; + pub const ENOTDIR: c_int = 20; + pub const EISDIR: c_int = 21; + pub const EINVAL: c_int = 22; + pub const ENFILE: c_int = 23; + pub const EMFILE: c_int = 24; + pub const ENOTTY: c_int = 25; + pub const ETXTBSY: c_int = 26; + pub const EFBIG: c_int = 27; + pub const ENOSPC: c_int = 28; + pub const ESPIPE: c_int = 29; + pub const EROFS: c_int = 30; + pub const EMLINK: c_int = 31; + pub const EPIPE: c_int = 32; + pub const EDOM: c_int = 33; + pub const ERANGE: c_int = 34; pub const EDEADLK: c_int = 35; pub const ENAMETOOLONG: c_int = 36; @@ -3190,114 +3444,114 @@ pub mod consts { use types::common::c95::c_void; use types::os::arch::posix88::mode_t; - pub const O_RDONLY : c_int = 0; - pub const O_WRONLY : c_int = 1; - pub const O_RDWR : c_int = 2; - pub const O_APPEND : c_int = 8; - pub const O_CREAT : c_int = 256; - pub const O_EXCL : c_int = 1024; - pub const O_NOCTTY : c_int = 2048; - pub const O_TRUNC : c_int = 512; - pub const S_IFIFO : mode_t = 4096; - pub const S_IFCHR : mode_t = 8192; - pub const S_IFBLK : mode_t = 24576; - pub const S_IFDIR : mode_t = 16384; - pub const S_IFREG : mode_t = 32768; - pub const S_IFLNK : mode_t = 40960; - pub const S_IFSOCK : mode_t = 49152; - pub const S_IFMT : mode_t = 61440; - pub const S_IEXEC : mode_t = 64; - pub const S_IWRITE : mode_t = 128; - pub const S_IREAD : mode_t = 256; - pub const S_IRWXU : mode_t = 448; - pub const S_IXUSR : mode_t = 64; - pub const S_IWUSR : mode_t = 128; - pub const S_IRUSR : mode_t = 256; - pub const S_IRWXG : mode_t = 56; - pub const S_IXGRP : mode_t = 8; - pub const S_IWGRP : mode_t = 16; - pub const S_IRGRP : mode_t = 32; - pub const S_IRWXO : mode_t = 7; - pub const S_IXOTH : mode_t = 1; - pub const S_IWOTH : mode_t = 2; - pub const S_IROTH : mode_t = 4; - pub const F_OK : c_int = 0; - pub const R_OK : c_int = 4; - pub const W_OK : c_int = 2; - pub const X_OK : c_int = 1; - pub const STDIN_FILENO : c_int = 0; - pub const STDOUT_FILENO : c_int = 1; - pub const STDERR_FILENO : c_int = 2; - pub const F_LOCK : c_int = 1; - pub const F_TEST : c_int = 3; - pub const F_TLOCK : c_int = 2; - pub const F_ULOCK : c_int = 0; - pub const SIGHUP : c_int = 1; - pub const SIGINT : c_int = 2; - pub const SIGQUIT : c_int = 3; - pub const SIGILL : c_int = 4; - pub const SIGABRT : c_int = 6; - pub const SIGFPE : c_int = 8; - pub const SIGKILL : c_int = 9; - pub const SIGSEGV : c_int = 11; - pub const SIGPIPE : c_int = 13; - pub const SIGALRM : c_int = 14; - pub const SIGTERM : c_int = 15; - - pub const PROT_NONE : c_int = 0; - pub const PROT_READ : c_int = 1; - pub const PROT_WRITE : c_int = 2; - pub const PROT_EXEC : c_int = 4; - - pub const MAP_FILE : c_int = 0x0000; - pub const MAP_SHARED : c_int = 0x0001; - pub const MAP_PRIVATE : c_int = 0x0002; - pub const MAP_FIXED : c_int = 0x0010; - pub const MAP_ANON : c_int = 0x0800; - - pub const MAP_FAILED : *mut c_void = !0 as *mut c_void; - - pub const MCL_CURRENT : c_int = 0x0001; - pub const MCL_FUTURE : c_int = 0x0002; - - pub const MS_ASYNC : c_int = 0x0001; - pub const MS_INVALIDATE : c_int = 0x0002; - pub const MS_SYNC : c_int = 0x0004; - - pub const EPERM : c_int = 1; - pub const ENOENT : c_int = 2; - pub const ESRCH : c_int = 3; - pub const EINTR : c_int = 4; - pub const EIO : c_int = 5; - pub const ENXIO : c_int = 6; - pub const E2BIG : c_int = 7; - pub const ENOEXEC : c_int = 8; - pub const EBADF : c_int = 9; - pub const ECHILD : c_int = 10; - pub const EAGAIN : c_int = 11; - pub const ENOMEM : c_int = 12; - pub const EACCES : c_int = 13; - pub const EFAULT : c_int = 14; - pub const ENOTBLK : c_int = 15; - pub const EBUSY : c_int = 16; - pub const EEXIST : c_int = 17; - pub const EXDEV : c_int = 18; - pub const ENODEV : c_int = 19; - pub const ENOTDIR : c_int = 20; - pub const EISDIR : c_int = 21; - pub const EINVAL : c_int = 22; - pub const ENFILE : c_int = 23; - pub const EMFILE : c_int = 24; - pub const ENOTTY : c_int = 25; - pub const ETXTBSY : c_int = 26; - pub const EFBIG : c_int = 27; - pub const ENOSPC : c_int = 28; - pub const ESPIPE : c_int = 29; - pub const EROFS : c_int = 30; - pub const EMLINK : c_int = 31; - pub const EPIPE : c_int = 32; - pub const EDOM : c_int = 33; - pub const ERANGE : c_int = 34; + pub const O_RDONLY: c_int = 0; + pub const O_WRONLY: c_int = 1; + pub const O_RDWR: c_int = 2; + pub const O_APPEND: c_int = 8; + pub const O_CREAT: c_int = 256; + pub const O_EXCL: c_int = 1024; + pub const O_NOCTTY: c_int = 2048; + pub const O_TRUNC: c_int = 512; + pub const S_IFIFO: mode_t = 4096; + pub const S_IFCHR: mode_t = 8192; + pub const S_IFBLK: mode_t = 24576; + pub const S_IFDIR: mode_t = 16384; + pub const S_IFREG: mode_t = 32768; + pub const S_IFLNK: mode_t = 40960; + pub const S_IFSOCK: mode_t = 49152; + pub const S_IFMT: mode_t = 61440; + pub const S_IEXEC: mode_t = 64; + pub const S_IWRITE: mode_t = 128; + pub const S_IREAD: mode_t = 256; + pub const S_IRWXU: mode_t = 448; + pub const S_IXUSR: mode_t = 64; + pub const S_IWUSR: mode_t = 128; + pub const S_IRUSR: mode_t = 256; + pub const S_IRWXG: mode_t = 56; + pub const S_IXGRP: mode_t = 8; + pub const S_IWGRP: mode_t = 16; + pub const S_IRGRP: mode_t = 32; + pub const S_IRWXO: mode_t = 7; + pub const S_IXOTH: mode_t = 1; + pub const S_IWOTH: mode_t = 2; + pub const S_IROTH: mode_t = 4; + pub const F_OK: c_int = 0; + pub const R_OK: c_int = 4; + pub const W_OK: c_int = 2; + pub const X_OK: c_int = 1; + pub const STDIN_FILENO: c_int = 0; + pub const STDOUT_FILENO: c_int = 1; + pub const STDERR_FILENO: c_int = 2; + pub const F_LOCK: c_int = 1; + pub const F_TEST: c_int = 3; + pub const F_TLOCK: c_int = 2; + pub const F_ULOCK: c_int = 0; + pub const SIGHUP: c_int = 1; + pub const SIGINT: c_int = 2; + pub const SIGQUIT: c_int = 3; + pub const SIGILL: c_int = 4; + pub const SIGABRT: c_int = 6; + pub const SIGFPE: c_int = 8; + pub const SIGKILL: c_int = 9; + pub const SIGSEGV: c_int = 11; + pub const SIGPIPE: c_int = 13; + pub const SIGALRM: c_int = 14; + pub const SIGTERM: c_int = 15; + + pub const PROT_NONE: c_int = 0; + pub const PROT_READ: c_int = 1; + pub const PROT_WRITE: c_int = 2; + pub const PROT_EXEC: c_int = 4; + + pub const MAP_FILE: c_int = 0x0000; + pub const MAP_SHARED: c_int = 0x0001; + pub const MAP_PRIVATE: c_int = 0x0002; + pub const MAP_FIXED: c_int = 0x0010; + pub const MAP_ANON: c_int = 0x0800; + + pub const MAP_FAILED: *mut c_void = !0 as *mut c_void; + + pub const MCL_CURRENT: c_int = 0x0001; + pub const MCL_FUTURE: c_int = 0x0002; + + pub const MS_ASYNC: c_int = 0x0001; + pub const MS_INVALIDATE: c_int = 0x0002; + pub const MS_SYNC: c_int = 0x0004; + + pub const EPERM: c_int = 1; + pub const ENOENT: c_int = 2; + pub const ESRCH: c_int = 3; + pub const EINTR: c_int = 4; + pub const EIO: c_int = 5; + pub const ENXIO: c_int = 6; + pub const E2BIG: c_int = 7; + pub const ENOEXEC: c_int = 8; + pub const EBADF: c_int = 9; + pub const ECHILD: c_int = 10; + pub const EAGAIN: c_int = 11; + pub const ENOMEM: c_int = 12; + pub const EACCES: c_int = 13; + pub const EFAULT: c_int = 14; + pub const ENOTBLK: c_int = 15; + pub const EBUSY: c_int = 16; + pub const EEXIST: c_int = 17; + pub const EXDEV: c_int = 18; + pub const ENODEV: c_int = 19; + pub const ENOTDIR: c_int = 20; + pub const EISDIR: c_int = 21; + pub const EINVAL: c_int = 22; + pub const ENFILE: c_int = 23; + pub const EMFILE: c_int = 24; + pub const ENOTTY: c_int = 25; + pub const ETXTBSY: c_int = 26; + pub const EFBIG: c_int = 27; + pub const ENOSPC: c_int = 28; + pub const ESPIPE: c_int = 29; + pub const EROFS: c_int = 30; + pub const EMLINK: c_int = 31; + pub const EPIPE: c_int = 32; + pub const EDOM: c_int = 33; + pub const ERANGE: c_int = 34; pub const ENOMSG: c_int = 35; pub const EIDRM: c_int = 36; @@ -3409,63 +3663,63 @@ pub mod consts { use types::os::arch::c95::{c_int, size_t}; use types::os::common::posix01::rlim_t; - pub const F_DUPFD : c_int = 0; - pub const F_GETFD : c_int = 1; - pub const F_SETFD : c_int = 2; - pub const F_GETFL : c_int = 3; - pub const F_SETFL : c_int = 4; + pub const F_DUPFD: c_int = 0; + pub const F_GETFD: c_int = 1; + pub const F_SETFD: c_int = 2; + pub const F_GETFL: c_int = 3; + pub const F_SETFL: c_int = 4; - pub const O_ACCMODE : c_int = 3; + pub const O_ACCMODE: c_int = 3; - pub const SIGTRAP : c_int = 5; + pub const SIGTRAP: c_int = 5; pub const SIG_IGN: size_t = 1; - pub const GLOB_ERR : c_int = 1 << 0; - pub const GLOB_MARK : c_int = 1 << 1; - pub const GLOB_NOSORT : c_int = 1 << 2; - pub const GLOB_DOOFFS : c_int = 1 << 3; - pub const GLOB_NOCHECK : c_int = 1 << 4; - pub const GLOB_APPEND : c_int = 1 << 5; - pub const GLOB_NOESCAPE : c_int = 1 << 6; - - pub const GLOB_NOSPACE : c_int = 1; - pub const GLOB_ABORTED : c_int = 2; - pub const GLOB_NOMATCH : c_int = 3; - - pub const POSIX_MADV_NORMAL : c_int = 0; - pub const POSIX_MADV_RANDOM : c_int = 1; - pub const POSIX_MADV_SEQUENTIAL : c_int = 2; - pub const POSIX_MADV_WILLNEED : c_int = 3; - pub const POSIX_MADV_DONTNEED : c_int = 4; - - pub const _SC_MQ_PRIO_MAX : c_int = 28; - pub const _SC_IOV_MAX : c_int = 60; - pub const _SC_GETGR_R_SIZE_MAX : c_int = 69; - pub const _SC_GETPW_R_SIZE_MAX : c_int = 70; - pub const _SC_LOGIN_NAME_MAX : c_int = 71; - pub const _SC_TTY_NAME_MAX : c_int = 72; - pub const _SC_THREADS : c_int = 67; - pub const _SC_THREAD_SAFE_FUNCTIONS : c_int = 68; - pub const _SC_THREAD_DESTRUCTOR_ITERATIONS : c_int = 73; - pub const _SC_THREAD_KEYS_MAX : c_int = 74; - pub const _SC_THREAD_STACK_MIN : c_int = 75; - pub const _SC_THREAD_THREADS_MAX : c_int = 76; - pub const _SC_THREAD_ATTR_STACKADDR : c_int = 77; - pub const _SC_THREAD_ATTR_STACKSIZE : c_int = 78; - pub const _SC_THREAD_PRIORITY_SCHEDULING : c_int = 79; - pub const _SC_THREAD_PRIO_INHERIT : c_int = 80; - pub const _SC_THREAD_PRIO_PROTECT : c_int = 81; - pub const _SC_THREAD_PROCESS_SHARED : c_int = 82; - pub const _SC_ATEXIT_MAX : c_int = 87; - pub const _SC_XOPEN_VERSION : c_int = 89; - pub const _SC_XOPEN_XCU_VERSION : c_int = 90; - pub const _SC_XOPEN_UNIX : c_int = 91; - pub const _SC_XOPEN_CRYPT : c_int = 92; - pub const _SC_XOPEN_ENH_I18N : c_int = 93; - pub const _SC_XOPEN_SHM : c_int = 94; - pub const _SC_XOPEN_LEGACY : c_int = 129; - pub const _SC_XOPEN_REALTIME : c_int = 130; - pub const _SC_XOPEN_REALTIME_THREADS : c_int = 131; + pub const GLOB_ERR: c_int = 1 << 0; + pub const GLOB_MARK: c_int = 1 << 1; + pub const GLOB_NOSORT: c_int = 1 << 2; + pub const GLOB_DOOFFS: c_int = 1 << 3; + pub const GLOB_NOCHECK: c_int = 1 << 4; + pub const GLOB_APPEND: c_int = 1 << 5; + pub const GLOB_NOESCAPE: c_int = 1 << 6; + + pub const GLOB_NOSPACE: c_int = 1; + pub const GLOB_ABORTED: c_int = 2; + pub const GLOB_NOMATCH: c_int = 3; + + pub const POSIX_MADV_NORMAL: c_int = 0; + pub const POSIX_MADV_RANDOM: c_int = 1; + pub const POSIX_MADV_SEQUENTIAL: c_int = 2; + pub const POSIX_MADV_WILLNEED: c_int = 3; + pub const POSIX_MADV_DONTNEED: c_int = 4; + + pub const _SC_MQ_PRIO_MAX: c_int = 28; + pub const _SC_IOV_MAX: c_int = 60; + pub const _SC_GETGR_R_SIZE_MAX: c_int = 69; + pub const _SC_GETPW_R_SIZE_MAX: c_int = 70; + pub const _SC_LOGIN_NAME_MAX: c_int = 71; + pub const _SC_TTY_NAME_MAX: c_int = 72; + pub const _SC_THREADS: c_int = 67; + pub const _SC_THREAD_SAFE_FUNCTIONS: c_int = 68; + pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: c_int = 73; + pub const _SC_THREAD_KEYS_MAX: c_int = 74; + pub const _SC_THREAD_STACK_MIN: c_int = 75; + pub const _SC_THREAD_THREADS_MAX: c_int = 76; + pub const _SC_THREAD_ATTR_STACKADDR: c_int = 77; + pub const _SC_THREAD_ATTR_STACKSIZE: c_int = 78; + pub const _SC_THREAD_PRIORITY_SCHEDULING: c_int = 79; + pub const _SC_THREAD_PRIO_INHERIT: c_int = 80; + pub const _SC_THREAD_PRIO_PROTECT: c_int = 81; + pub const _SC_THREAD_PROCESS_SHARED: c_int = 82; + pub const _SC_ATEXIT_MAX: c_int = 87; + pub const _SC_XOPEN_VERSION: c_int = 89; + pub const _SC_XOPEN_XCU_VERSION: c_int = 90; + pub const _SC_XOPEN_UNIX: c_int = 91; + pub const _SC_XOPEN_CRYPT: c_int = 92; + pub const _SC_XOPEN_ENH_I18N: c_int = 93; + pub const _SC_XOPEN_SHM: c_int = 94; + pub const _SC_XOPEN_LEGACY: c_int = 129; + pub const _SC_XOPEN_REALTIME: c_int = 130; + pub const _SC_XOPEN_REALTIME_THREADS: c_int = 131; @@ -3521,61 +3775,61 @@ pub mod consts { use types::os::arch::c95::{c_int, size_t}; use types::os::common::posix01::rlim_t; - pub const F_DUPFD : c_int = 0; - pub const F_GETFD : c_int = 1; - pub const F_SETFD : c_int = 2; - pub const F_GETFL : c_int = 3; - pub const F_SETFL : c_int = 4; + pub const F_DUPFD: c_int = 0; + pub const F_GETFD: c_int = 1; + pub const F_SETFD: c_int = 2; + pub const F_GETFL: c_int = 3; + pub const F_SETFL: c_int = 4; - pub const SIGTRAP : c_int = 5; + pub const SIGTRAP: c_int = 5; pub const SIG_IGN: size_t = 1; - pub const GLOB_ERR : c_int = 1 << 0; - pub const GLOB_MARK : c_int = 1 << 1; - pub const GLOB_NOSORT : c_int = 1 << 2; - pub const GLOB_DOOFFS : c_int = 1 << 3; - pub const GLOB_NOCHECK : c_int = 1 << 4; - pub const GLOB_APPEND : c_int = 1 << 5; - pub const GLOB_NOESCAPE : c_int = 1 << 6; - - pub const GLOB_NOSPACE : c_int = 1; - pub const GLOB_ABORTED : c_int = 2; - pub const GLOB_NOMATCH : c_int = 3; - - pub const POSIX_MADV_NORMAL : c_int = 0; - pub const POSIX_MADV_RANDOM : c_int = 1; - pub const POSIX_MADV_SEQUENTIAL : c_int = 2; - pub const POSIX_MADV_WILLNEED : c_int = 3; - pub const POSIX_MADV_DONTNEED : c_int = 4; - - pub const _SC_MQ_PRIO_MAX : c_int = 28; - pub const _SC_IOV_MAX : c_int = 60; - pub const _SC_GETGR_R_SIZE_MAX : c_int = 69; - pub const _SC_GETPW_R_SIZE_MAX : c_int = 70; - pub const _SC_LOGIN_NAME_MAX : c_int = 71; - pub const _SC_TTY_NAME_MAX : c_int = 72; - pub const _SC_THREADS : c_int = 67; - pub const _SC_THREAD_SAFE_FUNCTIONS : c_int = 68; - pub const _SC_THREAD_DESTRUCTOR_ITERATIONS : c_int = 73; - pub const _SC_THREAD_KEYS_MAX : c_int = 74; - pub const _SC_THREAD_STACK_MIN : c_int = 75; - pub const _SC_THREAD_THREADS_MAX : c_int = 76; - pub const _SC_THREAD_ATTR_STACKADDR : c_int = 77; - pub const _SC_THREAD_ATTR_STACKSIZE : c_int = 78; - pub const _SC_THREAD_PRIORITY_SCHEDULING : c_int = 79; - pub const _SC_THREAD_PRIO_INHERIT : c_int = 80; - pub const _SC_THREAD_PRIO_PROTECT : c_int = 81; - pub const _SC_THREAD_PROCESS_SHARED : c_int = 82; - pub const _SC_ATEXIT_MAX : c_int = 87; - pub const _SC_XOPEN_VERSION : c_int = 89; - pub const _SC_XOPEN_XCU_VERSION : c_int = 90; - pub const _SC_XOPEN_UNIX : c_int = 91; - pub const _SC_XOPEN_CRYPT : c_int = 92; - pub const _SC_XOPEN_ENH_I18N : c_int = 93; - pub const _SC_XOPEN_SHM : c_int = 94; - pub const _SC_XOPEN_LEGACY : c_int = 129; - pub const _SC_XOPEN_REALTIME : c_int = 130; - pub const _SC_XOPEN_REALTIME_THREADS : c_int = 131; + pub const GLOB_ERR: c_int = 1 << 0; + pub const GLOB_MARK: c_int = 1 << 1; + pub const GLOB_NOSORT: c_int = 1 << 2; + pub const GLOB_DOOFFS: c_int = 1 << 3; + pub const GLOB_NOCHECK: c_int = 1 << 4; + pub const GLOB_APPEND: c_int = 1 << 5; + pub const GLOB_NOESCAPE: c_int = 1 << 6; + + pub const GLOB_NOSPACE: c_int = 1; + pub const GLOB_ABORTED: c_int = 2; + pub const GLOB_NOMATCH: c_int = 3; + + pub const POSIX_MADV_NORMAL: c_int = 0; + pub const POSIX_MADV_RANDOM: c_int = 1; + pub const POSIX_MADV_SEQUENTIAL: c_int = 2; + pub const POSIX_MADV_WILLNEED: c_int = 3; + pub const POSIX_MADV_DONTNEED: c_int = 4; + + pub const _SC_MQ_PRIO_MAX: c_int = 28; + pub const _SC_IOV_MAX: c_int = 60; + pub const _SC_GETGR_R_SIZE_MAX: c_int = 69; + pub const _SC_GETPW_R_SIZE_MAX: c_int = 70; + pub const _SC_LOGIN_NAME_MAX: c_int = 71; + pub const _SC_TTY_NAME_MAX: c_int = 72; + pub const _SC_THREADS: c_int = 67; + pub const _SC_THREAD_SAFE_FUNCTIONS: c_int = 68; + pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: c_int = 73; + pub const _SC_THREAD_KEYS_MAX: c_int = 74; + pub const _SC_THREAD_STACK_MIN: c_int = 75; + pub const _SC_THREAD_THREADS_MAX: c_int = 76; + pub const _SC_THREAD_ATTR_STACKADDR: c_int = 77; + pub const _SC_THREAD_ATTR_STACKSIZE: c_int = 78; + pub const _SC_THREAD_PRIORITY_SCHEDULING: c_int = 79; + pub const _SC_THREAD_PRIO_INHERIT: c_int = 80; + pub const _SC_THREAD_PRIO_PROTECT: c_int = 81; + pub const _SC_THREAD_PROCESS_SHARED: c_int = 82; + pub const _SC_ATEXIT_MAX: c_int = 87; + pub const _SC_XOPEN_VERSION: c_int = 89; + pub const _SC_XOPEN_XCU_VERSION: c_int = 90; + pub const _SC_XOPEN_UNIX: c_int = 91; + pub const _SC_XOPEN_CRYPT: c_int = 92; + pub const _SC_XOPEN_ENH_I18N: c_int = 93; + pub const _SC_XOPEN_SHM: c_int = 94; + pub const _SC_XOPEN_LEGACY: c_int = 129; + pub const _SC_XOPEN_REALTIME: c_int = 130; + pub const _SC_XOPEN_REALTIME_THREADS: c_int = 131; pub const PTHREAD_CREATE_JOINABLE: c_int = 1; pub const PTHREAD_CREATE_DETACHED: c_int = 0; @@ -3625,17 +3879,17 @@ pub mod consts { pub mod bsd44 { use types::os::arch::c95::c_int; - pub const MADV_NORMAL : c_int = 0; - pub const MADV_RANDOM : c_int = 1; - pub const MADV_SEQUENTIAL : c_int = 2; - pub const MADV_WILLNEED : c_int = 3; - pub const MADV_DONTNEED : c_int = 4; - pub const MADV_REMOVE : c_int = 9; - pub const MADV_DONTFORK : c_int = 10; - pub const MADV_DOFORK : c_int = 11; - pub const MADV_MERGEABLE : c_int = 12; - pub const MADV_UNMERGEABLE : c_int = 13; - pub const MADV_HWPOISON : c_int = 100; + pub const MADV_NORMAL: c_int = 0; + pub const MADV_RANDOM: c_int = 1; + pub const MADV_SEQUENTIAL: c_int = 2; + pub const MADV_WILLNEED: c_int = 3; + pub const MADV_DONTNEED: c_int = 4; + pub const MADV_REMOVE: c_int = 9; + pub const MADV_DONTFORK: c_int = 10; + pub const MADV_DOFORK: c_int = 11; + pub const MADV_MERGEABLE: c_int = 12; + pub const MADV_UNMERGEABLE: c_int = 13; + pub const MADV_HWPOISON: c_int = 100; pub const IFF_LOOPBACK: c_int = 0x8; @@ -3716,17 +3970,17 @@ pub mod consts { pub mod bsd44 { use types::os::arch::c95::c_int; - pub const MADV_NORMAL : c_int = 0; - pub const MADV_RANDOM : c_int = 1; - pub const MADV_SEQUENTIAL : c_int = 2; - pub const MADV_WILLNEED : c_int = 3; - pub const MADV_DONTNEED : c_int = 4; - pub const MADV_REMOVE : c_int = 9; - pub const MADV_DONTFORK : c_int = 10; - pub const MADV_DOFORK : c_int = 11; - pub const MADV_MERGEABLE : c_int = 12; - pub const MADV_UNMERGEABLE : c_int = 13; - pub const MADV_HWPOISON : c_int = 100; + pub const MADV_NORMAL: c_int = 0; + pub const MADV_RANDOM: c_int = 1; + pub const MADV_SEQUENTIAL: c_int = 2; + pub const MADV_WILLNEED: c_int = 3; + pub const MADV_DONTNEED: c_int = 4; + pub const MADV_REMOVE: c_int = 9; + pub const MADV_DONTFORK: c_int = 10; + pub const MADV_DOFORK: c_int = 11; + pub const MADV_MERGEABLE: c_int = 12; + pub const MADV_UNMERGEABLE: c_int = 13; + pub const MADV_HWPOISON: c_int = 100; pub const AF_UNIX: c_int = 1; pub const AF_INET: c_int = 2; @@ -3809,117 +4063,121 @@ pub mod consts { pub mod extra { use types::os::arch::c95::c_int; - pub const AF_PACKET : c_int = 17; - pub const IPPROTO_RAW : c_int = 255; - - pub const O_RSYNC : c_int = 1052672; - pub const O_DSYNC : c_int = 4096; - pub const O_NONBLOCK : c_int = 2048; - pub const O_SYNC : c_int = 1052672; - - pub const PROT_GROWSDOWN : c_int = 0x010000000; - pub const PROT_GROWSUP : c_int = 0x020000000; - - pub const MAP_TYPE : c_int = 0x000f; - pub const MAP_ANONYMOUS : c_int = 0x0020; - pub const MAP_32BIT : c_int = 0x0040; - pub const MAP_GROWSDOWN : c_int = 0x0100; - pub const MAP_DENYWRITE : c_int = 0x0800; - pub const MAP_EXECUTABLE : c_int = 0x01000; - pub const MAP_LOCKED : c_int = 0x02000; - pub const MAP_NORESERVE : c_int = 0x04000; - pub const MAP_POPULATE : c_int = 0x08000; - pub const MAP_NONBLOCK : c_int = 0x010000; - pub const MAP_STACK : c_int = 0x020000; + pub const AF_PACKET: c_int = 17; + pub const IPPROTO_RAW: c_int = 255; + + pub const O_RSYNC: c_int = 1052672; + pub const O_DSYNC: c_int = 4096; + pub const O_NONBLOCK: c_int = 2048; + pub const O_SYNC: c_int = 1052672; + + pub const PROT_GROWSDOWN: c_int = 0x010000000; + pub const PROT_GROWSUP: c_int = 0x020000000; + + pub const MAP_TYPE: c_int = 0x000f; + pub const MAP_ANONYMOUS: c_int = 0x0020; + pub const MAP_32BIT: c_int = 0x0040; + pub const MAP_GROWSDOWN: c_int = 0x0100; + pub const MAP_DENYWRITE: c_int = 0x0800; + pub const MAP_EXECUTABLE: c_int = 0x01000; + pub const MAP_LOCKED: c_int = 0x02000; + pub const MAP_NORESERVE: c_int = 0x04000; + pub const MAP_POPULATE: c_int = 0x08000; + pub const MAP_NONBLOCK: c_int = 0x010000; + pub const MAP_STACK: c_int = 0x020000; + + pub const PATH_MAX: c_int = 4096; } #[cfg(any(target_arch = "mips", target_arch = "mipsel"))] pub mod extra { use types::os::arch::c95::c_int; - pub const AF_PACKET : c_int = 17; - pub const IPPROTO_RAW : c_int = 255; - - pub const O_RSYNC : c_int = 16400; - pub const O_DSYNC : c_int = 16; - pub const O_NONBLOCK : c_int = 128; - pub const O_SYNC : c_int = 16400; - - pub const PROT_GROWSDOWN : c_int = 0x01000000; - pub const PROT_GROWSUP : c_int = 0x02000000; - - pub const MAP_TYPE : c_int = 0x000f; - pub const MAP_ANONYMOUS : c_int = 0x0800; - pub const MAP_GROWSDOWN : c_int = 0x01000; - pub const MAP_DENYWRITE : c_int = 0x02000; - pub const MAP_EXECUTABLE : c_int = 0x04000; - pub const MAP_LOCKED : c_int = 0x08000; - pub const MAP_NORESERVE : c_int = 0x0400; - pub const MAP_POPULATE : c_int = 0x010000; - pub const MAP_NONBLOCK : c_int = 0x020000; - pub const MAP_STACK : c_int = 0x040000; + pub const AF_PACKET: c_int = 17; + pub const IPPROTO_RAW: c_int = 255; + + pub const O_RSYNC: c_int = 16400; + pub const O_DSYNC: c_int = 16; + pub const O_NONBLOCK: c_int = 128; + pub const O_SYNC: c_int = 16400; + + pub const PROT_GROWSDOWN: c_int = 0x01000000; + pub const PROT_GROWSUP: c_int = 0x02000000; + + pub const MAP_TYPE: c_int = 0x000f; + pub const MAP_ANONYMOUS: c_int = 0x0800; + pub const MAP_GROWSDOWN: c_int = 0x01000; + pub const MAP_DENYWRITE: c_int = 0x02000; + pub const MAP_EXECUTABLE: c_int = 0x04000; + pub const MAP_LOCKED: c_int = 0x08000; + pub const MAP_NORESERVE: c_int = 0x0400; + pub const MAP_POPULATE: c_int = 0x010000; + pub const MAP_NONBLOCK: c_int = 0x020000; + pub const MAP_STACK: c_int = 0x040000; + + pub const PATH_MAX: c_int = 4096; } #[cfg(target_os = "linux")] pub mod sysconf { use types::os::arch::c95::c_int; - pub const _SC_ARG_MAX : c_int = 0; - pub const _SC_CHILD_MAX : c_int = 1; - pub const _SC_CLK_TCK : c_int = 2; - pub const _SC_NGROUPS_MAX : c_int = 3; - pub const _SC_OPEN_MAX : c_int = 4; - pub const _SC_STREAM_MAX : c_int = 5; - pub const _SC_TZNAME_MAX : c_int = 6; - pub const _SC_JOB_CONTROL : c_int = 7; - pub const _SC_SAVED_IDS : c_int = 8; - pub const _SC_REALTIME_SIGNALS : c_int = 9; - pub const _SC_PRIORITY_SCHEDULING : c_int = 10; - pub const _SC_TIMERS : c_int = 11; - pub const _SC_ASYNCHRONOUS_IO : c_int = 12; - pub const _SC_PRIORITIZED_IO : c_int = 13; - pub const _SC_SYNCHRONIZED_IO : c_int = 14; - pub const _SC_FSYNC : c_int = 15; - pub const _SC_MAPPED_FILES : c_int = 16; - pub const _SC_MEMLOCK : c_int = 17; - pub const _SC_MEMLOCK_RANGE : c_int = 18; - pub const _SC_MEMORY_PROTECTION : c_int = 19; - pub const _SC_MESSAGE_PASSING : c_int = 20; - pub const _SC_SEMAPHORES : c_int = 21; - pub const _SC_SHARED_MEMORY_OBJECTS : c_int = 22; - pub const _SC_AIO_LISTIO_MAX : c_int = 23; - pub const _SC_AIO_MAX : c_int = 24; - pub const _SC_AIO_PRIO_DELTA_MAX : c_int = 25; - pub const _SC_DELAYTIMER_MAX : c_int = 26; - pub const _SC_MQ_OPEN_MAX : c_int = 27; - pub const _SC_VERSION : c_int = 29; - pub const _SC_PAGESIZE : c_int = 30; - pub const _SC_RTSIG_MAX : c_int = 31; - pub const _SC_SEM_NSEMS_MAX : c_int = 32; - pub const _SC_SEM_VALUE_MAX : c_int = 33; - pub const _SC_SIGQUEUE_MAX : c_int = 34; - pub const _SC_TIMER_MAX : c_int = 35; - pub const _SC_BC_BASE_MAX : c_int = 36; - pub const _SC_BC_DIM_MAX : c_int = 37; - pub const _SC_BC_SCALE_MAX : c_int = 38; - pub const _SC_BC_STRING_MAX : c_int = 39; - pub const _SC_COLL_WEIGHTS_MAX : c_int = 40; - pub const _SC_EXPR_NEST_MAX : c_int = 42; - pub const _SC_LINE_MAX : c_int = 43; - pub const _SC_RE_DUP_MAX : c_int = 44; - pub const _SC_2_VERSION : c_int = 46; - pub const _SC_2_C_BIND : c_int = 47; - pub const _SC_2_C_DEV : c_int = 48; - pub const _SC_2_FORT_DEV : c_int = 49; - pub const _SC_2_FORT_RUN : c_int = 50; - pub const _SC_2_SW_DEV : c_int = 51; - pub const _SC_2_LOCALEDEF : c_int = 52; - pub const _SC_NPROCESSORS_ONLN : c_int = 84; - pub const _SC_2_CHAR_TERM : c_int = 95; - pub const _SC_2_C_VERSION : c_int = 96; - pub const _SC_2_UPE : c_int = 97; - pub const _SC_XBS5_ILP32_OFF32 : c_int = 125; - pub const _SC_XBS5_ILP32_OFFBIG : c_int = 126; - pub const _SC_XBS5_LPBIG_OFFBIG : c_int = 128; + pub const _SC_ARG_MAX: c_int = 0; + pub const _SC_CHILD_MAX: c_int = 1; + pub const _SC_CLK_TCK: c_int = 2; + pub const _SC_NGROUPS_MAX: c_int = 3; + pub const _SC_OPEN_MAX: c_int = 4; + pub const _SC_STREAM_MAX: c_int = 5; + pub const _SC_TZNAME_MAX: c_int = 6; + pub const _SC_JOB_CONTROL: c_int = 7; + pub const _SC_SAVED_IDS: c_int = 8; + pub const _SC_REALTIME_SIGNALS: c_int = 9; + pub const _SC_PRIORITY_SCHEDULING: c_int = 10; + pub const _SC_TIMERS: c_int = 11; + pub const _SC_ASYNCHRONOUS_IO: c_int = 12; + pub const _SC_PRIORITIZED_IO: c_int = 13; + pub const _SC_SYNCHRONIZED_IO: c_int = 14; + pub const _SC_FSYNC: c_int = 15; + pub const _SC_MAPPED_FILES: c_int = 16; + pub const _SC_MEMLOCK: c_int = 17; + pub const _SC_MEMLOCK_RANGE: c_int = 18; + pub const _SC_MEMORY_PROTECTION: c_int = 19; + pub const _SC_MESSAGE_PASSING: c_int = 20; + pub const _SC_SEMAPHORES: c_int = 21; + pub const _SC_SHARED_MEMORY_OBJECTS: c_int = 22; + pub const _SC_AIO_LISTIO_MAX: c_int = 23; + pub const _SC_AIO_MAX: c_int = 24; + pub const _SC_AIO_PRIO_DELTA_MAX: c_int = 25; + pub const _SC_DELAYTIMER_MAX: c_int = 26; + pub const _SC_MQ_OPEN_MAX: c_int = 27; + pub const _SC_VERSION: c_int = 29; + pub const _SC_PAGESIZE: c_int = 30; + pub const _SC_RTSIG_MAX: c_int = 31; + pub const _SC_SEM_NSEMS_MAX: c_int = 32; + pub const _SC_SEM_VALUE_MAX: c_int = 33; + pub const _SC_SIGQUEUE_MAX: c_int = 34; + pub const _SC_TIMER_MAX: c_int = 35; + pub const _SC_BC_BASE_MAX: c_int = 36; + pub const _SC_BC_DIM_MAX: c_int = 37; + pub const _SC_BC_SCALE_MAX: c_int = 38; + pub const _SC_BC_STRING_MAX: c_int = 39; + pub const _SC_COLL_WEIGHTS_MAX: c_int = 40; + pub const _SC_EXPR_NEST_MAX: c_int = 42; + pub const _SC_LINE_MAX: c_int = 43; + pub const _SC_RE_DUP_MAX: c_int = 44; + pub const _SC_2_VERSION: c_int = 46; + pub const _SC_2_C_BIND: c_int = 47; + pub const _SC_2_C_DEV: c_int = 48; + pub const _SC_2_FORT_DEV: c_int = 49; + pub const _SC_2_FORT_RUN: c_int = 50; + pub const _SC_2_SW_DEV: c_int = 51; + pub const _SC_2_LOCALEDEF: c_int = 52; + pub const _SC_NPROCESSORS_ONLN: c_int = 84; + pub const _SC_2_CHAR_TERM: c_int = 95; + pub const _SC_2_C_VERSION: c_int = 96; + pub const _SC_2_UPE: c_int = 97; + pub const _SC_XBS5_ILP32_OFF32: c_int = 125; + pub const _SC_XBS5_ILP32_OFFBIG: c_int = 126; + pub const _SC_XBS5_LPBIG_OFFBIG: c_int = 128; pub const _PC_NAME_MAX: c_int = 3; pub const _PC_PATH_MAX: c_int = 4; @@ -3928,9 +4186,9 @@ pub mod consts { pub mod sysconf { use types::os::arch::c95::c_int; - pub static _SC_SENDMSG_MAX_SIZE : c_int = 0; - pub static _SC_NPROCESSORS_ONLN : c_int = 1; - pub static _SC_PAGESIZE : c_int = 2; + pub static _SC_SENDMSG_MAX_SIZE: c_int = 0; + pub static _SC_NPROCESSORS_ONLN: c_int = 1; + pub static _SC_PAGESIZE: c_int = 2; pub const _PC_NAME_MAX: c_int = 3; pub const _PC_PATH_MAX: c_int = 4; @@ -3940,35 +4198,35 @@ pub mod consts { pub mod sysconf { use types::os::arch::c95::c_int; - pub const _SC_ARG_MAX : c_int = 0; - pub const _SC_BC_BASE_MAX : c_int = 1; - pub const _SC_BC_DIM_MAX : c_int = 2; - pub const _SC_BC_SCALE_MAX : c_int = 3; - pub const _SC_BC_STRING_MAX : c_int = 4; - pub const _SC_CHILD_MAX : c_int = 5; - pub const _SC_CLK_TCK : c_int = 6; - pub const _SC_COLL_WEIGHTS_MAX : c_int = 7; - pub const _SC_EXPR_NEST_MAX : c_int = 8; - pub const _SC_LINE_MAX : c_int = 9; - pub const _SC_NGROUPS_MAX : c_int = 10; - pub const _SC_OPEN_MAX : c_int = 11; - pub const _SC_2_C_BIND : c_int = 13; - pub const _SC_2_C_DEV : c_int = 14; - pub const _SC_2_C_VERSION : c_int = 15; - pub const _SC_2_CHAR_TERM : c_int = 16; - pub const _SC_2_FORT_DEV : c_int = 17; - pub const _SC_2_FORT_RUN : c_int = 18; - pub const _SC_2_LOCALEDEF : c_int = 19; - pub const _SC_2_SW_DEV : c_int = 20; - pub const _SC_2_UPE : c_int = 21; - pub const _SC_2_VERSION : c_int = 22; - pub const _SC_JOB_CONTROL : c_int = 23; - pub const _SC_SAVED_IDS : c_int = 24; - pub const _SC_VERSION : c_int = 25; - pub const _SC_RE_DUP_MAX : c_int = 26; - pub const _SC_STREAM_MAX : c_int = 27; - pub const _SC_TZNAME_MAX : c_int = 28; - pub const _SC_PAGESIZE : c_int = 39; + pub const _SC_ARG_MAX: c_int = 0; + pub const _SC_BC_BASE_MAX: c_int = 1; + pub const _SC_BC_DIM_MAX: c_int = 2; + pub const _SC_BC_SCALE_MAX: c_int = 3; + pub const _SC_BC_STRING_MAX: c_int = 4; + pub const _SC_CHILD_MAX: c_int = 5; + pub const _SC_CLK_TCK: c_int = 6; + pub const _SC_COLL_WEIGHTS_MAX: c_int = 7; + pub const _SC_EXPR_NEST_MAX: c_int = 8; + pub const _SC_LINE_MAX: c_int = 9; + pub const _SC_NGROUPS_MAX: c_int = 10; + pub const _SC_OPEN_MAX: c_int = 11; + pub const _SC_2_C_BIND: c_int = 13; + pub const _SC_2_C_DEV: c_int = 14; + pub const _SC_2_C_VERSION: c_int = 15; + pub const _SC_2_CHAR_TERM: c_int = 16; + pub const _SC_2_FORT_DEV: c_int = 17; + pub const _SC_2_FORT_RUN: c_int = 18; + pub const _SC_2_LOCALEDEF: c_int = 19; + pub const _SC_2_SW_DEV: c_int = 20; + pub const _SC_2_UPE: c_int = 21; + pub const _SC_2_VERSION: c_int = 22; + pub const _SC_JOB_CONTROL: c_int = 23; + pub const _SC_SAVED_IDS: c_int = 24; + pub const _SC_VERSION: c_int = 25; + pub const _SC_RE_DUP_MAX: c_int = 26; + pub const _SC_STREAM_MAX: c_int = 27; + pub const _SC_TZNAME_MAX: c_int = 28; + pub const _SC_PAGESIZE: c_int = 39; pub const _PC_NAME_MAX: c_int = 4; pub const _PC_PATH_MAX: c_int = 5; @@ -3981,21 +4239,21 @@ pub mod consts { pub mod c95 { use types::os::arch::c95::{c_int, c_uint}; - pub const EXIT_FAILURE : c_int = 1; - pub const EXIT_SUCCESS : c_int = 0; - pub const RAND_MAX : c_int = 2147483647; - pub const EOF : c_int = -1; - pub const SEEK_SET : c_int = 0; - pub const SEEK_CUR : c_int = 1; - pub const SEEK_END : c_int = 2; - pub const _IOFBF : c_int = 0; - pub const _IONBF : c_int = 2; - pub const _IOLBF : c_int = 1; - pub const BUFSIZ : c_uint = 1024; - pub const FOPEN_MAX : c_uint = 20; - pub const FILENAME_MAX : c_uint = 1024; - pub const L_tmpnam : c_uint = 1024; - pub const TMP_MAX : c_uint = 308915776; + pub const EXIT_FAILURE: c_int = 1; + pub const EXIT_SUCCESS: c_int = 0; + pub const RAND_MAX: c_int = 2147483647; + pub const EOF: c_int = -1; + pub const SEEK_SET: c_int = 0; + pub const SEEK_CUR: c_int = 1; + pub const SEEK_END: c_int = 2; + pub const _IOFBF: c_int = 0; + pub const _IONBF: c_int = 2; + pub const _IOLBF: c_int = 1; + pub const BUFSIZ: c_uint = 1024; + pub const FOPEN_MAX: c_uint = 20; + pub const FILENAME_MAX: c_uint = 1024; + pub const L_tmpnam: c_uint = 1024; + pub const TMP_MAX: c_uint = 308915776; } pub mod c99 { } @@ -4004,241 +4262,241 @@ pub mod consts { use types::os::arch::c95::c_int; use types::os::arch::posix88::mode_t; - pub const O_RDONLY : c_int = 0; - pub const O_WRONLY : c_int = 1; - pub const O_RDWR : c_int = 2; - pub const O_APPEND : c_int = 8; - pub const O_CREAT : c_int = 512; - pub const O_EXCL : c_int = 2048; - pub const O_NOCTTY : c_int = 32768; - pub const O_TRUNC : c_int = 1024; - pub const S_IFIFO : mode_t = 4096; - pub const S_IFCHR : mode_t = 8192; - pub const S_IFBLK : mode_t = 24576; - pub const S_IFDIR : mode_t = 16384; - pub const S_IFREG : mode_t = 32768; - pub const S_IFLNK : mode_t = 40960; - pub const S_IFSOCK : mode_t = 49152; - pub const S_IFMT : mode_t = 61440; - pub const S_IEXEC : mode_t = 64; - pub const S_IWRITE : mode_t = 128; - pub const S_IREAD : mode_t = 256; - pub const S_IRWXU : mode_t = 448; - pub const S_IXUSR : mode_t = 64; - pub const S_IWUSR : mode_t = 128; - pub const S_IRUSR : mode_t = 256; - pub const S_IRWXG : mode_t = 56; - pub const S_IXGRP : mode_t = 8; - pub const S_IWGRP : mode_t = 16; - pub const S_IRGRP : mode_t = 32; - pub const S_IRWXO : mode_t = 7; - pub const S_IXOTH : mode_t = 1; - pub const S_IWOTH : mode_t = 2; - pub const S_IROTH : mode_t = 4; - pub const F_OK : c_int = 0; - pub const R_OK : c_int = 4; - pub const W_OK : c_int = 2; - pub const X_OK : c_int = 1; - pub const STDIN_FILENO : c_int = 0; - pub const STDOUT_FILENO : c_int = 1; - pub const STDERR_FILENO : c_int = 2; - pub const F_LOCK : c_int = 1; - pub const F_TEST : c_int = 3; - pub const F_TLOCK : c_int = 2; - pub const F_ULOCK : c_int = 0; - pub const SIGHUP : c_int = 1; - pub const SIGINT : c_int = 2; - pub const SIGQUIT : c_int = 3; - pub const SIGILL : c_int = 4; - pub const SIGABRT : c_int = 6; - pub const SIGFPE : c_int = 8; - pub const SIGKILL : c_int = 9; - pub const SIGSEGV : c_int = 11; - pub const SIGPIPE : c_int = 13; - pub const SIGALRM : c_int = 14; - pub const SIGTERM : c_int = 15; - - pub const PROT_NONE : c_int = 0; - pub const PROT_READ : c_int = 1; - pub const PROT_WRITE : c_int = 2; - pub const PROT_EXEC : c_int = 4; - - pub const MAP_FILE : c_int = 0x0000; - pub const MAP_SHARED : c_int = 0x0001; - pub const MAP_PRIVATE : c_int = 0x0002; - pub const MAP_FIXED : c_int = 0x0010; - pub const MAP_ANON : c_int = 0x1000; - - pub const MAP_FAILED : *mut c_void = !0 as *mut c_void; - - pub const MCL_CURRENT : c_int = 0x0001; - pub const MCL_FUTURE : c_int = 0x0002; - - pub const MS_SYNC : c_int = 0x0000; - pub const MS_ASYNC : c_int = 0x0001; - pub const MS_INVALIDATE : c_int = 0x0002; - - pub const EPERM : c_int = 1; - pub const ENOENT : c_int = 2; - pub const ESRCH : c_int = 3; - pub const EINTR : c_int = 4; - pub const EIO : c_int = 5; - pub const ENXIO : c_int = 6; - pub const E2BIG : c_int = 7; - pub const ENOEXEC : c_int = 8; - pub const EBADF : c_int = 9; - pub const ECHILD : c_int = 10; - pub const EDEADLK : c_int = 11; - pub const ENOMEM : c_int = 12; - pub const EACCES : c_int = 13; - pub const EFAULT : c_int = 14; - pub const ENOTBLK : c_int = 15; - pub const EBUSY : c_int = 16; - pub const EEXIST : c_int = 17; - pub const EXDEV : c_int = 18; - pub const ENODEV : c_int = 19; - pub const ENOTDIR : c_int = 20; - pub const EISDIR : c_int = 21; - pub const EINVAL : c_int = 22; - pub const ENFILE : c_int = 23; - pub const EMFILE : c_int = 24; - pub const ENOTTY : c_int = 25; - pub const ETXTBSY : c_int = 26; - pub const EFBIG : c_int = 27; - pub const ENOSPC : c_int = 28; - pub const ESPIPE : c_int = 29; - pub const EROFS : c_int = 30; - pub const EMLINK : c_int = 31; - pub const EPIPE : c_int = 32; - pub const EDOM : c_int = 33; - pub const ERANGE : c_int = 34; - pub const EAGAIN : c_int = 35; - pub const EWOULDBLOCK : c_int = 35; - pub const EINPROGRESS : c_int = 36; - pub const EALREADY : c_int = 37; - pub const ENOTSOCK : c_int = 38; - pub const EDESTADDRREQ : c_int = 39; - pub const EMSGSIZE : c_int = 40; - pub const EPROTOTYPE : c_int = 41; - pub const ENOPROTOOPT : c_int = 42; - pub const EPROTONOSUPPORT : c_int = 43; - pub const ESOCKTNOSUPPORT : c_int = 44; - pub const EOPNOTSUPP : c_int = 45; - pub const EPFNOSUPPORT : c_int = 46; - pub const EAFNOSUPPORT : c_int = 47; - pub const EADDRINUSE : c_int = 48; - pub const EADDRNOTAVAIL : c_int = 49; - pub const ENETDOWN : c_int = 50; - pub const ENETUNREACH : c_int = 51; - pub const ENETRESET : c_int = 52; - pub const ECONNABORTED : c_int = 53; - pub const ECONNRESET : c_int = 54; - pub const ENOBUFS : c_int = 55; - pub const EISCONN : c_int = 56; - pub const ENOTCONN : c_int = 57; - pub const ESHUTDOWN : c_int = 58; - pub const ETOOMANYREFS : c_int = 59; - pub const ETIMEDOUT : c_int = 60; - pub const ECONNREFUSED : c_int = 61; - pub const ELOOP : c_int = 62; - pub const ENAMETOOLONG : c_int = 63; - pub const EHOSTDOWN : c_int = 64; - pub const EHOSTUNREACH : c_int = 65; - pub const ENOTEMPTY : c_int = 66; - pub const EPROCLIM : c_int = 67; - pub const EUSERS : c_int = 68; - pub const EDQUOT : c_int = 69; - pub const ESTALE : c_int = 70; - pub const EREMOTE : c_int = 71; - pub const EBADRPC : c_int = 72; - pub const ERPCMISMATCH : c_int = 73; - pub const EPROGUNAVAIL : c_int = 74; - pub const EPROGMISMATCH : c_int = 75; - pub const EPROCUNAVAIL : c_int = 76; - pub const ENOLCK : c_int = 77; - pub const ENOSYS : c_int = 78; - pub const EFTYPE : c_int = 79; - pub const EAUTH : c_int = 80; - pub const ENEEDAUTH : c_int = 81; - pub const EIDRM : c_int = 82; - pub const ENOMSG : c_int = 83; - pub const EOVERFLOW : c_int = 84; - pub const ECANCELED : c_int = 85; - pub const EILSEQ : c_int = 86; - pub const ENOATTR : c_int = 87; - pub const EDOOFUS : c_int = 88; - pub const EBADMSG : c_int = 89; - pub const EMULTIHOP : c_int = 90; - pub const ENOLINK : c_int = 91; - pub const EPROTO : c_int = 92; - pub const ENOMEDIUM : c_int = 93; - pub const EUNUSED94 : c_int = 94; - pub const EUNUSED95 : c_int = 95; - pub const EUNUSED96 : c_int = 96; - pub const EUNUSED97 : c_int = 97; - pub const EUNUSED98 : c_int = 98; - pub const EASYNC : c_int = 99; - pub const ELAST : c_int = 99; + pub const O_RDONLY: c_int = 0; + pub const O_WRONLY: c_int = 1; + pub const O_RDWR: c_int = 2; + pub const O_APPEND: c_int = 8; + pub const O_CREAT: c_int = 512; + pub const O_EXCL: c_int = 2048; + pub const O_NOCTTY: c_int = 32768; + pub const O_TRUNC: c_int = 1024; + pub const S_IFIFO: mode_t = 4096; + pub const S_IFCHR: mode_t = 8192; + pub const S_IFBLK: mode_t = 24576; + pub const S_IFDIR: mode_t = 16384; + pub const S_IFREG: mode_t = 32768; + pub const S_IFLNK: mode_t = 40960; + pub const S_IFSOCK: mode_t = 49152; + pub const S_IFMT: mode_t = 61440; + pub const S_IEXEC: mode_t = 64; + pub const S_IWRITE: mode_t = 128; + pub const S_IREAD: mode_t = 256; + pub const S_IRWXU: mode_t = 448; + pub const S_IXUSR: mode_t = 64; + pub const S_IWUSR: mode_t = 128; + pub const S_IRUSR: mode_t = 256; + pub const S_IRWXG: mode_t = 56; + pub const S_IXGRP: mode_t = 8; + pub const S_IWGRP: mode_t = 16; + pub const S_IRGRP: mode_t = 32; + pub const S_IRWXO: mode_t = 7; + pub const S_IXOTH: mode_t = 1; + pub const S_IWOTH: mode_t = 2; + pub const S_IROTH: mode_t = 4; + pub const F_OK: c_int = 0; + pub const R_OK: c_int = 4; + pub const W_OK: c_int = 2; + pub const X_OK: c_int = 1; + pub const STDIN_FILENO: c_int = 0; + pub const STDOUT_FILENO: c_int = 1; + pub const STDERR_FILENO: c_int = 2; + pub const F_LOCK: c_int = 1; + pub const F_TEST: c_int = 3; + pub const F_TLOCK: c_int = 2; + pub const F_ULOCK: c_int = 0; + pub const SIGHUP: c_int = 1; + pub const SIGINT: c_int = 2; + pub const SIGQUIT: c_int = 3; + pub const SIGILL: c_int = 4; + pub const SIGABRT: c_int = 6; + pub const SIGFPE: c_int = 8; + pub const SIGKILL: c_int = 9; + pub const SIGSEGV: c_int = 11; + pub const SIGPIPE: c_int = 13; + pub const SIGALRM: c_int = 14; + pub const SIGTERM: c_int = 15; + + pub const PROT_NONE: c_int = 0; + pub const PROT_READ: c_int = 1; + pub const PROT_WRITE: c_int = 2; + pub const PROT_EXEC: c_int = 4; + + pub const MAP_FILE: c_int = 0x0000; + pub const MAP_SHARED: c_int = 0x0001; + pub const MAP_PRIVATE: c_int = 0x0002; + pub const MAP_FIXED: c_int = 0x0010; + pub const MAP_ANON: c_int = 0x1000; + + pub const MAP_FAILED: *mut c_void = !0 as *mut c_void; + + pub const MCL_CURRENT: c_int = 0x0001; + pub const MCL_FUTURE: c_int = 0x0002; + + pub const MS_SYNC: c_int = 0x0000; + pub const MS_ASYNC: c_int = 0x0001; + pub const MS_INVALIDATE: c_int = 0x0002; + + pub const EPERM: c_int = 1; + pub const ENOENT: c_int = 2; + pub const ESRCH: c_int = 3; + pub const EINTR: c_int = 4; + pub const EIO: c_int = 5; + pub const ENXIO: c_int = 6; + pub const E2BIG: c_int = 7; + pub const ENOEXEC: c_int = 8; + pub const EBADF: c_int = 9; + pub const ECHILD: c_int = 10; + pub const EDEADLK: c_int = 11; + pub const ENOMEM: c_int = 12; + pub const EACCES: c_int = 13; + pub const EFAULT: c_int = 14; + pub const ENOTBLK: c_int = 15; + pub const EBUSY: c_int = 16; + pub const EEXIST: c_int = 17; + pub const EXDEV: c_int = 18; + pub const ENODEV: c_int = 19; + pub const ENOTDIR: c_int = 20; + pub const EISDIR: c_int = 21; + pub const EINVAL: c_int = 22; + pub const ENFILE: c_int = 23; + pub const EMFILE: c_int = 24; + pub const ENOTTY: c_int = 25; + pub const ETXTBSY: c_int = 26; + pub const EFBIG: c_int = 27; + pub const ENOSPC: c_int = 28; + pub const ESPIPE: c_int = 29; + pub const EROFS: c_int = 30; + pub const EMLINK: c_int = 31; + pub const EPIPE: c_int = 32; + pub const EDOM: c_int = 33; + pub const ERANGE: c_int = 34; + pub const EAGAIN: c_int = 35; + pub const EWOULDBLOCK: c_int = 35; + pub const EINPROGRESS: c_int = 36; + pub const EALREADY: c_int = 37; + pub const ENOTSOCK: c_int = 38; + pub const EDESTADDRREQ: c_int = 39; + pub const EMSGSIZE: c_int = 40; + pub const EPROTOTYPE: c_int = 41; + pub const ENOPROTOOPT: c_int = 42; + pub const EPROTONOSUPPORT: c_int = 43; + pub const ESOCKTNOSUPPORT: c_int = 44; + pub const EOPNOTSUPP: c_int = 45; + pub const EPFNOSUPPORT: c_int = 46; + pub const EAFNOSUPPORT: c_int = 47; + pub const EADDRINUSE: c_int = 48; + pub const EADDRNOTAVAIL: c_int = 49; + pub const ENETDOWN: c_int = 50; + pub const ENETUNREACH: c_int = 51; + pub const ENETRESET: c_int = 52; + pub const ECONNABORTED: c_int = 53; + pub const ECONNRESET: c_int = 54; + pub const ENOBUFS: c_int = 55; + pub const EISCONN: c_int = 56; + pub const ENOTCONN: c_int = 57; + pub const ESHUTDOWN: c_int = 58; + pub const ETOOMANYREFS: c_int = 59; + pub const ETIMEDOUT: c_int = 60; + pub const ECONNREFUSED: c_int = 61; + pub const ELOOP: c_int = 62; + pub const ENAMETOOLONG: c_int = 63; + pub const EHOSTDOWN: c_int = 64; + pub const EHOSTUNREACH: c_int = 65; + pub const ENOTEMPTY: c_int = 66; + pub const EPROCLIM: c_int = 67; + pub const EUSERS: c_int = 68; + pub const EDQUOT: c_int = 69; + pub const ESTALE: c_int = 70; + pub const EREMOTE: c_int = 71; + pub const EBADRPC: c_int = 72; + pub const ERPCMISMATCH: c_int = 73; + pub const EPROGUNAVAIL: c_int = 74; + pub const EPROGMISMATCH: c_int = 75; + pub const EPROCUNAVAIL: c_int = 76; + pub const ENOLCK: c_int = 77; + pub const ENOSYS: c_int = 78; + pub const EFTYPE: c_int = 79; + pub const EAUTH: c_int = 80; + pub const ENEEDAUTH: c_int = 81; + pub const EIDRM: c_int = 82; + pub const ENOMSG: c_int = 83; + pub const EOVERFLOW: c_int = 84; + pub const ECANCELED: c_int = 85; + pub const EILSEQ: c_int = 86; + pub const ENOATTR: c_int = 87; + pub const EDOOFUS: c_int = 88; + pub const EBADMSG: c_int = 89; + pub const EMULTIHOP: c_int = 90; + pub const ENOLINK: c_int = 91; + pub const EPROTO: c_int = 92; + pub const ENOMEDIUM: c_int = 93; + pub const EUNUSED94: c_int = 94; + pub const EUNUSED95: c_int = 95; + pub const EUNUSED96: c_int = 96; + pub const EUNUSED97: c_int = 97; + pub const EUNUSED98: c_int = 98; + pub const EASYNC: c_int = 99; + pub const ELAST: c_int = 99; } pub mod posix01 { use types::os::arch::c95::{c_int, size_t}; use types::os::common::posix01::rlim_t; - pub const F_DUPFD : c_int = 0; - pub const F_GETFD : c_int = 1; - pub const F_SETFD : c_int = 2; - pub const F_GETFL : c_int = 3; - pub const F_SETFL : c_int = 4; + pub const F_DUPFD: c_int = 0; + pub const F_GETFD: c_int = 1; + pub const F_SETFD: c_int = 2; + pub const F_GETFL: c_int = 3; + pub const F_SETFL: c_int = 4; - pub const SIGTRAP : c_int = 5; + pub const SIGTRAP: c_int = 5; pub const SIG_IGN: size_t = 1; - pub const GLOB_APPEND : c_int = 0x0001; - pub const GLOB_DOOFFS : c_int = 0x0002; - pub const GLOB_ERR : c_int = 0x0004; - pub const GLOB_MARK : c_int = 0x0008; - pub const GLOB_NOCHECK : c_int = 0x0010; - pub const GLOB_NOSORT : c_int = 0x0020; - pub const GLOB_NOESCAPE : c_int = 0x2000; - - pub const GLOB_NOSPACE : c_int = -1; - pub const GLOB_ABORTED : c_int = -2; - pub const GLOB_NOMATCH : c_int = -3; - - pub const POSIX_MADV_NORMAL : c_int = 0; - pub const POSIX_MADV_RANDOM : c_int = 1; - pub const POSIX_MADV_SEQUENTIAL : c_int = 2; - pub const POSIX_MADV_WILLNEED : c_int = 3; - pub const POSIX_MADV_DONTNEED : c_int = 4; - - pub const _SC_IOV_MAX : c_int = 56; - pub const _SC_GETGR_R_SIZE_MAX : c_int = 70; - pub const _SC_GETPW_R_SIZE_MAX : c_int = 71; - pub const _SC_LOGIN_NAME_MAX : c_int = 73; - pub const _SC_MQ_PRIO_MAX : c_int = 75; - pub const _SC_THREAD_ATTR_STACKADDR : c_int = 82; - pub const _SC_THREAD_ATTR_STACKSIZE : c_int = 83; - pub const _SC_THREAD_DESTRUCTOR_ITERATIONS : c_int = 85; - pub const _SC_THREAD_KEYS_MAX : c_int = 86; - pub const _SC_THREAD_PRIO_INHERIT : c_int = 87; - pub const _SC_THREAD_PRIO_PROTECT : c_int = 88; - pub const _SC_THREAD_PRIORITY_SCHEDULING : c_int = 89; - pub const _SC_THREAD_PROCESS_SHARED : c_int = 90; - pub const _SC_THREAD_SAFE_FUNCTIONS : c_int = 91; - pub const _SC_THREAD_STACK_MIN : c_int = 93; - pub const _SC_THREAD_THREADS_MAX : c_int = 94; - pub const _SC_THREADS : c_int = 96; - pub const _SC_TTY_NAME_MAX : c_int = 101; - pub const _SC_ATEXIT_MAX : c_int = 107; - pub const _SC_XOPEN_CRYPT : c_int = 108; - pub const _SC_XOPEN_ENH_I18N : c_int = 109; - pub const _SC_XOPEN_LEGACY : c_int = 110; - pub const _SC_XOPEN_REALTIME : c_int = 111; - pub const _SC_XOPEN_REALTIME_THREADS : c_int = 112; - pub const _SC_XOPEN_SHM : c_int = 113; - pub const _SC_XOPEN_UNIX : c_int = 115; - pub const _SC_XOPEN_VERSION : c_int = 116; - pub const _SC_XOPEN_XCU_VERSION : c_int = 117; + pub const GLOB_APPEND: c_int = 0x0001; + pub const GLOB_DOOFFS: c_int = 0x0002; + pub const GLOB_ERR: c_int = 0x0004; + pub const GLOB_MARK: c_int = 0x0008; + pub const GLOB_NOCHECK: c_int = 0x0010; + pub const GLOB_NOSORT: c_int = 0x0020; + pub const GLOB_NOESCAPE: c_int = 0x2000; + + pub const GLOB_NOSPACE: c_int = -1; + pub const GLOB_ABORTED: c_int = -2; + pub const GLOB_NOMATCH: c_int = -3; + + pub const POSIX_MADV_NORMAL: c_int = 0; + pub const POSIX_MADV_RANDOM: c_int = 1; + pub const POSIX_MADV_SEQUENTIAL: c_int = 2; + pub const POSIX_MADV_WILLNEED: c_int = 3; + pub const POSIX_MADV_DONTNEED: c_int = 4; + + pub const _SC_IOV_MAX: c_int = 56; + pub const _SC_GETGR_R_SIZE_MAX: c_int = 70; + pub const _SC_GETPW_R_SIZE_MAX: c_int = 71; + pub const _SC_LOGIN_NAME_MAX: c_int = 73; + pub const _SC_MQ_PRIO_MAX: c_int = 75; + pub const _SC_THREAD_ATTR_STACKADDR: c_int = 82; + pub const _SC_THREAD_ATTR_STACKSIZE: c_int = 83; + pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: c_int = 85; + pub const _SC_THREAD_KEYS_MAX: c_int = 86; + pub const _SC_THREAD_PRIO_INHERIT: c_int = 87; + pub const _SC_THREAD_PRIO_PROTECT: c_int = 88; + pub const _SC_THREAD_PRIORITY_SCHEDULING: c_int = 89; + pub const _SC_THREAD_PROCESS_SHARED: c_int = 90; + pub const _SC_THREAD_SAFE_FUNCTIONS: c_int = 91; + pub const _SC_THREAD_STACK_MIN: c_int = 93; + pub const _SC_THREAD_THREADS_MAX: c_int = 94; + pub const _SC_THREADS: c_int = 96; + pub const _SC_TTY_NAME_MAX: c_int = 101; + pub const _SC_ATEXIT_MAX: c_int = 107; + pub const _SC_XOPEN_CRYPT: c_int = 108; + pub const _SC_XOPEN_ENH_I18N: c_int = 109; + pub const _SC_XOPEN_LEGACY: c_int = 110; + pub const _SC_XOPEN_REALTIME: c_int = 111; + pub const _SC_XOPEN_REALTIME_THREADS: c_int = 112; + pub const _SC_XOPEN_SHM: c_int = 113; + pub const _SC_XOPEN_UNIX: c_int = 115; + pub const _SC_XOPEN_VERSION: c_int = 116; + pub const _SC_XOPEN_XCU_VERSION: c_int = 117; pub const PTHREAD_CREATE_JOINABLE: c_int = 0; pub const PTHREAD_CREATE_DETACHED: c_int = 1; @@ -4297,24 +4555,24 @@ pub mod consts { pub mod bsd44 { use types::os::arch::c95::c_int; - pub const MADV_NORMAL : c_int = 0; - pub const MADV_RANDOM : c_int = 1; - pub const MADV_SEQUENTIAL : c_int = 2; - pub const MADV_WILLNEED : c_int = 3; - pub const MADV_DONTNEED : c_int = 4; - pub const MADV_FREE : c_int = 5; - pub const MADV_NOSYNC : c_int = 6; - pub const MADV_AUTOSYNC : c_int = 7; - pub const MADV_NOCORE : c_int = 8; - pub const MADV_CORE : c_int = 9; - pub const MADV_PROTECT : c_int = 10; - - pub const MINCORE_INCORE : c_int = 0x1; - pub const MINCORE_REFERENCED : c_int = 0x2; - pub const MINCORE_MODIFIED : c_int = 0x4; - pub const MINCORE_REFERENCED_OTHER : c_int = 0x8; - pub const MINCORE_MODIFIED_OTHER : c_int = 0x10; - pub const MINCORE_SUPER : c_int = 0x20; + pub const MADV_NORMAL: c_int = 0; + pub const MADV_RANDOM: c_int = 1; + pub const MADV_SEQUENTIAL: c_int = 2; + pub const MADV_WILLNEED: c_int = 3; + pub const MADV_DONTNEED: c_int = 4; + pub const MADV_FREE: c_int = 5; + pub const MADV_NOSYNC: c_int = 6; + pub const MADV_AUTOSYNC: c_int = 7; + pub const MADV_NOCORE: c_int = 8; + pub const MADV_CORE: c_int = 9; + pub const MADV_PROTECT: c_int = 10; + + pub const MINCORE_INCORE: c_int = 0x1; + pub const MINCORE_REFERENCED: c_int = 0x2; + pub const MINCORE_MODIFIED: c_int = 0x4; + pub const MINCORE_REFERENCED_OTHER: c_int = 0x8; + pub const MINCORE_MODIFIED_OTHER: c_int = 0x10; + pub const MINCORE_SUPER: c_int = 0x20; pub const AF_INET: c_int = 2; pub const AF_INET6: c_int = 28; @@ -4370,8 +4628,8 @@ pub mod consts { pub mod extra { use types::os::arch::c95::c_int; - pub const O_SYNC : c_int = 128; - pub const O_NONBLOCK : c_int = 4; + pub const O_SYNC: c_int = 128; + pub const O_NONBLOCK: c_int = 4; pub const CTL_KERN: c_int = 1; pub const KERN_PROC: c_int = 14; #[cfg(target_os = "freebsd")] @@ -4379,97 +4637,97 @@ pub mod consts { #[cfg(target_os = "dragonfly")] pub const KERN_PROC_PATHNAME: c_int = 9; - pub const MAP_COPY : c_int = 0x0002; - pub const MAP_RENAME : c_int = 0x0020; - pub const MAP_NORESERVE : c_int = 0x0040; - pub const MAP_HASSEMAPHORE : c_int = 0x0200; - pub const MAP_STACK : c_int = 0x0400; - pub const MAP_NOSYNC : c_int = 0x0800; - pub const MAP_NOCORE : c_int = 0x020000; + pub const MAP_COPY: c_int = 0x0002; + pub const MAP_RENAME: c_int = 0x0020; + pub const MAP_NORESERVE: c_int = 0x0040; + pub const MAP_HASSEMAPHORE: c_int = 0x0200; + pub const MAP_STACK: c_int = 0x0400; + pub const MAP_NOSYNC: c_int = 0x0800; + pub const MAP_NOCORE: c_int = 0x020000; - pub const IPPROTO_RAW : c_int = 255; + pub const IPPROTO_RAW: c_int = 255; } pub mod sysconf { use types::os::arch::c95::c_int; - pub const _SC_ARG_MAX : c_int = 1; - pub const _SC_CHILD_MAX : c_int = 2; - pub const _SC_CLK_TCK : c_int = 3; - pub const _SC_NGROUPS_MAX : c_int = 4; - pub const _SC_OPEN_MAX : c_int = 5; - pub const _SC_JOB_CONTROL : c_int = 6; - pub const _SC_SAVED_IDS : c_int = 7; - pub const _SC_VERSION : c_int = 8; - pub const _SC_BC_BASE_MAX : c_int = 9; - pub const _SC_BC_DIM_MAX : c_int = 10; - pub const _SC_BC_SCALE_MAX : c_int = 11; - pub const _SC_BC_STRING_MAX : c_int = 12; - pub const _SC_COLL_WEIGHTS_MAX : c_int = 13; - pub const _SC_EXPR_NEST_MAX : c_int = 14; - pub const _SC_LINE_MAX : c_int = 15; - pub const _SC_RE_DUP_MAX : c_int = 16; - pub const _SC_2_VERSION : c_int = 17; - pub const _SC_2_C_BIND : c_int = 18; - pub const _SC_2_C_DEV : c_int = 19; - pub const _SC_2_CHAR_TERM : c_int = 20; - pub const _SC_2_FORT_DEV : c_int = 21; - pub const _SC_2_FORT_RUN : c_int = 22; - pub const _SC_2_LOCALEDEF : c_int = 23; - pub const _SC_2_SW_DEV : c_int = 24; - pub const _SC_2_UPE : c_int = 25; - pub const _SC_STREAM_MAX : c_int = 26; - pub const _SC_TZNAME_MAX : c_int = 27; - pub const _SC_ASYNCHRONOUS_IO : c_int = 28; - pub const _SC_MAPPED_FILES : c_int = 29; - pub const _SC_MEMLOCK : c_int = 30; - pub const _SC_MEMLOCK_RANGE : c_int = 31; - pub const _SC_MEMORY_PROTECTION : c_int = 32; - pub const _SC_MESSAGE_PASSING : c_int = 33; - pub const _SC_PRIORITIZED_IO : c_int = 34; - pub const _SC_PRIORITY_SCHEDULING : c_int = 35; - pub const _SC_REALTIME_SIGNALS : c_int = 36; - pub const _SC_SEMAPHORES : c_int = 37; - pub const _SC_FSYNC : c_int = 38; - pub const _SC_SHARED_MEMORY_OBJECTS : c_int = 39; - pub const _SC_SYNCHRONIZED_IO : c_int = 40; - pub const _SC_TIMERS : c_int = 41; - pub const _SC_AIO_LISTIO_MAX : c_int = 42; - pub const _SC_AIO_MAX : c_int = 43; - pub const _SC_AIO_PRIO_DELTA_MAX : c_int = 44; - pub const _SC_DELAYTIMER_MAX : c_int = 45; - pub const _SC_MQ_OPEN_MAX : c_int = 46; - pub const _SC_PAGESIZE : c_int = 47; - pub const _SC_RTSIG_MAX : c_int = 48; - pub const _SC_SEM_NSEMS_MAX : c_int = 49; - pub const _SC_SEM_VALUE_MAX : c_int = 50; - pub const _SC_SIGQUEUE_MAX : c_int = 51; - pub const _SC_TIMER_MAX : c_int = 52; + pub const _SC_ARG_MAX: c_int = 1; + pub const _SC_CHILD_MAX: c_int = 2; + pub const _SC_CLK_TCK: c_int = 3; + pub const _SC_NGROUPS_MAX: c_int = 4; + pub const _SC_OPEN_MAX: c_int = 5; + pub const _SC_JOB_CONTROL: c_int = 6; + pub const _SC_SAVED_IDS: c_int = 7; + pub const _SC_VERSION: c_int = 8; + pub const _SC_BC_BASE_MAX: c_int = 9; + pub const _SC_BC_DIM_MAX: c_int = 10; + pub const _SC_BC_SCALE_MAX: c_int = 11; + pub const _SC_BC_STRING_MAX: c_int = 12; + pub const _SC_COLL_WEIGHTS_MAX: c_int = 13; + pub const _SC_EXPR_NEST_MAX: c_int = 14; + pub const _SC_LINE_MAX: c_int = 15; + pub const _SC_RE_DUP_MAX: c_int = 16; + pub const _SC_2_VERSION: c_int = 17; + pub const _SC_2_C_BIND: c_int = 18; + pub const _SC_2_C_DEV: c_int = 19; + pub const _SC_2_CHAR_TERM: c_int = 20; + pub const _SC_2_FORT_DEV: c_int = 21; + pub const _SC_2_FORT_RUN: c_int = 22; + pub const _SC_2_LOCALEDEF: c_int = 23; + pub const _SC_2_SW_DEV: c_int = 24; + pub const _SC_2_UPE: c_int = 25; + pub const _SC_STREAM_MAX: c_int = 26; + pub const _SC_TZNAME_MAX: c_int = 27; + pub const _SC_ASYNCHRONOUS_IO: c_int = 28; + pub const _SC_MAPPED_FILES: c_int = 29; + pub const _SC_MEMLOCK: c_int = 30; + pub const _SC_MEMLOCK_RANGE: c_int = 31; + pub const _SC_MEMORY_PROTECTION: c_int = 32; + pub const _SC_MESSAGE_PASSING: c_int = 33; + pub const _SC_PRIORITIZED_IO: c_int = 34; + pub const _SC_PRIORITY_SCHEDULING: c_int = 35; + pub const _SC_REALTIME_SIGNALS: c_int = 36; + pub const _SC_SEMAPHORES: c_int = 37; + pub const _SC_FSYNC: c_int = 38; + pub const _SC_SHARED_MEMORY_OBJECTS: c_int = 39; + pub const _SC_SYNCHRONIZED_IO: c_int = 40; + pub const _SC_TIMERS: c_int = 41; + pub const _SC_AIO_LISTIO_MAX: c_int = 42; + pub const _SC_AIO_MAX: c_int = 43; + pub const _SC_AIO_PRIO_DELTA_MAX: c_int = 44; + pub const _SC_DELAYTIMER_MAX: c_int = 45; + pub const _SC_MQ_OPEN_MAX: c_int = 46; + pub const _SC_PAGESIZE: c_int = 47; + pub const _SC_RTSIG_MAX: c_int = 48; + pub const _SC_SEM_NSEMS_MAX: c_int = 49; + pub const _SC_SEM_VALUE_MAX: c_int = 50; + pub const _SC_SIGQUEUE_MAX: c_int = 51; + pub const _SC_TIMER_MAX: c_int = 52; pub const _PC_NAME_MAX: c_int = 4; pub const _PC_PATH_MAX: c_int = 5; } } - #[cfg(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"))] + #[cfg(any(target_os = "bitrig", target_os = "openbsd"))] pub mod os { pub mod c95 { use types::os::arch::c95::{c_int, c_uint}; - pub const EXIT_FAILURE : c_int = 1; - pub const EXIT_SUCCESS : c_int = 0; - pub const RAND_MAX : c_int = 2147483647; - pub const EOF : c_int = -1; - pub const SEEK_SET : c_int = 0; - pub const SEEK_CUR : c_int = 1; - pub const SEEK_END : c_int = 2; - pub const _IOFBF : c_int = 0; - pub const _IONBF : c_int = 2; - pub const _IOLBF : c_int = 1; - pub const BUFSIZ : c_uint = 1024; - pub const FOPEN_MAX : c_uint = 20; - pub const FILENAME_MAX : c_uint = 1024; - pub const L_tmpnam : c_uint = 1024; - pub const TMP_MAX : c_uint = 308915776; + pub const EXIT_FAILURE: c_int = 1; + pub const EXIT_SUCCESS: c_int = 0; + pub const RAND_MAX: c_int = 2147483647; + pub const EOF: c_int = -1; + pub const SEEK_SET: c_int = 0; + pub const SEEK_CUR: c_int = 1; + pub const SEEK_END: c_int = 2; + pub const _IOFBF: c_int = 0; + pub const _IONBF: c_int = 2; + pub const _IOLBF: c_int = 1; + pub const BUFSIZ: c_uint = 1024; + pub const FOPEN_MAX: c_uint = 20; + pub const FILENAME_MAX: c_uint = 1024; + pub const L_tmpnam: c_uint = 1024; + pub const TMP_MAX: c_uint = 308915776; } pub mod c99 { } @@ -4478,245 +4736,245 @@ pub mod consts { use types::os::arch::c95::c_int; use types::os::arch::posix88::mode_t; - pub const O_RDONLY : c_int = 0; - pub const O_WRONLY : c_int = 1; - pub const O_RDWR : c_int = 2; - pub const O_APPEND : c_int = 8; - pub const O_CREAT : c_int = 512; - pub const O_EXCL : c_int = 2048; - pub const O_NOCTTY : c_int = 32768; - pub const O_TRUNC : c_int = 1024; - pub const S_IFIFO : mode_t = 4096; - pub const S_IFCHR : mode_t = 8192; - pub const S_IFBLK : mode_t = 24576; - pub const S_IFDIR : mode_t = 16384; - pub const S_IFREG : mode_t = 32768; - pub const S_IFLNK : mode_t = 40960; - pub const S_IFSOCK : mode_t = 49152; - pub const S_IFMT : mode_t = 61440; - pub const S_IEXEC : mode_t = 64; - pub const S_IWRITE : mode_t = 128; - pub const S_IREAD : mode_t = 256; - pub const S_IRWXU : mode_t = 448; - pub const S_IXUSR : mode_t = 64; - pub const S_IWUSR : mode_t = 128; - pub const S_IRUSR : mode_t = 256; - pub const S_IRWXG : mode_t = 56; - pub const S_IXGRP : mode_t = 8; - pub const S_IWGRP : mode_t = 16; - pub const S_IRGRP : mode_t = 32; - pub const S_IRWXO : mode_t = 7; - pub const S_IXOTH : mode_t = 1; - pub const S_IWOTH : mode_t = 2; - pub const S_IROTH : mode_t = 4; - pub const F_OK : c_int = 0; - pub const R_OK : c_int = 4; - pub const W_OK : c_int = 2; - pub const X_OK : c_int = 1; - pub const STDIN_FILENO : c_int = 0; - pub const STDOUT_FILENO : c_int = 1; - pub const STDERR_FILENO : c_int = 2; - pub const F_LOCK : c_int = 1; - pub const F_TEST : c_int = 3; - pub const F_TLOCK : c_int = 2; - pub const F_ULOCK : c_int = 0; - pub const SIGHUP : c_int = 1; - pub const SIGINT : c_int = 2; - pub const SIGQUIT : c_int = 3; - pub const SIGILL : c_int = 4; - pub const SIGABRT : c_int = 6; - pub const SIGFPE : c_int = 8; - pub const SIGKILL : c_int = 9; - pub const SIGSEGV : c_int = 11; - pub const SIGPIPE : c_int = 13; - pub const SIGALRM : c_int = 14; - pub const SIGTERM : c_int = 15; - - pub const PROT_NONE : c_int = 0; - pub const PROT_READ : c_int = 1; - pub const PROT_WRITE : c_int = 2; - pub const PROT_EXEC : c_int = 4; - - pub const MAP_FILE : c_int = 0x0000; - pub const MAP_SHARED : c_int = 0x0001; - pub const MAP_PRIVATE : c_int = 0x0002; - pub const MAP_FIXED : c_int = 0x0010; - pub const MAP_ANON : c_int = 0x1000; - - pub const MAP_FAILED : *mut c_void = !0 as *mut c_void; - - pub const MCL_CURRENT : c_int = 0x0001; - pub const MCL_FUTURE : c_int = 0x0002; - - pub const MS_ASYNC : c_int = 0x0001; - pub const MS_SYNC : c_int = 0x0002; - pub const MS_INVALIDATE : c_int = 0x0004; - - pub const EPERM : c_int = 1; - pub const ENOENT : c_int = 2; - pub const ESRCH : c_int = 3; - pub const EINTR : c_int = 4; - pub const EIO : c_int = 5; - pub const ENXIO : c_int = 6; - pub const E2BIG : c_int = 7; - pub const ENOEXEC : c_int = 8; - pub const EBADF : c_int = 9; - pub const ECHILD : c_int = 10; - pub const EDEADLK : c_int = 11; - pub const ENOMEM : c_int = 12; - pub const EACCES : c_int = 13; - pub const EFAULT : c_int = 14; - pub const ENOTBLK : c_int = 15; - pub const EBUSY : c_int = 16; - pub const EEXIST : c_int = 17; - pub const EXDEV : c_int = 18; - pub const ENODEV : c_int = 19; - pub const ENOTDIR : c_int = 20; - pub const EISDIR : c_int = 21; - pub const EINVAL : c_int = 22; - pub const ENFILE : c_int = 23; - pub const EMFILE : c_int = 24; - pub const ENOTTY : c_int = 25; - pub const ETXTBSY : c_int = 26; - pub const EFBIG : c_int = 27; - pub const ENOSPC : c_int = 28; - pub const ESPIPE : c_int = 29; - pub const EROFS : c_int = 30; - pub const EMLINK : c_int = 31; - pub const EPIPE : c_int = 32; - pub const EDOM : c_int = 33; - pub const ERANGE : c_int = 34; - pub const EAGAIN : c_int = 35; - pub const EWOULDBLOCK : c_int = 35; - pub const EINPROGRESS : c_int = 36; - pub const EALREADY : c_int = 37; - pub const ENOTSOCK : c_int = 38; - pub const EDESTADDRREQ : c_int = 39; - pub const EMSGSIZE : c_int = 40; - pub const EPROTOTYPE : c_int = 41; - pub const ENOPROTOOPT : c_int = 42; - pub const EPROTONOSUPPORT : c_int = 43; - pub const ESOCKTNOSUPPORT : c_int = 44; - pub const EOPNOTSUPP : c_int = 45; - pub const EPFNOSUPPORT : c_int = 46; - pub const EAFNOSUPPORT : c_int = 47; - pub const EADDRINUSE : c_int = 48; - pub const EADDRNOTAVAIL : c_int = 49; - pub const ENETDOWN : c_int = 50; - pub const ENETUNREACH : c_int = 51; - pub const ENETRESET : c_int = 52; - pub const ECONNABORTED : c_int = 53; - pub const ECONNRESET : c_int = 54; - pub const ENOBUFS : c_int = 55; - pub const EISCONN : c_int = 56; - pub const ENOTCONN : c_int = 57; - pub const ESHUTDOWN : c_int = 58; - pub const ETOOMANYREFS : c_int = 59; - pub const ETIMEDOUT : c_int = 60; - pub const ECONNREFUSED : c_int = 61; - pub const ELOOP : c_int = 62; - pub const ENAMETOOLONG : c_int = 63; - pub const EHOSTDOWN : c_int = 64; - pub const EHOSTUNREACH : c_int = 65; - pub const ENOTEMPTY : c_int = 66; - pub const EPROCLIM : c_int = 67; - pub const EUSERS : c_int = 68; - pub const EDQUOT : c_int = 69; - pub const ESTALE : c_int = 70; - pub const EREMOTE : c_int = 71; - pub const EBADRPC : c_int = 72; - pub const ERPCMISMATCH : c_int = 73; - pub const EPROGUNAVAIL : c_int = 74; - pub const EPROGMISMATCH : c_int = 75; - pub const EPROCUNAVAIL : c_int = 76; - pub const ENOLCK : c_int = 77; - pub const ENOSYS : c_int = 78; - pub const EFTYPE : c_int = 79; - pub const EAUTH : c_int = 80; - pub const ENEEDAUTH : c_int = 81; - pub const EIPSEC : c_int = 82; - pub const ENOATTR : c_int = 83; - pub const EILSEQ : c_int = 84; - pub const ENOMEDIUM : c_int = 85; - pub const EMEDIUMTYPE : c_int = 86; - pub const EOVERFLOW : c_int = 87; - pub const ECANCELED : c_int = 88; - pub const EIDRM : c_int = 89; - pub const ENOMSG : c_int = 90; - pub const ENOTSUP : c_int = 91; - pub const ELAST : c_int = 91; // must be equal to largest errno + pub const O_RDONLY: c_int = 0; + pub const O_WRONLY: c_int = 1; + pub const O_RDWR: c_int = 2; + pub const O_APPEND: c_int = 8; + pub const O_CREAT: c_int = 512; + pub const O_EXCL: c_int = 2048; + pub const O_NOCTTY: c_int = 32768; + pub const O_TRUNC: c_int = 1024; + pub const S_IFIFO: mode_t = 4096; + pub const S_IFCHR: mode_t = 8192; + pub const S_IFBLK: mode_t = 24576; + pub const S_IFDIR: mode_t = 16384; + pub const S_IFREG: mode_t = 32768; + pub const S_IFLNK: mode_t = 40960; + pub const S_IFSOCK: mode_t = 49152; + pub const S_IFMT: mode_t = 61440; + pub const S_IEXEC: mode_t = 64; + pub const S_IWRITE: mode_t = 128; + pub const S_IREAD: mode_t = 256; + pub const S_IRWXU: mode_t = 448; + pub const S_IXUSR: mode_t = 64; + pub const S_IWUSR: mode_t = 128; + pub const S_IRUSR: mode_t = 256; + pub const S_IRWXG: mode_t = 56; + pub const S_IXGRP: mode_t = 8; + pub const S_IWGRP: mode_t = 16; + pub const S_IRGRP: mode_t = 32; + pub const S_IRWXO: mode_t = 7; + pub const S_IXOTH: mode_t = 1; + pub const S_IWOTH: mode_t = 2; + pub const S_IROTH: mode_t = 4; + pub const F_OK: c_int = 0; + pub const R_OK: c_int = 4; + pub const W_OK: c_int = 2; + pub const X_OK: c_int = 1; + pub const STDIN_FILENO: c_int = 0; + pub const STDOUT_FILENO: c_int = 1; + pub const STDERR_FILENO: c_int = 2; + pub const F_LOCK: c_int = 1; + pub const F_TEST: c_int = 3; + pub const F_TLOCK: c_int = 2; + pub const F_ULOCK: c_int = 0; + pub const SIGHUP: c_int = 1; + pub const SIGINT: c_int = 2; + pub const SIGQUIT: c_int = 3; + pub const SIGILL: c_int = 4; + pub const SIGABRT: c_int = 6; + pub const SIGFPE: c_int = 8; + pub const SIGKILL: c_int = 9; + pub const SIGSEGV: c_int = 11; + pub const SIGPIPE: c_int = 13; + pub const SIGALRM: c_int = 14; + pub const SIGTERM: c_int = 15; + + pub const PROT_NONE: c_int = 0; + pub const PROT_READ: c_int = 1; + pub const PROT_WRITE: c_int = 2; + pub const PROT_EXEC: c_int = 4; + + pub const MAP_FILE: c_int = 0x0000; + pub const MAP_SHARED: c_int = 0x0001; + pub const MAP_PRIVATE: c_int = 0x0002; + pub const MAP_FIXED: c_int = 0x0010; + pub const MAP_ANON: c_int = 0x1000; + + pub const MAP_FAILED: *mut c_void = !0 as *mut c_void; + + pub const MCL_CURRENT: c_int = 0x0001; + pub const MCL_FUTURE: c_int = 0x0002; + + pub const MS_ASYNC: c_int = 0x0001; + pub const MS_SYNC: c_int = 0x0002; + pub const MS_INVALIDATE: c_int = 0x0004; + + pub const EPERM: c_int = 1; + pub const ENOENT: c_int = 2; + pub const ESRCH: c_int = 3; + pub const EINTR: c_int = 4; + pub const EIO: c_int = 5; + pub const ENXIO: c_int = 6; + pub const E2BIG: c_int = 7; + pub const ENOEXEC: c_int = 8; + pub const EBADF: c_int = 9; + pub const ECHILD: c_int = 10; + pub const EDEADLK: c_int = 11; + pub const ENOMEM: c_int = 12; + pub const EACCES: c_int = 13; + pub const EFAULT: c_int = 14; + pub const ENOTBLK: c_int = 15; + pub const EBUSY: c_int = 16; + pub const EEXIST: c_int = 17; + pub const EXDEV: c_int = 18; + pub const ENODEV: c_int = 19; + pub const ENOTDIR: c_int = 20; + pub const EISDIR: c_int = 21; + pub const EINVAL: c_int = 22; + pub const ENFILE: c_int = 23; + pub const EMFILE: c_int = 24; + pub const ENOTTY: c_int = 25; + pub const ETXTBSY: c_int = 26; + pub const EFBIG: c_int = 27; + pub const ENOSPC: c_int = 28; + pub const ESPIPE: c_int = 29; + pub const EROFS: c_int = 30; + pub const EMLINK: c_int = 31; + pub const EPIPE: c_int = 32; + pub const EDOM: c_int = 33; + pub const ERANGE: c_int = 34; + pub const EAGAIN: c_int = 35; + pub const EWOULDBLOCK: c_int = 35; + pub const EINPROGRESS: c_int = 36; + pub const EALREADY: c_int = 37; + pub const ENOTSOCK: c_int = 38; + pub const EDESTADDRREQ: c_int = 39; + pub const EMSGSIZE: c_int = 40; + pub const EPROTOTYPE: c_int = 41; + pub const ENOPROTOOPT: c_int = 42; + pub const EPROTONOSUPPORT: c_int = 43; + pub const ESOCKTNOSUPPORT: c_int = 44; + pub const EOPNOTSUPP: c_int = 45; + pub const EPFNOSUPPORT: c_int = 46; + pub const EAFNOSUPPORT: c_int = 47; + pub const EADDRINUSE: c_int = 48; + pub const EADDRNOTAVAIL: c_int = 49; + pub const ENETDOWN: c_int = 50; + pub const ENETUNREACH: c_int = 51; + pub const ENETRESET: c_int = 52; + pub const ECONNABORTED: c_int = 53; + pub const ECONNRESET: c_int = 54; + pub const ENOBUFS: c_int = 55; + pub const EISCONN: c_int = 56; + pub const ENOTCONN: c_int = 57; + pub const ESHUTDOWN: c_int = 58; + pub const ETOOMANYREFS: c_int = 59; + pub const ETIMEDOUT: c_int = 60; + pub const ECONNREFUSED: c_int = 61; + pub const ELOOP: c_int = 62; + pub const ENAMETOOLONG: c_int = 63; + pub const EHOSTDOWN: c_int = 64; + pub const EHOSTUNREACH: c_int = 65; + pub const ENOTEMPTY: c_int = 66; + pub const EPROCLIM: c_int = 67; + pub const EUSERS: c_int = 68; + pub const EDQUOT: c_int = 69; + pub const ESTALE: c_int = 70; + pub const EREMOTE: c_int = 71; + pub const EBADRPC: c_int = 72; + pub const ERPCMISMATCH: c_int = 73; + pub const EPROGUNAVAIL: c_int = 74; + pub const EPROGMISMATCH: c_int = 75; + pub const EPROCUNAVAIL: c_int = 76; + pub const ENOLCK: c_int = 77; + pub const ENOSYS: c_int = 78; + pub const EFTYPE: c_int = 79; + pub const EAUTH: c_int = 80; + pub const ENEEDAUTH: c_int = 81; + pub const EIPSEC: c_int = 82; + pub const ENOATTR: c_int = 83; + pub const EILSEQ: c_int = 84; + pub const ENOMEDIUM: c_int = 85; + pub const EMEDIUMTYPE: c_int = 86; + pub const EOVERFLOW: c_int = 87; + pub const ECANCELED: c_int = 88; + pub const EIDRM: c_int = 89; + pub const ENOMSG: c_int = 90; + pub const ENOTSUP: c_int = 91; + pub const ELAST: c_int = 91; // must be equal to largest errno } pub mod posix01 { use types::os::arch::c95::{c_int, size_t}; use types::os::common::posix01::rlim_t; - pub const F_DUPFD : c_int = 0; - pub const F_GETFD : c_int = 1; - pub const F_SETFD : c_int = 2; - pub const F_GETFL : c_int = 3; - pub const F_SETFL : c_int = 4; - pub const F_GETOWN : c_int = 5; - pub const F_SETOWN : c_int = 6; - pub const F_GETLK : c_int = 7; - pub const F_SETLK : c_int = 8; - pub const F_SETLKW : c_int = 9; - - pub const SIGTRAP : c_int = 5; + pub const F_DUPFD: c_int = 0; + pub const F_GETFD: c_int = 1; + pub const F_SETFD: c_int = 2; + pub const F_GETFL: c_int = 3; + pub const F_SETFL: c_int = 4; + pub const F_GETOWN: c_int = 5; + pub const F_SETOWN: c_int = 6; + pub const F_GETLK: c_int = 7; + pub const F_SETLK: c_int = 8; + pub const F_SETLKW: c_int = 9; + + pub const SIGTRAP: c_int = 5; pub const SIG_IGN: size_t = 1; - pub const GLOB_APPEND : c_int = 0x0001; - pub const GLOB_DOOFFS : c_int = 0x0002; - pub const GLOB_ERR : c_int = 0x0004; - pub const GLOB_MARK : c_int = 0x0008; - pub const GLOB_NOCHECK : c_int = 0x0010; - pub const GLOB_NOSORT : c_int = 0x0020; - pub const GLOB_NOESCAPE : c_int = 0x1000; - - pub const GLOB_NOSPACE : c_int = -1; - pub const GLOB_ABORTED : c_int = -2; - pub const GLOB_NOMATCH : c_int = -3; - pub const GLOB_NOSYS : c_int = -4; - - pub const POSIX_MADV_NORMAL : c_int = 0; - pub const POSIX_MADV_RANDOM : c_int = 1; - pub const POSIX_MADV_SEQUENTIAL : c_int = 2; - pub const POSIX_MADV_WILLNEED : c_int = 3; - pub const POSIX_MADV_DONTNEED : c_int = 4; - - pub const _SC_IOV_MAX : c_int = 51; - pub const _SC_GETGR_R_SIZE_MAX : c_int = 100; - pub const _SC_GETPW_R_SIZE_MAX : c_int = 101; - pub const _SC_LOGIN_NAME_MAX : c_int = 102; - pub const _SC_MQ_PRIO_MAX : c_int = 59; - pub const _SC_THREAD_ATTR_STACKADDR : c_int = 77; - pub const _SC_THREAD_ATTR_STACKSIZE : c_int = 78; - pub const _SC_THREAD_DESTRUCTOR_ITERATIONS : c_int = 80; - pub const _SC_THREAD_KEYS_MAX : c_int = 81; - pub const _SC_THREAD_PRIO_INHERIT : c_int = 82; - pub const _SC_THREAD_PRIO_PROTECT : c_int = 83; - pub const _SC_THREAD_PRIORITY_SCHEDULING : c_int = 84; - pub const _SC_THREAD_PROCESS_SHARED : c_int = 85; - pub const _SC_THREAD_SAFE_FUNCTIONS : c_int = 103; - pub const _SC_THREAD_STACK_MIN : c_int = 89; - pub const _SC_THREAD_THREADS_MAX : c_int = 90; - pub const _SC_THREADS : c_int = 91; - pub const _SC_TTY_NAME_MAX : c_int = 107; - pub const _SC_ATEXIT_MAX : c_int = 46; - pub const _SC_XOPEN_CRYPT : c_int = 117; - pub const _SC_XOPEN_ENH_I18N : c_int = 118; - pub const _SC_XOPEN_LEGACY : c_int = 119; - pub const _SC_XOPEN_REALTIME : c_int = 120; - pub const _SC_XOPEN_REALTIME_THREADS : c_int = 121; - pub const _SC_XOPEN_SHM : c_int = 30; - pub const _SC_XOPEN_UNIX : c_int = 123; - pub const _SC_XOPEN_VERSION : c_int = 125; - - pub const PTHREAD_CREATE_JOINABLE : c_int = 0; - pub const PTHREAD_CREATE_DETACHED : c_int = 1; - pub const PTHREAD_STACK_MIN : size_t = 2048; - - pub const CLOCK_REALTIME : c_int = 0; - pub const CLOCK_MONOTONIC : c_int = 3; + pub const GLOB_APPEND: c_int = 0x0001; + pub const GLOB_DOOFFS: c_int = 0x0002; + pub const GLOB_ERR: c_int = 0x0004; + pub const GLOB_MARK: c_int = 0x0008; + pub const GLOB_NOCHECK: c_int = 0x0010; + pub const GLOB_NOSORT: c_int = 0x0020; + pub const GLOB_NOESCAPE: c_int = 0x1000; + + pub const GLOB_NOSPACE: c_int = -1; + pub const GLOB_ABORTED: c_int = -2; + pub const GLOB_NOMATCH: c_int = -3; + pub const GLOB_NOSYS: c_int = -4; + + pub const POSIX_MADV_NORMAL: c_int = 0; + pub const POSIX_MADV_RANDOM: c_int = 1; + pub const POSIX_MADV_SEQUENTIAL: c_int = 2; + pub const POSIX_MADV_WILLNEED: c_int = 3; + pub const POSIX_MADV_DONTNEED: c_int = 4; + + pub const _SC_IOV_MAX: c_int = 51; + pub const _SC_GETGR_R_SIZE_MAX: c_int = 100; + pub const _SC_GETPW_R_SIZE_MAX: c_int = 101; + pub const _SC_LOGIN_NAME_MAX: c_int = 102; + pub const _SC_MQ_PRIO_MAX: c_int = 59; + pub const _SC_THREAD_ATTR_STACKADDR: c_int = 77; + pub const _SC_THREAD_ATTR_STACKSIZE: c_int = 78; + pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: c_int = 80; + pub const _SC_THREAD_KEYS_MAX: c_int = 81; + pub const _SC_THREAD_PRIO_INHERIT: c_int = 82; + pub const _SC_THREAD_PRIO_PROTECT: c_int = 83; + pub const _SC_THREAD_PRIORITY_SCHEDULING: c_int = 84; + pub const _SC_THREAD_PROCESS_SHARED: c_int = 85; + pub const _SC_THREAD_SAFE_FUNCTIONS: c_int = 103; + pub const _SC_THREAD_STACK_MIN: c_int = 89; + pub const _SC_THREAD_THREADS_MAX: c_int = 90; + pub const _SC_THREADS: c_int = 91; + pub const _SC_TTY_NAME_MAX: c_int = 107; + pub const _SC_ATEXIT_MAX: c_int = 46; + pub const _SC_XOPEN_CRYPT: c_int = 117; + pub const _SC_XOPEN_ENH_I18N: c_int = 118; + pub const _SC_XOPEN_LEGACY: c_int = 119; + pub const _SC_XOPEN_REALTIME: c_int = 120; + pub const _SC_XOPEN_REALTIME_THREADS: c_int = 121; + pub const _SC_XOPEN_SHM: c_int = 30; + pub const _SC_XOPEN_UNIX: c_int = 123; + pub const _SC_XOPEN_VERSION: c_int = 125; + + pub const PTHREAD_CREATE_JOINABLE: c_int = 0; + pub const PTHREAD_CREATE_DETACHED: c_int = 1; + pub const PTHREAD_STACK_MIN: size_t = 2048; + + pub const CLOCK_REALTIME: c_int = 0; + pub const CLOCK_MONOTONIC: c_int = 3; pub const RLIMIT_CPU: c_int = 0; pub const RLIMIT_FSIZE: c_int = 1; @@ -4737,27 +4995,20 @@ pub mod consts { pub const RUSAGE_CHILDREN: c_int = -1; pub const RUSAGE_THREAD: c_int = 1; } - #[cfg(any(target_os = "bitrig", target_os = "openbsd"))] pub mod posix08 { use types::os::arch::c95::c_int; pub const O_CLOEXEC: c_int = 0x10000; pub const F_DUPFD_CLOEXEC: c_int = 10; } - #[cfg(target_os = "netbsd")] - pub mod posix08 { - use types::os::arch::c95::c_int; - pub const O_CLOEXEC: c_int = 0x400000; - pub const F_DUPFD_CLOEXEC: c_int = 12; - } pub mod bsd44 { use types::os::arch::c95::c_int; - pub const MADV_NORMAL : c_int = 0; - pub const MADV_RANDOM : c_int = 1; - pub const MADV_SEQUENTIAL : c_int = 2; - pub const MADV_WILLNEED : c_int = 3; - pub const MADV_DONTNEED : c_int = 4; - pub const MADV_FREE : c_int = 6; + pub const MADV_NORMAL: c_int = 0; + pub const MADV_RANDOM: c_int = 1; + pub const MADV_SEQUENTIAL: c_int = 2; + pub const MADV_WILLNEED: c_int = 3; + pub const MADV_DONTNEED: c_int = 4; + pub const MADV_FREE: c_int = 6; pub const AF_UNIX: c_int = 1; pub const AF_INET: c_int = 2; @@ -4812,77 +5063,481 @@ pub mod consts { pub mod extra { use types::os::arch::c95::c_int; - pub const O_DSYNC : c_int = 128; // same as SYNC - pub const O_SYNC : c_int = 128; - pub const O_NONBLOCK : c_int = 4; - pub const CTL_KERN : c_int = 1; - pub const KERN_PROC : c_int = 66; + pub const O_DSYNC: c_int = 128; // same as SYNC + pub const O_SYNC: c_int = 128; + pub const O_NONBLOCK: c_int = 4; + pub const CTL_KERN: c_int = 1; + pub const KERN_PROC: c_int = 66; - pub const MAP_COPY : c_int = 0x0002; - pub const MAP_RENAME : c_int = 0x0000; - pub const MAP_NORESERVE : c_int = 0x0000; - pub const MAP_NOEXTEND : c_int = 0x0000; - pub const MAP_HASSEMAPHORE : c_int = 0x0000; + pub const MAP_COPY: c_int = 0x0002; + pub const MAP_RENAME: c_int = 0x0000; + pub const MAP_NORESERVE: c_int = 0x0000; + pub const MAP_NOEXTEND: c_int = 0x0000; + pub const MAP_HASSEMAPHORE: c_int = 0x0000; - pub const IPPROTO_RAW : c_int = 255; + pub const IPPROTO_RAW: c_int = 255; pub const PATH_MAX: c_int = 1024; } pub mod sysconf { use types::os::arch::c95::c_int; - pub const _SC_ARG_MAX : c_int = 1; - pub const _SC_CHILD_MAX : c_int = 2; - pub const _SC_CLK_TCK : c_int = 3; - pub const _SC_NGROUPS_MAX : c_int = 4; - pub const _SC_OPEN_MAX : c_int = 5; - pub const _SC_JOB_CONTROL : c_int = 6; - pub const _SC_SAVED_IDS : c_int = 7; - pub const _SC_VERSION : c_int = 8; - pub const _SC_BC_BASE_MAX : c_int = 9; - pub const _SC_BC_DIM_MAX : c_int = 10; - pub const _SC_BC_SCALE_MAX : c_int = 11; - pub const _SC_BC_STRING_MAX : c_int = 12; - pub const _SC_COLL_WEIGHTS_MAX : c_int = 13; - pub const _SC_EXPR_NEST_MAX : c_int = 14; - pub const _SC_LINE_MAX : c_int = 15; - pub const _SC_RE_DUP_MAX : c_int = 16; - pub const _SC_2_VERSION : c_int = 17; - pub const _SC_2_C_BIND : c_int = 18; - pub const _SC_2_C_DEV : c_int = 19; - pub const _SC_2_CHAR_TERM : c_int = 20; - pub const _SC_2_FORT_DEV : c_int = 21; - pub const _SC_2_FORT_RUN : c_int = 22; - pub const _SC_2_LOCALEDEF : c_int = 23; - pub const _SC_2_SW_DEV : c_int = 24; - pub const _SC_2_UPE : c_int = 25; - pub const _SC_STREAM_MAX : c_int = 26; - pub const _SC_TZNAME_MAX : c_int = 27; - pub const _SC_PAGESIZE : c_int = 28; - pub const _SC_FSYNC : c_int = 29; - pub const _SC_SEM_NSEMS_MAX : c_int = 31; - pub const _SC_SEM_VALUE_MAX : c_int = 32; - pub const _SC_AIO_LISTIO_MAX : c_int = 42; - pub const _SC_AIO_MAX : c_int = 43; - pub const _SC_AIO_PRIO_DELTA_MAX : c_int = 44; - pub const _SC_ASYNCHRONOUS_IO : c_int = 45; - pub const _SC_DELAYTIMER_MAX : c_int = 50; - pub const _SC_MAPPED_FILES : c_int = 53; - pub const _SC_MEMLOCK : c_int = 54; - pub const _SC_MEMLOCK_RANGE : c_int = 55; - pub const _SC_MEMORY_PROTECTION : c_int = 56; - pub const _SC_MESSAGE_PASSING : c_int = 57; - pub const _SC_MQ_OPEN_MAX : c_int = 58; - pub const _SC_PRIORITIZED_IO : c_int = 60; - pub const _SC_PRIORITY_SCHEDULING : c_int = 61; - pub const _SC_REALTIME_SIGNALS : c_int = 64; - pub const _SC_RTSIG_MAX : c_int = 66; - pub const _SC_SEMAPHORES : c_int = 67; - pub const _SC_SHARED_MEMORY_OBJECTS : c_int = 68; - pub const _SC_SIGQUEUE_MAX : c_int = 70; - pub const _SC_SYNCHRONIZED_IO : c_int = 75; - pub const _SC_TIMER_MAX : c_int = 93; - pub const _SC_TIMERS : c_int = 94; + pub const _SC_ARG_MAX: c_int = 1; + pub const _SC_CHILD_MAX: c_int = 2; + pub const _SC_CLK_TCK: c_int = 3; + pub const _SC_NGROUPS_MAX: c_int = 4; + pub const _SC_OPEN_MAX: c_int = 5; + pub const _SC_JOB_CONTROL: c_int = 6; + pub const _SC_SAVED_IDS: c_int = 7; + pub const _SC_VERSION: c_int = 8; + pub const _SC_BC_BASE_MAX: c_int = 9; + pub const _SC_BC_DIM_MAX: c_int = 10; + pub const _SC_BC_SCALE_MAX: c_int = 11; + pub const _SC_BC_STRING_MAX: c_int = 12; + pub const _SC_COLL_WEIGHTS_MAX: c_int = 13; + pub const _SC_EXPR_NEST_MAX: c_int = 14; + pub const _SC_LINE_MAX: c_int = 15; + pub const _SC_RE_DUP_MAX: c_int = 16; + pub const _SC_2_VERSION: c_int = 17; + pub const _SC_2_C_BIND: c_int = 18; + pub const _SC_2_C_DEV: c_int = 19; + pub const _SC_2_CHAR_TERM: c_int = 20; + pub const _SC_2_FORT_DEV: c_int = 21; + pub const _SC_2_FORT_RUN: c_int = 22; + pub const _SC_2_LOCALEDEF: c_int = 23; + pub const _SC_2_SW_DEV: c_int = 24; + pub const _SC_2_UPE: c_int = 25; + pub const _SC_STREAM_MAX: c_int = 26; + pub const _SC_TZNAME_MAX: c_int = 27; + pub const _SC_PAGESIZE: c_int = 28; + pub const _SC_FSYNC: c_int = 29; + pub const _SC_SEM_NSEMS_MAX: c_int = 31; + pub const _SC_SEM_VALUE_MAX: c_int = 32; + pub const _SC_AIO_LISTIO_MAX: c_int = 42; + pub const _SC_AIO_MAX: c_int = 43; + pub const _SC_AIO_PRIO_DELTA_MAX: c_int = 44; + pub const _SC_ASYNCHRONOUS_IO: c_int = 45; + pub const _SC_DELAYTIMER_MAX: c_int = 50; + pub const _SC_MAPPED_FILES: c_int = 53; + pub const _SC_MEMLOCK: c_int = 54; + pub const _SC_MEMLOCK_RANGE: c_int = 55; + pub const _SC_MEMORY_PROTECTION: c_int = 56; + pub const _SC_MESSAGE_PASSING: c_int = 57; + pub const _SC_MQ_OPEN_MAX: c_int = 58; + pub const _SC_PRIORITIZED_IO: c_int = 60; + pub const _SC_PRIORITY_SCHEDULING: c_int = 61; + pub const _SC_REALTIME_SIGNALS: c_int = 64; + pub const _SC_RTSIG_MAX: c_int = 66; + pub const _SC_SEMAPHORES: c_int = 67; + pub const _SC_SHARED_MEMORY_OBJECTS: c_int = 68; + pub const _SC_SIGQUEUE_MAX: c_int = 70; + pub const _SC_SYNCHRONIZED_IO: c_int = 75; + pub const _SC_TIMER_MAX: c_int = 93; + pub const _SC_TIMERS: c_int = 94; + + pub const _PC_NAME_MAX: c_int = 4; + pub const _PC_PATH_MAX: c_int = 5; + } + } + + #[cfg(target_os = "netbsd")] + pub mod os { + pub mod c95 { + use types::os::arch::c95::{c_int, c_uint}; + + pub const EXIT_FAILURE: c_int = 1; + pub const EXIT_SUCCESS: c_int = 0; + pub const RAND_MAX: c_int = 2147483647; + pub const EOF: c_int = -1; + pub const SEEK_SET: c_int = 0; + pub const SEEK_CUR: c_int = 1; + pub const SEEK_END: c_int = 2; + pub const _IOFBF: c_int = 0; + pub const _IONBF: c_int = 2; + pub const _IOLBF: c_int = 1; + pub const BUFSIZ: c_uint = 1024; + pub const FOPEN_MAX: c_uint = 20; + pub const FILENAME_MAX: c_uint = 1024; + pub const L_tmpnam: c_uint = 1024; + pub const TMP_MAX: c_uint = 308915776; + } + pub mod c99 { + } + pub mod posix88 { + use types::common::c95::c_void; + use types::os::arch::c95::c_int; + use types::os::arch::posix88::mode_t; + + pub const O_RDONLY: c_int = 0; + pub const O_WRONLY: c_int = 1; + pub const O_RDWR: c_int = 2; + pub const O_APPEND: c_int = 8; + pub const O_CREAT: c_int = 512; + pub const O_EXCL: c_int = 2048; + pub const O_NOCTTY: c_int = 32768; + pub const O_TRUNC: c_int = 1024; + pub const S_IFIFO: mode_t = 4096; + pub const S_IFCHR: mode_t = 8192; + pub const S_IFBLK: mode_t = 24576; + pub const S_IFDIR: mode_t = 16384; + pub const S_IFREG: mode_t = 32768; + pub const S_IFLNK: mode_t = 40960; + pub const S_IFSOCK: mode_t = 49152; + pub const S_IFMT: mode_t = 61440; + pub const S_IEXEC: mode_t = 64; + pub const S_IWRITE: mode_t = 128; + pub const S_IREAD: mode_t = 256; + pub const S_IRWXU: mode_t = 448; + pub const S_IXUSR: mode_t = 64; + pub const S_IWUSR: mode_t = 128; + pub const S_IRUSR: mode_t = 256; + pub const S_IRWXG: mode_t = 56; + pub const S_IXGRP: mode_t = 8; + pub const S_IWGRP: mode_t = 16; + pub const S_IRGRP: mode_t = 32; + pub const S_IRWXO: mode_t = 7; + pub const S_IXOTH: mode_t = 1; + pub const S_IWOTH: mode_t = 2; + pub const S_IROTH: mode_t = 4; + pub const F_OK: c_int = 0; + pub const R_OK: c_int = 4; + pub const W_OK: c_int = 2; + pub const X_OK: c_int = 1; + pub const STDIN_FILENO: c_int = 0; + pub const STDOUT_FILENO: c_int = 1; + pub const STDERR_FILENO: c_int = 2; + pub const F_LOCK: c_int = 1; + pub const F_TEST: c_int = 3; + pub const F_TLOCK: c_int = 2; + pub const F_ULOCK: c_int = 0; + pub const SIGHUP: c_int = 1; + pub const SIGINT: c_int = 2; + pub const SIGQUIT: c_int = 3; + pub const SIGILL: c_int = 4; + pub const SIGABRT: c_int = 6; + pub const SIGFPE: c_int = 8; + pub const SIGKILL: c_int = 9; + pub const SIGSEGV: c_int = 11; + pub const SIGPIPE: c_int = 13; + pub const SIGALRM: c_int = 14; + pub const SIGTERM: c_int = 15; + + pub const PROT_NONE: c_int = 0; + pub const PROT_READ: c_int = 1; + pub const PROT_WRITE: c_int = 2; + pub const PROT_EXEC: c_int = 4; + + pub const MAP_FILE: c_int = 0; + pub const MAP_SHARED: c_int = 1; + pub const MAP_PRIVATE: c_int = 2; + pub const MAP_FIXED: c_int = 16; + pub const MAP_ANON: c_int = 4096; + + pub const MAP_FAILED: *mut c_void = !0 as *mut c_void; + + pub const MCL_CURRENT: c_int = 1; + pub const MCL_FUTURE: c_int = 2; + + pub const MS_ASYNC: c_int = 1; + pub const MS_SYNC: c_int = 4; + pub const MS_INVALIDATE: c_int = 2; + + pub const EPERM: c_int = 1; + pub const ENOENT: c_int = 2; + pub const ESRCH: c_int = 3; + pub const EINTR: c_int = 4; + pub const EIO: c_int = 5; + pub const ENXIO: c_int = 6; + pub const E2BIG: c_int = 7; + pub const ENOEXEC: c_int = 8; + pub const EBADF: c_int = 9; + pub const ECHILD: c_int = 10; + pub const EDEADLK: c_int = 11; + pub const ENOMEM: c_int = 12; + pub const EACCES: c_int = 13; + pub const EFAULT: c_int = 14; + pub const ENOTBLK: c_int = 15; + pub const EBUSY: c_int = 16; + pub const EEXIST: c_int = 17; + pub const EXDEV: c_int = 18; + pub const ENODEV: c_int = 19; + pub const ENOTDIR: c_int = 20; + pub const EISDIR: c_int = 21; + pub const EINVAL: c_int = 22; + pub const ENFILE: c_int = 23; + pub const EMFILE: c_int = 24; + pub const ENOTTY: c_int = 25; + pub const ETXTBSY: c_int = 26; + pub const EFBIG: c_int = 27; + pub const ENOSPC: c_int = 28; + pub const ESPIPE: c_int = 29; + pub const EROFS: c_int = 30; + pub const EMLINK: c_int = 31; + pub const EPIPE: c_int = 32; + pub const EDOM: c_int = 33; + pub const ERANGE: c_int = 34; + pub const EAGAIN: c_int = 35; + pub const EWOULDBLOCK: c_int = 35; + pub const EINPROGRESS: c_int = 36; + pub const EALREADY: c_int = 37; + pub const ENOTSOCK: c_int = 38; + pub const EDESTADDRREQ: c_int = 39; + pub const EMSGSIZE: c_int = 40; + pub const EPROTOTYPE: c_int = 41; + pub const ENOPROTOOPT: c_int = 42; + pub const EPROTONOSUPPORT: c_int = 43; + pub const ESOCKTNOSUPPORT: c_int = 44; + pub const EOPNOTSUPP: c_int = 45; + pub const EPFNOSUPPORT: c_int = 46; + pub const EAFNOSUPPORT: c_int = 47; + pub const EADDRINUSE: c_int = 48; + pub const EADDRNOTAVAIL: c_int = 49; + pub const ENETDOWN: c_int = 50; + pub const ENETUNREACH: c_int = 51; + pub const ENETRESET: c_int = 52; + pub const ECONNABORTED: c_int = 53; + pub const ECONNRESET: c_int = 54; + pub const ENOBUFS: c_int = 55; + pub const EISCONN: c_int = 56; + pub const ENOTCONN: c_int = 57; + pub const ESHUTDOWN: c_int = 58; + pub const ETOOMANYREFS: c_int = 59; + pub const ETIMEDOUT: c_int = 60; + pub const ECONNREFUSED: c_int = 61; + pub const ELOOP: c_int = 62; + pub const ENAMETOOLONG: c_int = 63; + pub const EHOSTDOWN: c_int = 64; + pub const EHOSTUNREACH: c_int = 65; + pub const ENOTEMPTY: c_int = 66; + pub const EPROCLIM: c_int = 67; + pub const EUSERS: c_int = 68; + pub const EDQUOT: c_int = 69; + pub const ESTALE: c_int = 70; + pub const EREMOTE: c_int = 71; + pub const EBADRPC: c_int = 72; + pub const ERPCMISMATCH: c_int = 73; + pub const EPROGUNAVAIL: c_int = 74; + pub const EPROGMISMATCH: c_int = 75; + pub const EPROCUNAVAIL: c_int = 76; + pub const ENOLCK: c_int = 77; + pub const ENOSYS: c_int = 78; + pub const EFTYPE: c_int = 79; + pub const EAUTH: c_int = 80; + pub const ENEEDAUTH: c_int = 81; + pub const ENOATTR: c_int = 93; + pub const EILSEQ: c_int = 85; + pub const EOVERFLOW: c_int = 84; + pub const ECANCELED: c_int = 87; + pub const EIDRM: c_int = 82; + pub const ENOMSG: c_int = 83; + pub const ENOTSUP: c_int = 86; + pub const ELAST: c_int = 96; + } + pub mod posix01 { + use types::os::arch::c95::{c_int, size_t}; + use types::os::common::posix01::rlim_t; + + pub const F_DUPFD: c_int = 0; + pub const F_GETFD: c_int = 1; + pub const F_SETFD: c_int = 2; + pub const F_GETFL: c_int = 3; + pub const F_SETFL: c_int = 4; + pub const F_GETOWN: c_int = 5; + pub const F_SETOWN: c_int = 6; + pub const F_GETLK: c_int = 7; + pub const F_SETLK: c_int = 8; + pub const F_SETLKW: c_int = 9; + + pub const SIGTRAP: c_int = 5; + pub const SIG_IGN: size_t = 1; + + pub const GLOB_APPEND: c_int = 1; + pub const GLOB_DOOFFS: c_int = 2; + pub const GLOB_ERR: c_int = 4; + pub const GLOB_MARK: c_int = 8; + pub const GLOB_NOCHECK: c_int = 16; + pub const GLOB_NOSORT: c_int = 32; + pub const GLOB_NOESCAPE: c_int = 4096; + + pub const GLOB_NOSPACE: c_int = -1; + pub const GLOB_ABORTED: c_int = -2; + pub const GLOB_NOMATCH: c_int = -3; + pub const GLOB_NOSYS: c_int = -4; + + pub const POSIX_MADV_NORMAL: c_int = 0; + pub const POSIX_MADV_RANDOM: c_int = 1; + pub const POSIX_MADV_SEQUENTIAL: c_int = 2; + pub const POSIX_MADV_WILLNEED: c_int = 3; + pub const POSIX_MADV_DONTNEED: c_int = 4; + + pub const _SC_IOV_MAX: c_int = 32; + pub const _SC_GETGR_R_SIZE_MAX: c_int = 47; + pub const _SC_GETPW_R_SIZE_MAX: c_int = 48; + pub const _SC_LOGIN_NAME_MAX: c_int = 37; + pub const _SC_MQ_PRIO_MAX: c_int = 55; + pub const _SC_THREAD_ATTR_STACKADDR: c_int = 61; + pub const _SC_THREAD_ATTR_STACKSIZE: c_int = 62; + pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: c_int = 57; + pub const _SC_THREAD_KEYS_MAX: c_int = 58; + pub const _SC_THREAD_PRIO_INHERIT: c_int = 64; + pub const _SC_THREAD_PRIO_PROTECT: c_int = 65; + pub const _SC_THREAD_PRIORITY_SCHEDULING: c_int = 63; + pub const _SC_THREAD_PROCESS_SHARED: c_int = 66; + pub const _SC_THREAD_SAFE_FUNCTIONS: c_int = 67; + pub const _SC_THREAD_STACK_MIN: c_int = 59; + pub const _SC_THREAD_THREADS_MAX: c_int = 60; + pub const _SC_THREADS: c_int = 41; + pub const _SC_TTY_NAME_MAX: c_int = 68; + pub const _SC_ATEXIT_MAX: c_int = 40; + pub const _SC_XOPEN_SHM: c_int = 30; + + pub const PTHREAD_CREATE_JOINABLE: c_int = 0; + pub const PTHREAD_CREATE_DETACHED: c_int = 1; + pub const PTHREAD_STACK_MIN: size_t = 2048; + + pub const CLOCK_REALTIME: c_int = 0; + pub const CLOCK_MONOTONIC: c_int = 3; + + pub const RLIMIT_CPU: c_int = 0; + pub const RLIMIT_FSIZE: c_int = 1; + pub const RLIMIT_DATA: c_int = 2; + pub const RLIMIT_STACK: c_int = 3; + pub const RLIMIT_CORE: c_int = 4; + pub const RLIMIT_RSS: c_int = 5; + pub const RLIMIT_MEMLOCK: c_int = 6; + pub const RLIMIT_NPROC: c_int = 7; + pub const RLIMIT_NOFILE: c_int = 8; + pub const RLIM_NLIMITS: c_int = 9; + + pub const RLIM_INFINITY: rlim_t = 0x7fff_ffff_ffff_ffff; + pub const RLIM_SAVED_MAX: rlim_t = RLIM_INFINITY; + pub const RLIM_SAVED_CUR: rlim_t = RLIM_INFINITY; + + pub const RUSAGE_SELF: c_int = 0; + pub const RUSAGE_CHILDREN: c_int = -1; + pub const RUSAGE_THREAD: c_int = 1; + } + pub mod posix08 { + use types::os::arch::c95::c_int; + pub const O_CLOEXEC: c_int = 0x400000; + pub const F_DUPFD_CLOEXEC: c_int = 12; + } + pub mod bsd44 { + use types::os::arch::c95::c_int; + + pub const MADV_NORMAL: c_int = 0; + pub const MADV_RANDOM: c_int = 1; + pub const MADV_SEQUENTIAL: c_int = 2; + pub const MADV_WILLNEED: c_int = 3; + pub const MADV_DONTNEED: c_int = 4; + pub const MADV_FREE: c_int = 6; + + pub const AF_UNIX: c_int = 1; + pub const AF_INET: c_int = 2; + pub const AF_INET6: c_int = 24; + pub const SOCK_STREAM: c_int = 1; + pub const SOCK_DGRAM: c_int = 2; + pub const SOCK_RAW: c_int = 3; + pub const IPPROTO_TCP: c_int = 6; + pub const IPPROTO_IP: c_int = 0; + pub const IPPROTO_IPV6: c_int = 41; + pub const IP_MULTICAST_TTL: c_int = 10; + pub const IP_MULTICAST_LOOP: c_int = 11; + pub const IP_TTL: c_int = 4; + pub const IP_HDRINCL: c_int = 2; + pub const IP_ADD_MEMBERSHIP: c_int = 12; + pub const IP_DROP_MEMBERSHIP: c_int = 13; + + pub const TCP_NODELAY: c_int = 1; + pub const SOL_SOCKET: c_int = 65535; + pub const SO_DEBUG: c_int = 1; + pub const SO_ACCEPTCONN: c_int = 2; + pub const SO_REUSEADDR: c_int = 4; + pub const SO_KEEPALIVE: c_int = 8; + pub const SO_DONTROUTE: c_int = 16; + pub const SO_BROADCAST: c_int = 32; + pub const SO_USELOOPBACK: c_int = 64; + pub const SO_LINGER: c_int = 128; + pub const SO_OOBINLINE: c_int = 256; + pub const SO_REUSEPORT: c_int = 512; + pub const SO_SNDBUF: c_int = 4097; + pub const SO_RCVBUF: c_int = 4098; + pub const SO_SNDLOWAT: c_int = 4099; + pub const SO_RCVLOWAT: c_int = 4100; + pub const SO_SNDTIMEO: c_int = 4107; + pub const SO_RCVTIMEO: c_int = 4108; + pub const SO_ERROR: c_int = 4103; + pub const SO_TYPE: c_int = 4104; + + pub const IFF_LOOPBACK: c_int = 0x8; + + pub const SHUT_RD: c_int = 0; + pub const SHUT_WR: c_int = 1; + pub const SHUT_RDWR: c_int = 2; + + pub const LOCK_SH: c_int = 1; + pub const LOCK_EX: c_int = 2; + pub const LOCK_NB: c_int = 4; + pub const LOCK_UN: c_int = 8; + } + pub mod extra { + use types::os::arch::c95::c_int; + + + pub const MAP_RENAME: c_int = 32; + pub const MAP_NORESERVE: c_int = 64; + pub const MAP_HASSEMAPHORE: c_int = 512; + + pub const IPPROTO_RAW: c_int = 255; + + pub const PATH_MAX: c_int = 1024; + } + pub mod sysconf { + use types::os::arch::c95::c_int; + + pub const _SC_ARG_MAX: c_int = 1; + pub const _SC_CHILD_MAX: c_int = 2; + pub const _SC_CLK_TCK: c_int = 39; + pub const _SC_NGROUPS_MAX: c_int = 4; + pub const _SC_OPEN_MAX: c_int = 5; + pub const _SC_JOB_CONTROL: c_int = 6; + pub const _SC_SAVED_IDS: c_int = 7; + pub const _SC_VERSION: c_int = 8; + pub const _SC_BC_BASE_MAX: c_int = 9; + pub const _SC_BC_DIM_MAX: c_int = 10; + pub const _SC_BC_SCALE_MAX: c_int = 11; + pub const _SC_BC_STRING_MAX: c_int = 12; + pub const _SC_COLL_WEIGHTS_MAX: c_int = 13; + pub const _SC_EXPR_NEST_MAX: c_int = 14; + pub const _SC_LINE_MAX: c_int = 15; + pub const _SC_RE_DUP_MAX: c_int = 16; + pub const _SC_2_VERSION: c_int = 17; + pub const _SC_2_C_BIND: c_int = 18; + pub const _SC_2_C_DEV: c_int = 19; + pub const _SC_2_CHAR_TERM: c_int = 20; + pub const _SC_2_FORT_DEV: c_int = 21; + pub const _SC_2_FORT_RUN: c_int = 22; + pub const _SC_2_LOCALEDEF: c_int = 23; + pub const _SC_2_SW_DEV: c_int = 24; + pub const _SC_2_UPE: c_int = 25; + pub const _SC_STREAM_MAX: c_int = 26; + pub const _SC_TZNAME_MAX: c_int = 27; + pub const _SC_PAGESIZE: c_int = 28; + pub const _SC_FSYNC: c_int = 29; + pub const _SC_AIO_LISTIO_MAX: c_int = 51; + pub const _SC_AIO_MAX: c_int = 52; + pub const _SC_ASYNCHRONOUS_IO: c_int = 50; + pub const _SC_MAPPED_FILES: c_int = 33; + pub const _SC_MEMLOCK: c_int = 34; + pub const _SC_MEMLOCK_RANGE: c_int = 35; + pub const _SC_MEMORY_PROTECTION: c_int = 36; + pub const _SC_MESSAGE_PASSING: c_int = 53; + pub const _SC_MQ_OPEN_MAX: c_int = 54; + pub const _SC_PRIORITY_SCHEDULING: c_int = 56; + pub const _SC_SEMAPHORES: c_int = 42; + pub const _SC_SHARED_MEMORY_OBJECTS: c_int = 87; + pub const _SC_SYNCHRONIZED_IO: c_int = 31; + pub const _SC_TIMERS: c_int = 44; pub const _PC_NAME_MAX: c_int = 4; pub const _PC_PATH_MAX: c_int = 5; @@ -4894,21 +5549,21 @@ pub mod consts { pub mod c95 { use types::os::arch::c95::{c_int, c_uint}; - pub const EXIT_FAILURE : c_int = 1; - pub const EXIT_SUCCESS : c_int = 0; - pub const RAND_MAX : c_int = 2147483647; - pub const EOF : c_int = -1; - pub const SEEK_SET : c_int = 0; - pub const SEEK_CUR : c_int = 1; - pub const SEEK_END : c_int = 2; - pub const _IOFBF : c_int = 0; - pub const _IONBF : c_int = 2; - pub const _IOLBF : c_int = 1; - pub const BUFSIZ : c_uint = 1024; - pub const FOPEN_MAX : c_uint = 20; - pub const FILENAME_MAX : c_uint = 1024; - pub const L_tmpnam : c_uint = 1024; - pub const TMP_MAX : c_uint = 308915776; + pub const EXIT_FAILURE: c_int = 1; + pub const EXIT_SUCCESS: c_int = 0; + pub const RAND_MAX: c_int = 2147483647; + pub const EOF: c_int = -1; + pub const SEEK_SET: c_int = 0; + pub const SEEK_CUR: c_int = 1; + pub const SEEK_END: c_int = 2; + pub const _IOFBF: c_int = 0; + pub const _IONBF: c_int = 2; + pub const _IOLBF: c_int = 1; + pub const BUFSIZ: c_uint = 1024; + pub const FOPEN_MAX: c_uint = 20; + pub const FILENAME_MAX: c_uint = 1024; + pub const L_tmpnam: c_uint = 1024; + pub const TMP_MAX: c_uint = 308915776; } pub mod c99 { } @@ -4917,253 +5572,253 @@ pub mod consts { use types::os::arch::c95::c_int; use types::os::arch::posix88::mode_t; - pub const O_RDONLY : c_int = 0; - pub const O_WRONLY : c_int = 1; - pub const O_RDWR : c_int = 2; - pub const O_APPEND : c_int = 8; - pub const O_CREAT : c_int = 512; - pub const O_EXCL : c_int = 2048; - pub const O_NOCTTY : c_int = 131072; - pub const O_TRUNC : c_int = 1024; - pub const S_IFIFO : mode_t = 4096; - pub const S_IFCHR : mode_t = 8192; - pub const S_IFBLK : mode_t = 24576; - pub const S_IFDIR : mode_t = 16384; - pub const S_IFREG : mode_t = 32768; - pub const S_IFLNK : mode_t = 40960; - pub const S_IFSOCK : mode_t = 49152; - pub const S_IFMT : mode_t = 61440; - pub const S_IEXEC : mode_t = 64; - pub const S_IWRITE : mode_t = 128; - pub const S_IREAD : mode_t = 256; - pub const S_IRWXU : mode_t = 448; - pub const S_IXUSR : mode_t = 64; - pub const S_IWUSR : mode_t = 128; - pub const S_IRUSR : mode_t = 256; - pub const S_IRWXG : mode_t = 56; - pub const S_IXGRP : mode_t = 8; - pub const S_IWGRP : mode_t = 16; - pub const S_IRGRP : mode_t = 32; - pub const S_IRWXO : mode_t = 7; - pub const S_IXOTH : mode_t = 1; - pub const S_IWOTH : mode_t = 2; - pub const S_IROTH : mode_t = 4; - pub const F_OK : c_int = 0; - pub const R_OK : c_int = 4; - pub const W_OK : c_int = 2; - pub const X_OK : c_int = 1; - pub const STDIN_FILENO : c_int = 0; - pub const STDOUT_FILENO : c_int = 1; - pub const STDERR_FILENO : c_int = 2; - pub const F_LOCK : c_int = 1; - pub const F_TEST : c_int = 3; - pub const F_TLOCK : c_int = 2; - pub const F_ULOCK : c_int = 0; - pub const SIGHUP : c_int = 1; - pub const SIGINT : c_int = 2; - pub const SIGQUIT : c_int = 3; - pub const SIGILL : c_int = 4; - pub const SIGABRT : c_int = 6; - pub const SIGFPE : c_int = 8; - pub const SIGKILL : c_int = 9; - pub const SIGSEGV : c_int = 11; - pub const SIGPIPE : c_int = 13; - pub const SIGALRM : c_int = 14; - pub const SIGTERM : c_int = 15; - - pub const PROT_NONE : c_int = 0; - pub const PROT_READ : c_int = 1; - pub const PROT_WRITE : c_int = 2; - pub const PROT_EXEC : c_int = 4; - - pub const MAP_FILE : c_int = 0x0000; - pub const MAP_SHARED : c_int = 0x0001; - pub const MAP_PRIVATE : c_int = 0x0002; - pub const MAP_FIXED : c_int = 0x0010; - pub const MAP_ANON : c_int = 0x1000; - - pub const MAP_FAILED : *mut c_void = !0 as *mut c_void; - - pub const MCL_CURRENT : c_int = 0x0001; - pub const MCL_FUTURE : c_int = 0x0002; - - pub const MS_ASYNC : c_int = 0x0001; - pub const MS_INVALIDATE : c_int = 0x0002; - pub const MS_SYNC : c_int = 0x0010; - - pub const MS_KILLPAGES : c_int = 0x0004; - pub const MS_DEACTIVATE : c_int = 0x0008; - - pub const EPERM : c_int = 1; - pub const ENOENT : c_int = 2; - pub const ESRCH : c_int = 3; - pub const EINTR : c_int = 4; - pub const EIO : c_int = 5; - pub const ENXIO : c_int = 6; - pub const E2BIG : c_int = 7; - pub const ENOEXEC : c_int = 8; - pub const EBADF : c_int = 9; - pub const ECHILD : c_int = 10; - pub const EDEADLK : c_int = 11; - pub const ENOMEM : c_int = 12; - pub const EACCES : c_int = 13; - pub const EFAULT : c_int = 14; - pub const ENOTBLK : c_int = 15; - pub const EBUSY : c_int = 16; - pub const EEXIST : c_int = 17; - pub const EXDEV : c_int = 18; - pub const ENODEV : c_int = 19; - pub const ENOTDIR : c_int = 20; - pub const EISDIR : c_int = 21; - pub const EINVAL : c_int = 22; - pub const ENFILE : c_int = 23; - pub const EMFILE : c_int = 24; - pub const ENOTTY : c_int = 25; - pub const ETXTBSY : c_int = 26; - pub const EFBIG : c_int = 27; - pub const ENOSPC : c_int = 28; - pub const ESPIPE : c_int = 29; - pub const EROFS : c_int = 30; - pub const EMLINK : c_int = 31; - pub const EPIPE : c_int = 32; - pub const EDOM : c_int = 33; - pub const ERANGE : c_int = 34; - pub const EAGAIN : c_int = 35; - pub const EWOULDBLOCK : c_int = EAGAIN; - pub const EINPROGRESS : c_int = 36; - pub const EALREADY : c_int = 37; - pub const ENOTSOCK : c_int = 38; - pub const EDESTADDRREQ : c_int = 39; - pub const EMSGSIZE : c_int = 40; - pub const EPROTOTYPE : c_int = 41; - pub const ENOPROTOOPT : c_int = 42; - pub const EPROTONOSUPPORT : c_int = 43; - pub const ESOCKTNOSUPPORT : c_int = 44; - pub const ENOTSUP : c_int = 45; - pub const EPFNOSUPPORT : c_int = 46; - pub const EAFNOSUPPORT : c_int = 47; - pub const EADDRINUSE : c_int = 48; - pub const EADDRNOTAVAIL : c_int = 49; - pub const ENETDOWN : c_int = 50; - pub const ENETUNREACH : c_int = 51; - pub const ENETRESET : c_int = 52; - pub const ECONNABORTED : c_int = 53; - pub const ECONNRESET : c_int = 54; - pub const ENOBUFS : c_int = 55; - pub const EISCONN : c_int = 56; - pub const ENOTCONN : c_int = 57; - pub const ESHUTDOWN : c_int = 58; - pub const ETOOMANYREFS : c_int = 59; - pub const ETIMEDOUT : c_int = 60; - pub const ECONNREFUSED : c_int = 61; - pub const ELOOP : c_int = 62; - pub const ENAMETOOLONG : c_int = 63; - pub const EHOSTDOWN : c_int = 64; - pub const EHOSTUNREACH : c_int = 65; - pub const ENOTEMPTY : c_int = 66; - pub const EPROCLIM : c_int = 67; - pub const EUSERS : c_int = 68; - pub const EDQUOT : c_int = 69; - pub const ESTALE : c_int = 70; - pub const EREMOTE : c_int = 71; - pub const EBADRPC : c_int = 72; - pub const ERPCMISMATCH : c_int = 73; - pub const EPROGUNAVAIL : c_int = 74; - pub const EPROGMISMATCH : c_int = 75; - pub const EPROCUNAVAIL : c_int = 76; - pub const ENOLCK : c_int = 77; - pub const ENOSYS : c_int = 78; - pub const EFTYPE : c_int = 79; - pub const EAUTH : c_int = 80; - pub const ENEEDAUTH : c_int = 81; - pub const EPWROFF : c_int = 82; - pub const EDEVERR : c_int = 83; - pub const EOVERFLOW : c_int = 84; - pub const EBADEXEC : c_int = 85; - pub const EBADARCH : c_int = 86; - pub const ESHLIBVERS : c_int = 87; - pub const EBADMACHO : c_int = 88; - pub const ECANCELED : c_int = 89; - pub const EIDRM : c_int = 90; - pub const ENOMSG : c_int = 91; - pub const EILSEQ : c_int = 92; - pub const ENOATTR : c_int = 93; - pub const EBADMSG : c_int = 94; - pub const EMULTIHOP : c_int = 95; - pub const ENODATA : c_int = 96; - pub const ENOLINK : c_int = 97; - pub const ENOSR : c_int = 98; - pub const ENOSTR : c_int = 99; - pub const EPROTO : c_int = 100; - pub const ETIME : c_int = 101; - pub const EOPNOTSUPP : c_int = 102; - pub const ENOPOLICY : c_int = 103; - pub const ENOTRECOVERABLE : c_int = 104; - pub const EOWNERDEAD : c_int = 105; - pub const EQFULL : c_int = 106; - pub const ELAST : c_int = 106; + pub const O_RDONLY: c_int = 0; + pub const O_WRONLY: c_int = 1; + pub const O_RDWR: c_int = 2; + pub const O_APPEND: c_int = 8; + pub const O_CREAT: c_int = 512; + pub const O_EXCL: c_int = 2048; + pub const O_NOCTTY: c_int = 131072; + pub const O_TRUNC: c_int = 1024; + pub const S_IFIFO: mode_t = 4096; + pub const S_IFCHR: mode_t = 8192; + pub const S_IFBLK: mode_t = 24576; + pub const S_IFDIR: mode_t = 16384; + pub const S_IFREG: mode_t = 32768; + pub const S_IFLNK: mode_t = 40960; + pub const S_IFSOCK: mode_t = 49152; + pub const S_IFMT: mode_t = 61440; + pub const S_IEXEC: mode_t = 64; + pub const S_IWRITE: mode_t = 128; + pub const S_IREAD: mode_t = 256; + pub const S_IRWXU: mode_t = 448; + pub const S_IXUSR: mode_t = 64; + pub const S_IWUSR: mode_t = 128; + pub const S_IRUSR: mode_t = 256; + pub const S_IRWXG: mode_t = 56; + pub const S_IXGRP: mode_t = 8; + pub const S_IWGRP: mode_t = 16; + pub const S_IRGRP: mode_t = 32; + pub const S_IRWXO: mode_t = 7; + pub const S_IXOTH: mode_t = 1; + pub const S_IWOTH: mode_t = 2; + pub const S_IROTH: mode_t = 4; + pub const F_OK: c_int = 0; + pub const R_OK: c_int = 4; + pub const W_OK: c_int = 2; + pub const X_OK: c_int = 1; + pub const STDIN_FILENO: c_int = 0; + pub const STDOUT_FILENO: c_int = 1; + pub const STDERR_FILENO: c_int = 2; + pub const F_LOCK: c_int = 1; + pub const F_TEST: c_int = 3; + pub const F_TLOCK: c_int = 2; + pub const F_ULOCK: c_int = 0; + pub const SIGHUP: c_int = 1; + pub const SIGINT: c_int = 2; + pub const SIGQUIT: c_int = 3; + pub const SIGILL: c_int = 4; + pub const SIGABRT: c_int = 6; + pub const SIGFPE: c_int = 8; + pub const SIGKILL: c_int = 9; + pub const SIGSEGV: c_int = 11; + pub const SIGPIPE: c_int = 13; + pub const SIGALRM: c_int = 14; + pub const SIGTERM: c_int = 15; + + pub const PROT_NONE: c_int = 0; + pub const PROT_READ: c_int = 1; + pub const PROT_WRITE: c_int = 2; + pub const PROT_EXEC: c_int = 4; + + pub const MAP_FILE: c_int = 0x0000; + pub const MAP_SHARED: c_int = 0x0001; + pub const MAP_PRIVATE: c_int = 0x0002; + pub const MAP_FIXED: c_int = 0x0010; + pub const MAP_ANON: c_int = 0x1000; + + pub const MAP_FAILED: *mut c_void = !0 as *mut c_void; + + pub const MCL_CURRENT: c_int = 0x0001; + pub const MCL_FUTURE: c_int = 0x0002; + + pub const MS_ASYNC: c_int = 0x0001; + pub const MS_INVALIDATE: c_int = 0x0002; + pub const MS_SYNC: c_int = 0x0010; + + pub const MS_KILLPAGES: c_int = 0x0004; + pub const MS_DEACTIVATE: c_int = 0x0008; + + pub const EPERM: c_int = 1; + pub const ENOENT: c_int = 2; + pub const ESRCH: c_int = 3; + pub const EINTR: c_int = 4; + pub const EIO: c_int = 5; + pub const ENXIO: c_int = 6; + pub const E2BIG: c_int = 7; + pub const ENOEXEC: c_int = 8; + pub const EBADF: c_int = 9; + pub const ECHILD: c_int = 10; + pub const EDEADLK: c_int = 11; + pub const ENOMEM: c_int = 12; + pub const EACCES: c_int = 13; + pub const EFAULT: c_int = 14; + pub const ENOTBLK: c_int = 15; + pub const EBUSY: c_int = 16; + pub const EEXIST: c_int = 17; + pub const EXDEV: c_int = 18; + pub const ENODEV: c_int = 19; + pub const ENOTDIR: c_int = 20; + pub const EISDIR: c_int = 21; + pub const EINVAL: c_int = 22; + pub const ENFILE: c_int = 23; + pub const EMFILE: c_int = 24; + pub const ENOTTY: c_int = 25; + pub const ETXTBSY: c_int = 26; + pub const EFBIG: c_int = 27; + pub const ENOSPC: c_int = 28; + pub const ESPIPE: c_int = 29; + pub const EROFS: c_int = 30; + pub const EMLINK: c_int = 31; + pub const EPIPE: c_int = 32; + pub const EDOM: c_int = 33; + pub const ERANGE: c_int = 34; + pub const EAGAIN: c_int = 35; + pub const EWOULDBLOCK: c_int = EAGAIN; + pub const EINPROGRESS: c_int = 36; + pub const EALREADY: c_int = 37; + pub const ENOTSOCK: c_int = 38; + pub const EDESTADDRREQ: c_int = 39; + pub const EMSGSIZE: c_int = 40; + pub const EPROTOTYPE: c_int = 41; + pub const ENOPROTOOPT: c_int = 42; + pub const EPROTONOSUPPORT: c_int = 43; + pub const ESOCKTNOSUPPORT: c_int = 44; + pub const ENOTSUP: c_int = 45; + pub const EPFNOSUPPORT: c_int = 46; + pub const EAFNOSUPPORT: c_int = 47; + pub const EADDRINUSE: c_int = 48; + pub const EADDRNOTAVAIL: c_int = 49; + pub const ENETDOWN: c_int = 50; + pub const ENETUNREACH: c_int = 51; + pub const ENETRESET: c_int = 52; + pub const ECONNABORTED: c_int = 53; + pub const ECONNRESET: c_int = 54; + pub const ENOBUFS: c_int = 55; + pub const EISCONN: c_int = 56; + pub const ENOTCONN: c_int = 57; + pub const ESHUTDOWN: c_int = 58; + pub const ETOOMANYREFS: c_int = 59; + pub const ETIMEDOUT: c_int = 60; + pub const ECONNREFUSED: c_int = 61; + pub const ELOOP: c_int = 62; + pub const ENAMETOOLONG: c_int = 63; + pub const EHOSTDOWN: c_int = 64; + pub const EHOSTUNREACH: c_int = 65; + pub const ENOTEMPTY: c_int = 66; + pub const EPROCLIM: c_int = 67; + pub const EUSERS: c_int = 68; + pub const EDQUOT: c_int = 69; + pub const ESTALE: c_int = 70; + pub const EREMOTE: c_int = 71; + pub const EBADRPC: c_int = 72; + pub const ERPCMISMATCH: c_int = 73; + pub const EPROGUNAVAIL: c_int = 74; + pub const EPROGMISMATCH: c_int = 75; + pub const EPROCUNAVAIL: c_int = 76; + pub const ENOLCK: c_int = 77; + pub const ENOSYS: c_int = 78; + pub const EFTYPE: c_int = 79; + pub const EAUTH: c_int = 80; + pub const ENEEDAUTH: c_int = 81; + pub const EPWROFF: c_int = 82; + pub const EDEVERR: c_int = 83; + pub const EOVERFLOW: c_int = 84; + pub const EBADEXEC: c_int = 85; + pub const EBADARCH: c_int = 86; + pub const ESHLIBVERS: c_int = 87; + pub const EBADMACHO: c_int = 88; + pub const ECANCELED: c_int = 89; + pub const EIDRM: c_int = 90; + pub const ENOMSG: c_int = 91; + pub const EILSEQ: c_int = 92; + pub const ENOATTR: c_int = 93; + pub const EBADMSG: c_int = 94; + pub const EMULTIHOP: c_int = 95; + pub const ENODATA: c_int = 96; + pub const ENOLINK: c_int = 97; + pub const ENOSR: c_int = 98; + pub const ENOSTR: c_int = 99; + pub const EPROTO: c_int = 100; + pub const ETIME: c_int = 101; + pub const EOPNOTSUPP: c_int = 102; + pub const ENOPOLICY: c_int = 103; + pub const ENOTRECOVERABLE: c_int = 104; + pub const EOWNERDEAD: c_int = 105; + pub const EQFULL: c_int = 106; + pub const ELAST: c_int = 106; } pub mod posix01 { use types::os::arch::c95::{c_int, size_t}; use types::os::common::posix01::rlim_t; - pub const F_DUPFD : c_int = 0; - pub const F_GETFD : c_int = 1; - pub const F_SETFD : c_int = 2; - pub const F_GETFL : c_int = 3; - pub const F_SETFL : c_int = 4; + pub const F_DUPFD: c_int = 0; + pub const F_GETFD: c_int = 1; + pub const F_SETFD: c_int = 2; + pub const F_GETFL: c_int = 3; + pub const F_SETFL: c_int = 4; - pub const O_ACCMODE : c_int = 3; + pub const O_ACCMODE: c_int = 3; - pub const SIGTRAP : c_int = 5; + pub const SIGTRAP: c_int = 5; pub const SIG_IGN: size_t = 1; - pub const GLOB_APPEND : c_int = 0x0001; - pub const GLOB_DOOFFS : c_int = 0x0002; - pub const GLOB_ERR : c_int = 0x0004; - pub const GLOB_MARK : c_int = 0x0008; - pub const GLOB_NOCHECK : c_int = 0x0010; - pub const GLOB_NOSORT : c_int = 0x0020; - pub const GLOB_NOESCAPE : c_int = 0x2000; - - pub const GLOB_NOSPACE : c_int = -1; - pub const GLOB_ABORTED : c_int = -2; - pub const GLOB_NOMATCH : c_int = -3; - - pub const POSIX_MADV_NORMAL : c_int = 0; - pub const POSIX_MADV_RANDOM : c_int = 1; - pub const POSIX_MADV_SEQUENTIAL : c_int = 2; - pub const POSIX_MADV_WILLNEED : c_int = 3; - pub const POSIX_MADV_DONTNEED : c_int = 4; - - pub const _SC_IOV_MAX : c_int = 56; - pub const _SC_GETGR_R_SIZE_MAX : c_int = 70; - pub const _SC_GETPW_R_SIZE_MAX : c_int = 71; - pub const _SC_LOGIN_NAME_MAX : c_int = 73; - pub const _SC_MQ_PRIO_MAX : c_int = 75; - pub const _SC_THREAD_ATTR_STACKADDR : c_int = 82; - pub const _SC_THREAD_ATTR_STACKSIZE : c_int = 83; - pub const _SC_THREAD_DESTRUCTOR_ITERATIONS : c_int = 85; - pub const _SC_THREAD_KEYS_MAX : c_int = 86; - pub const _SC_THREAD_PRIO_INHERIT : c_int = 87; - pub const _SC_THREAD_PRIO_PROTECT : c_int = 88; - pub const _SC_THREAD_PRIORITY_SCHEDULING : c_int = 89; - pub const _SC_THREAD_PROCESS_SHARED : c_int = 90; - pub const _SC_THREAD_SAFE_FUNCTIONS : c_int = 91; - pub const _SC_THREAD_STACK_MIN : c_int = 93; - pub const _SC_THREAD_THREADS_MAX : c_int = 94; - pub const _SC_THREADS : c_int = 96; - pub const _SC_TTY_NAME_MAX : c_int = 101; - pub const _SC_ATEXIT_MAX : c_int = 107; - pub const _SC_XOPEN_CRYPT : c_int = 108; - pub const _SC_XOPEN_ENH_I18N : c_int = 109; - pub const _SC_XOPEN_LEGACY : c_int = 110; - pub const _SC_XOPEN_REALTIME : c_int = 111; - pub const _SC_XOPEN_REALTIME_THREADS : c_int = 112; - pub const _SC_XOPEN_SHM : c_int = 113; - pub const _SC_XOPEN_UNIX : c_int = 115; - pub const _SC_XOPEN_VERSION : c_int = 116; - pub const _SC_XOPEN_XCU_VERSION : c_int = 121; + pub const GLOB_APPEND: c_int = 0x0001; + pub const GLOB_DOOFFS: c_int = 0x0002; + pub const GLOB_ERR: c_int = 0x0004; + pub const GLOB_MARK: c_int = 0x0008; + pub const GLOB_NOCHECK: c_int = 0x0010; + pub const GLOB_NOSORT: c_int = 0x0020; + pub const GLOB_NOESCAPE: c_int = 0x2000; + + pub const GLOB_NOSPACE: c_int = -1; + pub const GLOB_ABORTED: c_int = -2; + pub const GLOB_NOMATCH: c_int = -3; + + pub const POSIX_MADV_NORMAL: c_int = 0; + pub const POSIX_MADV_RANDOM: c_int = 1; + pub const POSIX_MADV_SEQUENTIAL: c_int = 2; + pub const POSIX_MADV_WILLNEED: c_int = 3; + pub const POSIX_MADV_DONTNEED: c_int = 4; + + pub const _SC_IOV_MAX: c_int = 56; + pub const _SC_GETGR_R_SIZE_MAX: c_int = 70; + pub const _SC_GETPW_R_SIZE_MAX: c_int = 71; + pub const _SC_LOGIN_NAME_MAX: c_int = 73; + pub const _SC_MQ_PRIO_MAX: c_int = 75; + pub const _SC_THREAD_ATTR_STACKADDR: c_int = 82; + pub const _SC_THREAD_ATTR_STACKSIZE: c_int = 83; + pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: c_int = 85; + pub const _SC_THREAD_KEYS_MAX: c_int = 86; + pub const _SC_THREAD_PRIO_INHERIT: c_int = 87; + pub const _SC_THREAD_PRIO_PROTECT: c_int = 88; + pub const _SC_THREAD_PRIORITY_SCHEDULING: c_int = 89; + pub const _SC_THREAD_PROCESS_SHARED: c_int = 90; + pub const _SC_THREAD_SAFE_FUNCTIONS: c_int = 91; + pub const _SC_THREAD_STACK_MIN: c_int = 93; + pub const _SC_THREAD_THREADS_MAX: c_int = 94; + pub const _SC_THREADS: c_int = 96; + pub const _SC_TTY_NAME_MAX: c_int = 101; + pub const _SC_ATEXIT_MAX: c_int = 107; + pub const _SC_XOPEN_CRYPT: c_int = 108; + pub const _SC_XOPEN_ENH_I18N: c_int = 109; + pub const _SC_XOPEN_LEGACY: c_int = 110; + pub const _SC_XOPEN_REALTIME: c_int = 111; + pub const _SC_XOPEN_REALTIME_THREADS: c_int = 112; + pub const _SC_XOPEN_SHM: c_int = 113; + pub const _SC_XOPEN_UNIX: c_int = 115; + pub const _SC_XOPEN_VERSION: c_int = 116; + pub const _SC_XOPEN_XCU_VERSION: c_int = 121; pub const PTHREAD_CREATE_JOINABLE: c_int = 1; pub const PTHREAD_CREATE_DETACHED: c_int = 2; @@ -5195,22 +5850,22 @@ pub mod consts { pub mod bsd44 { use types::os::arch::c95::c_int; - pub const MADV_NORMAL : c_int = 0; - pub const MADV_RANDOM : c_int = 1; - pub const MADV_SEQUENTIAL : c_int = 2; - pub const MADV_WILLNEED : c_int = 3; - pub const MADV_DONTNEED : c_int = 4; - pub const MADV_FREE : c_int = 5; - pub const MADV_ZERO_WIRED_PAGES : c_int = 6; - pub const MADV_FREE_REUSABLE : c_int = 7; - pub const MADV_FREE_REUSE : c_int = 8; - pub const MADV_CAN_REUSE : c_int = 9; - - pub const MINCORE_INCORE : c_int = 0x1; - pub const MINCORE_REFERENCED : c_int = 0x2; - pub const MINCORE_MODIFIED : c_int = 0x4; - pub const MINCORE_REFERENCED_OTHER : c_int = 0x8; - pub const MINCORE_MODIFIED_OTHER : c_int = 0x10; + pub const MADV_NORMAL: c_int = 0; + pub const MADV_RANDOM: c_int = 1; + pub const MADV_SEQUENTIAL: c_int = 2; + pub const MADV_WILLNEED: c_int = 3; + pub const MADV_DONTNEED: c_int = 4; + pub const MADV_FREE: c_int = 5; + pub const MADV_ZERO_WIRED_PAGES: c_int = 6; + pub const MADV_FREE_REUSABLE: c_int = 7; + pub const MADV_FREE_REUSE: c_int = 8; + pub const MADV_CAN_REUSE: c_int = 9; + + pub const MINCORE_INCORE: c_int = 0x1; + pub const MINCORE_REFERENCED: c_int = 0x2; + pub const MINCORE_MODIFIED: c_int = 0x4; + pub const MINCORE_REFERENCED_OTHER: c_int = 0x8; + pub const MINCORE_MODIFIED_OTHER: c_int = 0x10; pub const AF_UNIX: c_int = 1; pub const AF_INET: c_int = 2; @@ -5267,22 +5922,22 @@ pub mod consts { pub mod extra { use types::os::arch::c95::c_int; - pub const O_DSYNC : c_int = 4194304; - pub const O_SYNC : c_int = 128; - pub const O_NONBLOCK : c_int = 4; - pub const F_GETPATH : c_int = 50; - pub const F_FULLFSYNC : c_int = 51; + pub const O_DSYNC: c_int = 4194304; + pub const O_SYNC: c_int = 128; + pub const O_NONBLOCK: c_int = 4; + pub const F_GETPATH: c_int = 50; + pub const F_FULLFSYNC: c_int = 51; + + pub const MAP_COPY: c_int = 0x0002; + pub const MAP_RENAME: c_int = 0x0020; + pub const MAP_NORESERVE: c_int = 0x0040; + pub const MAP_NOEXTEND: c_int = 0x0100; + pub const MAP_HASSEMAPHORE: c_int = 0x0200; + pub const MAP_NOCACHE: c_int = 0x0400; + pub const MAP_JIT: c_int = 0x0800; + pub const MAP_STACK: c_int = 0; - pub const MAP_COPY : c_int = 0x0002; - pub const MAP_RENAME : c_int = 0x0020; - pub const MAP_NORESERVE : c_int = 0x0040; - pub const MAP_NOEXTEND : c_int = 0x0100; - pub const MAP_HASSEMAPHORE : c_int = 0x0200; - pub const MAP_NOCACHE : c_int = 0x0400; - pub const MAP_JIT : c_int = 0x0800; - pub const MAP_STACK : c_int = 0; - - pub const IPPROTO_RAW : c_int = 255; + pub const IPPROTO_RAW: c_int = 255; pub const SO_NREAD: c_int = 0x1020; pub const SO_NKE: c_int = 0x1021; @@ -5298,106 +5953,106 @@ pub mod consts { pub mod sysconf { use types::os::arch::c95::c_int; - pub const _SC_ARG_MAX : c_int = 1; - pub const _SC_CHILD_MAX : c_int = 2; - pub const _SC_CLK_TCK : c_int = 3; - pub const _SC_NGROUPS_MAX : c_int = 4; - pub const _SC_OPEN_MAX : c_int = 5; - pub const _SC_JOB_CONTROL : c_int = 6; - pub const _SC_SAVED_IDS : c_int = 7; - pub const _SC_VERSION : c_int = 8; - pub const _SC_BC_BASE_MAX : c_int = 9; - pub const _SC_BC_DIM_MAX : c_int = 10; - pub const _SC_BC_SCALE_MAX : c_int = 11; - pub const _SC_BC_STRING_MAX : c_int = 12; - pub const _SC_COLL_WEIGHTS_MAX : c_int = 13; - pub const _SC_EXPR_NEST_MAX : c_int = 14; - pub const _SC_LINE_MAX : c_int = 15; - pub const _SC_RE_DUP_MAX : c_int = 16; - pub const _SC_2_VERSION : c_int = 17; - pub const _SC_2_C_BIND : c_int = 18; - pub const _SC_2_C_DEV : c_int = 19; - pub const _SC_2_CHAR_TERM : c_int = 20; - pub const _SC_2_FORT_DEV : c_int = 21; - pub const _SC_2_FORT_RUN : c_int = 22; - pub const _SC_2_LOCALEDEF : c_int = 23; - pub const _SC_2_SW_DEV : c_int = 24; - pub const _SC_2_UPE : c_int = 25; - pub const _SC_STREAM_MAX : c_int = 26; - pub const _SC_TZNAME_MAX : c_int = 27; - pub const _SC_ASYNCHRONOUS_IO : c_int = 28; - pub const _SC_PAGESIZE : c_int = 29; - pub const _SC_MEMLOCK : c_int = 30; - pub const _SC_MEMLOCK_RANGE : c_int = 31; - pub const _SC_MEMORY_PROTECTION : c_int = 32; - pub const _SC_MESSAGE_PASSING : c_int = 33; - pub const _SC_PRIORITIZED_IO : c_int = 34; - pub const _SC_PRIORITY_SCHEDULING : c_int = 35; - pub const _SC_REALTIME_SIGNALS : c_int = 36; - pub const _SC_SEMAPHORES : c_int = 37; - pub const _SC_FSYNC : c_int = 38; - pub const _SC_SHARED_MEMORY_OBJECTS : c_int = 39; - pub const _SC_SYNCHRONIZED_IO : c_int = 40; - pub const _SC_TIMERS : c_int = 41; - pub const _SC_AIO_LISTIO_MAX : c_int = 42; - pub const _SC_AIO_MAX : c_int = 43; - pub const _SC_AIO_PRIO_DELTA_MAX : c_int = 44; - pub const _SC_DELAYTIMER_MAX : c_int = 45; - pub const _SC_MQ_OPEN_MAX : c_int = 46; - pub const _SC_MAPPED_FILES : c_int = 47; - pub const _SC_RTSIG_MAX : c_int = 48; - pub const _SC_SEM_NSEMS_MAX : c_int = 49; - pub const _SC_SEM_VALUE_MAX : c_int = 50; - pub const _SC_SIGQUEUE_MAX : c_int = 51; - pub const _SC_TIMER_MAX : c_int = 52; - pub const _SC_NPROCESSORS_CONF : c_int = 57; - pub const _SC_NPROCESSORS_ONLN : c_int = 58; - pub const _SC_2_PBS : c_int = 59; - pub const _SC_2_PBS_ACCOUNTING : c_int = 60; - pub const _SC_2_PBS_CHECKPOINT : c_int = 61; - pub const _SC_2_PBS_LOCATE : c_int = 62; - pub const _SC_2_PBS_MESSAGE : c_int = 63; - pub const _SC_2_PBS_TRACK : c_int = 64; - pub const _SC_ADVISORY_INFO : c_int = 65; - pub const _SC_BARRIERS : c_int = 66; - pub const _SC_CLOCK_SELECTION : c_int = 67; - pub const _SC_CPUTIME : c_int = 68; - pub const _SC_FILE_LOCKING : c_int = 69; - pub const _SC_HOST_NAME_MAX : c_int = 72; - pub const _SC_MONOTONIC_CLOCK : c_int = 74; - pub const _SC_READER_WRITER_LOCKS : c_int = 76; - pub const _SC_REGEXP : c_int = 77; - pub const _SC_SHELL : c_int = 78; - pub const _SC_SPAWN : c_int = 79; - pub const _SC_SPIN_LOCKS : c_int = 80; - pub const _SC_SPORADIC_SERVER : c_int = 81; - pub const _SC_THREAD_CPUTIME : c_int = 84; - pub const _SC_THREAD_SPORADIC_SERVER : c_int = 92; - pub const _SC_TIMEOUTS : c_int = 95; - pub const _SC_TRACE : c_int = 97; - pub const _SC_TRACE_EVENT_FILTER : c_int = 98; - pub const _SC_TRACE_INHERIT : c_int = 99; - pub const _SC_TRACE_LOG : c_int = 100; - pub const _SC_TYPED_MEMORY_OBJECTS : c_int = 102; - pub const _SC_V6_ILP32_OFF32 : c_int = 103; - pub const _SC_V6_ILP32_OFFBIG : c_int = 104; - pub const _SC_V6_LP64_OFF64 : c_int = 105; - pub const _SC_V6_LPBIG_OFFBIG : c_int = 106; - pub const _SC_IPV6 : c_int = 118; - pub const _SC_RAW_SOCKETS : c_int = 119; - pub const _SC_SYMLOOP_MAX : c_int = 120; - pub const _SC_PAGE_SIZE : c_int = _SC_PAGESIZE; - pub const _SC_XOPEN_STREAMS : c_int = 114; - pub const _SC_XBS5_ILP32_OFF32 : c_int = 122; - pub const _SC_XBS5_ILP32_OFFBIG : c_int = 123; - pub const _SC_XBS5_LP64_OFF64 : c_int = 124; - pub const _SC_XBS5_LPBIG_OFFBIG : c_int = 125; - pub const _SC_SS_REPL_MAX : c_int = 126; - pub const _SC_TRACE_EVENT_NAME_MAX : c_int = 127; - pub const _SC_TRACE_NAME_MAX : c_int = 128; - pub const _SC_TRACE_SYS_MAX : c_int = 129; - pub const _SC_TRACE_USER_EVENT_MAX : c_int = 130; - pub const _SC_PASS_MAX : c_int = 131; + pub const _SC_ARG_MAX: c_int = 1; + pub const _SC_CHILD_MAX: c_int = 2; + pub const _SC_CLK_TCK: c_int = 3; + pub const _SC_NGROUPS_MAX: c_int = 4; + pub const _SC_OPEN_MAX: c_int = 5; + pub const _SC_JOB_CONTROL: c_int = 6; + pub const _SC_SAVED_IDS: c_int = 7; + pub const _SC_VERSION: c_int = 8; + pub const _SC_BC_BASE_MAX: c_int = 9; + pub const _SC_BC_DIM_MAX: c_int = 10; + pub const _SC_BC_SCALE_MAX: c_int = 11; + pub const _SC_BC_STRING_MAX: c_int = 12; + pub const _SC_COLL_WEIGHTS_MAX: c_int = 13; + pub const _SC_EXPR_NEST_MAX: c_int = 14; + pub const _SC_LINE_MAX: c_int = 15; + pub const _SC_RE_DUP_MAX: c_int = 16; + pub const _SC_2_VERSION: c_int = 17; + pub const _SC_2_C_BIND: c_int = 18; + pub const _SC_2_C_DEV: c_int = 19; + pub const _SC_2_CHAR_TERM: c_int = 20; + pub const _SC_2_FORT_DEV: c_int = 21; + pub const _SC_2_FORT_RUN: c_int = 22; + pub const _SC_2_LOCALEDEF: c_int = 23; + pub const _SC_2_SW_DEV: c_int = 24; + pub const _SC_2_UPE: c_int = 25; + pub const _SC_STREAM_MAX: c_int = 26; + pub const _SC_TZNAME_MAX: c_int = 27; + pub const _SC_ASYNCHRONOUS_IO: c_int = 28; + pub const _SC_PAGESIZE: c_int = 29; + pub const _SC_MEMLOCK: c_int = 30; + pub const _SC_MEMLOCK_RANGE: c_int = 31; + pub const _SC_MEMORY_PROTECTION: c_int = 32; + pub const _SC_MESSAGE_PASSING: c_int = 33; + pub const _SC_PRIORITIZED_IO: c_int = 34; + pub const _SC_PRIORITY_SCHEDULING: c_int = 35; + pub const _SC_REALTIME_SIGNALS: c_int = 36; + pub const _SC_SEMAPHORES: c_int = 37; + pub const _SC_FSYNC: c_int = 38; + pub const _SC_SHARED_MEMORY_OBJECTS: c_int = 39; + pub const _SC_SYNCHRONIZED_IO: c_int = 40; + pub const _SC_TIMERS: c_int = 41; + pub const _SC_AIO_LISTIO_MAX: c_int = 42; + pub const _SC_AIO_MAX: c_int = 43; + pub const _SC_AIO_PRIO_DELTA_MAX: c_int = 44; + pub const _SC_DELAYTIMER_MAX: c_int = 45; + pub const _SC_MQ_OPEN_MAX: c_int = 46; + pub const _SC_MAPPED_FILES: c_int = 47; + pub const _SC_RTSIG_MAX: c_int = 48; + pub const _SC_SEM_NSEMS_MAX: c_int = 49; + pub const _SC_SEM_VALUE_MAX: c_int = 50; + pub const _SC_SIGQUEUE_MAX: c_int = 51; + pub const _SC_TIMER_MAX: c_int = 52; + pub const _SC_NPROCESSORS_CONF: c_int = 57; + pub const _SC_NPROCESSORS_ONLN: c_int = 58; + pub const _SC_2_PBS: c_int = 59; + pub const _SC_2_PBS_ACCOUNTING: c_int = 60; + pub const _SC_2_PBS_CHECKPOINT: c_int = 61; + pub const _SC_2_PBS_LOCATE: c_int = 62; + pub const _SC_2_PBS_MESSAGE: c_int = 63; + pub const _SC_2_PBS_TRACK: c_int = 64; + pub const _SC_ADVISORY_INFO: c_int = 65; + pub const _SC_BARRIERS: c_int = 66; + pub const _SC_CLOCK_SELECTION: c_int = 67; + pub const _SC_CPUTIME: c_int = 68; + pub const _SC_FILE_LOCKING: c_int = 69; + pub const _SC_HOST_NAME_MAX: c_int = 72; + pub const _SC_MONOTONIC_CLOCK: c_int = 74; + pub const _SC_READER_WRITER_LOCKS: c_int = 76; + pub const _SC_REGEXP: c_int = 77; + pub const _SC_SHELL: c_int = 78; + pub const _SC_SPAWN: c_int = 79; + pub const _SC_SPIN_LOCKS: c_int = 80; + pub const _SC_SPORADIC_SERVER: c_int = 81; + pub const _SC_THREAD_CPUTIME: c_int = 84; + pub const _SC_THREAD_SPORADIC_SERVER: c_int = 92; + pub const _SC_TIMEOUTS: c_int = 95; + pub const _SC_TRACE: c_int = 97; + pub const _SC_TRACE_EVENT_FILTER: c_int = 98; + pub const _SC_TRACE_INHERIT: c_int = 99; + pub const _SC_TRACE_LOG: c_int = 100; + pub const _SC_TYPED_MEMORY_OBJECTS: c_int = 102; + pub const _SC_V6_ILP32_OFF32: c_int = 103; + pub const _SC_V6_ILP32_OFFBIG: c_int = 104; + pub const _SC_V6_LP64_OFF64: c_int = 105; + pub const _SC_V6_LPBIG_OFFBIG: c_int = 106; + pub const _SC_IPV6: c_int = 118; + pub const _SC_RAW_SOCKETS: c_int = 119; + pub const _SC_SYMLOOP_MAX: c_int = 120; + pub const _SC_PAGE_SIZE: c_int = _SC_PAGESIZE; + pub const _SC_XOPEN_STREAMS: c_int = 114; + pub const _SC_XBS5_ILP32_OFF32: c_int = 122; + pub const _SC_XBS5_ILP32_OFFBIG: c_int = 123; + pub const _SC_XBS5_LP64_OFF64: c_int = 124; + pub const _SC_XBS5_LPBIG_OFFBIG: c_int = 125; + pub const _SC_SS_REPL_MAX: c_int = 126; + pub const _SC_TRACE_EVENT_NAME_MAX: c_int = 127; + pub const _SC_TRACE_NAME_MAX: c_int = 128; + pub const _SC_TRACE_SYS_MAX: c_int = 129; + pub const _SC_TRACE_USER_EVENT_MAX: c_int = 130; + pub const _SC_PASS_MAX: c_int = 131; pub const _PC_NAME_MAX: c_int = 4; pub const _PC_PATH_MAX: c_int = 5; @@ -5436,16 +6091,15 @@ pub mod funcs { use types::os::arch::c95::{c_char, c_int, c_long, size_t}; extern { - pub fn fopen(filename: *const c_char, - mode: *const c_char) -> *mut FILE; - pub fn freopen(filename: *const c_char, mode: *const c_char, + pub fn fopen(filename: *const c_char, mode: *const c_char) -> *mut FILE; + pub fn freopen(filename: *const c_char, + mode: *const c_char, file: *mut FILE) -> *mut FILE; pub fn fflush(file: *mut FILE) -> c_int; pub fn fclose(file: *mut FILE) -> c_int; pub fn remove(filename: *const c_char) -> c_int; - pub fn rename(oldname: *const c_char, - newname: *const c_char) -> c_int; + pub fn rename(oldname: *const c_char, newname: *const c_char) -> c_int; pub fn tmpfile() -> *mut FILE; pub fn setvbuf(stream: *mut FILE, buffer: *mut c_char, @@ -5455,10 +6109,9 @@ pub mod funcs { pub fn setbuf(stream: *mut FILE, buf: *mut c_char); // Omitted: printf and scanf variants. pub fn fgetc(stream: *mut FILE) -> c_int; - pub fn fgets(buf: *mut c_char, n: c_int, stream: *mut FILE) - -> *mut c_char; + pub fn fgets(buf: *mut c_char, n: c_int, stream: *mut FILE) -> *mut c_char; pub fn fputc(c: c_int, stream: *mut FILE) -> c_int; - pub fn fputs(s: *const c_char, stream: *mut FILE)-> c_int; + pub fn fputs(s: *const c_char, stream: *mut FILE) -> c_int; // Omitted: getc, getchar (might be macros). // Omitted: gets, so ridiculously unsafe that it should not @@ -5477,8 +6130,7 @@ pub mod funcs { nobj: size_t, stream: *mut FILE) -> size_t; - pub fn fseek(stream: *mut FILE, offset: c_long, whence: c_int) - -> c_int; + pub fn fseek(stream: *mut FILE, offset: c_long, whence: c_int) -> c_int; pub fn ftell(stream: *mut FILE) -> c_long; pub fn rewind(stream: *mut FILE); pub fn fgetpos(stream: *mut FILE, ptr: *mut fpos_t) -> c_int; @@ -5493,7 +6145,7 @@ pub mod funcs { use types::common::c95::c_void; use types::os::arch::c95::{c_char, c_double, c_int}; use types::os::arch::c95::{c_long, c_uint, c_ulong}; - use types::os::arch::c95::{size_t}; + use types::os::arch::c95::size_t; extern { pub fn abs(i: c_int) -> c_int; @@ -5501,12 +6153,9 @@ pub mod funcs { // Omitted: div, ldiv (return pub type incomplete). pub fn atof(s: *const c_char) -> c_double; pub fn atoi(s: *const c_char) -> c_int; - pub fn strtod(s: *const c_char, - endp: *mut *mut c_char) -> c_double; - pub fn strtol(s: *const c_char, - endp: *mut *mut c_char, base: c_int) -> c_long; - pub fn strtoul(s: *const c_char, endp: *mut *mut c_char, - base: c_int) -> c_ulong; + pub fn strtod(s: *const c_char, endp: *mut *mut c_char) -> c_double; + pub fn strtol(s: *const c_char, endp: *mut *mut c_char, base: c_int) -> c_long; + pub fn strtoul(s: *const c_char, endp: *mut *mut c_char, base: c_int) -> c_ulong; pub fn calloc(nobj: size_t, size: size_t) -> *mut c_void; pub fn malloc(size: size_t) -> *mut c_void; pub fn realloc(p: *mut c_void, size: size_t) -> *mut c_void; @@ -5514,7 +6163,7 @@ pub mod funcs { /// Exits the running program in a possibly dangerous manner. /// - /// # Unsafety + /// # Safety /// /// While this forces your program to exit, it does so in a way that has /// consequences. This will skip all unwinding code, which means that anything @@ -5534,7 +6183,7 @@ pub mod funcs { /// ``` pub fn exit(status: c_int) -> !; pub fn _exit(status: c_int) -> !; - pub fn atexit(cb: extern fn()) -> c_int; + pub fn atexit(cb: extern "C" fn()) -> c_int; pub fn system(s: *const c_char) -> c_int; pub fn getenv(s: *const c_char) -> *mut c_char; // Omitted: bsearch, qsort @@ -5546,43 +6195,34 @@ pub mod funcs { pub mod string { use types::common::c95::c_void; use types::os::arch::c95::{c_char, c_int, size_t}; - use types::os::arch::c95::{wchar_t}; + use types::os::arch::c95::wchar_t; extern { - pub fn strcpy(dst: *mut c_char, - src: *const c_char) -> *mut c_char; - pub fn strncpy(dst: *mut c_char, src: *const c_char, n: size_t) - -> *mut c_char; + pub fn strcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char; + pub fn strncpy(dst: *mut c_char, src: *const c_char, n: size_t) -> *mut c_char; pub fn strcat(s: *mut c_char, ct: *const c_char) -> *mut c_char; - pub fn strncat(s: *mut c_char, ct: *const c_char, - n: size_t) -> *mut c_char; + pub fn strncat(s: *mut c_char, ct: *const c_char, n: size_t) -> *mut c_char; pub fn strcmp(cs: *const c_char, ct: *const c_char) -> c_int; - pub fn strncmp(cs: *const c_char, ct: *const c_char, - n: size_t) -> c_int; + pub fn strncmp(cs: *const c_char, ct: *const c_char, n: size_t) -> c_int; pub fn strcoll(cs: *const c_char, ct: *const c_char) -> c_int; pub fn strchr(cs: *const c_char, c: c_int) -> *mut c_char; pub fn strrchr(cs: *const c_char, c: c_int) -> *mut c_char; pub fn strspn(cs: *const c_char, ct: *const c_char) -> size_t; pub fn strcspn(cs: *const c_char, ct: *const c_char) -> size_t; - pub fn strpbrk(cs: *const c_char, - ct: *const c_char) -> *mut c_char; - pub fn strstr(cs: *const c_char, - ct: *const c_char) -> *mut c_char; + pub fn strpbrk(cs: *const c_char, ct: *const c_char) -> *mut c_char; + pub fn strstr(cs: *const c_char, ct: *const c_char) -> *mut c_char; pub fn strlen(cs: *const c_char) -> size_t; pub fn strerror(n: c_int) -> *mut c_char; pub fn strtok(s: *mut c_char, t: *const c_char) -> *mut c_char; - pub fn strxfrm(s: *mut c_char, ct: *const c_char, - n: size_t) -> size_t; + pub fn strxfrm(s: *mut c_char, ct: *const c_char, n: size_t) -> size_t; pub fn wcslen(buf: *const wchar_t) -> size_t; // Omitted: memcpy, memmove, memset (provided by LLVM) // These are fine to execute on the Rust stack. They must be, // in fact, because LLVM generates calls to them! - pub fn memcmp(cx: *const c_void, ct: *const c_void, - n: size_t) -> c_int; - pub fn memchr(cx: *const c_void, c: c_int, - n: size_t) -> *mut c_void; + pub fn memcmp(cx: *const c_void, ct: *const c_void, n: size_t) -> c_int; + pub fn memchr(cx: *const c_void, c: c_int, n: size_t) -> *mut c_void; } } } @@ -5625,8 +6265,7 @@ pub mod funcs { extern { #[link_name = "_popen"] - pub fn popen(command: *const c_char, - mode: *const c_char) -> *mut FILE; + pub fn popen(command: *const c_char, mode: *const c_char) -> *mut FILE; #[link_name = "_pclose"] pub fn pclose(stream: *mut FILE) -> c_int; #[link_name = "_fdopen"] @@ -5640,11 +6279,9 @@ pub mod funcs { use types::os::arch::c95::{c_int, c_char, wchar_t}; extern { #[link_name = "_open"] - pub fn open(path: *const c_char, oflag: c_int, mode: c_int) - -> c_int; + pub fn open(path: *const c_char, oflag: c_int, mode: c_int) -> c_int; #[link_name = "_wopen"] - pub fn wopen(path: *const wchar_t, oflag: c_int, mode: c_int) - -> c_int; + pub fn wopen(path: *const wchar_t, oflag: c_int, mode: c_int) -> c_int; #[link_name = "_creat"] pub fn creat(path: *const c_char, mode: c_int) -> c_int; } @@ -5656,8 +6293,7 @@ pub mod funcs { pub mod unistd { use types::common::c95::c_void; - use types::os::arch::c95::{c_int, c_uint, c_char, - c_long, size_t}; + use types::os::arch::c95::{c_int, c_uint, c_char, c_long, size_t}; use types::os::arch::c99::intptr_t; extern { @@ -5672,18 +6308,19 @@ pub mod funcs { #[link_name = "_dup2"] pub fn dup2(src: c_int, dst: c_int) -> c_int; #[link_name = "_execv"] - pub fn execv(prog: *const c_char, - argv: *const *const c_char) -> intptr_t; + pub fn execv(prog: *const c_char, argv: *const *const c_char) -> intptr_t; #[link_name = "_execve"] - pub fn execve(prog: *const c_char, argv: *const *const c_char, + pub fn execve(prog: *const c_char, + argv: *const *const c_char, envp: *const *const c_char) -> c_int; #[link_name = "_execvp"] - pub fn execvp(c: *const c_char, - argv: *const *const c_char) -> c_int; + pub fn execvp(c: *const c_char, argv: *const *const c_char) -> c_int; #[link_name = "_execvpe"] - pub fn execvpe(c: *const c_char, argv: *const *const c_char, - envp: *const *const c_char) -> c_int; + pub fn execvpe(c: *const c_char, + argv: *const *const c_char, + envp: *const *const c_char) + -> c_int; #[link_name = "_getcwd"] pub fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char; #[link_name = "_getpid"] @@ -5691,21 +6328,17 @@ pub mod funcs { #[link_name = "_isatty"] pub fn isatty(fd: c_int) -> c_int; #[link_name = "_lseek"] - pub fn lseek(fd: c_int, offset: c_long, origin: c_int) - -> c_long; + pub fn lseek(fd: c_int, offset: c_long, origin: c_int) -> c_long; #[link_name = "_pipe"] - pub fn pipe(fds: *mut c_int, psize: c_uint, textmode: c_int) - -> c_int; + pub fn pipe(fds: *mut c_int, psize: c_uint, textmode: c_int) -> c_int; #[link_name = "_read"] - pub fn read(fd: c_int, buf: *mut c_void, count: c_uint) - -> c_int; + pub fn read(fd: c_int, buf: *mut c_void, count: c_uint) -> c_int; #[link_name = "_rmdir"] pub fn rmdir(path: *const c_char) -> c_int; #[link_name = "_unlink"] pub fn unlink(c: *const c_char) -> c_int; #[link_name = "_write"] - pub fn write(fd: c_int, buf: *const c_void, - count: c_uint) -> c_int; + pub fn write(fd: c_int, buf: *const c_void, count: c_uint) -> c_int; } } @@ -5733,38 +6366,16 @@ pub mod funcs { pub fn chmod(path: *const c_char, mode: mode_t) -> c_int; pub fn fchmod(fd: c_int, mode: mode_t) -> c_int; - #[cfg(any(target_os = "linux", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "netbsd", - target_os = "openbsd", - target_os = "android", - target_os = "ios", - target_os = "nacl"))] - pub fn fstat(fildes: c_int, buf: *mut stat) -> c_int; - - #[cfg(target_os = "macos")] - #[link_name = "fstat64"] + #[cfg_attr(target_os = "macos", link_name = "fstat64")] + #[cfg_attr(target_os = "netbsd", link_name = "__fstat50")] pub fn fstat(fildes: c_int, buf: *mut stat) -> c_int; pub fn mkdir(path: *const c_char, mode: mode_t) -> c_int; #[cfg(not(target_os = "nacl"))] pub fn mkfifo(path: *const c_char, mode: mode_t) -> c_int; - #[cfg(any(target_os = "linux", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "netbsd", - target_os = "openbsd", - target_os = "android", - target_os = "ios", - target_os = "nacl"))] - pub fn stat(path: *const c_char, buf: *mut stat) -> c_int; - - #[cfg(target_os = "macos")] - #[link_name = "stat64"] + #[cfg_attr(target_os = "macos", link_name = "stat64")] + #[cfg_attr(target_os = "netbsd", link_name = "__stat50")] pub fn stat(path: *const c_char, buf: *mut stat) -> c_int; } } @@ -5774,8 +6385,7 @@ pub mod funcs { use types::os::arch::c95::{c_char, c_int}; extern { - pub fn popen(command: *const c_char, - mode: *const c_char) -> *mut FILE; + pub fn popen(command: *const c_char, mode: *const c_char) -> *mut FILE; pub fn pclose(stream: *mut FILE) -> c_int; pub fn fdopen(fd: c_int, mode: *const c_char) -> *mut FILE; pub fn fileno(stream: *mut FILE) -> c_int; @@ -5790,20 +6400,21 @@ pub mod funcs { extern { #[cfg(any(target_os = "macos", target_os = "ios"))] - pub fn open(path: *const ::c_char, oflag: ::c_int, ...) - -> ::c_int; + pub fn open(path: *const ::c_char, oflag: ::c_int, ...) -> ::c_int; #[cfg(not(any(target_os = "macos", target_os = "ios")))] - pub fn open(path: *const ::c_char, oflag: ::c_int, mode: ::mode_t) - -> ::c_int; + pub fn open(path: *const ::c_char, oflag: ::c_int, mode: ::mode_t) -> ::c_int; } } #[cfg(any(target_os = "macos", target_os = "ios"))] #[inline] - pub unsafe extern fn open(path: *const c_char, oflag: c_int, mode: mode_t) -> c_int { + pub unsafe extern "C" fn open(path: *const c_char, + oflag: c_int, + mode: mode_t) + -> c_int { use types::os::arch::c95::c_uint; open_shim::open(path, oflag, mode as c_uint) } @@ -5811,7 +6422,10 @@ pub mod funcs { #[cfg(not(any(target_os = "macos", target_os = "ios")))] #[inline] - pub unsafe extern fn open(path: *const c_char, oflag: c_int, mode: mode_t) -> c_int { + pub unsafe extern "C" fn open(path: *const c_char, + oflag: c_int, + mode: mode_t) + -> c_int { open_shim::open(path, oflag, mode) } @@ -5836,8 +6450,10 @@ pub mod funcs { #[link_name="rust_opendir"] pub fn opendir(dirname: *const c_char) -> *mut DIR; #[link_name="rust_readdir_r"] - pub fn readdir_r(dirp: *mut DIR, entry: *mut dirent_t, - result: *mut *mut dirent_t) -> c_int; + pub fn readdir_r(dirp: *mut DIR, + entry: *mut dirent_t, + result: *mut *mut dirent_t) + -> c_int; } extern { @@ -5851,7 +6467,7 @@ pub mod funcs { pub mod unistd { use types::common::c95::c_void; use types::os::arch::c95::{c_char, c_int, c_long, c_uint}; - use types::os::arch::c95::{size_t}; + use types::os::arch::c95::size_t; use types::os::common::posix01::timespec; use types::os::arch::posix01::utimbuf; use types::os::arch::posix88::{gid_t, off_t, pid_t}; @@ -5862,31 +6478,27 @@ pub mod funcs { pub fn access(path: *const c_char, amode: c_int) -> c_int; pub fn alarm(seconds: c_uint) -> c_uint; pub fn chdir(dir: *const c_char) -> c_int; - pub fn chown(path: *const c_char, uid: uid_t, - gid: gid_t) -> c_int; + pub fn chown(path: *const c_char, uid: uid_t, gid: gid_t) -> c_int; pub fn close(fd: c_int) -> c_int; pub fn dup(fd: c_int) -> c_int; pub fn dup2(src: c_int, dst: c_int) -> c_int; - pub fn execv(prog: *const c_char, - argv: *const *const c_char) -> c_int; - pub fn execve(prog: *const c_char, argv: *const *const c_char, + pub fn execv(prog: *const c_char, argv: *const *const c_char) -> c_int; + pub fn execve(prog: *const c_char, + argv: *const *const c_char, envp: *const *const c_char) -> c_int; - pub fn execvp(c: *const c_char, - argv: *const *const c_char) -> c_int; + pub fn execvp(c: *const c_char, argv: *const *const c_char) -> c_int; pub fn fork() -> pid_t; pub fn fpathconf(filedes: c_int, name: c_int) -> c_long; pub fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char; pub fn getegid() -> gid_t; pub fn geteuid() -> uid_t; pub fn getgid() -> gid_t; - pub fn getgroups(ngroups_max: c_int, groups: *mut gid_t) - -> c_int; + pub fn getgroups(ngroups_max: c_int, groups: *mut gid_t) -> c_int; pub fn getlogin() -> *mut c_char; // GNU getopt(3) modifies its arguments despite the // char * const [] prototype; see the manpage. - pub fn getopt(argc: c_int, argv: *mut *mut c_char, - optstr: *const c_char) -> c_int; + pub fn getopt(argc: c_int, argv: *mut *mut c_char, optstr: *const c_char) -> c_int; pub fn getpgrp() -> pid_t; pub fn getpid() -> pid_t; pub fn getppid() -> pid_t; @@ -5894,13 +6506,11 @@ pub mod funcs { pub fn getsid(pid: pid_t) -> pid_t; pub fn isatty(fd: c_int) -> c_int; pub fn link(src: *const c_char, dst: *const c_char) -> c_int; - pub fn lseek(fd: c_int, offset: off_t, whence: c_int) - -> off_t; + pub fn lseek(fd: c_int, offset: off_t, whence: c_int) -> off_t; pub fn pathconf(path: *mut c_char, name: c_int) -> c_long; pub fn pause() -> c_int; pub fn pipe(fds: *mut c_int) -> c_int; - pub fn read(fd: c_int, buf: *mut c_void, count: size_t) - -> ssize_t; + pub fn read(fd: c_int, buf: *mut c_void, count: size_t) -> ssize_t; pub fn rmdir(path: *const c_char) -> c_int; pub fn setgid(gid: gid_t) -> c_int; pub fn setpgid(pid: pid_t, pgid: pid_t) -> c_int; @@ -5908,82 +6518,80 @@ pub mod funcs { pub fn setuid(uid: uid_t) -> c_int; pub fn sleep(secs: c_uint) -> c_uint; pub fn usleep(secs: c_uint) -> c_int; - pub fn nanosleep(rqtp: *const timespec, - rmtp: *mut timespec) -> c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__nanosleep50")] + pub fn nanosleep(rqtp: *const timespec, rmtp: *mut timespec) -> c_int; pub fn sysconf(name: c_int) -> c_long; pub fn tcgetpgrp(fd: c_int) -> pid_t; pub fn ttyname(fd: c_int) -> *mut c_char; pub fn unlink(c: *const c_char) -> c_int; pub fn wait(status: *const c_int) -> pid_t; - pub fn waitpid(pid: pid_t, status: *const c_int, options: c_int) - -> pid_t; - pub fn write(fd: c_int, buf: *const c_void, count: size_t) - -> ssize_t; - pub fn pread(fd: c_int, buf: *mut c_void, count: size_t, - offset: off_t) -> ssize_t; - pub fn pwrite(fd: c_int, buf: *const c_void, count: size_t, - offset: off_t) -> ssize_t; + pub fn waitpid(pid: pid_t, status: *const c_int, options: c_int) -> pid_t; + pub fn write(fd: c_int, buf: *const c_void, count: size_t) -> ssize_t; + pub fn pread(fd: c_int, buf: *mut c_void, count: size_t, offset: off_t) -> ssize_t; + pub fn pwrite(fd: c_int, + buf: *const c_void, + count: size_t, + offset: off_t) + -> ssize_t; + #[cfg_attr(target_os = "netbsd", link_name = "__utime50")] pub fn utime(file: *const c_char, buf: *const utimbuf) -> c_int; } #[cfg(target_os = "nacl")] extern { pub fn access(path: *const c_char, amode: c_int) -> c_int; pub fn chdir(dir: *const c_char) -> c_int; - pub fn chown(path: *const c_char, uid: uid_t, - gid: gid_t) -> c_int; + pub fn chown(path: *const c_char, uid: uid_t, gid: gid_t) -> c_int; pub fn close(fd: c_int) -> c_int; pub fn dup(fd: c_int) -> c_int; pub fn dup2(src: c_int, dst: c_int) -> c_int; - pub fn execv(prog: *const c_char, - argv: *const *const c_char) -> c_int; - pub fn execve(prog: *const c_char, argv: *const *const c_char, + pub fn execv(prog: *const c_char, argv: *const *const c_char) -> c_int; + pub fn execve(prog: *const c_char, + argv: *const *const c_char, envp: *const *const c_char) -> c_int; - pub fn execvp(c: *const c_char, - argv: *const *const c_char) -> c_int; + pub fn execvp(c: *const c_char, argv: *const *const c_char) -> c_int; pub fn fork() -> pid_t; pub fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char; pub fn getegid() -> gid_t; pub fn geteuid() -> uid_t; pub fn getgid() -> gid_t; pub fn getlogin() -> *mut c_char; - pub fn getopt(argc: c_int, argv: *const *const c_char, - optstr: *const c_char) -> c_int; + pub fn getopt(argc: c_int, + argv: *const *const c_char, + optstr: *const c_char) + -> c_int; pub fn getuid() -> uid_t; pub fn getsid(pid: pid_t) -> pid_t; pub fn isatty(fd: c_int) -> c_int; pub fn link(src: *const c_char, dst: *const c_char) -> c_int; - pub fn lseek(fd: c_int, offset: off_t, whence: c_int) - -> off_t; + pub fn lseek(fd: c_int, offset: off_t, whence: c_int) -> off_t; pub fn pipe(fds: *mut c_int) -> c_int; - pub fn read(fd: c_int, buf: *mut c_void, count: size_t) - -> ssize_t; + pub fn read(fd: c_int, buf: *mut c_void, count: size_t) -> ssize_t; pub fn rmdir(path: *const c_char) -> c_int; pub fn setgid(gid: gid_t) -> c_int; pub fn setuid(uid: uid_t) -> c_int; pub fn sleep(secs: c_uint) -> c_uint; pub fn usleep(secs: c_uint) -> c_int; - pub fn nanosleep(rqtp: *const timespec, - rmtp: *mut timespec) -> c_int; + pub fn nanosleep(rqtp: *const timespec, rmtp: *mut timespec) -> c_int; pub fn sysconf(name: c_int) -> c_long; pub fn ttyname(fd: c_int) -> *mut c_char; pub fn unlink(c: *const c_char) -> c_int; pub fn wait(status: *const c_int) -> pid_t; - pub fn waitpid(pid: pid_t, status: *const c_int, options: c_int) - -> pid_t; - pub fn write(fd: c_int, buf: *const c_void, count: size_t) - -> ssize_t; - pub fn pread(fd: c_int, buf: *mut c_void, count: size_t, - offset: off_t) -> ssize_t; - pub fn pwrite(fd: c_int, buf: *const c_void, count: size_t, - offset: off_t) -> ssize_t; + pub fn waitpid(pid: pid_t, status: *const c_int, options: c_int) -> pid_t; + pub fn write(fd: c_int, buf: *const c_void, count: size_t) -> ssize_t; + pub fn pread(fd: c_int, buf: *mut c_void, count: size_t, offset: off_t) -> ssize_t; + pub fn pwrite(fd: c_int, + buf: *const c_void, + count: size_t, + offset: off_t) + -> ssize_t; pub fn utime(file: *const c_char, buf: *const utimbuf) -> c_int; } } pub mod signal { - use types::os::arch::c95::{c_int}; - use types::os::arch::posix88::{pid_t}; + use types::os::arch::c95::c_int; + use types::os::arch::posix88::pid_t; extern { pub fn kill(pid: pid_t, sig: c_int) -> c_int; @@ -5991,7 +6599,7 @@ pub mod funcs { } pub mod mman { - use types::common::c95::{c_void}; + use types::common::c95::c_void; use types::os::arch::c95::{size_t, c_int, c_char}; use types::os::arch::posix88::{mode_t, off_t}; @@ -6002,13 +6610,12 @@ pub mod funcs { pub fn mlockall(flags: c_int) -> c_int; pub fn munlockall() -> c_int; - pub fn mprotect(addr: *mut c_void, len: size_t, prot: c_int) - -> c_int; + pub fn mprotect(addr: *mut c_void, len: size_t, prot: c_int) -> c_int; - pub fn msync(addr: *mut c_void, len: size_t, flags: c_int) - -> c_int; - pub fn shm_open(name: *const c_char, oflag: c_int, mode: mode_t) - -> c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__msync13")] + pub fn msync(addr: *mut c_void, len: size_t, flags: c_int) -> c_int; + + pub fn shm_open(name: *const c_char, oflag: c_int, mode: mode_t) -> c_int; pub fn shm_unlink(name: *const c_char) -> c_int; } @@ -6051,19 +6658,8 @@ pub mod funcs { use types::os::arch::posix01::stat; extern { - #[cfg(any(target_os = "linux", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "netbsd", - target_os = "openbsd", - target_os = "android", - target_os = "ios", - target_os = "nacl"))] - pub fn lstat(path: *const c_char, buf: *mut stat) -> c_int; - - #[cfg(target_os = "macos")] - #[link_name = "lstat64"] + #[cfg_attr(target_os = "macos", link_name = "lstat64")] + #[cfg_attr(target_os = "netbsd", link_name = "__lstat50")] pub fn lstat(path: *const c_char, buf: *mut stat) -> c_int; } } @@ -6073,23 +6669,20 @@ pub mod funcs { use types::os::arch::posix88::{ssize_t, off_t}; extern { - pub fn readlink(path: *const c_char, - buf: *mut c_char, - bufsz: size_t) - -> ssize_t; + pub fn readlink(path: *const c_char, buf: *mut c_char, bufsz: size_t) -> ssize_t; pub fn fsync(fd: c_int) -> c_int; #[cfg(any(target_os = "linux", target_os = "android"))] pub fn fdatasync(fd: c_int) -> c_int; - pub fn setenv(name: *const c_char, val: *const c_char, - overwrite: c_int) -> c_int; + pub fn setenv(name: *const c_char, val: *const c_char, overwrite: c_int) -> c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__unsetenv13")] pub fn unsetenv(name: *const c_char) -> c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__putenv50")] pub fn putenv(string: *mut c_char) -> c_int; - pub fn symlink(path1: *const c_char, - path2: *const c_char) -> c_int; + pub fn symlink(path1: *const c_char, path2: *const c_char) -> c_int; pub fn ftruncate(fd: c_int, length: off_t) -> c_int; } @@ -6102,43 +6695,40 @@ pub mod funcs { #[cfg(not(all(target_os = "android", any(target_arch = "arm", target_arch = "x86"))))] extern { - pub fn signal(signum: c_int, - handler: sighandler_t) -> sighandler_t; + pub fn signal(signum: c_int, handler: sighandler_t) -> sighandler_t; } #[cfg(all(target_os = "android", any(target_arch = "arm", target_arch = "x86")))] extern { #[link_name = "bsd_signal"] - pub fn signal(signum: c_int, - handler: sighandler_t) -> sighandler_t; + pub fn signal(signum: c_int, handler: sighandler_t) -> sighandler_t; } } pub mod glob { use types::os::arch::c95::{c_char, c_int}; - use types::os::common::posix01::{glob_t}; + use types::os::common::posix01::glob_t; extern { + #[cfg_attr(target_os = "netbsd", link_name = "__glob30")] pub fn glob(pattern: *const c_char, flags: c_int, errfunc: ::core::option::Option c_int>, pglob: *mut glob_t); + #[cfg_attr(target_os = "netbsd", link_name = "__globfree30")] pub fn globfree(pglob: *mut glob_t); } } pub mod mman { - use types::common::c95::{c_void}; + use types::common::c95::c_void; use types::os::arch::c95::{c_int, size_t}; #[cfg(not(target_os = "nacl"))] extern { - pub fn posix_madvise(addr: *mut c_void, - len: size_t, - advice: c_int) - -> c_int; + pub fn posix_madvise(addr: *mut c_void, len: size_t, advice: c_int) -> c_int; } } @@ -6149,8 +6739,8 @@ pub mod funcs { extern { pub fn getrlimit(resource: c_int, rlim: *mut rlimit) -> c_int; pub fn setrlimit(resource: c_int, rlim: *const rlimit) -> c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__getrusage50")] pub fn getrusage(resource: c_int, usage: *mut rusage) -> c_int; - } } } @@ -6192,37 +6782,52 @@ pub mod funcs { #[cfg(not(windows))] pub mod bsd43 { - use types::common::c95::{c_void}; + use types::common::c95::c_void; use types::os::common::bsd44::{socklen_t, sockaddr, ifaddrs}; use types::os::arch::c95::{c_int, size_t}; use types::os::arch::posix88::ssize_t; extern "system" { + #[cfg_attr(target_os = "netbsd", link_name = "__socket30")] pub fn socket(domain: c_int, ty: c_int, protocol: c_int) -> c_int; - pub fn connect(socket: c_int, address: *const sockaddr, - len: socklen_t) -> c_int; - pub fn bind(socket: c_int, address: *const sockaddr, - address_len: socklen_t) -> c_int; + + pub fn connect(socket: c_int, address: *const sockaddr, len: socklen_t) -> c_int; + pub fn bind(socket: c_int, address: *const sockaddr, address_len: socklen_t) -> c_int; pub fn listen(socket: c_int, backlog: c_int) -> c_int; - pub fn accept(socket: c_int, address: *mut sockaddr, - address_len: *mut socklen_t) -> c_int; - pub fn getpeername(socket: c_int, address: *mut sockaddr, - address_len: *mut socklen_t) -> c_int; - pub fn getsockname(socket: c_int, address: *mut sockaddr, - address_len: *mut socklen_t) -> c_int; - pub fn setsockopt(socket: c_int, level: c_int, name: c_int, + pub fn accept(socket: c_int, + address: *mut sockaddr, + address_len: *mut socklen_t) + -> c_int; + pub fn getpeername(socket: c_int, + address: *mut sockaddr, + address_len: *mut socklen_t) + -> c_int; + pub fn getsockname(socket: c_int, + address: *mut sockaddr, + address_len: *mut socklen_t) + -> c_int; + pub fn setsockopt(socket: c_int, + level: c_int, + name: c_int, value: *const c_void, - option_len: socklen_t) -> c_int; - pub fn recv(socket: c_int, buf: *mut c_void, len: size_t, - flags: c_int) -> ssize_t; - pub fn send(socket: c_int, buf: *const c_void, len: size_t, - flags: c_int) -> ssize_t; - pub fn recvfrom(socket: c_int, buf: *mut c_void, len: size_t, - flags: c_int, addr: *mut sockaddr, - addrlen: *mut socklen_t) -> ssize_t; - pub fn sendto(socket: c_int, buf: *const c_void, len: size_t, - flags: c_int, addr: *const sockaddr, - addrlen: socklen_t) -> ssize_t; + option_len: socklen_t) + -> c_int; + pub fn recv(socket: c_int, buf: *mut c_void, len: size_t, flags: c_int) -> ssize_t; + pub fn send(socket: c_int, buf: *const c_void, len: size_t, flags: c_int) -> ssize_t; + pub fn recvfrom(socket: c_int, + buf: *mut c_void, + len: size_t, + flags: c_int, + addr: *mut sockaddr, + addrlen: *mut socklen_t) + -> ssize_t; + pub fn sendto(socket: c_int, + buf: *const c_void, + len: size_t, + flags: c_int, + addr: *const sockaddr, + addrlen: socklen_t) + -> ssize_t; pub fn getifaddrs(ifap: *mut *mut ifaddrs) -> c_int; pub fn freeifaddrs(ifa: *mut ifaddrs); pub fn shutdown(socket: c_int, how: c_int) -> c_int; @@ -6231,37 +6836,50 @@ pub mod funcs { #[cfg(windows)] pub mod bsd43 { - use types::common::c95::{c_void}; + use types::common::c95::c_void; use types::os::common::bsd44::{socklen_t, sockaddr, SOCKET}; use types::os::arch::c95::c_int; extern "system" { pub fn socket(domain: c_int, ty: c_int, protocol: c_int) -> SOCKET; - pub fn connect(socket: SOCKET, address: *const sockaddr, - len: socklen_t) -> c_int; - pub fn bind(socket: SOCKET, address: *const sockaddr, - address_len: socklen_t) -> c_int; + pub fn connect(socket: SOCKET, address: *const sockaddr, len: socklen_t) -> c_int; + pub fn bind(socket: SOCKET, address: *const sockaddr, address_len: socklen_t) -> c_int; pub fn listen(socket: SOCKET, backlog: c_int) -> c_int; - pub fn accept(socket: SOCKET, address: *mut sockaddr, - address_len: *mut socklen_t) -> SOCKET; - pub fn getpeername(socket: SOCKET, address: *mut sockaddr, - address_len: *mut socklen_t) -> c_int; - pub fn getsockname(socket: SOCKET, address: *mut sockaddr, - address_len: *mut socklen_t) -> c_int; - pub fn setsockopt(socket: SOCKET, level: c_int, name: c_int, + pub fn accept(socket: SOCKET, + address: *mut sockaddr, + address_len: *mut socklen_t) + -> SOCKET; + pub fn getpeername(socket: SOCKET, + address: *mut sockaddr, + address_len: *mut socklen_t) + -> c_int; + pub fn getsockname(socket: SOCKET, + address: *mut sockaddr, + address_len: *mut socklen_t) + -> c_int; + pub fn setsockopt(socket: SOCKET, + level: c_int, + name: c_int, value: *const c_void, - option_len: socklen_t) -> c_int; + option_len: socklen_t) + -> c_int; pub fn closesocket(socket: SOCKET) -> c_int; - pub fn recv(socket: SOCKET, buf: *mut c_void, len: c_int, - flags: c_int) -> c_int; - pub fn send(socket: SOCKET, buf: *const c_void, len: c_int, - flags: c_int) -> c_int; - pub fn recvfrom(socket: SOCKET, buf: *mut c_void, len: c_int, - flags: c_int, addr: *mut sockaddr, - addrlen: *mut c_int) -> c_int; - pub fn sendto(socket: SOCKET, buf: *const c_void, len: c_int, - flags: c_int, addr: *const sockaddr, - addrlen: c_int) -> c_int; + pub fn recv(socket: SOCKET, buf: *mut c_void, len: c_int, flags: c_int) -> c_int; + pub fn send(socket: SOCKET, buf: *const c_void, len: c_int, flags: c_int) -> c_int; + pub fn recvfrom(socket: SOCKET, + buf: *mut c_void, + len: c_int, + flags: c_int, + addr: *mut sockaddr, + addrlen: *mut c_int) + -> c_int; + pub fn sendto(socket: SOCKET, + buf: *const c_void, + len: c_int, + flags: c_int, + addr: *const sockaddr, + addrlen: c_int) + -> c_int; pub fn shutdown(socket: SOCKET, how: c_int) -> c_int; } } @@ -6274,7 +6892,7 @@ pub mod funcs { target_os = "netbsd", target_os = "openbsd"))] pub mod bsd44 { - use types::common::c95::{c_void}; + use types::common::c95::c_void; use types::os::arch::c95::{c_char, c_uchar, c_int, c_uint, c_ulong, size_t}; extern { @@ -6297,19 +6915,16 @@ pub mod funcs { sizep: *mut size_t) -> c_int; pub fn getdtablesize() -> c_int; - pub fn madvise(addr: *mut c_void, len: size_t, advice: c_int) - -> c_int; - pub fn mincore(addr: *mut c_void, len: size_t, vec: *mut c_uchar) - -> c_int; - pub fn realpath(pathname: *const c_char, resolved: *mut c_char) - -> *mut c_char; + pub fn madvise(addr: *mut c_void, len: size_t, advice: c_int) -> c_int; + pub fn mincore(addr: *mut c_void, len: size_t, vec: *mut c_uchar) -> c_int; + pub fn realpath(pathname: *const c_char, resolved: *mut c_char) -> *mut c_char; pub fn flock(fd: c_int, operation: c_int) -> c_int; } } #[cfg(any(target_os = "linux", target_os = "android"))] pub mod bsd44 { - use types::common::c95::{c_void}; + use types::common::c95::c_void; use types::os::arch::c95::{c_uchar, c_int, size_t}; #[cfg(not(feature = "cargo-build"))] use types::os::arch::c95::c_ulong; @@ -6327,10 +6942,8 @@ pub mod funcs { pub fn ioctl(fd: c_int, request: c_int, ...) -> c_int; #[cfg(not(feature = "cargo-build"))] pub fn ioctl(fd: c_int, request: c_ulong, ...) -> c_int; - pub fn madvise(addr: *mut c_void, len: size_t, advice: c_int) - -> c_int; - pub fn mincore(addr: *mut c_void, len: size_t, vec: *mut c_uchar) - -> c_int; + pub fn madvise(addr: *mut c_void, len: size_t, advice: c_int) -> c_int; + pub fn mincore(addr: *mut c_void, len: size_t, vec: *mut c_uchar) -> c_int; pub fn flock(fd: c_int, operation: c_int) -> c_int; } } @@ -6352,8 +6965,7 @@ pub mod funcs { use types::os::arch::c95::{c_char, c_int}; extern { - pub fn _NSGetExecutablePath(buf: *mut c_char, bufsize: *mut u32) - -> c_int; + pub fn _NSGetExecutablePath(buf: *mut c_char, bufsize: *mut u32) -> c_int; } } @@ -6374,26 +6986,17 @@ pub mod funcs { pub mod extra { pub mod kernel32 { - use types::os::arch::c95::{c_uint}; - use types::os::arch::extra::{BOOL, DWORD, SIZE_T, HMODULE, - LPCWSTR, LPWSTR, - LPWCH, LPDWORD, LPVOID, - LPCVOID, LPOVERLAPPED, - LPSECURITY_ATTRIBUTES, - LPSTARTUPINFO, - LPPROCESS_INFORMATION, - LPMEMORY_BASIC_INFORMATION, - LPSYSTEM_INFO, HANDLE, LPHANDLE, - LARGE_INTEGER, PLARGE_INTEGER, - LPFILETIME, LPWIN32_FIND_DATAW}; + use types::os::arch::c95::c_uint; + use types::os::arch::extra::{BOOL, DWORD, SIZE_T, HMODULE, LPCWSTR, LPWSTR, LPWCH, + LPDWORD, LPVOID, LPCVOID, LPOVERLAPPED, + LPSECURITY_ATTRIBUTES, LPSTARTUPINFO, + LPPROCESS_INFORMATION, LPMEMORY_BASIC_INFORMATION, + LPSYSTEM_INFO, HANDLE, LPHANDLE, LARGE_INTEGER, + PLARGE_INTEGER, LPFILETIME, LPWIN32_FIND_DATAW}; extern "system" { - pub fn GetEnvironmentVariableW(n: LPCWSTR, - v: LPWSTR, - nsize: DWORD) - -> DWORD; - pub fn SetEnvironmentVariableW(n: LPCWSTR, v: LPCWSTR) - -> BOOL; + pub fn GetEnvironmentVariableW(n: LPCWSTR, v: LPWSTR, nsize: DWORD) -> DWORD; + pub fn SetEnvironmentVariableW(n: LPCWSTR, v: LPCWSTR) -> BOOL; pub fn GetEnvironmentStringsW() -> LPWCH; pub fn FreeEnvironmentStringsW(env_ptr: LPWCH) -> BOOL; pub fn GetModuleFileNameW(hModule: HMODULE, @@ -6401,8 +7004,7 @@ pub mod funcs { nSize: DWORD) -> DWORD; pub fn CreateDirectoryW(lpPathName: LPCWSTR, - lpSecurityAttributes: - LPSECURITY_ATTRIBUTES) + lpSecurityAttributes: LPSECURITY_ATTRIBUTES) -> BOOL; pub fn CopyFileW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, @@ -6410,15 +7012,13 @@ pub mod funcs { -> BOOL; pub fn DeleteFileW(lpPathName: LPCWSTR) -> BOOL; pub fn RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL; - pub fn GetCurrentDirectoryW(nBufferLength: DWORD, - lpBuffer: LPWSTR) - -> DWORD; + pub fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: LPWSTR) -> DWORD; pub fn SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL; pub fn GetLastError() -> DWORD; - pub fn FindFirstFileW(fileName: LPCWSTR, findFileData: LPWIN32_FIND_DATAW) + pub fn FindFirstFileW(fileName: LPCWSTR, + findFileData: LPWIN32_FIND_DATAW) -> HANDLE; - pub fn FindNextFileW(findFile: HANDLE, findFileData: LPWIN32_FIND_DATAW) - -> BOOL; + pub fn FindNextFileW(findFile: HANDLE, findFileData: LPWIN32_FIND_DATAW) -> BOOL; pub fn FindClose(findFile: HANDLE) -> BOOL; pub fn DuplicateHandle(hSourceProcessHandle: HANDLE, hSourceHandle: HANDLE, @@ -6436,39 +7036,27 @@ pub mod funcs { pub fn GetCurrentProcess() -> HANDLE; pub fn CreateProcessW(lpApplicationName: LPCWSTR, lpCommandLine: LPWSTR, - lpProcessAttributes: - LPSECURITY_ATTRIBUTES, - lpThreadAttributes: - LPSECURITY_ATTRIBUTES, + lpProcessAttributes: LPSECURITY_ATTRIBUTES, + lpThreadAttributes: LPSECURITY_ATTRIBUTES, bInheritHandles: BOOL, dwCreationFlags: DWORD, lpEnvironment: LPVOID, lpCurrentDirectory: LPCWSTR, lpStartupInfo: LPSTARTUPINFO, - lpProcessInformation: - LPPROCESS_INFORMATION) + lpProcessInformation: LPPROCESS_INFORMATION) -> BOOL; - pub fn WaitForSingleObject(hHandle: HANDLE, - dwMilliseconds: DWORD) - -> DWORD; - pub fn TerminateProcess(hProcess: HANDLE, uExitCode: c_uint) - -> BOOL; - pub fn GetExitCodeProcess(hProcess: HANDLE, - lpExitCode: LPDWORD) - -> BOOL; + pub fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD; + pub fn TerminateProcess(hProcess: HANDLE, uExitCode: c_uint) -> BOOL; + pub fn GetExitCodeProcess(hProcess: HANDLE, lpExitCode: LPDWORD) -> BOOL; pub fn GetSystemInfo(lpSystemInfo: LPSYSTEM_INFO); pub fn VirtualAlloc(lpAddress: LPVOID, dwSize: SIZE_T, flAllocationType: DWORD, flProtect: DWORD) -> LPVOID; - pub fn VirtualFree(lpAddress: LPVOID, - dwSize: SIZE_T, - dwFreeType: DWORD) - -> BOOL; + pub fn VirtualFree(lpAddress: LPVOID, dwSize: SIZE_T, dwFreeType: DWORD) -> BOOL; pub fn VirtualLock(lpAddress: LPVOID, dwSize: SIZE_T) -> BOOL; - pub fn VirtualUnlock(lpAddress: LPVOID, dwSize: SIZE_T) - -> BOOL; + pub fn VirtualUnlock(lpAddress: LPVOID, dwSize: SIZE_T) -> BOOL; pub fn VirtualProtect(lpAddress: LPVOID, dwSize: SIZE_T, flNewProtect: DWORD, @@ -6494,11 +7082,12 @@ pub mod funcs { pub fn UnmapViewOfFile(lpBaseAddress: LPCVOID) -> BOOL; pub fn MoveFileExW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, - dwFlags: DWORD) -> BOOL; + dwFlags: DWORD) + -> BOOL; pub fn CreateHardLinkW(lpSymlinkFileName: LPCWSTR, lpTargetFileName: LPCWSTR, lpSecurityAttributes: LPSECURITY_ATTRIBUTES) - -> BOOL; + -> BOOL; pub fn FlushFileBuffers(hFile: HANDLE) -> BOOL; pub fn CreateFileW(lpFileName: LPCWSTR, dwDesiredAccess: DWORD, @@ -6506,59 +7095,59 @@ pub mod funcs { lpSecurityAttributes: LPSECURITY_ATTRIBUTES, dwCreationDisposition: DWORD, dwFlagsAndAttributes: DWORD, - hTemplateFile: HANDLE) -> HANDLE; + hTemplateFile: HANDLE) + -> HANDLE; pub fn ReadFile(hFile: HANDLE, lpBuffer: LPVOID, nNumberOfBytesToRead: DWORD, lpNumberOfBytesRead: LPDWORD, - lpOverlapped: LPOVERLAPPED) -> BOOL; + lpOverlapped: LPOVERLAPPED) + -> BOOL; pub fn WriteFile(hFile: HANDLE, lpBuffer: LPVOID, nNumberOfBytesToWrite: DWORD, lpNumberOfBytesWritten: LPDWORD, - lpOverlapped: LPOVERLAPPED) -> BOOL; + lpOverlapped: LPOVERLAPPED) + -> BOOL; pub fn SetFilePointerEx(hFile: HANDLE, liDistanceToMove: LARGE_INTEGER, lpNewFilePointer: PLARGE_INTEGER, - dwMoveMethod: DWORD) -> BOOL; + dwMoveMethod: DWORD) + -> BOOL; pub fn SetEndOfFile(hFile: HANDLE) -> BOOL; - pub fn GetSystemTimeAsFileTime( - lpSystemTimeAsFileTime: LPFILETIME); + pub fn GetSystemTimeAsFileTime(lpSystemTimeAsFileTime: LPFILETIME); - pub fn QueryPerformanceFrequency( - lpFrequency: *mut LARGE_INTEGER) -> BOOL; - pub fn QueryPerformanceCounter( - lpPerformanceCount: *mut LARGE_INTEGER) -> BOOL; + pub fn QueryPerformanceFrequency(lpFrequency: *mut LARGE_INTEGER) -> BOOL; + pub fn QueryPerformanceCounter(lpPerformanceCount: *mut LARGE_INTEGER) -> BOOL; pub fn GetCurrentProcessId() -> DWORD; - pub fn CreateNamedPipeW( - lpName: LPCWSTR, - dwOpenMode: DWORD, - dwPipeMode: DWORD, - nMaxInstances: DWORD, - nOutBufferSize: DWORD, - nInBufferSize: DWORD, - nDefaultTimeOut: DWORD, - lpSecurityAttributes: LPSECURITY_ATTRIBUTES - ) -> HANDLE; - pub fn ConnectNamedPipe(hNamedPipe: HANDLE, - lpOverlapped: LPOVERLAPPED) -> BOOL; - pub fn WaitNamedPipeW(lpNamedPipeName: LPCWSTR, - nTimeOut: DWORD) -> BOOL; + pub fn CreateNamedPipeW(lpName: LPCWSTR, + dwOpenMode: DWORD, + dwPipeMode: DWORD, + nMaxInstances: DWORD, + nOutBufferSize: DWORD, + nInBufferSize: DWORD, + nDefaultTimeOut: DWORD, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES) + -> HANDLE; + pub fn ConnectNamedPipe(hNamedPipe: HANDLE, lpOverlapped: LPOVERLAPPED) -> BOOL; + pub fn WaitNamedPipeW(lpNamedPipeName: LPCWSTR, nTimeOut: DWORD) -> BOOL; pub fn SetNamedPipeHandleState(hNamedPipe: HANDLE, lpMode: LPDWORD, lpMaxCollectionCount: LPDWORD, lpCollectDataTimeout: LPDWORD) - -> BOOL; + -> BOOL; pub fn CreateEventW(lpEventAttributes: LPSECURITY_ATTRIBUTES, bManualReset: BOOL, bInitialState: BOOL, - lpName: LPCWSTR) -> HANDLE; + lpName: LPCWSTR) + -> HANDLE; pub fn GetOverlappedResult(hFile: HANDLE, lpOverlapped: LPOVERLAPPED, lpNumberOfBytesTransferred: LPDWORD, - bWait: BOOL) -> BOOL; + bWait: BOOL) + -> BOOL; pub fn DisconnectNamedPipe(hNamedPipe: HANDLE) -> BOOL; } } @@ -6575,8 +7164,7 @@ pub mod funcs { pub fn get_osfhandle(fd: c_int) -> c_long; #[link_name = "_open_osfhandle"] - pub fn open_osfhandle(osfhandle: intptr_t, - flags: c_int) -> c_int; + pub fn open_osfhandle(osfhandle: intptr_t, flags: c_int) -> c_int; } } @@ -6591,4 +7179,6 @@ pub mod funcs { } } -#[test] fn work_on_windows() { } // FIXME #10872 needed for a happy windows +#[test] +fn work_on_windows() { +} // FIXME #10872 needed for a happy windows diff --git a/src/liblog/directive.rs b/src/liblog/directive.rs index 362303869d..3958969cfc 100644 --- a/src/liblog/directive.rs +++ b/src/liblog/directive.rs @@ -17,15 +17,17 @@ pub struct LogDirective { pub level: u32, } -pub const LOG_LEVEL_NAMES: [&'static str; 4] = ["ERROR", "WARN", "INFO", - "DEBUG"]; +pub const LOG_LEVEL_NAMES: [&'static str; 4] = ["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)) + 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)) } /// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1/foo") @@ -40,44 +42,48 @@ pub fn parse_logging_spec(spec: &str) -> (Vec, Option) { let mods = parts.next(); let filter = parts.next(); if parts.next().is_some() { - println!("warning: invalid logging spec '{}', \ - ignoring it (too many '/'s)", spec); + println!("warning: invalid logging spec '{}', ignoring it (too many '/'s)", + spec); return (dirs, None); } - mods.map(|m| { for s in m.split(',') { - if s.is_empty() { continue } - let mut parts = s.split('='); - let (log_level, name) = match (parts.next(), parts.next().map(|s| s.trim()), parts.next()) { - (Some(part0), None, None) => { - // 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)), - } + if let Some(m) = mods { + for s in m.split(',') { + if s.is_empty() { + 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 + 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)), } } - }, - _ => { - println!("warning: invalid logging spec '{}', \ - ignoring it", s); - continue - } - }; - dirs.push(LogDirective { - name: name.map(str::to_owned), - level: log_level, - }); - }}); + (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 + } + }; + dirs.push(LogDirective { + name: name.map(str::to_owned), + level: log_level, + }); + } + } (dirs, filter.map(str::to_owned)) } diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs index 2c91a88f6e..9cb835bd85 100644 --- a/src/liblog/lib.rs +++ b/src/liblog/lib.rs @@ -235,7 +235,9 @@ pub trait Logger { fn log(&mut self, record: &LogRecord); } -struct DefaultLogger { handle: Stderr } +struct DefaultLogger { + handle: Stderr, +} /// Wraps the log level with fmt implementations. #[derive(Copy, Clone, PartialEq, PartialOrd, Debug)] @@ -246,7 +248,7 @@ impl fmt::Display for LogLevel { let LogLevel(level) = *self; match LOG_LEVEL_NAMES.get(level as usize - 1) { Some(ref name) => fmt::Display::fmt(name, fmt), - None => fmt::Display::fmt(&level, fmt) + None => fmt::Display::fmt(&level, fmt), } } } @@ -301,11 +303,10 @@ pub fn log(level: u32, loc: &'static LogLocation, args: fmt::Arguments) { // Completely remove the local logger from TLS in case anyone attempts to // frob the slot while we're doing the logging. This will destroy any logger // set during logging. - let mut logger: Box = LOCAL_LOGGER.with(|s| { - s.borrow_mut().take() - }).unwrap_or_else(|| { - box DefaultLogger { handle: io::stderr() } - }); + let mut logger: Box = LOCAL_LOGGER.with(|s| s.borrow_mut().take()) + .unwrap_or_else(|| { + box DefaultLogger { handle: io::stderr() } + }); logger.log(&LogRecord { level: LogLevel(level), args: args, @@ -320,22 +321,20 @@ pub fn log(level: u32, loc: &'static LogLocation, args: fmt::Arguments) { /// safely #[doc(hidden)] #[inline(always)] -pub fn log_level() -> u32 { unsafe { LOG_LEVEL } } +pub fn log_level() -> u32 { + unsafe { LOG_LEVEL } +} /// Replaces the thread-local logger with the specified logger, returning the old /// logger. pub fn set_logger(logger: Box) -> Option> { - let mut l = Some(logger); - LOCAL_LOGGER.with(|slot| { - mem::replace(&mut *slot.borrow_mut(), l.take()) - }) + LOCAL_LOGGER.with(|slot| mem::replace(&mut *slot.borrow_mut(), Some(logger))) } /// A LogRecord is created by the logging macros, and passed as the only /// argument to Loggers. #[derive(Debug)] pub struct LogRecord<'a> { - /// The module path of where the LogRecord originated. pub module_path: &'a str, @@ -373,7 +372,9 @@ pub fn mod_enabled(level: u32, module: &str) -> bool { // again to whether they should really be here or not. Hence, despite this // check being expanded manually in the logging macro, this function checks // the log level again. - if level > unsafe { LOG_LEVEL } { return false } + if level > unsafe { LOG_LEVEL } { + return false + } // This assertion should never get tripped unless we're in an at_exit // handler after logging has been torn down and a logging attempt was made. @@ -385,14 +386,11 @@ pub fn mod_enabled(level: u32, module: &str) -> bool { } } -fn enabled(level: u32, - module: &str, - iter: slice::Iter) - -> bool { +fn enabled(level: u32, module: &str, iter: slice::Iter) -> bool { // Search for the longest match, the vector is assumed to be pre-sorted. for directive in iter.rev() { match directive.name { - Some(ref name) if !module.starts_with(&name[..]) => {}, + Some(ref name) if !module.starts_with(&name[..]) => {} Some(..) | None => { return level <= directive.level } @@ -445,16 +443,14 @@ mod tests { #[test] fn match_full_path() { - let dirs = [ - LogDirective { - name: Some("crate2".to_string()), - level: 3 - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 2 - } - ]; + let dirs = [LogDirective { + name: Some("crate2".to_string()), + level: 3, + }, + LogDirective { + name: Some("crate1::mod1".to_string()), + level: 2, + }]; assert!(enabled(2, "crate1::mod1", dirs.iter())); assert!(!enabled(3, "crate1::mod1", dirs.iter())); assert!(enabled(3, "crate2", dirs.iter())); @@ -463,49 +459,72 @@ mod tests { #[test] fn no_match() { - let dirs = [ - LogDirective { name: Some("crate2".to_string()), level: 3 }, - LogDirective { name: Some("crate1::mod1".to_string()), level: 2 } - ]; + let dirs = [LogDirective { + name: Some("crate2".to_string()), + level: 3, + }, + LogDirective { + name: Some("crate1::mod1".to_string()), + level: 2, + }]; assert!(!enabled(2, "crate3", dirs.iter())); } #[test] fn match_beginning() { - let dirs = [ - LogDirective { name: Some("crate2".to_string()), level: 3 }, - LogDirective { name: Some("crate1::mod1".to_string()), level: 2 } - ]; + let dirs = [LogDirective { + name: Some("crate2".to_string()), + level: 3, + }, + LogDirective { + name: Some("crate1::mod1".to_string()), + level: 2, + }]; assert!(enabled(3, "crate2::mod1", dirs.iter())); } #[test] fn match_beginning_longest_match() { - let dirs = [ - LogDirective { name: Some("crate2".to_string()), level: 3 }, - LogDirective { name: Some("crate2::mod".to_string()), level: 4 }, - LogDirective { name: Some("crate1::mod1".to_string()), level: 2 } - ]; + let dirs = [LogDirective { + name: Some("crate2".to_string()), + level: 3, + }, + LogDirective { + name: Some("crate2::mod".to_string()), + level: 4, + }, + LogDirective { + name: Some("crate1::mod1".to_string()), + level: 2, + }]; assert!(enabled(4, "crate2::mod1", dirs.iter())); assert!(!enabled(4, "crate2", dirs.iter())); } #[test] fn match_default() { - let dirs = [ - LogDirective { name: None, level: 3 }, - LogDirective { name: Some("crate1::mod1".to_string()), level: 2 } - ]; + let dirs = [LogDirective { + name: None, + level: 3, + }, + LogDirective { + name: Some("crate1::mod1".to_string()), + level: 2, + }]; assert!(enabled(2, "crate1::mod1", dirs.iter())); assert!(enabled(3, "crate2::mod2", dirs.iter())); } #[test] fn zero_level() { - let dirs = [ - LogDirective { name: None, level: 3 }, - LogDirective { name: Some("crate1::mod1".to_string()), level: 0 } - ]; + let dirs = [LogDirective { + name: None, + level: 3, + }, + LogDirective { + name: Some("crate1::mod1".to_string()), + level: 0, + }]; assert!(!enabled(1, "crate1::mod1", dirs.iter())); assert!(enabled(3, "crate2::mod2", dirs.iter())); } diff --git a/src/librand/chacha.rs b/src/librand/chacha.rs index db81ff5c07..411ca83608 100644 --- a/src/librand/chacha.rs +++ b/src/librand/chacha.rs @@ -27,15 +27,15 @@ const CHACHA_ROUNDS: usize = 20; // Cryptographically secure from 8 upwards as o /// Salsa20*](http://cr.yp.to/chacha.html) #[derive(Copy, Clone)] pub struct ChaChaRng { - buffer: [u32; STATE_WORDS], // Internal buffer of output - state: [u32; STATE_WORDS], // Initial state - index: usize, // Index into state + buffer: [u32; STATE_WORDS], // Internal buffer of output + state: [u32; STATE_WORDS], // Initial state + index: usize, // Index into state } static EMPTY: ChaChaRng = ChaChaRng { - buffer: [0; STATE_WORDS], - state: [0; STATE_WORDS], - index: STATE_WORDS + buffer: [0; STATE_WORDS], + state: [0; STATE_WORDS], + index: STATE_WORDS, }; @@ -95,9 +95,9 @@ impl ChaChaRng { /// associated with a particular nonce can call this function with /// arguments `0, desired_nonce`. pub fn set_counter(&mut self, counter_low: u64, counter_high: u64) { - self.state[12] = (counter_low >> 0) as u32; + self.state[12] = (counter_low >> 0) as u32; self.state[13] = (counter_low >> 32) as u32; - self.state[14] = (counter_high >> 0) as u32; + self.state[14] = (counter_high >> 0) as u32; self.state[15] = (counter_high >> 32) as u32; self.index = STATE_WORDS; // force recomputation } @@ -127,7 +127,7 @@ impl ChaChaRng { self.state[3] = 0x6B206574; for i in 0..KEY_WORDS { - self.state[4+i] = key[i]; + self.state[4 + i] = key[i]; } self.state[12] = 0; @@ -144,11 +144,17 @@ impl ChaChaRng { self.index = 0; // update 128-bit counter self.state[12] += 1; - if self.state[12] != 0 { return }; + if self.state[12] != 0 { + return; + } self.state[13] += 1; - if self.state[13] != 0 { return }; + if self.state[13] != 0 { + return; + } self.state[14] += 1; - if self.state[14] != 0 { return }; + if self.state[14] != 0 { + return; + } self.state[15] += 1; } } @@ -172,7 +178,7 @@ impl<'a> SeedableRng<&'a [u32]> for ChaChaRng { // reset state self.init(&[0; KEY_WORDS]); // set key in place - let key = &mut self.state[4 .. 4+KEY_WORDS]; + let key = &mut self.state[4..4 + KEY_WORDS]; for (k, s) in key.iter_mut().zip(seed) { *k = *s; } @@ -191,7 +197,7 @@ impl<'a> SeedableRng<&'a [u32]> for ChaChaRng { impl Rand for ChaChaRng { fn rand(other: &mut R) -> ChaChaRng { - let mut key : [u32; KEY_WORDS] = [0; KEY_WORDS]; + let mut key: [u32; KEY_WORDS] = [0; KEY_WORDS]; for word in &mut key { *word = other.gen(); } @@ -219,7 +225,7 @@ mod tests { #[test] fn test_rng_seeded() { - let seed : &[_] = &[0,1,2,3,4,5,6,7]; + let seed: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; let mut ra: ChaChaRng = SeedableRng::from_seed(seed); let mut rb: ChaChaRng = SeedableRng::from_seed(seed); assert!(order::equals(ra.gen_ascii_chars().take(100), @@ -239,10 +245,11 @@ mod tests { } #[test] + #[rustfmt_skip] fn test_rng_true_values() { // Test vectors 1 and 2 from // http://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04 - let seed : &[_] = &[0; 8]; + let seed: &[_] = &[0; 8]; let mut ra: ChaChaRng = SeedableRng::from_seed(seed); let v = (0..16).map(|_| ra.next_u32()).collect::>(); @@ -260,12 +267,12 @@ mod tests { 0x281fed31, 0x45fb0a51, 0x1f0ae1ac, 0x6f4d794b)); - let seed : &[_] = &[0,1,2,3,4,5,6,7]; + let seed: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; let mut ra: ChaChaRng = SeedableRng::from_seed(seed); // Store the 17*i-th 32-bit word, // i.e., the i-th word of the i-th 16-word block - let mut v : Vec = Vec::new(); + let mut v: Vec = Vec::new(); for _ in 0..16 { v.push(ra.next_u32()); for _ in 0..16 { @@ -282,7 +289,7 @@ mod tests { #[test] fn test_rng_clone() { - let seed : &[_] = &[0; 8]; + let seed: &[_] = &[0; 8]; let mut rng: ChaChaRng = SeedableRng::from_seed(seed); let mut clone = rng.clone(); for _ in 0..16 { diff --git a/src/librand/distributions/exponential.rs b/src/librand/distributions/exponential.rs index ce72fa08a7..f02b945178 100644 --- a/src/librand/distributions/exponential.rs +++ b/src/librand/distributions/exponential.rs @@ -35,20 +35,22 @@ pub struct Exp1(pub f64); // This could be done via `-rng.gen::().ln()` but that is slower. impl Rand for Exp1 { #[inline] - fn rand(rng: &mut R) -> Exp1 { + fn rand(rng: &mut R) -> Exp1 { #[inline] fn pdf(x: f64) -> f64 { (-x).exp() } #[inline] - fn zero_case(rng: &mut R, _u: f64) -> f64 { + fn zero_case(rng: &mut R, _u: f64) -> f64 { ziggurat_tables::ZIG_EXP_R - rng.gen::().ln() } - Exp1(ziggurat(rng, false, + Exp1(ziggurat(rng, + false, &ziggurat_tables::ZIG_EXP_X, &ziggurat_tables::ZIG_EXP_F, - pdf, zero_case)) + pdf, + zero_case)) } } @@ -59,7 +61,7 @@ impl Rand for Exp1 { #[derive(Copy, Clone)] pub struct Exp { /// `lambda` stored as `1/lambda`, since this is what we scale by. - lambda_inverse: f64 + lambda_inverse: f64, } impl Exp { @@ -72,7 +74,9 @@ impl Exp { } impl Sample for Exp { - fn sample(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } + fn sample(&mut self, rng: &mut R) -> f64 { + self.ind_sample(rng) + } } impl IndependentSample for Exp { fn ind_sample(&self, rng: &mut R) -> f64 { @@ -83,8 +87,6 @@ impl IndependentSample for Exp { #[cfg(test)] mod tests { - use std::prelude::v1::*; - use distributions::{Sample, IndependentSample}; use super::Exp; @@ -113,8 +115,6 @@ mod tests { mod bench { extern crate test; - use std::prelude::v1::*; - use self::test::Bencher; use std::mem::size_of; use super::Exp; diff --git a/src/librand/distributions/gamma.rs b/src/librand/distributions/gamma.rs index 2a5d4bbd2e..fceda64cbb 100644 --- a/src/librand/distributions/gamma.rs +++ b/src/librand/distributions/gamma.rs @@ -46,7 +46,7 @@ pub struct Gamma { enum GammaRepr { Large(GammaLargeShape), One(Exp), - Small(GammaSmallShape) + Small(GammaSmallShape), } // These two helpers could be made public, but saving the @@ -65,7 +65,7 @@ enum GammaRepr { /// shape parameters. struct GammaSmallShape { inv_shape: f64, - large_shape: GammaLargeShape + large_shape: GammaLargeShape, } /// Gamma distribution where the shape parameter is larger than 1. @@ -75,7 +75,7 @@ struct GammaSmallShape { struct GammaLargeShape { scale: f64, c: f64, - d: f64 + d: f64, } impl Gamma { @@ -88,9 +88,9 @@ impl Gamma { assert!(scale > 0.0, "Gamma::new called with scale <= 0"); let repr = match shape { - 1.0 => One(Exp::new(1.0 / scale)), + 1.0 => One(Exp::new(1.0 / scale)), 0.0 ... 1.0 => Small(GammaSmallShape::new_raw(shape, scale)), - _ => Large(GammaLargeShape::new_raw(shape, scale)) + _ => Large(GammaLargeShape::new_raw(shape, scale)), }; Gamma { repr: repr } } @@ -100,7 +100,7 @@ impl GammaSmallShape { fn new_raw(shape: f64, scale: f64) -> GammaSmallShape { GammaSmallShape { inv_shape: 1. / shape, - large_shape: GammaLargeShape::new_raw(shape + 1.0, scale) + large_shape: GammaLargeShape::new_raw(shape + 1.0, scale), } } } @@ -111,19 +111,25 @@ impl GammaLargeShape { GammaLargeShape { scale: scale, c: 1. / (9. * d).sqrt(), - d: d + d: d, } } } impl Sample for Gamma { - fn sample(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } + fn sample(&mut self, rng: &mut R) -> f64 { + self.ind_sample(rng) + } } impl Sample for GammaSmallShape { - fn sample(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } + fn sample(&mut self, rng: &mut R) -> f64 { + self.ind_sample(rng) + } } impl Sample for GammaLargeShape { - fn sample(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } + fn sample(&mut self, rng: &mut R) -> f64 { + self.ind_sample(rng) + } } impl IndependentSample for Gamma { @@ -148,7 +154,7 @@ impl IndependentSample for GammaLargeShape { let StandardNormal(x) = rng.gen::(); let v_cbrt = 1.0 + self.c * x; if v_cbrt <= 0.0 { // a^3 <= 0 iff a <= 0 - continue + continue; } let v = v_cbrt * v_cbrt * v_cbrt; @@ -156,8 +162,8 @@ impl IndependentSample for GammaLargeShape { let x_sqr = x * x; if u < 1.0 - 0.0331 * x_sqr * x_sqr || - u.ln() < 0.5 * x_sqr + self.d * (1.0 - v + v.ln()) { - return self.d * v * self.scale + u.ln() < 0.5 * x_sqr + self.d * (1.0 - v + v.ln()) { + return self.d * v * self.scale; } } } @@ -168,7 +174,7 @@ impl IndependentSample for GammaLargeShape { /// /// For `k > 0` integral, this distribution is the sum of the squares /// of `k` independent standard normal random variables. For other -/// `k`, this uses the equivalent characterisation `χ²(k) = Gamma(k/2, +/// `k`, this uses the equivalent characterization `χ²(k) = Gamma(k/2, /// 2)`. pub struct ChiSquared { repr: ChiSquaredRepr, @@ -196,7 +202,9 @@ impl ChiSquared { } } impl Sample for ChiSquared { - fn sample(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } + fn sample(&mut self, rng: &mut R) -> f64 { + self.ind_sample(rng) + } } impl IndependentSample for ChiSquared { fn ind_sample(&self, rng: &mut R) -> f64 { @@ -206,7 +214,7 @@ impl IndependentSample for ChiSquared { let StandardNormal(norm) = rng.gen::(); norm * norm } - DoFAnythingElse(ref g) => g.ind_sample(rng) + DoFAnythingElse(ref g) => g.ind_sample(rng), } } } @@ -234,12 +242,14 @@ impl FisherF { FisherF { numer: ChiSquared::new(m), denom: ChiSquared::new(n), - dof_ratio: n / m + dof_ratio: n / m, } } } impl Sample for FisherF { - fn sample(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } + fn sample(&mut self, rng: &mut R) -> f64 { + self.ind_sample(rng) + } } impl IndependentSample for FisherF { fn ind_sample(&self, rng: &mut R) -> f64 { @@ -251,7 +261,7 @@ impl IndependentSample for FisherF { /// freedom. pub struct StudentT { chi: ChiSquared, - dof: f64 + dof: f64, } impl StudentT { @@ -261,12 +271,14 @@ impl StudentT { assert!(n > 0.0, "StudentT::new called with `n <= 0`"); StudentT { chi: ChiSquared::new(n), - dof: n + dof: n, } } } impl Sample for StudentT { - fn sample(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } + fn sample(&mut self, rng: &mut R) -> f64 { + self.ind_sample(rng) + } } impl IndependentSample for StudentT { fn ind_sample(&self, rng: &mut R) -> f64 { @@ -277,8 +289,6 @@ impl IndependentSample for StudentT { #[cfg(test)] mod tests { - use std::prelude::v1::*; - use distributions::{Sample, IndependentSample}; use super::{ChiSquared, StudentT, FisherF}; @@ -339,7 +349,6 @@ mod tests { #[cfg(test)] mod bench { extern crate test; - use std::prelude::v1::*; use self::test::Bencher; use std::mem::size_of; use distributions::IndependentSample; diff --git a/src/librand/distributions/mod.rs b/src/librand/distributions/mod.rs index 5defe174cf..4c62e1a350 100644 --- a/src/librand/distributions/mod.rs +++ b/src/librand/distributions/mod.rs @@ -54,7 +54,9 @@ pub trait IndependentSample: Sample { /// A wrapper for generating types that implement `Rand` via the /// `Sample` & `IndependentSample` traits. -pub struct RandSample { _marker: PhantomData } +pub struct RandSample { + _marker: PhantomData, +} impl RandSample { pub fn new() -> RandSample { @@ -63,7 +65,9 @@ impl RandSample { } impl Sample for RandSample { - fn sample(&mut self, rng: &mut R) -> Sup { self.ind_sample(rng) } + fn sample(&mut self, rng: &mut R) -> Sup { + self.ind_sample(rng) + } } impl IndependentSample for RandSample { @@ -89,9 +93,9 @@ pub struct Weighted { /// `IndependentSample` traits. Note that `&T` is (cheaply) `Clone` for /// all `T`, as is `usize`, so one can store references or indices into /// another vector. -pub struct WeightedChoice<'a, T:'a> { +pub struct WeightedChoice<'a, T: 'a> { items: &'a mut [Weighted], - weight_range: Range + weight_range: Range, } impl<'a, T: Clone> WeightedChoice<'a, T> { @@ -103,7 +107,8 @@ impl<'a, T: Clone> WeightedChoice<'a, T> { /// - the total weight is larger than a `usize` can contain. pub fn new(items: &'a mut [Weighted]) -> WeightedChoice<'a, T> { // strictly speaking, this is subsumed by the total weight == 0 case - assert!(!items.is_empty(), "WeightedChoice::new called with no items"); + assert!(!items.is_empty(), + "WeightedChoice::new called with no items"); let mut running_total = 0_usize; @@ -113,25 +118,28 @@ impl<'a, T: Clone> WeightedChoice<'a, T> { for item in &mut *items { running_total = match running_total.checked_add(item.weight) { Some(n) => n, - None => panic!("WeightedChoice::new called with a total weight \ - larger than a usize can contain") + None => panic!("WeightedChoice::new called with a total weight larger than a \ + usize can contain"), }; item.weight = running_total; } - assert!(running_total != 0, "WeightedChoice::new called with a total weight of 0"); + assert!(running_total != 0, + "WeightedChoice::new called with a total weight of 0"); WeightedChoice { items: items, // we're likely to be generating numbers in this range // relatively often, so might as well cache it - weight_range: Range::new(0, running_total) + weight_range: Range::new(0, running_total), } } } impl<'a, T: Clone> Sample for WeightedChoice<'a, T> { - fn sample(&mut self, rng: &mut R) -> T { self.ind_sample(rng) } + fn sample(&mut self, rng: &mut R) -> T { + self.ind_sample(rng) + } } impl<'a, T: Clone> IndependentSample for WeightedChoice<'a, T> { @@ -195,14 +203,16 @@ mod ziggurat_tables; // the perf improvement (25-50%) is definitely worth the extra code // size from force-inlining. #[inline(always)] -fn ziggurat( - rng: &mut R, - symmetric: bool, - x_tab: ziggurat_tables::ZigTable, - f_tab: ziggurat_tables::ZigTable, - mut pdf: P, - mut zero_case: Z) - -> f64 where P: FnMut(f64) -> f64, Z: FnMut(&mut R, f64) -> f64 { +fn ziggurat(rng: &mut R, + symmetric: bool, + x_tab: ziggurat_tables::ZigTable, + f_tab: ziggurat_tables::ZigTable, + mut pdf: P, + mut zero_case: Z) + -> f64 + where P: FnMut(f64) -> f64, + Z: FnMut(&mut R, f64) -> f64 +{ const SCALE: f64 = (1u64 << 53) as f64; loop { // reimplement the f64 generation as an optimisation suggested @@ -224,10 +234,18 @@ fn ziggurat( // 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] { @@ -245,8 +263,6 @@ fn ziggurat( #[cfg(test)] mod tests { - use std::prelude::v1::*; - use {Rng, Rand}; use super::{RandSample, WeightedChoice, Weighted, Sample, IndependentSample}; @@ -259,7 +275,9 @@ mod tests { } // 0, 1, 2, 3, ... - struct CountingRng { i: u32 } + struct CountingRng { + i: u32, + } impl Rng for CountingRng { fn next_u32(&mut self) -> u32 { self.i += 1; @@ -278,6 +296,7 @@ mod tests { assert_eq!(rand_sample.ind_sample(&mut ::test::rng()), ConstRand(0)); } #[test] + #[rustfmt_skip] fn test_weighted_choice() { // this makes assumptions about the internal implementation of // WeightedChoice, specifically: it doesn't reorder the items, @@ -298,49 +317,55 @@ mod tests { }} } - t!(vec!(Weighted { weight: 1, item: 10}), [10]); + t!(vec!(Weighted { weight: 1, item: 10 }), + [10]); // skip some - t!(vec!(Weighted { weight: 0, item: 20}, - Weighted { weight: 2, item: 21}, - Weighted { weight: 0, item: 22}, - Weighted { weight: 1, item: 23}), - [21,21, 23]); + t!(vec!(Weighted { weight: 0, item: 20 }, + Weighted { weight: 2, item: 21 }, + Weighted { weight: 0, item: 22 }, + Weighted { weight: 1, item: 23 }), + [21, 21, 23]); // different weights - t!(vec!(Weighted { weight: 4, item: 30}, - Weighted { weight: 3, item: 31}), - [30,30,30,30, 31,31,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}, - Weighted { weight: 1, item: 41}, - Weighted { weight: 1, item: 42}, - Weighted { weight: 1, item: 43}, - Weighted { weight: 1, item: 44}), + 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 }), [40, 41, 42, 43, 44]); - 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}), + 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 }), [50, 51, 52, 53, 54, 55, 56]); } - #[test] #[should_panic] + #[test] + #[should_panic] fn test_weighted_choice_no_items() { WeightedChoice::::new(&mut []); } - #[test] #[should_panic] + #[test] + #[should_panic] + #[rustfmt_skip] fn test_weighted_choice_zero_weight() { - WeightedChoice::new(&mut [Weighted { weight: 0, item: 0}, - Weighted { weight: 0, item: 1}]); + WeightedChoice::new(&mut [Weighted { weight: 0, item: 0 }, + Weighted { weight: 0, item: 1 }]); } - #[test] #[should_panic] + #[test] + #[should_panic] + #[rustfmt_skip] fn test_weighted_choice_weight_overflows() { let x = (!0) as usize / 2; // x + x + 2 is the overflow WeightedChoice::new(&mut [Weighted { weight: x, item: 0 }, diff --git a/src/librand/distributions/normal.rs b/src/librand/distributions/normal.rs index cc70a695c8..b2ccc5eb60 100644 --- a/src/librand/distributions/normal.rs +++ b/src/librand/distributions/normal.rs @@ -32,13 +32,13 @@ use distributions::{ziggurat, ziggurat_tables, Sample, IndependentSample}; pub struct StandardNormal(pub f64); impl Rand for StandardNormal { - fn rand(rng: &mut R) -> StandardNormal { + fn rand(rng: &mut R) -> StandardNormal { #[inline] fn pdf(x: f64) -> f64 { - (-x*x/2.0).exp() + (-x * x / 2.0).exp() } #[inline] - fn zero_case(rng: &mut R, u: f64) -> f64 { + fn zero_case(rng: &mut R, u: f64) -> f64 { // compute a random number in the tail by hand // strange initial conditions, because the loop is not @@ -56,15 +56,19 @@ impl Rand for StandardNormal { y = y_.ln(); } - if u < 0.0 { x - ziggurat_tables::ZIG_NORM_R } else { ziggurat_tables::ZIG_NORM_R - x } + if u < 0.0 { + x - ziggurat_tables::ZIG_NORM_R + } else { + ziggurat_tables::ZIG_NORM_R - x + } } - StandardNormal(ziggurat( - rng, - true, // this is symmetric - &ziggurat_tables::ZIG_NORM_X, - &ziggurat_tables::ZIG_NORM_F, - pdf, zero_case)) + StandardNormal(ziggurat(rng, + true, // this is symmetric + &ziggurat_tables::ZIG_NORM_X, + &ziggurat_tables::ZIG_NORM_F, + pdf, + zero_case)) } } @@ -89,12 +93,14 @@ impl Normal { assert!(std_dev >= 0.0, "Normal::new called with `std_dev` < 0"); Normal { mean: mean, - std_dev: std_dev + std_dev: std_dev, } } } impl Sample for Normal { - fn sample(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } + fn sample(&mut self, rng: &mut R) -> f64 { + self.ind_sample(rng) + } } impl IndependentSample for Normal { fn ind_sample(&self, rng: &mut R) -> f64 { @@ -110,7 +116,7 @@ impl IndependentSample for Normal { /// std_dev**2)` distributed. #[derive(Copy, Clone)] pub struct LogNormal { - norm: Normal + norm: Normal, } impl LogNormal { @@ -126,7 +132,9 @@ impl LogNormal { } } impl Sample for LogNormal { - fn sample(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } + fn sample(&mut self, rng: &mut R) -> f64 { + self.ind_sample(rng) + } } impl IndependentSample for LogNormal { fn ind_sample(&self, rng: &mut R) -> f64 { @@ -136,8 +144,6 @@ impl IndependentSample for LogNormal { #[cfg(test)] mod tests { - use std::prelude::v1::*; - use distributions::{Sample, IndependentSample}; use super::{Normal, LogNormal}; @@ -176,10 +182,9 @@ mod tests { #[cfg(test)] mod bench { extern crate test; - use std::prelude::v1::*; use self::test::Bencher; use std::mem::size_of; - use distributions::{Sample}; + use distributions::Sample; use super::Normal; #[bench] diff --git a/src/librand/distributions/range.rs b/src/librand/distributions/range.rs index 26f92ee3b1..f94ef059da 100644 --- a/src/librand/distributions/range.rs +++ b/src/librand/distributions/range.rs @@ -32,7 +32,7 @@ use distributions::{Sample, IndependentSample}; pub struct Range { low: X, range: X, - accept_zone: X + accept_zone: X, } impl Range { @@ -46,7 +46,9 @@ impl Range { impl Sample for Range { #[inline] - fn sample(&mut self, rng: &mut R) -> Sup { self.ind_sample(rng) } + fn sample(&mut self, rng: &mut R) -> Sup { + self.ind_sample(rng) + } } impl IndependentSample for Range { fn ind_sample(&self, rng: &mut R) -> Sup { @@ -146,9 +148,8 @@ float_impl! { f64 } #[cfg(test)] mod tests { - use std::prelude::v1::*; use distributions::{Sample, IndependentSample}; - use super::Range as Range; + use super::Range; #[should_panic] #[test] @@ -182,8 +183,7 @@ mod tests { )* }} } - t!(i8, i16, i32, i64, isize, - u8, u16, u32, u64, usize) + t!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize) } #[test] diff --git a/src/librand/distributions/ziggurat_tables.rs b/src/librand/distributions/ziggurat_tables.rs index b6de4bf892..7dfb0f131a 100644 --- a/src/librand/distributions/ziggurat_tables.rs +++ b/src/librand/distributions/ziggurat_tables.rs @@ -13,6 +13,7 @@ pub type ZigTable = &'static [f64; 257]; pub const ZIG_NORM_R: f64 = 3.654152885361008796; +#[rustfmt_skip] pub static ZIG_NORM_X: [f64; 257] = [3.910757959537090045, 3.654152885361008796, 3.449278298560964462, 3.320244733839166074, 3.224575052047029100, 3.147889289517149969, 3.083526132001233044, 3.027837791768635434, @@ -79,6 +80,7 @@ pub static ZIG_NORM_X: [f64; 257] = 0.487443966121754335, 0.463634336771763245, 0.437518402186662658, 0.408389134588000746, 0.375121332850465727, 0.335737519180459465, 0.286174591747260509, 0.215241895913273806, 0.000000000000000000]; +#[rustfmt_skip] pub static ZIG_NORM_F: [f64; 257] = [0.000477467764586655, 0.001260285930498598, 0.002609072746106363, 0.004037972593371872, 0.005522403299264754, 0.007050875471392110, 0.008616582769422917, 0.010214971439731100, @@ -146,6 +148,7 @@ pub static ZIG_NORM_F: [f64; 257] = 0.932060075968990209, 0.945198953453078028, 0.959879091812415930, 0.977101701282731328, 1.000000000000000000]; pub const ZIG_EXP_R: f64 = 7.697117470131050077; +#[rustfmt_skip] pub static ZIG_EXP_X: [f64; 257] = [8.697117470131052741, 7.697117470131050077, 6.941033629377212577, 6.478378493832569696, 6.144164665772472667, 5.882144315795399869, 5.666410167454033697, 5.482890627526062488, @@ -212,6 +215,7 @@ pub static ZIG_EXP_X: [f64; 257] = 0.253658363385912022, 0.233790483059674731, 0.212671510630966620, 0.189958689622431842, 0.165127622564187282, 0.137304980940012589, 0.104838507565818778, 0.063852163815001570, 0.000000000000000000]; +#[rustfmt_skip] pub static ZIG_EXP_F: [f64; 257] = [0.000167066692307963, 0.000454134353841497, 0.000967269282327174, 0.001536299780301573, 0.002145967743718907, 0.002788798793574076, 0.003460264777836904, 0.004157295120833797, diff --git a/src/librand/isaac.rs b/src/librand/isaac.rs index f51483cc11..ac2b9b07ff 100644 --- a/src/librand/isaac.rs +++ b/src/librand/isaac.rs @@ -48,7 +48,9 @@ static EMPTY: IsaacRng = IsaacRng { cnt: 0, rsl: [w(0); RAND_SIZE_USIZE], mem: [w(0); RAND_SIZE_USIZE], - a: w(0), b: w(0), c: w(0), + a: w(0), + b: w(0), + c: w(0), }; impl IsaacRng { @@ -95,15 +97,23 @@ impl IsaacRng { macro_rules! memloop { ($arr:expr) => {{ for i in (0..RAND_SIZE_USIZE).step_by(8) { - a=a+$arr[i ]; b=b+$arr[i+1]; - c=c+$arr[i+2]; d=d+$arr[i+3]; - e=e+$arr[i+4]; f=f+$arr[i+5]; - g=g+$arr[i+6]; h=h+$arr[i+7]; + a = a + $arr[i]; + b = b + $arr[i + 1]; + c = c + $arr[i + 2]; + d = d + $arr[i + 3]; + e = e + $arr[i + 4]; + f = f + $arr[i + 5]; + g = g + $arr[i + 6]; + h = h + $arr[i + 7]; mix!(); - self.mem[i ]=a; self.mem[i+1]=b; - self.mem[i+2]=c; self.mem[i+3]=d; - self.mem[i+4]=e; self.mem[i+5]=f; - self.mem[i+6]=g; self.mem[i+7]=h; + self.mem[i] = a; + self.mem[i + 1] = b; + self.mem[i + 2] = c; + self.mem[i + 3] = d; + self.mem[i + 4] = e; + self.mem[i + 5] = f; + self.mem[i + 6] = g; + self.mem[i + 7] = h; } }} } @@ -113,10 +123,14 @@ impl IsaacRng { } else { for i in (0..RAND_SIZE_USIZE).step_by(8) { mix!(); - self.mem[i ]=a; self.mem[i+1]=b; - self.mem[i+2]=c; self.mem[i+3]=d; - self.mem[i+4]=e; self.mem[i+5]=f; - self.mem[i+6]=g; self.mem[i+7]=h; + self.mem[i] = a; + self.mem[i + 1] = b; + self.mem[i + 2] = c; + self.mem[i + 3] = d; + self.mem[i + 4] = e; + self.mem[i + 5] = f; + self.mem[i + 6] = g; + self.mem[i + 7] = h; } } @@ -290,7 +304,9 @@ static EMPTY_64: Isaac64Rng = Isaac64Rng { cnt: 0, rsl: [w(0); RAND_SIZE_64], mem: [w(0); RAND_SIZE_64], - a: w(0), b: w(0), c: w(0), + a: w(0), + b: w(0), + c: w(0), }; impl Isaac64Rng { @@ -311,8 +327,14 @@ impl Isaac64Rng { let mut $var = w(0x9e3779b97f4a7c13); ) } - init!(a); init!(b); init!(c); init!(d); - init!(e); init!(f); init!(g); init!(h); + init!(a); + init!(b); + init!(c); + init!(d); + init!(e); + init!(f); + init!(g); + init!(h); macro_rules! mix { () => {{ @@ -335,15 +357,23 @@ impl Isaac64Rng { macro_rules! memloop { ($arr:expr) => {{ for i in (0..RAND_SIZE_64 / 8).map(|i| i * 8) { - a=a+$arr[i ]; b=b+$arr[i+1]; - c=c+$arr[i+2]; d=d+$arr[i+3]; - e=e+$arr[i+4]; f=f+$arr[i+5]; - g=g+$arr[i+6]; h=h+$arr[i+7]; + a = a + $arr[i]; + b = b + $arr[i + 1]; + c = c + $arr[i + 2]; + d = d + $arr[i + 3]; + e = e + $arr[i + 4]; + f = f + $arr[i + 5]; + g = g + $arr[i + 6]; + h = h + $arr[i + 7]; mix!(); - self.mem[i ]=a; self.mem[i+1]=b; - self.mem[i+2]=c; self.mem[i+3]=d; - self.mem[i+4]=e; self.mem[i+5]=f; - self.mem[i+6]=g; self.mem[i+7]=h; + self.mem[i] = a; + self.mem[i + 1] = b; + self.mem[i + 2] = c; + self.mem[i + 3] = d; + self.mem[i + 4] = e; + self.mem[i + 5] = f; + self.mem[i + 6] = g; + self.mem[i + 7] = h; } }} } @@ -353,10 +383,14 @@ impl Isaac64Rng { } else { for i in (0..RAND_SIZE_64 / 8).map(|i| i * 8) { mix!(); - self.mem[i ]=a; self.mem[i+1]=b; - self.mem[i+2]=c; self.mem[i+3]=d; - self.mem[i+4]=e; self.mem[i+5]=f; - self.mem[i+6]=g; self.mem[i+7]=h; + self.mem[i] = a; + self.mem[i + 1] = b; + self.mem[i + 2] = c; + self.mem[i + 3] = d; + self.mem[i + 4] = e; + self.mem[i + 5] = f; + self.mem[i + 6] = g; + self.mem[i + 7] = h; } } @@ -370,7 +404,7 @@ impl Isaac64Rng { let mut a = self.a; let mut b = self.b + self.c; const MIDPOINT: usize = RAND_SIZE_64 / 2; - const MP_VEC: [(usize, usize); 2] = [(0,MIDPOINT), (MIDPOINT, 0)]; + const MP_VEC: [(usize, usize); 2] = [(0, MIDPOINT), (MIDPOINT, 0)]; macro_rules! ind { ($x:expr) => { *self.mem.get_unchecked((($x >> 3).0 as usize) & (RAND_SIZE_64 - 1)) @@ -573,6 +607,7 @@ mod tests { } #[test] + #[rustfmt_skip] fn test_rng_32_true_values() { let seed: &[_] = &[1, 23, 456, 7890, 12345]; let mut ra: IsaacRng = SeedableRng::from_seed(seed); @@ -585,7 +620,9 @@ mod tests { let seed: &[_] = &[12345, 67890, 54321, 9876]; let mut rb: IsaacRng = SeedableRng::from_seed(seed); // skip forward to the 10000th number - for _ in 0..10000 { rb.next_u32(); } + for _ in 0..10000 { + rb.next_u32(); + } let v = (0..10).map(|_| rb.next_u32()).collect::>(); assert_eq!(v, @@ -593,6 +630,7 @@ mod tests { 1576568959, 3507990155, 179069555, 141456972, 2478885421)); } #[test] + #[rustfmt_skip] fn test_rng_64_true_values() { let seed: &[_] = &[1, 23, 456, 7890, 12345]; let mut ra: Isaac64Rng = SeedableRng::from_seed(seed); @@ -607,7 +645,9 @@ mod tests { let seed: &[_] = &[12345, 67890, 54321, 9876]; let mut rb: Isaac64Rng = SeedableRng::from_seed(seed); // skip forward to the 10000th number - for _ in 0..10000 { rb.next_u64(); } + for _ in 0..10000 { + rb.next_u64(); + } let v = (0..10).map(|_| rb.next_u64()).collect::>(); assert_eq!(v, @@ -615,6 +655,7 @@ mod tests { 17196852593171130876, 2606123525235546165, 15790932315217671084, 596345674630742204, 9947027391921273664, 11788097613744130851, 10391409374914919106)); + } #[test] diff --git a/src/librand/lib.rs b/src/librand/lib.rs index c3dace5131..b5a1eb9520 100644 --- a/src/librand/lib.rs +++ b/src/librand/lib.rs @@ -36,13 +36,19 @@ #![feature(num_bits_bytes)] #![feature(staged_api)] #![feature(step_by)] +#![feature(custom_attribute)] +#![allow(unused_attributes)] -#![cfg_attr(test, feature(test, rand, rustc_private, iter_order))] +#![cfg_attr(test, feature(test, rand, rustc_private, iter_order_deprecated))] #![allow(deprecated)] -#[cfg(test)] #[macro_use] extern crate std; -#[cfg(test)] #[macro_use] extern crate log; +#[cfg(test)] +#[macro_use] +extern crate std; +#[cfg(test)] +#[macro_use] +extern crate log; use core::f64; use core::intrinsics; @@ -217,7 +223,10 @@ pub trait Rng : Sized { /// Return an iterator that will yield an infinite number of randomly /// generated items. fn gen_iter<'a, T: Rand>(&'a mut self) -> Generator<'a, T, Self> { - Generator { rng: self, _marker: PhantomData } + Generator { + rng: self, + _marker: PhantomData, + } } /// Generate a random value in the range [`low`, `high`). @@ -272,9 +281,9 @@ pub trait Rng : Sized { /// Iterator which will generate a stream of random items. /// /// This iterator is created via the `gen_iter` method on `Rng`. -pub struct Generator<'a, T, R:'a> { +pub struct Generator<'a, T, R: 'a> { rng: &'a mut R, - _marker: PhantomData + _marker: PhantomData, } impl<'a, T: Rand, R: Rng> Iterator for Generator<'a, T, R> { @@ -288,7 +297,7 @@ impl<'a, T: Rand, R: Rng> Iterator for Generator<'a, T, R> { /// Iterator which will continuously generate random ascii characters. /// /// This iterator is created via the `gen_ascii_chars` method on `Rng`. -pub struct AsciiGenerator<'a, R:'a> { +pub struct AsciiGenerator<'a, R: 'a> { rng: &'a mut R, } @@ -384,7 +393,7 @@ impl SeedableRng<[u32; 4]> for XorShiftRng { x: seed[0], y: seed[1], z: seed[2], - w: seed[3] + w: seed[3], } } } @@ -396,7 +405,12 @@ impl Rand for XorShiftRng { tuple = rng.gen(); } let (x, y, z, w) = tuple; - XorShiftRng { x: x, y: y, z: z, w: w } + XorShiftRng { + x: x, + y: y, + z: z, + w: w, + } } } @@ -420,7 +434,9 @@ pub struct Closed01(pub F); mod test { use std::__rand as rand; - pub struct MyRng { inner: R } + pub struct MyRng { + inner: R, + } impl ::Rng for MyRng { fn next_u32(&mut self) -> u32 { diff --git a/src/librand/rand_impls.rs b/src/librand/rand_impls.rs index 04093db4b6..726a455462 100644 --- a/src/librand/rand_impls.rs +++ b/src/librand/rand_impls.rs @@ -14,7 +14,7 @@ use core::char; use core::isize; use core::usize; -use {Rand,Rng}; +use {Rand, Rng}; impl Rand for isize { #[inline] @@ -185,7 +185,9 @@ macro_rules! tuple_impl { impl Rand for () { #[inline] - fn rand(_: &mut R) -> () { () } + fn rand(_: &mut R) -> () { + () + } } tuple_impl!{A} tuple_impl!{A, B} diff --git a/src/librand/reseeding.rs b/src/librand/reseeding.rs index 99fe2bb5ab..584cf78a1c 100644 --- a/src/librand/reseeding.rs +++ b/src/librand/reseeding.rs @@ -35,12 +35,12 @@ impl> ReseedingRng { /// * `rng`: the random number generator to use. /// * `generation_threshold`: the number of bytes of entropy at which to reseed the RNG. /// * `reseeder`: the reseeding object to use. - pub fn new(rng: R, generation_threshold: usize, reseeder: Rsdr) -> ReseedingRng { + pub fn new(rng: R, generation_threshold: usize, reseeder: Rsdr) -> ReseedingRng { ReseedingRng { rng: rng, generation_threshold: generation_threshold, bytes_generated: 0, - reseeder: reseeder + reseeder: reseeder, } } @@ -90,7 +90,7 @@ impl, Rsdr: Reseeder + Default> rng: SeedableRng::from_seed(seed), generation_threshold: DEFAULT_GENERATION_THRESHOLD, bytes_generated: 0, - reseeder: rsdr + reseeder: rsdr, } } } @@ -114,19 +114,21 @@ impl Reseeder for ReseedWithDefault { #[stable(feature = "rust1", since = "1.0.0")] impl Default for ReseedWithDefault { #[stable(feature = "rust1", since = "1.0.0")] - fn default() -> ReseedWithDefault { ReseedWithDefault } + fn default() -> ReseedWithDefault { + ReseedWithDefault + } } #[cfg(test)] mod tests { use std::prelude::v1::*; - use core::iter::{order, repeat}; + use core::iter::order; use super::{ReseedingRng, ReseedWithDefault}; use {SeedableRng, Rng}; struct Counter { - i: u32 + i: u32, } impl Rng for Counter { @@ -153,7 +155,7 @@ mod tests { #[test] fn test_reseeding() { - let mut rs = ReseedingRng::new(Counter {i:0}, 400, ReseedWithDefault); + let mut rs = ReseedingRng::new(Counter { i: 0 }, 400, ReseedWithDefault); let mut i = 0; for _ in 0..1000 { diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs index af36d45ab5..1c6cb06d54 100644 --- a/src/librbml/lib.rs +++ b/src/librbml/lib.rs @@ -467,37 +467,44 @@ pub mod reader { f(&d.data[d.start..d.end]) } - pub fn doc_as_u8(d: Doc) -> u8 { assert_eq!(d.end, d.start + 1); d.data[d.start] } - pub fn doc_as_u16(d: Doc) -> u16 { - assert_eq!(d.end, d.start + 2); - let mut b = [0; 2]; - bytes::copy_memory(&d.data[d.start..d.end], &mut b); - unsafe { (*(b.as_ptr() as *const u16)).to_be() } - } - - pub fn doc_as_u32(d: Doc) -> u32 { - assert_eq!(d.end, d.start + 4); - let mut b = [0; 4]; - bytes::copy_memory(&d.data[d.start..d.end], &mut b); - unsafe { (*(b.as_ptr() as *const u32)).to_be() } - } - pub fn doc_as_u64(d: Doc) -> u64 { - assert_eq!(d.end, d.start + 8); - let mut b = [0; 8]; - bytes::copy_memory(&d.data[d.start..d.end], &mut b); - unsafe { (*(b.as_ptr() as *const u64)).to_be() } + if d.end >= 8 { + // For performance, we read 8 big-endian bytes, + // and mask off the junk if there is any. This + // obviously won't work on the first 8 bytes + // of a file - we will fall of the start + // of the page and segfault. + + let mut b = [0; 8]; + bytes::copy_memory(&d.data[d.end-8..d.end], &mut b); + let data = unsafe { (*(b.as_ptr() as *const u64)).to_be() }; + let len = d.end - d.start; + if len < 8 { + data & ((1<<(len*8))-1) + } else { + data + } + } else { + let mut result = 0; + for b in &d.data[d.start..d.end] { + result = (result<<8) + (*b as u64); + } + result + } } - pub fn doc_as_i8(d: Doc) -> i8 { doc_as_u8(d) as i8 } - pub fn doc_as_i16(d: Doc) -> i16 { doc_as_u16(d) as i16 } - pub fn doc_as_i32(d: Doc) -> i32 { doc_as_u32(d) as i32 } - pub fn doc_as_i64(d: Doc) -> i64 { doc_as_u64(d) as i64 } + #[inline] pub fn doc_as_u16(d: Doc) -> u16 { doc_as_u64(d) as u16 } + #[inline] pub fn doc_as_u32(d: Doc) -> u32 { doc_as_u64(d) as u32 } + + #[inline] pub fn doc_as_i8(d: Doc) -> i8 { doc_as_u8(d) as i8 } + #[inline] pub fn doc_as_i16(d: Doc) -> i16 { doc_as_u16(d) as i16 } + #[inline] pub fn doc_as_i32(d: Doc) -> i32 { doc_as_u32(d) as i32 } + #[inline] pub fn doc_as_i64(d: Doc) -> i64 { doc_as_u64(d) as i64 } pub struct Decoder<'a> { parent: Doc<'a>, @@ -907,7 +914,7 @@ pub mod writer { } } - fn write_vuint(w: &mut W, n: usize) -> EncodeResult { + pub fn write_vuint(w: &mut W, n: usize) -> EncodeResult { if n < 0x7f { return write_sized_vuint(w, n, 1); } if n < 0x4000 { return write_sized_vuint(w, n, 2); } if n < 0x200000 { return write_sized_vuint(w, n, 3); } @@ -925,15 +932,6 @@ pub mod writer { } } - /// FIXME(pcwalton): Workaround for badness in trans. DO NOT USE ME. - pub unsafe fn unsafe_clone(&self) -> Encoder<'a> { - Encoder { - writer: mem::transmute_copy(&self.writer), - size_positions: self.size_positions.clone(), - relax_limit: self.relax_limit, - } - } - pub fn start_tag(&mut self, tag_id: usize) -> EncodeResult { debug!("Start tag {:?}", tag_id); assert!(tag_id >= NUM_IMPLICIT_TAGS); @@ -996,35 +994,43 @@ pub mod writer { pub fn wr_tagged_u64(&mut self, tag_id: usize, v: u64) -> EncodeResult { let bytes: [u8; 8] = unsafe { mem::transmute(v.to_be()) }; - self.wr_tagged_bytes(tag_id, &bytes) + // tagged integers are emitted in big-endian, with no + // leading zeros. + let leading_zero_bytes = v.leading_zeros()/8; + self.wr_tagged_bytes(tag_id, &bytes[leading_zero_bytes as usize..]) } - pub fn wr_tagged_u32(&mut self, tag_id: usize, v: u32) -> EncodeResult{ - let bytes: [u8; 4] = unsafe { mem::transmute(v.to_be()) }; - self.wr_tagged_bytes(tag_id, &bytes) + #[inline] + pub fn wr_tagged_u32(&mut self, tag_id: usize, v: u32) -> EncodeResult { + self.wr_tagged_u64(tag_id, v as u64) } + #[inline] pub fn wr_tagged_u16(&mut self, tag_id: usize, v: u16) -> EncodeResult { - let bytes: [u8; 2] = unsafe { mem::transmute(v.to_be()) }; - self.wr_tagged_bytes(tag_id, &bytes) + self.wr_tagged_u64(tag_id, v as u64) } + #[inline] pub fn wr_tagged_u8(&mut self, tag_id: usize, v: u8) -> EncodeResult { self.wr_tagged_bytes(tag_id, &[v]) } + #[inline] pub fn wr_tagged_i64(&mut self, tag_id: usize, v: i64) -> EncodeResult { self.wr_tagged_u64(tag_id, v as u64) } + #[inline] pub fn wr_tagged_i32(&mut self, tag_id: usize, v: i32) -> EncodeResult { self.wr_tagged_u32(tag_id, v as u32) } + #[inline] pub fn wr_tagged_i16(&mut self, tag_id: usize, v: i16) -> EncodeResult { self.wr_tagged_u16(tag_id, v as u16) } + #[inline] pub fn wr_tagged_i8(&mut self, tag_id: usize, v: i8) -> EncodeResult { self.wr_tagged_bytes(tag_id, &[v as u8]) } diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 9616b596c0..7cb2de78e2 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -298,10 +298,18 @@ const FOO: i32 = { 0 }; // but brackets are useless here ``` "##, +// FIXME(#24111) Change the language here when const fn stabilizes E0015: r##" The only functions that can be called in static or constant expressions are -`const` functions. Rust currently does not support more general compile-time -function execution. +`const` functions, and struct/enum constructors. `const` functions are only +available on a nightly compiler. Rust currently does not support more general +compile-time function execution. + +``` +const FOO: Option = Some(1); // enum constructor +struct Bar {x: u8} +const BAR: Bar = Bar {x: 1}; // struct constructor +``` See [RFC 911] for more details on the design of `const fn`s. @@ -1886,7 +1894,150 @@ This explicitly states that you expect the trait object `SomeTrait` to contain references (with a maximum lifetime of `'a`). [1]: https://github.com/rust-lang/rfcs/pull/1156 -"## +"##, + +E0454: r##" +A link name was given with an empty name. Erroneous code example: + +``` +#[link(name = "")] extern {} // error: #[link(name = "")] given with empty name +``` + +The rust compiler cannot link to an external library if you don't give it its +name. Example: + +``` +#[link(name = "some_lib")] extern {} // ok! +``` +"##, + +E0458: r##" +An unknown "kind" was specified for a link attribute. Erroneous code example: + +``` +#[link(kind = "wonderful_unicorn")] extern {} +// error: unknown kind: `wonderful_unicorn` +``` + +Please specify a valid "kind" value, from one of the following: + * static + * dylib + * framework +"##, + +E0459: r##" +A link was used without a name parameter. Erroneous code example: + +``` +#[link(kind = "dylib")] extern {} +// error: #[link(...)] specified without `name = "foo"` +``` + +Please add the name parameter to allow the rust compiler to find the library +you want. Example: + +``` +#[link(kind = "dylib", name = "some_lib")] extern {} // ok! +``` +"##, + +E0493: r##" +A type with a destructor was assigned to an invalid type of variable. Erroneous +code example: + +``` +struct Foo { + a: u32 +} + +impl Drop for Foo { + fn drop(&mut self) {} +} + +const F : Foo = Foo { a : 0 }; +// error: constants are not allowed to have destructors +static S : Foo = Foo { a : 0 }; +// error: statics are not allowed to have destructors +``` + +To solve this issue, please use a type which does allow the usage of type with +destructors. +"##, + +E0494: r##" +A reference of an interior static was assigned to another const/static. +Erroneous code example: + +``` +struct Foo { + a: u32 +} + +static S : Foo = Foo { a : 0 }; +static A : &'static u32 = &S.a; +// error: cannot refer to the interior of another static, use a +// constant instead +``` + +The "base" variable has to be a const if you want another static/const variable +to refer to one of its fields. Example: + +``` +struct Foo { + a: u32 +} + +const S : Foo = Foo { a : 0 }; +static A : &'static u32 = &S.a; // ok! +``` +"##, + +E0496: r##" +A lifetime name is shadowing another lifetime name. Erroneous code example: + +``` +struct Foo<'a> { + a: &'a i32, +} + +impl<'a> Foo<'a> { + fn f<'a>(x: &'a i32) { // error: lifetime name `'a` shadows a lifetime + // name that is already in scope + } +} +``` + +Please change the name of one of the lifetimes to remove this error. Example: + + +``` +struct Foo<'a> { + a: &'a i32, +} + +impl<'a> Foo<'a> { + fn f<'b>(x: &'b i32) { // ok! + } +} + +fn main() { +} +``` +"##, + +E0497: r##" +A stability attribute was used outside of the standard library. Erroneous code +example: + +``` +#[stable] // error: stability attributes may not be used outside of the + // standard library +fn foo() {} +``` + +It is not possible to use stability attributes outside of the standard library. +Also, for now, it is not possible to write deprecation messages either. +"##, } @@ -1914,5 +2065,46 @@ register_diagnostics! { E0314, // closure outlives stack frame E0315, // cannot invoke closure outside of its lifetime E0316, // nested quantification of lifetimes - E0400 // overloaded derefs are not allowed in constants + E0400, // overloaded derefs are not allowed in constants + E0452, // malformed lint attribute + E0453, // overruled by outer forbid + E0455, // native frameworks are only available on OSX targets + E0456, // plugin `..` is not available for triple `..` + E0457, // plugin `..` only found in rlib format, but must be available... + E0460, // found possibly newer version of crate `..` + E0461, // couldn't find crate `..` with expected target triple .. + E0462, // found staticlib `..` instead of rlib or dylib + E0463, // can't find crate for `..` + E0464, // multiple matching crates for `..` + E0465, // multiple .. candidates for `..` found + E0466, // bad macro import + E0467, // bad macro reexport + E0468, // an `extern crate` loading macros must be at the crate root + E0469, // imported macro not found + E0470, // reexported macro not found + E0471, // constant evaluation error: .. + E0472, // asm! is unsupported on this target + E0473, // dereference of reference outside its lifetime + E0474, // captured variable `..` does not outlive the enclosing closure + E0475, // index of slice outside its lifetime + E0476, // lifetime of the source pointer does not outlive lifetime bound... + E0477, // the type `..` does not fulfill the required lifetime... + E0478, // lifetime bound not satisfied + E0479, // the type `..` (provided as the value of a type parameter) is... + E0480, // lifetime of method receiver does not outlive the method call + E0481, // lifetime of function argument does not outlive the function call + E0482, // lifetime of return value does not outlive the function call + E0483, // lifetime of operand does not outlive the operation + E0484, // reference is not valid at the time of borrow + E0485, // automatically reference is not valid at the time of borrow + E0486, // type of expression contains references that are not valid during... + E0487, // unsafe use of destructor: destructor might be called while... + E0488, // lifetime of variable does not enclose its declaration + E0489, // type/lifetime parameter not in scope here + E0490, // a value of type `..` is borrowed for too long + E0491, // in type `..`, reference has a longer lifetime than the data it... + E0492, // cannot borrow a constant which contains interior mutability + E0495, // cannot infer an appropriate lifetime due to conflicting requirements + E0498, // malformed plugin attribute + E0514, // metadata version mismatch } diff --git a/src/librustc/front/check_attr.rs b/src/librustc/front/check_attr.rs new file mode 100644 index 0000000000..cca14f1fbf --- /dev/null +++ b/src/librustc/front/check_attr.rs @@ -0,0 +1,110 @@ +// 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 session::Session; + +use syntax::ast; +use syntax::attr::AttrMetaMethods; +use syntax::visit; +use syntax::visit::Visitor; + +#[derive(Copy, Clone, PartialEq)] +enum Target { + Fn, + Struct, + Enum, + Other, +} + +impl Target { + fn from_item(item: &ast::Item) -> Target { + match item.node { + ast::ItemFn(..) => Target::Fn, + ast::ItemStruct(..) => Target::Struct, + ast::ItemEnum(..) => Target::Enum, + _ => Target::Other, + } + } +} + +struct CheckAttrVisitor<'a> { + sess: &'a Session, +} + +impl<'a> CheckAttrVisitor<'a> { + fn check_inline(&self, attr: &ast::Attribute, target: Target) { + if target != Target::Fn { + self.sess.span_err( + attr.span, + "attribute should be applied to function"); + } + } + + fn check_repr(&self, attr: &ast::Attribute, target: Target) { + let words = match attr.meta_item_list() { + Some(words) => words, + None => { + return; + } + }; + for word in words { + let word: &str = &word.name(); + match word { + "C" => { + if target != Target::Struct && target != Target::Enum { + self.sess.span_err( + attr.span, + "attribute should be applied to struct or enum"); + } + } + "packed" | + "simd" => { + if target != Target::Struct { + self.sess.span_err( + attr.span, + "attribute should be applied to struct"); + } + } + "i8" | "u8" | "i16" | "u16" | + "i32" | "u32" | "i64" | "u64" | + "isize" | "usize" => { + if target != Target::Enum { + self.sess.span_err( + attr.span, + "attribute should be applied to enum"); + } + } + _ => (), + } + } + } + + fn check_attribute(&self, attr: &ast::Attribute, target: Target) { + let name: &str = &attr.name(); + match name { + "inline" => self.check_inline(attr, target), + "repr" => self.check_repr(attr, target), + _ => (), + } + } +} + +impl<'a, 'v> Visitor<'v> for CheckAttrVisitor<'a> { + fn visit_item(&mut self, item: &ast::Item) { + let target = Target::from_item(item); + for attr in &item.attrs { + self.check_attribute(attr, target); + } + } +} + +pub fn check_crate(sess: &Session, krate: &ast::Crate) { + visit::walk_crate(&mut CheckAttrVisitor { sess: sess }, krate); +} diff --git a/src/librustc/front/map/blocks.rs b/src/librustc/front/map/blocks.rs index 4e16d9e567..7d4809d457 100644 --- a/src/librustc/front/map/blocks.rs +++ b/src/librustc/front/map/blocks.rs @@ -26,7 +26,7 @@ pub use self::Code::*; use front::map::{self, Node}; use syntax::abi; use rustc_front::hir::{Block, FnDecl}; -use syntax::ast::{NodeId, Ident}; +use syntax::ast::{Name, NodeId}; use rustc_front::hir as ast; use syntax::codemap::Span; use rustc_front::visit::FnKind; @@ -107,7 +107,7 @@ impl<'a> Code<'a> { /// These are all the components one can extract from a fn item for /// use when implementing FnLikeNode operations. struct ItemFnParts<'a> { - ident: Ident, + name: Name, decl: &'a ast::FnDecl, unsafety: ast::Unsafety, constness: ast::Constness, @@ -189,13 +189,13 @@ impl<'a> FnLikeNode<'a> { pub fn kind(self) -> FnKind<'a> { let item = |p: ItemFnParts<'a>| -> FnKind<'a> { - FnKind::ItemFn(p.ident, p.generics, p.unsafety, p.constness, p.abi, p.vis) + FnKind::ItemFn(p.name, p.generics, p.unsafety, p.constness, p.abi, p.vis) }; let closure = |_: ClosureParts| { FnKind::Closure }; - let method = |_, ident, sig: &'a ast::MethodSig, vis, _, _| { - FnKind::Method(ident, sig, vis) + let method = |_, name: Name, sig: &'a ast::MethodSig, vis, _, _| { + FnKind::Method(name, sig, vis) }; self.handle(item, method, closure) } @@ -203,7 +203,7 @@ impl<'a> FnLikeNode<'a> { fn handle(self, item_fn: I, method: M, closure: C) -> A where I: FnOnce(ItemFnParts<'a>) -> A, M: FnOnce(NodeId, - Ident, + Name, &'a ast::MethodSig, Option, &'a ast::Block, @@ -216,7 +216,7 @@ impl<'a> FnLikeNode<'a> { ast::ItemFn(ref decl, unsafety, constness, abi, ref generics, ref block) => item_fn(ItemFnParts { id: i.id, - ident: i.ident, + name: i.name, decl: &**decl, unsafety: unsafety, body: &**block, @@ -230,14 +230,14 @@ impl<'a> FnLikeNode<'a> { }, map::NodeTraitItem(ti) => match ti.node { ast::MethodTraitItem(ref sig, Some(ref body)) => { - method(ti.id, ti.ident, sig, None, body, ti.span) + method(ti.id, ti.name, sig, None, body, ti.span) } _ => panic!("trait method FnLikeNode that is not fn-like"), }, map::NodeImplItem(ii) => { match ii.node { ast::MethodImplItem(ref sig, ref body) => { - method(ii.id, ii.ident, sig, Some(ii.vis), body, ii.span) + method(ii.id, ii.name, sig, Some(ii.vis), body, ii.span) } _ => { panic!("impl method FnLikeNode that is not fn-like") diff --git a/src/librustc/front/map/collector.rs b/src/librustc/front/map/collector.rs new file mode 100644 index 0000000000..f255949a9f --- /dev/null +++ b/src/librustc/front/map/collector.rs @@ -0,0 +1,316 @@ +// 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::*; +use super::MapEntry::*; + +use rustc_front::hir::*; +use rustc_front::util; +use rustc_front::visit::{self, Visitor}; +use middle::def_id::{CRATE_DEF_INDEX, DefIndex}; +use std::iter::repeat; +use syntax::ast::{NodeId, CRATE_NODE_ID, DUMMY_NODE_ID}; +use syntax::codemap::Span; + +/// A Visitor that walks over an AST and collects Node's into an AST +/// Map. +pub struct NodeCollector<'ast> { + pub map: Vec>, + pub definitions: Definitions, + pub parent_node: NodeId, +} + +impl<'ast> NodeCollector<'ast> { + pub fn root() -> NodeCollector<'ast> { + let mut collector = NodeCollector { + map: vec![], + definitions: Definitions::new(), + parent_node: CRATE_NODE_ID, + }; + collector.insert_entry(CRATE_NODE_ID, RootCrate); + + let result = collector.create_def_with_parent(None, CRATE_NODE_ID, DefPathData::CrateRoot); + assert_eq!(result, CRATE_DEF_INDEX); + + collector.create_def_with_parent(Some(CRATE_DEF_INDEX), DUMMY_NODE_ID, DefPathData::Misc); + + collector + } + + pub fn extend(parent: &'ast InlinedParent, + parent_node: NodeId, + parent_def_path: DefPath, + map: Vec>, + definitions: Definitions) + -> NodeCollector<'ast> { + let mut collector = NodeCollector { + map: map, + parent_node: parent_node, + definitions: definitions, + }; + + collector.insert_entry(parent_node, RootInlinedParent(parent)); + collector.create_def(parent_node, DefPathData::InlinedRoot(parent_def_path)); + + collector + } + + fn parent_def(&self) -> Option { + let mut parent_node = Some(self.parent_node); + while let Some(p) = parent_node { + if let Some(q) = self.definitions.opt_def_index(p) { + return Some(q); + } + parent_node = self.map[p as usize].parent_node(); + } + None + } + + fn create_def(&mut self, node_id: NodeId, data: DefPathData) -> DefIndex { + let parent_def = self.parent_def(); + self.definitions.create_def_with_parent(parent_def, node_id, data) + } + + fn create_def_with_parent(&mut self, + parent: Option, + node_id: NodeId, + data: DefPathData) + -> DefIndex { + self.definitions.create_def_with_parent(parent, node_id, data) + } + + fn insert_entry(&mut self, id: NodeId, entry: MapEntry<'ast>) { + debug!("ast_map: {:?} => {:?}", id, entry); + let len = self.map.len(); + if id as usize >= len { + self.map.extend(repeat(NotPresent).take(id as usize - len + 1)); + } + self.map[id as usize] = entry; + } + + fn insert_def(&mut self, id: NodeId, node: Node<'ast>, data: DefPathData) -> DefIndex { + self.insert(id, node); + self.create_def(id, data) + } + + fn insert(&mut self, id: NodeId, node: Node<'ast>) { + let entry = MapEntry::from_node(self.parent_node, node); + self.insert_entry(id, entry); + } +} + +impl<'ast> Visitor<'ast> for NodeCollector<'ast> { + fn visit_item(&mut self, i: &'ast Item) { + // Pick the def data. This need not be unique, but the more + // information we encapsulate into + let def_data = match i.node { + ItemDefaultImpl(..) | ItemImpl(..) => DefPathData::Impl, + ItemEnum(..) | ItemStruct(..) | ItemTrait(..) => DefPathData::Type(i.name), + ItemExternCrate(..) | ItemMod(..) => DefPathData::Mod(i.name), + ItemStatic(..) | ItemConst(..) | ItemFn(..) => DefPathData::Value(i.name), + _ => DefPathData::Misc, + }; + + self.insert_def(i.id, NodeItem(i), def_data); + + let parent_node = self.parent_node; + self.parent_node = i.id; + + match i.node { + ItemImpl(..) => {} + ItemEnum(ref enum_definition, _) => { + for v in &enum_definition.variants { + let variant_def_index = + self.insert_def(v.node.data.id(), + NodeVariant(&**v), + DefPathData::EnumVariant(v.node.name)); + + for field in v.node.data.fields() { + self.create_def_with_parent( + Some(variant_def_index), + field.node.id, + DefPathData::Field(field.node.kind)); + } + } + } + ItemForeignMod(..) => { + } + ItemStruct(ref struct_def, _) => { + // If this is a tuple-like struct, register the constructor. + if !struct_def.is_struct() { + self.insert_def(struct_def.id(), + NodeStructCtor(struct_def), + DefPathData::StructCtor); + } + + for field in struct_def.fields() { + self.create_def(field.node.id, DefPathData::Field(field.node.kind)); + } + } + ItemTrait(_, _, ref bounds, _) => { + for b in bounds.iter() { + if let TraitTyParamBound(ref t, TraitBoundModifier::None) = *b { + self.insert(t.trait_ref.ref_id, NodeItem(i)); + } + } + } + ItemUse(ref view_path) => { + match view_path.node { + ViewPathList(_, ref paths) => { + for path in paths { + self.insert(path.node.id(), NodeItem(i)); + } + } + _ => () + } + } + _ => {} + } + visit::walk_item(self, i); + self.parent_node = parent_node; + } + + fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) { + self.insert_def(foreign_item.id, + NodeForeignItem(foreign_item), + DefPathData::Value(foreign_item.name)); + + let parent_node = self.parent_node; + self.parent_node = foreign_item.id; + visit::walk_foreign_item(self, foreign_item); + self.parent_node = parent_node; + } + + fn visit_generics(&mut self, generics: &'ast Generics) { + for ty_param in generics.ty_params.iter() { + self.insert_def(ty_param.id, + NodeTyParam(ty_param), + DefPathData::TypeParam(ty_param.name)); + } + + visit::walk_generics(self, generics); + } + + fn visit_trait_item(&mut self, ti: &'ast TraitItem) { + let def_data = match ti.node { + MethodTraitItem(..) | ConstTraitItem(..) => DefPathData::Value(ti.name), + TypeTraitItem(..) => DefPathData::Type(ti.name), + }; + + self.insert(ti.id, NodeTraitItem(ti)); + self.create_def(ti.id, def_data); + + let parent_node = self.parent_node; + self.parent_node = ti.id; + + match ti.node { + ConstTraitItem(_, Some(ref expr)) => { + self.create_def(expr.id, DefPathData::Initializer); + } + _ => { } + } + + visit::walk_trait_item(self, ti); + + self.parent_node = parent_node; + } + + fn visit_impl_item(&mut self, ii: &'ast ImplItem) { + let def_data = match ii.node { + MethodImplItem(..) | ConstImplItem(..) => DefPathData::Value(ii.name), + TypeImplItem(..) => DefPathData::Type(ii.name), + }; + + self.insert_def(ii.id, NodeImplItem(ii), def_data); + + let parent_node = self.parent_node; + self.parent_node = ii.id; + + match ii.node { + ConstImplItem(_, ref expr) => { + self.create_def(expr.id, DefPathData::Initializer); + } + _ => { } + } + + visit::walk_impl_item(self, ii); + + self.parent_node = parent_node; + } + + fn visit_pat(&mut self, pat: &'ast Pat) { + let maybe_binding = match pat.node { + PatIdent(_, id, _) => Some(id.node), + _ => None + }; + + if let Some(id) = maybe_binding { + self.insert_def(pat.id, NodeLocal(pat), DefPathData::Binding(id.name)); + } else { + self.insert(pat.id, NodePat(pat)); + } + + let parent_node = self.parent_node; + self.parent_node = pat.id; + visit::walk_pat(self, pat); + self.parent_node = parent_node; + } + + fn visit_expr(&mut self, expr: &'ast Expr) { + self.insert(expr.id, NodeExpr(expr)); + + match expr.node { + ExprClosure(..) => { self.create_def(expr.id, DefPathData::ClosureExpr); } + _ => { } + } + + let parent_node = self.parent_node; + self.parent_node = expr.id; + visit::walk_expr(self, expr); + self.parent_node = parent_node; + } + + fn visit_stmt(&mut self, stmt: &'ast Stmt) { + let id = util::stmt_id(stmt); + self.insert(id, NodeStmt(stmt)); + let parent_node = self.parent_node; + self.parent_node = id; + visit::walk_stmt(self, stmt); + self.parent_node = parent_node; + } + + fn visit_fn(&mut self, fk: visit::FnKind<'ast>, fd: &'ast FnDecl, + b: &'ast Block, s: Span, id: NodeId) { + assert_eq!(self.parent_node, id); + visit::walk_fn(self, fk, fd, b, s); + } + + fn visit_block(&mut self, block: &'ast Block) { + self.insert(block.id, NodeBlock(block)); + let parent_node = self.parent_node; + self.parent_node = block.id; + visit::walk_block(self, block); + self.parent_node = parent_node; + } + + fn visit_lifetime(&mut self, lifetime: &'ast Lifetime) { + self.insert(lifetime.id, NodeLifetime(lifetime)); + } + + fn visit_lifetime_def(&mut self, def: &'ast LifetimeDef) { + self.create_def(def.lifetime.id, DefPathData::LifetimeDef(def.lifetime.name)); + self.visit_lifetime(&def.lifetime); + } + + fn visit_macro_def(&mut self, macro_def: &'ast MacroDef) { + self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.name)); + } +} + diff --git a/src/librustc/front/map/definitions.rs b/src/librustc/front/map/definitions.rs new file mode 100644 index 0000000000..c1eb5f1f11 --- /dev/null +++ b/src/librustc/front/map/definitions.rs @@ -0,0 +1,263 @@ +// 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 metadata::cstore::LOCAL_CRATE; +use middle::def_id::{DefId, DefIndex}; +use rustc_data_structures::fnv::FnvHashMap; +use rustc_front::hir; +use syntax::ast; +use syntax::parse::token::InternedString; +use util::nodemap::NodeMap; + +#[derive(Clone)] +pub struct Definitions { + data: Vec, + key_map: FnvHashMap, + node_map: NodeMap, +} + +/// A unique identifier that we can use to lookup a definition +/// precisely. It combines the index of the definition's parent (if +/// any) with a `DisambiguatedDefPathData`. +#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +pub struct DefKey { + /// Parent path. + pub parent: Option, + + /// Identifier of this node. + pub disambiguated_data: DisambiguatedDefPathData, +} + +/// Pair of `DefPathData` and an integer disambiguator. The integer is +/// normally 0, but in the event that there are multiple defs with the +/// same `parent` and `data`, we use this field to disambiguate +/// between them. This introduces some artificial ordering dependency +/// but means that if you have (e.g.) two impls for the same type in +/// the same module, they do get distinct def-ids. +#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +pub struct DisambiguatedDefPathData { + pub data: DefPathData, + pub disambiguator: u32 +} + +/// For each definition, we track the following data. A definition +/// here is defined somewhat circularly as "something with a def-id", +/// but it generally corresponds to things like structs, enums, etc. +/// There are also some rather random cases (like const initializer +/// expressions) that are mostly just leftovers. +#[derive(Clone, Debug)] +pub struct DefData { + pub key: DefKey, + + /// Local ID within the HIR. + pub node_id: ast::NodeId, +} + +pub type DefPath = Vec; + +#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +pub enum DefPathData { + // Root: these should only be used for the root nodes, because + // they are treated specially by the `def_path` function. + CrateRoot, + InlinedRoot(DefPath), + + // Catch-all for random DefId things like DUMMY_NODE_ID + Misc, + + // Different kinds of items and item-like things: + Impl, + Type(ast::Name), + Mod(ast::Name), + Value(ast::Name), + MacroDef(ast::Name), + ClosureExpr, + + // Subportions of items + TypeParam(ast::Name), + LifetimeDef(ast::Name), + EnumVariant(ast::Name), + PositionalField, + Field(hir::StructFieldKind), + StructCtor, // implicit ctor for a tuple-like struct + Initializer, // initializer for a const + Binding(ast::Name), // pattern binding + + // An external crate that does not have an `extern crate` in this + // crate. + DetachedCrate(ast::Name), +} + +impl Definitions { + pub fn new() -> Definitions { + Definitions { + data: vec![], + key_map: FnvHashMap(), + node_map: NodeMap(), + } + } + + pub fn len(&self) -> usize { + self.data.len() + } + + pub fn def_key(&self, index: DefIndex) -> DefKey { + self.data[index.as_usize()].key.clone() + } + + /// Returns the path from the crate root to `index`. The root + /// nodes are not included in the path (i.e., this will be an + /// empty vector for the crate root). For an inlined item, this + /// will be the path of the item in the external crate (but the + /// path will begin with the path to the external crate). + pub fn def_path(&self, index: DefIndex) -> DefPath { + make_def_path(index, |p| self.def_key(p)) + } + + pub fn opt_def_index(&self, node: ast::NodeId) -> Option { + self.node_map.get(&node).cloned() + } + + pub fn opt_local_def_id(&self, node: ast::NodeId) -> Option { + self.opt_def_index(node).map(DefId::local) + } + + pub fn as_local_node_id(&self, def_id: DefId) -> Option { + if def_id.krate == LOCAL_CRATE { + assert!(def_id.index.as_usize() < self.data.len()); + Some(self.data[def_id.index.as_usize()].node_id) + } else { + None + } + } + + pub fn create_def_with_parent(&mut self, + parent: Option, + node_id: ast::NodeId, + data: DefPathData) + -> DefIndex { + assert!(!self.node_map.contains_key(&node_id), + "adding a def'n for node-id {:?} and data {:?} but a previous def'n exists: {:?}", + node_id, + data, + self.data[self.node_map[&node_id].as_usize()]); + + // Find a unique DefKey. This basically means incrementing the disambiguator + // until we get no match. + let mut key = DefKey { + parent: parent, + disambiguated_data: DisambiguatedDefPathData { + data: data, + disambiguator: 0 + } + }; + + while self.key_map.contains_key(&key) { + key.disambiguated_data.disambiguator += 1; + } + + // Create the definition. + let index = DefIndex::new(self.data.len()); + self.data.push(DefData { key: key.clone(), node_id: node_id }); + self.node_map.insert(node_id, index); + self.key_map.insert(key, index); + + index + } +} + +impl DefPathData { + pub fn as_interned_str(&self) -> InternedString { + use self::DefPathData::*; + match *self { + Type(name) | + Mod(name) | + Value(name) | + MacroDef(name) | + TypeParam(name) | + LifetimeDef(name) | + EnumVariant(name) | + DetachedCrate(name) | + Binding(name) => { + name.as_str() + } + + Field(hir::StructFieldKind::NamedField(name, _)) => { + name.as_str() + } + + PositionalField | + Field(hir::StructFieldKind::UnnamedField(_)) => { + InternedString::new("") + } + + // note that this does not show up in user printouts + CrateRoot => { + InternedString::new("") + } + + // note that this does not show up in user printouts + InlinedRoot(_) => { + InternedString::new("") + } + + Misc => { + InternedString::new("?") + } + + Impl => { + InternedString::new("") + } + + ClosureExpr => { + InternedString::new("") + } + + StructCtor => { + InternedString::new("") + } + + Initializer => { + InternedString::new("") + } + } + } + + pub fn to_string(&self) -> String { + self.as_interned_str().to_string() + } +} + +pub fn make_def_path(start_index: DefIndex, mut get_key: FN) -> DefPath + where FN: FnMut(DefIndex) -> DefKey +{ + let mut result = vec![]; + let mut index = Some(start_index); + while let Some(p) = index { + let key = get_key(p); + match key.disambiguated_data.data { + DefPathData::CrateRoot => { + assert!(key.parent.is_none()); + break; + } + DefPathData::InlinedRoot(ref p) => { + assert!(key.parent.is_none()); + result.extend(p.iter().cloned().rev()); + break; + } + _ => { + result.push(key.disambiguated_data); + index = key.parent; + } + } + } + result.reverse(); + result +} diff --git a/src/librustc/front/map/mod.rs b/src/librustc/front/map/mod.rs index 764f54ce0f..94800db184 100644 --- a/src/librustc/front/map/mod.rs +++ b/src/librustc/front/map/mod.rs @@ -11,31 +11,34 @@ pub use self::Node::*; pub use self::PathElem::*; use self::MapEntry::*; +use self::collector::NodeCollector; +pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData, DisambiguatedDefPathData}; use metadata::inline::InlinedItem; use metadata::inline::InlinedItem as II; use middle::def_id::DefId; use syntax::abi; -use syntax::ast::{Name, NodeId, Ident, CRATE_NODE_ID, DUMMY_NODE_ID}; +use syntax::ast::{self, Name, NodeId, DUMMY_NODE_ID}; use syntax::codemap::{Span, Spanned}; use syntax::parse::token; use rustc_front::hir::*; use rustc_front::fold::Folder; -use rustc_front::visit::{self, Visitor}; -use rustc_front::util; +use rustc_front::visit; use rustc_front::print::pprust; use arena::TypedArena; use std::cell::RefCell; use std::fmt; use std::io; -use std::iter::{self, repeat}; +use std::iter; use std::mem; use std::slice; pub mod blocks; +mod collector; +pub mod definitions; #[derive(Clone, Copy, PartialEq, Debug)] pub enum PathElem { @@ -115,13 +118,12 @@ pub enum Node<'ast> { NodeVariant(&'ast Variant), NodeExpr(&'ast Expr), NodeStmt(&'ast Stmt), - NodeArg(&'ast Pat), NodeLocal(&'ast Pat), NodePat(&'ast Pat), NodeBlock(&'ast Block), /// NodeStructCtor represents a tuple struct. - NodeStructCtor(&'ast StructDef), + NodeStructCtor(&'ast VariantData), NodeLifetime(&'ast Lifetime), NodeTyParam(&'ast TyParam) @@ -130,7 +132,7 @@ pub enum Node<'ast> { /// Represents an entry and its parent NodeID. /// The odd layout is to bring down the total size. #[derive(Copy, Debug)] -enum MapEntry<'ast> { +pub enum MapEntry<'ast> { /// Placeholder for holes in the map. NotPresent, @@ -142,11 +144,10 @@ enum MapEntry<'ast> { EntryVariant(NodeId, &'ast Variant), EntryExpr(NodeId, &'ast Expr), EntryStmt(NodeId, &'ast Stmt), - EntryArg(NodeId, &'ast Pat), EntryLocal(NodeId, &'ast Pat), EntryPat(NodeId, &'ast Pat), EntryBlock(NodeId, &'ast Block), - EntryStructCtor(NodeId, &'ast StructDef), + EntryStructCtor(NodeId, &'ast VariantData), EntryLifetime(NodeId, &'ast Lifetime), EntryTyParam(NodeId, &'ast TyParam), @@ -177,7 +178,6 @@ impl<'ast> MapEntry<'ast> { NodeVariant(n) => EntryVariant(p, n), NodeExpr(n) => EntryExpr(p, n), NodeStmt(n) => EntryStmt(p, n), - NodeArg(n) => EntryArg(p, n), NodeLocal(n) => EntryLocal(p, n), NodePat(n) => EntryPat(p, n), NodeBlock(n) => EntryBlock(p, n), @@ -196,7 +196,6 @@ impl<'ast> MapEntry<'ast> { EntryVariant(id, _) => id, EntryExpr(id, _) => id, EntryStmt(id, _) => id, - EntryArg(id, _) => id, EntryLocal(id, _) => id, EntryPat(id, _) => id, EntryBlock(id, _) => id, @@ -216,7 +215,6 @@ impl<'ast> MapEntry<'ast> { EntryVariant(_, n) => NodeVariant(n), EntryExpr(_, n) => NodeExpr(n), EntryStmt(_, n) => NodeStmt(n), - EntryArg(_, n) => NodeArg(n), EntryLocal(_, n) => NodeLocal(n), EntryPat(_, n) => NodePat(n), EntryBlock(_, n) => NodeBlock(n), @@ -263,10 +261,45 @@ pub struct Map<'ast> { /// /// Also, indexing is pretty quick when you've got a vector and /// plain old integers. - map: RefCell>> + map: RefCell>>, + + definitions: RefCell, } impl<'ast> Map<'ast> { + pub fn num_local_def_ids(&self) -> usize { + self.definitions.borrow().len() + } + + pub fn def_key(&self, def_id: DefId) -> DefKey { + assert!(def_id.is_local()); + self.definitions.borrow().def_key(def_id.index) + } + + pub fn def_path_from_id(&self, id: NodeId) -> DefPath { + self.def_path(self.local_def_id(id)) + } + + pub fn def_path(&self, def_id: DefId) -> DefPath { + assert!(def_id.is_local()); + self.definitions.borrow().def_path(def_id.index) + } + + pub fn local_def_id(&self, node: NodeId) -> DefId { + self.opt_local_def_id(node).unwrap_or_else(|| { + panic!("local_def_id: no entry for `{}`, which has a map of `{:?}`", + node, self.find_entry(node)) + }) + } + + pub fn opt_local_def_id(&self, node: NodeId) -> Option { + self.definitions.borrow().opt_local_def_id(node) + } + + pub fn as_local_node_id(&self, def_id: DefId) -> Option { + self.definitions.borrow().as_local_node_id(def_id) + } + fn entry_count(&self) -> usize { self.map.borrow().len() } @@ -288,6 +321,10 @@ impl<'ast> Map<'ast> { } } + pub fn get_if_local(&self, id: DefId) -> Option> { + self.as_local_node_id(id).map(|id| self.get(id)) + } + /// Retrieve the Node corresponding to `id`, returning None if /// cannot be found. pub fn find(&self, id: NodeId) -> Option> { @@ -306,6 +343,27 @@ impl<'ast> Map<'ast> { self.find_entry(id).and_then(|x| x.parent_node()).unwrap_or(id) } + /// Check if the node is an argument. An argument is a local variable whose + /// immediate parent is an item or a closure. + pub fn is_argument(&self, id: NodeId) -> bool { + match self.find(id) { + Some(NodeLocal(_)) => (), + _ => return false, + } + match self.find(self.get_parent_node(id)) { + Some(NodeItem(_)) | + Some(NodeTraitItem(_)) | + Some(NodeImplItem(_)) => true, + Some(NodeExpr(e)) => { + match e.node { + ExprClosure(..) => true, + _ => false, + } + } + _ => false, + } + } + /// If there is some error when walking the parents (e.g., a node does not /// have a parent in the map or a node can't be found), then we return the /// last good node id we found. Note that reaching the crate root (id == 0), @@ -383,7 +441,7 @@ impl<'ast> Map<'ast> { match self.find_entry(parent) { Some(RootInlinedParent(&InlinedParent {ii: II::TraitItem(did, _), ..})) => did, Some(RootInlinedParent(&InlinedParent {ii: II::ImplItem(did, _), ..})) => did, - _ => DefId::local(parent) + _ => self.local_def_id(parent) } } @@ -429,18 +487,19 @@ impl<'ast> Map<'ast> { } } - pub fn expect_struct(&self, id: NodeId) -> &'ast StructDef { + pub fn expect_struct(&self, id: NodeId) -> &'ast VariantData { match self.find(id) { Some(NodeItem(i)) => { match i.node { - ItemStruct(ref struct_def, _) => &**struct_def, + ItemStruct(ref struct_def, _) => struct_def, _ => panic!("struct ID bound to non-struct") } } Some(NodeVariant(variant)) => { - match variant.node.kind { - StructVariantKind(ref struct_def) => &**struct_def, - _ => panic!("struct ID bound to enum variant that isn't struct-like"), + if variant.node.data.is_struct() { + &variant.node.data + } else { + panic!("struct ID bound to enum variant that isn't struct-like") } } _ => panic!(format!("expected struct, found {}", self.node_to_string(id))), @@ -475,16 +534,20 @@ impl<'ast> Map<'ast> { NodeItem(item) => { match item.node { ItemMod(_) | ItemForeignMod(_) => { - PathMod(item.ident.name) + PathMod(item.name) } - _ => PathName(item.ident.name) + _ => PathName(item.name) } } - NodeForeignItem(i) => PathName(i.ident.name), - NodeImplItem(ii) => PathName(ii.ident.name), - NodeTraitItem(ti) => PathName(ti.ident.name), - NodeVariant(v) => PathName(v.node.name.name), + NodeForeignItem(i) => PathName(i.name), + NodeImplItem(ii) => PathName(ii.name), + NodeTraitItem(ti) => PathName(ti.name), + NodeVariant(v) => PathName(v.node.name), NodeLifetime(lt) => PathName(lt.name), + NodeTyParam(tp) => PathName(tp.name), + NodeLocal(&Pat { node: PatIdent(_,l,_), .. }) => { + PathName(l.node.name) + }, _ => panic!("no path elem for {:?}", node) } } @@ -499,9 +562,9 @@ impl<'ast> Map<'ast> { self.with_path(id, |path| path_to_string(path)) } - fn path_to_str_with_ident(&self, id: NodeId, i: Ident) -> String { + fn path_to_str_with_name(&self, id: NodeId, name: Name) -> String { self.with_path(id, |path| { - path_to_string(path.chain(Some(PathName(i.name)))) + path_to_string(path.chain(Some(PathName(name)))) }) } @@ -536,9 +599,9 @@ impl<'ast> Map<'ast> { } } - /// Given a node ID, get a list of of attributes associated with the AST + /// Given a node ID, get a list of attributes associated with the AST /// corresponding to the Node ID - pub fn attrs(&self, id: NodeId) -> &'ast [Attribute] { + pub fn attrs(&self, id: NodeId) -> &'ast [ast::Attribute] { let attrs = match self.find(id) { Some(NodeItem(i)) => Some(&i.attrs[..]), Some(NodeForeignItem(fi)) => Some(&fi.attrs[..]), @@ -581,7 +644,7 @@ impl<'ast> Map<'ast> { Some(NodeVariant(variant)) => variant.span, Some(NodeExpr(expr)) => expr.span, Some(NodeStmt(stmt)) => stmt.span, - Some(NodeArg(pat)) | Some(NodeLocal(pat)) => pat.span, + Some(NodeLocal(pat)) => pat.span, Some(NodePat(pat)) => pat.span, Some(NodeBlock(block)) => block.span, Some(NodeStructCtor(_)) => self.expect_item(self.get_parent(id)).span, @@ -596,9 +659,13 @@ impl<'ast> Map<'ast> { .unwrap_or_else(|| panic!("AstMap.span: could not find span for id {:?}", id)) } + pub fn span_if_local(&self, id: DefId) -> Option { + self.as_local_node_id(id).map(|id| self.span(id)) + } + pub fn def_id_span(&self, def_id: DefId, fallback: Span) -> Span { - if def_id.is_local() { - self.opt_span(def_id.node).unwrap_or(fallback) + if let Some(node_id) = self.as_local_node_id(def_id) { + self.opt_span(node_id).unwrap_or(fallback) } else { fallback } @@ -652,7 +719,7 @@ impl<'a, 'ast> NodesMatchingSuffix<'a, 'ast> { match map.find(id) { None => return None, Some(NodeItem(item)) if item_is_mod(&*item) => - return Some((id, item.ident.name)), + return Some((id, item.name)), _ => {} } let parent = map.get_parent(id); @@ -708,11 +775,11 @@ trait Named { impl Named for Spanned { fn name(&self) -> Name { self.node.name() } } -impl Named for Item { fn name(&self) -> Name { self.ident.name } } -impl Named for ForeignItem { fn name(&self) -> Name { self.ident.name } } -impl Named for Variant_ { fn name(&self) -> Name { self.name.name } } -impl Named for TraitItem { fn name(&self) -> Name { self.ident.name } } -impl Named for ImplItem { fn name(&self) -> Name { self.ident.name } } +impl Named for Item { fn name(&self) -> Name { self.name } } +impl Named for ForeignItem { fn name(&self) -> Name { self.name } } +impl Named for Variant_ { fn name(&self) -> Name { self.name } } +impl Named for TraitItem { fn name(&self) -> Name { self.name } } +impl Named for ImplItem { fn name(&self) -> Name { self.name } } pub trait FoldOps { fn new_id(&self, id: NodeId) -> NodeId { @@ -741,194 +808,10 @@ impl Folder for IdAndSpanUpdater { } } -/// A Visitor that walks over an AST and collects Node's into an AST Map. -struct NodeCollector<'ast> { - map: Vec>, - parent_node: NodeId, -} - -impl<'ast> NodeCollector<'ast> { - fn insert_entry(&mut self, id: NodeId, entry: MapEntry<'ast>) { - debug!("ast_map: {:?} => {:?}", id, entry); - let len = self.map.len(); - if id as usize >= len { - self.map.extend(repeat(NotPresent).take(id as usize - len + 1)); - } - self.map[id as usize] = entry; - } - - fn insert(&mut self, id: NodeId, node: Node<'ast>) { - let entry = MapEntry::from_node(self.parent_node, node); - self.insert_entry(id, entry); - } - - fn visit_fn_decl(&mut self, decl: &'ast FnDecl) { - for a in &decl.inputs { - self.insert(a.id, NodeArg(&*a.pat)); - } - } -} - -impl<'ast> Visitor<'ast> for NodeCollector<'ast> { - fn visit_item(&mut self, i: &'ast Item) { - self.insert(i.id, NodeItem(i)); - - let parent_node = self.parent_node; - self.parent_node = i.id; - - match i.node { - ItemImpl(_, _, _, _, _, ref impl_items) => { - for ii in impl_items { - self.insert(ii.id, NodeImplItem(ii)); - } - } - ItemEnum(ref enum_definition, _) => { - for v in &enum_definition.variants { - self.insert(v.node.id, NodeVariant(&**v)); - } - } - ItemForeignMod(ref nm) => { - for nitem in &nm.items { - self.insert(nitem.id, NodeForeignItem(&**nitem)); - } - } - ItemStruct(ref struct_def, _) => { - // If this is a tuple-like struct, register the constructor. - match struct_def.ctor_id { - Some(ctor_id) => { - self.insert(ctor_id, NodeStructCtor(&**struct_def)); - } - None => {} - } - } - ItemTrait(_, _, ref bounds, ref trait_items) => { - for b in bounds.iter() { - if let TraitTyParamBound(ref t, TraitBoundModifier::None) = *b { - self.insert(t.trait_ref.ref_id, NodeItem(i)); - } - } - - for ti in trait_items { - self.insert(ti.id, NodeTraitItem(ti)); - } - } - ItemUse(ref view_path) => { - match view_path.node { - ViewPathList(_, ref paths) => { - for path in paths { - self.insert(path.node.id(), NodeItem(i)); - } - } - _ => () - } - } - _ => {} - } - visit::walk_item(self, i); - self.parent_node = parent_node; - } - - fn visit_generics(&mut self, generics: &'ast Generics) { - for ty_param in generics.ty_params.iter() { - self.insert(ty_param.id, NodeTyParam(ty_param)); - } - - visit::walk_generics(self, generics); - } - - fn visit_trait_item(&mut self, ti: &'ast TraitItem) { - let parent_node = self.parent_node; - self.parent_node = ti.id; - visit::walk_trait_item(self, ti); - self.parent_node = parent_node; - } - - fn visit_impl_item(&mut self, ii: &'ast ImplItem) { - let parent_node = self.parent_node; - self.parent_node = ii.id; - - visit::walk_impl_item(self, ii); - - self.parent_node = parent_node; - } - - fn visit_pat(&mut self, pat: &'ast Pat) { - self.insert(pat.id, match pat.node { - // Note: this is at least *potentially* a pattern... - PatIdent(..) => NodeLocal(pat), - _ => NodePat(pat) - }); - - let parent_node = self.parent_node; - self.parent_node = pat.id; - visit::walk_pat(self, pat); - self.parent_node = parent_node; - } - - fn visit_expr(&mut self, expr: &'ast Expr) { - self.insert(expr.id, NodeExpr(expr)); - let parent_node = self.parent_node; - self.parent_node = expr.id; - visit::walk_expr(self, expr); - self.parent_node = parent_node; - } - - fn visit_stmt(&mut self, stmt: &'ast Stmt) { - let id = util::stmt_id(stmt); - self.insert(id, NodeStmt(stmt)); - let parent_node = self.parent_node; - self.parent_node = id; - visit::walk_stmt(self, stmt); - self.parent_node = parent_node; - } - - fn visit_fn(&mut self, fk: visit::FnKind<'ast>, fd: &'ast FnDecl, - b: &'ast Block, s: Span, id: NodeId) { - let parent_node = self.parent_node; - self.parent_node = id; - self.visit_fn_decl(fd); - visit::walk_fn(self, fk, fd, b, s); - self.parent_node = parent_node; - } - - fn visit_ty(&mut self, ty: &'ast Ty) { - let parent_node = self.parent_node; - self.parent_node = ty.id; - match ty.node { - TyBareFn(ref fd) => { - self.visit_fn_decl(&*fd.decl); - } - _ => {} - } - visit::walk_ty(self, ty); - self.parent_node = parent_node; - } - - fn visit_block(&mut self, block: &'ast Block) { - self.insert(block.id, NodeBlock(block)); - let parent_node = self.parent_node; - self.parent_node = block.id; - visit::walk_block(self, block); - self.parent_node = parent_node; - } - - fn visit_lifetime_ref(&mut self, lifetime: &'ast Lifetime) { - self.insert(lifetime.id, NodeLifetime(lifetime)); - } - - fn visit_lifetime_def(&mut self, def: &'ast LifetimeDef) { - self.visit_lifetime_ref(&def.lifetime); - } -} - pub fn map_crate<'ast>(forest: &'ast mut Forest) -> Map<'ast> { - let mut collector = NodeCollector { - map: vec![], - parent_node: CRATE_NODE_ID, - }; - collector.insert_entry(CRATE_NODE_ID, RootCrate); + let mut collector = NodeCollector::root(); visit::walk_crate(&mut collector, &forest.krate); - let map = collector.map; + let NodeCollector { map, definitions, .. } = collector; if log_enabled!(::log::DEBUG) { // This only makes sense for ordered stores; note the @@ -948,7 +831,8 @@ pub fn map_crate<'ast>(forest: &'ast mut Forest) -> Map<'ast> { Map { forest: forest, - map: RefCell::new(map) + map: RefCell::new(map), + definitions: RefCell::new(definitions), } } @@ -957,6 +841,7 @@ pub fn map_crate<'ast>(forest: &'ast mut Forest) -> Map<'ast> { /// the item itself. pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>, path: Vec, + def_path: DefPath, ii: InlinedItem, fold_ops: F) -> &'ast InlinedItem { @@ -980,29 +865,18 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>, }); let ii_parent_id = fld.new_id(DUMMY_NODE_ID); - let mut collector = NodeCollector { - map: mem::replace(&mut *map.map.borrow_mut(), vec![]), - parent_node: ii_parent_id, - }; - collector.insert_entry(ii_parent_id, RootInlinedParent(ii_parent)); + let mut collector = + NodeCollector::extend( + ii_parent, + ii_parent_id, + def_path, + mem::replace(&mut *map.map.borrow_mut(), vec![]), + mem::replace(&mut *map.definitions.borrow_mut(), Definitions::new())); ii_parent.ii.visit(&mut collector); - // Methods get added to the AST map when their impl is visited. Since we - // don't decode and instantiate the impl, but just the method, we have to - // add it to the table now. Likewise with foreign items. - match ii_parent.ii { - II::Item(_) => {} - II::TraitItem(_, ref ti) => { - collector.insert(ti.id, NodeTraitItem(ti)); - } - II::ImplItem(_, ref ii) => { - collector.insert(ii.id, NodeImplItem(ii)); - } - II::Foreign(ref i) => { - collector.insert(i.id, NodeForeignItem(i)); - } - } *map.map.borrow_mut() = collector.map; + *map.definitions.borrow_mut() = collector.definitions; + &ii_parent.ii } @@ -1028,7 +902,6 @@ impl<'a> NodePrinter for pprust::State<'a> { // ast_map to reconstruct their full structure for pretty // printing. NodeLocal(_) => panic!("cannot print isolated Local"), - NodeArg(_) => panic!("cannot print isolated Arg"), NodeStructCtor(_) => panic!("cannot print isolated StructCtor"), } } @@ -1040,7 +913,7 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String { match map.find(id) { Some(NodeItem(item)) => { - let path_str = map.path_to_str_with_ident(id, item.ident); + let path_str = map.path_to_str_with_name(id, item.name); let item_str = match item.node { ItemExternCrate(..) => "extern crate", ItemUse(..) => "use", @@ -1059,25 +932,25 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String { format!("{} {}{}", item_str, path_str, id_str) } Some(NodeForeignItem(item)) => { - let path_str = map.path_to_str_with_ident(id, item.ident); + let path_str = map.path_to_str_with_name(id, item.name); format!("foreign item {}{}", path_str, id_str) } Some(NodeImplItem(ii)) => { match ii.node { ConstImplItem(..) => { format!("assoc const {} in {}{}", - ii.ident, + ii.name, map.path_to_string(id), id_str) } MethodImplItem(..) => { format!("method {} in {}{}", - ii.ident, + ii.name, map.path_to_string(id), id_str) } TypeImplItem(_) => { format!("assoc type {} in {}{}", - ii.ident, + ii.name, map.path_to_string(id), id_str) } @@ -1092,7 +965,7 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String { format!("{} {} in {}{}", kind, - ti.ident, + ti.name, map.path_to_string(id), id_str) } @@ -1107,9 +980,6 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String { Some(NodeStmt(ref stmt)) => { format!("stmt {}{}", pprust::stmt_to_string(&**stmt), id_str) } - Some(NodeArg(ref pat)) => { - format!("arg {}{}", pprust::pat_to_string(&**pat), id_str) - } Some(NodeLocal(ref pat)) => { format!("local {}{}", pprust::pat_to_string(&**pat), id_str) } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index cfeab976e2..393329b421 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -35,7 +35,6 @@ #![feature(duration_span)] #![feature(dynamic_lib)] #![feature(enumset)] -#![feature(fs_canonicalize)] #![feature(hashmap_hasher)] #![feature(into_cow)] #![feature(iter_cmp)] @@ -43,18 +42,13 @@ #![feature(libc)] #![feature(nonzero)] #![feature(num_bits_bytes)] -#![feature(path_ext)] #![feature(quote)] -#![feature(range_inclusive)] -#![feature(ref_slice)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] #![feature(scoped_tls)] -#![feature(slice_splits)] #![feature(slice_patterns)] #![feature(staged_api)] #![feature(str_char)] -#![feature(str_match_indices)] #![feature(vec_push_all)] #![feature(wrapping)] #![feature(cell_extras)] @@ -101,10 +95,12 @@ pub mod back { } pub mod front { + pub mod check_attr; pub mod map; } pub mod middle { + pub mod expr_use_visitor; // STAGE0: increase glitch immunity pub mod astconv_util; pub mod astencode; pub mod cfg; @@ -122,7 +118,6 @@ pub mod middle { pub mod dependency_format; pub mod effect; pub mod entry; - pub mod expr_use_visitor; pub mod free_region; pub mod intrinsicck; pub mod infer; diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 495044f945..26f663b1c9 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -14,7 +14,13 @@ //! compiler code, rather than using their own custom pass. Those //! lints are all available in `rustc_lint::builtin`. -use lint::{LintPass, LintArray}; +use lint::{LintPass, LateLintPass, LintArray}; + +declare_lint! { + pub CONST_ERR, + Warn, + "constant evaluation detected erroneous expression" +} declare_lint! { pub UNUSED_IMPORTS, @@ -134,7 +140,10 @@ impl LintPass for HardwiredLints { VARIANT_SIZE_DIFFERENCES, FAT_PTR_TRANSMUTES, TRIVIAL_CASTS, - TRIVIAL_NUMERIC_CASTS + TRIVIAL_NUMERIC_CASTS, + CONST_ERR ) } } + +impl LateLintPass for HardwiredLints {} diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 67be93cc2b..e3eac2e606 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -28,7 +28,8 @@ use self::TargetLint::*; use middle::privacy::ExportedItems; use middle::ty::{self, Ty}; use session::{early_error, Session}; -use lint::{Level, LevelSource, Lint, LintId, LintArray, LintPass, LintPassObject}; +use lint::{Level, LevelSource, Lint, LintId, LintArray, LintPass}; +use lint::{EarlyLintPass, EarlyLintPassObject, LateLintPass, LateLintPassObject}; use lint::{Default, CommandLine, Node, Allow, Warn, Deny, Forbid}; use lint::builtin; use util::nodemap::FnvHashMap; @@ -36,15 +37,15 @@ use util::nodemap::FnvHashMap; use std::cell::RefCell; use std::cmp; use std::mem; -use syntax::ast_util::IdVisitingOperation; -use rustc_front::attr::{self, AttrMetaMethods}; -use rustc_front::util; +use syntax::ast_util::{self, IdVisitingOperation}; +use syntax::attr::{self, AttrMetaMethods}; use syntax::codemap::Span; use syntax::parse::token::InternedString; use syntax::ast; use rustc_front::hir; -use rustc_front::visit::{self, Visitor, FnKind}; -use syntax::visit::Visitor as SyntaxVisitor; +use rustc_front::util; +use rustc_front::visit as hir_visit; +use syntax::visit as ast_visit; use syntax::diagnostic; /// Information about the registered lints. @@ -59,7 +60,8 @@ pub struct LintStore { /// Trait objects for each lint pass. /// This is only `None` while iterating over the objects. See the definition /// of run_lints. - passes: Option>, + early_passes: Option>, + late_passes: Option>, /// Lints indexed by name. by_name: FnvHashMap, @@ -115,7 +117,8 @@ impl LintStore { pub fn new() -> LintStore { LintStore { lints: vec!(), - passes: Some(vec!()), + early_passes: Some(vec!()), + late_passes: Some(vec!()), by_name: FnvHashMap(), levels: FnvHashMap(), lint_groups: FnvHashMap(), @@ -133,8 +136,27 @@ impl LintStore { v.1)).collect() } - pub fn register_pass(&mut self, sess: Option<&Session>, - from_plugin: bool, pass: LintPassObject) { + pub fn register_early_pass(&mut self, + sess: Option<&Session>, + from_plugin: bool, + pass: EarlyLintPassObject) { + self.push_pass(sess, from_plugin, &pass); + self.early_passes.as_mut().unwrap().push(pass); + } + + pub fn register_late_pass(&mut self, + sess: Option<&Session>, + from_plugin: bool, + pass: LateLintPassObject) { + self.push_pass(sess, from_plugin, &pass); + self.late_passes.as_mut().unwrap().push(pass); + } + + // Helper method for register_early/late_pass + fn push_pass(&mut self, + sess: Option<&Session>, + from_plugin: bool, + pass: &Box

) { for &lint in pass.get_lints() { self.lints.push((*lint, from_plugin)); @@ -156,7 +178,6 @@ impl LintStore { self.levels.insert(id, (lint.default_level, Default)); } } - self.passes.as_mut().unwrap().push(pass); } pub fn register_group(&mut self, sess: Option<&Session>, @@ -248,8 +269,8 @@ impl LintStore { } } -/// Context for lint checking. -pub struct Context<'a, 'tcx: 'a> { +/// Context for lint checking after type checking. +pub struct LateContext<'a, 'tcx: 'a> { /// Type context we're checking in. pub tcx: &'a ty::ctxt<'tcx>, @@ -272,21 +293,39 @@ pub struct Context<'a, 'tcx: 'a> { node_levels: RefCell>, } +/// Context for lint checking of the AST, after expansion, before lowering to +/// HIR. +pub struct EarlyContext<'a> { + /// Type context we're checking in. + pub sess: &'a Session, + + /// The crate being checked. + pub krate: &'a ast::Crate, + + /// The store of registered lints. + lints: LintStore, + + /// When recursing into an attributed node of the ast which modifies lint + /// levels, this stack keeps track of the previous lint levels of whatever + /// was modified. + level_stack: Vec<(LintId, LevelSource)>, +} + /// Convenience macro for calling a `LintPass` method on every pass in the context. -macro_rules! run_lints { ($cx:expr, $f:ident, $($args:expr),*) => ({ +macro_rules! run_lints { ($cx:expr, $f:ident, $ps:ident, $($args:expr),*) => ({ // Move the vector of passes out of `$cx` so that we can // iterate over it mutably while passing `$cx` to the methods. - let mut passes = $cx.lints.passes.take().unwrap(); + let mut passes = $cx.mut_lints().$ps.take().unwrap(); for obj in &mut passes { obj.$f($cx, $($args),*); } - $cx.lints.passes = Some(passes); + $cx.mut_lints().$ps = Some(passes); }) } /// Parse the lint attributes into a vector, with `Err`s for malformed lint /// attributes. Writing this as an iterator is an enormous mess. // See also the hir version just below. -pub fn gather_attrs(attrs: &[hir::Attribute]) +pub fn gather_attrs(attrs: &[ast::Attribute]) -> Vec> { let mut out = vec!(); for attr in attrs { @@ -299,7 +338,7 @@ pub fn gather_attrs(attrs: &[hir::Attribute]) let meta = &attr.node.value; let metas = match meta.node { - hir::MetaList(_, ref metas) => metas, + ast::MetaList(_, ref metas) => metas, _ => { out.push(Err(meta.span)); continue; @@ -308,41 +347,7 @@ pub fn gather_attrs(attrs: &[hir::Attribute]) for meta in metas { out.push(match meta.node { - hir::MetaWord(ref lint_name) => Ok((lint_name.clone(), level, meta.span)), - _ => Err(meta.span), - }); - } - } - out -} -// Copy-pasted from the above function :-( -pub fn gather_attrs_from_hir(attrs: &[::rustc_front::hir::Attribute]) - -> Vec> { - use ::rustc_front::attr::AttrMetaMethods; - - let mut out = vec!(); - for attr in attrs { - let level = match Level::from_str(&attr.name()) { - None => continue, - Some(lvl) => lvl, - }; - - ::rustc_front::attr::mark_used(attr); - - let meta = &attr.node.value; - let metas = match meta.node { - ::rustc_front::hir::MetaList(_, ref metas) => metas, - _ => { - out.push(Err(meta.span)); - continue; - } - }; - - for meta in metas { - out.push(match meta.node { - ::rustc_front::hir::MetaWord(ref lint_name) => { - Ok((lint_name.clone(), level, meta.span)) - } + ast::MetaWord(ref lint_name) => Ok((lint_name.clone(), level, meta.span)), _ => Err(meta.span), }); } @@ -398,65 +403,72 @@ pub fn raw_emit_lint(sess: &Session, lint: &'static Lint, } } -impl<'a, 'tcx> Context<'a, 'tcx> { - fn new(tcx: &'a ty::ctxt<'tcx>, - krate: &'a hir::Crate, - exported_items: &'a ExportedItems) -> Context<'a, 'tcx> { - // We want to own the lint store, so move it out of the session. - let lint_store = mem::replace(&mut *tcx.sess.lint_store.borrow_mut(), - LintStore::new()); - - Context { - tcx: tcx, - krate: krate, - exported_items: exported_items, - lints: lint_store, - level_stack: vec![], - node_levels: RefCell::new(FnvHashMap()), - } - } - - /// Get the overall compiler `Session` object. - pub fn sess(&'a self) -> &'a Session { - &self.tcx.sess - } +pub trait LintContext: Sized { + fn sess(&self) -> &Session; + fn lints(&self) -> &LintStore; + fn mut_lints(&mut self) -> &mut LintStore; + fn level_stack(&mut self) -> &mut Vec<(LintId, LevelSource)>; + fn enter_attrs(&mut self, attrs: &[ast::Attribute]); + fn exit_attrs(&mut self, attrs: &[ast::Attribute]); /// Get the level of `lint` at the current position of the lint /// traversal. - pub fn current_level(&self, lint: &'static Lint) -> Level { - self.lints.levels.get(&LintId::of(lint)).map_or(Allow, |&(lvl, _)| lvl) + fn current_level(&self, lint: &'static Lint) -> Level { + self.lints().levels.get(&LintId::of(lint)).map_or(Allow, |&(lvl, _)| lvl) } fn lookup_and_emit(&self, lint: &'static Lint, span: Option, msg: &str) { - let (level, src) = match self.lints.levels.get(&LintId::of(lint)) { + let (level, src) = match self.lints().levels.get(&LintId::of(lint)) { None => return, Some(&(Warn, src)) => { let lint_id = LintId::of(builtin::WARNINGS); - (self.lints.get_level_source(lint_id).0, src) + (self.lints().get_level_source(lint_id).0, src) } Some(&pair) => pair, }; - raw_emit_lint(&self.tcx.sess, lint, (level, src), span, msg); - } - - /// Emit a lint at the appropriate level, with no associated span. - pub fn lint(&self, lint: &'static Lint, msg: &str) { - self.lookup_and_emit(lint, None, msg); + raw_emit_lint(&self.sess(), lint, (level, src), span, msg); } /// Emit a lint at the appropriate level, for a particular span. - pub fn span_lint(&self, lint: &'static Lint, span: Span, msg: &str) { + fn span_lint(&self, lint: &'static Lint, span: Span, msg: &str) { self.lookup_and_emit(lint, Some(span), msg); } + /// Emit a lint and note at the appropriate level, for a particular span. + fn span_lint_note(&self, lint: &'static Lint, span: Span, msg: &str, + note_span: Span, note: &str) { + self.span_lint(lint, span, msg); + if self.current_level(lint) != Level::Allow { + if note_span == span { + self.sess().fileline_note(note_span, note) + } else { + self.sess().span_note(note_span, note) + } + } + } + + /// Emit a lint and help at the appropriate level, for a particular span. + fn span_lint_help(&self, lint: &'static Lint, span: Span, + msg: &str, help: &str) { + self.span_lint(lint, span, msg); + if self.current_level(lint) != Level::Allow { + self.sess().span_help(span, help) + } + } + + /// Emit a lint at the appropriate level, with no associated span. + fn lint(&self, lint: &'static Lint, msg: &str) { + self.lookup_and_emit(lint, None, msg); + } + /// Merge the lints specified by any lint attributes into the /// current lint context, call the provided function, then reset the /// lints in effect to their previous state. fn with_lint_attrs(&mut self, - attrs: &[hir::Attribute], - f: F) where - F: FnOnce(&mut Context), + attrs: &[ast::Attribute], + f: F) + where F: FnOnce(&mut Self), { // Parse all of the lint attributes, and then add them all to the // current dictionary of lint information. Along the way, keep a history @@ -467,14 +479,15 @@ impl<'a, 'tcx> Context<'a, 'tcx> { for result in gather_attrs(attrs) { let v = match result { Err(span) => { - self.tcx.sess.span_err(span, "malformed lint attribute"); + span_err!(self.sess(), span, E0452, + "malformed lint attribute"); continue; } Ok((lint_name, level, span)) => { - match self.lints.find_lint(&lint_name, &self.tcx.sess, Some(span)) { + match self.lints().find_lint(&lint_name, &self.sess(), Some(span)) { Ok(lint_id) => vec![(lint_id, level, span)], Err(FindLintError::NotFound) => { - match self.lints.lint_groups.get(&lint_name[..]) { + match self.lints().lint_groups.get(&lint_name[..]) { Some(&(ref v, _)) => v.iter() .map(|lint_id: &LintId| (*lint_id, level, span)) @@ -493,35 +506,82 @@ impl<'a, 'tcx> Context<'a, 'tcx> { }; for (lint_id, level, span) in v { - let now = self.lints.get_level_source(lint_id).0; + let now = self.lints().get_level_source(lint_id).0; if now == Forbid && level != Forbid { let lint_name = lint_id.as_str(); - self.tcx.sess.span_err(span, - &format!("{}({}) overruled by outer forbid({})", - level.as_str(), lint_name, - lint_name)); + span_err!(self.sess(), span, E0453, + "{}({}) overruled by outer forbid({})", + level.as_str(), lint_name, + lint_name); } else if now != level { - let src = self.lints.get_level_source(lint_id).1; - self.level_stack.push((lint_id, (now, src))); + let src = self.lints().get_level_source(lint_id).1; + self.level_stack().push((lint_id, (now, src))); pushed += 1; - self.lints.set_level(lint_id, (level, Node(span))); + self.mut_lints().set_level(lint_id, (level, Node(span))); } } } - run_lints!(self, enter_lint_attrs, attrs); + self.enter_attrs(attrs); f(self); - run_lints!(self, exit_lint_attrs, attrs); + self.exit_attrs(attrs); // rollback for _ in 0..pushed { - let (lint, lvlsrc) = self.level_stack.pop().unwrap(); - self.lints.set_level(lint, lvlsrc); + let (lint, lvlsrc) = self.level_stack().pop().unwrap(); + self.mut_lints().set_level(lint, lvlsrc); + } + } +} + + +impl<'a> EarlyContext<'a> { + fn new(sess: &'a Session, + krate: &'a ast::Crate) -> EarlyContext<'a> { + // We want to own the lint store, so move it out of the session. Remember + // to put it back later... + let lint_store = mem::replace(&mut *sess.lint_store.borrow_mut(), + LintStore::new()); + EarlyContext { + sess: sess, + krate: krate, + lints: lint_store, + level_stack: vec![], + } + } + + fn visit_ids(&mut self, f: F) + where F: FnOnce(&mut ast_util::IdVisitor) + { + let mut v = ast_util::IdVisitor { + operation: self, + pass_through_items: false, + visited_outermost: false, + }; + f(&mut v); + } +} + +impl<'a, 'tcx> LateContext<'a, 'tcx> { + fn new(tcx: &'a ty::ctxt<'tcx>, + krate: &'a hir::Crate, + exported_items: &'a ExportedItems) -> LateContext<'a, 'tcx> { + // We want to own the lint store, so move it out of the session. + let lint_store = mem::replace(&mut *tcx.sess.lint_store.borrow_mut(), + LintStore::new()); + + LateContext { + tcx: tcx, + krate: krate, + exported_items: exported_items, + lints: lint_store, + level_stack: vec![], + node_levels: RefCell::new(FnvHashMap()), } } - fn visit_ids(&mut self, f: F) where - F: FnOnce(&mut util::IdVisitor) + fn visit_ids(&mut self, f: F) + where F: FnOnce(&mut util::IdVisitor) { let mut v = util::IdVisitor { operation: self, @@ -532,158 +592,376 @@ impl<'a, 'tcx> Context<'a, 'tcx> { } } -impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> { +impl<'a, 'tcx> LintContext for LateContext<'a, 'tcx> { + /// Get the overall compiler `Session` object. + fn sess(&self) -> &Session { + &self.tcx.sess + } + + fn lints(&self) -> &LintStore { + &self.lints + } + + fn mut_lints(&mut self) -> &mut LintStore { + &mut self.lints + } + + fn level_stack(&mut self) -> &mut Vec<(LintId, LevelSource)> { + &mut self.level_stack + } + + fn enter_attrs(&mut self, attrs: &[ast::Attribute]) { + run_lints!(self, enter_lint_attrs, late_passes, attrs); + } + + fn exit_attrs(&mut self, attrs: &[ast::Attribute]) { + run_lints!(self, exit_lint_attrs, late_passes, attrs); + } +} + +impl<'a> LintContext for EarlyContext<'a> { + /// Get the overall compiler `Session` object. + fn sess(&self) -> &Session { + &self.sess + } + + fn lints(&self) -> &LintStore { + &self.lints + } + + fn mut_lints(&mut self) -> &mut LintStore { + &mut self.lints + } + + fn level_stack(&mut self) -> &mut Vec<(LintId, LevelSource)> { + &mut self.level_stack + } + + fn enter_attrs(&mut self, attrs: &[ast::Attribute]) { + run_lints!(self, enter_lint_attrs, early_passes, attrs); + } + + fn exit_attrs(&mut self, attrs: &[ast::Attribute]) { + run_lints!(self, exit_lint_attrs, early_passes, attrs); + } +} + +impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { fn visit_item(&mut self, it: &hir::Item) { self.with_lint_attrs(&it.attrs, |cx| { - run_lints!(cx, check_item, it); + run_lints!(cx, check_item, late_passes, it); cx.visit_ids(|v| v.visit_item(it)); - visit::walk_item(cx, it); + hir_visit::walk_item(cx, it); }) } fn visit_foreign_item(&mut self, it: &hir::ForeignItem) { self.with_lint_attrs(&it.attrs, |cx| { - run_lints!(cx, check_foreign_item, it); - visit::walk_foreign_item(cx, it); + run_lints!(cx, check_foreign_item, late_passes, it); + hir_visit::walk_foreign_item(cx, it); }) } fn visit_pat(&mut self, p: &hir::Pat) { - run_lints!(self, check_pat, p); - visit::walk_pat(self, p); + run_lints!(self, check_pat, late_passes, p); + hir_visit::walk_pat(self, p); } fn visit_expr(&mut self, e: &hir::Expr) { - run_lints!(self, check_expr, e); - visit::walk_expr(self, e); + run_lints!(self, check_expr, late_passes, e); + hir_visit::walk_expr(self, e); } fn visit_stmt(&mut self, s: &hir::Stmt) { - run_lints!(self, check_stmt, s); - visit::walk_stmt(self, s); + run_lints!(self, check_stmt, late_passes, s); + hir_visit::walk_stmt(self, s); } - fn visit_fn(&mut self, fk: FnKind<'v>, decl: &'v hir::FnDecl, + fn visit_fn(&mut self, fk: hir_visit::FnKind<'v>, decl: &'v hir::FnDecl, body: &'v hir::Block, span: Span, id: ast::NodeId) { - run_lints!(self, check_fn, fk, decl, body, span, id); - visit::walk_fn(self, fk, decl, body, span); + run_lints!(self, check_fn, late_passes, fk, decl, body, span, id); + hir_visit::walk_fn(self, fk, decl, body, span); } - fn visit_struct_def(&mut self, - s: &hir::StructDef, - ident: ast::Ident, + fn visit_variant_data(&mut self, + s: &hir::VariantData, + name: ast::Name, g: &hir::Generics, - id: ast::NodeId) { - run_lints!(self, check_struct_def, s, ident, g, id); - visit::walk_struct_def(self, s); - run_lints!(self, check_struct_def_post, s, ident, g, id); + item_id: ast::NodeId, + _: Span) { + run_lints!(self, check_struct_def, late_passes, s, name, g, item_id); + hir_visit::walk_struct_def(self, s); + run_lints!(self, check_struct_def_post, late_passes, s, name, g, item_id); } fn visit_struct_field(&mut self, s: &hir::StructField) { self.with_lint_attrs(&s.node.attrs, |cx| { - run_lints!(cx, check_struct_field, s); - visit::walk_struct_field(cx, s); + run_lints!(cx, check_struct_field, late_passes, s); + hir_visit::walk_struct_field(cx, s); }) } - fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics) { + fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics, item_id: ast::NodeId) { self.with_lint_attrs(&v.node.attrs, |cx| { - run_lints!(cx, check_variant, v, g); - visit::walk_variant(cx, v, g); - run_lints!(cx, check_variant_post, v, g); + run_lints!(cx, check_variant, late_passes, v, g); + hir_visit::walk_variant(cx, v, g, item_id); + run_lints!(cx, check_variant_post, late_passes, v, g); }) } fn visit_ty(&mut self, t: &hir::Ty) { - run_lints!(self, check_ty, t); - visit::walk_ty(self, t); + run_lints!(self, check_ty, late_passes, t); + hir_visit::walk_ty(self, t); } - fn visit_ident(&mut self, sp: Span, id: ast::Ident) { - run_lints!(self, check_ident, sp, id); + fn visit_name(&mut self, sp: Span, name: ast::Name) { + run_lints!(self, check_name, late_passes, sp, name); } fn visit_mod(&mut self, m: &hir::Mod, s: Span, n: ast::NodeId) { - run_lints!(self, check_mod, m, s, n); - visit::walk_mod(self, m); + run_lints!(self, check_mod, late_passes, m, s, n); + hir_visit::walk_mod(self, m); } fn visit_local(&mut self, l: &hir::Local) { - run_lints!(self, check_local, l); - visit::walk_local(self, l); + run_lints!(self, check_local, late_passes, l); + hir_visit::walk_local(self, l); } fn visit_block(&mut self, b: &hir::Block) { - run_lints!(self, check_block, b); - visit::walk_block(self, b); + run_lints!(self, check_block, late_passes, b); + hir_visit::walk_block(self, b); } fn visit_arm(&mut self, a: &hir::Arm) { - run_lints!(self, check_arm, a); - visit::walk_arm(self, a); + run_lints!(self, check_arm, late_passes, a); + hir_visit::walk_arm(self, a); } fn visit_decl(&mut self, d: &hir::Decl) { - run_lints!(self, check_decl, d); - visit::walk_decl(self, d); + run_lints!(self, check_decl, late_passes, d); + hir_visit::walk_decl(self, d); } fn visit_expr_post(&mut self, e: &hir::Expr) { - run_lints!(self, check_expr_post, e); + run_lints!(self, check_expr_post, late_passes, e); } fn visit_generics(&mut self, g: &hir::Generics) { - run_lints!(self, check_generics, g); - visit::walk_generics(self, g); + run_lints!(self, check_generics, late_passes, g); + hir_visit::walk_generics(self, g); } fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) { self.with_lint_attrs(&trait_item.attrs, |cx| { - run_lints!(cx, check_trait_item, trait_item); + run_lints!(cx, check_trait_item, late_passes, trait_item); cx.visit_ids(|v| v.visit_trait_item(trait_item)); - visit::walk_trait_item(cx, trait_item); + hir_visit::walk_trait_item(cx, trait_item); }); } fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) { self.with_lint_attrs(&impl_item.attrs, |cx| { - run_lints!(cx, check_impl_item, impl_item); + run_lints!(cx, check_impl_item, late_passes, impl_item); cx.visit_ids(|v| v.visit_impl_item(impl_item)); - visit::walk_impl_item(cx, impl_item); + hir_visit::walk_impl_item(cx, impl_item); }); } - fn visit_opt_lifetime_ref(&mut self, sp: Span, lt: &Option) { - run_lints!(self, check_opt_lifetime_ref, sp, lt); - } - - fn visit_lifetime_ref(&mut self, lt: &hir::Lifetime) { - run_lints!(self, check_lifetime_ref, lt); + fn visit_lifetime(&mut self, lt: &hir::Lifetime) { + run_lints!(self, check_lifetime, late_passes, lt); } fn visit_lifetime_def(&mut self, lt: &hir::LifetimeDef) { - run_lints!(self, check_lifetime_def, lt); + run_lints!(self, check_lifetime_def, late_passes, lt); } fn visit_explicit_self(&mut self, es: &hir::ExplicitSelf) { - run_lints!(self, check_explicit_self, es); - visit::walk_explicit_self(self, es); + run_lints!(self, check_explicit_self, late_passes, es); + hir_visit::walk_explicit_self(self, es); } fn visit_path(&mut self, p: &hir::Path, id: ast::NodeId) { - run_lints!(self, check_path, p, id); - visit::walk_path(self, p); + run_lints!(self, check_path, late_passes, p, id); + hir_visit::walk_path(self, p); + } + + fn visit_path_list_item(&mut self, prefix: &hir::Path, item: &hir::PathListItem) { + run_lints!(self, check_path_list_item, late_passes, item); + hir_visit::walk_path_list_item(self, prefix, item); } - fn visit_attribute(&mut self, attr: &hir::Attribute) { - run_lints!(self, check_attribute, attr); + fn visit_attribute(&mut self, attr: &ast::Attribute) { + run_lints!(self, check_attribute, late_passes, attr); + } +} + +impl<'a, 'v> ast_visit::Visitor<'v> for EarlyContext<'a> { + fn visit_item(&mut self, it: &ast::Item) { + self.with_lint_attrs(&it.attrs, |cx| { + run_lints!(cx, check_item, early_passes, it); + cx.visit_ids(|v| v.visit_item(it)); + ast_visit::walk_item(cx, it); + }) + } + + fn visit_foreign_item(&mut self, it: &ast::ForeignItem) { + self.with_lint_attrs(&it.attrs, |cx| { + run_lints!(cx, check_foreign_item, early_passes, it); + ast_visit::walk_foreign_item(cx, it); + }) + } + + fn visit_pat(&mut self, p: &ast::Pat) { + run_lints!(self, check_pat, early_passes, p); + ast_visit::walk_pat(self, p); + } + + fn visit_expr(&mut self, e: &ast::Expr) { + run_lints!(self, check_expr, early_passes, e); + ast_visit::walk_expr(self, e); + } + + fn visit_stmt(&mut self, s: &ast::Stmt) { + run_lints!(self, check_stmt, early_passes, s); + ast_visit::walk_stmt(self, s); + } + + fn visit_fn(&mut self, fk: ast_visit::FnKind<'v>, decl: &'v ast::FnDecl, + body: &'v ast::Block, span: Span, id: ast::NodeId) { + run_lints!(self, check_fn, early_passes, fk, decl, body, span, id); + ast_visit::walk_fn(self, fk, decl, body, span); + } + + fn visit_variant_data(&mut self, + s: &ast::VariantData, + ident: ast::Ident, + g: &ast::Generics, + item_id: ast::NodeId, + _: Span) { + run_lints!(self, check_struct_def, early_passes, s, ident, g, item_id); + ast_visit::walk_struct_def(self, s); + run_lints!(self, check_struct_def_post, early_passes, s, ident, g, item_id); + } + + fn visit_struct_field(&mut self, s: &ast::StructField) { + self.with_lint_attrs(&s.node.attrs, |cx| { + run_lints!(cx, check_struct_field, early_passes, s); + ast_visit::walk_struct_field(cx, s); + }) + } + + fn visit_variant(&mut self, v: &ast::Variant, g: &ast::Generics, item_id: ast::NodeId) { + self.with_lint_attrs(&v.node.attrs, |cx| { + run_lints!(cx, check_variant, early_passes, v, g); + ast_visit::walk_variant(cx, v, g, item_id); + run_lints!(cx, check_variant_post, early_passes, v, g); + }) + } + + fn visit_ty(&mut self, t: &ast::Ty) { + run_lints!(self, check_ty, early_passes, t); + ast_visit::walk_ty(self, t); + } + + fn visit_ident(&mut self, sp: Span, id: ast::Ident) { + run_lints!(self, check_ident, early_passes, sp, id); + } + + fn visit_mod(&mut self, m: &ast::Mod, s: Span, n: ast::NodeId) { + run_lints!(self, check_mod, early_passes, m, s, n); + ast_visit::walk_mod(self, m); + } + + fn visit_local(&mut self, l: &ast::Local) { + run_lints!(self, check_local, early_passes, l); + ast_visit::walk_local(self, l); + } + + fn visit_block(&mut self, b: &ast::Block) { + run_lints!(self, check_block, early_passes, b); + ast_visit::walk_block(self, b); + } + + fn visit_arm(&mut self, a: &ast::Arm) { + run_lints!(self, check_arm, early_passes, a); + ast_visit::walk_arm(self, a); + } + + fn visit_decl(&mut self, d: &ast::Decl) { + run_lints!(self, check_decl, early_passes, d); + ast_visit::walk_decl(self, d); + } + + fn visit_expr_post(&mut self, e: &ast::Expr) { + run_lints!(self, check_expr_post, early_passes, e); + } + + fn visit_generics(&mut self, g: &ast::Generics) { + run_lints!(self, check_generics, early_passes, g); + ast_visit::walk_generics(self, g); + } + + fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) { + self.with_lint_attrs(&trait_item.attrs, |cx| { + run_lints!(cx, check_trait_item, early_passes, trait_item); + cx.visit_ids(|v| v.visit_trait_item(trait_item)); + ast_visit::walk_trait_item(cx, trait_item); + }); + } + + fn visit_impl_item(&mut self, impl_item: &ast::ImplItem) { + self.with_lint_attrs(&impl_item.attrs, |cx| { + run_lints!(cx, check_impl_item, early_passes, impl_item); + cx.visit_ids(|v| v.visit_impl_item(impl_item)); + ast_visit::walk_impl_item(cx, impl_item); + }); + } + + fn visit_lifetime(&mut self, lt: &ast::Lifetime) { + run_lints!(self, check_lifetime, early_passes, lt); + } + + fn visit_lifetime_def(&mut self, lt: &ast::LifetimeDef) { + run_lints!(self, check_lifetime_def, early_passes, lt); + } + + fn visit_explicit_self(&mut self, es: &ast::ExplicitSelf) { + run_lints!(self, check_explicit_self, early_passes, es); + ast_visit::walk_explicit_self(self, es); + } + + fn visit_path(&mut self, p: &ast::Path, id: ast::NodeId) { + run_lints!(self, check_path, early_passes, p, id); + ast_visit::walk_path(self, p); + } + + fn visit_path_list_item(&mut self, prefix: &ast::Path, item: &ast::PathListItem) { + run_lints!(self, check_path_list_item, early_passes, item); + ast_visit::walk_path_list_item(self, prefix, item); + } + + fn visit_attribute(&mut self, attr: &ast::Attribute) { + run_lints!(self, check_attribute, early_passes, attr); } } // Output any lints that were previously added to the session. -impl<'a, 'tcx> IdVisitingOperation for Context<'a, 'tcx> { +impl<'a, 'tcx> IdVisitingOperation for LateContext<'a, 'tcx> { + fn visit_id(&mut self, id: ast::NodeId) { + match self.sess().lints.borrow_mut().remove(&id) { + None => {} + Some(lints) => { + for (lint_id, span, msg) in lints { + self.span_lint(lint_id.lint, span, &msg[..]) + } + } + } + } +} +impl<'a> IdVisitingOperation for EarlyContext<'a> { fn visit_id(&mut self, id: ast::NodeId) { - match self.tcx.sess.lints.borrow_mut().remove(&id) { + match self.sess.lints.borrow_mut().remove(&id) { None => {} Some(lints) => { for (lint_id, span, msg) in lints { @@ -694,7 +972,7 @@ impl<'a, 'tcx> IdVisitingOperation for Context<'a, 'tcx> { } } -// This lint pass is defined here because it touches parts of the `Context` +// This lint pass is defined here because it touches parts of the `LateContext` // that we don't want to expose. It records the lint level at certain AST // nodes, so that the variant size difference check in trans can call // `raw_emit_lint`. @@ -705,8 +983,10 @@ impl LintPass for GatherNodeLevels { fn get_lints(&self) -> LintArray { lint_array!() } +} - fn check_item(&mut self, cx: &Context, it: &hir::Item) { +impl LateLintPass for GatherNodeLevels { + fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { match it.node { hir::ItemEnum(..) => { let lint_id = LintId::of(builtin::VARIANT_SIZE_DIFFERENCES); @@ -731,21 +1011,21 @@ pub fn check_crate(tcx: &ty::ctxt, krate: &hir::Crate, exported_items: &ExportedItems) { - let mut cx = Context::new(tcx, krate, exported_items); + let mut cx = LateContext::new(tcx, krate, exported_items); // Visit the whole crate. cx.with_lint_attrs(&krate.attrs, |cx| { cx.visit_id(ast::CRATE_NODE_ID); cx.visit_ids(|v| { v.visited_outermost = true; - visit::walk_crate(v, krate); + hir_visit::walk_crate(v, krate); }); // since the root module isn't visited as an item (because it isn't an // item), warn for it here. - run_lints!(cx, check_crate, krate); + run_lints!(cx, check_crate, late_passes, krate); - visit::walk_crate(cx, krate); + hir_visit::walk_crate(cx, krate); }); // If we missed any lints added to the session, then there's a bug somewhere @@ -760,3 +1040,35 @@ pub fn check_crate(tcx: &ty::ctxt, *tcx.node_lint_levels.borrow_mut() = cx.node_levels.into_inner(); } + +pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) { + let mut cx = EarlyContext::new(sess, krate); + + // Visit the whole crate. + cx.with_lint_attrs(&krate.attrs, |cx| { + cx.visit_id(ast::CRATE_NODE_ID); + cx.visit_ids(|v| { + v.visited_outermost = true; + ast_visit::walk_crate(v, krate); + }); + + // since the root module isn't visited as an item (because it isn't an + // item), warn for it here. + run_lints!(cx, check_crate, early_passes, krate); + + ast_visit::walk_crate(cx, krate); + }); + + // Put the lint store back in the session. + mem::replace(&mut *sess.lint_store.borrow_mut(), cx.lints); + + // 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 { + sess.span_bug(span, + &format!("unprocessed lint {}: {}", + lint.as_str(), *msg)) + } + } +} diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 2b3a6c6e28..14c11af6f3 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -35,11 +35,13 @@ use std::hash; use std::ascii::AsciiExt; use syntax::codemap::Span; use rustc_front::visit::FnKind; +use syntax::visit as ast_visit; use syntax::ast; use rustc_front::hir; -pub use lint::context::{Context, LintStore, raw_emit_lint, check_crate, gather_attrs, - gather_attrs_from_hir, GatherNodeLevels}; +pub use lint::context::{LateContext, EarlyContext, LintContext, LintStore, + raw_emit_lint, check_crate, check_ast_crate, gather_attrs, + GatherNodeLevels}; /// Specification of a single lint. #[derive(Copy, Clone, Debug)] @@ -87,7 +89,6 @@ macro_rules! lint_initializer { /// Declare a static item of type `&'static Lint`. #[macro_export] macro_rules! declare_lint { - // FIXME(#14660): deduplicate (pub $name:ident, $level:ident, $desc:expr) => ( pub static $name: &'static ::rustc::lint::Lint = &lint_initializer!($name, $level, $desc); @@ -109,14 +110,6 @@ macro_rules! lint_array { ($( $lint:expr ),*) => ( pub type LintArray = &'static [&'static &'static Lint]; -/// Trait for types providing lint checks. -/// -/// Each `check` method checks a single syntax node, and should not -/// invoke methods recursively (unlike `Visitor`). By default they -/// do nothing. -// -// FIXME: eliminate the duplication with `Visitor`. But this also -// contains a few lint-specific methods with no equivalent in `Visitor`. pub trait LintPass { /// Get descriptions of the lints this `LintPass` object can emit. /// @@ -125,51 +118,104 @@ pub trait LintPass { /// parts of the compiler. If you want enforced access restrictions for your /// `Lint`, make it a private `static` item in its own module. fn get_lints(&self) -> LintArray; +} + - fn check_crate(&mut self, _: &Context, _: &hir::Crate) { } - fn check_ident(&mut self, _: &Context, _: Span, _: ast::Ident) { } - fn check_mod(&mut self, _: &Context, _: &hir::Mod, _: Span, _: ast::NodeId) { } - fn check_foreign_item(&mut self, _: &Context, _: &hir::ForeignItem) { } - fn check_item(&mut self, _: &Context, _: &hir::Item) { } - fn check_local(&mut self, _: &Context, _: &hir::Local) { } - fn check_block(&mut self, _: &Context, _: &hir::Block) { } - fn check_stmt(&mut self, _: &Context, _: &hir::Stmt) { } - fn check_arm(&mut self, _: &Context, _: &hir::Arm) { } - fn check_pat(&mut self, _: &Context, _: &hir::Pat) { } - fn check_decl(&mut self, _: &Context, _: &hir::Decl) { } - fn check_expr(&mut self, _: &Context, _: &hir::Expr) { } - fn check_expr_post(&mut self, _: &Context, _: &hir::Expr) { } - fn check_ty(&mut self, _: &Context, _: &hir::Ty) { } - fn check_generics(&mut self, _: &Context, _: &hir::Generics) { } - fn check_fn(&mut self, _: &Context, +/// Trait for types providing lint checks. +/// +/// Each `check` method checks a single syntax node, and should not +/// invoke methods recursively (unlike `Visitor`). By default they +/// do nothing. +// +// FIXME: eliminate the duplication with `Visitor`. But this also +// contains a few lint-specific methods with no equivalent in `Visitor`. +pub trait LateLintPass: LintPass { + fn check_name(&mut self, _: &LateContext, _: Span, _: ast::Name) { } + fn check_crate(&mut self, _: &LateContext, _: &hir::Crate) { } + fn check_mod(&mut self, _: &LateContext, _: &hir::Mod, _: Span, _: ast::NodeId) { } + fn check_foreign_item(&mut self, _: &LateContext, _: &hir::ForeignItem) { } + fn check_item(&mut self, _: &LateContext, _: &hir::Item) { } + fn check_local(&mut self, _: &LateContext, _: &hir::Local) { } + fn check_block(&mut self, _: &LateContext, _: &hir::Block) { } + fn check_stmt(&mut self, _: &LateContext, _: &hir::Stmt) { } + fn check_arm(&mut self, _: &LateContext, _: &hir::Arm) { } + fn check_pat(&mut self, _: &LateContext, _: &hir::Pat) { } + fn check_decl(&mut self, _: &LateContext, _: &hir::Decl) { } + fn check_expr(&mut self, _: &LateContext, _: &hir::Expr) { } + fn check_expr_post(&mut self, _: &LateContext, _: &hir::Expr) { } + fn check_ty(&mut self, _: &LateContext, _: &hir::Ty) { } + fn check_generics(&mut self, _: &LateContext, _: &hir::Generics) { } + fn check_fn(&mut self, _: &LateContext, _: FnKind, _: &hir::FnDecl, _: &hir::Block, _: Span, _: ast::NodeId) { } - fn check_trait_item(&mut self, _: &Context, _: &hir::TraitItem) { } - fn check_impl_item(&mut self, _: &Context, _: &hir::ImplItem) { } - fn check_struct_def(&mut self, _: &Context, - _: &hir::StructDef, _: ast::Ident, _: &hir::Generics, _: ast::NodeId) { } - fn check_struct_def_post(&mut self, _: &Context, - _: &hir::StructDef, _: ast::Ident, _: &hir::Generics, _: ast::NodeId) { } - fn check_struct_field(&mut self, _: &Context, _: &hir::StructField) { } - fn check_variant(&mut self, _: &Context, _: &hir::Variant, _: &hir::Generics) { } - fn check_variant_post(&mut self, _: &Context, _: &hir::Variant, _: &hir::Generics) { } - fn check_opt_lifetime_ref(&mut self, _: &Context, _: Span, _: &Option) { } - fn check_lifetime_ref(&mut self, _: &Context, _: &hir::Lifetime) { } - fn check_lifetime_def(&mut self, _: &Context, _: &hir::LifetimeDef) { } - fn check_explicit_self(&mut self, _: &Context, _: &hir::ExplicitSelf) { } - fn check_mac(&mut self, _: &Context, _: &ast::Mac) { } - fn check_path(&mut self, _: &Context, _: &hir::Path, _: ast::NodeId) { } - fn check_attribute(&mut self, _: &Context, _: &hir::Attribute) { } + fn check_trait_item(&mut self, _: &LateContext, _: &hir::TraitItem) { } + fn check_impl_item(&mut self, _: &LateContext, _: &hir::ImplItem) { } + fn check_struct_def(&mut self, _: &LateContext, + _: &hir::VariantData, _: ast::Name, _: &hir::Generics, _: ast::NodeId) { } + fn check_struct_def_post(&mut self, _: &LateContext, + _: &hir::VariantData, _: ast::Name, _: &hir::Generics, _: ast::NodeId) { } + fn check_struct_field(&mut self, _: &LateContext, _: &hir::StructField) { } + fn check_variant(&mut self, _: &LateContext, _: &hir::Variant, _: &hir::Generics) { } + fn check_variant_post(&mut self, _: &LateContext, _: &hir::Variant, _: &hir::Generics) { } + fn check_lifetime(&mut self, _: &LateContext, _: &hir::Lifetime) { } + fn check_lifetime_def(&mut self, _: &LateContext, _: &hir::LifetimeDef) { } + fn check_explicit_self(&mut self, _: &LateContext, _: &hir::ExplicitSelf) { } + fn check_path(&mut self, _: &LateContext, _: &hir::Path, _: ast::NodeId) { } + fn check_path_list_item(&mut self, _: &LateContext, _: &hir::PathListItem) { } + fn check_attribute(&mut self, _: &LateContext, _: &ast::Attribute) { } + + /// Called when entering a syntax node that can have lint attributes such + /// as `#[allow(...)]`. Called with *all* the attributes of that node. + fn enter_lint_attrs(&mut self, _: &LateContext, _: &[ast::Attribute]) { } + + /// Counterpart to `enter_lint_attrs`. + fn exit_lint_attrs(&mut self, _: &LateContext, _: &[ast::Attribute]) { } +} + +pub trait EarlyLintPass: LintPass { + fn check_ident(&mut self, _: &EarlyContext, _: Span, _: ast::Ident) { } + fn check_crate(&mut self, _: &EarlyContext, _: &ast::Crate) { } + fn check_mod(&mut self, _: &EarlyContext, _: &ast::Mod, _: Span, _: ast::NodeId) { } + fn check_foreign_item(&mut self, _: &EarlyContext, _: &ast::ForeignItem) { } + fn check_item(&mut self, _: &EarlyContext, _: &ast::Item) { } + fn check_local(&mut self, _: &EarlyContext, _: &ast::Local) { } + fn check_block(&mut self, _: &EarlyContext, _: &ast::Block) { } + fn check_stmt(&mut self, _: &EarlyContext, _: &ast::Stmt) { } + fn check_arm(&mut self, _: &EarlyContext, _: &ast::Arm) { } + fn check_pat(&mut self, _: &EarlyContext, _: &ast::Pat) { } + fn check_decl(&mut self, _: &EarlyContext, _: &ast::Decl) { } + fn check_expr(&mut self, _: &EarlyContext, _: &ast::Expr) { } + fn check_expr_post(&mut self, _: &EarlyContext, _: &ast::Expr) { } + fn check_ty(&mut self, _: &EarlyContext, _: &ast::Ty) { } + fn check_generics(&mut self, _: &EarlyContext, _: &ast::Generics) { } + fn check_fn(&mut self, _: &EarlyContext, + _: ast_visit::FnKind, _: &ast::FnDecl, _: &ast::Block, _: Span, _: ast::NodeId) { } + fn check_trait_item(&mut self, _: &EarlyContext, _: &ast::TraitItem) { } + fn check_impl_item(&mut self, _: &EarlyContext, _: &ast::ImplItem) { } + fn check_struct_def(&mut self, _: &EarlyContext, + _: &ast::VariantData, _: ast::Ident, _: &ast::Generics, _: ast::NodeId) { } + fn check_struct_def_post(&mut self, _: &EarlyContext, + _: &ast::VariantData, _: ast::Ident, _: &ast::Generics, _: ast::NodeId) { } + fn check_struct_field(&mut self, _: &EarlyContext, _: &ast::StructField) { } + fn check_variant(&mut self, _: &EarlyContext, _: &ast::Variant, _: &ast::Generics) { } + fn check_variant_post(&mut self, _: &EarlyContext, _: &ast::Variant, _: &ast::Generics) { } + fn check_lifetime(&mut self, _: &EarlyContext, _: &ast::Lifetime) { } + fn check_lifetime_def(&mut self, _: &EarlyContext, _: &ast::LifetimeDef) { } + fn check_explicit_self(&mut self, _: &EarlyContext, _: &ast::ExplicitSelf) { } + fn check_path(&mut self, _: &EarlyContext, _: &ast::Path, _: ast::NodeId) { } + fn check_path_list_item(&mut self, _: &EarlyContext, _: &ast::PathListItem) { } + fn check_attribute(&mut self, _: &EarlyContext, _: &ast::Attribute) { } /// Called when entering a syntax node that can have lint attributes such /// as `#[allow(...)]`. Called with *all* the attributes of that node. - fn enter_lint_attrs(&mut self, _: &Context, _: &[hir::Attribute]) { } + fn enter_lint_attrs(&mut self, _: &EarlyContext, _: &[ast::Attribute]) { } /// Counterpart to `enter_lint_attrs`. - fn exit_lint_attrs(&mut self, _: &Context, _: &[hir::Attribute]) { } + fn exit_lint_attrs(&mut self, _: &EarlyContext, _: &[ast::Attribute]) { } } /// A lint pass boxed up as a trait object. -pub type LintPassObject = Box; +pub type EarlyLintPassObject = Box; +pub type LateLintPassObject = Box; /// Identifies a lint known to the compiler. #[derive(Clone, Copy)] diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 0fb55bd790..a4fee5b7aa 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -43,9 +43,15 @@ pub const tag_items_data_parent_item: usize = 0x28; pub const tag_items_data_item_is_tuple_struct_ctor: usize = 0x29; -pub const tag_index: usize = 0x2a; +pub const tag_items_closure_kind: usize = 0x2a; +pub const tag_items_closure_ty: usize = 0x2b; +pub const tag_def_key: usize = 0x2c; -// GAP 0x2b, 0x2c, 0x2d, 0x2e +// GAP 0x2d 0x2e + +pub const tag_index: usize = 0x110; // top-level only +pub const tag_xref_index: usize = 0x111; // top-level only +pub const tag_xref_data: usize = 0x112; // top-level only pub const tag_meta_item_name_value: usize = 0x2f; @@ -74,8 +80,6 @@ pub const tag_crate_dep_crate_name: usize = 0x36; pub const tag_crate_dep_hash: usize = 0x37; pub const tag_crate_dep_explicitly_linked: usize = 0x38; // top-level only -pub const tag_mod_impl: usize = 0x39; - pub const tag_item_trait_item: usize = 0x3a; pub const tag_item_trait_ref: usize = 0x3b; @@ -89,7 +93,6 @@ pub const tag_path_len: usize = 0x3e; pub const tag_path_elem_mod: usize = 0x3f; pub const tag_path_elem_name: usize = 0x40; pub const tag_item_field: usize = 0x41; -pub const tag_item_field_origin: usize = 0x42; pub const tag_item_variances: usize = 0x43; /* @@ -119,29 +122,20 @@ enum_from_u32! { tag_tree = 0x51, - tag_id_range = 0x52, - + // GAP 0x52 tag_table = 0x53, // GAP 0x54, 0x55 tag_table_def = 0x56, tag_table_node_type = 0x57, tag_table_item_subst = 0x58, tag_table_freevars = 0x59, - tag_table_tcache = 0x5a, - tag_table_param_defs = 0x5b, - tag_table_mutbl = 0x5c, - tag_table_last_use = 0x5d, - tag_table_spill = 0x5e, + // GAP 0x5a, 0x5b, 0x5c, 0x5d, 0x5e tag_table_method_map = 0x5f, - tag_table_vtable_map = 0x60, + // GAP 0x60 tag_table_adjustments = 0x61, - tag_table_moves_map = 0x62, - tag_table_capture_map = 0x63, - tag_table_closure_tys = 0x64, - tag_table_closure_kinds = 0x65, + // GAP 0x62, 0x63, 0x64, 0x65 tag_table_upvar_capture_map = 0x66, - tag_table_capture_modes = 0x67, - // GAP 0x68 + // GAP 0x67, 0x68 tag_table_const_qualif = 0x69, tag_table_cast_kinds = 0x6a, } @@ -149,10 +143,6 @@ enum_from_u32! { pub const tag_item_trait_item_sort: usize = 0x70; -pub const tag_item_trait_parent_sort: usize = 0x71; - -pub const tag_item_impl_type_basename: usize = 0x72; - pub const tag_crate_triple: usize = 0x105; // top-level only pub const tag_dylib_dependency_formats: usize = 0x106; // top-level only @@ -162,33 +152,27 @@ pub const tag_dylib_dependency_formats: usize = 0x106; // top-level only // tag_lang_items // - tag_lang_items_item // - tag_lang_items_item_id: u32 -// - tag_lang_items_item_node_id: u32 +// - tag_lang_items_item_index: u32 pub const tag_lang_items: usize = 0x107; // top-level only pub const tag_lang_items_item: usize = 0x73; pub const tag_lang_items_item_id: usize = 0x74; -pub const tag_lang_items_item_node_id: usize = 0x75; +pub const tag_lang_items_item_index: usize = 0x75; pub const tag_lang_items_missing: usize = 0x76; pub const tag_item_unnamed_field: usize = 0x77; pub const tag_items_data_item_visibility: usize = 0x78; - -pub const tag_item_method_tps: usize = 0x79; -pub const tag_item_method_fty: usize = 0x7a; - +pub const tag_items_data_item_inherent_impl: usize = 0x79; +// GAP 0x7a pub const tag_mod_child: usize = 0x7b; pub const tag_misc_info: usize = 0x108; // top-level only pub const tag_misc_info_crate_items: usize = 0x7c; -pub const tag_item_method_provided_source: usize = 0x7d; -pub const tag_item_impl_vtables: usize = 0x7e; - pub const tag_impls: usize = 0x109; // top-level only -pub const tag_impls_impl: usize = 0x7f; -pub const tag_impls_impl_trait_def_id: usize = 0x8d; +pub const tag_impls_trait: usize = 0x7d; +pub const tag_impls_trait_impl: usize = 0x7e; -pub const tag_items_data_item_inherent_impl: usize = 0x80; -pub const tag_items_data_item_extension_impl: usize = 0x81; +// GAP 0x7f, 0x80, 0x81 pub const tag_native_libraries: usize = 0x10a; // top-level only pub const tag_native_libraries_lib: usize = 0x82; @@ -215,10 +199,10 @@ pub struct LinkMeta { pub const tag_struct_fields: usize = 0x10d; // top-level only pub const tag_struct_field: usize = 0x8a; -pub const tag_struct_field_id: usize = 0x8b; +pub const tag_items_data_item_struct_ctor: usize = 0x8b; pub const tag_attribute_is_sugared_doc: usize = 0x8c; - +// GAP 0x8d pub const tag_items_data_region: usize = 0x8e; pub const tag_region_param_def: usize = 0x8f; @@ -232,9 +216,9 @@ pub const tag_type_param_def: usize = 0x94; pub const tag_item_generics: usize = 0x95; pub const tag_method_ty_generics: usize = 0x96; -pub const tag_predicate: usize = 0x97; -pub const tag_predicate_space: usize = 0x98; -pub const tag_predicate_data: usize = 0x99; +pub const tag_type_predicate: usize = 0x97; +pub const tag_self_predicate: usize = 0x98; +pub const tag_fn_predicate: usize = 0x99; pub const tag_unsafety: usize = 0x9a; @@ -259,3 +243,11 @@ pub const tag_defaulted_trait: usize = 0xa4; pub const tag_impl_coerce_unsized_kind: usize = 0xa5; pub const tag_items_data_item_constness: usize = 0xa6; + +pub const tag_rustc_version: usize = 0x10f; +pub fn rustc_version() -> String { + format!( + "rustc {}", + option_env!("CFG_VERSION").unwrap_or("unknown version") + ) +} diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs index 5ac8457836..6c81562f7b 100644 --- a/src/librustc/metadata/creader.rs +++ b/src/librustc/metadata/creader.rs @@ -15,6 +15,7 @@ use back::svh::Svh; use session::{config, Session}; use session::search_paths::PathKind; +use metadata::common::rustc_version; use metadata::cstore; use metadata::cstore::{CStore, CrateSource, MetadataBlob}; use metadata::decoder; @@ -33,13 +34,11 @@ use syntax::abi; use syntax::codemap::{self, Span, mk_sp, Pos}; use syntax::parse; use syntax::attr; +use syntax::attr::AttrMetaMethods; use syntax::parse::token::InternedString; use syntax::util::small_vector::SmallVector; use rustc_front::visit; use rustc_front::hir; -use rustc_front::attr as attr_front; -use rustc_front::attr::AttrMetaMethods; -use rustc_front::lowering::unlower_attribute; use log; pub struct LocalCrateReader<'a, 'b:'a> { @@ -79,10 +78,9 @@ fn dump_crates(cstore: &CStore) { fn should_link(i: &ast::Item) -> bool { !attr::contains_name(&i.attrs, "no_link") } - // Dup for the hir fn should_link_hir(i: &hir::Item) -> bool { - !attr_front::contains_name(&i.attrs, "no_link") + !attr::contains_name(&i.attrs, "no_link") } struct CrateInfo { @@ -122,8 +120,8 @@ fn register_native_lib(sess: &Session, if name.is_empty() { match span { Some(span) => { - sess.span_err(span, "#[link(name = \"\")] given with \ - empty name"); + span_err!(sess, span, E0454, + "#[link(name = \"\")] given with empty name"); } None => { sess.err("empty library name given via `-l`"); @@ -135,7 +133,10 @@ fn register_native_lib(sess: &Session, if kind == cstore::NativeFramework && !is_osx { let msg = "native frameworks are only available on OSX targets"; match span { - Some(span) => sess.span_err(span, msg), + Some(span) => { + span_err!(sess, span, E0455, + "{}", msg) + } None => sess.err(msg), } } @@ -201,17 +202,17 @@ impl<'a> CrateReader<'a> { match i.node { hir::ItemExternCrate(ref path_opt) => { debug!("resolving extern crate stmt. ident: {} path_opt: {:?}", - i.ident, path_opt); + i.name, path_opt); let name = match *path_opt { Some(name) => { validate_crate_name(Some(self.sess), &name.as_str(), Some(i.span)); name.to_string() } - None => i.ident.to_string(), + None => i.name.to_string(), }; Some(CrateInfo { - ident: i.ident.to_string(), + ident: i.name.to_string(), name: name, id: i.id, should_link: should_link_hir(i), @@ -270,6 +271,24 @@ impl<'a> CrateReader<'a> { return ret; } + fn verify_rustc_version(&self, + name: &str, + span: Span, + metadata: &MetadataBlob) { + let crate_rustc_version = decoder::crate_rustc_version(metadata.as_slice()); + if crate_rustc_version != Some(rustc_version()) { + span_err!(self.sess, span, E0514, + "the crate `{}` has been compiled with {}, which is \ + incompatible with this version of rustc", + name, + crate_rustc_version + .as_ref().map(|s|&**s) + .unwrap_or("an old version of rustc") + ); + self.sess.abort_if_errors(); + } + } + fn register_crate(&mut self, root: &Option, ident: &str, @@ -279,6 +298,8 @@ impl<'a> CrateReader<'a> { explicitly_linked: bool) -> (ast::CrateNum, Rc, cstore::CrateSource) { + self.verify_rustc_version(name, span, &lib.metadata); + // Claim this crate number and cache it let cnum = self.next_crate_num; self.next_crate_num += 1; @@ -304,7 +325,9 @@ impl<'a> CrateReader<'a> { let cmeta = Rc::new(cstore::crate_metadata { name: name.to_string(), local_path: RefCell::new(SmallVector::zero()), + local_def_path: RefCell::new(vec![]), index: decoder::load_index(metadata.as_slice()), + xref_index: decoder::load_xrefs(metadata.as_slice()), data: metadata, cnum_map: RefCell::new(cnum_map), cnum: cnum, @@ -329,7 +352,7 @@ impl<'a> CrateReader<'a> { let attrs = decoder::get_crate_attributes(data); for attr in &attrs { if &attr.name()[..] == "staged_api" { - match attr.node.value.node { hir::MetaWord(_) => return true, _ => (/*pass*/) } + match attr.node.value.node { ast::MetaWord(_) => return true, _ => (/*pass*/) } } } @@ -481,9 +504,15 @@ impl<'a> CrateReader<'a> { }; let span = mk_sp(lo, p.last_span.hi); p.abort_if_errors(); + + // Mark the attrs as used + for attr in &attrs { + attr::mark_used(attr); + } + macros.push(ast::MacroDef { - ident: name.ident(), - attrs: attrs.iter().map(|a| unlower_attribute(a)).collect(), + ident: ast::Ident::with_empty_ctxt(name), + attrs: attrs, id: ast::DUMMY_NODE_ID, span: span, imported_from: Some(item.ident), @@ -517,20 +546,21 @@ impl<'a> CrateReader<'a> { name, config::host_triple(), self.sess.opts.target_triple); - self.sess.span_err(span, &message[..]); + span_err!(self.sess, span, E0456, "{}", &message[..]); self.sess.abort_if_errors(); } - let registrar = decoder::get_plugin_registrar_fn(ekrate.metadata.as_slice()) + let registrar = + decoder::get_plugin_registrar_fn(ekrate.metadata.as_slice()) .map(|id| decoder::get_symbol_from_buf(ekrate.metadata.as_slice(), id)); match (ekrate.dylib.as_ref(), registrar) { (Some(dylib), Some(reg)) => Some((dylib.to_path_buf(), reg)), (None, Some(_)) => { - let message = format!("plugin `{}` only found in rlib format, \ - but must be available in dylib format", - name); - self.sess.span_err(span, &message[..]); + span_err!(self.sess, span, E0457, + "plugin `{}` only found in rlib format, but must be available \ + in dylib format", + name); // No need to abort because the loading code will just ignore this // empty dylib. None @@ -724,6 +754,9 @@ impl<'a, 'b> LocalCrateReader<'a, 'b> { i.span, PathKind::Crate, true); + let def_id = self.ast_map.local_def_id(i.id); + let def_path = self.ast_map.def_path(def_id); + cmeta.update_local_def_path(def_path); self.ast_map.with_path(i.id, |path| { cmeta.update_local_path(path) }); @@ -763,7 +796,8 @@ impl<'a, 'b> LocalCrateReader<'a, 'b> { Some("dylib") => cstore::NativeUnknown, Some("framework") => cstore::NativeFramework, Some(k) => { - self.sess.span_err(m.span, &format!("unknown kind: `{}`", k)); + span_err!(self.sess, m.span, E0458, + "unknown kind: `{}`", k); cstore::NativeUnknown } None => cstore::NativeUnknown @@ -774,8 +808,8 @@ impl<'a, 'b> LocalCrateReader<'a, 'b> { let n = match n { Some(n) => n, None => { - self.sess.span_err(m.span, "#[link(...)] specified without \ - `name = \"foo\"`"); + span_err!(self.sess, m.span, E0459, + "#[link(...)] specified without `name = \"foo\"`"); InternedString::new("foo") } }; diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index e1cb9bd0e7..e04df51dc6 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -14,14 +14,14 @@ use front::map as ast_map; use metadata::cstore; use metadata::decoder; use metadata::inline::InlinedItem; -use middle::def_id::DefId; +use middle::def_id::{DefId, DefIndex}; use middle::lang_items; use middle::ty; use util::nodemap::FnvHashMap; use std::rc::Rc; use syntax::ast; -use rustc_front::attr; +use syntax::attr; use rustc_front::hir; #[derive(Copy, Clone)] @@ -33,7 +33,7 @@ pub struct MethodInfo { pub fn get_symbol(cstore: &cstore::CStore, def: DefId) -> String { let cdata = cstore.get_crate_data(def.krate); - decoder::get_symbol(&cdata, def.node) + decoder::get_symbol(&cdata, def.index) } /// Iterates over all the language items in the given crate. @@ -41,7 +41,7 @@ pub fn each_lang_item(cstore: &cstore::CStore, cnum: ast::CrateNum, f: F) -> bool where - F: FnMut(ast::NodeId, usize) -> bool, + F: FnMut(DefIndex, usize) -> bool, { let crate_data = cstore.get_crate_data(cnum); decoder::each_lang_item(&*crate_data, f) @@ -59,7 +59,7 @@ pub fn each_child_of_item(cstore: &cstore::CStore, }; decoder::each_child_of_item(cstore.intr.clone(), &*crate_data, - def_id.node, + def_id.index, get_crate_data, callback) } @@ -83,7 +83,7 @@ pub fn each_top_level_item_of_crate(cstore: &cstore::CStore, pub fn get_item_path(tcx: &ty::ctxt, def: DefId) -> Vec { let cstore = &tcx.sess.cstore; let cdata = cstore.get_crate_data(def.krate); - let path = decoder::get_item_path(&*cdata, def.node); + let path = decoder::get_item_path(&*cdata, def.index); cdata.with_local_path(|cpath| { let mut r = Vec::with_capacity(cpath.len() + path.len()); @@ -96,7 +96,7 @@ pub fn get_item_path(tcx: &ty::ctxt, def: DefId) -> Vec { pub fn get_item_name(tcx: &ty::ctxt, def: DefId) -> ast::Name { let cstore = &tcx.sess.cstore; let cdata = cstore.get_crate_data(def.krate); - decoder::get_item_name(&cstore.intr, &cdata, def.node) + decoder::get_item_name(&cstore.intr, &cdata, def.index) } pub enum FoundAst<'ast> { @@ -113,14 +113,14 @@ pub fn maybe_get_item_ast<'tcx>(tcx: &ty::ctxt<'tcx>, def: DefId, -> FoundAst<'tcx> { let cstore = &tcx.sess.cstore; let cdata = cstore.get_crate_data(def.krate); - decoder::maybe_get_item_ast(&*cdata, tcx, def.node, decode_inlined_item) + decoder::maybe_get_item_ast(&*cdata, tcx, def.index, decode_inlined_item) } /// Returns information about the given implementation. pub fn get_impl_items(cstore: &cstore::CStore, impl_def_id: DefId) -> Vec { let cdata = cstore.get_crate_data(impl_def_id.krate); - decoder::get_impl_items(&*cdata, impl_def_id.node) + decoder::get_impl_items(&*cdata, impl_def_id.index) } pub fn get_impl_or_trait_item<'tcx>(tcx: &ty::ctxt<'tcx>, def: DefId) @@ -128,7 +128,7 @@ pub fn get_impl_or_trait_item<'tcx>(tcx: &ty::ctxt<'tcx>, def: DefId) let cdata = tcx.sess.cstore.get_crate_data(def.krate); decoder::get_impl_or_trait_item(tcx.sess.cstore.intr.clone(), &*cdata, - def.node, + def.index, tcx) } @@ -136,24 +136,24 @@ pub fn get_trait_name(cstore: &cstore::CStore, def: DefId) -> ast::Name { let cdata = cstore.get_crate_data(def.krate); decoder::get_trait_name(cstore.intr.clone(), &*cdata, - def.node) + def.index) } pub fn is_static_method(cstore: &cstore::CStore, def: DefId) -> bool { let cdata = cstore.get_crate_data(def.krate); - decoder::is_static_method(&*cdata, def.node) + decoder::is_static_method(&*cdata, def.index) } pub fn get_trait_item_def_ids(cstore: &cstore::CStore, def: DefId) -> Vec { let cdata = cstore.get_crate_data(def.krate); - decoder::get_trait_item_def_ids(&*cdata, def.node) + decoder::get_trait_item_def_ids(&*cdata, def.index) } pub fn get_item_variances(cstore: &cstore::CStore, def: DefId) -> ty::ItemVariances { let cdata = cstore.get_crate_data(def.krate); - decoder::get_item_variances(&*cdata, def.node) + decoder::get_item_variances(&*cdata, def.index) } pub fn get_provided_trait_methods<'tcx>(tcx: &ty::ctxt<'tcx>, @@ -161,43 +161,37 @@ pub fn get_provided_trait_methods<'tcx>(tcx: &ty::ctxt<'tcx>, -> Vec>> { let cstore = &tcx.sess.cstore; let cdata = cstore.get_crate_data(def.krate); - decoder::get_provided_trait_methods(cstore.intr.clone(), &*cdata, def.node, tcx) + decoder::get_provided_trait_methods(cstore.intr.clone(), &*cdata, def.index, tcx) } pub fn get_associated_consts<'tcx>(tcx: &ty::ctxt<'tcx>, def: DefId) -> Vec>> { let cstore = &tcx.sess.cstore; let cdata = cstore.get_crate_data(def.krate); - decoder::get_associated_consts(cstore.intr.clone(), &*cdata, def.node, tcx) -} - -pub fn get_type_name_if_impl(cstore: &cstore::CStore, def: DefId) - -> Option { - let cdata = cstore.get_crate_data(def.krate); - decoder::get_type_name_if_impl(&*cdata, def.node) + decoder::get_associated_consts(cstore.intr.clone(), &*cdata, def.index, tcx) } pub fn get_methods_if_impl(cstore: &cstore::CStore, def: DefId) -> Option > { let cdata = cstore.get_crate_data(def.krate); - decoder::get_methods_if_impl(cstore.intr.clone(), &*cdata, def.node) + decoder::get_methods_if_impl(cstore.intr.clone(), &*cdata, def.index) } pub fn get_item_attrs(cstore: &cstore::CStore, def_id: DefId) - -> Vec { + -> Vec { let cdata = cstore.get_crate_data(def_id.krate); - decoder::get_item_attrs(&*cdata, def_id.node) + decoder::get_item_attrs(&*cdata, def_id.index) } pub fn get_struct_field_names(cstore: &cstore::CStore, def: DefId) -> Vec { let cdata = cstore.get_crate_data(def.krate); - decoder::get_struct_field_names(&cstore.intr, &*cdata, def.node) + decoder::get_struct_field_names(&cstore.intr, &*cdata, def.index) } -pub fn get_struct_field_attrs(cstore: &cstore::CStore, def: DefId) -> FnvHashMap> { +pub fn get_struct_field_attrs(cstore: &cstore::CStore, def: DefId) + -> FnvHashMap> { let cdata = cstore.get_crate_data(def.krate); decoder::get_struct_field_attrs(&*cdata) } @@ -207,19 +201,19 @@ pub fn get_type<'tcx>(tcx: &ty::ctxt<'tcx>, -> ty::TypeScheme<'tcx> { let cstore = &tcx.sess.cstore; let cdata = cstore.get_crate_data(def.krate); - decoder::get_type(&*cdata, def.node, tcx) + decoder::get_type(&*cdata, def.index, tcx) } pub fn get_trait_def<'tcx>(tcx: &ty::ctxt<'tcx>, def: DefId) -> ty::TraitDef<'tcx> { let cstore = &tcx.sess.cstore; let cdata = cstore.get_crate_data(def.krate); - decoder::get_trait_def(&*cdata, def.node, tcx) + decoder::get_trait_def(&*cdata, def.index, tcx) } pub fn get_adt_def<'tcx>(tcx: &ty::ctxt<'tcx>, def: DefId) -> ty::AdtDefMaster<'tcx> { let cstore = &tcx.sess.cstore; let cdata = cstore.get_crate_data(def.krate); - decoder::get_adt_def(&cstore.intr, &*cdata, def.node, tcx) + decoder::get_adt_def(&cstore.intr, &*cdata, def.index, tcx) } pub fn get_predicates<'tcx>(tcx: &ty::ctxt<'tcx>, def: DefId) @@ -227,7 +221,7 @@ pub fn get_predicates<'tcx>(tcx: &ty::ctxt<'tcx>, def: DefId) { let cstore = &tcx.sess.cstore; let cdata = cstore.get_crate_data(def.krate); - decoder::get_predicates(&*cdata, def.node, tcx) + decoder::get_predicates(&*cdata, def.index, tcx) } pub fn get_super_predicates<'tcx>(tcx: &ty::ctxt<'tcx>, def: DefId) @@ -235,7 +229,7 @@ pub fn get_super_predicates<'tcx>(tcx: &ty::ctxt<'tcx>, def: DefId) { let cstore = &tcx.sess.cstore; let cdata = cstore.get_crate_data(def.krate); - decoder::get_super_predicates(&*cdata, def.node, tcx) + decoder::get_super_predicates(&*cdata, def.index, tcx) } pub fn get_impl_polarity<'tcx>(tcx: &ty::ctxt<'tcx>, @@ -244,7 +238,7 @@ pub fn get_impl_polarity<'tcx>(tcx: &ty::ctxt<'tcx>, { let cstore = &tcx.sess.cstore; let cdata = cstore.get_crate_data(def.krate); - decoder::get_impl_polarity(&*cdata, def.node) + decoder::get_impl_polarity(&*cdata, def.index) } pub fn get_custom_coerce_unsized_kind<'tcx>( @@ -254,7 +248,7 @@ pub fn get_custom_coerce_unsized_kind<'tcx>( { let cstore = &tcx.sess.cstore; let cdata = cstore.get_crate_data(def.krate); - decoder::get_custom_coerce_unsized_kind(&*cdata, def.node) + decoder::get_custom_coerce_unsized_kind(&*cdata, def.index) } // Given a def_id for an impl, return the trait it implements, @@ -264,7 +258,7 @@ pub fn get_impl_trait<'tcx>(tcx: &ty::ctxt<'tcx>, -> Option> { let cstore = &tcx.sess.cstore; let cdata = cstore.get_crate_data(def.krate); - decoder::get_impl_trait(&*cdata, def.node, tcx) + decoder::get_impl_trait(&*cdata, def.index, tcx) } pub fn get_native_libraries(cstore: &cstore::CStore, crate_num: ast::CrateNum) @@ -279,7 +273,7 @@ pub fn each_inherent_implementation_for_type(cstore: &cstore::CStore, F: FnMut(DefId), { let cdata = cstore.get_crate_data(def_id.krate); - decoder::each_inherent_implementation_for_type(&*cdata, def_id.node, callback) + decoder::each_inherent_implementation_for_type(&*cdata, def_id.index, callback) } pub fn each_implementation_for_trait(cstore: &cstore::CStore, @@ -300,7 +294,7 @@ pub fn get_trait_of_item(cstore: &cstore::CStore, tcx: &ty::ctxt) -> Option { let cdata = cstore.get_crate_data(def_id.krate); - decoder::get_trait_of_item(&*cdata, def_id.node, tcx) + decoder::get_trait_of_item(&*cdata, def_id.index, tcx) } pub fn get_tuple_struct_definition_if_ctor(cstore: &cstore::CStore, @@ -308,7 +302,7 @@ pub fn get_tuple_struct_definition_if_ctor(cstore: &cstore::CStore, -> Option { let cdata = cstore.get_crate_data(def_id.krate); - decoder::get_tuple_struct_definition_if_ctor(&*cdata, def_id.node) + decoder::get_tuple_struct_definition_if_ctor(&*cdata, def_id.index) } pub fn get_dylib_dependency_formats(cstore: &cstore::CStore, @@ -330,7 +324,7 @@ pub fn get_method_arg_names(cstore: &cstore::CStore, did: DefId) -> Vec { let cdata = cstore.get_crate_data(did.krate); - decoder::get_method_arg_names(&*cdata, did.node) + decoder::get_method_arg_names(&*cdata, did.index) } pub fn get_reachable_ids(cstore: &cstore::CStore, cnum: ast::CrateNum) @@ -342,24 +336,24 @@ pub fn get_reachable_ids(cstore: &cstore::CStore, cnum: ast::CrateNum) pub fn is_typedef(cstore: &cstore::CStore, did: DefId) -> bool { let cdata = cstore.get_crate_data(did.krate); - decoder::is_typedef(&*cdata, did.node) + decoder::is_typedef(&*cdata, did.index) } pub fn is_const_fn(cstore: &cstore::CStore, did: DefId) -> bool { let cdata = cstore.get_crate_data(did.krate); - decoder::is_const_fn(&*cdata, did.node) + decoder::is_const_fn(&*cdata, did.index) } pub fn is_impl(cstore: &cstore::CStore, did: DefId) -> bool { let cdata = cstore.get_crate_data(did.krate); - decoder::is_impl(&*cdata, did.node) + decoder::is_impl(&*cdata, did.index) } pub fn get_stability(cstore: &cstore::CStore, def: DefId) -> Option { let cdata = cstore.get_crate_data(def.krate); - decoder::get_stability(&*cdata, def.node) + decoder::get_stability(&*cdata, def.index) } pub fn is_staged_api(cstore: &cstore::CStore, krate: ast::CrateNum) -> bool { @@ -369,21 +363,42 @@ pub fn is_staged_api(cstore: &cstore::CStore, krate: ast::CrateNum) -> bool { pub fn get_repr_attrs(cstore: &cstore::CStore, def: DefId) -> Vec { let cdata = cstore.get_crate_data(def.krate); - decoder::get_repr_attrs(&*cdata, def.node) + decoder::get_repr_attrs(&*cdata, def.index) } pub fn is_defaulted_trait(cstore: &cstore::CStore, trait_def_id: DefId) -> bool { let cdata = cstore.get_crate_data(trait_def_id.krate); - decoder::is_defaulted_trait(&*cdata, trait_def_id.node) + decoder::is_defaulted_trait(&*cdata, trait_def_id.index) } pub fn is_default_impl(cstore: &cstore::CStore, impl_did: DefId) -> bool { let cdata = cstore.get_crate_data(impl_did.krate); - decoder::is_default_impl(&*cdata, impl_did.node) + decoder::is_default_impl(&*cdata, impl_did.index) } pub fn is_extern_fn(cstore: &cstore::CStore, did: DefId, tcx: &ty::ctxt) -> bool { let cdata = cstore.get_crate_data(did.krate); - decoder::is_extern_fn(&*cdata, did.node, tcx) + decoder::is_extern_fn(&*cdata, did.index, tcx) +} + +pub fn closure_kind<'tcx>(tcx: &ty::ctxt<'tcx>, def_id: DefId) -> ty::ClosureKind { + assert!(!def_id.is_local()); + let cdata = tcx.sess.cstore.get_crate_data(def_id.krate); + decoder::closure_kind(&*cdata, def_id.index) +} + +pub fn closure_ty<'tcx>(tcx: &ty::ctxt<'tcx>, def_id: DefId) -> ty::ClosureTy<'tcx> { + assert!(!def_id.is_local()); + let cdata = tcx.sess.cstore.get_crate_data(def_id.krate); + decoder::closure_ty(&*cdata, def_id.index, tcx) +} + +pub fn def_path(tcx: &ty::ctxt, def: DefId) -> ast_map::DefPath { + let cstore = &tcx.sess.cstore; + let cdata = cstore.get_crate_data(def.krate); + let path = decoder::def_path(&*cdata, def.index); + let local_path = cdata.local_def_path(); + local_path.into_iter().chain(path).collect() } + diff --git a/src/librustc/metadata/cstore.rs b/src/librustc/metadata/cstore.rs index 42f52b2d20..873c22c35d 100644 --- a/src/librustc/metadata/cstore.rs +++ b/src/librustc/metadata/cstore.rs @@ -27,7 +27,7 @@ use std::rc::Rc; use std::path::PathBuf; use flate::Bytes; use syntax::ast; -use rustc_front::attr; +use syntax::attr; use syntax::codemap; use syntax::parse::token; use syntax::parse::token::IdentInterner; @@ -59,13 +59,16 @@ pub struct ImportedFileMap { pub struct crate_metadata { pub name: String, pub local_path: RefCell>, + pub local_def_path: RefCell, pub data: MetadataBlob, pub cnum_map: RefCell, pub cnum: ast::CrateNum, pub codemap_import_info: RefCell>, pub span: codemap::Span, pub staged_api: bool, + pub index: index::Index, + pub xref_index: index::DenseIndex, /// Flag if this crate is required by an rlib version of this crate, or in /// other words whether it was explicitly linked to. An example of a crate @@ -109,6 +112,10 @@ pub struct CStore { pub intr: Rc, } +/// Item definitions in the currently-compiled crate would have the CrateNum +/// LOCAL_CRATE in their DefId. +pub const LOCAL_CRATE: ast::CrateNum = 0; + impl CStore { pub fn new(intr: Rc) -> CStore { CStore { @@ -200,7 +207,7 @@ impl CStore { visit(cstore, dep, ordering); } ordering.push(cnum); - }; + } for (&num, _) in self.metas.borrow().iter() { visit(self, num, &mut ordering); } @@ -308,6 +315,23 @@ impl crate_metadata { } } + pub fn local_def_path(&self) -> ast_map::DefPath { + let local_def_path = self.local_def_path.borrow(); + if local_def_path.is_empty() { + let name = ast_map::DefPathData::DetachedCrate(token::intern(&self.name)); + vec![ast_map::DisambiguatedDefPathData { data: name, disambiguator: 0 }] + } else { + local_def_path.clone() + } + } + + pub fn update_local_def_path(&self, candidate: ast_map::DefPath) { + let mut local_def_path = self.local_def_path.borrow_mut(); + if local_def_path.is_empty() || candidate.len() < local_def_path.len() { + *local_def_path = candidate; + } + } + pub fn is_allocator(&self) -> bool { let attrs = decoder::get_crate_attributes(self.data()); attr::contains_name(&attrs, "allocator") diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index e2cf50cf30..0780252fc8 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -15,12 +15,12 @@ pub use self::DefLike::*; use self::Family::*; -use front::map as ast_map; -use rustc_front::print::pprust; +use front::map as hir_map; use rustc_front::hir; use back::svh::Svh; use metadata::cstore::crate_metadata; +use metadata::cstore::LOCAL_CRATE; use metadata::common::*; use metadata::csearch::MethodInfo; use metadata::csearch; @@ -30,7 +30,7 @@ use metadata::index; use metadata::inline::InlinedItem; use metadata::tydecode::TyDecoder; use middle::def; -use middle::def_id::{DefId, LOCAL_CRATE}; +use middle::def_id::{DefId, DefIndex}; use middle::lang_items; use middle::subst; use middle::ty::{ImplContainer, TraitContainer}; @@ -46,27 +46,28 @@ use std::str; use rbml::reader; use rbml; use serialize::Decodable; -use rustc_front::attr; +use syntax::attr; use syntax::parse::token::{IdentInterner, special_idents}; use syntax::parse::token; use syntax::ast; use syntax::abi; use syntax::codemap; +use syntax::print::pprust; use syntax::ptr::P; pub type Cmd<'a> = &'a crate_metadata; impl crate_metadata { - fn get_item(&self, item_id: ast::NodeId) -> Option { + fn get_item(&self, item_id: DefIndex) -> Option { self.index.lookup_item(self.data(), item_id).map(|pos| { reader::doc_at(self.data(), pos as usize).unwrap().doc }) } - fn lookup_item(&self, item_id: ast::NodeId) -> rbml::Doc { + fn lookup_item(&self, item_id: DefIndex) -> rbml::Doc { match self.get_item(item_id) { - None => panic!("lookup_item: id not found: {}", item_id), + None => panic!("lookup_item: id not found: {:?}", item_id), Some(d) => d } } @@ -74,7 +75,17 @@ impl crate_metadata { pub fn load_index(data: &[u8]) -> index::Index { let index = reader::get_doc(rbml::Doc::new(data), tag_index); - index::Index::from_buf(index.data, index.start, index.end) + index::Index::from_rbml(index) +} + +pub fn crate_rustc_version(data: &[u8]) -> Option { + let doc = rbml::Doc::new(data); + reader::maybe_get_doc(doc, tag_rustc_version).map(|s| s.as_str()) +} + +pub fn load_xrefs(data: &[u8]) -> index::DenseIndex { + let index = reader::get_doc(rbml::Doc::new(data), tag_xref_index); + index::DenseIndex::from_buf(index.data, index.start, index.end) } #[derive(Debug, PartialEq)] @@ -164,7 +175,8 @@ fn item_symbol(item: rbml::Doc) -> String { fn translated_def_id(cdata: Cmd, d: rbml::Doc) -> DefId { let id = reader::doc_as_u64(d); - let def_id = DefId { krate: (id >> 32) as u32, node: id as u32 }; + let index = DefIndex::new((id & 0xFFFF_FFFF) as usize); + let def_id = DefId { krate: (id >> 32) as u32, index: index }; translate_def_id(cdata, def_id) } @@ -182,12 +194,6 @@ fn item_def_id(d: rbml::Doc, cdata: Cmd) -> DefId { translated_def_id(cdata, reader::get_doc(d, tag_def_id)) } -fn get_provided_source(d: rbml::Doc, cdata: Cmd) -> Option { - reader::maybe_get_doc(d, tag_item_method_provided_source).map(|doc| { - translated_def_id(cdata, doc) - }) -} - fn reexports<'a>(d: rbml::Doc<'a>) -> reader::TaggedDocsIterator<'a> { reader::tagged_docs(d, tag_items_data_item_reexport) } @@ -203,26 +209,18 @@ fn variant_disr_val(d: rbml::Doc) -> Option { fn doc_type<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) -> Ty<'tcx> { let tp = reader::get_doc(doc, tag_items_data_item_type); TyDecoder::with_doc(tcx, cdata.cnum, tp, - &mut |_, did| translate_def_id(cdata, did)) + &mut |did| translate_def_id(cdata, did)) .parse_ty() } fn maybe_doc_type<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) -> Option> { reader::maybe_get_doc(doc, tag_items_data_item_type).map(|tp| { TyDecoder::with_doc(tcx, cdata.cnum, tp, - &mut |_, did| translate_def_id(cdata, did)) + &mut |did| translate_def_id(cdata, did)) .parse_ty() }) } -fn doc_method_fty<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, - cdata: Cmd) -> ty::BareFnTy<'tcx> { - let tp = reader::get_doc(doc, tag_item_method_fty); - TyDecoder::with_doc(tcx, cdata.cnum, tp, - &mut |_, did| translate_def_id(cdata, did)) - .parse_bare_fn_ty() -} - pub fn item_type<'tcx>(_item_id: DefId, item: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) -> Ty<'tcx> { doc_type(item, tcx, cdata) @@ -231,7 +229,7 @@ pub fn item_type<'tcx>(_item_id: DefId, item: rbml::Doc, fn doc_trait_ref<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) -> ty::TraitRef<'tcx> { TyDecoder::with_doc(tcx, cdata.cnum, doc, - &mut |_, did| translate_def_id(cdata, did)) + &mut |did| translate_def_id(cdata, did)) .parse_trait_ref() } @@ -241,15 +239,15 @@ fn item_trait_ref<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) doc_trait_ref(tp, tcx, cdata) } -fn item_path(item_doc: rbml::Doc) -> Vec { +fn item_path(item_doc: rbml::Doc) -> Vec { let path_doc = reader::get_doc(item_doc, tag_path); reader::docs(path_doc).filter_map(|(tag, elt_doc)| { if tag == tag_path_elem_mod { let s = elt_doc.as_str_slice(); - Some(ast_map::PathMod(token::intern(s))) + Some(hir_map::PathMod(token::intern(s))) } else if tag == tag_path_elem_name { let s = elt_doc.as_str_slice(); - Some(ast_map::PathName(token::intern(s))) + Some(hir_map::PathName(token::intern(s))) } else { // ignore tag_path_len element None @@ -271,11 +269,14 @@ fn item_to_def_like(cdata: Cmd, item: rbml::Doc, did: DefId) -> DefLike { match fam { Constant => { // Check whether we have an associated const item. - if item_sort(item) == Some('C') { - DlDef(def::DefAssociatedConst(did)) - } else { - // Regular const item. - DlDef(def::DefConst(did)) + match item_sort(item) { + Some('C') | Some('c') => { + DlDef(def::DefAssociatedConst(did)) + } + _ => { + // Regular const item. + DlDef(def::DefConst(did)) + } } } ImmStatic => DlDef(def::DefStatic(did, false)), @@ -342,7 +343,7 @@ fn parse_associated_type_names(item_doc: rbml::Doc) -> Vec { } pub fn get_trait_def<'tcx>(cdata: Cmd, - item_id: ast::NodeId, + item_id: DefIndex, tcx: &ty::ctxt<'tcx>) -> ty::TraitDef<'tcx> { let item_doc = cdata.lookup_item(item_id); @@ -365,7 +366,7 @@ pub fn get_trait_def<'tcx>(cdata: Cmd, pub fn get_adt_def<'tcx>(intr: &IdentInterner, cdata: Cmd, - item_id: ast::NodeId, + item_id: DefIndex, tcx: &ty::ctxt<'tcx>) -> ty::AdtDefMaster<'tcx> { fn get_enum_variants<'tcx>(intr: &IdentInterner, @@ -375,7 +376,7 @@ pub fn get_adt_def<'tcx>(intr: &IdentInterner, let mut disr_val = 0; reader::tagged_docs(doc, tag_items_data_item_variant).map(|p| { let did = translated_def_id(cdata, p); - let item = cdata.lookup_item(did.node); + let item = cdata.lookup_item(did.index); if let Some(disr) = variant_disr_val(item) { disr_val = disr; @@ -425,13 +426,22 @@ pub fn get_adt_def<'tcx>(intr: &IdentInterner, } let doc = cdata.lookup_item(item_id); - let did = DefId { krate: cdata.cnum, node: item_id }; + let did = DefId { krate: cdata.cnum, index: item_id }; let (kind, variants) = match item_family(doc) { - Enum => (ty::AdtKind::Enum, - get_enum_variants(intr, cdata, doc, tcx)), - Struct => (ty::AdtKind::Struct, - vec![get_struct_variant(intr, cdata, doc, did, tcx)]), - _ => tcx.sess.bug("get_adt_def called on a non-ADT") + Enum => { + (ty::AdtKind::Enum, + get_enum_variants(intr, cdata, doc, tcx)) + } + Struct => { + let ctor_did = + reader::maybe_get_doc(doc, tag_items_data_item_struct_ctor). + map_or(did, |ctor_doc| translated_def_id(cdata, ctor_doc)); + (ty::AdtKind::Struct, + vec![get_struct_variant(intr, cdata, doc, ctor_did, tcx)]) + } + _ => tcx.sess.bug( + &format!("get_adt_def called on a non-ADT {:?} - {:?}", + item_family(doc), did)) }; let adt = tcx.intern_adt_def(did, kind, variants); @@ -445,7 +455,7 @@ pub fn get_adt_def<'tcx>(intr: &IdentInterner, // from the ctor. debug!("evaluating the ctor-type of {:?}", variant.name); - let ctor_ty = get_type(cdata, variant.did.node, tcx).ty; + let ctor_ty = get_type(cdata, variant.did.index, tcx).ty; debug!("evaluating the ctor-type of {:?}.. {:?}", variant.name, ctor_ty); @@ -465,7 +475,7 @@ pub fn get_adt_def<'tcx>(intr: &IdentInterner, } else { for field in &variant.fields { debug!("evaluating the type of {:?}::{:?}", variant.name, field.name); - let ty = get_type(cdata, field.did.node, tcx).ty; + let ty = get_type(cdata, field.did.index, tcx).ty; field.fulfill_ty(ty); debug!("evaluating the type of {:?}::{:?}: {:?}", variant.name, field.name, ty); @@ -477,7 +487,7 @@ pub fn get_adt_def<'tcx>(intr: &IdentInterner, } pub fn get_predicates<'tcx>(cdata: Cmd, - item_id: ast::NodeId, + item_id: DefIndex, tcx: &ty::ctxt<'tcx>) -> ty::GenericPredicates<'tcx> { @@ -486,7 +496,7 @@ pub fn get_predicates<'tcx>(cdata: Cmd, } pub fn get_super_predicates<'tcx>(cdata: Cmd, - item_id: ast::NodeId, + item_id: DefIndex, tcx: &ty::ctxt<'tcx>) -> ty::GenericPredicates<'tcx> { @@ -494,11 +504,11 @@ pub fn get_super_predicates<'tcx>(cdata: Cmd, doc_predicates(item_doc, tcx, cdata, tag_item_super_predicates) } -pub fn get_type<'tcx>(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt<'tcx>) +pub fn get_type<'tcx>(cdata: Cmd, id: DefIndex, tcx: &ty::ctxt<'tcx>) -> ty::TypeScheme<'tcx> { let item_doc = cdata.lookup_item(id); - let t = item_type(DefId { krate: cdata.cnum, node: id }, item_doc, tcx, + let t = item_type(DefId { krate: cdata.cnum, index: id }, item_doc, tcx, cdata); let generics = doc_generics(item_doc, tcx, cdata, tag_item_generics); ty::TypeScheme { @@ -507,7 +517,7 @@ pub fn get_type<'tcx>(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt<'tcx>) } } -pub fn get_stability(cdata: Cmd, id: ast::NodeId) -> Option { +pub fn get_stability(cdata: Cmd, id: DefIndex) -> Option { let item = cdata.lookup_item(id); reader::maybe_get_doc(item, tag_items_data_item_stability).map(|doc| { let mut decoder = reader::Decoder::new(doc); @@ -515,7 +525,7 @@ pub fn get_stability(cdata: Cmd, id: ast::NodeId) -> Option { }) } -pub fn get_repr_attrs(cdata: Cmd, id: ast::NodeId) -> Vec { +pub fn get_repr_attrs(cdata: Cmd, id: DefIndex) -> Vec { let item = cdata.lookup_item(id); match reader::maybe_get_doc(item, tag_items_data_item_repr).map(|doc| { let mut decoder = reader::Decoder::new(doc); @@ -527,7 +537,7 @@ pub fn get_repr_attrs(cdata: Cmd, id: ast::NodeId) -> Vec { } pub fn get_impl_polarity<'tcx>(cdata: Cmd, - id: ast::NodeId) + id: DefIndex) -> Option { let item_doc = cdata.lookup_item(id); @@ -542,7 +552,7 @@ pub fn get_impl_polarity<'tcx>(cdata: Cmd, pub fn get_custom_coerce_unsized_kind<'tcx>( cdata: Cmd, - id: ast::NodeId) + id: DefIndex) -> Option { let item_doc = cdata.lookup_item(id); @@ -553,7 +563,7 @@ pub fn get_custom_coerce_unsized_kind<'tcx>( } pub fn get_impl_trait<'tcx>(cdata: Cmd, - id: ast::NodeId, + id: DefIndex, tcx: &ty::ctxt<'tcx>) -> Option> { @@ -569,12 +579,12 @@ pub fn get_impl_trait<'tcx>(cdata: Cmd, } } -pub fn get_symbol(cdata: Cmd, id: ast::NodeId) -> String { +pub fn get_symbol(cdata: Cmd, id: DefIndex) -> String { return item_symbol(cdata.lookup_item(id)); } /// If you have a crate_metadata, call get_symbol instead -pub fn get_symbol_from_buf(data: &[u8], id: ast::NodeId) -> String { +pub fn get_symbol_from_buf(data: &[u8], id: DefIndex) -> String { let index = load_index(data); let pos = index.lookup_item(data, id).unwrap(); let doc = reader::doc_at(data, pos as usize).unwrap().doc; @@ -591,18 +601,17 @@ pub enum DefLike { /// Iterates over the language items in the given crate. pub fn each_lang_item(cdata: Cmd, mut f: F) -> bool where - F: FnMut(ast::NodeId, usize) -> bool, + F: FnMut(DefIndex, usize) -> bool, { let root = rbml::Doc::new(cdata.data()); let lang_items = reader::get_doc(root, tag_lang_items); reader::tagged_docs(lang_items, tag_lang_items_item).all(|item_doc| { let id_doc = reader::get_doc(item_doc, tag_lang_items_item_id); let id = reader::doc_as_u32(id_doc) as usize; - let node_id_doc = reader::get_doc(item_doc, - tag_lang_items_item_node_id); - let node_id = reader::doc_as_u32(node_id_doc) as ast::NodeId; + let index_doc = reader::get_doc(item_doc, tag_lang_items_item_index); + let index = DefIndex::from_u32(reader::doc_as_u32(index_doc)); - f(node_id, id) + f(index, id) }) } @@ -631,7 +640,7 @@ fn each_child_of_item_or_crate(intr: Rc, }; // Get the item. - match crate_data.get_item(child_def_id.node) { + match crate_data.get_item(child_def_id.index) { None => {} Some(child_item_doc) => { // Hand off the item to the callback. @@ -649,12 +658,12 @@ fn each_child_of_item_or_crate(intr: Rc, for inherent_impl_def_id_doc in reader::tagged_docs(item_doc, tag_items_data_item_inherent_impl) { let inherent_impl_def_id = item_def_id(inherent_impl_def_id_doc, cdata); - if let Some(inherent_impl_doc) = cdata.get_item(inherent_impl_def_id.node) { + if let Some(inherent_impl_doc) = cdata.get_item(inherent_impl_def_id.index) { for impl_item_def_id_doc in reader::tagged_docs(inherent_impl_doc, tag_item_impl_item) { let impl_item_def_id = item_def_id(impl_item_def_id_doc, cdata); - if let Some(impl_method_doc) = cdata.get_item(impl_item_def_id.node) { + if let Some(impl_method_doc) = cdata.get_item(impl_item_def_id.index) { if let StaticMethod = item_family(impl_method_doc) { // Hand off the static method to the callback. let static_method_name = item_name(&*intr, impl_method_doc); @@ -690,7 +699,7 @@ fn each_child_of_item_or_crate(intr: Rc, }; // Get the item. - if let Some(child_item_doc) = crate_data.get_item(child_def_id.node) { + if let Some(child_item_doc) = crate_data.get_item(child_def_id.index) { // Hand off the item to the callback. let def_like = item_to_def_like(crate_data, child_item_doc, child_def_id); // These items have a public visibility because they're part of @@ -703,7 +712,7 @@ fn each_child_of_item_or_crate(intr: Rc, /// Iterates over each child of the given item. pub fn each_child_of_item(intr: Rc, cdata: Cmd, - id: ast::NodeId, + id: DefIndex, get_crate_data: G, callback: F) where F: FnMut(DefLike, ast::Name, hir::Visibility), @@ -742,34 +751,39 @@ pub fn each_top_level_item_of_crate(intr: Rc, callback) } -pub fn get_item_path(cdata: Cmd, id: ast::NodeId) -> Vec { +pub fn get_item_path(cdata: Cmd, id: DefIndex) -> Vec { item_path(cdata.lookup_item(id)) } -pub fn get_item_name(intr: &IdentInterner, cdata: Cmd, id: ast::NodeId) -> ast::Name { +pub fn get_item_name(intr: &IdentInterner, cdata: Cmd, id: DefIndex) -> ast::Name { item_name(intr, cdata.lookup_item(id)) } pub type DecodeInlinedItem<'a> = Box FnMut(Cmd, &ty::ctxt<'tcx>, - Vec, - rbml::Doc) - -> Result<&'tcx InlinedItem, Vec> + 'a>; - -pub fn maybe_get_item_ast<'tcx>(cdata: Cmd, tcx: &ty::ctxt<'tcx>, id: ast::NodeId, + Vec, + hir_map::DefPath, + rbml::Doc, + DefId) + -> Result<&'tcx InlinedItem, (Vec, + hir_map::DefPath)> + 'a>; + +pub fn maybe_get_item_ast<'tcx>(cdata: Cmd, tcx: &ty::ctxt<'tcx>, id: DefIndex, mut decode_inlined_item: DecodeInlinedItem) -> csearch::FoundAst<'tcx> { - debug!("Looking up item: {}", id); + debug!("Looking up item: {:?}", id); let item_doc = cdata.lookup_item(id); + let item_did = item_def_id(item_doc, cdata); let path = item_path(item_doc).split_last().unwrap().1.to_vec(); - match decode_inlined_item(cdata, tcx, path, item_doc) { + let def_path = def_path(cdata, id); + match decode_inlined_item(cdata, tcx, path, def_path, item_doc, item_did) { Ok(ii) => csearch::FoundAst::Found(ii), - Err(path) => { + Err((path, def_path)) => { match item_parent_item(cdata, item_doc) { Some(did) => { - let parent_item = cdata.lookup_item(did.node); - match decode_inlined_item(cdata, tcx, path, parent_item) { + let parent_item = cdata.lookup_item(did.index); + match decode_inlined_item(cdata, tcx, path, def_path, parent_item, did) { Ok(ii) => csearch::FoundAst::FoundParent(did, ii), Err(_) => csearch::FoundAst::NotFound } @@ -808,12 +822,12 @@ fn get_explicit_self(item: rbml::Doc) -> ty::ExplicitSelfCategory { } /// Returns the def IDs of all the items in the given implementation. -pub fn get_impl_items(cdata: Cmd, impl_id: ast::NodeId) +pub fn get_impl_items(cdata: Cmd, impl_id: DefIndex) -> Vec { reader::tagged_docs(cdata.lookup_item(impl_id), tag_item_impl_item).map(|doc| { let def_id = item_def_id(doc, cdata); match item_sort(doc) { - Some('C') => ty::ConstTraitItemId(def_id), + Some('C') | Some('c') => ty::ConstTraitItemId(def_id), Some('r') | Some('p') => ty::MethodTraitItemId(def_id), Some('t') => ty::TypeTraitItemId(def_id), _ => panic!("unknown impl item sort"), @@ -823,13 +837,13 @@ pub fn get_impl_items(cdata: Cmd, impl_id: ast::NodeId) pub fn get_trait_name(intr: Rc, cdata: Cmd, - id: ast::NodeId) + id: DefIndex) -> ast::Name { let doc = cdata.lookup_item(id); item_name(&*intr, doc) } -pub fn is_static_method(cdata: Cmd, id: ast::NodeId) -> bool { +pub fn is_static_method(cdata: Cmd, id: DefIndex) -> bool { let doc = cdata.lookup_item(id); match item_sort(doc) { Some('r') | Some('p') => { @@ -841,7 +855,7 @@ pub fn is_static_method(cdata: Cmd, id: ast::NodeId) -> bool { pub fn get_impl_or_trait_item<'tcx>(intr: Rc, cdata: Cmd, - id: ast::NodeId, + id: DefIndex, tcx: &ty::ctxt<'tcx>) -> ty::ImplOrTraitItem<'tcx> { let item_doc = cdata.lookup_item(id); @@ -849,7 +863,7 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc, let def_id = item_def_id(item_doc, cdata); let container_id = item_require_parent_item(cdata, item_doc); - let container_doc = cdata.lookup_item(container_id.node); + let container_doc = cdata.lookup_item(container_id.index); let container = match item_family(container_doc) { Trait => TraitContainer(container_id), _ => ImplContainer(container_id), @@ -859,24 +873,28 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc, let vis = item_visibility(item_doc); match item_sort(item_doc) { - Some('C') => { + sort @ Some('C') | sort @ Some('c') => { let ty = doc_type(item_doc, tcx, cdata); - let default = get_provided_source(item_doc, cdata); ty::ConstTraitItem(Rc::new(ty::AssociatedConst { name: name, ty: ty, vis: vis, def_id: def_id, container: container, - default: default, + has_value: sort == Some('C') })) } Some('r') | Some('p') => { let generics = doc_generics(item_doc, tcx, cdata, tag_method_ty_generics); let predicates = doc_predicates(item_doc, tcx, cdata, tag_method_ty_generics); - let fty = doc_method_fty(item_doc, tcx, cdata); + let ity = tcx.lookup_item_type(def_id).ty; + let fty = match ity.sty { + ty::TyBareFn(_, fty) => fty.clone(), + _ => tcx.sess.bug(&format!( + "the type {:?} of the method {:?} is not a function?", + ity, name)) + }; let explicit_self = get_explicit_self(item_doc); - let provided_source = get_provided_source(item_doc, cdata); ty::MethodTraitItem(Rc::new(ty::Method::new(name, generics, @@ -885,8 +903,7 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc, explicit_self, vis, def_id, - container, - provided_source))) + container))) } Some('t') => { let ty = maybe_doc_type(item_doc, tcx, cdata); @@ -902,13 +919,13 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc, } } -pub fn get_trait_item_def_ids(cdata: Cmd, id: ast::NodeId) +pub fn get_trait_item_def_ids(cdata: Cmd, id: DefIndex) -> Vec { let item = cdata.lookup_item(id); reader::tagged_docs(item, tag_item_trait_item).map(|mth| { let def_id = item_def_id(mth, cdata); match item_sort(mth) { - Some('C') => ty::ConstTraitItemId(def_id), + Some('C') | Some('c') => ty::ConstTraitItemId(def_id), Some('r') | Some('p') => ty::MethodTraitItemId(def_id), Some('t') => ty::TypeTraitItemId(def_id), _ => panic!("unknown trait item sort"), @@ -916,7 +933,7 @@ pub fn get_trait_item_def_ids(cdata: Cmd, id: ast::NodeId) }).collect() } -pub fn get_item_variances(cdata: Cmd, id: ast::NodeId) -> ty::ItemVariances { +pub fn get_item_variances(cdata: Cmd, id: DefIndex) -> ty::ItemVariances { let item_doc = cdata.lookup_item(id); let variance_doc = reader::get_doc(item_doc, tag_item_variances); let mut decoder = reader::Decoder::new(variance_doc); @@ -925,19 +942,19 @@ pub fn get_item_variances(cdata: Cmd, id: ast::NodeId) -> ty::ItemVariances { pub fn get_provided_trait_methods<'tcx>(intr: Rc, cdata: Cmd, - id: ast::NodeId, + id: DefIndex, tcx: &ty::ctxt<'tcx>) -> Vec>> { let item = cdata.lookup_item(id); reader::tagged_docs(item, tag_item_trait_item).filter_map(|mth_id| { let did = item_def_id(mth_id, cdata); - let mth = cdata.lookup_item(did.node); + let mth = cdata.lookup_item(did.index); if item_sort(mth) == Some('p') { let trait_item = get_impl_or_trait_item(intr.clone(), cdata, - did.node, + did.index, tcx); if let ty::MethodTraitItem(ref method) = trait_item { Some((*method).clone()) @@ -952,7 +969,7 @@ pub fn get_provided_trait_methods<'tcx>(intr: Rc, pub fn get_associated_consts<'tcx>(intr: Rc, cdata: Cmd, - id: ast::NodeId, + id: DefIndex, tcx: &ty::ctxt<'tcx>) -> Vec>> { let item = cdata.lookup_item(id); @@ -960,40 +977,29 @@ pub fn get_associated_consts<'tcx>(intr: Rc, [tag_item_trait_item, tag_item_impl_item].iter().flat_map(|&tag| { reader::tagged_docs(item, tag).filter_map(|ac_id| { let did = item_def_id(ac_id, cdata); - let ac_doc = cdata.lookup_item(did.node); - - if item_sort(ac_doc) == Some('C') { - let trait_item = get_impl_or_trait_item(intr.clone(), - cdata, - did.node, - tcx); - if let ty::ConstTraitItem(ref ac) = trait_item { - Some((*ac).clone()) - } else { - None + let ac_doc = cdata.lookup_item(did.index); + + match item_sort(ac_doc) { + Some('C') | Some('c') => { + let trait_item = get_impl_or_trait_item(intr.clone(), + cdata, + did.index, + tcx); + if let ty::ConstTraitItem(ref ac) = trait_item { + Some((*ac).clone()) + } else { + None + } } - } else { - None + _ => None } }) }).collect() } -pub fn get_type_name_if_impl(cdata: Cmd, - node_id: ast::NodeId) -> Option { - let item = cdata.lookup_item(node_id); - if item_family(item) != Impl { - return None; - } - - reader::tagged_docs(item, tag_item_impl_type_basename).nth(0).map(|doc| { - token::intern(doc.as_str_slice()) - }) -} - pub fn get_methods_if_impl(intr: Rc, cdata: Cmd, - node_id: ast::NodeId) + node_id: DefIndex) -> Option > { let item = cdata.lookup_item(node_id); if item_family(item) != Impl { @@ -1010,7 +1016,7 @@ pub fn get_methods_if_impl(intr: Rc, let mut impl_methods = Vec::new(); for impl_method_id in impl_method_ids { - let impl_method_doc = cdata.lookup_item(impl_method_id.node); + let impl_method_doc = cdata.lookup_item(impl_method_id.index); let family = item_family(impl_method_doc); match family { StaticMethod | Method => { @@ -1030,7 +1036,7 @@ pub fn get_methods_if_impl(intr: Rc, /// If node_id is the constructor of a tuple struct, retrieve the NodeId of /// the actual type definition, otherwise, return None pub fn get_tuple_struct_definition_if_ctor(cdata: Cmd, - node_id: ast::NodeId) + node_id: DefIndex) -> Option { let item = cdata.lookup_item(node_id); @@ -1040,24 +1046,24 @@ pub fn get_tuple_struct_definition_if_ctor(cdata: Cmd, } pub fn get_item_attrs(cdata: Cmd, - orig_node_id: ast::NodeId) - -> Vec { + orig_node_id: DefIndex) + -> Vec { // The attributes for a tuple struct are attached to the definition, not the ctor; // we assume that someone passing in a tuple struct ctor is actually wanting to // look at the definition let node_id = get_tuple_struct_definition_if_ctor(cdata, orig_node_id); - let node_id = node_id.map(|x| x.node).unwrap_or(orig_node_id); + let node_id = node_id.map(|x| x.index).unwrap_or(orig_node_id); let item = cdata.lookup_item(node_id); get_attributes(item) } -pub fn get_struct_field_attrs(cdata: Cmd) -> FnvHashMap> { +pub fn get_struct_field_attrs(cdata: Cmd) -> FnvHashMap> { let data = rbml::Doc::new(cdata.data()); let fields = reader::get_doc(data, tag_struct_fields); reader::tagged_docs(fields, tag_struct_field).map(|field| { - let id = reader::doc_as_u32(reader::get_doc(field, tag_struct_field_id)); + let def_id = translated_def_id(cdata, reader::get_doc(field, tag_def_id)); let attrs = get_attributes(field); - (id, attrs) + (def_id, attrs) }).collect() } @@ -1069,7 +1075,7 @@ fn struct_field_family_to_visibility(family: Family) -> hir::Visibility { } } -pub fn get_struct_field_names(intr: &IdentInterner, cdata: Cmd, id: ast::NodeId) +pub fn get_struct_field_names(intr: &IdentInterner, cdata: Cmd, id: DefIndex) -> Vec { let item = cdata.lookup_item(id); reader::tagged_docs(item, tag_item_field).map(|an_item| { @@ -1079,7 +1085,7 @@ pub fn get_struct_field_names(intr: &IdentInterner, cdata: Cmd, id: ast::NodeId) })).collect() } -fn get_meta_items(md: rbml::Doc) -> Vec> { +fn get_meta_items(md: rbml::Doc) -> Vec> { reader::tagged_docs(md, tag_meta_item_word).map(|meta_item_doc| { let nd = reader::get_doc(meta_item_doc, tag_meta_item_name); let n = token::intern_and_get_ident(nd.as_str_slice()); @@ -1100,7 +1106,7 @@ fn get_meta_items(md: rbml::Doc) -> Vec> { })).collect() } -fn get_attributes(md: rbml::Doc) -> Vec { +fn get_attributes(md: rbml::Doc) -> Vec { match reader::maybe_get_doc(md, tag_attributes) { Some(attrs_d) => { reader::tagged_docs(attrs_d, tag_attribute).map(|attr_doc| { @@ -1113,9 +1119,9 @@ fn get_attributes(md: rbml::Doc) -> Vec { assert_eq!(meta_items.len(), 1); let meta_item = meta_items.into_iter().nth(0).unwrap(); codemap::Spanned { - node: hir::Attribute_ { + node: ast::Attribute_ { id: attr::mk_attr_id(), - style: hir::AttrOuter, + style: ast::AttrStyle::Outer, value: meta_item, is_sugared_doc: is_sugared_doc, }, @@ -1139,7 +1145,7 @@ fn list_crate_attributes(md: rbml::Doc, hash: &Svh, write!(out, "\n\n") } -pub fn get_crate_attributes(data: &[u8]) -> Vec { +pub fn get_crate_attributes(data: &[u8]) -> Vec { get_attributes(rbml::Doc::new(data)) } @@ -1227,14 +1233,14 @@ pub fn list_crate_metadata(bytes: &[u8], out: &mut io::Write) -> io::Result<()> // crate to the correct local crate number. pub fn translate_def_id(cdata: Cmd, did: DefId) -> DefId { if did.is_local() { - return DefId { krate: cdata.cnum, node: did.node }; + return DefId { krate: cdata.cnum, index: did.index }; } match cdata.cnum_map.borrow().get(&did.krate) { Some(&n) => { DefId { krate: n, - node: did.node, + index: did.index, } } None => panic!("didn't find a crate in the cnum_map") @@ -1245,12 +1251,12 @@ pub fn translate_def_id(cdata: Cmd, did: DefId) -> DefId { // for an external crate. fn reverse_translate_def_id(cdata: Cmd, did: DefId) -> Option { if did.krate == cdata.cnum { - return Some(DefId { krate: LOCAL_CRATE, node: did.node }); + return Some(DefId { krate: LOCAL_CRATE, index: did.index }); } for (&local, &global) in cdata.cnum_map.borrow().iter() { if global == did.krate { - return Some(DefId { krate: local, node: did.node }); + return Some(DefId { krate: local, index: did.index }); } } @@ -1258,7 +1264,7 @@ fn reverse_translate_def_id(cdata: Cmd, did: DefId) -> Option { } pub fn each_inherent_implementation_for_type(cdata: Cmd, - id: ast::NodeId, + id: DefIndex, mut callback: F) where F: FnMut(DefId), { @@ -1275,37 +1281,32 @@ pub fn each_implementation_for_trait(cdata: Cmd, mut callback: F) where F: FnMut(DefId), { - if cdata.cnum == def_id.krate { - let item_doc = cdata.lookup_item(def_id.node); - for impl_doc in reader::tagged_docs(item_doc, tag_items_data_item_extension_impl) { - callback(item_def_id(impl_doc, cdata)); - } - return; - } - // Do a reverse lookup beforehand to avoid touching the crate_num // hash map in the loop below. if let Some(crate_local_did) = reverse_translate_def_id(cdata, def_id) { let def_id_u64 = def_to_u64(crate_local_did); let impls_doc = reader::get_doc(rbml::Doc::new(cdata.data()), tag_impls); - for impl_doc in reader::tagged_docs(impls_doc, tag_impls_impl) { - let impl_trait = reader::get_doc(impl_doc, tag_impls_impl_trait_def_id); - if reader::doc_as_u64(impl_trait) == def_id_u64 { - callback(item_def_id(impl_doc, cdata)); + for trait_doc in reader::tagged_docs(impls_doc, tag_impls_trait) { + let trait_def_id = reader::get_doc(trait_doc, tag_def_id); + if reader::doc_as_u64(trait_def_id) != def_id_u64 { + continue; + } + for impl_doc in reader::tagged_docs(trait_doc, tag_impls_trait_impl) { + callback(translated_def_id(cdata, impl_doc)); } } } } -pub fn get_trait_of_item(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt) +pub fn get_trait_of_item(cdata: Cmd, id: DefIndex, tcx: &ty::ctxt) -> Option { let item_doc = cdata.lookup_item(id); let parent_item_id = match item_parent_item(cdata, item_doc) { None => return None, Some(item_id) => item_id, }; - let parent_item_doc = cdata.lookup_item(parent_item_id.node); + let parent_item_doc = cdata.lookup_item(parent_item_id.index); match item_family(parent_item_doc) { Trait => Some(item_def_id(parent_item_doc, cdata)), Impl | DefaultImpl => { @@ -1331,13 +1332,13 @@ pub fn get_native_libraries(cdata: Cmd) }).collect() } -pub fn get_plugin_registrar_fn(data: &[u8]) -> Option { +pub fn get_plugin_registrar_fn(data: &[u8]) -> Option { reader::maybe_get_doc(rbml::Doc::new(data), tag_plugin_registrar_fn) - .map(|doc| reader::doc_as_u32(doc)) + .map(|doc| DefIndex::from_u32(reader::doc_as_u32(doc))) } pub fn each_exported_macro(data: &[u8], intr: &IdentInterner, mut f: F) where - F: FnMut(ast::Name, Vec, String) -> bool, + F: FnMut(ast::Name, Vec, String) -> bool, { let macros = reader::get_doc(rbml::Doc::new(data), tag_macro_defs); for macro_doc in reader::tagged_docs(macros, tag_macro_def) { @@ -1385,7 +1386,7 @@ pub fn get_missing_lang_items(cdata: Cmd) }).collect() } -pub fn get_method_arg_names(cdata: Cmd, id: ast::NodeId) -> Vec { +pub fn get_method_arg_names(cdata: Cmd, id: DefIndex) -> Vec { let method_doc = cdata.lookup_item(id); match reader::maybe_get_doc(method_doc, tag_method_argument_names) { Some(args_doc) => { @@ -1403,12 +1404,12 @@ pub fn get_reachable_ids(cdata: Cmd) -> Vec { reader::tagged_docs(items, tag_reachable_id).map(|doc| { DefId { krate: cdata.cnum, - node: reader::doc_as_u32(doc), + index: DefIndex::from_u32(reader::doc_as_u32(doc)), } }).collect() } -pub fn is_typedef(cdata: Cmd, id: ast::NodeId) -> bool { +pub fn is_typedef(cdata: Cmd, id: DefIndex) -> bool { let item_doc = cdata.lookup_item(id); match item_family(item_doc) { Type => true, @@ -1416,7 +1417,7 @@ pub fn is_typedef(cdata: Cmd, id: ast::NodeId) -> bool { } } -pub fn is_const_fn(cdata: Cmd, id: ast::NodeId) -> bool { +pub fn is_const_fn(cdata: Cmd, id: DefIndex) -> bool { let item_doc = cdata.lookup_item(id); match fn_constness(item_doc) { hir::Constness::Const => true, @@ -1424,7 +1425,7 @@ pub fn is_const_fn(cdata: Cmd, id: ast::NodeId) -> bool { } } -pub fn is_impl(cdata: Cmd, id: ast::NodeId) -> bool { +pub fn is_impl(cdata: Cmd, id: DefIndex) -> bool { let item_doc = cdata.lookup_item(id); match item_family(item_doc) { Impl => true, @@ -1444,7 +1445,7 @@ fn doc_generics<'tcx>(base_doc: rbml::Doc, for p in reader::tagged_docs(doc, tag_type_param_def) { let bd = TyDecoder::with_doc(tcx, cdata.cnum, p, - &mut |_, did| translate_def_id(cdata, did)) + &mut |did| translate_def_id(cdata, did)) .parse_type_param_def(); types.push(bd.space, bd); } @@ -1466,7 +1467,7 @@ fn doc_generics<'tcx>(base_doc: rbml::Doc, let bounds = reader::tagged_docs(rp_doc, tag_items_data_region).map(|p| { TyDecoder::with_doc(tcx, cdata.cnum, p, - &mut |_, did| translate_def_id(cdata, did)) + &mut |did| translate_def_id(cdata, did)) .parse_region() }).collect(); @@ -1480,6 +1481,19 @@ fn doc_generics<'tcx>(base_doc: rbml::Doc, ty::Generics { types: types, regions: regions } } +fn doc_predicate<'tcx>(cdata: Cmd, + doc: rbml::Doc, + tcx: &ty::ctxt<'tcx>) + -> ty::Predicate<'tcx> +{ + let predicate_pos = cdata.xref_index.lookup( + cdata.data(), reader::doc_as_u32(doc)).unwrap() as usize; + TyDecoder::new( + cdata.data(), cdata.cnum, predicate_pos, tcx, + &mut |did| translate_def_id(cdata, did) + ).parse_predicate() +} + fn doc_predicates<'tcx>(base_doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd, @@ -1489,30 +1503,30 @@ fn doc_predicates<'tcx>(base_doc: rbml::Doc, let doc = reader::get_doc(base_doc, tag); let mut predicates = subst::VecPerParamSpace::empty(); - for predicate_doc in reader::tagged_docs(doc, tag_predicate) { - let space_doc = reader::get_doc(predicate_doc, tag_predicate_space); - let space = subst::ParamSpace::from_uint(reader::doc_as_u8(space_doc) as usize); - - let data_doc = reader::get_doc(predicate_doc, tag_predicate_data); - let data = - TyDecoder::with_doc(tcx, cdata.cnum, data_doc, - &mut |_, did| translate_def_id(cdata, did)) - .parse_predicate(); - - predicates.push(space, data); + for predicate_doc in reader::tagged_docs(doc, tag_type_predicate) { + predicates.push(subst::TypeSpace, + doc_predicate(cdata, predicate_doc, tcx)); + } + for predicate_doc in reader::tagged_docs(doc, tag_self_predicate) { + predicates.push(subst::SelfSpace, + doc_predicate(cdata, predicate_doc, tcx)); + } + for predicate_doc in reader::tagged_docs(doc, tag_fn_predicate) { + predicates.push(subst::FnSpace, + doc_predicate(cdata, predicate_doc, tcx)); } ty::GenericPredicates { predicates: predicates } } -pub fn is_defaulted_trait(cdata: Cmd, trait_id: ast::NodeId) -> bool { +pub fn is_defaulted_trait(cdata: Cmd, trait_id: DefIndex) -> bool { let trait_doc = cdata.lookup_item(trait_id); assert!(item_family(trait_doc) == Family::Trait); let defaulted_doc = reader::get_doc(trait_doc, tag_defaulted_trait); reader::doc_as_u8(defaulted_doc) != 0 } -pub fn is_default_impl(cdata: Cmd, impl_id: ast::NodeId) -> bool { +pub fn is_default_impl(cdata: Cmd, impl_id: DefIndex) -> bool { let impl_doc = cdata.lookup_item(impl_id); item_family(impl_doc) == Family::DefaultImpl } @@ -1527,7 +1541,7 @@ pub fn get_imported_filemaps(metadata: &[u8]) -> Vec { }).collect() } -pub fn is_extern_fn(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt) -> bool { +pub fn is_extern_fn(cdata: Cmd, id: DefIndex, tcx: &ty::ctxt) -> bool { let item_doc = match cdata.get_item(id) { Some(doc) => doc, None => return false, @@ -1542,3 +1556,41 @@ pub fn is_extern_fn(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt) -> bool { false } } + +pub fn closure_kind(cdata: Cmd, closure_id: DefIndex) -> ty::ClosureKind { + let closure_doc = cdata.lookup_item(closure_id); + let closure_kind_doc = reader::get_doc(closure_doc, tag_items_closure_kind); + let mut decoder = reader::Decoder::new(closure_kind_doc); + ty::ClosureKind::decode(&mut decoder).unwrap() +} + +pub fn closure_ty<'tcx>(cdata: Cmd, closure_id: DefIndex, tcx: &ty::ctxt<'tcx>) + -> ty::ClosureTy<'tcx> { + let closure_doc = cdata.lookup_item(closure_id); + let closure_ty_doc = reader::get_doc(closure_doc, tag_items_closure_ty); + TyDecoder::with_doc(tcx, cdata.cnum, closure_ty_doc, &mut |did| translate_def_id(cdata, did)) + .parse_closure_ty() +} + +fn def_key(item_doc: rbml::Doc) -> hir_map::DefKey { + match reader::maybe_get_doc(item_doc, tag_def_key) { + Some(def_key_doc) => { + let mut decoder = reader::Decoder::new(def_key_doc); + hir_map::DefKey::decode(&mut decoder).unwrap() + } + None => { + panic!("failed to find block with tag {:?} for item with family {:?}", + tag_def_key, + item_family(item_doc)) + } + } +} + +pub fn def_path(cdata: Cmd, id: DefIndex) -> hir_map::DefPath { + debug!("def_path(id={:?})", id); + hir_map::definitions::make_def_path(id, |parent| { + debug!("def_path: parent={:?}", parent); + let parent_doc = cdata.lookup_item(parent); + def_key(parent_doc) + }) +} diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index ff24541692..8e2c2e6a0b 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -17,14 +17,16 @@ use back::svh::Svh; use session::config; use metadata::common::*; use metadata::cstore; +use metadata::cstore::LOCAL_CRATE; use metadata::decoder; use metadata::tyencode; -use metadata::index::{self, IndexEntry}; +use metadata::index::{self, IndexData}; use metadata::inline::InlinedItemRef; use middle::def; -use middle::def_id::{DefId, LOCAL_CRATE}; +use middle::def_id::{CRATE_DEF_INDEX, DefId}; use middle::dependency_format::Linkage; use middle::stability; +use middle::subst; use middle::ty::{self, Ty}; use util::nodemap::{FnvHashMap, NodeMap, NodeSet}; @@ -33,18 +35,19 @@ use std::cell::RefCell; use std::io::prelude::*; use std::io::{Cursor, SeekFrom}; use std::rc::Rc; +use std::u32; use syntax::abi; -use syntax::ast::{NodeId, Name, CRATE_NODE_ID, CrateNum}; +use syntax::ast::{self, NodeId, Name, CRATE_NODE_ID, CrateNum}; +use syntax::attr; +use syntax::attr::AttrMetaMethods; use syntax::diagnostic::SpanHandler; use syntax::parse::token::special_idents; use syntax; use rbml::writer::Encoder; -use rustc_front::hir as ast; +use rustc_front::hir; use rustc_front::visit::Visitor; use rustc_front::visit; -use rustc_front::attr; -use rustc_front::attr::AttrMetaMethods; use front::map::{LinkedPath, PathElem, PathElems}; use front::map as ast_map; @@ -74,18 +77,61 @@ pub struct EncodeContext<'a, 'tcx: 'a> { pub reachable: &'a NodeSet, } -fn encode_name(rbml_w: &mut Encoder, name: Name) { - rbml_w.wr_tagged_str(tag_paths_data_name, &name.as_str()); +impl<'a, 'tcx> EncodeContext<'a,'tcx> { + fn local_id(&self, def_id: DefId) -> NodeId { + self.tcx.map.as_local_node_id(def_id).unwrap() + } +} + +/// "interned" entries referenced by id +#[derive(PartialEq, Eq, Hash)] +pub enum XRef<'tcx> { Predicate(ty::Predicate<'tcx>) } + +struct CrateIndex<'tcx> { + items: IndexData, + xrefs: FnvHashMap, u32>, // sequentially-assigned } -fn encode_impl_type_basename(rbml_w: &mut Encoder, name: Name) { - rbml_w.wr_tagged_str(tag_item_impl_type_basename, &name.as_str()); +impl<'tcx> CrateIndex<'tcx> { + fn record(&mut self, id: DefId, rbml_w: &mut Encoder) { + let position = rbml_w.mark_stable_position(); + self.items.record(id, position); + } + + fn add_xref(&mut self, xref: XRef<'tcx>) -> u32 { + let old_len = self.xrefs.len() as u32; + *self.xrefs.entry(xref).or_insert(old_len) + } +} + +fn encode_name(rbml_w: &mut Encoder, name: Name) { + rbml_w.wr_tagged_str(tag_paths_data_name, &name.as_str()); } fn encode_def_id(rbml_w: &mut Encoder, id: DefId) { rbml_w.wr_tagged_u64(tag_def_id, def_to_u64(id)); } +/// For every DefId that we create a metadata item for, we include a +/// serialized copy of its DefKey, which allows us to recreate a path. +fn encode_def_id_and_key(ecx: &EncodeContext, + rbml_w: &mut Encoder, + def_id: DefId) +{ + encode_def_id(rbml_w, def_id); + encode_def_key(ecx, rbml_w, def_id); +} + +fn encode_def_key(ecx: &EncodeContext, + rbml_w: &mut Encoder, + def_id: DefId) +{ + rbml_w.start_tag(tag_def_key); + let def_key = ecx.tcx.map.def_key(def_id); + def_key.encode(rbml_w); + rbml_w.end_tag(); +} + fn encode_trait_ref<'a, 'tcx>(rbml_w: &mut Encoder, ecx: &EncodeContext<'a, 'tcx>, trait_ref: ty::TraitRef<'tcx>, @@ -108,17 +154,18 @@ fn encode_family(rbml_w: &mut Encoder, c: char) { } pub fn def_to_u64(did: DefId) -> u64 { - (did.krate as u64) << 32 | (did.node as u64) + assert!(did.index.as_u32() < u32::MAX); + (did.krate as u64) << 32 | (did.index.as_usize() as u64) } pub fn def_to_string(did: DefId) -> String { - format!("{}:{}", did.krate, did.node) + format!("{}:{}", did.krate, did.index.as_usize()) } fn encode_item_variances(rbml_w: &mut Encoder, ecx: &EncodeContext, id: NodeId) { - let v = ecx.tcx.item_variances(DefId::local(id)); + let v = ecx.tcx.item_variances(ecx.tcx.map.local_def_id(id)); rbml_w.start_tag(tag_item_variances); v.encode(rbml_w); rbml_w.end_tag(); @@ -126,18 +173,22 @@ fn encode_item_variances(rbml_w: &mut Encoder, fn encode_bounds_and_type_for_item<'a, 'tcx>(rbml_w: &mut Encoder, ecx: &EncodeContext<'a, 'tcx>, + index: &mut CrateIndex<'tcx>, id: NodeId) { encode_bounds_and_type(rbml_w, ecx, - &ecx.tcx.lookup_item_type(DefId::local(id)), - &ecx.tcx.lookup_predicates(DefId::local(id))); + index, + &ecx.tcx.lookup_item_type(ecx.tcx.map.local_def_id(id)), + &ecx.tcx.lookup_predicates(ecx.tcx.map.local_def_id(id))); } fn encode_bounds_and_type<'a, 'tcx>(rbml_w: &mut Encoder, ecx: &EncodeContext<'a, 'tcx>, + index: &mut CrateIndex<'tcx>, scheme: &ty::TypeScheme<'tcx>, predicates: &ty::GenericPredicates<'tcx>) { - encode_generics(rbml_w, ecx, &scheme.generics, &predicates, tag_item_generics); + encode_generics(rbml_w, ecx, index, + &scheme.generics, &predicates, tag_item_generics); encode_type(ecx, rbml_w, scheme.ty); } @@ -211,22 +262,6 @@ fn encode_region(ecx: &EncodeContext, rbml_w.end_tag(); } -fn encode_method_fty<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, - rbml_w: &mut Encoder, - typ: &ty::BareFnTy<'tcx>) { - rbml_w.start_tag(tag_item_method_fty); - - let ty_str_ctxt = &tyencode::ctxt { - diag: ecx.diag, - ds: def_to_string, - tcx: ecx.tcx, - abbrevs: &ecx.type_abbrevs - }; - tyencode::enc_bare_fn_ty(rbml_w, ty_str_ctxt, typ); - - rbml_w.end_tag(); -} - fn encode_symbol(ecx: &EncodeContext, rbml_w: &mut Encoder, id: NodeId) { @@ -253,8 +288,7 @@ fn encode_parent_item(rbml_w: &mut Encoder, id: DefId) { } fn encode_struct_fields(rbml_w: &mut Encoder, - variant: ty::VariantDef, - origin: DefId) { + variant: ty::VariantDef) { for f in &variant.fields { if f.name == special_idents::unnamed_field.name { rbml_w.start_tag(tag_item_unnamed_field); @@ -264,25 +298,24 @@ fn encode_struct_fields(rbml_w: &mut Encoder, } encode_struct_field_family(rbml_w, f.vis); encode_def_id(rbml_w, f.did); - rbml_w.wr_tagged_u64(tag_item_field_origin, def_to_u64(origin)); rbml_w.end_tag(); } } -fn encode_enum_variant_info(ecx: &EncodeContext, - rbml_w: &mut Encoder, - id: NodeId, - vis: ast::Visibility, - index: &mut Vec) { +fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, + rbml_w: &mut Encoder, + id: NodeId, + vis: hir::Visibility, + index: &mut CrateIndex<'tcx>) { debug!("encode_enum_variant_info(id={})", id); let mut disr_val = 0; - let def = ecx.tcx.lookup_adt_def(DefId::local(id)); + let def = ecx.tcx.lookup_adt_def(ecx.tcx.map.local_def_id(id)); for variant in &def.variants { let vid = variant.did; - assert!(vid.is_local()); + let variant_node_id = ecx.local_id(vid); - if let ty::VariantKind::Dict = variant.kind() { + if let ty::VariantKind::Struct = variant.kind() { // tuple-like enum variant fields aren't really items so // don't try to encode them. for field in &variant.fields { @@ -290,18 +323,15 @@ fn encode_enum_variant_info(ecx: &EncodeContext, } } - index.push(IndexEntry { - node: vid.node, - pos: rbml_w.mark_stable_position(), - }); + index.record(vid, rbml_w); rbml_w.start_tag(tag_items_data_item); - encode_def_id(rbml_w, vid); + encode_def_id_and_key(ecx, rbml_w, vid); encode_family(rbml_w, match variant.kind() { ty::VariantKind::Unit | ty::VariantKind::Tuple => 'v', - ty::VariantKind::Dict => 'V' + ty::VariantKind::Struct => 'V' }); encode_name(rbml_w, variant.name); - encode_parent_item(rbml_w, DefId::local(id)); + encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(id)); encode_visibility(rbml_w, vis); let attrs = ecx.tcx.get_attrs(vid); @@ -311,16 +341,16 @@ fn encode_enum_variant_info(ecx: &EncodeContext, let stab = stability::lookup(ecx.tcx, vid); encode_stability(rbml_w, stab); - encode_struct_fields(rbml_w, variant, vid); + encode_struct_fields(rbml_w, variant); let specified_disr_val = variant.disr_val; if specified_disr_val != disr_val { encode_disr_val(ecx, rbml_w, specified_disr_val); disr_val = specified_disr_val; } - encode_bounds_and_type_for_item(rbml_w, ecx, vid.node); + encode_bounds_and_type_for_item(rbml_w, ecx, index, variant_node_id); - ecx.tcx.map.with_path(vid.node, |path| encode_path(rbml_w, path)); + ecx.tcx.map.with_path(variant_node_id, |path| encode_path(rbml_w, path)); rbml_w.end_tag(); disr_val = disr_val.wrapping_add(1); } @@ -340,124 +370,19 @@ fn encode_path>(rbml_w: &mut Encoder, path: PI) { rbml_w.end_tag(); } -fn encode_reexported_static_method(rbml_w: &mut Encoder, - exp: &def::Export, - method_def_id: DefId, - method_name: Name) { - debug!("(encode reexported static method) {}::{}", - exp.name, method_name); - rbml_w.start_tag(tag_items_data_item_reexport); - rbml_w.wr_tagged_u64(tag_items_data_item_reexport_def_id, - def_to_u64(method_def_id)); - rbml_w.wr_tagged_str(tag_items_data_item_reexport_name, - &format!("{}::{}", exp.name, - method_name)); - rbml_w.end_tag(); -} - -fn encode_reexported_static_base_methods(ecx: &EncodeContext, - rbml_w: &mut Encoder, - exp: &def::Export) - -> bool { - let impl_items = ecx.tcx.impl_items.borrow(); - match ecx.tcx.inherent_impls.borrow().get(&exp.def_id) { - Some(implementations) => { - for base_impl_did in implementations.iter() { - for &method_did in impl_items.get(base_impl_did).unwrap() { - let impl_item = ecx.tcx.impl_or_trait_item(method_did.def_id()); - if let ty::MethodTraitItem(ref m) = impl_item { - encode_reexported_static_method(rbml_w, - exp, - m.def_id, - m.name); - } - } - } - - true - } - None => { false } - } -} - -fn encode_reexported_static_trait_methods(ecx: &EncodeContext, - rbml_w: &mut Encoder, - exp: &def::Export) - -> bool { - match ecx.tcx.trait_items_cache.borrow().get(&exp.def_id) { - Some(trait_items) => { - for trait_item in trait_items.iter() { - if let ty::MethodTraitItem(ref m) = *trait_item { - encode_reexported_static_method(rbml_w, - exp, - m.def_id, - m.name); - } - } - true - } - None => { false } - } -} - -fn encode_reexported_static_methods(ecx: &EncodeContext, - rbml_w: &mut Encoder, - mod_path: PathElems, - exp: &def::Export) { - if let Some(ast_map::NodeItem(item)) = ecx.tcx.map.find(exp.def_id.node) { - let path_differs = ecx.tcx.map.with_path(exp.def_id.node, |path| { - let (mut a, mut b) = (path, mod_path.clone()); - loop { - match (a.next(), b.next()) { - (None, None) => return true, - (None, _) | (_, None) => return false, - (Some(x), Some(y)) => if x != y { return false }, - } - } - }); - - // - // We don't need to reexport static methods on items - // declared in the same module as our `pub use ...` since - // that's done when we encode the item itself. - // - // The only exception is when the reexport *changes* the - // name e.g. `pub use Foo = self::Bar` -- we have - // encoded metadata for static methods relative to Bar, - // but not yet for Foo. - // - if path_differs || item.ident.name != exp.name { - if !encode_reexported_static_base_methods(ecx, rbml_w, exp) { - if encode_reexported_static_trait_methods(ecx, rbml_w, exp) { - debug!("(encode reexported static methods) {} [trait]", - item.ident.name); - } - } - else { - debug!("(encode reexported static methods) {} [base]", - item.ident.name); - } - } - } -} - /// Iterates through "auxiliary node IDs", which are node IDs that describe /// top-level items that are sub-items of the given item. Specifically: /// /// * For newtype structs, iterates through the node ID of the constructor. -fn each_auxiliary_node_id(item: &ast::Item, callback: F) -> bool where +fn each_auxiliary_node_id(item: &hir::Item, callback: F) -> bool where F: FnOnce(NodeId) -> bool, { let mut continue_ = true; match item.node { - ast::ItemStruct(ref struct_def, _) => { + hir::ItemStruct(ref struct_def, _) => { // If this is a newtype struct, return the constructor. - match struct_def.ctor_id { - Some(ctor_id) if !struct_def.fields.is_empty() && - struct_def.fields[0].node.kind.is_unnamed() => { - continue_ = callback(ctor_id); - } - _ => {} + if struct_def.is_tuple() { + continue_ = callback(struct_def.id()); } } _ => {} @@ -468,18 +393,16 @@ fn each_auxiliary_node_id(item: &ast::Item, callback: F) -> bool where fn encode_reexports(ecx: &EncodeContext, rbml_w: &mut Encoder, - id: NodeId, - path: PathElems) { + id: NodeId) { debug!("(encoding info for module) encoding reexports for {}", id); match ecx.reexports.get(&id) { Some(exports) => { debug!("(encoding info for module) found reexports for {}", id); for exp in exports { - debug!("(encoding info for module) reexport '{}' ({}/{}) for \ + debug!("(encoding info for module) reexport '{}' ({:?}) for \ {}", exp.name, - exp.def_id.krate, - exp.def_id.node, + exp.def_id, id); rbml_w.start_tag(tag_items_data_item_reexport); rbml_w.wr_tagged_u64(tag_items_data_item_reexport_def_id, @@ -487,7 +410,6 @@ fn encode_reexports(ecx: &EncodeContext, rbml_w.wr_tagged_str(tag_items_data_item_reexport_name, &exp.name.as_str()); rbml_w.end_tag(); - encode_reexported_static_methods(ecx, rbml_w, path.clone(), exp); } }, None => debug!("(encoding info for module) found no reexports for {}", id), @@ -496,14 +418,14 @@ fn encode_reexports(ecx: &EncodeContext, fn encode_info_for_mod(ecx: &EncodeContext, rbml_w: &mut Encoder, - md: &ast::Mod, + md: &hir::Mod, attrs: &[ast::Attribute], id: NodeId, path: PathElems, name: Name, - vis: ast::Visibility) { + vis: hir::Visibility) { rbml_w.start_tag(tag_items_data_item); - encode_def_id(rbml_w, DefId::local(id)); + encode_def_id_and_key(ecx, rbml_w, ecx.tcx.map.local_def_id(id)); encode_family(rbml_w, 'm'); encode_name(rbml_w, name); debug!("(encoding info for module) encoding info for module ID {}", id); @@ -511,34 +433,25 @@ fn encode_info_for_mod(ecx: &EncodeContext, // Encode info about all the module children. for item in &md.items { rbml_w.wr_tagged_u64(tag_mod_child, - def_to_u64(DefId::local(item.id))); + def_to_u64(ecx.tcx.map.local_def_id(item.id))); each_auxiliary_node_id(&**item, |auxiliary_node_id| { rbml_w.wr_tagged_u64(tag_mod_child, - def_to_u64(DefId::local(auxiliary_node_id))); + def_to_u64(ecx.tcx.map.local_def_id(auxiliary_node_id))); true }); - - if let ast::ItemImpl(..) = item.node { - let (ident, did) = (item.ident, item.id); - debug!("(encoding info for module) ... encoding impl {} ({}/{})", - ident, - did, ecx.tcx.map.node_to_string(did)); - - rbml_w.wr_tagged_u64(tag_mod_impl, def_to_u64(DefId::local(did))); - } } encode_path(rbml_w, path.clone()); encode_visibility(rbml_w, vis); - let stab = stability::lookup(ecx.tcx, DefId::local(id)); + let stab = stability::lookup(ecx.tcx, ecx.tcx.map.local_def_id(id)); encode_stability(rbml_w, stab); // Encode the reexports of this module, if this module is public. - if vis == ast::Public { + if vis == hir::Public { debug!("(encoding info for module) encoding reexports for {}", id); - encode_reexports(ecx, rbml_w, id, path); + encode_reexports(ecx, rbml_w, id); } encode_attributes(rbml_w, attrs); @@ -546,26 +459,26 @@ fn encode_info_for_mod(ecx: &EncodeContext, } fn encode_struct_field_family(rbml_w: &mut Encoder, - visibility: ast::Visibility) { + visibility: hir::Visibility) { encode_family(rbml_w, match visibility { - ast::Public => 'g', - ast::Inherited => 'N' + hir::Public => 'g', + hir::Inherited => 'N' }); } -fn encode_visibility(rbml_w: &mut Encoder, visibility: ast::Visibility) { +fn encode_visibility(rbml_w: &mut Encoder, visibility: hir::Visibility) { let ch = match visibility { - ast::Public => 'y', - ast::Inherited => 'i', + hir::Public => 'y', + hir::Inherited => 'i', }; rbml_w.wr_tagged_u8(tag_items_data_item_visibility, ch as u8); } -fn encode_constness(rbml_w: &mut Encoder, constness: ast::Constness) { +fn encode_constness(rbml_w: &mut Encoder, constness: hir::Constness) { rbml_w.start_tag(tag_items_data_item_constness); let ch = match constness { - ast::Constness::Const => 'c', - ast::Constness::NotConst => 'n', + hir::Constness::Const => 'c', + hir::Constness::NotConst => 'n', }; rbml_w.wr_str(&ch.to_string()); rbml_w.end_tag(); @@ -593,10 +506,10 @@ fn encode_explicit_self(rbml_w: &mut Encoder, } } - fn encode_mutability(m: ast::Mutability) -> u8 { + fn encode_mutability(m: hir::Mutability) -> u8 { match m { - ast::MutImmutable => 'i' as u8, - ast::MutMutable => 'm' as u8, + hir::MutImmutable => 'i' as u8, + hir::MutMutable => 'm' as u8, } } } @@ -605,35 +518,20 @@ fn encode_item_sort(rbml_w: &mut Encoder, sort: char) { rbml_w.wr_tagged_u8(tag_item_trait_item_sort, sort as u8); } -fn encode_parent_sort(rbml_w: &mut Encoder, sort: char) { - rbml_w.wr_tagged_u8(tag_item_trait_parent_sort, sort as u8); -} - -fn encode_provided_source(rbml_w: &mut Encoder, - source_opt: Option) { - if let Some(source) = source_opt { - rbml_w.wr_tagged_u64(tag_item_method_provided_source, def_to_u64(source)); - } -} - fn encode_field<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, field: ty::FieldDef<'tcx>, - global_index: &mut Vec) { + index: &mut CrateIndex<'tcx>) { let nm = field.name; - let id = field.did.node; + let id = ecx.local_id(field.did); - let pos = rbml_w.mark_stable_position(); - global_index.push(IndexEntry { - node: id, - pos: pos, - }); + index.record(field.did, rbml_w); rbml_w.start_tag(tag_items_data_item); debug!("encode_field: encoding {} {}", nm, id); encode_struct_field_family(rbml_w, field.vis); encode_name(rbml_w, nm); - encode_bounds_and_type_for_item(rbml_w, ecx, id); - encode_def_id(rbml_w, DefId::local(id)); + encode_bounds_and_type_for_item(rbml_w, ecx, index, id); + encode_def_id_and_key(ecx, rbml_w, field.did); let stab = stability::lookup(ecx.tcx, field.did); encode_stability(rbml_w, stab); @@ -641,30 +539,28 @@ fn encode_field<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w.end_tag(); } -fn encode_info_for_struct_ctor(ecx: &EncodeContext, - rbml_w: &mut Encoder, - name: Name, - ctor_id: NodeId, - index: &mut Vec, - struct_id: NodeId) { - index.push(IndexEntry { - node: ctor_id, - pos: rbml_w.mark_stable_position(), - }); +fn encode_info_for_struct_ctor<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, + rbml_w: &mut Encoder, + name: Name, + ctor_id: NodeId, + index: &mut CrateIndex<'tcx>, + struct_id: NodeId) { + let ctor_def_id = ecx.tcx.map.local_def_id(ctor_id); + index.record(ctor_def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); - encode_def_id(rbml_w, DefId::local(ctor_id)); + encode_def_id_and_key(ecx, rbml_w, ctor_def_id); encode_family(rbml_w, 'o'); - encode_bounds_and_type_for_item(rbml_w, ecx, ctor_id); + encode_bounds_and_type_for_item(rbml_w, ecx, index, ctor_id); encode_name(rbml_w, name); ecx.tcx.map.with_path(ctor_id, |path| encode_path(rbml_w, path)); - encode_parent_item(rbml_w, DefId::local(struct_id)); + encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(struct_id)); if ecx.item_symbols.borrow().contains_key(&ctor_id) { encode_symbol(ecx, rbml_w, ctor_id); } - let stab = stability::lookup(ecx.tcx, DefId::local(ctor_id)); + let stab = stability::lookup(ecx.tcx, ecx.tcx.map.local_def_id(ctor_id)); encode_stability(rbml_w, stab); // indicate that this is a tuple struct ctor, because downstream users will normally want @@ -677,6 +573,7 @@ fn encode_info_for_struct_ctor(ecx: &EncodeContext, fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder, ecx: &EncodeContext<'a, 'tcx>, + index: &mut CrateIndex<'tcx>, generics: &ty::Generics<'tcx>, predicates: &ty::GenericPredicates<'tcx>, tag: usize) @@ -721,53 +618,48 @@ fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder, rbml_w.end_tag(); } - encode_predicates_in_current_doc(rbml_w, ecx, predicates); + encode_predicates_in_current_doc(rbml_w, ecx, index, predicates); rbml_w.end_tag(); } fn encode_predicates_in_current_doc<'a,'tcx>(rbml_w: &mut Encoder, - ecx: &EncodeContext<'a,'tcx>, + _ecx: &EncodeContext<'a,'tcx>, + index: &mut CrateIndex<'tcx>, predicates: &ty::GenericPredicates<'tcx>) { - let ty_str_ctxt = &tyencode::ctxt { - diag: ecx.diag, - ds: def_to_string, - tcx: ecx.tcx, - abbrevs: &ecx.type_abbrevs - }; - for (space, _, predicate) in predicates.predicates.iter_enumerated() { - rbml_w.start_tag(tag_predicate); - - rbml_w.wr_tagged_u8(tag_predicate_space, space as u8); - - rbml_w.start_tag(tag_predicate_data); - tyencode::enc_predicate(rbml_w, ty_str_ctxt, predicate); - rbml_w.end_tag(); + let tag = match space { + subst::TypeSpace => tag_type_predicate, + subst::SelfSpace => tag_self_predicate, + subst::FnSpace => tag_fn_predicate + }; - rbml_w.end_tag(); + rbml_w.wr_tagged_u32(tag, + index.add_xref(XRef::Predicate(predicate.clone()))); } } fn encode_predicates<'a,'tcx>(rbml_w: &mut Encoder, ecx: &EncodeContext<'a,'tcx>, + index: &mut CrateIndex<'tcx>, predicates: &ty::GenericPredicates<'tcx>, tag: usize) { rbml_w.start_tag(tag); - encode_predicates_in_current_doc(rbml_w, ecx, predicates); + encode_predicates_in_current_doc(rbml_w, ecx, index, predicates); rbml_w.end_tag(); } fn encode_method_ty_fields<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, + index: &mut CrateIndex<'tcx>, method_ty: &ty::Method<'tcx>) { - encode_def_id(rbml_w, method_ty.def_id); + encode_def_id_and_key(ecx, rbml_w, method_ty.def_id); encode_name(rbml_w, method_ty.name); - encode_generics(rbml_w, ecx, &method_ty.generics, &method_ty.predicates, + encode_generics(rbml_w, ecx, index, + &method_ty.generics, &method_ty.predicates, tag_method_ty_generics); - encode_method_fty(ecx, rbml_w, &method_ty.fty); encode_visibility(rbml_w, method_ty.vis); encode_explicit_self(rbml_w, &method_ty.explicit_self); match method_ty.explicit_self { @@ -776,31 +668,32 @@ fn encode_method_ty_fields<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, } _ => encode_family(rbml_w, METHOD_FAMILY) } - encode_provided_source(rbml_w, method_ty.provided_source); } -fn encode_info_for_associated_const(ecx: &EncodeContext, - rbml_w: &mut Encoder, - associated_const: &ty::AssociatedConst, - impl_path: PathElems, - parent_id: NodeId, - impl_item_opt: Option<&ast::ImplItem>) { +fn encode_info_for_associated_const<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, + rbml_w: &mut Encoder, + index: &mut CrateIndex<'tcx>, + associated_const: &ty::AssociatedConst, + impl_path: PathElems, + parent_id: NodeId, + impl_item_opt: Option<&hir::ImplItem>) { debug!("encode_info_for_associated_const({:?},{:?})", associated_const.def_id, associated_const.name); + index.record(associated_const.def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); - encode_def_id(rbml_w, associated_const.def_id); + encode_def_id_and_key(ecx, rbml_w, associated_const.def_id); encode_name(rbml_w, associated_const.name); encode_visibility(rbml_w, associated_const.vis); encode_family(rbml_w, 'C'); - encode_provided_source(rbml_w, associated_const.default); - encode_parent_item(rbml_w, DefId::local(parent_id)); + encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id)); encode_item_sort(rbml_w, 'C'); - encode_bounds_and_type_for_item(rbml_w, ecx, associated_const.def_id.local_id()); + encode_bounds_and_type_for_item(rbml_w, ecx, index, + ecx.local_id(associated_const.def_id)); let stab = stability::lookup(ecx.tcx, associated_const.def_id); encode_stability(rbml_w, stab); @@ -810,7 +703,10 @@ fn encode_info_for_associated_const(ecx: &EncodeContext, if let Some(ii) = impl_item_opt { encode_attributes(rbml_w, &ii.attrs); - encode_inlined_item(ecx, rbml_w, InlinedItemRef::ImplItem(DefId::local(parent_id), ii)); + encode_inlined_item(ecx, + rbml_w, + InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id), + ii)); } rbml_w.end_tag(); @@ -818,42 +714,47 @@ fn encode_info_for_associated_const(ecx: &EncodeContext, fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, + index: &mut CrateIndex<'tcx>, m: &ty::Method<'tcx>, impl_path: PathElems, is_default_impl: bool, parent_id: NodeId, - impl_item_opt: Option<&ast::ImplItem>) { + impl_item_opt: Option<&hir::ImplItem>) { debug!("encode_info_for_method: {:?} {:?}", m.def_id, m.name); + index.record(m.def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); - encode_method_ty_fields(ecx, rbml_w, m); - encode_parent_item(rbml_w, DefId::local(parent_id)); + encode_method_ty_fields(ecx, rbml_w, index, m); + encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id)); encode_item_sort(rbml_w, 'r'); let stab = stability::lookup(ecx.tcx, m.def_id); encode_stability(rbml_w, stab); - // The type for methods gets encoded twice, which is unfortunate. - encode_bounds_and_type_for_item(rbml_w, ecx, m.def_id.local_id()); + let m_node_id = ecx.local_id(m.def_id); + encode_bounds_and_type_for_item(rbml_w, ecx, index, m_node_id); let elem = ast_map::PathName(m.name); encode_path(rbml_w, impl_path.chain(Some(elem))); if let Some(impl_item) = impl_item_opt { - if let ast::MethodImplItem(ref sig, _) = impl_item.node { + if let hir::MethodImplItem(ref sig, _) = impl_item.node { encode_attributes(rbml_w, &impl_item.attrs); let scheme = ecx.tcx.lookup_item_type(m.def_id); let any_types = !scheme.generics.types.is_empty(); let needs_inline = any_types || is_default_impl || attr::requests_inline(&impl_item.attrs); - if needs_inline || sig.constness == ast::Constness::Const { - encode_inlined_item(ecx, rbml_w, InlinedItemRef::ImplItem(DefId::local(parent_id), - impl_item)); + if needs_inline || sig.constness == hir::Constness::Const { + encode_inlined_item(ecx, + rbml_w, + InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id), + impl_item)); } encode_constness(rbml_w, sig.constness); if !any_types { - encode_symbol(ecx, rbml_w, m.def_id.node); + let m_id = ecx.local_id(m.def_id); + encode_symbol(ecx, rbml_w, m_id); } encode_method_argument_names(rbml_w, &sig.decl); } @@ -864,21 +765,23 @@ fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, fn encode_info_for_associated_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, + index: &mut CrateIndex<'tcx>, associated_type: &ty::AssociatedType<'tcx>, impl_path: PathElems, parent_id: NodeId, - impl_item_opt: Option<&ast::ImplItem>) { + impl_item_opt: Option<&hir::ImplItem>) { debug!("encode_info_for_associated_type({:?},{:?})", associated_type.def_id, associated_type.name); + index.record(associated_type.def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); - encode_def_id(rbml_w, associated_type.def_id); + encode_def_id_and_key(ecx, rbml_w, associated_type.def_id); encode_name(rbml_w, associated_type.name); encode_visibility(rbml_w, associated_type.vis); encode_family(rbml_w, 'y'); - encode_parent_item(rbml_w, DefId::local(parent_id)); + encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id)); encode_item_sort(rbml_w, 't'); let stab = stability::lookup(ecx.tcx, associated_type.def_id); @@ -890,7 +793,7 @@ fn encode_info_for_associated_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, if let Some(ii) = impl_item_opt { encode_attributes(rbml_w, &ii.attrs); } else { - encode_predicates(rbml_w, ecx, + encode_predicates(rbml_w, ecx, index, &ecx.tcx.lookup_predicates(associated_type.def_id), tag_item_generics); } @@ -903,11 +806,11 @@ fn encode_info_for_associated_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, } fn encode_method_argument_names(rbml_w: &mut Encoder, - decl: &ast::FnDecl) { + decl: &hir::FnDecl) { rbml_w.start_tag(tag_method_argument_names); for arg in &decl.inputs { let tag = tag_method_argument_name; - if let ast::PatIdent(_, ref path1, _) = arg.pat.node { + if let hir::PatIdent(_, ref path1, _) = arg.pat.node { let name = path1.node.name.as_str(); rbml_w.wr_tagged_bytes(tag, name.as_bytes()); } else { @@ -958,20 +861,6 @@ fn encode_inherent_implementations(ecx: &EncodeContext, } } -// Encodes the implementations of a trait defined in this crate. -fn encode_extension_implementations(ecx: &EncodeContext, - rbml_w: &mut Encoder, - trait_def_id: DefId) { - assert!(trait_def_id.is_local()); - let def = ecx.tcx.lookup_trait_def(trait_def_id); - - def.for_each_impl(ecx.tcx, |impl_def_id| { - rbml_w.start_tag(tag_items_data_item_extension_impl); - encode_def_id(rbml_w, impl_def_id); - rbml_w.end_tag(); - }); -} - fn encode_stability(rbml_w: &mut Encoder, stab_opt: Option<&attr::Stability>) { stab_opt.map(|stab| { rbml_w.start_tag(tag_items_data_item_stability); @@ -980,54 +869,74 @@ fn encode_stability(rbml_w: &mut Encoder, stab_opt: Option<&attr::Stability>) { }); } -fn encode_info_for_item(ecx: &EncodeContext, - rbml_w: &mut Encoder, - item: &ast::Item, - index: &mut Vec, - path: PathElems, - vis: ast::Visibility) { - let tcx = ecx.tcx; +fn encode_xrefs<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, + rbml_w: &mut Encoder, + xrefs: FnvHashMap, u32>) +{ + let ty_str_ctxt = &tyencode::ctxt { + diag: ecx.diag, + ds: def_to_string, + tcx: ecx.tcx, + abbrevs: &ecx.type_abbrevs + }; - fn add_to_index(item: &ast::Item, rbml_w: &mut Encoder, - index: &mut Vec) { - index.push(IndexEntry { - node: item.id, - pos: rbml_w.mark_stable_position(), - }); + let mut xref_positions = vec![0; xrefs.len()]; + rbml_w.start_tag(tag_xref_data); + for (xref, id) in xrefs.into_iter() { + xref_positions[id as usize] = rbml_w.mark_stable_position() as u32; + match xref { + XRef::Predicate(p) => { + tyencode::enc_predicate(rbml_w, ty_str_ctxt, &p) + } + } } + rbml_w.end_tag(); + + rbml_w.start_tag(tag_xref_index); + index::write_dense_index(xref_positions, rbml_w.writer); + rbml_w.end_tag(); +} + +fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, + rbml_w: &mut Encoder, + item: &hir::Item, + index: &mut CrateIndex<'tcx>, + path: PathElems, + vis: hir::Visibility) { + let tcx = ecx.tcx; debug!("encoding info for item at {}", tcx.sess.codemap().span_to_string(item.span)); - let def_id = DefId::local(item.id); - let stab = stability::lookup(tcx, DefId::local(item.id)); + let def_id = ecx.tcx.map.local_def_id(item.id); + let stab = stability::lookup(tcx, ecx.tcx.map.local_def_id(item.id)); match item.node { - ast::ItemStatic(_, m, _) => { - add_to_index(item, rbml_w, index); + hir::ItemStatic(_, m, _) => { + index.record(def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); - encode_def_id(rbml_w, def_id); - if m == ast::MutMutable { + encode_def_id_and_key(ecx, rbml_w, def_id); + if m == hir::MutMutable { encode_family(rbml_w, 'b'); } else { encode_family(rbml_w, 'c'); } - encode_bounds_and_type_for_item(rbml_w, ecx, item.id); + encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id); encode_symbol(ecx, rbml_w, item.id); - encode_name(rbml_w, item.ident.name); + encode_name(rbml_w, item.name); encode_path(rbml_w, path); encode_visibility(rbml_w, vis); encode_stability(rbml_w, stab); encode_attributes(rbml_w, &item.attrs); rbml_w.end_tag(); } - ast::ItemConst(_, _) => { - add_to_index(item, rbml_w, index); + hir::ItemConst(_, _) => { + index.record(def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); - encode_def_id(rbml_w, def_id); + encode_def_id_and_key(ecx, rbml_w, def_id); encode_family(rbml_w, 'C'); - encode_bounds_and_type_for_item(rbml_w, ecx, item.id); - encode_name(rbml_w, item.ident.name); + encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id); + encode_name(rbml_w, item.name); encode_path(rbml_w, path); encode_attributes(rbml_w, &item.attrs); encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(item)); @@ -1035,18 +944,18 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_stability(rbml_w, stab); rbml_w.end_tag(); } - ast::ItemFn(ref decl, _, constness, _, ref generics, _) => { - add_to_index(item, rbml_w, index); + hir::ItemFn(ref decl, _, constness, _, ref generics, _) => { + index.record(def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); - encode_def_id(rbml_w, def_id); + encode_def_id_and_key(ecx, rbml_w, def_id); encode_family(rbml_w, FN_FAMILY); let tps_len = generics.ty_params.len(); - encode_bounds_and_type_for_item(rbml_w, ecx, item.id); - encode_name(rbml_w, item.ident.name); + encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id); + encode_name(rbml_w, item.name); encode_path(rbml_w, path); encode_attributes(rbml_w, &item.attrs); let needs_inline = tps_len > 0 || attr::requests_inline(&item.attrs); - if needs_inline || constness == ast::Constness::Const { + if needs_inline || constness == hir::Constness::Const { encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(item)); } if tps_len == 0 { @@ -1058,59 +967,59 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_method_argument_names(rbml_w, &**decl); rbml_w.end_tag(); } - ast::ItemMod(ref m) => { - add_to_index(item, rbml_w, index); + hir::ItemMod(ref m) => { + index.record(def_id, rbml_w); encode_info_for_mod(ecx, rbml_w, m, &item.attrs, item.id, path, - item.ident.name, + item.name, item.vis); } - ast::ItemForeignMod(ref fm) => { - add_to_index(item, rbml_w, index); + hir::ItemForeignMod(ref fm) => { + index.record(def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); - encode_def_id(rbml_w, def_id); + encode_def_id_and_key(ecx, rbml_w, def_id); encode_family(rbml_w, 'n'); - encode_name(rbml_w, item.ident.name); + encode_name(rbml_w, item.name); encode_path(rbml_w, path); // Encode all the items in this module. for foreign_item in &fm.items { rbml_w.wr_tagged_u64(tag_mod_child, - def_to_u64(DefId::local(foreign_item.id))); + def_to_u64(ecx.tcx.map.local_def_id(foreign_item.id))); } encode_visibility(rbml_w, vis); encode_stability(rbml_w, stab); rbml_w.end_tag(); } - ast::ItemTy(..) => { - add_to_index(item, rbml_w, index); + hir::ItemTy(..) => { + index.record(def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); - encode_def_id(rbml_w, def_id); + encode_def_id_and_key(ecx, rbml_w, def_id); encode_family(rbml_w, 'y'); - encode_bounds_and_type_for_item(rbml_w, ecx, item.id); - encode_name(rbml_w, item.ident.name); + encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id); + encode_name(rbml_w, item.name); encode_path(rbml_w, path); encode_visibility(rbml_w, vis); encode_stability(rbml_w, stab); rbml_w.end_tag(); } - ast::ItemEnum(ref enum_definition, _) => { - add_to_index(item, rbml_w, index); + hir::ItemEnum(ref enum_definition, _) => { + index.record(def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); - encode_def_id(rbml_w, def_id); + encode_def_id_and_key(ecx, rbml_w, def_id); encode_family(rbml_w, 't'); encode_item_variances(rbml_w, ecx, item.id); - encode_bounds_and_type_for_item(rbml_w, ecx, item.id); - encode_name(rbml_w, item.ident.name); + encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id); + encode_name(rbml_w, item.name); encode_attributes(rbml_w, &item.attrs); encode_repr_attrs(rbml_w, ecx, &item.attrs); for v in &enum_definition.variants { - encode_variant_id(rbml_w, DefId::local(v.node.id)); + encode_variant_id(rbml_w, ecx.tcx.map.local_def_id(v.node.data.id())); } encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(item)); encode_path(rbml_w, path); @@ -1128,25 +1037,21 @@ fn encode_info_for_item(ecx: &EncodeContext, vis, index); } - ast::ItemStruct(ref struct_def, _) => { + hir::ItemStruct(ref struct_def, _) => { let def = ecx.tcx.lookup_adt_def(def_id); let variant = def.struct_variant(); - for field in &variant.fields { - encode_field(ecx, rbml_w, field, index); - } - /* Index the class*/ - add_to_index(item, rbml_w, index); + index.record(def_id, rbml_w); /* Now, make an item for the class itself */ rbml_w.start_tag(tag_items_data_item); - encode_def_id(rbml_w, def_id); + encode_def_id_and_key(ecx, rbml_w, def_id); encode_family(rbml_w, 'S'); - encode_bounds_and_type_for_item(rbml_w, ecx, item.id); + encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id); encode_item_variances(rbml_w, ecx, item.id); - encode_name(rbml_w, item.ident.name); + encode_name(rbml_w, item.name); encode_attributes(rbml_w, &item.attrs); encode_path(rbml_w, path.clone()); encode_stability(rbml_w, stab); @@ -1156,53 +1061,59 @@ fn encode_info_for_item(ecx: &EncodeContext, /* Encode def_ids for each field and method for methods, write all the stuff get_trait_method needs to know*/ - encode_struct_fields(rbml_w, variant, def_id); + encode_struct_fields(rbml_w, variant); encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(item)); // Encode inherent implementations for this structure. encode_inherent_implementations(ecx, rbml_w, def_id); + if !struct_def.is_struct() { + let ctor_did = ecx.tcx.map.local_def_id(struct_def.id()); + rbml_w.wr_tagged_u64(tag_items_data_item_struct_ctor, + def_to_u64(ctor_did)); + } + rbml_w.end_tag(); + for field in &variant.fields { + encode_field(ecx, rbml_w, field, index); + } + // If this is a tuple-like struct, encode the type of the constructor. - match struct_def.ctor_id { - Some(ctor_id) => { - encode_info_for_struct_ctor(ecx, rbml_w, item.ident.name, - ctor_id, index, def_id.node); - } - None => {} + if !struct_def.is_struct() { + encode_info_for_struct_ctor(ecx, rbml_w, item.name, struct_def.id(), index, item.id); } } - ast::ItemDefaultImpl(unsafety, _) => { - add_to_index(item, rbml_w, index); + hir::ItemDefaultImpl(unsafety, _) => { + index.record(def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); - encode_def_id(rbml_w, def_id); + encode_def_id_and_key(ecx, rbml_w, def_id); encode_family(rbml_w, 'd'); - encode_name(rbml_w, item.ident.name); + encode_name(rbml_w, item.name); encode_unsafety(rbml_w, unsafety); - let trait_ref = tcx.impl_trait_ref(DefId::local(item.id)).unwrap(); + let trait_ref = tcx.impl_trait_ref(ecx.tcx.map.local_def_id(item.id)).unwrap(); encode_trait_ref(rbml_w, ecx, trait_ref, tag_item_trait_ref); rbml_w.end_tag(); } - ast::ItemImpl(unsafety, polarity, _, _, ref ty, ref ast_items) => { + hir::ItemImpl(unsafety, polarity, _, _, _, ref ast_items) => { // We need to encode information about the default methods we // have inherited, so we drive this based on the impl structure. let impl_items = tcx.impl_items.borrow(); let items = impl_items.get(&def_id).unwrap(); - add_to_index(item, rbml_w, index); + index.record(def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); - encode_def_id(rbml_w, def_id); + encode_def_id_and_key(ecx, rbml_w, def_id); encode_family(rbml_w, 'i'); - encode_bounds_and_type_for_item(rbml_w, ecx, item.id); - encode_name(rbml_w, item.ident.name); + encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id); + encode_name(rbml_w, item.name); encode_attributes(rbml_w, &item.attrs); encode_unsafety(rbml_w, unsafety); encode_polarity(rbml_w, polarity); - match tcx.custom_coerce_unsized_kinds.borrow().get(&DefId::local(item.id)) { + match tcx.custom_coerce_unsized_kinds.borrow().get(&ecx.tcx.map.local_def_id(item.id)) { Some(&kind) => { rbml_w.start_tag(tag_impl_coerce_unsized_kind); kind.encode(rbml_w); @@ -1211,13 +1122,6 @@ fn encode_info_for_item(ecx: &EncodeContext, None => {} } - match ty.node { - ast::TyPath(None, ref path) if path.segments.len() == 1 => { - let name = path.segments.last().unwrap().identifier.name; - encode_impl_type_basename(rbml_w, name); - } - _ => {} - } for &item_def_id in items { rbml_w.start_tag(tag_item_impl_item); match item_def_id { @@ -1236,7 +1140,7 @@ fn encode_info_for_item(ecx: &EncodeContext, } rbml_w.end_tag(); } - if let Some(trait_ref) = tcx.impl_trait_ref(DefId::local(item.id)) { + if let Some(trait_ref) = tcx.impl_trait_ref(ecx.tcx.map.local_def_id(item.id)) { encode_trait_ref(rbml_w, ecx, trait_ref, tag_item_trait_ref); } encode_path(rbml_w, path.clone()); @@ -1255,15 +1159,11 @@ fn encode_info_for_item(ecx: &EncodeContext, None }; - index.push(IndexEntry { - node: trait_item_def_id.def_id().node, - pos: rbml_w.mark_stable_position(), - }); - match tcx.impl_or_trait_item(trait_item_def_id.def_id()) { ty::ConstTraitItem(ref associated_const) => { encode_info_for_associated_const(ecx, rbml_w, + index, &*associated_const, path.clone(), item.id, @@ -1272,6 +1172,7 @@ fn encode_info_for_item(ecx: &EncodeContext, ty::MethodTraitItem(ref method_type) => { encode_info_for_method(ecx, rbml_w, + index, &**method_type, path.clone(), false, @@ -1281,6 +1182,7 @@ fn encode_info_for_item(ecx: &EncodeContext, ty::TypeTraitItem(ref associated_type) => { encode_info_for_associated_type(ecx, rbml_w, + index, &**associated_type, path.clone(), item.id, @@ -1289,10 +1191,10 @@ fn encode_info_for_item(ecx: &EncodeContext, } } } - ast::ItemTrait(_, _, _, ref ms) => { - add_to_index(item, rbml_w, index); + hir::ItemTrait(_, _, _, ref ms) => { + index.record(def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); - encode_def_id(rbml_w, def_id); + encode_def_id_and_key(ecx, rbml_w, def_id); encode_family(rbml_w, 'I'); encode_item_variances(rbml_w, ecx, item.id); let trait_def = tcx.lookup_trait_def(def_id); @@ -1301,12 +1203,14 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_paren_sugar(rbml_w, trait_def.paren_sugar); encode_defaulted(rbml_w, tcx.trait_has_default_impl(def_id)); encode_associated_type_names(rbml_w, &trait_def.associated_type_names); - encode_generics(rbml_w, ecx, &trait_def.generics, &trait_predicates, + encode_generics(rbml_w, ecx, index, + &trait_def.generics, &trait_predicates, tag_item_generics); - encode_predicates(rbml_w, ecx, &tcx.lookup_super_predicates(def_id), + encode_predicates(rbml_w, ecx, index, + &tcx.lookup_super_predicates(def_id), tag_item_super_predicates); encode_trait_ref(rbml_w, ecx, trait_def.trait_ref, tag_item_trait_ref); - encode_name(rbml_w, item.ident.name); + encode_name(rbml_w, item.name); encode_attributes(rbml_w, &item.attrs); encode_visibility(rbml_w, vis); encode_stability(rbml_w, stab); @@ -1333,9 +1237,6 @@ fn encode_info_for_item(ecx: &EncodeContext, } encode_path(rbml_w, path.clone()); - // Encode the implementations of this trait. - encode_extension_implementations(ecx, rbml_w, def_id); - // Encode inherent implementations for this trait. encode_inherent_implementations(ecx, rbml_w, def_id); @@ -1346,11 +1247,7 @@ fn encode_info_for_item(ecx: &EncodeContext, for (i, &item_def_id) in r.iter().enumerate() { assert_eq!(item_def_id.def_id().krate, LOCAL_CRATE); - index.push(IndexEntry { - node: item_def_id.def_id().node, - pos: rbml_w.mark_stable_position(), - }); - + index.record(item_def_id.def_id(), rbml_w); rbml_w.start_tag(tag_items_data_item); encode_parent_item(rbml_w, def_id); @@ -1364,27 +1261,24 @@ fn encode_info_for_item(ecx: &EncodeContext, match trait_item_type { ty::ConstTraitItem(associated_const) => { encode_name(rbml_w, associated_const.name); - encode_def_id(rbml_w, associated_const.def_id); + encode_def_id_and_key(ecx, rbml_w, associated_const.def_id); encode_visibility(rbml_w, associated_const.vis); - encode_provided_source(rbml_w, associated_const.default); - let elem = ast_map::PathName(associated_const.name); encode_path(rbml_w, path.clone().chain(Some(elem))); - encode_item_sort(rbml_w, 'C'); encode_family(rbml_w, 'C'); - encode_bounds_and_type_for_item(rbml_w, ecx, - associated_const.def_id.local_id()); + encode_bounds_and_type_for_item(rbml_w, ecx, index, + ecx.local_id(associated_const.def_id)); is_nonstatic_method = false; } ty::MethodTraitItem(method_ty) => { let method_def_id = item_def_id.def_id(); - encode_method_ty_fields(ecx, rbml_w, &*method_ty); + encode_method_ty_fields(ecx, rbml_w, index, &*method_ty); let elem = ast_map::PathName(method_ty.name); encode_path(rbml_w, @@ -1400,14 +1294,15 @@ fn encode_info_for_item(ecx: &EncodeContext, METHOD_FAMILY); } } - encode_bounds_and_type_for_item(rbml_w, ecx, method_def_id.local_id()); + encode_bounds_and_type_for_item(rbml_w, ecx, index, + ecx.local_id(method_def_id)); is_nonstatic_method = method_ty.explicit_self != ty::StaticExplicitSelfCategory; } ty::TypeTraitItem(associated_type) => { encode_name(rbml_w, associated_type.name); - encode_def_id(rbml_w, associated_type.def_id); + encode_def_id_and_key(ecx, rbml_w, associated_type.def_id); let elem = ast_map::PathName(associated_type.name); encode_path(rbml_w, @@ -1424,23 +1319,27 @@ fn encode_info_for_item(ecx: &EncodeContext, } } - encode_parent_sort(rbml_w, 't'); - let trait_item = &*ms[i]; encode_attributes(rbml_w, &trait_item.attrs); match trait_item.node { - ast::ConstTraitItem(_, _) => { + hir::ConstTraitItem(_, ref default) => { + if default.is_some() { + encode_item_sort(rbml_w, 'C'); + } else { + encode_item_sort(rbml_w, 'c'); + } + encode_inlined_item(ecx, rbml_w, InlinedItemRef::TraitItem(def_id, trait_item)); } - ast::MethodTraitItem(ref sig, ref body) => { + hir::MethodTraitItem(ref sig, ref body) => { // If this is a static method, we've already // encoded this. if is_nonstatic_method { // FIXME: I feel like there is something funny // going on. - encode_bounds_and_type_for_item(rbml_w, ecx, - item_def_id.def_id().local_id()); + encode_bounds_and_type_for_item(rbml_w, ecx, index, + ecx.local_id(item_def_id.def_id())); } if body.is_some() { @@ -1453,82 +1352,107 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_method_argument_names(rbml_w, &sig.decl); } - ast::TypeTraitItem(..) => {} + hir::TypeTraitItem(..) => {} } rbml_w.end_tag(); } } - ast::ItemExternCrate(_) | ast::ItemUse(_) => { + hir::ItemExternCrate(_) | hir::ItemUse(_) => { // these are encoded separately } } } -fn encode_info_for_foreign_item(ecx: &EncodeContext, - rbml_w: &mut Encoder, - nitem: &ast::ForeignItem, - index: &mut Vec, - path: PathElems, - abi: abi::Abi) { - index.push(IndexEntry { - node: nitem.id, - pos: rbml_w.mark_stable_position(), - }); +fn encode_info_for_foreign_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, + rbml_w: &mut Encoder, + nitem: &hir::ForeignItem, + index: &mut CrateIndex<'tcx>, + path: PathElems, + abi: abi::Abi) { + let def_id = ecx.tcx.map.local_def_id(nitem.id); + index.record(def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); - encode_def_id(rbml_w, DefId::local(nitem.id)); + encode_def_id_and_key(ecx, rbml_w, def_id); encode_visibility(rbml_w, nitem.vis); match nitem.node { - ast::ForeignItemFn(ref fndecl, _) => { + hir::ForeignItemFn(ref fndecl, _) => { encode_family(rbml_w, FN_FAMILY); - encode_bounds_and_type_for_item(rbml_w, ecx, nitem.id); - encode_name(rbml_w, nitem.ident.name); + encode_bounds_and_type_for_item(rbml_w, ecx, index, nitem.id); + encode_name(rbml_w, nitem.name); if abi == abi::RustIntrinsic || abi == abi::PlatformIntrinsic { encode_inlined_item(ecx, rbml_w, InlinedItemRef::Foreign(nitem)); } encode_attributes(rbml_w, &*nitem.attrs); - let stab = stability::lookup(ecx.tcx, DefId::local(nitem.id)); + let stab = stability::lookup(ecx.tcx, ecx.tcx.map.local_def_id(nitem.id)); encode_stability(rbml_w, stab); encode_symbol(ecx, rbml_w, nitem.id); encode_method_argument_names(rbml_w, &*fndecl); } - ast::ForeignItemStatic(_, mutbl) => { + hir::ForeignItemStatic(_, mutbl) => { if mutbl { encode_family(rbml_w, 'b'); } else { encode_family(rbml_w, 'c'); } - encode_bounds_and_type_for_item(rbml_w, ecx, nitem.id); + encode_bounds_and_type_for_item(rbml_w, ecx, index, nitem.id); encode_attributes(rbml_w, &*nitem.attrs); - let stab = stability::lookup(ecx.tcx, DefId::local(nitem.id)); + let stab = stability::lookup(ecx.tcx, ecx.tcx.map.local_def_id(nitem.id)); encode_stability(rbml_w, stab); encode_symbol(ecx, rbml_w, nitem.id); - encode_name(rbml_w, nitem.ident.name); + encode_name(rbml_w, nitem.name); } } encode_path(rbml_w, path); rbml_w.end_tag(); } -fn my_visit_expr(_e: &ast::Expr) { } - -fn my_visit_item(i: &ast::Item, +fn my_visit_expr(expr: &hir::Expr, rbml_w: &mut Encoder, ecx: &EncodeContext, - index: &mut Vec) { + index: &mut CrateIndex) { + match expr.node { + hir::ExprClosure(..) => { + let def_id = ecx.tcx.map.local_def_id(expr.id); + + index.record(def_id, rbml_w); + + rbml_w.start_tag(tag_items_data_item); + encode_def_id_and_key(ecx, rbml_w, def_id); + + rbml_w.start_tag(tag_items_closure_ty); + write_closure_type(ecx, rbml_w, &ecx.tcx.tables.borrow().closure_tys[&def_id]); + rbml_w.end_tag(); + + rbml_w.start_tag(tag_items_closure_kind); + ecx.tcx.closure_kind(def_id).encode(rbml_w).unwrap(); + rbml_w.end_tag(); + + ecx.tcx.map.with_path(expr.id, |path| encode_path(rbml_w, path)); + + rbml_w.end_tag(); + } + _ => { } + } +} + +fn my_visit_item<'a, 'tcx>(i: &hir::Item, + rbml_w: &mut Encoder, + ecx: &EncodeContext<'a, 'tcx>, + index: &mut CrateIndex<'tcx>) { ecx.tcx.map.with_path(i.id, |path| { encode_info_for_item(ecx, rbml_w, i, index, path, i.vis); }); } -fn my_visit_foreign_item(ni: &ast::ForeignItem, - rbml_w: &mut Encoder, - ecx: &EncodeContext, - index: &mut Vec) { +fn my_visit_foreign_item<'a, 'tcx>(ni: &hir::ForeignItem, + rbml_w: &mut Encoder, + ecx: &EncodeContext<'a, 'tcx>, + index: &mut CrateIndex<'tcx>) { debug!("writing foreign item {}::{}", ecx.tcx.map.path_to_string(ni.id), - ni.ident); + ni.name); let abi = ecx.tcx.map.get_foreign_abi(ni.id); ecx.tcx.map.with_path(ni.id, |path| { @@ -1541,40 +1465,35 @@ fn my_visit_foreign_item(ni: &ast::ForeignItem, struct EncodeVisitor<'a, 'b:'a, 'c:'a, 'tcx:'c> { rbml_w_for_visit_item: &'a mut Encoder<'b>, ecx: &'a EncodeContext<'c,'tcx>, - index: &'a mut Vec, + index: &'a mut CrateIndex<'tcx>, } impl<'a, 'b, 'c, 'tcx, 'v> Visitor<'v> for EncodeVisitor<'a, 'b, 'c, 'tcx> { - fn visit_expr(&mut self, ex: &ast::Expr) { + fn visit_expr(&mut self, ex: &hir::Expr) { visit::walk_expr(self, ex); - my_visit_expr(ex); + my_visit_expr(ex, self.rbml_w_for_visit_item, self.ecx, self.index); } - fn visit_item(&mut self, i: &ast::Item) { + fn visit_item(&mut self, i: &hir::Item) { visit::walk_item(self, i); - my_visit_item(i, - self.rbml_w_for_visit_item, - self.ecx, - self.index); + my_visit_item(i, self.rbml_w_for_visit_item, self.ecx, self.index); } - fn visit_foreign_item(&mut self, ni: &ast::ForeignItem) { + fn visit_foreign_item(&mut self, ni: &hir::ForeignItem) { visit::walk_foreign_item(self, ni); - my_visit_foreign_item(ni, - self.rbml_w_for_visit_item, - self.ecx, - self.index); + my_visit_foreign_item(ni, self.rbml_w_for_visit_item, self.ecx, self.index); } } -fn encode_info_for_items(ecx: &EncodeContext, - rbml_w: &mut Encoder, - krate: &ast::Crate) - -> Vec { - let mut index = Vec::new(); +fn encode_info_for_items<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, + rbml_w: &mut Encoder, + krate: &hir::Crate) + -> CrateIndex<'tcx> { + let mut index = CrateIndex { + items: IndexData::new(ecx.tcx.map.num_local_def_ids()), + xrefs: FnvHashMap() + }; rbml_w.start_tag(tag_items_data); - index.push(IndexEntry { - node: CRATE_NODE_ID, - pos: rbml_w.mark_stable_position(), - }); + + index.record(DefId::local(CRATE_DEF_INDEX), rbml_w); encode_info_for_mod(ecx, rbml_w, &krate.module, @@ -1582,7 +1501,7 @@ fn encode_info_for_items(ecx: &EncodeContext, CRATE_NODE_ID, [].iter().cloned().chain(LinkedPath::empty()), syntax::parse::token::special_idents::invalid.name, - ast::Public); + hir::Public); visit::walk_crate(&mut EncodeVisitor { index: &mut index, @@ -1594,13 +1513,9 @@ fn encode_info_for_items(ecx: &EncodeContext, index } - - - -fn encode_index(rbml_w: &mut Encoder, index: Vec) -{ +fn encode_item_index(rbml_w: &mut Encoder, index: IndexData) { rbml_w.start_tag(tag_index); - index::write_index(index, rbml_w.writer); + index.write_index(rbml_w.writer); rbml_w.end_tag(); } @@ -1644,10 +1559,10 @@ fn encode_attributes(rbml_w: &mut Encoder, attrs: &[ast::Attribute]) { rbml_w.end_tag(); } -fn encode_unsafety(rbml_w: &mut Encoder, unsafety: ast::Unsafety) { +fn encode_unsafety(rbml_w: &mut Encoder, unsafety: hir::Unsafety) { let byte: u8 = match unsafety { - ast::Unsafety::Normal => 0, - ast::Unsafety::Unsafe => 1, + hir::Unsafety::Normal => 0, + hir::Unsafety::Unsafe => 1, }; rbml_w.wr_tagged_u8(tag_unsafety, byte); } @@ -1670,10 +1585,10 @@ fn encode_associated_type_names(rbml_w: &mut Encoder, names: &[Name]) { rbml_w.end_tag(); } -fn encode_polarity(rbml_w: &mut Encoder, polarity: ast::ImplPolarity) { +fn encode_polarity(rbml_w: &mut Encoder, polarity: hir::ImplPolarity) { let byte: u8 = match polarity { - ast::ImplPolarity::Positive => 0, - ast::ImplPolarity::Negative => 1, + hir::ImplPolarity::Positive => 0, + hir::ImplPolarity::Negative => 1, }; rbml_w.wr_tagged_u8(tag_polarity, byte); } @@ -1714,12 +1629,12 @@ fn encode_crate_deps(rbml_w: &mut Encoder, cstore: &cstore::CStore) { fn encode_lang_items(ecx: &EncodeContext, rbml_w: &mut Encoder) { rbml_w.start_tag(tag_lang_items); - for (i, &def_id) in ecx.tcx.lang_items.items() { - if let Some(id) = def_id { - if id.is_local() { + for (i, &opt_def_id) in ecx.tcx.lang_items.items() { + if let Some(def_id) = opt_def_id { + if def_id.is_local() { rbml_w.start_tag(tag_lang_items_item); rbml_w.wr_tagged_u32(tag_lang_items_item_id, i as u32); - rbml_w.wr_tagged_u32(tag_lang_items_item_node_id, id.node as u32); + rbml_w.wr_tagged_u32(tag_lang_items_item_index, def_id.index.as_u32()); rbml_w.end_tag(); } } @@ -1753,7 +1668,10 @@ fn encode_native_libraries(ecx: &EncodeContext, rbml_w: &mut Encoder) { fn encode_plugin_registrar_fn(ecx: &EncodeContext, rbml_w: &mut Encoder) { match ecx.tcx.sess.plugin_registrar_fn.get() { - Some(id) => { rbml_w.wr_tagged_u32(tag_plugin_registrar_fn, id); } + Some(id) => { + let def_id = ecx.tcx.map.local_def_id(id); + rbml_w.wr_tagged_u32(tag_plugin_registrar_fn, def_id.index.as_u32()); + } None => {} } } @@ -1782,12 +1700,12 @@ fn encode_codemap(ecx: &EncodeContext, rbml_w: &mut Encoder) { /// Serialize the text of the exported macros fn encode_macro_defs(rbml_w: &mut Encoder, - krate: &ast::Crate) { + krate: &hir::Crate) { rbml_w.start_tag(tag_macro_defs); for def in &krate.exported_macros { rbml_w.start_tag(tag_macro_def); - encode_name(rbml_w, def.ident.name); + encode_name(rbml_w, def.name); encode_attributes(rbml_w, &def.attrs); rbml_w.wr_tagged_str(tag_macro_def_body, @@ -1798,97 +1716,90 @@ fn encode_macro_defs(rbml_w: &mut Encoder, rbml_w.end_tag(); } -fn encode_struct_field_attrs(rbml_w: &mut Encoder, krate: &ast::Crate) { - struct StructFieldVisitor<'a, 'b:'a> { - rbml_w: &'a mut Encoder<'b>, +fn encode_struct_field_attrs(ecx: &EncodeContext, + rbml_w: &mut Encoder, + krate: &hir::Crate) { + struct StructFieldVisitor<'a, 'b:'a, 'c:'a, 'tcx:'b> { + ecx: &'a EncodeContext<'b, 'tcx>, + rbml_w: &'a mut Encoder<'c>, } - impl<'a, 'b, 'v> Visitor<'v> for StructFieldVisitor<'a, 'b> { - fn visit_struct_field(&mut self, field: &ast::StructField) { + impl<'a, 'b, 'c, 'tcx, 'v> Visitor<'v> for StructFieldVisitor<'a, 'b, 'c, 'tcx> { + fn visit_struct_field(&mut self, field: &hir::StructField) { self.rbml_w.start_tag(tag_struct_field); - self.rbml_w.wr_tagged_u32(tag_struct_field_id, field.node.id); + let def_id = self.ecx.tcx.map.local_def_id(field.node.id); + encode_def_id(self.rbml_w, def_id); encode_attributes(self.rbml_w, &field.node.attrs); self.rbml_w.end_tag(); } } rbml_w.start_tag(tag_struct_fields); - visit::walk_crate(&mut StructFieldVisitor { - rbml_w: rbml_w - }, krate); + visit::walk_crate(&mut StructFieldVisitor { ecx: ecx, rbml_w: rbml_w }, krate); rbml_w.end_tag(); } -struct ImplVisitor<'a, 'b:'a, 'c:'a, 'tcx:'b> { - ecx: &'a EncodeContext<'b, 'tcx>, - rbml_w: &'a mut Encoder<'c>, +struct ImplVisitor<'a, 'tcx:'a> { + tcx: &'a ty::ctxt<'tcx>, + impls: FnvHashMap> } -impl<'a, 'b, 'c, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'b, 'c, 'tcx> { - fn visit_item(&mut self, item: &ast::Item) { - if let ast::ItemImpl(_, _, _, Some(ref trait_ref), _, _) = item.node { - let def_id = self.ecx.tcx.def_map.borrow().get(&trait_ref.ref_id).unwrap().def_id(); - - // Load eagerly if this is an implementation of the Drop trait - // or if the trait is not defined in this crate. - if Some(def_id) == self.ecx.tcx.lang_items.drop_trait() || - def_id.krate != LOCAL_CRATE { - self.rbml_w.start_tag(tag_impls_impl); - encode_def_id(self.rbml_w, DefId::local(item.id)); - self.rbml_w.wr_tagged_u64(tag_impls_impl_trait_def_id, def_to_u64(def_id)); - self.rbml_w.end_tag(); +impl<'a, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'tcx> { + fn visit_item(&mut self, item: &hir::Item) { + 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) + .or_insert(vec![]) + .push(impl_id); } } visit::walk_item(self, item); } } -/// Encodes implementations that are eagerly loaded. -/// -/// None of this is necessary in theory; we can load all implementations -/// lazily. However, in two cases the optimizations to lazily load -/// implementations are not yet implemented. These two cases, which require us -/// to load implementations eagerly, are: -/// -/// * Destructors (implementations of the Drop trait). -/// -/// * Implementations of traits not defined in this crate. +/// Encodes an index, mapping each trait to its (local) implementations. fn encode_impls<'a>(ecx: &'a EncodeContext, - krate: &ast::Crate, + krate: &hir::Crate, rbml_w: &'a mut Encoder) { - rbml_w.start_tag(tag_impls); + let mut visitor = ImplVisitor { + tcx: ecx.tcx, + impls: FnvHashMap() + }; + visit::walk_crate(&mut visitor, krate); - { - let mut visitor = ImplVisitor { - ecx: ecx, - rbml_w: rbml_w, - }; - visit::walk_crate(&mut visitor, krate); + rbml_w.start_tag(tag_impls); + for (trait_, trait_impls) in visitor.impls { + rbml_w.start_tag(tag_impls_trait); + encode_def_id(rbml_w, trait_); + for impl_ in trait_impls { + rbml_w.wr_tagged_u64(tag_impls_trait_impl, def_to_u64(impl_)); + } + rbml_w.end_tag(); } - rbml_w.end_tag(); } fn encode_misc_info(ecx: &EncodeContext, - krate: &ast::Crate, + krate: &hir::Crate, rbml_w: &mut Encoder) { rbml_w.start_tag(tag_misc_info); rbml_w.start_tag(tag_misc_info_crate_items); for item in &krate.module.items { rbml_w.wr_tagged_u64(tag_mod_child, - def_to_u64(DefId::local(item.id))); + def_to_u64(ecx.tcx.map.local_def_id(item.id))); each_auxiliary_node_id(&**item, |auxiliary_node_id| { rbml_w.wr_tagged_u64(tag_mod_child, - def_to_u64(DefId::local(auxiliary_node_id))); + def_to_u64(ecx.tcx.map.local_def_id(auxiliary_node_id))); true }); } // Encode reexports for the root module. - encode_reexports(ecx, rbml_w, 0, [].iter().cloned().chain(LinkedPath::empty())); + encode_reexports(ecx, rbml_w, 0); rbml_w.end_tag(); rbml_w.end_tag(); @@ -1902,8 +1813,9 @@ fn encode_misc_info(ecx: &EncodeContext, // definition (as that's not defined in this crate). fn encode_reachable(ecx: &EncodeContext, rbml_w: &mut Encoder) { rbml_w.start_tag(tag_reachable_ids); - for id in ecx.reachable { - rbml_w.wr_tagged_u32(tag_reachable_id, *id); + for &id in ecx.reachable { + let def_id = ecx.tcx.map.local_def_id(id); + rbml_w.wr_tagged_u32(tag_reachable_id, def_id.index.as_u32()); } rbml_w.end_tag(); } @@ -1923,6 +1835,10 @@ fn encode_hash(rbml_w: &mut Encoder, hash: &Svh) { rbml_w.wr_tagged_str(tag_crate_hash, hash.as_str()); } +fn encode_rustc_version(rbml_w: &mut Encoder) { + rbml_w.wr_tagged_str(tag_rustc_version, &rustc_version()); +} + fn encode_crate_name(rbml_w: &mut Encoder, crate_name: &str) { rbml_w.wr_tagged_str(tag_crate_crate_name, crate_name); } @@ -1956,7 +1872,7 @@ fn encode_dylib_dependency_formats(rbml_w: &mut Encoder, ecx: &EncodeContext) { #[allow(non_upper_case_globals)] pub const metadata_encoding_version : &'static [u8] = &[b'r', b'u', b's', b't', 0, 0, 0, 2 ]; -pub fn encode_metadata(parms: EncodeParams, krate: &ast::Crate) -> Vec { +pub fn encode_metadata(parms: EncodeParams, krate: &hir::Crate) -> Vec { let mut wr = Cursor::new(Vec::new()); encode_metadata_inner(&mut wr, parms, krate); @@ -1995,7 +1911,7 @@ pub fn encode_metadata(parms: EncodeParams, krate: &ast::Crate) -> Vec { fn encode_metadata_inner(wr: &mut Cursor>, parms: EncodeParams, - krate: &ast::Crate) { + krate: &hir::Crate) { struct Stats { attr_bytes: u64, dep_bytes: u64, @@ -2008,6 +1924,7 @@ fn encode_metadata_inner(wr: &mut Cursor>, misc_bytes: u64, item_bytes: u64, index_bytes: u64, + xref_bytes: u64, zero_bytes: u64, total_bytes: u64, } @@ -2023,6 +1940,7 @@ fn encode_metadata_inner(wr: &mut Cursor>, misc_bytes: 0, item_bytes: 0, index_bytes: 0, + xref_bytes: 0, zero_bytes: 0, total_bytes: 0, }; @@ -2051,6 +1969,7 @@ fn encode_metadata_inner(wr: &mut Cursor>, let mut rbml_w = Encoder::new(wr); + encode_rustc_version(&mut rbml_w); encode_crate_name(&mut rbml_w, &ecx.link_meta.crate_name); encode_crate_triple(&mut rbml_w, &tcx.sess.opts.target_triple); encode_hash(&mut rbml_w, &ecx.link_meta.crate_hash); @@ -2103,15 +2022,19 @@ fn encode_metadata_inner(wr: &mut Cursor>, // Encode and index the items. rbml_w.start_tag(tag_items); i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); - let items_index = encode_info_for_items(&ecx, &mut rbml_w, krate); + let index = encode_info_for_items(&ecx, &mut rbml_w, krate); stats.item_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; rbml_w.end_tag(); i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); - encode_index(&mut rbml_w, items_index); + encode_item_index(&mut rbml_w, index.items); stats.index_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; - encode_struct_field_attrs(&mut rbml_w, krate); + i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); + encode_xrefs(&ecx, &mut rbml_w, index.xrefs); + stats.xref_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; + + encode_struct_field_attrs(&ecx, &mut rbml_w, krate); stats.total_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); @@ -2134,13 +2057,14 @@ fn encode_metadata_inner(wr: &mut Cursor>, println!(" misc bytes: {}", stats.misc_bytes); println!(" item bytes: {}", stats.item_bytes); println!(" index bytes: {}", stats.index_bytes); + println!(" xref bytes: {}", stats.xref_bytes); println!(" zero bytes: {}", stats.zero_bytes); println!(" total bytes: {}", stats.total_bytes); } } // Get the encoded string for a type -pub fn encoded_ty<'tcx>(tcx: &ty::ctxt<'tcx>, t: Ty<'tcx>) -> String { +pub fn encoded_ty<'tcx>(tcx: &ty::ctxt<'tcx>, t: Ty<'tcx>) -> Vec { let mut wr = Cursor::new(Vec::new()); tyencode::enc_ty(&mut Encoder::new(&mut wr), &tyencode::ctxt { diag: tcx.sess.diagnostic(), @@ -2148,5 +2072,5 @@ pub fn encoded_ty<'tcx>(tcx: &ty::ctxt<'tcx>, t: Ty<'tcx>) -> String { tcx: tcx, abbrevs: &RefCell::new(FnvHashMap()) }, t); - String::from_utf8(wr.into_inner()).unwrap() + wr.into_inner() } diff --git a/src/librustc/metadata/index.rs b/src/librustc/metadata/index.rs index b02a9022a7..60bbdaddd7 100644 --- a/src/librustc/metadata/index.rs +++ b/src/librustc/metadata/index.rs @@ -8,145 +8,126 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use middle::def_id::{DefId, DefIndex}; +use rbml; use std::io::{Cursor, Write}; use std::slice; use std::u32; -use syntax::ast::NodeId; -#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord)] -pub struct IndexEntry { - pub node: NodeId, - pub pos: u64 -} - -#[derive(Debug)] -pub struct IndexArrayEntry { - bits: u32, - first_pos: u32 +/// As part of the metadata, we generate an index that stores, for +/// each DefIndex, the position of the corresponding RBML document (if +/// any). This is just a big `[u32]` slice, where an entry of +/// `u32::MAX` indicates that there is no RBML document. This little +/// struct just stores the offsets within the metadata of the start +/// and end of this slice. These are actually part of an RBML +/// document, but for looking things up in the metadata, we just +/// discard the RBML positioning and jump directly to the data. +pub struct Index { + data_start: usize, + data_end: usize, } -impl IndexArrayEntry { - fn encode_to(&self, b: &mut W) { - write_be_u32(b, self.bits); - write_be_u32(b, self.first_pos); +impl Index { + /// Given the RBML doc representing the index, save the offests + /// for later. + pub fn from_rbml(index: rbml::Doc) -> Index { + Index { data_start: index.start, data_end: index.end } } - fn decode_from(b: &[u32]) -> Self { - IndexArrayEntry { - bits: b[0].to_be(), - first_pos: b[1].to_be() + /// Given the metadata, extract out the offset of a particular + /// DefIndex (if any). + #[inline(never)] + pub fn lookup_item(&self, bytes: &[u8], def_index: DefIndex) -> Option { + let words = bytes_to_words(&bytes[self.data_start..self.data_end]); + let index = def_index.as_usize(); + + debug!("lookup_item: index={:?} words.len={:?}", + index, words.len()); + + let position = u32::from_be(words[index]); + if position == u32::MAX { + debug!("lookup_item: position=u32::MAX"); + None + } else { + debug!("lookup_item: position={:?}", position); + Some(position) } } } -/// The Item Index -/// -/// This index maps the NodeId of each item to its location in the -/// metadata. -/// -/// The index is a sparse bit-vector consisting of a index-array -/// and a position-array. Each entry in the index-array handles 32 nodes. -/// The first word is a bit-array consisting of the nodes that hold items, -/// the second is the index of the first of the items in the position-array. -/// If there is a large set of non-item trailing nodes, they can be omitted -/// from the index-array. -/// -/// The index is serialized as an array of big-endian 32-bit words. -/// The first word is the number of items in the position-array. -/// Then, for each item, its position in the metadata follows. -/// After that the index-array is stored. -/// -/// struct index { -/// u32 item_count; -/// u32 items[self.item_count]; -/// struct { u32 bits; u32 offset; } positions[..]; -/// } -pub struct Index { - position_start: usize, - index_start: usize, - index_end: usize, +/// While we are generating the metadata, we also track the position +/// of each DefIndex. It is not required that all definitions appear +/// in the metadata, nor that they are serialized in order, and +/// therefore we first allocate the vector here and fill it with +/// `u32::MAX`. Whenever an index is visited, we fill in the +/// appropriate spot by calling `record_position`. We should never +/// visit the same index twice. +pub struct IndexData { + positions: Vec, } -pub fn write_index(mut entries: Vec, buf: &mut Cursor>) { - assert!(entries.len() < u32::MAX as usize); - entries.sort(); +impl IndexData { + pub fn new(max_index: usize) -> IndexData { + IndexData { + positions: vec![u32::MAX; max_index] + } + } + + pub fn record(&mut self, def_id: DefId, position: u64) { + assert!(def_id.is_local()); + self.record_index(def_id.index, position) + } + + pub fn record_index(&mut self, item: DefIndex, position: u64) { + let item = item.as_usize(); + + assert!(position < (u32::MAX as u64)); + let position = position as u32; - let mut last_entry = IndexArrayEntry { bits: 0, first_pos: 0 }; + assert!(self.positions[item] == u32::MAX, + "recorded position for item {:?} twice, first at {:?} and now at {:?}", + item, self.positions[item], position); - write_be_u32(buf, entries.len() as u32); - for &IndexEntry { pos, .. } in &entries { - assert!(pos < u32::MAX as u64); - write_be_u32(buf, pos as u32); + self.positions[item] = position; } - let mut pos_in_index_array = 0; - for (i, &IndexEntry { node, .. }) in entries.iter().enumerate() { - let (x, s) = (node / 32 as u32, node % 32 as u32); - while x > pos_in_index_array { - pos_in_index_array += 1; - last_entry.encode_to(buf); - last_entry = IndexArrayEntry { bits: 0, first_pos: i as u32 }; + pub fn write_index(&self, buf: &mut Cursor>) { + for &position in &self.positions { + write_be_u32(buf, position); } - last_entry.bits |= 1< Option { - let ix = (i as usize)*2; - if ix >= index.len() { - None - } else { - Some(IndexArrayEntry::decode_from(&index[ix..ix+2])) +impl DenseIndex { + pub fn lookup(&self, buf: &[u8], ix: u32) -> Option { + let data = bytes_to_words(&buf[self.start..self.end]); + data.get(ix as usize).map(|d| u32::from_be(*d)) + } + pub fn from_buf(buf: &[u8], start: usize, end: usize) -> Self { + assert!((end-start)%4 == 0 && start <= end && end <= buf.len()); + DenseIndex { + start: start, + end: end } } +} - fn item_from_pos(&self, positions: &[u32], pos: u32) -> u32 { - positions[pos as usize].to_be() - } +pub fn write_dense_index(entries: Vec, buf: &mut Cursor>) { + let elen = entries.len(); + assert!(elen < u32::MAX as usize); - #[inline(never)] - pub fn lookup_item(&self, buf: &[u8], node: NodeId) -> Option { - let index = bytes_to_words(&buf[self.index_start..self.index_end]); - let positions = bytes_to_words(&buf[self.position_start..self.index_start]); - let (x, s) = (node / 32 as u32, node % 32 as u32); - let result = match self.lookup_index(index, x) { - Some(IndexArrayEntry { bits, first_pos }) => { - let bit = 1< None // trailing zero - }; - debug!("lookup_item({:?}) = {:?}", node, result); - result + for entry in entries { + write_be_u32(buf, entry); } - pub fn from_buf(buf: &[u8], start: usize, end: usize) -> Self { - let buf = bytes_to_words(&buf[start..end]); - let position_count = buf[0].to_be() as usize; - let position_len = position_count*4; - info!("loaded index - position: {}-{}-{}", start, start+position_len, end); - debug!("index contents are {:?}", - buf.iter().map(|b| format!("{:08x}", b)).collect::>().concat()); - assert!(end-4-start >= position_len); - assert_eq!((end-4-start-position_len)%8, 0); - Index { - position_start: start+4, - index_start: start+position_len+4, - index_end: end - } - } + info!("write_dense_index: {} entries", elen); } fn write_be_u32(w: &mut W, u: u32) { @@ -162,47 +143,3 @@ fn bytes_to_words(b: &[u8]) -> &[u32] { assert!(b.len() % 4 == 0); unsafe { slice::from_raw_parts(b.as_ptr() as *const u32, b.len()/4) } } - -#[test] -fn test_index() { - let entries = vec![ - IndexEntry { node: 0, pos: 17 }, - IndexEntry { node: 31, pos: 29 }, - IndexEntry { node: 32, pos: 1175 }, - IndexEntry { node: 191, pos: 21 }, - IndexEntry { node: 128, pos: 34 }, - IndexEntry { node: 145, pos: 70 }, - IndexEntry { node: 305, pos: 93214 }, - IndexEntry { node: 138, pos: 64 }, - IndexEntry { node: 129, pos: 53 }, - IndexEntry { node: 192, pos: 33334 }, - IndexEntry { node: 200, pos: 80123 }, - ]; - let mut c = Cursor::new(vec![]); - write_index(entries.clone(), &mut c); - let mut buf = c.into_inner(); - let expected: &[u8] = &[ - 0, 0, 0, 11, // # entries - // values: - 0,0,0,17, 0,0,0,29, 0,0,4,151, 0,0,0,34, - 0,0,0,53, 0,0,0,64, 0,0,0,70, 0,0,0,21, - 0,0,130,54, 0,1,56,251, 0,1,108,30, - // index: - 128,0,0,1,0,0,0,0, 0,0,0,1,0,0,0,2, - 0,0,0,0,0,0,0,3, 0,0,0,0,0,0,0,3, - 0,2,4,3,0,0,0,3, 128,0,0,0,0,0,0,7, - 0,0,1,1,0,0,0,8, 0,0,0,0,0,0,0,10, - 0,0,0,0,0,0,0,10, 0,2,0,0,0,0,0,10 - ]; - assert_eq!(buf, expected); - - // insert some junk padding - for i in 0..17 { buf.insert(0, i); buf.push(i) } - let index = Index::from_buf(&buf, 17, buf.len()-17); - - // test round-trip - for i in 0..4096 { - assert_eq!(index.lookup_item(&buf, i), - entries.iter().find(|e| e.node == i).map(|n| n.pos as u32)); - } -} diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs index 2f481f70aa..77092d0802 100644 --- a/src/librustc/metadata/loader.rs +++ b/src/librustc/metadata/loader.rs @@ -308,23 +308,28 @@ impl<'a> Context<'a> { } pub fn report_load_errs(&mut self) { - let message = if !self.rejected_via_hash.is_empty() { - format!("found possibly newer version of crate `{}`", - self.ident) + let add = match self.root { + &None => String::new(), + &Some(ref r) => format!(" which `{}` depends on", + r.ident) + }; + if !self.rejected_via_hash.is_empty() { + span_err!(self.sess, self.span, E0460, + "found possibly newer version of crate `{}`{}", + self.ident, add); } else if !self.rejected_via_triple.is_empty() { - format!("couldn't find crate `{}` with expected target triple {}", - self.ident, self.triple) + span_err!(self.sess, self.span, E0461, + "couldn't find crate `{}` with expected target triple {}{}", + self.ident, self.triple, add); } else if !self.rejected_via_kind.is_empty() { - format!("found staticlib `{}` instead of rlib or dylib", self.ident) + span_err!(self.sess, self.span, E0462, + "found staticlib `{}` instead of rlib or dylib{}", + self.ident, add); } else { - format!("can't find crate for `{}`", self.ident) - }; - let message = match self.root { - &None => message, - &Some(ref r) => format!("{} which `{}` depends on", - message, r.ident) - }; - self.sess.span_err(self.span, &message[..]); + span_err!(self.sess, self.span, E0463, + "can't find crate for `{}`{}", + self.ident, add); + } if !self.rejected_via_triple.is_empty() { let mismatches = self.rejected_via_triple.iter(); @@ -473,9 +478,9 @@ impl<'a> Context<'a> { 0 => None, 1 => Some(libraries.into_iter().next().unwrap()), _ => { - self.sess.span_err(self.span, - &format!("multiple matching crates for `{}`", - self.crate_name)); + span_err!(self.sess, self.span, E0464, + "multiple matching crates for `{}`", + self.crate_name); self.sess.note("candidates:"); for lib in &libraries { match lib.dylib { @@ -543,11 +548,9 @@ impl<'a> Context<'a> { } }; if ret.is_some() { - self.sess.span_err(self.span, - &format!("multiple {} candidates for `{}` \ - found", - flavor, - self.crate_name)); + span_err!(self.sess, self.span, E0465, + "multiple {} candidates for `{}` found", + flavor, self.crate_name); self.sess.span_note(self.span, &format!(r"candidate #1: {}", ret.as_ref().unwrap().0 @@ -723,7 +726,7 @@ fn get_metadata_section(target: &Target, filename: &Path) ret = Some(get_metadata_section_imp(target, filename)); }); info!("reading {:?} => {:?}", filename.file_name().unwrap(), dur); - return ret.unwrap();; + ret.unwrap() } fn get_metadata_section_imp(target: &Target, filename: &Path) diff --git a/src/librustc/metadata/macro_import.rs b/src/librustc/metadata/macro_import.rs index 527f5919e2..ca5999afbd 100644 --- a/src/librustc/metadata/macro_import.rs +++ b/src/librustc/metadata/macro_import.rs @@ -21,7 +21,6 @@ use syntax::attr; use syntax::visit; use syntax::visit::Visitor; use syntax::attr::AttrMetaMethods; -use rustc_front::attr::AttrMetaMethods as FrontAttrMetaMethods; struct MacroLoader<'a> { sess: &'a Session, @@ -41,6 +40,10 @@ impl<'a> MacroLoader<'a> { } } +pub fn call_bad_macro_reexport(a: &Session, b: Span) { + span_err!(a, b, E0467, "bad macro reexport"); +} + /// Read exported macros. pub fn read_macro_defs(sess: &Session, krate: &ast::Crate) -> Vec { let mut loader = MacroLoader::new(sess); @@ -91,7 +94,7 @@ impl<'a, 'v> Visitor<'v> for MacroLoader<'a> { if let ast::MetaWord(ref name) = attr.node { sel.insert(name.clone(), attr.span); } else { - self.sess.span_err(attr.span, "bad macro import"); + span_err!(self.sess, attr.span, E0466, "bad macro import"); } } } @@ -100,7 +103,7 @@ impl<'a, 'v> Visitor<'v> for MacroLoader<'a> { let names = match attr.meta_item_list() { Some(names) => names, None => { - self.sess.span_err(attr.span, "bad macro reexport"); + call_bad_macro_reexport(self.sess, attr.span); continue; } }; @@ -109,7 +112,7 @@ impl<'a, 'v> Visitor<'v> for MacroLoader<'a> { if let ast::MetaWord(ref name) = attr.node { reexport.insert(name.clone(), attr.span); } else { - self.sess.span_err(attr.span, "bad macro reexport"); + call_bad_macro_reexport(self.sess, attr.span); } } } @@ -141,8 +144,8 @@ impl<'a> MacroLoader<'a> { } if !self.span_whitelist.contains(&vi.span) { - self.sess.span_err(vi.span, "an `extern crate` loading macros must be at \ - the crate root"); + span_err!(self.sess, vi.span, E0468, + "an `extern crate` loading macros must be at the crate root"); return; } @@ -167,14 +170,16 @@ impl<'a> MacroLoader<'a> { if let Some(sel) = import.as_ref() { for (name, span) in sel { if !seen.contains(&name) { - self.sess.span_err(*span, "imported macro not found"); + span_err!(self.sess, *span, E0469, + "imported macro not found"); } } } for (name, span) in &reexport { if !seen.contains(&name) { - self.sess.span_err(*span, "reexported macro not found"); + span_err!(self.sess, *span, E0470, + "reexported macro not found"); } } } diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 7856890724..d03af6b672 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -16,11 +16,9 @@ #![allow(non_camel_case_types)] -pub use self::DefIdSource::*; - use rustc_front::hir; -use middle::def_id::DefId; +use middle::def_id::{DefId, DefIndex}; use middle::region; use middle::subst; use middle::subst::VecPerParamSpace; @@ -36,32 +34,7 @@ use syntax::parse::token; // parse_from_str. Extra parameters are for converting to/from def_ids in the // data buffer. Whatever format you choose should not contain pipe characters. -// Def id conversion: when we encounter def-ids, they have to be translated. -// For example, the crate number must be converted from the crate number used -// in the library we are reading from into the local crate numbers in use -// here. To perform this translation, the type decoder is supplied with a -// conversion function of type `conv_did`. -// -// Sometimes, particularly when inlining, the correct translation of the -// def-id will depend on where it originated from. Therefore, the conversion -// function is given an indicator of the source of the def-id. See -// astencode.rs for more information. -#[derive(Copy, Clone, Debug)] -pub enum DefIdSource { - // Identifies a struct, trait, enum, etc. - NominalType, - - // Identifies a type alias (`type X = ...`). - TypeWithId, - - // Identifies a region parameter (`fn foo<'X>() { ... }`). - RegionParameter, - - // Identifies a closure - ClosureSource -} - -pub type DefIdConvert<'a> = &'a mut FnMut(DefIdSource, DefId) -> DefId; +pub type DefIdConvert<'a> = &'a mut FnMut(DefId) -> DefId; pub struct TyDecoder<'a, 'tcx: 'a> { data: &'a [u8], @@ -125,6 +98,12 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { return &self.data[start_pos..end_pos]; } + fn parse_vuint(&mut self) -> usize { + let res = rbml::reader::vuint_at(self.data, self.pos).unwrap(); + self.pos = res.next; + res.val + } + fn parse_name(&mut self, last: char) -> ast::Name { fn is_last(b: char, c: char) -> bool { return c == b; } let bytes = self.scan(|a| is_last(last, a)); @@ -183,9 +162,9 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { ty::BrAnon(id) } '[' => { - let def = self.parse_def(RegionParameter); - let ident = token::str_to_ident(&self.parse_str(']')); - ty::BrNamed(def, ident.name) + let def = self.parse_def(); + let name = token::intern(&self.parse_str(']')); + ty::BrNamed(def, name) } 'f' => { let id = self.parse_u32(); @@ -209,22 +188,17 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } 'B' => { assert_eq!(self.next(), '['); - // this is the wrong NodeId, but `param_id` is only accessed - // by the receiver-matching code in collect, which won't - // be going down this code path, and anyway I will kill it - // the moment wfcheck becomes the standard. - let node_id = self.parse_uint() as ast::NodeId; - assert_eq!(self.next(), '|'); + let def_id = self.parse_def(); let space = self.parse_param_space(); assert_eq!(self.next(), '|'); let index = self.parse_u32(); assert_eq!(self.next(), '|'); - let nm = token::str_to_ident(&self.parse_str(']')); + let name = token::intern(&self.parse_str(']')); ty::ReEarlyBound(ty::EarlyBoundRegion { - param_id: node_id, + def_id: def_id, space: space, index: index, - name: nm.name + name: name }) } 'f' => { @@ -314,7 +288,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } pub fn parse_trait_ref(&mut self) -> ty::TraitRef<'tcx> { - let def = self.parse_def(NominalType); + let def = self.parse_def(); let substs = self.tcx.mk_substs(self.parse_substs()); ty::TraitRef {def_id: def, substs: substs} } @@ -343,7 +317,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { 'c' => return tcx.types.char, 't' => { assert_eq!(self.next(), '['); - let did = self.parse_def(NominalType); + let did = self.parse_def(); let substs = self.parse_substs(); assert_eq!(self.next(), ']'); let def = self.tcx.lookup_adt_def(did); @@ -390,7 +364,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { return tcx.mk_tup(params); } 'F' => { - let def_id = self.parse_def(NominalType); + let def_id = self.parse_def(); return tcx.mk_fn(Some(def_id), tcx.mk_bare_fn(self.parse_bare_fn_ty())); } 'G' => { @@ -405,11 +379,8 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { // we return it (modulo closure types, see below). But if not, then we // jump to offset 123 and read the type from there. - let pos = self.parse_hex(); - assert_eq!(self.next(), ':'); - let len = self.parse_hex(); - assert_eq!(self.next(), '#'); - let key = ty::CReaderCacheKey {cnum: self.krate, pos: pos, len: len }; + let pos = self.parse_vuint(); + let key = ty::CReaderCacheKey { cnum: self.krate, pos: pos }; match tcx.rcache.borrow().get(&key).cloned() { Some(tt) => { // If there is a closure buried in the type some where, then we @@ -432,13 +403,13 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { return tt; } '\"' => { - let _ = self.parse_def(TypeWithId); + let _ = self.parse_def(); let inner = self.parse_ty(); inner } 'a' => { assert_eq!(self.next(), '['); - let did = self.parse_def(NominalType); + let did = self.parse_def(); let substs = self.parse_substs(); assert_eq!(self.next(), ']'); let def = self.tcx.lookup_adt_def(did); @@ -446,7 +417,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } 'k' => { assert_eq!(self.next(), '['); - let did = self.parse_def(ClosureSource); + let did = self.parse_def(); let substs = self.parse_substs(); let mut tys = vec![]; while self.peek() != '.' { @@ -481,9 +452,9 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { ty::TypeAndMut { ty: self.parse_ty(), mutbl: m } } - fn parse_def(&mut self, source: DefIdSource) -> DefId { + fn parse_def(&mut self) -> DefId { let def_id = parse_defid(self.scan(|c| c == '|')); - return (self.conv_def_id)(source, def_id); + return (self.conv_def_id)(def_id); } fn parse_uint(&mut self) -> usize { @@ -508,19 +479,6 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { subst::ParamSpace::from_uint(self.parse_uint()) } - fn parse_hex(&mut self) -> usize { - let mut n = 0; - loop { - let cur = self.peek(); - if (cur < '0' || cur > '9') && (cur < 'a' || cur > 'f') { return n; } - self.pos = self.pos + 1; - n *= 16; - if '0' <= cur && cur <= '9' { - n += (cur as usize) - ('0' as usize); - } else { n += 10 + (cur as usize) - ('a' as usize); } - }; - } - fn parse_abi_set(&mut self) -> abi::Abi { assert_eq!(self.next(), '['); let bytes = self.scan(|c| c == ']'); @@ -586,7 +544,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { 'p' => ty::Binder(self.parse_projection_predicate()).to_predicate(), 'w' => ty::Predicate::WellFormed(self.parse_ty()), 'O' => { - let def_id = self.parse_def(NominalType); + let def_id = self.parse_def(); assert_eq!(self.next(), '|'); ty::Predicate::ObjectSafe(def_id) } @@ -598,7 +556,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { ty::ProjectionPredicate { projection_ty: ty::ProjectionTy { trait_ref: self.parse_trait_ref(), - item_name: token::str_to_ident(&self.parse_str('|')).name, + item_name: token::intern(&self.parse_str('|')), }, ty: self.parse_ty(), } @@ -606,12 +564,12 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { pub fn parse_type_param_def(&mut self) -> ty::TypeParameterDef<'tcx> { let name = self.parse_name(':'); - let def_id = self.parse_def(NominalType); + let def_id = self.parse_def(); let space = self.parse_param_space(); assert_eq!(self.next(), '|'); let index = self.parse_u32(); assert_eq!(self.next(), '|'); - let default_def_id = self.parse_def(NominalType); + let default_def_id = self.parse_def(); let default = self.parse_opt(|this| this.parse_ty()); let object_lifetime_default = self.parse_object_lifetime_default(); @@ -628,7 +586,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { pub fn parse_region_param_def(&mut self) -> ty::RegionParameterDef { let name = self.parse_name(':'); - let def_id = self.parse_def(NominalType); + let def_id = self.parse_def(); let space = self.parse_param_space(); assert_eq!(self.next(), '|'); let index = self.parse_u32(); @@ -736,11 +694,12 @@ fn parse_defid(buf: &[u8]) -> DefId { let def_num = match str::from_utf8(def_part).ok().and_then(|s| { s.parse::().ok() }) { - Some(dn) => dn as ast::NodeId, + Some(dn) => dn, None => panic!("internal error: parse_defid: id expected, found {:?}", def_part) }; - DefId { krate: crate_num, node: def_num } + let index = DefIndex::new(def_num); + DefId { krate: crate_num, index: index } } fn parse_unsafety(c: char) -> hir::Unsafety { diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index d7554c4cf7..1b993a00e2 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -14,6 +14,7 @@ #![allow(non_camel_case_types)] use std::cell::RefCell; +use std::io::Cursor; use std::io::prelude::*; use middle::def_id::DefId; @@ -27,9 +28,10 @@ use util::nodemap::FnvHashMap; use rustc_front::hir; use syntax::abi::Abi; +use syntax::ast; use syntax::diagnostic::SpanHandler; -use rbml::writer::Encoder; +use rbml::writer::{self, Encoder}; macro_rules! mywrite { ($w:expr, $($arg:tt)*) => ({ write!($w.writer, $($arg)*); }) } @@ -46,14 +48,14 @@ pub struct ctxt<'a, 'tcx: 'a> { // Extra parameters are for converting to/from def_ids in the string rep. // Whatever format you choose should not contain pipe characters. pub struct ty_abbrev { - s: String + s: Vec } pub type abbrev_map<'tcx> = RefCell, ty_abbrev>>; pub fn enc_ty<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx>) { match cx.abbrevs.borrow_mut().get(&t) { - Some(a) => { w.writer.write_all(a.s.as_bytes()); return; } + Some(a) => { w.writer.write_all(&a.s); return; } None => {} } @@ -65,26 +67,26 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx>) { ty::TyChar => mywrite!(w, "c"), ty::TyInt(t) => { match t { - hir::TyIs => mywrite!(w, "is"), - hir::TyI8 => mywrite!(w, "MB"), - hir::TyI16 => mywrite!(w, "MW"), - hir::TyI32 => mywrite!(w, "ML"), - hir::TyI64 => mywrite!(w, "MD") + ast::TyIs => mywrite!(w, "is"), + ast::TyI8 => mywrite!(w, "MB"), + ast::TyI16 => mywrite!(w, "MW"), + ast::TyI32 => mywrite!(w, "ML"), + ast::TyI64 => mywrite!(w, "MD") } } ty::TyUint(t) => { match t { - hir::TyUs => mywrite!(w, "us"), - hir::TyU8 => mywrite!(w, "Mb"), - hir::TyU16 => mywrite!(w, "Mw"), - hir::TyU32 => mywrite!(w, "Ml"), - hir::TyU64 => mywrite!(w, "Md") + ast::TyUs => mywrite!(w, "us"), + ast::TyU8 => mywrite!(w, "Mb"), + ast::TyU16 => mywrite!(w, "Mw"), + ast::TyU32 => mywrite!(w, "Ml"), + ast::TyU64 => mywrite!(w, "Md") } } ty::TyFloat(t) => { match t { - hir::TyF32 => mywrite!(w, "Mf"), - hir::TyF64 => mywrite!(w, "MF"), + ast::TyF32 => mywrite!(w, "Mf"), + ast::TyF64 => mywrite!(w, "MF"), } } ty::TyEnum(def, substs) => { @@ -165,19 +167,22 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx>) { let end = w.mark_stable_position(); let len = end - pos; - fn estimate_sz(u: u64) -> u64 { - let mut n = u; - let mut len = 0; - while n != 0 { len += 1; n = n >> 4; } - return len; - } - let abbrev_len = 3 + estimate_sz(pos) + estimate_sz(len); - if abbrev_len < len { - // I.e. it's actually an abbreviation. - cx.abbrevs.borrow_mut().insert(t, ty_abbrev { - s: format!("#{:x}:{:x}#", pos, len) - }); - } + + let buf: &mut [u8] = &mut [0; 16]; // vuint < 15 bytes + let mut abbrev = Cursor::new(buf); + abbrev.write_all(b"#"); + writer::write_vuint(&mut abbrev, pos as usize); + + cx.abbrevs.borrow_mut().insert(t, ty_abbrev { + s: if abbrev.position() < len { + abbrev.get_ref()[..abbrev.position() as usize].to_owned() + } else { + // if the abbreviation is longer than the real type, + // don't use #-notation. However, insert it here so + // other won't have to `mark_stable_position` + w.writer.get_ref()[pos as usize..end as usize].to_owned() + } + }); } fn enc_mutability(w: &mut Encoder, mt: hir::Mutability) { @@ -249,7 +254,7 @@ pub fn enc_region(w: &mut Encoder, cx: &ctxt, r: ty::Region) { } ty::ReEarlyBound(ref data) => { mywrite!(w, "B[{}|{}|{}|{}]", - data.param_id, + (cx.ds)(data.def_id), data.space.to_uint(), data.index, data.name); diff --git a/src/librustc/middle/astconv_util.rs b/src/librustc/middle/astconv_util.rs index 3b83727720..2bf749d93c 100644 --- a/src/librustc/middle/astconv_util.rs +++ b/src/librustc/middle/astconv_util.rs @@ -60,6 +60,8 @@ pub fn prim_ty_to_ty<'tcx>(tcx: &ty::ctxt<'tcx>, } } +/// If a type in the AST is a primitive type, return the ty::Ty corresponding +/// to it. pub fn ast_ty_to_prim_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ast_ty: &ast::Ty) -> Option> { if let ast::TyPath(None, ref path) = ast_ty.node { diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 0bd4434857..e81445f19e 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -24,21 +24,19 @@ use metadata::decoder; use metadata::encoder as e; use metadata::inline::{InlinedItem, InlinedItemRef}; use metadata::tydecode; -use metadata::tydecode::{DefIdSource, NominalType, TypeWithId}; -use metadata::tydecode::{RegionParameter, ClosureSource}; use metadata::tyencode; use middle::ty::adjustment; use middle::ty::cast; use middle::check_const::ConstQualif; use middle::def; -use middle::def_id::{DefId, LOCAL_CRATE}; +use middle::def_id::DefId; use middle::privacy::{AllPublic, LastMod}; use middle::region; use middle::subst; -use middle::subst::VecPerParamSpace; use middle::ty::{self, Ty}; use syntax::{ast, ast_util, codemap}; +use syntax::ast::NodeIdAssigner; use syntax::codemap::Span; use syntax::ptr::P; @@ -56,8 +54,9 @@ use serialize::EncoderHelpers; #[cfg(test)] use std::io::Cursor; #[cfg(test)] use syntax::parse; +#[cfg(test)] use syntax::ast::NodeId; #[cfg(test)] use rustc_front::print::pprust; -#[cfg(test)] use rustc_front::lowering::lower_item; +#[cfg(test)] use rustc_front::lowering::{lower_item, LoweringContext}; struct DecodeContext<'a, 'b, 'tcx: 'a> { tcx: &'a ty::ctxt<'tcx>, @@ -72,10 +71,6 @@ trait tr { fn tr(&self, dcx: &DecodeContext) -> Self; } -trait tr_intern { - fn tr_intern(&self, dcx: &DecodeContext) -> DefId; -} - // ______________________________________________________________________ // Top-level methods. @@ -129,10 +124,13 @@ impl<'a, 'b, 'c, 'tcx> ast_map::FoldOps for &'a DecodeContext<'b, 'c, 'tcx> { pub fn decode_inlined_item<'tcx>(cdata: &cstore::crate_metadata, tcx: &ty::ctxt<'tcx>, path: Vec, - par_doc: rbml::Doc) - -> Result<&'tcx InlinedItem, Vec> { + def_path: ast_map::DefPath, + par_doc: rbml::Doc, + orig_did: DefId) + -> Result<&'tcx InlinedItem, (Vec, + ast_map::DefPath)> { match par_doc.opt_child(c::tag_ast) { - None => Err(path), + None => Err((path, def_path)), Some(ast_doc) => { let mut path_as_str = None; debug!("> Decoding inlined fn: {:?}::?", @@ -153,20 +151,21 @@ pub fn decode_inlined_item<'tcx>(cdata: &cstore::crate_metadata, last_filemap_index: Cell::new(0) }; let raw_ii = decode_ast(ast_doc); - let ii = ast_map::map_decoded_item(&dcx.tcx.map, path, raw_ii, dcx); + let ii = ast_map::map_decoded_item(&dcx.tcx.map, path, def_path, raw_ii, dcx); - let ident = match *ii { - InlinedItem::Item(ref i) => i.ident, - InlinedItem::Foreign(ref i) => i.ident, - InlinedItem::TraitItem(_, ref ti) => ti.ident, - InlinedItem::ImplItem(_, ref ii) => ii.ident + let name = match *ii { + InlinedItem::Item(ref i) => i.name, + InlinedItem::Foreign(ref i) => i.name, + InlinedItem::TraitItem(_, ref ti) => ti.name, + InlinedItem::ImplItem(_, ref ii) => ii.name }; - debug!("Fn named: {}", ident); + debug!("Fn named: {}", name); debug!("< Decoded inlined fn: {}::{}", path_as_str.unwrap(), - ident); + name); region::resolve_inlined_item(&tcx.sess, &tcx.region_maps, ii); decode_side_tables(dcx, ast_doc); + copy_item_types(dcx, ii, orig_did); match *ii { InlinedItem::Item(ref i) => { debug!(">>> DECODED ITEM >>>\n{}\n<<< DECODED ITEM <<<", @@ -213,24 +212,10 @@ impl<'a, 'b, 'tcx> DecodeContext<'a, 'b, 'tcx> { /// be inlined. Note that even when the inlined function is referencing itself recursively, we /// would want `tr_def_id` for that reference--- conceptually the function calls the original, /// non-inlined version, and trans deals with linking that recursive call to the inlined copy. - /// - /// However, there are a *few* cases where def-ids are used but we know that the thing being - /// referenced is in fact *internal* to the item being inlined. In those cases, you should use - /// `tr_intern_def_id()` below. pub fn tr_def_id(&self, did: DefId) -> DefId { - decoder::translate_def_id(self.cdata, did) } - /// Translates an INTERNAL def-id, meaning a def-id that is - /// known to refer to some part of the item currently being - /// inlined. In that case, we want to convert the def-id to - /// refer to the current crate and to the new, inlined node-id. - pub fn tr_intern_def_id(&self, did: DefId) -> DefId { - assert_eq!(did.krate, LOCAL_CRATE); - DefId { krate: LOCAL_CRATE, node: self.tr_id(did.node) } - } - /// Translates a `Span` from an extern crate to the corresponding `Span` /// within the local crate's codemap. `creader::import_codemap()` will /// already have allocated any additionally needed FileMaps in the local @@ -289,12 +274,6 @@ impl<'a, 'b, 'tcx> DecodeContext<'a, 'b, 'tcx> { } } -impl tr_intern for DefId { - fn tr_intern(&self, dcx: &DecodeContext) -> DefId { - dcx.tr_intern_def_id(*self) - } -} - impl tr for DefId { fn tr(&self, dcx: &DecodeContext) -> DefId { dcx.tr_def_id(*self) @@ -460,7 +439,11 @@ impl tr for def::Def { def::DefStatic(did, m) => { def::DefStatic(did.tr(dcx), m) } def::DefConst(did) => { def::DefConst(did.tr(dcx)) } def::DefAssociatedConst(did) => def::DefAssociatedConst(did.tr(dcx)), - def::DefLocal(nid) => { def::DefLocal(dcx.tr_id(nid)) } + def::DefLocal(_, nid) => { + let nid = dcx.tr_id(nid); + let did = dcx.tcx.map.local_def_id(nid); + def::DefLocal(did, nid) + } def::DefVariant(e_did, v_did, is_s) => { def::DefVariant(e_did.tr(dcx), v_did.tr(dcx), is_s) }, @@ -471,11 +454,13 @@ impl tr for def::Def { def::DefPrimTy(p) => def::DefPrimTy(p), def::DefTyParam(s, index, def_id, n) => def::DefTyParam(s, index, def_id.tr(dcx), n), def::DefUse(did) => def::DefUse(did.tr(dcx)), - def::DefUpvar(nid1, index, nid2) => { - def::DefUpvar(dcx.tr_id(nid1), index, dcx.tr_id(nid2)) + def::DefUpvar(_, nid1, index, nid2) => { + let nid1 = dcx.tr_id(nid1); + let nid2 = dcx.tr_id(nid2); + let did1 = dcx.tcx.map.local_def_id(nid1); + def::DefUpvar(did1, nid1, index, nid2) } def::DefStruct(did) => def::DefStruct(did.tr(dcx)), - def::DefRegion(nid) => def::DefRegion(dcx.tr_id(nid)), def::DefLabel(nid) => def::DefLabel(dcx.tr_id(nid)) } } @@ -568,44 +553,10 @@ impl<'a, 'tcx> read_method_callee_helper<'tcx> for reader::Decoder<'a> { } } -pub fn encode_closure_kind(ebml_w: &mut Encoder, kind: ty::ClosureKind) { - kind.encode(ebml_w).unwrap(); -} - pub fn encode_cast_kind(ebml_w: &mut Encoder, kind: cast::CastKind) { kind.encode(ebml_w).unwrap(); } -pub trait vtable_decoder_helpers<'tcx> { - fn read_vec_per_param_space(&mut self, f: F) -> VecPerParamSpace where - F: FnMut(&mut Self) -> T; -} - -impl<'tcx, 'a> vtable_decoder_helpers<'tcx> for reader::Decoder<'a> { - fn read_vec_per_param_space(&mut self, mut f: F) -> VecPerParamSpace where - F: FnMut(&mut reader::Decoder<'a>) -> T, - { - let types = self.read_to_vec(|this| Ok(f(this))).unwrap(); - let selfs = self.read_to_vec(|this| Ok(f(this))).unwrap(); - let fns = self.read_to_vec(|this| Ok(f(this))).unwrap(); - VecPerParamSpace::new(types, selfs, fns) - } -} - -// ___________________________________________________________________________ -// - -fn encode_vec_per_param_space(rbml_w: &mut Encoder, - v: &subst::VecPerParamSpace, - mut f: F) where - F: FnMut(&mut Encoder, &T), -{ - for &space in &subst::ParamSpace::all() { - rbml_w.emit_from_vec(v.get_slice(space), - |rbml_w, n| Ok(f(rbml_w, n))).unwrap(); - } -} - // ______________________________________________________________________ // Encoding and decoding the side tables @@ -625,21 +576,13 @@ impl<'a, 'tcx> get_ty_str_ctxt<'tcx> for e::EncodeContext<'a, 'tcx> { } trait rbml_writer_helpers<'tcx> { - fn emit_closure_type<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, - closure_type: &ty::ClosureTy<'tcx>); fn emit_region(&mut self, ecx: &e::EncodeContext, r: ty::Region); fn emit_ty<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, ty: Ty<'tcx>); fn emit_tys<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, tys: &[Ty<'tcx>]); - fn emit_type_param_def<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, - type_param_def: &ty::TypeParameterDef<'tcx>); - fn emit_region_param_def(&mut self, ecx: &e::EncodeContext, - region_param_def: &ty::RegionParameterDef); fn emit_predicate<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, predicate: &ty::Predicate<'tcx>); fn emit_trait_ref<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, ty: &ty::TraitRef<'tcx>); - fn emit_type_scheme<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, - type_scheme: ty::TypeScheme<'tcx>); fn emit_substs<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, substs: &subst::Substs<'tcx>); fn emit_existential_bounds<'b>(&mut self, ecx: &e::EncodeContext<'b,'tcx>, @@ -655,14 +598,6 @@ trait rbml_writer_helpers<'tcx> { } impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { - fn emit_closure_type<'b>(&mut self, - ecx: &e::EncodeContext<'b, 'tcx>, - closure_type: &ty::ClosureTy<'tcx>) { - self.emit_opaque(|this| { - Ok(e::write_closure_type(ecx, this, closure_type)) - }); - } - fn emit_region(&mut self, ecx: &e::EncodeContext, r: ty::Region) { self.emit_opaque(|this| Ok(e::write_region(ecx, this, r))); } @@ -680,22 +615,6 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { self.emit_opaque(|this| Ok(e::write_trait_ref(ecx, this, trait_ref))); } - fn emit_type_param_def<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, - type_param_def: &ty::TypeParameterDef<'tcx>) { - self.emit_opaque(|this| { - Ok(tyencode::enc_type_param_def(this, - &ecx.ty_str_ctxt(), - type_param_def)) - }); - } - fn emit_region_param_def(&mut self, ecx: &e::EncodeContext, - region_param_def: &ty::RegionParameterDef) { - self.emit_opaque(|this| { - Ok(tyencode::enc_region_param_def(this, - &ecx.ty_str_ctxt(), - region_param_def)) - }); - } fn emit_predicate<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, predicate: &ty::Predicate<'tcx>) { self.emit_opaque(|this| { @@ -705,32 +624,6 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { }); } - fn emit_type_scheme<'b>(&mut self, - ecx: &e::EncodeContext<'b, 'tcx>, - type_scheme: ty::TypeScheme<'tcx>) { - use serialize::Encoder; - - self.emit_struct("TypeScheme", 2, |this| { - this.emit_struct_field("generics", 0, |this| { - this.emit_struct("Generics", 2, |this| { - this.emit_struct_field("types", 0, |this| { - Ok(encode_vec_per_param_space( - this, &type_scheme.generics.types, - |this, def| this.emit_type_param_def(ecx, def))) - }); - this.emit_struct_field("regions", 1, |this| { - Ok(encode_vec_per_param_space( - this, &type_scheme.generics.regions, - |this, def| this.emit_region_param_def(ecx, def))) - }) - }) - }); - this.emit_struct_field("ty", 1, |this| { - Ok(this.emit_ty(ecx, type_scheme.ty)) - }) - }); - } - fn emit_existential_bounds<'b>(&mut self, ecx: &e::EncodeContext<'b,'tcx>, bounds: &ty::ExistentialBounds<'tcx>) { self.emit_opaque(|this| Ok(tyencode::enc_existential_bounds(this, @@ -933,7 +826,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, rbml_w.tag(c::tag_table_upvar_capture_map, |rbml_w| { rbml_w.id(id); - let var_id = freevar.def.def_id().node; + let var_id = freevar.def.var_id(); let upvar_id = ty::UpvarId { var_id: var_id, closure_expr_id: id @@ -950,21 +843,6 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, } } - let lid = DefId { krate: LOCAL_CRATE, node: id }; - if let Some(type_scheme) = tcx.tcache.borrow().get(&lid) { - rbml_w.tag(c::tag_table_tcache, |rbml_w| { - rbml_w.id(id); - rbml_w.emit_type_scheme(ecx, type_scheme.clone()); - }) - } - - if let Some(type_param_def) = tcx.ty_param_defs.borrow().get(&id) { - rbml_w.tag(c::tag_table_param_defs, |rbml_w| { - rbml_w.id(id); - rbml_w.emit_type_param_def(ecx, type_param_def) - }) - } - let method_call = ty::MethodCall::expr(id); if let Some(method) = tcx.tables.borrow().method_map.get(&method_call) { rbml_w.tag(c::tag_table_method_map, |rbml_w| { @@ -996,20 +874,6 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, }) } - if let Some(closure_type) = tcx.tables.borrow().closure_tys.get(&DefId::local(id)) { - rbml_w.tag(c::tag_table_closure_tys, |rbml_w| { - rbml_w.id(id); - rbml_w.emit_closure_type(ecx, closure_type); - }) - } - - if let Some(closure_kind) = tcx.tables.borrow().closure_kinds.get(&DefId::local(id)) { - rbml_w.tag(c::tag_table_closure_kinds, |rbml_w| { - rbml_w.id(id); - encode_closure_kind(rbml_w, *closure_kind) - }) - } - if let Some(cast_kind) = tcx.cast_kinds.borrow().get(&id) { rbml_w.tag(c::tag_table_cast_kinds, |rbml_w| { rbml_w.id(id); @@ -1049,14 +913,8 @@ trait rbml_decoder_decoder_helpers<'tcx> { -> ty::TraitRef<'tcx>; fn read_poly_trait_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> ty::PolyTraitRef<'tcx>; - fn read_type_param_def<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> ty::TypeParameterDef<'tcx>; - fn read_region_param_def(&mut self, dcx: &DecodeContext) - -> ty::RegionParameterDef; fn read_predicate<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> ty::Predicate<'tcx>; - fn read_type_scheme<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> ty::TypeScheme<'tcx>; fn read_existential_bounds<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> ty::ExistentialBounds<'tcx>; fn read_substs<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) @@ -1067,17 +925,12 @@ trait rbml_decoder_decoder_helpers<'tcx> { -> adjustment::AutoAdjustment<'tcx>; fn read_cast_kind<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> cast::CastKind; - fn read_closure_kind<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> ty::ClosureKind; - fn read_closure_ty<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> ty::ClosureTy<'tcx>; fn read_auto_deref_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> adjustment::AutoDerefRef<'tcx>; fn read_autoref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> adjustment::AutoRef<'tcx>; fn convert_def_id(&mut self, dcx: &DecodeContext, - source: DefIdSource, did: DefId) -> DefId; @@ -1101,7 +954,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { self.read_opaque(|_, doc| { Ok( tydecode::TyDecoder::with_doc(tcx, cdata.cnum, doc, - &mut |_, id| decoder::translate_def_id(cdata, id)) + &mut |id| decoder::translate_def_id(cdata, id)) .parse_ty()) }).unwrap() } @@ -1123,7 +976,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { self.read_opaque(|_, doc| { Ok( tydecode::TyDecoder::with_doc(tcx, cdata.cnum, doc, - &mut |_, id| decoder::translate_def_id(cdata, id)) + &mut |id| decoder::translate_def_id(cdata, id)) .parse_substs()) }).unwrap() } @@ -1136,7 +989,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { Ok(op( &mut tydecode::TyDecoder::with_doc( dcx.tcx, dcx.cdata.cnum, doc, - &mut |s, a| this.convert_def_id(dcx, s, a)))) + &mut |a| this.convert_def_id(dcx, a)))) }).unwrap(); fn type_string(doc: rbml::Doc) -> String { @@ -1173,48 +1026,12 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { ty::Binder(self.read_ty_encoded(dcx, |decoder| decoder.parse_trait_ref())) } - fn read_type_param_def<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> ty::TypeParameterDef<'tcx> { - self.read_ty_encoded(dcx, |decoder| decoder.parse_type_param_def()) - } - fn read_region_param_def(&mut self, dcx: &DecodeContext) - -> ty::RegionParameterDef { - self.read_ty_encoded(dcx, |decoder| decoder.parse_region_param_def()) - } fn read_predicate<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> ty::Predicate<'tcx> { self.read_ty_encoded(dcx, |decoder| decoder.parse_predicate()) } - fn read_type_scheme<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> ty::TypeScheme<'tcx> { - self.read_struct("TypeScheme", 3, |this| { - Ok(ty::TypeScheme { - generics: this.read_struct_field("generics", 0, |this| { - this.read_struct("Generics", 2, |this| { - Ok(ty::Generics { - types: - this.read_struct_field("types", 0, |this| { - Ok(this.read_vec_per_param_space( - |this| this.read_type_param_def(dcx))) - }).unwrap(), - - regions: - this.read_struct_field("regions", 1, |this| { - Ok(this.read_vec_per_param_space( - |this| this.read_region_param_def(dcx))) - }).unwrap(), - }) - }) - }).unwrap(), - ty: this.read_struct_field("ty", 1, |this| { - Ok(this.read_ty(dcx)) - }).unwrap() - }) - }).unwrap() - } - fn read_existential_bounds<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> ty::ExistentialBounds<'tcx> { @@ -1225,7 +1042,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { -> subst::Substs<'tcx> { self.read_opaque(|this, doc| { Ok(tydecode::TyDecoder::with_doc(dcx.tcx, dcx.cdata.cnum, doc, - &mut |s, a| this.convert_def_id(dcx, s, a)) + &mut |a| this.convert_def_id(dcx, a)) .parse_substs()) }).unwrap() } @@ -1332,18 +1149,6 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { Decodable::decode(self).unwrap() } - fn read_closure_kind<'b, 'c>(&mut self, _dcx: &DecodeContext<'b, 'c, 'tcx>) - -> ty::ClosureKind - { - Decodable::decode(self).unwrap() - } - - fn read_closure_ty<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> ty::ClosureTy<'tcx> - { - self.read_ty_encoded(dcx, |decoder| decoder.parse_closure_ty()) - } - /// Converts a def-id that appears in a type. The correct /// translation will depend on what kind of def-id this is. /// This is a subtle point: type definitions are not @@ -1378,14 +1183,10 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { /// def-ids so that all these distinctions were unnecessary. fn convert_def_id(&mut self, dcx: &DecodeContext, - source: tydecode::DefIdSource, did: DefId) -> DefId { - let r = match source { - NominalType | TypeWithId | RegionParameter => dcx.tr_def_id(did), - ClosureSource => dcx.tr_intern_def_id(did) - }; - debug!("convert_def_id(source={:?}, did={:?})={:?}", source, did, r); + let r = dcx.tr_def_id(did); + debug!("convert_def_id(did={:?})={:?}", did, r); return r; } } @@ -1450,15 +1251,6 @@ fn decode_side_tables(dcx: &DecodeContext, let ub = val_dsr.read_upvar_capture(dcx); dcx.tcx.tables.borrow_mut().upvar_capture_map.insert(upvar_id, ub); } - c::tag_table_tcache => { - let type_scheme = val_dsr.read_type_scheme(dcx); - let lid = DefId { krate: LOCAL_CRATE, node: id }; - dcx.tcx.register_item_type(lid, type_scheme); - } - c::tag_table_param_defs => { - let bounds = val_dsr.read_type_param_def(dcx); - dcx.tcx.ty_param_defs.borrow_mut().insert(id, bounds); - } c::tag_table_method_map => { let (autoderef, method) = val_dsr.read_method_callee(dcx); let method_call = ty::MethodCall { @@ -1472,18 +1264,6 @@ fn decode_side_tables(dcx: &DecodeContext, val_dsr.read_auto_adjustment(dcx); dcx.tcx.tables.borrow_mut().adjustments.insert(id, adj); } - c::tag_table_closure_tys => { - let closure_ty = - val_dsr.read_closure_ty(dcx); - dcx.tcx.tables.borrow_mut().closure_tys.insert(DefId::local(id), - closure_ty); - } - c::tag_table_closure_kinds => { - let closure_kind = - val_dsr.read_closure_kind(dcx); - dcx.tcx.tables.borrow_mut().closure_kinds.insert(DefId::local(id), - closure_kind); - } c::tag_table_cast_kinds => { let cast_kind = val_dsr.read_cast_kind(dcx); @@ -1506,6 +1286,53 @@ fn decode_side_tables(dcx: &DecodeContext, } } +// copy the tcache entries from the original item to the new +// inlined item +fn copy_item_types(dcx: &DecodeContext, ii: &InlinedItem, orig_did: DefId) { + fn copy_item_type(dcx: &DecodeContext, + inlined_id: ast::NodeId, + remote_did: DefId) { + let inlined_did = dcx.tcx.map.local_def_id(inlined_id); + dcx.tcx.register_item_type(inlined_did, + dcx.tcx.lookup_item_type(remote_did)); + + } + // copy the entry for the item itself + 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::Foreign(ref fi) => fi.id + }; + copy_item_type(dcx, item_node_id, orig_did); + + // copy the entries of inner items + if let &InlinedItem::Item(ref item) = ii { + match item.node { + hir::ItemEnum(ref def, _) => { + let orig_def = dcx.tcx.lookup_adt_def(orig_did); + for (i_variant, orig_variant) in + def.variants.iter().zip(orig_def.variants.iter()) + { + debug!("astencode: copying variant {:?} => {:?}", + orig_variant.did, i_variant.node.data.id()); + copy_item_type(dcx, i_variant.node.data.id(), orig_variant.did); + } + } + hir::ItemStruct(ref def, _) => { + if !def.is_struct() { + let ctor_did = dcx.tcx.lookup_adt_def(orig_did) + .struct_variant().did; + debug!("astencode: copying ctor {:?} => {:?}", ctor_did, + def.id()); + copy_item_type(dcx, def.id(), ctor_did); + } + } + _ => {} + } + } +} + // ______________________________________________________________________ // Testing of astencode_gen @@ -1551,6 +1378,22 @@ impl FakeExtCtxt for parse::ParseSess { fn parse_sess(&self) -> &parse::ParseSess { self } } +#[cfg(test)] +struct FakeNodeIdAssigner; + +#[cfg(test)] +// It should go without saying that this may give unexpected results. Avoid +// lowering anything which needs new nodes. +impl NodeIdAssigner for FakeNodeIdAssigner { + fn next_node_id(&self) -> NodeId { + 0 + } + + fn peek_node_id(&self) -> NodeId { + 0 + } +} + #[cfg(test)] fn mk_ctxt() -> parse::ParseSess { parse::ParseSess::new() @@ -1569,7 +1412,9 @@ fn roundtrip(in_item: P) { #[test] fn test_basic() { let cx = mk_ctxt(); - roundtrip(lower_item("e_item!(&cx, + let fnia = FakeNodeIdAssigner; + let lcx = LoweringContext::new(&fnia, None); + roundtrip(lower_item(&lcx, "e_item!(&cx, fn foo() {} ).unwrap())); } @@ -1577,7 +1422,9 @@ fn test_basic() { #[test] fn test_smalltalk() { let cx = mk_ctxt(); - roundtrip(lower_item("e_item!(&cx, + let fnia = FakeNodeIdAssigner; + let lcx = LoweringContext::new(&fnia, None); + roundtrip(lower_item(&lcx, "e_item!(&cx, fn foo() -> isize { 3 + 4 } // first smalltalk program ever executed. ).unwrap())); } @@ -1585,7 +1432,9 @@ fn test_smalltalk() { #[test] fn test_more() { let cx = mk_ctxt(); - roundtrip(lower_item("e_item!(&cx, + let fnia = FakeNodeIdAssigner; + let lcx = LoweringContext::new(&fnia, None); + roundtrip(lower_item(&lcx, "e_item!(&cx, fn foo(x: usize, y: usize) -> usize { let z = x + y; return z; @@ -1602,10 +1451,12 @@ fn test_simplification() { return alist {eq_fn: eq_int, data: Vec::new()}; } ).unwrap(); - let hir_item = lower_item(&item); + let fnia = FakeNodeIdAssigner; + let lcx = LoweringContext::new(&fnia, None); + let hir_item = lower_item(&lcx, &item); let item_in = InlinedItemRef::Item(&hir_item); let item_out = simplify_ast(item_in); - let item_exp = InlinedItem::Item(lower_item("e_item!(&cx, + let item_exp = InlinedItem::Item(lower_item(&lcx, "e_item!(&cx, fn new_int_alist() -> alist { return alist {eq_fn: eq_int, data: Vec::new()}; } diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index 3f6385ad82..3b04dc3fb9 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -284,7 +284,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { } hir::ExprBreak(label) => { - let loop_scope = self.find_scope(expr, label.map(|l| l.node)); + let loop_scope = self.find_scope(expr, label.map(|l| l.node.name)); let b = self.add_ast_node(expr.id, &[pred]); self.add_exiting_edge(expr, b, loop_scope, loop_scope.break_index); @@ -292,7 +292,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { } hir::ExprAgain(label) => { - let loop_scope = self.find_scope(expr, label.map(|l| l.node)); + let loop_scope = self.find_scope(expr, label.map(|l| l.node.name)); let a = self.add_ast_node(expr.id, &[pred]); self.add_exiting_edge(expr, a, loop_scope, loop_scope.continue_index); @@ -344,17 +344,15 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { self.straightline(expr, pred, [r, l].iter().map(|&e| &**e)) } - hir::ExprBox(Some(ref l), ref r) | hir::ExprIndex(ref l, ref r) | hir::ExprBinary(_, ref l, ref r) => { // NB: && and || handled earlier self.straightline(expr, pred, [l, r].iter().map(|&e| &**e)) } - hir::ExprBox(None, ref e) | + hir::ExprBox(ref e) | hir::ExprAddrOf(_, ref e) | hir::ExprCast(ref e, _) | hir::ExprUnary(_, ref e) | - hir::ExprParen(ref e) | hir::ExprField(ref e, _) | hir::ExprTupField(ref e, _) => { self.straightline(expr, pred, Some(&**e).into_iter()) @@ -587,7 +585,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { fn find_scope(&self, expr: &hir::Expr, - label: Option) -> LoopScope { + label: Option) -> LoopScope { if label.is_none() { return *self.loop_scopes.last().unwrap(); } diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index 661299cd7f..263c9bd157 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -39,6 +39,7 @@ use util::nodemap::NodeMap; use rustc_front::hir; use syntax::ast; use syntax::codemap::Span; +use syntax::feature_gate::UnstableFeatures; use rustc_front::visit::{self, FnKind, Visitor}; use std::collections::hash_map::Entry; @@ -175,6 +176,7 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> { if mode == Mode::ConstFn { for arg in &fd.inputs { match arg.pat.node { + hir::PatWild(_) => {} hir::PatIdent(hir::BindByValue(hir::MutImmutable), _, None) => {} _ => { span_err!(self.tcx.sess, arg.pat.span, E0022, @@ -471,12 +473,12 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { ty::TyUint(_) | ty::TyInt(_) if div_or_rem => { if !self.qualif.intersects(ConstQualif::NOT_CONST) { match const_eval::eval_const_expr_partial( - self.tcx, ex, ExprTypeChecked) { + self.tcx, ex, ExprTypeChecked, None) { Ok(_) => {} Err(msg) => { - span_err!(self.tcx.sess, msg.span, E0020, - "{} in a constant expression", - msg.description()) + self.tcx.sess.add_lint(::lint::builtin::CONST_ERR, ex.id, + msg.span, + msg.description().into_owned()) } } } @@ -499,9 +501,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { if self.qualif.intersects(ConstQualif::MUTABLE_MEM) && tc.interior_unsafe() { outer = outer | ConstQualif::NOT_CONST; if self.mode != Mode::Var { - self.tcx.sess.span_err(ex.span, - "cannot borrow a constant which contains \ - interior mutability, create a static instead"); + span_err!(self.tcx.sess, ex.span, E0492, + "cannot borrow a constant which contains \ + interior mutability, create a static instead"); } } // If the reference has to be 'static, avoid in-place initialization @@ -548,9 +550,9 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, ty::TyEnum(def, _) if def.has_dtor() => { v.add_qualif(ConstQualif::NEEDS_DROP); if v.mode != Mode::Var { - v.tcx.sess.span_err(e.span, - &format!("{}s are not allowed to have destructors", - v.msg())); + span_err!(v.tcx.sess, e.span, E0493, + "{}s are not allowed to have destructors", + v.msg()); } } _ => {} @@ -567,8 +569,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, "user-defined operators are not allowed in {}s", v.msg()); } } - hir::ExprBox(..) | - hir::ExprUnary(hir::UnUniq, _) => { + hir::ExprBox(_) => { v.add_qualif(ConstQualif::NOT_CONST); if v.mode != Mode::Var { span_err!(v.tcx.sess, e.span, E0010, @@ -659,7 +660,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, doesn't point to a constant"); } } - Some(def::DefLocal(_)) if v.mode == Mode::ConstFn => { + Some(def::DefLocal(..)) if v.mode == Mode::ConstFn => { // Sadly, we can't determine whether the types are zero-sized. v.add_qualif(ConstQualif::NOT_CONST | ConstQualif::NON_ZERO_SIZED); } @@ -678,7 +679,6 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, let mut callee = &**callee; loop { callee = match callee.node { - hir::ExprParen(ref inner) => &**inner, hir::ExprBlock(ref block) => match block.expr { Some(ref tail) => &**tail, None => break @@ -710,10 +710,27 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, if !is_const { v.add_qualif(ConstQualif::NOT_CONST); if v.mode != Mode::Var { - span_err!(v.tcx.sess, e.span, E0015, - "function calls in {}s are limited to \ - constant functions, \ - struct and enum constructors", v.msg()); + fn span_limited_call_error(tcx: &ty::ctxt, span: Span, s: &str) { + span_err!(tcx.sess, span, E0015, "{}", s); + } + + // FIXME(#24111) Remove this check when const fn stabilizes + if let UnstableFeatures::Disallow = v.tcx.sess.opts.unstable_features { + span_limited_call_error(&v.tcx, e.span, + &format!("function calls in {}s are limited to \ + struct and enum constructors", + v.msg())); + v.tcx.sess.span_note(e.span, + "a limited form of compile-time function \ + evaluation is available on a nightly \ + compiler via `const fn`"); + } else { + span_limited_call_error(&v.tcx, e.span, + &format!("function calls in {}s are limited \ + to constant functions, \ + struct and enum constructors", + v.msg())); + } } } } @@ -763,7 +780,6 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, hir::ExprField(..) | hir::ExprTupField(..) | hir::ExprVec(_) | - hir::ExprParen(..) | hir::ExprTup(..) => {} // Conditional control flow (possible to implement). @@ -909,9 +925,9 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'tcx> { // Borrowed statics can specifically *only* have their address taken, // not any number of other borrows such as borrowing fields, reading // elements of an array, etc. - self.tcx.sess.span_err(borrow_span, - "cannot refer to the interior of another \ - static, use a constant instead"); + span_err!(self.tcx.sess, borrow_span, E0494, + "cannot refer to the interior of another \ + static, use a constant instead"); } break; } diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 8d592c9262..f8786c7daa 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -29,13 +29,13 @@ use middle::ty::*; use middle::ty; use std::cmp::Ordering; use std::fmt; -use std::iter::{range_inclusive, FromIterator, IntoIterator, repeat}; -use std::slice; +use std::iter::{FromIterator, IntoIterator, repeat}; use rustc_front::hir; use rustc_front::hir::Pat; use rustc_front::visit::{self, Visitor, FnKind}; use rustc_front::util as front_util; +use rustc_back::slice; use syntax::ast::{self, DUMMY_NODE_ID, NodeId}; use syntax::ast_util; @@ -245,7 +245,7 @@ fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat) let pat_ty = cx.tcx.pat_ty(p); if let ty::TyEnum(edef, _) = pat_ty.sty { let def = cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def()); - if let Some(DefLocal(_)) = def { + if let Some(DefLocal(..)) = def { if edef.variants.iter().any(|variant| variant.name == ident.node.name && variant.kind() == VariantKind::Unit @@ -272,7 +272,7 @@ fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat) fn check_for_static_nan(cx: &MatchCheckCtxt, pat: &Pat) { front_util::walk_pat(pat, |p| { if let hir::PatLit(ref expr) = p.node { - match eval_const_expr_partial(cx.tcx, &**expr, ExprTypeChecked) { + 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, \ @@ -281,11 +281,10 @@ fn check_for_static_nan(cx: &MatchCheckCtxt, pat: &Pat) { Ok(_) => {} Err(err) => { - let subspan = p.span.lo <= err.span.lo && err.span.hi <= p.span.hi; - cx.tcx.sess.span_err(err.span, - &format!("constant evaluation error: {}", - err.description())); - if !subspan { + span_err!(cx.tcx.sess, err.span, E0471, + "constant evaluation error: {}", + err.description()); + if !p.span.contains(err.span) { cx.tcx.sess.span_note(p.span, "in pattern here") } @@ -404,7 +403,7 @@ fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, matrix: &Matrix, source: hir: fn const_val_to_expr(value: &ConstVal) -> P { let node = match value { - &ConstVal::Bool(b) => hir::LitBool(b), + &ConstVal::Bool(b) => ast::LitBool(b), _ => unreachable!() }; P(hir::Expr { @@ -519,14 +518,14 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor, ty::TyEnum(adt, _) | ty::TyStruct(adt, _) => { let v = adt.variant_of_ctor(ctor); - if let VariantKind::Dict = v.kind() { + if let VariantKind::Struct = v.kind() { let field_pats: Vec<_> = v.fields.iter() .zip(pats) .filter(|&(_, ref pat)| pat.node != hir::PatWild(hir::PatWildSingle)) .map(|(field, pat)| Spanned { span: DUMMY_SP, node: hir::FieldPat { - ident: ast::Ident::new(field.name), + name: field.name, pat: pat, is_shorthand: false, } @@ -616,7 +615,7 @@ fn all_constructors(_cx: &MatchCheckCtxt, left_ty: Ty, ty::TyRef(_, ty::TypeAndMut { ty, .. }) => match ty.sty { ty::TySlice(_) => - range_inclusive(0, max_slice_length).map(|length| Slice(length)).collect(), + (0..max_slice_length+1).map(|length| Slice(length)).collect(), _ => vec![Single] }, @@ -791,7 +790,7 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat, match left_ty.sty { ty::TyArray(_, _) => vec!(Single), _ => if slice.is_some() { - range_inclusive(before.len() + after.len(), max_slice_length) + (before.len() + after.len()..max_slice_length+1) .map(|length| Slice(length)) .collect() } else { @@ -910,7 +909,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], let def_variant = adt.variant_of_def(def); if variant.did == def_variant.did { Some(variant.fields.iter().map(|sf| { - match pattern_fields.iter().find(|f| f.node.ident.name == sf.name) { + match pattern_fields.iter().find(|f| f.node.name == sf.name) { Some(ref f) => &*f.node.pat, _ => DUMMY_WILD_PAT } diff --git a/src/librustc/middle/check_no_asm.rs b/src/librustc/middle/check_no_asm.rs index aa1b7457aa..b9f8f20536 100644 --- a/src/librustc/middle/check_no_asm.rs +++ b/src/librustc/middle/check_no_asm.rs @@ -32,8 +32,8 @@ struct CheckNoAsm<'a> { impl<'a, 'v> Visitor<'v> for CheckNoAsm<'a> { fn visit_expr(&mut self, e: &ast::Expr) { match e.node { - ast::ExprInlineAsm(_) => self.sess.span_err(e.span, - "asm! is unsupported on this target"), + ast::ExprInlineAsm(_) => span_err!(self.sess, e.span, E0472, + "asm! is unsupported on this target"), _ => {}, } visit::walk_expr(self, e) diff --git a/src/librustc/middle/check_static_recursion.rs b/src/librustc/middle/check_static_recursion.rs index 942d8313ec..45671367a5 100644 --- a/src/librustc/middle/check_static_recursion.rs +++ b/src/librustc/middle/check_static_recursion.rs @@ -54,7 +54,7 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckCrateVisitor<'a, 'ast> { let mut recursion_visitor = CheckItemRecursionVisitor::new(self, &variant.span); recursion_visitor.populate_enum_discriminants(enum_def); - recursion_visitor.visit_variant(variant, generics); + recursion_visitor.visit_variant(variant, generics, it.id); } } } @@ -168,7 +168,7 @@ impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> { let mut discriminant_map = self.discriminant_map.borrow_mut(); match enum_definition.variants.first() { None => { return; } - Some(variant) if discriminant_map.contains_key(&variant.node.id) => { + Some(variant) if discriminant_map.contains_key(&variant.node.data.id()) => { return; } _ => {} @@ -177,7 +177,7 @@ impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> { // Go through all the variants. let mut variant_stack: Vec = Vec::new(); for variant in enum_definition.variants.iter().rev() { - variant_stack.push(variant.node.id); + variant_stack.push(variant.node.data.id()); // When we find an expression, every variant currently on the stack // is affected by that expression. if let Some(ref expr) = variant.node.disr_expr { @@ -201,14 +201,14 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> { } fn visit_enum_def(&mut self, enum_definition: &'ast hir::EnumDef, - generics: &'ast hir::Generics) { + generics: &'ast hir::Generics, item_id: ast::NodeId, _: Span) { self.populate_enum_discriminants(enum_definition); - visit::walk_enum_def(self, enum_definition, generics); + visit::walk_enum_def(self, enum_definition, generics, item_id); } fn visit_variant(&mut self, variant: &'ast hir::Variant, - _: &'ast hir::Generics) { - let variant_id = variant.node.id; + _: &'ast hir::Generics, _: ast::NodeId) { + let variant_id = variant.node.data.id(); let maybe_expr; if let Some(get_expr) = self.discriminant_map.borrow().get(&variant_id) { // This is necessary because we need to let the `discriminant_map` @@ -240,37 +240,44 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> { match self.def_map.borrow().get(&e.id).map(|d| d.base_def) { Some(DefStatic(def_id, _)) | Some(DefAssociatedConst(def_id)) | - Some(DefConst(def_id)) if def_id.is_local() => { - match self.ast_map.get(def_id.node) { - ast_map::NodeItem(item) => - self.visit_item(item), - ast_map::NodeTraitItem(item) => - self.visit_trait_item(item), - ast_map::NodeImplItem(item) => - self.visit_impl_item(item), - ast_map::NodeForeignItem(_) => {}, - _ => { - self.sess.span_bug( - e.span, - &format!("expected item, found {}", - self.ast_map.node_to_string(def_id.node))); - } + Some(DefConst(def_id)) => { + if let Some(node_id) = self.ast_map.as_local_node_id(def_id) { + match self.ast_map.get(node_id) { + ast_map::NodeItem(item) => + self.visit_item(item), + ast_map::NodeTraitItem(item) => + self.visit_trait_item(item), + ast_map::NodeImplItem(item) => + self.visit_impl_item(item), + ast_map::NodeForeignItem(_) => {}, + _ => { + self.sess.span_bug( + e.span, + &format!("expected item, found {}", + self.ast_map.node_to_string(node_id))); + } + } } } // For variants, we only want to check expressions that // affect the specific variant used, but we need to check // the whole enum definition to see what expression that // might be (if any). - Some(DefVariant(enum_id, variant_id, false)) if enum_id.is_local() => { - if let hir::ItemEnum(ref enum_def, ref generics) = - self.ast_map.expect_item(enum_id.local_id()).node { - self.populate_enum_discriminants(enum_def); - let variant = self.ast_map.expect_variant(variant_id.local_id()); - self.visit_variant(variant, generics); - } else { - self.sess.span_bug(e.span, - "`check_static_recursion` found \ - non-enum in DefVariant"); + Some(DefVariant(enum_id, variant_id, false)) => { + if let Some(enum_node_id) = self.ast_map.as_local_node_id(enum_id) { + if let hir::ItemEnum(ref enum_def, ref generics) = + self.ast_map.expect_item(enum_node_id).node + { + self.populate_enum_discriminants(enum_def); + let enum_id = self.ast_map.as_local_node_id(enum_id).unwrap(); + let variant_id = self.ast_map.as_local_node_id(variant_id).unwrap(); + let variant = self.ast_map.expect_variant(variant_id); + self.visit_variant(variant, generics, enum_id); + } else { + self.sess.span_bug(e.span, + "`check_static_recursion` found \ + non-enum in DefVariant"); + } } } _ => () diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index e1cf6ace84..1651e71c49 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -19,13 +19,14 @@ use front::map::blocks::FnLikeNode; use metadata::csearch; use metadata::inline::InlinedItem; use middle::{astencode, def, infer, subst, traits}; -use middle::def_id::{DefId}; +use middle::def_id::DefId; use middle::pat_util::def_to_path; use middle::ty::{self, Ty}; use middle::astconv_util::ast_ty_to_prim_ty; use util::num::ToPrimitive; +use util::nodemap::NodeMap; -use syntax::ast; +use syntax::{ast, abi}; use rustc_front::hir::Expr; use rustc_front::hir; use rustc_front::visit::FnKind; @@ -38,6 +39,7 @@ use std::borrow::{Cow, IntoCow}; use std::num::wrapping::OverflowingOps; use std::cmp::Ordering; use std::collections::hash_map::Entry::Vacant; +use std::mem::transmute; use std::{i8, i16, i32, i64, u8, u16, u32, u64}; use std::rc::Rc; @@ -62,48 +64,27 @@ fn lookup_variant_by_id<'a>(tcx: &'a ty::ctxt, fn variant_expr<'a>(variants: &'a [P], id: ast::NodeId) -> Option<&'a Expr> { for variant in variants { - if variant.node.id == id { + if variant.node.data.id() == id { return variant.node.disr_expr.as_ref().map(|e| &**e); } } None } - if enum_def.is_local() { - match tcx.map.find(enum_def.node) { + if let Some(enum_node_id) = tcx.map.as_local_node_id(enum_def) { + let variant_node_id = tcx.map.as_local_node_id(variant_def).unwrap(); + match tcx.map.find(enum_node_id) { None => None, Some(ast_map::NodeItem(it)) => match it.node { hir::ItemEnum(hir::EnumDef { ref variants }, _) => { - variant_expr(&variants[..], variant_def.node) + variant_expr(&variants[..], variant_node_id) } _ => None }, Some(_) => None } } else { - match tcx.extern_const_variants.borrow().get(&variant_def) { - Some(&ast::DUMMY_NODE_ID) => return None, - Some(&expr_id) => { - return Some(tcx.map.expect_expr(expr_id)); - } - None => {} - } - let expr_id = match csearch::maybe_get_item_ast(tcx, enum_def, - Box::new(|a, b, c, d| astencode::decode_inlined_item(a, b, c, d))) { - csearch::FoundAst::Found(&InlinedItem::Item(ref item)) => match item.node { - hir::ItemEnum(hir::EnumDef { ref variants }, _) => { - // NOTE this doesn't do the right thing, it compares inlined - // NodeId's to the original variant_def's NodeId, but they - // come from different crates, so they will likely never match. - variant_expr(&variants[..], variant_def.node).map(|e| e.id) - } - _ => None - }, - _ => None - }; - tcx.extern_const_variants.borrow_mut().insert(variant_def, - expr_id.unwrap_or(ast::DUMMY_NODE_ID)); - expr_id.map(|id| tcx.map.expect_expr(id)) + None } } @@ -111,8 +92,8 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>, def_id: DefId, maybe_ref_id: Option) -> Option<&'tcx Expr> { - if def_id.is_local() { - match tcx.map.find(def_id.node) { + if let Some(node_id) = tcx.map.as_local_node_id(def_id) { + match tcx.map.find(node_id) { None => None, Some(ast_map::NodeItem(it)) => match it.node { hir::ItemConst(_, ref const_expr) => { @@ -164,7 +145,7 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>, } let mut used_ref_id = false; let expr_id = match csearch::maybe_get_item_ast(tcx, def_id, - Box::new(|a, b, c, d| astencode::decode_inlined_item(a, b, c, d))) { + Box::new(astencode::decode_inlined_item)) { csearch::FoundAst::Found(&InlinedItem::Item(ref item)) => match item.node { hir::ItemConst(_, ref const_expr) => Some(const_expr.id), _ => None @@ -220,7 +201,7 @@ fn inline_const_fn_from_external_crate(tcx: &ty::ctxt, def_id: DefId) } let fn_id = match csearch::maybe_get_item_ast(tcx, def_id, - box |a, b, c, d| astencode::decode_inlined_item(a, b, c, d)) { + box astencode::decode_inlined_item) { csearch::FoundAst::Found(&InlinedItem::Item(ref item)) => Some(item.id), csearch::FoundAst::Found(&InlinedItem::ImplItem(_, ref item)) => Some(item.id), _ => None @@ -233,14 +214,14 @@ fn inline_const_fn_from_external_crate(tcx: &ty::ctxt, def_id: DefId) pub fn lookup_const_fn_by_id<'tcx>(tcx: &ty::ctxt<'tcx>, def_id: DefId) -> Option> { - let fn_id = if !def_id.is_local() { + let fn_id = if let Some(node_id) = tcx.map.as_local_node_id(def_id) { + node_id + } else { if let Some(fn_id) = inline_const_fn_from_external_crate(tcx, def_id) { fn_id } else { return None; } - } else { - def_id.node }; let fn_like = match FnLikeNode::from_node(tcx.map.get(fn_id)) { @@ -263,7 +244,7 @@ pub fn lookup_const_fn_by_id<'tcx>(tcx: &ty::ctxt<'tcx>, def_id: DefId) } } -#[derive(Clone, PartialEq)] +#[derive(Clone, Debug)] pub enum ConstVal { Float(f64), Int(i64), @@ -273,6 +254,28 @@ pub enum ConstVal { Bool(bool), Struct(ast::NodeId), Tuple(ast::NodeId), + Function(DefId), +} + +/// Note that equality for `ConstVal` means that the it is the same +/// constant, not that the rust values are equal. In particular, `NaN +/// == NaN` (at least if it's the same NaN; distinct encodings for NaN +/// are considering unequal). +impl PartialEq for ConstVal { + fn eq(&self, other: &ConstVal) -> bool { + match (self, other) { + (&Float(a), &Float(b)) => unsafe{transmute::<_,u64>(a) == transmute::<_,u64>(b)}, + (&Int(a), &Int(b)) => a == b, + (&Uint(a), &Uint(b)) => a == b, + (&Str(ref a), &Str(ref b)) => a == b, + (&ByteStr(ref a), &ByteStr(ref b)) => a == b, + (&Bool(a), &Bool(b)) => a == b, + (&Struct(a), &Struct(b)) => a == b, + (&Tuple(a), &Tuple(b)) => a == b, + (&Function(a), &Function(b)) => a == b, + _ => false, + } + } } impl ConstVal { @@ -287,6 +290,7 @@ impl ConstVal { Bool(_) => "boolean", Struct(_) => "struct", Tuple(_) => "tuple", + Function(_) => "function definition", } } } @@ -314,7 +318,7 @@ pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr, span: Span) -> P let field_pats = fields.iter().map(|field| codemap::Spanned { span: codemap::DUMMY_SP, node: hir::FieldPat { - ident: field.ident.node, + name: field.name.node, pat: const_expr_to_pat(tcx, &*field.expr, span), is_shorthand: false, }, @@ -349,12 +353,13 @@ pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr, span: Span) -> P } pub fn eval_const_expr(tcx: &ty::ctxt, e: &Expr) -> ConstVal { - match eval_const_expr_partial(tcx, e, ExprTypeChecked) { + match eval_const_expr_partial(tcx, e, ExprTypeChecked, None) { Ok(r) => r, Err(s) => tcx.sess.span_fatal(s.span, &s.description()) } } +pub type FnArgMap<'a> = Option<&'a NodeMap>; #[derive(Clone)] pub struct ConstEvalErr { @@ -388,6 +393,7 @@ pub enum ErrKind { ShiftRightWithOverflow, MissingStructField, NonConstPath, + UnresolvedPath, ExpectedConstTuple, ExpectedConstStruct, TupleIndexOutOfBounds, @@ -424,7 +430,8 @@ impl ConstEvalErr { ShiftLeftWithOverflow => "attempted left shift with overflow".into_cow(), ShiftRightWithOverflow => "attempted right shift with overflow".into_cow(), MissingStructField => "nonexistent struct field".into_cow(), - NonConstPath => "non-constant path in constant expr".into_cow(), + NonConstPath => "non-constant path in constant expression".into_cow(), + UnresolvedPath => "unresolved path in constant expression".into_cow(), ExpectedConstTuple => "expected constant tuple".into_cow(), ExpectedConstStruct => "expected constant struct".into_cow(), TupleIndexOutOfBounds => "tuple index out of bounds".into_cow(), @@ -466,35 +473,35 @@ pub enum IntTy { I8, I16, I32, I64 } pub enum UintTy { U8, U16, U32, U64 } impl IntTy { - pub fn from(tcx: &ty::ctxt, t: hir::IntTy) -> IntTy { - let t = if let hir::TyIs = t { + pub fn from(tcx: &ty::ctxt, t: ast::IntTy) -> IntTy { + let t = if let ast::TyIs = t { tcx.sess.target.int_type } else { t }; match t { - hir::TyIs => unreachable!(), - hir::TyI8 => IntTy::I8, - hir::TyI16 => IntTy::I16, - hir::TyI32 => IntTy::I32, - hir::TyI64 => IntTy::I64, + ast::TyIs => unreachable!(), + ast::TyI8 => IntTy::I8, + ast::TyI16 => IntTy::I16, + ast::TyI32 => IntTy::I32, + ast::TyI64 => IntTy::I64, } } } impl UintTy { - pub fn from(tcx: &ty::ctxt, t: hir::UintTy) -> UintTy { - let t = if let hir::TyUs = t { + pub fn from(tcx: &ty::ctxt, t: ast::UintTy) -> UintTy { + let t = if let ast::TyUs = t { tcx.sess.target.uint_type } else { t }; match t { - hir::TyUs => unreachable!(), - hir::TyU8 => UintTy::U8, - hir::TyU16 => UintTy::U16, - hir::TyU32 => UintTy::U32, - hir::TyU64 => UintTy::U64, + ast::TyUs => unreachable!(), + ast::TyU8 => UintTy::U8, + ast::TyU16 => UintTy::U16, + ast::TyU32 => UintTy::U32, + ast::TyU64 => UintTy::U64, } } } @@ -736,7 +743,8 @@ pub_fn_checked_op!{ const_uint_checked_shr_via_int(a: u64, b: i64,.. UintTy) { /// computing the length of an array. (See also the FIXME above EvalHint.) pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, e: &Expr, - ty_hint: EvalHint<'tcx>) -> EvalResult { + ty_hint: EvalHint<'tcx>, + fn_args: FnArgMap) -> EvalResult { fn fromb(b: bool) -> ConstVal { Int(b as i64) } // Try to compute the type of the expression based on the EvalHint. @@ -773,7 +781,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, let result = match e.node { hir::ExprUnary(hir::UnNeg, ref inner) => { - match try!(eval_const_expr_partial(tcx, &**inner, ty_hint)) { + match try!(eval_const_expr_partial(tcx, &**inner, ty_hint, fn_args)) { Float(f) => Float(-f), Int(n) => try!(const_int_checked_neg(n, e, expr_int_type)), Uint(i) => { @@ -783,7 +791,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, } } hir::ExprUnary(hir::UnNot, ref inner) => { - match try!(eval_const_expr_partial(tcx, &**inner, ty_hint)) { + match try!(eval_const_expr_partial(tcx, &**inner, ty_hint, fn_args)) { Int(i) => Int(!i), Uint(i) => const_uint_not(i, expr_uint_type), Bool(b) => Bool(!b), @@ -801,8 +809,8 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, } _ => ty_hint }; - match (try!(eval_const_expr_partial(tcx, &**a, ty_hint)), - try!(eval_const_expr_partial(tcx, &**b, b_ty))) { + match (try!(eval_const_expr_partial(tcx, &**a, ty_hint, fn_args)), + try!(eval_const_expr_partial(tcx, &**b, b_ty, fn_args))) { (Float(a), Float(b)) => { match op.node { hir::BiAdd => Float(a + b), @@ -909,18 +917,31 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, } }; - let val = try!(eval_const_expr_partial(tcx, &**base, base_hint)); + let val = try!(eval_const_expr_partial(tcx, &**base, base_hint, fn_args)); match cast_const(tcx, val, ety) { Ok(val) => val, Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }), } } hir::ExprPath(..) => { - let opt_def = tcx.def_map.borrow().get(&e.id).map(|d| d.full_def()); + let opt_def = if let Some(def) = tcx.def_map.borrow().get(&e.id) { + // After type-checking, def_map contains definition of the + // item referred to by the path. During type-checking, it + // can contain the raw output of path resolution, which + // might be a partially resolved path. + // FIXME: There's probably a better way to make sure we don't + // panic here. + if def.depth != 0 { + signal!(e, UnresolvedPath); + } + Some(def.full_def()) + } else { + None + }; let (const_expr, const_ty) = match opt_def { Some(def::DefConst(def_id)) => { - if def_id.is_local() { - match tcx.map.find(def_id.node) { + if let Some(node_id) = tcx.map.as_local_node_id(def_id) { + match tcx.map.find(node_id) { Some(ast_map::NodeItem(it)) => match it.node { hir::ItemConst(ref ty, ref expr) => { (Some(&**expr), Some(&**ty)) @@ -934,9 +955,9 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, } } Some(def::DefAssociatedConst(def_id)) => { - if def_id.is_local() { + if let Some(node_id) = tcx.map.as_local_node_id(def_id) { match tcx.impl_or_trait_item(def_id).container() { - ty::TraitContainer(trait_id) => match tcx.map.find(def_id.node) { + ty::TraitContainer(trait_id) => match tcx.map.find(node_id) { Some(ast_map::NodeTraitItem(ti)) => match ti.node { hir::ConstTraitItem(ref ty, _) => { if let ExprTypeChecked = ty_hint { @@ -954,7 +975,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, }, _ => (None, None) }, - ty::ImplContainer(_) => match tcx.map.find(def_id.node) { + ty::ImplContainer(_) => match tcx.map.find(node_id) { Some(ast_map::NodeImplItem(ii)) => match ii.node { hir::ConstImplItem(ref ty, ref expr) => { (Some(&**expr), Some(&**ty)) @@ -974,6 +995,16 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, Some(def::DefStruct(_)) => { return Ok(ConstVal::Struct(e.id)) } + Some(def::DefLocal(_, id)) => { + debug!("DefLocal({:?}): {:?}", id, fn_args); + if let Some(val) = fn_args.and_then(|args| args.get(&id)) { + return Ok(val.clone()); + } else { + (None, None) + } + }, + Some(def::DefFn(id, _)) => return Ok(Function(id)), + // FIXME: implement const methods? _ => (None, None) }; let const_expr = match const_expr { @@ -991,15 +1022,76 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, } else { ty_hint }; - try!(eval_const_expr_partial(tcx, const_expr, item_hint)) + try!(eval_const_expr_partial(tcx, const_expr, item_hint, fn_args)) } + hir::ExprCall(ref callee, ref args) => { + let sub_ty_hint = if let ExprTypeChecked = ty_hint { + ExprTypeChecked + } else { + UncheckedExprNoHint // we cannot reason about UncheckedExprHint here + }; + let ( + decl, + unsafety, + abi, + block, + constness, + ) = match try!(eval_const_expr_partial(tcx, callee, sub_ty_hint, fn_args)) { + Function(did) => if did.is_local() { + match tcx.map.find(did.index.as_u32()) { + Some(ast_map::NodeItem(it)) => match it.node { + hir::ItemFn( + ref decl, + unsafety, + constness, + abi, + _, // ducktype generics? types are funky in const_eval + ref block, + ) => (decl, unsafety, abi, block, constness), + _ => signal!(e, NonConstPath), + }, + _ => signal!(e, NonConstPath), + } + } else { + signal!(e, NonConstPath) + }, + _ => signal!(e, NonConstPath), + }; + if let ExprTypeChecked = ty_hint { + // no need to check for constness... either check_const + // already forbids this or we const eval over whatever + // we want + } else { + // we don't know much about the function, so we force it to be a const fn + // so compilation will fail later in case the const fn's body is not const + assert_eq!(constness, hir::Constness::Const) + } + assert_eq!(decl.inputs.len(), args.len()); + assert_eq!(unsafety, hir::Unsafety::Normal); + assert_eq!(abi, abi::Abi::Rust); + + let mut call_args = NodeMap(); + for (arg, arg_expr) in decl.inputs.iter().zip(args.iter()) { + let arg_val = try!(eval_const_expr_partial( + tcx, + arg_expr, + sub_ty_hint, + fn_args + )); + debug!("const call arg: {:?}", arg); + let old = call_args.insert(arg.pat.id, arg_val); + assert!(old.is_none()); + } + let result = block.expr.as_ref().unwrap(); + debug!("const call({:?})", call_args); + try!(eval_const_expr_partial(tcx, &**result, ty_hint, Some(&call_args))) + }, hir::ExprLit(ref lit) => { lit_to_const(&**lit, ety) } - hir::ExprParen(ref e) => try!(eval_const_expr_partial(tcx, &**e, ty_hint)), hir::ExprBlock(ref block) => { match block.expr { - Some(ref expr) => try!(eval_const_expr_partial(tcx, &**expr, ty_hint)), + Some(ref expr) => try!(eval_const_expr_partial(tcx, &**expr, ty_hint, fn_args)), None => Int(0) } } @@ -1011,11 +1103,11 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, } else { UncheckedExprNoHint }; - if let Ok(c) = eval_const_expr_partial(tcx, base, base_hint) { + if let Ok(c) = eval_const_expr_partial(tcx, base, base_hint, fn_args) { if let Tuple(tup_id) = c { if let hir::ExprTup(ref fields) = tcx.map.expect_expr(tup_id).node { if index.node < fields.len() { - return eval_const_expr_partial(tcx, &fields[index.node], base_hint) + return eval_const_expr_partial(tcx, &fields[index.node], base_hint, fn_args) } else { signal!(e, TupleIndexOutOfBounds); } @@ -1036,14 +1128,14 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, } else { UncheckedExprNoHint }; - if let Ok(c) = eval_const_expr_partial(tcx, base, base_hint) { + if let Ok(c) = eval_const_expr_partial(tcx, base, base_hint, fn_args) { if let Struct(struct_id) = c { if let hir::ExprStruct(_, ref fields, _) = tcx.map.expect_expr(struct_id).node { // Check that the given field exists and evaluate it // if the idents are compared run-pass/issue-19244 fails - if let Some(f) = fields.iter().find(|f| f.ident.node.name - == field_name.node.name) { - return eval_const_expr_partial(tcx, &*f.expr, base_hint) + if let Some(f) = fields.iter().find(|f| f.name.node + == field_name.node) { + return eval_const_expr_partial(tcx, &*f.expr, base_hint, fn_args) } else { signal!(e, MissingStructField); } @@ -1110,7 +1202,7 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>, match selection { traits::VtableImpl(ref impl_data) => { match tcx.associated_consts(impl_data.impl_def_id) - .iter().find(|ic| ic.name == ti.ident.name) { + .iter().find(|ic| ic.name == ti.name) { Some(ic) => lookup_const_by_id(tcx, ic.def_id, None), None => match ti.node { hir::ConstTraitItem(_, Some(ref expr)) => Some(&*expr), @@ -1141,60 +1233,60 @@ fn cast_const<'tcx>(tcx: &ty::ctxt<'tcx>, val: ConstVal, ty: Ty) -> CastResult { // Issue #23890: If isize/usize, then dispatch to appropriate target representation type match (&ty.sty, tcx.sess.target.int_type, tcx.sess.target.uint_type) { - (&ty::TyInt(hir::TyIs), hir::TyI32, _) => return convert_val!(i32, Int, i64), - (&ty::TyInt(hir::TyIs), hir::TyI64, _) => return convert_val!(i64, Int, i64), - (&ty::TyInt(hir::TyIs), _, _) => panic!("unexpected target.int_type"), + (&ty::TyInt(ast::TyIs), ast::TyI32, _) => return convert_val!(i32, Int, i64), + (&ty::TyInt(ast::TyIs), ast::TyI64, _) => return convert_val!(i64, Int, i64), + (&ty::TyInt(ast::TyIs), _, _) => panic!("unexpected target.int_type"), - (&ty::TyUint(hir::TyUs), _, hir::TyU32) => return convert_val!(u32, Uint, u64), - (&ty::TyUint(hir::TyUs), _, hir::TyU64) => return convert_val!(u64, Uint, u64), - (&ty::TyUint(hir::TyUs), _, _) => panic!("unexpected target.uint_type"), + (&ty::TyUint(ast::TyUs), _, ast::TyU32) => return convert_val!(u32, Uint, u64), + (&ty::TyUint(ast::TyUs), _, ast::TyU64) => return convert_val!(u64, Uint, u64), + (&ty::TyUint(ast::TyUs), _, _) => panic!("unexpected target.uint_type"), _ => {} } match ty.sty { - ty::TyInt(hir::TyIs) => unreachable!(), - ty::TyUint(hir::TyUs) => unreachable!(), + ty::TyInt(ast::TyIs) => unreachable!(), + ty::TyUint(ast::TyUs) => unreachable!(), - ty::TyInt(hir::TyI8) => convert_val!(i8, Int, i64), - ty::TyInt(hir::TyI16) => convert_val!(i16, Int, i64), - ty::TyInt(hir::TyI32) => convert_val!(i32, Int, i64), - ty::TyInt(hir::TyI64) => convert_val!(i64, Int, i64), + ty::TyInt(ast::TyI8) => convert_val!(i8, Int, i64), + ty::TyInt(ast::TyI16) => convert_val!(i16, Int, i64), + ty::TyInt(ast::TyI32) => convert_val!(i32, Int, i64), + ty::TyInt(ast::TyI64) => convert_val!(i64, Int, i64), - ty::TyUint(hir::TyU8) => convert_val!(u8, Uint, u64), - ty::TyUint(hir::TyU16) => convert_val!(u16, Uint, u64), - ty::TyUint(hir::TyU32) => convert_val!(u32, Uint, u64), - ty::TyUint(hir::TyU64) => convert_val!(u64, Uint, u64), + ty::TyUint(ast::TyU8) => convert_val!(u8, Uint, u64), + ty::TyUint(ast::TyU16) => convert_val!(u16, Uint, u64), + ty::TyUint(ast::TyU32) => convert_val!(u32, Uint, u64), + ty::TyUint(ast::TyU64) => convert_val!(u64, Uint, u64), - ty::TyFloat(hir::TyF32) => convert_val!(f32, Float, f64), - ty::TyFloat(hir::TyF64) => convert_val!(f64, Float, f64), + ty::TyFloat(ast::TyF32) => convert_val!(f32, Float, f64), + ty::TyFloat(ast::TyF64) => convert_val!(f64, Float, f64), _ => Err(ErrKind::CannotCast), } } -fn lit_to_const(lit: &hir::Lit, ty_hint: Option) -> ConstVal { +fn lit_to_const(lit: &ast::Lit, ty_hint: Option) -> ConstVal { match lit.node { - hir::LitStr(ref s, _) => Str((*s).clone()), - hir::LitByteStr(ref data) => { + ast::LitStr(ref s, _) => Str((*s).clone()), + ast::LitByteStr(ref data) => { ByteStr(data.clone()) } - hir::LitByte(n) => Uint(n as u64), - hir::LitChar(n) => Uint(n as u64), - hir::LitInt(n, hir::SignedIntLit(_, hir::Plus)) => Int(n as i64), - hir::LitInt(n, hir::UnsuffixedIntLit(hir::Plus)) => { + ast::LitByte(n) => Uint(n as u64), + ast::LitChar(n) => Uint(n as u64), + ast::LitInt(n, ast::SignedIntLit(_, ast::Plus)) => Int(n as i64), + ast::LitInt(n, ast::UnsuffixedIntLit(ast::Plus)) => { match ty_hint.map(|ty| &ty.sty) { Some(&ty::TyUint(_)) => Uint(n), _ => Int(n as i64) } } - hir::LitInt(n, hir::SignedIntLit(_, hir::Minus)) | - hir::LitInt(n, hir::UnsuffixedIntLit(hir::Minus)) => Int(-(n as i64)), - hir::LitInt(n, hir::UnsignedIntLit(_)) => Uint(n), - hir::LitFloat(ref n, _) | - hir::LitFloatUnsuffixed(ref n) => { + ast::LitInt(n, ast::SignedIntLit(_, ast::Minus)) | + ast::LitInt(n, ast::UnsuffixedIntLit(ast::Minus)) => Int(-(n as i64)), + ast::LitInt(n, ast::UnsignedIntLit(_)) => Uint(n), + ast::LitFloat(ref n, _) | + ast::LitFloatUnsuffixed(ref n) => { Float(n.parse::().unwrap() as f64) } - hir::LitBool(b) => Bool(b) + ast::LitBool(b) => Bool(b) } } @@ -1222,14 +1314,14 @@ pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option { pub fn compare_lit_exprs<'tcx>(tcx: &ty::ctxt<'tcx>, a: &Expr, b: &Expr) -> Option { - let a = match eval_const_expr_partial(tcx, a, ExprTypeChecked) { + let a = match eval_const_expr_partial(tcx, a, ExprTypeChecked, None) { Ok(a) => a, Err(e) => { tcx.sess.span_err(a.span, &e.description()); return None; } }; - let b = match eval_const_expr_partial(tcx, b, ExprTypeChecked) { + let b = match eval_const_expr_partial(tcx, b, ExprTypeChecked, None) { Ok(b) => b, Err(e) => { tcx.sess.span_err(b.span, &e.description()); diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index 14ba241f62..caedc81184 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -24,6 +24,7 @@ use std::usize; use syntax::ast; use syntax::ast_util::IdRange; use syntax::print::pp; +use syntax::print::pprust::PrintState; use util::nodemap::NodeMap; use rustc_front::hir; use rustc_front::visit; @@ -113,7 +114,7 @@ impl<'a, 'tcx, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, 'tcx, O ps: &mut pprust::State, node: pprust::AnnNode) -> io::Result<()> { let id = match node { - pprust::NodeIdent(_) | pprust::NodeName(_) => 0, + pprust::NodeName(_) => 0, pprust::NodeExpr(expr) => expr.id, pprust::NodeBlock(blk) => blk.id, pprust::NodeItem(_) | pprust::NodeSubItem(_) => 0, diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index ed9ca48b39..8c995ca292 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -15,7 +15,6 @@ use front::map as ast_map; use rustc_front::hir; use rustc_front::visit::{self, Visitor}; -use rustc_front::attr::{self, AttrMetaMethods}; use middle::{def, pat_util, privacy, ty}; use middle::def_id::{DefId}; @@ -24,22 +23,21 @@ use util::nodemap::NodeSet; use std::collections::HashSet; use syntax::{ast, codemap}; +use syntax::attr::{self, AttrMetaMethods}; // Any local node that may call something in its body block should be // explored. For example, if it's a live NodeItem that is a // function, then we should explore its block to check for codes that // may need to be marked as live. -fn should_explore(tcx: &ty::ctxt, def_id: DefId) -> bool { - if !def_id.is_local() { - return false; - } - - match tcx.map.find(def_id.node) { - Some(ast_map::NodeItem(..)) - | Some(ast_map::NodeImplItem(..)) - | Some(ast_map::NodeForeignItem(..)) - | Some(ast_map::NodeTraitItem(..)) => true, - _ => false +fn should_explore(tcx: &ty::ctxt, node_id: ast::NodeId) -> bool { + match tcx.map.find(node_id) { + Some(ast_map::NodeItem(..)) | + Some(ast_map::NodeImplItem(..)) | + Some(ast_map::NodeForeignItem(..)) | + Some(ast_map::NodeTraitItem(..)) => + true, + _ => + false } } @@ -50,7 +48,7 @@ struct MarkSymbolVisitor<'a, 'tcx: 'a> { struct_has_extern_repr: bool, ignore_non_const_paths: bool, inherited_pub_visibility: bool, - ignore_variant_stack: Vec, + ignore_variant_stack: Vec, } impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { @@ -68,10 +66,19 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { } fn check_def_id(&mut self, def_id: DefId) { - if should_explore(self.tcx, def_id) { - self.worklist.push(def_id.node); + if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) { + if should_explore(self.tcx, node_id) { + self.worklist.push(node_id); + } + self.live_symbols.insert(node_id); + } + } + + fn insert_def_id(&mut self, def_id: DefId) { + if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) { + debug_assert!(!should_explore(self.tcx, node_id)); + self.live_symbols.insert(node_id); } - self.live_symbols.insert(def_id.node); } fn lookup_and_handle_definition(&mut self, id: &ast::NodeId) { @@ -88,13 +95,14 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { self.tcx.def_map.borrow().get(id).map(|def| { match def.full_def() { def::DefConst(_) | def::DefAssociatedConst(..) => { - self.check_def_id(def.def_id()) + self.check_def_id(def.def_id()); } _ if self.ignore_non_const_paths => (), def::DefPrimTy(_) => (), + def::DefSelfTy(..) => (), def::DefVariant(enum_id, variant_id, _) => { self.check_def_id(enum_id); - if !self.ignore_variant_stack.contains(&variant_id.node) { + if !self.ignore_variant_stack.contains(&variant_id) { self.check_def_id(variant_id); } } @@ -113,7 +121,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { fn handle_field_access(&mut self, lhs: &hir::Expr, name: ast::Name) { if let ty::TyStruct(def, _) = self.tcx.expr_ty_adjusted(lhs).sty { - self.live_symbols.insert(def.struct_variant().field_named(name).did.node); + self.insert_def_id(def.struct_variant().field_named(name).did); } else { self.tcx.sess.span_bug(lhs.span, "named field access on non-struct") } @@ -121,7 +129,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { fn handle_tup_field_access(&mut self, lhs: &hir::Expr, idx: usize) { if let ty::TyStruct(def, _) = self.tcx.expr_ty_adjusted(lhs).sty { - self.live_symbols.insert(def.struct_variant().fields[idx].did.node); + self.insert_def_id(def.struct_variant().fields[idx].did); } } @@ -137,7 +145,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { if let hir::PatWild(hir::PatWildSingle) = pat.node.pat.node { continue; } - self.live_symbols.insert(variant.field_named(pat.node.ident.name).did.node); + self.insert_def_id(variant.field_named(pat.node.name).did); } } @@ -207,11 +215,11 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> { - fn visit_struct_def(&mut self, def: &hir::StructDef, _: ast::Ident, - _: &hir::Generics, _: ast::NodeId) { + fn visit_variant_data(&mut self, def: &hir::VariantData, _: ast::Name, + _: &hir::Generics, _: ast::NodeId, _: codemap::Span) { let has_extern_repr = self.struct_has_extern_repr; let inherited_pub_visibility = self.inherited_pub_visibility; - let live_fields = def.fields.iter().filter(|f| { + let live_fields = def.fields().iter().filter(|f| { has_extern_repr || inherited_pub_visibility || match f.node.kind { hir::NamedField(_, hir::Public) => true, _ => false @@ -227,8 +235,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> { hir::ExprMethodCall(..) => { self.lookup_and_handle_method(expr.id); } - hir::ExprField(ref lhs, ref ident) => { - self.handle_field_access(&**lhs, ident.node.name); + hir::ExprField(ref lhs, ref name) => { + self.handle_field_access(&**lhs, name.node); } hir::ExprTupField(ref lhs, idx) => { self.handle_tup_field_access(&**lhs, idx.node); @@ -279,19 +287,24 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> { visit::walk_path(self, path); } + fn visit_path_list_item(&mut self, path: &hir::Path, item: &hir::PathListItem) { + self.lookup_and_handle_definition(&item.node.id()); + visit::walk_path_list_item(self, path, item); + } + fn visit_item(&mut self, _: &hir::Item) { // Do not recurse into items. These items will be added to the // worklist and recursed into manually if necessary. } } -fn has_allow_dead_code_or_lang_attr(attrs: &[hir::Attribute]) -> bool { +fn has_allow_dead_code_or_lang_attr(attrs: &[ast::Attribute]) -> bool { if attr::contains_name(attrs, "lang") { return true; } let dead_code = lint::builtin::DEAD_CODE.name_lower(); - for attr in lint::gather_attrs_from_hir(attrs) { + for attr in lint::gather_attrs(attrs) { match attr { Ok((ref name, lint::Allow, _)) if &name[..] == dead_code => return true, @@ -326,7 +339,8 @@ impl<'v> Visitor<'v> for LifeSeeder { } match item.node { hir::ItemEnum(ref enum_def, _) if allow_dead_code => { - self.worklist.extend(enum_def.variants.iter().map(|variant| variant.node.id)); + self.worklist.extend(enum_def.variants.iter() + .map(|variant| variant.node.data.id())); } hir::ItemTrait(_, _, _, ref trait_items) => { for trait_item in trait_items { @@ -413,7 +427,9 @@ fn find_live(tcx: &ty::ctxt, fn get_struct_ctor_id(item: &hir::Item) -> Option { match item.node { - hir::ItemStruct(ref struct_def, _) => struct_def.ctor_id, + hir::ItemStruct(ref struct_def, _) if !struct_def.is_struct() => { + Some(struct_def.id()) + } _ => None } } @@ -438,7 +454,7 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { } fn should_warn_about_field(&mut self, node: &hir::StructField_) -> bool { - let is_named = node.ident().is_some(); + let is_named = node.name().is_some(); let field_type = self.tcx.node_id_to_type(node.id); let is_marker_field = match field_type.ty_to_def_id() { Some(def_id) => self.tcx.lang_items.items().any(|(_, item)| *item == Some(def_id)), @@ -451,7 +467,7 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { } fn should_warn_about_variant(&mut self, variant: &hir::Variant_) -> bool { - !self.symbol_is_live(variant.id, None) + !self.symbol_is_live(variant.data.id(), None) && !has_allow_dead_code_or_lang_attr(&variant.attrs) } @@ -464,8 +480,10 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { // `ctor_id`. On the other hand, in a statement like // `type = ;` where refers to a struct_ctor, // DefMap maps to `id` instead. - fn symbol_is_live(&mut self, id: ast::NodeId, - ctor_id: Option) -> bool { + fn symbol_is_live(&mut self, + id: ast::NodeId, + ctor_id: Option) + -> bool { if self.live_symbols.contains(&id) || ctor_id.map_or(false, |ctor| self.live_symbols.contains(&ctor)) { @@ -476,14 +494,16 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { // method of a private type is used, but the type itself is never // called directly. let impl_items = self.tcx.impl_items.borrow(); - match self.tcx.inherent_impls.borrow().get(&DefId::local(id)) { + match self.tcx.inherent_impls.borrow().get(&self.tcx.map.local_def_id(id)) { None => (), Some(impl_list) => { for impl_did in impl_list.iter() { for item_did in impl_items.get(impl_did).unwrap().iter() { - if self.live_symbols.contains(&item_did.def_id() - .node) { - return true; + if let Some(item_node_id) = + self.tcx.map.as_local_node_id(item_did.def_id()) { + if self.live_symbols.contains(&item_node_id) { + return true; + } } } } @@ -515,7 +535,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> { self.warn_dead_code( item.id, item.span, - item.ident.name, + item.name, item.node.descriptive_variant() ); } else { @@ -523,8 +543,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> { hir::ItemEnum(ref enum_def, _) => { for variant in &enum_def.variants { if self.should_warn_about_variant(&variant.node) { - self.warn_dead_code(variant.node.id, variant.span, - variant.node.name.name, "variant"); + self.warn_dead_code(variant.node.data.id(), variant.span, + variant.node.name, "variant"); } } }, @@ -536,7 +556,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> { fn visit_foreign_item(&mut self, fi: &hir::ForeignItem) { if !self.symbol_is_live(fi.id, None) { - self.warn_dead_code(fi.id, fi.span, fi.ident.name, fi.node.descriptive_variant()); + self.warn_dead_code(fi.id, fi.span, fi.name, fi.node.descriptive_variant()); } visit::walk_foreign_item(self, fi); } @@ -544,7 +564,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> { fn visit_struct_field(&mut self, field: &hir::StructField) { if self.should_warn_about_field(&field.node) { self.warn_dead_code(field.node.id, field.span, - field.node.ident().unwrap().name, "struct field"); + field.node.name().unwrap(), "struct field"); } visit::walk_struct_field(self, field); @@ -555,14 +575,14 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> { hir::ConstImplItem(_, ref expr) => { if !self.symbol_is_live(impl_item.id, None) { self.warn_dead_code(impl_item.id, impl_item.span, - impl_item.ident.name, "associated const"); + impl_item.name, "associated const"); } visit::walk_expr(self, expr) } hir::MethodImplItem(_, ref body) => { if !self.symbol_is_live(impl_item.id, None) { self.warn_dead_code(impl_item.id, impl_item.span, - impl_item.ident.name, "method"); + impl_item.name, "method"); } visit::walk_block(self, body) } diff --git a/src/librustc/middle/def.rs b/src/librustc/middle/def.rs index 86133aad67..ef2b918a9f 100644 --- a/src/librustc/middle/def.rs +++ b/src/librustc/middle/def.rs @@ -10,7 +10,7 @@ pub use self::Def::*; -use middle::def_id::{DefId, LOCAL_CRATE}; +use middle::def_id::DefId; use middle::privacy::LastPrivate; use middle::subst::ParamSpace; use util::nodemap::NodeMap; @@ -29,7 +29,8 @@ pub enum Def { DefStatic(DefId, bool /* is_mutbl */), DefConst(DefId), DefAssociatedConst(DefId), - DefLocal(ast::NodeId), + DefLocal(DefId, // def id of variable + ast::NodeId), // node id of variable DefVariant(DefId /* enum */, DefId /* variant */, bool /* is_structure */), DefTy(DefId, bool /* is_enum */), DefAssociatedTy(DefId /* trait */, DefId), @@ -37,20 +38,20 @@ pub enum Def { DefPrimTy(hir::PrimTy), DefTyParam(ParamSpace, u32, DefId, ast::Name), DefUse(DefId), - DefUpvar(ast::NodeId, // id of closed over local + DefUpvar(DefId, // def id of closed over local + ast::NodeId, // node id of closed over local usize, // index in the freevars list of the closure ast::NodeId), // expr node that creates the closure /// Note that if it's a tuple struct's definition, the node id of the DefId - /// may either refer to the item definition's id or the StructDef.ctor_id. + /// may either refer to the item definition's id or the VariantData.ctor_id. /// /// The cases that I have encountered so far are (this is not exhaustive): /// - If it's a ty_path referring to some tuple struct, then DefMap maps /// it to a def whose id is the item definition's id. /// - If it's an ExprPath referring to some tuple struct, then DefMap maps - /// it to a def whose id is the StructDef.ctor_id. + /// it to a def whose id is the VariantData.ctor_id. DefStruct(DefId), - DefRegion(ast::NodeId), DefLabel(ast::NodeId), DefMethod(DefId), } @@ -114,10 +115,21 @@ pub struct Export { } impl Def { - pub fn local_node_id(&self) -> ast::NodeId { - let def_id = self.def_id(); - assert_eq!(def_id.krate, LOCAL_CRATE); - def_id.node + pub fn var_id(&self) -> ast::NodeId { + match *self { + DefLocal(_, id) | + DefUpvar(_, id, _, _) => { + id + } + + DefFn(..) | DefMod(..) | DefForeignMod(..) | DefStatic(..) | + DefVariant(..) | DefTy(..) | DefAssociatedTy(..) | + DefTyParam(..) | DefUse(..) | DefStruct(..) | DefTrait(..) | + DefMethod(..) | DefConst(..) | DefAssociatedConst(..) | + DefPrimTy(..) | DefLabel(..) | DefSelfTy(..) => { + panic!("attempted .def_id() on invalid {:?}", self) + } + } } pub fn def_id(&self) -> DefId { @@ -126,19 +138,15 @@ impl Def { DefVariant(_, id, _) | DefTy(id, _) | DefAssociatedTy(_, id) | DefTyParam(_, _, id, _) | DefUse(id) | DefStruct(id) | DefTrait(id) | DefMethod(id) | DefConst(id) | DefAssociatedConst(id) | - DefSelfTy(Some(id), None)=> { + DefLocal(id, _) | DefUpvar(id, _, _, _) => { id } - DefLocal(id) | - DefUpvar(id, _, _) | - DefRegion(id) | - DefLabel(id) | - DefSelfTy(_, Some((_, id))) => { - DefId::local(id) - } - DefPrimTy(_) => panic!("attempted .def_id() on DefPrimTy"), - DefSelfTy(..) => panic!("attempted .def_id() on invalid DefSelfTy"), + DefLabel(..) | + DefPrimTy(..) | + DefSelfTy(..) => { + panic!("attempted .def_id() on invalid def: {:?}", self) + } } } diff --git a/src/librustc/middle/def_id.rs b/src/librustc/middle/def_id.rs index 2966339f0a..288eb01ebb 100644 --- a/src/librustc/middle/def_id.rs +++ b/src/librustc/middle/def_id.rs @@ -8,31 +8,69 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use metadata::cstore::LOCAL_CRATE; use middle::ty; -use syntax::ast::{CrateNum, NodeId}; +use syntax::ast::CrateNum; use std::fmt; +use std::u32; +/// A DefIndex is an index into the hir-map for a crate, identifying a +/// particular definition. It should really be considered an interned +/// shorthand for a particular DefPath. +#[derive(Clone, Debug, Eq, Ord, PartialOrd, PartialEq, RustcEncodable, + RustcDecodable, Hash, Copy)] +pub struct DefIndex(u32); + +impl DefIndex { + pub fn new(x: usize) -> DefIndex { + assert!(x < (u32::MAX as usize)); + DefIndex(x as u32) + } + + pub fn from_u32(x: u32) -> DefIndex { + DefIndex(x) + } + + pub fn as_usize(&self) -> usize { + self.0 as usize + } + + pub fn as_u32(&self) -> u32 { + self.0 + } +} + +/// The crate root is always assigned index 0 by the AST Map code, +/// thanks to `NodeCollector::new`. +pub const CRATE_DEF_INDEX: DefIndex = DefIndex(0); + +/// A DefId identifies a particular *definition*, by combining a crate +/// index and a def index. #[derive(Clone, Eq, Ord, PartialOrd, PartialEq, RustcEncodable, RustcDecodable, Hash, Copy)] pub struct DefId { pub krate: CrateNum, - pub node: NodeId, + pub index: DefIndex, } impl fmt::Debug for DefId { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "DefId {{ krate: {}, node: {}", - self.krate, self.node)); + try!(write!(f, "DefId {{ krate: {:?}, node: {:?}", + self.krate, self.index)); // Unfortunately, there seems to be no way to attempt to print // a path for a def-id, so I'll just make a best effort for now // and otherwise fallback to just printing the crate/node pair - try!(ty::tls::with_opt(|opt_tcx| { - if let Some(tcx) = opt_tcx { - try!(write!(f, " => {}", tcx.item_path_str(*self))); - } - Ok(()) - })); + if self.is_local() { // (1) + // (1) side-step fact that not all external things have paths at + // the moment, such as type parameters + try!(ty::tls::with_opt(|opt_tcx| { + if let Some(tcx) = opt_tcx { + try!(write!(f, " => {}", tcx.item_path_str(*self))); + } + Ok(()) + })); + } write!(f, " }}") } @@ -40,23 +78,11 @@ impl fmt::Debug for DefId { impl DefId { - pub fn local(id: NodeId) -> DefId { - DefId { krate: LOCAL_CRATE, node: id } - } - - /// Read the node id, asserting that this def-id is krate-local. - pub fn local_id(&self) -> NodeId { - assert_eq!(self.krate, LOCAL_CRATE); - self.node + pub fn local(index: DefIndex) -> DefId { + DefId { krate: LOCAL_CRATE, index: index } } pub fn is_local(&self) -> bool { self.krate == LOCAL_CRATE } } - - -/// Item definitions in the currently-compiled crate would have the CrateNum -/// LOCAL_CRATE in their DefId. -pub const LOCAL_CRATE: CrateNum = 0; - diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index d1e1434dad..f849580871 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -102,7 +102,6 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { fn visit_block(&mut self, block: &hir::Block) { let old_unsafe_context = self.unsafe_context; match block.rules { - hir::DefaultBlock => {} hir::UnsafeBlock(source) => { // By default only the outermost `unsafe` block is // "used" and so nested unsafe blocks are pointless @@ -131,6 +130,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { self.unsafe_context.push_unsafe_count = self.unsafe_context.push_unsafe_count.checked_sub(1).unwrap(); } + hir::DefaultBlock | hir::PushUnstableBlock | hir:: PopUnstableBlock => {} } visit::walk_block(self, block); @@ -151,7 +151,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { } } hir::ExprCall(ref base, _) => { - let base_type = self.tcx.node_id_to_type(base.id); + let base_type = self.tcx.expr_ty_adjusted(base); debug!("effect: call case, base type is {:?}", base_type); if type_is_unsafe_function(base_type) { @@ -159,7 +159,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { } } hir::ExprUnary(hir::UnDeref, ref base) => { - let base_type = self.tcx.node_id_to_type(base.id); + let base_type = self.tcx.expr_ty_adjusted(base); debug!("effect: unary case, base type is {:?}", base_type); if let ty::TyRawPtr(_) = base_type.sty { diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs index e32a9b280f..3cfcb52f90 100644 --- a/src/librustc/middle/entry.rs +++ b/src/librustc/middle/entry.rs @@ -12,10 +12,10 @@ use front::map as ast_map; use session::{config, Session}; use syntax::ast::NodeId; -use rustc_front::hir::{Item, ItemFn}; -use rustc_front::attr; +use syntax::attr; use syntax::codemap::Span; use syntax::entry::EntryPointType; +use rustc_front::hir::{Item, ItemFn}; use rustc_front::visit; use rustc_front::visit::Visitor; @@ -85,7 +85,7 @@ fn entry_point_type(item: &Item, depth: usize) -> EntryPointType { EntryPointType::Start } else if attr::contains_name(&item.attrs, "main") { EntryPointType::MainAttr - } else if item.ident.name == "main" { + } else if item.name.as_str() == "main" { if depth == 1 { // This is a top-level function so can be 'main' EntryPointType::MainNamed diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index a8fed5eab1..fb3a6b0f42 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -244,7 +244,7 @@ impl OverloadedCallType { // can just use the tcx as the typer. // // FIXME(stage0): the :'t here is probably only important for stage0 -pub struct ExprUseVisitor<'d, 't, 'a: 't, 'tcx:'a+'d+'t> { +pub struct ExprUseVisitor<'d, 't, 'a: 't, 'tcx:'a+'d> { typer: &'t infer::InferCtxt<'a, 'tcx>, mc: mc::MemCategorizationContext<'t, 'a, 'tcx>, delegate: &'d mut Delegate<'tcx>, @@ -276,17 +276,13 @@ enum PassArgs { } impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { - pub fn new(delegate: &'d mut Delegate<'tcx>, + pub fn new(delegate: &'d mut (Delegate<'tcx>), typer: &'t infer::InferCtxt<'a, 'tcx>) - -> ExprUseVisitor<'d,'t,'a,'tcx> + -> ExprUseVisitor<'d,'t,'a,'tcx> where 'tcx:'a+'d { - let result = ExprUseVisitor { - typer: typer, - mc: mc::MemCategorizationContext::new(typer), - delegate: delegate, - }; - - result + let mc: mc::MemCategorizationContext<'t, 'a, 'tcx> = + mc::MemCategorizationContext::new(typer); + ExprUseVisitor { typer: typer, mc: mc, delegate: delegate } } pub fn walk_fn(&mut self, @@ -362,9 +358,6 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { let cmt = return_if_err!(self.mc.cat_expr(expr)); self.delegate.borrow(expr.id, expr.span, cmt, r, bk, cause); - // Note: Unlike consume, we can ignore ExprParen. cat_expr - // already skips over them, and walk will uncover any - // attachments or whatever. self.walk_expr(expr) } @@ -378,10 +371,6 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { self.walk_adjustment(expr); match expr.node { - hir::ExprParen(ref subexpr) => { - self.walk_expr(&**subexpr) - } - hir::ExprPath(..) => { } hir::ExprUnary(hir::UnDeref, ref base) => { // *base @@ -532,11 +521,14 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { self.consume_expr(&**base); } - hir::ExprAssignOp(_, ref lhs, ref rhs) => { - // This will have to change if/when we support - // overloaded operators for `+=` and so forth. - self.mutate_expr(expr, &**lhs, WriteAndRead); - self.consume_expr(&**rhs); + hir::ExprAssignOp(op, ref lhs, ref rhs) => { + // NB All our assignment operations take the RHS by value + assert!(::rustc_front::util::is_by_value_binop(op.node)); + + if !self.walk_overloaded_operator(expr, lhs, vec![rhs], PassArgs::ByValue) { + self.mutate_expr(expr, &**lhs, WriteAndRead); + self.consume_expr(&**rhs); + } } hir::ExprRepeat(ref base, ref count) => { @@ -548,17 +540,8 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { self.walk_captures(expr) } - hir::ExprBox(ref place, ref base) => { - match *place { - Some(ref place) => self.consume_expr(&**place), - None => {} - } + hir::ExprBox(ref base) => { self.consume_expr(&**base); - if place.is_some() { - self.tcx().sess.span_bug( - expr.span, - "box with explicit place remains after expansion"); - } } } } @@ -714,7 +697,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { -> bool { fields.iter().any( - |f| f.ident.node.name == field.name) + |f| f.name.node == field.name) } } @@ -930,7 +913,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { self.consume_expr(&*arm.body); } - /// Walks an pat that occurs in isolation (i.e. top-level of fn + /// Walks a pat that occurs in isolation (i.e. top-level of fn /// arg or let binding. *Not* a match arm or nested pat.) fn walk_irrefutable_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat) { let mut mode = Unknown; @@ -1153,7 +1136,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { } hir::PatIdent(_, _, Some(_)) => { - // Do nothing; this is a binding (not a enum + // Do nothing; this is a binding (not an enum // variant or struct), and the cat_pattern call // will visit the substructure recursively. } @@ -1162,7 +1145,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { hir::PatRegion(..) | hir::PatLit(..) | hir::PatRange(..) | hir::PatVec(..) => { // Similarly, each of these cases does not - // correspond to a enum variant or struct, so we + // correspond to an enum variant or struct, so we // do not do any `matched_pat` calls for these // cases either. } @@ -1175,7 +1158,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { self.tcx().with_freevars(closure_expr.id, |freevars| { for freevar in freevars { - let id_var = freevar.def.def_id().node; + let id_var = freevar.def.var_id(); let upvar_id = ty::UpvarId { var_id: id_var, closure_expr_id: closure_expr.id }; let upvar_capture = self.typer.upvar_capture(upvar_id).unwrap(); @@ -1207,7 +1190,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { -> mc::McResult> { // Create the cmt for the variable being borrowed, from the // caller's perspective - let var_id = upvar_def.def_id().node; + let var_id = upvar_def.var_id(); let var_ty = try!(self.typer.node_ty(var_id)); self.mc.cat_def(closure_id, closure_span, var_ty, upvar_def) } diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index 2e9e5fafb1..face6d6293 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -10,7 +10,7 @@ //! This file handles the relationships between free regions -- //! meaning lifetime parameters. Ordinarily, free regions are -//! unrelated to one another, but they can be related vai implied or +//! unrelated to one another, but they can be related via implied or //! explicit bounds. In that case, we track the bounds using the //! `TransitiveRelation` type and use that to decide when one free //! region outlives another and so forth. diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs index 2447a8cee7..03554a5965 100644 --- a/src/librustc/middle/infer/combine.rs +++ b/src/librustc/middle/infer/combine.rs @@ -48,8 +48,8 @@ use middle::ty::error::TypeError; use middle::ty::fold::{TypeFolder, TypeFoldable}; use middle::ty::relate::{Relate, RelateResult, TypeRelation}; +use syntax::ast; use syntax::codemap::Span; -use rustc_front::hir; #[derive(Clone)] pub struct CombineFields<'a, 'tcx: 'a> { @@ -138,7 +138,7 @@ fn unify_integral_variable<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, fn unify_float_variable<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, vid_is_expected: bool, vid: ty::FloatVid, - val: hir::FloatTy) + val: ast::FloatTy) -> RelateResult<'tcx, Ty<'tcx>> { try!(infcx @@ -388,7 +388,7 @@ fn int_unification_error<'tcx>(a_is_expected: bool, v: (ty::IntVarValue, ty::Int } fn float_unification_error<'tcx>(a_is_expected: bool, - v: (hir::FloatTy, hir::FloatTy)) + v: (ast::FloatTy, ast::FloatTy)) -> TypeError<'tcx> { let (a, b) = v; diff --git a/src/librustc/middle/infer/equate.rs b/src/librustc/middle/infer/equate.rs index 07ce4688c0..d1dad4921a 100644 --- a/src/librustc/middle/infer/equate.rs +++ b/src/librustc/middle/infer/equate.rs @@ -17,6 +17,7 @@ use middle::ty::{self, Ty}; use middle::ty::TyVar; use middle::ty::relate::{Relate, RelateResult, TypeRelation}; +/// Ensures `a` is made equal to `b`. Returns `a` on success. pub struct Equate<'a, 'tcx: 'a> { fields: CombineFields<'a, 'tcx> } @@ -68,7 +69,8 @@ impl<'a, 'tcx> TypeRelation<'a,'tcx> for Equate<'a, 'tcx> { } _ => { - combine::super_combine_tys(self.fields.infcx, self, a, b) + try!(combine::super_combine_tys(self.fields.infcx, self, a, b)); + Ok(a) } } } diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index f0fa7d7cdf..880e181cde 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -65,7 +65,6 @@ use super::ValuePairs; use super::region_inference::RegionResolutionError; use super::region_inference::ConcreteFailure; use super::region_inference::SubSupConflict; -use super::region_inference::SupSupConflict; use super::region_inference::GenericBoundFailure; use super::region_inference::GenericKind; use super::region_inference::ProcessedErrors; @@ -258,13 +257,6 @@ pub trait ErrorReporting<'tcx> { sup_origin: SubregionOrigin<'tcx>, sup_region: Region); - fn report_sup_sup_conflict(&self, - var_origin: RegionVariableOrigin, - origin1: SubregionOrigin<'tcx>, - region1: Region, - origin2: SubregionOrigin<'tcx>, - region2: Region); - fn report_processed_errors(&self, var_origin: &[RegionVariableOrigin], trace_origin: &[(TypeTrace<'tcx>, TypeError<'tcx>)], @@ -284,7 +276,7 @@ trait ErrorReportingHelpers<'tcx> { decl: &hir::FnDecl, unsafety: hir::Unsafety, constness: hir::Constness, - ident: ast::Ident, + name: ast::Name, opt_explicit_self: Option<&hir::ExplicitSelf_>, generics: &hir::Generics, span: Span); @@ -313,14 +305,6 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { sup_origin, sup_r); } - SupSupConflict(var_origin, - origin1, r1, - origin2, r2) => { - self.report_sup_sup_conflict(var_origin, - origin1, r1, - origin2, r2); - } - ProcessedErrors(ref var_origins, ref trace_origins, ref same_regions) => { @@ -376,7 +360,6 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { None => processed_errors.push((*error).clone()), } } - SupSupConflict(..) => processed_errors.push((*error).clone()), _ => () // This shouldn't happen } } @@ -718,20 +701,17 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { ""); } infer::DerefPointer(span) => { - self.tcx.sess.span_err( - span, - "dereference of reference outside its lifetime"); + span_err!(self.tcx.sess, span, E0473, + "dereference of reference outside its lifetime"); self.tcx.note_and_explain_region( "the reference is only valid for ", sup, ""); } infer::FreeVariable(span, id) => { - self.tcx.sess.span_err( - span, - &format!("captured variable `{}` does not \ - outlive the enclosing closure", - self.tcx.local_var_name_str(id))); + span_err!(self.tcx.sess, span, E0474, + "captured variable `{}` does not outlive the enclosing closure", + self.tcx.local_var_name_str(id)); self.tcx.note_and_explain_region( "captured variable is valid for ", sup, @@ -742,18 +722,17 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { ""); } infer::IndexSlice(span) => { - self.tcx.sess.span_err(span, - "index of slice outside its lifetime"); + span_err!(self.tcx.sess, span, E0475, + "index of slice outside its lifetime"); self.tcx.note_and_explain_region( "the slice is only valid for ", sup, ""); } infer::RelateObjectBound(span) => { - self.tcx.sess.span_err( - span, - "lifetime of the source pointer does not outlive \ - lifetime bound of the object type"); + span_err!(self.tcx.sess, span, E0476, + "lifetime of the source pointer does not outlive \ + lifetime bound of the object type"); self.tcx.note_and_explain_region( "object type is valid for ", sub, @@ -764,20 +743,17 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { ""); } infer::RelateParamBound(span, ty) => { - self.tcx.sess.span_err( - span, - &format!("the type `{}` does not fulfill the \ - required lifetime", - self.ty_to_string(ty))); + span_err!(self.tcx.sess, span, E0477, + "the type `{}` does not fulfill the required lifetime", + self.ty_to_string(ty)); self.tcx.note_and_explain_region( "type must outlive ", sub, ""); } infer::RelateRegionParamBound(span) => { - self.tcx.sess.span_err( - span, - "lifetime bound not satisfied"); + span_err!(self.tcx.sess, span, E0478, + "lifetime bound not satisfied"); self.tcx.note_and_explain_region( "lifetime parameter instantiated with ", sup, @@ -788,92 +764,82 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { ""); } infer::RelateDefaultParamBound(span, ty) => { - self.tcx.sess.span_err( - span, - &format!("the type `{}` (provided as the value of \ - a type parameter) is not valid at this point", - self.ty_to_string(ty))); + span_err!(self.tcx.sess, span, E0479, + "the type `{}` (provided as the value of \ + a type parameter) is not valid at this point", + self.ty_to_string(ty)); self.tcx.note_and_explain_region( "type must outlive ", sub, ""); } infer::CallRcvr(span) => { - self.tcx.sess.span_err( - span, - "lifetime of method receiver does not outlive \ - the method call"); + span_err!(self.tcx.sess, span, E0480, + "lifetime of method receiver does not outlive \ + the method call"); self.tcx.note_and_explain_region( "the receiver is only valid for ", sup, ""); } infer::CallArg(span) => { - self.tcx.sess.span_err( - span, - "lifetime of function argument does not outlive \ - the function call"); + span_err!(self.tcx.sess, span, E0481, + "lifetime of function argument does not outlive \ + the function call"); self.tcx.note_and_explain_region( "the function argument is only valid for ", sup, ""); } infer::CallReturn(span) => { - self.tcx.sess.span_err( - span, - "lifetime of return value does not outlive \ - the function call"); + span_err!(self.tcx.sess, span, E0482, + "lifetime of return value does not outlive \ + the function call"); self.tcx.note_and_explain_region( "the return value is only valid for ", sup, ""); } infer::Operand(span) => { - self.tcx.sess.span_err( - span, - "lifetime of operand does not outlive \ - the operation"); + span_err!(self.tcx.sess, span, E0483, + "lifetime of operand does not outlive \ + the operation"); self.tcx.note_and_explain_region( "the operand is only valid for ", sup, ""); } infer::AddrOf(span) => { - self.tcx.sess.span_err( - span, - "reference is not valid \ - at the time of borrow"); + span_err!(self.tcx.sess, span, E0484, + "reference is not valid at the time of borrow"); self.tcx.note_and_explain_region( "the borrow is only valid for ", sup, ""); } infer::AutoBorrow(span) => { - self.tcx.sess.span_err( - span, - "automatically reference is not valid \ - at the time of borrow"); + span_err!(self.tcx.sess, span, E0485, + "automatically reference is not valid \ + at the time of borrow"); self.tcx.note_and_explain_region( "the automatic borrow is only valid for ", sup, ""); } infer::ExprTypeIsNotInScope(t, span) => { - self.tcx.sess.span_err( - span, - &format!("type of expression contains references \ - that are not valid during the expression: `{}`", - self.ty_to_string(t))); + span_err!(self.tcx.sess, span, E0486, + "type of expression contains references \ + that are not valid during the expression: `{}`", + self.ty_to_string(t)); self.tcx.note_and_explain_region( "type is only valid for ", sup, ""); } infer::SafeDestructor(span) => { - self.tcx.sess.span_err( - span, - "unsafe use of destructor: destructor might be called \ - while references are dead"); + span_err!(self.tcx.sess, span, E0487, + "unsafe use of destructor: destructor might be called \ + while references are dead"); // FIXME (22171): terms "super/subregion" are suboptimal self.tcx.note_and_explain_region( "superregion: ", @@ -885,37 +851,33 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { ""); } infer::BindingTypeIsNotValidAtDecl(span) => { - self.tcx.sess.span_err( - span, - "lifetime of variable does not enclose its declaration"); + span_err!(self.tcx.sess, span, E0488, + "lifetime of variable does not enclose its declaration"); self.tcx.note_and_explain_region( "the variable is only valid for ", sup, ""); } infer::ParameterInScope(_, span) => { - self.tcx.sess.span_err( - span, - &format!("type/lifetime parameter not in scope here")); + span_err!(self.tcx.sess, span, E0489, + "type/lifetime parameter not in scope here"); self.tcx.note_and_explain_region( "the parameter is only valid for ", sub, ""); } infer::DataBorrowed(ty, span) => { - self.tcx.sess.span_err( - span, - &format!("a value of type `{}` is borrowed for too long", - self.ty_to_string(ty))); + span_err!(self.tcx.sess, span, E0490, + "a value of type `{}` is borrowed for too long", + self.ty_to_string(ty)); self.tcx.note_and_explain_region("the type is valid for ", sub, ""); self.tcx.note_and_explain_region("but the borrow lasts for ", sup, ""); } infer::ReferenceOutlivesReferent(ty, span) => { - self.tcx.sess.span_err( - span, - &format!("in type `{}`, reference has a longer lifetime \ - than the data it references", - self.ty_to_string(ty))); + span_err!(self.tcx.sess, span, E0491, + "in type `{}`, reference has a longer lifetime \ + than the data it references", + self.ty_to_string(ty)); self.tcx.note_and_explain_region( "the pointer is valid for ", sub, @@ -951,29 +913,6 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { self.note_region_origin(&sub_origin); } - fn report_sup_sup_conflict(&self, - var_origin: RegionVariableOrigin, - origin1: SubregionOrigin<'tcx>, - region1: Region, - origin2: SubregionOrigin<'tcx>, - region2: Region) { - self.report_inference_failure(var_origin); - - self.tcx.note_and_explain_region( - "first, the lifetime must be contained by ", - region1, - "..."); - - self.note_region_origin(&origin1); - - self.tcx.note_and_explain_region( - "but, the lifetime must also be contained by ", - region2, - "..."); - - self.note_region_origin(&origin2); - } - fn report_processed_errors(&self, var_origins: &[RegionVariableOrigin], trace_origins: &[(TypeTrace<'tcx>, TypeError<'tcx>)], @@ -999,7 +938,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { match item.node { hir::ItemFn(ref fn_decl, unsafety, constness, _, ref gen, _) => { Some((fn_decl, gen, unsafety, constness, - item.ident, None, item.span)) + item.name, None, item.span)) }, _ => None } @@ -1011,7 +950,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { &sig.generics, sig.unsafety, sig.constness, - item.ident, + item.name, Some(&sig.explicit_self.node), item.span)) } @@ -1025,7 +964,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { &sig.generics, sig.unsafety, sig.constness, - item.ident, + item.name, Some(&sig.explicit_self.node), item.span)) } @@ -1036,12 +975,12 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { }, None => None }; - let (fn_decl, generics, unsafety, constness, ident, expl_self, span) + let (fn_decl, generics, unsafety, constness, name, expl_self, span) = node_inner.expect("expect item fn"); let rebuilder = Rebuilder::new(self.tcx, fn_decl, expl_self, generics, same_regions, &life_giver); let (fn_decl, expl_self, generics) = rebuilder.rebuild(); - self.give_expl_lifetime_param(&fn_decl, unsafety, constness, ident, + self.give_expl_lifetime_param(&fn_decl, unsafety, constness, name, expl_self.as_ref(), &generics, span); } } @@ -1148,7 +1087,7 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { names.push(lt_name); } names.sort(); - let name = token::str_to_ident(&names[0]).name; + let name = token::intern(&names[0]); return (name_to_dummy_lifetime(name), Kept); } return (self.life_giver.give_lifetime(), Fresh); @@ -1219,7 +1158,7 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { lifetime, region_names); hir::TyParam { - ident: ty_param.ident, + name: ty_param.name, id: ty_param.id, bounds: bounds, default: ty_param.default.clone(), @@ -1562,7 +1501,7 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { let new_bindings = data.bindings.map(|b| { P(hir::TypeBinding { id: b.id, - ident: b.ident, + name: b.name, ty: self.rebuild_arg_ty_or_output(&*b.ty, lifetime, anon_nums, @@ -1597,11 +1536,11 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> { decl: &hir::FnDecl, unsafety: hir::Unsafety, constness: hir::Constness, - ident: ast::Ident, + name: ast::Name, opt_explicit_self: Option<&hir::ExplicitSelf_>, generics: &hir::Generics, span: Span) { - let suggested_fn = pprust::fun_to_string(decl, unsafety, constness, ident, + let suggested_fn = pprust::fun_to_string(decl, unsafety, constness, name, opt_explicit_self, generics); let msg = format!("consider using an explicit lifetime \ parameter as shown: {}", suggested_fn); @@ -1648,11 +1587,10 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> { } }; - self.tcx.sess.span_err( - var_origin.span(), - &format!("cannot infer an appropriate lifetime{} \ - due to conflicting requirements", - var_description)); + span_err!(self.tcx.sess, var_origin.span(), E0495, + "cannot infer an appropriate lifetime{} \ + due to conflicting requirements", + var_description); } fn note_region_origin(&self, origin: &SubregionOrigin<'tcx>) { @@ -1779,7 +1717,7 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> { "...so that return value is valid for the call"); } infer::Operand(span) => { - self.tcx.sess.span_err( + self.tcx.sess.span_note( span, "...so that operand is valid for operation"); } @@ -1960,8 +1898,7 @@ impl LifeGiver { let mut s = String::from("'"); s.push_str(&num_to_string(self.counter.get())); if !self.taken.contains(&s) { - lifetime = name_to_dummy_lifetime( - token::str_to_ident(&s[..]).name); + lifetime = name_to_dummy_lifetime(token::intern(&s[..])); self.generated.borrow_mut().push(lifetime); break; } diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs index b0fce71d3f..ef6d9ae419 100644 --- a/src/librustc/middle/infer/higher_ranked/mod.rs +++ b/src/librustc/middle/infer/higher_ranked/mod.rs @@ -567,7 +567,7 @@ pub fn plug_leaks<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>, // 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 that + // represented. Because `leak_check` passed, we know that // these taint sets are mutually disjoint. let inv_skol_map: FnvHashMap = skol_map diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 0c1c905c8d..84673b0103 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -1462,7 +1462,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { def_id: DefId) -> Option { - self.tables.borrow().closure_kinds.get(&def_id).cloned() + if def_id.is_local() { + self.tables.borrow().closure_kinds.get(&def_id).cloned() + } else { + // During typeck, ALL closures are local. But afterwards, + // during trans, we see closure ids from other traits. + // That may require loading the closure data out of the + // cstore. + Some(ty::Tables::closure_kind(&self.tables, self.tcx, def_id)) + } } pub fn closure_type(&self, @@ -1470,12 +1478,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { substs: &ty::ClosureSubsts<'tcx>) -> ty::ClosureTy<'tcx> { - let closure_ty = self.tables - .borrow() - .closure_tys - .get(&def_id) - .unwrap() - .subst(self.tcx, &substs.func_substs); + let closure_ty = + ty::Tables::closure_type(self.tables, + self.tcx, + def_id, + substs); if self.normalize { normalize_associated_type(&self.tcx, &closure_ty) diff --git a/src/librustc/middle/infer/region_inference/README.md b/src/librustc/middle/infer/region_inference/README.md index 2dc16d4fa1..80da861139 100644 --- a/src/librustc/middle/infer/region_inference/README.md +++ b/src/librustc/middle/infer/region_inference/README.md @@ -2,13 +2,12 @@ Region inference # Terminology -Note that we use the terms region and lifetime interchangeably, -though the term `lifetime` is preferred. +Note that we use the terms region and lifetime interchangeably. # Introduction Region inference uses a somewhat more involved algorithm than type -inference. It is not the most efficient thing ever written though it +inference. It is not the most efficient thing ever written though it seems to work well enough in practice (famous last words). The reason that we use a different algorithm is because, unlike with types, it is impractical to hand-annotate with regions (in some cases, there aren't @@ -25,22 +24,42 @@ once. The constraints are always of one of three possible forms: -- ConstrainVarSubVar(R_i, R_j) states that region variable R_i - must be a subregion of R_j -- ConstrainRegSubVar(R, R_i) states that the concrete region R - (which must not be a variable) must be a subregion of the variable R_i -- ConstrainVarSubReg(R_i, R) is the inverse +- `ConstrainVarSubVar(Ri, Rj)` states that region variable Ri must be + a subregion of Rj +- `ConstrainRegSubVar(R, Ri)` states that the concrete region R (which + must not be a variable) must be a subregion of the variable Ri +- `ConstrainVarSubReg(Ri, R)` states the variable Ri shoudl be less + than the concrete region R. This is kind of deprecated and ought to + be replaced with a verify (they essentially play the same role). + +In addition to constraints, we also gather up a set of "verifys" +(what, you don't think Verify is a noun? Get used to it my +friend!). These represent relations that must hold but which don't +influence inference proper. These take the form of: + +- `VerifyRegSubReg(Ri, Rj)` indicates that Ri <= Rj must hold, + where Rj is not an inference variable (and Ri may or may not contain + one). This doesn't influence inference because we will already have + inferred Ri to be as small as possible, so then we just test whether + that result was less than Rj or not. +- `VerifyGenericBound(R, Vb)` is a more complex expression which tests + that the region R must satisfy the bound `Vb`. The bounds themselves + may have structure like "must outlive one of the following regions" + or "must outlive ALL of the following regions. These bounds arise + from constraints like `T: 'a` -- if we know that `T: 'b` and `T: 'c` + (say, from where clauses), then we can conclude that `T: 'a` if `'b: + 'a` *or* `'c: 'a`. # Building up the constraints Variables and constraints are created using the following methods: - `new_region_var()` creates a new, unconstrained region variable; -- `make_subregion(R_i, R_j)` states that R_i is a subregion of R_j -- `lub_regions(R_i, R_j) -> R_k` returns a region R_k which is - the smallest region that is greater than both R_i and R_j -- `glb_regions(R_i, R_j) -> R_k` returns a region R_k which is - the greatest region that is smaller than both R_i and R_j +- `make_subregion(Ri, Rj)` states that Ri is a subregion of Rj +- `lub_regions(Ri, Rj) -> Rk` returns a region Rk which is + the smallest region that is greater than both Ri and Rj +- `glb_regions(Ri, Rj) -> Rk` returns a region Rk which is + the greatest region that is smaller than both Ri and Rj The actual region resolution algorithm is not entirely obvious, though it is also not overly complex. @@ -54,14 +73,6 @@ Alternatively, you can call `commit()` which ends all snapshots. Snapshots can be recursive---so you can start a snapshot when another is in progress, but only the root snapshot can "commit". -# Resolving constraints - -The constraint resolution algorithm is not super complex but also not -entirely obvious. Here I describe the problem somewhat abstractly, -then describe how the current code works. There may be other, smarter -ways of doing this with which I am unfamiliar and can't be bothered to -research at the moment. - NDM - ## The problem Basically our input is a directed graph where nodes can be divided @@ -83,31 +94,20 @@ Before resolution begins, we build up the constraints in a hashmap that maps `Constraint` keys to spans. During resolution, we construct the actual `Graph` structure that we describe here. -## Our current algorithm - -We divide region variables into two groups: Expanding and Contracting. -Expanding region variables are those that have a concrete region -predecessor (direct or indirect). Contracting region variables are -all others. - -We first resolve the values of Expanding region variables and then -process Contracting ones. We currently use an iterative, fixed-point -procedure (but read on, I believe this could be replaced with a linear -walk). Basically we iterate over the edges in the graph, ensuring -that, if the source of the edge has a value, then this value is a -subregion of the target value. If the target does not yet have a -value, it takes the value from the source. If the target already had -a value, then the resulting value is Least Upper Bound of the old and -new values. When we are done, each Expanding node will have the -smallest region that it could possibly have and still satisfy the -constraints. - -We next process the Contracting nodes. Here we again iterate over the -edges, only this time we move values from target to source (if the -source is a Contracting node). For each contracting node, we compute -its value as the GLB of all its successors. Basically contracting -nodes ensure that there is overlap between their successors; we will -ultimately infer the largest overlap possible. +## Computing the values for region variables + +The algorithm is a simple dataflow algorithm. Each region variable +begins as empty. We iterate over the constraints, and for each constraint +we grow the relevant region variable to be as big as it must be to meet all the +constraints. This means the region variables can grow to be `'static` if +necessary. + +## Verification + +After all constraints are fully propoagated, we do a "verification" +step where we walk over the verify bounds and check that they are +satisfied. These bounds represent the "maximal" values that a region +variable can take on, basically. # The Region Hierarchy diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs index 1fc5294877..279ab9d5f3 100644 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -16,19 +16,16 @@ pub use self::UndoLogEntry::*; pub use self::CombineMapType::*; pub use self::RegionResolutionError::*; pub use self::VarValue::*; -use self::Classification::*; use super::{RegionVariableOrigin, SubregionOrigin, TypeTrace, MiscVariable}; use rustc_data_structures::graph::{self, Direction, NodeIndex}; use middle::free_region::FreeRegionMap; -use middle::region; use middle::ty::{self, Ty}; use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid}; use middle::ty::{ReEmpty, ReStatic, ReFree, ReEarlyBound}; use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh}; use middle::ty::error::TypeError; -use middle::ty::relate::RelateResult; use util::common::indenter; use util::nodemap::{FnvHashMap, FnvHashSet}; @@ -50,6 +47,8 @@ pub enum Constraint { ConstrainRegSubVar(Region, RegionVid), // Region variable is subregion of concrete region + // + // FIXME(#29436) -- should be remove in favor of a Verify ConstrainVarSubReg(RegionVid, Region), } @@ -144,15 +143,6 @@ pub enum RegionResolutionError<'tcx> { SubregionOrigin<'tcx>, Region, SubregionOrigin<'tcx>, Region), - /// `SupSupConflict(v, origin1, r1, origin2, r2)`: - /// - /// Could not infer a value for `v` because `v <= r1` (due to - /// `origin1`) and `v <= r2` (due to `origin2`) and - /// `r1` and `r2` have no intersection. - SupSupConflict(RegionVariableOrigin, - SubregionOrigin<'tcx>, Region, - SubregionOrigin<'tcx>, Region), - /// For subsets of `ConcreteFailure` and `SubSupConflict`, we can derive /// more specific errors message by suggesting to the user where they /// should put a lifetime. In those cases we process and put those errors @@ -824,147 +814,14 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { } } } - - fn glb_concrete_regions(&self, - free_regions: &FreeRegionMap, - a: Region, - b: Region) - -> RelateResult<'tcx, Region> - { - debug!("glb_concrete_regions({:?}, {:?})", a, b); - match (a, b) { - (ReLateBound(..), _) | - (_, ReLateBound(..)) | - (ReEarlyBound(..), _) | - (_, ReEarlyBound(..)) => { - self.tcx.sess.bug( - &format!("cannot relate bound region: GLB({:?}, {:?})", - a, - b)); - } - - (ReStatic, r) | (r, ReStatic) => { - // static lives longer than everything else - Ok(r) - } - - (ReEmpty, _) | (_, ReEmpty) => { - // nothing lives shorter than everything else - Ok(ReEmpty) - } - - (ReVar(v_id), _) | - (_, ReVar(v_id)) => { - self.tcx.sess.span_bug( - (*self.var_origins.borrow())[v_id.index as usize].span(), - &format!("glb_concrete_regions invoked with \ - non-concrete regions: {:?}, {:?}", - a, - b)); - } - - (ReFree(fr), ReScope(s_id)) | - (ReScope(s_id), ReFree(fr)) => { - let s = ReScope(s_id); - // Free region is something "at least as big as - // `fr.scope_id`." If we find that the scope `fr.scope_id` is bigger - // than the scope `s_id`, then we can say that the GLB - // is the scope `s_id`. Otherwise, as we do not know - // big the free region is precisely, the GLB is undefined. - if self.tcx.region_maps.nearest_common_ancestor(fr.scope, s_id) == fr.scope || - free_regions.is_static(fr) { - Ok(s) - } else { - Err(TypeError::RegionsNoOverlap(b, a)) - } - } - - (ReScope(a_id), ReScope(b_id)) => { - self.intersect_scopes(a, b, a_id, b_id) - } - - (ReFree(ref a_fr), ReFree(ref b_fr)) => { - self.glb_free_regions(free_regions, a_fr, b_fr) - } - - // For these types, we cannot define any additional - // relationship: - (ReSkolemized(..), _) | - (_, ReSkolemized(..)) => { - if a == b { - Ok(a) - } else { - Err(TypeError::RegionsNoOverlap(b, a)) - } - } - } - } - - /// Computes a region that is enclosed by both free region arguments, if any. Guarantees that - /// if the same two regions are given as argument, in any order, a consistent result is - /// returned. - fn glb_free_regions(&self, - free_regions: &FreeRegionMap, - a: &FreeRegion, - b: &FreeRegion) - -> RelateResult<'tcx, ty::Region> - { - return match a.cmp(b) { - Less => helper(self, free_regions, a, b), - Greater => helper(self, free_regions, b, a), - Equal => Ok(ty::ReFree(*a)) - }; - - fn helper<'a, 'tcx>(this: &RegionVarBindings<'a, 'tcx>, - free_regions: &FreeRegionMap, - a: &FreeRegion, - b: &FreeRegion) -> RelateResult<'tcx, ty::Region> - { - if free_regions.sub_free_region(*a, *b) { - Ok(ty::ReFree(*a)) - } else if free_regions.sub_free_region(*b, *a) { - Ok(ty::ReFree(*b)) - } else { - this.intersect_scopes(ty::ReFree(*a), ty::ReFree(*b), - a.scope, b.scope) - } - } - } - - fn intersect_scopes(&self, - region_a: ty::Region, - region_b: ty::Region, - scope_a: region::CodeExtent, - scope_b: region::CodeExtent) - -> RelateResult<'tcx, Region> - { - // We want to generate the intersection of two - // scopes or two free regions. So, if one of - // these scopes is a subscope of the other, return - // it. Otherwise fail. - debug!("intersect_scopes(scope_a={:?}, scope_b={:?}, region_a={:?}, region_b={:?})", - scope_a, scope_b, region_a, region_b); - let r_id = self.tcx.region_maps.nearest_common_ancestor(scope_a, scope_b); - if r_id == scope_a { - Ok(ReScope(scope_b)) - } else if r_id == scope_b { - Ok(ReScope(scope_a)) - } else { - Err(TypeError::RegionsNoOverlap(region_a, region_b)) - } - } } // ______________________________________________________________________ -#[derive(Copy, Clone, PartialEq, Debug)] -enum Classification { Expanding, Contracting } - #[derive(Copy, Clone, Debug)] -pub enum VarValue { NoValue, Value(Region), ErrorValue } +pub enum VarValue { Value(Region), ErrorValue } struct VarData { - classification: Classification, value: VarValue, } @@ -1005,12 +862,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { fn construct_var_data(&self) -> Vec { (0..self.num_vars() as usize).map(|_| { VarData { - // All nodes are initially classified as contracting; during - // the expansion phase, we will shift the classification for - // those nodes that have a concrete region predecessor to - // Expanding. - classification: Contracting, - value: NoValue, + value: Value(ty::ReEmpty), } }).collect() } @@ -1062,11 +914,11 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { } ConstrainVarSubVar(a_vid, b_vid) => { match var_data[a_vid.index as usize].value { - NoValue | ErrorValue => false, - Value(a_region) => { - let b_node = &mut var_data[b_vid.index as usize]; - self.expand_node(free_regions, a_region, b_vid, b_node) - } + ErrorValue => false, + Value(a_region) => { + let b_node = &mut var_data[b_vid.index as usize]; + self.expand_node(free_regions, a_region, b_vid, b_node) + } } } ConstrainVarSubReg(..) => { @@ -1100,16 +952,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { _ => { } } - b_data.classification = Expanding; match b_data.value { - NoValue => { - debug!("Setting initial value of {:?} to {:?}", - b_vid, a_region); - - b_data.value = Value(a_region); - return true; - } - Value(cur_region) => { let lub = self.lub_concrete_regions(free_regions, a_region, cur_region); if lub == cur_region { @@ -1131,6 +974,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { } } + // FIXME(#29436) -- this fn would just go away if we removed ConstrainVarSubReg fn contraction(&self, free_regions: &FreeRegionMap, var_data: &mut [VarData]) { @@ -1142,104 +986,31 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { .unwrap() ); match *constraint { - ConstrainRegSubVar(..) => { - // This is an expansion constraint. Ignore. - false - } - ConstrainVarSubVar(a_vid, b_vid) => { - match var_data[b_vid.index as usize].value { - NoValue | ErrorValue => false, - Value(b_region) => { - let a_data = &mut var_data[a_vid.index as usize]; - self.contract_node(free_regions, a_vid, a_data, b_region) - } + ConstrainRegSubVar(..) | + ConstrainVarSubVar(..) => { + // Expansion will ensure that these constraints hold. Ignore. } - } - ConstrainVarSubReg(a_vid, b_region) => { - let a_data = &mut var_data[a_vid.index as usize]; - self.contract_node(free_regions, a_vid, a_data, b_region) - } - } - }) - } - - fn contract_node(&self, - free_regions: &FreeRegionMap, - a_vid: RegionVid, - a_data: &mut VarData, - b_region: Region) - -> bool { - debug!("contract_node({:?} == {:?}/{:?}, {:?})", - a_vid, a_data.value, - a_data.classification, b_region); - - return match a_data.value { - NoValue => { - assert_eq!(a_data.classification, Contracting); - a_data.value = Value(b_region); - true // changed - } - - ErrorValue => false, // no change - - Value(a_region) => { - match a_data.classification { - Expanding => - check_node(self, free_regions, a_vid, a_data, a_region, b_region), - Contracting => - adjust_node(self, free_regions, a_vid, a_data, a_region, b_region), + ConstrainVarSubReg(a_vid, b_region) => { + let a_data = &mut var_data[a_vid.index as usize]; + debug!("contraction: {:?} == {:?}, {:?}", a_vid, a_data.value, b_region); + + let a_region = match a_data.value { + ErrorValue => return false, + Value(a_region) => a_region, + }; + + if !free_regions.is_subregion_of(self.tcx, a_region, b_region) { + debug!("Setting {:?} to ErrorValue: {:?} not subregion of {:?}", + a_vid, + a_region, + b_region); + a_data.value = ErrorValue; + } } } - }; - fn check_node(this: &RegionVarBindings, - free_regions: &FreeRegionMap, - a_vid: RegionVid, - a_data: &mut VarData, - a_region: Region, - b_region: Region) - -> bool - { - if !free_regions.is_subregion_of(this.tcx, a_region, b_region) { - debug!("Setting {:?} to ErrorValue: {:?} not subregion of {:?}", - a_vid, - a_region, - b_region); - a_data.value = ErrorValue; - } false - } - - fn adjust_node(this: &RegionVarBindings, - free_regions: &FreeRegionMap, - a_vid: RegionVid, - a_data: &mut VarData, - a_region: Region, - b_region: Region) - -> bool { - match this.glb_concrete_regions(free_regions, a_region, b_region) { - Ok(glb) => { - if glb == a_region { - false - } else { - debug!("Contracting value of {:?} from {:?} to {:?}", - a_vid, - a_region, - glb); - a_data.value = Value(glb); - true - } - } - Err(_) => { - debug!("Setting {:?} to ErrorValue: no glb of {:?}, {:?}", - a_vid, - a_region, - b_region); - a_data.value = ErrorValue; - false - } - } - } + }) } fn collect_concrete_region_errors(&self, @@ -1308,12 +1079,6 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { Value(_) => { /* Inference successful */ } - NoValue => { - /* Unconstrained inference: do not report an error - until the value of this variable is requested. - After all, sometimes we make region variables but never - really use their values. */ - } ErrorValue => { /* Inference impossible, this value contains inconsistent constraints. @@ -1339,18 +1104,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { this portion of the code and think hard about it. =) */ let node_vid = RegionVid { index: idx as u32 }; - match var_data[idx].classification { - Expanding => { - self.collect_error_for_expanding_node( - free_regions, graph, var_data, &mut dup_vec, - node_vid, errors); - } - Contracting => { - self.collect_error_for_contracting_node( - free_regions, graph, var_data, &mut dup_vec, - node_vid, errors); - } - } + self.collect_error_for_expanding_node( + free_regions, graph, &mut dup_vec, node_vid, errors); } } } @@ -1396,7 +1151,6 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { fn collect_error_for_expanding_node(&self, free_regions: &FreeRegionMap, graph: &RegionGraph, - var_data: &[VarData], dup_vec: &mut [u32], node_idx: RegionVid, errors: &mut Vec>) @@ -1404,11 +1158,9 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { // Errors in expanding nodes result from a lower-bound that is // not contained by an upper-bound. let (mut lower_bounds, lower_dup) = - self.collect_concrete_regions(graph, var_data, node_idx, - graph::INCOMING, dup_vec); + self.collect_concrete_regions(graph, node_idx, graph::INCOMING, dup_vec); let (mut upper_bounds, upper_dup) = - self.collect_concrete_regions(graph, var_data, node_idx, - graph::OUTGOING, dup_vec); + self.collect_concrete_regions(graph, node_idx, graph::OUTGOING, dup_vec); if lower_dup || upper_dup { return; @@ -1459,59 +1211,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { upper_bounds)); } - fn collect_error_for_contracting_node( - &self, - free_regions: &FreeRegionMap, - graph: &RegionGraph, - var_data: &[VarData], - dup_vec: &mut [u32], - node_idx: RegionVid, - errors: &mut Vec>) - { - // Errors in contracting nodes result from two upper-bounds - // that have no intersection. - let (upper_bounds, dup_found) = - self.collect_concrete_regions(graph, var_data, node_idx, - graph::OUTGOING, dup_vec); - - if dup_found { - return; - } - - for upper_bound_1 in &upper_bounds { - for upper_bound_2 in &upper_bounds { - match self.glb_concrete_regions(free_regions, - upper_bound_1.region, - upper_bound_2.region) { - Ok(_) => {} - Err(_) => { - let origin = (*self.var_origins.borrow())[node_idx.index as usize].clone(); - debug!("region inference error at {:?} for {:?}: \ - SupSupConflict sub: {:?} sup: {:?}", - origin, node_idx, upper_bound_1.region, upper_bound_2.region); - errors.push(SupSupConflict( - origin, - upper_bound_1.origin.clone(), - upper_bound_1.region, - upper_bound_2.origin.clone(), - upper_bound_2.region)); - return; - } - } - } - } - - self.tcx.sess.span_bug( - (*self.var_origins.borrow())[node_idx.index as usize].span(), - &format!("collect_error_for_contracting_node() could not find error \ - for var {:?}, upper_bounds={:?}", - node_idx, - upper_bounds)); - } - fn collect_concrete_regions(&self, graph: &RegionGraph, - var_data: &[VarData], orig_node_idx: RegionVid, dir: Direction, dup_vec: &mut [u32]) @@ -1536,7 +1237,6 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { while !state.stack.is_empty() { let node_idx = state.stack.pop().unwrap(); - let classification = var_data[node_idx.index as usize].classification; // check whether we've visited this node on some previous walk if dup_vec[node_idx.index as usize] == u32::MAX { @@ -1545,17 +1245,12 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { state.dup_found = true; } - debug!("collect_concrete_regions(orig_node_idx={:?}, node_idx={:?}, \ - classification={:?})", - orig_node_idx, node_idx, classification); + debug!("collect_concrete_regions(orig_node_idx={:?}, node_idx={:?})", + orig_node_idx, node_idx); // figure out the direction from which this node takes its // values, and search for concrete regions etc in that direction - let dir = match classification { - Expanding => graph::INCOMING, - Contracting => graph::OUTGOING, - }; - + let dir = graph::INCOMING; process_edges(self, &mut state, graph, node_idx, dir); } @@ -1638,7 +1333,6 @@ fn normalize(values: &Vec, r: ty::Region) -> ty::Region { fn lookup(values: &Vec, rid: ty::RegionVid) -> ty::Region { match values[rid.index as usize] { Value(r) => r, - NoValue => ReEmpty, // No constraints, return ty::ReEmpty ErrorValue => ReStatic, // Previously reported error. } } diff --git a/src/librustc/middle/infer/sub.rs b/src/librustc/middle/infer/sub.rs index 155f5f4400..2cd686fde1 100644 --- a/src/librustc/middle/infer/sub.rs +++ b/src/librustc/middle/infer/sub.rs @@ -18,7 +18,7 @@ use middle::ty::TyVar; use middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation}; use std::mem; -/// "Greatest lower bound" (common subtype) +/// Ensures `a` is made a subtype of `b`. Returns `a` on success. pub struct Sub<'a, 'tcx: 'a> { fields: CombineFields<'a, 'tcx>, } @@ -90,7 +90,8 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Sub<'a, 'tcx> { } _ => { - combine::super_combine_tys(self.fields.infcx, self, a, b) + try!(combine::super_combine_tys(self.fields.infcx, self, a, b)); + Ok(a) } } } diff --git a/src/librustc/middle/infer/unify_key.rs b/src/librustc/middle/infer/unify_key.rs index 6bb46ac787..41aa191ac2 100644 --- a/src/librustc/middle/infer/unify_key.rs +++ b/src/librustc/middle/infer/unify_key.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use syntax::ast; use middle::ty::{self, IntVarValue, Ty}; use rustc_data_structures::unify::UnifyKey; -use rustc_front::hir as ast; pub trait ToType<'tcx> { fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx>; diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index c042aea829..b3e287f6d7 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -55,7 +55,7 @@ impl<'a, 'tcx> IntrinsicCheckingVisitor<'a, 'tcx> { ty::TyBareFn(_, ref bfty) => bfty.abi == RustIntrinsic, _ => return false }; - intrinsic && self.tcx.item_name(def_id) == "transmute" + intrinsic && self.tcx.item_name(def_id).as_str() == "transmute" } fn check_transmute(&self, span: Span, from: Ty<'tcx>, to: Ty<'tcx>, id: ast::NodeId) { diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index a34571e4ac..03c75fc6cc 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -21,6 +21,7 @@ pub use self::LangItem::*; +use front::map as hir_map; use session::Session; use metadata::csearch::each_lang_item; use middle::def_id::DefId; @@ -28,7 +29,8 @@ use middle::ty; use middle::weak_lang_items; use util::nodemap::FnvHashMap; -use rustc_front::attr::AttrMetaMethods; +use syntax::ast; +use syntax::attr::AttrMetaMethods; use syntax::codemap::{DUMMY_SP, Span}; use syntax::parse::token::InternedString; use rustc_front::visit::Visitor; @@ -143,21 +145,23 @@ impl LanguageItems { )* } -struct LanguageItemCollector<'a> { +struct LanguageItemCollector<'a, 'tcx: 'a> { items: LanguageItems, + ast_map: &'a hir_map::Map<'tcx>, + session: &'a Session, item_refs: FnvHashMap<&'static str, usize>, } -impl<'a, 'v> Visitor<'v> for LanguageItemCollector<'a> { +impl<'a, 'v, 'tcx> Visitor<'v> for LanguageItemCollector<'a, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { if let Some(value) = extract(&item.attrs) { let item_index = self.item_refs.get(&value[..]).cloned(); if let Some(item_index) = item_index { - self.collect_item(item_index, DefId::local(item.id), item.span) + self.collect_item(item_index, self.ast_map.local_def_id(item.id), item.span) } } @@ -165,16 +169,18 @@ impl<'a, 'v> Visitor<'v> for LanguageItemCollector<'a> { } } -impl<'a> LanguageItemCollector<'a> { - pub fn new(session: &'a Session) -> LanguageItemCollector<'a> { +impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> { + pub fn new(session: &'a Session, ast_map: &'a hir_map::Map<'tcx>) + -> LanguageItemCollector<'a, 'tcx> { let mut item_refs = FnvHashMap(); $( item_refs.insert($name, $variant as usize); )* LanguageItemCollector { session: session, + ast_map: ast_map, items: LanguageItems::new(), - item_refs: item_refs + item_refs: item_refs, } } @@ -202,8 +208,8 @@ impl<'a> LanguageItemCollector<'a> { pub fn collect_external_language_items(&mut self) { let crate_store = &self.session.cstore; crate_store.iter_crate_data(|crate_number, _crate_metadata| { - each_lang_item(crate_store, crate_number, |node_id, item_index| { - let def_id = DefId { krate: crate_number, node: node_id }; + each_lang_item(crate_store, crate_number, |index, item_index| { + let def_id = DefId { krate: crate_number, index: index }; self.collect_item(item_index, def_id, DUMMY_SP); true }); @@ -216,7 +222,7 @@ impl<'a> LanguageItemCollector<'a> { } } -pub fn extract(attrs: &[hir::Attribute]) -> Option { +pub fn extract(attrs: &[ast::Attribute]) -> Option { for attribute in attrs { match attribute.value_str() { Some(ref value) if attribute.check_name("lang") => { @@ -229,9 +235,11 @@ pub fn extract(attrs: &[hir::Attribute]) -> Option { return None; } -pub fn collect_language_items(krate: &hir::Crate, - session: &Session) -> LanguageItems { - let mut collector = LanguageItemCollector::new(session); +pub fn collect_language_items(session: &Session, + map: &hir_map::Map) + -> LanguageItems { + let krate: &hir::Crate = map.krate(); + let mut collector = LanguageItemCollector::new(session, map); collector.collect(krate); let LanguageItemCollector { mut items, .. } = collector; weak_lang_items::check_crate(krate, session, &mut items); @@ -285,6 +293,16 @@ lets_do_this! { BitOrTraitLangItem, "bitor", bitor_trait; ShlTraitLangItem, "shl", shl_trait; ShrTraitLangItem, "shr", shr_trait; + AddAssignTraitLangItem, "add_assign", add_assign_trait; + SubAssignTraitLangItem, "sub_assign", sub_assign_trait; + MulAssignTraitLangItem, "mul_assign", mul_assign_trait; + DivAssignTraitLangItem, "div_assign", div_assign_trait; + RemAssignTraitLangItem, "rem_assign", rem_assign_trait; + BitXorAssignTraitLangItem, "bitxor_assign", bitxor_assign_trait; + BitAndAssignTraitLangItem, "bitand_assign", bitand_assign_trait; + BitOrAssignTraitLangItem, "bitor_assign", bitor_assign_trait; + ShlAssignTraitLangItem, "shl_assign", shl_assign_trait; + ShrAssignTraitLangItem, "shr_assign", shr_assign_trait; IndexTraitLangItem, "index", index_trait; IndexMutTraitLangItem, "index_mut", index_mut_trait; RangeStructLangItem, "range", range_struct; @@ -330,7 +348,6 @@ lets_do_this! { EhUnwindResumeLangItem, "eh_unwind_resume", eh_unwind_resume; MSVCTryFilterLangItem, "msvc_try_filter", msvc_try_filter; - ExchangeHeapLangItem, "exchange_heap", exchange_heap; OwnedBoxLangItem, "owned_box", owned_box; PhantomDataItem, "phantom_data", phantom_data; diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 561760b29f..3b56597d35 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -383,7 +383,7 @@ fn visit_fn(ir: &mut IrMaps, &*arg.pat, |_bm, arg_id, _x, path1| { debug!("adding argument {}", arg_id); - let name = path1.node.name; + let name = path1.node; fn_maps.add_variable(Arg(arg_id, name)); }) }; @@ -416,7 +416,7 @@ fn visit_fn(ir: &mut IrMaps, fn visit_local(ir: &mut IrMaps, local: &hir::Local) { pat_util::pat_bindings(&ir.tcx.def_map, &*local.pat, |_, p_id, sp, path1| { debug!("adding local variable {}", p_id); - let name = path1.node.name; + let name = path1.node; ir.add_live_node_for_node(p_id, VarDefNode(sp)); ir.add_variable(Local(LocalInfo { id: p_id, @@ -431,7 +431,7 @@ fn visit_arm(ir: &mut IrMaps, arm: &hir::Arm) { pat_util::pat_bindings(&ir.tcx.def_map, &**pat, |bm, p_id, sp, path1| { debug!("adding local variable {} from match with bm {:?}", p_id, bm); - let name = path1.node.name; + let name = path1.node; ir.add_live_node_for_node(p_id, VarDefNode(sp)); ir.add_variable(Local(LocalInfo { id: p_id, @@ -465,7 +465,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) { let mut call_caps = Vec::new(); ir.tcx.with_freevars(expr.id, |freevars| { for fv in freevars { - if let DefLocal(rv) = fv.def { + if let DefLocal(_, rv) = fv.def { let fv_ln = ir.add_live_node(FreeVarNode(fv.span)); call_caps.push(CaptureInfo {ln: fv_ln, var_nid: rv}); @@ -495,7 +495,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) { hir::ExprAgain(_) | hir::ExprLit(_) | hir::ExprRet(..) | hir::ExprBlock(..) | hir::ExprAssign(..) | hir::ExprAssignOp(..) | hir::ExprStruct(..) | hir::ExprRepeat(..) | - hir::ExprParen(..) | hir::ExprInlineAsm(..) | hir::ExprBox(..) | + hir::ExprInlineAsm(..) | hir::ExprBox(..) | hir::ExprRange(..) => { visit::walk_expr(ir, expr); } @@ -688,7 +688,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } fn find_loop_scope(&self, - opt_label: Option, + opt_label: Option, id: NodeId, sp: Span) -> NodeId { @@ -1049,7 +1049,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprBreak(opt_label) => { // Find which label this break jumps to - let sc = self.find_loop_scope(opt_label.map(|l| l.node), expr.id, expr.span); + let sc = self.find_loop_scope(opt_label.map(|l| l.node.name), expr.id, expr.span); // Now that we know the label we're going to, // look it up in the break loop nodes table @@ -1063,7 +1063,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprAgain(opt_label) => { // Find which label this expr continues to - let sc = self.find_loop_scope(opt_label.map(|l| l.node), expr.id, expr.span); + let sc = self.find_loop_scope(opt_label.map(|l| l.node.name), expr.id, expr.span); // Now that we know the label we're going to, // look it up in the continue loop nodes table @@ -1147,8 +1147,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } hir::ExprIndex(ref l, ref r) | - hir::ExprBinary(_, ref l, ref r) | - hir::ExprBox(Some(ref l), ref r) => { + hir::ExprBinary(_, ref l, ref r) => { let r_succ = self.propagate_through_expr(&**r, succ); self.propagate_through_expr(&**l, r_succ) } @@ -1158,11 +1157,10 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { e1.as_ref().map_or(succ, |e| self.propagate_through_expr(&**e, succ)) } - hir::ExprBox(None, ref e) | + hir::ExprBox(ref e) | hir::ExprAddrOf(_, ref e) | hir::ExprCast(ref e, _) | - hir::ExprUnary(_, ref e) | - hir::ExprParen(ref e) => { + hir::ExprUnary(_, ref e) => { self.propagate_through_expr(&**e, succ) } @@ -1270,7 +1268,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn access_path(&mut self, expr: &Expr, succ: LiveNode, acc: u32) -> LiveNode { match self.ir.tcx.def_map.borrow().get(&expr.id).unwrap().full_def() { - DefLocal(nid) => { + DefLocal(_, nid) => { let ln = self.live_node(expr.id, expr.span); if acc != 0 { self.init_from_succ(ln, succ); @@ -1400,9 +1398,8 @@ fn check_arm(this: &mut Liveness, arm: &hir::Arm) { fn check_expr(this: &mut Liveness, expr: &Expr) { match expr.node { - hir::ExprAssign(ref l, ref r) => { + hir::ExprAssign(ref l, _) => { this.check_lvalue(&**l); - this.visit_expr(&**r); visit::walk_expr(this, expr); } @@ -1435,7 +1432,7 @@ fn check_expr(this: &mut Liveness, expr: &Expr) { hir::ExprCast(..) | hir::ExprUnary(..) | hir::ExprRet(..) | hir::ExprBreak(..) | hir::ExprAgain(..) | hir::ExprLit(_) | hir::ExprBlock(..) | hir::ExprAddrOf(..) | - hir::ExprStruct(..) | hir::ExprRepeat(..) | hir::ExprParen(..) | + hir::ExprStruct(..) | hir::ExprRepeat(..) | hir::ExprClosure(..) | hir::ExprPath(..) | hir::ExprBox(..) | hir::ExprRange(..) => { visit::walk_expr(this, expr); @@ -1520,9 +1517,9 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn check_lvalue(&mut self, expr: &Expr) { match expr.node { hir::ExprPath(..) => { - if let DefLocal(nid) = self.ir.tcx.def_map.borrow().get(&expr.id) - .unwrap() - .full_def() { + if let DefLocal(_, nid) = self.ir.tcx.def_map.borrow().get(&expr.id) + .unwrap() + .full_def() { // Assignment to an immutable variable or argument: only legal // if there is no later assignment. If this local is actually // mutable, then check for a reassignment to flag the mutability @@ -1556,8 +1553,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { |_bm, p_id, sp, path1| { let var = self.variable(p_id, sp); // Ignore unused self. - let ident = path1.node; - if ident.name != special_idents::self_.name { + let name = path1.node; + if name != special_idents::self_.name { self.warn_about_unused(sp, p_id, entry_ln, var); } }) diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index dd2f48d25b..1fcd6e9230 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -305,7 +305,7 @@ impl MutabilityCategory { fn from_local(tcx: &ty::ctxt, id: ast::NodeId) -> MutabilityCategory { let ret = match tcx.map.get(id) { - ast_map::NodeLocal(p) | ast_map::NodeArg(p) => match p.node { + ast_map::NodeLocal(p) => match p.node { hir::PatIdent(bind_mode, _, _) => { if bind_mode == hir::BindByValue(hir::MutMutable) { McDeclared @@ -474,7 +474,7 @@ impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> { expr.id, expr, base_cmt); - Ok(self.cat_field(expr, base_cmt, f_name.node.name, expr_ty)) + Ok(self.cat_field(expr, base_cmt, f_name.node, expr_ty)) } hir::ExprTupField(ref base, idx) => { @@ -519,10 +519,6 @@ impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> { self.cat_def(expr.id, expr.span, expr_ty, def) } - hir::ExprParen(ref e) => { - self.cat_expr(&**e) - } - hir::ExprAddrOf(..) | hir::ExprCall(..) | hir::ExprAssign(..) | hir::ExprAssignOp(..) | hir::ExprClosure(..) | hir::ExprRet(..) | @@ -555,7 +551,7 @@ impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> { } def::DefMod(_) | def::DefForeignMod(_) | def::DefUse(_) | def::DefTrait(_) | def::DefTy(..) | def::DefPrimTy(_) | - def::DefTyParam(..) | def::DefRegion(_) | + def::DefTyParam(..) | def::DefLabel(_) | def::DefSelfTy(..) | def::DefAssociatedTy(..) => { Ok(Rc::new(cmt_ { @@ -579,7 +575,7 @@ impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> { })) } - def::DefUpvar(var_id, _, fn_node_id) => { + def::DefUpvar(_, var_id, _, fn_node_id) => { let ty = try!(self.node_ty(fn_node_id)); match ty.sty { ty::TyClosure(closure_id, _) => { @@ -604,7 +600,7 @@ impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> { } } - def::DefLocal(vid) => { + def::DefLocal(_, vid) => { Ok(Rc::new(cmt_ { id: id, span: span, @@ -1276,7 +1272,7 @@ impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> { // {f1: p1, ..., fN: pN} for fp in field_pats { let field_ty = try!(self.pat_ty(&*fp.node.pat)); // see (*2) - let cmt_field = self.cat_field(pat, cmt.clone(), fp.node.ident.name, field_ty); + let cmt_field = self.cat_field(pat, cmt.clone(), fp.node.name, field_ty); try!(self.cat_pattern_(cmt_field, &*fp.node.pat, op)); } } @@ -1467,11 +1463,10 @@ impl<'tcx> cmt_<'tcx> { "non-lvalue".to_string() } cat_local(vid) => { - match tcx.map.find(vid) { - Some(ast_map::NodeArg(_)) => { - "argument".to_string() - } - _ => "local variable".to_string() + if tcx.map.is_argument(vid) { + "argument".to_string() + } else { + "local variable".to_string() } } cat_deref(_, _, pk) => { diff --git a/src/librustc/middle/pat_util.rs b/src/librustc/middle/pat_util.rs index 3c483f70a4..04a754b82c 100644 --- a/src/librustc/middle/pat_util.rs +++ b/src/librustc/middle/pat_util.rs @@ -14,18 +14,19 @@ use middle::ty; use util::nodemap::FnvHashMap; use syntax::ast; +use syntax::ext::mtwt; use rustc_front::hir; use rustc_front::util::walk_pat; -use syntax::codemap::{Span, DUMMY_SP}; +use syntax::codemap::{respan, Span, Spanned, DUMMY_SP}; -pub type PatIdMap = FnvHashMap; +pub type PatIdMap = FnvHashMap; // This is used because same-named variables in alternative patterns need to // use the NodeId of their namesake in the first pattern. pub fn pat_id_map(dm: &DefMap, pat: &hir::Pat) -> PatIdMap { let mut map = FnvHashMap(); - pat_bindings(dm, pat, |_bm, p_id, _s, path1| { - map.insert(path1.node, p_id); + pat_bindings_hygienic(dm, pat, |_bm, p_id, _s, path1| { + map.insert(mtwt::resolve(path1.node), p_id); }); map } @@ -109,12 +110,26 @@ pub fn pat_is_binding_or_wild(dm: &DefMap, pat: &hir::Pat) -> bool { /// Call `it` on every "binding" in a pattern, e.g., on `a` in /// `match foo() { Some(a) => (), None => () }` pub fn pat_bindings(dm: &DefMap, pat: &hir::Pat, mut it: I) where - I: FnMut(hir::BindingMode, ast::NodeId, Span, &hir::SpannedIdent), + I: FnMut(hir::BindingMode, ast::NodeId, Span, &Spanned), { walk_pat(pat, |p| { match p.node { hir::PatIdent(binding_mode, ref pth, _) if pat_is_binding(dm, p) => { - it(binding_mode, p.id, p.span, pth); + it(binding_mode, p.id, p.span, &respan(pth.span, pth.node.name)); + } + _ => {} + } + true + }); +} + +pub fn pat_bindings_hygienic(dm: &DefMap, pat: &hir::Pat, mut it: I) where + I: FnMut(hir::BindingMode, ast::NodeId, Span, &Spanned), +{ + walk_pat(pat, |p| { + match p.node { + hir::PatIdent(binding_mode, ref pth, _) if pat_is_binding(dm, p) => { + it(binding_mode, p.id, p.span, &respan(pth.span, pth.node)); } _ => {} } @@ -182,10 +197,10 @@ pub fn pat_contains_bindings_or_wild(dm: &DefMap, pat: &hir::Pat) -> bool { contains_bindings } -pub fn simple_identifier<'a>(pat: &'a hir::Pat) -> Option<&'a ast::Ident> { +pub fn simple_name<'a>(pat: &'a hir::Pat) -> Option { match pat.node { hir::PatIdent(hir::BindByValue(_), ref path1, None) => { - Some(&path1.node) + Some(path1.node.name) } _ => { None @@ -197,7 +212,7 @@ pub fn def_to_path(tcx: &ty::ctxt, id: DefId) -> hir::Path { tcx.with_path(id, |path| hir::Path { global: false, segments: path.last().map(|elem| hir::PathSegment { - identifier: ast::Ident::new(elem.name()), + identifier: ast::Ident::with_empty_ctxt(elem.name()), parameters: hir::PathParameters::none(), }).into_iter().collect(), span: DUMMY_SP, @@ -205,7 +220,7 @@ pub fn def_to_path(tcx: &ty::ctxt, id: DefId) -> hir::Path { } /// Return variants that are necessary to exist for the pattern to match. -pub fn necessary_variants(dm: &DefMap, pat: &hir::Pat) -> Vec { +pub fn necessary_variants(dm: &DefMap, pat: &hir::Pat) -> Vec { let mut variants = vec![]; walk_pat(pat, |p| { match p.node { @@ -214,7 +229,7 @@ pub fn necessary_variants(dm: &DefMap, pat: &hir::Pat) -> Vec { hir::PatStruct(..) => { match dm.borrow().get(&p.id) { Some(&PathResolution { base_def: DefVariant(_, id, _), .. }) => { - variants.push(id.node); + variants.push(id); } _ => () } diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 03374fa492..a89da9704d 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -17,7 +17,7 @@ use front::map as ast_map; use middle::def; -use middle::def_id::{DefId, LOCAL_CRATE}; +use middle::def_id::DefId; use middle::ty; use middle::privacy; use session::config; @@ -26,8 +26,8 @@ use util::nodemap::NodeSet; use std::collections::HashSet; use syntax::abi; use syntax::ast; +use syntax::attr; use rustc_front::hir; -use rustc_front::attr; use rustc_front::visit::Visitor; use rustc_front::visit; @@ -61,20 +61,15 @@ fn method_might_be_inlined(tcx: &ty::ctxt, sig: &hir::MethodSig, generics_require_inlining(&sig.generics) { return true } - if impl_src.is_local() { - { - match tcx.map.find(impl_src.node) { - Some(ast_map::NodeItem(item)) => { - item_might_be_inlined(&*item) - } - Some(..) | None => { - tcx.sess.span_bug(impl_item.span, "impl did is not an item") - } - } + if let Some(impl_node_id) = tcx.map.as_local_node_id(impl_src) { + match tcx.map.find(impl_node_id) { + Some(ast_map::NodeItem(item)) => + item_might_be_inlined(&*item), + Some(..) | None => + tcx.sess.span_bug(impl_item.span, "impl did is not an item") } } else { - tcx.sess.span_bug(impl_item.span, "found a foreign impl as a parent \ - of a local method") + tcx.sess.span_bug(impl_item.span, "found a foreign impl as a parent of a local method") } } @@ -106,22 +101,22 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ReachableContext<'a, 'tcx> { }; let def_id = def.def_id(); - if def_id.is_local() { + if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) { if self.def_id_represents_local_inlined_item(def_id) { - self.worklist.push(def_id.node) + self.worklist.push(node_id); } else { match def { // If this path leads to a constant, then we need to // recurse into the constant to continue finding // items that are reachable. def::DefConst(..) | def::DefAssociatedConst(..) => { - self.worklist.push(def_id.node); + self.worklist.push(node_id); } // If this wasn't a static, then the destination is // surely reachable. _ => { - self.reachable_symbols.insert(def_id.node); + self.reachable_symbols.insert(node_id); } } } @@ -132,11 +127,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ReachableContext<'a, 'tcx> { let def_id = self.tcx.tables.borrow().method_map[&method_call].def_id; match self.tcx.impl_or_trait_item(def_id).container() { ty::ImplContainer(_) => { - if def_id.is_local() { + if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) { if self.def_id_represents_local_inlined_item(def_id) { - self.worklist.push(def_id.node) + self.worklist.push(node_id) } - self.reachable_symbols.insert(def_id.node); + self.reachable_symbols.insert(node_id); } } ty::TraitContainer(_) => {} @@ -171,11 +166,11 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { // Returns true if the given def ID represents a local item that is // eligible for inlining and false otherwise. fn def_id_represents_local_inlined_item(&self, def_id: DefId) -> bool { - if def_id.krate != LOCAL_CRATE { - return false - } + let node_id = match self.tcx.map.as_local_node_id(def_id) { + Some(node_id) => node_id, + None => { return false; } + }; - let node_id = def_id.node; match self.tcx.map.find(node_id) { Some(ast_map::NodeItem(item)) => { match item.node { @@ -204,11 +199,8 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { // Check the impl. If the generics on the self // type of the impl require inlining, this method // does too. - assert!(impl_did.is_local()); - match self.tcx - .map - .expect_item(impl_did.node) - .node { + let impl_node_id = self.tcx.map.as_local_node_id(impl_did).unwrap(); + match self.tcx.map.expect_item(impl_node_id).node { hir::ItemImpl(_, _, ref generics, _, _, _) => { generics_require_inlining(generics) } @@ -354,8 +346,8 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { drop_trait.for_each_impl(self.tcx, |drop_impl| { for destructor in &self.tcx.impl_items.borrow()[&drop_impl] { let destructor_did = destructor.def_id(); - if destructor_did.is_local() { - self.reachable_symbols.insert(destructor_did.node); + if let Some(destructor_node_id) = self.tcx.map.as_local_node_id(destructor_did) { + self.reachable_symbols.insert(destructor_node_id); } } }) @@ -377,8 +369,10 @@ pub fn find_reachable(tcx: &ty::ctxt, } for (_, item) in tcx.lang_items.items() { match *item { - Some(did) if did.is_local() => { - reachable_context.worklist.push(did.node); + Some(did) => { + if let Some(node_id) = tcx.map.as_local_node_id(did) { + reachable_context.worklist.push(node_id); + } } _ => {} } diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index af6211665f..1027bbf670 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -394,7 +394,7 @@ impl RegionMaps { self.code_extents.borrow()[e.0 as usize] } pub fn each_encl_scope(&self, mut e:E) where E: FnMut(&CodeExtent, &CodeExtent) { - for child_id in (1..self.code_extents.borrow().len()) { + for child_id in 1..self.code_extents.borrow().len() { let child = CodeExtent(child_id as u32); if let Some(parent) = self.opt_encl_scope(child) { e(&child, &parent) @@ -722,7 +722,7 @@ fn resolve_block(visitor: &mut RegionResolutionVisitor, blk: &hir::Block) { } visitor.visit_stmt(&**statement) } - visit::walk_expr_opt(visitor, &blk.expr) + walk_list!(visitor, visit_expr, &blk.expr); } visitor.cx = prev_cx; @@ -1011,11 +1011,7 @@ fn resolve_local(visitor: &mut RegionResolutionVisitor, local: &hir::Local) { visitor, &**subexpr, blk_id); } } - hir::ExprUnary(hir::UnUniq, ref subexpr) => { - record_rvalue_scope_if_borrow_expr(visitor, &**subexpr, blk_id); - } - hir::ExprCast(ref subexpr, _) | - hir::ExprParen(ref subexpr) => { + hir::ExprCast(ref subexpr, _) => { record_rvalue_scope_if_borrow_expr(visitor, &**subexpr, blk_id) } hir::ExprBlock(ref block) => { @@ -1064,8 +1060,7 @@ fn resolve_local(visitor: &mut RegionResolutionVisitor, local: &hir::Local) { hir::ExprUnary(hir::UnDeref, ref subexpr) | hir::ExprField(ref subexpr, _) | hir::ExprTupField(ref subexpr, _) | - hir::ExprIndex(ref subexpr, _) | - hir::ExprParen(ref subexpr) => { + hir::ExprIndex(ref subexpr, _) => { expr = &**subexpr; } _ => { diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 73b3b32f64..d9398a1c58 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -73,7 +73,7 @@ struct LifetimeContext<'a> { trait_ref_hack: bool, // List of labels in the function/method currently under analysis. - labels_in_fn: Vec<(ast::Ident, Span)>, + labels_in_fn: Vec<(ast::Name, Span)>, } enum ScopeChain<'a> { @@ -195,7 +195,6 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { fn visit_ty(&mut self, ty: &hir::Ty) { match ty.node { hir::TyBareFn(ref c) => { - visit::walk_lifetime_decls_helper(self, &c.lifetimes); self.with(LateScope(&c.lifetimes, self.scope), |old_scope, this| { // a bare fn has no bounds, so everything // contained within is scoped within its binder. @@ -245,7 +244,7 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { |_, this| visit::walk_block(this, b)); } - fn visit_lifetime_ref(&mut self, lifetime_ref: &hir::Lifetime) { + fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) { if lifetime_ref.name == special_idents::static_lifetime.name { self.insert_lifetime(lifetime_ref, DefStaticRegion); return; @@ -255,7 +254,7 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { fn visit_generics(&mut self, generics: &hir::Generics) { for ty_param in generics.ty_params.iter() { - visit::walk_ty_param_bounds_helper(self, &ty_param.bounds); + walk_list!(self, visit_ty_param_bound, &ty_param.bounds); match ty_param.default { Some(ref ty) => self.visit_ty(&**ty), None => {} @@ -273,22 +272,22 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { |old_scope, this| { this.check_lifetime_defs(old_scope, bound_lifetimes); this.visit_ty(&**bounded_ty); - visit::walk_ty_param_bounds_helper(this, bounds); + walk_list!(this, visit_ty_param_bound, bounds); }); self.trait_ref_hack = false; result } else { self.visit_ty(&**bounded_ty); - visit::walk_ty_param_bounds_helper(self, bounds); + walk_list!(self, visit_ty_param_bound, bounds); } } &hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate{ref lifetime, ref bounds, .. }) => { - self.visit_lifetime_ref(lifetime); + self.visit_lifetime(lifetime); for bound in bounds { - self.visit_lifetime_ref(bound); + self.visit_lifetime(bound); } } &hir::WherePredicate::EqPredicate(hir::WhereEqPredicate{ id, @@ -357,10 +356,10 @@ fn signal_shadowing_problem( sess: &Session, name: ast::Name, orig: Original, shadower: Shadower) { if let (ShadowKind::Lifetime, ShadowKind::Lifetime) = (orig.kind, shadower.kind) { // lifetime/lifetime shadowing is an error - sess.span_err(shadower.span, - &format!("{} name `{}` shadows a \ - {} name that is already in scope", - shadower.kind.desc(), name, orig.kind.desc())); + span_err!(sess, shadower.span, E0496, + "{} name `{}` shadows a \ + {} name that is already in scope", + shadower.kind.desc(), name, orig.kind.desc()); } else { // shadowing involving a label is only a warning, due to issues with // labels and lifetimes not being macro-hygienic. @@ -381,7 +380,7 @@ fn extract_labels<'v, 'a>(ctxt: &mut LifetimeContext<'a>, b: &'v hir::Block) { struct GatherLabels<'a> { sess: &'a Session, scope: Scope<'a>, - labels_in_fn: &'a mut Vec<(ast::Ident, Span)>, + labels_in_fn: &'a mut Vec<(ast::Name, Span)>, } let mut gather = GatherLabels { @@ -403,9 +402,9 @@ fn extract_labels<'v, 'a>(ctxt: &mut LifetimeContext<'a>, b: &'v hir::Block) { if let Some(label) = expression_label(ex) { for &(prior, prior_span) in &self.labels_in_fn[..] { // FIXME (#24278): non-hygienic comparison - if label.name == prior.name { + if label == prior { signal_shadowing_problem(self.sess, - label.name, + label, original_label(prior_span), shadower_label(ex.span)); } @@ -426,17 +425,17 @@ fn extract_labels<'v, 'a>(ctxt: &mut LifetimeContext<'a>, b: &'v hir::Block) { } } - fn expression_label(ex: &hir::Expr) -> Option { + fn expression_label(ex: &hir::Expr) -> Option { match ex.node { hir::ExprWhile(_, _, Some(label)) | - hir::ExprLoop(_, Some(label)) => Some(label), + hir::ExprLoop(_, Some(label)) => Some(label.name), _ => None, } } fn check_if_label_shadows_lifetime<'a>(sess: &'a Session, mut scope: Scope<'a>, - label: ast::Ident, + label: ast::Name, label_span: Span) { loop { match *scope { @@ -447,10 +446,10 @@ fn extract_labels<'v, 'a>(ctxt: &mut LifetimeContext<'a>, b: &'v hir::Block) { LateScope(lifetimes, s) => { for lifetime_def in lifetimes { // FIXME (#24278): non-hygienic comparison - if label.name == lifetime_def.lifetime.name { + if label == lifetime_def.lifetime.name { signal_shadowing_problem( sess, - label.name, + label, original_lifetime(&lifetime_def.lifetime), shadower_label(label_span)); return; @@ -703,7 +702,7 @@ impl<'a> LifetimeContext<'a> { { for &(label, label_span) in &self.labels_in_fn { // FIXME (#24278): non-hygienic comparison - if lifetime.name == label.name { + if lifetime.name == label { signal_shadowing_problem(self.sess, lifetime.name, original_label(label_span), @@ -799,7 +798,7 @@ fn early_bound_lifetime_names(generics: &hir::Generics) -> Vec { FreeLifetimeCollector { early_bound: &mut early_bound, late_bound: &mut late_bound }; for ty_param in generics.ty_params.iter() { - visit::walk_ty_param_bounds_helper(&mut collector, &ty_param.bounds); + walk_list!(&mut collector, visit_ty_param_bound, &ty_param.bounds); } for predicate in &generics.where_clause.predicates { match predicate { @@ -807,15 +806,15 @@ fn early_bound_lifetime_names(generics: &hir::Generics) -> Vec { ref bounded_ty, ..}) => { collector.visit_ty(&**bounded_ty); - visit::walk_ty_param_bounds_helper(&mut collector, bounds); + walk_list!(&mut collector, visit_ty_param_bound, bounds); } &hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate{ref lifetime, ref bounds, ..}) => { - collector.visit_lifetime_ref(lifetime); + collector.visit_lifetime(lifetime); for bound in bounds { - collector.visit_lifetime_ref(bound); + collector.visit_lifetime(bound); } } &hir::WherePredicate::EqPredicate(_) => unimplemented!() @@ -843,7 +842,7 @@ fn early_bound_lifetime_names(generics: &hir::Generics) -> Vec { } impl<'a, 'v> Visitor<'v> for FreeLifetimeCollector<'a> { - fn visit_lifetime_ref(&mut self, lifetime_ref: &hir::Lifetime) { + fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) { shuffle(self.early_bound, self.late_bound, lifetime_ref.name); } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 9c46974042..89c0f4f225 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -11,28 +11,43 @@ //! A pass that annotates every item and method with its stability level, //! propagating default levels lexically from parent to children ast nodes. +pub use self::StabilityLevel::*; + use session::Session; use lint; +use metadata::cstore::LOCAL_CRATE; use middle::def; -use middle::def_id::{DefId, LOCAL_CRATE}; +use middle::def_id::{CRATE_DEF_INDEX, DefId}; use middle::ty; use middle::privacy::PublicItems; use metadata::csearch; use syntax::parse::token::InternedString; use syntax::codemap::{Span, DUMMY_SP}; use syntax::ast; -use syntax::ast::NodeId; +use syntax::ast::{NodeId, Attribute}; use syntax::feature_gate::{GateIssue, emit_feature_err}; +use syntax::attr::{self, Stability, AttrMetaMethods}; use util::nodemap::{DefIdMap, FnvHashSet, FnvHashMap}; use rustc_front::hir; -use rustc_front::hir::{FnDecl, Attribute, Block, Crate, Item, Generics, StructField, Variant}; -use rustc_front::attr::{self, Stability, AttrMetaMethods}; +use rustc_front::hir::{FnDecl, Block, Crate, Item, Generics, StructField, Variant}; use rustc_front::visit::{self, FnKind, Visitor}; use std::mem::replace; use std::cmp::Ordering; +#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Copy, Debug, Eq, Hash)] +pub enum StabilityLevel { + Unstable, + Stable, +} + +impl StabilityLevel { + pub fn from_attr_level(level: &attr::StabilityLevel) -> Self { + if level.is_stable() { Stable } else { Unstable } + } +} + /// A stability index, giving the stability level for items and methods. pub struct Index<'tcx> { /// This is mostly a cache, except the stabilities of local items @@ -66,10 +81,9 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> { // if parent is deprecated and we're not, inherit this by merging // deprecated_since and its reason. if let Some(parent_stab) = self.parent { - if parent_stab.deprecated_since.is_some() - && stab.deprecated_since.is_none() { - stab.deprecated_since = parent_stab.deprecated_since.clone(); - stab.reason = parent_stab.reason.clone(); + if parent_stab.depr.is_some() + && stab.depr.is_none() { + stab.depr = parent_stab.depr.clone() } } @@ -77,9 +91,9 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> { // Check if deprecated_since < stable_since. If it is, // this is *almost surely* an accident. - let deprecated_predates_stable = match (stab.deprecated_since.as_ref(), - stab.since.as_ref()) { - (Some(dep_since), Some(stab_since)) => { + let deprecated_predates_stable = match (&stab.depr, &stab.level) { + (&Some(attr::Deprecation {since: ref dep_since, ..}), + &attr::Stable {since: ref stab_since}) => { // explicit version of iter::order::lt to handle parse errors properly let mut is_less = false; for (dep_v, stab_v) in dep_since.split(".").zip(stab_since.split(".")) { @@ -112,10 +126,11 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> { "An API can't be stabilized after it is deprecated"); } - self.index.map.insert(DefId::local(id), Some(stab)); + let def_id = self.tcx.map.local_def_id(id); + self.index.map.insert(def_id, Some(stab)); // Don't inherit #[stable(feature = "rust1", since = "1.0.0")] - if stab.level != attr::Stable { + if !stab.level.is_stable() { let parent = replace(&mut self.parent, Some(stab)); f(self); self.parent = parent; @@ -128,7 +143,8 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> { use_parent, self.parent); if use_parent { if let Some(stab) = self.parent { - self.index.map.insert(DefId::local(id), Some(stab)); + let def_id = self.tcx.map.local_def_id(id); + self.index.map.insert(def_id, Some(stab)); } else if self.index.staged_api[&LOCAL_CRATE] && required && self.export_map.contains(&id) && !self.tcx.sess.opts.test { @@ -182,9 +198,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> { |v| visit::walk_item(v, i), required); if let hir::ItemStruct(ref sd, _) = i.node { - sd.ctor_id.map(|id| { - self.annotate(id, true, &i.attrs, i.span, |_| {}, true) - }); + if !sd.is_struct() { + self.annotate(sd.id(), true, &i.attrs, i.span, |_| {}, true) + } } } @@ -204,9 +220,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> { |v| visit::walk_impl_item(v, ii), true); } - fn visit_variant(&mut self, var: &Variant, g: &'v Generics) { - self.annotate(var.node.id, true, &var.node.attrs, var.span, - |v| visit::walk_variant(v, var, g), true) + fn visit_variant(&mut self, var: &Variant, g: &'v Generics, item_id: NodeId) { + self.annotate(var.node.data.id(), true, &var.node.attrs, var.span, + |v| visit::walk_variant(v, var, g, item_id), true) } fn visit_struct_field(&mut self, s: &StructField) { @@ -237,7 +253,7 @@ impl<'tcx> Index<'tcx> { for attr in &krate.attrs { if &attr.name()[..] == "staged_api" { match attr.node.value.node { - hir::MetaWord(_) => { + ast::MetaWord(_) => { attr::mark_used(attr); is_staged_api = true; } @@ -258,7 +274,7 @@ impl<'tcx> Index<'tcx> { /// features and possibly prints errors. Returns a list of all /// features used. pub fn check_unstable_api_usage(tcx: &ty::ctxt) - -> FnvHashMap { + -> FnvHashMap { let ref active_lib_features = tcx.sess.features.borrow().declared_lib_features; // Put the active features into a map for quick lookup @@ -267,7 +283,8 @@ pub fn check_unstable_api_usage(tcx: &ty::ctxt) let mut checker = Checker { tcx: tcx, active_features: active_features, - used_features: FnvHashMap() + used_features: FnvHashMap(), + in_skip_block: 0, }; let krate = tcx.map.krate(); @@ -280,18 +297,27 @@ pub fn check_unstable_api_usage(tcx: &ty::ctxt) struct Checker<'a, 'tcx: 'a> { tcx: &'a ty::ctxt<'tcx>, active_features: FnvHashSet, - used_features: FnvHashMap + used_features: FnvHashMap, + // Within a block where feature gate checking can be skipped. + in_skip_block: u32, } impl<'a, 'tcx> Checker<'a, 'tcx> { fn check(&mut self, id: DefId, span: Span, stab: &Option<&Stability>) { // Only the cross-crate scenario matters when checking unstable APIs let cross_crate = !id.is_local(); - if !cross_crate { return } + if !cross_crate { + return + } + + // We don't need to check for stability - presumably compiler generated code. + if self.in_skip_block > 0 { + return; + } match *stab { - Some(&Stability { level: attr::Unstable, ref feature, ref reason, issue, .. }) => { - self.used_features.insert(feature.clone(), attr::Unstable); + Some(&Stability { level: attr::Unstable {ref reason, issue}, ref feature, .. }) => { + self.used_features.insert(feature.clone(), Unstable); if !self.active_features.contains(feature) { let msg = match *reason { @@ -299,13 +325,12 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { &feature, &r), None => format!("use of unstable library feature '{}'", &feature) }; - emit_feature_err(&self.tcx.sess.parse_sess.span_diagnostic, - &feature, span, GateIssue::Library(issue), &msg); + &feature, span, GateIssue::Library(Some(issue)), &msg); } } - Some(&Stability { level, ref feature, .. }) => { - self.used_features.insert(feature.clone(), level); + Some(&Stability { ref level, ref feature, .. }) => { + self.used_features.insert(feature.clone(), StabilityLevel::from_attr_level(level)); // Stable APIs are always ok to call and deprecated APIs are // handled by a lint. @@ -336,7 +361,7 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> { // When compiling with --test we don't enforce stability on the // compiler-generated test module, demarcated with `DUMMY_SP` plus the // name `__test` - if item.span == DUMMY_SP && item.ident.name == "__test" { return } + if item.span == DUMMY_SP && item.name.as_str() == "__test" { return } check_item(self.tcx, item, true, &mut |id, sp, stab| self.check(id, sp, stab)); @@ -355,11 +380,32 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> { visit::walk_path(self, path) } + fn visit_path_list_item(&mut self, prefix: &hir::Path, item: &hir::PathListItem) { + check_path_list_item(self.tcx, item, + &mut |id, sp, stab| self.check(id, sp, stab)); + visit::walk_path_list_item(self, prefix, item) + } + fn visit_pat(&mut self, pat: &hir::Pat) { check_pat(self.tcx, pat, &mut |id, sp, stab| self.check(id, sp, stab)); visit::walk_pat(self, pat) } + + fn visit_block(&mut self, b: &hir::Block) { + let old_skip_count = self.in_skip_block; + match b.rules { + hir::BlockCheckMode::PushUnstableBlock => { + self.in_skip_block += 1; + } + hir::BlockCheckMode::PopUnstableBlock => { + self.in_skip_block = self.in_skip_block.checked_sub(1).unwrap(); + } + _ => {} + } + visit::walk_block(self, b); + self.in_skip_block = old_skip_count; + } } /// Helper for discovering nodes to check for stability @@ -374,7 +420,7 @@ pub fn check_item(tcx: &ty::ctxt, item: &hir::Item, warn_about_defns: bool, Some(cnum) => cnum, None => return, }; - let id = DefId { krate: cnum, node: ast::CRATE_NODE_ID }; + let id = DefId { krate: cnum, index: CRATE_DEF_INDEX }; maybe_do_stability_check(tcx, id, item.span, cb); } @@ -387,7 +433,7 @@ pub fn check_item(tcx: &ty::ctxt, item: &hir::Item, warn_about_defns: bool, for impl_item in impl_items { let item = trait_items.iter().find(|item| { - item.name() == impl_item.ident.name + item.name() == impl_item.name }).unwrap(); if warn_about_defns { maybe_do_stability_check(tcx, item.def_id(), impl_item.span, cb); @@ -412,7 +458,7 @@ pub fn check_expr(tcx: &ty::ctxt, e: &hir::Expr, hir::ExprField(ref base_e, ref field) => { span = field.span; match tcx.expr_ty_adjusted(base_e).sty { - ty::TyStruct(def, _) => def.struct_variant().field_named(field.node.name).did, + ty::TyStruct(def, _) => def.struct_variant().field_named(field.node).did, _ => tcx.sess.span_bug(e.span, "stability::check_expr: named field access on non-struct") } @@ -435,7 +481,7 @@ pub fn check_expr(tcx: &ty::ctxt, e: &hir::Expr, // in the construction expression. for field in expr_fields { let did = def.struct_variant() - .field_named(field.ident.node.name) + .field_named(field.name.node) .did; maybe_do_stability_check(tcx, did, field.span, cb); } @@ -465,12 +511,23 @@ pub fn check_path(tcx: &ty::ctxt, path: &hir::Path, id: ast::NodeId, cb: &mut FnMut(DefId, Span, &Option<&Stability>)) { match tcx.def_map.borrow().get(&id).map(|d| d.full_def()) { Some(def::DefPrimTy(..)) => {} + Some(def::DefSelfTy(..)) => {} Some(def) => { maybe_do_stability_check(tcx, def.def_id(), path.span, cb); } None => {} } +} +pub fn check_path_list_item(tcx: &ty::ctxt, item: &hir::PathListItem, + cb: &mut FnMut(DefId, Span, &Option<&Stability>)) { + match tcx.def_map.borrow().get(&item.node.id()).map(|d| d.full_def()) { + Some(def::DefPrimTy(..)) => {} + Some(def) => { + maybe_do_stability_check(tcx, def.def_id(), item.span, cb); + } + None => {} + } } pub fn check_pat(tcx: &ty::ctxt, pat: &hir::Pat, @@ -497,7 +554,7 @@ pub fn check_pat(tcx: &ty::ctxt, pat: &hir::Pat, // Foo { a, b, c } hir::PatStruct(_, ref pat_fields, _) => { for field in pat_fields { - let did = v.field_named(field.node.ident.name).did; + let did = v.field_named(field.node.name).did; maybe_do_stability_check(tcx, did, field.span, cb); } } @@ -591,7 +648,7 @@ fn lookup_uncached<'tcx>(tcx: &ty::ctxt<'tcx>, id: DefId) -> Option<&'tcx Stabil /// libraries, identify activated features that don't exist and error about them. pub fn check_unused_or_stable_features(sess: &Session, lib_features_used: &FnvHashMap) { + StabilityLevel>) { let ref declared_lib_features = sess.features.borrow().declared_lib_features; let mut remaining_lib_features: FnvHashMap = declared_lib_features.clone().into_iter().collect(); @@ -608,7 +665,7 @@ pub fn check_unused_or_stable_features(sess: &Session, for (used_lib_feature, level) in lib_features_used { match remaining_lib_features.remove(used_lib_feature) { Some(span) => { - if *level == attr::Stable { + if *level == Stable { sess.add_lint(lint::builtin::STABLE_FEATURES, ast::CRATE_NODE_ID, span, diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs index 87939c45d6..a3795a32af 100644 --- a/src/librustc/middle/traits/coherence.rs +++ b/src/librustc/middle/traits/coherence.rs @@ -17,7 +17,8 @@ use super::PredicateObligation; use super::project; use super::util; -use middle::def_id::{DefId, LOCAL_CRATE}; +use metadata::cstore::LOCAL_CRATE; +use middle::def_id::DefId; use middle::subst::{Subst, Substs, TypeSpace}; use middle::ty::{self, ToPolyTraitRef, Ty}; use middle::infer::{self, InferCtxt}; diff --git a/src/librustc/middle/traits/error_reporting.rs b/src/librustc/middle/traits/error_reporting.rs index 4580e642d1..a54818b2b5 100644 --- a/src/librustc/middle/traits/error_reporting.rs +++ b/src/librustc/middle/traits/error_reporting.rs @@ -32,7 +32,7 @@ use util::nodemap::{FnvHashMap, FnvHashSet}; use std::fmt; use syntax::codemap::Span; -use rustc_front::attr::{AttributeMethods, AttrMetaMethods}; +use syntax::attr::{AttributeMethods, AttrMetaMethods}; #[derive(Debug, PartialEq, Eq, Hash)] pub struct TraitErrorKey<'tcx> { @@ -216,7 +216,7 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, is_warning, infcx.tcx.sess, obligation.cause.span, E0276, "the requirement `{}` appears on the impl \ method but not on the corresponding trait method", - obligation.predicate);; + obligation.predicate); } else { match obligation.predicate { ty::Predicate::Trait(ref trait_predicate) => { @@ -276,9 +276,12 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, } ty::Predicate::ObjectSafe(trait_def_id) => { + let violations = object_safety_violations( + infcx.tcx, trait_def_id); report_object_safety_error(infcx.tcx, obligation.cause.span, trait_def_id, + violations, is_warning); note_obligation_cause(infcx, obligation); } @@ -314,7 +317,9 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, } TraitNotObjectSafe(did) => { - report_object_safety_error(infcx.tcx, obligation.cause.span, did, is_warning); + let violations = object_safety_violations(infcx.tcx, did); + report_object_safety_error(infcx.tcx, obligation.cause.span, did, + violations, is_warning); note_obligation_cause(infcx, obligation); } } @@ -323,6 +328,7 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, pub fn report_object_safety_error<'tcx>(tcx: &ty::ctxt<'tcx>, span: Span, trait_def_id: DefId, + violations: Vec, is_warning: bool) { span_err_or_warn!( @@ -331,7 +337,7 @@ pub fn report_object_safety_error<'tcx>(tcx: &ty::ctxt<'tcx>, tcx.item_path_str(trait_def_id)); let mut reported_violations = FnvHashSet(); - for violation in object_safety_violations(tcx, trait_def_id) { + for violation in violations { if !reported_violations.insert(violation.clone()) { continue; } @@ -449,7 +455,7 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, if !infcx.tcx.sess.has_errors() { span_err!(infcx.tcx.sess, obligation.cause.span, E0284, "type annotations required: cannot resolve `{}`", - predicate);; + predicate); note_obligation_cause(infcx, obligation); } } diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index 7f76cfaee5..a037621f5c 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -39,6 +39,7 @@ pub use self::project::MismatchedProjectionTypes; pub use self::project::normalize; pub use self::project::Normalized; pub use self::object_safety::is_object_safe; +pub use self::object_safety::astconv_object_safety_violations; pub use self::object_safety::object_safety_violations; pub use self::object_safety::ObjectSafetyViolation; pub use self::object_safety::MethodViolationCode; diff --git a/src/librustc/middle/traits/object_safety.rs b/src/librustc/middle/traits/object_safety.rs index 333d23e6ec..934c35fa20 100644 --- a/src/librustc/middle/traits/object_safety.rs +++ b/src/librustc/middle/traits/object_safety.rs @@ -23,7 +23,7 @@ use super::elaborate_predicates; use middle::def_id::DefId; use middle::subst::{self, SelfSpace, TypeSpace}; use middle::traits; -use middle::ty::{self, ToPolyTraitRef, Ty}; +use middle::ty::{self, HasTypeFlags, ToPolyTraitRef, Ty}; use std::rc::Rc; use syntax::ast; @@ -76,6 +76,27 @@ pub fn is_object_safe<'tcx>(tcx: &ty::ctxt<'tcx>, result } +/// Returns the object safety violations that affect +/// astconv - currently, Self in supertraits. This is needed +/// because `object_safety_violations` can't be used during +/// type collection. +pub fn astconv_object_safety_violations<'tcx>(tcx: &ty::ctxt<'tcx>, + trait_def_id: DefId) + -> Vec> +{ + let mut violations = vec![]; + + if supertraits_reference_self(tcx, trait_def_id) { + violations.push(ObjectSafetyViolation::SupertraitSelf); + } + + debug!("object_safety_violations_for_trait(trait_def_id={:?}) = {:?}", + trait_def_id, + violations); + + violations +} + pub fn object_safety_violations<'tcx>(tcx: &ty::ctxt<'tcx>, trait_def_id: DefId) -> Vec> @@ -118,9 +139,9 @@ fn object_safety_violations_for_trait<'tcx>(tcx: &ty::ctxt<'tcx>, violations } -fn supertraits_reference_self<'tcx>(tcx: &ty::ctxt<'tcx>, - trait_def_id: DefId) - -> bool +pub fn supertraits_reference_self<'tcx>(tcx: &ty::ctxt<'tcx>, + trait_def_id: DefId) + -> bool { let trait_def = tcx.lookup_trait_def(trait_def_id); let trait_ref = trait_def.trait_ref.clone(); @@ -137,7 +158,7 @@ fn supertraits_reference_self<'tcx>(tcx: &ty::ctxt<'tcx>, data.0.trait_ref.substs.types.get_slice(TypeSpace) .iter() .cloned() - .any(is_self) + .any(|t| t.has_self_ty()) } ty::Predicate::Projection(..) | ty::Predicate::WellFormed(..) | @@ -177,7 +198,7 @@ fn generics_require_sized_self<'tcx>(tcx: &ty::ctxt<'tcx>, .any(|predicate| { match predicate { ty::Predicate::Trait(ref trait_pred) if trait_pred.def_id() == sized_def_id => { - is_self(trait_pred.0.self_ty()) + trait_pred.0.self_ty().is_self() } ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | @@ -355,10 +376,3 @@ fn contains_illegal_self_type_reference<'tcx>(tcx: &ty::ctxt<'tcx>, error } - -fn is_self<'tcx>(ty: Ty<'tcx>) -> bool { - match ty.sty { - ty::TyParam(ref data) => data.space == subst::SelfSpace, - _ => false, - } -} diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 6f422018c1..f6e35cf739 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -37,7 +37,7 @@ use super::{VtableImplData, VtableObjectData, VtableBuiltinData, use super::object_safety; use super::util; -use middle::def_id::{DefId, LOCAL_CRATE}; +use middle::def_id::DefId; use middle::infer; use middle::infer::{InferCtxt, TypeFreshener}; use middle::subst::{Subst, Substs, TypeSpace}; @@ -1719,7 +1719,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet ty::TyTuple(ref tys) => ok_if(tys.clone()), - ty::TyClosure(def_id, ref substs) => { + ty::TyClosure(_, ref substs) => { // FIXME -- This case is tricky. In the case of by-ref // closures particularly, we need the results of // inference to decide how to reflect the type of each @@ -1729,7 +1729,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // captures are by value. Really what we ought to do // is reserve judgement and then intertwine this // analysis with closure inference. - assert_eq!(def_id.krate, LOCAL_CRATE); // Unboxed closures shouldn't be // implicitly copyable @@ -1863,7 +1862,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { tys.clone() } - ty::TyClosure(def_id, ref substs) => { + ty::TyClosure(_, ref substs) => { // FIXME(#27086). We are invariant w/r/t our // substs.func_substs, but we don't see them as // constituent types; this seems RIGHT but also like @@ -1872,7 +1871,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // OIBIT interact? That is, there is no way to say // "make me invariant with respect to this TYPE, but // do not act as though I can reach it" - assert_eq!(def_id.krate, LOCAL_CRATE); substs.upvar_tys.clone() } @@ -2396,7 +2394,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// errors as if there is no applicable impl, but rather report /// errors are about mismatched argument types. /// - /// Here is an example. Imagine we have an closure expression + /// Here is an example. Imagine we have a closure expression /// and we desugared it so that the type of the expression is /// `Closure`, and `Closure` expects an int as argument. Then it /// is "as if" the compiler generated this impl: diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index 1c5156aab0..c50c9e9765 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -408,7 +408,7 @@ pub fn upcast<'tcx>(tcx: &ty::ctxt<'tcx>, .collect() } -/// Given an trait `trait_ref`, returns the number of vtable entries +/// Given a trait `trait_ref`, returns the number of vtable entries /// that come from `trait_ref`, excluding its supertraits. Used in /// computing the vtable base for an upcast trait of a trait object. pub fn count_own_vtable_entries<'tcx>(tcx: &ty::ctxt<'tcx>, diff --git a/src/librustc/middle/ty/adjustment.rs b/src/librustc/middle/ty/adjustment.rs index cadab499c0..c44ebcfdb6 100644 --- a/src/librustc/middle/ty/adjustment.rs +++ b/src/librustc/middle/ty/adjustment.rs @@ -48,7 +48,7 @@ pub enum AutoAdjustment<'tcx> { /// /// 1. The simplest cases are where the pointer is not adjusted fat vs thin. /// Here the pointer will be dereferenced N times (where a dereference can -/// happen to to raw or borrowed pointers or any smart pointer which implements +/// 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 diff --git a/src/librustc/middle/ty/cast.rs b/src/librustc/middle/ty/cast.rs index 8cb4f941a2..8233b6b2b2 100644 --- a/src/librustc/middle/ty/cast.rs +++ b/src/librustc/middle/ty/cast.rs @@ -13,7 +13,7 @@ use middle::ty::{self, Ty}; -use rustc_front::hir as ast; +use syntax::ast; /// Types that are represented as ints. #[derive(Copy, Clone, Debug, PartialEq, Eq)] diff --git a/src/librustc/middle/ty/contents.rs b/src/librustc/middle/ty/contents.rs index bcce9e8ea5..afe88f70d9 100644 --- a/src/librustc/middle/ty/contents.rs +++ b/src/librustc/middle/ty/contents.rs @@ -16,7 +16,7 @@ use util::nodemap::FnvHashMap; use std::fmt; use std::ops; -use rustc_front::hir; +use syntax::ast; /// Type contents is how the type checker reasons about kinds. /// They track what kinds of things are found within a type. You can @@ -182,7 +182,7 @@ impl<'tcx> ty::TyS<'tcx> { let result = match ty.sty { // usize and isize are ffi-unsafe - ty::TyUint(hir::TyUs) | ty::TyInt(hir::TyIs) => { + ty::TyUint(ast::TyUs) | ty::TyInt(ast::TyIs) => { TC::None } diff --git a/src/librustc/middle/ty/context.rs b/src/librustc/middle/ty/context.rs index ef9707967f..830232cf37 100644 --- a/src/librustc/middle/ty/context.rs +++ b/src/librustc/middle/ty/context.rs @@ -16,6 +16,7 @@ use front::map as ast_map; use session::Session; use lint; +use metadata::csearch; use middle; use middle::def::DefMap; use middle::def_id::DefId; @@ -41,11 +42,11 @@ use std::cell::{Cell, RefCell, Ref}; use std::hash::{Hash, Hasher}; use std::rc::Rc; use syntax::abi; -use syntax::ast::{Name, NodeId}; +use syntax::ast::{self, Name, NodeId}; +use syntax::attr; use syntax::parse::token::special_idents; use rustc_front::hir; -use rustc_front::attr; /// Internal storage pub struct CtxtArenas<'tcx> { @@ -134,6 +135,40 @@ impl<'tcx> Tables<'tcx> { closure_kinds: DefIdMap(), } } + + pub fn closure_kind(this: &RefCell, + tcx: &ty::ctxt<'tcx>, + def_id: DefId) + -> ty::ClosureKind { + // If this is a local def-id, it should be inserted into the + // tables by typeck; else, it will be retreived from + // the external crate metadata. + if let Some(&kind) = this.borrow().closure_kinds.get(&def_id) { + return kind; + } + + let kind = csearch::closure_kind(tcx, def_id); + this.borrow_mut().closure_kinds.insert(def_id, kind); + kind + } + + pub fn closure_type(this: &RefCell, + tcx: &ty::ctxt<'tcx>, + def_id: DefId, + substs: &ClosureSubsts<'tcx>) + -> ty::ClosureTy<'tcx> + { + // If this is a local def-id, it should be inserted into the + // tables by typeck; else, it will be retreived from + // the external crate metadata. + if let Some(ty) = this.borrow().closure_tys.get(&def_id) { + return ty.subst(tcx, &substs.func_substs); + } + + let ty = csearch::closure_ty(tcx, def_id); + this.borrow_mut().closure_tys.insert(def_id, ty.clone()); + ty.subst(tcx, &substs.func_substs) + } } impl<'tcx> CommonTypes<'tcx> { @@ -146,18 +181,18 @@ impl<'tcx> CommonTypes<'tcx> { bool: mk(TyBool), char: mk(TyChar), err: mk(TyError), - isize: mk(TyInt(hir::TyIs)), - i8: mk(TyInt(hir::TyI8)), - i16: mk(TyInt(hir::TyI16)), - i32: mk(TyInt(hir::TyI32)), - i64: mk(TyInt(hir::TyI64)), - usize: mk(TyUint(hir::TyUs)), - u8: mk(TyUint(hir::TyU8)), - u16: mk(TyUint(hir::TyU16)), - u32: mk(TyUint(hir::TyU32)), - u64: mk(TyUint(hir::TyU64)), - f32: mk(TyFloat(hir::TyF32)), - f64: mk(TyFloat(hir::TyF64)), + isize: mk(TyInt(ast::TyIs)), + i8: mk(TyInt(ast::TyI8)), + i16: mk(TyInt(ast::TyI16)), + i32: mk(TyInt(ast::TyI32)), + i64: mk(TyInt(ast::TyI64)), + usize: mk(TyUint(ast::TyUs)), + u8: mk(TyUint(ast::TyU8)), + u16: mk(TyUint(ast::TyU16)), + u32: mk(TyUint(ast::TyU32)), + u64: mk(TyUint(ast::TyU64)), + f32: mk(TyFloat(ast::TyF32)), + f64: mk(TyFloat(ast::TyF64)), } } } @@ -184,7 +219,7 @@ pub struct ctxt<'tcx> { /// Common types, pre-interned for your convenience. pub types: CommonTypes<'tcx>, - pub sess: Session, + pub sess: &'tcx Session, pub def_map: DefMap, pub named_region_map: resolve_lifetime::NamedRegionMap, @@ -235,8 +270,6 @@ pub struct ctxt<'tcx> { pub ty_param_defs: RefCell>>, pub normalized_cache: RefCell, Ty<'tcx>>>, pub lang_items: middle::lang_items::LanguageItems, - /// A mapping of fake provided method def_ids to the default implementation - pub provided_method_sources: RefCell>, /// Maps from def-id of a type or region parameter to its /// (inferred) variance. @@ -274,7 +307,6 @@ pub struct ctxt<'tcx> { /// These caches are used by const_eval when decoding external constants. pub extern_const_statics: RefCell>, - pub extern_const_variants: RefCell>, pub extern_const_fns: RefCell>, pub node_lint_levels: RefCell { /// constitute it. pub fragment_infos: RefCell>>, } -impl<'tcx> ctxt<'tcx> { - pub fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind { - *self.tables.borrow().closure_kinds.get(&def_id).unwrap() - } - - pub fn closure_type(&self, - def_id: DefId, - substs: &ClosureSubsts<'tcx>) - -> ty::ClosureTy<'tcx> - { - self.tables.borrow().closure_tys.get(&def_id).unwrap().subst(self, &substs.func_substs) - } +impl<'tcx> ctxt<'tcx> { pub fn type_parameter_def(&self, node_id: NodeId) -> ty::TypeParameterDef<'tcx> @@ -422,7 +443,7 @@ impl<'tcx> ctxt<'tcx> { /// to the context. The closure enforces that the type context and any interned /// value (types, substs, etc.) can only be used while `ty::tls` has a valid /// reference to the context, to allow formatting values that need it. - pub fn create_and_enter(s: Session, + pub fn create_and_enter(s: &'tcx Session, arenas: &'tcx CtxtArenas<'tcx>, def_map: DefMap, named_region_map: resolve_lifetime::NamedRegionMap, @@ -431,7 +452,7 @@ impl<'tcx> ctxt<'tcx> { region_maps: RegionMaps, lang_items: middle::lang_items::LanguageItems, stability: stability::Index<'tcx>, - f: F) -> (Session, R) + f: F) -> R where F: FnOnce(&ctxt<'tcx>) -> R { let interner = RefCell::new(FnvHashMap()); @@ -471,7 +492,6 @@ impl<'tcx> ctxt<'tcx> { ty_param_defs: RefCell::new(NodeMap()), normalized_cache: RefCell::new(FnvHashMap()), lang_items: lang_items, - provided_method_sources: RefCell::new(DefIdMap()), inherent_impls: RefCell::new(DefIdMap()), impl_items: RefCell::new(DefIdMap()), used_unsafe: RefCell::new(NodeSet()), @@ -479,7 +499,6 @@ impl<'tcx> ctxt<'tcx> { populated_external_types: RefCell::new(DefIdSet()), populated_external_primitive_impls: RefCell::new(DefIdSet()), extern_const_statics: RefCell::new(DefIdMap()), - extern_const_variants: RefCell::new(DefIdMap()), extern_const_fns: RefCell::new(DefIdMap()), node_lint_levels: RefCell::new(FnvHashMap()), transmute_restrictions: RefCell::new(Vec::new()), @@ -537,7 +556,6 @@ impl<'a, 'tcx> Lift<'tcx> for &'a Substs<'a> { pub mod tls { use middle::ty; - use session::Session; use std::fmt; use syntax::codemap; @@ -555,17 +573,15 @@ pub mod tls { }) } - pub fn enter<'tcx, F: FnOnce(&ty::ctxt<'tcx>) -> R, R>(tcx: ty::ctxt<'tcx>, f: F) - -> (Session, R) { - let result = codemap::SPAN_DEBUG.with(|span_dbg| { + pub fn enter<'tcx, F: FnOnce(&ty::ctxt<'tcx>) -> R, R>(tcx: ty::ctxt<'tcx>, f: F) -> R { + codemap::SPAN_DEBUG.with(|span_dbg| { let original_span_debug = span_dbg.get(); span_dbg.set(span_debug); let tls_ptr = &tcx as *const _ as *const ThreadLocalTyCx; let result = TLS_TCX.set(unsafe { &*tls_ptr }, || f(&tcx)); span_dbg.set(original_span_debug); result - }); - (tcx.sess, result) + }) } pub fn with R, R>(f: F) -> R { @@ -767,30 +783,30 @@ impl<'tcx> ctxt<'tcx> { ctxt::intern_ty(&self.arenas.type_, &self.interner, st) } - pub fn mk_mach_int(&self, tm: hir::IntTy) -> Ty<'tcx> { + pub fn mk_mach_int(&self, tm: ast::IntTy) -> Ty<'tcx> { match tm { - hir::TyIs => self.types.isize, - hir::TyI8 => self.types.i8, - hir::TyI16 => self.types.i16, - hir::TyI32 => self.types.i32, - hir::TyI64 => self.types.i64, + ast::TyIs => self.types.isize, + ast::TyI8 => self.types.i8, + ast::TyI16 => self.types.i16, + ast::TyI32 => self.types.i32, + ast::TyI64 => self.types.i64, } } - pub fn mk_mach_uint(&self, tm: hir::UintTy) -> Ty<'tcx> { + pub fn mk_mach_uint(&self, tm: ast::UintTy) -> Ty<'tcx> { match tm { - hir::TyUs => self.types.usize, - hir::TyU8 => self.types.u8, - hir::TyU16 => self.types.u16, - hir::TyU32 => self.types.u32, - hir::TyU64 => self.types.u64, + ast::TyUs => self.types.usize, + ast::TyU8 => self.types.u8, + ast::TyU16 => self.types.u16, + ast::TyU32 => self.types.u32, + ast::TyU64 => self.types.u64, } } - pub fn mk_mach_float(&self, tm: hir::FloatTy) -> Ty<'tcx> { + pub fn mk_mach_float(&self, tm: ast::FloatTy) -> Ty<'tcx> { match tm { - hir::TyF32 => self.types.f32, - hir::TyF64 => self.types.f64, + ast::TyF32 => self.types.f32, + ast::TyF64 => self.types.f64, } } diff --git a/src/librustc/middle/ty/error.rs b/src/librustc/middle/ty/error.rs index 72c4366c5b..61536934aa 100644 --- a/src/librustc/middle/ty/error.rs +++ b/src/librustc/middle/ty/error.rs @@ -15,7 +15,7 @@ use middle::ty::{self, BoundRegion, Region, Ty}; use std::fmt; use syntax::abi; -use syntax::ast::Name; +use syntax::ast::{self, Name}; use syntax::codemap::Span; use rustc_front::hir; @@ -49,7 +49,7 @@ pub enum TypeError<'tcx> { Sorts(ExpectedFound>), IntegerAsChar, IntMismatch(ExpectedFound), - FloatMismatch(ExpectedFound), + FloatMismatch(ExpectedFound), Traits(ExpectedFound), BuiltinBoundsMismatch(ExpectedFound), VariadicMismatch(ExpectedFound), @@ -302,13 +302,15 @@ impl<'tcx> ty::ctxt<'tcx> { expected.ty, found.ty)); - match (expected.def_id.is_local(), - self.map.opt_span(expected.def_id.node)) { - (true, Some(span)) => { + match + self.map.as_local_node_id(expected.def_id) + .and_then(|node_id| self.map.opt_span(node_id)) + { + Some(span) => { self.sess.span_note(span, &format!("a default was defined here...")); } - (_, _) => { + None => { self.sess.note( &format!("a default is defined on `{}`", self.item_path_str(expected.def_id))); @@ -319,13 +321,15 @@ impl<'tcx> ty::ctxt<'tcx> { expected.origin_span, &format!("...that was applied to an unconstrained type variable here")); - match (found.def_id.is_local(), - self.map.opt_span(found.def_id.node)) { - (true, Some(span)) => { + match + self.map.as_local_node_id(found.def_id) + .and_then(|node_id| self.map.opt_span(node_id)) + { + Some(span) => { self.sess.span_note(span, &format!("a second default was defined here...")); } - (_, _) => { + None => { self.sess.note( &format!("a second default is defined on `{}`", self.item_path_str(found.def_id))); diff --git a/src/librustc/middle/ty/fast_reject.rs b/src/librustc/middle/ty/fast_reject.rs index 2b81be1918..77608f4012 100644 --- a/src/librustc/middle/ty/fast_reject.rs +++ b/src/librustc/middle/ty/fast_reject.rs @@ -10,7 +10,7 @@ use middle::def_id::DefId; use middle::ty::{self, Ty}; -use rustc_front::hir; +use syntax::ast; use self::SimplifiedType::*; @@ -19,9 +19,9 @@ use self::SimplifiedType::*; pub enum SimplifiedType { BoolSimplifiedType, CharSimplifiedType, - IntSimplifiedType(hir::IntTy), - UintSimplifiedType(hir::UintTy), - FloatSimplifiedType(hir::FloatTy), + IntSimplifiedType(ast::IntTy), + UintSimplifiedType(ast::UintTy), + FloatSimplifiedType(ast::FloatTy), EnumSimplifiedType(DefId), StrSimplifiedType, VecSimplifiedType, diff --git a/src/librustc/middle/ty/mod.rs b/src/librustc/middle/ty/mod.rs index 3025d7b589..5736344149 100644 --- a/src/librustc/middle/ty/mod.rs +++ b/src/librustc/middle/ty/mod.rs @@ -22,9 +22,10 @@ pub use self::LvaluePreference::*; use front::map as ast_map; use front::map::LinkedPath; use metadata::csearch; +use metadata::cstore::LOCAL_CRATE; use middle; use middle::def::{self, ExportMap}; -use middle::def_id::{DefId, LOCAL_CRATE}; +use middle::def_id::DefId; use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem}; use middle::subst::{self, ParamSpace, Subst, Substs, VecPerParamSpace}; use middle::traits; @@ -44,13 +45,13 @@ use std::slice; use std::vec::IntoIter; use std::collections::{HashMap, HashSet}; use syntax::ast::{self, CrateNum, Name, NodeId}; +use syntax::attr::{self, AttrMetaMethods}; use syntax::codemap::Span; use syntax::parse::token::{InternedString, special_idents}; use rustc_front::hir; use rustc_front::hir::{ItemImpl, ItemTrait}; use rustc_front::hir::{MutImmutable, MutMutable, Visibility}; -use rustc_front::attr::{self, AttrMetaMethods}; pub use self::sty::{Binder, DebruijnIndex}; pub use self::sty::{BuiltinBound, BuiltinBounds, ExistentialBounds}; @@ -101,12 +102,12 @@ pub const INITIAL_DISCRIMINANT_VALUE: Disr = 0; /// The complete set of all analyses described in this module. This is /// produced by the driver and fed to trans and later passes. -pub struct CrateAnalysis { +pub struct CrateAnalysis<'a> { pub export_map: ExportMap, pub exported_items: middle::privacy::ExportedItems, pub public_items: middle::privacy::PublicItems, pub reachable: NodeSet, - pub name: String, + pub name: &'a str, pub glob_map: Option, } @@ -235,9 +236,6 @@ pub struct Method<'tcx> { pub vis: hir::Visibility, pub def_id: DefId, pub container: ImplOrTraitItemContainer, - - // If this method is provided, we need to know where it came from - pub provided_source: Option } impl<'tcx> Method<'tcx> { @@ -248,8 +246,7 @@ impl<'tcx> Method<'tcx> { explicit_self: ExplicitSelfCategory, vis: hir::Visibility, def_id: DefId, - container: ImplOrTraitItemContainer, - provided_source: Option) + container: ImplOrTraitItemContainer) -> Method<'tcx> { Method { name: name, @@ -260,7 +257,6 @@ impl<'tcx> Method<'tcx> { vis: vis, def_id: def_id, container: container, - provided_source: provided_source } } @@ -293,7 +289,7 @@ pub struct AssociatedConst<'tcx> { pub vis: hir::Visibility, pub def_id: DefId, pub container: ImplOrTraitItemContainer, - pub default: Option, + pub has_value: bool } #[derive(Clone, Copy, Debug)] @@ -371,7 +367,6 @@ pub type MethodMap<'tcx> = FnvHashMap>; pub struct CReaderCacheKey { pub cnum: CrateNum, pub pos: usize, - pub len: usize } /// A restriction that certain types must be the same size. The use of @@ -577,8 +572,8 @@ pub struct ClosureUpvar<'tcx> { #[derive(Clone, Copy, PartialEq)] pub enum IntVarValue { - IntType(hir::IntTy), - UintType(hir::UintTy), + IntType(ast::IntTy), + UintType(ast::UintTy), } /// Default region to use for the bound of objects that are @@ -622,7 +617,7 @@ pub struct RegionParameterDef { impl RegionParameterDef { pub fn to_early_bound_region(&self) -> ty::Region { ty::ReEarlyBound(ty::EarlyBoundRegion { - param_id: self.def_id.node, + def_id: self.def_id, space: self.space, index: self.index, name: self.name, @@ -1129,7 +1124,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { // associated types don't have their own entry (for some reason), // so for now just grab environment for the impl let impl_id = cx.map.get_parent(id); - let impl_def_id = DefId::local(impl_id); + let impl_def_id = cx.map.local_def_id(impl_id); let scheme = cx.lookup_item_type(impl_def_id); let predicates = cx.lookup_predicates(impl_def_id); cx.construct_parameter_environment(impl_item.span, @@ -1138,7 +1133,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { id) } hir::ConstImplItem(_, _) => { - let def_id = DefId::local(id); + let def_id = cx.map.local_def_id(id); let scheme = cx.lookup_item_type(def_id); let predicates = cx.lookup_predicates(def_id); cx.construct_parameter_environment(impl_item.span, @@ -1147,7 +1142,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { id) } hir::MethodImplItem(_, ref body) => { - let method_def_id = DefId::local(id); + let method_def_id = cx.map.local_def_id(id); match cx.impl_or_trait_item(method_def_id) { MethodTraitItem(ref method_ty) => { let method_generics = &method_ty.generics; @@ -1173,7 +1168,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { // associated types don't have their own entry (for some reason), // so for now just grab environment for the trait let trait_id = cx.map.get_parent(id); - let trait_def_id = DefId::local(trait_id); + let trait_def_id = cx.map.local_def_id(trait_id); let trait_def = cx.lookup_trait_def(trait_def_id); let predicates = cx.lookup_predicates(trait_def_id); cx.construct_parameter_environment(trait_item.span, @@ -1182,7 +1177,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { id) } hir::ConstTraitItem(..) => { - let def_id = DefId::local(id); + let def_id = cx.map.local_def_id(id); let scheme = cx.lookup_item_type(def_id); let predicates = cx.lookup_predicates(def_id); cx.construct_parameter_environment(trait_item.span, @@ -1195,8 +1190,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { // block, unless this is a trait method with // no default, then fallback to the method id. let body_id = body.as_ref().map(|b| b.id).unwrap_or(id); - let method_def_id = DefId::local(id); - + let method_def_id = cx.map.local_def_id(id); match cx.impl_or_trait_item(method_def_id) { MethodTraitItem(ref method_ty) => { let method_generics = &method_ty.generics; @@ -1221,7 +1215,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { match item.node { hir::ItemFn(_, _, _, _, _, ref body) => { // We assume this is a function. - let fn_def_id = DefId::local(id); + let fn_def_id = cx.map.local_def_id(id); let fn_scheme = cx.lookup_item_type(fn_def_id); let fn_predicates = cx.lookup_predicates(fn_def_id); @@ -1235,7 +1229,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { hir::ItemImpl(..) | hir::ItemConst(..) | hir::ItemStatic(..) => { - let def_id = DefId::local(id); + let def_id = cx.map.local_def_id(id); let scheme = cx.lookup_item_type(def_id); let predicates = cx.lookup_predicates(def_id); cx.construct_parameter_environment(item.span, @@ -1244,7 +1238,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { id) } hir::ItemTrait(..) => { - let def_id = DefId::local(id); + let def_id = cx.map.local_def_id(id); let trait_def = cx.lookup_trait_def(def_id); let predicates = cx.lookup_predicates(def_id); cx.construct_parameter_environment(item.span, @@ -1476,10 +1470,12 @@ pub type VariantDefMaster<'tcx> = &'tcx VariantDefData<'tcx, 'tcx>; pub type FieldDefMaster<'tcx> = &'tcx FieldDefData<'tcx, 'tcx>; pub struct VariantDefData<'tcx, 'container: 'tcx> { + /// The variant's DefId. If this is a tuple-like struct, + /// this is the DefId of the struct's ctor. pub did: DefId, pub name: Name, // struct's name if this is a struct pub disr_val: Disr, - pub fields: Vec> + pub fields: Vec>, } pub struct FieldDefData<'tcx, 'container: 'tcx> { @@ -1537,7 +1533,7 @@ impl<'tcx, 'container> Hash for AdtDefData<'tcx, 'container> { pub enum AdtKind { Struct, Enum } #[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum VariantKind { Dict, Tuple, Unit } +pub enum VariantKind { Struct, Tuple, Unit } impl<'tcx, 'container> AdtDefData<'tcx, 'container> { fn new(tcx: &ctxt<'tcx>, @@ -1720,7 +1716,7 @@ impl<'tcx, 'container> VariantDefData<'tcx, 'container> { Some(&FieldDefData { name, .. }) if name == special_idents::unnamed_field.name => { VariantKind::Tuple } - Some(_) => VariantKind::Dict + Some(_) => VariantKind::Struct } } @@ -2102,21 +2098,15 @@ impl<'tcx> ctxt<'tcx> { hir::ExprCast(..) => { false } - - hir::ExprParen(ref e) => self.expr_is_lval(e), } } - pub fn provided_source(&self, id: DefId) -> Option { - self.provided_method_sources.borrow().get(&id).cloned() - } - pub fn provided_trait_methods(&self, id: DefId) -> Vec>> { - if id.is_local() { - if let ItemTrait(_, _, _, ref ms) = self.map.expect_item(id.node).node { + if let Some(id) = self.map.as_local_node_id(id) { + if let ItemTrait(_, _, _, ref ms) = self.map.expect_item(id).node { ms.iter().filter_map(|ti| { if let hir::MethodTraitItem(_, Some(_)) = ti.node { - match self.impl_or_trait_item(DefId::local(ti.id)) { + match self.impl_or_trait_item(self.map.local_def_id(ti.id)) { MethodTraitItem(m) => Some(m), _ => { self.sess.bug("provided_trait_methods(): \ @@ -2137,12 +2127,12 @@ impl<'tcx> ctxt<'tcx> { } pub fn associated_consts(&self, id: DefId) -> Vec>> { - if id.is_local() { - match self.map.expect_item(id.node).node { + if let Some(id) = self.map.as_local_node_id(id) { + match self.map.expect_item(id).node { ItemTrait(_, _, _, ref tis) => { tis.iter().filter_map(|ti| { if let hir::ConstTraitItem(_, _) = ti.node { - match self.impl_or_trait_item(DefId::local(ti.id)) { + match self.impl_or_trait_item(self.map.local_def_id(ti.id)) { ConstTraitItem(ac) => Some(ac), _ => { self.sess.bug("associated_consts(): \ @@ -2158,7 +2148,7 @@ impl<'tcx> ctxt<'tcx> { ItemImpl(_, _, _, _, _, ref iis) => { iis.iter().filter_map(|ii| { if let hir::ConstImplItem(_, _) = ii.node { - match self.impl_or_trait_item(DefId::local(ii.id)) { + match self.impl_or_trait_item(self.map.local_def_id(ii.id)) { ConstTraitItem(ac) => Some(ac), _ => { self.sess.bug("associated_consts(): \ @@ -2198,8 +2188,8 @@ impl<'tcx> ctxt<'tcx> { } pub fn trait_impl_polarity(&self, id: DefId) -> Option { - if id.is_local() { - match self.map.find(id.node) { + if let Some(id) = self.map.as_local_node_id(id) { + match self.map.find(id) { Some(ast_map::NodeItem(item)) => { match item.node { hir::ItemImpl(_, polarity, _, _, _, _) => Some(polarity), @@ -2254,9 +2244,9 @@ impl<'tcx> ctxt<'tcx> { /// Returns whether this DefId refers to an impl pub fn is_impl(&self, id: DefId) -> bool { - if id.is_local() { + if let Some(id) = self.map.as_local_node_id(id) { if let Some(ast_map::NodeItem( - &hir::Item { node: hir::ItemImpl(..), .. })) = self.map.find(id.node) { + &hir::Item { node: hir::ItemImpl(..), .. })) = self.map.find(id) { true } else { false @@ -2274,19 +2264,27 @@ impl<'tcx> ctxt<'tcx> { self.with_path(id, |path| ast_map::path_to_string(path)) } + pub fn def_path(&self, id: DefId) -> ast_map::DefPath { + if id.is_local() { + self.map.def_path(id) + } else { + csearch::def_path(self, id) + } + } + pub fn with_path(&self, id: DefId, f: F) -> T where F: FnOnce(ast_map::PathElems) -> T, { - if id.is_local() { - self.map.with_path(id.node, f) + if let Some(id) = self.map.as_local_node_id(id) { + self.map.with_path(id, f) } else { f(csearch::get_item_path(self, id).iter().cloned().chain(LinkedPath::empty())) } } pub fn item_name(&self, id: DefId) -> ast::Name { - if id.is_local() { - self.map.get_path_elem(id.node).name() + if let Some(id) = self.map.as_local_node_id(id) { + self.map.get_path_elem(id).name() } else { csearch::get_item_name(self, id) } @@ -2345,9 +2343,9 @@ impl<'tcx> ctxt<'tcx> { } /// Get the attributes of a definition. - pub fn get_attrs(&self, did: DefId) -> Cow<'tcx, [hir::Attribute]> { - if did.is_local() { - Cow::Borrowed(self.map.attrs(did.node)) + pub fn get_attrs(&self, did: DefId) -> Cow<'tcx, [ast::Attribute]> { + if let Some(id) = self.map.as_local_node_id(did) { + Cow::Borrowed(self.map.attrs(id)) } else { Cow::Owned(csearch::get_item_attrs(&self.sess.cstore, did)) } @@ -2479,16 +2477,9 @@ impl<'tcx> ctxt<'tcx> { // the map. This is a bit unfortunate. for impl_item_def_id in &impl_items { let method_def_id = impl_item_def_id.def_id(); - match self.impl_or_trait_item(method_def_id) { - MethodTraitItem(method) => { - if let Some(source) = method.provided_source { - self.provided_method_sources - .borrow_mut() - .insert(method_def_id, source); - } - } - _ => {} - } + // load impl items eagerly for convenience + // FIXME: we may want to load these lazily + self.impl_or_trait_item(method_def_id); } // Store the implementation info. @@ -2498,6 +2489,18 @@ impl<'tcx> ctxt<'tcx> { def.flags.set(def.flags.get() | TraitFlags::IMPLS_VALID); } + pub fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind { + Tables::closure_kind(&self.tables, self, def_id) + } + + pub fn closure_type(&self, + def_id: DefId, + substs: &ClosureSubsts<'tcx>) + -> ty::ClosureTy<'tcx> + { + Tables::closure_type(&self.tables, self, def_id, substs) + } + /// Given the def_id of an impl, return the def_id of the trait it implements. /// If it implements no trait, return `None`. pub fn trait_id_of_impl(&self, def_id: DefId) -> Option { diff --git a/src/librustc/middle/ty/structural_impls.rs b/src/librustc/middle/ty/structural_impls.rs index 4ed87e673d..176dc5a743 100644 --- a/src/librustc/middle/ty/structural_impls.rs +++ b/src/librustc/middle/ty/structural_impls.rs @@ -417,7 +417,9 @@ impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>> Lift<'tcx> for (A, B) { impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for [T] { type Lifted = Vec; fn lift_to_tcx(&self, tcx: &ty::ctxt<'tcx>) -> Option { - let mut result = Vec::with_capacity(self.len()); + // type annotation needed to inform `projection_must_outlive` + let mut result : Vec<>::Lifted> + = Vec::with_capacity(self.len()); for x in self { if let Some(value) = tcx.lift(x) { result.push(value); diff --git a/src/librustc/middle/ty/sty.rs b/src/librustc/middle/ty/sty.rs index 3969738a22..37ed716eaa 100644 --- a/src/librustc/middle/ty/sty.rs +++ b/src/librustc/middle/ty/sty.rs @@ -23,7 +23,7 @@ use std::fmt; use std::ops; use std::mem; use syntax::abi; -use syntax::ast::{Name, NodeId}; +use syntax::ast::{self, Name}; use syntax::parse::token::special_idents; use rustc_front::hir; @@ -79,13 +79,13 @@ pub enum TypeVariants<'tcx> { TyChar, /// A primitive signed integer type. For example, `i32`. - TyInt(hir::IntTy), + TyInt(ast::IntTy), /// A primitive unsigned integer type. For example, `u32`. - TyUint(hir::UintTy), + TyUint(ast::UintTy), /// A primitive floating-point type. For example, `f64`. - TyFloat(hir::FloatTy), + TyFloat(ast::FloatTy), /// An enumerated type, defined with `enum`. /// @@ -93,7 +93,7 @@ pub enum TypeVariants<'tcx> { /// That is, even after substitution it is possible that there are type /// variables. This happens when the `TyEnum` corresponds to an enum /// definition and not a concrete use of it. To get the correct `TyEnum` - /// from the tcx, use the `NodeId` from the `hir::Ty` and look it up in + /// from the tcx, use the `NodeId` from the `ast::Ty` and look it up in /// the `ast_ty_to_ty_cache`. This is probably true for `TyStruct` as /// well. TyEnum(AdtDef<'tcx>, &'tcx Substs<'tcx>), @@ -126,7 +126,7 @@ pub enum TypeVariants<'tcx> { TyRef(&'tcx Region, TypeAndMut<'tcx>), /// If the def-id is Some(_), then this is the type of a specific - /// fn item. Otherwise, if None(_), it a fn pointer type. + /// fn item. Otherwise, if None(_), it is a fn pointer type. /// /// FIXME: Conflating function pointers and the type of a /// function is probably a terrible idea; a function pointer is a @@ -675,7 +675,7 @@ pub enum Region { #[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)] pub struct EarlyBoundRegion { - pub param_id: NodeId, + pub def_id: DefId, pub space: subst::ParamSpace, pub index: u32, pub name: Name, @@ -899,6 +899,14 @@ impl<'tcx> TyS<'tcx> { } } + pub fn is_phantom_data(&self) -> bool { + if let TyStruct(def, _) = self.sty { + def.is_phantom_data() + } else { + false + } + } + pub fn is_bool(&self) -> bool { self.sty == TyBool } pub fn is_param(&self, space: subst::ParamSpace, index: u32) -> bool { @@ -944,7 +952,7 @@ impl<'tcx> TyS<'tcx> { pub fn sequence_element_type(&self, cx: &ty::ctxt<'tcx>) -> Ty<'tcx> { match self.sty { TyArray(ty, _) | TySlice(ty) => ty, - TyStr => cx.mk_mach_uint(hir::TyU8), + TyStr => cx.mk_mach_uint(ast::TyU8), _ => cx.sess.bug(&format!("sequence_element_type called on non-sequence value: {}", self)), } @@ -1035,7 +1043,7 @@ impl<'tcx> TyS<'tcx> { pub fn is_uint(&self) -> bool { match self.sty { - TyInfer(IntVar(_)) | TyUint(hir::TyUs) => true, + TyInfer(IntVar(_)) | TyUint(ast::TyUs) => true, _ => false } } @@ -1081,7 +1089,7 @@ impl<'tcx> TyS<'tcx> { pub fn is_machine(&self) -> bool { match self.sty { - TyInt(hir::TyIs) | TyUint(hir::TyUs) => false, + TyInt(ast::TyIs) | TyUint(ast::TyUs) => false, TyInt(..) | TyUint(..) | TyFloat(..) => true, _ => false } diff --git a/src/librustc/middle/ty/util.rs b/src/librustc/middle/ty/util.rs index 8831461853..2142755d4a 100644 --- a/src/librustc/middle/ty/util.rs +++ b/src/librustc/middle/ty/util.rs @@ -14,7 +14,7 @@ use back::svh::Svh; use middle::const_eval::{self, ConstVal, ErrKind}; use middle::const_eval::EvalHint::UncheckedExprHint; use middle::def_id::DefId; -use middle::subst; +use middle::subst::{self, Subst, Substs}; use middle::infer; use middle::pat_util; use middle::traits; @@ -26,11 +26,12 @@ use util::num::ToPrimitive; use std::cmp; use std::hash::{Hash, SipHasher, Hasher}; -use syntax::ast::Name; +use std::rc::Rc; +use syntax::ast::{self, Name}; +use syntax::attr::{self, AttrMetaMethods, SignedInt, UnsignedInt}; use syntax::codemap::Span; use rustc_front::hir; -use rustc_front::attr::{self, AttrMetaMethods, SignedInt, UnsignedInt}; pub trait IntTypeExt { fn to_ty<'tcx>(&self, cx: &ty::ctxt<'tcx>) -> Ty<'tcx>; @@ -44,48 +45,48 @@ pub trait IntTypeExt { impl IntTypeExt for attr::IntType { fn to_ty<'tcx>(&self, cx: &ty::ctxt<'tcx>) -> Ty<'tcx> { match *self { - SignedInt(hir::TyI8) => cx.types.i8, - SignedInt(hir::TyI16) => cx.types.i16, - SignedInt(hir::TyI32) => cx.types.i32, - SignedInt(hir::TyI64) => cx.types.i64, - SignedInt(hir::TyIs) => cx.types.isize, - UnsignedInt(hir::TyU8) => cx.types.u8, - UnsignedInt(hir::TyU16) => cx.types.u16, - UnsignedInt(hir::TyU32) => cx.types.u32, - UnsignedInt(hir::TyU64) => cx.types.u64, - UnsignedInt(hir::TyUs) => cx.types.usize, + SignedInt(ast::TyI8) => cx.types.i8, + SignedInt(ast::TyI16) => cx.types.i16, + SignedInt(ast::TyI32) => cx.types.i32, + SignedInt(ast::TyI64) => cx.types.i64, + SignedInt(ast::TyIs) => cx.types.isize, + UnsignedInt(ast::TyU8) => cx.types.u8, + UnsignedInt(ast::TyU16) => cx.types.u16, + UnsignedInt(ast::TyU32) => cx.types.u32, + UnsignedInt(ast::TyU64) => cx.types.u64, + UnsignedInt(ast::TyUs) => cx.types.usize, } } fn i64_to_disr(&self, val: i64) -> Option { match *self { - SignedInt(hir::TyI8) => val.to_i8() .map(|v| v as Disr), - SignedInt(hir::TyI16) => val.to_i16() .map(|v| v as Disr), - SignedInt(hir::TyI32) => val.to_i32() .map(|v| v as Disr), - SignedInt(hir::TyI64) => val.to_i64() .map(|v| v as Disr), - UnsignedInt(hir::TyU8) => val.to_u8() .map(|v| v as Disr), - UnsignedInt(hir::TyU16) => val.to_u16() .map(|v| v as Disr), - UnsignedInt(hir::TyU32) => val.to_u32() .map(|v| v as Disr), - UnsignedInt(hir::TyU64) => val.to_u64() .map(|v| v as Disr), - - UnsignedInt(hir::TyUs) | - SignedInt(hir::TyIs) => unreachable!(), + SignedInt(ast::TyI8) => val.to_i8() .map(|v| v as Disr), + SignedInt(ast::TyI16) => val.to_i16() .map(|v| v as Disr), + SignedInt(ast::TyI32) => val.to_i32() .map(|v| v as Disr), + SignedInt(ast::TyI64) => val.to_i64() .map(|v| v as Disr), + UnsignedInt(ast::TyU8) => val.to_u8() .map(|v| v as Disr), + UnsignedInt(ast::TyU16) => val.to_u16() .map(|v| v as Disr), + UnsignedInt(ast::TyU32) => val.to_u32() .map(|v| v as Disr), + UnsignedInt(ast::TyU64) => val.to_u64() .map(|v| v as Disr), + + UnsignedInt(ast::TyUs) | + SignedInt(ast::TyIs) => unreachable!(), } } fn u64_to_disr(&self, val: u64) -> Option { match *self { - SignedInt(hir::TyI8) => val.to_i8() .map(|v| v as Disr), - SignedInt(hir::TyI16) => val.to_i16() .map(|v| v as Disr), - SignedInt(hir::TyI32) => val.to_i32() .map(|v| v as Disr), - SignedInt(hir::TyI64) => val.to_i64() .map(|v| v as Disr), - UnsignedInt(hir::TyU8) => val.to_u8() .map(|v| v as Disr), - UnsignedInt(hir::TyU16) => val.to_u16() .map(|v| v as Disr), - UnsignedInt(hir::TyU32) => val.to_u32() .map(|v| v as Disr), - UnsignedInt(hir::TyU64) => val.to_u64() .map(|v| v as Disr), - - UnsignedInt(hir::TyUs) | - SignedInt(hir::TyIs) => unreachable!(), + SignedInt(ast::TyI8) => val.to_i8() .map(|v| v as Disr), + SignedInt(ast::TyI16) => val.to_i16() .map(|v| v as Disr), + SignedInt(ast::TyI32) => val.to_i32() .map(|v| v as Disr), + SignedInt(ast::TyI64) => val.to_i64() .map(|v| v as Disr), + UnsignedInt(ast::TyU8) => val.to_u8() .map(|v| v as Disr), + UnsignedInt(ast::TyU16) => val.to_u16() .map(|v| v as Disr), + UnsignedInt(ast::TyU32) => val.to_u32() .map(|v| v as Disr), + UnsignedInt(ast::TyU64) => val.to_u64() .map(|v| v as Disr), + + UnsignedInt(ast::TyUs) | + SignedInt(ast::TyIs) => unreachable!(), } } @@ -97,18 +98,18 @@ impl IntTypeExt for attr::IntType { // SignedInt repr means we *want* to reinterpret the bits // treating the highest bit of Disr as a sign-bit, so // cast to i64 before range-checking. - SignedInt(hir::TyI8) => add1!((val as i64).to_i8()), - SignedInt(hir::TyI16) => add1!((val as i64).to_i16()), - SignedInt(hir::TyI32) => add1!((val as i64).to_i32()), - SignedInt(hir::TyI64) => add1!(Some(val as i64)), - - UnsignedInt(hir::TyU8) => add1!(val.to_u8()), - UnsignedInt(hir::TyU16) => add1!(val.to_u16()), - UnsignedInt(hir::TyU32) => add1!(val.to_u32()), - UnsignedInt(hir::TyU64) => add1!(Some(val)), - - UnsignedInt(hir::TyUs) | - SignedInt(hir::TyIs) => unreachable!(), + SignedInt(ast::TyI8) => add1!((val as i64).to_i8()), + SignedInt(ast::TyI16) => add1!((val as i64).to_i16()), + SignedInt(ast::TyI32) => add1!((val as i64).to_i32()), + SignedInt(ast::TyI64) => add1!(Some(val as i64)), + + UnsignedInt(ast::TyU8) => add1!(val.to_u8()), + UnsignedInt(ast::TyU16) => add1!(val.to_u16()), + UnsignedInt(ast::TyU32) => add1!(val.to_u32()), + UnsignedInt(ast::TyU64) => add1!(Some(val)), + + UnsignedInt(ast::TyUs) | + SignedInt(ast::TyIs) => unreachable!(), } } @@ -117,17 +118,17 @@ impl IntTypeExt for attr::IntType { // full range from `i64::MIN` through `u64::MAX`. fn disr_string(&self, val: Disr) -> String { match *self { - SignedInt(hir::TyI8) => format!("{}", val as i8 ), - SignedInt(hir::TyI16) => format!("{}", val as i16), - SignedInt(hir::TyI32) => format!("{}", val as i32), - SignedInt(hir::TyI64) => format!("{}", val as i64), - UnsignedInt(hir::TyU8) => format!("{}", val as u8 ), - UnsignedInt(hir::TyU16) => format!("{}", val as u16), - UnsignedInt(hir::TyU32) => format!("{}", val as u32), - UnsignedInt(hir::TyU64) => format!("{}", val as u64), - - UnsignedInt(hir::TyUs) | - SignedInt(hir::TyIs) => unreachable!(), + SignedInt(ast::TyI8) => format!("{}", val as i8 ), + SignedInt(ast::TyI16) => format!("{}", val as i16), + SignedInt(ast::TyI32) => format!("{}", val as i32), + SignedInt(ast::TyI64) => format!("{}", val as i64), + UnsignedInt(ast::TyU8) => format!("{}", val as u8 ), + UnsignedInt(ast::TyU16) => format!("{}", val as u16), + UnsignedInt(ast::TyU32) => format!("{}", val as u32), + UnsignedInt(ast::TyU64) => format!("{}", val as u64), + + UnsignedInt(ast::TyUs) | + SignedInt(ast::TyIs) => unreachable!(), } } @@ -137,17 +138,17 @@ impl IntTypeExt for attr::IntType { } let val = val.unwrap_or(ty::INITIAL_DISCRIMINANT_VALUE); match *self { - SignedInt(hir::TyI8) => add1!(val as i8 ), - SignedInt(hir::TyI16) => add1!(val as i16), - SignedInt(hir::TyI32) => add1!(val as i32), - SignedInt(hir::TyI64) => add1!(val as i64), - UnsignedInt(hir::TyU8) => add1!(val as u8 ), - UnsignedInt(hir::TyU16) => add1!(val as u16), - UnsignedInt(hir::TyU32) => add1!(val as u32), - UnsignedInt(hir::TyU64) => add1!(val as u64), - - UnsignedInt(hir::TyUs) | - SignedInt(hir::TyIs) => unreachable!(), + SignedInt(ast::TyI8) => add1!(val as i8 ), + SignedInt(ast::TyI16) => add1!(val as i16), + SignedInt(ast::TyI32) => add1!(val as i32), + SignedInt(ast::TyI64) => add1!(val as i64), + UnsignedInt(ast::TyU8) => add1!(val as u8 ), + UnsignedInt(ast::TyU16) => add1!(val as u16), + UnsignedInt(ast::TyU32) => add1!(val as u32), + UnsignedInt(ast::TyU64) => add1!(val as u64), + + UnsignedInt(ast::TyUs) | + SignedInt(ast::TyIs) => unreachable!(), } } } @@ -279,14 +280,14 @@ impl<'tcx> ty::ctxt<'tcx> { // // NB. Historically `fn enum_variants` generate i64 here, while // rustc_typeck::check would generate isize. - _ => SignedInt(hir::TyIs), + _ => SignedInt(ast::TyIs), }; let repr_type_ty = repr_type.to_ty(self); let repr_type = match repr_type { - SignedInt(hir::TyIs) => + SignedInt(ast::TyIs) => SignedInt(self.sess.target.int_type), - UnsignedInt(hir::TyUs) => + UnsignedInt(ast::TyUs) => UnsignedInt(self.sess.target.uint_type), other => other }; @@ -334,7 +335,7 @@ impl<'tcx> ty::ctxt<'tcx> { /// Returns the repeat count for a repeating vector expression. pub fn eval_repeat_count(&self, count_expr: &hir::Expr) -> usize { let hint = UncheckedExprHint(self.types.usize); - match const_eval::eval_const_expr_partial(self, count_expr, hint) { + match const_eval::eval_const_expr_partial(self, count_expr, hint, None) { Ok(val) => { let found = match val { ConstVal::Uint(count) => return count as usize, @@ -460,7 +461,7 @@ impl<'tcx> ty::ctxt<'tcx> { tcx.sess.cstore.get_crate_hash(did.krate) }; h.as_str().hash(state); - did.node.hash(state); + did.index.hash(state); }; let mt = |state: &mut SipHasher, mt: TypeAndMut| { mt.mutbl.hash(state); @@ -565,84 +566,86 @@ impl<'tcx> ty::ctxt<'tcx> { } } - /// Returns true if this ADT is a dtorck type, i.e. whether it being - /// safe for destruction requires it to be alive + /// Returns true if this ADT is a dtorck type. + /// + /// Invoking the destructor of a dtorck type during usual cleanup + /// (e.g. the glue emitted for stack unwinding) requires all + /// lifetimes in the type-structure of `adt` to strictly outlive + /// the adt value itself. + /// + /// If `adt` is not dtorck, then the adt's destructor can be + /// invoked even when there are lifetimes in the type-structure of + /// `adt` that do not strictly outlive the adt value itself. + /// (This allows programs to make cyclic structures without + /// resorting to unasfe means; see RFCs 769 and 1238). pub fn is_adt_dtorck(&self, adt: ty::AdtDef<'tcx>) -> bool { let dtor_method = match adt.destructor() { Some(dtor) => dtor, None => return false }; - let impl_did = self.impl_of_method(dtor_method).unwrap_or_else(|| { - self.sess.bug(&format!("no Drop impl for the dtor of `{:?}`", adt)) - }); - let generics = adt.type_scheme(self).generics; - - // In `impl<'a> Drop ...`, we automatically assume - // `'a` is meaningful and thus represents a bound - // through which we could reach borrowed data. + + // RFC 1238: if the destructor method is tagged with the + // attribute `unsafe_destructor_blind_to_params`, then the + // compiler is being instructed to *assume* that the + // destructor will not access borrowed data, + // even if such data is otherwise reachable. // - // FIXME (pnkfelix): In the future it would be good to - // extend the language to allow the user to express, - // in the impl signature, that a lifetime is not - // actually used (something like `where 'a: ?Live`). - if generics.has_region_params(subst::TypeSpace) { - debug!("typ: {:?} has interesting dtor due to region params", - adt); - return true; - } + // Such access can be in plain sight (e.g. dereferencing + // `*foo.0` of `Foo<'a>(&'a u32)`) or indirectly hidden + // (e.g. calling `foo.0.clone()` of `Foo`). + return !self.has_attr(dtor_method, "unsafe_destructor_blind_to_params"); + } +} - let mut seen_items = Vec::new(); - let mut items_to_inspect = vec![impl_did]; - while let Some(item_def_id) = items_to_inspect.pop() { - if seen_items.contains(&item_def_id) { - continue; - } +#[derive(Debug)] +pub struct ImplMethod<'tcx> { + pub method: Rc>, + pub substs: Substs<'tcx>, + pub is_provided: bool +} - for pred in self.lookup_predicates(item_def_id).predicates { - let result = match pred { - ty::Predicate::Equate(..) | - ty::Predicate::RegionOutlives(..) | - ty::Predicate::TypeOutlives(..) | - ty::Predicate::WellFormed(..) | - ty::Predicate::ObjectSafe(..) | - ty::Predicate::Projection(..) => { - // For now, assume all these where-clauses - // may give drop implementation capabilty - // to access borrowed data. - true +impl<'tcx> ty::ctxt<'tcx> { + #[inline(never)] // is this perfy enough? + pub fn get_impl_method(&self, + impl_def_id: DefId, + substs: Substs<'tcx>, + name: Name) + -> ImplMethod<'tcx> + { + // there don't seem to be nicer accessors to these: + let impl_or_trait_items_map = self.impl_or_trait_items.borrow(); + + for impl_item in &self.impl_items.borrow()[&impl_def_id] { + if let ty::MethodTraitItem(ref meth) = + impl_or_trait_items_map[&impl_item.def_id()] { + if meth.name == name { + return ImplMethod { + method: meth.clone(), + substs: substs, + is_provided: false } + } + } + } - ty::Predicate::Trait(ty::Binder(ref t_pred)) => { - let def_id = t_pred.trait_ref.def_id; - if self.trait_items(def_id).len() != 0 { - // If trait has items, assume it adds - // capability to access borrowed data. - true - } else { - // Trait without items is itself - // uninteresting from POV of dropck. - // - // However, may have parent w/ items; - // so schedule checking of predicates, - items_to_inspect.push(def_id); - // and say "no capability found" for now. - false - } + // It is not in the impl - get the default from the trait. + let trait_ref = self.impl_trait_ref(impl_def_id).unwrap(); + for trait_item in self.trait_items(trait_ref.def_id).iter() { + if let &ty::MethodTraitItem(ref meth) = trait_item { + if meth.name == name { + let impl_to_trait_substs = self + .make_substs_for_receiver_types(&trait_ref, meth); + return ImplMethod { + method: meth.clone(), + substs: impl_to_trait_substs.subst(self, &substs), + is_provided: true } - }; - - if result { - debug!("typ: {:?} has interesting dtor due to generic preds, e.g. {:?}", - adt, pred); - return true; } } - - seen_items.push(item_def_id); } - debug!("typ: {:?} is dtorck-safe", adt); - false + self.sess.bug(&format!("method {:?} not found in {:?}", + name, impl_def_id)) } } diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs index 43b7943fd2..96c8e5c7d5 100644 --- a/src/librustc/middle/weak_lang_items.rs +++ b/src/librustc/middle/weak_lang_items.rs @@ -15,6 +15,7 @@ use session::Session; use metadata::csearch; use middle::lang_items; +use syntax::ast; use syntax::codemap::Span; use syntax::parse::token::InternedString; use rustc_front::visit::Visitor; @@ -54,7 +55,7 @@ pub fn check_crate(krate: &hir::Crate, verify(sess, items); } -pub fn link_name(attrs: &[hir::Attribute]) -> Option { +pub fn link_name(attrs: &[ast::Attribute]) -> Option { lang_items::extract(attrs).and_then(|name| { $(if &name[..] == stringify!($name) { Some(InternedString::new(stringify!($sym))) diff --git a/src/librustc/plugin/build.rs b/src/librustc/plugin/build.rs index 55fd63b753..ea85b26426 100644 --- a/src/librustc/plugin/build.rs +++ b/src/librustc/plugin/build.rs @@ -11,12 +11,12 @@ //! Used by `rustc` when compiling a plugin crate. use syntax::ast; +use syntax::attr; use syntax::codemap::Span; use syntax::diagnostic; use rustc_front::visit; use rustc_front::visit::Visitor; use rustc_front::hir; -use rustc_front::attr; struct RegistrarFinder { registrars: Vec<(ast::NodeId, Span)> , diff --git a/src/librustc/plugin/load.rs b/src/librustc/plugin/load.rs index e0cb47d6c9..751e748094 100644 --- a/src/librustc/plugin/load.rs +++ b/src/librustc/plugin/load.rs @@ -15,7 +15,6 @@ use metadata::creader::CrateReader; use plugin::registry::Registry; use std::borrow::ToOwned; -use std::dynamic_lib::DynamicLibrary; use std::env; use std::mem; use std::path::PathBuf; @@ -39,6 +38,10 @@ struct PluginLoader<'a> { plugins: Vec, } +fn call_malformed_plugin_attribute(a: &Session, b: Span) { + span_err!(a, b, E0498, "malformed plugin attribute"); +} + /// Read plugin metadata and dynamically load registrar functions. pub fn load_plugins(sess: &Session, krate: &ast::Crate, addl_plugins: Option>) -> Vec { @@ -52,14 +55,14 @@ pub fn load_plugins(sess: &Session, krate: &ast::Crate, let plugins = match attr.meta_item_list() { Some(xs) => xs, None => { - sess.span_err(attr.span, "malformed plugin attribute"); + call_malformed_plugin_attribute(sess, attr.span); continue; } }; for plugin in plugins { if plugin.value_str().is_some() { - sess.span_err(attr.span, "malformed plugin attribute"); + call_malformed_plugin_attribute(sess, attr.span); continue; } @@ -99,10 +102,13 @@ impl<'a> PluginLoader<'a> { } // Dynamically link a registrar function into the compiler process. + #[allow(deprecated)] fn dylink_registrar(&mut self, span: Span, path: PathBuf, symbol: String) -> PluginRegistrarFun { + use std::dynamic_lib::DynamicLibrary; + // Make sure the path contains a / or the linker will search for it. let path = env::current_dir().unwrap().join(&path); diff --git a/src/librustc/plugin/registry.rs b/src/librustc/plugin/registry.rs index e79721b434..50ca092dfe 100644 --- a/src/librustc/plugin/registry.rs +++ b/src/librustc/plugin/registry.rs @@ -10,7 +10,7 @@ //! Used by plugin crates to tell `rustc` about the plugins they provide. -use lint::{LintPassObject, LintId, Lint}; +use lint::{EarlyLintPassObject, LateLintPassObject, LintId, Lint}; use session::Session; use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT}; @@ -48,7 +48,10 @@ pub struct Registry<'a> { pub syntax_exts: Vec, #[doc(hidden)] - pub lint_passes: Vec, + pub early_lint_passes: Vec, + + #[doc(hidden)] + pub late_lint_passes: Vec, #[doc(hidden)] pub lint_groups: HashMap<&'static str, Vec>, @@ -68,7 +71,8 @@ impl<'a> Registry<'a> { args_hidden: None, krate_span: krate.span, syntax_exts: vec!(), - lint_passes: vec!(), + early_lint_passes: vec!(), + late_lint_passes: vec!(), lint_groups: HashMap::new(), llvm_passes: vec!(), attributes: vec!(), @@ -89,7 +93,6 @@ impl<'a> Registry<'a> { /// Register a syntax extension of any kind. /// /// This is the most general hook into `libsyntax`'s expansion behavior. - #[allow(deprecated)] pub fn register_syntax_extension(&mut self, name: ast::Name, extension: SyntaxExtension) { self.syntax_exts.push((name, match extension { NormalTT(ext, _, allow_internal_unstable) => { @@ -118,10 +121,14 @@ impl<'a> Registry<'a> { } /// Register a compiler lint pass. - pub fn register_lint_pass(&mut self, lint_pass: LintPassObject) { - self.lint_passes.push(lint_pass); + pub fn register_early_lint_pass(&mut self, lint_pass: EarlyLintPassObject) { + self.early_lint_passes.push(lint_pass); } + /// Register a compiler lint pass. + pub fn register_late_lint_pass(&mut self, lint_pass: LateLintPassObject) { + self.late_lint_passes.push(lint_pass); + } /// Register a lint group. pub fn register_lint_group(&mut self, name: &'static str, to: Vec<&'static Lint>) { self.lint_groups.insert(name, to.into_iter().map(|x| LintId::of(x)).collect()); diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index b56283e756..7e8104d08d 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -15,7 +15,6 @@ pub use self::EntryFnType::*; pub use self::CrateType::*; pub use self::Passes::*; pub use self::OptLevel::*; -pub use self::OutputType::*; pub use self::DebugInfoLevel::*; use session::{early_error, early_warn, Session}; @@ -25,11 +24,9 @@ use rustc_back::target::Target; use lint; use metadata::cstore; -use syntax::ast; -use rustc_front::hir::{IntTy, UintTy}; +use syntax::ast::{self, IntTy, UintTy}; use syntax::attr; use syntax::attr::AttrMetaMethods; -use rustc_front::hir; use syntax::diagnostic::{ColorConfig, Auto, Always, Never, SpanHandler}; use syntax::parse; use syntax::parse::token::InternedString; @@ -64,14 +61,14 @@ pub enum DebugInfoLevel { FullDebugInfo, } -#[derive(Clone, Copy, PartialEq, PartialOrd, Ord, Eq)] +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub enum OutputType { - OutputTypeBitcode, - OutputTypeAssembly, - OutputTypeLlvmAssembly, - OutputTypeObject, - OutputTypeExe, - OutputTypeDepInfo, + Bitcode, + Assembly, + LlvmAssembly, + Object, + Exe, + DepInfo, } #[derive(Clone)] @@ -87,7 +84,7 @@ pub struct Options { pub lint_opts: Vec<(String, lint::Level)>, pub lint_cap: Option, pub describe_lints: bool, - pub output_types: Vec, + pub output_types: HashMap>, // This was mutable for rustpkg, which updates search paths based on the // parsed code. It remains mutable in case its replacements wants to use // this. @@ -104,11 +101,8 @@ pub struct Options { pub parse_only: bool, pub no_trans: bool, pub treat_err_as_bug: bool, - pub always_build_mir: bool, pub no_analysis: bool, pub debugging_opts: DebuggingOptions, - /// Whether to write dependency files. It's (enabled, optional filename). - pub write_dependency_info: (bool, Option), pub prints: Vec, pub cg: CodegenOptions, pub color: ColorConfig, @@ -153,26 +147,25 @@ pub struct OutputFilenames { pub out_filestem: String, pub single_output_file: Option, pub extra: String, + pub outputs: HashMap>, } impl OutputFilenames { pub fn path(&self, flavor: OutputType) -> PathBuf { - match self.single_output_file { - Some(ref path) => return path.clone(), - None => {} - } - self.temp_path(flavor) + self.outputs.get(&flavor).and_then(|p| p.to_owned()) + .or_else(|| self.single_output_file.clone()) + .unwrap_or_else(|| self.temp_path(flavor)) } pub fn temp_path(&self, flavor: OutputType) -> PathBuf { let base = self.out_directory.join(&self.filestem()); match flavor { - OutputTypeBitcode => base.with_extension("bc"), - OutputTypeAssembly => base.with_extension("s"), - OutputTypeLlvmAssembly => base.with_extension("ll"), - OutputTypeObject => base.with_extension("o"), - OutputTypeDepInfo => base.with_extension("d"), - OutputTypeExe => base, + OutputType::Bitcode => base.with_extension("bc"), + OutputType::Assembly => base.with_extension("s"), + OutputType::LlvmAssembly => base.with_extension("ll"), + OutputType::Object => base.with_extension("o"), + OutputType::DepInfo => base.with_extension("d"), + OutputType::Exe => base, } } @@ -208,7 +201,7 @@ pub fn basic_options() -> Options { lint_opts: Vec::new(), lint_cap: None, describe_lints: false, - output_types: Vec::new(), + output_types: HashMap::new(), search_paths: SearchPaths::new(), maybe_sysroot: None, target_triple: host_triple().to_string(), @@ -217,10 +210,8 @@ pub fn basic_options() -> Options { parse_only: false, no_trans: false, treat_err_as_bug: false, - always_build_mir: false, no_analysis: false, debugging_opts: basic_debugging_options(), - write_dependency_info: (false, None), prints: Vec::new(), cg: basic_codegen_options(), color: Auto, @@ -585,8 +576,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "Run all passes except translation; no output"), treat_err_as_bug: bool = (false, parse_bool, "Treat all errors that occur as bugs"), - always_build_mir: bool = (false, parse_bool, - "Always build MIR for all fns, even without a #[rustc_mir] annotation"), no_analysis: bool = (false, parse_bool, "Parse and expand the source, but run no analysis"), extra_plugins: Vec = (Vec::new(), parse_list, @@ -603,6 +592,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "For every macro invocation, print its name and arguments"), enable_nonzeroing_move_hints: bool = (false, parse_bool, "Force nonzeroing move optimization on"), + keep_mtwt_tables: bool = (false, parse_bool, + "Don't clear the resolution tables after analysis"), } pub fn default_lib_output() -> CrateType { @@ -617,6 +608,7 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig { let wordsz = &sess.target.target.target_pointer_width; let os = &sess.target.target.target_os; let env = &sess.target.target.target_env; + let vendor = &sess.target.target.target_vendor; let fam = match sess.target.target.options.is_like_windows { true => InternedString::new("windows"), @@ -632,6 +624,7 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig { mk(InternedString::new("target_endian"), intern(end)), mk(InternedString::new("target_pointer_width"), intern(wordsz)), mk(InternedString::new("target_env"), intern(env)), + mk(InternedString::new("target_vendor"), intern(vendor)), ]; if sess.opts.debug_assertions { ret.push(attr::mk_word_item(InternedString::new("debug_assertions"))); @@ -669,8 +662,8 @@ pub fn build_target_config(opts: &Options, sp: &SpanHandler) -> Config { }; let (int_type, uint_type) = match &target.target_pointer_width[..] { - "32" => (hir::TyI32, hir::TyU32), - "64" => (hir::TyI64, hir::TyU64), + "32" => (ast::TyI32, ast::TyU32), + "64" => (ast::TyI64, ast::TyU64), w => sp.handler().fatal(&format!("target specification was invalid: unrecognized \ target-pointer-width {}", w)) }; @@ -898,38 +891,36 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let parse_only = debugging_opts.parse_only; let no_trans = debugging_opts.no_trans; let treat_err_as_bug = debugging_opts.treat_err_as_bug; - let always_build_mir = debugging_opts.always_build_mir; let no_analysis = debugging_opts.no_analysis; if debugging_opts.debug_llvm { unsafe { llvm::LLVMSetDebug(1); } } - let mut output_types = Vec::new(); + let mut output_types = HashMap::new(); if !debugging_opts.parse_only && !no_trans { - let unparsed_output_types = matches.opt_strs("emit"); - for unparsed_output_type in &unparsed_output_types { - for part in unparsed_output_type.split(',') { - let output_type = match part { - "asm" => OutputTypeAssembly, - "llvm-ir" => OutputTypeLlvmAssembly, - "llvm-bc" => OutputTypeBitcode, - "obj" => OutputTypeObject, - "link" => OutputTypeExe, - "dep-info" => OutputTypeDepInfo, - _ => { + for list in matches.opt_strs("emit") { + for output_type in list.split(',') { + let mut parts = output_type.splitn(2, '='); + let output_type = match parts.next().unwrap() { + "asm" => OutputType::Assembly, + "llvm-ir" => OutputType::LlvmAssembly, + "llvm-bc" => OutputType::Bitcode, + "obj" => OutputType::Object, + "link" => OutputType::Exe, + "dep-info" => OutputType::DepInfo, + part => { early_error(color, &format!("unknown emission type: `{}`", part)) } }; - output_types.push(output_type) + let path = parts.next().map(PathBuf::from); + output_types.insert(output_type, path); } } }; - output_types.sort(); - output_types.dedup(); if output_types.is_empty() { - output_types.push(OutputTypeExe); + output_types.insert(OutputType::Exe, None); } let cg = build_codegen_options(matches, color); @@ -1002,7 +993,6 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let cfg = parse_cfgspecs(matches.opt_strs("cfg")); let test = matches.opt_present("test"); - let write_dependency_info = (output_types.contains(&OutputTypeDepInfo), None); let prints = matches.opt_strs("print").into_iter().map(|s| { match &*s { @@ -1054,10 +1044,8 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { parse_only: parse_only, no_trans: no_trans, treat_err_as_bug: treat_err_as_bug, - always_build_mir: always_build_mir, no_analysis: no_analysis, debugging_opts: debugging_opts, - write_dependency_info: write_dependency_info, prints: prints, cg: cg, color: color, diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index ff732ee7b9..0a1df25f11 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -15,7 +15,7 @@ use middle::dependency_format; use session::search_paths::PathKind; use util::nodemap::{NodeMap, FnvHashMap}; -use syntax::ast::NodeId; +use syntax::ast::{NodeId, NodeIdAssigner}; use syntax::codemap::Span; use syntax::diagnostic::{self, Emitter}; use syntax::diagnostics; @@ -236,9 +236,6 @@ impl Session { } lints.insert(id, vec!((lint_id, sp, msg))); } - pub fn next_node_id(&self) -> ast::NodeId { - self.reserve_node_ids(1) - } pub fn reserve_node_ids(&self, count: ast::NodeId) -> ast::NodeId { let id = self.next_node_id.get(); @@ -317,6 +314,16 @@ impl Session { } } +impl NodeIdAssigner for Session { + fn next_node_id(&self) -> NodeId { + self.reserve_node_ids(1) + } + + fn peek_node_id(&self) -> NodeId { + self.next_node_id.get().checked_add(1).unwrap() + } +} + fn split_msg_into_multilines(msg: &str) -> Option { // Conditions for enabling multi-line errors: if !msg.contains("mismatched types") && @@ -331,10 +338,10 @@ fn split_msg_into_multilines(msg: &str) -> Option { let first = msg.match_indices("expected").filter(|s| { s.0 > 0 && (msg.char_at_reverse(s.0) == ' ' || msg.char_at_reverse(s.0) == '(') - }).map(|(a, b)| (a - 1, b)); + }).map(|(a, b)| (a - 1, a + b.len())); let second = msg.match_indices("found").filter(|s| { msg.char_at_reverse(s.0) == ' ' - }).map(|(a, b)| (a - 1, b)); + }).map(|(a, b)| (a - 1, a + b.len())); let mut new_msg = String::new(); let mut head = 0; diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index fee60d46dc..67ced5d325 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -25,9 +25,10 @@ use middle::ty::fold::TypeFoldable; use std::fmt; use syntax::abi; +use syntax::ast; use syntax::parse::token; -use syntax::ast::DUMMY_NODE_ID; -use rustc_front::hir as ast; +use syntax::ast::CRATE_NODE_ID; +use rustc_front::hir; pub fn verbose() -> bool { ty::tls::with(|tcx| tcx.sess.verbose()) @@ -231,7 +232,7 @@ fn in_binder<'tcx, T, U>(f: &mut fmt::Formatter, ty::BrEnv => { let name = token::intern("'r"); let _ = write!(f, "{}", name); - ty::BrNamed(DefId::local(DUMMY_NODE_ID), name) + ty::BrNamed(tcx.map.local_def_id(CRATE_NODE_ID), name) } }) }).0; @@ -308,18 +309,18 @@ impl<'tcx> fmt::Display for ty::TraitTy<'tcx> { impl<'tcx> fmt::Debug for ty::TypeParameterDef<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "TypeParameterDef({}, {}:{}, {:?}/{})", + write!(f, "TypeParameterDef({}, {:?}, {:?}/{})", self.name, - self.def_id.krate, self.def_id.node, + self.def_id, self.space, self.index) } } impl fmt::Debug for ty::RegionParameterDef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "RegionParameterDef({}, {}:{}, {:?}/{}, {:?})", + write!(f, "RegionParameterDef({}, {:?}, {:?}/{}, {:?})", self.name, - self.def_id.krate, self.def_id.node, + self.def_id, self.space, self.index, self.bounds) } @@ -334,7 +335,7 @@ impl<'tcx> fmt::Debug for ty::TyS<'tcx> { impl<'tcx> fmt::Display for ty::TypeAndMut<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}{}", - if self.mutbl == ast::MutMutable { "mut " } else { "" }, + if self.mutbl == hir::MutMutable { "mut " } else { "" }, self.ty) } } @@ -454,7 +455,7 @@ impl fmt::Debug for ty::BoundRegion { BrAnon(n) => write!(f, "BrAnon({:?})", n), BrFresh(n) => write!(f, "BrFresh({:?})", n), BrNamed(did, name) => { - write!(f, "BrNamed({}:{}, {:?})", did.krate, did.node, name) + write!(f, "BrNamed({:?}, {:?})", did, name) } BrEnv => "BrEnv".fmt(f), } @@ -465,8 +466,8 @@ impl fmt::Debug for ty::Region { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { ty::ReEarlyBound(ref data) => { - write!(f, "ReEarlyBound({}, {:?}, {}, {})", - data.param_id, + write!(f, "ReEarlyBound({:?}, {:?}, {}, {})", + data.def_id, data.space, data.index, data.name) @@ -825,8 +826,8 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { TyBox(typ) => write!(f, "Box<{}>", typ), TyRawPtr(ref tm) => { write!(f, "*{} {}", match tm.mutbl { - ast::MutMutable => "mut", - ast::MutImmutable => "const", + hir::MutMutable => "mut", + hir::MutImmutable => "const", }, tm.ty) } TyRef(r, ref tm) => { @@ -853,7 +854,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { write!(f, ")") } TyBareFn(opt_def_id, ref bare_fn) => { - if bare_fn.unsafety == ast::Unsafety::Unsafe { + if bare_fn.unsafety == hir::Unsafety::Unsafe { try!(write!(f, "unsafe ")); } @@ -887,15 +888,15 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { TyTrait(ref data) => write!(f, "{}", data), ty::TyProjection(ref data) => write!(f, "{}", data), TyStr => write!(f, "str"), - TyClosure(ref did, ref substs) => ty::tls::with(|tcx| { + TyClosure(did, ref substs) => ty::tls::with(|tcx| { try!(write!(f, "[closure")); - if did.is_local() { - try!(write!(f, "@{:?}", tcx.map.span(did.node))); + if let Some(node_id) = tcx.map.as_local_node_id(did) { + try!(write!(f, "@{:?}", tcx.map.span(node_id))); let mut sep = " "; - try!(tcx.with_freevars(did.node, |freevars| { + try!(tcx.with_freevars(node_id, |freevars| { for (freevar, upvar_ty) in freevars.iter().zip(&substs.upvar_tys) { - let node_id = freevar.def.local_node_id(); + let node_id = freevar.def.var_id(); try!(write!(f, "{}{}:{}", sep, @@ -966,10 +967,10 @@ impl fmt::Display for ty::ExplicitSelfCategory { f.write_str(match *self { ty::StaticExplicitSelfCategory => "static", ty::ByValueExplicitSelfCategory => "self", - ty::ByReferenceExplicitSelfCategory(_, ast::MutMutable) => { + ty::ByReferenceExplicitSelfCategory(_, hir::MutMutable) => { "&mut self" } - ty::ByReferenceExplicitSelfCategory(_, ast::MutImmutable) => "&self", + ty::ByReferenceExplicitSelfCategory(_, hir::MutImmutable) => "&self", ty::ByBoxExplicitSelfCategory => "Box", }) } diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs index 4a6646bca1..14fb064b7a 100644 --- a/src/librustc_back/lib.rs +++ b/src/librustc_back/lib.rs @@ -33,9 +33,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(box_syntax)] -#![feature(fs_canonicalize)] #![feature(libc)] -#![feature(path_ext)] #![feature(rand)] #![feature(rustc_private)] #![feature(slice_bytes)] @@ -57,3 +55,4 @@ pub mod rpath; pub mod sha2; pub mod svh; pub mod target; +pub mod slice; diff --git a/src/rustbook/javascript.rs b/src/librustc_back/slice.rs similarity index 69% rename from src/rustbook/javascript.rs rename to src/librustc_back/slice.rs index beddc23fe2..5d8fc3acef 100644 --- a/src/rustbook/javascript.rs +++ b/src/librustc_back/slice.rs @@ -8,9 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// The rust-book JavaScript in string form. +use std::mem; -pub static JAVASCRIPT: &'static str = r#" - - -"#; +pub fn ref_slice(ptr: &T) -> &[T; 1] { + unsafe { mem::transmute(ptr) } +} + +pub fn mut_ref_slice(ptr: &mut T) -> &mut [T; 1] { + unsafe { mem::transmute(ptr) } +} diff --git a/src/librustc_back/svh.rs b/src/librustc_back/svh.rs index 5f6bf939fb..a9cfc7138d 100644 --- a/src/librustc_back/svh.rs +++ b/src/librustc_back/svh.rs @@ -131,7 +131,7 @@ mod svh_visitor { pub use self::SawExprComponent::*; pub use self::SawStmtComponent::*; use self::SawAbiComponent::*; - use syntax::ast::{self, NodeId, Ident}; + use syntax::ast::{self, Name, NodeId}; use syntax::codemap::Span; use syntax::parse::token; use rustc_front::visit; @@ -177,7 +177,7 @@ mod svh_visitor { SawIdent(token::InternedString), SawStructDef(token::InternedString), - SawLifetimeRef(token::InternedString), + SawLifetime(token::InternedString), SawLifetimeDef(token::InternedString), SawMod, @@ -193,7 +193,6 @@ mod svh_visitor { SawVariant, SawExplicitSelf, SawPath, - SawOptLifetimeRef, SawBlock, SawPat, SawLocal, @@ -232,7 +231,7 @@ mod svh_visitor { SawExprTup, SawExprBinary(hir::BinOp_), SawExprUnary(hir::UnOp), - SawExprLit(hir::Lit_), + SawExprLit(ast::Lit_), SawExprCast, SawExprIf, SawExprWhile, @@ -249,7 +248,6 @@ mod svh_visitor { SawExprInlineAsm(&'a hir::InlineAsm), SawExprStruct, SawExprRepeat, - SawExprParen, } fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> { @@ -271,7 +269,7 @@ mod svh_visitor { ExprBlock(..) => SawExprBlock, ExprAssign(..) => SawExprAssign, ExprAssignOp(op, _, _) => SawExprAssignOp(op.node), - ExprField(_, id) => SawExprField(id.node.name.as_str()), + ExprField(_, name) => SawExprField(name.node.as_str()), ExprTupField(_, id) => SawExprTupField(id.node), ExprIndex(..) => SawExprIndex, ExprRange(..) => SawExprRange, @@ -283,7 +281,6 @@ mod svh_visitor { ExprInlineAsm(ref asm) => SawExprInlineAsm(asm), ExprStruct(..) => SawExprStruct, ExprRepeat(..) => SawExprRepeat, - ExprParen(..) => SawExprParen, } } @@ -304,29 +301,18 @@ mod svh_visitor { } impl<'a, 'v> Visitor<'v> for StrictVersionHashVisitor<'a> { - fn visit_struct_def(&mut self, s: &StructDef, ident: Ident, - g: &Generics, _: NodeId) { - SawStructDef(ident.name.as_str()).hash(self.st); + fn visit_variant_data(&mut self, s: &VariantData, name: Name, + g: &Generics, _: NodeId, _: Span) { + SawStructDef(name.as_str()).hash(self.st); visit::walk_generics(self, g); visit::walk_struct_def(self, s) } - fn visit_variant(&mut self, v: &Variant, g: &Generics) { + fn visit_variant(&mut self, v: &Variant, g: &Generics, item_id: NodeId) { SawVariant.hash(self.st); // walk_variant does not call walk_generics, so do it here. visit::walk_generics(self, g); - visit::walk_variant(self, v, g) - } - - fn visit_opt_lifetime_ref(&mut self, _: Span, l: &Option) { - SawOptLifetimeRef.hash(self.st); - // (This is a strange method in the visitor trait, in that - // it does not expose a walk function to do the subroutine - // calls.) - match *l { - Some(ref l) => self.visit_lifetime_ref(l), - None => () - } + visit::walk_variant(self, v, g, item_id) } // All of the remaining methods just record (in the hash @@ -343,12 +329,12 @@ mod svh_visitor { // (If you edit a method such that it deviates from the // pattern, please move that method up above this comment.) - fn visit_ident(&mut self, _: Span, ident: Ident) { - SawIdent(ident.name.as_str()).hash(self.st); + fn visit_name(&mut self, _: Span, name: Name) { + SawIdent(name.as_str()).hash(self.st); } - fn visit_lifetime_ref(&mut self, l: &Lifetime) { - SawLifetimeRef(l.name.as_str()).hash(self.st); + fn visit_lifetime(&mut self, l: &Lifetime) { + SawLifetime(l.name.as_str()).hash(self.st); } fn visit_lifetime_def(&mut self, l: &LifetimeDef) { @@ -425,6 +411,10 @@ mod svh_visitor { SawPath.hash(self.st); visit::walk_path(self, path) } + fn visit_path_list_item(&mut self, prefix: &Path, item: &'v PathListItem) { + SawPath.hash(self.st); visit::walk_path_list_item(self, prefix, item) + } + fn visit_block(&mut self, b: &Block) { SawBlock.hash(self.st); visit::walk_block(self, b) } diff --git a/src/librustc_back/target/aarch64_apple_ios.rs b/src/librustc_back/target/aarch64_apple_ios.rs index e87cb43128..e1242560e6 100644 --- a/src/librustc_back/target/aarch64_apple_ios.rs +++ b/src/librustc_back/target/aarch64_apple_ios.rs @@ -19,6 +19,7 @@ pub fn target() -> Target { arch: "aarch64".to_string(), target_os: "ios".to_string(), target_env: "".to_string(), + target_vendor: "apple".to_string(), options: TargetOptions { features: "+neon,+fp-armv8,+cyclone".to_string(), eliminate_frame_pointer: false, diff --git a/src/librustc_back/target/aarch64_linux_android.rs b/src/librustc_back/target/aarch64_linux_android.rs index 8c350e8b28..c6901a4cc4 100644 --- a/src/librustc_back/target/aarch64_linux_android.rs +++ b/src/librustc_back/target/aarch64_linux_android.rs @@ -18,6 +18,7 @@ pub fn target() -> Target { arch: "aarch64".to_string(), target_os: "android".to_string(), target_env: "".to_string(), + target_vendor: "unknown".to_string(), options: super::android_base::opts(), } } diff --git a/src/librustc_back/target/aarch64_unknown_linux_gnu.rs b/src/librustc_back/target/aarch64_unknown_linux_gnu.rs index ed79caf486..51abab6609 100644 --- a/src/librustc_back/target/aarch64_unknown_linux_gnu.rs +++ b/src/librustc_back/target/aarch64_unknown_linux_gnu.rs @@ -19,6 +19,7 @@ pub fn target() -> Target { target_env: "gnu".to_string(), arch: "aarch64".to_string(), target_os: "linux".to_string(), + target_vendor: "unknown".to_string(), options: base, } } diff --git a/src/librustc_back/target/apple_base.rs b/src/librustc_back/target/apple_base.rs index 0c4e28d970..8b75bb3941 100644 --- a/src/librustc_back/target/apple_base.rs +++ b/src/librustc_back/target/apple_base.rs @@ -24,7 +24,7 @@ pub fn opts() -> TargetOptions { dll_suffix: ".dylib".to_string(), archive_format: "bsd".to_string(), pre_link_args: Vec::new(), - exe_allocation_crate: super::best_allocator(), + exe_allocation_crate: super::maybe_jemalloc(), .. Default::default() } } diff --git a/src/librustc_back/target/arm_linux_androideabi.rs b/src/librustc_back/target/arm_linux_androideabi.rs index 0770fe70e8..732f1a353a 100644 --- a/src/librustc_back/target/arm_linux_androideabi.rs +++ b/src/librustc_back/target/arm_linux_androideabi.rs @@ -21,6 +21,7 @@ pub fn target() -> Target { arch: "arm".to_string(), target_os: "android".to_string(), target_env: "gnu".to_string(), + target_vendor: "unknown".to_string(), options: base, } } diff --git a/src/librustc_back/target/arm_unknown_linux_gnueabi.rs b/src/librustc_back/target/arm_unknown_linux_gnueabi.rs index 084f989277..7c35b43fd4 100644 --- a/src/librustc_back/target/arm_unknown_linux_gnueabi.rs +++ b/src/librustc_back/target/arm_unknown_linux_gnueabi.rs @@ -19,6 +19,7 @@ pub fn target() -> Target { arch: "arm".to_string(), target_os: "linux".to_string(), target_env: "gnueabi".to_string(), + target_vendor: "unknown".to_string(), options: TargetOptions { features: "+v6".to_string(), diff --git a/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs b/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs index 08f1aa5ade..a99ec45996 100644 --- a/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs +++ b/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs @@ -19,6 +19,7 @@ pub fn target() -> Target { arch: "arm".to_string(), target_os: "linux".to_string(), target_env: "gnueabihf".to_string(), + target_vendor: "unknown".to_string(), options: TargetOptions { features: "+v6,+vfp2".to_string(), diff --git a/src/librustc_back/target/armv7_apple_ios.rs b/src/librustc_back/target/armv7_apple_ios.rs index a6d649ea16..d306480029 100644 --- a/src/librustc_back/target/armv7_apple_ios.rs +++ b/src/librustc_back/target/armv7_apple_ios.rs @@ -19,6 +19,7 @@ pub fn target() -> Target { arch: "arm".to_string(), target_os: "ios".to_string(), target_env: "".to_string(), + target_vendor: "apple".to_string(), options: TargetOptions { features: "+v7,+vfp3,+neon".to_string(), .. opts(Arch::Armv7) diff --git a/src/librustc_back/target/armv7s_apple_ios.rs b/src/librustc_back/target/armv7s_apple_ios.rs index 264385512a..66ec6efca0 100644 --- a/src/librustc_back/target/armv7s_apple_ios.rs +++ b/src/librustc_back/target/armv7s_apple_ios.rs @@ -19,6 +19,7 @@ pub fn target() -> Target { arch: "arm".to_string(), target_os: "ios".to_string(), target_env: "".to_string(), + target_vendor: "apple".to_string(), options: TargetOptions { features: "+v7,+vfp4,+neon".to_string(), .. opts(Arch::Armv7s) diff --git a/src/librustc_back/target/bitrig_base.rs b/src/librustc_back/target/bitrig_base.rs index 96680dc375..2b84244cda 100644 --- a/src/librustc_back/target/bitrig_base.rs +++ b/src/librustc_back/target/bitrig_base.rs @@ -20,7 +20,7 @@ pub fn opts() -> TargetOptions { has_rpath: true, position_independent_executables: true, archive_format: "gnu".to_string(), - exe_allocation_crate: super::best_allocator(), + exe_allocation_crate: "alloc_system".to_string(), .. Default::default() } diff --git a/src/librustc_back/target/dragonfly_base.rs b/src/librustc_back/target/dragonfly_base.rs index 41c5f36099..b78fdc9f59 100644 --- a/src/librustc_back/target/dragonfly_base.rs +++ b/src/librustc_back/target/dragonfly_base.rs @@ -27,7 +27,7 @@ pub fn opts() -> TargetOptions { ), position_independent_executables: true, archive_format: "gnu".to_string(), - exe_allocation_crate: super::best_allocator(), + 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 a5807d2787..e955f8c302 100644 --- a/src/librustc_back/target/freebsd_base.rs +++ b/src/librustc_back/target/freebsd_base.rs @@ -18,7 +18,7 @@ pub fn opts() -> TargetOptions { executables: true, has_rpath: true, archive_format: "gnu".to_string(), - exe_allocation_crate: super::best_allocator(), + exe_allocation_crate: super::maybe_jemalloc(), .. Default::default() } diff --git a/src/librustc_back/target/i386_apple_ios.rs b/src/librustc_back/target/i386_apple_ios.rs index d17aa91546..52b5901192 100644 --- a/src/librustc_back/target/i386_apple_ios.rs +++ b/src/librustc_back/target/i386_apple_ios.rs @@ -19,6 +19,7 @@ pub fn target() -> Target { arch: "x86".to_string(), target_os: "ios".to_string(), target_env: "".to_string(), + target_vendor: "apple".to_string(), options: opts(Arch::I386) } } diff --git a/src/librustc_back/target/i686_apple_darwin.rs b/src/librustc_back/target/i686_apple_darwin.rs index 9fe15e7694..98f4654eca 100644 --- a/src/librustc_back/target/i686_apple_darwin.rs +++ b/src/librustc_back/target/i686_apple_darwin.rs @@ -22,6 +22,7 @@ pub fn target() -> Target { arch: "x86".to_string(), target_os: "macos".to_string(), target_env: "".to_string(), + target_vendor: "apple".to_string(), options: base, } } diff --git a/src/librustc_back/target/i686_linux_android.rs b/src/librustc_back/target/i686_linux_android.rs index 708e7756b9..f548fdad3c 100644 --- a/src/librustc_back/target/i686_linux_android.rs +++ b/src/librustc_back/target/i686_linux_android.rs @@ -21,6 +21,7 @@ pub fn target() -> Target { arch: "x86".to_string(), target_os: "android".to_string(), target_env: "gnu".to_string(), + target_vendor: "unknown".to_string(), options: base, } } diff --git a/src/librustc_back/target/i686_pc_windows_gnu.rs b/src/librustc_back/target/i686_pc_windows_gnu.rs index ae1b4d450a..c825f6043d 100644 --- a/src/librustc_back/target/i686_pc_windows_gnu.rs +++ b/src/librustc_back/target/i686_pc_windows_gnu.rs @@ -30,6 +30,7 @@ pub fn target() -> Target { arch: "x86".to_string(), target_os: "windows".to_string(), target_env: "gnu".to_string(), + target_vendor: "pc".to_string(), options: options, } } diff --git a/src/librustc_back/target/i686_pc_windows_msvc.rs b/src/librustc_back/target/i686_pc_windows_msvc.rs index d8c1c79b47..96b2d37ab2 100644 --- a/src/librustc_back/target/i686_pc_windows_msvc.rs +++ b/src/librustc_back/target/i686_pc_windows_msvc.rs @@ -21,6 +21,7 @@ pub fn target() -> Target { arch: "x86".to_string(), target_os: "windows".to_string(), target_env: "msvc".to_string(), + target_vendor: "pc".to_string(), options: base, } } diff --git a/src/librustc_back/target/i686_unknown_dragonfly.rs b/src/librustc_back/target/i686_unknown_dragonfly.rs index f2478e6d0d..32a15b9f2d 100644 --- a/src/librustc_back/target/i686_unknown_dragonfly.rs +++ b/src/librustc_back/target/i686_unknown_dragonfly.rs @@ -22,6 +22,7 @@ pub fn target() -> Target { arch: "x86".to_string(), target_os: "dragonfly".to_string(), target_env: "".to_string(), + target_vendor: "unknown".to_string(), options: base, } } diff --git a/src/librustc_back/target/i686_unknown_freebsd.rs b/src/librustc_back/target/i686_unknown_freebsd.rs index 6b2d9b5053..812ba11cd7 100644 --- a/src/librustc_back/target/i686_unknown_freebsd.rs +++ b/src/librustc_back/target/i686_unknown_freebsd.rs @@ -22,6 +22,7 @@ pub fn target() -> Target { arch: "x86".to_string(), target_os: "freebsd".to_string(), target_env: "".to_string(), + target_vendor: "unknown".to_string(), options: base, } } diff --git a/src/librustc_back/target/i686_unknown_linux_gnu.rs b/src/librustc_back/target/i686_unknown_linux_gnu.rs index 074d5b2b9e..ac2af0c64f 100644 --- a/src/librustc_back/target/i686_unknown_linux_gnu.rs +++ b/src/librustc_back/target/i686_unknown_linux_gnu.rs @@ -22,6 +22,7 @@ pub fn target() -> Target { arch: "x86".to_string(), target_os: "linux".to_string(), target_env: "gnu".to_string(), + target_vendor: "unknown".to_string(), options: base, } } diff --git a/src/librustc_back/target/le32_unknown_nacl.rs b/src/librustc_back/target/le32_unknown_nacl.rs new file mode 100644 index 0000000000..a5daebafda --- /dev/null +++ b/src/librustc_back/target/le32_unknown_nacl.rs @@ -0,0 +1,41 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use super::{Target, TargetOptions}; + +pub fn target() -> Target { + let opts = TargetOptions { + linker: "pnacl-clang".to_string(), + ar: "pnacl-ar".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()), + dynamic_linking: false, + executables: true, + exe_suffix: ".pexe".to_string(), + no_compiler_rt: false, + linker_is_gnu: true, + allow_asm: false, + archive_format: "gnu".to_string(), + .. Default::default() + }; + Target { + llvm_target: "le32-unknown-nacl".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + target_os: "nacl".to_string(), + target_env: "newlib".to_string(), + target_vendor: "unknown".to_string(), + arch: "le32".to_string(), + options: opts, + } +} diff --git a/src/librustc_back/target/linux_base.rs b/src/librustc_back/target/linux_base.rs index d6b50a955b..6492fa5015 100644 --- a/src/librustc_back/target/linux_base.rs +++ b/src/librustc_back/target/linux_base.rs @@ -29,7 +29,7 @@ pub fn opts() -> TargetOptions { ], position_independent_executables: true, archive_format: "gnu".to_string(), - exe_allocation_crate: super::best_allocator(), + exe_allocation_crate: super::maybe_jemalloc(), .. Default::default() } } diff --git a/src/librustc_back/target/mips_unknown_linux_gnu.rs b/src/librustc_back/target/mips_unknown_linux_gnu.rs index 3f3da6d6c9..357499c48e 100644 --- a/src/librustc_back/target/mips_unknown_linux_gnu.rs +++ b/src/librustc_back/target/mips_unknown_linux_gnu.rs @@ -18,6 +18,7 @@ pub fn target() -> Target { arch: "mips".to_string(), target_os: "linux".to_string(), target_env: "gnu".to_string(), + target_vendor: "unknown".to_string(), options: 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 d7f286c8aa..3d0088add0 100644 --- a/src/librustc_back/target/mipsel_unknown_linux_gnu.rs +++ b/src/librustc_back/target/mipsel_unknown_linux_gnu.rs @@ -18,6 +18,7 @@ pub fn target() -> Target { arch: "mips".to_string(), target_os: "linux".to_string(), target_env: "gnu".to_string(), + target_vendor: "unknown".to_string(), options: super::linux_base::opts() } diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 56562c8dfd..6ae74355a7 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -77,6 +77,8 @@ pub struct Target { pub target_os: String, /// Environment name to use for conditional compilation. pub target_env: String, + /// Vendor name to use for conditional compilation. + pub target_vendor: String, /// Architecture to use for ABI considerations. Valid options: "x86", "x86_64", "arm", /// "aarch64", "mips", and "powerpc". "mips" includes "mipsel". pub arch: String, @@ -157,6 +159,9 @@ pub struct TargetOptions { /// Whether to disable linking to compiler-rt. Defaults to false, as LLVM /// will emit references to the functions that compiler-rt provides. pub no_compiler_rt: bool, + /// Whether to disable linking to the default libraries, typically corresponds + /// to `-nodefaultlibs`. Defaults to true. + pub no_default_libraries: bool, /// Dynamically linked executables can be compiled as position independent /// if the default relocation model of position independent code is not /// changed. This is a requirement to take advantage of ASLR, as otherwise @@ -212,6 +217,7 @@ impl Default for TargetOptions { linker_is_gnu: false, has_rpath: false, no_compiler_rt: false, + no_default_libraries: true, position_independent_executables: false, pre_link_objects: Vec::new(), post_link_objects: Vec::new(), @@ -256,14 +262,20 @@ impl Target { } }; + let get_opt_field = |name: &str, default: &str| { + obj.find(name).and_then(|s| s.as_string()) + .map(|s| s.to_string()) + .unwrap_or(default.to_string()) + }; + let mut base = Target { llvm_target: get_req_field("llvm-target"), target_endian: get_req_field("target-endian"), target_pointer_width: get_req_field("target-pointer-width"), arch: get_req_field("arch"), target_os: get_req_field("os"), - target_env: obj.find("env").and_then(|s| s.as_string()) - .map(|s| s.to_string()).unwrap_or(String::new()), + target_env: get_opt_field("env", ""), + target_vendor: get_opt_field("vendor", "unknown"), options: Default::default(), }; @@ -319,6 +331,7 @@ impl Target { key!(linker_is_gnu, bool); key!(has_rpath, bool); key!(no_compiler_rt, bool); + key!(no_default_libraries, bool); key!(pre_link_args, list); key!(post_link_args, list); key!(allow_asm, bool); @@ -398,6 +411,7 @@ impl Target { x86_64_unknown_bitrig, x86_64_unknown_openbsd, x86_64_unknown_netbsd, + x86_64_rumprun_netbsd, x86_64_apple_darwin, i686_apple_darwin, @@ -412,7 +426,9 @@ impl Target { i686_pc_windows_gnu, x86_64_pc_windows_msvc, - i686_pc_windows_msvc + i686_pc_windows_msvc, + + le32_unknown_nacl ); @@ -444,7 +460,7 @@ impl Target { } } -fn best_allocator() -> String { +fn maybe_jemalloc() -> String { if cfg!(disable_jemalloc) { "alloc_system".to_string() } else { diff --git a/src/librustc_back/target/openbsd_base.rs b/src/librustc_back/target/openbsd_base.rs index 3b02111d93..2e4aa27cf8 100644 --- a/src/librustc_back/target/openbsd_base.rs +++ b/src/librustc_back/target/openbsd_base.rs @@ -27,7 +27,7 @@ pub fn opts() -> TargetOptions { ), position_independent_executables: true, archive_format: "gnu".to_string(), - exe_allocation_crate: super::best_allocator(), + exe_allocation_crate: "alloc_system".to_string(), .. Default::default() } } diff --git a/src/librustc_back/target/powerpc_unknown_linux_gnu.rs b/src/librustc_back/target/powerpc_unknown_linux_gnu.rs index 896824eba0..6664abf545 100644 --- a/src/librustc_back/target/powerpc_unknown_linux_gnu.rs +++ b/src/librustc_back/target/powerpc_unknown_linux_gnu.rs @@ -21,6 +21,7 @@ pub fn target() -> Target { arch: "powerpc".to_string(), target_os: "linux".to_string(), target_env: "gnu".to_string(), + target_vendor: "unknown".to_string(), options: base, } } diff --git a/src/librustc_back/target/windows_base.rs b/src/librustc_back/target/windows_base.rs index fedae51e0e..2e59736790 100644 --- a/src/librustc_back/target/windows_base.rs +++ b/src/librustc_back/target/windows_base.rs @@ -23,6 +23,10 @@ pub fn opts() -> TargetOptions { exe_suffix: ".exe".to_string(), staticlib_prefix: "".to_string(), staticlib_suffix: ".lib".to_string(), + // Unfortunately right now passing -nodefaultlibs to gcc on windows + // doesn't work so hot (in terms of native dependencies). This flag + // should hopefully be removed one day though! + no_default_libraries: false, is_like_windows: true, archive_format: "gnu".to_string(), pre_link_args: vec!( @@ -60,7 +64,7 @@ pub fn opts() -> TargetOptions { // Always enable DEP (NX bit) when it is available "-Wl,--nxcompat".to_string(), ), - exe_allocation_crate: super::best_allocator(), + exe_allocation_crate: super::maybe_jemalloc(), .. Default::default() } diff --git a/src/librustc_back/target/windows_msvc_base.rs b/src/librustc_back/target/windows_msvc_base.rs index fe9ac32ee8..fb88ce158e 100644 --- a/src/librustc_back/target/windows_msvc_base.rs +++ b/src/librustc_back/target/windows_msvc_base.rs @@ -60,7 +60,7 @@ pub fn opts() -> TargetOptions { "/NXCOMPAT".to_string(), ], archive_format: "gnu".to_string(), - exe_allocation_crate: super::best_allocator(), + exe_allocation_crate: "alloc_system".to_string(), .. 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 ef40c2f200..3e19e14829 100644 --- a/src/librustc_back/target/x86_64_apple_darwin.rs +++ b/src/librustc_back/target/x86_64_apple_darwin.rs @@ -23,6 +23,7 @@ pub fn target() -> Target { arch: "x86_64".to_string(), target_os: "macos".to_string(), target_env: "".to_string(), + target_vendor: "apple".to_string(), options: base, } } diff --git a/src/librustc_back/target/x86_64_apple_ios.rs b/src/librustc_back/target/x86_64_apple_ios.rs index 7aca8c554d..63234c0bae 100644 --- a/src/librustc_back/target/x86_64_apple_ios.rs +++ b/src/librustc_back/target/x86_64_apple_ios.rs @@ -19,6 +19,7 @@ pub fn target() -> Target { arch: "x86_64".to_string(), target_os: "ios".to_string(), target_env: "".to_string(), + target_vendor: "apple".to_string(), options: opts(Arch::X86_64) } } 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 aef1d7471b..2bd363e46b 100644 --- a/src/librustc_back/target/x86_64_pc_windows_gnu.rs +++ b/src/librustc_back/target/x86_64_pc_windows_gnu.rs @@ -25,6 +25,7 @@ pub fn target() -> Target { arch: "x86_64".to_string(), target_os: "windows".to_string(), target_env: "gnu".to_string(), + target_vendor: "pc".to_string(), options: base, } } 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 85756db960..5030a1ff44 100644 --- a/src/librustc_back/target/x86_64_pc_windows_msvc.rs +++ b/src/librustc_back/target/x86_64_pc_windows_msvc.rs @@ -22,6 +22,7 @@ pub fn target() -> Target { arch: "x86_64".to_string(), target_os: "windows".to_string(), target_env: "msvc".to_string(), + target_vendor: "pc".to_string(), options: base, } } diff --git a/src/librustc_back/target/x86_64_rumprun_netbsd.rs b/src/librustc_back/target/x86_64_rumprun_netbsd.rs new file mode 100644 index 0000000000..d63ad53cc2 --- /dev/null +++ b/src/librustc_back/target/x86_64_rumprun_netbsd.rs @@ -0,0 +1,35 @@ +// 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. + +use target::Target; + +pub fn target() -> Target { + let mut base = super::netbsd_base::opts(); + 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.dynamic_linking = false; + base.has_rpath = false; + base.position_independent_executables = false; + base.disable_redzone = true; + base.no_default_libraries = false; + + Target { + llvm_target: "x86_64-rumprun-netbsd".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "64".to_string(), + arch: "x86_64".to_string(), + target_os: "netbsd".to_string(), + target_env: "".to_string(), + target_vendor: "rumprun".to_string(), + options: base, + } +} diff --git a/src/librustc_back/target/x86_64_unknown_bitrig.rs b/src/librustc_back/target/x86_64_unknown_bitrig.rs index 6ecf885aba..04456b1b27 100644 --- a/src/librustc_back/target/x86_64_unknown_bitrig.rs +++ b/src/librustc_back/target/x86_64_unknown_bitrig.rs @@ -21,6 +21,7 @@ pub fn target() -> Target { arch: "x86_64".to_string(), target_os: "bitrig".to_string(), target_env: "".to_string(), + target_vendor: "unknown".to_string(), options: base, } } diff --git a/src/librustc_back/target/x86_64_unknown_dragonfly.rs b/src/librustc_back/target/x86_64_unknown_dragonfly.rs index f0e665967e..62654176aa 100644 --- a/src/librustc_back/target/x86_64_unknown_dragonfly.rs +++ b/src/librustc_back/target/x86_64_unknown_dragonfly.rs @@ -22,6 +22,7 @@ pub fn target() -> Target { arch: "x86_64".to_string(), target_os: "dragonfly".to_string(), target_env: "".to_string(), + target_vendor: "unknown".to_string(), options: base, } } diff --git a/src/librustc_back/target/x86_64_unknown_freebsd.rs b/src/librustc_back/target/x86_64_unknown_freebsd.rs index f742ebfde1..888b7f58bf 100644 --- a/src/librustc_back/target/x86_64_unknown_freebsd.rs +++ b/src/librustc_back/target/x86_64_unknown_freebsd.rs @@ -22,6 +22,7 @@ pub fn target() -> Target { arch: "x86_64".to_string(), target_os: "freebsd".to_string(), target_env: "".to_string(), + target_vendor: "unknown".to_string(), options: base, } } 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 4749e481fd..e3ccd9c4c7 100644 --- a/src/librustc_back/target/x86_64_unknown_linux_gnu.rs +++ b/src/librustc_back/target/x86_64_unknown_linux_gnu.rs @@ -22,6 +22,7 @@ pub fn target() -> Target { arch: "x86_64".to_string(), target_os: "linux".to_string(), target_env: "gnu".to_string(), + target_vendor: "unknown".to_string(), options: base, } } 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 c66192c28b..a5ac78cd5b 100644 --- a/src/librustc_back/target/x86_64_unknown_linux_musl.rs +++ b/src/librustc_back/target/x86_64_unknown_linux_musl.rs @@ -76,6 +76,7 @@ pub fn target() -> Target { arch: "x86_64".to_string(), target_os: "linux".to_string(), target_env: "musl".to_string(), + target_vendor: "unknown".to_string(), options: base, } } diff --git a/src/librustc_back/target/x86_64_unknown_netbsd.rs b/src/librustc_back/target/x86_64_unknown_netbsd.rs index e13e58e3a1..4101fabe73 100644 --- a/src/librustc_back/target/x86_64_unknown_netbsd.rs +++ b/src/librustc_back/target/x86_64_unknown_netbsd.rs @@ -21,6 +21,7 @@ pub fn target() -> Target { arch: "x86_64".to_string(), target_os: "netbsd".to_string(), target_env: "".to_string(), + target_vendor: "unknown".to_string(), options: base, } } diff --git a/src/librustc_back/target/x86_64_unknown_openbsd.rs b/src/librustc_back/target/x86_64_unknown_openbsd.rs index a404db48b2..07a1e137b4 100644 --- a/src/librustc_back/target/x86_64_unknown_openbsd.rs +++ b/src/librustc_back/target/x86_64_unknown_openbsd.rs @@ -21,6 +21,7 @@ pub fn target() -> Target { arch: "x86_64".to_string(), target_os: "openbsd".to_string(), target_env: "".to_string(), + target_vendor: "unknown".to_string(), options: base, } } diff --git a/src/librustc_bitflags/lib.rs b/src/librustc_bitflags/lib.rs index 3ee45c3506..16f586cf5e 100644 --- a/src/librustc_bitflags/lib.rs +++ b/src/librustc_bitflags/lib.rs @@ -22,7 +22,9 @@ //! A typesafe bitmask flag generator. -#[cfg(test)] #[macro_use] extern crate std; +#[cfg(test)] +#[macro_use] +extern crate std; /// The `bitflags!` macro generates a `struct` that holds a set of C-style /// bitmask flags. It is useful for creating typesafe wrappers for C APIs. @@ -321,7 +323,7 @@ mod tests { } #[test] - fn test_bits(){ + fn test_bits() { assert_eq!(Flags::empty().bits(), 0b00000000); assert_eq!(Flags::FlagA.bits(), 0b00000001); assert_eq!(Flags::FlagABC.bits(), 0b00000111); @@ -354,7 +356,7 @@ mod tests { } #[test] - fn test_is_empty(){ + fn test_is_empty() { assert!(Flags::empty().is_empty()); assert!(!Flags::FlagA.is_empty()); assert!(!Flags::FlagABC.is_empty()); @@ -413,7 +415,7 @@ mod tests { } #[test] - fn test_insert(){ + fn test_insert() { let mut e1 = Flags::FlagA; let e2 = Flags::FlagA | Flags::FlagB; e1.insert(e2); @@ -425,7 +427,7 @@ mod tests { } #[test] - fn test_remove(){ + fn test_remove() { let mut e1 = Flags::FlagA | Flags::FlagB; let e2 = Flags::FlagA | Flags::FlagC; e1.remove(e2); @@ -484,12 +486,12 @@ mod tests { #[test] fn test_hash() { - let mut x = Flags::empty(); - let mut y = Flags::empty(); - assert!(hash(&x) == hash(&y)); - x = Flags::all(); - y = Flags::FlagABC; - assert!(hash(&x) == hash(&y)); + let mut x = Flags::empty(); + let mut y = Flags::empty(); + assert!(hash(&x) == hash(&y)); + x = Flags::all(); + y = Flags::FlagABC; + assert!(hash(&x) == hash(&y)); } fn hash(t: &T) -> u64 { diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index eed8f82b5d..ff5d364b96 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -363,13 +363,14 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { let new_loan_indices = self.loans_generated_by(node); debug!("new_loan_indices = {:?}", new_loan_indices); - self.each_issued_loan(node, |issued_loan| { - for &new_loan_index in &new_loan_indices { + for &new_loan_index in &new_loan_indices { + self.each_issued_loan(node, |issued_loan| { let new_loan = &self.all_loans[new_loan_index]; - self.report_error_if_loans_conflict(issued_loan, new_loan); - } - true - }); + // Only report an error for the first issued loan that conflicts + // to avoid O(n^2) errors. + self.report_error_if_loans_conflict(issued_loan, new_loan) + }); + } for (i, &x) in new_loan_indices.iter().enumerate() { let old_loan = &self.all_loans[x]; @@ -382,7 +383,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { pub fn report_error_if_loans_conflict(&self, old_loan: &Loan<'tcx>, - new_loan: &Loan<'tcx>) { + new_loan: &Loan<'tcx>) + -> bool { //! Checks whether `old_loan` and `new_loan` can safely be issued //! simultaneously. @@ -397,7 +399,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { self.report_error_if_loan_conflicts_with_restriction( old_loan, new_loan, old_loan, new_loan) && self.report_error_if_loan_conflicts_with_restriction( - new_loan, old_loan, old_loan, new_loan); + new_loan, old_loan, old_loan, new_loan) } pub fn report_error_if_loan_conflicts_with_restriction(&self, @@ -464,40 +466,36 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { match (new_loan.kind, old_loan.kind) { (ty::MutBorrow, ty::MutBorrow) => { - self.bccx.span_err( - new_loan.span, - &format!("cannot borrow `{}`{} as mutable \ - more than once at a time", - nl, new_loan_msg)) + span_err!(self.bccx, new_loan.span, E0499, + "cannot borrow `{}`{} as mutable \ + more than once at a time", + nl, new_loan_msg); } (ty::UniqueImmBorrow, _) => { - self.bccx.span_err( - new_loan.span, - &format!("closure requires unique access to `{}` \ - but {} is already borrowed{}", - nl, ol_pronoun, old_loan_msg)); + span_err!(self.bccx, new_loan.span, E0500, + "closure requires unique access to `{}` \ + but {} is already borrowed{}", + nl, ol_pronoun, old_loan_msg); } (_, ty::UniqueImmBorrow) => { - self.bccx.span_err( - new_loan.span, - &format!("cannot borrow `{}`{} as {} because \ - previous closure requires unique access", - nl, new_loan_msg, new_loan.kind.to_user_str())); + span_err!(self.bccx, new_loan.span, E0501, + "cannot borrow `{}`{} as {} because \ + previous closure requires unique access", + nl, new_loan_msg, new_loan.kind.to_user_str()); } (_, _) => { - self.bccx.span_err( - new_loan.span, - &format!("cannot borrow `{}`{} as {} because \ - {} is also borrowed as {}{}", - nl, - new_loan_msg, - new_loan.kind.to_user_str(), - ol_pronoun, - old_loan.kind.to_user_str(), - old_loan_msg)); + span_err!(self.bccx, new_loan.span, E0502, + "cannot borrow `{}`{} as {} because \ + {} is also borrowed as {}{}", + nl, + new_loan_msg, + new_loan.kind.to_user_str(), + ol_pronoun, + old_loan.kind.to_user_str(), + old_loan_msg); } } @@ -617,11 +615,9 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { match self.analyze_restrictions_on_use(id, copy_path, ty::ImmBorrow) { UseOk => { } UseWhileBorrowed(loan_path, loan_span) => { - self.bccx.span_err( - span, - &format!("cannot use `{}` because it was mutably borrowed", - &self.bccx.loan_path_to_string(copy_path)) - ); + span_err!(self.bccx, span, E0503, + "cannot use `{}` because it was mutably borrowed", + &self.bccx.loan_path_to_string(copy_path)); self.bccx.span_note( loan_span, &format!("borrow of `{}` occurs here", @@ -642,18 +638,19 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { match self.analyze_restrictions_on_use(id, move_path, ty::MutBorrow) { UseOk => { } UseWhileBorrowed(loan_path, loan_span) => { - let err_message = match move_kind { + match move_kind { move_data::Captured => - format!("cannot move `{}` into closure because it is borrowed", - &self.bccx.loan_path_to_string(move_path)), + span_err!(self.bccx, span, E0504, + "cannot move `{}` into closure because it is borrowed", + &self.bccx.loan_path_to_string(move_path)), move_data::Declared | move_data::MoveExpr | move_data::MovePat => - format!("cannot move out of `{}` because it is borrowed", - &self.bccx.loan_path_to_string(move_path)) + span_err!(self.bccx, span, E0505, + "cannot move out of `{}` because it is borrowed", + &self.bccx.loan_path_to_string(move_path)) }; - self.bccx.span_err(span, &err_message[..]); self.bccx.span_note( loan_span, &format!("borrow of `{}` occurs here", @@ -820,10 +817,9 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { span: Span, loan_path: &LoanPath<'tcx>, loan: &Loan) { - self.bccx.span_err( - span, - &format!("cannot assign to `{}` because it is borrowed", - self.bccx.loan_path_to_string(loan_path))); + span_err!(self.bccx, span, E0506, + "cannot assign to `{}` because it is borrowed", + self.bccx.loan_path_to_string(loan_path)); self.bccx.span_note( loan.span, &format!("borrow of `{}` occurs here", diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs index 86b6314b57..1639fcf77a 100644 --- a/src/librustc_borrowck/borrowck/fragments.rs +++ b/src/librustc_borrowck/borrowck/fragments.rs @@ -20,7 +20,7 @@ use borrowck::LoanPathKind::{LpVar, LpUpvar, LpDowncast, LpExtend}; use borrowck::LoanPathElem::{LpDeref, LpInterior}; use borrowck::move_data::InvalidMovePathIndex; use borrowck::move_data::{MoveData, MovePathIndex}; -use rustc::middle::def_id::{DefId, LOCAL_CRATE}; +use rustc::middle::def_id::{DefId}; use rustc::middle::ty; use rustc::middle::mem_categorization as mc; @@ -28,7 +28,7 @@ use std::mem; use std::rc::Rc; use syntax::ast; use syntax::codemap::Span; -use rustc_front::attr::AttrMetaMethods; +use syntax::attr::AttrMetaMethods; #[derive(PartialEq, Eq, PartialOrd, Ord)] enum Fragment { @@ -133,7 +133,7 @@ pub fn build_unfragmented_map(this: &mut borrowck::BorrowckCtxt, } let mut fraginfo_map = this.tcx.fragment_infos.borrow_mut(); - let fn_did = DefId { krate: LOCAL_CRATE, node: id }; + let fn_did = this.tcx.map.local_def_id(id); let prev = fraginfo_map.insert(fn_did, fragment_infos); assert!(prev.is_none()); } @@ -159,7 +159,7 @@ pub struct FragmentSets { /// FIXME(pnkfelix) probably do not want/need /// `parents_of_fragments` at all, if we can avoid it. /// - /// Update: I do not see a way to to avoid it. Maybe just remove + /// Update: I do not see a way to avoid it. Maybe just remove /// above fixme, or at least document why doing this may be hard. parents_of_fragments: Vec, diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs index 3515b53b00..83fac73b7f 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs @@ -99,7 +99,7 @@ pub fn gather_move_from_pat<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, let pat_span_path_opt = match move_pat.node { hir::PatIdent(_, ref path1, _) => { Some(MoveSpanAndPath{span: move_pat.span, - ident: path1.node}) + name: path1.node.name}) }, _ => None, }; diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index c39b1a9da0..59f914895a 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -15,7 +15,6 @@ use rustc::middle::ty; use std::cell::RefCell; use syntax::ast; use syntax::codemap; -use rustc_front::print::pprust; use rustc_front::hir; pub struct MoveErrorCollector<'tcx> { @@ -57,7 +56,7 @@ impl<'tcx> MoveError<'tcx> { #[derive(Clone)] pub struct MoveSpanAndPath { pub span: codemap::Span, - pub ident: ast::Ident + pub name: ast::Name, } pub struct GroupedMoveErrors<'tcx> { @@ -73,7 +72,7 @@ fn report_move_errors<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, let mut is_first_note = true; for move_to in &error.move_to_places { note_move_destination(bccx, move_to.span, - &move_to.ident, is_first_note); + move_to.name, is_first_note); is_first_note = false; } } @@ -119,18 +118,18 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, mc::cat_deref(_, _, mc::Implicit(..)) | mc::cat_deref(_, _, mc::UnsafePtr(..)) | mc::cat_static_item => { - bccx.span_err(move_from.span, - &format!("cannot move out of {}", - move_from.descriptive_string(bccx.tcx))); + span_err!(bccx, move_from.span, E0507, + "cannot move out of {}", + move_from.descriptive_string(bccx.tcx)); } mc::cat_interior(ref b, mc::InteriorElement(Kind::Index, _)) => { let expr = bccx.tcx.map.expect_expr(move_from.id); if let hir::ExprIndex(..) = expr.node { - bccx.span_err(move_from.span, - &format!("cannot move out of type `{}`, \ - a non-copy fixed-size array", - b.ty)); + span_err!(bccx, move_from.span, E0508, + "cannot move out of type `{}`, \ + a non-copy fixed-size array", + b.ty); } } @@ -139,11 +138,10 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, match b.ty.sty { ty::TyStruct(def, _) | ty::TyEnum(def, _) if def.has_dtor() => { - bccx.span_err( - move_from.span, - &format!("cannot move out of type `{}`, \ - which defines the `Drop` trait", - b.ty)); + span_err!(bccx, move_from.span, E0509, + "cannot move out of type `{}`, \ + which defines the `Drop` trait", + b.ty); }, _ => { bccx.span_bug(move_from.span, "this path should not cause illegal move") @@ -158,9 +156,8 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, fn note_move_destination(bccx: &BorrowckCtxt, move_to_span: codemap::Span, - pat_ident: &ast::Ident, + pat_name: ast::Name, is_first_note: bool) { - let pat_name = pprust::ident_to_string(pat_ident); if is_first_note { bccx.span_note( move_to_span, diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 57e578d10c..10e29ef843 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -373,7 +373,7 @@ const DOWNCAST_PRINTED_OPERATOR: &'static str = " as "; // A local, "cleaned" version of `mc::InteriorKind` that drops // information that is not relevant to loan-path analysis. (In -// particular, the distinction between how precisely a array-element +// particular, the distinction between how precisely an array-element // is tracked is irrelevant here.) #[derive(Clone, Copy, PartialEq, Eq, Hash)] pub enum InteriorKind { @@ -803,6 +803,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { self.tcx.sess.span_err(s, m); } + pub fn span_err_with_code(&self, s: Span, msg: &str, code: &str) { + self.tcx.sess.span_err_with_code(s, msg, code); + } + pub fn span_bug(&self, s: Span, m: &str) { self.tcx.sess.span_bug(s, m); } diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs index e94a214309..a5b313e2dd 100644 --- a/src/librustc_borrowck/diagnostics.rs +++ b/src/librustc_borrowck/diagnostics.rs @@ -263,12 +263,50 @@ fn mutable() { You can read more about cell types in the API documentation: https://doc.rust-lang.org/std/cell/ -"## +"##, + +E0499: r##" +A variable was borrowed as mutable more than once. Erroneous code example: + +``` +let mut i = 0; +let mut x = &mut i; +let mut a = &mut i; +// error: cannot borrow `i` as mutable more than once at a time +``` + +Please note that in rust, you can either have many immutable references, or one +mutable reference. Take a look at +https://doc.rust-lang.org/stable/book/references-and-borrowing.html for more +information. Example: + + +``` +let mut i = 0; +let mut x = &mut i; // ok! + +// or: +let mut i = 0; +let a = &i; // ok! +let b = &i; // still ok! +let c = &i; // still ok! +``` +"##, } register_diagnostics! { E0385, // {} in an aliasable location E0388, // {} in a static location - E0389 // {} in a `&` reference + E0389, // {} in a `&` reference + E0500, // closure requires unique access to `..` but .. is already borrowed + E0501, // cannot borrow `..`.. as .. because previous closure requires unique access + E0502, // cannot borrow `..`.. as .. because .. is also borrowed as ... + E0503, // cannot use `..` because it was mutably borrowed + E0504, // cannot move `..` into closure because it is borrowed + E0505, // cannot move out of `..` because it is borrowed + E0506, // cannot assign to `..` because it is borrowed + E0507, // cannot move out of .. + E0508, // cannot move out of type `..`, a non-copy fixed-size array + E0509, // cannot move out of type `..`, which defines the `Drop` trait } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index f3038624ac..c9e4d30fef 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -12,7 +12,7 @@ use rustc::front; use rustc::front::map as hir_map; use rustc_mir as mir; use rustc::session::Session; -use rustc::session::config::{self, Input, OutputFilenames}; +use rustc::session::config::{self, Input, OutputFilenames, OutputType}; use rustc::session::search_paths::PathKind; use rustc::lint; use rustc::metadata; @@ -31,20 +31,22 @@ use rustc_trans::trans; use rustc_typeck as typeck; use rustc_privacy; use rustc_front::hir; -use rustc_front::lowering::lower_crate; +use rustc_front::lowering::{lower_crate, LoweringContext}; use super::Compilation; use serialize::json; +use std::collections::HashMap; use std::env; use std::ffi::{OsString, OsStr}; use std::fs; use std::io::{self, Write}; use std::path::{Path, PathBuf}; -use syntax::ast; +use syntax::ast::{self, NodeIdAssigner}; use syntax::attr; use syntax::attr::AttrMetaMethods; use syntax::diagnostics; +use syntax::feature_gate::UnstableFeatures; use syntax::fold::Folder; use syntax::parse; use syntax::parse::token; @@ -70,7 +72,7 @@ pub fn compile_input(sess: Session, // We need nested scopes here, because the intermediate results can keep // large chunks of memory alive and we want to free them as soon as // possible to keep the peak memory usage low - let (sess, result) = { + let result = { let (outputs, expanded_crate, id) = { let krate = phase_1_parse_input(&sess, cfg, input); @@ -111,13 +113,14 @@ pub fn compile_input(sess: Session, let expanded_crate = assign_node_ids(&sess, expanded_crate); // Lower ast -> hir. + let lcx = LoweringContext::new(&sess, Some(&expanded_crate)); let mut hir_forest = time(sess.time_passes(), "lowering ast -> hir", - || hir_map::Forest::new(lower_crate(&expanded_crate))); + || hir_map::Forest::new(lower_crate(&lcx, &expanded_crate))); let arenas = ty::CtxtArenas::new(); let ast_map = make_map(&sess, &mut hir_forest); - write_out_deps(&sess, input, &outputs, &id[..]); + write_out_deps(&sess, &outputs, &id); controller_entry_point!(after_write_deps, sess, @@ -127,14 +130,21 @@ pub fn compile_input(sess: Session, &ast_map, &expanded_crate, &ast_map.krate(), - &id[..])); + &id[..], + &lcx)); + time(sess.time_passes(), "attribute checking", || { + front::check_attr::check_crate(&sess, &expanded_crate); + }); + + time(sess.time_passes(), "early lint checks", || { + lint::check_ast_crate(&sess, &expanded_crate) + }); - phase_3_run_analysis_passes(sess, + phase_3_run_analysis_passes(&sess, ast_map, - &expanded_crate, &arenas, - id, + &id, control.make_glob_map, |tcx, analysis| { @@ -145,7 +155,9 @@ pub fn compile_input(sess: Session, &expanded_crate, tcx.map.krate(), &analysis, - tcx); + tcx, + &lcx, + &id); (control.after_analysis.callback)(state); tcx.sess.abort_if_errors(); @@ -269,8 +281,9 @@ pub struct CompileState<'a, 'ast: 'a, 'tcx: 'a> { pub expanded_crate: Option<&'a ast::Crate>, pub hir_crate: Option<&'a hir::Crate>, pub ast_map: Option<&'a hir_map::Map<'ast>>, - pub analysis: Option<&'a ty::CrateAnalysis>, + pub analysis: Option<&'a ty::CrateAnalysis<'a>>, pub tcx: Option<&'a ty::ctxt<'tcx>>, + pub lcx: Option<&'a LoweringContext<'a>>, pub trans: Option<&'a trans::CrateTranslation>, } @@ -292,6 +305,7 @@ impl<'a, 'ast, 'tcx> CompileState<'a, 'ast, 'tcx> { ast_map: None, analysis: None, tcx: None, + lcx: None, trans: None, } } @@ -326,13 +340,15 @@ impl<'a, 'ast, 'tcx> CompileState<'a, 'ast, 'tcx> { ast_map: &'a hir_map::Map<'ast>, krate: &'a ast::Crate, hir_crate: &'a hir::Crate, - crate_name: &'a str) + crate_name: &'a str, + lcx: &'a LoweringContext<'a>) -> CompileState<'a, 'ast, 'tcx> { CompileState { crate_name: Some(crate_name), ast_map: Some(ast_map), krate: Some(krate), hir_crate: Some(hir_crate), + lcx: Some(lcx), .. CompileState::empty(input, session, out_dir) } } @@ -343,13 +359,17 @@ impl<'a, 'ast, 'tcx> CompileState<'a, 'ast, 'tcx> { krate: &'a ast::Crate, hir_crate: &'a hir::Crate, analysis: &'a ty::CrateAnalysis, - tcx: &'a ty::ctxt<'tcx>) + tcx: &'a ty::ctxt<'tcx>, + lcx: &'a LoweringContext<'a>, + crate_name: &'a str) -> CompileState<'a, 'ast, 'tcx> { CompileState { analysis: Some(analysis), tcx: Some(tcx), krate: Some(krate), hir_crate: Some(hir_crate), + lcx: Some(lcx), + crate_name: Some(crate_name), .. CompileState::empty(input, session, out_dir) } } @@ -480,13 +500,16 @@ pub fn phase_2_configure_and_expand(sess: &Session, } }); - let Registry { syntax_exts, lint_passes, lint_groups, + let Registry { syntax_exts, early_lint_passes, late_lint_passes, lint_groups, llvm_passes, attributes, .. } = registry; { let mut ls = sess.lint_store.borrow_mut(); - for pass in lint_passes { - ls.register_pass(Some(sess), true, pass); + for pass in early_lint_passes { + ls.register_early_pass(Some(sess), true, pass); + } + for pass in late_lint_passes { + ls.register_late_pass(Some(sess), true, pass); } for (name, to) in lint_groups { @@ -639,14 +662,13 @@ pub fn make_map<'ast>(sess: &Session, /// Run the resolution, typechecking, region checking and other /// miscellaneous analysis passes on the crate. Return various /// structures carrying the results of the analysis. -pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: Session, +pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, ast_map: front::map::Map<'tcx>, - ast_crate: &ast::Crate, arenas: &'tcx ty::CtxtArenas<'tcx>, - name: String, + name: &str, make_glob_map: resolve::MakeGlobMap, f: F) - -> (Session, R) + -> R where F: for<'a> FnOnce(&'a ty::ctxt<'tcx>, ty::CrateAnalysis) -> R { @@ -654,10 +676,10 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: Session, let krate = ast_map.krate(); time(time_passes, "external crate/lib resolution", || - LocalCrateReader::new(&sess, &ast_map).read_crates(krate)); + LocalCrateReader::new(sess, &ast_map).read_crates(krate)); let lang_items = time(time_passes, "language item collection", || - middle::lang_items::collect_language_items(krate, &sess)); + middle::lang_items::collect_language_items(&sess, &ast_map)); let resolve::CrateMap { def_map, @@ -668,16 +690,19 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: Session, glob_map, } = time(time_passes, "resolution", - || resolve::resolve_crate(&sess, &ast_map, make_glob_map)); + || resolve::resolve_crate(sess, &ast_map, make_glob_map)); // Discard MTWT tables that aren't required past resolution. - syntax::ext::mtwt::clear_tables(); + // FIXME: get rid of uses of MTWT tables in typeck, mir and trans and clear them + if !sess.opts.debugging_opts.keep_mtwt_tables { + // syntax::ext::mtwt::clear_tables(); + } let named_region_map = time(time_passes, "lifetime resolution", - || middle::resolve_lifetime::krate(&sess, krate, &def_map)); + || middle::resolve_lifetime::krate(sess, krate, &def_map)); time(time_passes, "looking for entry point", - || middle::entry::find_entry_point(&sess, &ast_map)); + || middle::entry::find_entry_point(sess, &ast_map)); sess.plugin_registrar_fn.set( time(time_passes, "looking for plugin registrar", || @@ -685,13 +710,13 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: Session, sess.diagnostic(), krate))); let region_map = time(time_passes, "region resolution", || - middle::region::resolve_crate(&sess, krate)); + middle::region::resolve_crate(sess, krate)); time(time_passes, "loop checking", || - middle::check_loop::check_crate(&sess, krate)); + middle::check_loop::check_crate(sess, krate)); time(time_passes, "static item recursion checking", || - middle::check_static_recursion::check_crate(&sess, krate, &def_map, &ast_map)); + middle::check_static_recursion::check_crate(sess, krate, &def_map, &ast_map)); ty::ctxt::create_and_enter(sess, arenas, @@ -707,9 +732,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: Session, // passes are timed inside typeck typeck::check_crate(tcx, trait_map); - time(time_passes, "MIR dump", || - mir::dump::dump_crate(tcx)); - time(time_passes, "const checking", || middle::check_const::check_crate(tcx)); @@ -730,6 +752,19 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: Session, time(time_passes, "match checking", || middle::check_match::check_crate(tcx)); + match tcx.sess.opts.unstable_features { + UnstableFeatures::Disallow => { + // use this as a shorthand for beta/stable, and skip + // MIR construction there until known regressions are + // addressed + } + UnstableFeatures::Allow | UnstableFeatures::Cheat => { + let _mir_map = + time(time_passes, "MIR dump", || + mir::mir_map::build_mir_for_crate(tcx)); + } + } + time(time_passes, "liveness checking", || middle::liveness::check_crate(tcx)); @@ -765,7 +800,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: Session, &tcx.sess, lib_features_used)); time(time_passes, "lint checking", || - lint::check_crate(tcx, &lower_crate(ast_crate), &exported_items)); + lint::check_crate(tcx, krate, &exported_items)); // The above three passes generate errors w/o aborting tcx.sess.abort_if_errors(); @@ -801,16 +836,16 @@ pub fn phase_5_run_llvm_passes(sess: &Session, trans: &trans::CrateTranslation, outputs: &OutputFilenames) { if sess.opts.cg.no_integrated_as { - let output_type = config::OutputTypeAssembly; - + let mut map = HashMap::new(); + map.insert(OutputType::Assembly, None); time(sess.time_passes(), "LLVM passes", || - write::run_passes(sess, trans, &[output_type], outputs)); + write::run_passes(sess, trans, &map, outputs)); write::run_assembler(sess, outputs); // Remove assembly source, unless --save-temps was specified if !sess.opts.cg.save_temps { - fs::remove_file(&outputs.temp_path(config::OutputTypeAssembly)).unwrap(); + fs::remove_file(&outputs.temp_path(OutputType::Assembly)).unwrap(); } } else { time(sess.time_passes(), "LLVM passes", || @@ -841,16 +876,12 @@ fn escape_dep_filename(filename: &str) -> String { filename.replace(" ", "\\ ") } -fn write_out_deps(sess: &Session, - input: &Input, - outputs: &OutputFilenames, - id: &str) { - +fn write_out_deps(sess: &Session, outputs: &OutputFilenames, id: &str) { let mut out_filenames = Vec::new(); - for output_type in &sess.opts.output_types { + for output_type in sess.opts.output_types.keys() { let file = outputs.path(*output_type); match *output_type { - config::OutputTypeExe => { + OutputType::Exe => { for output in sess.crate_types.borrow().iter() { let p = link::filename_for_input(sess, *output, id, outputs); @@ -861,23 +892,11 @@ fn write_out_deps(sess: &Session, } } - // Write out dependency rules to the dep-info file if requested with - // --dep-info - let deps_filename = match sess.opts.write_dependency_info { - // Use filename from --dep-file argument if given - (true, Some(ref filename)) => filename.clone(), - // Use default filename: crate source filename with extension replaced - // by ".d" - (true, None) => match *input { - Input::File(..) => outputs.with_extension("d"), - Input::Str(..) => { - sess.warn("can not write --dep-info without a filename \ - when compiling stdin."); - return - }, - }, - _ => return, - }; + // Write out dependency rules to the dep-info file if requested + if !sess.opts.output_types.contains_key(&OutputType::DepInfo) { + return + } + let deps_filename = outputs.path(OutputType::DepInfo); let result = (|| -> io::Result<()> { // Build a list of files used to compile the output and @@ -890,9 +909,16 @@ fn write_out_deps(sess: &Session, .collect(); let mut file = try!(fs::File::create(&deps_filename)); for path in &out_filenames { - try!(write!(&mut file, + try!(write!(file, "{}: {}\n\n", path.display(), files.join(" "))); } + + // Emit a fake target for each input file to the compilation. This + // prevents `make` from spitting out an error if a file is later + // deleted. For more info see #28735 + for path in files { + try!(writeln!(file, "{}:", path)); + } Ok(()) })(); @@ -1006,11 +1032,15 @@ pub fn build_output_filenames(input: &Input, out_filestem: stem, single_output_file: None, extra: sess.opts.cg.extra_filename.clone(), + outputs: sess.opts.output_types.clone(), } } Some(ref out_file) => { - let ofile = if sess.opts.output_types.len() > 1 { + let unnamed_output_types = sess.opts.output_types.values() + .filter(|a| a.is_none()) + .count(); + let ofile = if unnamed_output_types > 1 { sess.warn("ignoring specified output filename because multiple \ outputs were requested"); None @@ -1029,6 +1059,7 @@ pub fn build_output_filenames(input: &Input, .to_str().unwrap().to_string(), single_output_file: ofile, extra: sess.opts.cg.extra_filename.clone(), + outputs: sess.opts.output_types.clone(), } } } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 7d9c74fe48..ce40d9b53f 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -63,7 +63,7 @@ use rustc_resolve as resolve; use rustc_trans::back::link; use rustc_trans::save; use rustc::session::{config, Session, build_session}; -use rustc::session::config::{Input, PrintRequest}; +use rustc::session::config::{Input, PrintRequest, OutputType}; use rustc::lint::Lint; use rustc::lint; use rustc::metadata; @@ -285,7 +285,12 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { -> Compilation { match matches.opt_str("explain") { Some(ref code) => { - match descriptions.find_description(&code[..]) { + let normalised = if !code.starts_with("E") { + format!("E{0:0>4}", code) + } else { + code.to_string() + }; + match descriptions.find_description(&normalised) { Some(ref description) => { // Slice off the leading newline and print. print!("{}", &description[1..]); @@ -382,7 +387,7 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { control.after_analysis.stop = Compilation::Stop; } - if !sess.opts.output_types.iter().any(|&i| i == config::OutputTypeExe) { + if !sess.opts.output_types.keys().any(|&i| i == OutputType::Exe) { control.after_llvm.stop = Compilation::Stop; } @@ -391,8 +396,10 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { time(state.session.time_passes(), "save analysis", || save::process_crate(state.tcx.unwrap(), + state.lcx.unwrap(), state.krate.unwrap(), state.analysis.unwrap(), + state.crate_name.unwrap(), state.out_dir)); }; control.make_glob_map = resolve::MakeGlobMap::Yes; diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 989a586cee..a30c437197 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -32,6 +32,7 @@ use syntax::ast; use syntax::codemap; use syntax::fold::{self, Folder}; use syntax::print::{pp, pprust}; +use syntax::print::pprust::PrintState; use syntax::ptr::P; use syntax::util::small_vector::SmallVector; @@ -46,7 +47,7 @@ use std::str::FromStr; use rustc::front::map as hir_map; use rustc::front::map::{blocks, NodePrinter}; use rustc_front::hir; -use rustc_front::lowering::lower_crate; +use rustc_front::lowering::{lower_crate, LoweringContext}; use rustc_front::print::pprust as pprust_hir; #[derive(Copy, Clone, PartialEq, Debug)] @@ -130,7 +131,7 @@ pub fn parse_pretty(sess: &Session, impl PpSourceMode { /// Constructs a `PrinterSupport` object and passes it to `f`. fn call_with_pp_support<'tcx, A, B, F>(&self, - sess: Session, + sess: &'tcx Session, ast_map: Option>, payload: B, f: F) -> A where @@ -154,11 +155,10 @@ impl PpSourceMode { } } fn call_with_pp_support_hir<'tcx, A, B, F>(&self, - sess: Session, + sess: &'tcx Session, ast_map: &hir_map::Map<'tcx>, - ast_crate: &ast::Crate, arenas: &'tcx ty::CtxtArenas<'tcx>, - id: String, + id: &str, payload: B, f: F) -> A where F: FnOnce(&HirPrinterSupport, B, &hir::Crate) -> A, @@ -179,14 +179,13 @@ impl PpSourceMode { PpmTyped => { driver::phase_3_run_analysis_passes(sess, ast_map.clone(), - ast_crate, arenas, id, resolve::MakeGlobMap::No, |tcx, _| { let annotation = TypedAnnotation { tcx: tcx }; f(&annotation, payload, &ast_map.forest.krate) - }).1 + }) } _ => panic!("Should use call_with_pp_support"), } @@ -226,12 +225,12 @@ trait HirPrinterSupport<'ast>: pprust_hir::PpAnn { } struct NoAnn<'ast> { - sess: Session, + sess: &'ast Session, ast_map: Option> } impl<'ast> PrinterSupport<'ast> for NoAnn<'ast> { - fn sess<'a>(&'a self) -> &'a Session { &self.sess } + fn sess<'a>(&'a self) -> &'a Session { self.sess } fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> { self.ast_map.as_ref() @@ -241,7 +240,7 @@ impl<'ast> PrinterSupport<'ast> for NoAnn<'ast> { } impl<'ast> HirPrinterSupport<'ast> for NoAnn<'ast> { - fn sess<'a>(&'a self) -> &'a Session { &self.sess } + fn sess<'a>(&'a self) -> &'a Session { self.sess } fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> { self.ast_map.as_ref() @@ -254,12 +253,12 @@ impl<'ast> pprust::PpAnn for NoAnn<'ast> {} impl<'ast> pprust_hir::PpAnn for NoAnn<'ast> {} struct IdentifiedAnnotation<'ast> { - sess: Session, + sess: &'ast Session, ast_map: Option>, } impl<'ast> PrinterSupport<'ast> for IdentifiedAnnotation<'ast> { - fn sess<'a>(&'a self) -> &'a Session { &self.sess } + fn sess<'a>(&'a self) -> &'a Session { self.sess } fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> { self.ast_map.as_ref() @@ -309,7 +308,7 @@ impl<'ast> pprust::PpAnn for IdentifiedAnnotation<'ast> { } impl<'ast> HirPrinterSupport<'ast> for IdentifiedAnnotation<'ast> { - fn sess<'a>(&'a self) -> &'a Session { &self.sess } + fn sess<'a>(&'a self) -> &'a Session { self.sess } fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> { self.ast_map.as_ref() @@ -331,8 +330,7 @@ impl<'ast> pprust_hir::PpAnn for IdentifiedAnnotation<'ast> { s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> { match node { - pprust_hir::NodeIdent(_) | pprust_hir::NodeName(_) => Ok(()), - + pprust_hir::NodeName(_) => Ok(()), pprust_hir::NodeItem(item) => { try!(pp::space(&mut s.s)); s.synth_comment(item.id.to_string()) @@ -359,12 +357,12 @@ impl<'ast> pprust_hir::PpAnn for IdentifiedAnnotation<'ast> { } struct HygieneAnnotation<'ast> { - sess: Session, + sess: &'ast Session, ast_map: Option>, } impl<'ast> PrinterSupport<'ast> for HygieneAnnotation<'ast> { - fn sess<'a>(&'a self) -> &'a Session { &self.sess } + fn sess<'a>(&'a self) -> &'a Session { self.sess } fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> { self.ast_map.as_ref() @@ -382,7 +380,7 @@ impl<'ast> pprust::PpAnn for HygieneAnnotation<'ast> { try!(pp::space(&mut s.s)); // FIXME #16420: this doesn't display the connections // between syntax contexts - s.synth_comment(format!("{}#{}", nm, ctxt)) + s.synth_comment(format!("{}#{}", nm, ctxt.0)) } pprust::NodeName(&ast::Name(nm)) => { try!(pp::space(&mut s.s)); @@ -672,9 +670,10 @@ pub fn pretty_print_input(sess: Session, // There is some twisted, god-forsaken tangle of lifetimes here which makes // the ordering of stuff super-finicky. let mut hir_forest; + let lcx = LoweringContext::new(&sess, Some(&krate)); let arenas = ty::CtxtArenas::new(); let ast_map = if compute_ast_map { - hir_forest = hir_map::Forest::new(lower_crate(&krate)); + hir_forest = hir_map::Forest::new(lower_crate(&lcx, &krate)); let map = driver::make_map(&sess, &mut hir_forest); Some(map) } else { @@ -697,7 +696,7 @@ pub fn pretty_print_input(sess: Session, // Silently ignores an identified node. let out: &mut Write = &mut out; s.call_with_pp_support( - sess, ast_map, box out, |annotation, out| { + &sess, ast_map, box out, |annotation, out| { debug!("pretty printing source code {:?}", s); let sess = annotation.sess(); pprust::print_crate(sess.codemap(), @@ -714,7 +713,7 @@ pub fn pretty_print_input(sess: Session, (PpmHir(s), None) => { let out: &mut Write = &mut out; s.call_with_pp_support_hir( - sess, &ast_map.unwrap(), &krate, &arenas, id, box out, |annotation, out, krate| { + &sess, &ast_map.unwrap(), &arenas, &id, box out, |annotation, out, krate| { debug!("pretty printing source code {:?}", s); let sess = annotation.sess(); pprust_hir::print_crate(sess.codemap(), @@ -730,11 +729,10 @@ pub fn pretty_print_input(sess: Session, (PpmHir(s), Some(uii)) => { let out: &mut Write = &mut out; - s.call_with_pp_support_hir(sess, + s.call_with_pp_support_hir(&sess, &ast_map.unwrap(), - &krate, &arenas, - id, + &id, (out,uii), |annotation, (out,uii), _| { debug!("pretty printing source code {:?}", s); @@ -779,15 +777,14 @@ pub fn pretty_print_input(sess: Session, match code { Some(code) => { let variants = gather_flowgraph_variants(&sess); - driver::phase_3_run_analysis_passes(sess, + driver::phase_3_run_analysis_passes(&sess, ast_map, - &krate, &arenas, - id, + &id, resolve::MakeGlobMap::No, |tcx, _| { print_flowgraph(variants, tcx, code, mode, out) - }).1 + }) } None => { let message = format!("--pretty=flowgraph needs \ diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 96d9572b48..4bbc22ef1a 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -38,7 +38,7 @@ use syntax::diagnostic::{Level, RenderSpan, Bug, Fatal, Error, Warning, Note, He use syntax::parse::token; use syntax::feature_gate::UnstableFeatures; -use rustc_front::lowering::lower_crate; +use rustc_front::lowering::{lower_crate, LoweringContext}; use rustc_front::hir; struct Env<'a, 'tcx: 'a> { @@ -124,18 +124,19 @@ fn test_env(source_string: &str, .expect("phase 2 aborted"); let krate = driver::assign_node_ids(&sess, krate); - let mut hir_forest = hir_map::Forest::new(lower_crate(&krate)); + let lcx = LoweringContext::new(&sess, Some(&krate)); + let mut hir_forest = hir_map::Forest::new(lower_crate(&lcx, &krate)); let arenas = ty::CtxtArenas::new(); let ast_map = driver::make_map(&sess, &mut hir_forest); let krate = ast_map.krate(); // run just enough stuff to build a tcx: - let lang_items = lang_items::collect_language_items(krate, &sess); + let lang_items = lang_items::collect_language_items(&sess, &ast_map); let resolve::CrateMap { def_map, freevars, .. } = resolve::resolve_crate(&sess, &ast_map, resolve::MakeGlobMap::No); let named_region_map = resolve_lifetime::krate(&sess, krate, &def_map); let region_map = region::resolve_crate(&sess, krate); - ty::ctxt::create_and_enter(sess, + ty::ctxt::create_and_enter(&sess, &arenas, def_map, named_region_map, @@ -195,7 +196,7 @@ impl<'a, 'tcx> Env<'a, 'tcx> { -> Option { assert!(idx < names.len()); for item in &m.items { - if item.ident.to_string() == names[idx] { + if item.name.to_string() == names[idx] { return search(this, &**item, idx+1, names); } } @@ -295,7 +296,7 @@ impl<'a, 'tcx> Env<'a, 'tcx> { { let name = token::intern(name); ty::ReEarlyBound(ty::EarlyBoundRegion { - param_id: ast::DUMMY_NODE_ID, + def_id: self.infcx.tcx.map.local_def_id(ast::DUMMY_NODE_ID), space: space, index: index, name: name @@ -350,6 +351,11 @@ impl<'a, 'tcx> Env<'a, 'tcx> { self.tcx().types.isize) } + pub fn t_rptr_empty(&self) -> Ty<'tcx> { + self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(ty::ReEmpty), + self.tcx().types.isize) + } + pub fn dummy_type_trace(&self) -> infer::TypeTrace<'tcx> { infer::TypeTrace::dummy(self.tcx()) } @@ -592,16 +598,15 @@ fn lub_free_free() { #[test] fn lub_returning_scope() { - test_env(EMPTY_SOURCE_STR, - errors(&["cannot infer an appropriate lifetime"]), |env| { - env.create_simple_region_hierarchy(); - let t_rptr_scope10 = env.t_rptr_scope(10); - let t_rptr_scope11 = env.t_rptr_scope(11); - - // this should generate an error when regions are resolved - env.make_lub_ty(env.t_fn(&[], t_rptr_scope10), - env.t_fn(&[], t_rptr_scope11)); - }) + test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + env.create_simple_region_hierarchy(); + let t_rptr_scope10 = env.t_rptr_scope(10); + let t_rptr_scope11 = env.t_rptr_scope(11); + let t_rptr_empty = env.t_rptr_empty(); + env.check_lub(env.t_fn(&[t_rptr_scope10], env.tcx().types.isize), + env.t_fn(&[t_rptr_scope11], env.tcx().types.isize), + env.t_fn(&[t_rptr_empty], env.tcx().types.isize)); + }); } #[test] diff --git a/src/librustc_front/attr.rs b/src/librustc_front/attr.rs deleted file mode 100644 index 8609fd9b9d..0000000000 --- a/src/librustc_front/attr.rs +++ /dev/null @@ -1,628 +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. - -// Functions dealing with attributes and meta items - -pub use self::StabilityLevel::*; -pub use self::ReprAttr::*; -pub use self::IntType::*; - -use hir; -use hir::{AttrId, Attribute, Attribute_, MetaItem, MetaWord, MetaNameValue, MetaList}; -use lowering::{lower_attr_style, unlower_attribute}; -use syntax::codemap::{Span, Spanned, spanned, dummy_spanned}; -use syntax::codemap::BytePos; -use syntax::diagnostic::SpanHandler; -use syntax::attr as syntax_attr; -use syntax::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; -use syntax::parse::token::{InternedString, intern_and_get_ident}; -use syntax::parse::token; -use syntax::ptr::P; - -use std::cell::Cell; -use std::collections::HashSet; -use std::fmt; - -pub fn mark_used(attr: &Attribute) { - syntax_attr::mark_used(&unlower_attribute(attr)) -} - -pub trait AttrMetaMethods { - fn check_name(&self, name: &str) -> bool { - name == &self.name()[..] - } - - /// Retrieve the name of the meta item, e.g. `foo` in `#[foo]`, - /// `#[foo="bar"]` and `#[foo(bar)]` - fn name(&self) -> InternedString; - - /// Gets the string value if self is a MetaNameValue variant - /// containing a string, otherwise None. - fn value_str(&self) -> Option; - /// Gets a list of inner meta items from a list MetaItem type. - fn meta_item_list<'a>(&'a self) -> Option<&'a [P]>; - - fn span(&self) -> Span; -} - -impl AttrMetaMethods for Attribute { - fn check_name(&self, name: &str) -> bool { - let matches = name == &self.name()[..]; - if matches { - syntax_attr::mark_used(&unlower_attribute(self)); - } - matches - } - fn name(&self) -> InternedString { self.meta().name() } - fn value_str(&self) -> Option { - self.meta().value_str() - } - fn meta_item_list<'a>(&'a self) -> Option<&'a [P]> { - self.node.value.meta_item_list() - } - fn span(&self) -> Span { self.meta().span } -} - -impl AttrMetaMethods for MetaItem { - fn name(&self) -> InternedString { - match self.node { - MetaWord(ref n) => (*n).clone(), - MetaNameValue(ref n, _) => (*n).clone(), - MetaList(ref n, _) => (*n).clone(), - } - } - - fn value_str(&self) -> Option { - match self.node { - MetaNameValue(_, ref v) => { - match v.node { - hir::LitStr(ref s, _) => Some((*s).clone()), - _ => None, - } - }, - _ => None - } - } - - fn meta_item_list<'a>(&'a self) -> Option<&'a [P]> { - match self.node { - MetaList(_, ref l) => Some(&l[..]), - _ => None - } - } - fn span(&self) -> Span { self.span } -} - -// Annoying, but required to get test_cfg to work -impl AttrMetaMethods for P { - fn name(&self) -> InternedString { (**self).name() } - fn value_str(&self) -> Option { (**self).value_str() } - fn meta_item_list<'a>(&'a self) -> Option<&'a [P]> { - (**self).meta_item_list() - } - fn span(&self) -> Span { (**self).span() } -} - - -pub trait AttributeMethods { - fn meta<'a>(&'a self) -> &'a MetaItem; - fn with_desugared_doc(&self, f: F) -> T where - F: FnOnce(&Attribute) -> T; -} - -impl AttributeMethods for Attribute { - /// Extract the MetaItem from inside this Attribute. - fn meta<'a>(&'a self) -> &'a MetaItem { - &*self.node.value - } - - /// Convert self to a normal #[doc="foo"] comment, if it is a - /// comment like `///` or `/** */`. (Returns self unchanged for - /// non-sugared doc attributes.) - fn with_desugared_doc(&self, f: F) -> T where - F: FnOnce(&Attribute) -> T, - { - if self.node.is_sugared_doc { - let comment = self.value_str().unwrap(); - let meta = mk_name_value_item_str( - InternedString::new("doc"), - token::intern_and_get_ident(&strip_doc_comment_decoration( - &comment))); - if self.node.style == hir::AttrOuter { - f(&mk_attr_outer(self.node.id, meta)) - } else { - f(&mk_attr_inner(self.node.id, meta)) - } - } else { - f(self) - } - } -} - -/* Constructors */ - -pub fn mk_name_value_item_str(name: InternedString, value: InternedString) - -> P { - let value_lit = dummy_spanned(hir::LitStr(value, hir::CookedStr)); - mk_name_value_item(name, value_lit) -} - -pub fn mk_name_value_item(name: InternedString, value: hir::Lit) - -> P { - P(dummy_spanned(MetaNameValue(name, value))) -} - -pub fn mk_list_item(name: InternedString, items: Vec>) -> P { - P(dummy_spanned(MetaList(name, items))) -} - -pub fn mk_word_item(name: InternedString) -> P { - P(dummy_spanned(MetaWord(name))) -} - -thread_local! { static NEXT_ATTR_ID: Cell = Cell::new(0) } - -pub fn mk_attr_id() -> AttrId { - let id = NEXT_ATTR_ID.with(|slot| { - let r = slot.get(); - slot.set(r + 1); - r - }); - AttrId(id) -} - -/// Returns an inner attribute with the given value. -pub fn mk_attr_inner(id: AttrId, item: P) -> Attribute { - dummy_spanned(Attribute_ { - id: id, - style: hir::AttrInner, - value: item, - is_sugared_doc: false, - }) -} - -/// Returns an outer attribute with the given value. -pub fn mk_attr_outer(id: AttrId, item: P) -> Attribute { - dummy_spanned(Attribute_ { - id: id, - style: hir::AttrOuter, - value: item, - is_sugared_doc: false, - }) -} - -pub fn mk_sugared_doc_attr(id: AttrId, text: InternedString, lo: BytePos, - hi: BytePos) - -> Attribute { - let style = lower_attr_style(doc_comment_style(&text)); - let lit = spanned(lo, hi, hir::LitStr(text, hir::CookedStr)); - let attr = Attribute_ { - id: id, - style: style, - value: P(spanned(lo, hi, MetaNameValue(InternedString::new("doc"), - lit))), - is_sugared_doc: true - }; - spanned(lo, hi, attr) -} - -/* Searching */ -/// Check if `needle` occurs in `haystack` by a structural -/// comparison. This is slightly subtle, and relies on ignoring the -/// span included in the `==` comparison a plain MetaItem. -pub fn contains(haystack: &[P], needle: &MetaItem) -> bool { - debug!("attr::contains (name={})", needle.name()); - haystack.iter().any(|item| { - debug!(" testing: {}", item.name()); - item.node == needle.node - }) -} - -pub fn contains_name(metas: &[AM], name: &str) -> bool { - debug!("attr::contains_name (name={})", name); - metas.iter().any(|item| { - debug!(" testing: {}", item.name()); - item.check_name(name) - }) -} - -pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: &str) - -> Option { - attrs.iter() - .find(|at| at.check_name(name)) - .and_then(|at| at.value_str()) -} - -pub fn last_meta_item_value_str_by_name(items: &[P], name: &str) - -> Option { - items.iter() - .rev() - .find(|mi| mi.check_name(name)) - .and_then(|i| i.value_str()) -} - -/* Higher-level applications */ - -pub fn sort_meta_items(items: Vec>) -> Vec> { - // This is sort of stupid here, but we need to sort by - // human-readable strings. - let mut v = items.into_iter() - .map(|mi| (mi.name(), mi)) - .collect::)>>(); - - v.sort_by(|&(ref a, _), &(ref b, _)| a.cmp(b)); - - // There doesn't seem to be a more optimal way to do this - v.into_iter().map(|(_, m)| m.map(|Spanned {node, span}| { - Spanned { - node: match node { - MetaList(n, mis) => MetaList(n, sort_meta_items(mis)), - _ => node - }, - span: span - } - })).collect() -} - -pub fn find_crate_name(attrs: &[Attribute]) -> Option { - first_attr_value_str_by_name(attrs, "crate_name") -} - -/// Find the value of #[export_name=*] attribute and check its validity. -pub fn find_export_name_attr(diag: &SpanHandler, attrs: &[Attribute]) -> Option { - attrs.iter().fold(None, |ia,attr| { - if attr.check_name("export_name") { - if let s@Some(_) = attr.value_str() { - s - } else { - diag.span_err(attr.span, "export_name attribute has invalid format"); - diag.handler.help("use #[export_name=\"*\"]"); - None - } - } else { - ia - } - }) -} - -#[derive(Copy, Clone, PartialEq)] -pub enum InlineAttr { - None, - Hint, - Always, - Never, -} - -/// Determine what `#[inline]` attribute is present in `attrs`, if any. -pub fn find_inline_attr(diagnostic: Option<&SpanHandler>, attrs: &[Attribute]) -> InlineAttr { - // FIXME (#2809)---validate the usage of #[inline] and #[inline] - attrs.iter().fold(InlineAttr::None, |ia,attr| { - match attr.node.value.node { - MetaWord(ref n) if *n == "inline" => { - syntax_attr::mark_used(&unlower_attribute(attr)); - InlineAttr::Hint - } - MetaList(ref n, ref items) if *n == "inline" => { - syntax_attr::mark_used(&unlower_attribute(attr)); - if items.len() != 1 { - diagnostic.map(|d|{ d.span_err(attr.span, "expected one argument"); }); - InlineAttr::None - } else if contains_name(&items[..], "always") { - InlineAttr::Always - } else if contains_name(&items[..], "never") { - InlineAttr::Never - } else { - diagnostic.map(|d|{ d.span_err((*items[0]).span, "invalid argument"); }); - InlineAttr::None - } - } - _ => ia - } - }) -} - -/// True if `#[inline]` or `#[inline(always)]` is present in `attrs`. -pub fn requests_inline(attrs: &[Attribute]) -> bool { - match find_inline_attr(None, attrs) { - InlineAttr::Hint | InlineAttr::Always => true, - InlineAttr::None | InlineAttr::Never => false, - } -} - -/// Represents the #[deprecated] and friends attributes. -#[derive(RustcEncodable, RustcDecodable, Clone, Debug, PartialEq, Eq, Hash)] -pub struct Stability { - pub level: StabilityLevel, - pub feature: InternedString, - pub since: Option, - pub deprecated_since: Option, - // The reason for the current stability level. If deprecated, the - // reason for deprecation. - pub reason: Option, - // The relevant rust-lang issue - pub issue: Option -} - -/// The available stability levels. -#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Copy, Eq, Hash)] -pub enum StabilityLevel { - Unstable, - Stable, -} - -impl fmt::Display for StabilityLevel { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(self, f) - } -} - -fn find_stability_generic<'a, - AM: AttrMetaMethods, - I: Iterator> - (diagnostic: &SpanHandler, attrs: I, item_sp: Span) - -> (Option, Vec<&'a AM>) { - - let mut stab: Option = None; - let mut deprecated: Option<(Option, Option)> = None; - let mut used_attrs: Vec<&'a AM> = vec![]; - - 'outer: for attr in attrs { - let tag = attr.name(); - let tag = &tag[..]; - if tag != "deprecated" && tag != "unstable" && tag != "stable" { - continue // not a stability level - } - - used_attrs.push(attr); - - let (feature, since, reason, issue) = match attr.meta_item_list() { - Some(metas) => { - let mut feature = None; - let mut since = None; - let mut reason = None; - let mut issue = None; - for meta in metas { - match &*meta.name() { - "feature" => { - match meta.value_str() { - Some(v) => feature = Some(v), - None => { - diagnostic.span_err(meta.span, "incorrect meta item"); - continue 'outer; - } - } - } - "since" => { - match meta.value_str() { - Some(v) => since = Some(v), - None => { - diagnostic.span_err(meta.span, "incorrect meta item"); - continue 'outer; - } - } - } - "reason" => { - match meta.value_str() { - Some(v) => reason = Some(v), - None => { - diagnostic.span_err(meta.span, "incorrect meta item"); - continue 'outer; - } - } - } - "issue" => { - match meta.value_str().and_then(|s| s.parse().ok()) { - Some(v) => issue = Some(v), - None => { - diagnostic.span_err(meta.span, "incorrect meta item"); - continue 'outer; - } - } - } - _ => {} - } - } - (feature, since, reason, issue) - } - None => { - diagnostic.span_err(attr.span(), "incorrect stability attribute type"); - continue - } - }; - - // Deprecated tags don't require feature names - if feature == None && tag != "deprecated" { - diagnostic.span_err(attr.span(), "missing 'feature'"); - } - - // Unstable tags don't require a version - if since == None && tag != "unstable" { - diagnostic.span_err(attr.span(), "missing 'since'"); - } - - if tag == "unstable" || tag == "stable" { - if stab.is_some() { - diagnostic.span_err(item_sp, "multiple stability levels"); - } - - let level = match tag { - "unstable" => Unstable, - "stable" => Stable, - _ => unreachable!() - }; - - stab = Some(Stability { - level: level, - feature: feature.unwrap_or(intern_and_get_ident("bogus")), - since: since, - deprecated_since: None, - reason: reason, - issue: issue, - }); - } else { // "deprecated" - if deprecated.is_some() { - diagnostic.span_err(item_sp, "multiple deprecated attributes"); - } - - deprecated = Some((since, reason)); - } - } - - // Merge the deprecation info into the stability info - if deprecated.is_some() { - match stab { - Some(ref mut s) => { - let (since, reason) = deprecated.unwrap(); - s.deprecated_since = since; - s.reason = reason; - } - None => { - diagnostic.span_err(item_sp, "deprecated attribute must be paired with \ - either stable or unstable attribute"); - } - } - } else if stab.as_ref().map_or(false, |s| s.level == Unstable && s.issue.is_none()) { - // non-deprecated unstable items need to point to issues. - diagnostic.span_err(item_sp, - "non-deprecated unstable items need to point \ - to an issue with `issue = \"NNN\"`"); - } - - (stab, used_attrs) -} - -/// Find the first stability attribute. `None` if none exists. -pub fn find_stability(diagnostic: &SpanHandler, attrs: &[Attribute], - item_sp: Span) -> Option { - let (s, used) = find_stability_generic(diagnostic, attrs.iter(), item_sp); - for used in used { syntax_attr::mark_used(&unlower_attribute(used)) } - return s; -} - -pub fn require_unique_names(diagnostic: &SpanHandler, metas: &[P]) { - let mut set = HashSet::new(); - for meta in metas { - let name = meta.name(); - - if !set.insert(name.clone()) { - panic!(diagnostic.span_fatal(meta.span, - &format!("duplicate meta item `{}`", name))); - } - } -} - - -/// Parse #[repr(...)] forms. -/// -/// Valid repr contents: any of the primitive integral type names (see -/// `int_type_of_word`, below) to specify enum discriminant type; `C`, to use -/// the same discriminant size that the corresponding C enum would or C -/// structure layout, and `packed` to remove padding. -pub fn find_repr_attrs(diagnostic: &SpanHandler, attr: &Attribute) -> Vec { - let mut acc = Vec::new(); - match attr.node.value.node { - hir::MetaList(ref s, ref items) if *s == "repr" => { - syntax_attr::mark_used(&unlower_attribute(attr)); - for item in items { - match item.node { - hir::MetaWord(ref word) => { - let hint = match &word[..] { - // Can't use "extern" because it's not a lexical identifier. - "C" => Some(ReprExtern), - "packed" => Some(ReprPacked), - "simd" => Some(ReprSimd), - _ => match int_type_of_word(&word) { - Some(ity) => Some(ReprInt(item.span, ity)), - None => { - // Not a word we recognize - diagnostic.span_err(item.span, - "unrecognized representation hint"); - None - } - } - }; - - match hint { - Some(h) => acc.push(h), - None => { } - } - } - // Not a word: - _ => diagnostic.span_err(item.span, "unrecognized enum representation hint") - } - } - } - // Not a "repr" hint: ignore. - _ => { } - } - acc -} - -fn int_type_of_word(s: &str) -> Option { - match s { - "i8" => Some(SignedInt(hir::TyI8)), - "u8" => Some(UnsignedInt(hir::TyU8)), - "i16" => Some(SignedInt(hir::TyI16)), - "u16" => Some(UnsignedInt(hir::TyU16)), - "i32" => Some(SignedInt(hir::TyI32)), - "u32" => Some(UnsignedInt(hir::TyU32)), - "i64" => Some(SignedInt(hir::TyI64)), - "u64" => Some(UnsignedInt(hir::TyU64)), - "isize" => Some(SignedInt(hir::TyIs)), - "usize" => Some(UnsignedInt(hir::TyUs)), - _ => None - } -} - -#[derive(PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)] -pub enum ReprAttr { - ReprAny, - ReprInt(Span, IntType), - ReprExtern, - ReprPacked, - ReprSimd, -} - -impl ReprAttr { - pub fn is_ffi_safe(&self) -> bool { - match *self { - ReprAny => false, - ReprInt(_sp, ity) => ity.is_ffi_safe(), - ReprExtern => true, - ReprPacked => false, - ReprSimd => true, - } - } -} - -#[derive(Eq, Hash, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)] -pub enum IntType { - SignedInt(hir::IntTy), - UnsignedInt(hir::UintTy) -} - -impl IntType { - #[inline] - pub fn is_signed(self) -> bool { - match self { - SignedInt(..) => true, - UnsignedInt(..) => false - } - } - fn is_ffi_safe(self) -> bool { - match self { - SignedInt(hir::TyI8) | UnsignedInt(hir::TyU8) | - SignedInt(hir::TyI16) | UnsignedInt(hir::TyU16) | - SignedInt(hir::TyI32) | UnsignedInt(hir::TyU32) | - SignedInt(hir::TyI64) | UnsignedInt(hir::TyU64) => true, - SignedInt(hir::TyIs) | UnsignedInt(hir::TyUs) => false - } - } -} diff --git a/src/librustc_front/fold.rs b/src/librustc_front/fold.rs index ba20b46090..c1bcba1830 100644 --- a/src/librustc_front/fold.rs +++ b/src/librustc_front/fold.rs @@ -12,7 +12,8 @@ //! and returns a piece of the same type. use hir::*; -use syntax::ast::{Ident, NodeId, DUMMY_NODE_ID}; +use syntax::ast::{Ident, Name, NodeId, DUMMY_NODE_ID, Attribute, Attribute_, MetaItem}; +use syntax::ast::{MetaWord, MetaList, MetaNameValue}; use hir; use syntax::codemap::{respan, Span, Spanned}; use syntax::owned_slice::OwnedSlice; @@ -28,7 +29,9 @@ pub trait MoveMap { } impl MoveMap for Vec { - fn move_map(mut self, mut f: F) -> Vec where F: FnMut(T) -> T { + fn move_map(mut self, mut f: F) -> Vec + where F: FnMut(T) -> T + { for p in &mut self { unsafe { // FIXME(#5016) this shouldn't need to zero to be safe. @@ -40,7 +43,9 @@ impl MoveMap for Vec { } impl MoveMap for OwnedSlice { - fn move_map(self, f: F) -> OwnedSlice where F: FnMut(T) -> T { + fn move_map(self, f: F) -> OwnedSlice + where F: FnMut(T) -> T + { OwnedSlice::from_vec(self.into_vec().move_map(f)) } } @@ -146,6 +151,10 @@ pub trait Folder : Sized { noop_fold_variant(v, self) } + fn fold_name(&mut self, n: Name) -> Name { + noop_fold_name(n, self) + } + fn fold_ident(&mut self, i: Ident) -> Ident { noop_fold_ident(i, self) } @@ -162,15 +171,15 @@ pub trait Folder : Sized { noop_fold_path_parameters(p, self) } - fn fold_angle_bracketed_parameter_data(&mut self, p: AngleBracketedParameterData) - -> AngleBracketedParameterData - { + fn fold_angle_bracketed_parameter_data(&mut self, + p: AngleBracketedParameterData) + -> AngleBracketedParameterData { noop_fold_angle_bracketed_parameter_data(p, self) } - fn fold_parenthesized_parameter_data(&mut self, p: ParenthesizedParameterData) - -> ParenthesizedParameterData - { + fn fold_parenthesized_parameter_data(&mut self, + p: ParenthesizedParameterData) + -> ParenthesizedParameterData { noop_fold_parenthesized_parameter_data(p, self) } @@ -214,8 +223,8 @@ pub trait Folder : Sized { noop_fold_poly_trait_ref(p, self) } - fn fold_struct_def(&mut self, struct_def: P) -> P { - noop_fold_struct_def(struct_def, self) + fn fold_variant_data(&mut self, vdata: VariantData) -> VariantData { + noop_fold_variant_data(vdata, self) } fn fold_lifetimes(&mut self, lts: Vec) -> Vec { @@ -238,17 +247,13 @@ pub trait Folder : Sized { noop_fold_opt_lifetime(o_lt, self) } - fn fold_variant_arg(&mut self, va: VariantArg) -> VariantArg { - noop_fold_variant_arg(va, self) - } - - fn fold_opt_bounds(&mut self, b: Option>) + fn fold_opt_bounds(&mut self, + b: Option>) -> Option> { noop_fold_opt_bounds(b, self) } - fn fold_bounds(&mut self, b: OwnedSlice) - -> OwnedSlice { + fn fold_bounds(&mut self, b: OwnedSlice) -> OwnedSlice { noop_fold_bounds(b, self) } @@ -264,13 +269,11 @@ pub trait Folder : Sized { noop_fold_field(field, self) } - fn fold_where_clause(&mut self, where_clause: WhereClause) - -> WhereClause { + fn fold_where_clause(&mut self, where_clause: WhereClause) -> WhereClause { noop_fold_where_clause(where_clause, self) } - fn fold_where_predicate(&mut self, where_predicate: WherePredicate) - -> WherePredicate { + fn fold_where_predicate(&mut self, where_predicate: WherePredicate) -> WherePredicate { noop_fold_where_predicate(where_predicate, self) } @@ -283,43 +286,44 @@ pub trait Folder : Sized { } } -pub fn noop_fold_meta_items(meta_items: Vec>, fld: &mut T) +pub fn noop_fold_meta_items(meta_items: Vec>, + fld: &mut T) -> Vec> { meta_items.move_map(|x| fld.fold_meta_item(x)) } pub fn noop_fold_view_path(view_path: P, fld: &mut T) -> P { - view_path.map(|Spanned {node, span}| Spanned { - node: match node { - ViewPathSimple(ident, path) => { - ViewPathSimple(ident, fld.fold_path(path)) - } - ViewPathGlob(path) => { - ViewPathGlob(fld.fold_path(path)) - } - ViewPathList(path, path_list_idents) => { - ViewPathList(fld.fold_path(path), - path_list_idents.move_map(|path_list_ident| { - Spanned { - node: match path_list_ident.node { - PathListIdent { id, name, rename } => - PathListIdent { - id: fld.new_id(id), - name: name, - rename: rename, - }, - PathListMod { id, rename } => - PathListMod { - id: fld.new_id(id), - rename: rename, - } - }, - span: fld.new_span(path_list_ident.span) - } - })) - } - }, - span: fld.new_span(span) + view_path.map(|Spanned { node, span }| { + Spanned { + node: match node { + ViewPathSimple(name, path) => { + ViewPathSimple(name, fld.fold_path(path)) + } + ViewPathGlob(path) => { + ViewPathGlob(fld.fold_path(path)) + } + ViewPathList(path, path_list_idents) => { + ViewPathList(fld.fold_path(path), + path_list_idents.move_map(|path_list_ident| { + Spanned { + node: match path_list_ident.node { + PathListIdent { id, name, rename } => PathListIdent { + id: fld.new_id(id), + name: name, + rename: rename, + }, + PathListMod { id, rename } => PathListMod { + id: fld.new_id(id), + rename: rename, + }, + }, + span: fld.new_span(path_list_ident.span), + } + })) + } + }, + span: fld.new_span(span), + } }) } @@ -327,7 +331,7 @@ pub fn fold_attrs(attrs: Vec, fld: &mut T) -> Vec(Arm {attrs, pats, guard, body}: Arm, fld: &mut T) -> Arm { +pub fn noop_fold_arm(Arm { attrs, pats, guard, body }: Arm, fld: &mut T) -> Arm { Arm { attrs: fold_attrs(attrs, fld), pats: pats.move_map(|x| fld.fold_pat(x)), @@ -337,76 +341,89 @@ pub fn noop_fold_arm(Arm {attrs, pats, guard, body}: Arm, fld: &mut T } pub fn noop_fold_decl(d: P, fld: &mut T) -> SmallVector> { - d.and_then(|Spanned {node, span}| match node { - DeclLocal(l) => SmallVector::one(P(Spanned { - node: DeclLocal(fld.fold_local(l)), - span: fld.new_span(span) - })), - DeclItem(it) => fld.fold_item(it).into_iter().map(|i| P(Spanned { - node: DeclItem(i), - span: fld.new_span(span) - })).collect() + d.and_then(|Spanned { node, span }| { + match node { + DeclLocal(l) => SmallVector::one(P(Spanned { + node: DeclLocal(fld.fold_local(l)), + span: fld.new_span(span), + })), + DeclItem(it) => fld.fold_item(it) + .into_iter() + .map(|i| { + P(Spanned { + node: DeclItem(i), + span: fld.new_span(span), + }) + }) + .collect(), + } }) } pub fn noop_fold_ty_binding(b: P, fld: &mut T) -> P { - b.map(|TypeBinding { id, ident, ty, span }| TypeBinding { - id: fld.new_id(id), - ident: ident, - ty: fld.fold_ty(ty), - span: fld.new_span(span), + b.map(|TypeBinding { id, name, ty, span }| { + TypeBinding { + id: fld.new_id(id), + name: name, + ty: fld.fold_ty(ty), + span: fld.new_span(span), + } }) } pub fn noop_fold_ty(t: P, fld: &mut T) -> P { - t.map(|Ty {id, node, span}| Ty { - id: fld.new_id(id), - node: match node { - TyInfer => node, - TyVec(ty) => TyVec(fld.fold_ty(ty)), - TyPtr(mt) => TyPtr(fld.fold_mt(mt)), - TyRptr(region, mt) => { - TyRptr(fld.fold_opt_lifetime(region), fld.fold_mt(mt)) - } - TyBareFn(f) => { - TyBareFn(f.map(|BareFnTy {lifetimes, unsafety, abi, decl}| BareFnTy { - lifetimes: fld.fold_lifetime_defs(lifetimes), - unsafety: unsafety, - abi: abi, - decl: fld.fold_fn_decl(decl) - })) - } - TyTup(tys) => TyTup(tys.move_map(|ty| fld.fold_ty(ty))), - TyParen(ty) => TyParen(fld.fold_ty(ty)), - TyPath(qself, path) => { - let qself = qself.map(|QSelf { ty, position }| { - QSelf { - ty: fld.fold_ty(ty), - position: position - } - }); - TyPath(qself, fld.fold_path(path)) - } - TyObjectSum(ty, bounds) => { - TyObjectSum(fld.fold_ty(ty), - fld.fold_bounds(bounds)) - } - TyFixedLengthVec(ty, e) => { - TyFixedLengthVec(fld.fold_ty(ty), fld.fold_expr(e)) - } - TyTypeof(expr) => { - TyTypeof(fld.fold_expr(expr)) - } - TyPolyTraitRef(bounds) => { - TyPolyTraitRef(bounds.move_map(|b| fld.fold_ty_param_bound(b))) - } - }, - span: fld.new_span(span) + t.map(|Ty { id, node, span }| { + Ty { + id: fld.new_id(id), + node: match node { + TyInfer => node, + TyVec(ty) => TyVec(fld.fold_ty(ty)), + TyPtr(mt) => TyPtr(fld.fold_mt(mt)), + TyRptr(region, mt) => { + TyRptr(fld.fold_opt_lifetime(region), fld.fold_mt(mt)) + } + TyBareFn(f) => { + TyBareFn(f.map(|BareFnTy { lifetimes, unsafety, abi, decl }| { + BareFnTy { + lifetimes: fld.fold_lifetime_defs(lifetimes), + unsafety: unsafety, + abi: abi, + decl: fld.fold_fn_decl(decl), + } + })) + } + TyTup(tys) => TyTup(tys.move_map(|ty| fld.fold_ty(ty))), + TyParen(ty) => TyParen(fld.fold_ty(ty)), + TyPath(qself, path) => { + let qself = qself.map(|QSelf { ty, position }| { + QSelf { + ty: fld.fold_ty(ty), + position: position, + } + }); + TyPath(qself, fld.fold_path(path)) + } + TyObjectSum(ty, bounds) => { + TyObjectSum(fld.fold_ty(ty), fld.fold_bounds(bounds)) + } + TyFixedLengthVec(ty, e) => { + TyFixedLengthVec(fld.fold_ty(ty), fld.fold_expr(e)) + } + TyTypeof(expr) => { + TyTypeof(fld.fold_expr(expr)) + } + TyPolyTraitRef(bounds) => { + TyPolyTraitRef(bounds.move_map(|b| fld.fold_ty_param_bound(b))) + } + }, + span: fld.new_span(span), + } }) } -pub fn noop_fold_foreign_mod(ForeignMod {abi, items}: ForeignMod, - fld: &mut T) -> ForeignMod { +pub fn noop_fold_foreign_mod(ForeignMod { abi, items }: ForeignMod, + fld: &mut T) + -> ForeignMod { ForeignMod { abi: abi, items: items.move_map(|x| fld.fold_foreign_item(x)), @@ -414,27 +431,21 @@ pub fn noop_fold_foreign_mod(ForeignMod {abi, items}: ForeignMod, } pub fn noop_fold_variant(v: P, fld: &mut T) -> P { - v.map(|Spanned {node: Variant_ {id, name, attrs, kind, disr_expr, vis}, span}| Spanned { + v.map(|Spanned {node: Variant_ {name, attrs, data, disr_expr}, span}| Spanned { node: Variant_ { - id: fld.new_id(id), name: name, attrs: fold_attrs(attrs, fld), - kind: match kind { - TupleVariantKind(variant_args) => { - TupleVariantKind(variant_args.move_map(|x| - fld.fold_variant_arg(x))) - } - StructVariantKind(struct_def) => { - StructVariantKind(fld.fold_struct_def(struct_def)) - } - }, + data: fld.fold_variant_data(data), disr_expr: disr_expr.map(|e| fld.fold_expr(e)), - vis: vis, }, span: fld.new_span(span), }) } +pub fn noop_fold_name(n: Name, _: &mut T) -> Name { + n +} + pub fn noop_fold_ident(i: Ident, _: &mut T) -> Ident { i } @@ -443,20 +454,22 @@ pub fn noop_fold_usize(i: usize, _: &mut T) -> usize { i } -pub fn noop_fold_path(Path {global, segments, span}: Path, fld: &mut T) -> Path { +pub fn noop_fold_path(Path { global, segments, span }: Path, fld: &mut T) -> Path { Path { global: global, - segments: segments.move_map(|PathSegment {identifier, parameters}| PathSegment { - identifier: fld.fold_ident(identifier), - parameters: fld.fold_path_parameters(parameters), + segments: segments.move_map(|PathSegment { identifier, parameters }| { + PathSegment { + identifier: fld.fold_ident(identifier), + parameters: fld.fold_path_parameters(parameters), + } }), - span: fld.new_span(span) + span: fld.new_span(span), } } -pub fn noop_fold_path_parameters(path_parameters: PathParameters, fld: &mut T) - -> PathParameters -{ +pub fn noop_fold_path_parameters(path_parameters: PathParameters, + fld: &mut T) + -> PathParameters { match path_parameters { AngleBracketedParameters(data) => AngleBracketedParameters(fld.fold_angle_bracketed_parameter_data(data)), @@ -467,31 +480,35 @@ pub fn noop_fold_path_parameters(path_parameters: PathParameters, fld pub fn noop_fold_angle_bracketed_parameter_data(data: AngleBracketedParameterData, fld: &mut T) - -> AngleBracketedParameterData -{ + -> AngleBracketedParameterData { let AngleBracketedParameterData { lifetimes, types, bindings } = data; - AngleBracketedParameterData { lifetimes: fld.fold_lifetimes(lifetimes), - types: types.move_map(|ty| fld.fold_ty(ty)), - bindings: bindings.move_map(|b| fld.fold_ty_binding(b)) } + AngleBracketedParameterData { + lifetimes: fld.fold_lifetimes(lifetimes), + types: types.move_map(|ty| fld.fold_ty(ty)), + bindings: bindings.move_map(|b| fld.fold_ty_binding(b)), + } } pub fn noop_fold_parenthesized_parameter_data(data: ParenthesizedParameterData, fld: &mut T) - -> ParenthesizedParameterData -{ + -> ParenthesizedParameterData { let ParenthesizedParameterData { inputs, output, span } = data; - ParenthesizedParameterData { inputs: inputs.move_map(|ty| fld.fold_ty(ty)), - output: output.map(|ty| fld.fold_ty(ty)), - span: fld.new_span(span) } + ParenthesizedParameterData { + inputs: inputs.move_map(|ty| fld.fold_ty(ty)), + output: output.map(|ty| fld.fold_ty(ty)), + span: fld.new_span(span), + } } pub fn noop_fold_local(l: P, fld: &mut T) -> P { - l.map(|Local {id, pat, ty, init, span}| Local { - id: fld.new_id(id), - ty: ty.map(|t| fld.fold_ty(t)), - pat: fld.fold_pat(pat), - init: init.map(|e| fld.fold_expr(e)), - span: fld.new_span(span) + l.map(|Local { id, pat, ty, init, span }| { + Local { + id: fld.new_id(id), + ty: ty.map(|t| fld.fold_ty(t)), + pat: fld.fold_pat(pat), + init: init.map(|e| fld.fold_expr(e)), + span: fld.new_span(span), + } }) } @@ -502,69 +519,75 @@ pub fn noop_fold_attribute(at: Attribute, fld: &mut T) -> Option(es: ExplicitSelf_, fld: &mut T) +pub fn noop_fold_explicit_self_underscore(es: ExplicitSelf_, + fld: &mut T) -> ExplicitSelf_ { match es { SelfStatic | SelfValue(_) => es, - SelfRegion(lifetime, m, ident) => { - SelfRegion(fld.fold_opt_lifetime(lifetime), m, ident) + SelfRegion(lifetime, m, name) => { + SelfRegion(fld.fold_opt_lifetime(lifetime), m, name) } - SelfExplicit(typ, ident) => { - SelfExplicit(fld.fold_ty(typ), ident) + SelfExplicit(typ, name) => { + SelfExplicit(fld.fold_ty(typ), name) } } } -pub fn noop_fold_explicit_self(Spanned {span, node}: ExplicitSelf, fld: &mut T) +pub fn noop_fold_explicit_self(Spanned { span, node }: ExplicitSelf, + fld: &mut T) -> ExplicitSelf { Spanned { node: fld.fold_explicit_self_underscore(node), - span: fld.new_span(span) + span: fld.new_span(span), } } pub fn noop_fold_meta_item(mi: P, fld: &mut T) -> P { - mi.map(|Spanned {node, span}| Spanned { - node: match node { - MetaWord(id) => MetaWord(id), - MetaList(id, mis) => { - MetaList(id, mis.move_map(|e| fld.fold_meta_item(e))) - } - MetaNameValue(id, s) => MetaNameValue(id, s) - }, - span: fld.new_span(span) + mi.map(|Spanned { node, span }| { + Spanned { + node: match node { + MetaWord(id) => MetaWord(id), + MetaList(id, mis) => { + MetaList(id, mis.move_map(|e| fld.fold_meta_item(e))) + } + MetaNameValue(id, s) => MetaNameValue(id, s), + }, + span: fld.new_span(span), + } }) } -pub fn noop_fold_arg(Arg {id, pat, ty}: Arg, fld: &mut T) -> Arg { +pub fn noop_fold_arg(Arg { id, pat, ty }: Arg, fld: &mut T) -> Arg { Arg { id: fld.new_id(id), pat: fld.fold_pat(pat), - ty: fld.fold_ty(ty) + ty: fld.fold_ty(ty), } } pub fn noop_fold_fn_decl(decl: P, fld: &mut T) -> P { - decl.map(|FnDecl {inputs, output, variadic}| FnDecl { - inputs: inputs.move_map(|x| fld.fold_arg(x)), - output: match output { - Return(ty) => Return(fld.fold_ty(ty)), - DefaultReturn(span) => DefaultReturn(span), - NoReturn(span) => NoReturn(span) - }, - variadic: variadic + decl.map(|FnDecl { inputs, output, variadic }| { + FnDecl { + inputs: inputs.move_map(|x| fld.fold_arg(x)), + output: match output { + Return(ty) => Return(fld.fold_ty(ty)), + DefaultReturn(span) => DefaultReturn(span), + NoReturn(span) => NoReturn(span), + }, + variadic: variadic, + } }) } -pub fn noop_fold_ty_param_bound(tpb: TyParamBound, fld: &mut T) - -> TyParamBound - where T: Folder { +pub fn noop_fold_ty_param_bound(tpb: TyParamBound, fld: &mut T) -> TyParamBound + where T: Folder +{ match tpb { TraitTyParamBound(ty, modifier) => TraitTyParamBound(fld.fold_poly_trait_ref(ty), modifier), RegionTyParamBound(lifetime) => RegionTyParamBound(fld.fold_lifetime(lifetime)), @@ -572,17 +595,18 @@ 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 {id, name, bounds, default, span} = tp; TyParam { id: fld.new_id(id), - ident: ident, + name: name, bounds: fld.fold_bounds(bounds), default: default.map(|x| fld.fold_ty(x)), - span: span + span: span, } } -pub fn noop_fold_ty_params(tps: OwnedSlice, fld: &mut T) +pub fn noop_fold_ty_params(tps: OwnedSlice, + fld: &mut T) -> OwnedSlice { tps.move_map(|tp| fld.fold_ty_param(tp)) } @@ -591,12 +615,11 @@ pub fn noop_fold_lifetime(l: Lifetime, fld: &mut T) -> Lifetime { Lifetime { id: fld.new_id(l.id), name: l.name, - span: fld.new_span(l.span) + span: fld.new_span(l.span), } } -pub fn noop_fold_lifetime_def(l: LifetimeDef, fld: &mut T) - -> LifetimeDef { +pub fn noop_fold_lifetime_def(l: LifetimeDef, fld: &mut T) -> LifetimeDef { LifetimeDef { lifetime: fld.fold_lifetime(l.lifetime), bounds: fld.fold_lifetimes(l.bounds), @@ -607,18 +630,17 @@ pub fn noop_fold_lifetimes(lts: Vec, fld: &mut T) -> Vec

  • (lts: Vec, fld: &mut T) - -> Vec { +pub fn noop_fold_lifetime_defs(lts: Vec, fld: &mut T) -> Vec { lts.move_map(|l| fld.fold_lifetime_def(l)) } -pub fn noop_fold_opt_lifetime(o_lt: Option, fld: &mut T) - -> Option { +pub fn noop_fold_opt_lifetime(o_lt: Option, fld: &mut T) -> Option { o_lt.map(|lt| fld.fold_lifetime(lt)) } -pub fn noop_fold_generics(Generics {ty_params, lifetimes, where_clause}: Generics, - fld: &mut T) -> Generics { +pub fn noop_fold_generics(Generics { ty_params, lifetimes, where_clause }: Generics, + fld: &mut T) + -> Generics { Generics { ty_params: fld.fold_ty_params(ty_params), lifetimes: fld.fold_lifetime_defs(lifetimes), @@ -626,22 +648,16 @@ pub fn noop_fold_generics(Generics {ty_params, lifetimes, where_claus } } -pub fn noop_fold_where_clause( - WhereClause {id, predicates}: WhereClause, - fld: &mut T) - -> WhereClause { +pub fn noop_fold_where_clause(WhereClause { id, predicates }: WhereClause, + fld: &mut T) + -> WhereClause { WhereClause { id: fld.new_id(id), - predicates: predicates.move_map(|predicate| { - fld.fold_where_predicate(predicate) - }) + predicates: predicates.move_map(|predicate| fld.fold_where_predicate(predicate)), } } -pub fn noop_fold_where_predicate( - pred: WherePredicate, - fld: &mut T) - -> WherePredicate { +pub fn noop_fold_where_predicate(pred: WherePredicate, fld: &mut T) -> WherePredicate { match pred { hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate{bound_lifetimes, bounded_ty, @@ -651,7 +667,7 @@ pub fn noop_fold_where_predicate( bound_lifetimes: fld.fold_lifetime_defs(bound_lifetimes), bounded_ty: fld.fold_ty(bounded_ty), bounds: bounds.move_map(|x| fld.fold_ty_param_bound(x)), - span: fld.new_span(span) + span: fld.new_span(span), }) } hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate{lifetime, @@ -660,28 +676,33 @@ pub fn noop_fold_where_predicate( hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate { span: fld.new_span(span), lifetime: fld.fold_lifetime(lifetime), - bounds: bounds.move_map(|bound| fld.fold_lifetime(bound)) + bounds: bounds.move_map(|bound| fld.fold_lifetime(bound)), }) } hir::WherePredicate::EqPredicate(hir::WhereEqPredicate{id, path, ty, span}) => { - hir::WherePredicate::EqPredicate(hir::WhereEqPredicate{ + hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { id: fld.new_id(id), path: fld.fold_path(path), - ty:fld.fold_ty(ty), - span: fld.new_span(span) + ty: fld.fold_ty(ty), + span: fld.new_span(span), }) } } } -pub fn noop_fold_struct_def(struct_def: P, fld: &mut T) -> P { - struct_def.map(|StructDef { fields, ctor_id }| StructDef { - fields: fields.move_map(|f| fld.fold_struct_field(f)), - ctor_id: ctor_id.map(|cid| fld.new_id(cid)), - }) +pub fn noop_fold_variant_data(vdata: VariantData, fld: &mut T) -> VariantData { + match vdata { + VariantData::Struct(fields, id) => { + VariantData::Struct(fields.move_map(|f| fld.fold_struct_field(f)), fld.new_id(id)) + } + VariantData::Tuple(fields, id) => { + VariantData::Tuple(fields.move_map(|f| fld.fold_struct_field(f)), fld.new_id(id)) + } + VariantData::Unit(id) => VariantData::Unit(fld.new_id(id)) + } } pub fn noop_fold_trait_ref(p: TraitRef, fld: &mut T) -> TraitRef { @@ -713,50 +734,45 @@ pub fn noop_fold_struct_field(f: StructField, fld: &mut T) -> StructF ty: fld.fold_ty(ty), attrs: fold_attrs(attrs, fld), }, - span: fld.new_span(span) + span: fld.new_span(span), } } -pub fn noop_fold_field(Field {ident, expr, span}: Field, folder: &mut T) -> Field { +pub fn noop_fold_field(Field { name, expr, span }: Field, folder: &mut T) -> Field { Field { - ident: respan(ident.span, folder.fold_ident(ident.node)), + name: respan(folder.new_span(name.span), + folder.fold_name(name.node)), expr: folder.fold_expr(expr), - span: folder.new_span(span) + span: folder.new_span(span), } } -pub fn noop_fold_mt(MutTy {ty, mutbl}: MutTy, folder: &mut T) -> MutTy { +pub fn noop_fold_mt(MutTy { ty, mutbl }: MutTy, folder: &mut T) -> MutTy { MutTy { ty: folder.fold_ty(ty), mutbl: mutbl, } } -pub fn noop_fold_opt_bounds(b: Option>, folder: &mut T) +pub fn noop_fold_opt_bounds(b: Option>, + folder: &mut T) -> Option> { b.map(|bounds| folder.fold_bounds(bounds)) } -fn noop_fold_bounds(bounds: TyParamBounds, folder: &mut T) - -> TyParamBounds { +fn noop_fold_bounds(bounds: TyParamBounds, folder: &mut T) -> TyParamBounds { bounds.move_map(|bound| folder.fold_ty_param_bound(bound)) } -fn noop_fold_variant_arg(VariantArg {id, ty}: VariantArg, folder: &mut T) - -> VariantArg { - VariantArg { - id: folder.new_id(id), - ty: folder.fold_ty(ty) - } -} - pub fn noop_fold_block(b: P, folder: &mut T) -> P { - b.map(|Block {id, stmts, expr, rules, span}| Block { - id: folder.new_id(id), - stmts: stmts.into_iter().flat_map(|s| folder.fold_stmt(s).into_iter()).collect(), - expr: expr.map(|x| folder.fold_expr(x)), - rules: rules, - span: folder.new_span(span), + b.map(|Block { id, stmts, expr, rules, span }| { + Block { + id: folder.new_id(id), + stmts: stmts.into_iter().flat_map(|s| folder.fold_stmt(s).into_iter()).collect(), + expr: expr.map(|x| folder.fold_expr(x)), + rules: rules, + span: folder.new_span(span), + } }) } @@ -773,14 +789,12 @@ pub fn noop_fold_item_underscore(i: Item_, folder: &mut T) -> Item_ { ItemConst(folder.fold_ty(t), folder.fold_expr(e)) } ItemFn(decl, unsafety, constness, abi, generics, body) => { - ItemFn( - folder.fold_fn_decl(decl), - unsafety, - constness, - abi, - folder.fold_generics(generics), - folder.fold_block(body) - ) + ItemFn(folder.fold_fn_decl(decl), + unsafety, + constness, + abi, + folder.fold_generics(generics), + folder.fold_block(body)) } ItemMod(m) => ItemMod(folder.fold_mod(m)), ItemForeignMod(nm) => ItemForeignMod(folder.fold_foreign_mod(nm)), @@ -788,23 +802,25 @@ pub fn noop_fold_item_underscore(i: Item_, folder: &mut T) -> Item_ { ItemTy(folder.fold_ty(t), folder.fold_generics(generics)) } ItemEnum(enum_definition, generics) => { - ItemEnum( - hir::EnumDef { - variants: enum_definition.variants.move_map(|x| folder.fold_variant(x)), - }, - folder.fold_generics(generics)) + ItemEnum(hir::EnumDef { + variants: enum_definition.variants.move_map(|x| folder.fold_variant(x)), + }, + folder.fold_generics(generics)) } ItemStruct(struct_def, generics) => { - let struct_def = folder.fold_struct_def(struct_def); + let struct_def = folder.fold_variant_data(struct_def); ItemStruct(struct_def, folder.fold_generics(generics)) } ItemDefaultImpl(unsafety, ref trait_ref) => { - ItemDefaultImpl(unsafety, folder.fold_trait_ref((*trait_ref).clone())) + ItemDefaultImpl(unsafety, + folder.fold_trait_ref((*trait_ref).clone())) } ItemImpl(unsafety, polarity, generics, ifce, ty, impl_items) => { - let new_impl_items = impl_items.into_iter().flat_map(|item| { - folder.fold_impl_item(item).into_iter() - }).collect(); + let new_impl_items = impl_items.into_iter() + .flat_map(|item| { + folder.fold_impl_item(item).into_iter() + }) + .collect(); let ifce = match ifce { None => None, Some(ref trait_ref) => { @@ -820,81 +836,84 @@ pub fn noop_fold_item_underscore(i: Item_, folder: &mut T) -> Item_ { } ItemTrait(unsafety, generics, bounds, items) => { let bounds = folder.fold_bounds(bounds); - let items = items.into_iter().flat_map(|item| { - folder.fold_trait_item(item).into_iter() - }).collect(); - ItemTrait(unsafety, - folder.fold_generics(generics), - bounds, - items) + let items = items.into_iter() + .flat_map(|item| folder.fold_trait_item(item).into_iter()) + .collect(); + ItemTrait(unsafety, folder.fold_generics(generics), bounds, items) } } } -pub fn noop_fold_trait_item(i: P, folder: &mut T) +pub fn noop_fold_trait_item(i: P, + folder: &mut T) -> SmallVector> { - SmallVector::one(i.map(|TraitItem {id, ident, attrs, node, span}| TraitItem { - id: folder.new_id(id), - ident: folder.fold_ident(ident), - attrs: fold_attrs(attrs, folder), - node: match node { - ConstTraitItem(ty, default) => { - ConstTraitItem(folder.fold_ty(ty), - default.map(|x| folder.fold_expr(x))) - } - MethodTraitItem(sig, body) => { - MethodTraitItem(noop_fold_method_sig(sig, folder), - body.map(|x| folder.fold_block(x))) - } - TypeTraitItem(bounds, default) => { - TypeTraitItem(folder.fold_bounds(bounds), - default.map(|x| folder.fold_ty(x))) - } - }, - span: folder.new_span(span) + SmallVector::one(i.map(|TraitItem { id, name, attrs, node, span }| { + TraitItem { + id: folder.new_id(id), + name: folder.fold_name(name), + attrs: fold_attrs(attrs, folder), + node: match node { + ConstTraitItem(ty, default) => { + ConstTraitItem(folder.fold_ty(ty), + default.map(|x| folder.fold_expr(x))) + } + MethodTraitItem(sig, body) => { + MethodTraitItem(noop_fold_method_sig(sig, folder), + body.map(|x| folder.fold_block(x))) + } + TypeTraitItem(bounds, default) => { + TypeTraitItem(folder.fold_bounds(bounds), + default.map(|x| folder.fold_ty(x))) + } + }, + span: folder.new_span(span), + } })) } -pub fn noop_fold_impl_item(i: P, folder: &mut T) - -> SmallVector> { - SmallVector::one(i.map(|ImplItem {id, ident, attrs, node, vis, span}| ImplItem { - id: folder.new_id(id), - ident: folder.fold_ident(ident), - attrs: fold_attrs(attrs, folder), - vis: vis, - node: match node { - ConstImplItem(ty, expr) => { - ConstImplItem(folder.fold_ty(ty), folder.fold_expr(expr)) - } - MethodImplItem(sig, body) => { - MethodImplItem(noop_fold_method_sig(sig, folder), - folder.fold_block(body)) - } - TypeImplItem(ty) => TypeImplItem(folder.fold_ty(ty)), - }, - span: folder.new_span(span) +pub fn noop_fold_impl_item(i: P, folder: &mut T) -> SmallVector> { + SmallVector::one(i.map(|ImplItem { id, name, attrs, node, vis, span }| { + ImplItem { + id: folder.new_id(id), + name: folder.fold_name(name), + attrs: fold_attrs(attrs, folder), + vis: vis, + node: match node { + ConstImplItem(ty, expr) => { + ConstImplItem(folder.fold_ty(ty), folder.fold_expr(expr)) + } + MethodImplItem(sig, body) => { + MethodImplItem(noop_fold_method_sig(sig, folder), + folder.fold_block(body)) + } + TypeImplItem(ty) => TypeImplItem(folder.fold_ty(ty)), + }, + span: folder.new_span(span), + } })) } -pub fn noop_fold_mod(Mod {inner, items}: Mod, folder: &mut T) -> Mod { +pub fn noop_fold_mod(Mod { inner, items }: Mod, folder: &mut T) -> Mod { Mod { inner: folder.new_span(inner), items: items.into_iter().flat_map(|x| folder.fold_item(x).into_iter()).collect(), } } -pub fn noop_fold_crate(Crate {module, attrs, config, span, exported_macros}: Crate, - folder: &mut T) -> Crate { +pub fn noop_fold_crate(Crate { module, attrs, config, span, exported_macros }: Crate, + folder: &mut T) + -> Crate { let config = folder.fold_meta_items(config); let mut items = folder.fold_item(P(hir::Item { - ident: token::special_idents::invalid, - attrs: attrs, - id: DUMMY_NODE_ID, - vis: hir::Public, - span: span, - node: hir::ItemMod(module), - })).into_iter(); + name: token::special_idents::invalid.name, + attrs: attrs, + id: DUMMY_NODE_ID, + vis: hir::Public, + span: span, + node: hir::ItemMod(module), + })) + .into_iter(); let (module, attrs, span) = match items.next() { Some(item) => { @@ -910,7 +929,9 @@ pub fn noop_fold_crate(Crate {module, attrs, config, span, exported_m None => (hir::Mod { inner: span, items: vec![], - }, vec![], span) + }, + vec![], + span), }; Crate { @@ -928,8 +949,9 @@ pub fn noop_fold_item(i: P, folder: &mut T) -> SmallVector(Item {id, ident, attrs, node, vis, span}: Item, - folder: &mut T) -> Item { +pub fn noop_fold_item_simple(Item { id, name, attrs, node, vis, span }: Item, + folder: &mut T) + -> Item { let id = folder.new_id(id); let node = folder.fold_item_underscore(node); // FIXME: we should update the impl_pretty_name, but it uses pretty printing. @@ -943,29 +965,32 @@ pub fn noop_fold_item_simple(Item {id, ident, attrs, node, vis, span} Item { id: id, - ident: folder.fold_ident(ident), + name: folder.fold_name(name), attrs: fold_attrs(attrs, folder), node: node, vis: vis, - span: folder.new_span(span) + span: folder.new_span(span), } } pub fn noop_fold_foreign_item(ni: P, folder: &mut T) -> P { - ni.map(|ForeignItem {id, ident, attrs, node, span, vis}| ForeignItem { - id: folder.new_id(id), - ident: folder.fold_ident(ident), - attrs: fold_attrs(attrs, folder), - node: match node { - ForeignItemFn(fdec, generics) => { - ForeignItemFn(folder.fold_fn_decl(fdec), folder.fold_generics(generics)) - } - ForeignItemStatic(t, m) => { - ForeignItemStatic(folder.fold_ty(t), m) - } - }, - vis: vis, - span: folder.new_span(span) + ni.map(|ForeignItem { id, name, attrs, node, span, vis }| { + ForeignItem { + id: folder.new_id(id), + name: folder.fold_name(name), + attrs: fold_attrs(attrs, folder), + node: match node { + ForeignItemFn(fdec, generics) => { + ForeignItemFn(folder.fold_fn_decl(fdec), + folder.fold_generics(generics)) + } + ForeignItemStatic(t, m) => { + ForeignItemStatic(folder.fold_ty(t), m) + } + }, + vis: vis, + span: folder.new_span(span), + } }) } @@ -976,64 +1001,70 @@ pub fn noop_fold_method_sig(sig: MethodSig, folder: &mut T) -> Method explicit_self: folder.fold_explicit_self(sig.explicit_self), unsafety: sig.unsafety, constness: sig.constness, - decl: folder.fold_fn_decl(sig.decl) + decl: folder.fold_fn_decl(sig.decl), } } pub fn noop_fold_pat(p: P, folder: &mut T) -> P { - p.map(|Pat {id, node, span}| Pat { - id: folder.new_id(id), - node: match node { - PatWild(k) => PatWild(k), - PatIdent(binding_mode, pth1, sub) => { - PatIdent(binding_mode, - Spanned{span: folder.new_span(pth1.span), - node: folder.fold_ident(pth1.node)}, - sub.map(|x| folder.fold_pat(x))) - } - PatLit(e) => PatLit(folder.fold_expr(e)), - PatEnum(pth, pats) => { - PatEnum(folder.fold_path(pth), - pats.map(|pats| pats.move_map(|x| folder.fold_pat(x)))) - } - PatQPath(qself, pth) => { - let qself = QSelf {ty: folder.fold_ty(qself.ty), .. qself}; - PatQPath(qself, folder.fold_path(pth)) - } - PatStruct(pth, fields, etc) => { - let pth = folder.fold_path(pth); - let fs = fields.move_map(|f| { - Spanned { span: folder.new_span(f.span), - node: hir::FieldPat { - ident: f.node.ident, - pat: folder.fold_pat(f.node.pat), - is_shorthand: f.node.is_shorthand, - }} - }); - PatStruct(pth, fs, etc) - } - PatTup(elts) => PatTup(elts.move_map(|x| folder.fold_pat(x))), - PatBox(inner) => PatBox(folder.fold_pat(inner)), - PatRegion(inner, mutbl) => PatRegion(folder.fold_pat(inner), mutbl), - PatRange(e1, e2) => { - PatRange(folder.fold_expr(e1), folder.fold_expr(e2)) + p.map(|Pat { id, node, span }| { + Pat { + id: folder.new_id(id), + node: match node { + PatWild(k) => PatWild(k), + PatIdent(binding_mode, pth1, sub) => { + PatIdent(binding_mode, + Spanned { + span: folder.new_span(pth1.span), + node: folder.fold_ident(pth1.node), + }, + sub.map(|x| folder.fold_pat(x))) + } + PatLit(e) => PatLit(folder.fold_expr(e)), + PatEnum(pth, pats) => { + PatEnum(folder.fold_path(pth), + pats.map(|pats| pats.move_map(|x| folder.fold_pat(x)))) + } + PatQPath(qself, pth) => { + let qself = QSelf { ty: folder.fold_ty(qself.ty), ..qself }; + PatQPath(qself, folder.fold_path(pth)) + } + PatStruct(pth, fields, etc) => { + let pth = folder.fold_path(pth); + let fs = fields.move_map(|f| { + Spanned { + span: folder.new_span(f.span), + node: hir::FieldPat { + name: f.node.name, + pat: folder.fold_pat(f.node.pat), + is_shorthand: f.node.is_shorthand, + }, + } + }); + PatStruct(pth, fs, etc) + } + PatTup(elts) => PatTup(elts.move_map(|x| folder.fold_pat(x))), + PatBox(inner) => PatBox(folder.fold_pat(inner)), + PatRegion(inner, mutbl) => PatRegion(folder.fold_pat(inner), mutbl), + PatRange(e1, e2) => { + PatRange(folder.fold_expr(e1), folder.fold_expr(e2)) + } + PatVec(before, slice, after) => { + PatVec(before.move_map(|x| folder.fold_pat(x)), + slice.map(|x| folder.fold_pat(x)), + after.move_map(|x| folder.fold_pat(x))) + } }, - PatVec(before, slice, after) => { - PatVec(before.move_map(|x| folder.fold_pat(x)), - slice.map(|x| folder.fold_pat(x)), - after.move_map(|x| folder.fold_pat(x))) - } - }, - span: folder.new_span(span) + span: folder.new_span(span), + } }) } -pub fn noop_fold_expr(Expr {id, node, span}: Expr, folder: &mut T) -> Expr { +pub fn noop_fold_expr(Expr { id, node, span }: Expr, folder: &mut T) -> Expr { Expr { id: folder.new_id(id), node: match node { - ExprBox(p, e) => { - ExprBox(p.map(|e|folder.fold_expr(e)), folder.fold_expr(e)) + ExprBox(e) => { + ExprBox(folder.fold_expr(e)) } ExprVec(exprs) => { ExprVec(exprs.move_map(|x| folder.fold_expr(x))) @@ -1046,16 +1077,14 @@ pub fn noop_fold_expr(Expr {id, node, span}: Expr, folder: &mut T) -> ExprCall(folder.fold_expr(f), args.move_map(|x| folder.fold_expr(x))) } - ExprMethodCall(i, tps, args) => { - ExprMethodCall( - respan(folder.new_span(i.span), folder.fold_ident(i.node)), - tps.move_map(|x| folder.fold_ty(x)), - args.move_map(|x| folder.fold_expr(x))) + ExprMethodCall(name, tps, args) => { + ExprMethodCall(respan(folder.new_span(name.span), + folder.fold_name(name.node)), + tps.move_map(|x| folder.fold_ty(x)), + args.move_map(|x| folder.fold_expr(x))) } ExprBinary(binop, lhs, rhs) => { - ExprBinary(binop, - folder.fold_expr(lhs), - folder.fold_expr(rhs)) + ExprBinary(binop, folder.fold_expr(lhs), folder.fold_expr(rhs)) } ExprUnary(binop, ohs) => { ExprUnary(binop, folder.fold_expr(ohs)) @@ -1077,12 +1106,12 @@ pub fn noop_fold_expr(Expr {id, node, span}: Expr, folder: &mut T) -> } ExprLoop(body, opt_ident) => { ExprLoop(folder.fold_block(body), - opt_ident.map(|i| folder.fold_ident(i))) + opt_ident.map(|i| folder.fold_ident(i))) } ExprMatch(expr, arms, source) => { ExprMatch(folder.fold_expr(expr), - arms.move_map(|x| folder.fold_arm(x)), - source) + arms.move_map(|x| folder.fold_arm(x)), + source) } ExprClosure(capture_clause, decl, body) => { ExprClosure(capture_clause, @@ -1094,19 +1123,17 @@ pub fn noop_fold_expr(Expr {id, node, span}: Expr, folder: &mut T) -> ExprAssign(folder.fold_expr(el), folder.fold_expr(er)) } ExprAssignOp(op, el, er) => { - ExprAssignOp(op, - folder.fold_expr(el), - folder.fold_expr(er)) + ExprAssignOp(op, folder.fold_expr(el), folder.fold_expr(er)) } - ExprField(el, ident) => { + ExprField(el, name) => { ExprField(folder.fold_expr(el), - respan(folder.new_span(ident.span), - folder.fold_ident(ident.node))) + respan(folder.new_span(name.span), + folder.fold_name(name.node))) } - ExprTupField(el, ident) => { + ExprTupField(el, index) => { ExprTupField(folder.fold_expr(el), - respan(folder.new_span(ident.span), - folder.fold_usize(ident.node))) + respan(folder.new_span(index.span), + folder.fold_usize(index.node))) } ExprIndex(el, er) => { ExprIndex(folder.fold_expr(el), folder.fold_expr(er)) @@ -1119,19 +1146,19 @@ pub fn noop_fold_expr(Expr {id, node, span}: Expr, folder: &mut T) -> let qself = qself.map(|QSelf { ty, position }| { QSelf { ty: folder.fold_ty(ty), - position: position + position: position, } }); ExprPath(qself, folder.fold_path(path)) } - ExprBreak(opt_ident) => ExprBreak(opt_ident.map(|label| + ExprBreak(opt_ident) => ExprBreak(opt_ident.map(|label| { respan(folder.new_span(label.span), - folder.fold_ident(label.node))) - ), - ExprAgain(opt_ident) => ExprAgain(opt_ident.map(|label| + folder.fold_ident(label.node)) + })), + ExprAgain(opt_ident) => ExprAgain(opt_ident.map(|label| { respan(folder.new_span(label.span), - folder.fold_ident(label.node))) - ), + folder.fold_ident(label.node)) + })), ExprRet(e) => ExprRet(e.map(|x| folder.fold_expr(x))), ExprInlineAsm(InlineAsm { inputs, @@ -1144,12 +1171,8 @@ pub fn noop_fold_expr(Expr {id, node, span}: Expr, folder: &mut T) -> dialect, expn_id, }) => ExprInlineAsm(InlineAsm { - inputs: inputs.move_map(|(c, input)| { - (c, folder.fold_expr(input)) - }), - outputs: outputs.move_map(|(c, out, is_rw)| { - (c, folder.fold_expr(out), is_rw) - }), + inputs: inputs.move_map(|(c, input)| (c, folder.fold_expr(input))), + outputs: outputs.move_map(|(c, out, is_rw)| (c, folder.fold_expr(out), is_rw)), asm: asm, asm_str_style: asm_str_style, clobbers: clobbers, @@ -1160,38 +1183,43 @@ pub fn noop_fold_expr(Expr {id, node, span}: Expr, folder: &mut T) -> }), ExprStruct(path, fields, maybe_expr) => { ExprStruct(folder.fold_path(path), - fields.move_map(|x| folder.fold_field(x)), - maybe_expr.map(|x| folder.fold_expr(x))) - }, - ExprParen(ex) => ExprParen(folder.fold_expr(ex)) + fields.move_map(|x| folder.fold_field(x)), + maybe_expr.map(|x| folder.fold_expr(x))) + } }, - span: folder.new_span(span) + span: folder.new_span(span), } } -pub fn noop_fold_stmt(Spanned {node, span}: Stmt, folder: &mut T) +pub fn noop_fold_stmt(Spanned { node, span }: Stmt, + folder: &mut T) -> SmallVector> { let span = folder.new_span(span); match node { StmtDecl(d, id) => { let id = folder.new_id(id); - folder.fold_decl(d).into_iter().map(|d| P(Spanned { - node: StmtDecl(d, id), - span: span - })).collect() + folder.fold_decl(d) + .into_iter() + .map(|d| { + P(Spanned { + node: StmtDecl(d, id), + span: span, + }) + }) + .collect() } StmtExpr(e, id) => { let id = folder.new_id(id); SmallVector::one(P(Spanned { node: StmtExpr(folder.fold_expr(e), id), - span: span + span: span, })) } StmtSemi(e, id) => { let id = folder.new_id(id); SmallVector::one(P(Spanned { node: StmtSemi(folder.fold_expr(e), id), - span: span + span: span, })) } } diff --git a/src/librustc_front/hir.rs b/src/librustc_front/hir.rs index f8f1761731..079bf677c8 100644 --- a/src/librustc_front/hir.rs +++ b/src/librustc_front/hir.rs @@ -10,8 +10,6 @@ // The Rust HIR. -pub use self::AsmDialect::*; -pub use self::AttrStyle::*; pub use self::BindingMode::*; pub use self::BinOp_::*; pub use self::BlockCheckMode::*; @@ -19,38 +17,30 @@ pub use self::CaptureClause::*; pub use self::Decl_::*; pub use self::ExplicitSelf_::*; pub use self::Expr_::*; -pub use self::FloatTy::*; pub use self::FunctionRetTy::*; pub use self::ForeignItem_::*; pub use self::ImplItem_::*; -pub use self::IntTy::*; pub use self::Item_::*; -pub use self::Lit_::*; -pub use self::LitIntType::*; -pub use self::MetaItem_::*; pub use self::Mutability::*; pub use self::Pat_::*; pub use self::PathListItem_::*; pub use self::PatWildKind::*; pub use self::PrimTy::*; -pub use self::Sign::*; pub use self::Stmt_::*; -pub use self::StrStyle::*; pub use self::StructFieldKind::*; pub use self::TraitItem_::*; pub use self::Ty_::*; pub use self::TyParamBound::*; -pub use self::UintTy::*; pub use self::UnOp::*; pub use self::UnsafeSource::*; -pub use self::VariantKind::*; pub use self::ViewPath_::*; pub use self::Visibility::*; pub use self::PathParameters::*; use syntax::codemap::{self, Span, Spanned, DUMMY_SP, ExpnId}; use syntax::abi::Abi; -use syntax::ast::{Name, Ident, NodeId, DUMMY_NODE_ID, TokenTree}; +use syntax::ast::{Name, Ident, NodeId, DUMMY_NODE_ID, TokenTree, AsmDialect}; +use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, CrateConfig}; use syntax::owned_slice::OwnedSlice; use syntax::parse::token::InternedString; use syntax::ptr::P; @@ -59,23 +49,21 @@ use print::pprust; use util; use std::fmt; -use std::rc::Rc; use serialize::{Encodable, Encoder, Decoder}; - -/// Function name (not all functions have names) -pub type FnIdent = Option; - #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)] pub struct Lifetime { pub id: NodeId, pub span: Span, - pub name: Name + pub name: Name, } impl fmt::Debug for Lifetime { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "lifetime({}: {})", self.id, pprust::lifetime_to_string(self)) + write!(f, + "lifetime({}: {})", + self.id, + pprust::lifetime_to_string(self)) } } @@ -83,7 +71,7 @@ impl fmt::Debug for Lifetime { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct LifetimeDef { pub lifetime: Lifetime, - pub bounds: Vec + pub bounds: Vec, } /// A "Path" is essentially Rust's notion of a name; for instance: @@ -175,7 +163,8 @@ impl PathParameters { data.types.iter().collect() } ParenthesizedParameters(ref data) => { - data.inputs.iter() + data.inputs + .iter() .chain(data.output.iter()) .collect() } @@ -243,7 +232,7 @@ pub struct ParenthesizedParameterData { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum TyParamBound { TraitTyParamBound(PolyTraitRef, TraitBoundModifier), - RegionTyParamBound(Lifetime) + RegionTyParamBound(Lifetime), } /// A modifier on a bound, currently this is only used for `?Sized`, where the @@ -258,11 +247,11 @@ pub type TyParamBounds = OwnedSlice; #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct TyParam { - pub ident: Ident, + pub name: Name, pub id: NodeId, pub bounds: TyParamBounds, pub default: Option>, - pub span: Span + pub span: Span, } /// Represents lifetimes and type parameters attached to a declaration @@ -301,7 +290,7 @@ pub enum WherePredicate { /// A lifetime predicate, e.g. `'a: 'b+'c` RegionPredicate(WhereRegionPredicate), /// An equality predicate (unsupported) - EqPredicate(WhereEqPredicate) + EqPredicate(WhereEqPredicate), } /// A type bound, eg `for<'c> Foo: Send+Clone+'c` @@ -333,10 +322,6 @@ pub struct WhereEqPredicate { pub ty: P, } -/// The set of MetaItems that define the compilation environment of the crate, -/// used to drive conditional compilation -pub type CrateConfig = Vec> ; - #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct Crate { pub module: Mod, @@ -351,51 +336,17 @@ pub struct Crate { /// Not parsed directly, but created on macro import or `macro_rules!` expansion. #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct MacroDef { - pub ident: Ident, + pub name: Name, pub attrs: Vec, pub id: NodeId, pub span: Span, - pub imported_from: Option, + pub imported_from: Option, pub export: bool, pub use_locally: bool, pub allow_internal_unstable: bool, pub body: Vec, } -pub type MetaItem = Spanned; - -#[derive(Clone, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub enum MetaItem_ { - MetaWord(InternedString), - MetaList(InternedString, Vec>), - MetaNameValue(InternedString, Lit), -} - -// can't be derived because the MetaList requires an unordered comparison -impl PartialEq for MetaItem_ { - fn eq(&self, other: &MetaItem_) -> bool { - match *self { - MetaWord(ref ns) => match *other { - MetaWord(ref no) => (*ns) == (*no), - _ => false - }, - MetaNameValue(ref ns, ref vs) => match *other { - MetaNameValue(ref no, ref vo) => { - (*ns) == (*no) && vs.node == vo.node - } - _ => false - }, - MetaList(ref ns, ref miss) => match *other { - MetaList(ref no, ref miso) => { - ns == no && - miss.iter().all(|mi| miso.iter().any(|x| x.node == mi.node)) - } - _ => false - } - } - } -} - #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct Block { /// Statements in a block @@ -430,7 +381,7 @@ impl fmt::Debug for Pat { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct FieldPat { /// The identifier for the field - pub ident: Ident, + pub name: Name, /// The pattern the field is destructured to pub pat: P, pub is_shorthand: bool, @@ -464,7 +415,7 @@ pub enum Pat_ { /// which it is. The resolver determines this, and /// records this pattern's NodeId in an auxiliary /// set (of "PatIdents that refer to nullary enums") - PatIdent(BindingMode, SpannedIdent, Option>), + PatIdent(BindingMode, Spanned, Option>), /// "None" means a * pattern where we don't bind the fields to names. PatEnum(Path, Option>>), @@ -543,14 +494,12 @@ pub type BinOp = Spanned; #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] pub enum UnOp { - /// The `box` operator - UnUniq, /// The `*` operator for dereferencing UnDeref, /// The `!` operator for logical inversion UnNot, /// The `-` operator for negation - UnNeg + UnNeg, } /// A statement @@ -560,7 +509,8 @@ impl fmt::Debug for Stmt_ { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // Sadness. let spanned = codemap::dummy_spanned(self.clone()); - write!(f, "stmt({}: {})", + write!(f, + "stmt({}: {})", util::stmt_id(&spanned), pprust::stmt_to_string(&spanned)) } @@ -612,19 +562,20 @@ pub struct Arm { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct Field { - pub ident: SpannedIdent, + pub name: Spanned, pub expr: P, pub span: Span, } -pub type SpannedIdent = Spanned; - #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] pub enum BlockCheckMode { DefaultBlock, UnsafeBlock(UnsafeSource), PushUnsafeBlock(UnsafeSource), PopUnsafeBlock(UnsafeSource), + // Within this block (but outside a PopUnstableBlock), we suspend checking of stability. + PushUnstableBlock, + PopUnstableBlock, } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] @@ -634,7 +585,7 @@ pub enum UnsafeSource { } /// An expression -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash,)] +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)] pub struct Expr { pub id: NodeId, pub node: Expr_, @@ -649,8 +600,8 @@ impl fmt::Debug for Expr { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum Expr_ { - /// First expr is the place; second expr is the value. - ExprBox(Option>, P), + /// A `box x` expression. + ExprBox(P), /// An array (`[a, b, c, d]`) ExprVec(Vec>), /// A function call @@ -660,7 +611,7 @@ pub enum Expr_ { ExprCall(P, Vec>), /// A method call (`x.foo::(a, b, c, d)`) /// - /// The `SpannedIdent` is the identifier for the method name. + /// The `Spanned` is the identifier for the method name. /// The vector of `Ty`s are the ascripted type parameters for the method /// (within the angle brackets). /// @@ -670,7 +621,7 @@ pub enum Expr_ { /// /// Thus, `x.foo::(a, b, c, d)` is represented as /// `ExprMethodCall(foo, [Bar, Baz], [x, a, b, c, d])`. - ExprMethodCall(SpannedIdent, Vec>, Vec>), + ExprMethodCall(Spanned, Vec>, Vec>), /// A tuple (`(a, b, c ,d)`) ExprTup(Vec>), /// A binary operation (For example: `a + b`, `a * b`) @@ -685,7 +636,6 @@ pub enum Expr_ { /// /// `if expr { block } else { expr }` ExprIf(P, P, Option>), - // FIXME #6993: change to Option ... or not, if these are hygienic. /// A while loop, with an optional label /// /// `'label: while expr { block }` @@ -693,7 +643,6 @@ pub enum Expr_ { /// Conditionless loop (can be exited with break, continue, or return) /// /// `'label: loop { block }` - // FIXME #6993: change to Option ... or not, if these are hygienic. ExprLoop(P, Option), /// A `match` block, with a source that indicates whether or not it is /// the result of a desugaring, and if so, which kind. @@ -710,7 +659,7 @@ pub enum Expr_ { /// For example, `a += 1`. ExprAssignOp(BinOp, P, P), /// Access of a named struct field (`obj.foo`) - ExprField(P, SpannedIdent), + ExprField(P, Spanned), /// Access of an unnamed field of a struct or tuple-struct /// /// For example, `foo.0`. @@ -730,9 +679,9 @@ pub enum Expr_ { /// A referencing operation (`&a` or `&mut a`) ExprAddrOf(Mutability, P), /// A `break`, with an optional label to break - ExprBreak(Option), + ExprBreak(Option>), /// A `continue`, with an optional label - ExprAgain(Option), + ExprAgain(Option>), /// A `return`, with an optional value to be returned ExprRet(Option>), @@ -750,9 +699,6 @@ pub enum Expr_ { /// For example, `[1u8; 5]`. The first expression is the element /// to be repeated; the second is the number of times to repeat it. ExprRepeat(P, P), - - /// No-op: used solely so we can pretty-print faithfully - ExprParen(P) } /// The explicit Self type in a "qualified path". The actual @@ -770,13 +716,15 @@ pub enum Expr_ { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct QSelf { pub ty: P, - pub position: usize + pub position: usize, } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] pub enum MatchSource { Normal, - IfLetDesugar { contains_else_clause: bool }, + IfLetDesugar { + contains_else_clause: bool, + }, WhileLetDesugar, ForLoopDesugar, } @@ -787,72 +735,6 @@ pub enum CaptureClause { CaptureByRef, } - -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] -pub enum StrStyle { - /// A regular string, like `"foo"` - CookedStr, - /// A raw string, like `r##"foo"##` - /// - /// The uint is the number of `#` symbols used - RawStr(usize) -} - -/// A literal -pub type Lit = Spanned; - -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] -pub enum Sign { - Minus, - Plus -} - -impl Sign { - pub fn new(n: T) -> Sign { - n.sign() - } -} - -pub trait IntSign { - fn sign(&self) -> Sign; -} -macro_rules! doit { - ($($t:ident)*) => ($(impl IntSign for $t { - #[allow(unused_comparisons)] - fn sign(&self) -> Sign { - if *self < 0 {Minus} else {Plus} - } - })*) -} -doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } - -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] -pub enum LitIntType { - SignedIntLit(IntTy, Sign), - UnsignedIntLit(UintTy), - UnsuffixedIntLit(Sign) -} - -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub enum Lit_ { - /// A string literal (`"foo"`) - LitStr(InternedString, StrStyle), - /// A byte string (`b"foo"`) - LitByteStr(Rc>), - /// A byte char (`b'f'`) - LitByte(u8), - /// A character literal (`'a'`) - LitChar(char), - /// An integer literal (`1u8`) - LitInt(u64, LitIntType), - /// A float literal (`1f64` or `1E10f64`) - LitFloat(InternedString, FloatTy), - /// A float literal without a suffix (`1.0 or 1.0E10`) - LitFloatUnsuffixed(InternedString), - /// A boolean literal - LitBool(bool), -} - // NB: If you change this, you'll probably want to change the corresponding // type structure in middle/ty.rs as well. #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] @@ -861,13 +743,6 @@ pub struct MutTy { pub mutbl: Mutability, } -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub struct TypeField { - pub ident: Ident, - pub mt: MutTy, - pub span: Span, -} - /// Represents a method's signature in a trait declaration, /// or in an implementation. #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] @@ -887,7 +762,7 @@ pub struct MethodSig { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct TraitItem { pub id: NodeId, - pub ident: Ident, + pub name: Name, pub attrs: Vec, pub node: TraitItem_, pub span: Span, @@ -903,7 +778,7 @@ pub enum TraitItem_ { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct ImplItem { pub id: NodeId, - pub ident: Ident, + pub name: Name, pub vis: Visibility, pub attrs: Vec, pub node: ImplItem_, @@ -917,104 +792,11 @@ pub enum ImplItem_ { TypeImplItem(P), } -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)] -pub enum IntTy { - TyIs, - TyI8, - TyI16, - TyI32, - TyI64, -} - -impl fmt::Debug for IntTy { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(self, f) - } -} - -impl fmt::Display for IntTy { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", util::int_ty_to_string(*self, None)) - } -} - -impl IntTy { - pub fn bit_width(&self) -> Option { - Some(match *self { - TyIs => return None, - TyI8 => 8, - TyI16 => 16, - TyI32 => 32, - TyI64 => 64, - }) - } -} - -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)] -pub enum UintTy { - TyUs, - TyU8, - TyU16, - TyU32, - TyU64, -} - -impl UintTy { - pub fn bit_width(&self) -> Option { - Some(match *self { - TyUs => return None, - TyU8 => 8, - TyU16 => 16, - TyU32 => 32, - TyU64 => 64, - }) - } -} - -impl fmt::Debug for UintTy { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(self, f) - } -} - -impl fmt::Display for UintTy { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", util::uint_ty_to_string(*self, None)) - } -} - -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)] -pub enum FloatTy { - TyF32, - TyF64, -} - -impl fmt::Debug for FloatTy { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(self, f) - } -} - -impl fmt::Display for FloatTy { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", util::float_ty_to_string(*self)) - } -} - -impl FloatTy { - pub fn bit_width(&self) -> usize { - match *self { - TyF32 => 32, - TyF64 => 64, - } - } -} - // Bind a type to an associated type: `A=Foo`. #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct TypeBinding { pub id: NodeId, - pub ident: Ident, + pub name: Name, pub ty: P, pub span: Span, } @@ -1042,7 +824,7 @@ pub enum PrimTy { TyFloat(FloatTy), TyStr, TyBool, - TyChar + TyChar, } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] @@ -1050,7 +832,7 @@ pub struct BareFnTy { pub unsafety: Unsafety, pub abi: Abi, pub lifetimes: Vec, - pub decl: P + pub decl: P, } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] @@ -1066,7 +848,7 @@ pub enum Ty_ { /// A bare function (e.g. `fn(usize) -> bool`) TyBareFn(P), /// A tuple (`(A, B, C, D,...)`) - TyTup(Vec> ), + TyTup(Vec>), /// A path (`module::module::...::Type`), optionally /// "qualified", e.g. ` as SomeTrait>::SomeType`. /// @@ -1085,12 +867,6 @@ pub enum Ty_ { TyInfer, } -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] -pub enum AsmDialect { - AsmAtt, - AsmIntel -} - #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct InlineAsm { pub asm: InternedString, @@ -1114,7 +890,10 @@ pub struct Arg { impl Arg { pub fn new_self(span: Span, mutability: Mutability, self_ident: Ident) -> Arg { - let path = Spanned{span:span,node:self_ident}; + let path = Spanned { + span: span, + node: self_ident, + }; Arg { // HACK(eddyb) fake type for the self argument. ty: P(Ty { @@ -1125,9 +904,9 @@ impl Arg { pat: P(Pat { id: DUMMY_NODE_ID, node: PatIdent(BindByValue(mutability), path, None), - span: span + span: span, }), - id: DUMMY_NODE_ID + id: DUMMY_NODE_ID, } } } @@ -1137,7 +916,7 @@ impl Arg { pub struct FnDecl { pub inputs: Vec, pub output: FunctionRetTy, - pub variadic: bool + pub variadic: bool, } #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] @@ -1155,9 +934,10 @@ pub enum Constness { impl fmt::Display for Unsafety { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(match *self { - Unsafety::Normal => "normal", - Unsafety::Unsafe => "unsafe", - }, f) + Unsafety::Normal => "normal", + Unsafety::Unsafe => "unsafe", + }, + f) } } @@ -1199,7 +979,7 @@ impl FunctionRetTy { match *self { NoReturn(span) => span, DefaultReturn(span) => span, - Return(ref ty) => ty.span + Return(ref ty) => ty.span, } } } @@ -1210,11 +990,11 @@ pub enum ExplicitSelf_ { /// No self SelfStatic, /// `self` - SelfValue(Ident), + SelfValue(Name), /// `&'lt self`, `&'lt mut self` - SelfRegion(Option, Mutability, Ident), + SelfRegion(Option, Mutability, Name), /// `self: TYPE` - SelfExplicit(P, Ident), + SelfExplicit(P, Name), } pub type ExplicitSelf = Spanned; @@ -1234,20 +1014,6 @@ pub struct ForeignMod { pub items: Vec>, } -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub struct VariantArg { - pub ty: P, - pub id: NodeId, -} - -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub enum VariantKind { - /// Tuple variant, e.g. `Foo(A, B)` - TupleVariantKind(Vec), - /// Struct variant, e.g. `Foo {x: A, y: B}` - StructVariantKind(P), -} - #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct EnumDef { pub variants: Vec>, @@ -1255,13 +1021,11 @@ pub struct EnumDef { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct Variant_ { - pub name: Ident, + pub name: Name, pub attrs: Vec, - pub kind: VariantKind, - pub id: NodeId, + pub data: VariantData, /// Explicit discriminant, eg `Foo = 1` pub disr_expr: Option>, - pub vis: Visibility, } pub type Variant = Spanned; @@ -1269,28 +1033,35 @@ pub type Variant = Spanned; #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] pub enum PathListItem_ { PathListIdent { - name: Ident, + name: Name, /// renamed in list, eg `use foo::{bar as baz};` - rename: Option, - id: NodeId + rename: Option, + id: NodeId, }, PathListMod { /// renamed in list, eg `use foo::{self as baz};` - rename: Option, - id: NodeId - } + rename: Option, + id: NodeId, + }, } impl PathListItem_ { pub fn id(&self) -> NodeId { match *self { - PathListIdent { id, .. } | PathListMod { id, .. } => id + PathListIdent { id, .. } | PathListMod { id, .. } => id, + } + } + + pub fn name(&self) -> Option { + match *self { + PathListIdent { name, .. } => Some(name), + PathListMod { .. } => None, } } - pub fn rename(&self) -> Option { + pub fn rename(&self) -> Option { match *self { - PathListIdent { rename, .. } | PathListMod { rename, .. } => rename + PathListIdent { rename, .. } | PathListMod { rename, .. } => rename, } } } @@ -1307,37 +1078,13 @@ pub enum ViewPath_ { /// or just /// /// `foo::bar::baz` (with `as baz` implicitly on the right) - ViewPathSimple(Ident, Path), + ViewPathSimple(Name, Path), /// `foo::bar::*` ViewPathGlob(Path), /// `foo::bar::{a,b,c}` - ViewPathList(Path, Vec) -} - -/// Meta-data associated with an item -pub type Attribute = Spanned; - -/// Distinguishes between Attributes that decorate items and Attributes that -/// are contained as statements within items. These two cases need to be -/// distinguished for pretty-printing. -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] -pub enum AttrStyle { - AttrOuter, - AttrInner, -} - -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] -pub struct AttrId(pub usize); - -/// Doc-comments are promoted to attributes that have is_sugared_doc = true -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub struct Attribute_ { - pub id: AttrId, - pub style: AttrStyle, - pub value: P, - pub is_sugared_doc: bool, + ViewPathList(Path, Vec), } /// TraitRef's appear in impls. @@ -1373,7 +1120,7 @@ impl Visibility { pub fn inherit_from(&self, parent_visibility: Visibility) -> Visibility { match self { &Inherited => parent_visibility, - &Public => *self + &Public => *self, } } } @@ -1387,10 +1134,10 @@ pub struct StructField_ { } impl StructField_ { - pub fn ident(&self) -> Option { + pub fn name(&self) -> Option { match self.kind { - NamedField(ref ident, _) => Some(ident.clone()), - UnnamedField(_) => None + NamedField(name, _) => Some(name), + UnnamedField(_) => None, } } } @@ -1399,7 +1146,7 @@ pub type StructField = Spanned; #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] pub enum StructFieldKind { - NamedField(Ident, Visibility), + NamedField(Name, Visibility), /// Element of a tuple-like struct UnnamedField(Visibility), } @@ -1413,13 +1160,45 @@ impl StructFieldKind { } } +/// Fields and Ids of enum variants and structs +/// +/// For enum variants: `NodeId` represents both an Id of the variant itself (relevant for all +/// variant kinds) and an Id of the variant's constructor (not relevant for `Struct`-variants). +/// One shared Id can be successfully used for these two purposes. +/// Id of the whole enum lives in `Item`. +/// +/// For structs: `NodeId` represents an Id of the structure's constructor, so it is not actually +/// used for `Struct`-structs (but still presents). Structures don't have an analogue of "Id of +/// the variant itself" from enum variants. +/// Id of the whole struct lives in `Item`. #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub struct StructDef { - /// Fields, not including ctor - pub fields: Vec, - /// ID of the constructor. This is only used for tuple- or enum-like - /// structs. - pub ctor_id: Option, +pub enum VariantData { + Struct(Vec, NodeId), + Tuple(Vec, NodeId), + Unit(NodeId), +} + +impl VariantData { + pub fn fields(&self) -> &[StructField] { + match *self { + VariantData::Struct(ref fields, _) | VariantData::Tuple(ref fields, _) => fields, + _ => &[], + } + } + pub fn id(&self) -> NodeId { + match *self { + VariantData::Struct(_, id) | VariantData::Tuple(_, id) | VariantData::Unit(id) => id + } + } + pub fn is_struct(&self) -> bool { + if let VariantData::Struct(..) = *self { true } else { false } + } + pub fn is_tuple(&self) -> bool { + if let VariantData::Tuple(..) = *self { true } else { false } + } + pub fn is_unit(&self) -> bool { + if let VariantData::Unit(..) = *self { true } else { false } + } } /* @@ -1431,7 +1210,7 @@ pub struct StructDef { /// The name might be a dummy name in case of anonymous items #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct Item { - pub ident: Ident, + pub name: Name, pub attrs: Vec, pub id: NodeId, pub node: Item_, @@ -1463,12 +1242,9 @@ pub enum Item_ { /// An enum definition, e.g. `enum Foo {C, D}` ItemEnum(EnumDef, Generics), /// A struct definition, e.g. `struct Foo {x: A}` - ItemStruct(P, Generics), + ItemStruct(VariantData, Generics), /// Represents a Trait Declaration - ItemTrait(Unsafety, - Generics, - TyParamBounds, - Vec>), + ItemTrait(Unsafety, Generics, TyParamBounds, Vec>), // Default trait implementations /// @@ -1498,14 +1274,14 @@ impl Item_ { ItemStruct(..) => "struct", ItemTrait(..) => "trait", ItemImpl(..) | - ItemDefaultImpl(..) => "item" + ItemDefaultImpl(..) => "item", } } } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct ForeignItem { - pub ident: Ident, + pub name: Name, pub attrs: Vec, pub node: ForeignItem_, pub id: NodeId, @@ -1527,7 +1303,7 @@ impl ForeignItem_ { pub fn descriptive_variant(&self) -> &str { match *self { ForeignItemFn(..) => "foreign function", - ForeignItemStatic(..) => "foreign static item" + ForeignItemStatic(..) => "foreign static item", } } } diff --git a/src/librustc_front/lib.rs b/src/librustc_front/lib.rs index fae4f15725..022744cbc3 100644 --- a/src/librustc_front/lib.rs +++ b/src/librustc_front/lib.rs @@ -36,13 +36,15 @@ #![feature(staged_api)] #![feature(str_char)] #![feature(filling_drop)] -#![feature(str_escape)] -#![cfg_attr(test, feature(test))] extern crate serialize; -#[macro_use] extern crate log; -#[macro_use] extern crate syntax; -#[macro_use] #[no_link] extern crate rustc_bitflags; +#[macro_use] +extern crate log; +#[macro_use] +extern crate syntax; +#[macro_use] +#[no_link] +extern crate rustc_bitflags; extern crate serialize as rustc_serialize; // used by deriving @@ -50,7 +52,6 @@ pub mod hir; pub mod lowering; pub mod fold; pub mod visit; -pub mod attr; pub mod util; pub mod print { diff --git a/src/librustc_front/lowering.rs b/src/librustc_front/lowering.rs index aa7545d52d..42b84b392f 100644 --- a/src/librustc_front/lowering.rs +++ b/src/librustc_front/lowering.rs @@ -8,123 +8,245 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Lowers the AST to the HIR +// Lowers the AST to the HIR. +// +// Since the AST and HIR are fairly similar, this is mostly a simple procedure, +// much like a fold. Where lowering involves a bit more work things get more +// interesting and there are some invariants you should know about. These mostly +// concern spans and ids. +// +// Spans are assigned to AST nodes during parsing and then are modified during +// expansion to indicate the origin of a node and the process it went through +// being expanded. Ids are assigned to AST nodes just before lowering. +// +// For the simpler lowering steps, ids and spans should be preserved. Unlike +// expansion we do not preserve the process of lowering in the spans, so spans +// should not be modified here. When creating a new node (as opposed to +// 'folding' an existing one), then you create a new id using `next_id()`. +// +// You must ensure that ids are unique. That means that you should only use the +// id from an AST node in a single HIR node (you can assume that AST node ids +// are unique). Every new node must have a unique id. Avoid cloning HIR nodes. +// If you do, you must then set the new node's id to a fresh one. +// +// Lowering must be reproducable (the compiler only lowers once, but tools and +// custom lints may lower an AST node to a HIR node to interact with the +// compiler). The most interesting bit of this is ids - if you lower an AST node +// and create new HIR nodes with fresh ids, when re-lowering the same node, you +// must ensure you get the same ids! To do this, we keep track of the next id +// when we translate a node which requires new ids. By checking this cache and +// using node ids starting with the cached id, we ensure ids are reproducible. +// To use this system, you just need to hold on to a CachedIdSetter object +// whilst lowering. This is an RAII object that takes care of setting and +// restoring the cached id, etc. +// +// This whole system relies on node ids being incremented one at a time and +// all increments being for lowering. This means that you should not call any +// non-lowering function which will use new node ids. +// +// We must also cache gensym'ed Idents to ensure that we get the same Ident +// every time we lower a node with gensym'ed names. One consequence of this is +// that you can only gensym a name once in a lowering (you don't need to worry +// about nested lowering though). That's because we cache based on the name and +// the currently cached node id, which is unique per lowered node. +// +// Spans are used for error messages and for tools to map semantics back to +// source code. It is therefore not as important with spans as ids to be strict +// about use (you can't break the compiler by screwing up a span). Obviously, a +// HIR node can only have a single span. But multiple nodes can have the same +// span and spans don't need to be kept in order, etc. Where code is preserved +// by lowering, it should have the same span as in the AST. Where HIR nodes are +// new it is probably best to give a span for the whole AST node being lowered. +// All nodes should have real spans, don't use dummy spans. Tools are likely to +// get confused if the spans from leaf AST nodes occur in multiple places +// in the HIR, especially for multiple identifiers. use hir; +use std::collections::HashMap; + use syntax::ast::*; use syntax::ptr::P; -use syntax::codemap::Spanned; +use syntax::codemap::{respan, Spanned, Span}; use syntax::owned_slice::OwnedSlice; +use syntax::parse::token::{self, str_to_ident}; +use syntax::std_inject; + +use std::cell::{Cell, RefCell}; + +pub struct LoweringContext<'a> { + crate_root: Option<&'static str>, + // Map AST ids to ids used for expanded nodes. + id_cache: RefCell>, + // Use if there are no cached ids for the current node. + id_assigner: &'a NodeIdAssigner, + // 0 == no cached id. Must be incremented to align with previous id + // incrementing. + cached_id: Cell, + // Keep track of gensym'ed idents. + gensym_cache: RefCell>, + // A copy of cached_id, but is also set to an id while it is being cached. + gensym_key: Cell, +} + +impl<'a, 'hir> LoweringContext<'a> { + pub fn new(id_assigner: &'a NodeIdAssigner, c: Option<&Crate>) -> LoweringContext<'a> { + let crate_root = c.and_then(|c| { + if std_inject::no_core(c) { + None + } else if std_inject::no_std(c) { + Some("core") + } else { + Some("std") + } + }); + + LoweringContext { + crate_root: crate_root, + id_cache: RefCell::new(HashMap::new()), + id_assigner: id_assigner, + cached_id: Cell::new(0), + gensym_cache: RefCell::new(HashMap::new()), + gensym_key: Cell::new(0), + } + } + fn next_id(&self) -> NodeId { + let cached = self.cached_id.get(); + if cached == 0 { + return self.id_assigner.next_node_id() + } -pub fn lower_meta_items(meta_items: &Vec>) -> Vec> { - meta_items.iter().map(|x| lower_meta_item(x)).collect() + self.cached_id.set(cached + 1); + cached + } + + fn str_to_ident(&self, s: &'static str) -> Ident { + let cached_id = self.gensym_key.get(); + if cached_id == 0 { + return token::gensym_ident(s); + } + + let cached = self.gensym_cache.borrow().contains_key(&(cached_id, s)); + if cached { + self.gensym_cache.borrow()[&(cached_id, s)] + } else { + let result = token::gensym_ident(s); + self.gensym_cache.borrow_mut().insert((cached_id, s), result); + result + } + } } -pub fn lower_view_path(view_path: &ViewPath) -> P { +pub fn lower_view_path(_lctx: &LoweringContext, view_path: &ViewPath) -> P { P(Spanned { node: match view_path.node { ViewPathSimple(ident, ref path) => { - hir::ViewPathSimple(ident, lower_path(path)) + hir::ViewPathSimple(ident.name, lower_path(_lctx, path)) } ViewPathGlob(ref path) => { - hir::ViewPathGlob(lower_path(path)) + hir::ViewPathGlob(lower_path(_lctx, path)) } ViewPathList(ref path, ref path_list_idents) => { - hir::ViewPathList(lower_path(path), - path_list_idents.iter().map(|path_list_ident| { - Spanned { - node: match path_list_ident.node { - PathListIdent { id, name, rename } => - hir::PathListIdent { - id: id, - name: name, - rename: rename.clone(), - }, - PathListMod { id, rename } => - hir::PathListMod { id: id, rename: rename.clone() } - }, - span: path_list_ident.span - } - }).collect()) + hir::ViewPathList(lower_path(_lctx, path), + path_list_idents.iter() + .map(|path_list_ident| { + Spanned { + node: match path_list_ident.node { + PathListIdent { id, name, rename } => + hir::PathListIdent { + id: id, + name: name.name, + rename: rename.map(|x| x.name), + }, + PathListMod { id, rename } => + hir::PathListMod { + id: id, + rename: rename.map(|x| x.name), + }, + }, + span: path_list_ident.span, + } + }) + .collect()) } }, span: view_path.span, }) } -pub fn lower_attrs(attrs: &Vec) -> Vec { - attrs.iter().map(|x| lower_attribute(x)).collect() -} - -pub fn lower_arm(arm: &Arm) -> hir::Arm { +pub fn lower_arm(_lctx: &LoweringContext, arm: &Arm) -> hir::Arm { hir::Arm { - attrs: lower_attrs(&arm.attrs), - pats: arm.pats.iter().map(|x| lower_pat(x)).collect(), - guard: arm.guard.as_ref().map(|ref x| lower_expr(x)), - body: lower_expr(&arm.body), + attrs: arm.attrs.clone(), + pats: arm.pats.iter().map(|x| lower_pat(_lctx, x)).collect(), + guard: arm.guard.as_ref().map(|ref x| lower_expr(_lctx, x)), + body: lower_expr(_lctx, &arm.body), } } -pub fn lower_decl(d: &Decl) -> P { +pub fn lower_decl(_lctx: &LoweringContext, d: &Decl) -> P { match d.node { DeclLocal(ref l) => P(Spanned { - node: hir::DeclLocal(lower_local(l)), - span: d.span + node: hir::DeclLocal(lower_local(_lctx, l)), + span: d.span, }), DeclItem(ref it) => P(Spanned { - node: hir::DeclItem(lower_item(it)), - span: d.span + node: hir::DeclItem(lower_item(_lctx, it)), + span: d.span, }), } } -pub fn lower_ty_binding(b: &TypeBinding) -> P { - P(hir::TypeBinding { id: b.id, ident: b.ident, ty: lower_ty(&b.ty), span: b.span }) +pub fn lower_ty_binding(_lctx: &LoweringContext, b: &TypeBinding) -> P { + P(hir::TypeBinding { + id: b.id, + name: b.ident.name, + ty: lower_ty(_lctx, &b.ty), + span: b.span, + }) } -pub fn lower_ty(t: &Ty) -> P { +pub fn lower_ty(_lctx: &LoweringContext, t: &Ty) -> P { P(hir::Ty { id: t.id, node: match t.node { TyInfer => hir::TyInfer, - TyVec(ref ty) => hir::TyVec(lower_ty(ty)), - TyPtr(ref mt) => hir::TyPtr(lower_mt(mt)), + TyVec(ref ty) => hir::TyVec(lower_ty(_lctx, ty)), + TyPtr(ref mt) => hir::TyPtr(lower_mt(_lctx, mt)), TyRptr(ref region, ref mt) => { - hir::TyRptr(lower_opt_lifetime(region), lower_mt(mt)) + hir::TyRptr(lower_opt_lifetime(_lctx, region), + lower_mt(_lctx, mt)) } TyBareFn(ref f) => { hir::TyBareFn(P(hir::BareFnTy { - lifetimes: lower_lifetime_defs(&f.lifetimes), - unsafety: lower_unsafety(f.unsafety), + lifetimes: lower_lifetime_defs(_lctx, &f.lifetimes), + unsafety: lower_unsafety(_lctx, f.unsafety), abi: f.abi, - decl: lower_fn_decl(&f.decl) + decl: lower_fn_decl(_lctx, &f.decl), })) } - TyTup(ref tys) => hir::TyTup(tys.iter().map(|ty| lower_ty(ty)).collect()), - TyParen(ref ty) => hir::TyParen(lower_ty(ty)), + TyTup(ref tys) => hir::TyTup(tys.iter().map(|ty| lower_ty(_lctx, ty)).collect()), + TyParen(ref ty) => hir::TyParen(lower_ty(_lctx, ty)), TyPath(ref qself, ref path) => { let qself = qself.as_ref().map(|&QSelf { ref ty, position }| { hir::QSelf { - ty: lower_ty(ty), - position: position + ty: lower_ty(_lctx, ty), + position: position, } }); - hir::TyPath(qself, lower_path(path)) + hir::TyPath(qself, lower_path(_lctx, path)) } TyObjectSum(ref ty, ref bounds) => { - hir::TyObjectSum(lower_ty(ty), - lower_bounds(bounds)) + hir::TyObjectSum(lower_ty(_lctx, ty), lower_bounds(_lctx, bounds)) } TyFixedLengthVec(ref ty, ref e) => { - hir::TyFixedLengthVec(lower_ty(ty), lower_expr(e)) + hir::TyFixedLengthVec(lower_ty(_lctx, ty), lower_expr(_lctx, e)) } TyTypeof(ref expr) => { - hir::TyTypeof(lower_expr(expr)) + hir::TyTypeof(lower_expr(_lctx, expr)) } TyPolyTraitRef(ref bounds) => { - hir::TyPolyTraitRef(bounds.iter().map(|b| lower_ty_param_bound(b)).collect()) + hir::TyPolyTraitRef(bounds.iter().map(|b| lower_ty_param_bound(_lctx, b)).collect()) } TyMac(_) => panic!("TyMac should have been expanded by now."), }, @@ -132,248 +254,225 @@ pub fn lower_ty(t: &Ty) -> P { }) } -pub fn lower_foreign_mod(fm: &ForeignMod) -> hir::ForeignMod { +pub fn lower_foreign_mod(_lctx: &LoweringContext, fm: &ForeignMod) -> hir::ForeignMod { hir::ForeignMod { abi: fm.abi, - items: fm.items.iter().map(|x| lower_foreign_item(x)).collect(), + items: fm.items.iter().map(|x| lower_foreign_item(_lctx, x)).collect(), } } -pub fn lower_variant(v: &Variant) -> P { +pub fn lower_variant(_lctx: &LoweringContext, v: &Variant) -> P { P(Spanned { node: hir::Variant_ { - id: v.node.id, - name: v.node.name, - attrs: lower_attrs(&v.node.attrs), - kind: match v.node.kind { - TupleVariantKind(ref variant_args) => { - hir::TupleVariantKind(variant_args.iter().map(|ref x| - lower_variant_arg(x)).collect()) - } - StructVariantKind(ref struct_def) => { - hir::StructVariantKind(lower_struct_def(struct_def)) - } - }, - disr_expr: v.node.disr_expr.as_ref().map(|e| lower_expr(e)), - vis: lower_visibility(v.node.vis), + name: v.node.name.name, + attrs: v.node.attrs.clone(), + data: lower_variant_data(_lctx, &v.node.data), + disr_expr: v.node.disr_expr.as_ref().map(|e| lower_expr(_lctx, e)), }, span: v.span, }) } -pub fn lower_path(p: &Path) -> hir::Path { +pub fn lower_path(_lctx: &LoweringContext, p: &Path) -> hir::Path { hir::Path { global: p.global, - segments: p.segments.iter().map(|&PathSegment {identifier, ref parameters}| - hir::PathSegment { - identifier: identifier, - parameters: lower_path_parameters(parameters), - }).collect(), + segments: p.segments + .iter() + .map(|&PathSegment { identifier, ref parameters }| { + hir::PathSegment { + identifier: identifier, + parameters: lower_path_parameters(_lctx, parameters), + } + }) + .collect(), span: p.span, } } -pub fn lower_path_parameters(path_parameters: &PathParameters) -> hir::PathParameters { +pub fn lower_path_parameters(_lctx: &LoweringContext, + path_parameters: &PathParameters) + -> hir::PathParameters { match *path_parameters { AngleBracketedParameters(ref data) => - hir::AngleBracketedParameters(lower_angle_bracketed_parameter_data(data)), + hir::AngleBracketedParameters(lower_angle_bracketed_parameter_data(_lctx, data)), ParenthesizedParameters(ref data) => - hir::ParenthesizedParameters(lower_parenthesized_parameter_data(data)), + hir::ParenthesizedParameters(lower_parenthesized_parameter_data(_lctx, data)), } } -pub fn lower_angle_bracketed_parameter_data(data: &AngleBracketedParameterData) +pub fn lower_angle_bracketed_parameter_data(_lctx: &LoweringContext, + data: &AngleBracketedParameterData) -> hir::AngleBracketedParameterData { let &AngleBracketedParameterData { ref lifetimes, ref types, ref bindings } = data; hir::AngleBracketedParameterData { - lifetimes: lower_lifetimes(lifetimes), - types: types.iter().map(|ty| lower_ty(ty)).collect(), - bindings: bindings.iter().map(|b| lower_ty_binding(b)).collect(), + lifetimes: lower_lifetimes(_lctx, lifetimes), + types: types.iter().map(|ty| lower_ty(_lctx, ty)).collect(), + bindings: bindings.iter().map(|b| lower_ty_binding(_lctx, b)).collect(), } } -pub fn lower_parenthesized_parameter_data(data: &ParenthesizedParameterData) +pub fn lower_parenthesized_parameter_data(_lctx: &LoweringContext, + data: &ParenthesizedParameterData) -> hir::ParenthesizedParameterData { let &ParenthesizedParameterData { ref inputs, ref output, span } = data; hir::ParenthesizedParameterData { - inputs: inputs.iter().map(|ty| lower_ty(ty)).collect(), - output: output.as_ref().map(|ty| lower_ty(ty)), + inputs: inputs.iter().map(|ty| lower_ty(_lctx, ty)).collect(), + output: output.as_ref().map(|ty| lower_ty(_lctx, ty)), span: span, } } -pub fn lower_local(l: &Local) -> P { +pub fn lower_local(_lctx: &LoweringContext, l: &Local) -> P { P(hir::Local { - id: l.id, - ty: l.ty.as_ref().map(|t| lower_ty(t)), - pat: lower_pat(&l.pat), - init: l.init.as_ref().map(|e| lower_expr(e)), - span: l.span, - }) -} - -pub fn lower_attribute(at: &Attribute) -> hir::Attribute { - Spanned { - node: hir::Attribute_ { - id: hir::AttrId(at.node.id.0), - style: lower_attr_style(at.node.style), - value: lower_meta_item(&at.node.value), - is_sugared_doc: at.node.is_sugared_doc, - }, - span: at.span, - } -} - -// FIXME we should probably just unify hir and ast Attributes. -pub fn unlower_attribute(at: &hir::Attribute) -> Attribute { - Spanned { - node: Attribute_ { - id: AttrId(at.node.id.0), - style: unlower_attr_style(at.node.style), - value: unlower_meta_item(&at.node.value), - is_sugared_doc: at.node.is_sugared_doc, - }, - span: at.span, - } + id: l.id, + ty: l.ty.as_ref().map(|t| lower_ty(_lctx, t)), + pat: lower_pat(_lctx, &l.pat), + init: l.init.as_ref().map(|e| lower_expr(_lctx, e)), + span: l.span, + }) } -pub fn lower_explicit_self_underscore(es: &ExplicitSelf_) -> hir::ExplicitSelf_ { +pub fn lower_explicit_self_underscore(_lctx: &LoweringContext, + es: &ExplicitSelf_) + -> hir::ExplicitSelf_ { match *es { SelfStatic => hir::SelfStatic, - SelfValue(v) => hir::SelfValue(v), + SelfValue(v) => hir::SelfValue(v.name), SelfRegion(ref lifetime, m, ident) => { - hir::SelfRegion(lower_opt_lifetime(lifetime), lower_mutability(m), ident) + hir::SelfRegion(lower_opt_lifetime(_lctx, lifetime), + lower_mutability(_lctx, m), + ident.name) } SelfExplicit(ref typ, ident) => { - hir::SelfExplicit(lower_ty(typ), ident) + hir::SelfExplicit(lower_ty(_lctx, typ), ident.name) } } } -pub fn lower_mutability(m: Mutability) -> hir::Mutability { +pub fn lower_mutability(_lctx: &LoweringContext, m: Mutability) -> hir::Mutability { match m { MutMutable => hir::MutMutable, MutImmutable => hir::MutImmutable, } } -pub fn lower_explicit_self(s: &ExplicitSelf) -> hir::ExplicitSelf { - Spanned { node: lower_explicit_self_underscore(&s.node), span: s.span } -} - - -pub fn lower_meta_item(mi: &MetaItem) -> P { - P(Spanned { - node: match mi.node { - MetaWord(ref id) => hir::MetaWord(id.clone()), - MetaList(ref id, ref mis) => { - hir::MetaList(id.clone(), mis.iter().map(|mi| lower_meta_item(mi)).collect()) - } - MetaNameValue(ref id, ref s) => hir::MetaNameValue(id.clone(), lower_lit(s)) - }, - span: mi.span, - }) -} - -pub fn unlower_meta_item(mi: &hir::MetaItem) -> P { - P(Spanned { - node: match mi.node { - hir::MetaWord(ref id) => MetaWord(id.clone()), - hir::MetaList(ref id, ref mis) => { - MetaList(id.clone(), mis.iter().map(|mi| unlower_meta_item(mi)).collect()) - } - hir::MetaNameValue(ref id, ref s) => MetaNameValue(id.clone(), unlower_lit(s)) - }, - span: mi.span, - }) +pub fn lower_explicit_self(_lctx: &LoweringContext, s: &ExplicitSelf) -> hir::ExplicitSelf { + Spanned { + node: lower_explicit_self_underscore(_lctx, &s.node), + span: s.span, + } } -pub fn lower_arg(arg: &Arg) -> hir::Arg { - hir::Arg { id: arg.id, pat: lower_pat(&arg.pat), ty: lower_ty(&arg.ty) } +pub fn lower_arg(_lctx: &LoweringContext, arg: &Arg) -> hir::Arg { + hir::Arg { + id: arg.id, + pat: lower_pat(_lctx, &arg.pat), + ty: lower_ty(_lctx, &arg.ty), + } } -pub fn lower_fn_decl(decl: &FnDecl) -> P { +pub fn lower_fn_decl(_lctx: &LoweringContext, decl: &FnDecl) -> P { P(hir::FnDecl { - inputs: decl.inputs.iter().map(|x| lower_arg(x)).collect(), + inputs: decl.inputs.iter().map(|x| lower_arg(_lctx, x)).collect(), output: match decl.output { - Return(ref ty) => hir::Return(lower_ty(ty)), + Return(ref ty) => hir::Return(lower_ty(_lctx, ty)), DefaultReturn(span) => hir::DefaultReturn(span), - NoReturn(span) => hir::NoReturn(span) + NoReturn(span) => hir::NoReturn(span), }, variadic: decl.variadic, }) } -pub fn lower_ty_param_bound(tpb: &TyParamBound) -> hir::TyParamBound { +pub fn lower_ty_param_bound(_lctx: &LoweringContext, tpb: &TyParamBound) -> hir::TyParamBound { match *tpb { TraitTyParamBound(ref ty, modifier) => { - hir::TraitTyParamBound(lower_poly_trait_ref(ty), lower_trait_bound_modifier(modifier)) + hir::TraitTyParamBound(lower_poly_trait_ref(_lctx, ty), + lower_trait_bound_modifier(_lctx, modifier)) + } + RegionTyParamBound(ref lifetime) => { + hir::RegionTyParamBound(lower_lifetime(_lctx, lifetime)) } - RegionTyParamBound(ref lifetime) => hir::RegionTyParamBound(lower_lifetime(lifetime)), } } -pub fn lower_ty_param(tp: &TyParam) -> hir::TyParam { +pub fn lower_ty_param(_lctx: &LoweringContext, tp: &TyParam) -> hir::TyParam { hir::TyParam { id: tp.id, - ident: tp.ident, - bounds: lower_bounds(&tp.bounds), - default: tp.default.as_ref().map(|x| lower_ty(x)), + name: tp.ident.name, + bounds: lower_bounds(_lctx, &tp.bounds), + default: tp.default.as_ref().map(|x| lower_ty(_lctx, x)), span: tp.span, } } -pub fn lower_ty_params(tps: &OwnedSlice) -> OwnedSlice { - tps.iter().map(|tp| lower_ty_param(tp)).collect() +pub fn lower_ty_params(_lctx: &LoweringContext, + tps: &OwnedSlice) + -> OwnedSlice { + tps.iter().map(|tp| lower_ty_param(_lctx, tp)).collect() } -pub fn lower_lifetime(l: &Lifetime) -> hir::Lifetime { - hir::Lifetime { id: l.id, name: l.name, span: l.span } +pub fn lower_lifetime(_lctx: &LoweringContext, l: &Lifetime) -> hir::Lifetime { + hir::Lifetime { + id: l.id, + name: l.name, + span: l.span, + } } -pub fn lower_lifetime_def(l: &LifetimeDef) -> hir::LifetimeDef { - hir::LifetimeDef { lifetime: lower_lifetime(&l.lifetime), bounds: lower_lifetimes(&l.bounds) } +pub fn lower_lifetime_def(_lctx: &LoweringContext, l: &LifetimeDef) -> hir::LifetimeDef { + hir::LifetimeDef { + lifetime: lower_lifetime(_lctx, &l.lifetime), + bounds: lower_lifetimes(_lctx, &l.bounds), + } } -pub fn lower_lifetimes(lts: &Vec) -> Vec { - lts.iter().map(|l| lower_lifetime(l)).collect() +pub fn lower_lifetimes(_lctx: &LoweringContext, lts: &Vec) -> Vec { + lts.iter().map(|l| lower_lifetime(_lctx, l)).collect() } -pub fn lower_lifetime_defs(lts: &Vec) -> Vec { - lts.iter().map(|l| lower_lifetime_def(l)).collect() +pub fn lower_lifetime_defs(_lctx: &LoweringContext, + lts: &Vec) + -> Vec { + lts.iter().map(|l| lower_lifetime_def(_lctx, l)).collect() } -pub fn lower_opt_lifetime(o_lt: &Option) -> Option { - o_lt.as_ref().map(|lt| lower_lifetime(lt)) +pub fn lower_opt_lifetime(_lctx: &LoweringContext, + o_lt: &Option) + -> Option { + o_lt.as_ref().map(|lt| lower_lifetime(_lctx, lt)) } -pub fn lower_generics(g: &Generics) -> hir::Generics { +pub fn lower_generics(_lctx: &LoweringContext, g: &Generics) -> hir::Generics { hir::Generics { - ty_params: lower_ty_params(&g.ty_params), - lifetimes: lower_lifetime_defs(&g.lifetimes), - where_clause: lower_where_clause(&g.where_clause), + ty_params: lower_ty_params(_lctx, &g.ty_params), + lifetimes: lower_lifetime_defs(_lctx, &g.lifetimes), + where_clause: lower_where_clause(_lctx, &g.where_clause), } } -pub fn lower_where_clause(wc: &WhereClause) -> hir::WhereClause { +pub fn lower_where_clause(_lctx: &LoweringContext, wc: &WhereClause) -> hir::WhereClause { hir::WhereClause { id: wc.id, - predicates: wc.predicates.iter().map(|predicate| - lower_where_predicate(predicate)).collect(), + predicates: wc.predicates + .iter() + .map(|predicate| lower_where_predicate(_lctx, predicate)) + .collect(), } } -pub fn lower_where_predicate(pred: &WherePredicate) -> hir::WherePredicate { +pub fn lower_where_predicate(_lctx: &LoweringContext, + pred: &WherePredicate) + -> hir::WherePredicate { match *pred { WherePredicate::BoundPredicate(WhereBoundPredicate{ ref bound_lifetimes, ref bounded_ty, ref bounds, span}) => { hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { - bound_lifetimes: lower_lifetime_defs(bound_lifetimes), - bounded_ty: lower_ty(bounded_ty), - bounds: bounds.iter().map(|x| lower_ty_param_bound(x)).collect(), - span: span + bound_lifetimes: lower_lifetime_defs(_lctx, bound_lifetimes), + bounded_ty: lower_ty(_lctx, bounded_ty), + bounds: bounds.iter().map(|x| lower_ty_param_bound(_lctx, x)).collect(), + span: span, }) } WherePredicate::RegionPredicate(WhereRegionPredicate{ ref lifetime, @@ -381,142 +480,161 @@ pub fn lower_where_predicate(pred: &WherePredicate) -> hir::WherePredicate { span}) => { hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate { span: span, - lifetime: lower_lifetime(lifetime), - bounds: bounds.iter().map(|bound| lower_lifetime(bound)).collect() + lifetime: lower_lifetime(_lctx, lifetime), + bounds: bounds.iter().map(|bound| lower_lifetime(_lctx, bound)).collect(), }) } WherePredicate::EqPredicate(WhereEqPredicate{ id, ref path, ref ty, span}) => { - hir::WherePredicate::EqPredicate(hir::WhereEqPredicate{ + hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { id: id, - path: lower_path(path), - ty:lower_ty(ty), - span: span + path: lower_path(_lctx, path), + ty: lower_ty(_lctx, ty), + span: span, }) } } } -pub fn lower_struct_def(sd: &StructDef) -> P { - P(hir::StructDef { - fields: sd.fields.iter().map(|f| lower_struct_field(f)).collect(), - ctor_id: sd.ctor_id, - }) +pub fn lower_variant_data(_lctx: &LoweringContext, vdata: &VariantData) -> hir::VariantData { + match *vdata { + VariantData::Struct(ref fields, id) => { + hir::VariantData::Struct(fields.iter() + .map(|f| lower_struct_field(_lctx, f)).collect(), id) + } + VariantData::Tuple(ref fields, id) => { + hir::VariantData::Tuple(fields.iter() + .map(|f| lower_struct_field(_lctx, f)).collect(), id) + } + VariantData::Unit(id) => hir::VariantData::Unit(id) + } } -pub fn lower_trait_ref(p: &TraitRef) -> hir::TraitRef { - hir::TraitRef { path: lower_path(&p.path), ref_id: p.ref_id } +pub fn lower_trait_ref(_lctx: &LoweringContext, p: &TraitRef) -> hir::TraitRef { + hir::TraitRef { + path: lower_path(_lctx, &p.path), + ref_id: p.ref_id, + } } -pub fn lower_poly_trait_ref(p: &PolyTraitRef) -> hir::PolyTraitRef { +pub fn lower_poly_trait_ref(_lctx: &LoweringContext, p: &PolyTraitRef) -> hir::PolyTraitRef { hir::PolyTraitRef { - bound_lifetimes: lower_lifetime_defs(&p.bound_lifetimes), - trait_ref: lower_trait_ref(&p.trait_ref), + bound_lifetimes: lower_lifetime_defs(_lctx, &p.bound_lifetimes), + trait_ref: lower_trait_ref(_lctx, &p.trait_ref), span: p.span, } } -pub fn lower_struct_field(f: &StructField) -> hir::StructField { +pub fn lower_struct_field(_lctx: &LoweringContext, f: &StructField) -> hir::StructField { Spanned { node: hir::StructField_ { id: f.node.id, - kind: lower_struct_field_kind(&f.node.kind), - ty: lower_ty(&f.node.ty), - attrs: lower_attrs(&f.node.attrs), + kind: lower_struct_field_kind(_lctx, &f.node.kind), + ty: lower_ty(_lctx, &f.node.ty), + attrs: f.node.attrs.clone(), }, span: f.span, } } -pub fn lower_field(f: &Field) -> hir::Field { - hir::Field { ident: f.ident, expr: lower_expr(&f.expr), span: f.span } +pub fn lower_field(_lctx: &LoweringContext, f: &Field) -> hir::Field { + hir::Field { + name: respan(f.ident.span, f.ident.node.name), + expr: lower_expr(_lctx, &f.expr), + span: f.span, + } } -pub fn lower_mt(mt: &MutTy) -> hir::MutTy { - hir::MutTy { ty: lower_ty(&mt.ty), mutbl: lower_mutability(mt.mutbl) } +pub fn lower_mt(_lctx: &LoweringContext, mt: &MutTy) -> hir::MutTy { + hir::MutTy { + ty: lower_ty(_lctx, &mt.ty), + mutbl: lower_mutability(_lctx, mt.mutbl), + } } -pub fn lower_opt_bounds(b: &Option>) +pub fn lower_opt_bounds(_lctx: &LoweringContext, + b: &Option>) -> Option> { - b.as_ref().map(|ref bounds| lower_bounds(bounds)) + b.as_ref().map(|ref bounds| lower_bounds(_lctx, bounds)) } -fn lower_bounds(bounds: &TyParamBounds) -> hir::TyParamBounds { - bounds.iter().map(|bound| lower_ty_param_bound(bound)).collect() +fn lower_bounds(_lctx: &LoweringContext, bounds: &TyParamBounds) -> hir::TyParamBounds { + bounds.iter().map(|bound| lower_ty_param_bound(_lctx, bound)).collect() } -fn lower_variant_arg(va: &VariantArg) -> hir::VariantArg { - hir::VariantArg { id: va.id, ty: lower_ty(&va.ty) } -} - -pub fn lower_block(b: &Block) -> P { +pub fn lower_block(_lctx: &LoweringContext, b: &Block) -> P { P(hir::Block { id: b.id, - stmts: b.stmts.iter().map(|s| lower_stmt(s)).collect(), - expr: b.expr.as_ref().map(|ref x| lower_expr(x)), - rules: lower_block_check_mode(&b.rules), + stmts: b.stmts.iter().map(|s| lower_stmt(_lctx, s)).collect(), + expr: b.expr.as_ref().map(|ref x| lower_expr(_lctx, x)), + rules: lower_block_check_mode(_lctx, &b.rules), span: b.span, }) } -pub fn lower_item_underscore(i: &Item_) -> hir::Item_ { +pub fn lower_item_underscore(_lctx: &LoweringContext, i: &Item_) -> hir::Item_ { match *i { ItemExternCrate(string) => hir::ItemExternCrate(string), ItemUse(ref view_path) => { - hir::ItemUse(lower_view_path(view_path)) + hir::ItemUse(lower_view_path(_lctx, view_path)) } ItemStatic(ref t, m, ref e) => { - hir::ItemStatic(lower_ty(t), lower_mutability(m), lower_expr(e)) + hir::ItemStatic(lower_ty(_lctx, t), + lower_mutability(_lctx, m), + lower_expr(_lctx, e)) } ItemConst(ref t, ref e) => { - hir::ItemConst(lower_ty(t), lower_expr(e)) + hir::ItemConst(lower_ty(_lctx, t), lower_expr(_lctx, e)) } ItemFn(ref decl, unsafety, constness, abi, ref generics, ref body) => { - hir::ItemFn( - lower_fn_decl(decl), - lower_unsafety(unsafety), - lower_constness(constness), - abi, - lower_generics(generics), - lower_block(body) - ) + hir::ItemFn(lower_fn_decl(_lctx, decl), + lower_unsafety(_lctx, unsafety), + lower_constness(_lctx, constness), + abi, + lower_generics(_lctx, generics), + lower_block(_lctx, body)) } - ItemMod(ref m) => hir::ItemMod(lower_mod(m)), - ItemForeignMod(ref nm) => hir::ItemForeignMod(lower_foreign_mod(nm)), + ItemMod(ref m) => hir::ItemMod(lower_mod(_lctx, m)), + ItemForeignMod(ref nm) => hir::ItemForeignMod(lower_foreign_mod(_lctx, nm)), ItemTy(ref t, ref generics) => { - hir::ItemTy(lower_ty(t), lower_generics(generics)) + hir::ItemTy(lower_ty(_lctx, t), lower_generics(_lctx, generics)) } ItemEnum(ref enum_definition, ref generics) => { - hir::ItemEnum( - hir::EnumDef { - variants: enum_definition.variants.iter().map(|x| lower_variant(x)).collect(), - }, - lower_generics(generics)) + hir::ItemEnum(hir::EnumDef { + variants: enum_definition.variants + .iter() + .map(|x| lower_variant(_lctx, x)) + .collect(), + }, + lower_generics(_lctx, generics)) } ItemStruct(ref struct_def, ref generics) => { - let struct_def = lower_struct_def(struct_def); - hir::ItemStruct(struct_def, lower_generics(generics)) + let struct_def = lower_variant_data(_lctx, struct_def); + hir::ItemStruct(struct_def, lower_generics(_lctx, generics)) } ItemDefaultImpl(unsafety, ref trait_ref) => { - hir::ItemDefaultImpl(lower_unsafety(unsafety), lower_trait_ref(trait_ref)) + hir::ItemDefaultImpl(lower_unsafety(_lctx, unsafety), + lower_trait_ref(_lctx, trait_ref)) } ItemImpl(unsafety, polarity, ref generics, ref ifce, ref ty, ref impl_items) => { - let new_impl_items = impl_items.iter().map(|item| lower_impl_item(item)).collect(); - let ifce = ifce.as_ref().map(|trait_ref| lower_trait_ref(trait_ref)); - hir::ItemImpl(lower_unsafety(unsafety), - lower_impl_polarity(polarity), - lower_generics(generics), + let new_impl_items = impl_items.iter() + .map(|item| lower_impl_item(_lctx, item)) + .collect(); + let ifce = ifce.as_ref().map(|trait_ref| lower_trait_ref(_lctx, trait_ref)); + hir::ItemImpl(lower_unsafety(_lctx, unsafety), + lower_impl_polarity(_lctx, polarity), + lower_generics(_lctx, generics), ifce, - lower_ty(ty), + lower_ty(_lctx, ty), new_impl_items) } ItemTrait(unsafety, ref generics, ref bounds, ref items) => { - let bounds = lower_bounds(bounds); - let items = items.iter().map(|item| lower_trait_item(item)).collect(); - hir::ItemTrait(lower_unsafety(unsafety), - lower_generics(generics), + let bounds = lower_bounds(_lctx, bounds); + let items = items.iter().map(|item| lower_trait_item(_lctx, item)).collect(); + hir::ItemTrait(lower_unsafety(_lctx, unsafety), + lower_generics(_lctx, generics), bounds, items) } @@ -524,73 +642,74 @@ pub fn lower_item_underscore(i: &Item_) -> hir::Item_ { } } -pub fn lower_trait_item(i: &TraitItem) -> P { +pub fn lower_trait_item(_lctx: &LoweringContext, i: &TraitItem) -> P { P(hir::TraitItem { - id: i.id, - ident: i.ident, - attrs: lower_attrs(&i.attrs), - node: match i.node { + id: i.id, + name: i.ident.name, + attrs: i.attrs.clone(), + node: match i.node { ConstTraitItem(ref ty, ref default) => { - hir::ConstTraitItem(lower_ty(ty), - default.as_ref().map(|x| lower_expr(x))) + hir::ConstTraitItem(lower_ty(_lctx, ty), + default.as_ref().map(|x| lower_expr(_lctx, x))) } MethodTraitItem(ref sig, ref body) => { - hir::MethodTraitItem(lower_method_sig(sig), - body.as_ref().map(|x| lower_block(x))) + hir::MethodTraitItem(lower_method_sig(_lctx, sig), + body.as_ref().map(|x| lower_block(_lctx, x))) } TypeTraitItem(ref bounds, ref default) => { - hir::TypeTraitItem(lower_bounds(bounds), - default.as_ref().map(|x| lower_ty(x))) + hir::TypeTraitItem(lower_bounds(_lctx, bounds), + default.as_ref().map(|x| lower_ty(_lctx, x))) } }, - span: i.span, - }) + span: i.span, + }) } -pub fn lower_impl_item(i: &ImplItem) -> P { +pub fn lower_impl_item(_lctx: &LoweringContext, i: &ImplItem) -> P { P(hir::ImplItem { - id: i.id, - ident: i.ident, - attrs: lower_attrs(&i.attrs), - vis: lower_visibility(i.vis), - node: match i.node { + id: i.id, + name: i.ident.name, + attrs: i.attrs.clone(), + vis: lower_visibility(_lctx, i.vis), + node: match i.node { ConstImplItem(ref ty, ref expr) => { - hir::ConstImplItem(lower_ty(ty), lower_expr(expr)) + hir::ConstImplItem(lower_ty(_lctx, ty), lower_expr(_lctx, expr)) } MethodImplItem(ref sig, ref body) => { - hir::MethodImplItem(lower_method_sig(sig), - lower_block(body)) + hir::MethodImplItem(lower_method_sig(_lctx, sig), + lower_block(_lctx, body)) } - TypeImplItem(ref ty) => hir::TypeImplItem(lower_ty(ty)), + TypeImplItem(ref ty) => hir::TypeImplItem(lower_ty(_lctx, ty)), MacImplItem(..) => panic!("Shouldn't exist any more"), }, - span: i.span, - }) + span: i.span, + }) } -pub fn lower_mod(m: &Mod) -> hir::Mod { - hir::Mod { inner: m.inner, items: m.items.iter().map(|x| lower_item(x)).collect() } +pub fn lower_mod(_lctx: &LoweringContext, m: &Mod) -> hir::Mod { + hir::Mod { + inner: m.inner, + items: m.items.iter().map(|x| lower_item(_lctx, x)).collect(), + } } -pub fn lower_crate(c: &Crate) -> hir::Crate { - let config = lower_meta_items(&c.config); - +pub fn lower_crate(_lctx: &LoweringContext, c: &Crate) -> hir::Crate { hir::Crate { - module: lower_mod(&c.module), - attrs: lower_attrs(&c.attrs), - config: config, + module: lower_mod(_lctx, &c.module), + attrs: c.attrs.clone(), + config: c.config.clone(), span: c.span, - exported_macros: c.exported_macros.iter().map(|m| lower_macro_def(m)).collect(), + exported_macros: c.exported_macros.iter().map(|m| lower_macro_def(_lctx, m)).collect(), } } -pub fn lower_macro_def(m: &MacroDef) -> hir::MacroDef { +pub fn lower_macro_def(_lctx: &LoweringContext, m: &MacroDef) -> hir::MacroDef { hir::MacroDef { - ident: m.ident, - attrs: m.attrs.iter().map(|a| lower_attribute(a)).collect(), + name: m.ident.name, + attrs: m.attrs.clone(), id: m.id, span: m.span, - imported_from: m.imported_from, + imported_from: m.imported_from.map(|x| x.name), export: m.export, use_locally: m.use_locally, allow_internal_unstable: m.allow_internal_unstable, @@ -599,108 +718,77 @@ pub fn lower_macro_def(m: &MacroDef) -> hir::MacroDef { } // fold one item into possibly many items -pub fn lower_item(i: &Item) -> P { - P(lower_item_simple(i)) +pub fn lower_item(_lctx: &LoweringContext, i: &Item) -> P { + P(lower_item_simple(_lctx, i)) } // fold one item into exactly one item -pub fn lower_item_simple(i: &Item) -> hir::Item { - let node = lower_item_underscore(&i.node); +pub fn lower_item_simple(_lctx: &LoweringContext, i: &Item) -> hir::Item { + let node = lower_item_underscore(_lctx, &i.node); hir::Item { id: i.id, - ident: i.ident, - attrs: lower_attrs(&i.attrs), + name: i.ident.name, + attrs: i.attrs.clone(), node: node, - vis: lower_visibility(i.vis), + vis: lower_visibility(_lctx, i.vis), span: i.span, } } -pub fn lower_foreign_item(i: &ForeignItem) -> P { +pub fn lower_foreign_item(_lctx: &LoweringContext, i: &ForeignItem) -> P { P(hir::ForeignItem { - id: i.id, - ident: i.ident, - attrs: lower_attrs(&i.attrs), - node: match i.node { + id: i.id, + name: i.ident.name, + attrs: i.attrs.clone(), + node: match i.node { ForeignItemFn(ref fdec, ref generics) => { - hir::ForeignItemFn(lower_fn_decl(fdec), lower_generics(generics)) + hir::ForeignItemFn(lower_fn_decl(_lctx, fdec), + lower_generics(_lctx, generics)) } ForeignItemStatic(ref t, m) => { - hir::ForeignItemStatic(lower_ty(t), m) + hir::ForeignItemStatic(lower_ty(_lctx, t), m) } }, - vis: lower_visibility(i.vis), - span: i.span, - }) + vis: lower_visibility(_lctx, i.vis), + span: i.span, + }) } -pub fn lower_method_sig(sig: &MethodSig) -> hir::MethodSig { +pub fn lower_method_sig(_lctx: &LoweringContext, sig: &MethodSig) -> hir::MethodSig { hir::MethodSig { - generics: lower_generics(&sig.generics), + generics: lower_generics(_lctx, &sig.generics), abi: sig.abi, - explicit_self: lower_explicit_self(&sig.explicit_self), - unsafety: lower_unsafety(sig.unsafety), - constness: lower_constness(sig.constness), - decl: lower_fn_decl(&sig.decl), + explicit_self: lower_explicit_self(_lctx, &sig.explicit_self), + unsafety: lower_unsafety(_lctx, sig.unsafety), + constness: lower_constness(_lctx, sig.constness), + decl: lower_fn_decl(_lctx, &sig.decl), } } -pub fn lower_unsafety(u: Unsafety) -> hir::Unsafety { +pub fn lower_unsafety(_lctx: &LoweringContext, u: Unsafety) -> hir::Unsafety { match u { Unsafety::Unsafe => hir::Unsafety::Unsafe, Unsafety::Normal => hir::Unsafety::Normal, } } -pub fn lower_constness(c: Constness) -> hir::Constness { +pub fn lower_constness(_lctx: &LoweringContext, c: Constness) -> hir::Constness { match c { Constness::Const => hir::Constness::Const, Constness::NotConst => hir::Constness::NotConst, } } -pub fn lower_lit(l: &Lit) -> hir::Lit { - Spanned { - node: match l.node { - LitStr(ref i, s) => hir::LitStr(i.clone(), lower_string_style(s)), - LitByteStr(ref b) => hir::LitByteStr(b.clone()), - LitByte(u) => hir::LitByte(u), - LitChar(c) => hir::LitChar(c), - LitInt(u, ref t) => hir::LitInt(u, lower_lit_int_type(t)), - LitFloat(ref i, t) => hir::LitFloat(i.clone(), lower_float_ty(t)), - LitFloatUnsuffixed(ref i) => hir::LitFloatUnsuffixed(i.clone()), - LitBool(b) => hir::LitBool(b), - }, - span: l.span, - } -} - -pub fn unlower_lit(l: &hir::Lit) -> Lit { - Spanned { - node: match l.node { - hir::LitStr(ref i, s) => LitStr(i.clone(), unlower_string_style(s)), - hir::LitByteStr(ref b) => LitByteStr(b.clone()), - hir::LitByte(u) => LitByte(u), - hir::LitChar(c) => LitChar(c), - hir::LitInt(u, ref t) => LitInt(u, unlower_lit_int_type(t)), - hir::LitFloat(ref i, t) => LitFloat(i.clone(), unlower_float_ty(t)), - hir::LitFloatUnsuffixed(ref i) => LitFloatUnsuffixed(i.clone()), - hir::LitBool(b) => LitBool(b), - }, - span: l.span, - } -} -pub fn lower_unop(u: UnOp) -> hir::UnOp { +pub fn lower_unop(_lctx: &LoweringContext, u: UnOp) -> hir::UnOp { match u { - UnUniq => hir::UnUniq, UnDeref => hir::UnDeref, UnNot => hir::UnNot, UnNeg => hir::UnNeg, } } -pub fn lower_binop(b: BinOp) -> hir::BinOp { +pub fn lower_binop(_lctx: &LoweringContext, b: BinOp) -> hir::BinOp { Spanned { node: match b.node { BiAdd => hir::BiAdd, @@ -726,154 +814,350 @@ pub fn lower_binop(b: BinOp) -> hir::BinOp { } } -pub fn lower_pat(p: &Pat) -> P { +pub fn lower_pat(_lctx: &LoweringContext, p: &Pat) -> P { P(hir::Pat { - id: p.id, - node: match p.node { - PatWild(k) => hir::PatWild(lower_pat_wild_kind(k)), + id: p.id, + node: match p.node { + PatWild(k) => hir::PatWild(lower_pat_wild_kind(_lctx, k)), PatIdent(ref binding_mode, pth1, ref sub) => { - hir::PatIdent(lower_binding_mode(binding_mode), - pth1, - sub.as_ref().map(|x| lower_pat(x))) + hir::PatIdent(lower_binding_mode(_lctx, binding_mode), + pth1, + sub.as_ref().map(|x| lower_pat(_lctx, x))) } - PatLit(ref e) => hir::PatLit(lower_expr(e)), + PatLit(ref e) => hir::PatLit(lower_expr(_lctx, e)), PatEnum(ref pth, ref pats) => { - hir::PatEnum(lower_path(pth), - pats.as_ref().map(|pats| pats.iter().map(|x| lower_pat(x)).collect())) + hir::PatEnum(lower_path(_lctx, pth), + pats.as_ref() + .map(|pats| pats.iter().map(|x| lower_pat(_lctx, x)).collect())) } PatQPath(ref qself, ref pth) => { let qself = hir::QSelf { - ty: lower_ty(&qself.ty), + ty: lower_ty(_lctx, &qself.ty), position: qself.position, }; - hir::PatQPath(qself, lower_path(pth)) + hir::PatQPath(qself, lower_path(_lctx, pth)) } PatStruct(ref pth, ref fields, etc) => { - let pth = lower_path(pth); - let fs = fields.iter().map(|f| { - Spanned { span: f.span, - node: hir::FieldPat { - ident: f.node.ident, - pat: lower_pat(&f.node.pat), - is_shorthand: f.node.is_shorthand, - }} - }).collect(); + let pth = lower_path(_lctx, pth); + let fs = fields.iter() + .map(|f| { + Spanned { + span: f.span, + node: hir::FieldPat { + name: f.node.ident.name, + pat: lower_pat(_lctx, &f.node.pat), + is_shorthand: f.node.is_shorthand, + }, + } + }) + .collect(); hir::PatStruct(pth, fs, etc) } - PatTup(ref elts) => hir::PatTup(elts.iter().map(|x| lower_pat(x)).collect()), - PatBox(ref inner) => hir::PatBox(lower_pat(inner)), - PatRegion(ref inner, mutbl) => hir::PatRegion(lower_pat(inner), - lower_mutability(mutbl)), + PatTup(ref elts) => hir::PatTup(elts.iter().map(|x| lower_pat(_lctx, x)).collect()), + PatBox(ref inner) => hir::PatBox(lower_pat(_lctx, inner)), + PatRegion(ref inner, mutbl) => hir::PatRegion(lower_pat(_lctx, inner), + lower_mutability(_lctx, mutbl)), PatRange(ref e1, ref e2) => { - hir::PatRange(lower_expr(e1), lower_expr(e2)) - }, + hir::PatRange(lower_expr(_lctx, e1), lower_expr(_lctx, e2)) + } PatVec(ref before, ref slice, ref after) => { - hir::PatVec(before.iter().map(|x| lower_pat(x)).collect(), - slice.as_ref().map(|x| lower_pat(x)), - after.iter().map(|x| lower_pat(x)).collect()) + hir::PatVec(before.iter().map(|x| lower_pat(_lctx, x)).collect(), + slice.as_ref().map(|x| lower_pat(_lctx, x)), + after.iter().map(|x| lower_pat(_lctx, x)).collect()) } PatMac(_) => panic!("Shouldn't exist here"), }, - span: p.span, - }) + span: p.span, + }) +} + +// RAII utility for setting and unsetting the cached id. +struct CachedIdSetter<'a> { + reset: bool, + lctx: &'a LoweringContext<'a>, +} + +impl<'a> CachedIdSetter<'a> { + fn new(lctx: &'a LoweringContext, expr_id: NodeId) -> CachedIdSetter<'a> { + // Only reset the id if it was previously 0, i.e., was not cached. + // If it was cached, we are in a nested node, but our id count will + // still count towards the parent's count. + let reset_cached_id = lctx.cached_id.get() == 0; + + let id_cache: &mut HashMap<_, _> = &mut lctx.id_cache.borrow_mut(); + + if id_cache.contains_key(&expr_id) { + let cached_id = lctx.cached_id.get(); + if cached_id == 0 { + // We're entering a node where we need to track ids, but are not + // yet tracking. + lctx.cached_id.set(id_cache[&expr_id]); + lctx.gensym_key.set(id_cache[&expr_id]); + } else { + // We're already tracking - check that the tracked id is the same + // as the expected id. + assert!(cached_id == id_cache[&expr_id], "id mismatch"); + } + } else { + let next_id = lctx.id_assigner.peek_node_id(); + id_cache.insert(expr_id, next_id); + lctx.gensym_key.set(next_id); + } + + CachedIdSetter { + reset: reset_cached_id, + lctx: lctx, + } + } } -pub fn lower_expr(e: &Expr) -> P { +impl<'a> Drop for CachedIdSetter<'a> { + fn drop(&mut self) { + if self.reset { + self.lctx.cached_id.set(0); + self.lctx.gensym_key.set(0); + } + } +} + +pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P { P(hir::Expr { - id: e.id, - node: match e.node { - ExprBox(ref p, ref e) => { - hir::ExprBox(p.as_ref().map(|e| lower_expr(e)), lower_expr(e)) - } - ExprVec(ref exprs) => { - hir::ExprVec(exprs.iter().map(|x| lower_expr(x)).collect()) - } - ExprRepeat(ref expr, ref count) => { - hir::ExprRepeat(lower_expr(expr), lower_expr(count)) - } - ExprTup(ref elts) => hir::ExprTup(elts.iter().map(|x| lower_expr(x)).collect()), - ExprCall(ref f, ref args) => { - hir::ExprCall(lower_expr(f), - args.iter().map(|x| lower_expr(x)).collect()) - } - ExprMethodCall(i, ref tps, ref args) => { - hir::ExprMethodCall( - i, - tps.iter().map(|x| lower_ty(x)).collect(), - args.iter().map(|x| lower_expr(x)).collect()) - } - ExprBinary(binop, ref lhs, ref rhs) => { - hir::ExprBinary(lower_binop(binop), - lower_expr(lhs), - lower_expr(rhs)) - } - ExprUnary(op, ref ohs) => { - hir::ExprUnary(lower_unop(op), lower_expr(ohs)) - } - ExprLit(ref l) => hir::ExprLit(P(lower_lit(l))), - ExprCast(ref expr, ref ty) => { - hir::ExprCast(lower_expr(expr), lower_ty(ty)) - } - ExprAddrOf(m, ref ohs) => hir::ExprAddrOf(lower_mutability(m), lower_expr(ohs)), - ExprIf(ref cond, ref tr, ref fl) => { - hir::ExprIf(lower_expr(cond), - lower_block(tr), - fl.as_ref().map(|x| lower_expr(x))) - } - ExprWhile(ref cond, ref body, opt_ident) => { - hir::ExprWhile(lower_expr(cond), - lower_block(body), - opt_ident) - } - ExprLoop(ref body, opt_ident) => { - hir::ExprLoop(lower_block(body), - opt_ident) - } - ExprMatch(ref expr, ref arms, ref source) => { - hir::ExprMatch(lower_expr(expr), - arms.iter().map(|x| lower_arm(x)).collect(), - lower_match_source(source)) - } - ExprClosure(capture_clause, ref decl, ref body) => { - hir::ExprClosure(lower_capture_clause(capture_clause), - lower_fn_decl(decl), - lower_block(body)) - } - ExprBlock(ref blk) => hir::ExprBlock(lower_block(blk)), - ExprAssign(ref el, ref er) => { - hir::ExprAssign(lower_expr(el), lower_expr(er)) - } - ExprAssignOp(op, ref el, ref er) => { - hir::ExprAssignOp(lower_binop(op), - lower_expr(el), - lower_expr(er)) - } - ExprField(ref el, ident) => { - hir::ExprField(lower_expr(el), ident) - } - ExprTupField(ref el, ident) => { - hir::ExprTupField(lower_expr(el), ident) - } - ExprIndex(ref el, ref er) => { - hir::ExprIndex(lower_expr(el), lower_expr(er)) - } - ExprRange(ref e1, ref e2) => { - hir::ExprRange(e1.as_ref().map(|x| lower_expr(x)), - e2.as_ref().map(|x| lower_expr(x))) - } - ExprPath(ref qself, ref path) => { - let qself = qself.as_ref().map(|&QSelf { ref ty, position }| { - hir::QSelf { - ty: lower_ty(ty), - position: position + id: e.id, + node: match e.node { + // Issue #22181: + // Eventually a desugaring for `box EXPR` + // (similar to the desugaring above for `in PLACE BLOCK`) + // should go here, desugaring + // + // to: + // + // let mut place = BoxPlace::make_place(); + // let raw_place = Place::pointer(&mut place); + // let value = $value; + // unsafe { + // ::std::ptr::write(raw_place, value); + // Boxed::finalize(place) + // } + // + // But for now there are type-inference issues doing that. + ExprBox(ref e) => { + hir::ExprBox(lower_expr(lctx, e)) + } + + // Desugar ExprBox: `in (PLACE) EXPR` + ExprInPlace(ref placer, ref value_expr) => { + // to: + // + // let p = PLACE; + // let mut place = Placer::make_place(p); + // let raw_place = Place::pointer(&mut place); + // push_unsafe!({ + // std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR )); + // InPlace::finalize(place) + // }) + let _old_cached = CachedIdSetter::new(lctx, e.id); + + let placer_expr = lower_expr(lctx, placer); + let value_expr = lower_expr(lctx, value_expr); + + let placer_ident = lctx.str_to_ident("placer"); + let agent_ident = lctx.str_to_ident("place"); + let p_ptr_ident = lctx.str_to_ident("p_ptr"); + + let make_place = ["ops", "Placer", "make_place"]; + let place_pointer = ["ops", "Place", "pointer"]; + let move_val_init = ["intrinsics", "move_val_init"]; + let inplace_finalize = ["ops", "InPlace", "finalize"]; + + let make_call = |lctx, p, args| { + let path = core_path(lctx, e.span, p); + let path = expr_path(lctx, path); + expr_call(lctx, e.span, path, args) + }; + + let mk_stmt_let = |lctx, bind, expr| stmt_let(lctx, e.span, false, bind, expr); + let mk_stmt_let_mut = |lctx, bind, expr| stmt_let(lctx, e.span, true, bind, expr); + + // let placer = ; + let s1 = mk_stmt_let(lctx, + placer_ident, + signal_block_expr(lctx, + vec![], + placer_expr, + e.span, + hir::PopUnstableBlock)); + + // let mut place = Placer::make_place(placer); + let s2 = { + let call = make_call(lctx, + &make_place, + vec![expr_ident(lctx, e.span, placer_ident)]); + mk_stmt_let_mut(lctx, agent_ident, call) + }; + + // let p_ptr = Place::pointer(&mut place); + let s3 = { + let args = vec![expr_mut_addr_of(lctx, + e.span, + expr_ident(lctx, e.span, agent_ident))]; + let call = make_call(lctx, &place_pointer, args); + mk_stmt_let(lctx, p_ptr_ident, call) + }; + + // pop_unsafe!(EXPR)); + let pop_unsafe_expr = + signal_block_expr(lctx, + vec![], + signal_block_expr(lctx, + vec![], + value_expr, + e.span, + hir::PopUnstableBlock), + e.span, + hir::PopUnsafeBlock(hir::CompilerGenerated)); + + // push_unsafe!({ + // std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR )); + // InPlace::finalize(place) + // }) + let expr = { + let call_move_val_init = hir::StmtSemi(make_call(lctx, + &move_val_init, + vec![expr_ident(lctx, e.span, p_ptr_ident), + pop_unsafe_expr]), + lctx.next_id()); + let call_move_val_init = respan(e.span, call_move_val_init); + + let call = make_call(lctx, + &inplace_finalize, + vec![expr_ident(lctx, e.span, agent_ident)]); + signal_block_expr(lctx, + vec![P(call_move_val_init)], + call, + e.span, + hir::PushUnsafeBlock(hir::CompilerGenerated)) + }; + + return signal_block_expr(lctx, + vec![s1, s2, s3], + expr, + e.span, + hir::PushUnstableBlock); + } + + ExprVec(ref exprs) => { + hir::ExprVec(exprs.iter().map(|x| lower_expr(lctx, x)).collect()) + } + ExprRepeat(ref expr, ref count) => { + hir::ExprRepeat(lower_expr(lctx, expr), lower_expr(lctx, count)) + } + ExprTup(ref elts) => { + hir::ExprTup(elts.iter().map(|x| lower_expr(lctx, x)).collect()) + } + ExprCall(ref f, ref args) => { + hir::ExprCall(lower_expr(lctx, f), + args.iter().map(|x| lower_expr(lctx, x)).collect()) + } + ExprMethodCall(i, ref tps, ref args) => { + hir::ExprMethodCall(respan(i.span, i.node.name), + tps.iter().map(|x| lower_ty(lctx, x)).collect(), + args.iter().map(|x| lower_expr(lctx, x)).collect()) + } + ExprBinary(binop, ref lhs, ref rhs) => { + hir::ExprBinary(lower_binop(lctx, binop), + lower_expr(lctx, lhs), + lower_expr(lctx, rhs)) + } + ExprUnary(op, ref ohs) => { + hir::ExprUnary(lower_unop(lctx, op), lower_expr(lctx, ohs)) + } + ExprLit(ref l) => hir::ExprLit(P((**l).clone())), + ExprCast(ref expr, ref ty) => { + hir::ExprCast(lower_expr(lctx, expr), lower_ty(lctx, ty)) + } + ExprAddrOf(m, ref ohs) => { + hir::ExprAddrOf(lower_mutability(lctx, m), lower_expr(lctx, ohs)) + } + // More complicated than you might expect because the else branch + // might be `if let`. + ExprIf(ref cond, ref blk, ref else_opt) => { + let else_opt = else_opt.as_ref().map(|els| { + match els.node { + ExprIfLet(..) => { + let _old_cached = CachedIdSetter::new(lctx, e.id); + // wrap the if-let expr in a block + let span = els.span; + let blk = P(hir::Block { + stmts: vec![], + expr: Some(lower_expr(lctx, els)), + id: lctx.next_id(), + rules: hir::DefaultBlock, + span: span, + }); + expr_block(lctx, blk) } - }); - hir::ExprPath(qself, lower_path(path)) - } - ExprBreak(opt_ident) => hir::ExprBreak(opt_ident), - ExprAgain(opt_ident) => hir::ExprAgain(opt_ident), - ExprRet(ref e) => hir::ExprRet(e.as_ref().map(|x| lower_expr(x))), - ExprInlineAsm(InlineAsm { + _ => lower_expr(lctx, els), + } + }); + + hir::ExprIf(lower_expr(lctx, cond), + lower_block(lctx, blk), + else_opt) + } + ExprWhile(ref cond, ref body, opt_ident) => { + hir::ExprWhile(lower_expr(lctx, cond), + lower_block(lctx, body), + opt_ident) + } + ExprLoop(ref body, opt_ident) => { + hir::ExprLoop(lower_block(lctx, body), opt_ident) + } + ExprMatch(ref expr, ref arms) => { + hir::ExprMatch(lower_expr(lctx, expr), + arms.iter().map(|x| lower_arm(lctx, x)).collect(), + hir::MatchSource::Normal) + } + ExprClosure(capture_clause, ref decl, ref body) => { + hir::ExprClosure(lower_capture_clause(lctx, capture_clause), + lower_fn_decl(lctx, decl), + lower_block(lctx, body)) + } + ExprBlock(ref blk) => hir::ExprBlock(lower_block(lctx, blk)), + ExprAssign(ref el, ref er) => { + hir::ExprAssign(lower_expr(lctx, el), lower_expr(lctx, er)) + } + ExprAssignOp(op, ref el, ref er) => { + hir::ExprAssignOp(lower_binop(lctx, op), + lower_expr(lctx, el), + lower_expr(lctx, er)) + } + ExprField(ref el, ident) => { + hir::ExprField(lower_expr(lctx, el), + respan(ident.span, ident.node.name)) + } + ExprTupField(ref el, ident) => { + hir::ExprTupField(lower_expr(lctx, el), ident) + } + ExprIndex(ref el, ref er) => { + hir::ExprIndex(lower_expr(lctx, el), lower_expr(lctx, er)) + } + ExprRange(ref e1, ref e2) => { + hir::ExprRange(e1.as_ref().map(|x| lower_expr(lctx, x)), + e2.as_ref().map(|x| lower_expr(lctx, x))) + } + ExprPath(ref qself, ref path) => { + let qself = qself.as_ref().map(|&QSelf { ref ty, position }| { + hir::QSelf { + ty: lower_ty(lctx, ty), + position: position, + } + }); + hir::ExprPath(qself, lower_path(lctx, path)) + } + ExprBreak(opt_ident) => hir::ExprBreak(opt_ident), + ExprAgain(opt_ident) => hir::ExprAgain(opt_ident), + ExprRet(ref e) => hir::ExprRet(e.as_ref().map(|x| lower_expr(lctx, x))), + ExprInlineAsm(InlineAsm { ref inputs, ref outputs, ref asm, @@ -884,250 +1168,690 @@ pub fn lower_expr(e: &Expr) -> P { dialect, expn_id, }) => hir::ExprInlineAsm(hir::InlineAsm { - inputs: inputs.iter().map(|&(ref c, ref input)| { - (c.clone(), lower_expr(input)) - }).collect(), - outputs: outputs.iter().map(|&(ref c, ref out, ref is_rw)| { - (c.clone(), lower_expr(out), *is_rw) - }).collect(), - asm: asm.clone(), - asm_str_style: lower_string_style(asm_str_style), - clobbers: clobbers.clone(), - volatile: volatile, - alignstack: alignstack, - dialect: lower_asm_dialect(dialect), - expn_id: expn_id, - }), - ExprStruct(ref path, ref fields, ref maybe_expr) => { - hir::ExprStruct(lower_path(path), - fields.iter().map(|x| lower_field(x)).collect(), - maybe_expr.as_ref().map(|x| lower_expr(x))) - }, - ExprParen(ref ex) => hir::ExprParen(lower_expr(ex)), - ExprIfLet(..) | - ExprWhileLet(..) | - ExprForLoop(..) | - ExprMac(_) => panic!("Shouldn't exist here"), - }, - span: e.span, - }) -} - -pub fn lower_stmt(s: &Stmt) -> P { + inputs: inputs.iter() + .map(|&(ref c, ref input)| (c.clone(), lower_expr(lctx, input))) + .collect(), + outputs: outputs.iter() + .map(|&(ref c, ref out, ref is_rw)| { + (c.clone(), lower_expr(lctx, out), *is_rw) + }) + .collect(), + asm: asm.clone(), + asm_str_style: asm_str_style, + clobbers: clobbers.clone(), + volatile: volatile, + alignstack: alignstack, + dialect: dialect, + expn_id: expn_id, + }), + ExprStruct(ref path, ref fields, ref maybe_expr) => { + hir::ExprStruct(lower_path(lctx, path), + fields.iter().map(|x| lower_field(lctx, x)).collect(), + maybe_expr.as_ref().map(|x| lower_expr(lctx, x))) + } + ExprParen(ref ex) => { + return lower_expr(lctx, ex); + } + + // Desugar ExprIfLet + // From: `if let = []` + ExprIfLet(ref pat, ref sub_expr, ref body, ref else_opt) => { + // to: + // + // match { + // => , + // [_ if => ,] + // _ => [ | ()] + // } + + let _old_cached = CachedIdSetter::new(lctx, e.id); + + // ` => ` + let pat_arm = { + let body_expr = expr_block(lctx, lower_block(lctx, body)); + arm(vec![lower_pat(lctx, pat)], body_expr) + }; + + // `[_ if => ,]` + let mut else_opt = else_opt.as_ref().map(|e| lower_expr(lctx, e)); + let else_if_arms = { + let mut arms = vec![]; + loop { + let else_opt_continue = else_opt.and_then(|els| { + els.and_then(|els| { + match els.node { + // else if + hir::ExprIf(cond, then, else_opt) => { + let pat_under = pat_wild(lctx, e.span); + arms.push(hir::Arm { + attrs: vec![], + pats: vec![pat_under], + guard: Some(cond), + body: expr_block(lctx, then), + }); + else_opt.map(|else_opt| (else_opt, true)) + } + _ => Some((P(els), false)), + } + }) + }); + match else_opt_continue { + Some((e, true)) => { + else_opt = Some(e); + } + Some((e, false)) => { + else_opt = Some(e); + break; + } + None => { + else_opt = None; + break; + } + } + } + arms + }; + + let contains_else_clause = else_opt.is_some(); + + // `_ => [ | ()]` + let else_arm = { + let pat_under = pat_wild(lctx, e.span); + let else_expr = else_opt.unwrap_or_else(|| expr_tuple(lctx, e.span, vec![])); + arm(vec![pat_under], else_expr) + }; + + let mut arms = Vec::with_capacity(else_if_arms.len() + 2); + arms.push(pat_arm); + arms.extend(else_if_arms); + arms.push(else_arm); + + let match_expr = expr(lctx, + e.span, + hir::ExprMatch(lower_expr(lctx, sub_expr), + arms, + hir::MatchSource::IfLetDesugar { + contains_else_clause: contains_else_clause, + })); + return match_expr; + } + + // Desugar ExprWhileLet + // From: `[opt_ident]: while let = ` + ExprWhileLet(ref pat, ref sub_expr, ref body, opt_ident) => { + // to: + // + // [opt_ident]: loop { + // match { + // => , + // _ => break + // } + // } + + let _old_cached = CachedIdSetter::new(lctx, e.id); + + // ` => ` + let pat_arm = { + let body_expr = expr_block(lctx, lower_block(lctx, body)); + arm(vec![lower_pat(lctx, pat)], body_expr) + }; + + // `_ => break` + let break_arm = { + let pat_under = pat_wild(lctx, e.span); + let break_expr = expr_break(lctx, e.span); + arm(vec![pat_under], break_expr) + }; + + // `match { ... }` + let arms = vec![pat_arm, break_arm]; + let match_expr = expr(lctx, + e.span, + hir::ExprMatch(lower_expr(lctx, sub_expr), + arms, + hir::MatchSource::WhileLetDesugar)); + + // `[opt_ident]: loop { ... }` + let loop_block = block_expr(lctx, match_expr); + return expr(lctx, e.span, hir::ExprLoop(loop_block, opt_ident)); + } + + // Desugar ExprForLoop + // From: `[opt_ident]: for in ` + ExprForLoop(ref pat, ref head, ref body, opt_ident) => { + // to: + // + // { + // let result = match ::std::iter::IntoIterator::into_iter() { + // mut iter => { + // [opt_ident]: loop { + // match ::std::iter::Iterator::next(&mut iter) { + // ::std::option::Option::Some() => , + // ::std::option::Option::None => break + // } + // } + // } + // }; + // result + // } + + let _old_cached = CachedIdSetter::new(lctx, e.id); + + // expand + let head = lower_expr(lctx, head); + + let iter = lctx.str_to_ident("iter"); + + // `::std::option::Option::Some() => ` + let pat_arm = { + let body_block = lower_block(lctx, body); + let body_span = body_block.span; + let body_expr = P(hir::Expr { + id: lctx.next_id(), + node: hir::ExprBlock(body_block), + span: body_span, + }); + let pat = lower_pat(lctx, pat); + let some_pat = pat_some(lctx, e.span, pat); + + arm(vec![some_pat], body_expr) + }; + + // `::std::option::Option::None => break` + let break_arm = { + let break_expr = expr_break(lctx, e.span); + + arm(vec![pat_none(lctx, e.span)], break_expr) + }; + + // `match ::std::iter::Iterator::next(&mut iter) { ... }` + let match_expr = { + let next_path = { + let strs = std_path(lctx, &["iter", "Iterator", "next"]); + + path_global(e.span, strs) + }; + let ref_mut_iter = expr_mut_addr_of(lctx, + e.span, + expr_ident(lctx, e.span, iter)); + let next_expr = expr_call(lctx, + e.span, + expr_path(lctx, next_path), + vec![ref_mut_iter]); + let arms = vec![pat_arm, break_arm]; + + expr(lctx, + e.span, + hir::ExprMatch(next_expr, arms, hir::MatchSource::ForLoopDesugar)) + }; + + // `[opt_ident]: loop { ... }` + let loop_block = block_expr(lctx, match_expr); + let loop_expr = expr(lctx, e.span, hir::ExprLoop(loop_block, opt_ident)); + + // `mut iter => { ... }` + let iter_arm = { + let iter_pat = pat_ident_binding_mode(lctx, + e.span, + iter, + hir::BindByValue(hir::MutMutable)); + arm(vec![iter_pat], loop_expr) + }; + + // `match ::std::iter::IntoIterator::into_iter() { ... }` + let into_iter_expr = { + let into_iter_path = { + let strs = std_path(lctx, &["iter", "IntoIterator", "into_iter"]); + + path_global(e.span, strs) + }; + + expr_call(lctx, + e.span, + expr_path(lctx, into_iter_path), + vec![head]) + }; + + let match_expr = expr_match(lctx, + e.span, + into_iter_expr, + vec![iter_arm], + hir::MatchSource::ForLoopDesugar); + + // `{ let result = ...; result }` + let result_ident = lctx.str_to_ident("result"); + return expr_block(lctx, + block_all(lctx, + e.span, + vec![stmt_let(lctx, + e.span, + false, + result_ident, + match_expr)], + Some(expr_ident(lctx, e.span, result_ident)))) + } + + ExprMac(_) => panic!("Shouldn't exist here"), + }, + span: e.span, + }) +} + +pub fn lower_stmt(_lctx: &LoweringContext, s: &Stmt) -> P { match s.node { StmtDecl(ref d, id) => { P(Spanned { - node: hir::StmtDecl(lower_decl(d), id), - span: s.span + node: hir::StmtDecl(lower_decl(_lctx, d), id), + span: s.span, }) } StmtExpr(ref e, id) => { P(Spanned { - node: hir::StmtExpr(lower_expr(e), id), - span: s.span + node: hir::StmtExpr(lower_expr(_lctx, e), id), + span: s.span, }) } StmtSemi(ref e, id) => { P(Spanned { - node: hir::StmtSemi(lower_expr(e), id), - span: s.span + node: hir::StmtSemi(lower_expr(_lctx, e), id), + span: s.span, }) } - StmtMac(..) => panic!("Shouldn't exist here") - } -} - -pub fn lower_string_style(s: StrStyle) -> hir::StrStyle { - match s { - CookedStr => hir::CookedStr, - RawStr(u) => hir::RawStr(u), - } -} - -pub fn unlower_string_style(s: hir::StrStyle) -> StrStyle { - match s { - hir::CookedStr => CookedStr, - hir::RawStr(u) => RawStr(u), - } -} - -pub fn lower_match_source(m: &MatchSource) -> hir::MatchSource { - match *m { - MatchSource::Normal => hir::MatchSource::Normal, - MatchSource::IfLetDesugar { contains_else_clause } => { - hir::MatchSource::IfLetDesugar { contains_else_clause: contains_else_clause } - } - MatchSource::WhileLetDesugar => hir::MatchSource::WhileLetDesugar, - MatchSource::ForLoopDesugar => hir::MatchSource::ForLoopDesugar, + StmtMac(..) => panic!("Shouldn't exist here"), } } -pub fn lower_capture_clause(c: CaptureClause) -> hir::CaptureClause { +pub fn lower_capture_clause(_lctx: &LoweringContext, c: CaptureClause) -> hir::CaptureClause { match c { CaptureByValue => hir::CaptureByValue, CaptureByRef => hir::CaptureByRef, } } -pub fn lower_asm_dialect(a: AsmDialect) -> hir::AsmDialect { - match a { - AsmAtt => hir::AsmAtt, - AsmIntel => hir::AsmIntel, - } -} - -pub fn lower_visibility(v: Visibility) -> hir::Visibility { +pub fn lower_visibility(_lctx: &LoweringContext, v: Visibility) -> hir::Visibility { match v { Public => hir::Public, Inherited => hir::Inherited, } } -pub fn lower_block_check_mode(b: &BlockCheckMode) -> hir::BlockCheckMode { +pub fn lower_block_check_mode(_lctx: &LoweringContext, b: &BlockCheckMode) -> hir::BlockCheckMode { match *b { DefaultBlock => hir::DefaultBlock, - UnsafeBlock(u) => hir::UnsafeBlock(lower_unsafe_source(u)), - PushUnsafeBlock(u) => hir::PushUnsafeBlock(lower_unsafe_source(u)), - PopUnsafeBlock(u) => hir::PopUnsafeBlock(lower_unsafe_source(u)), + UnsafeBlock(u) => hir::UnsafeBlock(lower_unsafe_source(_lctx, u)), } } -pub fn lower_pat_wild_kind(p: PatWildKind) -> hir::PatWildKind { +pub fn lower_pat_wild_kind(_lctx: &LoweringContext, p: PatWildKind) -> hir::PatWildKind { match p { PatWildSingle => hir::PatWildSingle, PatWildMulti => hir::PatWildMulti, } } -pub fn lower_binding_mode(b: &BindingMode) -> hir::BindingMode { +pub fn lower_binding_mode(_lctx: &LoweringContext, b: &BindingMode) -> hir::BindingMode { match *b { - BindByRef(m) => hir::BindByRef(lower_mutability(m)), - BindByValue(m) => hir::BindByValue(lower_mutability(m)), + BindByRef(m) => hir::BindByRef(lower_mutability(_lctx, m)), + BindByValue(m) => hir::BindByValue(lower_mutability(_lctx, m)), } } -pub fn lower_struct_field_kind(s: &StructFieldKind) -> hir::StructFieldKind { +pub fn lower_struct_field_kind(_lctx: &LoweringContext, + s: &StructFieldKind) + -> hir::StructFieldKind { match *s { - NamedField(ident, vis) => hir::NamedField(ident, lower_visibility(vis)), - UnnamedField(vis) => hir::UnnamedField(lower_visibility(vis)), + NamedField(ident, vis) => hir::NamedField(ident.name, lower_visibility(_lctx, vis)), + UnnamedField(vis) => hir::UnnamedField(lower_visibility(_lctx, vis)), } } -pub fn lower_unsafe_source(u: UnsafeSource) -> hir::UnsafeSource { +pub fn lower_unsafe_source(_lctx: &LoweringContext, u: UnsafeSource) -> hir::UnsafeSource { match u { CompilerGenerated => hir::CompilerGenerated, UserProvided => hir::UserProvided, } } -pub fn lower_impl_polarity(i: ImplPolarity) -> hir::ImplPolarity { +pub fn lower_impl_polarity(_lctx: &LoweringContext, i: ImplPolarity) -> hir::ImplPolarity { match i { ImplPolarity::Positive => hir::ImplPolarity::Positive, ImplPolarity::Negative => hir::ImplPolarity::Negative, } } -pub fn lower_float_ty(f: FloatTy) -> hir::FloatTy { +pub fn lower_trait_bound_modifier(_lctx: &LoweringContext, + f: TraitBoundModifier) + -> hir::TraitBoundModifier { match f { - TyF32 => hir::TyF32, - TyF64 => hir::TyF64, + TraitBoundModifier::None => hir::TraitBoundModifier::None, + TraitBoundModifier::Maybe => hir::TraitBoundModifier::Maybe, } } -pub fn unlower_float_ty(f: hir::FloatTy) -> FloatTy { - match f { - hir::TyF32 => TyF32, - hir::TyF64 => TyF64, +// Helper methods for building HIR. + +fn arm(pats: Vec>, expr: P) -> hir::Arm { + hir::Arm { + attrs: vec!(), + pats: pats, + guard: None, + body: expr, } } -pub fn lower_lit_int_type(i: &LitIntType) -> hir::LitIntType { - match *i { - SignedIntLit(i, s) => hir::SignedIntLit(lower_int_ty(i), lower_sign(s)), - UnsignedIntLit(u) => hir::UnsignedIntLit(lower_uint_ty(u)), - UnsuffixedIntLit(s) => hir::UnsuffixedIntLit(lower_sign(s)), - } +fn expr_break(lctx: &LoweringContext, span: Span) -> P { + expr(lctx, span, hir::ExprBreak(None)) } -pub fn unlower_lit_int_type(i: &hir::LitIntType) -> LitIntType { - match *i { - hir::SignedIntLit(i, s) => SignedIntLit(unlower_int_ty(i), unlower_sign(s)), - hir::UnsignedIntLit(u) => UnsignedIntLit(unlower_uint_ty(u)), - hir::UnsuffixedIntLit(s) => UnsuffixedIntLit(unlower_sign(s)), - } +fn expr_call(lctx: &LoweringContext, + span: Span, + e: P, + args: Vec>) + -> P { + expr(lctx, span, hir::ExprCall(e, args)) } -pub fn lower_int_ty(i: IntTy) -> hir::IntTy { - match i { - TyIs => hir::TyIs, - TyI8 => hir::TyI8, - TyI16 => hir::TyI16, - TyI32 => hir::TyI32, - TyI64 => hir::TyI64, - } +fn expr_ident(lctx: &LoweringContext, span: Span, id: Ident) -> P { + expr_path(lctx, path_ident(span, id)) } -pub fn unlower_int_ty(i: hir::IntTy) -> IntTy { - match i { - hir::TyIs => TyIs, - hir::TyI8 => TyI8, - hir::TyI16 => TyI16, - hir::TyI32 => TyI32, - hir::TyI64 => TyI64, - } +fn expr_mut_addr_of(lctx: &LoweringContext, span: Span, e: P) -> P { + expr(lctx, span, hir::ExprAddrOf(hir::MutMutable, e)) } -pub fn lower_uint_ty(u: UintTy) -> hir::UintTy { - match u { - TyUs => hir::TyUs, - TyU8 => hir::TyU8, - TyU16 => hir::TyU16, - TyU32 => hir::TyU32, - TyU64 => hir::TyU64, - } +fn expr_path(lctx: &LoweringContext, path: hir::Path) -> P { + expr(lctx, path.span, hir::ExprPath(None, path)) } -pub fn unlower_uint_ty(u: hir::UintTy) -> UintTy { - match u { - hir::TyUs => TyUs, - hir::TyU8 => TyU8, - hir::TyU16 => TyU16, - hir::TyU32 => TyU32, - hir::TyU64 => TyU64, - } +fn expr_match(lctx: &LoweringContext, + span: Span, + arg: P, + arms: Vec, + source: hir::MatchSource) + -> P { + expr(lctx, + span, + hir::ExprMatch(arg, arms, source)) } -pub fn lower_sign(f: Sign) -> hir::Sign { - match f { - Minus => hir::Minus, - Plus => hir::Plus, - } +fn expr_block(lctx: &LoweringContext, b: P) -> P { + expr(lctx, b.span, hir::ExprBlock(b)) } -pub fn unlower_sign(f: hir::Sign) -> Sign { - match f { - hir::Minus => Minus, - hir::Plus => Plus, - } +fn expr_tuple(lctx: &LoweringContext, sp: Span, exprs: Vec>) -> P { + expr(lctx, sp, hir::ExprTup(exprs)) } -pub fn lower_trait_bound_modifier(f: TraitBoundModifier) -> hir::TraitBoundModifier { - match f { - TraitBoundModifier::None => hir::TraitBoundModifier::None, - TraitBoundModifier::Maybe => hir::TraitBoundModifier::Maybe, +fn expr(lctx: &LoweringContext, span: Span, node: hir::Expr_) -> P { + P(hir::Expr { + id: lctx.next_id(), + node: node, + span: span, + }) +} + +fn stmt_let(lctx: &LoweringContext, + sp: Span, + mutbl: bool, + ident: Ident, + ex: P) + -> P { + let pat = if mutbl { + pat_ident_binding_mode(lctx, sp, ident, hir::BindByValue(hir::MutMutable)) + } else { + pat_ident(lctx, sp, ident) + }; + let local = P(hir::Local { + pat: pat, + ty: None, + init: Some(ex), + id: lctx.next_id(), + span: sp, + }); + let decl = respan(sp, hir::DeclLocal(local)); + P(respan(sp, hir::StmtDecl(P(decl), lctx.next_id()))) +} + +fn block_expr(lctx: &LoweringContext, expr: P) -> P { + block_all(lctx, expr.span, Vec::new(), Some(expr)) +} + +fn block_all(lctx: &LoweringContext, + span: Span, + stmts: Vec>, + expr: Option>) + -> P { + P(hir::Block { + stmts: stmts, + expr: expr, + id: lctx.next_id(), + rules: hir::DefaultBlock, + span: span, + }) +} + +fn pat_some(lctx: &LoweringContext, span: Span, pat: P) -> P { + let some = std_path(lctx, &["option", "Option", "Some"]); + let path = path_global(span, some); + pat_enum(lctx, span, path, vec!(pat)) +} + +fn pat_none(lctx: &LoweringContext, span: Span) -> P { + let none = std_path(lctx, &["option", "Option", "None"]); + let path = path_global(span, none); + pat_enum(lctx, span, path, vec![]) +} + +fn pat_enum(lctx: &LoweringContext, + span: Span, + path: hir::Path, + subpats: Vec>) + -> P { + let pt = hir::PatEnum(path, Some(subpats)); + pat(lctx, span, pt) +} + +fn pat_ident(lctx: &LoweringContext, span: Span, ident: Ident) -> P { + pat_ident_binding_mode(lctx, span, ident, hir::BindByValue(hir::MutImmutable)) +} + +fn pat_ident_binding_mode(lctx: &LoweringContext, + span: Span, + ident: Ident, + bm: hir::BindingMode) + -> P { + let pat_ident = hir::PatIdent(bm, + Spanned { + span: span, + node: ident, + }, + None); + pat(lctx, span, pat_ident) +} + +fn pat_wild(lctx: &LoweringContext, span: Span) -> P { + pat(lctx, span, hir::PatWild(hir::PatWildSingle)) +} + +fn pat(lctx: &LoweringContext, span: Span, pat: hir::Pat_) -> P { + P(hir::Pat { + id: lctx.next_id(), + node: pat, + span: span, + }) +} + +fn path_ident(span: Span, id: Ident) -> hir::Path { + path(span, vec!(id)) +} + +fn path(span: Span, strs: Vec) -> hir::Path { + path_all(span, false, strs, Vec::new(), Vec::new(), Vec::new()) +} + +fn path_global(span: Span, strs: Vec) -> hir::Path { + path_all(span, true, strs, Vec::new(), Vec::new(), Vec::new()) +} + +fn path_all(sp: Span, + global: bool, + mut idents: Vec, + lifetimes: Vec, + types: Vec>, + bindings: Vec>) + -> hir::Path { + let last_identifier = idents.pop().unwrap(); + let mut segments: Vec = idents.into_iter() + .map(|ident| { + hir::PathSegment { + identifier: ident, + parameters: hir::PathParameters::none(), + } + }) + .collect(); + segments.push(hir::PathSegment { + identifier: last_identifier, + parameters: hir::AngleBracketedParameters(hir::AngleBracketedParameterData { + lifetimes: lifetimes, + types: OwnedSlice::from_vec(types), + bindings: OwnedSlice::from_vec(bindings), + }), + }); + hir::Path { + span: sp, + global: global, + segments: segments, } } -pub fn lower_attr_style(f: AttrStyle) -> hir::AttrStyle { - match f { - AttrOuter => hir::AttrOuter, - AttrInner => hir::AttrInner, +fn std_path(lctx: &LoweringContext, components: &[&str]) -> Vec { + let mut v = Vec::new(); + if let Some(s) = lctx.crate_root { + v.push(str_to_ident(s)); } + v.extend(components.iter().map(|s| str_to_ident(s))); + return v } -pub fn unlower_attr_style(f: hir::AttrStyle) -> AttrStyle { - match f { - hir::AttrOuter => AttrOuter, - hir::AttrInner => AttrInner, +// Given suffix ["b","c","d"], returns path `::std::b::c::d` when +// `fld.cx.use_std`, and `::core::b::c::d` otherwise. +fn core_path(lctx: &LoweringContext, span: Span, components: &[&str]) -> hir::Path { + let idents = std_path(lctx, components); + path_global(span, idents) +} + +fn signal_block_expr(lctx: &LoweringContext, + stmts: Vec>, + expr: P, + span: Span, + rule: hir::BlockCheckMode) + -> P { + expr_block(lctx, + P(hir::Block { + rules: rule, + span: span, + id: lctx.next_id(), + stmts: stmts, + expr: Some(expr), + })) +} + + + +#[cfg(test)] +mod test { + use super::*; + use syntax::ast::{self, NodeId, NodeIdAssigner}; + use syntax::{parse, codemap}; + use syntax::fold::Folder; + use std::cell::Cell; + + struct MockAssigner { + next_id: Cell, + } + + impl MockAssigner { + fn new() -> MockAssigner { + MockAssigner { + next_id: Cell::new(0), + } + } + } + + trait FakeExtCtxt { + fn call_site(&self) -> codemap::Span; + fn cfg(&self) -> ast::CrateConfig; + fn ident_of(&self, st: &str) -> ast::Ident; + fn name_of(&self, st: &str) -> ast::Name; + fn parse_sess(&self) -> &parse::ParseSess; + } + + impl FakeExtCtxt for parse::ParseSess { + fn call_site(&self) -> codemap::Span { + codemap::Span { + lo: codemap::BytePos(0), + hi: codemap::BytePos(0), + expn_id: codemap::NO_EXPANSION, + } + } + fn cfg(&self) -> ast::CrateConfig { Vec::new() } + fn ident_of(&self, st: &str) -> ast::Ident { + parse::token::str_to_ident(st) + } + fn name_of(&self, st: &str) -> ast::Name { + parse::token::intern(st) + } + fn parse_sess(&self) -> &parse::ParseSess { self } + } + + impl NodeIdAssigner for MockAssigner { + fn next_node_id(&self) -> NodeId { + let result = self.next_id.get(); + self.next_id.set(result + 1); + result + } + + fn peek_node_id(&self) -> NodeId { + self.next_id.get() + } + } + + impl Folder for MockAssigner { + fn new_id(&mut self, old_id: NodeId) -> NodeId { + assert_eq!(old_id, ast::DUMMY_NODE_ID); + self.next_node_id() + } + } + + #[test] + fn test_preserves_ids() { + let cx = parse::ParseSess::new(); + let mut assigner = MockAssigner::new(); + + let ast_if_let = quote_expr!(&cx, if let Some(foo) = baz { bar(foo); }); + let ast_if_let = assigner.fold_expr(ast_if_let); + let ast_while_let = quote_expr!(&cx, while let Some(foo) = baz { bar(foo); }); + let ast_while_let = assigner.fold_expr(ast_while_let); + let ast_for = quote_expr!(&cx, for i in 0..10 { foo(i); }); + let ast_for = assigner.fold_expr(ast_for); + let ast_in = quote_expr!(&cx, in HEAP { foo() }); + let ast_in = assigner.fold_expr(ast_in); + + let lctx = LoweringContext::new(&assigner, None); + let hir1 = lower_expr(&lctx, &ast_if_let); + let hir2 = lower_expr(&lctx, &ast_if_let); + assert!(hir1 == hir2); + + let hir1 = lower_expr(&lctx, &ast_while_let); + let hir2 = lower_expr(&lctx, &ast_while_let); + assert!(hir1 == hir2); + + let hir1 = lower_expr(&lctx, &ast_for); + let hir2 = lower_expr(&lctx, &ast_for); + assert!(hir1 == hir2); + + let hir1 = lower_expr(&lctx, &ast_in); + let hir2 = lower_expr(&lctx, &ast_in); + assert!(hir1 == hir2); } } diff --git a/src/librustc_front/print/pp.rs b/src/librustc_front/print/pp.rs deleted file mode 100644 index 7c5a46465f..0000000000 --- a/src/librustc_front/print/pp.rs +++ /dev/null @@ -1,686 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! This pretty-printer is a direct reimplementation of Philip Karlton's -//! Mesa pretty-printer, as described in appendix A of -//! -//! STAN-CS-79-770: "Pretty Printing", by Derek C. Oppen. -//! Stanford Department of Computer Science, 1979. -//! -//! The algorithm's aim is to break a stream into as few lines as possible -//! while respecting the indentation-consistency requirements of the enclosing -//! block, and avoiding breaking at silly places on block boundaries, for -//! example, between "x" and ")" in "x)". -//! -//! I am implementing this algorithm because it comes with 20 pages of -//! documentation explaining its theory, and because it addresses the set of -//! concerns I've seen other pretty-printers fall down on. Weirdly. Even though -//! it's 32 years old. What can I say? -//! -//! Despite some redundancies and quirks in the way it's implemented in that -//! paper, I've opted to keep the implementation here as similar as I can, -//! changing only what was blatantly wrong, a typo, or sufficiently -//! non-idiomatic rust that it really stuck out. -//! -//! In particular you'll see a certain amount of churn related to INTEGER vs. -//! CARDINAL in the Mesa implementation. Mesa apparently interconverts the two -//! somewhat readily? In any case, I've used usize for indices-in-buffers and -//! ints for character-sizes-and-indentation-offsets. This respects the need -//! for ints to "go negative" while carrying a pending-calculation balance, and -//! helps differentiate all the numbers flying around internally (slightly). -//! -//! I also inverted the indentation arithmetic used in the print stack, since -//! the Mesa implementation (somewhat randomly) stores the offset on the print -//! stack in terms of margin-col rather than col itself. I store col. -//! -//! I also implemented a small change in the String token, in that I store an -//! explicit length for the string. For most tokens this is just the length of -//! the accompanying string. But it's necessary to permit it to differ, for -//! encoding things that are supposed to "go on their own line" -- certain -//! classes of comment and blank-line -- where relying on adjacent -//! hardbreak-like Break tokens with long blankness indication doesn't actually -//! work. To see why, consider when there is a "thing that should be on its own -//! line" between two long blocks, say functions. If you put a hardbreak after -//! each function (or before each) and the breaking algorithm decides to break -//! there anyways (because the functions themselves are long) you wind up with -//! extra blank lines. If you don't put hardbreaks you can wind up with the -//! "thing which should be on its own line" not getting its own line in the -//! rare case of "really small functions" or such. This re-occurs with comments -//! and explicit blank lines. So in those cases we use a string with a payload -//! we want isolated to a line and an explicit length that's huge, surrounded -//! by two zero-length breaks. The algorithm will try its best to fit it on a -//! line (which it can't) and so naturally place the content on its own line to -//! avoid combining it with other lines and making matters even worse. - -use std::io; -use std::string; - -#[derive(Clone, Copy, PartialEq)] -pub enum Breaks { - Consistent, - Inconsistent, -} - -#[derive(Clone, Copy)] -pub struct BreakToken { - offset: isize, - blank_space: isize -} - -#[derive(Clone, Copy)] -pub struct BeginToken { - offset: isize, - breaks: Breaks -} - -#[derive(Clone)] -pub enum Token { - String(String, isize), - Break(BreakToken), - Begin(BeginToken), - End, - Eof, -} - -impl Token { - pub fn is_eof(&self) -> bool { - match *self { - Token::Eof => true, - _ => false, - } - } - - pub fn is_hardbreak_tok(&self) -> bool { - match *self { - Token::Break(BreakToken { - offset: 0, - blank_space: bs - }) if bs == SIZE_INFINITY => - true, - _ => - false - } - } -} - -pub fn tok_str(token: &Token) -> String { - match *token { - Token::String(ref s, len) => format!("STR({},{})", s, len), - Token::Break(_) => "BREAK".to_string(), - Token::Begin(_) => "BEGIN".to_string(), - Token::End => "END".to_string(), - Token::Eof => "EOF".to_string() - } -} - -pub fn buf_str(toks: &[Token], - szs: &[isize], - left: usize, - right: usize, - lim: usize) - -> String { - let n = toks.len(); - assert_eq!(n, szs.len()); - let mut i = left; - let mut l = lim; - let mut s = string::String::from("["); - while i != right && l != 0 { - l -= 1; - if i != left { - s.push_str(", "); - } - s.push_str(&format!("{}={}", - szs[i], - tok_str(&toks[i]))); - i += 1; - i %= n; - } - s.push(']'); - s -} - -#[derive(Copy, Clone)] -pub enum PrintStackBreak { - Fits, - Broken(Breaks), -} - -#[derive(Copy, Clone)] -pub struct PrintStackElem { - offset: isize, - pbreak: PrintStackBreak -} - -const SIZE_INFINITY: isize = 0xffff; - -pub fn mk_printer<'a>(out: Box, linewidth: usize) -> Printer<'a> { - // Yes 3, it makes the ring buffers big enough to never - // fall behind. - let n: usize = 3 * linewidth; - debug!("mk_printer {}", linewidth); - let token = vec![Token::Eof; n]; - let size = vec![0_isize; n]; - let scan_stack = vec![0_usize; n]; - Printer { - out: out, - buf_len: n, - margin: linewidth as isize, - space: linewidth as isize, - left: 0, - right: 0, - token: token, - size: size, - left_total: 0, - right_total: 0, - scan_stack: scan_stack, - scan_stack_empty: true, - top: 0, - bottom: 0, - print_stack: Vec::new(), - pending_indentation: 0 - } -} - - -/// In case you do not have the paper, here is an explanation of what's going -/// on. -/// -/// There is a stream of input tokens flowing through this printer. -/// -/// The printer buffers up to 3N tokens inside itself, where N is linewidth. -/// Yes, linewidth is chars and tokens are multi-char, but in the worst -/// case every token worth buffering is 1 char long, so it's ok. -/// -/// Tokens are String, Break, and Begin/End to delimit blocks. -/// -/// Begin tokens can carry an offset, saying "how far to indent when you break -/// inside here", as well as a flag indicating "consistent" or "inconsistent" -/// breaking. Consistent breaking means that after the first break, no attempt -/// will be made to flow subsequent breaks together onto lines. Inconsistent -/// is the opposite. Inconsistent breaking example would be, say: -/// -/// foo(hello, there, good, friends) -/// -/// breaking inconsistently to become -/// -/// foo(hello, there -/// good, friends); -/// -/// whereas a consistent breaking would yield: -/// -/// foo(hello, -/// there -/// good, -/// friends); -/// -/// That is, in the consistent-break blocks we value vertical alignment -/// more than the ability to cram stuff onto a line. But in all cases if it -/// can make a block a one-liner, it'll do so. -/// -/// Carrying on with high-level logic: -/// -/// The buffered tokens go through a ring-buffer, 'tokens'. The 'left' and -/// 'right' indices denote the active portion of the ring buffer as well as -/// describing hypothetical points-in-the-infinite-stream at most 3N tokens -/// apart (i.e. "not wrapped to ring-buffer boundaries"). The paper will switch -/// between using 'left' and 'right' terms to denote the wrapped-to-ring-buffer -/// and point-in-infinite-stream senses freely. -/// -/// There is a parallel ring buffer, 'size', that holds the calculated size of -/// each token. Why calculated? Because for Begin/End pairs, the "size" -/// includes everything between the pair. That is, the "size" of Begin is -/// actually the sum of the sizes of everything between Begin and the paired -/// End that follows. Since that is arbitrarily far in the future, 'size' is -/// being rewritten regularly while the printer runs; in fact most of the -/// machinery is here to work out 'size' entries on the fly (and give up when -/// they're so obviously over-long that "infinity" is a good enough -/// approximation for purposes of line breaking). -/// -/// The "input side" of the printer is managed as an abstract process called -/// SCAN, which uses 'scan_stack', 'scan_stack_empty', 'top' and 'bottom', to -/// manage calculating 'size'. SCAN is, in other words, the process of -/// calculating 'size' entries. -/// -/// The "output side" of the printer is managed by an abstract process called -/// PRINT, which uses 'print_stack', 'margin' and 'space' to figure out what to -/// do with each token/size pair it consumes as it goes. It's trying to consume -/// the entire buffered window, but can't output anything until the size is >= -/// 0 (sizes are set to negative while they're pending calculation). -/// -/// So SCAN takes input and buffers tokens and pending calculations, while -/// PRINT gobbles up completed calculations and tokens from the buffer. The -/// theory is that the two can never get more than 3N tokens apart, because -/// once there's "obviously" too much data to fit on a line, in a size -/// calculation, SCAN will write "infinity" to the size and let PRINT consume -/// it. -/// -/// In this implementation (following the paper, again) the SCAN process is -/// the method called 'pretty_print', and the 'PRINT' process is the method -/// called 'print'. -pub struct Printer<'a> { - pub out: Box, - buf_len: usize, - /// Width of lines we're constrained to - margin: isize, - /// Number of spaces left on line - space: isize, - /// Index of left side of input stream - 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 , - /// Running size of stream "...left" - left_total: isize, - /// Running size of stream "...right" - right_total: isize, - /// Pseudo-stack, really a ring too. Holds the - /// primary-ring-buffers index of the Begin that started the - /// current block, possibly with the most recent Break after that - /// 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: Vec , - /// Top==bottom disambiguator - scan_stack_empty: bool, - /// Index of top of scan_stack - top: usize, - /// Index of bottom of scan_stack - bottom: usize, - /// Stack of blocks-in-progress being flushed by print - print_stack: Vec , - /// Buffered indentation to avoid writing trailing whitespace - pending_indentation: isize, -} - -impl<'a> Printer<'a> { - pub fn last_token(&mut self) -> Token { - self.token[self.right].clone() - } - // be very careful with this! - pub fn replace_last_token(&mut self, t: Token) { - self.token[self.right] = t; - } - pub fn pretty_print(&mut self, token: Token) -> io::Result<()> { - debug!("pp Vec<{},{}>", self.left, self.right); - match token { - Token::Eof => { - if !self.scan_stack_empty { - self.check_stack(0); - try!(self.advance_left()); - } - self.indent(0); - Ok(()) - } - Token::Begin(b) => { - if self.scan_stack_empty { - self.left_total = 1; - self.right_total = 1; - self.left = 0; - self.right = 0; - } 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; - let right = self.right; - self.scan_push(right); - Ok(()) - } - Token::End => { - if self.scan_stack_empty { - debug!("pp End/print Vec<{},{}>", self.left, self.right); - self.print(token, 0) - } else { - debug!("pp End/buffer Vec<{},{}>", self.left, self.right); - self.advance_right(); - self.token[self.right] = token; - self.size[self.right] = -1; - let right = self.right; - self.scan_push(right); - Ok(()) - } - } - Token::Break(b) => { - if self.scan_stack_empty { - self.left_total = 1; - self.right_total = 1; - self.left = 0; - self.right = 0; - } else { self.advance_right(); } - debug!("pp Break({})/buffer Vec<{},{}>", - b.offset, self.left, self.right); - 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.right_total += b.blank_space; - Ok(()) - } - Token::String(s, len) => { - if self.scan_stack_empty { - debug!("pp String('{}')/print Vec<{},{}>", - s, self.left, self.right); - self.print(Token::String(s, len), len) - } else { - 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.right_total += len; - self.check_stream() - } - } - } - } - pub fn check_stream(&mut self) -> io::Result<()> { - debug!("check_stream Vec<{}, {}> with left_total={}, right_total={}", - self.left, self.right, self.left_total, self.right_total); - if self.right_total - self.left_total > self.space { - debug!("scan window is {}, longer than space on line ({})", - self.right_total - self.left_total, self.space); - if !self.scan_stack_empty { - if self.left == self.scan_stack[self.bottom] { - debug!("setting {} to infinity and popping", self.left); - let scanned = self.scan_pop_bottom(); - self.size[scanned] = SIZE_INFINITY; - } - } - try!(self.advance_left()); - if self.left != self.right { - try!(self.check_stream()); - } - } - Ok(()) - } - pub fn scan_push(&mut self, x: usize) { - debug!("scan_push {}", x); - if self.scan_stack_empty { - self.scan_stack_empty = false; - } else { - self.top += 1; - self.top %= self.buf_len; - assert!((self.top != self.bottom)); - } - self.scan_stack[self.top] = x; - } - pub fn scan_pop(&mut self) -> usize { - assert!((!self.scan_stack_empty)); - let x = self.scan_stack[self.top]; - if self.top == self.bottom { - self.scan_stack_empty = true; - } else { - self.top += self.buf_len - 1; self.top %= self.buf_len; - } - return x; - } - pub fn scan_top(&mut self) -> usize { - assert!((!self.scan_stack_empty)); - return self.scan_stack[self.top]; - } - pub fn scan_pop_bottom(&mut self) -> usize { - assert!((!self.scan_stack_empty)); - let x = self.scan_stack[self.bottom]; - if self.top == self.bottom { - self.scan_stack_empty = true; - } else { - self.bottom += 1; self.bottom %= self.buf_len; - } - return x; - } - pub fn advance_right(&mut self) { - self.right += 1; - self.right %= self.buf_len; - assert!((self.right != self.left)); - } - pub fn advance_left(&mut self) -> io::Result<()> { - debug!("advance_left Vec<{},{}>, sizeof({})={}", self.left, self.right, - self.left, self.size[self.left]); - - let mut left_size = self.size[self.left]; - - while left_size >= 0 { - let left = self.token[self.left].clone(); - - let len = match left { - Token::Break(b) => b.blank_space, - Token::String(_, len) => { - assert_eq!(len, left_size); - len - } - _ => 0 - }; - - try!(self.print(left, left_size)); - - self.left_total += len; - - if self.left == self.right { - break; - } - - self.left += 1; - self.left %= self.buf_len; - - left_size = self.size[self.left]; - } - - Ok(()) - } - pub fn check_stack(&mut self, k: isize) { - if !self.scan_stack_empty { - let x = self.scan_top(); - match self.token[x] { - Token::Begin(_) => { - if k > 0 { - let popped = self.scan_pop(); - self.size[popped] = self.size[x] + 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.check_stack(k + 1); - } - _ => { - let popped = self.scan_pop(); - self.size[popped] = self.size[x] + self.right_total; - if k > 0 { - self.check_stack(k); - } - } - } - } - } - pub fn print_newline(&mut self, amount: isize) -> io::Result<()> { - debug!("NEWLINE {}", amount); - let ret = write!(self.out, "\n"); - self.pending_indentation = 0; - self.indent(amount); - return ret; - } - pub fn indent(&mut self, amount: isize) { - debug!("INDENT {}", amount); - self.pending_indentation += amount; - } - pub fn get_top(&mut self) -> PrintStackElem { - let print_stack = &mut self.print_stack; - let n = print_stack.len(); - if n != 0 { - (*print_stack)[n - 1] - } else { - PrintStackElem { - offset: 0, - pbreak: PrintStackBreak::Broken(Breaks::Inconsistent) - } - } - } - pub fn print_str(&mut self, s: &str) -> io::Result<()> { - while self.pending_indentation > 0 { - try!(write!(self.out, " ")); - self.pending_indentation -= 1; - } - write!(self.out, "{}", s) - } - pub fn print(&mut self, token: Token, l: isize) -> io::Result<()> { - debug!("print {} {} (remaining line space={})", tok_str(&token), l, - self.space); - debug!("{}", buf_str(&self.token, - &self.size, - self.left, - self.right, - 6)); - match token { - Token::Begin(b) => { - if l > self.space { - let col = self.margin - self.space + b.offset; - debug!("print Begin -> push broken block at col {}", col); - self.print_stack.push(PrintStackElem { - offset: col, - pbreak: PrintStackBreak::Broken(b.breaks) - }); - } else { - debug!("print Begin -> push fitting block"); - self.print_stack.push(PrintStackElem { - offset: 0, - pbreak: PrintStackBreak::Fits - }); - } - Ok(()) - } - Token::End => { - debug!("print End -> pop End"); - let print_stack = &mut self.print_stack; - assert!((!print_stack.is_empty())); - print_stack.pop().unwrap(); - Ok(()) - } - Token::Break(b) => { - let top = self.get_top(); - match top.pbreak { - PrintStackBreak::Fits => { - debug!("print Break({}) in fitting block", b.blank_space); - self.space -= b.blank_space; - self.indent(b.blank_space); - Ok(()) - } - PrintStackBreak::Broken(Breaks::Consistent) => { - debug!("print Break({}+{}) in consistent block", - top.offset, b.offset); - let ret = self.print_newline(top.offset + b.offset); - self.space = self.margin - (top.offset + b.offset); - ret - } - PrintStackBreak::Broken(Breaks::Inconsistent) => { - if l > self.space { - debug!("print Break({}+{}) w/ newline in inconsistent", - top.offset, b.offset); - let ret = self.print_newline(top.offset + b.offset); - self.space = self.margin - (top.offset + b.offset); - ret - } else { - debug!("print Break({}) w/o newline in inconsistent", - b.blank_space); - self.indent(b.blank_space); - self.space -= b.blank_space; - Ok(()) - } - } - } - } - Token::String(s, len) => { - debug!("print String({})", s); - assert_eq!(l, len); - // assert!(l <= space); - self.space -= len; - self.print_str(&s[..]) - } - Token::Eof => { - // Eof should never get here. - panic!(); - } - } - } -} - -// Convenience functions to talk to the printer. -// -// "raw box" -pub fn rbox(p: &mut Printer, indent: usize, b: Breaks) -> io::Result<()> { - p.pretty_print(Token::Begin(BeginToken { - offset: indent as isize, - breaks: b - })) -} - -pub fn ibox(p: &mut Printer, indent: usize) -> io::Result<()> { - rbox(p, indent, Breaks::Inconsistent) -} - -pub fn cbox(p: &mut Printer, indent: usize) -> io::Result<()> { - rbox(p, indent, Breaks::Consistent) -} - -pub fn break_offset(p: &mut Printer, n: usize, off: isize) -> io::Result<()> { - p.pretty_print(Token::Break(BreakToken { - offset: off, - blank_space: n as isize - })) -} - -pub fn end(p: &mut Printer) -> io::Result<()> { - p.pretty_print(Token::End) -} - -pub fn eof(p: &mut Printer) -> io::Result<()> { - p.pretty_print(Token::Eof) -} - -pub fn word(p: &mut Printer, wrd: &str) -> io::Result<()> { - p.pretty_print(Token::String(/* bad */ wrd.to_string(), wrd.len() as isize)) -} - -pub fn huge_word(p: &mut Printer, wrd: &str) -> io::Result<()> { - p.pretty_print(Token::String(/* bad */ wrd.to_string(), SIZE_INFINITY)) -} - -pub fn zero_word(p: &mut Printer, wrd: &str) -> io::Result<()> { - p.pretty_print(Token::String(/* bad */ wrd.to_string(), 0)) -} - -pub fn spaces(p: &mut Printer, n: usize) -> io::Result<()> { - break_offset(p, n, 0) -} - -pub fn zerobreak(p: &mut Printer) -> io::Result<()> { - spaces(p, 0) -} - -pub fn space(p: &mut Printer) -> io::Result<()> { - spaces(p, 1) -} - -pub fn hardbreak(p: &mut Printer) -> io::Result<()> { - spaces(p, SIZE_INFINITY as usize) -} - -pub fn hardbreak_tok_offset(off: isize) -> Token { - Token::Break(BreakToken {offset: off, blank_space: SIZE_INFINITY}) -} - -pub fn hardbreak_tok() -> Token { - hardbreak_tok_offset(0) -} diff --git a/src/librustc_front/print/pprust.rs b/src/librustc_front/print/pprust.rs index a1382b467f..a3a4bede37 100644 --- a/src/librustc_front/print/pprust.rs +++ b/src/librustc_front/print/pprust.rs @@ -13,26 +13,23 @@ pub use self::AnnNode::*; use syntax::abi; use syntax::ast; use syntax::owned_slice::OwnedSlice; -use syntax::codemap::{self, CodeMap, BytePos}; +use syntax::codemap::{self, CodeMap, BytePos, Spanned}; use syntax::diagnostic; use syntax::parse::token::{self, BinOpToken}; use syntax::parse::lexer::comments; use syntax::parse; -use syntax::print::pp::{self, break_offset, word, space, zerobreak, hardbreak}; +use syntax::print::pp::{self, break_offset, word, space, hardbreak}; use syntax::print::pp::{Breaks, eof}; use syntax::print::pp::Breaks::{Consistent, Inconsistent}; +use syntax::print::pprust::{self as ast_pp, PrintState}; use syntax::ptr::P; use hir; use hir::{RegionTyParamBound, TraitTyParamBound, TraitBoundModifier}; -use attr::{AttrMetaMethods, AttributeMethods}; -use std::ascii; use std::io::{self, Write, Read}; -use std::iter; pub enum AnnNode<'a> { - NodeIdent(&'a ast::Ident), NodeName(&'a ast::Name), NodeBlock(&'a hir::Block), NodeItem(&'a hir::Item), @@ -42,8 +39,12 @@ pub enum AnnNode<'a> { } pub trait PpAnn { - fn pre(&self, _state: &mut State, _node: AnnNode) -> io::Result<()> { Ok(()) } - fn post(&self, _state: &mut State, _node: AnnNode) -> io::Result<()> { Ok(()) } + fn pre(&self, _state: &mut State, _node: AnnNode) -> io::Result<()> { + Ok(()) + } + fn post(&self, _state: &mut State, _node: AnnNode) -> io::Result<()> { + Ok(()) + } } #[derive(Copy, Clone)] @@ -51,37 +52,53 @@ pub struct NoAnn; impl PpAnn for NoAnn {} -#[derive(Copy, Clone)] -pub struct CurrentCommentAndLiteral { - cur_cmnt: usize, - cur_lit: usize, -} pub struct State<'a> { pub s: pp::Printer<'a>, cm: Option<&'a CodeMap>, - comments: Option >, - literals: Option >, - cur_cmnt_and_lit: CurrentCommentAndLiteral, + comments: Option>, + literals: Option>, + cur_cmnt_and_lit: ast_pp::CurrentCommentAndLiteral, boxes: Vec, - ann: &'a (PpAnn+'a), + ann: &'a (PpAnn + 'a), } -pub fn rust_printer<'a>(writer: Box) -> State<'a> { +impl<'a> PrintState<'a> for State<'a> { + fn writer(&mut self) -> &mut pp::Printer<'a> { + &mut self.s + } + + fn boxes(&mut self) -> &mut Vec { + &mut self.boxes + } + + fn comments(&mut self) -> &mut Option> { + &mut self.comments + } + + fn cur_cmnt_and_lit(&mut self) -> &mut ast_pp::CurrentCommentAndLiteral { + &mut self.cur_cmnt_and_lit + } + + fn literals(&self) -> &Option> { + &self.literals + } +} + +pub fn rust_printer<'a>(writer: Box) -> State<'a> { static NO_ANN: NoAnn = NoAnn; rust_printer_annotated(writer, &NO_ANN) } -pub fn rust_printer_annotated<'a>(writer: Box, - ann: &'a PpAnn) -> State<'a> { +pub fn rust_printer_annotated<'a>(writer: Box, ann: &'a PpAnn) -> State<'a> { State { s: pp::mk_printer(writer, default_columns), cm: None, comments: None, literals: None, - cur_cmnt_and_lit: CurrentCommentAndLiteral { + cur_cmnt_and_lit: ast_pp::CurrentCommentAndLiteral { cur_cmnt: 0, - cur_lit: 0 + cur_lit: 0, }, boxes: Vec::new(), ann: ann, @@ -103,16 +120,11 @@ pub fn print_crate<'a>(cm: &'a CodeMap, krate: &hir::Crate, filename: String, input: &mut Read, - out: Box, + out: Box, ann: &'a PpAnn, - is_expanded: bool) -> io::Result<()> { - let mut s = State::new_from_input(cm, - span_diagnostic, - filename, - input, - out, - ann, - is_expanded); + is_expanded: bool) + -> io::Result<()> { + let mut s = State::new_from_input(cm, span_diagnostic, filename, input, out, ann, is_expanded); // When printing the AST, we sometimes need to inject `#[no_std]` here. // Since you can't compile the HIR, it's not necessary. @@ -127,38 +139,42 @@ impl<'a> State<'a> { span_diagnostic: &diagnostic::SpanHandler, filename: String, input: &mut Read, - out: Box, + out: Box, ann: &'a PpAnn, - is_expanded: bool) -> State<'a> { - let (cmnts, lits) = comments::gather_comments_and_literals( - span_diagnostic, - filename, - input); - - State::new( - cm, - out, - ann, - Some(cmnts), - // If the code is post expansion, don't use the table of - // literals, since it doesn't correspond with the literals - // in the AST anymore. - if is_expanded { None } else { Some(lits) }) + is_expanded: bool) + -> State<'a> { + let (cmnts, lits) = comments::gather_comments_and_literals(span_diagnostic, + filename, + input); + + State::new(cm, + out, + ann, + Some(cmnts), + // If the code is post expansion, don't use the table of + // literals, since it doesn't correspond with the literals + // in the AST anymore. + if is_expanded { + None + } else { + Some(lits) + }) } pub fn new(cm: &'a CodeMap, - out: Box, + out: Box, ann: &'a PpAnn, comments: Option>, - literals: Option>) -> State<'a> { + literals: Option>) + -> State<'a> { State { s: pp::mk_printer(out, default_columns), cm: Some(cm), - comments: comments, - literals: literals, - cur_cmnt_and_lit: CurrentCommentAndLiteral { + comments: comments.clone(), + literals: literals.clone(), + cur_cmnt_and_lit: ast_pp::CurrentCommentAndLiteral { cur_cmnt: 0, - cur_lit: 0 + cur_lit: 0, }, boxes: Vec::new(), ann: ann, @@ -166,8 +182,8 @@ impl<'a> State<'a> { } } -pub fn to_string(f: F) -> String where - F: FnOnce(&mut State) -> io::Result<()>, +pub fn to_string(f: F) -> String + where F: FnOnce(&mut State) -> io::Result<()> { let mut wr = Vec::new(); { @@ -180,16 +196,16 @@ pub fn to_string(f: F) -> String where pub fn binop_to_string(op: BinOpToken) -> &'static str { match op { - token::Plus => "+", - token::Minus => "-", - token::Star => "*", - token::Slash => "/", - token::Percent => "%", - token::Caret => "^", - token::And => "&", - token::Or => "|", - token::Shl => "<<", - token::Shr => ">>", + token::Plus => "+", + token::Minus => "-", + token::Star => "*", + token::Slash => "/", + token::Percent => "%", + token::Caret => "^", + token::And => "&", + token::Or => "|", + token::Shl => "<<", + token::Shr => ">>", } } @@ -221,10 +237,6 @@ pub fn stmt_to_string(stmt: &hir::Stmt) -> String { to_string(|s| s.print_stmt(stmt)) } -pub fn attr_to_string(attr: &hir::Attribute) -> String { - to_string(|s| s.print_attribute(attr)) -} - pub fn item_to_string(i: &hir::Item) -> String { to_string(|s| s.print_item(i)) } @@ -253,21 +265,27 @@ pub fn path_to_string(p: &hir::Path) -> String { to_string(|s| s.print_path(p, false, 0)) } -pub fn ident_to_string(id: &ast::Ident) -> String { - to_string(|s| s.print_ident(*id)) +pub fn name_to_string(name: ast::Name) -> String { + to_string(|s| s.print_name(name)) } pub fn fun_to_string(decl: &hir::FnDecl, unsafety: hir::Unsafety, constness: hir::Constness, - name: ast::Ident, + name: ast::Name, opt_explicit_self: Option<&hir::ExplicitSelf_>, generics: &hir::Generics) -> String { to_string(|s| { try!(s.head("")); - try!(s.print_fn(decl, unsafety, constness, abi::Rust, Some(name), - generics, opt_explicit_self, hir::Inherited)); + try!(s.print_fn(decl, + unsafety, + constness, + abi::Rust, + Some(name), + generics, + opt_explicit_self, + hir::Inherited)); try!(s.end()); // Close the head box s.end() // Close the outer box }) @@ -283,18 +301,6 @@ pub fn block_to_string(blk: &hir::Block) -> String { }) } -pub fn meta_item_to_string(mi: &hir::MetaItem) -> String { - to_string(|s| s.print_meta_item(mi)) -} - -pub fn attribute_to_string(attr: &hir::Attribute) -> String { - to_string(|s| s.print_attribute(attr)) -} - -pub fn lit_to_string(l: &hir::Lit) -> String { - to_string(|s| s.print_literal(l)) -} - pub fn explicit_self_to_string(explicit_self: &hir::ExplicitSelf_) -> String { to_string(|s| s.print_explicit_self(explicit_self, hir::MutImmutable).map(|_| {})) } @@ -310,57 +316,36 @@ pub fn arg_to_string(arg: &hir::Arg) -> String { pub fn visibility_qualified(vis: hir::Visibility, s: &str) -> String { match vis { hir::Public => format!("pub {}", s), - hir::Inherited => s.to_string() + hir::Inherited => s.to_string(), } } fn needs_parentheses(expr: &hir::Expr) -> bool { match expr.node { - hir::ExprAssign(..) | hir::ExprBinary(..) | + hir::ExprAssign(..) | + hir::ExprBinary(..) | hir::ExprClosure(..) | - hir::ExprAssignOp(..) | hir::ExprCast(..) => true, + hir::ExprAssignOp(..) | + hir::ExprCast(..) => true, _ => false, } } impl<'a> State<'a> { - pub fn ibox(&mut self, u: usize) -> io::Result<()> { - self.boxes.push(pp::Breaks::Inconsistent); - pp::ibox(&mut self.s, u) - } - - pub fn end(&mut self) -> io::Result<()> { - self.boxes.pop().unwrap(); - pp::end(&mut self.s) - } - pub fn cbox(&mut self, u: usize) -> io::Result<()> { self.boxes.push(pp::Breaks::Consistent); pp::cbox(&mut self.s, u) } - // "raw box" - pub fn rbox(&mut self, u: usize, b: pp::Breaks) -> io::Result<()> { - self.boxes.push(b); - pp::rbox(&mut self.s, u, b) + pub fn nbsp(&mut self) -> io::Result<()> { + word(&mut self.s, " ") } - pub fn nbsp(&mut self) -> io::Result<()> { word(&mut self.s, " ") } - pub fn word_nbsp(&mut self, w: &str) -> io::Result<()> { try!(word(&mut self.s, w)); self.nbsp() } - pub fn word_space(&mut self, w: &str) -> io::Result<()> { - try!(word(&mut self.s, w)); - space(&mut self.s) - } - - pub fn popen(&mut self) -> io::Result<()> { word(&mut self.s, "(") } - - pub fn pclose(&mut self) -> io::Result<()> { word(&mut self.s, ")") } - pub fn head(&mut self, w: &str) -> io::Result<()> { // outer-box is consistent try!(self.cbox(indent_unit)); @@ -378,12 +363,14 @@ impl<'a> State<'a> { self.end() // close the head-box } - pub fn bclose_(&mut self, span: codemap::Span, - indented: usize) -> io::Result<()> { + pub fn bclose_(&mut self, span: codemap::Span, indented: usize) -> io::Result<()> { self.bclose_maybe_open(span, indented, true) } - pub fn bclose_maybe_open (&mut self, span: codemap::Span, - indented: usize, close_box: bool) -> io::Result<()> { + pub fn bclose_maybe_open(&mut self, + span: codemap::Span, + indented: usize, + close_box: bool) + -> io::Result<()> { try!(self.maybe_print_comment(span.hi)); try!(self.break_offset_if_not_bol(1, -(indented as isize))); try!(word(&mut self.s, "}")); @@ -396,44 +383,19 @@ impl<'a> State<'a> { self.bclose_(span, indent_unit) } - pub fn is_begin(&mut self) -> bool { - match self.s.last_token() { - pp::Token::Begin(_) => true, - _ => false, - } - } - - pub fn is_end(&mut self) -> bool { - match self.s.last_token() { - pp::Token::End => true, - _ => false, - } - } - - // is this the beginning of a line? - pub fn is_bol(&mut self) -> bool { - self.s.last_token().is_eof() || self.s.last_token().is_hardbreak_tok() - } - pub fn in_cbox(&self) -> bool { match self.boxes.last() { Some(&last_box) => last_box == pp::Breaks::Consistent, - None => false + None => false, } } - - pub fn hardbreak_if_not_bol(&mut self) -> io::Result<()> { + pub fn space_if_not_bol(&mut self) -> io::Result<()> { if !self.is_bol() { - try!(hardbreak(&mut self.s)) + try!(space(&mut self.s)); } Ok(()) } - pub fn space_if_not_bol(&mut self) -> io::Result<()> { - if !self.is_bol() { try!(space(&mut self.s)); } - Ok(()) - } - pub fn break_offset_if_not_bol(&mut self, n: usize, - off: isize) -> io::Result<()> { + pub fn break_offset_if_not_bol(&mut self, n: usize, off: isize) -> io::Result<()> { if !self.is_bol() { break_offset(&mut self.s, n, off) } else { @@ -457,26 +419,15 @@ impl<'a> State<'a> { word(&mut self.s, "*/") } - pub fn commasep(&mut self, b: Breaks, elts: &[T], mut op: F) -> io::Result<()> where - F: FnMut(&mut State, &T) -> io::Result<()>, - { - try!(self.rbox(0, b)); - let mut first = true; - for elt in elts { - if first { first = false; } else { try!(self.word_space(",")); } - try!(op(self, elt)); - } - self.end() - } - pub fn commasep_cmnt(&mut self, b: Breaks, elts: &[T], mut op: F, - mut get_span: G) -> io::Result<()> where - F: FnMut(&mut State, &T) -> io::Result<()>, - G: FnMut(&T) -> codemap::Span, + mut get_span: G) + -> io::Result<()> + where F: FnMut(&mut State, &T) -> io::Result<()>, + G: FnMut(&T) -> codemap::Span { try!(self.rbox(0, b)); let len = elts.len(); @@ -487,21 +438,18 @@ impl<'a> State<'a> { i += 1; if i < len { try!(word(&mut self.s, ",")); - try!(self.maybe_print_trailing_comment(get_span(elt), - Some(get_span(&elts[i]).hi))); + try!(self.maybe_print_trailing_comment(get_span(elt), Some(get_span(&elts[i]).hi))); try!(self.space_if_not_bol()); } } self.end() } - pub fn commasep_exprs(&mut self, b: Breaks, - exprs: &[P]) -> io::Result<()> { + pub fn commasep_exprs(&mut self, b: Breaks, exprs: &[P]) -> io::Result<()> { self.commasep_cmnt(b, exprs, |s, e| s.print_expr(&**e), |e| e.span) } - pub fn print_mod(&mut self, _mod: &hir::Mod, - attrs: &[hir::Attribute]) -> io::Result<()> { + pub fn print_mod(&mut self, _mod: &hir::Mod, attrs: &[ast::Attribute]) -> io::Result<()> { try!(self.print_inner_attributes(attrs)); for item in &_mod.items { try!(self.print_item(&**item)); @@ -509,8 +457,10 @@ impl<'a> State<'a> { Ok(()) } - pub fn print_foreign_mod(&mut self, nmod: &hir::ForeignMod, - attrs: &[hir::Attribute]) -> io::Result<()> { + pub fn print_foreign_mod(&mut self, + nmod: &hir::ForeignMod, + attrs: &[ast::Attribute]) + -> io::Result<()> { try!(self.print_inner_attributes(attrs)); for item in &nmod.items { try!(self.print_foreign_item(&**item)); @@ -518,8 +468,7 @@ impl<'a> State<'a> { Ok(()) } - pub fn print_opt_lifetime(&mut self, - lifetime: &Option) -> io::Result<()> { + pub fn print_opt_lifetime(&mut self, lifetime: &Option) -> io::Result<()> { if let Some(l) = *lifetime { try!(self.print_lifetime(&l)); try!(self.nbsp()); @@ -551,8 +500,7 @@ impl<'a> State<'a> { } hir::TyTup(ref elts) => { try!(self.popen()); - try!(self.commasep(Inconsistent, &elts[..], - |s, ty| s.print_type(&**ty))); + try!(self.commasep(Inconsistent, &elts[..], |s, ty| s.print_type(&**ty))); if elts.len() == 1 { try!(word(&mut self.s, ",")); } @@ -572,12 +520,7 @@ impl<'a> State<'a> { predicates: Vec::new(), }, }; - try!(self.print_ty_fn(f.abi, - f.unsafety, - &*f.decl, - None, - &generics, - None)); + try!(self.print_ty_fn(f.abi, f.unsafety, &*f.decl, None, &generics, None)); } hir::TyPath(None, ref path) => { try!(self.print_path(path, false, 0)); @@ -611,29 +554,31 @@ impl<'a> State<'a> { self.end() } - pub fn print_foreign_item(&mut self, - item: &hir::ForeignItem) -> io::Result<()> { + pub fn print_foreign_item(&mut self, item: &hir::ForeignItem) -> io::Result<()> { try!(self.hardbreak_if_not_bol()); try!(self.maybe_print_comment(item.span.lo)); try!(self.print_outer_attributes(&item.attrs)); match item.node { hir::ForeignItemFn(ref decl, ref generics) => { try!(self.head("")); - try!(self.print_fn(decl, hir::Unsafety::Normal, + try!(self.print_fn(decl, + hir::Unsafety::Normal, hir::Constness::NotConst, - abi::Rust, Some(item.ident), - generics, None, item.vis)); + abi::Rust, + Some(item.name), + generics, + None, + item.vis)); try!(self.end()); // end head-ibox try!(word(&mut self.s, ";")); self.end() // end the outer fn box } hir::ForeignItemStatic(ref t, m) => { - try!(self.head(&visibility_qualified(item.vis, - "static"))); + try!(self.head(&visibility_qualified(item.vis, "static"))); if m { try!(self.word_space("mut")); } - try!(self.print_ident(item.ident)); + try!(self.print_name(item.name)); try!(self.word_space(":")); try!(self.print_type(&**t)); try!(word(&mut self.s, ";")); @@ -644,15 +589,14 @@ impl<'a> State<'a> { } fn print_associated_const(&mut self, - ident: ast::Ident, + name: ast::Name, ty: &hir::Ty, default: Option<&hir::Expr>, vis: hir::Visibility) - -> io::Result<()> - { + -> io::Result<()> { try!(word(&mut self.s, &visibility_qualified(vis, ""))); try!(self.word_space("const")); - try!(self.print_ident(ident)); + try!(self.print_name(name)); try!(self.word_space(":")); try!(self.print_type(ty)); if let Some(expr) = default { @@ -664,12 +608,12 @@ impl<'a> State<'a> { } fn print_associated_type(&mut self, - ident: ast::Ident, + name: ast::Name, bounds: Option<&hir::TyParamBounds>, ty: Option<&hir::Ty>) -> io::Result<()> { try!(self.word_space("type")); - try!(self.print_ident(ident)); + try!(self.print_name(name)); if let Some(bounds) = bounds { try!(self.print_bounds(":", bounds)); } @@ -689,12 +633,11 @@ impl<'a> State<'a> { try!(self.ann.pre(self, NodeItem(item))); match item.node { hir::ItemExternCrate(ref optional_path) => { - try!(self.head(&visibility_qualified(item.vis, - "extern crate"))); + try!(self.head(&visibility_qualified(item.vis, "extern crate"))); if let Some(p) = *optional_path { let val = p.as_str(); if val.contains("-") { - try!(self.print_string(&val, hir::CookedStr)); + try!(self.print_string(&val, ast::CookedStr)); } else { try!(self.print_name(p)); } @@ -702,26 +645,24 @@ impl<'a> State<'a> { try!(word(&mut self.s, "as")); try!(space(&mut self.s)); } - try!(self.print_ident(item.ident)); + try!(self.print_name(item.name)); try!(word(&mut self.s, ";")); try!(self.end()); // end inner head-block try!(self.end()); // end outer head-block } hir::ItemUse(ref vp) => { - try!(self.head(&visibility_qualified(item.vis, - "use"))); + try!(self.head(&visibility_qualified(item.vis, "use"))); try!(self.print_view_path(&**vp)); try!(word(&mut self.s, ";")); try!(self.end()); // end inner head-block try!(self.end()); // end outer head-block } hir::ItemStatic(ref ty, m, ref expr) => { - try!(self.head(&visibility_qualified(item.vis, - "static"))); + try!(self.head(&visibility_qualified(item.vis, "static"))); if m == hir::MutMutable { try!(self.word_space("mut")); } - try!(self.print_ident(item.ident)); + try!(self.print_name(item.name)); try!(self.word_space(":")); try!(self.print_type(&**ty)); try!(space(&mut self.s)); @@ -733,9 +674,8 @@ impl<'a> State<'a> { try!(self.end()); // end the outer cbox } hir::ItemConst(ref ty, ref expr) => { - try!(self.head(&visibility_qualified(item.vis, - "const"))); - try!(self.print_ident(item.ident)); + try!(self.head(&visibility_qualified(item.vis, "const"))); + try!(self.print_name(item.name)); try!(self.word_space(":")); try!(self.print_type(&**ty)); try!(space(&mut self.s)); @@ -748,23 +688,20 @@ impl<'a> State<'a> { } hir::ItemFn(ref decl, unsafety, constness, abi, ref typarams, ref body) => { try!(self.head("")); - try!(self.print_fn( - decl, - unsafety, - constness, - abi, - Some(item.ident), - typarams, - None, - item.vis - )); + try!(self.print_fn(decl, + unsafety, + constness, + abi, + Some(item.name), + typarams, + None, + item.vis)); try!(word(&mut self.s, " ")); try!(self.print_block_with_attrs(&**body, &item.attrs)); } hir::ItemMod(ref _mod) => { - try!(self.head(&visibility_qualified(item.vis, - "mod"))); - try!(self.print_ident(item.ident)); + try!(self.head(&visibility_qualified(item.vis, "mod"))); + try!(self.print_name(item.name)); try!(self.nbsp()); try!(self.bopen()); try!(self.print_mod(_mod, &item.attrs)); @@ -781,7 +718,7 @@ impl<'a> State<'a> { try!(self.ibox(indent_unit)); try!(self.ibox(0)); try!(self.word_nbsp(&visibility_qualified(item.vis, "type"))); - try!(self.print_ident(item.ident)); + try!(self.print_name(item.name)); try!(self.print_generics(params)); try!(self.end()); // end the inner ibox @@ -793,17 +730,11 @@ impl<'a> State<'a> { try!(self.end()); // end the outer ibox } hir::ItemEnum(ref enum_definition, ref params) => { - try!(self.print_enum_def( - enum_definition, - params, - item.ident, - item.span, - item.vis - )); + try!(self.print_enum_def(enum_definition, params, item.name, item.span, item.vis)); } hir::ItemStruct(ref struct_def, ref generics) => { - try!(self.head(&visibility_qualified(item.vis,"struct"))); - try!(self.print_struct(&**struct_def, generics, item.ident, item.span)); + try!(self.head(&visibility_qualified(item.vis, "struct"))); + try!(self.print_struct(struct_def, generics, item.name, item.span, true)); } hir::ItemDefaultImpl(unsafety, ref trait_ref) => { @@ -837,7 +768,7 @@ impl<'a> State<'a> { match polarity { hir::ImplPolarity::Negative => { try!(word(&mut self.s, "!")); - }, + } _ => {} } @@ -866,7 +797,7 @@ impl<'a> State<'a> { try!(self.print_visibility(item.vis)); try!(self.print_unsafety(unsafety)); try!(self.word_nbsp("trait")); - try!(self.print_ident(item.ident)); + try!(self.print_name(item.name)); try!(self.print_generics(generics)); let mut real_bounds = Vec::with_capacity(bounds.len()); for b in bounds.iter() { @@ -916,12 +847,15 @@ impl<'a> State<'a> { self.print_trait_ref(&t.trait_ref) } - pub fn print_enum_def(&mut self, enum_definition: &hir::EnumDef, - generics: &hir::Generics, ident: ast::Ident, + pub fn print_enum_def(&mut self, + enum_definition: &hir::EnumDef, + generics: &hir::Generics, + name: ast::Name, span: codemap::Span, - visibility: hir::Visibility) -> io::Result<()> { + visibility: hir::Visibility) + -> io::Result<()> { try!(self.head(&visibility_qualified(visibility, "enum"))); - try!(self.print_ident(ident)); + try!(self.print_name(name)); try!(self.print_generics(generics)); try!(self.print_where_clause(&generics.where_clause)); try!(space(&mut self.s)); @@ -930,7 +864,8 @@ impl<'a> State<'a> { pub fn print_variants(&mut self, variants: &[P], - span: codemap::Span) -> io::Result<()> { + span: codemap::Span) + -> io::Result<()> { try!(self.bopen()); for v in variants { try!(self.space_if_not_bol()); @@ -948,37 +883,40 @@ impl<'a> State<'a> { pub fn print_visibility(&mut self, vis: hir::Visibility) -> io::Result<()> { match vis { hir::Public => self.word_nbsp("pub"), - hir::Inherited => Ok(()) + hir::Inherited => Ok(()), } } pub fn print_struct(&mut self, - struct_def: &hir::StructDef, + struct_def: &hir::VariantData, generics: &hir::Generics, - ident: ast::Ident, - span: codemap::Span) -> io::Result<()> { - try!(self.print_ident(ident)); + name: ast::Name, + span: codemap::Span, + print_finalizer: bool) + -> io::Result<()> { + try!(self.print_name(name)); try!(self.print_generics(generics)); - if ::util::struct_def_is_tuple_like(struct_def) { - if !struct_def.fields.is_empty() { + if !struct_def.is_struct() { + if struct_def.is_tuple() { try!(self.popen()); - try!(self.commasep( - Inconsistent, &struct_def.fields, - |s, field| { - match field.node.kind { - hir::NamedField(..) => panic!("unexpected named field"), - hir::UnnamedField(vis) => { - try!(s.print_visibility(vis)); - try!(s.maybe_print_comment(field.span.lo)); - s.print_type(&*field.node.ty) - } - } - } - )); + try!(self.commasep(Inconsistent, + struct_def.fields(), + |s, field| { + match field.node.kind { + hir::NamedField(..) => panic!("unexpected named field"), + hir::UnnamedField(vis) => { + try!(s.print_visibility(vis)); + try!(s.maybe_print_comment(field.span.lo)); + s.print_type(&*field.node.ty) + } + } + })); try!(self.pclose()); } try!(self.print_where_clause(&generics.where_clause)); - try!(word(&mut self.s, ";")); + if print_finalizer { + try!(word(&mut self.s, ";")); + } try!(self.end()); self.end() // close the outer-box } else { @@ -987,15 +925,15 @@ impl<'a> State<'a> { try!(self.bopen()); try!(self.hardbreak_if_not_bol()); - for field in &struct_def.fields { + for field in struct_def.fields() { match field.node.kind { hir::UnnamedField(..) => panic!("unexpected unnamed field"), - hir::NamedField(ident, visibility) => { + hir::NamedField(name, visibility) => { try!(self.hardbreak_if_not_bol()); try!(self.maybe_print_comment(field.span.lo)); try!(self.print_outer_attributes(&field.node.attrs)); try!(self.print_visibility(visibility)); - try!(self.print_ident(ident)); + try!(self.print_name(name)); try!(self.word_nbsp(":")); try!(self.print_type(&*field.node.ty)); try!(word(&mut self.s, ",")); @@ -1008,36 +946,21 @@ impl<'a> State<'a> { } pub fn print_variant(&mut self, v: &hir::Variant) -> io::Result<()> { - try!(self.print_visibility(v.node.vis)); - match v.node.kind { - hir::TupleVariantKind(ref args) => { - try!(self.print_ident(v.node.name)); - if !args.is_empty() { - try!(self.popen()); - try!(self.commasep(Consistent, - &args[..], - |s, arg| s.print_type(&*arg.ty))); - try!(self.pclose()); - } - } - hir::StructVariantKind(ref struct_def) => { - try!(self.head("")); - let generics = ::util::empty_generics(); - try!(self.print_struct(&**struct_def, &generics, v.node.name, v.span)); - } - } + try!(self.head("")); + let generics = ::util::empty_generics(); + try!(self.print_struct(&v.node.data, &generics, v.node.name, v.span, false)); match v.node.disr_expr { Some(ref d) => { try!(space(&mut self.s)); try!(self.word_space("=")); self.print_expr(&**d) } - _ => Ok(()) + _ => Ok(()), } } pub fn print_method_sig(&mut self, - ident: ast::Ident, + name: ast::Name, m: &hir::MethodSig, vis: hir::Visibility) -> io::Result<()> { @@ -1045,21 +968,21 @@ impl<'a> State<'a> { m.unsafety, m.constness, m.abi, - Some(ident), + Some(name), &m.generics, Some(&m.explicit_self.node), vis) } - pub fn print_trait_item(&mut self, ti: &hir::TraitItem) - -> io::Result<()> { + pub fn print_trait_item(&mut self, ti: &hir::TraitItem) -> io::Result<()> { try!(self.ann.pre(self, NodeSubItem(ti.id))); try!(self.hardbreak_if_not_bol()); try!(self.maybe_print_comment(ti.span.lo)); try!(self.print_outer_attributes(&ti.attrs)); match ti.node { hir::ConstTraitItem(ref ty, ref default) => { - try!(self.print_associated_const(ti.ident, &ty, + try!(self.print_associated_const(ti.name, + &ty, default.as_ref().map(|expr| &**expr), hir::Inherited)); } @@ -1067,7 +990,7 @@ impl<'a> State<'a> { if body.is_some() { try!(self.head("")); } - try!(self.print_method_sig(ti.ident, sig, hir::Inherited)); + try!(self.print_method_sig(ti.name, sig, hir::Inherited)); if let Some(ref body) = *body { try!(self.nbsp()); try!(self.print_block_with_attrs(body, &ti.attrs)); @@ -1076,7 +999,8 @@ impl<'a> State<'a> { } } hir::TypeTraitItem(ref bounds, ref default) => { - try!(self.print_associated_type(ti.ident, Some(bounds), + try!(self.print_associated_type(ti.name, + Some(bounds), default.as_ref().map(|ty| &**ty))); } } @@ -1090,73 +1014,21 @@ impl<'a> State<'a> { try!(self.print_outer_attributes(&ii.attrs)); match ii.node { hir::ConstImplItem(ref ty, ref expr) => { - try!(self.print_associated_const(ii.ident, &ty, Some(&expr), ii.vis)); + try!(self.print_associated_const(ii.name, &ty, Some(&expr), ii.vis)); } hir::MethodImplItem(ref sig, ref body) => { try!(self.head("")); - try!(self.print_method_sig(ii.ident, sig, ii.vis)); + try!(self.print_method_sig(ii.name, sig, ii.vis)); try!(self.nbsp()); try!(self.print_block_with_attrs(body, &ii.attrs)); } hir::TypeImplItem(ref ty) => { - try!(self.print_associated_type(ii.ident, None, Some(ty))); + try!(self.print_associated_type(ii.name, None, Some(ty))); } } self.ann.post(self, NodeSubItem(ii.id)) } - pub fn print_outer_attributes(&mut self, - attrs: &[hir::Attribute]) -> io::Result<()> { - let mut count = 0; - for attr in attrs { - match attr.node.style { - hir::AttrOuter => { - try!(self.print_attribute(attr)); - count += 1; - } - _ => {/* fallthrough */ } - } - } - if count > 0 { - try!(self.hardbreak_if_not_bol()); - } - Ok(()) - } - - pub fn print_inner_attributes(&mut self, - attrs: &[hir::Attribute]) -> io::Result<()> { - let mut count = 0; - for attr in attrs { - match attr.node.style { - hir::AttrInner => { - try!(self.print_attribute(attr)); - count += 1; - } - _ => {/* fallthrough */ } - } - } - if count > 0 { - try!(self.hardbreak_if_not_bol()); - } - Ok(()) - } - - pub fn print_attribute(&mut self, attr: &hir::Attribute) -> io::Result<()> { - try!(self.hardbreak_if_not_bol()); - try!(self.maybe_print_comment(attr.span.lo)); - if attr.node.is_sugared_doc { - word(&mut self.s, &attr.value_str().unwrap()) - } else { - match attr.node.style { - hir::AttrInner => try!(word(&mut self.s, "#![")), - hir::AttrOuter => try!(word(&mut self.s, "#[")), - } - try!(self.print_meta_item(&*attr.meta())); - word(&mut self.s, "]") - } - } - - pub fn print_stmt(&mut self, st: &hir::Stmt) -> io::Result<()> { try!(self.maybe_print_comment(st.span.lo)); match st.node { @@ -1187,25 +1059,33 @@ impl<'a> State<'a> { self.print_block_unclosed_indent(blk, indent_unit) } - pub fn print_block_unclosed_indent(&mut self, blk: &hir::Block, - indented: usize) -> io::Result<()> { + pub fn print_block_unclosed_indent(&mut self, + blk: &hir::Block, + indented: usize) + -> io::Result<()> { self.print_block_maybe_unclosed(blk, indented, &[], false) } pub fn print_block_with_attrs(&mut self, blk: &hir::Block, - attrs: &[hir::Attribute]) -> io::Result<()> { + attrs: &[ast::Attribute]) + -> io::Result<()> { self.print_block_maybe_unclosed(blk, indent_unit, attrs, true) } pub fn print_block_maybe_unclosed(&mut self, blk: &hir::Block, indented: usize, - attrs: &[hir::Attribute], - close_box: bool) -> io::Result<()> { + attrs: &[ast::Attribute], + close_box: bool) + -> io::Result<()> { match blk.rules { - hir::UnsafeBlock(..) | hir::PushUnsafeBlock(..) => try!(self.word_space("unsafe")), - hir::DefaultBlock | hir::PopUnsafeBlock(..) => () + hir::UnsafeBlock(..) => try!(self.word_space("unsafe")), + hir::PushUnsafeBlock(..) => try!(self.word_space("push_unsafe")), + hir::PopUnsafeBlock(..) => try!(self.word_space("pop_unsafe")), + hir::PushUnstableBlock => try!(self.word_space("push_unstable")), + hir::PopUnstableBlock => try!(self.word_space("pop_unstable")), + hir::DefaultBlock => (), } try!(self.maybe_print_comment(blk.span.lo)); try!(self.ann.pre(self, NodeBlock(blk))); @@ -1222,7 +1102,7 @@ impl<'a> State<'a> { try!(self.print_expr(&**expr)); try!(self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi))); } - _ => () + _ => (), } try!(self.bclose_maybe_open(blk.span, indented, close_box)); self.ann.post(self, NodeBlock(blk)) @@ -1255,12 +1135,15 @@ impl<'a> State<'a> { } } } - _ => Ok(()) + _ => Ok(()), } } - pub fn print_if(&mut self, test: &hir::Expr, blk: &hir::Block, - elseopt: Option<&hir::Expr>) -> io::Result<()> { + pub fn print_if(&mut self, + test: &hir::Expr, + blk: &hir::Block, + elseopt: Option<&hir::Expr>) + -> io::Result<()> { try!(self.head("if")); try!(self.print_expr(test)); try!(space(&mut self.s)); @@ -1268,8 +1151,12 @@ impl<'a> State<'a> { self.print_else(elseopt) } - pub fn print_if_let(&mut self, pat: &hir::Pat, expr: &hir::Expr, blk: &hir::Block, - elseopt: Option<&hir::Expr>) -> io::Result<()> { + pub fn print_if_let(&mut self, + pat: &hir::Pat, + expr: &hir::Expr, + blk: &hir::Block, + elseopt: Option<&hir::Expr>) + -> io::Result<()> { try!(self.head("if let")); try!(self.print_pat(pat)); try!(space(&mut self.s)); @@ -1299,16 +1186,6 @@ impl<'a> State<'a> { Ok(()) } - fn print_expr_box(&mut self, - place: &Option>, - expr: &hir::Expr) -> io::Result<()> { - try!(word(&mut self.s, "box")); - try!(word(&mut self.s, "(")); - try!(place.as_ref().map_or(Ok(()), |e|self.print_expr(&**e))); - try!(self.word_space(")")); - self.print_expr(expr) - } - fn print_expr_vec(&mut self, exprs: &[P]) -> io::Result<()> { try!(self.ibox(indent_unit)); try!(word(&mut self.s, "[")); @@ -1317,9 +1194,7 @@ impl<'a> State<'a> { self.end() } - fn print_expr_repeat(&mut self, - element: &hir::Expr, - count: &hir::Expr) -> io::Result<()> { + fn print_expr_repeat(&mut self, element: &hir::Expr, count: &hir::Expr) -> io::Result<()> { try!(self.ibox(indent_unit)); try!(word(&mut self.s, "[")); try!(self.print_expr(element)); @@ -1332,36 +1207,36 @@ impl<'a> State<'a> { fn print_expr_struct(&mut self, path: &hir::Path, fields: &[hir::Field], - wth: &Option>) -> io::Result<()> { + wth: &Option>) + -> io::Result<()> { try!(self.print_path(path, true, 0)); - if !(fields.is_empty() && wth.is_none()) { - try!(word(&mut self.s, "{")); - try!(self.commasep_cmnt( - Consistent, - &fields[..], - |s, field| { - try!(s.ibox(indent_unit)); - try!(s.print_ident(field.ident.node)); - try!(s.word_space(":")); - try!(s.print_expr(&*field.expr)); - s.end() - }, - |f| f.span)); - match *wth { - Some(ref expr) => { - try!(self.ibox(indent_unit)); - if !fields.is_empty() { - try!(word(&mut self.s, ",")); - try!(space(&mut self.s)); - } - try!(word(&mut self.s, "..")); - try!(self.print_expr(&**expr)); - try!(self.end()); + try!(word(&mut self.s, "{")); + try!(self.commasep_cmnt(Consistent, + &fields[..], + |s, field| { + try!(s.ibox(indent_unit)); + try!(s.print_name(field.name.node)); + try!(s.word_space(":")); + try!(s.print_expr(&*field.expr)); + s.end() + }, + |f| f.span)); + match *wth { + Some(ref expr) => { + try!(self.ibox(indent_unit)); + if !fields.is_empty() { + try!(word(&mut self.s, ",")); + try!(space(&mut self.s)); } - _ => try!(word(&mut self.s, ",")), + try!(word(&mut self.s, "..")); + try!(self.print_expr(&**expr)); + try!(self.end()); } - try!(word(&mut self.s, "}")); + _ => if !fields.is_empty() { + try!(word(&mut self.s, ",")) + }, } + try!(word(&mut self.s, "}")); Ok(()) } @@ -1374,25 +1249,23 @@ impl<'a> State<'a> { self.pclose() } - fn print_expr_call(&mut self, - func: &hir::Expr, - args: &[P]) -> io::Result<()> { + fn print_expr_call(&mut self, func: &hir::Expr, args: &[P]) -> io::Result<()> { try!(self.print_expr_maybe_paren(func)); self.print_call_post(args) } fn print_expr_method_call(&mut self, - ident: hir::SpannedIdent, + name: Spanned, tys: &[P], - args: &[P]) -> io::Result<()> { + args: &[P]) + -> io::Result<()> { let base_args = &args[1..]; try!(self.print_expr(&*args[0])); try!(word(&mut self.s, ".")); - try!(self.print_ident(ident.node)); + try!(self.print_name(name.node)); if !tys.is_empty() { try!(word(&mut self.s, "::<")); - try!(self.commasep(Inconsistent, tys, - |s, ty| s.print_type(&**ty))); + try!(self.commasep(Inconsistent, tys, |s, ty| s.print_type(&**ty))); try!(word(&mut self.s, ">")); } self.print_call_post(base_args) @@ -1401,23 +1274,23 @@ impl<'a> State<'a> { fn print_expr_binary(&mut self, op: hir::BinOp, lhs: &hir::Expr, - rhs: &hir::Expr) -> io::Result<()> { + rhs: &hir::Expr) + -> io::Result<()> { try!(self.print_expr(lhs)); try!(space(&mut self.s)); try!(self.word_space(::util::binop_to_string(op.node))); self.print_expr(rhs) } - fn print_expr_unary(&mut self, - op: hir::UnOp, - expr: &hir::Expr) -> io::Result<()> { + fn print_expr_unary(&mut self, op: hir::UnOp, expr: &hir::Expr) -> io::Result<()> { try!(word(&mut self.s, ::util::unop_to_string(op))); self.print_expr_maybe_paren(expr) } fn print_expr_addr_of(&mut self, mutability: hir::Mutability, - expr: &hir::Expr) -> io::Result<()> { + expr: &hir::Expr) + -> io::Result<()> { try!(word(&mut self.s, "&")); try!(self.print_mutability(mutability)); self.print_expr_maybe_paren(expr) @@ -1428,8 +1301,9 @@ impl<'a> State<'a> { try!(self.ibox(indent_unit)); try!(self.ann.pre(self, NodeExpr(expr))); match expr.node { - hir::ExprBox(ref place, ref expr) => { - try!(self.print_expr_box(place, &**expr)); + hir::ExprBox(ref expr) => { + try!(self.word_space("box")); + try!(self.print_expr(expr)); } hir::ExprVec(ref exprs) => { try!(self.print_expr_vec(&exprs[..])); @@ -1446,8 +1320,8 @@ impl<'a> State<'a> { hir::ExprCall(ref func, ref args) => { try!(self.print_expr_call(&**func, &args[..])); } - hir::ExprMethodCall(ident, ref tys, ref args) => { - try!(self.print_expr_method_call(ident, &tys[..], &args[..])); + hir::ExprMethodCall(name, ref tys, ref args) => { + try!(self.print_expr_method_call(name, &tys[..], &args[..])); } hir::ExprBinary(op, ref lhs, ref rhs) => { try!(self.print_expr_binary(op, &**lhs, &**rhs)); @@ -1472,7 +1346,7 @@ impl<'a> State<'a> { } hir::ExprWhile(ref test, ref blk, opt_ident) => { if let Some(ident) = opt_ident { - try!(self.print_ident(ident)); + try!(self.print_name(ident.name)); try!(self.word_space(":")); } try!(self.head("while")); @@ -1482,7 +1356,7 @@ impl<'a> State<'a> { } hir::ExprLoop(ref blk, opt_ident) => { if let Some(ident) = opt_ident { - try!(self.print_ident(ident)); + try!(self.print_name(ident.name)); try!(self.word_space(":")); } try!(self.head("loop")); @@ -1509,7 +1383,7 @@ impl<'a> State<'a> { let default_return = match decl.output { hir::DefaultReturn(..) => true, - _ => false + _ => false, }; if !default_return || !body.stmts.is_empty() || body.expr.is_none() { @@ -1552,10 +1426,10 @@ impl<'a> State<'a> { try!(self.word_space("=")); try!(self.print_expr(&**rhs)); } - hir::ExprField(ref expr, id) => { + hir::ExprField(ref expr, name) => { try!(self.print_expr(&**expr)); try!(word(&mut self.s, ".")); - try!(self.print_ident(id.node)); + try!(self.print_name(name.node)); } hir::ExprTupField(ref expr, id) => { try!(self.print_expr(&**expr)); @@ -1587,7 +1461,7 @@ impl<'a> State<'a> { try!(word(&mut self.s, "break")); try!(space(&mut self.s)); if let Some(ident) = opt_ident { - try!(self.print_ident(ident.node)); + try!(self.print_name(ident.node.name)); try!(space(&mut self.s)); } } @@ -1595,7 +1469,7 @@ impl<'a> State<'a> { try!(word(&mut self.s, "continue")); try!(space(&mut self.s)); if let Some(ident) = opt_ident { - try!(self.print_ident(ident.node)); + try!(self.print_name(ident.node.name)); try!(space(&mut self.s)) } } @@ -1606,7 +1480,7 @@ impl<'a> State<'a> { try!(word(&mut self.s, " ")); try!(self.print_expr(&**expr)); } - _ => () + _ => (), } } hir::ExprInlineAsm(ref a) => { @@ -1615,39 +1489,42 @@ impl<'a> State<'a> { try!(self.print_string(&a.asm, a.asm_str_style)); try!(self.word_space(":")); - try!(self.commasep(Inconsistent, &a.outputs, + try!(self.commasep(Inconsistent, + &a.outputs, |s, &(ref co, ref o, is_rw)| { - match co.slice_shift_char() { - Some(('=', operand)) if is_rw => { - try!(s.print_string(&format!("+{}", operand), - hir::CookedStr)) - } - _ => try!(s.print_string(&co, hir::CookedStr)) - } - try!(s.popen()); - try!(s.print_expr(&**o)); - try!(s.pclose()); - Ok(()) - })); + match co.slice_shift_char() { + Some(('=', operand)) if is_rw => { + try!(s.print_string(&format!("+{}", operand), + ast::CookedStr)) + } + _ => try!(s.print_string(&co, ast::CookedStr)), + } + try!(s.popen()); + try!(s.print_expr(&**o)); + try!(s.pclose()); + Ok(()) + })); try!(space(&mut self.s)); try!(self.word_space(":")); - try!(self.commasep(Inconsistent, &a.inputs, + try!(self.commasep(Inconsistent, + &a.inputs, |s, &(ref co, ref o)| { - try!(s.print_string(&co, hir::CookedStr)); - try!(s.popen()); - try!(s.print_expr(&**o)); - try!(s.pclose()); - Ok(()) - })); + try!(s.print_string(&co, ast::CookedStr)); + try!(s.popen()); + try!(s.print_expr(&**o)); + try!(s.pclose()); + Ok(()) + })); try!(space(&mut self.s)); try!(self.word_space(":")); - try!(self.commasep(Inconsistent, &a.clobbers, + try!(self.commasep(Inconsistent, + &a.clobbers, |s, co| { - try!(s.print_string(&co, hir::CookedStr)); - Ok(()) - })); + try!(s.print_string(&co, ast::CookedStr)); + Ok(()) + })); let mut options = vec!(); if a.volatile { @@ -1656,27 +1533,23 @@ impl<'a> State<'a> { if a.alignstack { options.push("alignstack"); } - if a.dialect == hir::AsmDialect::AsmIntel { + if a.dialect == ast::AsmDialect::Intel { options.push("intel"); } if !options.is_empty() { try!(space(&mut self.s)); try!(self.word_space(":")); - try!(self.commasep(Inconsistent, &*options, + try!(self.commasep(Inconsistent, + &*options, |s, &co| { - try!(s.print_string(co, hir::CookedStr)); - Ok(()) - })); + try!(s.print_string(co, ast::CookedStr)); + Ok(()) + })); } try!(self.pclose()); } - hir::ExprParen(ref e) => { - try!(self.popen()); - try!(self.print_expr(&**e)); - try!(self.pclose()); - } } try!(self.ann.post(self, NodeExpr(expr))); self.end() @@ -1709,15 +1582,10 @@ impl<'a> State<'a> { } self.end() } - hir::DeclItem(ref item) => self.print_item(&**item) + hir::DeclItem(ref item) => self.print_item(&**item), } } - pub fn print_ident(&mut self, ident: ast::Ident) -> io::Result<()> { - try!(word(&mut self.s, &ident.name.as_str())); - self.ann.post(self, NodeIdent(&ident)) - } - pub fn print_usize(&mut self, i: usize) -> io::Result<()> { word(&mut self.s, &i.to_string()) } @@ -1727,8 +1595,7 @@ impl<'a> State<'a> { self.ann.post(self, NodeName(&name)) } - pub fn print_for_decl(&mut self, loc: &hir::Local, - coll: &hir::Expr) -> io::Result<()> { + pub fn print_for_decl(&mut self, loc: &hir::Local, coll: &hir::Expr) -> io::Result<()> { try!(self.print_local_decl(loc)); try!(space(&mut self.s)); try!(self.word_space("in")); @@ -1739,8 +1606,7 @@ impl<'a> State<'a> { path: &hir::Path, colons_before_params: bool, depth: usize) - -> io::Result<()> - { + -> io::Result<()> { try!(self.maybe_print_comment(path.span.lo)); let mut first = !path.global; @@ -1751,7 +1617,7 @@ impl<'a> State<'a> { try!(word(&mut self.s, "::")) } - try!(self.print_ident(segment.identifier)); + try!(self.print_name(segment.identifier.name)); try!(self.print_path_parameters(&segment.parameters, colons_before_params)); } @@ -1763,8 +1629,7 @@ impl<'a> State<'a> { path: &hir::Path, qself: &hir::QSelf, colons_before_params: bool) - -> io::Result<()> - { + -> io::Result<()> { try!(word(&mut self.s, "<")); try!(self.print_type(&qself.ty)); if qself.position > 0 { @@ -1776,15 +1641,14 @@ impl<'a> State<'a> { try!(word(&mut self.s, ">")); try!(word(&mut self.s, "::")); let item_segment = path.segments.last().unwrap(); - try!(self.print_ident(item_segment.identifier)); + try!(self.print_name(item_segment.identifier.name)); self.print_path_parameters(&item_segment.parameters, colons_before_params) } fn print_path_parameters(&mut self, parameters: &hir::PathParameters, colons_before_params: bool) - -> io::Result<()> - { + -> io::Result<()> { if parameters.is_empty() { return Ok(()); } @@ -1810,18 +1674,15 @@ impl<'a> State<'a> { if comma { try!(self.word_space(",")) } - try!(self.commasep( - Inconsistent, - &data.types, - |s, ty| s.print_type(&**ty))); - comma = true; + try!(self.commasep(Inconsistent, &data.types, |s, ty| s.print_type(&**ty))); + comma = true; } for binding in data.bindings.iter() { if comma { try!(self.word_space(",")) } - try!(self.print_ident(binding.ident)); + try!(self.print_name(binding.name)); try!(space(&mut self.s)); try!(self.word_space("=")); try!(self.print_type(&*binding.ty)); @@ -1833,14 +1694,13 @@ impl<'a> State<'a> { hir::ParenthesizedParameters(ref data) => { try!(word(&mut self.s, "(")); - try!(self.commasep( - Inconsistent, - &data.inputs, - |s, ty| s.print_type(&**ty))); + try!(self.commasep(Inconsistent, + &data.inputs, + |s, ty| s.print_type(&**ty))); try!(word(&mut self.s, ")")); match data.output { - None => { } + None => {} Some(ref ty) => { try!(self.space_if_not_bol()); try!(self.word_space("->")); @@ -1872,13 +1732,13 @@ impl<'a> State<'a> { try!(self.word_nbsp("mut")); } } - try!(self.print_ident(path1.node)); + try!(self.print_name(path1.node.name)); match *sub { Some(ref p) => { try!(word(&mut self.s, "@")); try!(self.print_pat(&**p)); } - None => () + None => (), } } hir::PatEnum(ref path, ref args_) => { @@ -1888,8 +1748,7 @@ impl<'a> State<'a> { Some(ref args) => { if !args.is_empty() { try!(self.popen()); - try!(self.commasep(Inconsistent, &args[..], - |s, p| s.print_pat(&**p))); + try!(self.commasep(Inconsistent, &args[..], |s, p| s.print_pat(&**p))); try!(self.pclose()); } } @@ -1902,20 +1761,22 @@ impl<'a> State<'a> { try!(self.print_path(path, true, 0)); try!(self.nbsp()); try!(self.word_space("{")); - try!(self.commasep_cmnt( - Consistent, &fields[..], - |s, f| { - try!(s.cbox(indent_unit)); - if !f.node.is_shorthand { - try!(s.print_ident(f.node.ident)); - try!(s.word_nbsp(":")); - } - try!(s.print_pat(&*f.node.pat)); - s.end() - }, - |f| f.node.pat.span)); + try!(self.commasep_cmnt(Consistent, + &fields[..], + |s, f| { + try!(s.cbox(indent_unit)); + if !f.node.is_shorthand { + try!(s.print_name(f.node.name)); + try!(s.word_nbsp(":")); + } + try!(s.print_pat(&*f.node.pat)); + s.end() + }, + |f| f.node.pat.span)); if etc { - if !fields.is_empty() { try!(self.word_space(",")); } + if !fields.is_empty() { + try!(self.word_space(",")); + } try!(word(&mut self.s, "..")); } try!(space(&mut self.s)); @@ -1923,9 +1784,7 @@ impl<'a> State<'a> { } hir::PatTup(ref elts) => { try!(self.popen()); - try!(self.commasep(Inconsistent, - &elts[..], - |s, p| s.print_pat(&**p))); + try!(self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&**p))); if elts.len() == 1 { try!(word(&mut self.s, ",")); } @@ -1951,11 +1810,11 @@ impl<'a> State<'a> { } hir::PatVec(ref before, ref slice, ref after) => { try!(word(&mut self.s, "[")); - try!(self.commasep(Inconsistent, - &before[..], - |s, p| s.print_pat(&**p))); + try!(self.commasep(Inconsistent, &before[..], |s, p| s.print_pat(&**p))); if let Some(ref p) = *slice { - if !before.is_empty() { try!(self.word_space(",")); } + if !before.is_empty() { + try!(self.word_space(",")); + } try!(self.print_pat(&**p)); match **p { hir::Pat { node: hir::PatWild(hir::PatWildMulti), .. } => { @@ -1963,11 +1822,11 @@ impl<'a> State<'a> { } _ => try!(word(&mut self.s, "..")), } - if !after.is_empty() { try!(self.word_space(",")); } + if !after.is_empty() { + try!(self.word_space(",")); + } } - try!(self.commasep(Inconsistent, - &after[..], - |s, p| s.print_pat(&**p))); + try!(self.commasep(Inconsistent, &after[..], |s, p| s.print_pat(&**p))); try!(word(&mut self.s, "]")); } } @@ -2023,10 +1882,13 @@ impl<'a> State<'a> { // Returns whether it printed anything fn print_explicit_self(&mut self, explicit_self: &hir::ExplicitSelf_, - mutbl: hir::Mutability) -> io::Result { + mutbl: hir::Mutability) + -> io::Result { try!(self.print_mutability(mutbl)); match *explicit_self { - hir::SelfStatic => { return Ok(false); } + hir::SelfStatic => { + return Ok(false); + } hir::SelfValue(_) => { try!(word(&mut self.s, "self")); } @@ -2050,24 +1912,26 @@ impl<'a> State<'a> { unsafety: hir::Unsafety, constness: hir::Constness, abi: abi::Abi, - name: Option, + name: Option, generics: &hir::Generics, opt_explicit_self: Option<&hir::ExplicitSelf_>, - vis: hir::Visibility) -> io::Result<()> { + vis: hir::Visibility) + -> io::Result<()> { try!(self.print_fn_header_info(unsafety, constness, abi, vis)); if let Some(name) = name { try!(self.nbsp()); - try!(self.print_ident(name)); + try!(self.print_name(name)); } try!(self.print_generics(generics)); try!(self.print_fn_args_and_ret(decl, opt_explicit_self)); self.print_where_clause(&generics.where_clause) } - pub fn print_fn_args(&mut self, decl: &hir::FnDecl, + pub fn print_fn_args(&mut self, + decl: &hir::FnDecl, opt_explicit_self: Option<&hir::ExplicitSelf_>) - -> io::Result<()> { + -> io::Result<()> { // It is unfortunate to duplicate the commasep logic, but we want the // self type and the args all in the same box. try!(self.rbox(0, Inconsistent)); @@ -2077,8 +1941,8 @@ impl<'a> State<'a> { &hir::SelfStatic => hir::MutImmutable, _ => match decl.inputs[0].pat.node { hir::PatIdent(hir::BindByValue(m), _, _) => m, - _ => hir::MutImmutable - } + _ => hir::MutImmutable, + }, }; first = !try!(self.print_explicit_self(explicit_self, m)); } @@ -2091,16 +1955,21 @@ impl<'a> State<'a> { }; for arg in args { - if first { first = false; } else { try!(self.word_space(",")); } + if first { + first = false; + } else { + try!(self.word_space(",")); + } try!(self.print_arg(arg)); } self.end() } - pub fn print_fn_args_and_ret(&mut self, decl: &hir::FnDecl, + pub fn print_fn_args_and_ret(&mut self, + decl: &hir::FnDecl, opt_explicit_self: Option<&hir::ExplicitSelf_>) - -> io::Result<()> { + -> io::Result<()> { try!(self.popen()); try!(self.print_fn_args(decl, opt_explicit_self)); if decl.variadic { @@ -2111,10 +1980,7 @@ impl<'a> State<'a> { self.print_fn_output(decl) } - pub fn print_fn_block_args( - &mut self, - decl: &hir::FnDecl) - -> io::Result<()> { + pub fn print_fn_block_args(&mut self, decl: &hir::FnDecl) -> io::Result<()> { try!(word(&mut self.s, "|")); try!(self.print_fn_args(decl, None)); try!(word(&mut self.s, "|")); @@ -2138,18 +2004,14 @@ impl<'a> State<'a> { } } - pub fn print_capture_clause(&mut self, capture_clause: hir::CaptureClause) - -> io::Result<()> { + pub fn print_capture_clause(&mut self, capture_clause: hir::CaptureClause) -> io::Result<()> { match capture_clause { hir::CaptureByValue => self.word_space("move"), hir::CaptureByRef => Ok(()), } } - pub fn print_bounds(&mut self, - prefix: &str, - bounds: &[hir::TyParamBound]) - -> io::Result<()> { + pub fn print_bounds(&mut self, prefix: &str, bounds: &[hir::TyParamBound]) -> io::Result<()> { if !bounds.is_empty() { try!(word(&mut self.s, prefix)); let mut first = true; @@ -2180,17 +2042,11 @@ impl<'a> State<'a> { } } - pub fn print_lifetime(&mut self, - lifetime: &hir::Lifetime) - -> io::Result<()> - { + pub fn print_lifetime(&mut self, lifetime: &hir::Lifetime) -> io::Result<()> { self.print_name(lifetime.name) } - pub fn print_lifetime_def(&mut self, - lifetime: &hir::LifetimeDef) - -> io::Result<()> - { + pub fn print_lifetime_def(&mut self, lifetime: &hir::LifetimeDef) -> io::Result<()> { try!(self.print_lifetime(&lifetime.lifetime)); let mut sep = ":"; for v in &lifetime.bounds { @@ -2201,10 +2057,7 @@ impl<'a> State<'a> { Ok(()) } - pub fn print_generics(&mut self, - generics: &hir::Generics) - -> io::Result<()> - { + pub fn print_generics(&mut self, generics: &hir::Generics) -> io::Result<()> { let total = generics.lifetimes.len() + generics.ty_params.len(); if total == 0 { return Ok(()); @@ -2217,23 +2070,25 @@ impl<'a> State<'a> { ints.push(i); } - try!(self.commasep(Inconsistent, &ints[..], |s, &idx| { - if idx < generics.lifetimes.len() { - let lifetime = &generics.lifetimes[idx]; - s.print_lifetime_def(lifetime) - } else { - let idx = idx - generics.lifetimes.len(); - let param = &generics.ty_params[idx]; - s.print_ty_param(param) - } - })); + try!(self.commasep(Inconsistent, + &ints[..], + |s, &idx| { + if idx < generics.lifetimes.len() { + let lifetime = &generics.lifetimes[idx]; + s.print_lifetime_def(lifetime) + } else { + let idx = idx - generics.lifetimes.len(); + let param = &generics.ty_params[idx]; + s.print_ty_param(param) + } + })); try!(word(&mut self.s, ">")); Ok(()) } pub fn print_ty_param(&mut self, param: &hir::TyParam) -> io::Result<()> { - try!(self.print_ident(param.ident)); + try!(self.print_name(param.name)); try!(self.print_bounds(":", ¶m.bounds)); match param.default { Some(ref default) => { @@ -2241,12 +2096,11 @@ impl<'a> State<'a> { try!(self.word_space("=")); self.print_type(&**default) } - _ => Ok(()) + _ => Ok(()), } } - pub fn print_where_clause(&mut self, where_clause: &hir::WhereClause) - -> io::Result<()> { + pub fn print_where_clause(&mut self, where_clause: &hir::WhereClause) -> io::Result<()> { if where_clause.predicates.is_empty() { return Ok(()) } @@ -2294,40 +2148,15 @@ impl<'a> State<'a> { Ok(()) } - pub fn print_meta_item(&mut self, item: &hir::MetaItem) -> io::Result<()> { - try!(self.ibox(indent_unit)); - match item.node { - hir::MetaWord(ref name) => { - try!(word(&mut self.s, &name)); - } - hir::MetaNameValue(ref name, ref value) => { - try!(self.word_space(&name[..])); - try!(self.word_space("=")); - try!(self.print_literal(value)); - } - hir::MetaList(ref name, ref items) => { - try!(word(&mut self.s, &name)); - try!(self.popen()); - try!(self.commasep(Consistent, - &items[..], - |s, i| s.print_meta_item(&**i))); - try!(self.pclose()); - } - } - self.end() - } - pub fn print_view_path(&mut self, vp: &hir::ViewPath) -> io::Result<()> { match vp.node { - hir::ViewPathSimple(ident, ref path) => { + hir::ViewPathSimple(name, ref path) => { try!(self.print_path(path, false, 0)); - // FIXME(#6993) can't compare identifiers directly here - if path.segments.last().unwrap().identifier.name != - ident.name { + if path.segments.last().unwrap().identifier.name != name { try!(space(&mut self.s)); try!(self.word_space("as")); - try!(self.print_ident(ident)); + try!(self.print_name(name)); } Ok(()) @@ -2338,30 +2167,31 @@ impl<'a> State<'a> { word(&mut self.s, "::*") } - hir::ViewPathList(ref path, ref idents) => { + hir::ViewPathList(ref path, ref segments) => { if path.segments.is_empty() { try!(word(&mut self.s, "{")); } else { try!(self.print_path(path, false, 0)); try!(word(&mut self.s, "::{")); } - try!(self.commasep(Inconsistent, &idents[..], |s, w| { - match w.node { - hir::PathListIdent { name, .. } => { - s.print_ident(name) - }, - hir::PathListMod { .. } => { - word(&mut s.s, "self") - } - } - })); + try!(self.commasep(Inconsistent, + &segments[..], + |s, w| { + match w.node { + hir::PathListIdent { name, .. } => { + s.print_name(name) + } + hir::PathListMod { .. } => { + word(&mut s.s, "self") + } + } + })); word(&mut self.s, "}") } } } - pub fn print_mutability(&mut self, - mutbl: hir::Mutability) -> io::Result<()> { + pub fn print_mutability(&mut self, mutbl: hir::Mutability) -> io::Result<()> { match mutbl { hir::MutMutable => self.word_nbsp("mut"), hir::MutImmutable => Ok(()), @@ -2405,17 +2235,15 @@ impl<'a> State<'a> { try!(self.ibox(indent_unit)); try!(self.word_space("->")); match decl.output { - hir::NoReturn(_) => - try!(self.word_nbsp("!")), + hir::NoReturn(_) => try!(self.word_nbsp("!")), hir::DefaultReturn(..) => unreachable!(), - hir::Return(ref ty) => - try!(self.print_type(&**ty)) + hir::Return(ref ty) => try!(self.print_type(&**ty)), } try!(self.end()); match decl.output { hir::Return(ref output) => self.maybe_print_comment(output.span.lo), - _ => Ok(()) + _ => Ok(()), } } @@ -2423,7 +2251,7 @@ impl<'a> State<'a> { abi: abi::Abi, unsafety: hir::Unsafety, decl: &hir::FnDecl, - name: Option, + name: Option, generics: &hir::Generics, opt_explicit_self: Option<&hir::ExplicitSelf_>) -> io::Result<()> { @@ -2451,27 +2279,33 @@ impl<'a> State<'a> { self.end() } - pub fn maybe_print_trailing_comment(&mut self, span: codemap::Span, + pub fn maybe_print_trailing_comment(&mut self, + span: codemap::Span, next_pos: Option) - -> io::Result<()> { + -> io::Result<()> { let cm = match self.cm { Some(cm) => cm, - _ => return Ok(()) + _ => return Ok(()), }; match self.next_comment() { Some(ref cmnt) => { - 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); - match next_pos { None => (), Some(p) => next = p } + match next_pos { + None => (), + Some(p) => next = p, + } if span.hi < (*cmnt).pos && (*cmnt).pos < next && - span_line.line == comment_line.line { - try!(self.print_comment(cmnt)); - self.cur_cmnt_and_lit.cur_cmnt += 1; - } + span_line.line == comment_line.line { + try!(self.print_comment(cmnt)); + self.cur_cmnt_and_lit.cur_cmnt += 1; + } } - _ => () + _ => (), } Ok(()) } @@ -2488,208 +2322,32 @@ impl<'a> State<'a> { try!(self.print_comment(cmnt)); self.cur_cmnt_and_lit.cur_cmnt += 1; } - _ => break - } - } - Ok(()) - } - - pub fn print_literal(&mut self, lit: &hir::Lit) -> io::Result<()> { - try!(self.maybe_print_comment(lit.span.lo)); - match self.next_lit(lit.span.lo) { - Some(ref ltrl) => { - return word(&mut self.s, &(*ltrl).lit); - } - _ => () - } - match lit.node { - hir::LitStr(ref st, style) => self.print_string(&st, style), - hir::LitByte(byte) => { - let mut res = String::from("b'"); - res.extend(ascii::escape_default(byte).map(|c| c as char)); - res.push('\''); - word(&mut self.s, &res[..]) - } - hir::LitChar(ch) => { - let mut res = String::from("'"); - res.extend(ch.escape_default()); - res.push('\''); - word(&mut self.s, &res[..]) - } - hir::LitInt(i, t) => { - match t { - hir::SignedIntLit(st, hir::Plus) => { - word(&mut self.s, - &::util::int_ty_to_string(st, Some(i as i64))) - } - hir::SignedIntLit(st, hir::Minus) => { - let istr = ::util::int_ty_to_string(st, Some(-(i as i64))); - word(&mut self.s, - &format!("-{}", istr)) - } - hir::UnsignedIntLit(ut) => { - word(&mut self.s, &::util::uint_ty_to_string(ut, Some(i))) - } - hir::UnsuffixedIntLit(hir::Plus) => { - word(&mut self.s, &format!("{}", i)) - } - hir::UnsuffixedIntLit(hir::Minus) => { - word(&mut self.s, &format!("-{}", i)) - } - } - } - hir::LitFloat(ref f, t) => { - word(&mut self.s, - &format!( - "{}{}", - &f, - &::util::float_ty_to_string(t))) - } - hir::LitFloatUnsuffixed(ref f) => word(&mut self.s, &f[..]), - hir::LitBool(val) => { - if val { word(&mut self.s, "true") } else { word(&mut self.s, "false") } - } - hir::LitByteStr(ref v) => { - let mut escaped: String = String::new(); - for &ch in v.iter() { - escaped.extend(ascii::escape_default(ch) - .map(|c| c as char)); - } - word(&mut self.s, &format!("b\"{}\"", escaped)) - } - } - } - - pub fn next_lit(&mut self, pos: BytePos) -> Option { - match self.literals { - Some(ref lits) => { - while self.cur_cmnt_and_lit.cur_lit < lits.len() { - let ltrl = (*lits)[self.cur_cmnt_and_lit.cur_lit].clone(); - if ltrl.pos > pos { return None; } - self.cur_cmnt_and_lit.cur_lit += 1; - if ltrl.pos == pos { return Some(ltrl); } - } - None - } - _ => None - } - } - - pub 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 + _ => break, } } Ok(()) } - pub fn print_comment(&mut self, - cmnt: &comments::Comment) -> io::Result<()> { - match cmnt.style { - comments::Mixed => { - assert_eq!(cmnt.lines.len(), 1); - try!(zerobreak(&mut self.s)); - try!(word(&mut self.s, &cmnt.lines[0])); - zerobreak(&mut self.s) - } - comments::Isolated => { - try!(self.hardbreak_if_not_bol()); - for line in &cmnt.lines { - // Don't print empty lines because they will end up as trailing - // whitespace - if !line.is_empty() { - try!(word(&mut self.s, &line[..])); - } - try!(hardbreak(&mut self.s)); - } - Ok(()) - } - comments::Trailing => { - try!(word(&mut self.s, " ")); - if cmnt.lines.len() == 1 { - try!(word(&mut self.s, &cmnt.lines[0])); - hardbreak(&mut self.s) - } else { - try!(self.ibox(0)); - for line in &cmnt.lines { - if !line.is_empty() { - try!(word(&mut self.s, &line[..])); - } - try!(hardbreak(&mut self.s)); - } - self.end() - } - } - comments::BlankLine => { - // We need to do at least one, possibly two hardbreaks. - let is_semi = match self.s.last_token() { - pp::Token::String(s, _) => ";" == s, - _ => false - }; - if is_semi || self.is_begin() || self.is_end() { - try!(hardbreak(&mut self.s)); - } - hardbreak(&mut self.s) - } - } - } - - pub fn print_string(&mut self, st: &str, - style: hir::StrStyle) -> io::Result<()> { - let st = match style { - hir::CookedStr => { - (format!("\"{}\"", st.escape_default())) - } - hir::RawStr(n) => { - (format!("r{delim}\"{string}\"{delim}", - delim=repeat("#", n), - string=st)) - } - }; - word(&mut self.s, &st[..]) - } - - pub fn next_comment(&mut self) -> Option { - match self.comments { - Some(ref cmnts) => { - if self.cur_cmnt_and_lit.cur_cmnt < cmnts.len() { - Some(cmnts[self.cur_cmnt_and_lit.cur_cmnt].clone()) - } else { - None - } - } - _ => None - } - } - pub fn print_opt_abi_and_extern_if_nondefault(&mut self, opt_abi: Option) - -> io::Result<()> { + -> io::Result<()> { match opt_abi { Some(abi::Rust) => Ok(()), Some(abi) => { try!(self.word_nbsp("extern")); self.word_nbsp(&abi.to_string()) } - None => Ok(()) + None => Ok(()), } } - pub fn print_extern_opt_abi(&mut self, - opt_abi: Option) -> io::Result<()> { + pub fn print_extern_opt_abi(&mut self, opt_abi: Option) -> io::Result<()> { match opt_abi { Some(abi) => { try!(self.word_nbsp("extern")); self.word_nbsp(&abi.to_string()) } - None => Ok(()) + None => Ok(()), } } @@ -2697,13 +2355,14 @@ impl<'a> State<'a> { unsafety: hir::Unsafety, constness: hir::Constness, abi: abi::Abi, - vis: hir::Visibility) -> io::Result<()> { + vis: hir::Visibility) + -> io::Result<()> { try!(word(&mut self.s, &visibility_qualified(vis, ""))); try!(self.print_unsafety(unsafety)); match constness { hir::Constness::NotConst => {} - hir::Constness::Const => try!(self.word_nbsp("const")) + hir::Constness::Const => try!(self.word_nbsp("const")), } if abi != abi::Rust { @@ -2722,8 +2381,6 @@ impl<'a> State<'a> { } } -fn repeat(s: &str, n: usize) -> String { iter::repeat(s).take(n).collect() } - // Dup'ed from parse::classify, but adapted for the HIR. /// Does this expression require a semicolon to be treated /// as a statement? The negation of this: 'can this expression @@ -2734,12 +2391,12 @@ fn repeat(s: &str, n: usize) -> String { iter::repeat(s).take(n).collect() } /// isn't parsed as (if true {...} else {...} | x) | 5 fn expr_requires_semi_to_be_stmt(e: &hir::Expr) -> bool { match e.node { - hir::ExprIf(..) - | hir::ExprMatch(..) - | hir::ExprBlock(_) - | hir::ExprWhile(..) - | hir::ExprLoop(..) => false, - _ => true + hir::ExprIf(..) | + hir::ExprMatch(..) | + hir::ExprBlock(_) | + hir::ExprWhile(..) | + hir::ExprLoop(..) => false, + _ => true, } } @@ -2751,10 +2408,14 @@ fn stmt_ends_with_semi(stmt: &hir::Stmt_) -> bool { hir::StmtDecl(ref d, _) => { match d.node { hir::DeclLocal(_) => true, - hir::DeclItem(_) => false + hir::DeclItem(_) => false, } } - hir::StmtExpr(ref e, _) => { expr_requires_semi_to_be_stmt(&**e) } - hir::StmtSemi(..) => { false } + hir::StmtExpr(ref e, _) => { + expr_requires_semi_to_be_stmt(&**e) + } + hir::StmtSemi(..) => { + false + } } } diff --git a/src/librustc_front/util.rs b/src/librustc_front/util.rs index 247ea2ea23..5d8973ead4 100644 --- a/src/librustc_front/util.rs +++ b/src/librustc_front/util.rs @@ -12,14 +12,18 @@ use hir; use hir::*; use visit::{self, Visitor, FnKind}; use syntax::ast_util; -use syntax::ast::{Ident, NodeId, DUMMY_NODE_ID}; +use syntax::ast::{Ident, Name, NodeId, DUMMY_NODE_ID}; use syntax::codemap::Span; use syntax::ptr::P; use syntax::owned_slice::OwnedSlice; -pub fn walk_pat(pat: &Pat, mut it: F) -> bool where F: FnMut(&Pat) -> bool { +pub fn walk_pat(pat: &Pat, mut it: F) -> bool + where F: FnMut(&Pat) -> bool +{ // FIXME(#19596) this is a workaround, but there should be a better way - fn walk_pat_(pat: &Pat, it: &mut G) -> bool where G: FnMut(&Pat) -> bool { + fn walk_pat_(pat: &Pat, it: &mut G) -> bool + where G: FnMut(&Pat) -> bool + { if !(*it)(pat) { return false; } @@ -40,8 +44,12 @@ pub fn walk_pat(pat: &Pat, mut it: F) -> bool where F: FnMut(&Pat) -> bool { slice.iter().all(|p| walk_pat_(&**p, it)) && after.iter().all(|p| walk_pat_(&**p, it)) } - PatWild(_) | PatLit(_) | PatRange(_, _) | PatIdent(_, _, _) | - PatEnum(_, _) | PatQPath(_, _) => { + PatWild(_) | + PatLit(_) | + PatRange(_, _) | + PatIdent(_, _, _) | + PatEnum(_, _) | + PatQPath(_, _) => { true } } @@ -69,47 +77,49 @@ pub fn binop_to_string(op: BinOp_) -> &'static str { BiLe => "<=", BiNe => "!=", BiGe => ">=", - BiGt => ">" + BiGt => ">", } } -/// Returns true if the given struct def is tuple-like; i.e. that its fields -/// are unnamed. -pub fn struct_def_is_tuple_like(struct_def: &hir::StructDef) -> bool { - struct_def.ctor_id.is_some() -} - pub fn stmt_id(s: &Stmt) -> NodeId { match s.node { - StmtDecl(_, id) => id, - StmtExpr(_, id) => id, - StmtSemi(_, id) => id, + StmtDecl(_, id) => id, + StmtExpr(_, id) => id, + StmtSemi(_, id) => id, } } pub fn lazy_binop(b: BinOp_) -> bool { match b { - BiAnd => true, - BiOr => true, - _ => false + BiAnd => true, + BiOr => true, + _ => false, } } pub fn is_shift_binop(b: BinOp_) -> bool { match b { - BiShl => true, - BiShr => true, - _ => false + BiShl => true, + BiShr => true, + _ => false, } } pub fn is_comparison_binop(b: BinOp_) -> bool { match b { - BiEq | BiLt | BiLe | BiNe | BiGt | BiGe => - true, - BiAnd | BiOr | BiAdd | BiSub | BiMul | BiDiv | BiRem | - BiBitXor | BiBitAnd | BiBitOr | BiShl | BiShr => - false, + BiEq | BiLt | BiLe | BiNe | BiGt | BiGe => true, + BiAnd | + BiOr | + BiAdd | + BiSub | + BiMul | + BiDiv | + BiRem | + BiBitXor | + BiBitAnd | + BiBitOr | + BiShl | + BiShr => false, } } @@ -128,14 +138,13 @@ pub fn is_by_value_unop(u: UnOp) -> bool { pub fn unop_to_string(op: UnOp) -> &'static str { match op { - UnUniq => "box() ", - UnDeref => "*", - UnNot => "!", - UnNeg => "-", + UnDeref => "*", + UnNot => "!", + UnNeg => "-", } } -pub struct IdVisitor<'a, O:'a> { +pub struct IdVisitor<'a, O: 'a> { pub operation: &'a mut O, pub pass_through_items: bool, pub visited_outermost: bool, @@ -153,10 +162,7 @@ impl<'a, O: ast_util::IdVisitingOperation> IdVisitor<'a, O> { } impl<'a, 'v, O: ast_util::IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> { - fn visit_mod(&mut self, - module: &Mod, - _: Span, - node_id: NodeId) { + fn visit_mod(&mut self, module: &Mod, _: Span, node_id: NodeId) { self.operation.visit_id(node_id); visit::walk_mod(self, module) } @@ -188,11 +194,6 @@ impl<'a, 'v, O: ast_util::IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> } } } - ItemEnum(ref enum_definition, _) => { - for variant in &enum_definition.variants { - self.operation.visit_id(variant.node.id) - } - } _ => {} } @@ -266,11 +267,7 @@ impl<'a, 'v, O: ast_util::IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> self.operation.visit_id(argument.id) } - visit::walk_fn(self, - function_kind, - function_declaration, - block, - span); + visit::walk_fn(self, function_kind, function_declaration, block, span); if !self.pass_through_items { if let FnKind::Method(..) = function_kind { @@ -284,13 +281,13 @@ impl<'a, 'v, O: ast_util::IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> visit::walk_struct_field(self, struct_field) } - fn visit_struct_def(&mut self, - struct_def: &StructDef, - _: Ident, + fn visit_variant_data(&mut self, + struct_def: &VariantData, + _: Name, _: &hir::Generics, - id: NodeId) { - self.operation.visit_id(id); - struct_def.ctor_id.map(|ctor_id| self.operation.visit_id(ctor_id)); + _: NodeId, + _: Span) { + self.operation.visit_id(struct_def.id()); visit::walk_struct_def(self, struct_def); } @@ -304,12 +301,12 @@ impl<'a, 'v, O: ast_util::IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> visit::walk_impl_item(self, ii); } - fn visit_lifetime_ref(&mut self, lifetime: &Lifetime) { + fn visit_lifetime(&mut self, lifetime: &Lifetime) { self.operation.visit_id(lifetime.id); } fn visit_lifetime_def(&mut self, def: &LifetimeDef) { - self.visit_lifetime_ref(&def.lifetime); + self.visit_lifetime(&def.lifetime); } fn visit_trait_ref(&mut self, trait_ref: &TraitRef) { @@ -324,11 +321,8 @@ pub fn compute_id_range_for_fn_body(fk: FnKind, body: &Block, sp: Span, id: NodeId) - -> ast_util::IdRange -{ - let mut visitor = ast_util::IdRangeComputingVisitor { - result: ast_util::IdRange::max() - }; + -> ast_util::IdRange { + let mut visitor = ast_util::IdRangeComputingVisitor { result: ast_util::IdRange::max() }; let mut id_visitor = IdVisitor { operation: &mut visitor, pass_through_items: false, @@ -338,64 +332,13 @@ pub fn compute_id_range_for_fn_body(fk: FnKind, id_visitor.operation.result } -/// Returns true if this literal is a string and false otherwise. -pub fn lit_is_str(lit: &Lit) -> bool { - match lit.node { - LitStr(..) => true, - _ => false, - } -} - pub fn is_path(e: P) -> bool { - match e.node { ExprPath(..) => true, _ => false } -} - -/// Get a string representation of a signed int type, with its value. -/// We want to avoid "45int" and "-3int" in favor of "45" and "-3" -pub fn int_ty_to_string(t: IntTy, val: Option) -> String { - let s = match t { - TyIs => "isize", - TyI8 => "i8", - TyI16 => "i16", - TyI32 => "i32", - TyI64 => "i64" - }; - - match val { - // cast to a u64 so we can correctly print INT64_MIN. All integral types - // are parsed as u64, so we wouldn't want to print an extra negative - // sign. - Some(n) => format!("{}{}", n as u64, s), - None => s.to_string() - } -} - - -/// Get a string representation of an unsigned int type, with its value. -/// We want to avoid "42u" in favor of "42us". "42uint" is right out. -pub fn uint_ty_to_string(t: UintTy, val: Option) -> String { - let s = match t { - TyUs => "usize", - TyU8 => "u8", - TyU16 => "u16", - TyU32 => "u32", - TyU64 => "u64" - }; - - match val { - Some(n) => format!("{}{}", n, s), - None => s.to_string() - } -} - -pub fn float_ty_to_string(t: FloatTy) -> String { - match t { - TyF32 => "f32".to_string(), - TyF64 => "f64".to_string(), + match e.node { + ExprPath(..) => true, + _ => false, } } - pub fn empty_generics() -> Generics { Generics { lifetimes: Vec::new(), @@ -403,25 +346,23 @@ pub fn empty_generics() -> Generics { where_clause: WhereClause { id: DUMMY_NODE_ID, predicates: Vec::new(), - } + }, } } // convert a span and an identifier to the corresponding // 1-segment path -pub fn ident_to_path(s: Span, identifier: Ident) -> Path { +pub fn ident_to_path(s: Span, ident: Ident) -> Path { hir::Path { span: s, global: false, - segments: vec!( - hir::PathSegment { - identifier: identifier, - parameters: hir::AngleBracketedParameters(hir::AngleBracketedParameterData { - lifetimes: Vec::new(), - types: OwnedSlice::empty(), - bindings: OwnedSlice::empty(), - }) - } - ), + segments: vec!(hir::PathSegment { + identifier: ident, + parameters: hir::AngleBracketedParameters(hir::AngleBracketedParameterData { + lifetimes: Vec::new(), + types: OwnedSlice::empty(), + bindings: OwnedSlice::empty(), + }), + }), } } diff --git a/src/librustc_front/visit.rs b/src/librustc_front/visit.rs index f20e5345f2..547651bef8 100644 --- a/src/librustc_front/visit.rs +++ b/src/librustc_front/visit.rs @@ -24,23 +24,19 @@ //! those that are created by the expansion of a macro. use syntax::abi::Abi; -use syntax::ast::{Ident, NodeId, CRATE_NODE_ID, Name}; -use hir::*; -use hir; +use syntax::ast::{Ident, NodeId, CRATE_NODE_ID, Name, Attribute}; use syntax::codemap::Span; -use syntax::ptr::P; -use syntax::owned_slice::OwnedSlice; +use hir::*; #[derive(Copy, Clone, PartialEq, Eq)] pub enum FnKind<'a> { /// fn foo() or extern "Abi" fn foo() - ItemFn(Ident, &'a Generics, Unsafety, Constness, Abi, Visibility), + ItemFn(Name, &'a Generics, Unsafety, Constness, Abi, Visibility), /// fn foo(&self) - Method(Ident, &'a MethodSig, Option), + Method(Name, &'a MethodSig, Option), - /// |x, y| ... - /// proc(x, y) ... + /// |x, y| {} Closure, } @@ -58,59 +54,80 @@ pub trait Visitor<'v> : Sized { // Nothing to do. } fn visit_ident(&mut self, span: Span, ident: Ident) { - self.visit_name(span, ident.name); - } - fn visit_mod(&mut self, m: &'v Mod, _s: Span, _n: NodeId) { walk_mod(self, m) } - fn visit_foreign_item(&mut self, i: &'v ForeignItem) { walk_foreign_item(self, i) } - fn visit_item(&mut self, i: &'v Item) { walk_item(self, i) } - fn visit_local(&mut self, l: &'v Local) { walk_local(self, l) } - fn visit_block(&mut self, b: &'v Block) { walk_block(self, b) } - fn visit_stmt(&mut self, s: &'v Stmt) { walk_stmt(self, s) } - fn visit_arm(&mut self, a: &'v Arm) { walk_arm(self, a) } - fn visit_pat(&mut self, p: &'v Pat) { walk_pat(self, p) } - fn visit_decl(&mut self, d: &'v Decl) { walk_decl(self, d) } - fn visit_expr(&mut self, ex: &'v Expr) { walk_expr(self, ex) } - fn visit_expr_post(&mut self, _ex: &'v Expr) { } - fn visit_ty(&mut self, t: &'v Ty) { walk_ty(self, t) } - fn visit_generics(&mut self, g: &'v Generics) { walk_generics(self, g) } + walk_ident(self, span, ident); + } + fn visit_mod(&mut self, m: &'v Mod, _s: Span, _n: NodeId) { + walk_mod(self, m) + } + fn visit_foreign_item(&mut self, i: &'v ForeignItem) { + walk_foreign_item(self, i) + } + fn visit_item(&mut self, i: &'v Item) { + walk_item(self, i) + } + fn visit_local(&mut self, l: &'v Local) { + walk_local(self, l) + } + fn visit_block(&mut self, b: &'v Block) { + walk_block(self, b) + } + fn visit_stmt(&mut self, s: &'v Stmt) { + walk_stmt(self, s) + } + fn visit_arm(&mut self, a: &'v Arm) { + walk_arm(self, a) + } + fn visit_pat(&mut self, p: &'v Pat) { + walk_pat(self, p) + } + fn visit_decl(&mut self, d: &'v Decl) { + walk_decl(self, d) + } + fn visit_expr(&mut self, ex: &'v Expr) { + walk_expr(self, ex) + } + fn visit_expr_post(&mut self, _ex: &'v Expr) { + } + fn visit_ty(&mut self, t: &'v Ty) { + walk_ty(self, t) + } + fn visit_generics(&mut self, g: &'v Generics) { + walk_generics(self, g) + } fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: &'v Block, s: Span, _: NodeId) { walk_fn(self, fk, fd, b, s) } - fn visit_trait_item(&mut self, ti: &'v TraitItem) { walk_trait_item(self, ti) } - fn visit_impl_item(&mut self, ii: &'v ImplItem) { walk_impl_item(self, ii) } - fn visit_trait_ref(&mut self, t: &'v TraitRef) { walk_trait_ref(self, t) } + fn visit_trait_item(&mut self, ti: &'v TraitItem) { + walk_trait_item(self, ti) + } + fn visit_impl_item(&mut self, ii: &'v ImplItem) { + walk_impl_item(self, ii) + } + fn visit_trait_ref(&mut self, t: &'v TraitRef) { + walk_trait_ref(self, t) + } fn visit_ty_param_bound(&mut self, bounds: &'v TyParamBound) { walk_ty_param_bound(self, bounds) } fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef, m: &'v TraitBoundModifier) { walk_poly_trait_ref(self, t, m) } - fn visit_struct_def(&mut self, s: &'v StructDef, _: Ident, _: &'v Generics, _: NodeId) { + fn visit_variant_data(&mut self, s: &'v VariantData, _: Name, + _: &'v Generics, _: NodeId, _: Span) { walk_struct_def(self, s) } - fn visit_struct_field(&mut self, s: &'v StructField) { walk_struct_field(self, s) } - fn visit_enum_def(&mut self, enum_definition: &'v EnumDef, - generics: &'v Generics) { - walk_enum_def(self, enum_definition, generics) + fn visit_struct_field(&mut self, s: &'v StructField) { + walk_struct_field(self, s) } - - fn visit_variant(&mut self, v: &'v Variant, g: &'v Generics) { walk_variant(self, v, g) } - - /// Visits an optional reference to a lifetime. The `span` is the span of some surrounding - /// reference should opt_lifetime be None. - fn visit_opt_lifetime_ref(&mut self, - _span: Span, - opt_lifetime: &'v Option) { - match *opt_lifetime { - Some(ref l) => self.visit_lifetime_ref(l), - None => () - } + fn visit_enum_def(&mut self, enum_definition: &'v EnumDef, + generics: &'v Generics, item_id: NodeId, _: Span) { + walk_enum_def(self, enum_definition, generics, item_id) } - fn visit_lifetime_bound(&mut self, lifetime: &'v Lifetime) { - walk_lifetime_bound(self, lifetime) + fn visit_variant(&mut self, v: &'v Variant, g: &'v Generics, item_id: NodeId) { + walk_variant(self, v, g, item_id) } - fn visit_lifetime_ref(&mut self, lifetime: &'v Lifetime) { - walk_lifetime_ref(self, lifetime) + fn visit_lifetime(&mut self, lifetime: &'v Lifetime) { + walk_lifetime(self, lifetime) } fn visit_lifetime_def(&mut self, lifetime: &'v LifetimeDef) { walk_lifetime_def(self, lifetime) @@ -121,6 +138,9 @@ pub trait Visitor<'v> : Sized { fn visit_path(&mut self, path: &'v Path, _id: NodeId) { walk_path(self, path) } + fn visit_path_list_item(&mut self, prefix: &'v Path, item: &'v PathListItem) { + walk_path_list_item(self, prefix, item) + } fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v PathSegment) { walk_path_segment(self, path_span, path_segment) } @@ -130,54 +150,74 @@ pub trait Visitor<'v> : Sized { fn visit_assoc_type_binding(&mut self, type_binding: &'v TypeBinding) { walk_assoc_type_binding(self, type_binding) } - fn visit_attribute(&mut self, _attr: &'v Attribute) {} + fn visit_attribute(&mut self, _attr: &'v Attribute) { + } + fn visit_macro_def(&mut self, macro_def: &'v MacroDef) { + walk_macro_def(self, macro_def) + } } -pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate) { - visitor.visit_mod(&krate.module, krate.span, CRATE_NODE_ID); - for attr in &krate.attrs { - visitor.visit_attribute(attr); +pub fn walk_opt_name<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_name: Option) { + for name in opt_name { + visitor.visit_name(span, name); } } -pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod) { - for item in &module.items { - visitor.visit_item(&**item) +pub fn walk_opt_ident<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_ident: Option) { + for ident in opt_ident { + visitor.visit_ident(span, ident); } } -pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) { - visitor.visit_pat(&*local.pat); - walk_ty_opt(visitor, &local.ty); - walk_expr_opt(visitor, &local.init); +pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, ident: Ident) { + visitor.visit_name(span, ident.name); } -pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V, - lifetime_def: &'v LifetimeDef) { - visitor.visit_name(lifetime_def.lifetime.span, lifetime_def.lifetime.name); - for bound in &lifetime_def.bounds { - visitor.visit_lifetime_bound(bound); - } +pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate) { + visitor.visit_mod(&krate.module, krate.span, CRATE_NODE_ID); + walk_list!(visitor, visit_attribute, &krate.attrs); + walk_list!(visitor, visit_macro_def, &krate.exported_macros); +} + +pub fn walk_macro_def<'v, V: Visitor<'v>>(visitor: &mut V, macro_def: &'v MacroDef) { + visitor.visit_name(macro_def.span, macro_def.name); + walk_opt_name(visitor, macro_def.span, macro_def.imported_from); + walk_list!(visitor, visit_attribute, ¯o_def.attrs); +} + +pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod) { + walk_list!(visitor, visit_item, &module.items); } -pub fn walk_lifetime_bound<'v, V: Visitor<'v>>(visitor: &mut V, - lifetime_ref: &'v Lifetime) { - visitor.visit_lifetime_ref(lifetime_ref) +pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) { + visitor.visit_pat(&local.pat); + walk_list!(visitor, visit_ty, &local.ty); + walk_list!(visitor, visit_expr, &local.init); +} + +pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) { + visitor.visit_name(lifetime.span, lifetime.name); } -pub fn walk_lifetime_ref<'v, V: Visitor<'v>>(visitor: &mut V, - lifetime_ref: &'v Lifetime) { - visitor.visit_name(lifetime_ref.span, lifetime_ref.name) +pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V, lifetime_def: &'v LifetimeDef) { + visitor.visit_lifetime(&lifetime_def.lifetime); + walk_list!(visitor, visit_lifetime, &lifetime_def.bounds); } -pub fn walk_explicit_self<'v, V: Visitor<'v>>(visitor: &mut V, - explicit_self: &'v ExplicitSelf) { +pub fn walk_explicit_self<'v, V: Visitor<'v>>(visitor: &mut V, explicit_self: &'v ExplicitSelf) { match explicit_self.node { - SelfStatic | SelfValue(_) => {}, - SelfRegion(ref lifetime, _, _) => { - visitor.visit_opt_lifetime_ref(explicit_self.span, lifetime) + SelfStatic => {} + SelfValue(name) => { + visitor.visit_name(explicit_self.span, name) + } + SelfRegion(ref opt_lifetime, _, name) => { + visitor.visit_name(explicit_self.span, name); + walk_list!(visitor, visit_lifetime, opt_lifetime); + } + SelfExplicit(ref typ, name) => { + visitor.visit_name(explicit_self.span, name); + visitor.visit_ty(typ) } - SelfExplicit(ref typ, _) => visitor.visit_ty(&**typ), } } @@ -186,56 +226,58 @@ pub fn walk_poly_trait_ref<'v, V>(visitor: &mut V, _modifier: &'v TraitBoundModifier) where V: Visitor<'v> { - walk_lifetime_decls_helper(visitor, &trait_ref.bound_lifetimes); + walk_list!(visitor, + visit_lifetime_def, + &trait_ref.bound_lifetimes); visitor.visit_trait_ref(&trait_ref.trait_ref); } -pub fn walk_trait_ref<'v,V>(visitor: &mut V, - trait_ref: &'v TraitRef) +pub fn walk_trait_ref<'v, V>(visitor: &mut V, trait_ref: &'v TraitRef) where V: Visitor<'v> { visitor.visit_path(&trait_ref.path, trait_ref.ref_id) } pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { - visitor.visit_ident(item.span, item.ident); + visitor.visit_name(item.span, item.name); match item.node { - ItemExternCrate(..) => {} + ItemExternCrate(opt_name) => { + walk_opt_name(visitor, item.span, opt_name) + } ItemUse(ref vp) => { match vp.node { - ViewPathSimple(ident, ref path) => { - visitor.visit_ident(vp.span, ident); + ViewPathSimple(name, ref path) => { + visitor.visit_name(vp.span, name); visitor.visit_path(path, item.id); } ViewPathGlob(ref path) => { visitor.visit_path(path, item.id); } ViewPathList(ref prefix, ref list) => { - for id in list { - match id.node { - PathListIdent { name, .. } => { - visitor.visit_ident(id.span, name); - } - PathListMod { .. } => () + if !list.is_empty() { + for item in list { + visitor.visit_path_list_item(prefix, item) } + } else { + visitor.visit_path(prefix, item.id); } - - // Note that the `prefix` here is not a complete - // path, so we don't use `visit_path`. - walk_path(visitor, prefix); } } } ItemStatic(ref typ, _, ref expr) | ItemConst(ref typ, ref expr) => { - visitor.visit_ty(&**typ); - visitor.visit_expr(&**expr); + visitor.visit_ty(typ); + visitor.visit_expr(expr); } ItemFn(ref declaration, unsafety, constness, abi, ref generics, ref body) => { - visitor.visit_fn(FnKind::ItemFn(item.ident, generics, unsafety, - constness, abi, item.vis), - &**declaration, - &**body, + visitor.visit_fn(FnKind::ItemFn(item.name, + generics, + unsafety, + constness, + abi, + item.vis), + declaration, + body, item.span, item.id) } @@ -243,125 +285,81 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { visitor.visit_mod(module, item.span, item.id) } ItemForeignMod(ref foreign_module) => { - for foreign_item in &foreign_module.items { - visitor.visit_foreign_item(&**foreign_item) - } + walk_list!(visitor, visit_foreign_item, &foreign_module.items); } ItemTy(ref typ, ref type_parameters) => { - visitor.visit_ty(&**typ); + visitor.visit_ty(typ); visitor.visit_generics(type_parameters) } ItemEnum(ref enum_definition, ref type_parameters) => { visitor.visit_generics(type_parameters); - visitor.visit_enum_def(enum_definition, type_parameters) + visitor.visit_enum_def(enum_definition, type_parameters, item.id, item.span) } ItemDefaultImpl(_, ref trait_ref) => { visitor.visit_trait_ref(trait_ref) } ItemImpl(_, _, ref type_parameters, - ref trait_reference, + ref opt_trait_reference, ref typ, ref impl_items) => { visitor.visit_generics(type_parameters); - match *trait_reference { - Some(ref trait_reference) => visitor.visit_trait_ref(trait_reference), - None => () - } - visitor.visit_ty(&**typ); - for impl_item in impl_items { - visitor.visit_impl_item(impl_item); - } + walk_list!(visitor, visit_trait_ref, opt_trait_reference); + visitor.visit_ty(typ); + walk_list!(visitor, visit_impl_item, impl_items); } ItemStruct(ref struct_definition, ref generics) => { visitor.visit_generics(generics); - visitor.visit_struct_def(&**struct_definition, - item.ident, - generics, - item.id) + visitor.visit_variant_data(struct_definition, item.name, + generics, item.id, item.span); } ItemTrait(_, ref generics, ref bounds, ref methods) => { visitor.visit_generics(generics); - walk_ty_param_bounds_helper(visitor, bounds); - for method in methods { - visitor.visit_trait_item(method) - } + walk_list!(visitor, visit_ty_param_bound, bounds); + walk_list!(visitor, visit_trait_item, methods); } } - for attr in &item.attrs { - visitor.visit_attribute(attr); - } + walk_list!(visitor, visit_attribute, &item.attrs); } pub fn walk_enum_def<'v, V: Visitor<'v>>(visitor: &mut V, enum_definition: &'v EnumDef, - generics: &'v Generics) { - for variant in &enum_definition.variants { - visitor.visit_variant(&**variant, generics); - } + generics: &'v Generics, + item_id: NodeId) { + walk_list!(visitor, visit_variant, &enum_definition.variants, generics, item_id); } pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V, variant: &'v Variant, - generics: &'v Generics) { - visitor.visit_ident(variant.span, variant.node.name); - - match variant.node.kind { - TupleVariantKind(ref variant_arguments) => { - for variant_argument in variant_arguments { - visitor.visit_ty(&*variant_argument.ty) - } - } - StructVariantKind(ref struct_definition) => { - visitor.visit_struct_def(&**struct_definition, - variant.node.name, - generics, - variant.node.id) - } - } - match variant.node.disr_expr { - Some(ref expr) => visitor.visit_expr(&**expr), - None => () - } - for attr in &variant.node.attrs { - visitor.visit_attribute(attr); - } -} - -pub fn skip_ty<'v, V: Visitor<'v>>(_: &mut V, _: &'v Ty) { - // Empty! -} - -pub fn walk_ty_opt<'v, V: Visitor<'v>>(visitor: &mut V, optional_type: &'v Option>) { - match *optional_type { - Some(ref ty) => visitor.visit_ty(&**ty), - None => () - } + generics: &'v Generics, + item_id: NodeId) { + visitor.visit_name(variant.span, variant.node.name); + visitor.visit_variant_data(&variant.node.data, variant.node.name, + generics, item_id, variant.span); + walk_list!(visitor, visit_expr, &variant.node.disr_expr); + walk_list!(visitor, visit_attribute, &variant.node.attrs); } pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { match typ.node { TyVec(ref ty) | TyParen(ref ty) => { - visitor.visit_ty(&**ty) + visitor.visit_ty(ty) } TyPtr(ref mutable_type) => { - visitor.visit_ty(&*mutable_type.ty) + visitor.visit_ty(&mutable_type.ty) } - TyRptr(ref lifetime, ref mutable_type) => { - visitor.visit_opt_lifetime_ref(typ.span, lifetime); - visitor.visit_ty(&*mutable_type.ty) + TyRptr(ref opt_lifetime, ref mutable_type) => { + walk_list!(visitor, visit_lifetime, opt_lifetime); + visitor.visit_ty(&mutable_type.ty) } TyTup(ref tuple_element_types) => { - for tuple_element_type in tuple_element_types { - visitor.visit_ty(&**tuple_element_type) - } + walk_list!(visitor, visit_ty, tuple_element_types); } TyBareFn(ref function_declaration) => { - for argument in &function_declaration.decl.inputs { - visitor.visit_ty(&*argument.ty) - } - walk_fn_ret_ty(visitor, &function_declaration.decl.output); - walk_lifetime_decls_helper(visitor, &function_declaration.lifetimes); + walk_fn_decl(visitor, &function_declaration.decl); + walk_list!(visitor, + visit_lifetime_def, + &function_declaration.lifetimes); } TyPath(ref maybe_qself, ref path) => { if let Some(ref qself) = *maybe_qself { @@ -370,36 +368,40 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { visitor.visit_path(path, typ.id); } TyObjectSum(ref ty, ref bounds) => { - visitor.visit_ty(&**ty); - walk_ty_param_bounds_helper(visitor, bounds); + visitor.visit_ty(ty); + walk_list!(visitor, visit_ty_param_bound, bounds); } TyFixedLengthVec(ref ty, ref expression) => { - visitor.visit_ty(&**ty); - visitor.visit_expr(&**expression) + visitor.visit_ty(ty); + visitor.visit_expr(expression) } TyPolyTraitRef(ref bounds) => { - walk_ty_param_bounds_helper(visitor, bounds) + walk_list!(visitor, visit_ty_param_bound, bounds); } TyTypeof(ref expression) => { - visitor.visit_expr(&**expression) + visitor.visit_expr(expression) } TyInfer => {} } } -pub fn walk_lifetime_decls_helper<'v, V: Visitor<'v>>(visitor: &mut V, - lifetimes: &'v Vec) { - for l in lifetimes { - visitor.visit_lifetime_def(l); - } -} - pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path) { for segment in &path.segments { visitor.visit_path_segment(path.span, segment); } } +pub fn walk_path_list_item<'v, V: Visitor<'v>>(visitor: &mut V, + prefix: &'v Path, + item: &'v PathListItem) { + for segment in &prefix.segments { + visitor.visit_path_segment(prefix.span, segment); + } + + walk_opt_name(visitor, item.span, item.node.name()); + walk_opt_name(visitor, item.span, item.node.rename()); +} + pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V, path_span: Span, segment: &'v PathSegment) { @@ -411,42 +413,30 @@ pub fn walk_path_parameters<'v, V: Visitor<'v>>(visitor: &mut V, _path_span: Span, path_parameters: &'v PathParameters) { match *path_parameters { - hir::AngleBracketedParameters(ref data) => { - for typ in data.types.iter() { - visitor.visit_ty(&**typ); - } - for lifetime in &data.lifetimes { - visitor.visit_lifetime_ref(lifetime); - } - for binding in data.bindings.iter() { - visitor.visit_assoc_type_binding(&**binding); - } + AngleBracketedParameters(ref data) => { + walk_list!(visitor, visit_ty, &data.types); + walk_list!(visitor, visit_lifetime, &data.lifetimes); + walk_list!(visitor, visit_assoc_type_binding, &data.bindings); } - hir::ParenthesizedParameters(ref data) => { - for typ in &data.inputs { - visitor.visit_ty(&**typ); - } - if let Some(ref typ) = data.output { - visitor.visit_ty(&**typ); - } + ParenthesizedParameters(ref data) => { + walk_list!(visitor, visit_ty, &data.inputs); + walk_list!(visitor, visit_ty, &data.output); } } } pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V, type_binding: &'v TypeBinding) { - visitor.visit_ident(type_binding.span, type_binding.ident); - visitor.visit_ty(&*type_binding.ty); + visitor.visit_name(type_binding.span, type_binding.name); + visitor.visit_ty(&type_binding.ty); } pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { match pattern.node { - PatEnum(ref path, ref children) => { + PatEnum(ref path, ref opt_children) => { visitor.visit_path(path, pattern.id); - if let Some(ref children) = *children { - for child in children { - visitor.visit_pat(&*child) - } + if let Some(ref children) = *opt_children { + walk_list!(visitor, visit_pat, children); } } PatQPath(ref qself, ref path) => { @@ -456,111 +446,89 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { PatStruct(ref path, ref fields, _) => { visitor.visit_path(path, pattern.id); for field in fields { - visitor.visit_pat(&*field.node.pat) + visitor.visit_name(field.span, field.node.name); + visitor.visit_pat(&field.node.pat) } } PatTup(ref tuple_elements) => { - for tuple_element in tuple_elements { - visitor.visit_pat(&**tuple_element) - } + walk_list!(visitor, visit_pat, tuple_elements); } PatBox(ref subpattern) | PatRegion(ref subpattern, _) => { - visitor.visit_pat(&**subpattern) + visitor.visit_pat(subpattern) } PatIdent(_, ref pth1, ref optional_subpattern) => { visitor.visit_ident(pth1.span, pth1.node); - match *optional_subpattern { - None => {} - Some(ref subpattern) => visitor.visit_pat(&**subpattern), - } + walk_list!(visitor, visit_pat, optional_subpattern); } - PatLit(ref expression) => visitor.visit_expr(&**expression), + PatLit(ref expression) => visitor.visit_expr(expression), PatRange(ref lower_bound, ref upper_bound) => { - visitor.visit_expr(&**lower_bound); - visitor.visit_expr(&**upper_bound) + visitor.visit_expr(lower_bound); + visitor.visit_expr(upper_bound) } PatWild(_) => (), - PatVec(ref prepattern, ref slice_pattern, ref postpatterns) => { - for prepattern in prepattern { - visitor.visit_pat(&**prepattern) - } - if let Some(ref slice_pattern) = *slice_pattern { - visitor.visit_pat(&**slice_pattern) - } - for postpattern in postpatterns { - visitor.visit_pat(&**postpattern) - } + PatVec(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); } } } -pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, - foreign_item: &'v ForeignItem) { - visitor.visit_ident(foreign_item.span, foreign_item.ident); +pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v ForeignItem) { + visitor.visit_name(foreign_item.span, foreign_item.name); match foreign_item.node { ForeignItemFn(ref function_declaration, ref generics) => { - walk_fn_decl(visitor, &**function_declaration); + walk_fn_decl(visitor, function_declaration); visitor.visit_generics(generics) } - ForeignItemStatic(ref typ, _) => visitor.visit_ty(&**typ), + ForeignItemStatic(ref typ, _) => visitor.visit_ty(typ), } - for attr in &foreign_item.attrs { - visitor.visit_attribute(attr); - } + walk_list!(visitor, visit_attribute, &foreign_item.attrs); } -pub fn walk_ty_param_bounds_helper<'v, V: Visitor<'v>>(visitor: &mut V, - bounds: &'v OwnedSlice) { - for bound in bounds.iter() { - visitor.visit_ty_param_bound(bound) - } -} - -pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, - bound: &'v TyParamBound) { +pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v TyParamBound) { match *bound { TraitTyParamBound(ref typ, ref modifier) => { visitor.visit_poly_trait_ref(typ, modifier); } RegionTyParamBound(ref lifetime) => { - visitor.visit_lifetime_bound(lifetime); + visitor.visit_lifetime(lifetime); } } } pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics) { - for param in generics.ty_params.iter() { - visitor.visit_ident(param.span, param.ident); - walk_ty_param_bounds_helper(visitor, ¶m.bounds); - walk_ty_opt(visitor, ¶m.default); + for param in &generics.ty_params { + visitor.visit_name(param.span, param.name); + walk_list!(visitor, visit_ty_param_bound, ¶m.bounds); + walk_list!(visitor, visit_ty, ¶m.default); } - walk_lifetime_decls_helper(visitor, &generics.lifetimes); + walk_list!(visitor, visit_lifetime_def, &generics.lifetimes); for predicate in &generics.where_clause.predicates { match predicate { - &hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate{ref bounded_ty, + &WherePredicate::BoundPredicate(WhereBoundPredicate{ref bounded_ty, ref bounds, + ref bound_lifetimes, ..}) => { - visitor.visit_ty(&**bounded_ty); - walk_ty_param_bounds_helper(visitor, bounds); + visitor.visit_ty(bounded_ty); + walk_list!(visitor, visit_ty_param_bound, bounds); + walk_list!(visitor, visit_lifetime_def, bound_lifetimes); } - &hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate{ref lifetime, + &WherePredicate::RegionPredicate(WhereRegionPredicate{ref lifetime, ref bounds, ..}) => { - visitor.visit_lifetime_ref(lifetime); - - for bound in bounds { - visitor.visit_lifetime_ref(bound); - } + visitor.visit_lifetime(lifetime); + walk_list!(visitor, visit_lifetime, bounds); } - &hir::WherePredicate::EqPredicate(hir::WhereEqPredicate{id, + &WherePredicate::EqPredicate(WhereEqPredicate{id, ref path, ref ty, ..}) => { visitor.visit_path(path, id); - visitor.visit_ty(&**ty); + visitor.visit_ty(ty); } } } @@ -568,20 +536,26 @@ pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics pub fn walk_fn_ret_ty<'v, V: Visitor<'v>>(visitor: &mut V, ret_ty: &'v FunctionRetTy) { if let Return(ref output_ty) = *ret_ty { - visitor.visit_ty(&**output_ty) + visitor.visit_ty(output_ty) } } pub fn walk_fn_decl<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl) { for argument in &function_declaration.inputs { - visitor.visit_pat(&*argument.pat); - visitor.visit_ty(&*argument.ty) + visitor.visit_pat(&argument.pat); + visitor.visit_ty(&argument.ty) } walk_fn_ret_ty(visitor, &function_declaration.output) } -pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, - function_kind: FnKind<'v>) { +pub fn walk_fn_decl_nopat<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl) { + for argument in &function_declaration.inputs { + visitor.visit_ty(&argument.ty) + } + walk_fn_ret_ty(visitor, &function_declaration.output) +} + +pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'v>) { match function_kind { FnKind::ItemFn(_, generics, _, _, _, _) => { visitor.visit_generics(generics); @@ -590,7 +564,7 @@ pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, visitor.visit_generics(&sig.generics); visitor.visit_explicit_self(&sig.explicit_self); } - FnKind::Closure(..) => {} + FnKind::Closure => {} } } @@ -605,16 +579,12 @@ pub fn walk_fn<'v, V: Visitor<'v>>(visitor: &mut V, } pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem) { - visitor.visit_ident(trait_item.span, trait_item.ident); - for attr in &trait_item.attrs { - visitor.visit_attribute(attr); - } + visitor.visit_name(trait_item.span, trait_item.name); + walk_list!(visitor, visit_attribute, &trait_item.attrs); match trait_item.node { ConstTraitItem(ref ty, ref default) => { visitor.visit_ty(ty); - if let Some(ref expr) = *default { - visitor.visit_expr(expr); - } + walk_list!(visitor, visit_expr, default); } MethodTraitItem(ref sig, None) => { visitor.visit_explicit_self(&sig.explicit_self); @@ -622,29 +592,33 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai walk_fn_decl(visitor, &sig.decl); } MethodTraitItem(ref sig, Some(ref body)) => { - visitor.visit_fn(FnKind::Method(trait_item.ident, sig, None), &sig.decl, - body, trait_item.span, trait_item.id); + visitor.visit_fn(FnKind::Method(trait_item.name, sig, None), + &sig.decl, + body, + trait_item.span, + trait_item.id); } TypeTraitItem(ref bounds, ref default) => { - walk_ty_param_bounds_helper(visitor, bounds); - walk_ty_opt(visitor, default); + walk_list!(visitor, visit_ty_param_bound, bounds); + walk_list!(visitor, visit_ty, default); } } } pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplItem) { - visitor.visit_ident(impl_item.span, impl_item.ident); - for attr in &impl_item.attrs { - visitor.visit_attribute(attr); - } + visitor.visit_name(impl_item.span, impl_item.name); + walk_list!(visitor, visit_attribute, &impl_item.attrs); match impl_item.node { ConstImplItem(ref ty, ref expr) => { visitor.visit_ty(ty); visitor.visit_expr(expr); } MethodImplItem(ref sig, ref body) => { - visitor.visit_fn(FnKind::Method(impl_item.ident, sig, Some(impl_item.vis)), &sig.decl, - body, impl_item.span, impl_item.id); + visitor.visit_fn(FnKind::Method(impl_item.name, sig, Some(impl_item.vis)), + &sig.decl, + body, + impl_item.span, + impl_item.id); } TypeImplItem(ref ty) => { visitor.visit_ty(ty); @@ -652,157 +626,129 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt } } -pub fn walk_struct_def<'v, V: Visitor<'v>>(visitor: &mut V, - struct_definition: &'v StructDef) { - for field in &struct_definition.fields { - visitor.visit_struct_field(field) - } +pub fn walk_struct_def<'v, V: Visitor<'v>>(visitor: &mut V, struct_definition: &'v VariantData) { + walk_list!(visitor, visit_struct_field, struct_definition.fields()); } -pub fn walk_struct_field<'v, V: Visitor<'v>>(visitor: &mut V, - struct_field: &'v StructField) { - if let NamedField(name, _) = struct_field.node.kind { - visitor.visit_ident(struct_field.span, name); - } - - visitor.visit_ty(&*struct_field.node.ty); - - for attr in &struct_field.node.attrs { - visitor.visit_attribute(attr); - } +pub fn walk_struct_field<'v, V: Visitor<'v>>(visitor: &mut V, struct_field: &'v StructField) { + walk_opt_name(visitor, struct_field.span, struct_field.node.name()); + visitor.visit_ty(&struct_field.node.ty); + walk_list!(visitor, visit_attribute, &struct_field.node.attrs); } pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block) { - for statement in &block.stmts { - visitor.visit_stmt(&**statement) - } - walk_expr_opt(visitor, &block.expr) + walk_list!(visitor, visit_stmt, &block.stmts); + walk_list!(visitor, visit_expr, &block.expr); } pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt) { match statement.node { - StmtDecl(ref declaration, _) => visitor.visit_decl(&**declaration), + StmtDecl(ref declaration, _) => visitor.visit_decl(declaration), StmtExpr(ref expression, _) | StmtSemi(ref expression, _) => { - visitor.visit_expr(&**expression) + visitor.visit_expr(expression) } } } pub fn walk_decl<'v, V: Visitor<'v>>(visitor: &mut V, declaration: &'v Decl) { match declaration.node { - DeclLocal(ref local) => visitor.visit_local(&**local), - DeclItem(ref item) => visitor.visit_item(&**item), - } -} - -pub fn walk_expr_opt<'v, V: Visitor<'v>>(visitor: &mut V, - optional_expression: &'v Option>) { - match *optional_expression { - None => {} - Some(ref expression) => visitor.visit_expr(&**expression), - } -} - -pub fn walk_exprs<'v, V: Visitor<'v>>(visitor: &mut V, expressions: &'v [P]) { - for expression in expressions { - visitor.visit_expr(&**expression) + DeclLocal(ref local) => visitor.visit_local(local), + DeclItem(ref item) => visitor.visit_item(item), } } pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { match expression.node { - ExprBox(ref place, ref subexpression) => { - place.as_ref().map(|e|visitor.visit_expr(&**e)); - visitor.visit_expr(&**subexpression) + ExprBox(ref subexpression) => { + visitor.visit_expr(subexpression) } ExprVec(ref subexpressions) => { - walk_exprs(visitor, subexpressions) + walk_list!(visitor, visit_expr, subexpressions); } ExprRepeat(ref element, ref count) => { - visitor.visit_expr(&**element); - visitor.visit_expr(&**count) + visitor.visit_expr(element); + visitor.visit_expr(count) } ExprStruct(ref path, ref fields, ref optional_base) => { visitor.visit_path(path, expression.id); for field in fields { - visitor.visit_expr(&*field.expr) + visitor.visit_name(field.name.span, field.name.node); + visitor.visit_expr(&field.expr) } - walk_expr_opt(visitor, optional_base) + walk_list!(visitor, visit_expr, optional_base); } ExprTup(ref subexpressions) => { - for subexpression in subexpressions { - visitor.visit_expr(&**subexpression) - } + walk_list!(visitor, visit_expr, subexpressions); } ExprCall(ref callee_expression, ref arguments) => { - for argument in arguments { - visitor.visit_expr(&**argument) - } - visitor.visit_expr(&**callee_expression) + walk_list!(visitor, visit_expr, arguments); + visitor.visit_expr(callee_expression) } - ExprMethodCall(_, ref types, ref arguments) => { - walk_exprs(visitor, arguments); - for typ in types { - visitor.visit_ty(&**typ) - } + ExprMethodCall(ref name, ref types, ref arguments) => { + visitor.visit_name(name.span, name.node); + walk_list!(visitor, visit_expr, arguments); + walk_list!(visitor, visit_ty, types); } ExprBinary(_, ref left_expression, ref right_expression) => { - visitor.visit_expr(&**left_expression); - visitor.visit_expr(&**right_expression) + visitor.visit_expr(left_expression); + visitor.visit_expr(right_expression) } ExprAddrOf(_, ref subexpression) | ExprUnary(_, ref subexpression) => { - visitor.visit_expr(&**subexpression) + visitor.visit_expr(subexpression) } ExprLit(_) => {} ExprCast(ref subexpression, ref typ) => { - visitor.visit_expr(&**subexpression); - visitor.visit_ty(&**typ) + visitor.visit_expr(subexpression); + visitor.visit_ty(typ) } ExprIf(ref head_expression, ref if_block, ref optional_else) => { - visitor.visit_expr(&**head_expression); - visitor.visit_block(&**if_block); - walk_expr_opt(visitor, optional_else) + visitor.visit_expr(head_expression); + visitor.visit_block(if_block); + walk_list!(visitor, visit_expr, optional_else); } - ExprWhile(ref subexpression, ref block, _) => { - visitor.visit_expr(&**subexpression); - visitor.visit_block(&**block) + ExprWhile(ref subexpression, ref block, opt_ident) => { + visitor.visit_expr(subexpression); + visitor.visit_block(block); + walk_opt_ident(visitor, expression.span, opt_ident) + } + ExprLoop(ref block, opt_ident) => { + visitor.visit_block(block); + walk_opt_ident(visitor, expression.span, opt_ident) } - ExprLoop(ref block, _) => visitor.visit_block(&**block), ExprMatch(ref subexpression, ref arms, _) => { - visitor.visit_expr(&**subexpression); - for arm in arms { - visitor.visit_arm(arm) - } + visitor.visit_expr(subexpression); + walk_list!(visitor, visit_arm, arms); } ExprClosure(_, ref function_declaration, ref body) => { visitor.visit_fn(FnKind::Closure, - &**function_declaration, - &**body, + function_declaration, + body, expression.span, expression.id) } - ExprBlock(ref block) => visitor.visit_block(&**block), + ExprBlock(ref block) => visitor.visit_block(block), ExprAssign(ref left_hand_expression, ref right_hand_expression) => { - visitor.visit_expr(&**right_hand_expression); - visitor.visit_expr(&**left_hand_expression) + visitor.visit_expr(right_hand_expression); + visitor.visit_expr(left_hand_expression) } ExprAssignOp(_, ref left_expression, ref right_expression) => { - visitor.visit_expr(&**right_expression); - visitor.visit_expr(&**left_expression) + visitor.visit_expr(right_expression); + visitor.visit_expr(left_expression) } - ExprField(ref subexpression, _) => { - visitor.visit_expr(&**subexpression); + ExprField(ref subexpression, ref name) => { + visitor.visit_expr(subexpression); + visitor.visit_name(name.span, name.node); } ExprTupField(ref subexpression, _) => { - visitor.visit_expr(&**subexpression); + visitor.visit_expr(subexpression); } ExprIndex(ref main_expression, ref index_expression) => { - visitor.visit_expr(&**main_expression); - visitor.visit_expr(&**index_expression) + visitor.visit_expr(main_expression); + visitor.visit_expr(index_expression) } ExprRange(ref start, ref end) => { - walk_expr_opt(visitor, start); - walk_expr_opt(visitor, end) + walk_list!(visitor, visit_expr, start); + walk_list!(visitor, visit_expr, end); } ExprPath(ref maybe_qself, ref path) => { if let Some(ref qself) = *maybe_qself { @@ -810,21 +756,20 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { } visitor.visit_path(path, expression.id) } - ExprBreak(_) | ExprAgain(_) => {} - ExprRet(ref optional_expression) => { - walk_expr_opt(visitor, optional_expression) + ExprBreak(ref opt_sp_ident) | ExprAgain(ref opt_sp_ident) => { + for sp_ident in opt_sp_ident { + visitor.visit_ident(sp_ident.span, sp_ident.node); + } } - ExprParen(ref subexpression) => { - visitor.visit_expr(&**subexpression) + ExprRet(ref optional_expression) => { + walk_list!(visitor, visit_expr, optional_expression); } ExprInlineAsm(ref ia) => { - for input in &ia.inputs { - let (_, ref input) = *input; - visitor.visit_expr(&**input) + for &(_, ref input) in &ia.inputs { + visitor.visit_expr(&input) } - for output in &ia.outputs { - let (_, ref output, _) = *output; - visitor.visit_expr(&**output) + for &(_, ref output, _) in &ia.outputs { + visitor.visit_expr(&output) } } } @@ -833,12 +778,8 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { } pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm) { - for pattern in &arm.pats { - visitor.visit_pat(&**pattern) - } - walk_expr_opt(visitor, &arm.guard); - visitor.visit_expr(&*arm.body); - for attr in &arm.attrs { - visitor.visit_attribute(attr); - } + walk_list!(visitor, visit_pat, &arm.pats); + walk_list!(visitor, visit_expr, &arm.guard); + visitor.visit_expr(&arm.body); + walk_list!(visitor, visit_attribute, &arm.attrs); } diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs new file mode 100644 index 0000000000..693de1740b --- /dev/null +++ b/src/librustc_lint/bad_style.rs @@ -0,0 +1,372 @@ +// 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 middle::def; +use middle::ty; +use lint::{LateContext, LintContext, LintArray}; +use lint::{LintPass, LateLintPass}; + +use syntax::ast; +use syntax::attr::{self, AttrMetaMethods}; +use syntax::codemap::Span; + +use rustc_front::hir; +use rustc_front::visit::FnKind; + +#[derive(PartialEq)] +pub enum MethodLateContext { + TraitDefaultImpl, + TraitImpl, + 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 => cx.sess().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 + } + } + } + } +} + +declare_lint! { + pub NON_CAMEL_CASE_TYPES, + Warn, + "types, variants, traits and type parameters should have camel case names" +} + +#[derive(Copy, Clone)] +pub struct NonCamelCaseTypes; + +impl NonCamelCaseTypes { + fn check_case(&self, cx: &LateContext, sort: &str, name: ast::Name, span: Span) { + fn is_camel_case(name: ast::Name) -> bool { + let name = name.as_str(); + if name.is_empty() { + return true; + } + let name = name.trim_matches('_'); + + // 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.char_at(0).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() + } + + let s = name.as_str(); + + 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) + } else { + format!("{} `{}` should have a camel case name such as `{}`", sort, s, c) + }; + cx.span_lint(NON_CAMEL_CASE_TYPES, span, &m[..]); + } + } +} + +impl LintPass for NonCamelCaseTypes { + fn get_lints(&self) -> LintArray { + lint_array!(NON_CAMEL_CASE_TYPES) + } +} + +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 has_extern_repr = extern_repr_count > 0; + + if has_extern_repr { + return; + } + + match it.node { + hir::ItemTy(..) | hir::ItemStruct(..) => { + 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; + } + self.check_case(cx, "type", it.name, it.span); + for variant in &enum_definition.variants { + self.check_case(cx, "variant", variant.node.name, variant.span); + } + } + _ => () + } + } + + fn check_generics(&mut self, cx: &LateContext, it: &hir::Generics) { + for gen in it.ty_params.iter() { + self.check_case(cx, "type parameter", gen.name, gen.span); + } + } +} + +declare_lint! { + pub NON_SNAKE_CASE, + Warn, + "methods, functions, lifetime parameters and modules should have snake case names" +} + +#[derive(Copy, Clone)] +pub struct NonSnakeCase; + +impl NonSnakeCase { + fn to_snake_case(mut str: &str) -> String { + let mut words = vec![]; + // Preserve leading underscores + str = str.trim_left_matches(|c: char| { + if c == '_' { + words.push(String::new()); + true + } else { + false + } + }); + for s in str.split('_') { + let mut last_upper = false; + let mut buf = String::new(); + if s.is_empty() { + continue; + } + for ch in s.chars() { + if !buf.is_empty() && buf != "'" + && ch.is_uppercase() + && !last_upper { + words.push(buf); + buf = String::new(); + } + last_upper = ch.is_uppercase(); + buf.extend(ch.to_lowercase()); + } + words.push(buf); + } + words.join("_") + } + + fn check_snake_case(&self, cx: &LateContext, sort: &str, name: &str, span: Option) { + fn is_snake_case(ident: &str) -> bool { + if ident.is_empty() { + return true; + } + let ident = ident.trim_left_matches('\''); + let ident = ident.trim_matches('_'); + + let mut allow_underscore = true; + ident.chars().all(|c| { + allow_underscore = match c { + '_' if !allow_underscore => return false, + '_' => false, + // It would be more obvious to use `c.is_lowercase()`, + // but some characters do not have a lowercase form + c if !c.is_uppercase() => true, + _ => return false, + }; + true + }) + } + + if !is_snake_case(name) { + let sc = NonSnakeCase::to_snake_case(name); + let msg = if sc != name { + format!("{} `{}` should have a snake case name such as `{}`", + sort, name, sc) + } else { + format!("{} `{}` should have a snake case name", + sort, name) + }; + match span { + Some(span) => cx.span_lint(NON_SNAKE_CASE, span, &msg), + None => cx.lint(NON_SNAKE_CASE, &msg), + } + } + } +} + +impl LintPass for NonSnakeCase { + fn get_lints(&self) -> LintArray { + lint_array!(NON_SNAKE_CASE) + } +} + +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))); + 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 { + self.check_snake_case(cx, "crate", name, Some(attr.span)); + } + } + + 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::ItemFn(name, _, _, _, _, _) => { + self.check_snake_case(cx, "function", &name.as_str(), Some(span)) + }, + _ => (), + } + } + + fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { + if let hir::ItemMod(_) = it.node { + self.check_snake_case(cx, "module", &it.name.as_str(), Some(it.span)); + } + } + + 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(), + 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(), + Some(t.lifetime.span)); + } + + fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) { + if let &hir::PatIdent(_, ref path1, _) = &p.node { + let def = cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def()); + if let Some(def::DefLocal(..)) = def { + self.check_snake_case(cx, "variable", &path1.node.name.as_str(), Some(p.span)); + } + } + } + + fn check_struct_def(&mut self, cx: &LateContext, s: &hir::VariantData, + _: ast::Name, _: &hir::Generics, _: ast::NodeId) { + for sf in s.fields() { + if let hir::StructField_ { kind: hir::NamedField(name, _), .. } = sf.node { + self.check_snake_case(cx, "structure field", &name.as_str(), + Some(sf.span)); + } + } + } +} + +declare_lint! { + pub NON_UPPER_CASE_GLOBALS, + Warn, + "static constants should have uppercase identifiers" +} + +#[derive(Copy, Clone)] +pub struct NonUpperCaseGlobals; + +impl NonUpperCaseGlobals { + fn check_upper_case(cx: &LateContext, sort: &str, name: ast::Name, span: Span) { + let s = name.as_str(); + + 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)); + } else { + cx.span_lint(NON_UPPER_CASE_GLOBALS, span, + &format!("{} `{}` should have an upper case name", + sort, s)); + } + } + } +} + +impl LintPass for NonUpperCaseGlobals { + fn get_lints(&self) -> LintArray { + lint_array!(NON_UPPER_CASE_GLOBALS) + } +} + +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::ItemConst(..) => { + NonUpperCaseGlobals::check_upper_case(cx, "constant", it.name, it.span); + } + _ => {} + } + } + + 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); + } + _ => {} + } + } + + fn check_impl_item(&mut self, cx: &LateContext, ii: &hir::ImplItem) { + match ii.node { + hir::ConstImplItem(..) => { + NonUpperCaseGlobals::check_upper_case(cx, "associated constant", + ii.name, ii.span); + } + _ => {} + } + } + + fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) { + // Lint for constants that look like binding identifiers (#7526) + match (&p.node, cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def())) { + (&hir::PatIdent(_, ref path1, _), Some(def::DefConst(..))) => { + NonUpperCaseGlobals::check_upper_case(cx, "constant in pattern", + path1.node.name, p.span); + } + _ => {} + } + } +} diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 717690addd..a001289b19 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -28,1474 +28,198 @@ //! Use the former for unit-like structs and the latter for structs with //! a `pub fn new()`. -use metadata::{csearch, decoder}; -use middle::{cfg, def, infer, pat_util, stability, traits}; +use metadata::decoder; +use middle::{cfg, def, infer, stability, traits}; use middle::def_id::DefId; use middle::subst::Substs; use middle::ty::{self, Ty}; use middle::ty::adjustment; -use middle::const_eval::{eval_const_expr_partial, ConstVal}; -use middle::const_eval::EvalHint::ExprTypeChecked; use rustc::front::map as hir_map; -use util::nodemap::{FnvHashMap, FnvHashSet, NodeSet}; -use lint::{Level, Context, LintPass, LintArray, Lint}; +use util::nodemap::{NodeSet}; +use lint::{Level, LateContext, LintContext, LintArray, Lint}; +use lint::{LintPass, LateLintPass}; use std::collections::HashSet; -use std::collections::hash_map::Entry::{Occupied, Vacant}; -use std::{cmp, slice}; -use std::{i8, i16, i32, i64, u8, u16, u32, u64, f32, f64}; -use syntax::{abi, ast}; -use syntax::attr as syntax_attr; +use syntax::{ast}; +use syntax::attr::{self, AttrMetaMethods}; use syntax::codemap::{self, Span}; -use syntax::feature_gate::{KNOWN_ATTRIBUTES, AttributeType}; -use rustc_front::hir::{TyIs, TyUs, TyI8, TyU8, TyI16, TyU16, TyI32, TyU32, TyI64, TyU64}; -use syntax::ptr::P; use rustc_front::hir; +use rustc_front::visit::{self, FnKind, Visitor}; -use rustc_front::attr::{self, AttrMetaMethods}; -use rustc_front::visit::{self, FnKind, Visitor}; -use rustc_front::lowering::unlower_attribute; - -use rustc_front::util::is_shift_binop; - -// hardwired lints from librustc -pub use lint::builtin::*; - -declare_lint! { - WHILE_TRUE, - Warn, - "suggest using `loop { }` instead of `while true { }`" -} - -#[derive(Copy, Clone)] -pub struct WhileTrue; - -impl LintPass for WhileTrue { - fn get_lints(&self) -> LintArray { - lint_array!(WHILE_TRUE) - } - - fn check_expr(&mut self, cx: &Context, e: &hir::Expr) { - if let hir::ExprWhile(ref cond, _, _) = e.node { - if let hir::ExprLit(ref lit) = cond.node { - if let hir::LitBool(true) = lit.node { - cx.span_lint(WHILE_TRUE, e.span, - "denote infinite loops with loop { ... }"); - } - } - } - } -} - -declare_lint! { - UNUSED_COMPARISONS, - Warn, - "comparisons made useless by limits of the types involved" -} - -declare_lint! { - OVERFLOWING_LITERALS, - Warn, - "literal out of range for its type" -} - -declare_lint! { - EXCEEDING_BITSHIFTS, - Deny, - "shift exceeds the type's number of bits" -} - -#[derive(Copy, Clone)] -pub struct TypeLimits { - /// Id of the last visited negated expression - negated_expr_id: ast::NodeId, -} - -impl TypeLimits { - pub fn new() -> TypeLimits { - TypeLimits { - negated_expr_id: !0, - } - } -} - -impl LintPass for TypeLimits { - fn get_lints(&self) -> LintArray { - lint_array!(UNUSED_COMPARISONS, OVERFLOWING_LITERALS, EXCEEDING_BITSHIFTS) - } - - fn check_expr(&mut self, cx: &Context, e: &hir::Expr) { - match e.node { - hir::ExprUnary(hir::UnNeg, ref expr) => { - match expr.node { - hir::ExprLit(ref lit) => { - match lit.node { - hir::LitInt(_, hir::UnsignedIntLit(_)) => { - check_unsigned_negation_feature(cx, e.span); - }, - hir::LitInt(_, hir::UnsuffixedIntLit(_)) => { - if let ty::TyUint(_) = cx.tcx.node_id_to_type(e.id).sty { - check_unsigned_negation_feature(cx, e.span); - } - }, - _ => () - } - }, - _ => { - let t = cx.tcx.node_id_to_type(expr.id); - match t.sty { - ty::TyUint(_) => { - check_unsigned_negation_feature(cx, e.span); - }, - _ => () - } - } - }; - // propagate negation, if the negation itself isn't negated - if self.negated_expr_id != e.id { - self.negated_expr_id = expr.id; - } - }, - hir::ExprParen(ref expr) 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, - "comparison is useless due to type limits"); - } - - if is_shift_binop(binop.node) { - let opt_ty_bits = match cx.tcx.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 - }; - - if let Some(bits) = opt_ty_bits { - let exceeding = if let hir::ExprLit(ref lit) = r.node { - if let hir::LitInt(shift, _) = lit.node { shift >= bits } - else { false } - } else { - match eval_const_expr_partial(cx.tcx, &r, ExprTypeChecked) { - Ok(ConstVal::Int(shift)) => { shift as u64 >= bits }, - Ok(ConstVal::Uint(shift)) => { shift >= bits }, - _ => { false } - } - }; - if exceeding { - 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 { - ty::TyInt(t) => { - match lit.node { - hir::LitInt(v, hir::SignedIntLit(_, hir::Plus)) | - hir::LitInt(v, hir::UnsuffixedIntLit(hir::Plus)) => { - let int_type = if let hir::TyIs = t { - cx.sess().target.int_type - } else { - t - }; - let (_, max) = int_ty_range(int_type); - let negative = self.negated_expr_id == e.id; - - // Detect literal value out of range [min, max] inclusive - // 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, - &*format!("literal out of range for {:?}", t)); - return; - } - } - _ => panic!() - }; - }, - ty::TyUint(t) => { - let uint_type = if let hir::TyUs = t { - cx.sess().target.uint_type - } else { - t - }; - let (min, max) = uint_ty_range(uint_type); - let lit_val: u64 = match lit.node { - hir::LitByte(_v) => return, // _v is u8, within range by definition - hir::LitInt(v, _) => v, - _ => panic!() - }; - if lit_val < min || lit_val > max { - 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 { - hir::LitFloat(ref v, _) | - hir::LitFloatUnsuffixed(ref v) => { - match v.parse() { - Ok(f) => f, - Err(_) => return - } - } - _ => panic!() - }; - if lit_val < min || lit_val > max { - 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 { - 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::BiEq | hir::BiNe => v >= min && v <= max, - _ => panic!() - } - } - - 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 - }) - } - - // 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: hir::IntTy) -> (i64, i64) { - match int_ty { - hir::TyIs => (i64::MIN, i64::MAX), - hir::TyI8 => (i8::MIN as i64, i8::MAX as i64), - hir::TyI16 => (i16::MIN as i64, i16::MAX as i64), - hir::TyI32 => (i32::MIN as i64, i32::MAX as i64), - hir::TyI64 => (i64::MIN, i64::MAX) - } - } - - fn uint_ty_range(uint_ty: hir::UintTy) -> (u64, u64) { - match uint_ty { - hir::TyUs => (u64::MIN, u64::MAX), - hir::TyU8 => (u8::MIN as u64, u8::MAX as u64), - hir::TyU16 => (u16::MIN as u64, u16::MAX as u64), - hir::TyU32 => (u32::MIN as u64, u32::MAX as u64), - hir::TyU64 => (u64::MIN, u64::MAX) - } - } - - fn float_ty_range(float_ty: hir::FloatTy) -> (f64, f64) { - match float_ty { - hir::TyF32 => (f32::MIN as f64, f32::MAX as f64), - hir::TyF64 => (f64::MIN, f64::MAX) - } - } - - fn int_ty_bits(int_ty: hir::IntTy, target_int_ty: hir::IntTy) -> u64 { - match int_ty { - hir::TyIs => int_ty_bits(target_int_ty, target_int_ty), - hir::TyI8 => i8::BITS as u64, - hir::TyI16 => i16::BITS as u64, - hir::TyI32 => i32::BITS as u64, - hir::TyI64 => i64::BITS as u64 - } - } - - fn uint_ty_bits(uint_ty: hir::UintTy, target_uint_ty: hir::UintTy) -> u64 { - match uint_ty { - hir::TyUs => uint_ty_bits(target_uint_ty, target_uint_ty), - hir::TyU8 => u8::BITS as u64, - hir::TyU16 => u16::BITS as u64, - hir::TyU32 => u32::BITS as u64, - hir::TyU64 => u64::BITS as u64 - } - } - - fn check_limits(tcx: &ty::ctxt, binop: hir::BinOp, - l: &hir::Expr, 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 - }; - // 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 { - 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 { - hir::LitInt(v, hir::SignedIntLit(_, hir::Plus)) | - hir::LitInt(v, hir::UnsuffixedIntLit(hir::Plus)) => v as i64, - hir::LitInt(v, hir::SignedIntLit(_, hir::Minus)) | - hir::LitInt(v, hir::UnsuffixedIntLit(hir::Minus)) => -(v as i64), - _ => return true - }, - _ => panic!() - }; - 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 { - hir::LitInt(v, _) => v, - _ => return true - }, - _ => panic!() - }; - is_valid(norm_binop, lit_val, min, max) - } - _ => 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 - } - } - - fn check_unsigned_negation_feature(cx: &Context, span: Span) { - if !cx.sess().features.borrow().negate_unsigned { - // FIXME(#27141): change this to syntax::feature_gate::emit_feature_err… - cx.sess().span_warn(span, - "unary negation of unsigned integers will be feature gated in the future"); - // …and remove following two expressions. - if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some() { return; } - cx.sess().fileline_help(span, "add #![feature(negate_unsigned)] to the \ - crate attributes to enable the gate in advance"); - } - } - } -} - -declare_lint! { - IMPROPER_CTYPES, - Warn, - "proper use of libc types in foreign modules" -} - -struct ImproperCTypesVisitor<'a, 'tcx: 'a> { - cx: &'a Context<'a, 'tcx> -} - -enum FfiResult { - FfiSafe, - FfiUnsafe(&'static str), - FfiBadStruct(DefId, &'static str), - FfiBadEnum(DefId, &'static str) -} - -/// Check if this enum can be safely exported based on the -/// "nullable pointer optimization". Currently restricted -/// to function pointers and references, but could be -/// expanded to cover NonZero raw pointers and newtypes. -/// FIXME: This duplicates code in trans. -fn is_repr_nullable_ptr<'tcx>(tcx: &ty::ctxt<'tcx>, - def: ty::AdtDef<'tcx>, - substs: &Substs<'tcx>) - -> bool { - if def.variants.len() == 2 { - let data_idx; - - if def.variants[0].fields.is_empty() { - data_idx = 1; - } else if def.variants[1].fields.is_empty() { - data_idx = 0; - } else { - return false; - } - - if def.variants[data_idx].fields.len() == 1 { - match def.variants[data_idx].fields[0].ty(tcx, substs).sty { - ty::TyBareFn(None, _) => { return true; } - ty::TyRef(..) => { return true; } - _ => { } - } - } - } - false -} - -fn ast_ty_to_normalized<'tcx>(tcx: &ty::ctxt<'tcx>, - id: ast::NodeId) - -> Ty<'tcx> { - let tty = match tcx.ast_ty_to_ty_cache.borrow().get(&id) { - Some(&t) => t, - None => panic!("ast_ty_to_ty_cache was incomplete after typeck!") - }; - infer::normalize_associated_type(tcx, &tty) -} - -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 { - use self::FfiResult::*; - let cx = &self.cx.tcx; - - // Protect against infinite recursion, for example - // `struct S(*mut S);`. - // FIXME: A recursion limit is necessary as well, for irregular - // recusive types. - if !cache.insert(ty) { - return FfiSafe; - } - - match ty.sty { - ty::TyStruct(def, substs) => { - 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"); - } - - for field in &def.struct_variant().fields { - let field_ty = infer::normalize_associated_type(cx, &field.ty(cx, substs)); - let r = self.check_type_for_ffi(cache, field_ty); - match r { - FfiSafe => {} - FfiBadStruct(..) | FfiBadEnum(..) => { return r; } - FfiUnsafe(s) => { return FfiBadStruct(def.did, s); } - } - } - FfiSafe - } - ty::TyEnum(def, substs) => { - 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") - } - } - [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 too many #[repr(...)] attributes"); - } - } - - // Check the contained variants. - for variant in &def.variants { - for field in &variant.fields { - let arg = infer::normalize_associated_type(cx, &field.ty(cx, substs)); - let r = self.check_type_for_ffi(cache, arg); - match r { - FfiSafe => {} - FfiBadStruct(..) | FfiBadEnum(..) => { return r; } - FfiUnsafe(s) => { return FfiBadEnum(def.did, s); } - } - } - } - FfiSafe - } - - ty::TyChar => { - FfiUnsafe("found Rust type `char` in foreign module, while \ - `u32` or `libc::wchar_t` should be used") - } - - // Primitive types with a stable representation. - ty::TyBool | ty::TyInt(..) | ty::TyUint(..) | - ty::TyFloat(..) => FfiSafe, - - ty::TyBox(..) => { - FfiUnsafe("found Rust type Box<_> in foreign module, \ - consider using a raw pointer instead") - } - - ty::TySlice(_) => { - FfiUnsafe("found Rust slice type in foreign module, \ - consider using a raw pointer instead") - } - - ty::TyTrait(..) => { - FfiUnsafe("found Rust trait type in foreign module, \ - consider using a raw pointer instead") - } - - ty::TyStr => { - FfiUnsafe("found Rust type `str` in foreign module; \ - consider using a `*const libc::c_char`") - } - - ty::TyTuple(_) => { - FfiUnsafe("found Rust tuple type in foreign module; \ - consider using a struct instead`") - } - - 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::TyBareFn(None, 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") - } - _ => {} - } - - let sig = cx.erase_late_bound_regions(&bare_fn.sig); - match sig.output { - ty::FnDiverging => {} - ty::FnConverging(output) => { - if !output.is_nil() { - let r = self.check_type_for_ffi(cache, output); - match r { - FfiSafe => {} - _ => { return r; } - } - } - } - } - for arg in sig.inputs { - let r = self.check_type_for_ffi(cache, arg); - match r { - FfiSafe => {} - _ => { return r; } - } - } - FfiSafe - } - - ty::TyParam(..) | ty::TyInfer(..) | ty::TyError | - ty::TyClosure(..) | ty::TyProjection(..) | - ty::TyBareFn(Some(_), _) => { - panic!("Unexpected type in foreign function") - } - } - } - - fn check_def(&mut self, sp: Span, id: ast::NodeId) { - let tty = ast_ty_to_normalized(self.cx.tcx, id); - - match ImproperCTypesVisitor::check_type_for_ffi(self, &mut FnvHashSet(), tty) { - FfiResult::FfiSafe => {} - FfiResult::FfiUnsafe(s) => { - self.cx.span_lint(IMPROPER_CTYPES, sp, s); - } - 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)); - } - 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)); - } - } - } -} - -impl<'a, 'tcx, 'v> Visitor<'v> for ImproperCTypesVisitor<'a, 'tcx> { - fn visit_ty(&mut self, ty: &hir::Ty) { - match ty.node { - hir::TyPath(..) | - hir::TyBareFn(..) => self.check_def(ty.span, ty.id), - hir::TyVec(..) => { - self.cx.span_lint(IMPROPER_CTYPES, ty.span, - "found Rust slice type in foreign module, consider \ - using a raw pointer instead"); - } - hir::TyFixedLengthVec(ref ty, _) => self.visit_ty(ty), - hir::TyTup(..) => { - self.cx.span_lint(IMPROPER_CTYPES, ty.span, - "found Rust tuple type in foreign module; \ - consider using a struct instead`") - } - _ => visit::walk_ty(self, ty) - } - } -} - -#[derive(Copy, Clone)] -pub struct ImproperCTypes; - -impl LintPass for ImproperCTypes { - fn get_lints(&self) -> LintArray { - lint_array!(IMPROPER_CTYPES) - } - - fn check_item(&mut self, cx: &Context, it: &hir::Item) { - fn check_ty(cx: &Context, ty: &hir::Ty) { - let mut vis = ImproperCTypesVisitor { cx: cx }; - vis.visit_ty(ty); - } - - fn check_foreign_fn(cx: &Context, decl: &hir::FnDecl) { - for input in &decl.inputs { - check_ty(cx, &*input.ty); - } - if let hir::Return(ref ret_ty) = decl.output { - let tty = ast_ty_to_normalized(cx.tcx, ret_ty.id); - if !tty.is_nil() { - check_ty(cx, &ret_ty); - } - } - } - - match it.node { - hir::ItemForeignMod(ref nmod) - if nmod.abi != abi::RustIntrinsic && - nmod.abi != abi::PlatformIntrinsic => { - for ni in &nmod.items { - match ni.node { - hir::ForeignItemFn(ref decl, _) => check_foreign_fn(cx, &**decl), - hir::ForeignItemStatic(ref t, _) => check_ty(cx, &**t) - } - } - } - _ => (), - } - } -} - -declare_lint! { - BOX_POINTERS, - Allow, - "use of owned (Box type) heap memory" -} - -#[derive(Copy, Clone)] -pub struct BoxPointers; - -impl BoxPointers { - fn check_heap_type<'a, 'tcx>(&self, cx: &Context<'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); - cx.span_lint(BOX_POINTERS, span, &m); - } - } - } -} - -impl LintPass for BoxPointers { - fn get_lints(&self) -> LintArray { - lint_array!(BOX_POINTERS) - } - - fn check_item(&mut self, cx: &Context, it: &hir::Item) { - match it.node { - hir::ItemFn(..) | - hir::ItemTy(..) | - hir::ItemEnum(..) | - hir::ItemStruct(..) => - self.check_heap_type(cx, it.span, - cx.tcx.node_id_to_type(it.id)), - _ => () - } - - // If it's a struct, we also have to check the fields' types - match it.node { - hir::ItemStruct(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.node.id)); - } - } - _ => () - } - } - - fn check_expr(&mut self, cx: &Context, e: &hir::Expr) { - let ty = cx.tcx.node_id_to_type(e.id); - self.check_heap_type(cx, e.span, ty); - } -} - -declare_lint! { - RAW_POINTER_DERIVE, - Warn, - "uses of #[derive] with raw pointers are rarely correct" -} - -struct RawPtrDeriveVisitor<'a, 'tcx: 'a> { - cx: &'a Context<'a, 'tcx> -} - -impl<'a, 'tcx, 'v> Visitor<'v> for RawPtrDeriveVisitor<'a, 'tcx> { - fn visit_ty(&mut self, ty: &hir::Ty) { - const MSG: &'static str = "use of `#[derive]` with a raw pointer"; - if let hir::TyPtr(..) = ty.node { - self.cx.span_lint(RAW_POINTER_DERIVE, ty.span, MSG); - } - visit::walk_ty(self, ty); - } - // explicit override to a no-op to reduce code bloat - fn visit_expr(&mut self, _: &hir::Expr) {} - fn visit_block(&mut self, _: &hir::Block) {} -} - -pub struct RawPointerDerive { - checked_raw_pointers: NodeSet, -} - -impl RawPointerDerive { - pub fn new() -> RawPointerDerive { - RawPointerDerive { - checked_raw_pointers: NodeSet(), - } - } -} - -impl LintPass for RawPointerDerive { - fn get_lints(&self) -> LintArray { - lint_array!(RAW_POINTER_DERIVE) - } - - fn check_item(&mut self, cx: &Context, item: &hir::Item) { - if !attr::contains_name(&item.attrs, "automatically_derived") { - return; - } - let did = match item.node { - hir::ItemImpl(_, _, _, ref t_ref_opt, _, _) => { - // Deriving the Copy trait does not cause a warning - if let &Some(ref trait_ref) = t_ref_opt { - let def_id = cx.tcx.trait_ref_to_def_id(trait_ref); - if Some(def_id) == cx.tcx.lang_items.copy_trait() { - return; - } - } - - match cx.tcx.node_id_to_type(item.id).sty { - ty::TyEnum(def, _) => def.did, - ty::TyStruct(def, _) => def.did, - _ => return, - } - } - _ => return, - }; - if !did.is_local() { - return; - } - let item = match cx.tcx.map.find(did.node) { - Some(hir_map::NodeItem(item)) => item, - _ => return, - }; - if !self.checked_raw_pointers.insert(item.id) { - return; - } - match item.node { - hir::ItemStruct(..) | hir::ItemEnum(..) => { - let mut visitor = RawPtrDeriveVisitor { cx: cx }; - visit::walk_item(&mut visitor, &item); - } - _ => {} - } - } -} - -declare_lint! { - UNUSED_ATTRIBUTES, - Warn, - "detects attributes that were not used by the compiler" -} - -#[derive(Copy, Clone)] -pub struct UnusedAttributes; - -impl LintPass for UnusedAttributes { - fn get_lints(&self) -> LintArray { - lint_array!(UNUSED_ATTRIBUTES) - } - - fn check_attribute(&mut self, cx: &Context, attr: &hir::Attribute) { - // Note that check_name() marks the attribute as used if it matches. - for &(ref name, ty, _) in KNOWN_ATTRIBUTES { - match ty { - AttributeType::Whitelisted if attr.check_name(name) => { - break; - }, - _ => () - } - } - - let plugin_attributes = cx.sess().plugin_attributes.borrow_mut(); - for &(ref name, ty) in plugin_attributes.iter() { - if ty == AttributeType::Whitelisted && attr.check_name(&*name) { - break; - } - } - - if !syntax_attr::is_used(&unlower_attribute(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(); - - // 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 { - let msg = match attr.node.style { - hir::AttrOuter => "crate-level attribute should be an inner \ - attribute: add an exclamation mark: #![foo]", - hir::AttrInner => "crate-level attribute should be in the \ - root module", - }; - cx.span_lint(UNUSED_ATTRIBUTES, attr.span, msg); - } - } - } -} - -declare_lint! { - pub PATH_STATEMENTS, - Warn, - "path statements with no effect" -} - -#[derive(Copy, Clone)] -pub struct PathStatements; - -impl LintPass for PathStatements { - fn get_lints(&self) -> LintArray { - lint_array!(PATH_STATEMENTS) - } - - fn check_stmt(&mut self, cx: &Context, s: &hir::Stmt) { - match s.node { - hir::StmtSemi(ref expr, _) => { - match expr.node { - hir::ExprPath(..) => cx.span_lint(PATH_STATEMENTS, s.span, - "path statement with no effect"), - _ => () - } - } - _ => () - } - } -} - -declare_lint! { - pub UNUSED_MUST_USE, - Warn, - "unused result of a type flagged as #[must_use]" -} - -declare_lint! { - pub UNUSED_RESULTS, - Allow, - "unused result of an expression in a statement" -} - -#[derive(Copy, Clone)] -pub struct UnusedResults; - -impl LintPass for UnusedResults { - fn get_lints(&self) -> LintArray { - lint_array!(UNUSED_MUST_USE, UNUSED_RESULTS) - } - - fn check_stmt(&mut self, cx: &Context, s: &hir::Stmt) { - let expr = match s.node { - hir::StmtSemi(ref expr, _) => &**expr, - _ => return - }; - - if let hir::ExprRet(..) = expr.node { - return; - } - - let t = cx.tcx.expr_ty(&expr); - let warned = match t.sty { - ty::TyTuple(ref tys) if tys.is_empty() => return, - ty::TyBool => return, - ty::TyStruct(def, _) | - ty::TyEnum(def, _) => { - if def.did.is_local() { - if let hir_map::NodeItem(it) = cx.tcx.map.get(def.did.node) { - check_must_use(cx, &it.attrs, s.span) - } else { - false - } - } else { - let attrs = csearch::get_item_attrs(&cx.sess().cstore, def.did); - check_must_use(cx, &attrs[..], s.span) - } - } - _ => false, - }; - if !warned { - cx.span_lint(UNUSED_RESULTS, s.span, "unused result"); - } - - fn check_must_use(cx: &Context, attrs: &[hir::Attribute], sp: Span) -> bool { - for attr in attrs { - if attr.check_name("must_use") { - let mut msg = "unused result which must be used".to_string(); - // check for #[must_use="..."] - match attr.value_str() { - None => {} - Some(s) => { - msg.push_str(": "); - msg.push_str(&s); - } - } - cx.span_lint(UNUSED_MUST_USE, sp, &msg); - return true; - } - } - false - } - } -} - -declare_lint! { - pub NON_CAMEL_CASE_TYPES, - Warn, - "types, variants, traits and type parameters should have camel case names" -} - -#[derive(Copy, Clone)] -pub struct NonCamelCaseTypes; - -impl NonCamelCaseTypes { - fn check_case(&self, cx: &Context, sort: &str, ident: ast::Ident, span: Span) { - fn is_camel_case(ident: ast::Ident) -> bool { - let ident = ident.name.as_str(); - if ident.is_empty() { - return true; - } - let ident = ident.trim_matches('_'); - - // start with a non-lowercase letter rather than non-uppercase - // ones (some scripts don't have a concept of upper/lowercase) - !ident.is_empty() && !ident.char_at(0).is_lowercase() && !ident.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() - } - - let s = ident.name.as_str(); - - if !is_camel_case(ident) { - let c = to_camel_case(&s); - let m = if c.is_empty() { - 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) - }; - cx.span_lint(NON_CAMEL_CASE_TYPES, span, &m[..]); - } - } -} - -impl LintPass for NonCamelCaseTypes { - fn get_lints(&self) -> LintArray { - lint_array!(NON_CAMEL_CASE_TYPES) - } - - fn check_item(&mut self, cx: &Context, 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 has_extern_repr = extern_repr_count > 0; - - if has_extern_repr { - return; - } - - match it.node { - hir::ItemTy(..) | hir::ItemStruct(..) => { - self.check_case(cx, "type", it.ident, it.span) - } - hir::ItemTrait(..) => { - self.check_case(cx, "trait", it.ident, it.span) - } - hir::ItemEnum(ref enum_definition, _) => { - if has_extern_repr { - return; - } - self.check_case(cx, "type", it.ident, it.span); - for variant in &enum_definition.variants { - self.check_case(cx, "variant", variant.node.name, variant.span); - } - } - _ => () - } - } - - fn check_generics(&mut self, cx: &Context, it: &hir::Generics) { - for gen in it.ty_params.iter() { - self.check_case(cx, "type parameter", gen.ident, gen.span); - } - } -} - -#[derive(PartialEq)] -enum MethodContext { - TraitDefaultImpl, - TraitImpl, - PlainImpl -} - -fn method_context(cx: &Context, id: ast::NodeId, span: Span) -> MethodContext { - match cx.tcx.impl_or_trait_items.borrow().get(&DefId::local(id)) { - None => cx.sess().span_bug(span, "missing method descriptor?!"), - Some(item) => match item.container() { - ty::TraitContainer(..) => MethodContext::TraitDefaultImpl, - ty::ImplContainer(cid) => { - match cx.tcx.impl_trait_ref(cid) { - Some(_) => MethodContext::TraitImpl, - None => MethodContext::PlainImpl - } - } - } - } -} - -declare_lint! { - pub NON_SNAKE_CASE, - Warn, - "methods, functions, lifetime parameters and modules should have snake case names" -} - -#[derive(Copy, Clone)] -pub struct NonSnakeCase; - -impl NonSnakeCase { - fn to_snake_case(mut str: &str) -> String { - let mut words = vec![]; - // Preserve leading underscores - str = str.trim_left_matches(|c: char| { - if c == '_' { - words.push(String::new()); - true - } else { - false - } - }); - for s in str.split('_') { - let mut last_upper = false; - let mut buf = String::new(); - if s.is_empty() { - continue; - } - for ch in s.chars() { - if !buf.is_empty() && buf != "'" - && ch.is_uppercase() - && !last_upper { - words.push(buf); - buf = String::new(); - } - last_upper = ch.is_uppercase(); - buf.extend(ch.to_lowercase()); - } - words.push(buf); - } - words.join("_") - } - - fn check_snake_case(&self, cx: &Context, sort: &str, name: &str, span: Option) { - fn is_snake_case(ident: &str) -> bool { - if ident.is_empty() { - return true; - } - let ident = ident.trim_left_matches('\''); - let ident = ident.trim_matches('_'); - - let mut allow_underscore = true; - ident.chars().all(|c| { - allow_underscore = match c { - '_' if !allow_underscore => return false, - '_' => false, - // It would be more obvious to use `c.is_lowercase()`, - // but some characters do not have a lowercase form - c if !c.is_uppercase() => true, - _ => return false, - }; - true - }) - } - - if !is_snake_case(name) { - let sc = NonSnakeCase::to_snake_case(name); - let msg = if sc != name { - format!("{} `{}` should have a snake case name such as `{}`", - sort, name, sc) - } else { - format!("{} `{}` should have a snake case name", - sort, name) - }; - match span { - Some(span) => cx.span_lint(NON_SNAKE_CASE, span, &msg), - None => cx.lint(NON_SNAKE_CASE, &msg), - } - } - } -} - -impl LintPass for NonSnakeCase { - fn get_lints(&self) -> LintArray { - lint_array!(NON_SNAKE_CASE) - } - - fn check_crate(&mut self, cx: &Context, 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))); - 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 { - self.check_snake_case(cx, "crate", name, Some(attr.span)); - } - } - - fn check_fn(&mut self, cx: &Context, - fk: FnKind, _: &hir::FnDecl, - _: &hir::Block, span: Span, id: ast::NodeId) { - match fk { - FnKind::Method(ident, _, _) => match method_context(cx, id, span) { - MethodContext::PlainImpl => { - self.check_snake_case(cx, "method", &ident.name.as_str(), Some(span)) - }, - MethodContext::TraitDefaultImpl => { - self.check_snake_case(cx, "trait method", &ident.name.as_str(), Some(span)) - }, - _ => (), - }, - FnKind::ItemFn(ident, _, _, _, _, _) => { - self.check_snake_case(cx, "function", &ident.name.as_str(), Some(span)) - }, - _ => (), - } - } - - fn check_item(&mut self, cx: &Context, it: &hir::Item) { - if let hir::ItemMod(_) = it.node { - self.check_snake_case(cx, "module", &it.ident.name.as_str(), Some(it.span)); - } - } +use bad_style::{MethodLateContext, method_context}; - fn check_trait_item(&mut self, cx: &Context, trait_item: &hir::TraitItem) { - if let hir::MethodTraitItem(_, None) = trait_item.node { - self.check_snake_case(cx, "trait method", &trait_item.ident.name.as_str(), - Some(trait_item.span)); - } - } +// hardwired lints from librustc +pub use lint::builtin::*; - fn check_lifetime_def(&mut self, cx: &Context, t: &hir::LifetimeDef) { - self.check_snake_case(cx, "lifetime", &t.lifetime.name.as_str(), - Some(t.lifetime.span)); - } +declare_lint! { + WHILE_TRUE, + Warn, + "suggest using `loop { }` instead of `while true { }`" +} - fn check_pat(&mut self, cx: &Context, p: &hir::Pat) { - if let &hir::PatIdent(_, ref path1, _) = &p.node { - let def = cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def()); - if let Some(def::DefLocal(_)) = def { - self.check_snake_case(cx, "variable", &path1.node.name.as_str(), Some(p.span)); - } - } +#[derive(Copy, Clone)] +pub struct WhileTrue; + +impl LintPass for WhileTrue { + fn get_lints(&self) -> LintArray { + lint_array!(WHILE_TRUE) } +} - fn check_struct_def(&mut self, cx: &Context, s: &hir::StructDef, - _: ast::Ident, _: &hir::Generics, _: ast::NodeId) { - for sf in &s.fields { - if let hir::StructField_ { kind: hir::NamedField(ident, _), .. } = sf.node { - self.check_snake_case(cx, "structure field", &ident.name.as_str(), - Some(sf.span)); +impl LateLintPass for WhileTrue { + fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { + if let hir::ExprWhile(ref cond, _, _) = e.node { + if let hir::ExprLit(ref lit) = cond.node { + if let ast::LitBool(true) = lit.node { + cx.span_lint(WHILE_TRUE, e.span, + "denote infinite loops with loop { ... }"); + } } } } } declare_lint! { - pub NON_UPPER_CASE_GLOBALS, - Warn, - "static constants should have uppercase identifiers" + BOX_POINTERS, + Allow, + "use of owned (Box type) heap memory" } #[derive(Copy, Clone)] -pub struct NonUpperCaseGlobals; - -impl NonUpperCaseGlobals { - fn check_upper_case(cx: &Context, sort: &str, ident: ast::Ident, span: Span) { - let s = ident.name.as_str(); - - 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)); - } else { - cx.span_lint(NON_UPPER_CASE_GLOBALS, span, - &format!("{} `{}` should have an upper case name", - sort, s)); +pub struct BoxPointers; + +impl BoxPointers { + 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); + cx.span_lint(BOX_POINTERS, span, &m); } } } } -impl LintPass for NonUpperCaseGlobals { +impl LintPass for BoxPointers { fn get_lints(&self) -> LintArray { - lint_array!(NON_UPPER_CASE_GLOBALS) + lint_array!(BOX_POINTERS) } +} - fn check_item(&mut self, cx: &Context, it: &hir::Item) { +impl LateLintPass for BoxPointers { + 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.ident, it.span); - } - hir::ItemConst(..) => { - NonUpperCaseGlobals::check_upper_case(cx, "constant", it.ident, it.span); - } - _ => {} - } - } - - fn check_trait_item(&mut self, cx: &Context, ti: &hir::TraitItem) { - match ti.node { - hir::ConstTraitItem(..) => { - NonUpperCaseGlobals::check_upper_case(cx, "associated constant", - ti.ident, ti.span); - } - _ => {} + hir::ItemFn(..) | + hir::ItemTy(..) | + hir::ItemEnum(..) | + hir::ItemStruct(..) => + self.check_heap_type(cx, it.span, + cx.tcx.node_id_to_type(it.id)), + _ => () } - } - fn check_impl_item(&mut self, cx: &Context, ii: &hir::ImplItem) { - match ii.node { - hir::ConstImplItem(..) => { - NonUpperCaseGlobals::check_upper_case(cx, "associated constant", - ii.ident, ii.span); + // If it's a struct, we also have to check the fields' types + match it.node { + hir::ItemStruct(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.node.id)); + } } - _ => {} + _ => () } } - fn check_pat(&mut self, cx: &Context, p: &hir::Pat) { - // Lint for constants that look like binding identifiers (#7526) - match (&p.node, cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def())) { - (&hir::PatIdent(_, ref path1, _), Some(def::DefConst(..))) => { - NonUpperCaseGlobals::check_upper_case(cx, "constant in pattern", - path1.node, p.span); - } - _ => {} - } + fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { + let ty = cx.tcx.node_id_to_type(e.id); + self.check_heap_type(cx, e.span, ty); } } declare_lint! { - UNUSED_PARENS, + RAW_POINTER_DERIVE, Warn, - "`if`, `match`, `while` and `return` do not need parentheses" + "uses of #[derive] with raw pointers are rarely correct" } -#[derive(Copy, Clone)] -pub struct UnusedParens; - -impl UnusedParens { - fn check_unused_parens_core(&self, cx: &Context, value: &hir::Expr, msg: &str, - struct_lit_needs_parens: bool) { - if let hir::ExprParen(ref inner) = value.node { - let necessary = struct_lit_needs_parens && contains_exterior_struct_lit(&**inner); - if !necessary { - cx.span_lint(UNUSED_PARENS, value.span, - &format!("unnecessary parentheses around {}", msg)) - } - } - - /// Expressions that syntactically contain an "exterior" struct - /// literal i.e. not surrounded by any parens or other - /// delimiters, e.g. `X { y: 1 }`, `X { y: 1 }.method()`, `foo - /// == X { y: 1 }` and `X { y: 1 } == foo` all do, but `(X { - /// y: 1 }) == foo` does not. - fn contains_exterior_struct_lit(value: &hir::Expr) -> bool { - match value.node { - hir::ExprStruct(..) => true, - - hir::ExprAssign(ref lhs, ref rhs) | - hir::ExprAssignOp(_, ref lhs, ref rhs) | - hir::ExprBinary(_, ref lhs, ref rhs) => { - // X { y: 1 } + X { y: 2 } - contains_exterior_struct_lit(&**lhs) || - contains_exterior_struct_lit(&**rhs) - } - hir::ExprUnary(_, ref x) | - hir::ExprCast(ref x, _) | - hir::ExprField(ref x, _) | - hir::ExprTupField(ref x, _) | - hir::ExprIndex(ref x, _) => { - // &X { y: 1 }, X { y: 1 }.y - contains_exterior_struct_lit(&**x) - } - - hir::ExprMethodCall(_, _, ref exprs) => { - // X { y: 1 }.bar(...) - contains_exterior_struct_lit(&*exprs[0]) - } +struct RawPtrDeriveVisitor<'a, 'tcx: 'a> { + cx: &'a LateContext<'a, 'tcx> +} - _ => false - } +impl<'a, 'tcx, 'v> Visitor<'v> for RawPtrDeriveVisitor<'a, 'tcx> { + fn visit_ty(&mut self, ty: &hir::Ty) { + const MSG: &'static str = "use of `#[derive]` with a raw pointer"; + if let hir::TyPtr(..) = ty.node { + self.cx.span_lint(RAW_POINTER_DERIVE, ty.span, MSG); } + visit::walk_ty(self, ty); } + // explicit override to a no-op to reduce code bloat + fn visit_expr(&mut self, _: &hir::Expr) {} + fn visit_block(&mut self, _: &hir::Block) {} } -impl LintPass for UnusedParens { - fn get_lints(&self) -> LintArray { - lint_array!(UNUSED_PARENS) - } - - fn check_expr(&mut self, cx: &Context, e: &hir::Expr) { - let (value, msg, struct_lit_needs_parens) = match e.node { - hir::ExprIf(ref cond, _, _) => (cond, "`if` condition", true), - hir::ExprWhile(ref cond, _, _) => (cond, "`while` condition", true), - hir::ExprMatch(ref head, _, source) => match source { - hir::MatchSource::Normal => (head, "`match` head expression", true), - hir::MatchSource::IfLetDesugar { .. } => (head, "`if let` head expression", true), - hir::MatchSource::WhileLetDesugar => (head, "`while let` head expression", true), - hir::MatchSource::ForLoopDesugar => (head, "`for` head expression", true), - }, - hir::ExprRet(Some(ref value)) => (value, "`return` value", false), - hir::ExprAssign(_, ref value) => (value, "assigned value", false), - hir::ExprAssignOp(_, _, ref value) => (value, "assigned value", false), - _ => return - }; - self.check_unused_parens_core(cx, &**value, msg, struct_lit_needs_parens); - } - - fn check_stmt(&mut self, cx: &Context, s: &hir::Stmt) { - let (value, msg) = match s.node { - hir::StmtDecl(ref decl, _) => match decl.node { - hir::DeclLocal(ref local) => match local.init { - Some(ref value) => (value, "assigned value"), - None => return - }, - _ => return - }, - _ => return - }; - self.check_unused_parens_core(cx, &**value, msg, false); - } +pub struct RawPointerDerive { + checked_raw_pointers: NodeSet, } -declare_lint! { - UNUSED_IMPORT_BRACES, - Allow, - "unnecessary braces around an imported item" +impl RawPointerDerive { + pub fn new() -> RawPointerDerive { + RawPointerDerive { + checked_raw_pointers: NodeSet(), + } + } } -#[derive(Copy, Clone)] -pub struct UnusedImportBraces; - -impl LintPass for UnusedImportBraces { +impl LintPass for RawPointerDerive { fn get_lints(&self) -> LintArray { - lint_array!(UNUSED_IMPORT_BRACES) + lint_array!(RAW_POINTER_DERIVE) } +} - fn check_item(&mut self, cx: &Context, item: &hir::Item) { - if let hir::ItemUse(ref view_path) = item.node { - if let hir::ViewPathList(_, ref items) = view_path.node { - if items.len() == 1 { - if let hir::PathListIdent {ref name, ..} = items[0].node { - let m = format!("braces around {} is unnecessary", - name); - cx.span_lint(UNUSED_IMPORT_BRACES, item.span, - &m[..]); +impl LateLintPass for RawPointerDerive { + fn check_item(&mut self, cx: &LateContext, item: &hir::Item) { + if !attr::contains_name(&item.attrs, "automatically_derived") { + return; + } + let did = match item.node { + hir::ItemImpl(_, _, _, ref t_ref_opt, _, _) => { + // Deriving the Copy trait does not cause a warning + if let &Some(ref trait_ref) = t_ref_opt { + let def_id = cx.tcx.trait_ref_to_def_id(trait_ref); + if Some(def_id) == cx.tcx.lang_items.copy_trait() { + return; } } + + match cx.tcx.node_id_to_type(item.id).sty { + ty::TyEnum(def, _) => def.did, + ty::TyStruct(def, _) => def.did, + _ => return, + } + } + _ => return, + }; + let node_id = if let Some(node_id) = cx.tcx.map.as_local_node_id(did) { + node_id + } else { + return; + }; + let item = match cx.tcx.map.find(node_id) { + Some(hir_map::NodeItem(item)) => item, + _ => return, + }; + if !self.checked_raw_pointers.insert(item.id) { + return; + } + match item.node { + hir::ItemStruct(..) | hir::ItemEnum(..) => { + let mut visitor = RawPtrDeriveVisitor { cx: cx }; + visit::walk_item(&mut visitor, &item); } + _ => {} } } } @@ -1513,8 +237,10 @@ impl LintPass for NonShorthandFieldPatterns { fn get_lints(&self) -> LintArray { lint_array!(NON_SHORTHAND_FIELD_PATTERNS) } +} - fn check_pat(&mut self, cx: &Context, pat: &hir::Pat) { +impl LateLintPass for NonShorthandFieldPatterns { + fn check_pat(&mut self, cx: &LateContext, pat: &hir::Pat) { let def_map = cx.tcx.def_map.borrow(); if let hir::PatStruct(_, ref v, _) = pat.node { let field_pats = v.iter().filter(|fieldpat| { @@ -1522,11 +248,15 @@ impl LintPass for NonShorthandFieldPatterns { return false; } let def = def_map.get(&fieldpat.node.pat.id).map(|d| d.full_def()); - def == Some(def::DefLocal(fieldpat.node.pat.id)) + if let Some(def_id) = cx.tcx.map.opt_local_def_id(fieldpat.node.pat.id) { + def == Some(def::DefLocal(def_id, fieldpat.node.pat.id)) + } else { + false + } }); for fieldpat in field_pats { if let hir::PatIdent(_, ident, None) = fieldpat.node.pat.node { - if ident.node.name == fieldpat.node.ident.name { + if ident.node.name == fieldpat.node.name { // FIXME: should this comparison really be done on the name? // doing it on the ident will fail during compilation of libcore cx.span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span, @@ -1539,31 +269,6 @@ impl LintPass for NonShorthandFieldPatterns { } } -declare_lint! { - pub UNUSED_UNSAFE, - Warn, - "unnecessary use of an `unsafe` block" -} - -#[derive(Copy, Clone)] -pub struct UnusedUnsafe; - -impl LintPass for UnusedUnsafe { - fn get_lints(&self) -> LintArray { - lint_array!(UNUSED_UNSAFE) - } - - fn check_expr(&mut self, cx: &Context, e: &hir::Expr) { - 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"); - } - } - } -} - declare_lint! { UNSAFE_CODE, Allow, @@ -1577,8 +282,10 @@ impl LintPass for UnsafeCode { fn get_lints(&self) -> LintArray { lint_array!(UNSAFE_CODE) } +} - fn check_expr(&mut self, cx: &Context, e: &hir::Expr) { +impl LateLintPass for UnsafeCode { + fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { 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) { @@ -1587,7 +294,7 @@ impl LintPass for UnsafeCode { } } - fn check_item(&mut self, cx: &Context, it: &hir::Item) { + 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"), @@ -1599,7 +306,7 @@ impl LintPass for UnsafeCode { } } - fn check_fn(&mut self, cx: &Context, fk: FnKind, _: &hir::FnDecl, + fn check_fn(&mut self, cx: &LateContext, fk: FnKind, _: &hir::FnDecl, _: &hir::Block, span: Span, _: ast::NodeId) { match fk { FnKind::ItemFn(_, _, hir::Unsafety::Unsafe, _, _, _) => @@ -1615,7 +322,7 @@ impl LintPass for UnsafeCode { } } - fn check_trait_item(&mut self, cx: &Context, trait_item: &hir::TraitItem) { + 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, @@ -1625,115 +332,6 @@ impl LintPass for UnsafeCode { } } -declare_lint! { - pub UNUSED_MUT, - Warn, - "detect mut variables which don't need to be mutable" -} - -#[derive(Copy, Clone)] -pub struct UnusedMut; - -impl UnusedMut { - fn check_unused_mut_pat(&self, cx: &Context, pats: &[P]) { - // collect all mutable pattern and group their NodeIDs by their Identifier to - // avoid false warnings in match arms with multiple patterns - - let mut mutables = FnvHashMap(); - for p in pats { - pat_util::pat_bindings(&cx.tcx.def_map, p, |mode, id, _, path1| { - let ident = path1.node; - if let hir::BindByValue(hir::MutMutable) = mode { - if !ident.name.as_str().starts_with("_") { - match mutables.entry(ident.name.usize()) { - Vacant(entry) => { entry.insert(vec![id]); }, - Occupied(mut entry) => { entry.get_mut().push(id); }, - } - } - } - }); - } - - 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]), - "variable does not need to be mutable"); - } - } - } -} - -impl LintPass for UnusedMut { - fn get_lints(&self) -> LintArray { - lint_array!(UNUSED_MUT) - } - - fn check_expr(&mut self, cx: &Context, e: &hir::Expr) { - if let hir::ExprMatch(_, ref arms, _) = e.node { - for a in arms { - self.check_unused_mut_pat(cx, &a.pats) - } - } - } - - fn check_stmt(&mut self, cx: &Context, s: &hir::Stmt) { - if let hir::StmtDecl(ref d, _) = s.node { - if let hir::DeclLocal(ref l) = d.node { - self.check_unused_mut_pat(cx, slice::ref_slice(&l.pat)); - } - } - } - - fn check_fn(&mut self, cx: &Context, - _: 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)); - } - } -} - -declare_lint! { - UNUSED_ALLOCATION, - Warn, - "detects unnecessary allocations that can be eliminated" -} - -#[derive(Copy, Clone)] -pub struct UnusedAllocation; - -impl LintPass for UnusedAllocation { - fn get_lints(&self) -> LintArray { - lint_array!(UNUSED_ALLOCATION) - } - - fn check_expr(&mut self, cx: &Context, e: &hir::Expr) { - match e.node { - hir::ExprUnary(hir::UnUniq, _) => (), - _ => return - } - - if let Some(adjustment) = cx.tcx.tables.borrow().adjustments.get(&e.id) { - if let adjustment::AdjustDerefRef(adjustment::AutoDerefRef { - ref autoref, .. - }) = *adjustment { - match autoref { - &Some(adjustment::AutoPtr(_, 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, - "unnecessary allocation, use &mut instead"); - } - _ => () - } - } - } - } -} - declare_lint! { MISSING_DOCS, Allow, @@ -1770,9 +368,9 @@ impl MissingDoc { } fn check_missing_docs_attrs(&self, - cx: &Context, + cx: &LateContext, id: Option, - attrs: &[hir::Attribute], + attrs: &[ast::Attribute], sp: Span, desc: &'static str) { // If we're building a test harness, then warning about @@ -1797,7 +395,7 @@ impl MissingDoc { let has_doc = attrs.iter().any(|a| { match a.node.value.node { - hir::MetaNameValue(ref name, _) if *name == "doc" => true, + ast::MetaNameValue(ref name, _) if *name == "doc" => true, _ => false } }); @@ -1812,8 +410,10 @@ impl LintPass for MissingDoc { fn get_lints(&self) -> LintArray { lint_array!(MISSING_DOCS) } +} - fn enter_lint_attrs(&mut self, _: &Context, attrs: &[hir::Attribute]) { +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() { None => false, @@ -1823,26 +423,26 @@ impl LintPass for MissingDoc { self.doc_hidden_stack.push(doc_hidden); } - fn exit_lint_attrs(&mut self, _: &Context, _: &[hir::Attribute]) { + fn exit_lint_attrs(&mut self, _: &LateContext, _: &[ast::Attribute]) { self.doc_hidden_stack.pop().expect("empty doc_hidden_stack"); } - fn check_struct_def(&mut self, _: &Context, _: &hir::StructDef, - _: ast::Ident, _: &hir::Generics, id: ast::NodeId) { - self.struct_def_stack.push(id); + 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, _: &Context, _: &hir::StructDef, - _: ast::Ident, _: &hir::Generics, 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 == id); + assert!(popped == item_id); } - fn check_crate(&mut self, cx: &Context, krate: &hir::Crate) { + fn check_crate(&mut self, cx: &LateContext, krate: &hir::Crate) { self.check_missing_docs_attrs(cx, None, &krate.attrs, krate.span, "crate"); } - fn check_item(&mut self, cx: &Context, it: &hir::Item) { + fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { let desc = match it.node { hir::ItemFn(..) => "a function", hir::ItemMod(..) => "a module", @@ -1864,13 +464,15 @@ impl LintPass for MissingDoc { // If the trait is private, add the impl items to private_traits so they don't get // reported for missing docs. let real_trait = cx.tcx.trait_ref_to_def_id(trait_ref); - match cx.tcx.map.find(real_trait.node) { - Some(hir_map::NodeItem(item)) => if item.vis == hir::Visibility::Inherited { - for itm in impl_items { - self.private_traits.insert(itm.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); + } + }, + _ => { } + } } return }, @@ -1882,7 +484,7 @@ impl LintPass for MissingDoc { self.check_missing_docs_attrs(cx, Some(it.id), &it.attrs, it.span, desc); } - fn check_trait_item(&mut self, cx: &Context, trait_item: &hir::TraitItem) { + fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) { if self.private_traits.contains(&trait_item.id) { return } let desc = match trait_item.node { @@ -1896,9 +498,9 @@ impl LintPass for MissingDoc { trait_item.span, desc); } - fn check_impl_item(&mut self, cx: &Context, impl_item: &hir::ImplItem) { + fn check_impl_item(&mut self, cx: &LateContext, impl_item: &hir::ImplItem) { // If the method is an impl for a trait, don't doc. - if method_context(cx, impl_item.id, impl_item.span) == MethodContext::TraitImpl { + if method_context(cx, impl_item.id, impl_item.span) == MethodLateContext::TraitImpl { return; } @@ -1912,7 +514,7 @@ impl LintPass for MissingDoc { impl_item.span, desc); } - fn check_struct_field(&mut self, cx: &Context, sf: &hir::StructField) { + fn check_struct_field(&mut self, cx: &LateContext, sf: &hir::StructField) { if let hir::NamedField(_, vis) = sf.node.kind { if vis == hir::Public || self.in_variant { let cur_struct_def = *self.struct_def_stack.last() @@ -1924,13 +526,14 @@ impl LintPass for MissingDoc { } } - fn check_variant(&mut self, cx: &Context, v: &hir::Variant, _: &hir::Generics) { - self.check_missing_docs_attrs(cx, Some(v.node.id), &v.node.attrs, v.span, "a variant"); + 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"); assert!(!self.in_variant); self.in_variant = true; } - fn check_variant_post(&mut self, _: &Context, _: &hir::Variant, _: &hir::Generics) { + fn check_variant_post(&mut self, _: &LateContext, _: &hir::Variant, _: &hir::Generics) { assert!(self.in_variant); self.in_variant = false; } @@ -1949,8 +552,10 @@ impl LintPass for MissingCopyImplementations { fn get_lints(&self) -> LintArray { lint_array!(MISSING_COPY_IMPLEMENTATIONS) } +} - fn check_item(&mut self, cx: &Context, item: &hir::Item) { +impl LateLintPass for MissingCopyImplementations { + fn check_item(&mut self, cx: &LateContext, item: &hir::Item) { if !cx.exported_items.contains(&item.id) { return; } @@ -1959,7 +564,7 @@ impl LintPass for MissingCopyImplementations { if ast_generics.is_parameterized() { return; } - let def = cx.tcx.lookup_adt_def(DefId::local(item.id)); + let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id)); (def, cx.tcx.mk_struct(def, cx.tcx.mk_substs(Substs::empty()))) } @@ -1967,7 +572,7 @@ impl LintPass for MissingCopyImplementations { if ast_generics.is_parameterized() { return; } - let def = cx.tcx.lookup_adt_def(DefId::local(item.id)); + let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id)); (def, cx.tcx.mk_enum(def, cx.tcx.mk_substs(Substs::empty()))) } @@ -2011,8 +616,10 @@ impl LintPass for MissingDebugImplementations { fn get_lints(&self) -> LintArray { lint_array!(MISSING_DEBUG_IMPLEMENTATIONS) } +} - fn check_item(&mut self, cx: &Context, item: &hir::Item) { +impl LateLintPass for MissingDebugImplementations { + fn check_item(&mut self, cx: &LateContext, item: &hir::Item) { if !cx.exported_items.contains(&item.id) { return; } @@ -2031,9 +638,11 @@ impl LintPass for MissingDebugImplementations { let debug_def = cx.tcx.lookup_trait_def(debug); let mut impls = NodeSet(); debug_def.for_each_impl(cx.tcx, |d| { - if d.is_local() { - if let Some(ty_def) = cx.tcx.node_id_to_type(d.node).ty_to_def_id() { - impls.insert(ty_def.node); + 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(node_id) = cx.tcx.map.as_local_node_id(ty_def) { + impls.insert(node_id); + } } } }); @@ -2062,22 +671,22 @@ declare_lint! { pub struct Stability; impl Stability { - fn lint(&self, cx: &Context, _id: DefId, + fn lint(&self, cx: &LateContext, _id: DefId, span: Span, stability: &Option<&attr::Stability>) { // Deprecated attributes apply in-crate and cross-crate. let (lint, label) = match *stability { - Some(&attr::Stability { deprecated_since: Some(_), .. }) => + Some(&attr::Stability { depr: Some(_), .. }) => (DEPRECATED, "deprecated"), _ => return }; output(cx, span, stability, lint, label); - fn output(cx: &Context, span: Span, stability: &Option<&attr::Stability>, + fn output(cx: &LateContext, span: Span, stability: &Option<&attr::Stability>, lint: &'static Lint, label: &'static str) { let msg = match *stability { - Some(&attr::Stability { reason: Some(ref s), .. }) => { - format!("use of {} item: {}", label, *s) + Some(&attr::Stability {depr: Some(attr::Deprecation {ref reason, ..}), ..}) => { + format!("use of {} item: {}", label, reason) } _ => format!("use of {} item", label) }; @@ -2087,51 +696,41 @@ impl Stability { } } -fn hir_to_ast_stability(stab: &attr::Stability) -> attr::Stability { - attr::Stability { - level: match stab.level { - attr::Unstable => attr::Unstable, - attr::Stable => attr::Stable, - }, - feature: stab.feature.clone(), - since: stab.since.clone(), - deprecated_since: stab.deprecated_since.clone(), - reason: stab.reason.clone(), - issue: stab.issue, - } -} - impl LintPass for Stability { fn get_lints(&self) -> LintArray { lint_array!(DEPRECATED) } +} - fn check_item(&mut self, cx: &Context, item: &hir::Item) { +impl LateLintPass for Stability { + fn check_item(&mut self, cx: &LateContext, item: &hir::Item) { stability::check_item(cx.tcx, item, false, &mut |id, sp, stab| - self.lint(cx, id, sp, - &stab.map(|s| hir_to_ast_stability(s)).as_ref())); + self.lint(cx, id, sp, &stab)); } - fn check_expr(&mut self, cx: &Context, e: &hir::Expr) { + fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { stability::check_expr(cx.tcx, e, &mut |id, sp, stab| - self.lint(cx, id, sp, - &stab.map(|s| hir_to_ast_stability(s)).as_ref())); + self.lint(cx, id, sp, &stab)); } - fn check_path(&mut self, cx: &Context, path: &hir::Path, id: ast::NodeId) { + fn check_path(&mut self, cx: &LateContext, path: &hir::Path, id: ast::NodeId) { stability::check_path(cx.tcx, path, id, &mut |id, sp, stab| - self.lint(cx, id, sp, - &stab.map(|s| hir_to_ast_stability(s)).as_ref())); + self.lint(cx, id, sp, &stab)); + } + + fn check_path_list_item(&mut self, cx: &LateContext, item: &hir::PathListItem) { + stability::check_path_list_item(cx.tcx, item, + &mut |id, sp, stab| + self.lint(cx, id, sp, &stab)); } - fn check_pat(&mut self, cx: &Context, pat: &hir::Pat) { + fn check_pat(&mut self, cx: &LateContext, pat: &hir::Pat) { stability::check_pat(cx.tcx, pat, &mut |id, sp, stab| - self.lint(cx, id, sp, - &stab.map(|s| hir_to_ast_stability(s)).as_ref())); + self.lint(cx, id, sp, &stab)); } } @@ -2149,16 +748,15 @@ impl LintPass for UnconditionalRecursion { fn get_lints(&self) -> LintArray { lint_array![UNCONDITIONAL_RECURSION] } +} - fn check_fn(&mut self, cx: &Context, fn_kind: FnKind, _: &hir::FnDecl, +impl LateLintPass for UnconditionalRecursion { + fn check_fn(&mut self, cx: &LateContext, fn_kind: FnKind, _: &hir::FnDecl, blk: &hir::Block, sp: Span, id: ast::NodeId) { - type F = for<'tcx> fn(&ty::ctxt<'tcx>, - ast::NodeId, ast::NodeId, ast::Ident, ast::NodeId) -> bool; - let method = match fn_kind { FnKind::ItemFn(..) => None, FnKind::Method(..) => { - cx.tcx.impl_or_trait_item(DefId::local(id)).as_opt_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 @@ -2271,8 +869,11 @@ impl LintPass for UnconditionalRecursion { id: ast::NodeId) -> bool { match tcx.map.get(id) { hir_map::NodeExpr(&hir::Expr { node: hir::ExprCall(ref callee, _), .. }) => { - tcx.def_map.borrow().get(&callee.id) - .map_or(false, |def| def.def_id() == DefId::local(fn_id)) + tcx.def_map + .borrow() + .get(&callee.id) + .map_or(false, + |def| def.def_id() == tcx.map.local_def_id(fn_id)) } _ => false } @@ -2282,20 +883,22 @@ impl LintPass for UnconditionalRecursion { fn expr_refers_to_this_method(tcx: &ty::ctxt, method: &ty::Method, id: ast::NodeId) -> bool { - let tables = tcx.tables.borrow(); - // Check for method calls and overloaded operators. - if let Some(m) = tables.method_map.get(&ty::MethodCall::expr(id)) { + let opt_m = tcx.tables.borrow().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; } } // Check for overloaded autoderef method calls. - if let Some(&adjustment::AdjustDerefRef(ref adj)) = tables.adjustments.get(&id) { + 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 method_call = ty::MethodCall::autoderef(id, i as u32); - if let Some(m) = tables.method_map.get(&method_call) { + if let Some(m) = tcx.tables.borrow().method_map + .get(&method_call) + .cloned() { if method_call_refers_to_method(tcx, method, m.def_id, m.substs, id) { return true; } @@ -2308,9 +911,13 @@ impl LintPass for UnconditionalRecursion { hir_map::NodeExpr(&hir::Expr { node: hir::ExprCall(ref callee, _), .. }) => { match tcx.def_map.borrow().get(&callee.id).map(|d| d.full_def()) { Some(def::DefMethod(def_id)) => { - let no_substs = &ty::ItemSubsts::empty(); - let ts = tables.item_substs.get(&callee.id).unwrap_or(no_substs); - method_call_refers_to_method(tcx, method, def_id, &ts.substs, id) + let item_substs = + tcx.tables.borrow().item_substs + .get(&callee.id) + .cloned() + .unwrap_or_else(|| ty::ItemSubsts::empty()); + method_call_refers_to_method( + tcx, method, def_id, &item_substs.substs, id) } _ => false } @@ -2347,7 +954,12 @@ impl LintPass for UnconditionalRecursion { traits::Obligation::new(traits::ObligationCause::misc(span, expr_id), trait_ref.to_poly_trait_predicate()); - let param_env = ty::ParameterEnvironment::for_item(tcx, method.def_id.node); + // unwrap() is ok here b/c `method` is the method + // defined in this crate whose body we are + // checking, so it's always local + let node_id = tcx.map.as_local_node_id(method.def_id).unwrap(); + + let param_env = ty::ParameterEnvironment::for_item(tcx, node_id); let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(param_env), false); let mut selcx = traits::SelectionContext::new(&infcx); match selcx.select(&obligation) { @@ -2396,8 +1008,10 @@ impl LintPass for PluginAsLibrary { fn get_lints(&self) -> LintArray { lint_array![PLUGIN_AS_LIBRARY] } +} - fn check_item(&mut self, cx: &Context, it: &hir::Item) { +impl LateLintPass for PluginAsLibrary { + fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { if cx.sess().plugin_registrar_fn.get().is_some() { // We're compiling a plugin; it's fine to link other plugins. return; @@ -2452,14 +1066,16 @@ impl LintPass for InvalidNoMangleItems { PRIVATE_NO_MANGLE_STATICS, NO_MANGLE_CONST_ITEMS) } +} - fn check_item(&mut self, cx: &Context, it: &hir::Item) { +impl LateLintPass for InvalidNoMangleItems { + fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { match it.node { hir::ItemFn(..) => { if attr::contains_name(&it.attrs, "no_mangle") && !cx.exported_items.contains(&it.id) { let msg = format!("function {} is marked #[no_mangle], but not exported", - it.ident); + it.name); cx.span_lint(PRIVATE_NO_MANGLE_FNS, it.span, &msg); } }, @@ -2467,7 +1083,7 @@ impl LintPass for InvalidNoMangleItems { if attr::contains_name(&it.attrs, "no_mangle") && !cx.exported_items.contains(&it.id) { let msg = format!("static {} is marked #[no_mangle], but not exported", - it.ident); + it.name); cx.span_lint(PRIVATE_NO_MANGLE_STATICS, it.span, &msg); } }, @@ -2498,8 +1114,10 @@ impl LintPass for MutableTransmutes { fn get_lints(&self) -> LintArray { lint_array!(MUTABLE_TRANSMUTES) } +} - fn check_expr(&mut self, cx: &Context, expr: &hir::Expr) { +impl LateLintPass for MutableTransmutes { + fn check_expr(&mut self, cx: &LateContext, expr: &hir::Expr) { use syntax::abi::RustIntrinsic; let msg = "mutating transmuted &mut T from &T may cause undefined behavior,\ @@ -2514,7 +1132,7 @@ impl LintPass for MutableTransmutes { _ => () } - fn get_transmute_from_to<'a, 'tcx>(cx: &Context<'a, 'tcx>, expr: &hir::Expr) + 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(..) => (), @@ -2538,7 +1156,7 @@ impl LintPass for MutableTransmutes { None } - fn def_id_is_transmute(cx: &Context, def_id: DefId) -> bool { + fn def_id_is_transmute(cx: &LateContext, def_id: DefId) -> bool { match cx.tcx.lookup_item_type(def_id).ty.sty { ty::TyBareFn(_, ref bfty) if bfty.abi == RustIntrinsic => (), _ => return false @@ -2565,7 +1183,10 @@ impl LintPass for UnstableFeatures { fn get_lints(&self) -> LintArray { lint_array!(UNSTABLE_FEATURES) } - fn check_attribute(&mut self, ctx: &Context, attr: &hir::Attribute) { +} + +impl LateLintPass for UnstableFeatures { + fn check_attribute(&mut self, ctx: &LateContext, attr: &ast::Attribute) { if attr::contains_name(&[attr.node.value.clone()], "feature") { if let Some(items) = attr.node.value.meta_item_list() { for item in items { @@ -2591,8 +1212,10 @@ impl LintPass for DropWithReprExtern { fn get_lints(&self) -> LintArray { lint_array!(DROP_WITH_REPR_EXTERN) } +} - fn check_crate(&mut self, ctx: &Context, _: &hir::Crate) { +impl LateLintPass for DropWithReprExtern { + fn check_crate(&mut self, ctx: &LateContext, _: &hir::Crate) { let drop_trait = match ctx.tcx.lang_items.drop_trait() { Some(id) => ctx.tcx.lookup_trait_def(id), None => { return } }; @@ -2613,15 +1236,12 @@ impl LintPass for DropWithReprExtern { codemap::DUMMY_SP); let self_defn_span = ctx.tcx.map.def_id_span(self_type_did, codemap::DUMMY_SP); - ctx.span_lint(DROP_WITH_REPR_EXTERN, - drop_impl_span, - "implementing Drop adds hidden state to types, \ - possibly conflicting with `#[repr(C)]`"); - // FIXME #19668: could be span_lint_note instead of manual guard. - if ctx.current_level(DROP_WITH_REPR_EXTERN) != Level::Allow { - ctx.sess().span_note(self_defn_span, - "the `#[repr(C)]` attribute is attached here"); - } + ctx.span_lint_note(DROP_WITH_REPR_EXTERN, + drop_impl_span, + "implementing Drop adds hidden state to types, \ + possibly conflicting with `#[repr(C)]`", + self_defn_span, + "the `#[repr(C)]` attribute is attached here"); } } _ => {} diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 517a3d13dd..920e034137 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -35,7 +35,6 @@ #![feature(box_syntax)] #![feature(num_bits_bytes)] #![feature(quote)] -#![feature(ref_slice)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] #![feature(slice_patterns)] @@ -48,6 +47,7 @@ extern crate rustc; #[macro_use] extern crate log; extern crate rustc_front; +extern crate rustc_back; pub use rustc::lint as lint; pub use rustc::metadata as metadata; @@ -58,7 +58,15 @@ pub use rustc::util as util; use session::Session; use lint::LintId; +mod bad_style; mod builtin; +mod types; +mod unused; + +use bad_style::*; +use builtin::*; +use types::*; +use unused::*; /// Tell the `LintStore` about all the built-in lints (the ones /// defined in this crate and the ones defined in @@ -67,7 +75,15 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { macro_rules! add_builtin { ($sess:ident, $($name:ident),*,) => ( {$( - store.register_pass($sess, false, box builtin::$name); + store.register_late_pass($sess, false, box $name); + )*} + ) + } + + macro_rules! add_early_builtin { + ($sess:ident, $($name:ident),*,) => ( + {$( + store.register_early_pass($sess, false, box $name); )*} ) } @@ -75,17 +91,21 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { macro_rules! add_builtin_with_new { ($sess:ident, $($name:ident),*,) => ( {$( - store.register_pass($sess, false, box builtin::$name::new()); + store.register_late_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(builtin::$lint)),*]); + store.register_group($sess, false, $name, vec![$(LintId::of($lint)),*]); ) } + add_early_builtin!(sess, + UnusedParens, + ); + add_builtin!(sess, HardwiredLints, WhileTrue, @@ -97,7 +117,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { NonCamelCaseTypes, NonSnakeCase, NonUpperCaseGlobals, - UnusedParens, UnusedImportBraces, NonShorthandFieldPatterns, UnusedUnsafe, @@ -127,10 +146,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { 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_UNSAFE, PATH_STATEMENTS, UNUSED_ATTRIBUTES); // We have one lint pass defined specially - store.register_pass(sess, false, box lint::GatherNodeLevels); + store.register_late_pass(sess, false, box lint::GatherNodeLevels); // Insert temporary renamings for a one-time deprecation store.register_renamed("raw_pointer_deriving", "raw_pointer_derive"); diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs new file mode 100644 index 0000000000..264228a705 --- /dev/null +++ b/src/librustc_lint/types.rs @@ -0,0 +1,676 @@ +// 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 middle::{infer}; +use middle::def_id::DefId; +use middle::subst::Substs; +use middle::ty::{self, Ty}; +use middle::const_eval::{eval_const_expr_partial, ConstVal}; +use middle::const_eval::EvalHint::ExprTypeChecked; +use util::nodemap::{FnvHashSet}; +use lint::{LateContext, LintContext, LintArray}; +use lint::{LintPass, LateLintPass}; + +use std::cmp; +use std::{i8, i16, i32, i64, u8, u16, u32, u64, f32, f64}; + +use syntax::{abi, ast}; +use syntax::attr::{self, AttrMetaMethods}; +use syntax::codemap::{self, Span}; +use syntax::feature_gate::{emit_feature_err, GateIssue}; +use syntax::ast::{TyIs, TyUs, TyI8, TyU8, TyI16, TyU16, TyI32, TyU32, TyI64, TyU64}; + +use rustc_front::hir; +use rustc_front::visit::{self, Visitor}; +use rustc_front::util::is_shift_binop; + +declare_lint! { + UNUSED_COMPARISONS, + Warn, + "comparisons made useless by limits of the types involved" +} + +declare_lint! { + OVERFLOWING_LITERALS, + Warn, + "literal out of range for its type" +} + +declare_lint! { + EXCEEDING_BITSHIFTS, + Deny, + "shift exceeds the type's number of bits" +} + +#[derive(Copy, Clone)] +pub struct TypeLimits { + /// Id of the last visited negated expression + negated_expr_id: ast::NodeId, +} + +impl TypeLimits { + pub fn new() -> TypeLimits { + TypeLimits { + negated_expr_id: !0, + } + } +} + +impl LintPass for TypeLimits { + fn get_lints(&self) -> LintArray { + lint_array!(UNUSED_COMPARISONS, OVERFLOWING_LITERALS, EXCEEDING_BITSHIFTS) + } +} + +impl LateLintPass for TypeLimits { + fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { + match e.node { + hir::ExprUnary(hir::UnNeg, ref expr) => { + match expr.node { + hir::ExprLit(ref lit) => { + match lit.node { + ast::LitInt(_, ast::UnsignedIntLit(_)) => { + check_unsigned_negation_feature(cx, e.span); + }, + ast::LitInt(_, ast::UnsuffixedIntLit(_)) => { + if let ty::TyUint(_) = cx.tcx.node_id_to_type(e.id).sty { + check_unsigned_negation_feature(cx, e.span); + } + }, + _ => () + } + }, + _ => { + let t = cx.tcx.node_id_to_type(expr.id); + match t.sty { + ty::TyUint(_) => { + check_unsigned_negation_feature(cx, e.span); + }, + _ => () + } + } + }; + // propagate negation, if the negation itself isn't negated + 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, + "comparison is useless due to type limits"); + } + + if is_shift_binop(binop.node) { + let opt_ty_bits = match cx.tcx.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 + }; + + if let Some(bits) = opt_ty_bits { + let exceeding = if let hir::ExprLit(ref lit) = r.node { + if let ast::LitInt(shift, _) = lit.node { shift >= bits } + else { false } + } else { + match eval_const_expr_partial(cx.tcx, &r, ExprTypeChecked, None) { + Ok(ConstVal::Int(shift)) => { shift as u64 >= bits }, + Ok(ConstVal::Uint(shift)) => { shift >= bits }, + _ => { false } + } + }; + if exceeding { + 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 { + ty::TyInt(t) => { + match lit.node { + ast::LitInt(v, ast::SignedIntLit(_, ast::Plus)) | + ast::LitInt(v, ast::UnsuffixedIntLit(ast::Plus)) => { + let int_type = if let ast::TyIs = t { + cx.sess().target.int_type + } else { + t + }; + let (_, max) = int_ty_range(int_type); + let negative = self.negated_expr_id == e.id; + + // Detect literal value out of range [min, max] inclusive + // 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, + &*format!("literal out of range for {:?}", t)); + return; + } + } + _ => panic!() + }; + }, + ty::TyUint(t) => { + let uint_type = if let ast::TyUs = t { + cx.sess().target.uint_type + } else { + t + }; + let (min, max) = uint_ty_range(uint_type); + let lit_val: u64 = match lit.node { + ast::LitByte(_v) => return, // _v is u8, within range by definition + ast::LitInt(v, _) => v, + _ => panic!() + }; + if lit_val < min || lit_val > max { + 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 { + ast::LitFloat(ref v, _) | + ast::LitFloatUnsuffixed(ref v) => { + match v.parse() { + Ok(f) => f, + Err(_) => return + } + } + _ => panic!() + }; + if lit_val < min || lit_val > max { + 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 { + 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::BiEq | hir::BiNe => v >= min && v <= max, + _ => panic!() + } + } + + 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 + }) + } + + // 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::TyIs => (i64::MIN, i64::MAX), + ast::TyI8 => (i8::MIN as i64, i8::MAX as i64), + ast::TyI16 => (i16::MIN as i64, i16::MAX as i64), + ast::TyI32 => (i32::MIN as i64, i32::MAX as i64), + ast::TyI64 => (i64::MIN, i64::MAX) + } + } + + fn uint_ty_range(uint_ty: ast::UintTy) -> (u64, u64) { + match uint_ty { + ast::TyUs => (u64::MIN, u64::MAX), + ast::TyU8 => (u8::MIN as u64, u8::MAX as u64), + ast::TyU16 => (u16::MIN as u64, u16::MAX as u64), + ast::TyU32 => (u32::MIN as u64, u32::MAX as u64), + ast::TyU64 => (u64::MIN, u64::MAX) + } + } + + fn float_ty_range(float_ty: ast::FloatTy) -> (f64, f64) { + match float_ty { + ast::TyF32 => (f32::MIN as f64, f32::MAX as f64), + ast::TyF64 => (f64::MIN, f64::MAX) + } + } + + fn int_ty_bits(int_ty: ast::IntTy, target_int_ty: ast::IntTy) -> u64 { + match int_ty { + ast::TyIs => int_ty_bits(target_int_ty, target_int_ty), + ast::TyI8 => i8::BITS as u64, + ast::TyI16 => i16::BITS as u64, + ast::TyI32 => i32::BITS as u64, + ast::TyI64 => i64::BITS as u64 + } + } + + fn uint_ty_bits(uint_ty: ast::UintTy, target_uint_ty: ast::UintTy) -> u64 { + match uint_ty { + ast::TyUs => uint_ty_bits(target_uint_ty, target_uint_ty), + ast::TyU8 => u8::BITS as u64, + ast::TyU16 => u16::BITS as u64, + ast::TyU32 => u32::BITS as u64, + ast::TyU64 => u64::BITS as u64 + } + } + + fn check_limits(tcx: &ty::ctxt, binop: hir::BinOp, + l: &hir::Expr, 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 + }; + // 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 { + 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::LitInt(v, ast::SignedIntLit(_, ast::Plus)) | + ast::LitInt(v, ast::UnsuffixedIntLit(ast::Plus)) => v as i64, + ast::LitInt(v, ast::SignedIntLit(_, ast::Minus)) | + ast::LitInt(v, ast::UnsuffixedIntLit(ast::Minus)) => -(v as i64), + _ => return true + }, + _ => panic!() + }; + 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::LitInt(v, _) => v, + _ => return true + }, + _ => panic!() + }; + is_valid(norm_binop, lit_val, min, max) + } + _ => 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 + } + } + + fn check_unsigned_negation_feature(cx: &LateContext, span: Span) { + if !cx.sess().features.borrow().negate_unsigned { + emit_feature_err( + &cx.sess().parse_sess.span_diagnostic, + "negate_unsigned", + span, + GateIssue::Language, + "unary negation of unsigned integers may be removed in the future"); + } + } + } +} + +declare_lint! { + IMPROPER_CTYPES, + Warn, + "proper use of libc types in foreign modules" +} + +struct ImproperCTypesVisitor<'a, 'tcx: 'a> { + cx: &'a LateContext<'a, 'tcx> +} + +enum FfiResult { + FfiSafe, + FfiUnsafe(&'static str), + FfiBadStruct(DefId, &'static str), + FfiBadEnum(DefId, &'static str) +} + +/// Check if this enum can be safely exported based on the +/// "nullable pointer optimization". Currently restricted +/// to function pointers and references, but could be +/// expanded to cover NonZero raw pointers and newtypes. +/// FIXME: This duplicates code in trans. +fn is_repr_nullable_ptr<'tcx>(tcx: &ty::ctxt<'tcx>, + def: ty::AdtDef<'tcx>, + substs: &Substs<'tcx>) + -> bool { + if def.variants.len() == 2 { + let data_idx; + + if def.variants[0].fields.is_empty() { + data_idx = 1; + } else if def.variants[1].fields.is_empty() { + data_idx = 0; + } else { + return false; + } + + if def.variants[data_idx].fields.len() == 1 { + match def.variants[data_idx].fields[0].ty(tcx, substs).sty { + ty::TyBareFn(None, _) => { return true; } + ty::TyRef(..) => { return true; } + _ => { } + } + } + } + false +} + +fn ast_ty_to_normalized<'tcx>(tcx: &ty::ctxt<'tcx>, + id: ast::NodeId) + -> Ty<'tcx> { + let tty = match tcx.ast_ty_to_ty_cache.borrow().get(&id) { + Some(&t) => t, + None => panic!("ast_ty_to_ty_cache was incomplete after typeck!") + }; + infer::normalize_associated_type(tcx, &tty) +} + +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 { + use self::FfiResult::*; + let cx = &self.cx.tcx; + + // Protect against infinite recursion, for example + // `struct S(*mut S);`. + // FIXME: A recursion limit is necessary as well, for irregular + // recusive types. + if !cache.insert(ty) { + return FfiSafe; + } + + match ty.sty { + ty::TyStruct(def, substs) => { + 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"); + } + + for field in &def.struct_variant().fields { + let field_ty = infer::normalize_associated_type(cx, &field.ty(cx, substs)); + let r = self.check_type_for_ffi(cache, field_ty); + match r { + FfiSafe => {} + FfiBadStruct(..) | FfiBadEnum(..) => { return r; } + FfiUnsafe(s) => { return FfiBadStruct(def.did, s); } + } + } + FfiSafe + } + ty::TyEnum(def, substs) => { + 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") + } + } + [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 too many #[repr(...)] attributes"); + } + } + + // Check the contained variants. + for variant in &def.variants { + for field in &variant.fields { + let arg = infer::normalize_associated_type(cx, &field.ty(cx, substs)); + let r = self.check_type_for_ffi(cache, arg); + match r { + FfiSafe => {} + FfiBadStruct(..) | FfiBadEnum(..) => { return r; } + FfiUnsafe(s) => { return FfiBadEnum(def.did, s); } + } + } + } + FfiSafe + } + + ty::TyChar => { + FfiUnsafe("found Rust type `char` in foreign module, while \ + `u32` or `libc::wchar_t` should be used") + } + + // Primitive types with a stable representation. + ty::TyBool | ty::TyInt(..) | ty::TyUint(..) | + ty::TyFloat(..) => FfiSafe, + + ty::TyBox(..) => { + FfiUnsafe("found Rust type Box<_> in foreign module, \ + consider using a raw pointer instead") + } + + ty::TySlice(_) => { + FfiUnsafe("found Rust slice type in foreign module, \ + consider using a raw pointer instead") + } + + ty::TyTrait(..) => { + FfiUnsafe("found Rust trait type in foreign module, \ + consider using a raw pointer instead") + } + + ty::TyStr => { + FfiUnsafe("found Rust type `str` in foreign module; \ + consider using a `*const libc::c_char`") + } + + ty::TyTuple(_) => { + FfiUnsafe("found Rust tuple type in foreign module; \ + consider using a struct instead`") + } + + 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::TyBareFn(None, 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") + } + _ => {} + } + + let sig = cx.erase_late_bound_regions(&bare_fn.sig); + match sig.output { + ty::FnDiverging => {} + ty::FnConverging(output) => { + if !output.is_nil() { + let r = self.check_type_for_ffi(cache, output); + match r { + FfiSafe => {} + _ => { return r; } + } + } + } + } + for arg in sig.inputs { + let r = self.check_type_for_ffi(cache, arg); + match r { + FfiSafe => {} + _ => { return r; } + } + } + FfiSafe + } + + ty::TyParam(..) | ty::TyInfer(..) | ty::TyError | + ty::TyClosure(..) | ty::TyProjection(..) | + ty::TyBareFn(Some(_), _) => { + panic!("Unexpected type in foreign function") + } + } + } + + fn check_def(&mut self, sp: Span, id: ast::NodeId) { + let tty = ast_ty_to_normalized(self.cx.tcx, id); + + match ImproperCTypesVisitor::check_type_for_ffi(self, &mut FnvHashSet(), tty) { + FfiResult::FfiSafe => {} + FfiResult::FfiUnsafe(s) => { + self.cx.span_lint(IMPROPER_CTYPES, sp, s); + } + 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)); + } + 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)); + } + } + } +} + +impl<'a, 'tcx, 'v> Visitor<'v> for ImproperCTypesVisitor<'a, 'tcx> { + fn visit_ty(&mut self, ty: &hir::Ty) { + match ty.node { + hir::TyPath(..) | + hir::TyBareFn(..) => self.check_def(ty.span, ty.id), + hir::TyVec(..) => { + self.cx.span_lint(IMPROPER_CTYPES, ty.span, + "found Rust slice type in foreign module, consider \ + using a raw pointer instead"); + } + hir::TyFixedLengthVec(ref ty, _) => self.visit_ty(ty), + hir::TyTup(..) => { + self.cx.span_lint(IMPROPER_CTYPES, ty.span, + "found Rust tuple type in foreign module; \ + consider using a struct instead`") + } + _ => visit::walk_ty(self, ty) + } + } +} + +#[derive(Copy, Clone)] +pub struct ImproperCTypes; + +impl LintPass for ImproperCTypes { + fn get_lints(&self) -> LintArray { + lint_array!(IMPROPER_CTYPES) + } +} + +impl LateLintPass for ImproperCTypes { + fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { + fn check_ty(cx: &LateContext, ty: &hir::Ty) { + let mut vis = ImproperCTypesVisitor { cx: cx }; + vis.visit_ty(ty); + } + + fn check_foreign_fn(cx: &LateContext, decl: &hir::FnDecl) { + for input in &decl.inputs { + check_ty(cx, &*input.ty); + } + if let hir::Return(ref ret_ty) = decl.output { + let tty = ast_ty_to_normalized(cx.tcx, ret_ty.id); + if !tty.is_nil() { + check_ty(cx, &ret_ty); + } + } + } + + match it.node { + hir::ItemForeignMod(ref nmod) + if nmod.abi != abi::RustIntrinsic && + nmod.abi != abi::PlatformIntrinsic => { + for ni in &nmod.items { + match ni.node { + hir::ForeignItemFn(ref decl, _) => check_foreign_fn(cx, &**decl), + hir::ForeignItemStatic(ref t, _) => check_ty(cx, &**t) + } + } + } + _ => (), + } + } +} diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs new file mode 100644 index 0000000000..8ed4706b1c --- /dev/null +++ b/src/librustc_lint/unused.rs @@ -0,0 +1,465 @@ +// 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 metadata::csearch; +use middle::pat_util; +use middle::ty; +use middle::ty::adjustment; +use rustc::front::map as hir_map; +use util::nodemap::FnvHashMap; +use lint::{LateContext, EarlyContext, LintContext, LintArray}; +use lint::{LintPass, EarlyLintPass, LateLintPass}; + +use std::collections::hash_map::Entry::{Occupied, Vacant}; + +use syntax::ast; +use syntax::attr::{self, AttrMetaMethods}; +use syntax::codemap::Span; +use syntax::feature_gate::{KNOWN_ATTRIBUTES, AttributeType}; +use syntax::ptr::P; + +use rustc_back::slice; +use rustc_front::hir; +use rustc_front::visit::FnKind; + +declare_lint! { + pub UNUSED_MUT, + Warn, + "detect mut variables which don't need to be mutable" +} + +#[derive(Copy, Clone)] +pub struct UnusedMut; + +impl UnusedMut { + fn check_unused_mut_pat(&self, cx: &LateContext, pats: &[P]) { + // collect all mutable pattern and group their NodeIDs by their Identifier to + // avoid false warnings in match arms with multiple patterns + + let mut mutables = FnvHashMap(); + for p in pats { + pat_util::pat_bindings(&cx.tcx.def_map, p, |mode, id, _, path1| { + let name = path1.node; + 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); }, + } + } + } + }); + } + + 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]), + "variable does not need to be mutable"); + } + } + } +} + +impl LintPass for UnusedMut { + fn get_lints(&self) -> LintArray { + lint_array!(UNUSED_MUT) + } +} + +impl LateLintPass for UnusedMut { + fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { + if let hir::ExprMatch(_, ref arms, _) = e.node { + for a in arms { + self.check_unused_mut_pat(cx, &a.pats) + } + } + } + + fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) { + if let hir::StmtDecl(ref d, _) = s.node { + if let hir::DeclLocal(ref l) = d.node { + self.check_unused_mut_pat(cx, slice::ref_slice(&l.pat)); + } + } + } + + 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)); + } + } +} + +declare_lint! { + pub UNUSED_MUST_USE, + Warn, + "unused result of a type flagged as #[must_use]" +} + +declare_lint! { + pub UNUSED_RESULTS, + Allow, + "unused result of an expression in a statement" +} + +#[derive(Copy, Clone)] +pub struct UnusedResults; + +impl LintPass for UnusedResults { + fn get_lints(&self) -> LintArray { + lint_array!(UNUSED_MUST_USE, UNUSED_RESULTS) + } +} + +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 + }; + + if let hir::ExprRet(..) = expr.node { + return; + } + + let t = cx.tcx.expr_ty(&expr); + let warned = match t.sty { + ty::TyTuple(ref tys) if tys.is_empty() => return, + ty::TyBool => return, + ty::TyStruct(def, _) | + ty::TyEnum(def, _) => { + if let Some(def_node_id) = cx.tcx.map.as_local_node_id(def.did) { + if let hir_map::NodeItem(it) = cx.tcx.map.get(def_node_id) { + check_must_use(cx, &it.attrs, s.span) + } else { + false + } + } else { + let attrs = csearch::get_item_attrs(&cx.sess().cstore, def.did); + check_must_use(cx, &attrs[..], s.span) + } + } + _ => false, + }; + if !warned { + cx.span_lint(UNUSED_RESULTS, s.span, "unused result"); + } + + fn check_must_use(cx: &LateContext, attrs: &[ast::Attribute], sp: Span) -> bool { + for attr in attrs { + if attr.check_name("must_use") { + let mut msg = "unused result which must be used".to_string(); + // check for #[must_use="..."] + match attr.value_str() { + None => {} + Some(s) => { + msg.push_str(": "); + msg.push_str(&s); + } + } + cx.span_lint(UNUSED_MUST_USE, sp, &msg); + return true; + } + } + false + } + } +} + +declare_lint! { + pub UNUSED_UNSAFE, + Warn, + "unnecessary use of an `unsafe` block" +} + +#[derive(Copy, Clone)] +pub struct UnusedUnsafe; + +impl LintPass for UnusedUnsafe { + fn get_lints(&self) -> LintArray { + lint_array!(UNUSED_UNSAFE) + } +} + +impl LateLintPass for UnusedUnsafe { + fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { + 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"); + } + } + } +} + +declare_lint! { + pub PATH_STATEMENTS, + Warn, + "path statements with no effect" +} + +#[derive(Copy, Clone)] +pub struct PathStatements; + +impl LintPass for PathStatements { + fn get_lints(&self) -> LintArray { + lint_array!(PATH_STATEMENTS) + } +} + +impl LateLintPass for PathStatements { + fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) { + match s.node { + hir::StmtSemi(ref expr, _) => { + match expr.node { + hir::ExprPath(..) => cx.span_lint(PATH_STATEMENTS, s.span, + "path statement with no effect"), + _ => () + } + } + _ => () + } + } +} + +declare_lint! { + pub UNUSED_ATTRIBUTES, + Warn, + "detects attributes that were not used by the compiler" +} + +#[derive(Copy, Clone)] +pub struct UnusedAttributes; + +impl LintPass for UnusedAttributes { + fn get_lints(&self) -> LintArray { + lint_array!(UNUSED_ATTRIBUTES) + } +} + +impl LateLintPass for UnusedAttributes { + fn check_attribute(&mut self, cx: &LateContext, attr: &ast::Attribute) { + // Note that check_name() marks the attribute as used if it matches. + for &(ref name, ty, _) in KNOWN_ATTRIBUTES { + match ty { + AttributeType::Whitelisted if attr.check_name(name) => { + break; + }, + _ => () + } + } + + let plugin_attributes = cx.sess().plugin_attributes.borrow_mut(); + for &(ref name, ty) in plugin_attributes.iter() { + if ty == AttributeType::Whitelisted && attr.check_name(&*name) { + break; + } + } + + if !attr::is_used(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(); + + // 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 { + 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", + }; + cx.span_lint(UNUSED_ATTRIBUTES, attr.span, msg); + } + } + } +} + +declare_lint! { + UNUSED_PARENS, + Warn, + "`if`, `match`, `while` and `return` do not need parentheses" +} + +#[derive(Copy, Clone)] +pub struct UnusedParens; + +impl UnusedParens { + fn check_unused_parens_core(&self, cx: &EarlyContext, value: &ast::Expr, msg: &str, + struct_lit_needs_parens: bool) { + if let ast::ExprParen(ref inner) = value.node { + let necessary = struct_lit_needs_parens && contains_exterior_struct_lit(&**inner); + if !necessary { + cx.span_lint(UNUSED_PARENS, value.span, + &format!("unnecessary parentheses around {}", msg)) + } + } + + /// Expressions that syntactically contain an "exterior" struct + /// literal i.e. not surrounded by any parens or other + /// delimiters, e.g. `X { y: 1 }`, `X { y: 1 }.method()`, `foo + /// == X { y: 1 }` and `X { y: 1 } == foo` all do, but `(X { + /// y: 1 }) == foo` does not. + fn contains_exterior_struct_lit(value: &ast::Expr) -> bool { + match value.node { + ast::ExprStruct(..) => true, + + ast::ExprAssign(ref lhs, ref rhs) | + ast::ExprAssignOp(_, ref lhs, ref rhs) | + ast::ExprBinary(_, ref lhs, ref rhs) => { + // X { y: 1 } + X { y: 2 } + contains_exterior_struct_lit(&**lhs) || + contains_exterior_struct_lit(&**rhs) + } + ast::ExprUnary(_, ref x) | + ast::ExprCast(ref x, _) | + ast::ExprField(ref x, _) | + ast::ExprTupField(ref x, _) | + ast::ExprIndex(ref x, _) => { + // &X { y: 1 }, X { y: 1 }.y + contains_exterior_struct_lit(&**x) + } + + ast::ExprMethodCall(_, _, ref exprs) => { + // X { y: 1 }.bar(...) + contains_exterior_struct_lit(&*exprs[0]) + } + + _ => false + } + } + } +} + +impl LintPass for UnusedParens { + fn get_lints(&self) -> LintArray { + lint_array!(UNUSED_PARENS) + } +} + +impl EarlyLintPass for UnusedParens { + fn check_expr(&mut self, cx: &EarlyContext, e: &ast::Expr) { + let (value, msg, struct_lit_needs_parens) = match e.node { + ast::ExprIf(ref cond, _, _) => (cond, "`if` condition", true), + ast::ExprWhile(ref cond, _, _) => (cond, "`while` condition", true), + ast::ExprIfLet(_, ref cond, _, _) => (cond, "`if let` head expression", true), + ast::ExprWhileLet(_, ref cond, _, _) => (cond, "`while let` head expression", true), + ast::ExprForLoop(_, ref cond, _, _) => (cond, "`for` head expression", true), + ast::ExprMatch(ref head, _) => (head, "`match` head expression", true), + ast::ExprRet(Some(ref value)) => (value, "`return` value", false), + ast::ExprAssign(_, ref value) => (value, "assigned value", false), + ast::ExprAssignOp(_, _, ref value) => (value, "assigned value", false), + _ => 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::StmtDecl(ref decl, _) => match decl.node { + ast::DeclLocal(ref local) => match local.init { + Some(ref value) => (value, "assigned value"), + None => return + }, + _ => return + }, + _ => return + }; + self.check_unused_parens_core(cx, &**value, msg, false); + } +} + +declare_lint! { + UNUSED_IMPORT_BRACES, + Allow, + "unnecessary braces around an imported item" +} + +#[derive(Copy, Clone)] +pub struct UnusedImportBraces; + +impl LintPass for UnusedImportBraces { + fn get_lints(&self) -> LintArray { + lint_array!(UNUSED_IMPORT_BRACES) + } +} + +impl LateLintPass for UnusedImportBraces { + fn check_item(&mut self, cx: &LateContext, item: &hir::Item) { + if let hir::ItemUse(ref view_path) = item.node { + if let hir::ViewPathList(_, ref items) = view_path.node { + if items.len() == 1 { + if let hir::PathListIdent {ref name, ..} = items[0].node { + let m = format!("braces around {} is unnecessary", + name); + cx.span_lint(UNUSED_IMPORT_BRACES, item.span, + &m[..]); + } + } + } + } + } +} + +declare_lint! { + UNUSED_ALLOCATION, + Warn, + "detects unnecessary allocations that can be eliminated" +} + +#[derive(Copy, Clone)] +pub struct UnusedAllocation; + +impl LintPass for UnusedAllocation { + fn get_lints(&self) -> LintArray { + lint_array!(UNUSED_ALLOCATION) + } +} + +impl LateLintPass for UnusedAllocation { + fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { + match e.node { + hir::ExprBox(_) => {} + _ => return + } + + if let Some(adjustment) = cx.tcx.tables.borrow().adjustments.get(&e.id) { + if let adjustment::AdjustDerefRef(adjustment::AutoDerefRef { + ref autoref, .. + }) = *adjustment { + match autoref { + &Some(adjustment::AutoPtr(_, 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, + "unnecessary allocation, use &mut instead"); + } + _ => () + } + } + } + } +} + diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index aa3a991b8b..fe84cffa8c 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -60,7 +60,7 @@ pub use self::DLLStorageClassTypes::*; use std::ffi::CString; use std::cell::RefCell; -use std::{slice, mem}; +use std::slice; use libc::{c_uint, c_ushort, uint64_t, c_int, size_t, c_char}; use libc::{c_longlong, c_ulonglong, c_void}; use debuginfo::{DIBuilderRef, DIDescriptor, @@ -2307,7 +2307,7 @@ pub unsafe extern "C" fn rust_llvm_string_write_impl(sr: RustStringRef, size: size_t) { let slice = slice::from_raw_parts(ptr as *const u8, size as usize); - let sr: RustStringRepr = mem::transmute(sr); + let sr = sr as RustStringRepr; (*sr).borrow_mut().push_all(slice); } diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index 5604c78e09..21a77bbd23 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -8,15 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use build::{BlockAnd, Builder}; use hair::*; use repr::*; -use build::{BlockAnd, Builder}; +use rustc_front::hir; -impl Builder { +impl<'a,'tcx> Builder<'a,'tcx> { pub fn ast_block(&mut self, - destination: &Lvalue, + destination: &Lvalue<'tcx>, mut block: BasicBlock, - ast_block: H::Block) + ast_block: &'tcx hir::Block) -> BlockAnd<()> { let this = self; let Block { extent, span: _, stmts, expr } = this.hir.mirror(ast_block); diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs index 955e1b7146..318ae70408 100644 --- a/src/librustc_mir/build/cfg.rs +++ b/src/librustc_mir/build/cfg.rs @@ -14,22 +14,22 @@ //! Routines for manipulating the control-flow graph. use build::CFG; -use hair::*; use repr::*; +use syntax::codemap::Span; -impl CFG { - pub fn block_data(&self, blk: BasicBlock) -> &BasicBlockData { +impl<'tcx> CFG<'tcx> { + pub fn block_data(&self, blk: BasicBlock) -> &BasicBlockData<'tcx> { &self.basic_blocks[blk.index()] } - pub fn block_data_mut(&mut self, blk: BasicBlock) -> &mut BasicBlockData { + pub fn block_data_mut(&mut self, blk: BasicBlock) -> &mut BasicBlockData<'tcx> { &mut self.basic_blocks[blk.index()] } pub fn end_point(&self, block: BasicBlock) -> ExecutionPoint { ExecutionPoint { block: block, - statement: self.block_data(block).statements.len() as u32 + statement: self.block_data(block).statements.len() as u32, } } @@ -39,21 +39,21 @@ impl CFG { BasicBlock::new(node_index) } - pub fn push(&mut self, block: BasicBlock, statement: Statement) { + pub fn push(&mut self, block: BasicBlock, statement: Statement<'tcx>) { debug!("push({:?}, {:?})", block, statement); self.block_data_mut(block).statements.push(statement); } pub fn push_assign_constant(&mut self, block: BasicBlock, - span: H::Span, - temp: &Lvalue, - constant: Constant) { + span: Span, + temp: &Lvalue<'tcx>, + constant: Constant<'tcx>) { self.push_assign(block, span, temp, Rvalue::Use(Operand::Constant(constant))); } - pub fn push_drop(&mut self, block: BasicBlock, span: H::Span, - kind: DropKind, lvalue: &Lvalue) { + pub fn push_drop(&mut self, block: BasicBlock, span: Span, + kind: DropKind, lvalue: &Lvalue<'tcx>) { self.push(block, Statement { span: span, kind: StatementKind::Drop(kind, lvalue.clone()) @@ -62,9 +62,9 @@ impl CFG { pub fn push_assign(&mut self, block: BasicBlock, - span: H::Span, - lvalue: &Lvalue, - rvalue: Rvalue) { + span: Span, + lvalue: &Lvalue<'tcx>, + rvalue: Rvalue<'tcx>) { self.push(block, Statement { span: span, kind: StatementKind::Assign(lvalue.clone(), rvalue) @@ -73,7 +73,7 @@ impl CFG { pub fn terminate(&mut self, block: BasicBlock, - terminator: Terminator) { + terminator: Terminator<'tcx>) { // Check whether this block has already been terminated. For // this, we rely on the fact that the initial state is to have // a Diverge terminator and an empty list of targets (which diff --git a/src/librustc_mir/build/expr/as_constant.rs b/src/librustc_mir/build/expr/as_constant.rs index a6d06c447a..b362f98176 100644 --- a/src/librustc_mir/build/expr/as_constant.rs +++ b/src/librustc_mir/build/expr/as_constant.rs @@ -10,114 +10,32 @@ //! See docs in build/expr/mod.rs -use rustc_data_structures::fnv::FnvHashMap; - -use build::{Builder}; +use build::Builder; use hair::*; use repr::*; -impl Builder { +impl<'a,'tcx> Builder<'a,'tcx> { /// Compile `expr`, yielding a compile-time constant. Assumes that /// `expr` is a valid compile-time constant! - pub fn as_constant(&mut self, expr: M) -> Constant - where M: Mirror> + pub fn as_constant(&mut self, expr: M) -> Constant<'tcx> + where M: Mirror<'tcx, Output=Expr<'tcx>> { let expr = self.hir.mirror(expr); self.expr_as_constant(expr) } - fn expr_as_constant(&mut self, expr: Expr) -> Constant { + fn expr_as_constant(&mut self, expr: Expr<'tcx>) -> Constant<'tcx> { let this = self; - let Expr { ty: _, temp_lifetime: _, span, kind } = expr; - let kind = match kind { - ExprKind::Scope { extent: _, value } => { - return this.as_constant(value); - } - ExprKind::Paren { arg } => { - return this.as_constant(arg); - } - ExprKind::Literal { literal } => { - ConstantKind::Literal(literal) - } - ExprKind::Vec { fields } => { - let fields = this.as_constants(fields); - ConstantKind::Aggregate(AggregateKind::Vec, fields) - } - ExprKind::Tuple { fields } => { - let fields = this.as_constants(fields); - ConstantKind::Aggregate(AggregateKind::Tuple, fields) - } - ExprKind::Adt { adt_def, variant_index, substs, fields, base: None } => { - let field_names = this.hir.fields(adt_def, variant_index); - let fields = this.named_field_constants(field_names, fields); - ConstantKind::Aggregate(AggregateKind::Adt(adt_def, variant_index, substs), fields) - } - ExprKind::Repeat { value, count } => { - let value = Box::new(this.as_constant(value)); - let count = Box::new(this.as_constant(count)); - ConstantKind::Repeat(value, count) - } - ExprKind::Binary { op, lhs, rhs } => { - let lhs = Box::new(this.as_constant(lhs)); - let rhs = Box::new(this.as_constant(rhs)); - ConstantKind::BinaryOp(op, lhs, rhs) - } - ExprKind::Unary { op, arg } => { - let arg = Box::new(this.as_constant(arg)); - ConstantKind::UnaryOp(op, arg) - } - ExprKind::Field { lhs, name } => { - let lhs = this.as_constant(lhs); - ConstantKind::Projection( - Box::new(ConstantProjection { - base: lhs, - elem: ProjectionElem::Field(name), - })) - } - ExprKind::Deref { arg } => { - let arg = this.as_constant(arg); - ConstantKind::Projection( - Box::new(ConstantProjection { - base: arg, - elem: ProjectionElem::Deref, - })) - } - ExprKind::Call { fun, args } => { - let fun = this.as_constant(fun); - let args = this.as_constants(args); - ConstantKind::Call(Box::new(fun), args) - } - _ => { + let Expr { ty, temp_lifetime: _, span, kind } = expr; + match kind { + ExprKind::Scope { extent: _, value } => + this.as_constant(value), + ExprKind::Literal { literal } => + Constant { span: span, ty: ty, literal: literal }, + _ => this.hir.span_bug( span, - &format!("expression is not a valid constant {:?}", kind)); - } - }; - Constant { span: span, kind: kind } - } - - fn as_constants(&mut self, - exprs: Vec>) - -> Vec> - { - exprs.into_iter().map(|expr| self.as_constant(expr)).collect() - } - - fn named_field_constants(&mut self, - field_names: Vec>, - field_exprs: Vec>) - -> Vec> - { - let fields_map: FnvHashMap<_, _> = - field_exprs.into_iter() - .map(|f| (f.name, self.as_constant(f.expr))) - .collect(); - - let fields: Vec<_> = - field_names.into_iter() - .map(|n| fields_map[&n].clone()) - .collect(); - - fields + &format!("expression is not a valid constant {:?}", kind)), + } } } diff --git a/src/librustc_mir/build/expr/as_lvalue.rs b/src/librustc_mir/build/expr/as_lvalue.rs index 0ceafcc9a6..d93304f034 100644 --- a/src/librustc_mir/build/expr/as_lvalue.rs +++ b/src/librustc_mir/build/expr/as_lvalue.rs @@ -15,13 +15,13 @@ use build::expr::category::Category; use hair::*; use repr::*; -impl Builder { +impl<'a,'tcx> Builder<'a,'tcx> { /// Compile `expr`, yielding an lvalue that we can move from etc. pub fn as_lvalue(&mut self, block: BasicBlock, expr: M) - -> BlockAnd> - where M: Mirror> + -> BlockAnd> + where M: Mirror<'tcx, Output=Expr<'tcx>> { let expr = self.hir.mirror(expr); self.expr_as_lvalue(block, expr) @@ -29,22 +29,15 @@ impl Builder { fn expr_as_lvalue(&mut self, mut block: BasicBlock, - expr: Expr) - -> BlockAnd> - { - debug!("expr_as_lvalue(block={:?}, expr={:?})", - block, expr); + expr: Expr<'tcx>) + -> BlockAnd> { + debug!("expr_as_lvalue(block={:?}, expr={:?})", block, expr); let this = self; let expr_span = expr.span; match expr.kind { ExprKind::Scope { extent, value } => { - this.in_scope(extent, block, |this| { - this.as_lvalue(block, value) - }) - } - ExprKind::Paren { arg } => { - this.as_lvalue(block, arg) + this.in_scope(extent, block, |this| this.as_lvalue(block, value)) } ExprKind::Field { lhs, name } => { let lvalue = unpack!(block = this.as_lvalue(block, lhs)); @@ -72,12 +65,11 @@ impl Builder { idx.clone(), Operand::Consume(len))); - let (success, failure) = (this.cfg.start_new_block(), - this.cfg.start_new_block()); + let (success, failure) = (this.cfg.start_new_block(), this.cfg.start_new_block()); this.cfg.terminate(block, Terminator::If { cond: Operand::Consume(lt), - targets: [success, failure] + targets: [success, failure], }); this.panic(failure); success.and(slice.index(idx)) diff --git a/src/librustc_mir/build/expr/as_operand.rs b/src/librustc_mir/build/expr/as_operand.rs index ee090571b7..6b2c487d0f 100644 --- a/src/librustc_mir/build/expr/as_operand.rs +++ b/src/librustc_mir/build/expr/as_operand.rs @@ -15,16 +15,13 @@ use build::expr::category::Category; use hair::*; use repr::*; -impl Builder { +impl<'a,'tcx> Builder<'a,'tcx> { /// Compile `expr` into a value that can be used as an operand. /// If `expr` is an lvalue like `x`, this will introduce a /// temporary `tmp = x`, so that we capture the value of `x` at /// this time. - pub fn as_operand(&mut self, - block: BasicBlock, - expr: M) - -> BlockAnd> - where M: Mirror> + pub fn as_operand(&mut self, block: BasicBlock, expr: M) -> BlockAnd> + where M: Mirror<'tcx, Output = Expr<'tcx>> { let expr = self.hir.mirror(expr); self.expr_as_operand(block, expr) @@ -32,23 +29,13 @@ impl Builder { fn expr_as_operand(&mut self, mut block: BasicBlock, - expr: Expr) - -> BlockAnd> - { - debug!("expr_as_operand(block={:?}, expr={:?})", - block, expr); + expr: Expr<'tcx>) + -> BlockAnd> { + debug!("expr_as_operand(block={:?}, expr={:?})", block, expr); let this = self; - match expr.kind { - ExprKind::Scope { extent, value } => { - return this.in_scope(extent, block, |this| { - this.as_operand(block, value) - }); - } - ExprKind::Paren { arg } => { - return this.as_operand(block, arg); - } - _ => { } + if let ExprKind::Scope { extent, value } = expr.kind { + return this.in_scope(extent, block, |this| this.as_operand(block, value)); } let category = Category::of(&expr.kind).unwrap(); diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index e4d3ad2150..3cfc51ec3c 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -17,13 +17,10 @@ use build::expr::category::{Category, RvalueFunc}; use hair::*; use repr::*; -impl Builder { +impl<'a,'tcx> Builder<'a,'tcx> { /// Compile `expr`, yielding an rvalue. - pub fn as_rvalue(&mut self, - block: BasicBlock, - expr: M) - -> BlockAnd> - where M: Mirror> + pub fn as_rvalue(&mut self, block: BasicBlock, expr: M) -> BlockAnd> + where M: Mirror<'tcx, Output = Expr<'tcx>> { let expr = self.hir.mirror(expr); self.expr_as_rvalue(block, expr) @@ -31,23 +28,16 @@ impl Builder { fn expr_as_rvalue(&mut self, mut block: BasicBlock, - expr: Expr) - -> BlockAnd> - { - debug!("expr_as_rvalue(block={:?}, expr={:?})", - block, expr); + expr: Expr<'tcx>) + -> BlockAnd> { + debug!("expr_as_rvalue(block={:?}, expr={:?})", block, expr); let this = self; let expr_span = expr.span; match expr.kind { ExprKind::Scope { extent, value } => { - this.in_scope(extent, block, |this| { - this.as_rvalue(block, value) - }) - } - ExprKind::Paren { arg } => { - this.as_rvalue(block, arg) + this.in_scope(extent, block, |this| this.as_rvalue(block, value)) } ExprKind::InlineAsm { asm } => { block.and(Rvalue::InlineAsm(asm)) @@ -70,7 +60,7 @@ impl Builder { let arg = unpack!(block = this.as_operand(block, arg)); block.and(Rvalue::UnaryOp(op, arg)) } - ExprKind::Box { place: _, value } => { + ExprKind::Box { value } => { let value = this.hir.mirror(value); let value_ty = value.ty.clone(); let result = this.temp(value_ty.clone()); @@ -165,11 +155,9 @@ impl Builder { .map(|f| (f.name, unpack!(block = this.as_operand(block, f.expr)))) .collect(); - let field_names = - this.hir.fields(adt_def, variant_index); + let field_names = this.hir.fields(adt_def, variant_index); - let base = - base.map(|base| unpack!(block = this.as_lvalue(block, base))); + let base = base.map(|base| unpack!(block = this.as_lvalue(block, base))); // for the actual values we use, take either the // expr the user specified or, if they didn't diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index 50f04e0177..7c85e9e717 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -15,38 +15,22 @@ use build::expr::category::Category; use hair::*; use repr::*; -impl Builder { +impl<'a,'tcx> Builder<'a,'tcx> { /// Compile `expr` into a fresh temporary. This is used when building /// up rvalues so as to freeze the value that will be consumed. - pub fn as_temp(&mut self, - block: BasicBlock, - expr: M) - -> BlockAnd> - where M: Mirror> + pub fn as_temp(&mut self, block: BasicBlock, expr: M) -> BlockAnd> + where M: Mirror<'tcx, Output = Expr<'tcx>> { let expr = self.hir.mirror(expr); self.expr_as_temp(block, expr) } - fn expr_as_temp(&mut self, - mut block: BasicBlock, - expr: Expr) - -> BlockAnd> - { - debug!("expr_as_temp(block={:?}, expr={:?})", - block, expr); + fn expr_as_temp(&mut self, mut block: BasicBlock, expr: Expr<'tcx>) -> BlockAnd> { + debug!("expr_as_temp(block={:?}, expr={:?})", block, expr); let this = self; - match expr.kind { - ExprKind::Scope { extent, value } => { - return this.in_scope(extent, block, |this| { - this.as_temp(block, value) - }); - } - ExprKind::Paren { arg } => { - return this.as_temp(block, arg); - } - _ => { } + if let ExprKind::Scope { extent, value } = expr.kind { + return this.in_scope(extent, block, |this| this.as_temp(block, value)); } let expr_ty = expr.ty.clone(); @@ -54,9 +38,7 @@ impl Builder { let temp_lifetime = match expr.temp_lifetime { Some(t) => t, None => { - this.hir.span_bug( - expr.span, - &format!("no temp_lifetime for expr")); + this.hir.span_bug(expr.span, &format!("no temp_lifetime for expr")); } }; this.schedule_drop(expr.span, temp_lifetime, DropKind::Deep, &temp, expr_ty); diff --git a/src/librustc_mir/build/expr/category.rs b/src/librustc_mir/build/expr/category.rs index 1f9928acdc..658b7779b4 100644 --- a/src/librustc_mir/build/expr/category.rs +++ b/src/librustc_mir/build/expr/category.rs @@ -41,11 +41,9 @@ pub enum RvalueFunc { /// Determines the category for a given expression. Note that scope /// and paren expressions have no category. impl Category { - pub fn of(ek: &ExprKind) -> Option { + pub fn of<'tcx>(ek: &ExprKind<'tcx>) -> Option { match *ek { - ExprKind::Scope { .. } | - ExprKind::Paren { .. } => - None, + ExprKind::Scope { .. } => None, ExprKind::Field { .. } | ExprKind::Deref { .. } | diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index b409903ad7..a7d68b09b5 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -15,14 +15,16 @@ use build::expr::category::{Category, RvalueFunc}; use build::scope::LoopScope; use hair::*; use repr::*; +use rustc::middle::region::CodeExtent; +use syntax::codemap::Span; -impl Builder { +impl<'a,'tcx> Builder<'a,'tcx> { /// Compile `expr`, storing the result into `destination`, which /// is assumed to be uninitialized. pub fn into_expr(&mut self, - destination: &Lvalue, + destination: &Lvalue<'tcx>, mut block: BasicBlock, - expr: Expr) + expr: Expr<'tcx>) -> BlockAnd<()> { debug!("into_expr(destination={:?}, block={:?}, expr={:?})", @@ -36,12 +38,7 @@ impl Builder { match expr.kind { ExprKind::Scope { extent, value } => { - this.in_scope(extent, block, |this| { - this.into(destination, block, value) - }) - } - ExprKind::Paren { arg } => { - this.into(destination, block, arg) + this.in_scope(extent, block, |this| this.into(destination, block, value)) } ExprKind::Block { body: ast_block } => { this.ast_block(destination, block, ast_block) @@ -102,14 +99,16 @@ impl Builder { true_block, expr_span, destination, Constant { span: expr_span, - kind: ConstantKind::Literal(Literal::Bool { value: true }), + ty: this.hir.bool_ty(), + literal: this.hir.true_literal(), }); this.cfg.push_assign_constant( false_block, expr_span, destination, Constant { span: expr_span, - kind: ConstantKind::Literal(Literal::Bool { value: false }), + ty: this.hir.bool_ty(), + literal: this.hir.false_literal(), }); this.cfg.terminate(true_block, Terminator::Goto { target: join_block }); @@ -203,8 +202,7 @@ impl Builder { |loop_scope| loop_scope.continue_block) } ExprKind::Break { label } => { - this.break_or_continue(expr_span, label, block, - |loop_scope| loop_scope.break_block) + this.break_or_continue(expr_span, label, block, |loop_scope| loop_scope.break_block) } ExprKind::Return { value } => { unpack!(block = this.into(&Lvalue::ReturnPointer, block, value)); @@ -225,9 +223,9 @@ impl Builder { data: CallData { destination: destination.clone(), func: fun, - args: args + args: args, }, - targets: [success, panic] + targets: [success, panic], }); success.unit() } @@ -267,12 +265,12 @@ impl Builder { } fn break_or_continue(&mut self, - span: H::Span, - label: Option, + span: Span, + label: Option, block: BasicBlock, exit_selector: F) -> BlockAnd<()> - where F: FnOnce(&LoopScope) -> BasicBlock + where F: FnOnce(&LoopScope) -> BasicBlock { let loop_scope = self.find_loop_scope(span, label); let exit_block = exit_selector(&loop_scope); diff --git a/src/librustc_mir/build/into.rs b/src/librustc_mir/build/into.rs index 426e59f1c4..c6f1b777d6 100644 --- a/src/librustc_mir/build/into.rs +++ b/src/librustc_mir/build/into.rs @@ -18,53 +18,56 @@ use build::{BlockAnd, Builder}; use hair::*; use repr::*; -pub trait EvalInto { - fn eval_into(self, builder: &mut Builder, destination: &Lvalue, - block: BasicBlock) -> BlockAnd<()>; +pub trait EvalInto<'tcx> { + fn eval_into<'a>(self, + builder: &mut Builder<'a, 'tcx>, + destination: &Lvalue<'tcx>, + block: BasicBlock) + -> BlockAnd<()>; } -impl Builder { +impl<'a,'tcx> Builder<'a,'tcx> { pub fn into(&mut self, - destination: &Lvalue, + destination: &Lvalue<'tcx>, block: BasicBlock, expr: E) -> BlockAnd<()> - where E: EvalInto + where E: EvalInto<'tcx> { expr.eval_into(self, destination, block) } } -impl EvalInto for ExprRef { - fn eval_into(self, - builder: &mut Builder, - destination: &Lvalue, - block: BasicBlock) - -> BlockAnd<()> { +impl<'tcx> EvalInto<'tcx> for ExprRef<'tcx> { + fn eval_into<'a>(self, + builder: &mut Builder<'a, 'tcx>, + destination: &Lvalue<'tcx>, + block: BasicBlock) + -> BlockAnd<()> { let expr = builder.hir.mirror(self); builder.into_expr(destination, block, expr) } } -impl EvalInto for Expr { - fn eval_into(self, - builder: &mut Builder, - destination: &Lvalue, - block: BasicBlock) - -> BlockAnd<()> { +impl<'tcx> EvalInto<'tcx> for Expr<'tcx> { + fn eval_into<'a>(self, + builder: &mut Builder<'a, 'tcx>, + destination: &Lvalue<'tcx>, + block: BasicBlock) + -> BlockAnd<()> { builder.into_expr(destination, block, self) } } -impl EvalInto for Option> { - fn eval_into(self, - builder: &mut Builder, - destination: &Lvalue, - block: BasicBlock) - -> BlockAnd<()> { +impl<'tcx> EvalInto<'tcx> for Option> { + fn eval_into<'a>(self, + builder: &mut Builder<'a, 'tcx>, + destination: &Lvalue<'tcx>, + block: BasicBlock) + -> BlockAnd<()> { match self { Some(expr) => builder.into(destination, block, expr), - None => block.unit() + None => block.unit(), } } } diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 7f0b3ee3b3..6e0b05d5de 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -15,31 +15,43 @@ use build::{BlockAnd, Builder}; use repr::*; +use rustc::middle::region::CodeExtent; +use rustc::middle::ty::{AdtDef, Ty}; use hair::*; +use syntax::ast::{Name, NodeId}; +use syntax::codemap::Span; // helper functions, broken out by category: mod simplify; mod test; mod util; -impl Builder { +impl<'a,'tcx> Builder<'a,'tcx> { pub fn match_expr(&mut self, - destination: &Lvalue, - span: H::Span, + destination: &Lvalue<'tcx>, + span: Span, mut block: BasicBlock, - discriminant: ExprRef, - arms: Vec>) - -> BlockAnd<()> - { - let discriminant_lvalue = - unpack!(block = self.as_lvalue(block, discriminant)); + discriminant: ExprRef<'tcx>, + arms: Vec>) + -> BlockAnd<()> { + let discriminant_lvalue = unpack!(block = self.as_lvalue(block, discriminant)); + + // Before we do anything, create uninitialized variables with + // suitable extent for all of the bindings in this match. It's + // easiest to do this up front because some of these arms may + // be unreachable or reachable multiple times. + let var_extent = self.extent_of_innermost_scope().unwrap(); + for arm in &arms { + self.declare_bindings(var_extent, arm.patterns[0].clone()); + } - let arm_blocks: Vec = - arms.iter() - .map(|_| self.cfg.start_new_block()) - .collect(); + let mut arm_blocks = ArmBlocks { + blocks: arms.iter() + .map(|_| self.cfg.start_new_block()) + .collect(), + }; - let arm_bodies: Vec> = + let arm_bodies: Vec> = arms.iter() .map(|arm| arm.body.clone()) .collect(); @@ -50,36 +62,34 @@ impl Builder { // highest priority candidate comes last in the list. This the // reverse of the order in which candidates are written in the // source. - let candidates: Vec> = - arms.into_iter() - .zip(arm_blocks.iter()) + let candidates: Vec> = + arms.iter() + .enumerate() .rev() // highest priority comes last - .flat_map(|(arm, &arm_block)| { - let guard = arm.guard; - arm.patterns.into_iter() + .flat_map(|(arm_index, arm)| { + arm.patterns.iter() .rev() - .map(move |pat| (arm_block, pat, guard.clone())) + .map(move |pat| (arm_index, pat.clone(), arm.guard.clone())) }) - .map(|(arm_block, pattern, guard)| { + .map(|(arm_index, pattern, guard)| { Candidate { match_pairs: vec![self.match_pair(discriminant_lvalue.clone(), pattern)], bindings: vec![], guard: guard, - arm_block: arm_block, + arm_index: arm_index, } }) .collect(); // this will generate code to test discriminant_lvalue and // branch to the appropriate arm block - let var_extent = self.extent_of_innermost_scope().unwrap(); - self.match_candidates(span, var_extent, candidates, block); + self.match_candidates(span, &mut arm_blocks, candidates, block); // all the arm blocks will rejoin here let end_block = self.cfg.start_new_block(); - for (arm_body, &arm_block) in arm_bodies.into_iter().zip(arm_blocks.iter()) { - let mut arm_block = arm_block; + for (arm_index, arm_body) in arm_bodies.into_iter().enumerate() { + let mut arm_block = arm_blocks.blocks[arm_index]; unpack!(arm_block = self.into(destination, arm_block, arm_body)); self.cfg.terminate(arm_block, Terminator::Goto { target: end_block }); } @@ -89,11 +99,10 @@ impl Builder { pub fn expr_into_pattern(&mut self, mut block: BasicBlock, - var_extent: H::CodeExtent, // lifetime of vars - irrefutable_pat: PatternRef, - initializer: ExprRef) - -> BlockAnd<()> - { + var_extent: CodeExtent, // lifetime of vars + irrefutable_pat: PatternRef<'tcx>, + initializer: ExprRef<'tcx>) + -> BlockAnd<()> { // optimize the case of `let x = ...` let irrefutable_pat = self.hir.mirror(irrefutable_pat); match irrefutable_pat.kind { @@ -103,31 +112,39 @@ impl Builder { var, ty, subpattern: None } => { - let index = self.declare_binding(var_extent, mutability, name, - var, ty, irrefutable_pat.span); + let index = self.declare_binding(var_extent, + mutability, + name, + var, + ty, + irrefutable_pat.span); let lvalue = Lvalue::Var(index); return self.into(&lvalue, block, initializer); } - _ => { } + _ => {} } let lvalue = unpack!(block = self.as_lvalue(block, initializer)); - self.lvalue_into_pattern(block, var_extent, - PatternRef::Mirror(Box::new(irrefutable_pat)), &lvalue) + self.lvalue_into_pattern(block, + var_extent, + PatternRef::Mirror(Box::new(irrefutable_pat)), + &lvalue) } pub fn lvalue_into_pattern(&mut self, mut block: BasicBlock, - var_extent: H::CodeExtent, - irrefutable_pat: PatternRef, - initializer: &Lvalue) - -> BlockAnd<()> - { + var_extent: CodeExtent, + irrefutable_pat: PatternRef<'tcx>, + initializer: &Lvalue<'tcx>) + -> BlockAnd<()> { + // first, creating the bindings + self.declare_bindings(var_extent, irrefutable_pat.clone()); + // create a dummy candidate - let mut candidate = Candidate:: { - match_pairs: vec![self.match_pair(initializer.clone(), irrefutable_pat)], + let mut candidate = Candidate::<'tcx> { + match_pairs: vec![self.match_pair(initializer.clone(), irrefutable_pat.clone())], bindings: vec![], guard: None, - arm_block: block + arm_index: 0, // since we don't call `match_candidates`, this field is unused }; // Simplify the candidate. Since the pattern is irrefutable, this should @@ -135,119 +152,133 @@ impl Builder { unpack!(block = self.simplify_candidate(block, &mut candidate)); if !candidate.match_pairs.is_empty() { - self.hir.span_bug( - candidate.match_pairs[0].pattern.span, - &format!("match pairs {:?} remaining after simplifying irrefutable pattern", - candidate.match_pairs)); + self.hir.span_bug(candidate.match_pairs[0].pattern.span, + &format!("match pairs {:?} remaining after simplifying \ + irrefutable pattern", + candidate.match_pairs)); } // now apply the bindings, which will also declare the variables - self.bind_matched_candidate(block, var_extent, candidate.bindings); + self.bind_matched_candidate(block, candidate.bindings); block.unit() } - pub fn declare_uninitialized_variables(&mut self, - var_extent: H::CodeExtent, - pattern: PatternRef) - { + pub fn declare_bindings(&mut self, var_extent: CodeExtent, pattern: PatternRef<'tcx>) { let pattern = self.hir.mirror(pattern); match pattern.kind { PatternKind::Binding { mutability, name, mode: _, var, ty, subpattern } => { self.declare_binding(var_extent, mutability, name, var, ty, pattern.span); if let Some(subpattern) = subpattern { - self.declare_uninitialized_variables(var_extent, subpattern); + self.declare_bindings(var_extent, subpattern); } } PatternKind::Array { prefix, slice, suffix } | PatternKind::Slice { prefix, slice, suffix } => { for subpattern in prefix.into_iter().chain(slice).chain(suffix) { - self.declare_uninitialized_variables(var_extent, subpattern); + self.declare_bindings(var_extent, subpattern); } } - PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => { - } + PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {} PatternKind::Deref { subpattern } => { - self.declare_uninitialized_variables(var_extent, subpattern); + self.declare_bindings(var_extent, subpattern); } PatternKind::Leaf { subpatterns } | PatternKind::Variant { subpatterns, .. } => { for subpattern in subpatterns { - self.declare_uninitialized_variables(var_extent, subpattern.pattern); + self.declare_bindings(var_extent, subpattern.pattern); } } } } } +/// List of blocks for each arm (and potentially other metadata in the +/// future). +struct ArmBlocks { + blocks: Vec, +} + #[derive(Clone, Debug)] -struct Candidate { +struct Candidate<'tcx> { // all of these must be satisfied... - match_pairs: Vec>, + match_pairs: Vec>, // ...these bindings established... - bindings: Vec>, + bindings: Vec>, // ...and the guard must be evaluated... - guard: Option>, + guard: Option>, - // ...and then we branch here. - arm_block: BasicBlock, + // ...and then we branch to arm with this index. + arm_index: usize, } #[derive(Clone, Debug)] -struct Binding { - span: H::Span, - source: Lvalue, - name: H::Ident, - var_id: H::VarId, - var_ty: H::Ty, +struct Binding<'tcx> { + span: Span, + source: Lvalue<'tcx>, + name: Name, + var_id: NodeId, + var_ty: Ty<'tcx>, mutability: Mutability, - binding_mode: BindingMode, + binding_mode: BindingMode, } #[derive(Clone, Debug)] -struct MatchPair { +struct MatchPair<'tcx> { // this lvalue... - lvalue: Lvalue, + lvalue: Lvalue<'tcx>, // ... must match this pattern. - pattern: Pattern, + pattern: Pattern<'tcx>, } #[derive(Clone, Debug, PartialEq)] -enum TestKind { +enum TestKind<'tcx> { // test the branches of enum - Switch { adt_def: H::AdtDef }, + Switch { + adt_def: AdtDef<'tcx>, + }, // test for equality - Eq { value: Constant, ty: H::Ty }, + Eq { + value: Literal<'tcx>, + ty: Ty<'tcx>, + }, // test whether the value falls within an inclusive range - Range { lo: Constant, hi: Constant, ty: H::Ty }, + Range { + lo: Literal<'tcx>, + hi: Literal<'tcx>, + ty: Ty<'tcx>, + }, // test length of the slice is equal to len - Len { len: usize, op: BinOp }, + Len { + len: usize, + op: BinOp, + }, } #[derive(Debug)] -struct Test { - span: H::Span, - kind: TestKind, +struct Test<'tcx> { + span: Span, + kind: TestKind<'tcx>, } /////////////////////////////////////////////////////////////////////////// // Main matching algorithm -impl Builder { +impl<'a,'tcx> Builder<'a,'tcx> { fn match_candidates(&mut self, - span: H::Span, - var_extent: H::CodeExtent, - mut candidates: Vec>, + span: Span, + arm_blocks: &mut ArmBlocks, + mut candidates: Vec>, mut block: BasicBlock) { - debug!("matched_candidate(span={:?}, var_extent={:?}, block={:?}, candidates={:?})", - span, var_extent, block, candidates); + debug!("matched_candidate(span={:?}, block={:?}, candidates={:?})", + span, block, candidates); // Start by simplifying candidates. Once this process is // complete, all the match pairs which remain require some @@ -267,9 +298,12 @@ impl Builder { // If so, apply any bindings, test the guard (if any), and // branch to the arm. let candidate = candidates.pop().unwrap(); - match self.bind_and_guard_matched_candidate(block, var_extent, candidate) { - None => { return; } - Some(b) => { block = b; } + if let Some(b) = self.bind_and_guard_matched_candidate(block, arm_blocks, candidate) { + block = b; + } else { + // if None is returned, then any remaining candidates + // are unreachable (at least not through this path). + return; } } @@ -286,7 +320,7 @@ impl Builder { let target_blocks = self.perform_test(block, &match_pair.lvalue, &test); for (outcome, mut target_block) in target_blocks.into_iter().enumerate() { - let applicable_candidates: Vec> = + let applicable_candidates: Vec> = candidates.iter() .filter_map(|candidate| { unpack!(target_block = @@ -297,7 +331,7 @@ impl Builder { candidate)) }) .collect(); - self.match_candidates(span, var_extent, applicable_candidates, target_block); + self.match_candidates(span, arm_blocks, applicable_candidates, target_block); } } @@ -315,15 +349,17 @@ impl Builder { /// MIR). fn bind_and_guard_matched_candidate(&mut self, mut block: BasicBlock, - var_extent: H::CodeExtent, - candidate: Candidate) + arm_blocks: &mut ArmBlocks, + candidate: Candidate<'tcx>) -> Option { - debug!("bind_and_guard_matched_candidate(block={:?}, var_extent={:?}, candidate={:?})", - block, var_extent, candidate); + debug!("bind_and_guard_matched_candidate(block={:?}, candidate={:?})", + block, candidate); debug_assert!(candidate.match_pairs.is_empty()); - self.bind_matched_candidate(block, var_extent, candidate.bindings); + self.bind_matched_candidate(block, candidate.bindings); + + let arm_block = arm_blocks.blocks[candidate.arm_index]; if let Some(guard) = candidate.guard { // the block to branch to if the guard fails; if there is no @@ -331,36 +367,26 @@ impl Builder { let cond = unpack!(block = self.as_operand(block, guard)); let otherwise = self.cfg.start_new_block(); self.cfg.terminate(block, Terminator::If { cond: cond, - targets: [candidate.arm_block, otherwise]}); + targets: [arm_block, otherwise]}); Some(otherwise) } else { - self.cfg.terminate(block, Terminator::Goto { target: candidate.arm_block }); + self.cfg.terminate(block, Terminator::Goto { target: arm_block }); None } } fn bind_matched_candidate(&mut self, block: BasicBlock, - var_extent: H::CodeExtent, - bindings: Vec>) { - debug!("bind_matched_candidate(block={:?}, var_extent={:?}, bindings={:?})", - block, var_extent, bindings); + bindings: Vec>) { + debug!("bind_matched_candidate(block={:?}, bindings={:?})", + block, bindings); // Assign each of the bindings. This may trigger moves out of the candidate. for binding in bindings { - // Create a variable for the `var_id` being bound. In the - // case where there are multiple patterns for a single - // arm, it may already exist. - let var_index = if !self.var_indices.contains_key(&binding.var_id) { - self.declare_binding(var_extent, - binding.mutability, - binding.name, - binding.var_id, - binding.var_ty, - binding.span) - } else { - self.var_indices[&binding.var_id] - }; + // Find the variable for the `var_id` being bound. It + // should have been created by a previous call to + // `declare_bindings`. + let var_index = self.var_indices[&binding.var_id]; let rvalue = match binding.binding_mode { BindingMode::ByValue => @@ -374,19 +400,19 @@ impl Builder { } fn declare_binding(&mut self, - var_extent: H::CodeExtent, + var_extent: CodeExtent, mutability: Mutability, - name: H::Ident, - var_id: H::VarId, - var_ty: H::Ty, - span: H::Span) + name: Name, + var_id: NodeId, + var_ty: Ty<'tcx>, + span: Span) -> u32 { debug!("declare_binding(var_id={:?}, name={:?}, var_ty={:?}, var_extent={:?}, span={:?})", var_id, name, var_ty, var_extent, span); let index = self.var_decls.len(); - self.var_decls.push(VarDecl:: { + self.var_decls.push(VarDecl::<'tcx> { mutability: mutability, name: name, ty: var_ty.clone(), @@ -400,4 +426,3 @@ impl Builder { index } } - diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs index f15b2ed5d4..0267e9b10c 100644 --- a/src/librustc_mir/build/matches/simplify.rs +++ b/src/librustc_mir/build/matches/simplify.rs @@ -29,19 +29,20 @@ use repr::*; use std::mem; -impl Builder { +impl<'a,'tcx> Builder<'a,'tcx> { pub fn simplify_candidate(&mut self, mut block: BasicBlock, - candidate: &mut Candidate) - -> BlockAnd<()> - { + candidate: &mut Candidate<'tcx>) + -> BlockAnd<()> { // repeatedly simplify match pairs until fixed point is reached loop { let match_pairs = mem::replace(&mut candidate.match_pairs, vec![]); let mut progress = match_pairs.len(); // count how many were simplified for match_pair in match_pairs { match self.simplify_match_pair(block, match_pair, candidate) { - Ok(b) => { block = b; } + Ok(b) => { + block = b; + } Err(match_pair) => { candidate.match_pairs.push(match_pair); progress -= 1; // this one was not simplified @@ -56,14 +57,14 @@ impl Builder { /// Tries to simplify `match_pair`, returning true if /// successful. If successful, new match pairs and bindings will - /// have been pushed into the candidate. On failure (if false is - /// returned), no changes are made to candidate. + /// have been pushed into the candidate. If no simplification is + /// possible, Err is returned and no changes are made to + /// candidate. fn simplify_match_pair(&mut self, mut block: BasicBlock, - match_pair: MatchPair, - candidate: &mut Candidate) - -> Result> // returns Err() if cannot simplify - { + match_pair: MatchPair<'tcx>, + candidate: &mut Candidate<'tcx>) + -> Result> { match match_pair.pattern.kind { PatternKind::Wild(..) => { // nothing left to do @@ -114,8 +115,8 @@ impl Builder { PatternKind::Leaf { subpatterns } => { // tuple struct, match subpats (if any) - candidate.match_pairs.extend( - self.field_match_pairs(match_pair.lvalue, subpatterns)); + candidate.match_pairs + .extend(self.field_match_pairs(match_pair.lvalue, subpatterns)); Ok(block) } @@ -128,4 +129,3 @@ impl Builder { } } } - diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 2d0a6e61be..d5745eb28c 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -19,12 +19,13 @@ use build::{BlockAnd, Builder}; use build::matches::{Candidate, MatchPair, Test, TestKind}; use hair::*; use repr::*; +use syntax::codemap::Span; -impl Builder { +impl<'a,'tcx> Builder<'a,'tcx> { /// Identifies what test is needed to decide if `match_pair` is applicable. /// /// It is a bug to call this with a simplifyable pattern. - pub fn test(&mut self, match_pair: &MatchPair) -> Test { + pub fn test(&mut self, match_pair: &MatchPair<'tcx>) -> Test<'tcx> { match match_pair.pattern.kind { PatternKind::Variant { ref adt_def, variant_index: _, subpatterns: _ } => { Test { @@ -33,26 +34,34 @@ impl Builder { } } - PatternKind::Constant { ref expr } => { - let expr = self.as_constant(expr.clone()); + PatternKind::Constant { ref value } => { Test { span: match_pair.pattern.span, - kind: TestKind::Eq { value: expr, ty: match_pair.pattern.ty.clone() }, + kind: TestKind::Eq { + value: value.clone(), + ty: match_pair.pattern.ty.clone(), + }, } } PatternKind::Range { ref lo, ref hi } => { - let lo = self.as_constant(lo.clone()); - let hi = self.as_constant(hi.clone()); Test { span: match_pair.pattern.span, - kind: TestKind::Range { lo: lo, hi: hi, ty: match_pair.pattern.ty.clone() }, + kind: TestKind::Range { + lo: lo.clone(), + hi: hi.clone(), + ty: match_pair.pattern.ty.clone(), + }, } } PatternKind::Slice { ref prefix, ref slice, ref suffix } => { let len = prefix.len() + suffix.len(); - let op = if slice.is_some() {BinOp::Ge} else {BinOp::Eq}; + let op = if slice.is_some() { + BinOp::Ge + } else { + BinOp::Eq + }; Test { span: match_pair.pattern.span, kind: TestKind::Len { len: len, op: op }, @@ -72,8 +81,8 @@ impl Builder { /// Generates the code to perform a test. pub fn perform_test(&mut self, block: BasicBlock, - lvalue: &Lvalue, - test: &Test) + lvalue: &Lvalue<'tcx>, + test: &Test<'tcx>) -> Vec { match test.kind.clone() { TestKind::Switch { adt_def } => { @@ -90,22 +99,28 @@ impl Builder { TestKind::Eq { value, ty } => { // call PartialEq::eq(discrim, constant) - let constant = self.push_constant(block, test.span, ty.clone(), value); + let constant = self.push_literal(block, test.span, ty.clone(), value); let item_ref = self.hir.partial_eq(ty); self.call_comparison_fn(block, test.span, item_ref, lvalue.clone(), constant) } TestKind::Range { lo, hi, ty } => { // Test `v` by computing `PartialOrd::le(lo, v) && PartialOrd::le(v, hi)`. - let lo = self.push_constant(block, test.span, ty.clone(), lo); - let hi = self.push_constant(block, test.span, ty.clone(), hi); + let lo = self.push_literal(block, test.span, ty.clone(), lo); + let hi = self.push_literal(block, test.span, ty.clone(), hi); let item_ref = self.hir.partial_le(ty); - let lo_blocks = - self.call_comparison_fn(block, test.span, item_ref.clone(), lo, lvalue.clone()); + let lo_blocks = self.call_comparison_fn(block, + test.span, + item_ref.clone(), + lo, + lvalue.clone()); - let hi_blocks = - self.call_comparison_fn(lo_blocks[0], test.span, item_ref, lvalue.clone(), hi); + let hi_blocks = self.call_comparison_fn(lo_blocks[0], + test.span, + item_ref, + lvalue.clone(), + hi); let failure = self.cfg.start_new_block(); self.cfg.terminate(lo_blocks[1], Terminator::Goto { target: failure }); @@ -119,20 +134,18 @@ impl Builder { let (actual, result) = (self.temp(usize_ty), self.temp(bool_ty)); // actual = len(lvalue) - self.cfg.push_assign( - block, test.span, - &actual, Rvalue::Len(lvalue.clone())); + self.cfg.push_assign(block, test.span, &actual, Rvalue::Len(lvalue.clone())); // expected = - let expected = - self.push_usize(block, test.span, len); + let expected = self.push_usize(block, test.span, len); // result = actual == expected OR result = actual < expected - self.cfg.push_assign( - block, test.span, - &result, Rvalue::BinaryOp(op, - Operand::Consume(actual), - Operand::Consume(expected))); + self.cfg.push_assign(block, + test.span, + &result, + Rvalue::BinaryOp(op, + Operand::Consume(actual), + Operand::Consume(expected))); // branch based on result let target_blocks: Vec<_> = vec![self.cfg.start_new_block(), @@ -149,13 +162,12 @@ impl Builder { fn call_comparison_fn(&mut self, block: BasicBlock, - span: H::Span, - item_ref: ItemRef, - lvalue1: Lvalue, - lvalue2: Lvalue) + span: Span, + item_ref: ItemRef<'tcx>, + lvalue1: Lvalue<'tcx>, + lvalue2: Lvalue<'tcx>) -> Vec { - let target_blocks = vec![self.cfg.start_new_block(), - self.cfg.start_new_block()]; + let target_blocks = vec![self.cfg.start_new_block(), self.cfg.start_new_block()]; let bool_ty = self.hir.bool_ty(); let eq_result = self.temp(bool_ty); @@ -175,7 +187,7 @@ impl Builder { self.cfg.terminate(call_blocks[0], Terminator::If { cond: Operand::Consume(eq_result), - targets: [target_blocks[0], target_blocks[1]] + targets: [target_blocks[0], target_blocks[1]], }); target_blocks @@ -194,11 +206,11 @@ impl Builder { /// @ 22])`. pub fn candidate_under_assumption(&mut self, mut block: BasicBlock, - test_lvalue: &Lvalue, - test_kind: &TestKind, + test_lvalue: &Lvalue<'tcx>, + test_kind: &TestKind<'tcx>, test_outcome: usize, - candidate: &Candidate) - -> BlockAnd>> { + candidate: &Candidate<'tcx>) + -> BlockAnd>> { let candidate = candidate.clone(); let match_pairs = candidate.match_pairs; let result = unpack!(block = self.match_pairs_under_assumption(block, @@ -208,7 +220,7 @@ impl Builder { match_pairs)); block.and(match result { Some(match_pairs) => Some(Candidate { match_pairs: match_pairs, ..candidate }), - None => None + None => None, }) } @@ -216,11 +228,11 @@ impl Builder { /// work of transforming the list of match pairs. fn match_pairs_under_assumption(&mut self, mut block: BasicBlock, - test_lvalue: &Lvalue, - test_kind: &TestKind, + test_lvalue: &Lvalue<'tcx>, + test_kind: &TestKind<'tcx>, test_outcome: usize, - match_pairs: Vec>) - -> BlockAnd>>> { + match_pairs: Vec>) + -> BlockAnd>>> { let mut result = vec![]; for match_pair in match_pairs { @@ -279,9 +291,9 @@ impl Builder { /// It is a bug to call this with a simplifyable pattern. pub fn consequent_match_pairs_under_assumption(&mut self, mut block: BasicBlock, - match_pair: MatchPair, + match_pair: MatchPair<'tcx>, test_outcome: usize) - -> BlockAnd>>> { + -> BlockAnd>>> { match match_pair.pattern.kind { PatternKind::Variant { adt_def, variant_index, subpatterns } => { if test_outcome != variant_index { @@ -339,9 +351,8 @@ impl Builder { } } - fn error_simplifyable(&mut self, match_pair: &MatchPair) -> ! { - self.hir.span_bug( - match_pair.pattern.span, - &format!("simplifyable pattern found: {:?}", match_pair.pattern)) + fn error_simplifyable(&mut self, match_pair: &MatchPair<'tcx>) -> ! { + self.hir.span_bug(match_pair.pattern.span, + &format!("simplifyable pattern found: {:?}", match_pair.pattern)) } } diff --git a/src/librustc_mir/build/matches/util.rs b/src/librustc_mir/build/matches/util.rs index 65a0886866..28925f9b38 100644 --- a/src/librustc_mir/build/matches/util.rs +++ b/src/librustc_mir/build/matches/util.rs @@ -14,11 +14,11 @@ use hair::*; use repr::*; use std::u32; -impl Builder { +impl<'a,'tcx> Builder<'a,'tcx> { pub fn field_match_pairs(&mut self, - lvalue: Lvalue, - subpatterns: Vec>) - -> Vec> { + lvalue: Lvalue<'tcx>, + subpatterns: Vec>) + -> Vec> { subpatterns.into_iter() .map(|fieldpat| { let lvalue = lvalue.clone().field(fieldpat.field); @@ -27,7 +27,10 @@ impl Builder { .collect() } - pub fn match_pair(&mut self, lvalue: Lvalue, pattern: PatternRef) -> MatchPair { + pub fn match_pair(&mut self, + lvalue: Lvalue<'tcx>, + pattern: PatternRef<'tcx>) + -> MatchPair<'tcx> { let pattern = self.hir.mirror(pattern); MatchPair::new(lvalue, pattern) } @@ -47,23 +50,24 @@ impl Builder { /// /// and creates a match pair `tmp0 @ s` pub fn prefix_suffix_slice(&mut self, - match_pairs: &mut Vec>, + match_pairs: &mut Vec>, block: BasicBlock, - lvalue: Lvalue, - prefix: Vec>, - opt_slice: Option>, - suffix: Vec>) - -> BlockAnd<()> - { + lvalue: Lvalue<'tcx>, + prefix: Vec>, + opt_slice: Option>, + suffix: Vec>) + -> BlockAnd<()> { // If there is a `..P` pattern, create a temporary `t0` for // the slice and then a match pair `t0 @ P`: if let Some(slice) = opt_slice { let slice = self.hir.mirror(slice); let prefix_len = prefix.len(); let suffix_len = suffix.len(); - let rvalue = Rvalue::Slice { input: lvalue.clone(), - from_start: prefix_len, - from_end: suffix_len }; + let rvalue = Rvalue::Slice { + input: lvalue.clone(), + from_start: prefix_len, + from_end: suffix_len, + }; let temp = self.temp(slice.ty.clone()); // no need to schedule drop, temp is always copy self.cfg.push_assign(block, slice.span, &temp, rvalue); match_pairs.push(MatchPair::new(temp, slice)); @@ -76,11 +80,10 @@ impl Builder { /// Helper for `prefix_suffix_slice` which just processes the prefix and suffix. fn prefix_suffix(&mut self, - match_pairs: &mut Vec>, - lvalue: Lvalue, - prefix: Vec>, - suffix: Vec>) - { + match_pairs: &mut Vec>, + lvalue: Lvalue<'tcx>, + prefix: Vec>, + suffix: Vec>) { let min_length = prefix.len() + suffix.len(); assert!(min_length < u32::MAX as usize); let min_length = min_length as u32; @@ -118,8 +121,11 @@ impl Builder { } } -impl MatchPair { - pub fn new(lvalue: Lvalue, pattern: Pattern) -> MatchPair { - MatchPair { lvalue: lvalue, pattern: pattern } +impl<'tcx> MatchPair<'tcx> { + pub fn new(lvalue: Lvalue<'tcx>, pattern: Pattern<'tcx>) -> MatchPair<'tcx> { + MatchPair { + lvalue: lvalue, + pattern: pattern, + } } } diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index 1c44988e4b..86b6df19b7 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -14,16 +14,17 @@ use build::Builder; use hair::*; use repr::*; - +use rustc::middle::ty::Ty; use std::u32; +use syntax::codemap::Span; -impl Builder { +impl<'a,'tcx> Builder<'a,'tcx> { /// Add a new temporary value of type `ty` storing the result of /// evaluating `expr`. /// /// NB: **No cleanup is scheduled for this temporary.** You should /// call `schedule_drop` once the temporary is initialized. - pub fn temp(&mut self, ty: H::Ty) -> Lvalue { + pub fn temp(&mut self, ty: Ty<'tcx>) -> Lvalue<'tcx> { let index = self.temp_decls.len(); self.temp_decls.push(TempDecl { ty: ty }); assert!(index < (u32::MAX) as usize); @@ -33,46 +34,44 @@ impl Builder { lvalue } - pub fn push_constant(&mut self, - block: BasicBlock, - span: H::Span, - ty: H::Ty, - constant: Constant) - -> Lvalue { - let temp = self.temp(ty); + pub fn push_literal(&mut self, + block: BasicBlock, + span: Span, + ty: Ty<'tcx>, + literal: Literal<'tcx>) + -> Lvalue<'tcx> { + let temp = self.temp(ty.clone()); + let constant = Constant { + span: span, + ty: ty, + literal: literal, + }; self.cfg.push_assign_constant(block, span, &temp, constant); temp } - pub fn push_usize(&mut self, - block: BasicBlock, - span: H::Span, - value: usize) - -> Lvalue { + pub fn push_usize(&mut self, block: BasicBlock, span: Span, value: usize) -> Lvalue<'tcx> { let usize_ty = self.hir.usize_ty(); let temp = self.temp(usize_ty); self.cfg.push_assign_constant( block, span, &temp, Constant { span: span, - kind: ConstantKind::Literal(Literal::Uint { bits: IntegralBits::BSize, - value: value as u64 }), + ty: self.hir.usize_ty(), + literal: self.hir.usize_literal(value), }); temp } pub fn push_item_ref(&mut self, block: BasicBlock, - span: H::Span, - item_ref: ItemRef) - -> Lvalue { - let constant = Constant { - span: span, - kind: ConstantKind::Literal(Literal::Item { - def_id: item_ref.def_id, - substs: item_ref.substs - }) + span: Span, + item_ref: ItemRef<'tcx>) + -> Lvalue<'tcx> { + let literal = Literal::Item { + def_id: item_ref.def_id, + substs: item_ref.substs, }; - self.push_constant(block, span, item_ref.ty, constant) + self.push_literal(block, span, item_ref.ty, literal) } } diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 9d00044c66..857540e210 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -8,24 +8,30 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use hair::{self, Hair}; +use hair; +use rustc::middle::region::CodeExtent; +use rustc::middle::ty::Ty; use rustc_data_structures::fnv::FnvHashMap; +use rustc_front::hir; use repr::*; - -struct Builder { - hir: H, - extents: FnvHashMap>, - cfg: CFG, - scopes: Vec>, - loop_scopes: Vec>, - unit_temp: Lvalue, - var_decls: Vec>, - var_indices: FnvHashMap, - temp_decls: Vec>, +use syntax::ast; +use syntax::codemap::Span; +use tcx::{Cx, PatNode}; + +struct Builder<'a, 'tcx: 'a> { + hir: Cx<'a, 'tcx>, + extents: FnvHashMap>, + cfg: CFG<'tcx>, + scopes: Vec>, + loop_scopes: Vec, + unit_temp: Lvalue<'tcx>, + var_decls: Vec>, + var_indices: FnvHashMap, + temp_decls: Vec>, } -struct CFG { - basic_blocks: Vec> +struct CFG<'tcx> { + basic_blocks: Vec>, } /////////////////////////////////////////////////////////////////////////// @@ -69,18 +75,18 @@ macro_rules! unpack { /////////////////////////////////////////////////////////////////////////// // construct() -- the main entry point for building MIR for a function -pub fn construct(mut hir: H, - _span: H::Span, - implicit_arguments: Vec, - explicit_arguments: Vec<(H::Ty, H::Pattern)>, - argument_extent: H::CodeExtent, - ast_block: H::Block) - -> Mir { +pub fn construct<'a, 'tcx>(mut hir: Cx<'a, 'tcx>, + _span: Span, + implicit_arguments: Vec>, + explicit_arguments: Vec<(Ty<'tcx>, PatNode<'tcx>)>, + argument_extent: CodeExtent, + ast_block: &'tcx hir::Block) + -> Mir<'tcx> { let cfg = CFG { basic_blocks: vec![] }; // it's handy to have a temporary of type `()` sometimes, so make // one from the start and keep it available - let temp_decls = vec![TempDecl:: { ty: hir.unit_ty() }]; + let temp_decls = vec![TempDecl::<'tcx> { ty: hir.unit_ty() }]; let unit_temp = Lvalue::Temp(0); let mut builder = Builder { @@ -109,7 +115,7 @@ pub fn construct(mut hir: H, builder.cfg.terminate(block, Terminator::Goto { target: END_BLOCK }); builder.cfg.terminate(END_BLOCK, Terminator::Return); - Mir { + Mir { basic_blocks: builder.cfg.basic_blocks, extents: builder.extents, var_decls: builder.var_decls, @@ -118,14 +124,14 @@ pub fn construct(mut hir: H, } } -impl Builder { +impl<'a,'tcx> Builder<'a,'tcx> { fn args_and_body(&mut self, mut block: BasicBlock, - implicit_arguments: Vec, - explicit_arguments: Vec<(H::Ty, H::Pattern)>, - argument_extent: H::CodeExtent, - ast_block: H::Block) - -> BlockAnd>> + implicit_arguments: Vec>, + explicit_arguments: Vec<(Ty<'tcx>, PatNode<'tcx>)>, + argument_extent: CodeExtent, + ast_block: &'tcx hir::Block) + -> BlockAnd>> { self.in_scope(argument_extent, block, |this| { let arg_decls = { @@ -171,4 +177,3 @@ mod matches; mod misc; mod scope; mod stmt; - diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index 87a4731ac7..cecd610ff7 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -12,7 +12,7 @@ Managing the scope stack. The scopes are tied to lexical scopes, so as we descend the HAIR, we push a scope on the stack, translate ite contents, and then pop it off. Every scope is named by a -`H::CodeExtent`. +`CodeExtent`. ### SEME Regions @@ -23,7 +23,7 @@ via a `break` or `return` or just by fallthrough, that marks an exit from the scope. Each lexical scope thus corresponds to a single-entry, multiple-exit (SEME) region in the control-flow graph. -For now, we keep a mapping from each `H::CodeExtent` to its +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 @@ -87,37 +87,41 @@ should go to. */ use build::{BlockAnd, Builder, CFG}; -use hair::Hair; use repr::*; +use rustc::middle::region::CodeExtent; +use rustc::middle::ty::Ty; +use syntax::codemap::Span; -pub struct Scope { - extent: H::CodeExtent, +pub struct Scope<'tcx> { + extent: CodeExtent, exits: Vec, - drops: Vec<(DropKind, H::Span, Lvalue)>, + drops: Vec<(DropKind, Span, Lvalue<'tcx>)>, cached_block: Option, } #[derive(Clone, Debug)] -pub struct LoopScope { - pub extent: H::CodeExtent, // extent of the loop +pub struct LoopScope { + pub extent: CodeExtent, // extent of the loop pub continue_block: BasicBlock, // where to go on a `loop` - pub break_block: BasicBlock, // where to go on a `break + pub break_block: BasicBlock, // where to go on a `break } -impl Builder { +impl<'a,'tcx> Builder<'a,'tcx> { /// Start a loop scope, which tracks where `continue` and `break` /// should branch to. See module comment for more details. - pub fn in_loop_scope(&mut self, - loop_block: BasicBlock, - break_block: BasicBlock, - f: F) - -> BlockAnd - where F: FnOnce(&mut Builder) -> BlockAnd + pub fn in_loop_scope(&mut self, + loop_block: BasicBlock, + break_block: BasicBlock, + f: F) + -> BlockAnd + where F: FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd { let extent = self.extent_of_innermost_scope().unwrap(); - let loop_scope = LoopScope:: { extent: extent.clone(), - continue_block: loop_block, - break_block: break_block }; + let loop_scope = LoopScope { + extent: extent.clone(), + continue_block: loop_block, + break_block: break_block, + }; self.loop_scopes.push(loop_scope); let r = f(self); assert!(self.loop_scopes.pop().unwrap().extent == extent); @@ -126,12 +130,8 @@ impl Builder { /// Start a scope. The closure `f` should translate the contents /// of the scope. See module comment for more details. - pub fn in_scope(&mut self, - extent: H::CodeExtent, - block: BasicBlock, - f: F) - -> BlockAnd - where F: FnOnce(&mut Builder) -> BlockAnd + pub fn in_scope(&mut self, extent: CodeExtent, block: BasicBlock, f: F) -> BlockAnd + where F: FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd { debug!("in_scope(extent={:?}, block={:?})", extent, block); @@ -171,18 +171,24 @@ impl Builder { /// exit points. fn graph_extent(&self, entry: ExecutionPoint, exits: Vec) -> GraphExtent { if exits.len() == 1 && entry.block == exits[0].block { - GraphExtent { entry: entry, exit: GraphExtentExit::Statement(exits[0].statement) } + GraphExtent { + entry: entry, + exit: GraphExtentExit::Statement(exits[0].statement), + } } else { - GraphExtent { entry: entry, exit: GraphExtentExit::Points(exits) } + GraphExtent { + entry: entry, + exit: GraphExtentExit::Points(exits), + } } } /// Finds the loop scope for a given label. This is used for /// resolving `break` and `continue`. pub fn find_loop_scope(&mut self, - span: H::Span, - label: Option) - -> LoopScope { + span: Span, + label: Option) + -> LoopScope { let loop_scope = match label { None => { @@ -202,7 +208,7 @@ impl Builder { match loop_scope { Some(loop_scope) => loop_scope.clone(), - None => self.hir.span_bug(span, "no enclosing loop scope found?") + None => self.hir.span_bug(span, "no enclosing loop scope found?"), } } @@ -211,8 +217,8 @@ impl Builder { /// needed, as well as tracking this exit for the SEME region. See /// module comment for details. pub fn exit_scope(&mut self, - span: H::Span, - extent: H::CodeExtent, + span: Span, + extent: CodeExtent, block: BasicBlock, target: BasicBlock) { let popped_scopes = @@ -249,12 +255,11 @@ impl Builder { /// Indicates that `lvalue` should be dropped on exit from /// `extent`. pub fn schedule_drop(&mut self, - span: H::Span, - extent: H::CodeExtent, + span: Span, + extent: CodeExtent, kind: DropKind, - lvalue: &Lvalue, - lvalue_ty: H::Ty) - { + lvalue: &Lvalue<'tcx>, + lvalue_ty: Ty<'tcx>) { if self.hir.needs_drop(lvalue_ty, span) { match self.scopes.iter_mut().rev().find(|s| s.extent == extent) { Some(scope) => { @@ -267,18 +272,16 @@ impl Builder { } } - pub fn extent_of_innermost_scope(&self) -> Option { + pub fn extent_of_innermost_scope(&self) -> Option { self.scopes.last().map(|scope| scope.extent) } - pub fn extent_of_outermost_scope(&self) -> Option { + pub fn extent_of_outermost_scope(&self) -> Option { self.scopes.first().map(|scope| scope.extent) } } -fn diverge_cleanup_helper(cfg: &mut CFG, - scopes: &mut [Scope]) - -> BasicBlock { +fn diverge_cleanup_helper<'tcx>(cfg: &mut CFG<'tcx>, scopes: &mut [Scope<'tcx>]) -> BasicBlock { let len = scopes.len(); if len == 0 { diff --git a/src/librustc_mir/build/stmt.rs b/src/librustc_mir/build/stmt.rs index 9d5a83154d..01fda2498f 100644 --- a/src/librustc_mir/build/stmt.rs +++ b/src/librustc_mir/build/stmt.rs @@ -12,15 +12,15 @@ use build::{BlockAnd, Builder}; use hair::*; use repr::*; -impl Builder { - pub fn stmts(&mut self, mut block: BasicBlock, stmts: Vec>) -> BlockAnd<()> { +impl<'a,'tcx> Builder<'a,'tcx> { + pub fn stmts(&mut self, mut block: BasicBlock, stmts: Vec>) -> BlockAnd<()> { for stmt in stmts { unpack!(block = self.stmt(block, stmt)); } block.unit() } - pub fn stmt(&mut self, mut block: BasicBlock, stmt: StmtRef) -> BlockAnd<()> { + pub fn stmt(&mut self, mut block: BasicBlock, stmt: StmtRef<'tcx>) -> BlockAnd<()> { let this = self; let Stmt { span, kind } = this.hir.mirror(stmt); match kind { @@ -40,7 +40,7 @@ impl Builder { StmtKind::Let { remainder_scope, init_scope, pattern, initializer: None, stmts } => { this.in_scope(remainder_scope, block, |this| { unpack!(block = this.in_scope(init_scope, block, |this| { - this.declare_uninitialized_variables(remainder_scope, pattern); + this.declare_bindings(remainder_scope, pattern); block.unit() })); this.stmts(block, stmts) diff --git a/src/librustc_mir/graphviz/mod.rs b/src/librustc_mir/graphviz/mod.rs index 01ccf20ae0..9da05a27e8 100644 --- a/src/librustc_mir/graphviz/mod.rs +++ b/src/librustc_mir/graphviz/mod.rs @@ -9,7 +9,6 @@ // except according to those terms. use dot; -use hair::Hair; use repr::*; use std::borrow::IntoCow; @@ -20,7 +19,7 @@ pub struct EdgeIndex { index: usize, } -impl<'a,H:Hair> dot::Labeller<'a, BasicBlock, EdgeIndex> for Mir { +impl<'a,'tcx> dot::Labeller<'a, BasicBlock, EdgeIndex> for Mir<'tcx> { fn graph_id(&'a self) -> dot::Id<'a> { dot::Id::new("Mir").unwrap() } @@ -62,7 +61,7 @@ impl<'a,H:Hair> dot::Labeller<'a, BasicBlock, EdgeIndex> for Mir { } } -impl<'a,H:Hair> dot::GraphWalk<'a, BasicBlock, EdgeIndex> for Mir { +impl<'a,'tcx> dot::GraphWalk<'a, BasicBlock, EdgeIndex> for Mir<'tcx> { fn nodes(&'a self) -> dot::Nodes<'a, BasicBlock> { self.all_basic_blocks().into_cow() } @@ -71,15 +70,18 @@ impl<'a,H:Hair> dot::GraphWalk<'a, BasicBlock, EdgeIndex> for Mir { self.all_basic_blocks() .into_iter() .flat_map(|source| { - self.basic_block_data(source).terminator - .successors() - .iter() - .enumerate() - .map(move |(index, &target)| { - EdgeIndex { source: source, - target: target, - index: index } - }) + self.basic_block_data(source) + .terminator + .successors() + .iter() + .enumerate() + .map(move |(index, &target)| { + EdgeIndex { + source: source, + target: target, + index: index, + } + }) }) .collect::>() .into_cow() @@ -119,7 +121,10 @@ fn all_to_subscript(header: &str, mut text: String) -> String { /// Returns an updated string if changes were made, else None. fn to_subscript1(header: &str, text: &str, offset: &mut usize) -> Option { let a = match text[*offset..].find(header) { - None => { *offset = text.len(); return None; } + None => { + *offset = text.len(); + return None; + } Some(a) => a + *offset, }; @@ -142,8 +147,12 @@ fn all_to_subscript(header: &str, mut text: String) -> String { result.push_str(&text[..b]); while let Some(c) = chars.next() { - if c == ')' { break; } - if !c.is_digit(10) { return None; } + if c == ')' { + break; + } + if !c.is_digit(10) { + return None; + } // 0x208 is _0 in unicode, 0x209 is _1, etc const SUBSCRIPTS: &'static str = "₀₁₂₃₄₅₆₇₈₉"; diff --git a/src/librustc_mir/hair.rs b/src/librustc_mir/hair.rs index c63a034833..641cbae4be 100644 --- a/src/librustc_mir/hair.rs +++ b/src/librustc_mir/hair.rs @@ -15,135 +15,78 @@ //! structures. use repr::{BinOp, BorrowKind, Field, Literal, Mutability, UnOp}; -use std::fmt::Debug; -use std::hash::Hash; - -pub trait Hair: Sized+Debug+Clone+Eq+Hash { // (*) - - // (*) the `Sized` and Debug` bounds are the only ones that really - // make sense. The rest are just there so that we can - // `#[derive(Clone)]` on things that are parameterized over - // `H:HAIR`. It's kind of lame. - - type VarId: Copy+Debug+Eq+Hash; // e.g., NodeId for a variable - type DefId: Copy+Debug+Eq+Hash; // e.g., DefId - type AdtDef: Copy+Debug+Eq+Hash; // e.g., AdtDef<'tcx> - type Name: Copy+Debug+Eq+Hash; // e.g., ast::Name - type Ident: Copy+Debug+Eq+Hash; // e.g., ast::Ident - type InternedString: Clone+Debug+Eq+Hash; // e.g., InternedString - type Bytes: Clone+Debug+Eq+Hash; // e.g., Rc> - type Span: Copy+Debug+Eq; // e.g., syntax::codemap::Span - type Projection: Clone+Debug+Eq; // e.g., ty::ProjectionTy<'tcx> - type Substs: Clone+Debug+Eq; // e.g., substs::Substs<'tcx> - type ClosureSubsts: Clone+Debug+Eq; // e.g., ty::ClosureSubsts<'tcx> - type Ty: Clone+Debug+Eq; // e.g., ty::Ty<'tcx> - type Region: Copy+Debug; // e.g., ty::Region - type CodeExtent: Copy+Debug+Hash+Eq; // e.g., region::CodeExtent - type Pattern: Clone+Debug+Mirror>; // e.g., &P - type Expr: Clone+Debug+Mirror>; // e.g., &P - type Stmt: Clone+Debug+Mirror>; // e.g., &P - type Block: Clone+Debug+Mirror>; // e.g., &P - type InlineAsm: Clone+Debug+Eq+Hash; // e.g., ast::InlineAsm - - /// Normalizes `ast` into the appropriate `mirror` type. - fn mirror>(&mut self, ast: M) -> M::Output { - ast.make_mirror(self) - } - - /// Returns the unit type `()` - fn unit_ty(&mut self) -> Self::Ty; - - /// Returns the type `usize`. - fn usize_ty(&mut self) -> Self::Ty; - - /// Returns the type `bool`. - fn bool_ty(&mut self) -> Self::Ty; - - /// Returns a reference to `PartialEq::::eq` - fn partial_eq(&mut self, ty: Self::Ty) -> ItemRef; - - /// Returns a reference to `PartialOrd::::le` - fn partial_le(&mut self, ty: Self::Ty) -> ItemRef; - - /// Returns the number of variants for the given enum - fn num_variants(&mut self, adt: Self::AdtDef) -> usize; - - fn fields(&mut self, adt: Self::AdtDef, variant_index: usize) -> Vec>; - - /// true if a value of type `ty` (may) need to be dropped; this - /// may return false even for non-Copy types if there is no - /// destructor to execute. If correct result is not known, may be - /// approximated by returning `true`; this will result in more - /// drops but not incorrect code. - fn needs_drop(&mut self, ty: Self::Ty, span: Self::Span) -> bool; - - /// Report an internal inconsistency. - fn span_bug(&mut self, span: Self::Span, message: &str) -> !; -} +use rustc::middle::def_id::DefId; +use rustc::middle::region::CodeExtent; +use rustc::middle::subst::Substs; +use rustc::middle::ty::{AdtDef, ClosureSubsts, Region, Ty}; +use rustc_front::hir; +use syntax::ast; +use syntax::codemap::Span; +use tcx::{Cx, PatNode}; #[derive(Clone, Debug)] -pub struct ItemRef { - pub ty: H::Ty, - pub def_id: H::DefId, - pub substs: H::Substs, +pub struct ItemRef<'tcx> { + pub ty: Ty<'tcx>, + pub def_id: DefId, + pub substs: &'tcx Substs<'tcx>, } #[derive(Clone, Debug)] -pub struct Block { - pub extent: H::CodeExtent, - pub span: H::Span, - pub stmts: Vec>, - pub expr: Option>, +pub struct Block<'tcx> { + pub extent: CodeExtent, + pub span: Span, + pub stmts: Vec>, + pub expr: Option>, } #[derive(Clone, Debug)] -pub enum StmtRef { - Hair(H::Stmt), - Mirror(Box>), +pub enum StmtRef<'tcx> { + Hair(&'tcx hir::Stmt), + Mirror(Box>), } #[derive(Clone, Debug)] -pub struct Stmt { - pub span: H::Span, - pub kind: StmtKind, +pub struct Stmt<'tcx> { + pub span: Span, + pub kind: StmtKind<'tcx>, } #[derive(Clone, Debug)] -pub enum StmtKind { +pub enum StmtKind<'tcx> { Expr { /// scope for this statement; may be used as lifetime of temporaries - scope: H::CodeExtent, + scope: CodeExtent, /// expression being evaluated in this statement - expr: ExprRef + expr: ExprRef<'tcx>, }, Let { /// scope for variables bound in this let; covers this and /// remaining statements in block - remainder_scope: H::CodeExtent, + remainder_scope: CodeExtent, /// scope for the initialization itself; might be used as /// lifetime of temporaries - init_scope: H::CodeExtent, + init_scope: CodeExtent, /// let = ... - pattern: PatternRef, + pattern: PatternRef<'tcx>, /// let pat = ... - initializer: Option>, + initializer: Option>, /// let pat = init; - stmts: Vec> + stmts: Vec>, }, } -// The Hair trait implementor translates their expressions (`H::Expr`) +// The Hair trait implementor translates their expressions (`&'tcx H::Expr`) // into instances of this `Expr` enum. This translation can be done // basically as lazilly or as eagerly as desired: every recursive -// reference to an expression in this enum is an `ExprRef`, which +// reference to an expression in this enum is an `ExprRef<'tcx>`, which // may in turn be another instance of this enum (boxed), or else an -// untranslated `H::Expr`. Note that instances of `Expr` are very +// untranslated `&'tcx H::Expr`. Note that instances of `Expr` are very // shortlived. They are created by `Hair::to_expr`, analyzed and // converted into MIR, and then discarded. // @@ -153,180 +96,284 @@ pub enum StmtKind { // example, method calls and overloaded operators are absent: they are // expected to be converted into `Expr::Call` instances. #[derive(Clone, Debug)] -pub struct Expr { +pub struct Expr<'tcx> { // type of this expression - pub ty: H::Ty, + pub ty: Ty<'tcx>, // lifetime of this expression if it should be spilled into a // temporary; should be None only if in a constant context - pub temp_lifetime: Option, + pub temp_lifetime: Option, // span of the expression in the source - pub span: H::Span, + pub span: Span, // kind of expression - pub kind: ExprKind, + pub kind: ExprKind<'tcx>, } #[derive(Clone, Debug)] -pub enum ExprKind { - Scope { extent: H::CodeExtent, value: ExprRef }, - Paren { arg: ExprRef }, // ugh. should be able to remove this! - Box { place: Option>, value: ExprRef }, - Call { fun: ExprRef, args: Vec> }, - Deref { arg: ExprRef }, // NOT overloaded! - Binary { op: BinOp, lhs: ExprRef, rhs: ExprRef }, // NOT overloaded! - LogicalOp { op: LogicalOp, lhs: ExprRef, rhs: ExprRef }, - Unary { op: UnOp, arg: ExprRef }, // NOT overloaded! - Cast { source: ExprRef }, - ReifyFnPointer { source: ExprRef }, - UnsafeFnPointer { source: ExprRef }, - Unsize { source: ExprRef }, - If { condition: ExprRef, then: ExprRef, otherwise: Option> }, - Loop { condition: Option>, body: ExprRef, }, - Match { discriminant: ExprRef, arms: Vec> }, - Block { body: H::Block }, - Assign { lhs: ExprRef, rhs: ExprRef }, - AssignOp { op: BinOp, lhs: ExprRef, rhs: ExprRef }, - Field { lhs: ExprRef, name: Field }, - Index { lhs: ExprRef, index: ExprRef }, - VarRef { id: H::VarId }, +pub enum ExprKind<'tcx> { + Scope { + extent: CodeExtent, + value: ExprRef<'tcx>, + }, + Box { + value: ExprRef<'tcx>, + }, + Call { + fun: ExprRef<'tcx>, + args: Vec>, + }, + Deref { + arg: ExprRef<'tcx>, + }, // NOT overloaded! + Binary { + op: BinOp, + lhs: ExprRef<'tcx>, + rhs: ExprRef<'tcx>, + }, // NOT overloaded! + LogicalOp { + op: LogicalOp, + lhs: ExprRef<'tcx>, + rhs: ExprRef<'tcx>, + }, + Unary { + op: UnOp, + arg: ExprRef<'tcx>, + }, // NOT overloaded! + Cast { + source: ExprRef<'tcx>, + }, + ReifyFnPointer { + source: ExprRef<'tcx>, + }, + UnsafeFnPointer { + source: ExprRef<'tcx>, + }, + Unsize { + source: ExprRef<'tcx>, + }, + If { + condition: ExprRef<'tcx>, + then: ExprRef<'tcx>, + otherwise: Option>, + }, + Loop { + condition: Option>, + body: ExprRef<'tcx>, + }, + Match { + discriminant: ExprRef<'tcx>, + arms: Vec>, + }, + Block { + body: &'tcx hir::Block, + }, + Assign { + lhs: ExprRef<'tcx>, + rhs: ExprRef<'tcx>, + }, + AssignOp { + op: BinOp, + lhs: ExprRef<'tcx>, + rhs: ExprRef<'tcx>, + }, + Field { + lhs: ExprRef<'tcx>, + name: Field, + }, + Index { + lhs: ExprRef<'tcx>, + index: ExprRef<'tcx>, + }, + VarRef { + id: ast::NodeId, + }, SelfRef, // first argument, used for self in a closure - StaticRef { id: H::DefId }, - Borrow { region: H::Region, borrow_kind: BorrowKind, arg: ExprRef }, - Break { label: Option }, - Continue { label: Option }, - Return { value: Option> }, - Repeat { value: ExprRef, count: ExprRef }, - Vec { fields: Vec> }, - Tuple { fields: Vec> }, - Adt { adt_def: H::AdtDef, - variant_index: usize, - substs: H::Substs, - fields: Vec>, - base: Option> }, - Closure { closure_id: H::DefId, substs: H::ClosureSubsts, - upvars: Vec> }, - Literal { literal: Literal }, - InlineAsm { asm: H::InlineAsm }, + StaticRef { + id: DefId, + }, + Borrow { + region: Region, + borrow_kind: BorrowKind, + arg: ExprRef<'tcx>, + }, + Break { + label: Option, + }, + Continue { + label: Option, + }, + Return { + value: Option>, + }, + Repeat { + value: ExprRef<'tcx>, + count: ExprRef<'tcx>, + }, + Vec { + fields: Vec>, + }, + Tuple { + fields: Vec>, + }, + Adt { + adt_def: AdtDef<'tcx>, + variant_index: usize, + substs: &'tcx Substs<'tcx>, + fields: Vec>, + base: Option>, + }, + Closure { + closure_id: DefId, + substs: &'tcx ClosureSubsts<'tcx>, + upvars: Vec>, + }, + Literal { + literal: Literal<'tcx>, + }, + InlineAsm { + asm: &'tcx hir::InlineAsm, + }, } #[derive(Clone, Debug)] -pub enum ExprRef { - Hair(H::Expr), - Mirror(Box>), +pub enum ExprRef<'tcx> { + Hair(&'tcx hir::Expr), + Mirror(Box>), } #[derive(Clone, Debug)] -pub struct FieldExprRef { - pub name: Field, - pub expr: ExprRef, +pub struct FieldExprRef<'tcx> { + pub name: Field, + pub expr: ExprRef<'tcx>, } #[derive(Clone, Debug)] -pub struct Arm { - pub patterns: Vec>, - pub guard: Option>, - pub body: ExprRef, +pub struct Arm<'tcx> { + pub patterns: Vec>, + pub guard: Option>, + pub body: ExprRef<'tcx>, } #[derive(Clone, Debug)] -pub struct Pattern { - pub ty: H::Ty, - pub span: H::Span, - pub kind: PatternKind, +pub struct Pattern<'tcx> { + pub ty: Ty<'tcx>, + pub span: Span, + pub kind: PatternKind<'tcx>, } #[derive(Copy, Clone, Debug)] pub enum LogicalOp { And, - Or + Or, } #[derive(Clone, Debug)] -pub enum PatternKind { +pub enum PatternKind<'tcx> { Wild, // x, ref x, x @ P, etc - Binding { mutability: Mutability, - name: H::Ident, - mode: BindingMode, - var: H::VarId, - ty: H::Ty, - subpattern: Option> }, + Binding { + mutability: Mutability, + name: ast::Name, + mode: BindingMode, + 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: H::AdtDef, variant_index: usize, subpatterns: Vec> }, + 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> }, + Leaf { + subpatterns: Vec>, + }, - Deref { subpattern: PatternRef }, // box P, &P, &mut P, etc + Deref { + subpattern: PatternRef<'tcx>, + }, // box P, &P, &mut P, etc - Constant { expr: ExprRef }, + Constant { + value: Literal<'tcx>, + }, - Range { lo: ExprRef, hi: ExprRef }, + Range { + lo: Literal<'tcx>, + hi: Literal<'tcx>, + }, // matches against a slice, checking the length and extracting elements - Slice { prefix: Vec>, - slice: Option>, - suffix: Vec> }, + Slice { + prefix: Vec>, + slice: Option>, + suffix: Vec>, + }, // fixed match against an array, irrefutable - Array { prefix: Vec>, - slice: Option>, - suffix: Vec> }, + Array { + prefix: Vec>, + slice: Option>, + suffix: Vec>, + }, } #[derive(Copy, Clone, Debug)] -pub enum BindingMode { +pub enum BindingMode { ByValue, - ByRef(H::Region, BorrowKind), + ByRef(Region, BorrowKind), } #[derive(Clone, Debug)] -pub enum PatternRef { - Hair(H::Pattern), - Mirror(Box>), +pub enum PatternRef<'tcx> { + Hair(PatNode<'tcx>), + Mirror(Box>), } #[derive(Clone, Debug)] -pub struct FieldPatternRef { - pub field: Field, - pub pattern: PatternRef, +pub struct FieldPatternRef<'tcx> { + pub field: Field, + pub pattern: PatternRef<'tcx>, } /////////////////////////////////////////////////////////////////////////// // The Mirror trait -/// "Mirroring" is the process of converting from a Hair type into one -/// of the types in this file. For example, the mirror of a `H::Expr` -/// is an `Expr`. Mirroring is the point at which the actual IR is -/// converting into the more idealized representation described in -/// this file. Mirroring is gradual: when you mirror an outer -/// expression like `e1 + e2`, the references to the inner expressions -/// `e1` and `e2` are `ExprRef` instances, and they may or may not -/// be eagerly mirrored. This allows a single AST node from the -/// compiler to expand into one or more Hair nodes, which lets the Hair -/// nodes be simpler. -pub trait Mirror { +/// "Mirroring" is the process of converting from a HIR type into one +/// of the HAIR types defined in this file. This is basically a "on +/// the fly" desugaring step that hides a lot of the messiness in the +/// tcx. For example, the mirror of a `&'tcx hir::Expr` is an +/// `Expr<'tcx>`. +/// +/// Mirroring is gradual: when you mirror an outer expression like `e1 +/// + e2`, the references to the inner expressions `e1` and `e2` are +/// `ExprRef<'tcx>` instances, and they may or may not be eagerly +/// mirrored. This allows a single AST node from the compiler to +/// expand into one or more Hair nodes, which lets the Hair nodes be +/// simpler. +pub trait Mirror<'tcx> { type Output; - fn make_mirror(self, hir: &mut H) -> Self::Output; + fn make_mirror<'a>(self, cx: &mut Cx<'a, 'tcx>) -> Self::Output; } -impl Mirror for Expr { - type Output = Expr; +impl<'tcx> Mirror<'tcx> for Expr<'tcx> { + type Output = Expr<'tcx>; - fn make_mirror(self, _: &mut H) -> Expr { + fn make_mirror<'a>(self, _: &mut Cx<'a, 'tcx>) -> Expr<'tcx> { self } } -impl Mirror for ExprRef { - type Output = Expr; +impl<'tcx> Mirror<'tcx> for ExprRef<'tcx> { + type Output = Expr<'tcx>; - fn make_mirror(self, hir: &mut H) -> Expr { + fn make_mirror<'a>(self, hir: &mut Cx<'a, 'tcx>) -> Expr<'tcx> { match self { ExprRef::Hair(h) => h.make_mirror(hir), ExprRef::Mirror(m) => *m, @@ -334,18 +381,18 @@ impl Mirror for ExprRef { } } -impl Mirror for Stmt { - type Output = Stmt; +impl<'tcx> Mirror<'tcx> for Stmt<'tcx> { + type Output = Stmt<'tcx>; - fn make_mirror(self, _: &mut H) -> Stmt { + fn make_mirror<'a>(self, _: &mut Cx<'a, 'tcx>) -> Stmt<'tcx> { self } } -impl Mirror for StmtRef { - type Output = Stmt; +impl<'tcx> Mirror<'tcx> for StmtRef<'tcx> { + type Output = Stmt<'tcx>; - fn make_mirror(self, hir: &mut H) -> Stmt { + fn make_mirror<'a>(self, hir: &mut Cx<'a, 'tcx>) -> Stmt<'tcx> { match self { StmtRef::Hair(h) => h.make_mirror(hir), StmtRef::Mirror(m) => *m, @@ -353,18 +400,18 @@ impl Mirror for StmtRef { } } -impl Mirror for Pattern { - type Output = Pattern; +impl<'tcx> Mirror<'tcx> for Pattern<'tcx> { + type Output = Pattern<'tcx>; - fn make_mirror(self, _: &mut H) -> Pattern { + fn make_mirror<'a>(self, _: &mut Cx<'a, 'tcx>) -> Pattern<'tcx> { self } } -impl Mirror for PatternRef { - type Output = Pattern; +impl<'tcx> Mirror<'tcx> for PatternRef<'tcx> { + type Output = Pattern<'tcx>; - fn make_mirror(self, hir: &mut H) -> Pattern { + fn make_mirror<'a>(self, hir: &mut Cx<'a, 'tcx>) -> Pattern<'tcx> { match self { PatternRef::Hair(h) => h.make_mirror(hir), PatternRef::Mirror(m) => *m, @@ -372,11 +419,10 @@ impl Mirror for PatternRef { } } -impl Mirror for Block { - type Output = Block; +impl<'tcx> Mirror<'tcx> for Block<'tcx> { + type Output = Block<'tcx>; - fn make_mirror(self, _: &mut H) -> Block { + fn make_mirror<'a>(self, _: &mut Cx<'a, 'tcx>) -> Block<'tcx> { self } } - diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index ebec160995..934dd66017 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -18,16 +18,19 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![crate_type = "rlib"] #![crate_type = "dylib"] -#![feature(ref_slice)] #![feature(rustc_private)] #![feature(into_cow)] #[macro_use] extern crate log; extern crate graphviz as dot; +extern crate rustc; extern crate rustc_data_structures; +extern crate rustc_front; +extern crate rustc_back; +extern crate syntax; pub mod build; -pub mod dump; +pub mod mir_map; pub mod hair; pub mod repr; mod graphviz; diff --git a/src/librustc_mir/dump.rs b/src/librustc_mir/mir_map.rs similarity index 57% rename from src/librustc_mir/dump.rs rename to src/librustc_mir/mir_map.rs index 8e608de024..1acbc8d733 100644 --- a/src/librustc_mir/dump.rs +++ b/src/librustc_mir/mir_map.rs @@ -26,48 +26,54 @@ use repr::Mir; use std::fs::File; use tcx::{PatNode, Cx}; -use self::rustc::middle::def_id::DefId; use self::rustc::middle::infer; use self::rustc::middle::region::CodeExtentData; use self::rustc::middle::ty::{self, Ty}; use self::rustc::util::common::ErrorReported; +use self::rustc::util::nodemap::NodeMap; use self::rustc_front::hir; -use self::rustc_front::attr::{AttrMetaMethods}; use self::rustc_front::visit; use self::syntax::ast; +use self::syntax::attr::AttrMetaMethods; use self::syntax::codemap::Span; -pub fn dump_crate(tcx: &ty::ctxt) { - let mut dump = OuterDump { tcx: tcx }; - visit::walk_crate(&mut dump, tcx.map.krate()); +pub type MirMap<'tcx> = NodeMap>; + +pub fn build_mir_for_crate<'tcx>(tcx: &ty::ctxt<'tcx>) -> MirMap<'tcx> { + let mut map = NodeMap(); + { + let mut dump = OuterDump { + tcx: tcx, + map: &mut map, + }; + visit::walk_crate(&mut dump, tcx.map.krate()); + } + map } /////////////////////////////////////////////////////////////////////////// // OuterDump -- walks a crate, looking for fn items and methods to build MIR from -struct OuterDump<'a,'tcx:'a> { +struct OuterDump<'a, 'tcx: 'a> { tcx: &'a ty::ctxt<'tcx>, + map: &'a mut MirMap<'tcx>, } impl<'a, 'tcx> OuterDump<'a, 'tcx> { - fn visit_mir(&self, attributes: &'tcx [hir::Attribute], mut walk_op: OP) - where OP: FnMut(&mut InnerDump<'a,'tcx>) + fn visit_mir(&mut self, attributes: &'a [ast::Attribute], mut walk_op: OP) + where OP: for<'m> FnMut(&mut InnerDump<'a, 'm, 'tcx>) { - let mut built_mir = false; - + let mut closure_dump = InnerDump { + tcx: self.tcx, + attr: None, + map: &mut *self.map, + }; for attr in attributes { if attr.check_name("rustc_mir") { - let mut closure_dump = InnerDump { tcx: self.tcx, attr: Some(attr) }; - walk_op(&mut closure_dump); - built_mir = true; + closure_dump.attr = Some(attr); } } - - let always_build_mir = self.tcx.sess.opts.always_build_mir; - if !built_mir && always_build_mir { - let mut closure_dump = InnerDump { tcx: self.tcx, attr: None }; - walk_op(&mut closure_dump); - } + walk_op(&mut closure_dump); } } @@ -83,25 +89,46 @@ impl<'a, 'tcx> visit::Visitor<'tcx> for OuterDump<'a, 'tcx> { hir::MethodTraitItem(_, Some(_)) => { self.visit_mir(&trait_item.attrs, |c| visit::walk_trait_item(c, trait_item)); } - _ => { } + hir::MethodTraitItem(_, None) | + hir::ConstTraitItem(..) | + hir::TypeTraitItem(..) => {} } visit::walk_trait_item(self, trait_item); } + + fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { + match impl_item.node { + hir::MethodImplItem(..) => { + self.visit_mir(&impl_item.attrs, |c| visit::walk_impl_item(c, impl_item)); + } + hir::ConstImplItem(..) | hir::TypeImplItem(..) => {} + } + visit::walk_impl_item(self, impl_item); + } } /////////////////////////////////////////////////////////////////////////// // InnerDump -- dumps MIR for a single fn and its contained closures -struct InnerDump<'a,'tcx:'a> { +struct InnerDump<'a, 'm, 'tcx: 'a + 'm> { tcx: &'a ty::ctxt<'tcx>, - attr: Option<&'a hir::Attribute>, + map: &'m mut MirMap<'tcx>, + attr: Option<&'a ast::Attribute>, } -impl<'a, 'tcx> visit::Visitor<'tcx> for InnerDump<'a,'tcx> { +impl<'a, 'm, 'tcx> visit::Visitor<'tcx> for InnerDump<'a,'m,'tcx> { fn visit_item(&mut self, _: &'tcx hir::Item) { // ignore nested items; they need their own graphviz annotation } + fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem) { + // ignore nested items; they need their own graphviz annotation + } + + fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem) { + // ignore nested items; they need their own graphviz annotation + } + fn visit_fn(&mut self, fk: visit::FnKind<'tcx>, decl: &'tcx hir::FnDecl, @@ -115,21 +142,16 @@ impl<'a, 'tcx> visit::Visitor<'tcx> for InnerDump<'a,'tcx> { (format!(""), vec![]), }; - let param_env = - ty::ParameterEnvironment::for_item(self.tcx, id); + let param_env = ty::ParameterEnvironment::for_item(self.tcx, id); - let infcx = - infer::new_infer_ctxt(self.tcx, - &self.tcx.tables, - Some(param_env), - true); + let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, Some(param_env), true); match build_mir(Cx::new(&infcx), implicit_arg_tys, id, span, decl, body) { Ok(mir) => { - let meta_item_list = - self.attr.iter() - .flat_map(|a| a.meta_item_list()) - .flat_map(|l| l.iter()); + let meta_item_list = self.attr + .iter() + .flat_map(|a| a.meta_item_list()) + .flat_map(|l| l.iter()); for item in meta_item_list { if item.check_name("graphviz") { match item.value_str() { @@ -156,61 +178,55 @@ impl<'a, 'tcx> visit::Visitor<'tcx> for InnerDump<'a,'tcx> { } } } + + let previous = self.map.insert(id, mir); + assert!(previous.is_none()); } - Err(ErrorReported) => { } + Err(ErrorReported) => {} } visit::walk_fn(self, fk, decl, body, span); } } -fn build_mir<'a,'tcx:'a>(cx: Cx<'a,'tcx>, - implicit_arg_tys: Vec>, - fn_id: ast::NodeId, - span: Span, - decl: &'tcx hir::FnDecl, - body: &'tcx hir::Block) - -> Result>, ErrorReported> { - let arguments = - decl.inputs - .iter() - .map(|arg| { - let ty = cx.tcx.node_id_to_type(arg.id); - (ty, PatNode::irrefutable(&arg.pat)) - }) - .collect(); - - let parameter_scope = - cx.tcx.region_maps.lookup_code_extent( - CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body.id }); - Ok(build::construct(cx, - span, - implicit_arg_tys, - arguments, - parameter_scope, - body)) +fn build_mir<'a, 'tcx: 'a>(cx: Cx<'a, 'tcx>, + implicit_arg_tys: Vec>, + fn_id: ast::NodeId, + span: Span, + decl: &'tcx hir::FnDecl, + body: &'tcx hir::Block) + -> Result, ErrorReported> { + let arguments = decl.inputs + .iter() + .map(|arg| { + let ty = cx.tcx().node_id_to_type(arg.id); + (ty, PatNode::irrefutable(&arg.pat)) + }) + .collect(); + + let parameter_scope = cx.tcx().region_maps.lookup_code_extent(CodeExtentData::ParameterScope { + fn_id: fn_id, + body_id: body.id, + }); + Ok(build::construct(cx, span, implicit_arg_tys, arguments, parameter_scope, body)) } -fn closure_self_ty<'a,'tcx>(tcx: &ty::ctxt<'tcx>, - closure_expr_id: ast::NodeId, - body_id: ast::NodeId) - -> Ty<'tcx> -{ +fn closure_self_ty<'a, 'tcx>(tcx: &ty::ctxt<'tcx>, + closure_expr_id: ast::NodeId, + body_id: ast::NodeId) + -> Ty<'tcx> { let closure_ty = tcx.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 // number 0, hokey. - let region = - ty::Region::ReFree( - ty::FreeRegion { - scope: tcx.region_maps.item_extent(body_id), - bound_region: ty::BoundRegion::BrAnon(0) - }); - let region = - tcx.mk_region(region); - - match tcx.closure_kind(DefId::local(closure_expr_id)) { + let region = ty::Region::ReFree(ty::FreeRegion { + scope: tcx.region_maps.item_extent(body_id), + bound_region: ty::BoundRegion::BrAnon(0), + }); + let region = tcx.mk_region(region); + + match tcx.closure_kind(tcx.map.local_def_id(closure_expr_id)) { ty::ClosureKind::FnClosureKind => tcx.mk_ref(region, ty::TypeAndMut { ty: closure_ty, diff --git a/src/librustc_mir/repr.rs b/src/librustc_mir/repr.rs index a54942144c..5059955c5d 100644 --- a/src/librustc_mir/repr.rs +++ b/src/librustc_mir/repr.rs @@ -8,22 +8,29 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use hair::Hair; +use rustc::middle::const_eval::ConstVal; +use rustc::middle::def_id::DefId; +use rustc::middle::region::CodeExtent; +use rustc::middle::subst::Substs; +use rustc::middle::ty::{AdtDef, ClosureSubsts, Region, Ty}; +use rustc_back::slice; use rustc_data_structures::fnv::FnvHashMap; +use rustc_front::hir::InlineAsm; +use syntax::ast::Name; +use syntax::codemap::Span; use std::fmt::{Debug, Formatter, Error}; -use std::slice; use std::u32; /// Lowered representation of a single function. -pub struct Mir { - pub basic_blocks: Vec>, +pub struct Mir<'tcx> { + pub basic_blocks: Vec>, // for every node id - pub extents: FnvHashMap>, + pub extents: FnvHashMap>, - pub var_decls: Vec>, - pub arg_decls: Vec>, - pub temp_decls: Vec>, + pub var_decls: Vec>, + pub arg_decls: Vec>, + pub temp_decls: Vec>, } /// where execution begins @@ -35,18 +42,18 @@ pub const END_BLOCK: BasicBlock = BasicBlock(1); /// where execution ends, on panic pub const DIVERGE_BLOCK: BasicBlock = BasicBlock(2); -impl Mir { +impl<'tcx> Mir<'tcx> { pub fn all_basic_blocks(&self) -> Vec { (0..self.basic_blocks.len()) .map(|i| BasicBlock::new(i)) .collect() } - pub fn basic_block_data(&self, bb: BasicBlock) -> &BasicBlockData { + pub fn basic_block_data(&self, bb: BasicBlock) -> &BasicBlockData<'tcx> { &self.basic_blocks[bb.index()] } - pub fn basic_block_data_mut(&mut self, bb: BasicBlock) -> &mut BasicBlockData { + pub fn basic_block_data_mut(&mut self, bb: BasicBlock) -> &mut BasicBlockData<'tcx> { &mut self.basic_blocks[bb.index()] } } @@ -103,7 +110,7 @@ pub enum BorrowKind { Unique, /// Data is mutable and not aliasable. - Mut + Mut, } /////////////////////////////////////////////////////////////////////////// @@ -111,16 +118,16 @@ pub enum BorrowKind { // A "variable" is a binding declared by the user as part of the fn // decl, a let, etc. -pub struct VarDecl { +pub struct VarDecl<'tcx> { pub mutability: Mutability, - pub name: H::Ident, - pub ty: H::Ty, + pub name: Name, + pub ty: Ty<'tcx>, } // A "temp" is a temporary that we place on the stack. They are // anonymous, always mutable, and have only a type. -pub struct TempDecl { - pub ty: H::Ty, +pub struct TempDecl<'tcx> { + pub ty: Ty<'tcx>, } // A "arg" is one of the function's formal arguments. These are @@ -134,8 +141,8 @@ pub struct TempDecl { // // there is only one argument, of type `(i32, u32)`, but two bindings // (`x` and `y`). -pub struct ArgDecl { - pub ty: H::Ty, +pub struct ArgDecl<'tcx> { + pub ty: Ty<'tcx>, } /////////////////////////////////////////////////////////////////////////// @@ -212,24 +219,34 @@ impl Debug for BasicBlock { // BasicBlock and Terminator #[derive(Debug)] -pub struct BasicBlockData { - pub statements: Vec>, - pub terminator: Terminator, +pub struct BasicBlockData<'tcx> { + pub statements: Vec>, + pub terminator: Terminator<'tcx>, } -pub enum Terminator { +pub enum Terminator<'tcx> { /// block should have one successor in the graph; we jump there - Goto { target: BasicBlock }, + Goto { + target: BasicBlock, + }, /// block should initiate unwinding; should be one successor /// that does cleanup and branches to DIVERGE_BLOCK - Panic { target: BasicBlock }, + Panic { + target: BasicBlock, + }, /// jump to branch 0 if this lvalue evaluates to true - If { cond: Operand, targets: [BasicBlock; 2] }, + If { + cond: Operand<'tcx>, + targets: [BasicBlock; 2], + }, /// lvalue evaluates to some enum; jump depending on the branch - Switch { discr: Lvalue, targets: Vec }, + Switch { + discr: Lvalue<'tcx>, + targets: Vec, + }, /// Indicates that the last statement in the block panics, aborts, /// etc. No successors. This terminator appears on exactly one @@ -247,10 +264,13 @@ pub enum Terminator { /// block ends with a call; it should have two successors. The /// first successor indicates normal return. The second indicates /// unwinding. - Call { data: CallData, targets: [BasicBlock; 2] }, + Call { + data: CallData<'tcx>, + targets: [BasicBlock; 2], + }, } -impl Terminator { +impl<'tcx> Terminator<'tcx> { pub fn successors(&self) -> &[BasicBlock] { use self::Terminator::*; match *self { @@ -266,19 +286,19 @@ impl Terminator { } #[derive(Debug)] -pub struct CallData { +pub struct CallData<'tcx> { /// where the return value is written to - pub destination: Lvalue, + pub destination: Lvalue<'tcx>, /// the fn being called - pub func: Lvalue, + pub func: Lvalue<'tcx>, /// the arguments - pub args: Vec>, + pub args: Vec>, } -impl BasicBlockData { - pub fn new(terminator: Terminator) -> BasicBlockData { +impl<'tcx> BasicBlockData<'tcx> { + pub fn new(terminator: Terminator<'tcx>) -> BasicBlockData<'tcx> { BasicBlockData { statements: vec![], terminator: terminator, @@ -286,7 +306,7 @@ impl BasicBlockData { } } -impl Debug for Terminator { +impl<'tcx> Debug for Terminator<'tcx> { fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { use self::Terminator::*; match *self { @@ -305,7 +325,9 @@ impl Debug for Terminator { Call { data: ref c, targets } => { try!(write!(fmt, "{:?} = {:?}(", c.destination, c.func)); for (index, arg) in c.args.iter().enumerate() { - if index > 0 { try!(write!(fmt, ", ")); } + if index > 0 { + try!(write!(fmt, ", ")); + } try!(write!(fmt, "{:?}", arg)); } write!(fmt, ") -> {:?}", targets) @@ -318,24 +340,24 @@ impl Debug for Terminator { /////////////////////////////////////////////////////////////////////////// // Statements -pub struct Statement { - pub span: H::Span, - pub kind: StatementKind, +pub struct Statement<'tcx> { + pub span: Span, + pub kind: StatementKind<'tcx>, } #[derive(Debug)] -pub enum StatementKind { - Assign(Lvalue, Rvalue), - Drop(DropKind, Lvalue), +pub enum StatementKind<'tcx> { + Assign(Lvalue<'tcx>, Rvalue<'tcx>), + Drop(DropKind, Lvalue<'tcx>), } #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum DropKind { Shallow, - Deep + Deep, } -impl Debug for Statement { +impl<'tcx> Debug for Statement<'tcx> { fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { use self::StatementKind::*; match self.kind { @@ -351,7 +373,7 @@ impl Debug for Statement { /// A path to a value; something that can be evaluated without /// changing or disturbing program state. #[derive(Clone, PartialEq)] -pub enum Lvalue { +pub enum Lvalue<'tcx> { /// local variable declared by the user Var(u32), @@ -363,13 +385,13 @@ pub enum Lvalue { Arg(u32), /// static or static mut variable - Static(H::DefId), + Static(DefId), /// the return pointer of the fn ReturnPointer, /// projection out of an lvalue (access a field, deref a pointer, etc) - Projection(Box>) + Projection(Box>), } /// The `Projection` data structure defines things of the form `B.x` @@ -377,15 +399,15 @@ pub enum Lvalue { /// shared between `Constant` and `Lvalue`. See the aliases /// `LvalueProjection` etc below. #[derive(Clone, Debug, PartialEq)] -pub struct Projection { +pub struct Projection<'tcx, B, V> { pub base: B, - pub elem: ProjectionElem, + pub elem: ProjectionElem<'tcx, V>, } #[derive(Clone, Debug, PartialEq)] -pub enum ProjectionElem { +pub enum ProjectionElem<'tcx, V> { Deref, - Field(Field), + Field(Field), Index(V), // These indices are generated by slice patterns. Easiest to explain @@ -406,44 +428,47 @@ pub enum ProjectionElem { // "Downcast" to a variant of an ADT. Currently, we only introduce // this for ADTs with more than one variant. It may be better to // just introduce it always, or always for enums. - Downcast(H::AdtDef, usize), + Downcast(AdtDef<'tcx>, usize), } /// Alias for projections as they appear in lvalues, where the base is an lvalue /// and the index is an operand. -pub type LvalueProjection = - Projection,Operand>; +pub type LvalueProjection<'tcx> = + Projection<'tcx,Lvalue<'tcx>,Operand<'tcx>>; /// Alias for projections as they appear in lvalues, where the base is an lvalue /// and the index is an operand. -pub type LvalueElem = - ProjectionElem>; +pub type LvalueElem<'tcx> = + ProjectionElem<'tcx,Operand<'tcx>>; #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub enum Field { - Named(H::Name), +pub enum Field { + Named(Name), Indexed(usize), } -impl Lvalue { - pub fn field(self, f: Field) -> Lvalue { +impl<'tcx> Lvalue<'tcx> { + pub fn field(self, f: Field) -> Lvalue<'tcx> { self.elem(ProjectionElem::Field(f)) } - pub fn deref(self) -> Lvalue { + pub fn deref(self) -> Lvalue<'tcx> { self.elem(ProjectionElem::Deref) } - pub fn index(self, index: Operand) -> Lvalue { + pub fn index(self, index: Operand<'tcx>) -> Lvalue<'tcx> { self.elem(ProjectionElem::Index(index)) } - pub fn elem(self, elem: LvalueElem) -> Lvalue { - Lvalue::Projection(Box::new(LvalueProjection { base: self, elem: elem })) + pub fn elem(self, elem: LvalueElem<'tcx>) -> Lvalue<'tcx> { + Lvalue::Projection(Box::new(LvalueProjection { + base: self, + elem: elem, + })) } } -impl Debug for Lvalue { +impl<'tcx> Debug for Lvalue<'tcx> { fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { use self::Lvalue::*; @@ -487,12 +512,12 @@ impl Debug for Lvalue { // being nested in one another. #[derive(Clone, PartialEq)] -pub enum Operand { - Consume(Lvalue), - Constant(Constant), +pub enum Operand<'tcx> { + Consume(Lvalue<'tcx>), + Constant(Constant<'tcx>), } -impl Debug for Operand { +impl<'tcx> Debug for Operand<'tcx> { fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { use self::Operand::*; match *self { @@ -506,34 +531,34 @@ impl Debug for Operand { // Rvalues #[derive(Clone)] -pub enum Rvalue { +pub enum Rvalue<'tcx> { // x (either a move or copy, depending on type of x) - Use(Operand), + Use(Operand<'tcx>), // [x; 32] - Repeat(Operand, Operand), + Repeat(Operand<'tcx>, Operand<'tcx>), // &x or &mut x - Ref(H::Region, BorrowKind, Lvalue), + Ref(Region, BorrowKind, Lvalue<'tcx>), // length of a [X] or [X;n] value - Len(Lvalue), + Len(Lvalue<'tcx>), - Cast(CastKind, Operand, H::Ty), + Cast(CastKind, Operand<'tcx>, Ty<'tcx>), - BinaryOp(BinOp, Operand, Operand), + BinaryOp(BinOp, Operand<'tcx>, Operand<'tcx>), - UnaryOp(UnOp, Operand), + UnaryOp(UnOp, Operand<'tcx>), // Creates an *uninitialized* Box - Box(H::Ty), + Box(Ty<'tcx>), // Create an aggregate value, like a tuple or struct. This is // only needed because we want to distinguish `dest = Foo { x: // ..., y: ... }` from `dest.x = ...; dest.y = ...;` in the case // that `Foo` has a destructor. These rvalues can be optimized // away after type-checking and before lowering. - Aggregate(AggregateKind, Vec>), + Aggregate(AggregateKind<'tcx>, Vec>), // Generates a slice of the form `&input[from_start..L-from_end]` // where `L` is the length of the slice. This is only created by @@ -541,12 +566,12 @@ pub enum Rvalue { // .., z]` might create a slice with `from_start=2` and // `from_end=1`. Slice { - input: Lvalue, + input: Lvalue<'tcx>, from_start: usize, from_end: usize, }, - InlineAsm(H::InlineAsm), + InlineAsm(&'tcx InlineAsm), } #[derive(Clone, Debug, PartialEq, Eq)] @@ -568,11 +593,11 @@ pub enum CastKind { } #[derive(Clone, Debug, PartialEq, Eq)] -pub enum AggregateKind { +pub enum AggregateKind<'tcx> { Vec, Tuple, - Adt(H::AdtDef, usize, H::Substs), - Closure(H::DefId, H::ClosureSubsts), + Adt(AdtDef<'tcx>, usize, &'tcx Substs<'tcx>), + Closure(DefId, &'tcx ClosureSubsts<'tcx>), } #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -616,10 +641,10 @@ pub enum UnOp { /// The `!` operator for logical inversion Not, /// The `-` operator for negation - Neg + Neg, } -impl Debug for Rvalue { +impl<'tcx> Debug for Rvalue<'tcx> { fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { use self::Rvalue::*; @@ -634,56 +659,33 @@ impl Debug for Rvalue { Box(ref t) => write!(fmt, "Box {:?}", t), Aggregate(ref kind, ref lvs) => write!(fmt, "Aggregate<{:?}>({:?})", kind, lvs), InlineAsm(ref asm) => write!(fmt, "InlineAsm({:?})", asm), - Slice { ref input, from_start, from_end } => write!(fmt, "{:?}[{:?}..-{:?}]", - input, from_start, from_end), + Slice { ref input, from_start, from_end } => + write!(fmt, "{:?}[{:?}..-{:?}]", input, from_start, from_end), } } } /////////////////////////////////////////////////////////////////////////// // Constants +// +// Two constants are equal if they are the same constant. Note that +// this does not necessarily mean that they are "==" in Rust -- in +// particular one must be wary of `NaN`! #[derive(Clone, Debug, PartialEq)] -pub struct Constant { - pub span: H::Span, - pub kind: ConstantKind -} - -#[derive(Clone, Debug, PartialEq)] -pub enum ConstantKind { - Literal(Literal), - Aggregate(AggregateKind, Vec>), - Call(Box>, Vec>), - Cast(Box>, H::Ty), - Repeat(Box>, Box>), - Ref(BorrowKind, Box>), - BinaryOp(BinOp, Box>, Box>), - UnaryOp(UnOp, Box>), - Projection(Box>) +pub struct Constant<'tcx> { + pub span: Span, + pub ty: Ty<'tcx>, + pub literal: Literal<'tcx>, } -pub type ConstantProjection = - Projection,Constant>; - #[derive(Clone, Debug, PartialEq)] -pub enum Literal { - Item { def_id: H::DefId, substs: H::Substs }, - Projection { projection: H::Projection }, - Int { bits: IntegralBits, value: i64 }, - Uint { bits: IntegralBits, value: u64 }, - Float { bits: FloatBits, value: f64 }, - Char { c: char }, - Bool { value: bool }, - Bytes { value: H::Bytes }, - String { value: H::InternedString }, -} - -#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] -pub enum IntegralBits { - B8, B16, B32, B64, BSize -} - -#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] -pub enum FloatBits { - F32, F64 +pub enum Literal<'tcx> { + Item { + def_id: DefId, + substs: &'tcx Substs<'tcx>, + }, + Value { + value: ConstVal, + }, } diff --git a/src/librustc_mir/tcx/block.rs b/src/librustc_mir/tcx/block.rs index 033e6ed296..dc168bc7c2 100644 --- a/src/librustc_mir/tcx/block.rs +++ b/src/librustc_mir/tcx/block.rs @@ -12,16 +12,16 @@ use hair::*; use tcx::Cx; use tcx::pattern::PatNode; -use tcx::rustc::middle::region::{BlockRemainder, CodeExtentData}; -use tcx::rustc_front::hir; -use tcx::syntax::ast; -use tcx::syntax::ptr::P; use tcx::to_ref::ToRef; +use rustc::middle::region::{BlockRemainder, CodeExtentData}; +use rustc_front::hir; +use syntax::ast; +use syntax::ptr::P; -impl<'a,'tcx:'a> Mirror> for &'tcx hir::Block { - type Output = Block>; +impl<'tcx> Mirror<'tcx> for &'tcx hir::Block { + type Output = Block<'tcx>; - fn make_mirror(self, cx: &mut Cx<'a,'tcx>) -> Block> { + fn make_mirror<'a>(self, cx: &mut Cx<'a, 'tcx>) -> Block<'tcx> { // We have to eagerly translate the "spine" of the statements // in order to get the lexical scoping correctly. let stmts = mirror_stmts(cx, self.id, self.stmts.iter().enumerate()); @@ -29,15 +29,15 @@ impl<'a,'tcx:'a> Mirror> for &'tcx hir::Block { extent: cx.tcx.region_maps.node_extent(self.id), span: self.span, stmts: stmts, - expr: self.expr.to_ref() + expr: self.expr.to_ref(), } } } -impl<'a,'tcx:'a> Mirror> for &'tcx hir::Stmt { - type Output = Stmt>; +impl<'tcx> Mirror<'tcx> for &'tcx hir::Stmt { + type Output = Stmt<'tcx>; - fn make_mirror(self, _cx: &mut Cx<'a,'tcx>) -> Stmt> { + fn make_mirror<'a>(self, _cx: &mut Cx<'a, 'tcx>) -> Stmt<'tcx> { // In order to get the scoping correct, we eagerly mirror // statements when we translate the enclosing block, so we // should in fact never get to this point. @@ -45,11 +45,11 @@ impl<'a,'tcx:'a> Mirror> for &'tcx hir::Stmt { } } -fn mirror_stmts<'a,'tcx:'a,STMTS>(cx: &mut Cx<'a,'tcx>, - block_id: ast::NodeId, - mut stmts: STMTS) - -> Vec>> - where STMTS: Iterator)> +fn mirror_stmts<'a, 'tcx: 'a, STMTS>(cx: &mut Cx<'a, 'tcx>, + block_id: ast::NodeId, + mut stmts: STMTS) + -> Vec> + where STMTS: Iterator)> { let mut result = vec![]; while let Some((index, stmt)) = stmts.next() { @@ -68,7 +68,7 @@ fn mirror_stmts<'a,'tcx:'a,STMTS>(cx: &mut Cx<'a,'tcx>, hir::DeclLocal(ref local) => { let remainder_extent = CodeExtentData::Remainder(BlockRemainder { block: block_id, - first_statement_index: index as u32 + first_statement_index: index as u32, }); let remainder_extent = cx.tcx.region_maps.lookup_code_extent(remainder_extent); @@ -77,18 +77,16 @@ fn mirror_stmts<'a,'tcx:'a,STMTS>(cx: &mut Cx<'a,'tcx>, // they are within the scope of this let: let following_stmts = mirror_stmts(cx, block_id, stmts); - result.push( - StmtRef::Mirror( - Box::new(Stmt { - span: stmt.span, - kind: StmtKind::Let { - remainder_scope: remainder_extent, - init_scope: cx.tcx.region_maps.node_extent(id), - pattern: PatNode::irrefutable(&local.pat).to_ref(), - initializer: local.init.to_ref(), - stmts: following_stmts - } - }))); + result.push(StmtRef::Mirror(Box::new(Stmt { + span: stmt.span, + kind: StmtKind::Let { + remainder_scope: remainder_extent, + init_scope: cx.tcx.region_maps.node_extent(id), + pattern: PatNode::irrefutable(&local.pat).to_ref(), + initializer: local.init.to_ref(), + stmts: following_stmts, + }, + }))); return result; } @@ -99,16 +97,14 @@ fn mirror_stmts<'a,'tcx:'a,STMTS>(cx: &mut Cx<'a,'tcx>, return result; } -pub fn to_expr_ref<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>, - block: &'tcx hir::Block) - -> ExprRef> { +pub fn to_expr_ref<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, block: &'tcx hir::Block) -> ExprRef<'tcx> { let block_ty = cx.tcx.node_id_to_type(block.id); let temp_lifetime = cx.tcx.region_maps.temporary_scope(block.id); let expr = Expr { ty: block_ty, temp_lifetime: temp_lifetime, span: block.span, - kind: ExprKind::Block { body: block } + kind: ExprKind::Block { body: block }, }; expr.to_ref() } diff --git a/src/librustc_mir/tcx/expr.rs b/src/librustc_mir/tcx/expr.rs index f15470e785..4604ca957d 100644 --- a/src/librustc_mir/tcx/expr.rs +++ b/src/librustc_mir/tcx/expr.rs @@ -15,30 +15,29 @@ use std::rc::Rc; use tcx::Cx; use tcx::block; use tcx::pattern::PatNode; -use tcx::rustc::front::map; -use tcx::rustc::middle::def; -use tcx::rustc::middle::def_id::DefId; -use tcx::rustc::middle::region::CodeExtent; -use tcx::rustc::middle::pat_util; -use tcx::rustc::middle::ty::{self, Ty}; -use tcx::rustc_front::hir; -use tcx::rustc_front::util as hir_util; -use tcx::syntax::codemap::Span; -use tcx::syntax::parse::token; -use tcx::syntax::ptr::P; use tcx::to_ref::ToRef; - -impl<'a,'tcx:'a> Mirror> for &'tcx hir::Expr { - type Output = Expr>; - - fn make_mirror(self, cx: &mut Cx<'a,'tcx>) -> Expr> { +use rustc::front::map; +use rustc::middle::const_eval; +use rustc::middle::def; +use rustc::middle::region::CodeExtent; +use rustc::middle::pat_util; +use rustc::middle::ty::{self, Ty}; +use rustc_front::hir; +use rustc_front::util as hir_util; +use syntax::ext::mtwt; +use syntax::parse::token; +use syntax::ptr::P; + +impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { + type Output = Expr<'tcx>; + + fn make_mirror<'a>(self, cx: &mut Cx<'a, 'tcx>) -> Expr<'tcx> { debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span); let expr_ty = cx.tcx.expr_ty(self); // note: no adjustments (yet)! let kind = match self.node { // Here comes the interesting stuff: - hir::ExprMethodCall(_, _, ref args) => { // Rewrite a.b(c) into UFCS form like Trait::b(a, c) let expr = method_callee(cx, self, ty::MethodCall::expr(self.id)); @@ -47,24 +46,24 @@ impl<'a,'tcx:'a> Mirror> for &'tcx hir::Expr { .collect(); ExprKind::Call { fun: expr.to_ref(), - args: args + args: args, } } hir::ExprAddrOf(mutbl, ref expr) => { let region = match expr_ty.sty { ty::TyRef(r, _) => r, - _ => cx.tcx.sess.span_bug(expr.span, "type of & not region") + _ => cx.tcx.sess.span_bug(expr.span, "type of & not region"), }; - ExprKind::Borrow { region: *region, - borrow_kind: to_borrow_kind(mutbl), - arg: expr.to_ref() } + ExprKind::Borrow { + region: *region, + borrow_kind: to_borrow_kind(mutbl), + arg: expr.to_ref(), + } } hir::ExprBlock(ref blk) => { - ExprKind::Block { - body: &**blk - } + ExprKind::Block { body: &**blk } } hir::ExprAssign(ref lhs, ref rhs) => { @@ -83,9 +82,9 @@ impl<'a,'tcx:'a> Mirror> for &'tcx hir::Expr { } } - hir::ExprLit(ref lit) => { - let literal = convert_literal(cx, self.span, expr_ty, lit); - ExprKind::Literal { literal: literal } + hir::ExprLit(..) => { + let value = const_eval::eval_const_expr(cx.tcx, self); + ExprKind::Literal { literal: Literal::Value { value: value } } } hir::ExprBinary(op, ref lhs, ref rhs) => { @@ -101,20 +100,26 @@ impl<'a,'tcx:'a> Mirror> for &'tcx hir::Expr { // FIXME overflow match op.node { hir::BinOp_::BiAnd => { - ExprKind::LogicalOp { op: LogicalOp::And, - lhs: lhs.to_ref(), - rhs: rhs.to_ref() } + ExprKind::LogicalOp { + op: LogicalOp::And, + lhs: lhs.to_ref(), + rhs: rhs.to_ref(), + } } hir::BinOp_::BiOr => { - ExprKind::LogicalOp { op: LogicalOp::Or, - lhs: lhs.to_ref(), - rhs: rhs.to_ref() } + ExprKind::LogicalOp { + op: LogicalOp::Or, + lhs: lhs.to_ref(), + rhs: rhs.to_ref(), + } } _ => { let op = bin_op(op.node); - ExprKind::Binary { op: op, - lhs: lhs.to_ref(), - rhs: rhs.to_ref() } + ExprKind::Binary { + op: op, + lhs: lhs.to_ref(), + rhs: rhs.to_ref(), + } } } } @@ -125,8 +130,10 @@ impl<'a,'tcx:'a> Mirror> for &'tcx hir::Expr { overloaded_lvalue(cx, self, ty::MethodCall::expr(self.id), PassArgs::ByValue, lhs.to_ref(), vec![index]) } else { - ExprKind::Index { lhs: lhs.to_ref(), - index: index.to_ref() } + ExprKind::Index { + lhs: lhs.to_ref(), + index: index.to_ref(), + } } } @@ -139,11 +146,6 @@ impl<'a,'tcx:'a> Mirror> for &'tcx hir::Expr { } } - hir::ExprUnary(hir::UnOp::UnUniq, ref arg) => { - assert!(!cx.tcx.is_method_call(self.id)); - ExprKind::Box { place: None, value: arg.to_ref() } - } - hir::ExprUnary(op, ref arg) => { if cx.tcx.is_method_call(self.id) { overloaded_operator(cx, self, ty::MethodCall::expr(self.id), @@ -153,13 +155,16 @@ impl<'a,'tcx:'a> Mirror> for &'tcx hir::Expr { let op = match op { hir::UnOp::UnNot => UnOp::Not, hir::UnOp::UnNeg => UnOp::Neg, - hir::UnOp::UnUniq | hir::UnOp::UnDeref => { + hir::UnOp::UnDeref => { cx.tcx.sess.span_bug( self.span, - &format!("operator should have been handled elsewhere {:?}", op)); + "UnDeref should have been handled elsewhere"); } }; - ExprKind::Unary { op: op, arg: arg.to_ref() } + ExprKind::Unary { + op: op, + arg: arg.to_ref(), + } } } @@ -208,8 +213,8 @@ impl<'a,'tcx:'a> Mirror> for &'tcx hir::Expr { ty::TyClosure(def_id, ref substs) => (def_id, substs), _ => { cx.tcx.sess.span_bug(self.span, - &format!("closure expr w/o closure type: {:?}", - closure_ty)); + &format!("closure expr w/o closure type: {:?}", + closure_ty)); } }; let upvars = cx.tcx.with_freevars(self.id, |freevars| { @@ -230,15 +235,15 @@ impl<'a,'tcx:'a> Mirror> for &'tcx hir::Expr { let (adt_def, substs) = match range_ty.sty { ty::TyStruct(adt_def, substs) => (adt_def, substs), _ => { - cx.tcx.sess.span_bug( - self.span, - &format!("unexpanded ast")); + cx.tcx.sess.span_bug(self.span, &format!("unexpanded ast")); } }; let field_expr_ref = |s: &'tcx P, nm: &str| { - FieldExprRef { name: Field::Named(token::intern(nm)), - expr: s.to_ref() } + FieldExprRef { + name: Field::Named(token::intern(nm)), + expr: s.to_ref(), + } }; let start_field = start.as_ref() @@ -249,11 +254,13 @@ impl<'a,'tcx:'a> Mirror> for &'tcx hir::Expr { .into_iter() .map(|e| field_expr_ref(e, "end")); - ExprKind::Adt { adt_def: adt_def, - variant_index: 0, - substs: substs, - fields: start_field.chain(end_field).collect(), - base: None } + ExprKind::Adt { + adt_def: adt_def, + variant_index: 0, + substs: substs, + fields: start_field.chain(end_field).collect(), + base: None, + } } hir::ExprPath(..) => { @@ -266,8 +273,6 @@ impl<'a,'tcx:'a> Mirror> for &'tcx hir::Expr { // Now comes the rote stuff: - hir::ExprParen(ref p) => - ExprKind::Paren { arg: p.to_ref() }, hir::ExprRepeat(ref v, ref c) => ExprKind::Repeat { value: v.to_ref(), count: c.to_ref() }, hir::ExprRet(ref v) => @@ -289,16 +294,16 @@ impl<'a,'tcx:'a> Mirror> for &'tcx hir::Expr { hir::ExprLoop(ref body, _) => ExprKind::Loop { condition: None, body: block::to_expr_ref(cx, body) }, - hir::ExprField(ref source, ident) => + hir::ExprField(ref source, name) => ExprKind::Field { lhs: source.to_ref(), - name: Field::Named(ident.node.name) }, - hir::ExprTupField(ref source, ident) => + name: Field::Named(name.node) }, + hir::ExprTupField(ref source, index) => ExprKind::Field { lhs: source.to_ref(), - name: Field::Indexed(ident.node) }, + name: Field::Indexed(index.node) }, hir::ExprCast(ref source, _) => ExprKind::Cast { source: source.to_ref() }, - hir::ExprBox(ref place, ref value) => - ExprKind::Box { place: place.to_ref(), value: value.to_ref() }, + hir::ExprBox(ref value) => + ExprKind::Box { value: value.to_ref() }, hir::ExprVec(ref fields) => ExprKind::Vec { fields: fields.to_ref() }, hir::ExprTup(ref fields) => @@ -319,7 +324,7 @@ impl<'a,'tcx:'a> Mirror> for &'tcx hir::Expr { // Now apply adjustments, if any. match cx.tcx.tables.borrow().adjustments.get(&self.id) { - None => { } + None => {} Some(&ty::adjustment::AdjustReifyFnPointer) => { let adjusted_ty = cx.tcx.expr_ty_adjusted(self); expr = Expr { @@ -358,7 +363,7 @@ impl<'a,'tcx:'a> Mirror> for &'tcx hir::Expr { temp_lifetime: temp_lifetime, ty: adjusted_ty, span: self.span, - kind: kind + kind: kind, }; } @@ -367,7 +372,7 @@ impl<'a,'tcx:'a> Mirror> for &'tcx hir::Expr { temp_lifetime: temp_lifetime, ty: target, span: self.span, - kind: ExprKind::Unsize { source: expr.to_ref() } + kind: ExprKind::Unsize { source: expr.to_ref() }, }; } else if let Some(autoref) = adj.autoref { let adjusted_ty = expr.ty.adjust_for_autoref(cx.tcx, Some(autoref)); @@ -377,9 +382,11 @@ impl<'a,'tcx:'a> Mirror> for &'tcx hir::Expr { temp_lifetime: temp_lifetime, ty: adjusted_ty, span: self.span, - kind: ExprKind::Borrow { region: *r, - borrow_kind: to_borrow_kind(m), - arg: expr.to_ref() } + kind: ExprKind::Borrow { + region: *r, + borrow_kind: to_borrow_kind(m), + arg: expr.to_ref(), + }, }; } ty::adjustment::AutoUnsafe(m) => { @@ -392,15 +399,17 @@ impl<'a,'tcx:'a> Mirror> for &'tcx hir::Expr { temp_lifetime: temp_lifetime, ty: cx.tcx.mk_ref(region, ty::TypeAndMut { ty: expr.ty, mutbl: m }), span: self.span, - kind: ExprKind::Borrow { region: *region, - borrow_kind: to_borrow_kind(m), - arg: expr.to_ref() } + kind: ExprKind::Borrow { + region: *region, + borrow_kind: to_borrow_kind(m), + arg: expr.to_ref(), + }, }; expr = Expr { temp_lifetime: temp_lifetime, ty: adjusted_ty, span: self.span, - kind: ExprKind::Cast { source: expr.to_ref() } + kind: ExprKind::Cast { source: expr.to_ref() }, }; } } @@ -413,8 +422,10 @@ impl<'a,'tcx:'a> Mirror> for &'tcx hir::Expr { temp_lifetime: temp_lifetime, ty: expr.ty, span: self.span, - kind: ExprKind::Scope { extent: expr_extent, - value: expr.to_ref() } + kind: ExprKind::Scope { + extent: expr_extent, + value: expr.to_ref(), + }, }; // Finally, create a destruction scope, if any. @@ -423,7 +434,10 @@ impl<'a,'tcx:'a> Mirror> for &'tcx hir::Expr { temp_lifetime: temp_lifetime, ty: expr.ty, span: self.span, - kind: ExprKind::Scope { extent: extent, value: expr.to_ref() } + kind: ExprKind::Scope { + extent: extent, + value: expr.to_ref(), + }, }; } @@ -432,10 +446,10 @@ impl<'a,'tcx:'a> Mirror> for &'tcx hir::Expr { } } -fn method_callee<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>, - expr: &hir::Expr, - method_call: ty::MethodCall) - -> Expr> { +fn method_callee<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, + expr: &hir::Expr, + method_call: ty::MethodCall) + -> Expr<'tcx> { let tables = cx.tcx.tables.borrow(); let callee = &tables.method_map[&method_call]; let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id); @@ -447,8 +461,8 @@ fn method_callee<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>, literal: Literal::Item { def_id: callee.def_id, substs: callee.substs, - } - } + }, + }, } } @@ -459,87 +473,25 @@ fn to_borrow_kind(m: hir::Mutability) -> BorrowKind { } } -fn convert_literal<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>, - expr_span: Span, - expr_ty: Ty<'tcx>, - literal: &hir::Lit) - -> Literal> -{ - use repr::IntegralBits::*; - match (&literal.node, &expr_ty.sty) { - (&hir::LitStr(ref text, _), _) => - Literal::String { value: text.clone() }, - (&hir::LitByteStr(ref bytes), _) => - Literal::Bytes { value: bytes.clone() }, - (&hir::LitByte(c), _) => - Literal::Uint { bits: B8, value: c as u64 }, - (&hir::LitChar(c), _) => - Literal::Char { c: c }, - (&hir::LitInt(v, _), &ty::TyUint(hir::TyU8)) => - Literal::Uint { bits: B8, value: v }, - (&hir::LitInt(v, _), &ty::TyUint(hir::TyU16)) => - Literal::Uint { bits: B16, value: v }, - (&hir::LitInt(v, _), &ty::TyUint(hir::TyU32)) => - Literal::Uint { bits: B32, value: v }, - (&hir::LitInt(v, _), &ty::TyUint(hir::TyU64)) => - Literal::Uint { bits: B64, value: v }, - (&hir::LitInt(v, _), &ty::TyUint(hir::TyUs)) => - Literal::Uint { bits: BSize, value: v }, - (&hir::LitInt(v, hir::SignedIntLit(_, hir::Sign::Minus)), &ty::TyInt(hir::TyI8)) => - Literal::Int { bits: B8, value: -(v as i64) }, - (&hir::LitInt(v, hir::SignedIntLit(_, hir::Sign::Minus)), &ty::TyInt(hir::TyI16)) => - Literal::Int { bits: B16, value: -(v as i64) }, - (&hir::LitInt(v, hir::SignedIntLit(_, hir::Sign::Minus)), &ty::TyInt(hir::TyI32)) => - Literal::Int { bits: B32, value: -(v as i64) }, - (&hir::LitInt(v, hir::SignedIntLit(_, hir::Sign::Minus)), &ty::TyInt(hir::TyI64)) => - Literal::Int { bits: B64, value: -(v as i64) }, - (&hir::LitInt(v, hir::SignedIntLit(_, hir::Sign::Minus)), &ty::TyInt(hir::TyIs)) => - Literal::Int { bits: BSize, value: -(v as i64) }, - (&hir::LitInt(v, _), &ty::TyInt(hir::TyI8)) => - Literal::Int { bits: B8, value: v as i64 }, - (&hir::LitInt(v, _), &ty::TyInt(hir::TyI16)) => - Literal::Int { bits: B16, value: v as i64 }, - (&hir::LitInt(v, _), &ty::TyInt(hir::TyI32)) => - Literal::Int { bits: B32, value: v as i64 }, - (&hir::LitInt(v, _), &ty::TyInt(hir::TyI64)) => - Literal::Int { bits: B64, value: v as i64 }, - (&hir::LitInt(v, _), &ty::TyInt(hir::TyIs)) => - Literal::Int { bits: BSize, value: v as i64 }, - (&hir::LitFloat(ref v, _), &ty::TyFloat(hir::TyF32)) | - (&hir::LitFloatUnsuffixed(ref v), &ty::TyFloat(hir::TyF32)) => - Literal::Float { bits: FloatBits::F32, value: v.parse::().unwrap() }, - (&hir::LitFloat(ref v, _), &ty::TyFloat(hir::TyF64)) | - (&hir::LitFloatUnsuffixed(ref v), &ty::TyFloat(hir::TyF64)) => - Literal::Float { bits: FloatBits::F64, value: v.parse::().unwrap() }, - (&hir::LitBool(v), _) => - Literal::Bool { value: v }, - (ref l, ref t) => - cx.tcx.sess.span_bug( - expr_span, - &format!("Invalid literal/type combination: {:?},{:?}", l, t)) - } -} - -fn convert_arm<'a,'tcx:'a>(cx: &Cx<'a,'tcx>, arm: &'tcx hir::Arm) -> Arm> { +fn convert_arm<'a, 'tcx: 'a>(cx: &Cx<'a, 'tcx>, arm: &'tcx hir::Arm) -> Arm<'tcx> { let map = if arm.pats.len() == 1 { None } else { let mut map = FnvHashMap(); - pat_util::pat_bindings(&cx.tcx.def_map, &arm.pats[0], |_, p_id, _, path| { - map.insert(path.node, p_id); + pat_util::pat_bindings_hygienic(&cx.tcx.def_map, &arm.pats[0], |_, p_id, _, path| { + map.insert(mtwt::resolve(path.node), p_id); }); Some(Rc::new(map)) }; - Arm { patterns: arm.pats.iter().map(|p| PatNode::new(p, map.clone()).to_ref()).collect(), - guard: arm.guard.to_ref(), - body: arm.body.to_ref() } + Arm { + patterns: arm.pats.iter().map(|p| PatNode::new(p, map.clone()).to_ref()).collect(), + guard: arm.guard.to_ref(), + body: arm.body.to_ref(), + } } -fn convert_path_expr<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>, - expr: &'tcx hir::Expr) - -> ExprKind> -{ +fn convert_path_expr<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr) -> ExprKind<'tcx> { let substs = cx.tcx.mk_substs(cx.tcx.node_id_item_substs(expr.id).substs); match cx.tcx.def_map.borrow()[&expr.id].full_def() { def::DefVariant(_, def_id, false) | @@ -568,21 +520,20 @@ fn convert_path_expr<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>, } } -fn convert_var<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>, - expr: &'tcx hir::Expr, - def: def::Def) - -> ExprKind> -{ +fn convert_var<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, + expr: &'tcx hir::Expr, + def: def::Def) + -> ExprKind<'tcx> { let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id); match def { - def::DefLocal(node_id) => { + def::DefLocal(_, node_id) => { ExprKind::VarRef { id: node_id, } } - def::DefUpvar(id_var, index, closure_expr_id) => { + def::DefUpvar(_, id_var, index, closure_expr_id) => { debug!("convert_var(upvar({:?}, {:?}, {:?}))", id_var, index, closure_expr_id); let var_ty = cx.tcx.node_id_to_type(id_var); @@ -603,22 +554,18 @@ fn convert_var<'a,'tcx:'a>(cx: &mut Cx<'a,'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.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 // have a bound region with number 0 - let region = - ty::Region::ReFree( - ty::FreeRegion { - scope: cx.tcx.region_maps.node_extent(body_id), - bound_region: ty::BoundRegion::BrAnon(0) - }); - let region = - cx.tcx.mk_region(region); - - let self_expr = match cx.tcx.closure_kind(DefId::local(closure_expr_id)) { + let region = ty::Region::ReFree(ty::FreeRegion { + scope: cx.tcx.region_maps.node_extent(body_id), + bound_region: ty::BoundRegion::BrAnon(0), + }); + let region = cx.tcx.mk_region(region); + + let self_expr = match cx.tcx.closure_kind(cx.tcx.map.local_def_id(closure_expr_id)) { ty::ClosureKind::FnClosureKind => { let ref_closure_ty = cx.tcx.mk_ref(region, @@ -662,19 +609,23 @@ fn convert_var<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>, ty: closure_ty, temp_lifetime: temp_lifetime, span: expr.span, - kind: ExprKind::SelfRef + kind: ExprKind::SelfRef, } } }; // at this point we have `self.n`, which loads up the upvar - let field_kind = - ExprKind::Field { lhs: self_expr.to_ref(), - name: Field::Indexed(index) }; + let field_kind = ExprKind::Field { + lhs: self_expr.to_ref(), + name: Field::Indexed(index), + }; // ...but the upvar might be an `&T` or `&mut T` capture, at which // point we need an implicit deref - let upvar_id = ty::UpvarId { var_id: id_var, closure_expr_id: closure_expr_id }; + let upvar_id = ty::UpvarId { + var_id: id_var, + closure_expr_id: closure_expr_id, + }; let upvar_capture = match cx.tcx.upvar_capture(upvar_id) { Some(c) => c, None => { @@ -698,7 +649,7 @@ fn convert_var<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>, } } - _ => cx.tcx.sess.span_bug(expr.span, "type of & not region") + _ => cx.tcx.sess.span_bug(expr.span, "type of & not region"), } } @@ -721,23 +672,22 @@ fn bin_op(op: hir::BinOp_) -> BinOp { hir::BinOp_::BiNe => BinOp::Ne, hir::BinOp_::BiGe => BinOp::Ge, hir::BinOp_::BiGt => BinOp::Gt, - _ => panic!("no equivalent for ast binop {:?}", op) + _ => panic!("no equivalent for ast binop {:?}", op), } } enum PassArgs { ByValue, - ByRef + ByRef, } -fn overloaded_operator<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>, - expr: &'tcx hir::Expr, - method_call: ty::MethodCall, - pass_args: PassArgs, - receiver: ExprRef>, - args: Vec<&'tcx P>) - -> ExprKind> -{ +fn overloaded_operator<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, + expr: &'tcx hir::Expr, + method_call: ty::MethodCall, + pass_args: PassArgs, + receiver: ExprRef<'tcx>, + args: Vec<&'tcx P>) + -> ExprKind<'tcx> { // the receiver has all the adjustments that are needed, so we can // just push a reference to it let mut argrefs = vec![receiver]; @@ -746,9 +696,7 @@ fn overloaded_operator<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>, // operator, we have to gin up the autorefs (but by value is easy) match pass_args { PassArgs::ByValue => { - argrefs.extend( - args.iter() - .map(|arg| arg.to_ref())) + argrefs.extend(args.iter().map(|arg| arg.to_ref())) } PassArgs::ByRef => { @@ -783,14 +731,13 @@ fn overloaded_operator<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>, } } -fn overloaded_lvalue<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>, - expr: &'tcx hir::Expr, - method_call: ty::MethodCall, - pass_args: PassArgs, - receiver: ExprRef>, - args: Vec<&'tcx P>) - -> ExprKind> -{ +fn overloaded_lvalue<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, + expr: &'tcx hir::Expr, + method_call: ty::MethodCall, + pass_args: PassArgs, + receiver: ExprRef<'tcx>, + args: Vec<&'tcx P>) + -> ExprKind<'tcx> { // For an overloaded *x or x[y] expression of type T, the method // call returns an &T and we must add the deref so that the types // line up (this is because `*x` and `x[y]` represent lvalues): @@ -819,20 +766,25 @@ fn overloaded_lvalue<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>, ExprKind::Deref { arg: ref_expr.to_ref() } } -fn capture_freevar<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>, - closure_expr: &'tcx hir::Expr, - freevar: &ty::Freevar, - freevar_ty: Ty<'tcx>) - -> ExprRef> { - let id_var = freevar.def.def_id().node; - let upvar_id = ty::UpvarId { var_id: id_var, closure_expr_id: closure_expr.id }; +fn capture_freevar<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, + closure_expr: &'tcx hir::Expr, + freevar: &ty::Freevar, + freevar_ty: Ty<'tcx>) + -> ExprRef<'tcx> { + let id_var = freevar.def.var_id(); + let upvar_id = ty::UpvarId { + var_id: id_var, + closure_expr_id: closure_expr.id, + }; let upvar_capture = cx.tcx.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 captured_var = Expr { temp_lifetime: temp_lifetime, - ty: var_ty, - span: closure_expr.span, - kind: convert_var(cx, closure_expr, freevar.def) }; + let captured_var = Expr { + temp_lifetime: temp_lifetime, + ty: var_ty, + span: closure_expr.span, + kind: convert_var(cx, closure_expr, freevar.def), + }; match upvar_capture { ty::UpvarCapture::ByValue => { captured_var.to_ref() @@ -855,16 +807,11 @@ fn capture_freevar<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>, } } -fn loop_label<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>, - expr: &'tcx hir::Expr) - -> CodeExtent -{ +fn loop_label<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr) -> CodeExtent { match cx.tcx.def_map.borrow().get(&expr.id).map(|d| d.full_def()) { Some(def::DefLabel(loop_id)) => cx.tcx.region_maps.node_extent(loop_id), d => { - cx.tcx.sess.span_bug( - expr.span, - &format!("loop scope resolved to {:?}", d)); + cx.tcx.sess.span_bug(expr.span, &format!("loop scope resolved to {:?}", d)); } } } diff --git a/src/librustc_mir/tcx/mod.rs b/src/librustc_mir/tcx/mod.rs index 2e9eae0956..92b026e503 100644 --- a/src/librustc_mir/tcx/mod.rs +++ b/src/librustc_mir/tcx/mod.rs @@ -8,88 +8,86 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +/*! + * This module contains the code to convert from the wacky tcx data + * structures into the hair. The `builder` is generally ignorant of + * the tcx etc, and instead goes through the `Cx` for most of its + * work. + */ + use hair::*; use repr::*; -use std::fmt::{Debug, Formatter, Error}; -use std::hash::{Hash, Hasher}; -use std::rc::Rc; - -use self::rustc::middle::def_id::DefId; -use self::rustc::middle::infer::InferCtxt; -use self::rustc::middle::region::CodeExtent; -use self::rustc::middle::subst::{self, Subst, Substs}; -use self::rustc::middle::ty::{self, Ty}; -use self::rustc_front::hir; -use self::syntax::ast; -use self::syntax::codemap::Span; -use self::syntax::parse::token::{self, special_idents, InternedString}; - -extern crate rustc; -extern crate rustc_front; -extern crate syntax; + +use rustc::middle::const_eval::ConstVal; +use rustc::middle::def_id::DefId; +use rustc::middle::infer::InferCtxt; +use rustc::middle::subst::{Subst, Substs}; +use rustc::middle::ty::{self, Ty}; +use syntax::codemap::Span; +use syntax::parse::token::{self, special_idents}; #[derive(Copy, Clone)] -pub struct Cx<'a,'tcx:'a> { - pub tcx: &'a ty::ctxt<'tcx>, - pub infcx: &'a InferCtxt<'a,'tcx>, +pub struct Cx<'a, 'tcx: 'a> { + tcx: &'a ty::ctxt<'tcx>, + infcx: &'a InferCtxt<'a, 'tcx>, } impl<'a,'tcx> Cx<'a,'tcx> { - pub fn new(infcx: &'a InferCtxt<'a,'tcx>) -> Cx<'a,'tcx> { - Cx { tcx: infcx.tcx, infcx: infcx } + pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Cx<'a, 'tcx> { + Cx { + tcx: infcx.tcx, + infcx: infcx, + } } } pub use self::pattern::PatNode; -impl<'a,'tcx:'a> Hair for Cx<'a, 'tcx> { - type VarId = ast::NodeId; - type DefId = DefId; - type AdtDef = ty::AdtDef<'tcx>; - type Name = ast::Name; - type Ident = ast::Ident; - type InternedString = InternedString; - type Bytes = Rc>; - type Span = Span; - type Projection = ty::ProjectionTy<'tcx>; - type Substs = &'tcx subst::Substs<'tcx>; - type ClosureSubsts = &'tcx ty::ClosureSubsts<'tcx>; - type Ty = Ty<'tcx>; - type Region = ty::Region; - type CodeExtent = CodeExtent; - type Pattern = PatNode<'tcx>; - type Expr = &'tcx hir::Expr; - type Stmt = &'tcx hir::Stmt; - type Block = &'tcx hir::Block; - type InlineAsm = &'tcx hir::InlineAsm; - - fn unit_ty(&mut self) -> Ty<'tcx> { +impl<'a,'tcx:'a> Cx<'a, 'tcx> { + /// Normalizes `ast` into the appropriate `mirror` type. + pub fn mirror>(&mut self, ast: M) -> M::Output { + ast.make_mirror(self) + } + + pub fn unit_ty(&mut self) -> Ty<'tcx> { self.tcx.mk_nil() } - fn usize_ty(&mut self) -> Ty<'tcx> { + pub fn usize_ty(&mut self) -> Ty<'tcx> { self.tcx.types.usize } - fn bool_ty(&mut self) -> Ty<'tcx> { + pub fn usize_literal(&mut self, value: usize) -> Literal<'tcx> { + Literal::Value { value: ConstVal::Uint(value as u64) } + } + + pub fn bool_ty(&mut self) -> Ty<'tcx> { self.tcx.types.bool } - fn partial_eq(&mut self, ty: Ty<'tcx>) -> ItemRef { + pub fn true_literal(&mut self) -> Literal<'tcx> { + Literal::Value { value: ConstVal::Bool(true) } + } + + pub fn false_literal(&mut self) -> Literal<'tcx> { + Literal::Value { value: ConstVal::Bool(false) } + } + + pub fn partial_eq(&mut self, ty: Ty<'tcx>) -> ItemRef<'tcx> { let eq_def_id = self.tcx.lang_items.eq_trait().unwrap(); self.cmp_method_ref(eq_def_id, "eq", ty) } - fn partial_le(&mut self, ty: Ty<'tcx>) -> ItemRef { + pub fn partial_le(&mut self, ty: Ty<'tcx>) -> ItemRef<'tcx> { let ord_def_id = self.tcx.lang_items.ord_trait().unwrap(); self.cmp_method_ref(ord_def_id, "le", ty) } - fn num_variants(&mut self, adt_def: ty::AdtDef<'tcx>) -> usize { + pub fn num_variants(&mut self, adt_def: ty::AdtDef<'tcx>) -> usize { adt_def.variants.len() } - fn fields(&mut self, adt_def: ty::AdtDef<'tcx>, variant_index: usize) -> Vec> { + pub fn fields(&mut self, adt_def: ty::AdtDef<'tcx>, variant_index: usize) -> Vec { adt_def.variants[variant_index] .fields .iter() @@ -104,7 +102,7 @@ impl<'a,'tcx:'a> Hair for Cx<'a, 'tcx> { .collect() } - fn needs_drop(&mut self, ty: Ty<'tcx>, span: Self::Span) -> bool { + pub fn needs_drop(&mut self, ty: Ty<'tcx>, span: Span) -> bool { if self.infcx.type_moves_by_default(ty, span) { // FIXME(#21859) we should do an add'l check here to determine if // any dtor will execute, but the relevant fn @@ -117,17 +115,19 @@ impl<'a,'tcx:'a> Hair for Cx<'a, 'tcx> { } } - fn span_bug(&mut self, span: Self::Span, message: &str) -> ! { + pub fn span_bug(&mut self, span: Span, message: &str) -> ! { self.tcx.sess.span_bug(span, message) } -} -impl<'a,'tcx:'a> Cx<'a,'tcx> { + pub fn tcx(&self) -> &'a ty::ctxt<'tcx> { + self.tcx + } + fn cmp_method_ref(&mut self, trait_def_id: DefId, method_name: &str, arg_ty: Ty<'tcx>) - -> ItemRef> { + -> ItemRef<'tcx> { let method_name = token::intern(method_name); let substs = Substs::new_trait(vec![arg_ty], vec![], arg_ty); for trait_item in self.tcx.trait_items(trait_def_id).iter() { @@ -144,36 +144,11 @@ impl<'a,'tcx:'a> Cx<'a,'tcx> { } } ty::ImplOrTraitItem::ConstTraitItem(..) | - ty::ImplOrTraitItem::TypeTraitItem(..) => { - } + ty::ImplOrTraitItem::TypeTraitItem(..) => {} } } - self.tcx.sess.bug( - &format!("found no method `{}` in `{:?}`", method_name, trait_def_id)); - } -} - -// We only need this impl so that we do deriving for things that are -// defined relative to the `Hair` trait. See `Hair` trait for more -// details. -impl<'a,'tcx> PartialEq for Cx<'a,'tcx> { - fn eq(&self, _: &Cx<'a,'tcx>) -> bool { - panic!("Cx should never ACTUALLY be compared for equality") - } -} - -impl<'a,'tcx> Eq for Cx<'a,'tcx> { } - -impl<'a,'tcx> Hash for Cx<'a,'tcx> { - fn hash(&self, _: &mut H) { - panic!("Cx should never ACTUALLY be hashed") - } -} - -impl<'a,'tcx> Debug for Cx<'a,'tcx> { - fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { - write!(fmt, "Tcx") + self.tcx.sess.bug(&format!("found no method `{}` in `{:?}`", method_name, trait_def_id)); } } @@ -181,4 +156,3 @@ mod block; mod expr; mod pattern; mod to_ref; - diff --git a/src/librustc_mir/tcx/pattern.rs b/src/librustc_mir/tcx/pattern.rs index eee0911f1c..bb68ae825f 100644 --- a/src/librustc_mir/tcx/pattern.rs +++ b/src/librustc_mir/tcx/pattern.rs @@ -14,14 +14,16 @@ use repr::*; use rustc_data_structures::fnv::FnvHashMap; use std::rc::Rc; use tcx::Cx; -use tcx::rustc::middle::const_eval::lookup_const_by_id; -use tcx::rustc::middle::def; -use tcx::rustc::middle::pat_util::{pat_is_resolved_const, pat_is_binding}; -use tcx::rustc::middle::ty::{self, Ty}; -use tcx::rustc_front::hir; -use tcx::syntax::ast; -use tcx::syntax::ptr::P; use tcx::to_ref::ToRef; +use rustc::middle::const_eval; +use rustc::middle::def; +use rustc::middle::pat_util::{pat_is_resolved_const, pat_is_binding}; +use rustc::middle::subst::Substs; +use rustc::middle::ty::{self, Ty}; +use rustc_front::hir; +use syntax::ast; +use syntax::ext::mtwt; +use syntax::ptr::P; /// When there are multiple patterns in a single arm, each one has its /// own node-ids for the bindings. References to the variables always @@ -39,12 +41,12 @@ use tcx::to_ref::ToRef; #[derive(Clone, Debug)] pub struct PatNode<'tcx> { pat: &'tcx hir::Pat, - binding_map: Option>> + binding_map: Option>>, } impl<'tcx> PatNode<'tcx> { pub fn new(pat: &'tcx hir::Pat, - binding_map: Option>>) + binding_map: Option>>) -> PatNode<'tcx> { PatNode { pat: pat, @@ -52,20 +54,19 @@ impl<'tcx> PatNode<'tcx> { } } - pub fn irrefutable(pat: &'tcx hir::Pat) - -> PatNode<'tcx> { + pub fn irrefutable(pat: &'tcx hir::Pat) -> PatNode<'tcx> { PatNode::new(pat, None) } - fn pat_ref<'a>(&self, pat: &'tcx hir::Pat) -> PatternRef> { + fn pat_ref<'a>(&self, pat: &'tcx hir::Pat) -> PatternRef<'tcx> { PatNode::new(pat, self.binding_map.clone()).to_ref() } - fn pat_refs<'a>(&self, pats: &'tcx Vec>) -> Vec>> { + fn pat_refs<'a>(&self, pats: &'tcx Vec>) -> Vec> { pats.iter().map(|p| self.pat_ref(p)).collect() } - fn opt_pat_ref<'a>(&self, pat: &'tcx Option>) -> Option>> { + fn opt_pat_ref<'a>(&self, pat: &'tcx Option>) -> Option> { pat.as_ref().map(|p| self.pat_ref(p)) } @@ -75,8 +76,7 @@ impl<'tcx> PatNode<'tcx> { prefix: &'tcx Vec>, slice: &'tcx Option>, suffix: &'tcx Vec>) - -> PatternKind> - { + -> PatternKind<'tcx> { match ty.sty { ty::TySlice(..) => // matching a slice or fixed-length array @@ -97,26 +97,25 @@ impl<'tcx> PatNode<'tcx> { } _ => { - cx.tcx.sess.span_bug( - self.pat.span, - "unexpanded macro or bad constant etc"); + cx.tcx.sess.span_bug(self.pat.span, "unexpanded macro or bad constant etc"); } } } fn variant_or_leaf<'a>(&self, cx: &mut Cx<'a, 'tcx>, - subpatterns: Vec>>) - -> PatternKind> - { + subpatterns: Vec>) + -> PatternKind<'tcx> { let def = cx.tcx.def_map.borrow().get(&self.pat.id).unwrap().full_def(); match def { def::DefVariant(enum_id, variant_id, _) => { let adt_def = 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 } + PatternKind::Variant { + adt_def: adt_def, + variant_index: adt_def.variant_index_with_id(variant_id), + subpatterns: subpatterns, + } } else { PatternKind::Leaf { subpatterns: subpatterns } } @@ -129,28 +128,33 @@ impl<'tcx> PatNode<'tcx> { } _ => { - cx.tcx.sess.span_bug( - self.pat.span, - &format!("inappropriate def for pattern: {:?}", def)); + cx.tcx.sess.span_bug(self.pat.span, + &format!("inappropriate def for pattern: {:?}", def)); } } } } -impl<'a,'tcx:'a> Mirror> for PatNode<'tcx> { - type Output = Pattern>; +impl<'tcx> Mirror<'tcx> for PatNode<'tcx> { + type Output = Pattern<'tcx>; - fn make_mirror(self, cx: &mut Cx<'a,'tcx>) -> Pattern> { + fn make_mirror<'a>(self, cx: &mut Cx<'a, 'tcx>) -> Pattern<'tcx> { let kind = match self.pat.node { - hir::PatWild(..) => - PatternKind::Wild, + hir::PatWild(..) => PatternKind::Wild, - hir::PatLit(ref lt) => - PatternKind::Constant { expr: lt.to_ref() }, + hir::PatLit(ref value) => { + let value = const_eval::eval_const_expr(cx.tcx, value); + let value = Literal::Value { value: value }; + PatternKind::Constant { value: value } + } - hir::PatRange(ref begin, ref end) => - PatternKind::Range { lo: begin.to_ref(), - hi: end.to_ref() }, + hir::PatRange(ref lo, ref hi) => { + let lo = const_eval::eval_const_expr(cx.tcx, lo); + let lo = Literal::Value { value: lo }; + let hi = const_eval::eval_const_expr(cx.tcx, hi); + let hi = Literal::Value { value: hi }; + PatternKind::Range { lo: lo, hi: hi } + }, hir::PatEnum(..) | hir::PatIdent(..) | hir::PatQPath(..) if pat_is_resolved_const(&cx.tcx.def_map, self.pat) => @@ -158,13 +162,26 @@ impl<'a,'tcx:'a> Mirror> for PatNode<'tcx> { let def = cx.tcx.def_map.borrow().get(&self.pat.id).unwrap().full_def(); match def { def::DefConst(def_id) | def::DefAssociatedConst(def_id) => - match lookup_const_by_id(cx.tcx, def_id, Some(self.pat.id)) { - Some(const_expr) => - PatternKind::Constant { expr: const_expr.to_ref() }, - None => + match const_eval::lookup_const_by_id(cx.tcx, def_id, Some(self.pat.id)) { + Some(const_expr) => { + let opt_value = + const_eval::eval_const_expr_partial( + cx.tcx, const_expr, + const_eval::EvalHint::ExprTypeChecked, + None); + let literal = if let Ok(value) = opt_value { + Literal::Value { value: value } + } else { + let substs = cx.tcx.mk_substs(Substs::empty()); + Literal::Item { def_id: def_id, substs: substs } + }; + PatternKind::Constant { value: literal } + } + None => { cx.tcx.sess.span_bug( self.pat.span, - &format!("cannot eval constant: {:?}", def_id)), + &format!("cannot eval constant: {:?}", def_id)) + } }, _ => cx.tcx.sess.span_bug( @@ -220,7 +237,7 @@ impl<'a,'tcx:'a> Mirror> for PatNode<'tcx> { { let id = match self.binding_map { None => self.pat.id, - Some(ref map) => map[&ident.node], + Some(ref map) => map[&mtwt::resolve(ident.node)], }; let var_ty = cx.tcx.node_id_to_type(self.pat.id); let region = match var_ty.sty { @@ -240,7 +257,7 @@ impl<'a,'tcx:'a> Mirror> for PatNode<'tcx> { PatternKind::Binding { mutability: mutability, mode: mode, - name: ident.node, + name: ident.node.name, var: id, ty: var_ty, subpattern: self.opt_pat_ref(sub), @@ -268,7 +285,7 @@ impl<'a,'tcx:'a> Mirror> for PatNode<'tcx> { let subpatterns = fields.iter() .map(|field| FieldPatternRef { - field: Field::Named(field.node.ident.name), + field: Field::Named(field.node.name), pattern: self.pat_ref(&field.node.pat), }) .collect(); @@ -276,16 +293,16 @@ impl<'a,'tcx:'a> Mirror> for PatNode<'tcx> { } hir::PatQPath(..) => { - cx.tcx.sess.span_bug( - self.pat.span, - "unexpanded macro or bad constant etc"); + cx.tcx.sess.span_bug(self.pat.span, "unexpanded macro or bad constant etc"); } }; let ty = cx.tcx.node_id_to_type(self.pat.id); - Pattern { span: self.pat.span, - ty: ty, - kind: kind } + Pattern { + span: self.pat.span, + ty: ty, + kind: kind, + } } } diff --git a/src/librustc_mir/tcx/to_ref.rs b/src/librustc_mir/tcx/to_ref.rs index 6d5e4c2e3f..13ca82e3e4 100644 --- a/src/librustc_mir/tcx/to_ref.rs +++ b/src/librustc_mir/tcx/to_ref.rs @@ -11,58 +11,57 @@ use hair::*; use repr::*; -use tcx::Cx; use tcx::pattern::PatNode; -use tcx::rustc_front::hir; -use tcx::syntax::ptr::P; +use rustc_front::hir; +use syntax::ptr::P; -pub trait ToRef { +pub trait ToRef { type Output; fn to_ref(self) -> Self::Output; } -impl<'a,'tcx:'a> ToRef> for &'tcx hir::Expr { - type Output = ExprRef>; +impl<'a,'tcx:'a> ToRef for &'tcx hir::Expr { + type Output = ExprRef<'tcx>; - fn to_ref(self) -> ExprRef> { + fn to_ref(self) -> ExprRef<'tcx> { ExprRef::Hair(self) } } -impl<'a,'tcx:'a> ToRef> for &'tcx P { - type Output = ExprRef>; +impl<'a,'tcx:'a> ToRef for &'tcx P { + type Output = ExprRef<'tcx>; - fn to_ref(self) -> ExprRef> { + fn to_ref(self) -> ExprRef<'tcx> { ExprRef::Hair(&**self) } } -impl<'a,'tcx:'a> ToRef> for Expr> { - type Output = ExprRef>; +impl<'a,'tcx:'a> ToRef for Expr<'tcx> { + type Output = ExprRef<'tcx>; - fn to_ref(self) -> ExprRef> { + fn to_ref(self) -> ExprRef<'tcx> { ExprRef::Mirror(Box::new(self)) } } -impl<'a,'tcx:'a> ToRef> for PatNode<'tcx> { - type Output = PatternRef>; +impl<'a,'tcx:'a> ToRef for PatNode<'tcx> { + type Output = PatternRef<'tcx>; - fn to_ref(self) -> PatternRef> { + fn to_ref(self) -> PatternRef<'tcx> { PatternRef::Hair(self) } } -impl<'a,'tcx:'a> ToRef> for Pattern> { - type Output = PatternRef>; +impl<'a,'tcx:'a> ToRef for Pattern<'tcx> { + type Output = PatternRef<'tcx>; - fn to_ref(self) -> PatternRef> { + fn to_ref(self) -> PatternRef<'tcx> { PatternRef::Mirror(Box::new(self)) } } -impl<'a,'tcx:'a,T,U> ToRef> for &'tcx Option - where &'tcx T: ToRef, Output=U> +impl<'a,'tcx:'a,T,U> ToRef for &'tcx Option + where &'tcx T: ToRef { type Output = Option; @@ -71,8 +70,8 @@ impl<'a,'tcx:'a,T,U> ToRef> for &'tcx Option } } -impl<'a,'tcx:'a,T,U> ToRef> for &'tcx Vec - where &'tcx T: ToRef, Output=U> +impl<'a,'tcx:'a,T,U> ToRef for &'tcx Vec + where &'tcx T: ToRef { type Output = Vec; @@ -81,14 +80,13 @@ impl<'a,'tcx:'a,T,U> ToRef> for &'tcx Vec } } -impl<'a,'tcx:'a> ToRef> for &'tcx hir::Field { - type Output = FieldExprRef>; +impl<'a,'tcx:'a> ToRef for &'tcx hir::Field { + type Output = FieldExprRef<'tcx>; - fn to_ref(self) -> FieldExprRef> { + fn to_ref(self) -> FieldExprRef<'tcx> { FieldExprRef { - name: Field::Named(self.ident.node.name), - expr: self.expr.to_ref() + name: Field::Named(self.name.node), + expr: self.expr.to_ref(), } } } - diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 48efd34e21..dd990abaa9 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -82,7 +82,7 @@ impl<'v> Visitor<'v> for ParentVisitor { // The parent is considered the enclosing enum because the // enum will dictate the privacy visibility of this variant // instead. - self.parents.insert(variant.node.id, item.id); + self.parents.insert(variant.node.data.id(), item.id); } } @@ -128,18 +128,17 @@ impl<'v> Visitor<'v> for ParentVisitor { visit::walk_impl_item(self, ii); } - fn visit_struct_def(&mut self, s: &hir::StructDef, _: ast::Ident, - _: &'v hir::Generics, n: ast::NodeId) { + fn visit_variant_data(&mut self, s: &hir::VariantData, _: ast::Name, + _: &'v hir::Generics, item_id: ast::NodeId, _: Span) { // Struct constructors are parented to their struct definitions because // they essentially are the struct definitions. - match s.ctor_id { - Some(id) => { self.parents.insert(id, n); } - None => {} + if !s.is_struct() { + self.parents.insert(s.id(), item_id); } // While we have the id of the struct definition, go ahead and parent // all the fields. - for field in &s.fields { + for field in s.fields() { self.parents.insert(field.node.id, self.curparent); } visit::walk_struct_def(self, s) @@ -234,8 +233,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { // public all variants are public unless they're explicitly priv hir::ItemEnum(ref def, _) if public_first => { for variant in &def.variants { - self.exported_items.insert(variant.node.id); - self.public_items.insert(variant.node.id); + self.exported_items.insert(variant.node.data.id()); + self.public_items.insert(variant.node.data.id()); } } @@ -263,19 +262,26 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { hir::TyPath(..) => { match self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def() { def::DefPrimTy(..) => true, + def::DefSelfTy(..) => true, def => { let did = def.def_id(); - !did.is_local() || - self.exported_items.contains(&did.node) + if let Some(node_id) = self.tcx.map.as_local_node_id(did) { + self.exported_items.contains(&node_id) + } else { + true + } } } } _ => true, }; - let tr = self.tcx.impl_trait_ref(DefId::local(item.id)); + let tr = self.tcx.impl_trait_ref(self.tcx.map.local_def_id(item.id)); let public_trait = tr.clone().map_or(false, |tr| { - !tr.def_id.is_local() || - self.exported_items.contains(&tr.def_id.node) + if let Some(node_id) = self.tcx.map.as_local_node_id(tr.def_id) { + self.exported_items.contains(&node_id) + } else { + true + } }); if public_ty || public_trait { @@ -313,12 +319,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { // Struct constructors are public if the struct is all public. hir::ItemStruct(ref def, _) if public_first => { - match def.ctor_id { - Some(id) => { self.exported_items.insert(id); } - None => {} + if !def.is_struct() { + self.exported_items.insert(def.id()); } // fields can be public or private, so lets check - for field in &def.fields { + for field in def.fields() { let vis = match field.node.kind { hir::NamedField(_, vis) | hir::UnnamedField(vis) => vis }; @@ -331,11 +336,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { hir::ItemTy(ref ty, _) if public_first => { if let hir::TyPath(..) = ty.node { match self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def() { - def::DefPrimTy(..) | def::DefTyParam(..) => {}, + def::DefPrimTy(..) | def::DefSelfTy(..) | def::DefTyParam(..) => {}, def => { let did = def.def_id(); - if did.is_local() { - self.exported_items.insert(did.node); + if let Some(node_id) = self.tcx.map.as_local_node_id(did) { + self.exported_items.insert(node_id); } } } @@ -363,8 +368,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { if self.prev_exported { assert!(self.export_map.contains_key(&id), "wut {}", id); for export in self.export_map.get(&id).unwrap() { - if export.def_id.is_local() { - self.reexports.insert(export.def_id.node); + if let Some(node_id) = self.tcx.map.as_local_node_id(export.def_id) { + self.reexports.insert(node_id); } } } @@ -384,6 +389,7 @@ struct PrivacyVisitor<'a, 'tcx: 'a> { external_exports: ExternalExports, } +#[derive(Debug)] enum PrivacyResult { Allowable, ExternallyDenied, @@ -392,7 +398,6 @@ enum PrivacyResult { enum FieldName { UnnamedField(usize), // index - // (Name, not Ident, because struct fields are not macro-hygienic) NamedField(ast::Name), } @@ -405,7 +410,9 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { // Determines whether the given definition is public from the point of view // of the current item. fn def_privacy(&self, did: DefId) -> PrivacyResult { - if !did.is_local() { + let node_id = if let Some(node_id) = self.tcx.map.as_local_node_id(did) { + node_id + } else { if self.external_exports.contains(&did) { debug!("privacy - {:?} was externally exported", did); return Allowable; @@ -497,19 +504,19 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { ExternallyDenied } }; - } + }; debug!("privacy - local {} not public all the way down", - self.tcx.map.node_to_string(did.node)); + self.tcx.map.node_to_string(node_id)); // return quickly for things in the same module - if self.parents.get(&did.node) == self.parents.get(&self.curitem) { + if self.parents.get(&node_id) == self.parents.get(&self.curitem) { debug!("privacy - same parent, we're done here"); return Allowable; } // We now know that there is at least one private member between the // destination and the root. - let mut closest_private_id = did.node; + let mut closest_private_id = node_id; loop { debug!("privacy - examining {}", self.nodestr(closest_private_id)); let vis = match self.tcx.map.find(closest_private_id) { @@ -579,6 +586,15 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { } } + /// True if `id` is both local and private-accessible + fn local_private_accessible(&self, did: DefId) -> bool { + if let Some(node_id) = self.tcx.map.as_local_node_id(did) { + self.private_accessible(node_id) + } else { + false + } + } + /// For a local private node in the AST, this function will determine /// whether the node is accessible by the current module that iteration is /// inside. @@ -630,9 +646,17 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { /// Guarantee that a particular definition is public. Returns a CheckResult /// which contains any errors found. These can be reported using `report_error`. /// If the result is `None`, no errors were found. - fn ensure_public(&self, span: Span, to_check: DefId, - source_did: Option, msg: &str) -> CheckResult { - let id = match self.def_privacy(to_check) { + fn ensure_public(&self, + span: Span, + to_check: DefId, + source_did: Option, + msg: &str) + -> CheckResult { + debug!("ensure_public(span={:?}, to_check={:?}, source_did={:?}, msg={:?})", + span, to_check, source_did, msg); + let def_privacy = self.def_privacy(to_check); + debug!("ensure_public: def_privacy={:?}", def_privacy); + let id = match def_privacy { ExternallyDenied => { return Some((span, format!("{} is private", msg), None)) } @@ -640,11 +664,15 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { DisallowedBy(id) => id, }; - // If we're disallowed by a particular id, then we attempt to give a - // nice error message to say why it was disallowed. It was either - // because the item itself is private or because its parent is private - // and its parent isn't in our ancestry. - let (err_span, err_msg) = if id == source_did.unwrap_or(to_check).node { + // If we're disallowed by a particular id, then we attempt to + // give a nice error message to say why it was disallowed. It + // was either because the item itself is private or because + // its parent is private and its parent isn't in our + // ancestry. (Both the item being checked and its parent must + // be local.) + let def_id = source_did.unwrap_or(to_check); + let node_id = self.tcx.map.as_local_node_id(def_id); + let (err_span, err_msg) = if Some(id) == node_id { return Some((span, format!("{} is private", msg), None)); } else { (span, format!("{} is inaccessible", msg)) @@ -664,8 +692,8 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { }; let def = self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def(); let did = def.def_id(); - assert!(did.is_local()); - match self.tcx.map.get(did.node) { + let node_id = self.tcx.map.as_local_node_id(did).unwrap(); + match self.tcx.map.get(node_id) { ast_map::NodeItem(item) => item, _ => self.tcx.sess.span_bug(item.span, "path is not an item") @@ -683,7 +711,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { hir::ItemEnum(..) => "enum", _ => return Some((err_span, err_msg, None)) }; - let msg = format!("{} `{}` is private", desc, item.ident); + let msg = format!("{} `{}` is private", desc, item.name); Some((err_span, err_msg, Some((span, msg)))) } @@ -700,9 +728,8 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { } UnnamedField(idx) => &v.fields[idx] }; - if field.vis == hir::Public || - (field.did.is_local() && self.private_accessible(field.did.node)) { - return + if field.vis == hir::Public || self.local_private_accessible(field.did) { + return; } let struct_desc = match def.adt_kind() { @@ -726,19 +753,6 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { span: Span, method_id: DefId, name: ast::Name) { - // If the method is a default method, we need to use the def_id of - // the default implementation. - let method_id = match self.tcx.impl_or_trait_item(method_id) { - ty::MethodTraitItem(method_type) => { - method_type.provided_source.unwrap_or(method_id) - } - _ => { - self.tcx.sess - .span_bug(span, - "got non-method item in check_static_method") - } - }; - self.report_error(self.ensure_public(span, method_id, None, @@ -859,23 +873,6 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { - if let hir::ItemUse(ref vpath) = item.node { - if let hir::ViewPathList(ref prefix, ref list) = vpath.node { - for pid in list { - match pid.node { - hir::PathListIdent { id, name, .. } => { - debug!("privacy - ident item {}", id); - self.check_path(pid.span, id, name.name); - } - hir::PathListMod { id, .. } => { - debug!("privacy - mod item {}", id); - let name = prefix.segments.last().unwrap().identifier.name; - self.check_path(pid.span, id, name); - } - } - } - } - } let orig_curitem = replace(&mut self.curitem, item.id); visit::walk_item(self, item); self.curitem = orig_curitem; @@ -883,12 +880,12 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &hir::Expr) { match expr.node { - hir::ExprField(ref base, ident) => { + hir::ExprField(ref base, name) => { if let ty::TyStruct(def, _) = self.tcx.expr_ty_adjusted(&**base).sty { self.check_field(expr.span, def, def.struct_variant(), - NamedField(ident.node.name)); + NamedField(name.node)); } } hir::ExprTupField(ref base, idx) => { @@ -899,11 +896,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { UnnamedField(idx.node)); } } - hir::ExprMethodCall(ident, _, _) => { + hir::ExprMethodCall(name, _, _) => { let method_call = ty::MethodCall::expr(expr.id); let method = self.tcx.tables.borrow().method_map[&method_call]; debug!("(privacy checking) checking impl method"); - self.check_method(expr.span, method.def_id, ident.node.name); + self.check_method(expr.span, method.def_id, name.node); } hir::ExprStruct(..) => { let adt = self.tcx.expr_ty(expr).ty_adt_def().unwrap(); @@ -926,11 +923,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { _ => expr_ty }.ty_adt_def().unwrap(); let any_priv = def.struct_variant().fields.iter().any(|f| { - f.vis != hir::Public && ( - !f.did.is_local() || - !self.private_accessible(f.did.node)) - }); - + f.vis != hir::Public && !self.local_private_accessible(f.did) + }); if any_priv { span_err!(self.tcx.sess, expr.span, E0450, "cannot invoke tuple struct constructor with private \ @@ -958,7 +952,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { let variant = adt.variant_of_def(def); for field in fields { self.check_field(pattern.span, adt, variant, - NamedField(field.node.ident.name)); + NamedField(field.node.name)); } } @@ -997,8 +991,22 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { } fn visit_path(&mut self, path: &hir::Path, id: ast::NodeId) { - self.check_path(path.span, id, path.segments.last().unwrap().identifier.name); - visit::walk_path(self, path); + if !path.segments.is_empty() { + self.check_path(path.span, id, path.segments.last().unwrap().identifier.name); + visit::walk_path(self, path); + } + } + + fn visit_path_list_item(&mut self, prefix: &hir::Path, item: &hir::PathListItem) { + let name = if let hir::PathListIdent { name, .. } = item.node { + name + } else if !prefix.segments.is_empty() { + prefix.segments.last().unwrap().identifier.name + } else { + self.tcx.sess.bug("`self` import in an import list with empty prefix"); + }; + self.check_path(item.span, item.node.id(), name); + visit::walk_path_list_item(self, prefix, item); } } @@ -1075,20 +1083,7 @@ impl<'a, 'tcx> SanePrivacyVisitor<'a, 'tcx> { instead"); } - hir::ItemEnum(ref def, _) => { - for v in &def.variants { - match v.node.vis { - hir::Public => { - if item.vis == hir::Public { - span_err!(tcx.sess, v.span, E0448, - "unnecessary `pub` visibility"); - } - } - hir::Inherited => {} - } - } - } - + hir::ItemEnum(..) | hir::ItemTrait(..) | hir::ItemDefaultImpl(..) | hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemStruct(..) | hir::ItemFn(..) | hir::ItemMod(..) | hir::ItemTy(..) | @@ -1106,8 +1101,8 @@ impl<'a, 'tcx> SanePrivacyVisitor<'a, 'tcx> { "visibility has no effect inside functions"); } } - let check_struct = |def: &hir::StructDef| { - for f in &def.fields { + let check_struct = |def: &hir::VariantData| { + for f in def.fields() { match f.node.kind { hir::NamedField(_, p) => check_inherited(tcx, f.span, p), hir::UnnamedField(..) => {} @@ -1131,14 +1126,10 @@ impl<'a, 'tcx> SanePrivacyVisitor<'a, 'tcx> { check_inherited(tcx, i.span, i.vis); } } - hir::ItemEnum(ref def, _) => { - for v in &def.variants { - check_inherited(tcx, v.span, v.node.vis); - } - } - hir::ItemStruct(ref def, _) => check_struct(&**def), + hir::ItemStruct(ref def, _) => check_struct(def), + hir::ItemEnum(..) | hir::ItemExternCrate(_) | hir::ItemUse(_) | hir::ItemTrait(..) | hir::ItemDefaultImpl(..) | hir::ItemStatic(..) | hir::ItemConst(..) | @@ -1169,21 +1160,22 @@ impl<'a, 'tcx> VisiblePrivateTypesVisitor<'a, 'tcx> { fn path_is_private_type(&self, path_id: ast::NodeId) -> bool { let did = match self.tcx.def_map.borrow().get(&path_id).map(|d| d.full_def()) { // `int` etc. (None doesn't seem to occur.) - None | Some(def::DefPrimTy(..)) => return false, + None | Some(def::DefPrimTy(..)) | Some(def::DefSelfTy(..)) => return false, Some(def) => def.def_id(), }; + // A path can only be private if: // it's in this crate... - if !did.is_local() { + if let Some(node_id) = self.tcx.map.as_local_node_id(did) { + // .. and it corresponds to a private type in the AST (this returns + // None for type parameters) + match self.tcx.map.find(node_id) { + Some(ast_map::NodeItem(ref item)) => item.vis != hir::Public, + Some(_) | None => false, + } + } else { return false } - - // .. and it corresponds to a private type in the AST (this returns - // None for type parameters) - match self.tcx.map.find(did.node) { - Some(ast_map::NodeItem(ref item)) => item.vis != hir::Public, - Some(_) | None => false, - } } fn trait_is_public(&self, trait_id: ast::NodeId) -> bool { @@ -1283,7 +1275,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> { |tr| { let did = self.tcx.trait_ref_to_def_id(tr); - !did.is_local() || self.trait_is_public(did.node) + if let Some(node_id) = self.tcx.map.as_local_node_id(did) { + self.trait_is_public(node_id) + } else { + true // external traits must be public + } }); // `true` iff this is a trait impl or at least one method is public. @@ -1447,20 +1443,20 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> { visit::walk_ty(self, t) } - fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics) { - if self.exported_items.contains(&v.node.id) { + fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics, item_id: ast::NodeId) { + if self.exported_items.contains(&v.node.data.id()) { self.in_variant = true; - visit::walk_variant(self, v, g); + visit::walk_variant(self, v, g, item_id); self.in_variant = false; } } fn visit_struct_field(&mut self, s: &hir::StructField) { - match s.node.kind { - hir::NamedField(_, vis) if vis == hir::Public || self.in_variant => { - visit::walk_struct_field(self, s); - } - _ => {} + let vis = match s.node.kind { + hir::NamedField(_, vis) | hir::UnnamedField(vis) => vis + }; + if vis == hir::Public || self.in_variant { + visit::walk_struct_field(self, s); } } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 6e72e51d9f..0bbceafa4a 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -34,9 +34,10 @@ use self::NamespaceError::*; use rustc::metadata::csearch; use rustc::metadata::decoder::{DefLike, DlDef, DlField, DlImpl}; use rustc::middle::def::*; -use rustc::middle::def_id::DefId; +use rustc::middle::def_id::{CRATE_DEF_INDEX, DefId}; use syntax::ast::{Name, NodeId}; +use syntax::attr::AttrMetaMethods; use syntax::parse::token::special_idents; use syntax::codemap::{Span, DUMMY_SP}; @@ -48,12 +49,9 @@ use rustc_front::hir::{ItemForeignMod, ItemImpl, ItemMod, ItemStatic, ItemDefaul use rustc_front::hir::{ItemStruct, ItemTrait, ItemTy, ItemUse}; use rustc_front::hir::{NamedField, PathListIdent, PathListMod, Public}; use rustc_front::hir::StmtDecl; -use rustc_front::hir::StructVariantKind; -use rustc_front::hir::TupleVariantKind; use rustc_front::hir::UnnamedField; use rustc_front::hir::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple}; use rustc_front::hir::Visibility; -use rustc_front::attr::AttrMetaMethods; use rustc_front::visit::{self, Visitor}; use std::mem::replace; @@ -263,7 +261,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { /// Constructs the reduced graph for one item. fn build_reduced_graph_for_item(&mut self, item: &Item, parent: &Rc) -> Rc { - let name = item.ident.name; + let name = item.name; let sp = item.span; let is_public = item.vis == hir::Public; let modifiers = if is_public { @@ -281,14 +279,14 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { ViewPathSimple(_, ref full_path) => { full_path.segments .split_last().unwrap().1 - .iter().map(|ident| ident.identifier.name) + .iter().map(|seg| seg.identifier.name) .collect() } ViewPathGlob(ref module_ident_path) | ViewPathList(ref module_ident_path, _) => { module_ident_path.segments - .iter().map(|ident| ident.identifier.name).collect() + .iter().map(|seg| seg.identifier.name).collect() } }; @@ -312,8 +310,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { ResolutionError::SelfImportsOnlyAllowedWithin); } - let subclass = SingleImport(binding.name, - source_name); + let subclass = SingleImport(binding, source_name); self.build_import_directive(&**parent, module_path, subclass, @@ -343,7 +340,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { for source_item in source_items { let (module_path, name, rename) = match source_item.node { PathListIdent { name, rename, .. } => - (module_path.clone(), name.name, rename.unwrap_or(name).name), + (module_path.clone(), name, rename.unwrap_or(name)), PathListMod { rename, .. } => { let name = match module_path.last() { Some(name) => *name, @@ -358,7 +355,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { } }; let module_path = module_path.split_last().unwrap().1; - let rename = rename.map(|n| n.name).unwrap_or(name); + let rename = rename.unwrap_or(name); (module_path.to_vec(), name, rename) } }; @@ -388,7 +385,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { ItemExternCrate(_) => { // 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.find_extern_mod_stmt_cnum(item.id) { - let def_id = DefId { krate: crate_id, node: 0 }; + let def_id = DefId { krate: crate_id, index: CRATE_DEF_INDEX }; self.external_exports.insert(def_id); let parent_link = ModuleParentLink(Rc::downgrade(parent), name); let external_module = Rc::new(Module::new(parent_link, @@ -407,10 +404,33 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { } ItemMod(..) => { + let child = parent.children.borrow().get(&name).cloned(); + if let Some(child) = child { + // check if there's struct of the same name already defined + if child.defined_in_namespace(TypeNS) + && child.get_module_if_available().is_none() { + self.session.span_warn(sp, &format!( + "duplicate definition of {} `{}`. \ + Defining a module and a struct with \ + the same name will be disallowed \ + soon.", + namespace_error_to_string(TypeError), + name)); + { + let r = child.span_for_namespace(TypeNS); + if let Some(sp) = r { + self.session.span_note(sp, + &format!("first definition of {} `{}` here", + namespace_error_to_string(TypeError), + name)); + } + } + } + } let name_bindings = self.add_child(name, parent, ForbidDuplicateModules, sp); let parent_link = self.get_parent_link(parent, name); - let def_id = DefId { krate: 0, node: item.id }; + let def_id = self.ast_map.local_def_id(item.id); name_bindings.define_module(parent_link, Some(def_id), NormalModuleKind, @@ -428,18 +448,20 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { let name_bindings = self.add_child(name, parent, ForbidDuplicateValues, sp); let mutbl = m == hir::MutMutable; - name_bindings.define_value(DefStatic(DefId::local(item.id), mutbl), sp, modifiers); + name_bindings.define_value(DefStatic(self.ast_map.local_def_id(item.id), mutbl), + sp, + modifiers); parent.clone() } ItemConst(_, _) => { self.add_child(name, parent, ForbidDuplicateValues, sp) - .define_value(DefConst(DefId::local(item.id)), sp, modifiers); + .define_value(DefConst(self.ast_map.local_def_id(item.id)), sp, modifiers); parent.clone() } ItemFn(_, _, _, _, _, _) => { let name_bindings = self.add_child(name, parent, ForbidDuplicateValues, sp); - let def = DefFn(DefId::local(item.id), false); + let def = DefFn(self.ast_map.local_def_id(item.id), false); name_bindings.define_value(def, sp, modifiers); parent.clone() } @@ -449,12 +471,12 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { let name_bindings = self.add_child(name, parent, ForbidDuplicateTypesAndModules, sp); - name_bindings.define_type(DefTy(DefId::local(item.id), false), sp, + name_bindings.define_type(DefTy(self.ast_map.local_def_id(item.id), false), sp, modifiers); let parent_link = self.get_parent_link(parent, name); name_bindings.set_module_kind(parent_link, - Some(DefId::local(item.id)), + Some(self.ast_map.local_def_id(item.id)), TypeModuleKind, false, is_public, @@ -466,11 +488,13 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { let name_bindings = self.add_child(name, parent, ForbidDuplicateTypesAndModules, sp); - name_bindings.define_type(DefTy(DefId::local(item.id), true), sp, modifiers); + name_bindings.define_type(DefTy(self.ast_map.local_def_id(item.id), true), + sp, + modifiers); let parent_link = self.get_parent_link(parent, name); name_bindings.set_module_kind(parent_link, - Some(DefId::local(item.id)), + Some(self.ast_map.local_def_id(item.id)), EnumModuleKind, false, is_public, @@ -479,9 +503,10 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { let module = name_bindings.get_module(); for variant in &(*enum_definition).variants { + let item_def_id = self.ast_map.local_def_id(item.id); self.build_reduced_graph_for_variant( &**variant, - DefId::local(item.id), + item_def_id, &module); } parent.clone() @@ -490,30 +515,58 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { // These items live in both the type and value namespaces. ItemStruct(ref struct_def, _) => { // Adding to both Type and Value namespaces or just Type? - let (forbid, ctor_id) = match struct_def.ctor_id { - Some(ctor_id) => (ForbidDuplicateTypesAndValues, Some(ctor_id)), - None => (ForbidDuplicateTypesAndModules, None) + let (forbid, ctor_id) = if struct_def.is_struct() { + (ForbidDuplicateTypesAndModules, None) + } else { + let child = parent.children.borrow().get(&name).cloned(); + if let Some(child) = child { + // check if theres a DefMod + if let Some(DefMod(_)) = child.def_for_namespace(TypeNS) { + self.session.span_warn(sp, &format!( + "duplicate definition of {} `{}`. \ + Defining a module and a struct with \ + the same name will be disallowed \ + soon.", + namespace_error_to_string(TypeError), + name)); + { + let r = child.span_for_namespace(TypeNS); + if let Some(sp) = r { + self.session.span_note(sp, + &format!("first definition of {} `{}` here", + namespace_error_to_string(TypeError), + name)); + } + } + } + } + (ForbidDuplicateTypesAndValues, Some(struct_def.id())) }; let name_bindings = self.add_child(name, parent, forbid, sp); // Define a name in the type namespace. - name_bindings.define_type(DefTy(DefId::local(item.id), false), sp, modifiers); + name_bindings.define_type(DefTy(self.ast_map.local_def_id(item.id), false), + sp, + modifiers); // If this is a newtype or unit-like struct, define a name // in the value namespace as well if let Some(cid) = ctor_id { - name_bindings.define_value(DefStruct(DefId::local(cid)), sp, modifiers); + name_bindings.define_value(DefStruct(self.ast_map.local_def_id(cid)), + sp, + modifiers); } // Record the def ID and fields of this struct. - let named_fields = struct_def.fields.iter().filter_map(|f| { + let named_fields = struct_def.fields().iter().filter_map(|f| { match f.node.kind { - NamedField(ident, _) => Some(ident.name), + NamedField(name, _) => Some(name), UnnamedField(_) => None } }).collect(); - self.structs.insert(DefId::local(item.id), named_fields); + let item_def_id = self.ast_map.local_def_id(item.id); + self.structs.insert(item_def_id, named_fields); parent.clone() } @@ -528,43 +581,43 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { // Add all the items within to a new module. let parent_link = self.get_parent_link(parent, name); name_bindings.define_module(parent_link, - Some(DefId::local(item.id)), + Some(self.ast_map.local_def_id(item.id)), TraitModuleKind, false, is_public, sp); let module_parent = name_bindings.get_module(); - let def_id = DefId::local(item.id); + let def_id = self.ast_map.local_def_id(item.id); // Add the names of all the items to the trait info. for trait_item in items { - let name_bindings = self.add_child(trait_item.ident.name, + let name_bindings = self.add_child(trait_item.name, &module_parent, ForbidDuplicateTypesAndValues, trait_item.span); match trait_item.node { hir::ConstTraitItem(..) => { - let def = DefAssociatedConst(DefId::local(trait_item.id)); + let def = DefAssociatedConst(self.ast_map.local_def_id(trait_item.id)); // NB: not DefModifiers::IMPORTABLE name_bindings.define_value(def, trait_item.span, DefModifiers::PUBLIC); } hir::MethodTraitItem(..) => { - let def = DefMethod(DefId::local(trait_item.id)); + let def = DefMethod(self.ast_map.local_def_id(trait_item.id)); // NB: not DefModifiers::IMPORTABLE name_bindings.define_value(def, trait_item.span, DefModifiers::PUBLIC); } hir::TypeTraitItem(..) => { - let def = DefAssociatedTy(DefId::local(item.id), - DefId::local(trait_item.id)); + let def = DefAssociatedTy(self.ast_map.local_def_id(item.id), + self.ast_map.local_def_id(trait_item.id)); // NB: not DefModifiers::IMPORTABLE name_bindings.define_type(def, trait_item.span, DefModifiers::PUBLIC); } } - self.trait_item_map.insert((trait_item.ident.name, def_id), - DefId::local(trait_item.id)); + let trait_item_def_id = self.ast_map.local_def_id(trait_item.id); + self.trait_item_map.insert((trait_item.name, def_id), trait_item_def_id); } name_bindings.define_type(DefTrait(def_id), sp, modifiers); @@ -579,14 +632,14 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { variant: &Variant, item_id: DefId, parent: &Rc) { - let name = variant.node.name.name; - let is_exported = match variant.node.kind { - TupleVariantKind(_) => false, - StructVariantKind(_) => { - // Not adding fields for variants as they are not accessed with a self receiver - self.structs.insert(DefId::local(variant.node.id), Vec::new()); - true - } + let name = variant.node.name; + let is_exported = 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.ast_map.local_def_id(variant.node.data.id()); + self.structs.insert(variant_def_id, Vec::new()); + true + } else { + false }; let child = self.add_child(name, parent, @@ -595,10 +648,12 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { // variants are always treated as importable to allow them to be glob // used child.define_value(DefVariant(item_id, - DefId::local(variant.node.id), is_exported), + self.ast_map.local_def_id(variant.node.data.id()), + is_exported), variant.span, DefModifiers::PUBLIC | DefModifiers::IMPORTABLE); child.define_type(DefVariant(item_id, - DefId::local(variant.node.id), is_exported), + self.ast_map.local_def_id(variant.node.data.id()), + is_exported), variant.span, DefModifiers::PUBLIC | DefModifiers::IMPORTABLE); } @@ -606,7 +661,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { fn build_reduced_graph_for_foreign_item(&mut self, foreign_item: &ForeignItem, parent: &Rc) { - let name = foreign_item.ident.name; + let name = foreign_item.name; let is_public = foreign_item.vis == hir::Public; let modifiers = if is_public { DefModifiers::PUBLIC @@ -619,10 +674,10 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { let def = match foreign_item.node { ForeignItemFn(..) => { - DefFn(DefId::local(foreign_item.id), false) + DefFn(self.ast_map.local_def_id(foreign_item.id), false) } ForeignItemStatic(_, m) => { - DefStatic(DefId::local(foreign_item.id), m) + DefStatic(self.ast_map.local_def_id(foreign_item.id), m) } }; name_bindings.define_value(def, foreign_item.span, modifiers); @@ -806,7 +861,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { self.structs.insert(def_id, fields); } DefLocal(..) | DefPrimTy(..) | DefTyParam(..) | - DefUse(..) | DefUpvar(..) | DefRegion(..) | + DefUse(..) | DefUpvar(..) | DefLabel(..) | DefSelfTy(..) => { panic!("didn't expect `{:?}`", def); } diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index f06fd9f70e..4147f2bea4 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -609,6 +609,29 @@ match Something::NotFoo { ``` "##, +E0422: r##" +You are trying to use an identifier that is either undefined or not a +struct. For instance: +``` +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. + +``` +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. Example of erroneous code: @@ -888,7 +911,6 @@ register_diagnostics! { E0418, // is not an enum variant, struct or const E0420, // is not an associated const E0421, // unresolved associated const - E0422, // does not name a structure E0427, // cannot use `ref` binding mode with ... E0429, // `self` imports are only allowed within a { } list E0434, // can't capture dynamic environment in a fn item diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 79aa4e5352..106591724a 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -23,7 +23,6 @@ #![feature(borrow_state)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] -#![feature(slice_splits)] #![feature(staged_api)] #[macro_use] extern crate log; @@ -57,7 +56,7 @@ use rustc::metadata::csearch; use rustc::metadata::decoder::{DefLike, DlDef, DlField, DlImpl}; use rustc::middle::def::*; use rustc::middle::def_id::DefId; -use rustc::middle::pat_util::pat_bindings; +use rustc::middle::pat_util::pat_bindings_hygienic; use rustc::middle::privacy::*; use rustc::middle::subst::{ParamSpace, FnSpace, TypeSpace}; use rustc::middle::ty::{Freevar, FreevarMap, TraitMap, GlobMap}; @@ -65,7 +64,8 @@ use rustc::util::nodemap::{NodeMap, DefIdSet, FnvHashMap}; use rustc::util::lev_distance::lev_distance; use syntax::ast; -use syntax::ast::{Ident, Name, NodeId, CrateNum}; +use syntax::ast::{CRATE_NODE_ID, Ident, Name, NodeId, CrateNum, TyIs, TyI8, TyI16, TyI32, TyI64}; +use syntax::ast::{TyUs, TyU8, TyU16, TyU32, TyU64, TyF64, TyF32}; use syntax::attr::AttrMetaMethods; use syntax::ext::mtwt; use syntax::parse::token::{self, special_names, special_idents}; @@ -86,10 +86,8 @@ use rustc_front::hir::{ItemStruct, ItemTrait, ItemTy, ItemUse}; use rustc_front::hir::{Local, MethodImplItem}; use rustc_front::hir::{Pat, PatEnum, PatIdent, PatLit, PatQPath}; use rustc_front::hir::{PatRange, PatStruct, Path, PrimTy}; -use rustc_front::hir::{TraitRef, Ty, TyBool, TyChar, TyF32}; -use rustc_front::hir::{TyF64, TyFloat, TyIs, TyI8, TyI16, TyI32, TyI64, TyInt}; -use rustc_front::hir::{TyPath, TyPtr}; -use rustc_front::hir::{TyRptr, TyStr, TyUs, TyU8, TyU16, TyU32, TyU64, TyUint}; +use rustc_front::hir::{TraitRef, Ty, TyBool, TyChar, TyFloat, TyInt}; +use rustc_front::hir::{TyRptr, TyStr, TyUint, TyPath, TyPtr}; use rustc_front::hir::TypeImplItem; use rustc_front::util::walk_pat; @@ -492,7 +490,7 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Resolver<'a, 'tcx> { } visit::walk_poly_trait_ref(self, tref, m); } - fn visit_variant(&mut self, variant: &hir::Variant, generics: &Generics) { + fn visit_variant(&mut self, variant: &hir::Variant, generics: &Generics, item_id: ast::NodeId) { execute_callback!(hir_map::Node::NodeVariant(variant), self); if let Some(ref dis_expr) = variant.node.disr_expr { // resolve the discriminator expr as a constant @@ -502,19 +500,8 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Resolver<'a, 'tcx> { } // `visit::walk_variant` without the discriminant expression. - match variant.node.kind { - hir::TupleVariantKind(ref variant_arguments) => { - for variant_argument in variant_arguments { - self.visit_ty(&*variant_argument.ty); - } - } - hir::StructVariantKind(ref struct_definition) => { - self.visit_struct_def(&**struct_definition, - variant.node.name, - generics, - variant.node.id); - } - } + self.visit_variant_data(&variant.node.data, variant.node.name, + generics, item_id, variant.span); } fn visit_foreign_item(&mut self, foreign_item: &hir::ForeignItem) { execute_callback!(hir_map::Node::NodeForeignItem(foreign_item), self); @@ -1189,8 +1176,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { make_glob_map: MakeGlobMap) -> Resolver<'a, 'tcx> { let graph_root = NameBindings::new(); + let root_def_id = ast_map.local_def_id(CRATE_NODE_ID); graph_root.define_module(NoParentLink, - Some(DefId { krate: 0, node: 0 }), + Some(root_def_id), NormalModuleKind, false, true, @@ -1258,8 +1246,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } fn get_trait_name(&self, did: DefId) -> Name { - if did.is_local() { - self.ast_map.expect_item(did.node).ident.name + if let Some(node_id) = self.ast_map.as_local_node_id(did) { + self.ast_map.expect_item(node_id).name } else { csearch::get_trait_name(&self.session.cstore, did) } @@ -1982,7 +1970,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { self.session.span_bug(span, &format!("unexpected {:?} in bindings", def)) } - DefLocal(node_id) => { + DefLocal(_, node_id) => { for rib in ribs { match rib.kind { NormalRibKind => { @@ -1990,11 +1978,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } ClosureRibKind(function_id) => { let prev_def = def; + let node_def_id = self.ast_map.local_def_id(node_id); let mut seen = self.freevars_seen.borrow_mut(); let seen = seen.entry(function_id).or_insert_with(|| NodeMap()); if let Some(&index) = seen.get(&node_id) { - def = DefUpvar(node_id, index, function_id); + def = DefUpvar(node_def_id, node_id, index, function_id); continue; } let mut freevars = self.freevars.borrow_mut(); @@ -2003,7 +1992,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let depth = vec.len(); vec.push(Freevar { def: prev_def, span: span }); - def = DefUpvar(node_id, depth, function_id); + def = DefUpvar(node_def_id, node_id, depth, function_id); seen.insert(node_id, depth); } ItemRibKind | MethodRibKind => { @@ -2110,7 +2099,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } fn resolve_item(&mut self, item: &Item) { - let name = item.ident.name; + let name = item.name; debug!("(resolving item) resolving {}", name); @@ -2157,9 +2146,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { TypeSpace, ItemRibKind), |this| { - this.with_self_rib(DefSelfTy(Some(DefId::local(item.id)), None), |this| { + let local_def_id = this.ast_map.local_def_id(item.id); + this.with_self_rib(DefSelfTy(Some(local_def_id), None), |this| { this.visit_generics(generics); - visit::walk_ty_param_bounds_helper(this, bounds); + walk_list!(this, visit_ty_param_bound, bounds); for trait_item in trait_items { match trait_item.node { @@ -2185,7 +2175,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { }); } hir::TypeTraitItem(..) => { - this.check_if_primitive_type_name(trait_item.ident.name, + this.check_if_primitive_type_name(trait_item.name, trait_item.span); this.with_type_parameter_rib(NoTypeParameters, |this| { visit::walk_trait_item(this, trait_item) @@ -2211,23 +2201,39 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ItemUse(ref view_path) => { // check for imports shadowing primitive types - let check_rename = |id, ident: Ident| { - match self.def_map.borrow().get(&id).map(|d| d.full_def()) { + let check_rename = |this: &Self, id, name| { + match this.def_map.borrow().get(&id).map(|d| d.full_def()) { Some(DefTy(..)) | Some(DefStruct(..)) | Some(DefTrait(..)) | None => { - self.check_if_primitive_type_name(ident.name, item.span); + this.check_if_primitive_type_name(name, item.span); } _ => {} } }; match view_path.node { - hir::ViewPathSimple(ident, _) => { - check_rename(item.id, ident); + hir::ViewPathSimple(name, _) => { + check_rename(self, item.id, name); } - hir::ViewPathList(_, ref items) => { + hir::ViewPathList(ref prefix, ref items) => { for item in items { - if let Some(ident) = item.node.rename() { - check_rename(item.node.id(), ident); + if let Some(name) = item.node.rename() { + check_rename(self, item.node.id(), name); + } + } + + // Resolve prefix of an import with empty braces (issue #28388) + if items.is_empty() && !prefix.segments.is_empty() { + match self.resolve_crate_relative_path(prefix.span, + &prefix.segments, + TypeNS) { + Some((def, lp)) => self.record_def(item.id, + PathResolution::new(def, lp, 0)), + None => { + resolve_error(self, + prefix.span, + ResolutionError::FailedToResolve( + &path_names_to_string(prefix, 0))); + } } } } @@ -2249,7 +2255,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let mut function_type_rib = Rib::new(rib_kind); let mut seen_bindings = HashSet::new(); for (index, type_parameter) in generics.ty_params.iter().enumerate() { - let name = type_parameter.ident.name; + let name = type_parameter.name; debug!("with_type_parameter_rib: {}", type_parameter.id); if seen_bindings.contains(&name) { @@ -2265,7 +2271,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { function_type_rib.bindings.insert(name, DlDef(DefTyParam(space, index as u32, - DefId::local(type_parameter.id), + self.ast_map.local_def_id(type_parameter.id), name))); } self.type_ribs.push(function_type_rib); @@ -2375,7 +2381,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn resolve_generics(&mut self, generics: &Generics) { for type_parameter in generics.ty_params.iter() { - self.check_if_primitive_type_name(type_parameter.ident.name, type_parameter.span); + self.check_if_primitive_type_name(type_parameter.name, type_parameter.span); } for predicate in &generics.where_clause.predicates { match predicate { @@ -2471,7 +2477,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ConstImplItem(..) => { // If this is a trait impl, ensure the const // exists in trait - this.check_trait_item(impl_item.ident.name, + this.check_trait_item(impl_item.name, impl_item.span, |n, s| ResolutionError::ConstNotMemberOfTrait(n, s)); this.with_constant_rib(|this| { @@ -2481,7 +2487,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { MethodImplItem(ref sig, _) => { // If this is a trait impl, ensure the method // exists in trait - this.check_trait_item(impl_item.ident.name, + this.check_trait_item(impl_item.name, impl_item.span, |n, s| ResolutionError::MethodNotMemberOfTrait(n, s)); @@ -2498,7 +2504,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { TypeImplItem(ref ty) => { // If this is a trait impl, ensure the type // exists in trait - this.check_trait_item(impl_item.ident.name, + this.check_trait_item(impl_item.name, impl_item.span, |n, s| ResolutionError::TypeNotMemberOfTrait(n, s)); @@ -2527,10 +2533,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn resolve_local(&mut self, local: &Local) { // Resolve the type. - visit::walk_ty_opt(self, &local.ty); + walk_list!(self, visit_ty, &local.ty); // Resolve the initializer. - visit::walk_expr_opt(self, &local.init); + walk_list!(self, visit_expr, &local.init); // Resolve the pattern. self.resolve_pattern(&*local.pat, @@ -2544,7 +2550,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // user and one 'x' came from the macro. fn binding_mode_map(&mut self, pat: &Pat) -> BindingMap { let mut result = HashMap::new(); - pat_bindings(&self.def_map, pat, |binding_mode, _id, sp, path1| { + pat_bindings_hygienic(&self.def_map, pat, |binding_mode, _id, sp, path1| { let name = mtwt::resolve(path1.node); result.insert(name, BindingInfo { span: sp, @@ -2607,7 +2613,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // pat_idents are variants self.check_consistent_bindings(arm); - visit::walk_expr_opt(self, &arm.guard); + walk_list!(self, visit_expr, &arm.guard); self.visit_expr(&*arm.body); if !self.resolved { @@ -2800,7 +2806,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { debug!("(resolving pattern) binding `{}`", renamed); - let def = DefLocal(pattern.id); + let def_id = self.ast_map.local_def_id(pattern.id); + let def = DefLocal(def_id, pattern.id); // Record the definition so that later passes // will be able to distinguish variants from @@ -3482,8 +3489,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } fn is_static_method(this: &Resolver, did: DefId) -> bool { - if did.is_local() { - let sig = match this.ast_map.get(did.node) { + if let Some(node_id) = this.ast_map.as_local_node_id(did) { + let sig = match this.ast_map.get(node_id) { hir_map::NodeTraitItem(trait_item) => match trait_item.node { hir::MethodTraitItem(ref sig, _) => sig, _ => return false @@ -3695,7 +3702,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { false // Stop advancing }); - if method_scope && special_names::self_ == path_name { + if method_scope && special_names::self_.as_str() == &path_name[..] { resolve_error( self, expr.span, @@ -3802,19 +3809,19 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn record_candidate_traits_for_expr_if_necessary(&mut self, expr: &Expr) { match expr.node { - ExprField(_, ident) => { + ExprField(_, name) => { // FIXME(#6890): Even though you can't treat a method like a // field, we need to add any trait methods we find that match // the field name so that we can do some nice error reporting // later on in typeck. - let traits = self.get_traits_containing_item(ident.node.name); + let traits = self.get_traits_containing_item(name.node); self.trait_map.insert(expr.id, traits); } - ExprMethodCall(ident, _, _) => { + ExprMethodCall(name, _, _) => { debug!("(recording candidate traits for expr) recording \ traits for {}", expr.id); - let traits = self.get_traits_containing_item(ident.node.name); + let traits = self.get_traits_containing_item(name.node); self.trait_map.insert(expr.id, traits); } _ => { @@ -3830,9 +3837,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn add_trait_info(found_traits: &mut Vec, trait_def_id: DefId, name: Name) { - debug!("(adding trait info) found trait {}:{} for method '{}'", - trait_def_id.krate, - trait_def_id.node, + debug!("(adding trait info) found trait {:?} for method '{}'", + trait_def_id, name); found_traits.push(trait_def_id); } diff --git a/src/librustc_resolve/record_exports.rs b/src/librustc_resolve/record_exports.rs index 36ed2c1457..0eb1e2cc06 100644 --- a/src/librustc_resolve/record_exports.rs +++ b/src/librustc_resolve/record_exports.rs @@ -102,9 +102,9 @@ impl<'a, 'b, 'tcx> ExportRecorder<'a, 'b, 'tcx> { self.add_exports_for_module(&mut exports, module_); match module_.def_id.get() { Some(def_id) => { - self.export_map.insert(def_id.node, exports); - debug!("(computing exports) writing exports for {} (some)", - def_id.node); + let node_id = self.ast_map.as_local_node_id(def_id).unwrap(); + self.export_map.insert(node_id, exports); + debug!("(computing exports) writing exports for {} (some)", node_id); } None => {} } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 3c2612a134..99d7685f7c 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -537,7 +537,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { fn get_binding(this: &mut Resolver, import_resolution: &ImportResolution, namespace: Namespace, - source: &Name) + source: Name) -> NamespaceResult { // Import resolutions must be declared with "pub" @@ -560,7 +560,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { let id = import_resolution.id(namespace); // track used imports and extern crates as well this.used_imports.insert((id, namespace)); - this.record_import_use(id, *source); + this.record_import_use(id, source); match target_module.def_id.get() { Some(DefId{krate: kid, ..}) => { this.used_crates.insert(kid); @@ -578,14 +578,14 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { value_result = get_binding(self.resolver, import_resolution, ValueNS, - &source); + source); value_used_reexport = import_resolution.is_public; } if type_result.is_unknown() { type_result = get_binding(self.resolver, import_resolution, TypeNS, - &source); + source); type_used_reexport = import_resolution.is_public; } @@ -793,10 +793,10 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { ))); } - for (ident, target_import_resolution) in import_resolutions.iter() { + for (name, target_import_resolution) in import_resolutions.iter() { debug!("(resolving glob import) writing module resolution \ {} into `{}`", - *ident, + *name, module_to_string(module_)); if !target_import_resolution.is_public { @@ -806,7 +806,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { // Here we merge two import resolutions. let mut import_resolutions = module_.import_resolutions.borrow_mut(); - match import_resolutions.get_mut(ident) { + match import_resolutions.get_mut(name) { Some(dest_import_resolution) => { // Merge the two import resolutions at a finer-grained // level. @@ -818,7 +818,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { Some(ref value_target) => { self.check_for_conflicting_import(&dest_import_resolution, import_directive.span, - *ident, + *name, ValueNS); dest_import_resolution.value_target = Some(value_target.clone()); } @@ -830,7 +830,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { Some(ref type_target) => { self.check_for_conflicting_import(&dest_import_resolution, import_directive.span, - *ident, + *name, TypeNS); dest_import_resolution.type_target = Some(type_target.clone()); } @@ -848,7 +848,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { new_import_resolution.type_target = target_import_resolution.type_target.clone(); - import_resolutions.insert(*ident, new_import_resolution); + import_resolutions.insert(*name, new_import_resolution); } // Add all children from the containing module. diff --git a/src/librustc_trans/back/archive.rs b/src/librustc_trans/back/archive.rs index 76bbce00f1..1b3242eb97 100644 --- a/src/librustc_trans/back/archive.rs +++ b/src/librustc_trans/back/archive.rs @@ -145,10 +145,13 @@ impl<'a> ArchiveBuilder<'a> { /// Adds all of the contents of a native library to this archive. This will /// search in the relevant locations for a library named `name`. - pub fn add_native_library(&mut self, name: &str) -> io::Result<()> { + pub fn add_native_library(&mut self, name: &str) { let location = find_library(name, &self.config.lib_search_paths, self.config.sess); - self.add_archive(&location, name, |_| false) + self.add_archive(&location, name, |_| false).unwrap_or_else(|e| { + self.config.sess.fatal(&format!("failed to add native library {}: {}", + location.to_string_lossy(), e)); + }); } /// Adds all of the contents of the rlib at the specified path to this diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index d5486e84fc..6171ff1382 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -16,7 +16,7 @@ use super::msvc; use super::svh::Svh; use session::config; use session::config::NoDebugInfo; -use session::config::{OutputFilenames, Input, OutputTypeBitcode, OutputTypeExe, OutputTypeObject}; +use session::config::{OutputFilenames, Input, OutputType}; use session::search_paths::PathKind; use session::Session; use metadata::common::LinkMeta; @@ -25,17 +25,20 @@ use metadata::loader::METADATA_FILENAME; use metadata::{encoder, cstore, filesearch, csearch, creader}; use middle::dependency_format::Linkage; use middle::ty::{self, Ty}; -use rustc::front::map::{PathElem, PathElems, PathName}; +use rustc::front::map::DefPath; use trans::{CrateContext, CrateTranslation, gensym_name}; use util::common::time; use util::sha2::{Digest, Sha256}; use util::fs::fix_windows_verbatim_for_gcc; use rustc_back::tempdir::TempDir; +use std::ascii; +use std::char; use std::env; use std::ffi::OsString; -use std::fs::{self, PathExt}; +use std::fs; use std::io::{self, Read, Write}; +use std::iter::once; use std::mem; use std::path::{Path, PathBuf}; use std::process::Command; @@ -44,9 +47,8 @@ use flate; use serialize::hex::ToHex; use syntax::ast; use syntax::codemap::Span; -use syntax::parse::token; +use syntax::parse::token::{self, InternedString}; use syntax::attr::AttrMetaMethods; -use rustc_front::attr::AttrMetaMethods as FrontAttrMetaMethods; use rustc_front::hir; @@ -182,9 +184,9 @@ pub fn find_crate_name(sess: Option<&Session>, } pub fn build_link_meta(sess: &Session, krate: &hir::Crate, - name: String) -> LinkMeta { + name: &str) -> LinkMeta { let r = LinkMeta { - crate_name: name, + crate_name: name.to_owned(), crate_hash: Svh::calculate(&sess.opts.cg.metadata, krate), }; info!("{:?}", r); @@ -215,7 +217,7 @@ fn symbol_hash<'tcx>(tcx: &ty::ctxt<'tcx>, symbol_hasher.input_str(&meta[..]); } symbol_hasher.input_str("-"); - symbol_hasher.input_str(&encoder::encoded_ty(tcx, t)); + symbol_hasher.input(&encoder::encoded_ty(tcx, t)); // Prefix with 'h' so that it never blends into adjacent digits let mut hash = String::from("h"); hash.push_str(&truncated_hash_result(symbol_hasher)); @@ -285,8 +287,7 @@ pub fn sanitize(s: &str) -> String { return result; } -pub fn mangle>(path: PI, - hash: Option<&str>) -> String { +pub fn mangle>(path: PI, hash: Option<&str>) -> String { // Follow C++ namespace-mangling style, see // http://en.wikipedia.org/wiki/Name_mangling for more info. // @@ -309,8 +310,8 @@ pub fn mangle>(path: PI, } // First, connect each component with pairs. - for e in path { - push(&mut n, &e.name().as_str()) + for data in path { + push(&mut n, &data); } match hash { @@ -322,11 +323,13 @@ pub fn mangle>(path: PI, n } -pub fn exported_name(path: PathElems, hash: &str) -> String { +pub fn exported_name(path: DefPath, hash: &str) -> String { + let path = path.into_iter() + .map(|e| e.data.as_interned_str()); mangle(path, Some(hash)) } -pub fn mangle_exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, path: PathElems, +pub fn mangle_exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, path: DefPath, t: Ty<'tcx>, id: ast::NodeId) -> String { let mut hash = get_symbol_hash(ccx, t); @@ -354,14 +357,17 @@ pub fn mangle_exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, path: PathEl pub fn mangle_internal_name_by_type_and_seq<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, name: &str) -> String { - let path = [PathName(token::intern(&t.to_string())), - gensym_name(name)]; + let path = [token::intern(&t.to_string()).as_str(), gensym_name(name).as_str()]; let hash = get_symbol_hash(ccx, t); mangle(path.iter().cloned(), Some(&hash[..])) } -pub fn mangle_internal_name_by_path_and_seq(path: PathElems, flav: &str) -> String { - mangle(path.chain(Some(gensym_name(flav))), None) +pub fn mangle_internal_name_by_path_and_seq(path: DefPath, flav: &str) -> String { + let names = + path.into_iter() + .map(|e| e.data.as_interned_str()) + .chain(once(gensym_name(flav).as_str())); // append unique version of "flav" + mangle(names, None) } pub fn get_linker(sess: &Session) -> (String, Command) { @@ -487,7 +493,7 @@ pub fn filename_for_input(sess: &Session, } config::CrateTypeExecutable => { let suffix = &sess.target.target.options.exe_suffix; - let out_filename = outputs.path(OutputTypeExe); + let out_filename = outputs.path(OutputType::Exe); if suffix.is_empty() { out_filename.to_path_buf() } else { @@ -528,10 +534,12 @@ fn link_binary_output(sess: &Session, outputs: &OutputFilenames, crate_name: &str) -> PathBuf { let objects = object_filenames(sess, outputs); - let out_filename = match outputs.single_output_file { - Some(ref file) => file.clone(), - None => filename_for_input(sess, crate_type, crate_name, outputs), - }; + let default_filename = filename_for_input(sess, crate_type, crate_name, + outputs); + let out_filename = outputs.outputs.get(&OutputType::Exe) + .and_then(|s| s.to_owned()) + .or_else(|| outputs.single_output_file.clone()) + .unwrap_or(default_filename); // Make sure files are writeable. Mac, FreeBSD, and Windows system linkers // check this already -- however, the Linux linker will happily overwrite a @@ -543,7 +551,11 @@ fn link_binary_output(sess: &Session, } } - let tmpdir = TempDir::new("rustc").ok().expect("needs a temp dir"); + let tmpdir = match TempDir::new("rustc") { + Ok(tmpdir) => tmpdir, + Err(err) => sess.fatal(&format!("couldn't create a temp dir: {}", err)), + }; + match crate_type { config::CrateTypeRlib => { link_rlib(sess, Some(trans), &objects, &out_filename, @@ -568,7 +580,7 @@ fn link_binary_output(sess: &Session, fn object_filenames(sess: &Session, outputs: &OutputFilenames) -> Vec { (0..sess.opts.cg.codegen_units).map(|i| { let ext = format!("{}.o", i); - outputs.temp_path(OutputTypeObject).with_extension(&ext) + outputs.temp_path(OutputType::Object).with_extension(&ext) }).collect() } @@ -613,7 +625,7 @@ fn link_rlib<'a>(sess: &'a Session, for &(ref l, kind) in sess.cstore.get_used_libraries().borrow().iter() { match kind { - cstore::NativeStatic => ab.add_native_library(&l).unwrap(), + cstore::NativeStatic => ab.add_native_library(&l), cstore::NativeFramework | cstore::NativeUnknown => {} } } @@ -715,7 +727,7 @@ fn link_rlib<'a>(sess: &'a Session, // See the bottom of back::write::run_passes for an explanation // of when we do and don't keep .0.bc files around. let user_wants_numbered_bitcode = - sess.opts.output_types.contains(&OutputTypeBitcode) && + sess.opts.output_types.contains_key(&OutputType::Bitcode) && sess.opts.cg.codegen_units > 1; if !sess.opts.cg.save_temps && !user_wants_numbered_bitcode { remove(sess, &bc_filename); @@ -789,7 +801,7 @@ fn link_staticlib(sess: &Session, objects: &[PathBuf], out_filename: &Path, ab.build(); } if !sess.target.target.options.no_compiler_rt { - ab.add_native_library("compiler-rt").unwrap(); + ab.add_native_library("compiler-rt"); } let mut all_native_libs = vec![]; @@ -873,6 +885,16 @@ fn link_natively(sess: &Session, dylib: bool, let prog = time(sess.time_passes(), "running linker", || cmd.output()); match prog { Ok(prog) => { + fn escape_string(s: &[u8]) -> String { + str::from_utf8(s).map(|s| s.to_owned()) + .unwrap_or_else(|_| { + let mut x = "Non-UTF-8 output: ".to_string(); + x.extend(s.iter() + .flat_map(|&b| ascii::escape_default(b)) + .map(|b| char::from_u32(b as u32).unwrap())); + x + }) + } if !prog.status.success() { sess.err(&format!("linking with `{}` failed: {}", pname, @@ -880,11 +902,11 @@ fn link_natively(sess: &Session, dylib: bool, sess.note(&format!("{:?}", &cmd)); let mut output = prog.stderr.clone(); output.push_all(&prog.stdout); - sess.note(str::from_utf8(&output[..]).unwrap()); + sess.note(&*escape_string(&output[..])); sess.abort_if_errors(); } - info!("linker stderr:\n{}", String::from_utf8(prog.stderr).unwrap()); - info!("linker stdout:\n{}", String::from_utf8(prog.stdout).unwrap()); + info!("linker stderr:\n{}", escape_string(&prog.stderr[..])); + info!("linker stdout:\n{}", escape_string(&prog.stdout[..])); }, Err(e) => { sess.fatal(&format!("could not exec the linker `{}`: {}", pname, e)); @@ -967,7 +989,9 @@ fn link_args(cmd: &mut Linker, // default. Note that this does not happen for windows because windows pulls // in some large number of libraries and I couldn't quite figure out which // subset we wanted. - cmd.no_default_libraries(); + if t.options.no_default_libraries { + cmd.no_default_libraries(); + } // Take careful note of the ordering of the arguments we pass to the linker // here. Linkers will assume that things on the left depend on things to the @@ -979,31 +1003,24 @@ fn link_args(cmd: &mut Linker, // such: // // 1. The local object that LLVM just generated - // 2. Upstream rust libraries - // 3. Local native libraries + // 2. Local native libraries + // 3. Upstream rust libraries // 4. Upstream native libraries // - // This is generally fairly natural, but some may expect 2 and 3 to be - // swapped. The reason that all native libraries are put last is that it's - // not recommended for a native library to depend on a symbol from a rust - // crate. If this is the case then a staticlib crate is recommended, solving - // the problem. - // - // Additionally, it is occasionally the case that upstream rust libraries - // depend on a local native library. In the case of libraries such as - // lua/glfw/etc the name of the library isn't the same across all platforms, - // so only the consumer crate of a library knows the actual name. This means - // that downstream crates will provide the #[link] attribute which upstream - // crates will depend on. Hence local native libraries are after out - // upstream rust crates. + // The rationale behind this ordering is that those items lower down in the + // list can't depend on items higher up in the list. For example nothing can + // depend on what we just generated (e.g. that'd be a circular dependency). + // Upstream rust libraries are not allowed to depend on our local native + // libraries as that would violate the structure of the DAG, in that + // scenario they are required to link to them as well in a shared fashion. // - // In theory this means that a symbol in an upstream native library will be - // shadowed by a local native library when it wouldn't have been before, but - // this kind of behavior is pretty platform specific and generally not - // recommended anyway, so I don't think we're shooting ourself in the foot - // much with that. - add_upstream_rust_crates(cmd, sess, dylib, tmpdir); + // Note that upstream rust libraries may contain native dependencies as + // well, but they also can't depend on what we just started to add to the + // link line. And finally upstream native libraries can't depend on anything + // in this DAG so far because they're only dylibs and dylibs can only depend + // on other dylibs (e.g. other native deps). add_local_native_libraries(cmd, sess); + add_upstream_rust_crates(cmd, sess, dylib, tmpdir); add_upstream_native_libraries(cmd, sess); // # Telling the linker what we're doing diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index a4333dc10d..79a91e4f41 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -19,7 +19,6 @@ use back::archive; use metadata::csearch; use middle::dependency_format::Linkage; use session::Session; -use session::config::DebugInfoLevel::{NoDebugInfo, LimitedDebugInfo, FullDebugInfo}; use session::config::CrateTypeDylib; use session::config; use syntax::ast; @@ -159,12 +158,7 @@ impl<'a> Linker for GnuLinker<'a> { } fn no_default_libraries(&mut self) { - // Unfortunately right now passing -nodefaultlibs to gcc on windows - // doesn't work so hot (in terms of native dependencies). This if - // statement should hopefully be removed one day though! - if !self.sess.target.target.options.is_like_windows { - self.cmd.arg("-nodefaultlibs"); - } + self.cmd.arg("-nodefaultlibs"); } fn build_dylib(&mut self, out_filename: &Path) { @@ -286,17 +280,9 @@ impl<'a> Linker for MsvcLinker<'a> { } fn debuginfo(&mut self) { - match self.sess.opts.debuginfo { - NoDebugInfo => { - // Do nothing if debuginfo is disabled - }, - LimitedDebugInfo | - FullDebugInfo => { - // This will cause the Microsoft linker to generate a PDB file - // from the CodeView line tables in the object files. - self.cmd.arg("/DEBUG"); - } - } + // This will cause the Microsoft linker to generate a PDB file + // from the CodeView line tables in the object files. + self.cmd.arg("/DEBUG"); } fn whole_archives(&mut self) { diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index 00439c1fd5..ba6ec895a8 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -15,6 +15,7 @@ use llvm; use llvm::archive_ro::ArchiveRO; use llvm::{ModuleRef, TargetMachineRef, True, False}; use rustc::util::common::time; +use rustc::util::common::path2cstr; use back::write::{ModuleConfig, with_llvm_pmb}; use libc; @@ -24,7 +25,9 @@ use std::ffi::CString; pub fn run(sess: &session::Session, llmod: ModuleRef, tm: TargetMachineRef, reachable: &[String], - config: &ModuleConfig) { + config: &ModuleConfig, + name_extra: &str, + output_names: &config::OutputFilenames) { if sess.opts.cg.prefer_dynamic { sess.err("cannot prefer dynamic linking when performing LTO"); sess.note("only 'staticlib' and 'bin' outputs are supported with LTO"); @@ -124,6 +127,14 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, } } + if sess.opts.cg.save_temps { + let path = output_names.with_extension(&format!("{}.no-opt.lto.bc", name_extra)); + let cstr = path2cstr(&path); + unsafe { + llvm::LLVMWriteBitcodeToFile(llmod, cstr.as_ptr()); + } + } + // Now we have one massive module inside of llmod. Time to run the // LTO-specific optimization passes that LLVM provides. // diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index d75f2fcf12..807a19c828 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -12,7 +12,7 @@ use back::lto; use back::link::{get_linker, remove}; use session::config::{OutputFilenames, Passes, SomePasses, AllPasses}; use session::Session; -use session::config; +use session::config::{self, OutputType}; use llvm; use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef, ContextRef}; use llvm::SMDiagnosticRef; @@ -23,9 +23,10 @@ use syntax::codemap; use syntax::diagnostic; use syntax::diagnostic::{Emitter, Handler, Level}; +use std::collections::HashMap; use std::ffi::{CStr, CString}; use std::fs; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::ptr; use std::str; use std::sync::{Arc, Mutex}; @@ -33,15 +34,6 @@ use std::sync::mpsc::channel; use std::thread; use libc::{self, c_uint, c_int, c_void}; -#[derive(Clone, Copy, PartialEq, PartialOrd, Ord, Eq)] -pub enum OutputType { - OutputTypeBitcode, - OutputTypeAssembly, - OutputTypeLlvmAssembly, - OutputTypeObject, - OutputTypeExe, -} - pub fn llvm_err(handler: &diagnostic::Handler, msg: String) -> ! { unsafe { let cstr = llvm::LLVMRustGetLastError(); @@ -333,6 +325,8 @@ struct CodegenContext<'a> { plugin_passes: Vec, // LLVM optimizations for which we want to print remarks. remark: Passes, + // Worker thread number + worker: usize, } impl<'a> CodegenContext<'a> { @@ -342,6 +336,7 @@ impl<'a> CodegenContext<'a> { handler: sess.diagnostic().handler(), plugin_passes: sess.plugin_llvm_passes.borrow().clone(), remark: sess.opts.cg.remark.clone(), + worker: 0, } } } @@ -484,9 +479,9 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, cgcx.handler.abort_if_errors(); // Finally, run the actual optimization passes - time(config.time_passes, "llvm function passes", || + time(config.time_passes, &format!("llvm function passes [{}]", cgcx.worker), || llvm::LLVMRustRunFunctionPassManager(fpm, llmod)); - time(config.time_passes, "llvm module passes", || + time(config.time_passes, &format!("llvm module passes [{}]", cgcx.worker), || llvm::LLVMRunPassManager(mpm, llmod)); // Deallocate managers that we're now done with @@ -496,7 +491,8 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, match cgcx.lto_ctxt { Some((sess, reachable)) if sess.lto() => { time(sess.time_passes(), "all lto passes", || - lto::run(sess, llmod, tm, reachable, &config)); + lto::run(sess, llmod, tm, reachable, &config, + &name_extra, &output_names)); if config.emit_lto_bc { let name = format!("{}.lto.bc", name_extra); @@ -536,7 +532,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()); } - time(config.time_passes, "codegen passes", || { + time(config.time_passes, &format!("codegen passes [{}]", cgcx.worker), || { if config.emit_ir { let ext = format!("{}.ll", name_extra); let out = output_names.with_extension(&ext); @@ -570,7 +566,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, pub fn run_passes(sess: &Session, trans: &CrateTranslation, - output_types: &[config::OutputType], + output_types: &HashMap>, crate_output: &OutputFilenames) { // It's possible that we have `codegen_units > 1` but only one item in // `trans.modules`. We could theoretically proceed and do LTO in that @@ -610,32 +606,32 @@ pub fn run_passes(sess: &Session, // archive in order to allow LTO against it. let needs_crate_bitcode = sess.crate_types.borrow().contains(&config::CrateTypeRlib) && - sess.opts.output_types.contains(&config::OutputTypeExe); + sess.opts.output_types.contains_key(&OutputType::Exe); let needs_crate_object = - sess.opts.output_types.contains(&config::OutputTypeExe); + sess.opts.output_types.contains_key(&OutputType::Exe); if needs_crate_bitcode { modules_config.emit_bc = true; } - for output_type in output_types { + for output_type in output_types.keys() { match *output_type { - config::OutputTypeBitcode => { modules_config.emit_bc = true; }, - config::OutputTypeLlvmAssembly => { modules_config.emit_ir = true; }, - config::OutputTypeAssembly => { + OutputType::Bitcode => { modules_config.emit_bc = true; }, + OutputType::LlvmAssembly => { modules_config.emit_ir = true; }, + OutputType::Assembly => { modules_config.emit_asm = true; // If we're not using the LLVM assembler, this function // could be invoked specially with output_type_assembly, so // in this case we still want the metadata object file. - if !sess.opts.output_types.contains(&config::OutputTypeAssembly) { + if !sess.opts.output_types.contains_key(&OutputType::Assembly) { metadata_config.emit_obj = true; } }, - config::OutputTypeObject => { modules_config.emit_obj = true; }, - config::OutputTypeExe => { + OutputType::Object => { modules_config.emit_obj = true; }, + OutputType::Exe => { modules_config.emit_obj = true; metadata_config.emit_obj = true; }, - config::OutputTypeDepInfo => {} + OutputType::DepInfo => {} } } @@ -685,8 +681,9 @@ pub fn run_passes(sess: &Session, } }; - let copy_if_one_unit = |ext: &str, output_type: config::OutputType, keep_numbered: bool| { - // Three cases: + let copy_if_one_unit = |ext: &str, + output_type: OutputType, + keep_numbered: bool| { if sess.opts.cg.codegen_units == 1 { // 1) Only one codegen unit. In this case it's no difficulty // to copy `foo.0.x` to `foo.x`. @@ -696,17 +693,20 @@ pub fn run_passes(sess: &Session, // The user just wants `foo.x`, not `foo.0.x`. remove(sess, &crate_output.with_extension(ext)); } + } else if crate_output.outputs.contains_key(&output_type) { + // 2) Multiple codegen units, with `--emit foo=some_name`. We have + // no good solution for this case, so warn the user. + sess.warn(&format!("ignoring emit path because multiple .{} files \ + were produced", ext)); + } else if crate_output.single_output_file.is_some() { + // 3) Multiple codegen units, with `-o some_name`. We have + // no good solution for this case, so warn the user. + sess.warn(&format!("ignoring -o because multiple .{} files \ + were produced", ext)); } else { - if crate_output.single_output_file.is_some() { - // 2) Multiple codegen units, with `-o some_name`. We have - // no good solution for this case, so warn the user. - sess.warn(&format!("ignoring -o because multiple .{} files were produced", - ext)); - } else { - // 3) Multiple codegen units, but no `-o some_name`. We - // just leave the `foo.0.x` files in place. - // (We don't have to do any work in this case.) - } + // 4) Multiple codegen units, but no explicit name. We + // just leave the `foo.0.x` files in place. + // (We don't have to do any work in this case.) } }; @@ -715,27 +715,27 @@ pub fn run_passes(sess: &Session, // to get rid of it. let mut user_wants_bitcode = false; let mut user_wants_objects = false; - for output_type in output_types { + for output_type in output_types.keys() { match *output_type { - config::OutputTypeBitcode => { + OutputType::Bitcode => { user_wants_bitcode = true; // Copy to .bc, but always keep the .0.bc. There is a later // check to figure out if we should delete .0.bc files, or keep // them for making an rlib. - copy_if_one_unit("0.bc", config::OutputTypeBitcode, true); + copy_if_one_unit("0.bc", OutputType::Bitcode, true); } - config::OutputTypeLlvmAssembly => { - copy_if_one_unit("0.ll", config::OutputTypeLlvmAssembly, false); + OutputType::LlvmAssembly => { + copy_if_one_unit("0.ll", OutputType::LlvmAssembly, false); } - config::OutputTypeAssembly => { - copy_if_one_unit("0.s", config::OutputTypeAssembly, false); + OutputType::Assembly => { + copy_if_one_unit("0.s", OutputType::Assembly, false); } - config::OutputTypeObject => { + OutputType::Object => { user_wants_objects = true; - copy_if_one_unit("0.o", config::OutputTypeObject, true); + copy_if_one_unit("0.o", OutputType::Object, true); } - config::OutputTypeExe | - config::OutputTypeDepInfo => {} + OutputType::Exe | + OutputType::DepInfo => {} } } let user_wants_bitcode = user_wants_bitcode; @@ -872,6 +872,7 @@ fn run_work_multithreaded(sess: &Session, handler: &diag_handler, plugin_passes: plugin_passes, remark: remark, + worker: i, }; loop { @@ -912,8 +913,8 @@ fn run_work_multithreaded(sess: &Session, pub fn run_assembler(sess: &Session, outputs: &OutputFilenames) { let (pname, mut cmd) = get_linker(sess); - cmd.arg("-c").arg("-o").arg(&outputs.path(config::OutputTypeObject)) - .arg(&outputs.temp_path(config::OutputTypeAssembly)); + cmd.arg("-c").arg("-o").arg(&outputs.path(OutputType::Object)) + .arg(&outputs.temp_path(OutputType::Assembly)); debug!("{:?}", cmd); match cmd.output() { diff --git a/src/librustc_trans/diagnostics.rs b/src/librustc_trans/diagnostics.rs new file mode 100644 index 0000000000..2ad2e7528e --- /dev/null +++ b/src/librustc_trans/diagnostics.rs @@ -0,0 +1,122 @@ +// 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. + +#![allow(non_snake_case)] + +register_long_diagnostics! { + +E0510: r##" +`return_address` was used in an invalid context. Erroneous code example: + +``` +extern "rust-intrinsic" { + fn return_address() -> *const u8; +} + +pub unsafe fn by_value() -> i32 { + let _ = return_address(); + // error: invalid use of `return_address` intrinsic: function does + // not use out pointer + 0 +} +``` + +Return values may be stored in a return register(s) or written into a so-called +out pointer. In case the returned value is too big (this is +target-ABI-dependent and generally not portable or future proof) to fit into +the return register(s), the compiler will return the value by writing it into +space allocated in the caller's stack frame. Example: + +``` +extern "rust-intrinsic" { + fn return_address() -> *const u8; +} + +pub unsafe fn by_pointer() -> String { + let _ = return_address(); + String::new() // ok! +} +``` +"##, + +E0511: r##" +Invalid monomorphization of an intrinsic function was used. Erroneous code +example: + +``` +extern "platform-intrinsic" { + fn simd_add(a: T, b: T) -> T; +} + +unsafe { simd_add(0, 1); } +// error: invalid monomorphization of `simd_add` intrinsic +``` + +The generic type has to be a SIMD type. Example: + +``` +#[repr(simd)] +#[derive(Copy, Clone)] +struct i32x1(i32); + +extern "platform-intrinsic" { + fn simd_add(a: T, b: T) -> T; +} + +unsafe { simd_add(i32x1(0), i32x1(1)); } // ok! +``` +"##, + +E0512: r##" +Transmute with two differently sized types was attempted. Erroneous code +example: + +``` +extern "rust-intrinsic" { + pub fn ctpop8(x: u8) -> u8; +} + +fn main() { + unsafe { ctpop8(::std::mem::transmute(0u16)); } + // error: transmute called with differently sized types +} +``` + +Please use types with same size or use the expected type directly. Example: + +``` +extern "rust-intrinsic" { + pub fn ctpop8(x: u8) -> u8; +} + +fn main() { + unsafe { ctpop8(::std::mem::transmute(0i8)); } // ok! + // or: + unsafe { ctpop8(0u8); } // ok! +} +``` +"##, + +E0515: r##" +A constant index expression was out of bounds. Erroneous code example: + +``` +let x = &[0, 1, 2][7]; // error: const index-expr is out of bounds +``` + +Please specify a valid index (not inferior to 0 or superior to array length). +Example: + +``` +let x = &[0, 1, 2][2]; // ok +``` +"##, + +} diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index a7fb3af138..e02ce49132 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -28,19 +28,17 @@ #![feature(box_patterns)] #![feature(box_syntax)] #![feature(const_fn)] +#![feature(custom_attribute)] +#![allow(unused_attributes)] #![feature(iter_cmp)] #![feature(iter_arith)] #![feature(libc)] -#![feature(path_ext)] -#![feature(path_ext)] -#![feature(path_relative_from)] #![feature(path_relative_from)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] #![feature(staged_api)] #![feature(unicode)] -#![feature(unicode)] #![feature(vec_push_all)] #![allow(trivial_casts)] @@ -80,6 +78,8 @@ pub mod back { pub mod msvc; } +pub mod diagnostics; + pub mod trans; pub mod save; diff --git a/src/librustc_trans/save/dump_csv.rs b/src/librustc_trans/save/dump_csv.rs index 62b2f2949f..f6f504e27a 100644 --- a/src/librustc_trans/save/dump_csv.rs +++ b/src/librustc_trans/save/dump_csv.rs @@ -47,7 +47,7 @@ use syntax::visit::{self, Visitor}; use syntax::print::pprust::{path_to_string, ty_to_string}; use syntax::ptr::P; -use rustc_front::lowering::lower_expr; +use rustc_front::lowering::{lower_expr, LoweringContext}; use super::span_utils::SpanUtils; use super::recorder::{Recorder, FmtStrs}; @@ -58,7 +58,7 @@ macro_rules! down_cast_data { data } else { $this.sess.span_bug($sp, &format!("unexpected data kind: {:?}", $id)); - }; + } }; } @@ -66,28 +66,33 @@ pub struct DumpCsvVisitor<'l, 'tcx: 'l> { save_ctxt: SaveContext<'l, 'tcx>, sess: &'l Session, tcx: &'l ty::ctxt<'tcx>, - analysis: &'l ty::CrateAnalysis, + analysis: &'l ty::CrateAnalysis<'l>, span: SpanUtils<'l>, - fmt: FmtStrs<'l>, + fmt: FmtStrs<'l, 'tcx>, cur_scope: NodeId, } impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { pub fn new(tcx: &'l ty::ctxt<'tcx>, - analysis: &'l ty::CrateAnalysis, + lcx: &'l LoweringContext<'l>, + analysis: &'l ty::CrateAnalysis<'l>, output_file: Box) -> DumpCsvVisitor<'l, 'tcx> { let span_utils = SpanUtils::new(&tcx.sess); DumpCsvVisitor { sess: &tcx.sess, tcx: tcx, - save_ctxt: SaveContext::from_span_utils(tcx, span_utils.clone()), + save_ctxt: SaveContext::from_span_utils(tcx, lcx, span_utils.clone()), analysis: analysis, span: span_utils.clone(), - fmt: FmtStrs::new(box Recorder { out: output_file, dump_spans: false }, - span_utils), + fmt: FmtStrs::new(box Recorder { + out: output_file, + dump_spans: false, + }, + span_utils, + tcx), cur_scope: 0, } } @@ -123,13 +128,16 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { // always using the first ones. So, only error out if we don't have enough spans. // What could go wrong...? if spans.len() < path.segments.len() { - error!("Mis-calculated spans for path '{}'. \ - Found {} spans, expected {}. Found spans:", - path_to_string(path), spans.len(), path.segments.len()); + error!("Mis-calculated spans for path '{}'. Found {} spans, expected {}. Found spans:", + path_to_string(path), + spans.len(), + path.segments.len()); for s in &spans { let loc = self.sess.codemap().lookup_char_pos(s.lo); error!(" '{}' in {}, line {}", - self.span.snippet(*s), loc.file.name, loc.line); + self.span.snippet(*s), + loc.file.name, + loc.line); } return vec!(); } @@ -168,10 +176,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { } else { qualname.clone() }; - self.fmt.sub_mod_ref_str(path.span, - *span, - &qualname, - self.cur_scope); + self.fmt.sub_mod_ref_str(path.span, *span, &qualname, self.cur_scope); } } @@ -191,10 +196,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { } else { qualname.clone() }; - self.fmt.sub_mod_ref_str(path.span, - *span, - &qualname, - self.cur_scope); + self.fmt.sub_mod_ref_str(path.span, *span, &qualname, self.cur_scope); } } @@ -210,9 +212,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { // write the trait part of the sub-path let (ref span, ref qualname) = sub_paths[len-2]; - self.fmt.sub_type_ref_str(path.span, - *span, - &qualname); + self.fmt.sub_type_ref_str(path.span, *span, &qualname); // write the other sub-paths if len <= 2 { @@ -220,10 +220,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { } let sub_paths = &sub_paths[..len-2]; for &(ref span, ref qualname) in sub_paths { - self.fmt.sub_mod_ref_str(path.span, - *span, - &qualname, - self.cur_scope); + self.fmt.sub_mod_ref_str(path.span, *span, &qualname, self.cur_scope); } } @@ -231,11 +228,12 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { fn lookup_type_ref(&self, ref_id: NodeId) -> Option { if !self.tcx.def_map.borrow().contains_key(&ref_id) { self.sess.bug(&format!("def_map has no key for {} in lookup_type_ref", - ref_id)); + ref_id)); } let def = self.tcx.def_map.borrow().get(&ref_id).unwrap().full_def(); match def { - def::DefPrimTy(_) => None, + def::DefPrimTy(..) => None, + def::DefSelfTy(..) => None, _ => Some(def.def_id()), } } @@ -243,8 +241,9 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { fn lookup_def_kind(&self, ref_id: NodeId, span: Span) -> Option { let def_map = self.tcx.def_map.borrow(); if !def_map.contains_key(&ref_id) { - self.sess.span_bug(span, &format!("def_map has no key for {} in lookup_def_kind", - ref_id)); + self.sess.span_bug(span, + &format!("def_map has no key for {} in lookup_def_kind", + ref_id)); } let def = def_map.get(&ref_id).unwrap().full_def(); match def { @@ -257,21 +256,20 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { def::DefStatic(_, _) | def::DefConst(_) | def::DefAssociatedConst(..) | - def::DefLocal(_) | + def::DefLocal(..) | def::DefVariant(_, _, _) | def::DefUpvar(..) => Some(recorder::VarRef), def::DefFn(..) => Some(recorder::FnRef), def::DefSelfTy(..) | - def::DefRegion(_) | def::DefLabel(_) | def::DefTyParam(..) | def::DefUse(_) | def::DefMethod(..) | def::DefPrimTy(_) => { - self.sess.span_bug(span, &format!("lookup_def_kind for unexpected item: {:?}", - def)); + self.sess.span_bug(span, + &format!("lookup_def_kind for unexpected item: {:?}", def)); } } } @@ -340,10 +338,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { self.nest(id, |v| v.visit_block(body)); } - self.process_generic_params(&sig.generics, - span, - &method_data.qualname, - id); + self.process_generic_params(&sig.generics, span, &method_data.qualname, id); } fn process_trait_ref(&mut self, trait_ref: &ast::TraitRef) { @@ -382,18 +377,14 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { // However full span is the entire enum/fn/struct block, so we only want // the first few to match the number of generics we're looking for. let param_sub_spans = self.span.spans_for_ty_params(full_span, - (generics.ty_params.len() as isize)); + (generics.ty_params.len() as isize)); for (param, param_ss) in generics.ty_params.iter().zip(param_sub_spans) { // Append $id to name to make sure each one is unique let name = format!("{}::{}${}", prefix, escape(self.span.snippet(param_ss)), id); - self.fmt.typedef_str(full_span, - Some(param_ss), - param.id, - &name, - ""); + self.fmt.typedef_str(full_span, Some(param_ss), param.id, &name, ""); } self.visit_generics(generics); } @@ -444,19 +435,18 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { fn process_const(&mut self, id: ast::NodeId, - ident: &ast::Ident, + name: ast::Name, span: Span, typ: &ast::Ty, expr: &ast::Expr) { let qualname = format!("::{}", self.tcx.map.path_to_string(id)); - let sub_span = self.span.sub_span_after_keyword(span, - keywords::Const); + let sub_span = self.span.sub_span_after_keyword(span, keywords::Const); self.fmt.static_str(span, sub_span, id, - &ident.name.as_str(), + &name.as_str(), &qualname, &self.span.snippet(expr.span), &ty_to_string(&*typ), @@ -469,26 +459,22 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { fn process_struct(&mut self, item: &ast::Item, - def: &ast::StructDef, + def: &ast::VariantData, ty_params: &ast::Generics) { let qualname = format!("::{}", self.tcx.map.path_to_string(item.id)); - let ctor_id = match def.ctor_id { - Some(node_id) => node_id, - None => ast::DUMMY_NODE_ID, - }; let val = self.span.snippet(item.span); let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Struct); self.fmt.struct_str(item.span, sub_span, item.id, - ctor_id, + def.id(), &qualname, self.cur_scope, &val); // fields - for field in &def.fields { + for field in def.fields() { self.process_struct_field_def(field, item.id); self.visit_ty(&field.node.ty); } @@ -515,40 +501,19 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { qualname.push_str("::"); qualname.push_str(name); let val = self.span.snippet(variant.span); - match variant.node.kind { - ast::TupleVariantKind(ref args) => { - // first ident in span is the variant's name - self.fmt.tuple_variant_str(variant.span, - self.span.span_for_first_ident(variant.span), - variant.node.id, - name, - &qualname, - &enum_data.qualname, - &val, - enum_data.id); - for arg in args { - self.visit_ty(&*arg.ty); - } - } - ast::StructVariantKind(ref struct_def) => { - let ctor_id = match struct_def.ctor_id { - Some(node_id) => node_id, - None => ast::DUMMY_NODE_ID, - }; - self.fmt.struct_variant_str(variant.span, - self.span.span_for_first_ident(variant.span), - variant.node.id, - ctor_id, - &qualname, - &enum_data.qualname, - &val, - enum_data.id); - - for field in &struct_def.fields { - self.process_struct_field_def(field, variant.node.id); - self.visit_ty(&*field.node.ty); - } - } + + self.fmt.struct_variant_str(variant.span, + self.span.span_for_first_ident(variant.span), + variant.node.data.id(), + variant.node.data.id(), + &qualname, + &enum_data.qualname, + &val, + enum_data.id); + + for field in variant.node.data.fields() { + self.process_struct_field_def(field, variant.node.data.id()); + self.visit_ty(&*field.node.ty); } } self.process_generic_params(ty_params, item.span, &enum_data.qualname, enum_data.id); @@ -631,10 +596,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { sub_span, id, self.cur_scope); - self.fmt.inherit_str(trait_ref.path.span, - sub_span, - id, - item.id); + self.fmt.inherit_str(trait_ref.path.span, sub_span, id, item.id); } None => (), } @@ -669,18 +631,18 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { Some(pd) => pd, None => { self.tcx.sess.span_bug(path.span, - &format!("Unexpected def kind while looking \ - up path in `{}`", + &format!("Unexpected def kind while looking up path in \ + `{}`", self.span.snippet(path.span))) } }; match path_data { Data::VariableRefData(ref vrd) => { self.fmt.ref_str(ref_kind.unwrap_or(recorder::VarRef), - path.span, - Some(vrd.span), - vrd.ref_id, - vrd.scope); + path.span, + Some(vrd.span), + vrd.ref_id, + vrd.scope); } Data::TypeRefData(ref trd) => { @@ -698,10 +660,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { mcd.scope); } Data::FunctionCallData(fcd) => { - self.fmt.fn_call_str(path.span, - Some(fcd.span), - fcd.ref_id, - fcd.scope); + self.fmt.fn_call_str(path.span, Some(fcd.span), fcd.ref_id, fcd.scope); } _ => { self.sess.span_bug(path.span, @@ -721,7 +680,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { } } } - def::DefLocal(_) | + def::DefLocal(..) | def::DefStatic(_,_) | def::DefConst(..) | def::DefAssociatedConst(..) | @@ -758,9 +717,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { continue; } - let field_data = self.save_ctxt.get_field_ref_data(field, - variant, - scope); + let field_data = self.save_ctxt.get_field_ref_data(field, variant, scope); self.fmt.ref_str(recorder::VarRef, field.ident.span, Some(field_data.span), @@ -771,7 +728,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { } } - visit::walk_expr_opt(self, base) + walk_list!(self, visit_expr, base); } fn process_method_call(&mut self, ex: &ast::Expr, args: &Vec>) { @@ -785,7 +742,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { } // walk receiver and args - visit::walk_exprs(self, &args); + walk_list!(self, visit_expr, args); } fn process_pat(&mut self, p: &ast::Pat) { @@ -807,11 +764,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { let sub_span = self.span.span_for_first_ident(span); if let Some(f) = variant.find_field_named(field.ident.name) { - self.fmt.ref_str(recorder::VarRef, - span, - sub_span, - f.did, - self.cur_scope); + self.fmt.ref_str(recorder::VarRef, span, sub_span, f.did, self.cur_scope); } self.visit_pat(&field.pat); } @@ -819,6 +772,35 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { _ => visit::walk_pat(self, p), } } + + + fn process_var_decl(&mut self, p: &ast::Pat, value: String) { + // The local could declare multiple new vars, we must walk the + // pattern and collect them all. + let mut collector = PathCollector::new(); + collector.visit_pat(&p); + self.visit_pat(&p); + + for &(id, ref p, immut, _) in &collector.collected_paths { + let value = if immut == ast::MutImmutable { + value.to_string() + } else { + "".to_string() + }; + let types = self.tcx.node_types(); + let typ = 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 = self.span.span_for_last_ident(p.span); + // Rust uses the id of the pattern for var lookups, so we'll use it too. + self.fmt.variable_str(p.span, + sub_span, + id, + &path_to_string(p), + &value, + &typ); + } + } } impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { @@ -849,11 +831,11 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { // 'use' always introduces an alias, if there is not an explicit // one, there is an implicit one. - let sub_span = - match self.span.sub_span_after_keyword(use_item.span, keywords::As) { - Some(sub_span) => Some(sub_span), - None => sub_span, - }; + let sub_span = match self.span.sub_span_after_keyword(use_item.span, + keywords::As) { + Some(sub_span) => Some(sub_span), + None => sub_span, + }; self.fmt.use_alias_str(path.span, sub_span, @@ -877,8 +859,8 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { } } - let sub_span = self.span.sub_span_of_token(path.span, - token::BinOp(token::Star)); + let sub_span = self.span + .sub_span_of_token(path.span, token::BinOp(token::Star)); self.fmt.use_glob_str(path.span, sub_span, item.id, @@ -893,10 +875,11 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { match self.lookup_type_ref(id) { Some(def_id) => match self.lookup_def_kind(id, plid.span) { Some(kind) => { - self.fmt.ref_str( - kind, plid.span, - Some(plid.span), - def_id, self.cur_scope); + self.fmt.ref_str(kind, + plid.span, + Some(plid.span), + def_id, + self.cur_scope); } None => (), }, @@ -935,18 +918,14 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { self.process_static_or_const_item(item, typ, expr), ast::ItemConst(ref typ, ref expr) => self.process_static_or_const_item(item, &typ, &expr), - ast::ItemStruct(ref def, ref ty_params) => self.process_struct(item, &**def, ty_params), + ast::ItemStruct(ref def, ref ty_params) => self.process_struct(item, def, ty_params), ast::ItemEnum(ref def, ref ty_params) => self.process_enum(item, def, ty_params), ast::ItemImpl(_, _, ref ty_params, ref trait_ref, ref typ, ref impl_items) => { - self.process_impl(item, - ty_params, - trait_ref, - &typ, - impl_items) + self.process_impl(item, ty_params, trait_ref, &typ, impl_items) } ast::ItemTrait(_, ref generics, ref trait_refs, ref methods) => self.process_trait(item, generics, trait_refs, methods), @@ -958,11 +937,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { let qualname = format!("::{}", self.tcx.map.path_to_string(item.id)); let value = ty_to_string(&**ty); let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Type); - self.fmt.typedef_str(item.span, - sub_span, - item.id, - &qualname, - &value); + self.fmt.typedef_str(item.span, sub_span, item.id, &qualname, &value); self.visit_ty(&**ty); self.process_generic_params(ty_params, item.span, &qualname, item.id); @@ -988,8 +963,11 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) { match trait_item.node { ast::ConstTraitItem(ref ty, Some(ref expr)) => { - self.process_const(trait_item.id, &trait_item.ident, - trait_item.span, &*ty, &*expr); + self.process_const(trait_item.id, + trait_item.ident.name, + trait_item.span, + &*ty, + &*expr); } ast::MethodTraitItem(ref sig, ref body) => { self.process_method(sig, @@ -1006,8 +984,11 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { fn visit_impl_item(&mut self, impl_item: &ast::ImplItem) { match impl_item.node { ast::ConstImplItem(ref ty, ref expr) => { - self.process_const(impl_item.id, &impl_item.ident, - impl_item.span, &ty, &expr); + self.process_const(impl_item.id, + impl_item.ident.name, + impl_item.span, + &ty, + &expr); } ast::MethodImplItem(ref sig, ref body) => { self.process_method(sig, @@ -1031,11 +1012,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { match self.lookup_type_ref(t.id) { Some(id) => { let sub_span = self.span.sub_span_for_type_name(t.span); - self.fmt.ref_str(recorder::TypeRef, - t.span, - sub_span, - id, - self.cur_scope); + self.fmt.ref_str(recorder::TypeRef, t.span, sub_span, id, self.cur_scope); } None => (), } @@ -1064,14 +1041,10 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { visit::walk_expr(self, ex); } ast::ExprStruct(ref path, ref fields, ref base) => { - let hir_expr = lower_expr(ex); + let hir_expr = lower_expr(self.save_ctxt.lcx, ex); let adt = self.tcx.expr_ty(&hir_expr).ty_adt_def().unwrap(); let def = self.tcx.resolve_expr(&hir_expr); - self.process_struct_lit(ex, - path, - fields, - adt.variant_of_def(def), - base) + self.process_struct_lit(ex, path, fields, adt.variant_of_def(def), base) } ast::ExprMethodCall(_, _, ref args) => self.process_method_call(ex, args), ast::ExprField(ref sub_ex, _) => { @@ -1097,7 +1070,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { self.visit_expr(&**sub_ex); - let hir_node = self.tcx.map.expect_expr(sub_ex.id); + let hir_node = lower_expr(self.save_ctxt.lcx, sub_ex); let ty = &self.tcx.expr_ty_adjusted(&hir_node).sty; match *ty { ty::TyStruct(def, _) => { @@ -1110,8 +1083,8 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { } ty::TyTuple(_) => {} _ => self.sess.span_bug(ex.span, - &format!("Expected struct or tuple \ - type, found {:?}", ty)), + &format!("Expected struct or tuple type, found {:?}", + ty)), } } ast::ExprClosure(_, ref decl, ref body) => { @@ -1135,6 +1108,20 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { // walk the body self.nest(ex.id, |v| v.visit_block(&**body)); } + ast::ExprForLoop(ref pattern, ref subexpression, ref block, _) | + ast::ExprWhileLet(ref pattern, ref subexpression, ref block, _) => { + let value = self.span.snippet(mk_sp(ex.span.lo, subexpression.span.hi)); + self.process_var_decl(pattern, value); + visit::walk_expr(self, subexpression); + visit::walk_block(self, block); + } + ast::ExprIfLet(ref pattern, ref subexpression, ref block, ref opt_else) => { + let value = self.span.snippet(mk_sp(ex.span.lo, subexpression.span.hi)); + self.process_var_decl(pattern, value); + visit::walk_expr(self, subexpression); + visit::walk_block(self, block); + opt_else.as_ref().map(|el| visit::walk_expr(self, el)); + } _ => { visit::walk_expr(self, ex) } @@ -1165,25 +1152,20 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { let def_map = self.tcx.def_map.borrow(); if !def_map.contains_key(&id) { self.sess.span_bug(p.span, - &format!("def_map has no key for {} in visit_arm", - id)); + &format!("def_map has no key for {} in visit_arm", id)); } let def = def_map.get(&id).unwrap().full_def(); match def { - def::DefLocal(id) => { + def::DefLocal(_, id) => { let value = if immut == ast::MutImmutable { self.span.snippet(p.span).to_string() } else { "".to_string() }; - assert!(p.segments.len() == 1, "qualified path for local variable def in arm"); - self.fmt.variable_str(p.span, - Some(p.span), - id, - &path_to_string(p), - &value, - "") + assert!(p.segments.len() == 1, + "qualified path for local variable def in arm"); + self.fmt.variable_str(p.span, Some(p.span), id, &path_to_string(p), &value, "") } def::DefVariant(..) | def::DefTy(..) | def::DefStruct(..) => { paths_to_process.push((id, p.clone(), Some(ref_kind))) @@ -1200,7 +1182,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { for &(id, ref path, ref_kind) in &paths_to_process { self.process_path(id, path, ref_kind); } - visit::walk_expr_opt(self, &arm.guard); + walk_list!(self, visit_expr, &arm.guard); self.visit_expr(&arm.body); } @@ -1217,36 +1199,12 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { return } - // The local could declare multiple new vars, we must walk the - // pattern and collect them all. - let mut collector = PathCollector::new(); - collector.visit_pat(&l.pat); - self.visit_pat(&l.pat); - let value = self.span.snippet(l.span); - - for &(id, ref p, immut, _) in &collector.collected_paths { - let value = if immut == ast::MutImmutable { - value.to_string() - } else { - "".to_string() - }; - let types = self.tcx.node_types(); - let typ = 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 = self.span.span_for_last_ident(p.span); - // Rust uses the id of the pattern for var lookups, so we'll use it too. - self.fmt.variable_str(p.span, - sub_span, - id, - &path_to_string(p), - &value, - &typ); - } + self.process_var_decl(&l.pat, value); // Just walk the initialiser and type (don't want to walk the pattern again). - visit::walk_ty_opt(self, &l.ty); - visit::walk_expr_opt(self, &l.init); + walk_list!(self, visit_ty, &l.ty); + walk_list!(self, visit_expr, &l.init); } } + diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 9c6f1a0eb5..af9f3e4896 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -10,7 +10,7 @@ use middle::ty; use middle::def; -use middle::def_id::{DefId, LOCAL_CRATE}; +use middle::def_id::DefId; use std::env; use std::fs::{self, File}; @@ -18,9 +18,8 @@ use std::path::{Path, PathBuf}; use rustc_front; use rustc::front::map::NodeItem; -use rustc_front::hir; +use rustc_front::{hir, lowering}; -use syntax::attr; use syntax::ast::{self, NodeId}; use syntax::ast_util; use syntax::codemap::*; @@ -38,6 +37,7 @@ mod dump_csv; pub struct SaveContext<'l, 'tcx: 'l> { tcx: &'l ty::ctxt<'tcx>, + lcx: &'l lowering::LoweringContext<'l>, span_utils: SpanUtils<'l>, } @@ -176,15 +176,22 @@ pub struct MethodCallData { impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { - pub fn new(tcx: &'l ty::ctxt<'tcx>) -> SaveContext<'l, 'tcx> { + pub fn new(tcx: &'l ty::ctxt<'tcx>, + lcx: &'l lowering::LoweringContext<'l>) + -> SaveContext<'l, 'tcx> { let span_utils = SpanUtils::new(&tcx.sess); - SaveContext::from_span_utils(tcx, span_utils) + SaveContext::from_span_utils(tcx, lcx, span_utils) } pub fn from_span_utils(tcx: &'l ty::ctxt<'tcx>, + lcx: &'l lowering::LoweringContext<'l>, span_utils: SpanUtils<'l>) -> SaveContext<'l, 'tcx> { - SaveContext { tcx: tcx, span_utils: span_utils } + SaveContext { + tcx: tcx, + lcx: lcx, + span_utils: span_utils, + } } // List external crates used by the current crate. @@ -192,7 +199,10 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let mut result = Vec::new(); self.tcx.sess.cstore.iter_crate_data(|n, cmd| { - result.push(CrateData { name: cmd.name.clone(), number: n }); + result.push(CrateData { + name: cmd.name.clone(), + number: n, + }); }); result @@ -289,10 +299,12 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { // Common case impl for a struct or something basic. ast::TyPath(None, ref path) => { sub_span = self.span_utils.sub_span_for_type_name(path.span).unwrap(); - type_data = self.lookup_ref_id(typ.id).map(|id| TypeRefData { - span: sub_span, - scope: parent, - ref_id: id, + type_data = self.lookup_ref_id(typ.id).map(|id| { + TypeRefData { + span: sub_span, + scope: parent, + ref_id: id, + } }); } _ => { @@ -302,8 +314,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } } - let trait_data = - trait_ref.as_ref().and_then(|tr| self.get_trait_ref_data(tr, parent)); + let trait_data = trait_ref.as_ref() + .and_then(|tr| self.get_trait_ref_data(tr, parent)); Data::ImplData(ImplData { id: item.id, @@ -323,11 +335,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { pub fn get_field_data(&self, field: &ast::StructField, scope: NodeId) -> Option { match field.node.kind { ast::NamedField(ident, _) => { - let qualname = format!("::{}::{}", - self.tcx.map.path_to_string(scope), - ident); - let typ = self.tcx.node_types().get(&field.node.id).unwrap() - .to_string(); + let qualname = format!("::{}::{}", self.tcx.map.path_to_string(scope), ident); + let typ = self.tcx.node_types().get(&field.node.id).unwrap().to_string(); let sub_span = self.span_utils.sub_span_before_token(field.span, token::Colon); Some(VariableData { id: field.node.id, @@ -348,19 +357,18 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { pub fn get_method_data(&self, id: ast::NodeId, name: ast::Name, span: Span) -> FunctionData { // The qualname for a method is the trait name or name of the struct in an impl in // which the method is declared in, followed by the method's name. - let qualname = match self.tcx.impl_of_method(DefId::local(id)) { - Some(impl_id) => match self.tcx.map.get(impl_id.node) { - NodeItem(item) => { + let qualname = match self.tcx.impl_of_method(self.tcx.map.local_def_id(id)) { + Some(impl_id) => match self.tcx.map.get_if_local(impl_id) { + Some(NodeItem(item)) => { match item.node { hir::ItemImpl(_, _, _, _, ref ty, _) => { let mut result = String::from("<"); result.push_str(&rustc_front::print::pprust::ty_to_string(&**ty)); - match self.tcx.trait_of_item(DefId::local(id)) { + match self.tcx.trait_of_item(self.tcx.map.local_def_id(id)) { Some(def_id) => { result.push_str(" as "); - result.push_str( - &self.tcx.item_path_str(def_id)); + result.push_str(&self.tcx.item_path_str(def_id)); } None => {} } @@ -369,48 +377,56 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } _ => { self.tcx.sess.span_bug(span, - &format!("Container {} for method {} not an impl?", - impl_id.node, id)); + &format!("Container {:?} for method {} not \ + an impl?", + impl_id, + id)); } } } - _ => { + r => { self.tcx.sess.span_bug(span, - &format!("Container {} for method {} is not a node item {:?}", - impl_id.node, id, self.tcx.map.get(impl_id.node))); + &format!("Container {:?} for method {} is not a node \ + item {:?}", + impl_id, + id, + r)); } }, - None => match self.tcx.trait_of_item(DefId::local(id)) { + None => match self.tcx.trait_of_item(self.tcx.map.local_def_id(id)) { Some(def_id) => { - match self.tcx.map.get(def_id.node) { - NodeItem(_) => { + match self.tcx.map.get_if_local(def_id) { + Some(NodeItem(_)) => { format!("::{}", self.tcx.item_path_str(def_id)) } - _ => { + r => { self.tcx.sess.span_bug(span, - &format!("Could not find container {} for method {}", - def_id.node, id)); + &format!("Could not find container {:?} for \ + method {}, got {:?}", + def_id, + id, + r)); } } } None => { self.tcx.sess.span_bug(span, - &format!("Could not find container for method {}", id)); + &format!("Could not find container for method {}", id)); } }, }; let qualname = format!("{}::{}", qualname, name); - let decl_id = self.tcx.trait_item_of_item(DefId::local(id)) - .and_then(|new_id| { - let def_id = new_id.def_id(); - if def_id.node != 0 && def_id != DefId::local(id) { - Some(def_id) - } else { - None - } - }); + let def_id = self.tcx.map.local_def_id(id); + let decl_id = self.tcx.trait_item_of_item(def_id).and_then(|new_id| { + let new_def_id = new_id.def_id(); + if new_def_id != def_id { + Some(new_def_id) + } else { + None + } + }); let sub_span = self.span_utils.sub_span_after_keyword(span, keywords::Fn); @@ -442,7 +458,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { pub fn get_expr_data(&self, expr: &ast::Expr) -> Option { match expr.node { ast::ExprField(ref sub_ex, ident) => { - let hir_node = self.tcx.map.expect_expr(sub_ex.id); + let hir_node = lowering::lower_expr(self.lcx, sub_ex); let ty = &self.tcx.expr_ty_adjusted(&hir_node).sty; match *ty { ty::TyStruct(def, _) => { @@ -462,8 +478,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } } ast::ExprStruct(ref path, _, _) => { - let hir_node = self.tcx.map.expect_expr(expr.id); - let ty = &self.tcx.expr_ty_adjusted(hir_node).sty; + let hir_node = lowering::lower_expr(self.lcx, expr); + let ty = &self.tcx.expr_ty_adjusted(&hir_node).sty; match *ty { ty::TyStruct(def, _) => { let sub_span = self.span_utils.span_for_last_ident(path.span); @@ -545,11 +561,10 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let ti = self.tcx.impl_or_trait_item(decl_id); match ti.container() { ty::TraitContainer(def_id) => { - self.tcx.trait_items(def_id) + self.tcx + .trait_items(def_id) .iter() - .find(|mr| { - mr.name() == ti.name() && self.trait_method_has_body(mr) - }) + .find(|mr| mr.name() == ti.name() && self.trait_method_has_body(mr)) .map(|mr| mr.def_id()) } ty::ImplContainer(def_id) => { @@ -558,9 +573,9 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { .unwrap() .iter() .find(|mr| { - self.tcx.impl_or_trait_item(mr.def_id()).name() - == ti.name() - }) + self.tcx.impl_or_trait_item(mr.def_id()).name() == + ti.name() + }) .unwrap() .def_id()) } @@ -595,13 +610,13 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { fn trait_method_has_body(&self, mr: &ty::ImplOrTraitItem) -> bool { let def_id = mr.def_id(); - if def_id.krate != LOCAL_CRATE { - return false; - } - - let trait_item = self.tcx.map.expect_trait_item(def_id.node); - if let hir::TraitItem_::MethodTraitItem(_, Some(_)) = trait_item.node { - true + if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) { + let trait_item = self.tcx.map.expect_trait_item(node_id); + if let hir::TraitItem_::MethodTraitItem(_, Some(_)) = trait_item.node { + true + } else { + false + } } else { false } @@ -635,7 +650,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } let def = self.tcx.def_map.borrow().get(&ref_id).unwrap().full_def(); match def { - def::DefPrimTy(_) => None, + def::DefPrimTy(_) | def::DefSelfTy(..) => None, _ => Some(def.def_id()), } } @@ -666,10 +681,7 @@ impl<'v> Visitor<'v> for PathCollector { match p.node { ast::PatStruct(ref path, _, _) => { - self.collected_paths.push((p.id, - path.clone(), - ast::MutMutable, - recorder::TypeRef)); + self.collected_paths.push((p.id, path.clone(), ast::MutMutable, recorder::TypeRef)); } ast::PatEnum(ref path, _) | ast::PatQPath(_, ref path) => { @@ -697,22 +709,17 @@ impl<'v> Visitor<'v> for PathCollector { } } -pub fn process_crate(tcx: &ty::ctxt, - krate: &ast::Crate, - analysis: &ty::CrateAnalysis, - odir: Option<&Path>) { +pub fn process_crate<'l, 'tcx>(tcx: &'l ty::ctxt<'tcx>, + lcx: &'l lowering::LoweringContext<'l>, + krate: &ast::Crate, + analysis: &ty::CrateAnalysis, + cratename: &str, + odir: Option<&Path>) { if generated_code(krate.span) { return; } assert!(analysis.glob_map.is_some()); - let cratename = match attr::find_crate_name(&krate.attrs) { - Some(name) => name.to_string(), - None => { - info!("Could not find crate name, using 'unknown_crate'"); - String::from("unknown_crate") - } - }; info!("Dumping crate {}", cratename); @@ -727,7 +734,8 @@ pub fn process_crate(tcx: &ty::ctxt, if let Err(e) = fs::create_dir_all(&root_path) { tcx.sess.err(&format!("Could not create directory {}: {}", - root_path.display(), e)); + root_path.display(), + e)); } { @@ -736,7 +744,7 @@ pub fn process_crate(tcx: &ty::ctxt, } // Create output file. - let mut out_name = cratename.clone(); + let mut out_name = cratename.to_owned(); out_name.push_str(".csv"); root_path.push(&out_name); let output_file = match File::create(&root_path) { @@ -748,9 +756,9 @@ pub fn process_crate(tcx: &ty::ctxt, }; root_path.pop(); - let mut visitor = dump_csv::DumpCsvVisitor::new(tcx, analysis, output_file); + let mut visitor = dump_csv::DumpCsvVisitor::new(tcx, lcx, analysis, output_file); - visitor.dump_crate_info(&cratename, krate); + visitor.dump_crate_info(cratename, krate); visit::walk_crate(&mut visitor, krate); } diff --git a/src/librustc_trans/save/recorder.rs b/src/librustc_trans/save/recorder.rs index f8e6864985..a32d8b1b76 100644 --- a/src/librustc_trans/save/recorder.rs +++ b/src/librustc_trans/save/recorder.rs @@ -13,7 +13,9 @@ pub use self::Row::*; use super::escape; use super::span_utils::SpanUtils; -use middle::def_id::DefId; +use metadata::cstore::LOCAL_CRATE; +use middle::def_id::{CRATE_DEF_INDEX, DefId}; +use middle::ty; use std::io::Write; @@ -21,7 +23,10 @@ use syntax::ast; use syntax::ast::NodeId; use syntax::codemap::*; -const ZERO_DEF_ID: DefId = DefId { node: 0, krate: 0 }; +const CRATE_ROOT_DEF_ID: DefId = DefId { + krate: LOCAL_CRATE, + index: CRATE_DEF_INDEX, +}; pub struct Recorder { // output file @@ -40,14 +45,17 @@ impl Recorder { pub fn dump_span(&mut self, su: SpanUtils, kind: &str, span: Span, _sub_span: Option) { assert!(self.dump_spans); let result = format!("span,kind,{},{},text,\"{}\"\n", - kind, su.extent_str(span), escape(su.snippet(span))); + kind, + su.extent_str(span), + escape(su.snippet(span))); self.record(&result[..]); } } -pub struct FmtStrs<'a> { +pub struct FmtStrs<'a, 'tcx: 'a> { pub recorder: Box, span: SpanUtils<'a>, + tcx: &'a ty::ctxt<'tcx>, } macro_rules! s { ($e:expr) => { format!("{}", $e) }} @@ -90,9 +98,30 @@ pub enum Row { FnRef, } -impl<'a> FmtStrs<'a> { - pub fn new(rec: Box, span: SpanUtils<'a>) -> FmtStrs<'a> { - FmtStrs { recorder: rec, span: span } +impl<'a, 'tcx: 'a> FmtStrs<'a, 'tcx> { + pub fn new(rec: Box, + span: SpanUtils<'a>, + tcx: &'a ty::ctxt<'tcx>) + -> FmtStrs<'a, 'tcx> { + FmtStrs { + recorder: rec, + span: span, + tcx: tcx, + } + } + + // Emitted ids are used to cross-reference items across crates. DefIds and + // NodeIds do not usually correspond in any way. The strategy is to use the + // index from the DefId as a crate-local id. However, within a crate, DefId + // indices and NodeIds can overlap. So, we must adjust the NodeIds. If an + // item can be identified by a DefId as well as a NodeId, then we use the + // DefId index as the id. If it can't, then we have to use the NodeId, but + // need to adjust it so it will not clash with any possible DefId index. + fn normalize_node_id(&self, id: NodeId) -> usize { + match self.tcx.map.opt_local_def_id(id) { + Some(id) => id.index.as_usize(), + None => id as usize + self.tcx.map.num_local_def_ids() + } } // A map from kind of item to a tuple of @@ -103,52 +132,93 @@ impl<'a> FmtStrs<'a> { fn lookup_row(r: Row) -> (&'static str, Vec<&'static str>, bool, bool) { match r { Variable => ("variable", - vec!("id","name","qualname","value","type","scopeid"), + vec!("id", "name", "qualname", "value", "type", "scopeid"), true, true), - Enum => ("enum", vec!("id","qualname","scopeid","value"), true, true), + Enum => ("enum", + vec!("id", "qualname", "scopeid", "value"), + true, + true), Variant => ("variant", - vec!("id","name","qualname","type","value","scopeid"), + vec!("id", "name", "qualname", "type", "value", "scopeid"), true, true), VariantStruct => ("variant_struct", - vec!("id","ctor_id","qualname","type","value","scopeid"), + vec!("id", "ctor_id", "qualname", "type", "value", "scopeid"), true, true), Function => ("function", - vec!("id","qualname","declid","declidcrate","scopeid"), + vec!("id", "qualname", "declid", "declidcrate", "scopeid"), true, true), - MethodDecl => ("method_decl", vec!("id","qualname","scopeid"), true, true), - Struct => ("struct", vec!("id","ctor_id","qualname","scopeid","value"), true, true), - Trait => ("trait", vec!("id","qualname","scopeid","value"), true, true), + MethodDecl => ("method_decl", + vec!("id", "qualname", "scopeid"), + true, + true), + Struct => ("struct", + vec!("id", "ctor_id", "qualname", "scopeid", "value"), + true, + true), + Trait => ("trait", + vec!("id", "qualname", "scopeid", "value"), + true, + true), Impl => ("impl", - vec!("id","refid","refidcrate","traitid","traitidcrate","scopeid"), + vec!("id", + "refid", + "refidcrate", + "traitid", + "traitidcrate", + "scopeid"), true, true), - Module => ("module", vec!("id","qualname","scopeid","def_file"), true, false), - UseAlias => ("use_alias", vec!("id","refid","refidcrate","name","scopeid"), true, true), - UseGlob => ("use_glob", vec!("id","value","scopeid"), true, true), + Module => ("module", + vec!("id", "qualname", "scopeid", "def_file"), + true, + false), + UseAlias => ("use_alias", + vec!("id", "refid", "refidcrate", "name", "scopeid"), + true, + true), + UseGlob => ("use_glob", vec!("id", "value", "scopeid"), true, true), ExternCrate => ("extern_crate", - vec!("id","name","location","crate","scopeid"), + vec!("id", "name", "location", "crate", "scopeid"), true, true), Inheritance => ("inheritance", - vec!("base","basecrate","derived","derivedcrate"), + vec!("base", "basecrate", "derived", "derivedcrate"), true, false), MethodCall => ("method_call", - vec!("refid","refidcrate","declid","declidcrate","scopeid"), + vec!("refid", "refidcrate", "declid", "declidcrate", "scopeid"), true, true), - Typedef => ("typedef", vec!("id","qualname","value"), true, true), - ExternalCrate => ("external_crate", vec!("name","crate","file_name"), false, false), + Typedef => ("typedef", vec!("id", "qualname", "value"), true, true), + ExternalCrate => ("external_crate", + vec!("name", "crate", "file_name"), + false, + false), Crate => ("crate", vec!("name"), true, false), - FnCall => ("fn_call", vec!("refid","refidcrate","qualname","scopeid"), true, true), - ModRef => ("mod_ref", vec!("refid","refidcrate","qualname","scopeid"), true, true), - VarRef => ("var_ref", vec!("refid","refidcrate","qualname","scopeid"), true, true), - TypeRef => ("type_ref", vec!("refid","refidcrate","qualname","scopeid"), true, true), - FnRef => ("fn_ref", vec!("refid","refidcrate","qualname","scopeid"), true, true), + FnCall => ("fn_call", + vec!("refid", "refidcrate", "qualname", "scopeid"), + true, + true), + ModRef => ("mod_ref", + vec!("refid", "refidcrate", "qualname", "scopeid"), + true, + true), + VarRef => ("var_ref", + vec!("refid", "refidcrate", "qualname", "scopeid"), + true, + true), + TypeRef => ("type_ref", + vec!("refid", "refidcrate", "qualname", "scopeid"), + true, + true), + FnRef => ("fn_ref", + vec!("refid", "refidcrate", "qualname", "scopeid"), + true, + true), } } @@ -159,9 +229,12 @@ impl<'a> FmtStrs<'a> { span: Span) -> Option { if values.len() != fields.len() { - self.span.sess.span_bug(span, &format!( - "Mismatch between length of fields for '{}', expected '{}', found '{}'", - kind, fields.len(), values.len())); + self.span.sess.span_bug(span, + &format!("Mismatch between length of fields for '{}', \ + expected '{}', found '{}'", + kind, + fields.len(), + values.len())); } let values = values.iter().map(|s| { @@ -175,19 +248,21 @@ impl<'a> FmtStrs<'a> { let pairs = fields.iter().zip(values); let strs = pairs.map(|(f, v)| format!(",{},\"{}\"", f, escape(String::from(v)))); - Some(strs.fold(String::new(), |mut s, ss| { - s.push_str(&ss[..]); - s - })) + Some(strs.fold(String::new(), + |mut s, ss| { + s.push_str(&ss[..]); + s + })) } pub fn record_without_span(&mut self, kind: Row, values: Vec, span: Span) { let (label, ref fields, needs_span, dump_spans) = FmtStrs::lookup_row(kind); if needs_span { - self.span.sess.span_bug(span, &format!( - "Called record_without_span for '{}' which does requires a span", - label)); + self.span.sess.span_bug(span, + &format!("Called record_without_span for '{}' which does \ + requires a span", + label)); } assert!(!dump_spans); @@ -215,25 +290,26 @@ impl<'a> FmtStrs<'a> { if self.recorder.dump_spans { if dump_spans { - self.recorder.dump_span(self.span.clone(), - label, - span, - Some(sub_span)); + self.recorder.dump_span(self.span.clone(), label, span, Some(sub_span)); } return; } if !needs_span { self.span.sess.span_bug(span, - &format!("Called record_with_span for '{}' \ - which does not require a span", label)); + &format!("Called record_with_span for '{}' which does not \ + require a span", + label)); } let values_str = match self.make_values_str(label, fields, values, span) { Some(vs) => vs, None => return, }; - let result = format!("{},{}{}\n", label, self.span.extent_str(sub_span), values_str); + let result = format!("{},{}{}\n", + label, + self.span.extent_str(sub_span), + values_str); self.recorder.record(&result[..]); } @@ -265,6 +341,7 @@ impl<'a> FmtStrs<'a> { let mut qualname = String::from(name); qualname.push_str("$"); qualname.push_str(&id.to_string()); + let id = self.normalize_node_id(id); self.check_and_record(Variable, span, sub_span, @@ -282,6 +359,7 @@ impl<'a> FmtStrs<'a> { let mut qualname = String::from(fn_name); qualname.push_str("::"); qualname.push_str(name); + let id = self.normalize_node_id(id); self.check_and_record(Variable, span, sub_span, @@ -298,6 +376,8 @@ impl<'a> FmtStrs<'a> { value: &str, typ: &str, scope_id: NodeId) { + let id = self.normalize_node_id(id); + let scope_id = self.normalize_node_id(scope_id); self.check_and_record(Variable, span, sub_span, @@ -312,6 +392,8 @@ impl<'a> FmtStrs<'a> { qualname: &str, typ: &str, scope_id: NodeId) { + let id = self.normalize_node_id(id); + let scope_id = self.normalize_node_id(scope_id); self.check_and_record(Variable, span, sub_span, @@ -325,10 +407,9 @@ impl<'a> FmtStrs<'a> { name: &str, scope_id: NodeId, value: &str) { - self.check_and_record(Enum, - span, - sub_span, - svec!(id, name, scope_id, value)); + let id = self.normalize_node_id(id); + let scope_id = self.normalize_node_id(scope_id); + self.check_and_record(Enum, span, sub_span, svec!(id, name, scope_id, value)); } pub fn tuple_variant_str(&mut self, @@ -340,6 +421,8 @@ impl<'a> FmtStrs<'a> { typ: &str, val: &str, scope_id: NodeId) { + let id = self.normalize_node_id(id); + let scope_id = self.normalize_node_id(scope_id); self.check_and_record(Variant, span, sub_span, @@ -355,6 +438,9 @@ impl<'a> FmtStrs<'a> { typ: &str, val: &str, scope_id: NodeId) { + let id = self.normalize_node_id(id); + let scope_id = self.normalize_node_id(scope_id); + let ctor_id = self.normalize_node_id(ctor_id); self.check_and_record(VariantStruct, span, sub_span, @@ -367,6 +453,8 @@ impl<'a> FmtStrs<'a> { id: NodeId, name: &str, scope_id: NodeId) { + let id = self.normalize_node_id(id); + let scope_id = self.normalize_node_id(scope_id); self.check_and_record(Function, span, sub_span, @@ -380,14 +468,17 @@ impl<'a> FmtStrs<'a> { name: &str, decl_id: Option, scope_id: NodeId) { + let id = self.normalize_node_id(id); + let scope_id = self.normalize_node_id(scope_id); let values = match decl_id { - Some(decl_id) => svec!(id, name, decl_id.node, decl_id.krate, scope_id), + Some(decl_id) => svec!(id, + name, + decl_id.index.as_usize(), + decl_id.krate, + scope_id), None => svec!(id, name, "", "", scope_id), }; - self.check_and_record(Function, - span, - sub_span, - values); + self.check_and_record(Function, span, sub_span, values); } pub fn method_decl_str(&mut self, @@ -396,10 +487,9 @@ impl<'a> FmtStrs<'a> { id: NodeId, name: &str, scope_id: NodeId) { - self.check_and_record(MethodDecl, - span, - sub_span, - svec!(id, name, scope_id)); + let id = self.normalize_node_id(id); + let scope_id = self.normalize_node_id(scope_id); + self.check_and_record(MethodDecl, span, sub_span, svec!(id, name, scope_id)); } pub fn struct_str(&mut self, @@ -410,6 +500,9 @@ impl<'a> FmtStrs<'a> { name: &str, scope_id: NodeId, value: &str) { + let id = self.normalize_node_id(id); + let scope_id = self.normalize_node_id(scope_id); + let ctor_id = self.normalize_node_id(ctor_id); self.check_and_record(Struct, span, sub_span, @@ -423,10 +516,9 @@ impl<'a> FmtStrs<'a> { name: &str, scope_id: NodeId, value: &str) { - self.check_and_record(Trait, - span, - sub_span, - svec!(id, name, scope_id, value)); + let id = self.normalize_node_id(id); + let scope_id = self.normalize_node_id(scope_id); + self.check_and_record(Trait, span, sub_span, svec!(id, name, scope_id, value)); } pub fn impl_str(&mut self, @@ -436,15 +528,17 @@ impl<'a> FmtStrs<'a> { ref_id: Option, trait_id: Option, scope_id: NodeId) { - let ref_id = ref_id.unwrap_or(ZERO_DEF_ID); - let trait_id = trait_id.unwrap_or(ZERO_DEF_ID); + let id = self.normalize_node_id(id); + let scope_id = self.normalize_node_id(scope_id); + let ref_id = ref_id.unwrap_or(CRATE_ROOT_DEF_ID); + let trait_id = trait_id.unwrap_or(CRATE_ROOT_DEF_ID); self.check_and_record(Impl, span, sub_span, svec!(id, - ref_id.node, + ref_id.index.as_usize(), ref_id.krate, - trait_id.node, + trait_id.index.as_usize(), trait_id.krate, scope_id)); } @@ -456,6 +550,8 @@ impl<'a> FmtStrs<'a> { name: &str, parent: NodeId, filename: &str) { + let id = self.normalize_node_id(id); + let parent = self.normalize_node_id(parent); self.check_and_record(Module, span, sub_span, @@ -469,14 +565,13 @@ impl<'a> FmtStrs<'a> { mod_id: Option, name: &str, parent: NodeId) { - let (mod_node, mod_crate) = match mod_id { - Some(mod_id) => (mod_id.node, mod_id.krate), - None => (0, 0), - }; + let id = self.normalize_node_id(id); + let parent = self.normalize_node_id(parent); + let mod_id = mod_id.unwrap_or(CRATE_ROOT_DEF_ID); self.check_and_record(UseAlias, span, sub_span, - svec!(id, mod_node, mod_crate, name, parent)); + svec!(id, mod_id.index.as_usize(), mod_id.krate, name, parent)); } pub fn use_glob_str(&mut self, @@ -485,10 +580,9 @@ impl<'a> FmtStrs<'a> { id: NodeId, values: &str, parent: NodeId) { - self.check_and_record(UseGlob, - span, - sub_span, - svec!(id, values, parent)); + let id = self.normalize_node_id(id); + let parent = self.normalize_node_id(parent); + self.check_and_record(UseGlob, span, sub_span, svec!(id, values, parent)); } pub fn extern_crate_str(&mut self, @@ -499,6 +593,8 @@ impl<'a> FmtStrs<'a> { name: &str, loc: &str, parent: NodeId) { + let id = self.normalize_node_id(id); + let parent = self.normalize_node_id(parent); self.check_and_record(ExternCrate, span, sub_span, @@ -510,13 +606,11 @@ impl<'a> FmtStrs<'a> { sub_span: Option, base_id: DefId, deriv_id: NodeId) { + let deriv_id = self.normalize_node_id(deriv_id); self.check_and_record(Inheritance, span, sub_span, - svec!(base_id.node, - base_id.krate, - deriv_id, - 0)); + svec!(base_id.index.as_usize(), base_id.krate, deriv_id, 0)); } pub fn fn_call_str(&mut self, @@ -524,10 +618,11 @@ impl<'a> FmtStrs<'a> { sub_span: Option, id: DefId, scope_id: NodeId) { + let scope_id = self.normalize_node_id(scope_id); self.check_and_record(FnCall, span, sub_span, - svec!(id.node, id.krate, "", scope_id)); + svec!(id.index.as_usize(), id.krate, "", scope_id)); } pub fn meth_call_str(&mut self, @@ -536,25 +631,21 @@ impl<'a> FmtStrs<'a> { defid: Option, declid: Option, scope_id: NodeId) { - let (dfn, dfk) = match defid { - Some(defid) => (defid.node, defid.krate), - None => (0, 0), - }; + let scope_id = self.normalize_node_id(scope_id); + let defid = defid.unwrap_or(CRATE_ROOT_DEF_ID); let (dcn, dck) = match declid { - Some(declid) => (s!(declid.node), s!(declid.krate)), + Some(declid) => (s!(declid.index.as_usize()), s!(declid.krate)), None => ("".to_string(), "".to_string()), }; self.check_and_record(MethodCall, span, sub_span, - svec!(dfn, dfk, dcn, dck, scope_id)); + svec!(defid.index.as_usize(), defid.krate, dcn, dck, scope_id)); } pub fn sub_mod_ref_str(&mut self, span: Span, sub_span: Span, qualname: &str, parent: NodeId) { - self.record_with_span(ModRef, - span, - sub_span, - svec!(0, 0, qualname, parent)); + let parent = self.normalize_node_id(parent); + self.record_with_span(ModRef, span, sub_span, svec!(0, 0, qualname, parent)); } pub fn typedef_str(&mut self, @@ -563,17 +654,12 @@ impl<'a> FmtStrs<'a> { id: NodeId, qualname: &str, value: &str) { - self.check_and_record(Typedef, - span, - sub_span, - svec!(id, qualname, value)); + let id = self.normalize_node_id(id); + self.check_and_record(Typedef, span, sub_span, svec!(id, qualname, value)); } pub fn crate_str(&mut self, span: Span, name: &str) { - self.record_with_span(Crate, - span, - span, - svec!(name)); + self.record_with_span(Crate, span, span, svec!(name)); } pub fn external_crate_str(&mut self, span: Span, name: &str, num: ast::CrateNum) { @@ -584,10 +670,7 @@ impl<'a> FmtStrs<'a> { } pub fn sub_type_ref_str(&mut self, span: Span, sub_span: Span, qualname: &str) { - self.record_with_span(TypeRef, - span, - sub_span, - svec!(0, 0, qualname, 0)); + self.record_with_span(TypeRef, span, sub_span, svec!(0, 0, qualname, 0)); } // A slightly generic function for a reference to an item of any kind. @@ -597,9 +680,10 @@ impl<'a> FmtStrs<'a> { sub_span: Option, id: DefId, scope_id: NodeId) { + let scope_id = self.normalize_node_id(scope_id); self.check_and_record(kind, span, sub_span, - svec!(id.node, id.krate, "", scope_id)); + svec!(id.index.as_usize(), id.krate, "", scope_id)); } } diff --git a/src/librustc_trans/save/span_utils.rs b/src/librustc_trans/save/span_utils.rs index 5647e88658..aa19768043 100644 --- a/src/librustc_trans/save/span_utils.rs +++ b/src/librustc_trans/save/span_utils.rs @@ -29,10 +29,14 @@ pub struct SpanUtils<'a> { impl<'a> SpanUtils<'a> { pub fn new(sess: &'a Session) -> SpanUtils<'a> { - SpanUtils { sess: sess, err_count: Cell::new(0) } + SpanUtils { + sess: sess, + err_count: Cell::new(0), + } } // Standard string for extents/location. + #[rustfmt_skip] pub fn extent_str(&self, span: Span) -> String { let lo_loc = self.sess.codemap().lookup_char_pos(span.lo); let hi_loc = self.sess.codemap().lookup_char_pos(span.hi); @@ -54,7 +58,9 @@ impl<'a> SpanUtils<'a> { let loc = self.sess.codemap().lookup_char_pos(span.lo); assert!(!generated_code(span), "generated code; we should not be processing this `{}` in {}, line {}", - self.snippet(span), loc.file.name, loc.line); + self.snippet(span), + loc.file.name, + loc.line); match sub_span { None => None, @@ -86,8 +92,9 @@ impl<'a> SpanUtils<'a> { // the codemap as a new filemap. This is mostly OK, but means we should // not iterate over the codemap. Also, any spans over the new filemap // are incompatible with spans over other filemaps. - let filemap = self.sess.codemap().new_filemap(String::from(""), - self.snippet(span)); + let filemap = self.sess + .codemap() + .new_filemap(String::from(""), self.snippet(span)); let s = self.sess; lexer::StringReader::new(s.diagnostic(), filemap) } @@ -213,8 +220,11 @@ impl<'a> SpanUtils<'a> { if bracket_count != 0 { let loc = self.sess.codemap().lookup_char_pos(span.lo); self.sess.span_bug(span, - &format!("Mis-counted brackets when breaking path? Parsing '{}' in {}, line {}", - self.snippet(span), loc.file.name, loc.line)); + &format!("Mis-counted brackets when breaking path? Parsing '{}' \ + in {}, line {}", + self.snippet(span), + loc.file.name, + loc.line)); } if result.is_none() && prev.tok.is_ident() && bracket_count == 0 { return self.make_sub_span(span, Some(prev.sp)); @@ -239,9 +249,12 @@ impl<'a> SpanUtils<'a> { if ts.tok == token::Eof { if bracket_count != 0 { let loc = self.sess.codemap().lookup_char_pos(span.lo); - self.sess.span_bug(span, &format!( - "Mis-counted brackets when breaking path? Parsing '{}' in {}, line {}", - self.snippet(span), loc.file.name, loc.line)); + self.sess.span_bug(span, + &format!("Mis-counted brackets when breaking path? \ + Parsing '{}' in {}, line {}", + self.snippet(span), + loc.file.name, + loc.line)); } return result } @@ -355,8 +368,11 @@ impl<'a> SpanUtils<'a> { pub fn report_span_err(&self, kind: &str, span: Span) { let loc = self.sess.codemap().lookup_char_pos(span.lo); info!("({}) Could not find sub_span in `{}` in {}, line {}", - kind, self.snippet(span), loc.file.name, loc.line); - self.err_count.set(self.err_count.get()+1); + kind, + self.snippet(span), + loc.file.name, + loc.line); + self.err_count.set(self.err_count.get() + 1); if self.err_count.get() > 1000 { self.sess.bug("span errors reached 1000, giving up"); } diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index c6866004df..566b494f66 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -226,6 +226,7 @@ use std::fmt; use std::rc::Rc; use rustc_front::hir; use syntax::ast::{self, DUMMY_NODE_ID, NodeId}; +use syntax::ext::mtwt; use syntax::codemap::Span; use rustc_front::fold::Folder; use syntax::ptr::P; @@ -275,19 +276,30 @@ impl<'a, 'tcx> Opt<'a, 'tcx> { } fn trans<'blk>(&self, mut bcx: Block<'blk, 'tcx>) -> OptResult<'blk, 'tcx> { + use trans::consts::TrueConst::Yes; let _icx = push_ctxt("match::trans_opt"); let ccx = bcx.ccx(); match *self { ConstantValue(ConstantExpr(lit_expr), _) => { let lit_ty = bcx.tcx().node_id_to_type(lit_expr.id); - let (llval, _) = consts::const_expr(ccx, &*lit_expr, bcx.fcx.param_substs, None); + let expr = consts::const_expr(ccx, &*lit_expr, bcx.fcx.param_substs, None, Yes); + let llval = match expr { + Ok((llval, _)) => llval, + Err(err) => bcx.ccx().sess().span_fatal(lit_expr.span, &err.description()), + }; let lit_datum = immediate_rvalue(llval, lit_ty); let lit_datum = unpack_datum!(bcx, lit_datum.to_appropriate_datum(bcx)); SingleResult(Result::new(bcx, lit_datum.val)) } ConstantRange(ConstantExpr(ref l1), ConstantExpr(ref l2), _) => { - let (l1, _) = consts::const_expr(ccx, &**l1, bcx.fcx.param_substs, None); - let (l2, _) = consts::const_expr(ccx, &**l2, bcx.fcx.param_substs, None); + let l1 = match consts::const_expr(ccx, &**l1, bcx.fcx.param_substs, None, Yes) { + Ok((l1, _)) => l1, + Err(err) => bcx.ccx().sess().span_fatal(l1.span, &err.description()), + }; + let l2 = match consts::const_expr(ccx, &**l2, bcx.fcx.param_substs, None, Yes) { + Ok((l2, _)) => l2, + Err(err) => bcx.ccx().sess().span_fatal(l2.span, &err.description()), + }; RangeResult(Result::new(bcx, l1), Result::new(bcx, l2)) } Variant(disr_val, ref repr, _, _) => { @@ -375,7 +387,7 @@ pub struct BindingInfo<'tcx> { pub ty: Ty<'tcx>, } -type BindingsMap<'tcx> = FnvHashMap>; +type BindingsMap<'tcx> = FnvHashMap>; struct ArmData<'p, 'blk, 'tcx: 'blk> { bodycx: Block<'blk, 'tcx>, @@ -390,7 +402,7 @@ struct ArmData<'p, 'blk, 'tcx: 'blk> { struct Match<'a, 'p: 'a, 'blk: 'a, 'tcx: 'blk> { pats: Vec<&'p hir::Pat>, data: &'a ArmData<'p, 'blk, 'tcx>, - bound_ptrs: Vec<(ast::Ident, ValueRef)>, + bound_ptrs: Vec<(ast::Name, ValueRef)>, // Thread along renamings done by the check_match::StaticInliner, so we can // map back to original NodeIds pat_renaming_map: Option<&'a FnvHashMap<(NodeId, Span), NodeId>> @@ -464,7 +476,7 @@ fn expand_nested_bindings<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, loop { pat = match pat.node { hir::PatIdent(_, ref path, Some(ref inner)) => { - bound_ptrs.push((path.node, val.val)); + bound_ptrs.push((mtwt::resolve(path.node), val.val)); &**inner }, _ => break @@ -505,7 +517,7 @@ fn enter_match<'a, 'b, 'p, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, match this.node { hir::PatIdent(_, ref path, None) => { if pat_is_binding(dm, &*this) { - bound_ptrs.push((path.node, val.val)); + bound_ptrs.push((mtwt::resolve(path.node), val.val)); } } hir::PatVec(ref before, Some(ref slice), ref after) => { @@ -513,7 +525,7 @@ fn enter_match<'a, 'b, 'p, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, let subslice_val = bind_subslice_pat( bcx, this.id, val, before.len(), after.len()); - bound_ptrs.push((path.node, subslice_val)); + bound_ptrs.push((mtwt::resolve(path.node), subslice_val)); } } _ => {} @@ -905,7 +917,7 @@ fn compare_values<'blk, 'tcx>(cx: Block<'blk, 'tcx>, compare_str(cx, lhs_data, lhs_len, rhs_data, rhs_len, rhs_t, debug_loc) } ty::TyArray(ty, _) | ty::TySlice(ty) => match ty.sty { - ty::TyUint(hir::TyU8) => { + ty::TyUint(ast::TyU8) => { // NOTE: cast &[u8] and &[u8; N] to &str and abuse the str_eq lang item, // which calls memcmp(). let pat_len = val_ty(rhs).element_type().array_length(); @@ -943,7 +955,7 @@ fn insert_lllocals<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, bindings_map: &BindingsMap<'tcx>, cs: Option) -> Block<'blk, 'tcx> { - for (&ident, &binding_info) in bindings_map { + for (&name, &binding_info) in bindings_map { let (llval, aliases_other_state) = match binding_info.trmode { // By value mut binding for a copy type: load from the ptr // into the matched value and copy to our alloca @@ -963,8 +975,8 @@ fn insert_lllocals<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, // leaving the remainder of the tuple `(_, // D(B))` still to be dropped in the future. // - // Thus, here we must must zero the place that - // we are moving *from*, because we do not yet + // Thus, here we must zero the place that we + // are moving *from*, because we do not yet // track drop flags for a fragmented parent // match input expression. // @@ -1021,7 +1033,7 @@ fn insert_lllocals<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, debug!("binding {} to {}", binding_info.id, bcx.val_to_string(llval)); bcx.fcx.lllocals.borrow_mut().insert(binding_info.id, datum); - debuginfo::create_match_binding_metadata(bcx, ident.name, binding_info); + debuginfo::create_match_binding_metadata(bcx, name, binding_info); } bcx } @@ -1114,8 +1126,8 @@ fn compile_submatch<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } None => { let data = &m[0].data; - for &(ref ident, ref value_ptr) in &m[0].bound_ptrs { - let binfo = *data.bindings_map.get(ident).unwrap(); + for &(ref name, ref value_ptr) in &m[0].bound_ptrs { + let binfo = *data.bindings_map.get(name).unwrap(); call_lifetime_start(bcx, binfo.llmatch); if binfo.trmode == TrByRef && type_is_fat_ptr(bcx.tcx(), binfo.ty) { expr::copy_fat_ptr(bcx, *value_ptr, binfo.llmatch); @@ -1283,6 +1295,10 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let exhaustive = chk.is_infallible() && defaults.is_empty(); let len = opts.len(); + if exhaustive && kind == Switch { + build::Unreachable(else_cx); + } + // Compile subtrees for each option for (i, opt) in opts.iter().enumerate() { // In some cases of range and vector pattern matching, we need to @@ -1293,7 +1309,7 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let mut opt_cx = else_cx; let debug_loc = opt.debug_loc(); - if !exhaustive || i + 1 < len { + if kind == Switch || !exhaustive || i + 1 < len { opt_cx = bcx.fcx.new_temp_block("match_case"); match kind { Single => Br(bcx, opt_cx.llbb, debug_loc), @@ -1428,19 +1444,19 @@ pub fn trans_match<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, fn is_discr_reassigned(bcx: Block, discr: &hir::Expr, body: &hir::Expr) -> bool { let (vid, field) = match discr.node { hir::ExprPath(..) => match bcx.def(discr.id) { - def::DefLocal(vid) | def::DefUpvar(vid, _, _) => (vid, None), + def::DefLocal(_, vid) | def::DefUpvar(_, vid, _, _) => (vid, None), _ => return false }, hir::ExprField(ref base, field) => { let vid = match bcx.tcx().def_map.borrow().get(&base.id).map(|d| d.full_def()) { - Some(def::DefLocal(vid)) | Some(def::DefUpvar(vid, _, _)) => vid, + Some(def::DefLocal(_, vid)) | Some(def::DefUpvar(_, vid, _, _)) => vid, _ => return false }; - (vid, Some(mc::NamedField(field.node.name))) + (vid, Some(mc::NamedField(field.node))) }, hir::ExprTupField(ref base, field) => { let vid = match bcx.tcx().def_map.borrow().get(&base.id).map(|d| d.full_def()) { - Some(def::DefLocal(vid)) | Some(def::DefUpvar(vid, _, _)) => vid, + Some(def::DefLocal(_, vid)) | Some(def::DefUpvar(_, vid, _, _)) => vid, _ => return false }; (vid, Some(mc::PositionalField(field.node))) @@ -1509,9 +1525,8 @@ fn create_bindings_map<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pat: &hir::Pat, let tcx = bcx.tcx(); let reassigned = is_discr_reassigned(bcx, discr, body); let mut bindings_map = FnvHashMap(); - pat_bindings(&tcx.def_map, &*pat, |bm, p_id, span, path1| { - let ident = path1.node; - let name = ident.name; + pat_bindings_hygienic(&tcx.def_map, &*pat, |bm, p_id, span, path1| { + let name = mtwt::resolve(path1.node); let variable_ty = node_id_type(bcx, p_id); let llvariable_ty = type_of::type_of(ccx, variable_ty); let tcx = bcx.tcx(); @@ -1543,7 +1558,7 @@ fn create_bindings_map<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pat: &hir::Pat, trmode = TrByRef; } }; - bindings_map.insert(ident, BindingInfo { + bindings_map.insert(name, BindingInfo { llmatch: llmatch, trmode: trmode, id: p_id, @@ -1656,7 +1671,7 @@ pub fn store_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pat_bindings(&tcx.def_map, pat, |_, p_id, _, path1| { let scope = cleanup::var_scope(tcx, p_id); bcx = mk_binding_alloca( - bcx, p_id, path1.node.name, scope, (), + bcx, p_id, path1.node, scope, (), "_match::store_local::create_dummy_locals", |(), bcx, Datum { val: llval, ty, kind }| { // Dummy-locals start out uninitialized, so set their @@ -1693,11 +1708,11 @@ pub fn store_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // // In such cases, the more general path is unsafe, because // it assumes it is matching against a valid value. - match simple_identifier(&*pat) { - Some(ident) => { + match simple_name(pat) { + Some(name) => { let var_scope = cleanup::var_scope(tcx, local.id); return mk_binding_alloca( - bcx, pat.id, ident.name, var_scope, (), + bcx, pat.id, name, var_scope, (), "_match::store_local", |(), bcx, Datum { val: v, .. }| expr::trans_into(bcx, &**init_expr, expr::SaveIn(v))); @@ -1872,7 +1887,7 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let pat_repr = adt::represent_type(bcx.ccx(), pat_ty); let pat_v = VariantInfo::of_node(tcx, pat_ty, pat.id); for f in fields { - let name = f.node.ident.name; + let name = f.node.name; let fldptr = adt::trans_field_ptr( bcx, &*pat_repr, diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index 9b630037fe..de09e33ec1 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -51,9 +51,8 @@ use middle::subst; use middle::ty::{self, Ty}; use middle::ty::Disr; use syntax::ast; -use rustc_front::attr; -use rustc_front::attr::IntType; -use rustc_front::hir; +use syntax::attr; +use syntax::attr::IntType; use trans::_match; use trans::build::*; use trans::cleanup; @@ -387,11 +386,11 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let ity = if use_align { // Use the overall alignment match align { - 1 => attr::UnsignedInt(hir::TyU8), - 2 => attr::UnsignedInt(hir::TyU16), - 4 => attr::UnsignedInt(hir::TyU32), + 1 => attr::UnsignedInt(ast::TyU8), + 2 => attr::UnsignedInt(ast::TyU16), + 4 => attr::UnsignedInt(ast::TyU32), 8 if machine::llalign_of_min(cx, Type::i64(cx)) == 8 => - attr::UnsignedInt(hir::TyU64), + attr::UnsignedInt(ast::TyU64), _ => min_ity // use min_ity as a fallback } } else { @@ -583,12 +582,12 @@ fn range_to_inttype(cx: &CrateContext, hint: Hint, bounds: &IntBounds) -> IntTyp // Lists of sizes to try. u64 is always allowed as a fallback. #[allow(non_upper_case_globals)] const choose_shortest: &'static [IntType] = &[ - attr::UnsignedInt(hir::TyU8), attr::SignedInt(hir::TyI8), - attr::UnsignedInt(hir::TyU16), attr::SignedInt(hir::TyI16), - attr::UnsignedInt(hir::TyU32), attr::SignedInt(hir::TyI32)]; + attr::UnsignedInt(ast::TyU8), attr::SignedInt(ast::TyI8), + attr::UnsignedInt(ast::TyU16), attr::SignedInt(ast::TyI16), + attr::UnsignedInt(ast::TyU32), attr::SignedInt(ast::TyI32)]; #[allow(non_upper_case_globals)] const at_least_32: &'static [IntType] = &[ - attr::UnsignedInt(hir::TyU32), attr::SignedInt(hir::TyI32)]; + attr::UnsignedInt(ast::TyU32), attr::SignedInt(ast::TyI32)]; let attempts; match hint { @@ -622,7 +621,7 @@ fn range_to_inttype(cx: &CrateContext, hint: Hint, bounds: &IntBounds) -> IntTyp return ity; } } - return attr::UnsignedInt(hir::TyU64); + return attr::UnsignedInt(ast::TyU64); } pub fn ll_inttype(cx: &CrateContext, ity: IntType) -> Type { diff --git a/src/librustc_trans/trans/asm.rs b/src/librustc_trans/trans/asm.rs index 891baca75a..c59237e307 100644 --- a/src/librustc_trans/trans/asm.rs +++ b/src/librustc_trans/trans/asm.rs @@ -22,6 +22,7 @@ use trans::type_::Type; use rustc_front::hir as ast; use std::ffi::CString; +use syntax::ast::AsmDialect; use libc::{c_uint, c_char}; // Take an inline assembly expression and splat it out via LLVM @@ -105,8 +106,8 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm) }; let dialect = match ia.dialect { - ast::AsmAtt => llvm::AD_ATT, - ast::AsmIntel => llvm::AD_Intel + AsmDialect::Att => llvm::AD_ATT, + AsmDialect::Intel => llvm::AD_Intel }; let asm = CString::new(ia.asm.as_bytes()).unwrap(); diff --git a/src/librustc_trans/trans/attributes.rs b/src/librustc_trans/trans/attributes.rs index c77cb49144..af4c2205e6 100644 --- a/src/librustc_trans/trans/attributes.rs +++ b/src/librustc_trans/trans/attributes.rs @@ -15,8 +15,9 @@ use middle::ty; use middle::infer; use session::config::NoDebugInfo; use syntax::abi; +pub use syntax::attr::InlineAttr; +use syntax::ast; use rustc_front::hir; -pub use rustc_front::attr::InlineAttr; use trans::base; use trans::common; use trans::context::CrateContext; @@ -90,8 +91,8 @@ pub fn set_optimize_for_size(val: ValueRef, optimize: bool) { /// Composite function which sets LLVM attributes for function depending on its AST (#[attribute]) /// attributes. -pub fn from_fn_attrs(ccx: &CrateContext, attrs: &[hir::Attribute], llfn: ValueRef) { - use rustc_front::attr::*; +pub fn from_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRef) { + use syntax::attr::*; inline(llfn, find_inline_attr(Some(ccx.sess().diagnostic()), attrs)); // FIXME: #11906: Omitting frame pointers breaks retrieving the value of a diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 79484ad3dd..14fea610fc 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -37,10 +37,10 @@ use llvm; use metadata::{csearch, encoder, loader}; use middle::astencode; use middle::cfg; -use middle::def_id::{DefId, LOCAL_CRATE}; +use middle::def_id::DefId; use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem}; use middle::weak_lang_items; -use middle::pat_util::simple_identifier; +use middle::pat_util::simple_name; use middle::subst::Substs; use middle::ty::{self, Ty, HasTypeFlags}; use rustc::front::map as hir_map; @@ -89,15 +89,14 @@ use libc::c_uint; use std::ffi::{CStr, CString}; use std::cell::{Cell, RefCell}; use std::collections::{HashMap, HashSet}; -use std::mem; use std::str; use std::{i8, i16, i32, i64}; use syntax::abi::{Rust, RustCall, RustIntrinsic, PlatformIntrinsic, Abi}; use syntax::codemap::Span; use syntax::parse::token::InternedString; +use syntax::attr::AttrMetaMethods; +use syntax::attr; use rustc_front; -use rustc_front::attr::AttrMetaMethods; -use rustc_front::attr; use rustc_front::visit::Visitor; use rustc_front::visit; use rustc_front::hir; @@ -581,12 +580,12 @@ pub fn llty_and_min_for_signed_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, ty::TyInt(t) => { let llty = Type::int_from_ty(cx.ccx(), t); let min = match t { - hir::TyIs if llty == Type::i32(cx.ccx()) => i32::MIN as u64, - hir::TyIs => i64::MIN as u64, - hir::TyI8 => i8::MIN as u64, - hir::TyI16 => i16::MIN as u64, - hir::TyI32 => i32::MIN as u64, - hir::TyI64 => i64::MIN as u64, + ast::TyIs if llty == Type::i32(cx.ccx()) => i32::MIN as u64, + ast::TyIs => i64::MIN as u64, + ast::TyI8 => i8::MIN as u64, + ast::TyI16 => i16::MIN as u64, + ast::TyI32 => i32::MIN as u64, + ast::TyI64 => i64::MIN as u64, }; (llty, min) } @@ -1167,7 +1166,7 @@ fn has_nested_returns(tcx: &ty::ctxt, cfg: &cfg::CFG, blk_id: ast::NodeId) -> bo } Some(hir_map::NodeBlock(blk)) if blk.id == blk_id => { let mut visitor = FindNestedReturn::new(); - visit::walk_expr_opt(&mut visitor, &blk.expr); + walk_list!(&mut visitor, visit_expr, &blk.expr); if visitor.found { return true; } @@ -1286,7 +1285,7 @@ pub fn init_function<'a, 'tcx>(fcx: &'a FunctionContext<'a, 'tcx>, // Create the drop-flag hints for every unfragmented path in the function. let tcx = fcx.ccx.tcx(); - let fn_did = DefId { krate: LOCAL_CRATE, node: fcx.id }; + let fn_did = tcx.map.local_def_id(fcx.id); let mut hints = fcx.lldropflag_hints.borrow_mut(); let fragment_infos = tcx.fragment_infos.borrow(); @@ -1447,10 +1446,10 @@ pub fn create_datums_for_fn_args<'a, 'tcx>(mut bcx: Block<'a, 'tcx>, }; let pat = &*args[i].pat; - bcx = if let Some(ident) = simple_identifier(&*pat) { + bcx = if let Some(name) = simple_name(pat) { // Generate nicer LLVM for the common case of fn a pattern // like `x: T` - set_value_name(arg_datum.val, &bcx.name(ident.name)); + set_value_name(arg_datum.val, &bcx.name(name)); bcx.fcx.lllocals.borrow_mut().insert(pat.id, arg_datum); bcx } else { @@ -1563,7 +1562,7 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>, llfndecl: ValueRef, param_substs: &'tcx Substs<'tcx>, fn_ast_id: ast::NodeId, - _attributes: &[hir::Attribute], + _attributes: &[ast::Attribute], output_type: ty::FnOutput<'tcx>, abi: Abi, closure_env: closure::ClosureEnv<'b>) { @@ -1576,7 +1575,7 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>, param_substs); let has_env = match closure_env { - closure::ClosureEnv::Closure(_) => true, + closure::ClosureEnv::Closure(..) => true, closure::ClosureEnv::NotClosure => false, }; @@ -1682,7 +1681,7 @@ pub fn trans_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, llfndecl: ValueRef, param_substs: &'tcx Substs<'tcx>, id: ast::NodeId, - attrs: &[hir::Attribute]) { + attrs: &[ast::Attribute]) { let _s = StatRecorder::new(ccx, ccx.tcx().map.path_to_string(id).to_string()); debug!("trans_fn(param_substs={:?})", param_substs); let _icx = push_ctxt("trans_fn"); @@ -2085,7 +2084,8 @@ pub fn trans_item(ccx: &CrateContext, item: &hir::Item) { // error in trans. This is used to write compile-fail tests // that actually test that compilation succeeds without // reporting an error. - if ccx.tcx().has_attr(DefId::local(item.id), "rustc_error") { + let item_def_id = ccx.tcx().map.local_def_id(item.id); + if ccx.tcx().has_attr(item_def_id, "rustc_error") { ccx.tcx().sess.span_fatal(item.span, "compilation successful"); } } @@ -2099,7 +2099,7 @@ pub fn trans_item(ccx: &CrateContext, item: &hir::Item) { } hir::ItemImpl(_, _, ref generics, _, _, ref impl_items) => { meth::trans_impl(ccx, - item.ident, + item.name, &impl_items[..], generics, item.id); @@ -2124,7 +2124,10 @@ pub fn trans_item(ccx: &CrateContext, item: &hir::Item) { let mut v = TransItemVisitor{ ccx: ccx }; v.visit_expr(&**expr); - let g = consts::trans_static(ccx, m, expr, item.id, &item.attrs); + let g = match consts::trans_static(ccx, m, expr, item.id, &item.attrs) { + Ok(g) => g, + Err(err) => ccx.tcx().sess.span_fatal(expr.span, &err.description()), + }; set_global_section(ccx, g, item); update_linkage(ccx, g, Some(item.id), OriginalTranslation); }, @@ -2252,13 +2255,14 @@ pub fn create_entry_wrapper(ccx: &CrateContext, Ok(id) => id, Err(s) => { ccx.sess().fatal(&s[..]); } }; - let start_fn = if start_def_id.is_local() { - get_item_val(ccx, start_def_id.node) - } else { - let start_fn_type = csearch::get_type(ccx.tcx(), - start_def_id).ty; - trans_external_path(ccx, start_def_id, start_fn_type) - }; + let start_fn = + if let Some(start_node_id) = ccx.tcx().map.as_local_node_id(start_def_id) { + get_item_val(ccx, start_node_id) + } else { + let start_fn_type = csearch::get_type(ccx.tcx(), + start_def_id).ty; + trans_external_path(ccx, start_def_id, start_fn_type) + }; let args = { let opaque_rust_main = llvm::LLVMBuildPointerCast(bld, @@ -2294,7 +2298,7 @@ pub fn create_entry_wrapper(ccx: &CrateContext, } fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, id: ast::NodeId, - ty: Ty<'tcx>, attrs: &[hir::Attribute]) -> String { + ty: Ty<'tcx>, attrs: &[ast::Attribute]) -> String { match ccx.external_srcs().borrow().get(&id) { Some(&did) => { let sym = csearch::get_symbol(&ccx.sess().cstore, did); @@ -2307,10 +2311,11 @@ fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, id: ast::NodeId, match attr::find_export_name_attr(ccx.sess().diagnostic(), attrs) { // Use provided name Some(name) => name.to_string(), - _ => ccx.tcx().map.with_path(id, |path| { + _ => { + let path = ccx.tcx().map.def_path_from_id(id); if attr::contains_name(attrs, "no_mangle") { // Don't mangle - path.last().unwrap().to_string() + path.last().unwrap().data.to_string() } else { match weak_lang_items::link_name(attrs) { Some(name) => name.to_string(), @@ -2320,7 +2325,7 @@ fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, id: ast::NodeId, } } } - }) + } } } @@ -2425,13 +2430,12 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { hir_map::NodeVariant(ref v) => { let llfn; - let args = match v.node.kind { - hir::TupleVariantKind(ref args) => args, - hir::StructVariantKind(_) => { - ccx.sess().bug("struct variant kind unexpected in get_item_val") - } + let fields = if v.node.data.is_struct() { + ccx.sess().bug("struct variant kind unexpected in get_item_val") + } else { + v.node.data.fields() }; - assert!(!args.is_empty()); + assert!(!fields.is_empty()); let ty = ccx.tcx().node_id_to_type(id); let parent = ccx.tcx().map.get_parent(id); let enm = ccx.tcx().map.expect_item(parent); @@ -2452,12 +2456,11 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { hir_map::NodeStructCtor(struct_def) => { // Only register the constructor if this is a tuple-like struct. - let ctor_id = match struct_def.ctor_id { - None => { - ccx.sess().bug("attempt to register a constructor of \ - a non-tuple-like struct") - } - Some(ctor_id) => ctor_id, + let ctor_id = if struct_def.is_struct() { + ccx.sess().bug("attempt to register a constructor of \ + a non-tuple-like struct") + } else { + struct_def.id() }; let parent = ccx.tcx().map.get_parent(id); let struct_item = ccx.tcx().map.expect_item(parent); @@ -2492,7 +2495,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { } fn register_method(ccx: &CrateContext, id: ast::NodeId, - attrs: &[hir::Attribute], span: Span) -> ValueRef { + attrs: &[ast::Attribute], span: Span) -> ValueRef { let mty = ccx.tcx().node_id_to_type(id); let sym = exported_name(ccx, id, mty, &attrs); @@ -2660,11 +2663,7 @@ impl Iterator for ValueIter { fn next(&mut self) -> Option { let old = self.cur; if !old.is_null() { - self.cur = unsafe { - let step: unsafe extern "C" fn(ValueRef) -> ValueRef = - mem::transmute_copy(&self.step); - step(old) - }; + self.cur = unsafe { (self.step)(old) }; Some(old) } else { None diff --git a/src/librustc_trans/trans/cabi_x86_64.rs b/src/librustc_trans/trans/cabi_x86_64.rs index fa3824866c..00d8fdad32 100644 --- a/src/librustc_trans/trans/cabi_x86_64.rs +++ b/src/librustc_trans/trans/cabi_x86_64.rs @@ -410,18 +410,53 @@ pub fn compute_abi_info(ccx: &CrateContext, } } - let mut arg_tys = Vec::new(); - for t in atys { - let ty = x86_64_ty(ccx, *t, |cls| cls.is_pass_byval(), Attribute::ByVal); - arg_tys.push(ty); - } + let mut int_regs = 6; // RDI, RSI, RDX, RCX, R8, R9 + let mut sse_regs = 8; // XMM0-7 let ret_ty = if ret_def { - x86_64_ty(ccx, rty, |cls| cls.is_ret_bysret(), Attribute::StructRet) + x86_64_ty(ccx, rty, |cls| { + if cls.is_ret_bysret() { + // `sret` parameter thus one less register available + int_regs -= 1; + true + } else { + false + } + }, Attribute::StructRet) } else { ArgType::direct(Type::void(ccx), None, None, None) }; + let mut arg_tys = Vec::new(); + for t in atys { + let ty = x86_64_ty(ccx, *t, |cls| { + let needed_int = cls.iter().filter(|&&c| c == Int).count() as isize; + let needed_sse = cls.iter().filter(|c| c.is_sse()).count() as isize; + let in_mem = cls.is_pass_byval() || + int_regs < needed_int || + sse_regs < needed_sse; + if in_mem { + // `byval` parameter thus one less integer register available + int_regs -= 1; + } else { + // split into sized chunks passed individually + int_regs -= needed_int; + sse_regs -= needed_sse; + } + in_mem + }, Attribute::ByVal); + arg_tys.push(ty); + + // An integer, pointer, double or float parameter + // thus the above closure passed to `x86_64_ty` won't + // get called. + if t.kind() == Integer || t.kind() == Pointer { + int_regs -= 1; + } else if t.kind() == Double || t.kind() == Float { + sse_regs -= 1; + } + } + return FnType { arg_tys: arg_tys, ret_ty: ret_ty, diff --git a/src/librustc_trans/trans/cabi_x86_win64.rs b/src/librustc_trans/trans/cabi_x86_win64.rs index 0a39150dbd..120c8dc038 100644 --- a/src/librustc_trans/trans/cabi_x86_win64.rs +++ b/src/librustc_trans/trans/cabi_x86_win64.rs @@ -46,7 +46,7 @@ pub fn compute_abi_info(ccx: &CrateContext, 2 => ArgType::direct(t, Some(Type::i16(ccx)), None, None), 4 => ArgType::direct(t, Some(Type::i32(ccx)), None, None), 8 => ArgType::direct(t, Some(Type::i64(ccx)), None, None), - _ => ArgType::indirect(t, Some(Attribute::ByVal)) + _ => ArgType::indirect(t, None) } } _ => { diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 124f50d660..c8525e33e2 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -22,11 +22,12 @@ use arena::TypedArena; use back::link; use session; use llvm::{self, ValueRef, get_params}; +use metadata::cstore::LOCAL_CRATE; use middle::def; -use middle::def_id::{DefId, LOCAL_CRATE}; +use middle::def_id::DefId; use middle::infer::normalize_associated_type; use middle::subst; -use middle::subst::{Subst, Substs}; +use middle::subst::{Substs}; use rustc::front::map as hir_map; use trans::adt; use trans::base; @@ -139,8 +140,10 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &hir::Expr) match def { def::DefFn(did, _) if { let maybe_def_id = inline::get_local_instance(bcx.ccx(), did); - let maybe_ast_node = maybe_def_id.and_then(|def_id| bcx.tcx().map - .find(def_id.node)); + let maybe_ast_node = maybe_def_id.and_then(|def_id| { + let node_id = bcx.tcx().map.as_local_node_id(def_id).unwrap(); + bcx.tcx().map.find(node_id) + }); match maybe_ast_node { Some(hir_map::NodeStructCtor(_)) => true, _ => false @@ -161,7 +164,8 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &hir::Expr) ExprId(ref_expr.id), bcx.fcx.param_substs); let def_id = inline::maybe_instantiate_inline(bcx.ccx(), did); - Callee { bcx: bcx, data: Intrinsic(def_id.node, substs), ty: expr_ty } + let node_id = bcx.tcx().map.as_local_node_id(def_id).unwrap(); + Callee { bcx: bcx, data: Intrinsic(node_id, substs), ty: expr_ty } } def::DefFn(did, _) => { fn_callee(bcx, trans_fn_ref(bcx.ccx(), did, ExprId(ref_expr.id), @@ -211,8 +215,8 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &hir::Expr) } def::DefMod(..) | def::DefForeignMod(..) | def::DefTrait(..) | def::DefTy(..) | def::DefPrimTy(..) | def::DefAssociatedTy(..) | - def::DefUse(..) | def::DefRegion(..) | def::DefLabel(..) | - def::DefTyParam(..) | def::DefSelfTy(..) => { + def::DefUse(..) | def::DefLabel(..) | def::DefTyParam(..) | + def::DefSelfTy(..) => { bcx.tcx().sess.span_bug( ref_expr.span, &format!("cannot translate def {:?} \ @@ -335,7 +339,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( let llargs = get_params(fcx.llfn); let self_idx = fcx.arg_offset(); - // the first argument (`self`) will be ptr to the the fn pointer + // the first argument (`self`) will be ptr to the fn pointer let llfnpointer = if is_by_ref { Load(bcx, llargs[self_idx]) } else { @@ -398,91 +402,30 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>( assert!(!substs.types.has_escaping_regions()); let substs = substs.erase_regions(); - // Load the info for the appropriate trait if necessary. - match tcx.trait_of_item(def_id) { - None => {} - Some(trait_id) => { - tcx.populate_implementations_for_trait_if_necessary(trait_id) - } - } - - // We need to do a bunch of special handling for default methods. - // We need to modify the def_id and our substs in order to monomorphize - // the function. - let (is_default, def_id, substs) = match tcx.provided_source(def_id) { - None => { - (false, def_id, tcx.mk_substs(substs)) - } - Some(source_id) => { - // There are two relevant substitutions when compiling - // default methods. First, there is the substitution for - // the type parameters of the impl we are using and the - // method we are calling. This substitution is the substs - // argument we already have. - // In order to compile a default method, though, we need - // to consider another substitution: the substitution for - // the type parameters on trait; the impl we are using - // implements the trait at some particular type - // parameters, and we need to substitute for those first. - // So, what we need to do is find this substitution and - // compose it with the one we already have. - - let impl_id = tcx.impl_or_trait_item(def_id).container() - .id(); - let impl_or_trait_item = tcx.impl_or_trait_item(source_id); - match impl_or_trait_item { - ty::MethodTraitItem(method) => { - let trait_ref = tcx.impl_trait_ref(impl_id).unwrap(); - - // Compute the first substitution - let first_subst = - tcx.make_substs_for_receiver_types(&trait_ref, &*method) - .erase_regions(); - - // And compose them - let new_substs = tcx.mk_substs(first_subst.subst(tcx, &substs)); - - debug!("trans_fn_with_vtables - default method: \ - substs = {:?}, trait_subst = {:?}, \ - first_subst = {:?}, new_subst = {:?}", - substs, trait_ref.substs, - first_subst, new_substs); - - (true, source_id, new_substs) - } - _ => { - tcx.sess.bug("trans_fn_ref_with_vtables() tried \ - to translate a non-method?!") - } - } - } - }; - // Check whether this fn has an inlined copy and, if so, redirect // def_id to the local id of the inlined copy. let def_id = inline::maybe_instantiate_inline(ccx, def_id); - // We must monomorphise if the fn has type parameters, is a default method, - // or is a named tuple constructor. - let must_monomorphise = if !substs.types.is_empty() || is_default { - true - } else if def_id.is_local() { + fn is_named_tuple_constructor(tcx: &ty::ctxt, def_id: DefId) -> bool { + let node_id = match tcx.map.as_local_node_id(def_id) { + Some(n) => n, + None => { return false; } + }; let map_node = session::expect( - ccx.sess(), - tcx.map.find(def_id.node), + &tcx.sess, + tcx.map.find(node_id), || "local item should be in ast map".to_string()); match map_node { - hir_map::NodeVariant(v) => match v.node.kind { - hir::TupleVariantKind(ref args) => !args.is_empty(), - _ => false - }, + hir_map::NodeVariant(v) => { + v.node.data.is_tuple() + } hir_map::NodeStructCtor(_) => true, _ => false } - } else { - false - }; + } + let must_monomorphise = + !substs.types.is_empty() || is_named_tuple_constructor(tcx, def_id); debug!("trans_fn_ref_with_substs({:?}) must_monomorphise: {}", def_id, must_monomorphise); @@ -497,6 +440,7 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>( MethodCallKey(_) => None, }; + let substs = tcx.mk_substs(substs); let (val, fn_ty, must_cast) = monomorphize::monomorphic_fn(ccx, def_id, substs, opt_ref_id); if must_cast && node != ExprId(0) { @@ -526,9 +470,9 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>( // Find the actual function pointer. let mut val = { - if def_id.is_local() { + if let Some(node_id) = ccx.tcx().map.as_local_node_id(def_id) { // Internal reference. - get_item_val(ccx, def_id.node) + get_item_val(ccx, node_id) } else { // External reference. trans_external_path(ccx, def_id, fn_type) @@ -561,10 +505,10 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>( let llty = type_of::type_of_fn_from_ty(ccx, fn_type); let llptrty = llty.ptr_to(); if common::val_ty(val) != llptrty { - debug!("trans_fn_ref_with_vtables(): casting pointer!"); + debug!("trans_fn_ref_with_substs(): casting pointer!"); val = consts::ptrcast(val, llptrty); } else { - debug!("trans_fn_ref_with_vtables(): not casting pointer!"); + debug!("trans_fn_ref_with_substs(): not casting pointer!"); } Datum::new(val, fn_type, Rvalue::new(ByValue)) diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index dc9ea62e9d..d3509c2f81 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -36,6 +36,7 @@ use rustc_front::hir; fn load_closure_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + closure_def_id: DefId, arg_scope_id: ScopeId, freevars: &[ty::Freevar]) -> Block<'blk, 'tcx> @@ -43,10 +44,9 @@ fn load_closure_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let _icx = push_ctxt("closure::load_closure_environment"); // Special case for small by-value selfs. - let closure_id = DefId::local(bcx.fcx.id); - let self_type = self_type_for_closure(bcx.ccx(), closure_id, - node_id_type(bcx, closure_id.node)); - let kind = kind_for_closure(bcx.ccx(), closure_id); + let closure_ty = node_id_type(bcx, bcx.fcx.id); + let self_type = self_type_for_closure(bcx.ccx(), closure_def_id, closure_ty); + let kind = kind_for_closure(bcx.ccx(), closure_def_id); let llenv = if kind == ty::FnOnceClosureKind && !arg_is_indirect(bcx.ccx(), self_type) { let datum = rvalue_scratch_datum(bcx, @@ -69,8 +69,8 @@ fn load_closure_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, }; for (i, freevar) in freevars.iter().enumerate() { - let upvar_id = ty::UpvarId { var_id: freevar.def.local_node_id(), - closure_expr_id: closure_id.node }; + let upvar_id = ty::UpvarId { var_id: freevar.def.var_id(), + closure_expr_id: bcx.fcx.id }; let upvar_capture = bcx.tcx().upvar_capture(upvar_id).unwrap(); let mut upvar_ptr = StructGEP(bcx, llenv, i); let captured_by_ref = match upvar_capture { @@ -80,21 +80,21 @@ fn load_closure_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, true } }; - let def_id = freevar.def.def_id(); - bcx.fcx.llupvars.borrow_mut().insert(def_id.node, upvar_ptr); + let node_id = freevar.def.var_id(); + bcx.fcx.llupvars.borrow_mut().insert(node_id, upvar_ptr); if kind == ty::FnOnceClosureKind && !captured_by_ref { let hint = bcx.fcx.lldropflag_hints.borrow().hint_datum(upvar_id.var_id); bcx.fcx.schedule_drop_mem(arg_scope_id, upvar_ptr, - node_id_type(bcx, def_id.node), + node_id_type(bcx, node_id), hint) } if let Some(env_pointer_alloca) = env_pointer_alloca { debuginfo::create_captured_var_metadata( bcx, - def_id.node, + node_id, env_pointer_alloca, i, captured_by_ref, @@ -107,7 +107,7 @@ fn load_closure_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pub enum ClosureEnv<'a> { NotClosure, - Closure(&'a [ty::Freevar]), + Closure(DefId, &'a [ty::Freevar]), } impl<'a> ClosureEnv<'a> { @@ -116,11 +116,11 @@ impl<'a> ClosureEnv<'a> { { match self { ClosureEnv::NotClosure => bcx, - ClosureEnv::Closure(freevars) => { + ClosureEnv::Closure(def_id, freevars) => { if freevars.is_empty() { bcx } else { - load_closure_environment(bcx, arg_scope, freevars) + load_closure_environment(bcx, def_id, arg_scope, freevars) } } } @@ -147,9 +147,8 @@ pub fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, return llfn; } - let symbol = ccx.tcx().map.with_path(closure_id.node, |path| { - mangle_internal_name_by_path_and_seq(path, "closure") - }); + let path = ccx.tcx().def_path(closure_id); + let symbol = mangle_internal_name_by_path_and_seq(path, "closure"); let function_type = ccx.tcx().mk_closure_from_closure_substs(closure_id, Box::new(substs)); let llfn = declare::define_internal_rust_fn(ccx, &symbol[..], function_type); @@ -176,9 +175,14 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>, decl: &hir::FnDecl, body: &hir::Block, id: ast::NodeId, + closure_def_id: DefId, // (*) closure_substs: &'tcx ty::ClosureSubsts<'tcx>) -> Option> { + // (*) Note that in the case of inlined functions, the `closure_def_id` will be the + // defid of the closure in its original crate, whereas `id` will be the id of the local + // inlined copy. + let param_substs = closure_substs.func_substs; let ccx = match dest { @@ -188,10 +192,10 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>, let tcx = ccx.tcx(); let _icx = push_ctxt("closure::trans_closure_expr"); - debug!("trans_closure_expr()"); + debug!("trans_closure_expr(id={:?}, closure_def_id={:?}, closure_substs={:?})", + id, closure_def_id, closure_substs); - let closure_id = DefId::local(id); - let llfn = get_or_create_closure_declaration(ccx, closure_id, closure_substs); + let llfn = get_or_create_closure_declaration(ccx, closure_def_id, closure_substs); // Get the type of this closure. Use the current `param_substs` as // the closure substitutions. This makes sense because the closure @@ -200,7 +204,7 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>, // of the closure expression. let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables); - let function_type = infcx.closure_type(closure_id, closure_substs); + let function_type = infcx.closure_type(closure_def_id, closure_substs); let freevars: Vec = tcx.with_freevars(id, |fv| fv.iter().cloned().collect()); @@ -216,7 +220,7 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>, &[], sig.output, function_type.abi, - ClosureEnv::Closure(&freevars)); + ClosureEnv::Closure(closure_def_id, &freevars)); // Don't hoist this to the top of the function. It's perfectly legitimate // to have a zero-size closure (in which case dest will be `Ignore`) and @@ -235,7 +239,7 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>, for (i, freevar) in freevars.iter().enumerate() { let datum = expr::trans_local_var(bcx, freevar.def); let upvar_slot_dest = adt::trans_field_ptr(bcx, &*repr, dest_addr, 0, i); - let upvar_id = ty::UpvarId { var_id: freevar.def.local_node_id(), + let upvar_id = ty::UpvarId { var_id: freevar.def.var_id(), closure_expr_id: id }; match tcx.upvar_capture(upvar_id).unwrap() { ty::UpvarCapture::ByValue => { diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index ec34d0dd59..d160465c61 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -39,7 +39,6 @@ use trans::type_of; use middle::traits; use middle::ty::{self, HasTypeFlags, Ty}; use middle::ty::fold::{TypeFolder, TypeFoldable}; -use rustc::front::map::{PathElem, PathName}; use rustc_front::hir; use util::nodemap::{FnvHashMap, NodeMap}; @@ -167,11 +166,11 @@ pub fn return_type_is_void(ccx: &CrateContext, ty: Ty) -> bool { /// Generates a unique symbol based off the name given. This is used to create /// unique symbols for things like closures. -pub fn gensym_name(name: &str) -> PathElem { - let num = token::gensym(name).usize(); +pub fn gensym_name(name: &str) -> ast::Name { + let num = token::gensym(name).0; // use one colon which will get translated to a period by the mangler, and // we're guaranteed that `num` is globally unique for this crate. - PathName(token::gensym(&format!("{}:{}", name, num))) + token::gensym(&format!("{}:{}", name, num)) } /* @@ -829,7 +828,7 @@ pub fn C_cstr(cx: &CrateContext, s: InternedString, null_terminated: bool) -> Va !null_terminated as Bool); let gsym = token::gensym("str"); - let sym = format!("str{}", gsym.usize()); + let sym = format!("str{}", gsym.0); let g = declare::define_global(cx, &sym[..], val_ty(sc)).unwrap_or_else(||{ cx.sess().bug(&format!("symbol `{}` is already defined", sym)); }); @@ -1020,7 +1019,7 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, trait_ref); ccx.sess().span_fatal( span, - "reached the recursion limit during monomorphization"); + "reached the recursion limit during monomorphization (selection ambiguity)"); } Err(e) => { tcx.sess.span_bug( @@ -1145,8 +1144,9 @@ pub fn inlined_variant_def<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, }), ..}) => ty, _ => ctor_ty }.ty_adt_def().unwrap(); + let inlined_vid_def_id = ccx.tcx().map.local_def_id(inlined_vid); adt_def.variants.iter().find(|v| { - DefId::local(inlined_vid) == v.did || + inlined_vid_def_id == v.did || ccx.external().borrow().get(&v.did) == Some(&Some(inlined_vid)) }).unwrap_or_else(|| { ccx.sess().bug(&format!("no variant for {:?}::{}", adt_def, inlined_vid)) diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index a2d74635b5..90faef51c2 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -13,8 +13,9 @@ use back::abi; use llvm; use llvm::{ConstFCmp, ConstICmp, SetLinkage, SetUnnamedAddr}; use llvm::{InternalLinkage, ValueRef, Bool, True}; +use metadata::cstore::LOCAL_CRATE; use middle::{check_const, def}; -use middle::const_eval::{self, ConstVal}; +use middle::const_eval::{self, ConstVal, ConstEvalErr}; use middle::const_eval::{const_int_checked_neg, const_uint_checked_neg}; use middle::const_eval::{const_int_checked_add, const_uint_checked_add}; use middle::const_eval::{const_int_checked_sub, const_uint_checked_sub}; @@ -25,10 +26,13 @@ use middle::const_eval::{const_int_checked_shl, const_uint_checked_shl}; use middle::const_eval::{const_int_checked_shr, const_uint_checked_shr}; use middle::const_eval::EvalHint::ExprTypeChecked; use middle::const_eval::eval_const_expr_partial; -use middle::def_id::{DefId, LOCAL_CRATE}; +use middle::def_id::DefId; use trans::{adt, closure, debuginfo, expr, inline, machine}; use trans::base::{self, push_ctxt}; -use trans::common::*; +use trans::common::{CrateContext, C_integral, C_floating, C_bool, C_str_slice, C_bytes, val_ty}; +use trans::common::{type_is_sized, ExprOrMethodCall, node_id_substs, C_nil, const_get_elt}; +use trans::common::{C_struct, C_undef, const_to_opt_int, const_to_opt_uint, VariantInfo, C_uint}; +use trans::common::{type_is_fat_ptr, Field, C_vector, C_array, C_null, ExprId, MethodCallKey}; use trans::declare; use trans::monomorphize; use trans::type_::Type; @@ -41,30 +45,31 @@ use middle::ty::cast::{CastTy,IntTy}; use util::nodemap::NodeMap; use rustc_front::hir; -use rustc_front::attr; use std::ffi::{CStr, CString}; +use std::borrow::Cow; use libc::c_uint; use syntax::ast; +use syntax::attr; use syntax::parse::token; use syntax::ptr::P; pub type FnArgMap<'a> = Option<&'a NodeMap>; -pub fn const_lit(cx: &CrateContext, e: &hir::Expr, lit: &hir::Lit) +pub fn const_lit(cx: &CrateContext, e: &hir::Expr, lit: &ast::Lit) -> ValueRef { let _icx = push_ctxt("trans_lit"); debug!("const_lit: {:?}", lit); match lit.node { - hir::LitByte(b) => C_integral(Type::uint_from_ty(cx, hir::TyU8), b as u64, false), - hir::LitChar(i) => C_integral(Type::char(cx), i as u64, false), - hir::LitInt(i, hir::SignedIntLit(t, _)) => { + ast::LitByte(b) => C_integral(Type::uint_from_ty(cx, ast::TyU8), b as u64, false), + ast::LitChar(i) => C_integral(Type::char(cx), i as u64, false), + ast::LitInt(i, ast::SignedIntLit(t, _)) => { C_integral(Type::int_from_ty(cx, t), i, true) } - hir::LitInt(u, hir::UnsignedIntLit(t)) => { + ast::LitInt(u, ast::UnsignedIntLit(t)) => { C_integral(Type::uint_from_ty(cx, t), u, false) } - hir::LitInt(i, hir::UnsuffixedIntLit(_)) => { + ast::LitInt(i, ast::UnsuffixedIntLit(_)) => { let lit_int_ty = cx.tcx().node_id_to_type(e.id); match lit_int_ty.sty { ty::TyInt(t) => { @@ -79,10 +84,10 @@ pub fn const_lit(cx: &CrateContext, e: &hir::Expr, lit: &hir::Lit) lit_int_ty)) } } - hir::LitFloat(ref fs, t) => { + ast::LitFloat(ref fs, t) => { C_floating(&fs, Type::float_from_ty(cx, t)) } - hir::LitFloatUnsuffixed(ref fs) => { + ast::LitFloatUnsuffixed(ref fs) => { let lit_float_ty = cx.tcx().node_id_to_type(e.id); match lit_float_ty.sty { ty::TyFloat(t) => { @@ -94,10 +99,10 @@ pub fn const_lit(cx: &CrateContext, e: &hir::Expr, lit: &hir::Lit) } } } - hir::LitBool(b) => C_bool(cx, b), - hir::LitStr(ref s, _) => C_str_slice(cx, (*s).clone()), - hir::LitByteStr(ref data) => { - addr_of(cx, C_bytes(cx, &data[..]), "byte_str") + ast::LitBool(b) => C_bool(cx, b), + ast::LitStr(ref s, _) => C_str_slice(cx, (*s).clone()), + ast::LitByteStr(ref data) => { + addr_of(cx, C_bytes(cx, &data[..]), 1, "byte_str") } } } @@ -110,17 +115,19 @@ pub fn ptrcast(val: ValueRef, ty: Type) -> ValueRef { fn addr_of_mut(ccx: &CrateContext, cv: ValueRef, + align: machine::llalign, 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.usize()); + let name = format!("{}{}", kind, gsym.0); let gv = declare::define_global(ccx, &name[..], val_ty(cv)).unwrap_or_else(||{ ccx.sess().bug(&format!("symbol `{}` is already defined", name)); }); llvm::LLVMSetInitializer(gv, cv); + llvm::LLVMSetAlignment(gv, align); SetLinkage(gv, InternalLinkage); SetUnnamedAddr(gv, true); gv @@ -129,13 +136,23 @@ fn addr_of_mut(ccx: &CrateContext, pub fn addr_of(ccx: &CrateContext, cv: ValueRef, + align: machine::llalign, kind: &str) -> ValueRef { match ccx.const_globals().borrow().get(&cv) { - Some(&gv) => return gv, + Some(&gv) => { + unsafe { + // Upgrade the alignment in cases where the same constant is used with different + // alignment requirements + if align > llvm::LLVMGetAlignment(gv) { + llvm::LLVMSetAlignment(gv, align); + } + } + return gv; + } None => {} } - let gv = addr_of_mut(ccx, cv, kind); + let gv = addr_of_mut(ccx, cv, align, kind); unsafe { llvm::LLVMSetGlobalConstant(gv, True); } @@ -178,7 +195,8 @@ fn const_fn_call<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, node: ExprOrMethodCall, def_id: DefId, arg_vals: &[ValueRef], - param_substs: &'tcx Substs<'tcx>) -> ValueRef { + param_substs: &'tcx Substs<'tcx>, + trueconst: TrueConst) -> Result { let fn_like = const_eval::lookup_const_fn_by_id(ccx.tcx(), def_id); let fn_like = fn_like.expect("lookup_const_fn_by_id failed in const_fn_call"); @@ -191,9 +209,9 @@ fn const_fn_call<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let substs = ccx.tcx().mk_substs(node_id_substs(ccx, node, param_substs)); match fn_like.body().expr { Some(ref expr) => { - const_expr(ccx, &**expr, substs, Some(&fn_args)).0 - } - None => C_nil(ccx) + const_expr(ccx, &**expr, substs, Some(&fn_args), trueconst).map(|(res, _)| res) + }, + None => Ok(C_nil(ccx)), } } @@ -216,19 +234,57 @@ pub fn get_const_expr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } } +pub enum ConstEvalFailure { + /// in case the const evaluator failed on something that panic at runtime + /// as defined in RFC 1229 + Runtime(ConstEvalErr), + // in case we found a true constant + Compiletime(ConstEvalErr), +} + +impl ConstEvalFailure { + fn into_inner(self) -> ConstEvalErr { + match self { + Runtime(e) => e, + Compiletime(e) => e, + } + } + pub fn description(&self) -> Cow { + match self { + &Runtime(ref e) => e.description(), + &Compiletime(ref e) => e.description(), + } + } +} + +#[derive(Copy, Clone)] +pub enum TrueConst { + Yes, No +} + +use self::ConstEvalFailure::*; + fn get_const_val(ccx: &CrateContext, def_id: DefId, - ref_expr: &hir::Expr) -> ValueRef { + ref_expr: &hir::Expr) -> Result { let expr = get_const_expr(ccx, def_id, ref_expr); let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty()); - get_const_expr_as_global(ccx, expr, check_const::ConstQualif::empty(), empty_substs) + match get_const_expr_as_global(ccx, expr, check_const::ConstQualif::empty(), + empty_substs, TrueConst::Yes) { + Err(Runtime(err)) => { + ccx.tcx().sess.span_err(expr.span, &err.description()); + Err(Compiletime(err)) + }, + other => other, + } } pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, expr: &hir::Expr, qualif: check_const::ConstQualif, - param_substs: &'tcx Substs<'tcx>) - -> ValueRef { + param_substs: &'tcx Substs<'tcx>, + trueconst: TrueConst) + -> Result { debug!("get_const_expr_as_global: {:?}", expr.id); // Special-case constants to cache a common global for all uses. match expr.node { @@ -250,17 +306,20 @@ pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let key = (expr.id, param_substs); match ccx.const_values().borrow().get(&key) { - Some(&val) => return val, + Some(&val) => return Ok(val), None => {} } + let ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs, + &ccx.tcx().expr_ty(expr)); let val = if qualif.intersects(check_const::ConstQualif::NON_STATIC_BORROWS) { // Avoid autorefs as they would create global instead of stack // references, even when only the latter are correct. - let ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs, - &ccx.tcx().expr_ty(expr)); - const_expr_unadjusted(ccx, expr, ty, param_substs, None) + try!(const_expr_unadjusted(ccx, expr, ty, param_substs, None, trueconst)) } else { - const_expr(ccx, expr, param_substs, None).0 + match const_expr(ccx, expr, param_substs, None, trueconst) { + Err(err) => return Err(err), + Ok((ok, _)) => ok, + } }; // boolean SSA values are i1, but they have to be stored in i8 slots, @@ -273,19 +332,20 @@ pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } }; - let lvalue = addr_of(ccx, val, "const"); + let lvalue = addr_of(ccx, val, type_of::align_of(ccx, ty), "const"); ccx.const_values().borrow_mut().insert(key, lvalue); - lvalue + Ok(lvalue) } pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, e: &hir::Expr, param_substs: &'tcx Substs<'tcx>, - fn_args: FnArgMap) - -> (ValueRef, Ty<'tcx>) { + fn_args: FnArgMap, + trueconst: TrueConst) + -> Result<(ValueRef, Ty<'tcx>), ConstEvalFailure> { let ety = monomorphize::apply_param_substs(cx.tcx(), param_substs, &cx.tcx().expr_ty(e)); - let llconst = const_expr_unadjusted(cx, e, ety, param_substs, fn_args); + let llconst = try!(const_expr_unadjusted(cx, e, ety, param_substs, fn_args, trueconst)); let mut llconst = llconst; let mut ety_adjusted = monomorphize::apply_param_substs(cx.tcx(), param_substs, &cx.tcx().expr_ty_adjusted(e)); @@ -313,7 +373,7 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, if adj.autoderefs == 0 { // Don't copy data to do a deref+ref // (i.e., skip the last auto-deref). - llconst = addr_of(cx, llconst, "autoref"); + llconst = addr_of(cx, llconst, type_of::align_of(cx, ty), "autoref"); ty = cx.tcx().mk_imm_ref(cx.tcx().mk_region(ty::ReStatic), ty); } } else { @@ -380,11 +440,11 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, e, ety_adjusted, csize, tsize)); } - (llconst, ety_adjusted) + Ok((llconst, ety_adjusted)) } fn check_unary_expr_validity(cx: &CrateContext, e: &hir::Expr, t: Ty, - te: ValueRef) { + te: ValueRef, trueconst: TrueConst) -> Result<(), ConstEvalFailure> { // The only kind of unary expression that we check for validity // here is `-expr`, to check if it "overflows" (e.g. `-i32::MIN`). if let hir::ExprUnary(hir::UnNeg, ref inner_e) = e.node { @@ -397,13 +457,13 @@ fn check_unary_expr_validity(cx: &CrateContext, e: &hir::Expr, t: Ty, // // Catch this up front by looking for ExprLit directly, // and just accepting it. - if let hir::ExprLit(_) = inner_e.node { return; } + if let hir::ExprLit(_) = inner_e.node { return Ok(()); } let result = match t.sty { ty::TyInt(int_type) => { let input = match const_to_opt_int(te) { Some(v) => v, - None => return, + None => return Ok(()), }; const_int_checked_neg( input, e, Some(const_eval::IntTy::from(cx.tcx(), int_type))) @@ -411,31 +471,51 @@ fn check_unary_expr_validity(cx: &CrateContext, e: &hir::Expr, t: Ty, ty::TyUint(uint_type) => { let input = match const_to_opt_uint(te) { Some(v) => v, - None => return, + None => return Ok(()), }; const_uint_checked_neg( input, e, Some(const_eval::UintTy::from(cx.tcx(), uint_type))) } - _ => return, + _ => return Ok(()), }; + const_err(cx, e, result, trueconst) + } else { + Ok(()) + } +} - // We do not actually care about a successful result. - if let Err(err) = result { +fn const_err(cx: &CrateContext, + e: &hir::Expr, + result: Result, + trueconst: TrueConst) + -> Result<(), ConstEvalFailure> { + match (result, trueconst) { + (Ok(_), _) => { + // We do not actually care about a successful result. + Ok(()) + }, + (Err(err), TrueConst::Yes) => { cx.tcx().sess.span_err(e.span, &err.description()); - } + Err(Compiletime(err)) + }, + (Err(err), TrueConst::No) => { + cx.tcx().sess.span_warn(e.span, &err.description()); + Err(Runtime(err)) + }, } } fn check_binary_expr_validity(cx: &CrateContext, e: &hir::Expr, t: Ty, - te1: ValueRef, te2: ValueRef) { - let b = if let hir::ExprBinary(b, _, _) = e.node { b } else { return }; + te1: ValueRef, te2: ValueRef, + trueconst: TrueConst) -> Result<(), ConstEvalFailure> { + let b = if let hir::ExprBinary(b, _, _) = e.node { b } else { unreachable!() }; let result = match t.sty { ty::TyInt(int_type) => { let (lhs, rhs) = match (const_to_opt_int(te1), const_to_opt_int(te2)) { (Some(v1), Some(v2)) => (v1, v2), - _ => return, + _ => return Ok(()), }; let opt_ety = Some(const_eval::IntTy::from(cx.tcx(), int_type)); @@ -447,14 +527,14 @@ fn check_binary_expr_validity(cx: &CrateContext, e: &hir::Expr, t: Ty, hir::BiRem => const_int_checked_rem(lhs, rhs, e, opt_ety), hir::BiShl => const_int_checked_shl(lhs, rhs, e, opt_ety), hir::BiShr => const_int_checked_shr(lhs, rhs, e, opt_ety), - _ => return, + _ => return Ok(()), } } ty::TyUint(uint_type) => { let (lhs, rhs) = match (const_to_opt_uint(te1), const_to_opt_uint(te2)) { (Some(v1), Some(v2)) => (v1, v2), - _ => return, + _ => return Ok(()), }; let opt_ety = Some(const_eval::UintTy::from(cx.tcx(), uint_type)); @@ -466,43 +546,44 @@ fn check_binary_expr_validity(cx: &CrateContext, e: &hir::Expr, t: Ty, hir::BiRem => const_uint_checked_rem(lhs, rhs, e, opt_ety), hir::BiShl => const_uint_checked_shl(lhs, rhs, e, opt_ety), hir::BiShr => const_uint_checked_shr(lhs, rhs, e, opt_ety), - _ => return, + _ => return Ok(()), } } - _ => return, + _ => return Ok(()), }; - // We do not actually care about a successful result. - if let Err(err) = result { - cx.tcx().sess.span_err(e.span, &err.description()); - } + const_err(cx, e, result, trueconst) } fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, e: &hir::Expr, ety: Ty<'tcx>, param_substs: &'tcx Substs<'tcx>, - fn_args: FnArgMap) - -> ValueRef + fn_args: FnArgMap, + trueconst: TrueConst) + -> Result { debug!("const_expr_unadjusted(e={:?}, ety={:?}, param_substs={:?})", e, ety, param_substs); - let map_list = |exprs: &[P]| -> Vec { + let map_list = |exprs: &[P]| -> Result, ConstEvalFailure> { exprs.iter() - .map(|e| const_expr(cx, &**e, param_substs, fn_args).0) + .map(|e| const_expr(cx, &**e, param_substs, fn_args, trueconst).map(|(l, _)| l)) + .collect::>>() + .into_iter() .collect() + // this dance is necessary to eagerly run const_expr so all errors are reported }; let _icx = push_ctxt("const_expr"); - match e.node { + Ok(match e.node { hir::ExprLit(ref lit) => { const_lit(cx, e, &**lit) }, hir::ExprBinary(b, ref e1, ref e2) => { /* Neither type is bottom, and we expect them to be unified * already, so the following is safe. */ - let (te1, ty) = const_expr(cx, &**e1, param_substs, fn_args); + let (te1, ty) = try!(const_expr(cx, &**e1, param_substs, fn_args, trueconst)); debug!("const_expr_unadjusted: te1={}, ty={:?}", cx.tn().val_to_string(te1), ty); @@ -510,9 +591,9 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let is_float = ty.is_fp(); let signed = ty.is_signed(); - let (te2, _) = const_expr(cx, &**e2, param_substs, fn_args); + let (te2, _) = try!(const_expr(cx, &**e2, param_substs, fn_args, trueconst)); - check_binary_expr_validity(cx, e, ty, te1, te2); + try!(check_binary_expr_validity(cx, e, ty, te1, te2, trueconst)); unsafe { match b.node { hir::BiAdd if is_float => llvm::LLVMConstFAdd(te1, te2), @@ -558,35 +639,34 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } } // unsafe { match b.node { }, hir::ExprUnary(u, ref inner_e) => { - let (te, ty) = const_expr(cx, &**inner_e, param_substs, fn_args); + let (te, ty) = try!(const_expr(cx, &**inner_e, param_substs, fn_args, trueconst)); - check_unary_expr_validity(cx, e, ty, te); + try!(check_unary_expr_validity(cx, e, ty, te, trueconst)); let is_float = ty.is_fp(); unsafe { match u { - hir::UnUniq | hir::UnDeref => const_deref(cx, te, ty).0, - hir::UnNot => llvm::LLVMConstNot(te), - hir::UnNeg if is_float => llvm::LLVMConstFNeg(te), - hir::UnNeg => llvm::LLVMConstNeg(te), + hir::UnDeref => const_deref(cx, te, ty).0, + hir::UnNot => llvm::LLVMConstNot(te), + hir::UnNeg if is_float => llvm::LLVMConstFNeg(te), + hir::UnNeg => llvm::LLVMConstNeg(te), } } }, hir::ExprField(ref base, field) => { - let (bv, bt) = const_expr(cx, &**base, param_substs, fn_args); + let (bv, bt) = try!(const_expr(cx, &**base, param_substs, fn_args, trueconst)); let brepr = adt::represent_type(cx, bt); let vinfo = VariantInfo::from_ty(cx.tcx(), bt, None); - let ix = vinfo.field_index(field.node.name); + let ix = vinfo.field_index(field.node); adt::const_get_field(cx, &*brepr, bv, vinfo.discr, ix) }, hir::ExprTupField(ref base, idx) => { - let (bv, bt) = const_expr(cx, &**base, param_substs, fn_args); + let (bv, bt) = try!(const_expr(cx, &**base, param_substs, fn_args, trueconst)); let brepr = adt::represent_type(cx, bt); let vinfo = VariantInfo::from_ty(cx.tcx(), bt, None); adt::const_get_field(cx, &*brepr, bv, vinfo.discr, idx.node) }, - hir::ExprIndex(ref base, ref index) => { - let (bv, bt) = const_expr(cx, &**base, param_substs, fn_args); - let iv = match eval_const_expr_partial(cx.tcx(), &index, ExprTypeChecked) { + let (bv, bt) = try!(const_expr(cx, &**base, param_substs, fn_args, trueconst)); + let iv = match eval_const_expr_partial(cx.tcx(), &index, ExprTypeChecked, None) { Ok(ConstVal::Int(i)) => i as u64, Ok(ConstVal::Uint(u)) => u, _ => cx.sess().span_bug(index.span, @@ -627,9 +707,9 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, if iv >= len { // FIXME #3170: report this earlier on in the const-eval // pass. Reporting here is a bit late. - cx.sess().span_err(e.span, - "const index-expr is out of bounds"); - C_undef(type_of::type_of(cx, bt).element_type()) + span_err!(cx.sess(), e.span, E0515, + "const index-expr is out of bounds"); + C_undef(val_ty(arr).element_type()) } else { const_get_elt(cx, arr, &[iv as c_uint]) } @@ -637,10 +717,10 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, hir::ExprCast(ref base, _) => { let t_cast = ety; let llty = type_of::type_of(cx, t_cast); - let (v, t_expr) = const_expr(cx, &**base, param_substs, fn_args); + let (v, t_expr) = try!(const_expr(cx, &**base, param_substs, fn_args, trueconst)); debug!("trans_const_cast({:?} as {:?})", t_expr, t_cast); if expr::cast_is_noop(cx.tcx(), base, t_expr, t_cast) { - return v; + return Ok(v); } if type_is_fat_ptr(cx.tcx(), t_expr) { // Fat pointer casts. @@ -651,9 +731,9 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ptr_ty); if type_is_fat_ptr(cx.tcx(), t_cast) { let info = const_get_elt(cx, v, &[abi::FAT_PTR_EXTRA as u32]); - return C_struct(cx, &[addr, info], false) + return Ok(C_struct(cx, &[addr, info], false)) } else { - return addr; + return Ok(addr); } } unsafe { match ( @@ -703,7 +783,6 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let mut cur = sub; loop { match cur.node { - hir::ExprParen(ref sub) => cur = sub, hir::ExprBlock(ref blk) => { if let Some(ref sub) = blk.expr { cur = sub; @@ -720,35 +799,47 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } else { // If this isn't the address of a static, then keep going through // normal constant evaluation. - let (v, _) = const_expr(cx, &**sub, param_substs, fn_args); - addr_of(cx, v, "ref") + let (v, ty) = try!(const_expr(cx, &**sub, param_substs, fn_args, trueconst)); + addr_of(cx, v, type_of::align_of(cx, ty), "ref") } }, hir::ExprAddrOf(hir::MutMutable, ref sub) => { - let (v, _) = const_expr(cx, &**sub, param_substs, fn_args); - addr_of_mut(cx, v, "ref_mut_slice") + let (v, ty) = try!(const_expr(cx, &**sub, param_substs, fn_args, trueconst)); + addr_of_mut(cx, v, type_of::align_of(cx, ty), "ref_mut_slice") }, hir::ExprTup(ref es) => { let repr = adt::represent_type(cx, ety); - let vals = map_list(&es[..]); + let vals = try!(map_list(&es[..])); adt::trans_const(cx, &*repr, 0, &vals[..]) }, hir::ExprStruct(_, ref fs, ref base_opt) => { let repr = adt::represent_type(cx, ety); let base_val = match *base_opt { - Some(ref base) => Some(const_expr(cx, &**base, param_substs, fn_args)), + Some(ref base) => Some(try!(const_expr( + cx, + &**base, + param_substs, + fn_args, + trueconst, + ))), None => None }; let VariantInfo { discr, fields } = VariantInfo::of_node(cx.tcx(), ety, e.id); let cs = fields.iter().enumerate().map(|(ix, &Field(f_name, _))| { - match (fs.iter().find(|f| f_name == f.ident.node.name), base_val) { - (Some(ref f), _) => const_expr(cx, &*f.expr, param_substs, fn_args).0, - (_, Some((bv, _))) => adt::const_get_field(cx, &*repr, bv, discr, ix), + match (fs.iter().find(|f| f_name == f.name.node), base_val) { + (Some(ref f), _) => { + const_expr(cx, &*f.expr, param_substs, fn_args, trueconst).map(|(l, _)| l) + }, + (_, Some((bv, _))) => Ok(adt::const_get_field(cx, &*repr, bv, discr, ix)), (_, None) => cx.sess().span_bug(e.span, "missing struct field"), } - }).collect::>(); + }) + .collect::>>() + .into_iter() + .collect::,ConstEvalFailure>>(); + let cs = try!(cs); if ety.is_simd() { C_vector(&cs[..]) } else { @@ -759,8 +850,17 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let unit_ty = ety.sequence_element_type(cx.tcx()); let llunitty = type_of::type_of(cx, unit_ty); let vs = es.iter() - .map(|e| const_expr(cx, &**e, param_substs, fn_args).0) - .collect::>(); + .map(|e| const_expr( + cx, + &**e, + param_substs, + fn_args, + trueconst, + ).map(|(l, _)| l)) + .collect::>>() + .into_iter() + .collect::, ConstEvalFailure>>(); + let vs = try!(vs); // If the vector contains enums, an LLVM array won't work. if vs.iter().any(|vi| val_ty(*vi) != llunitty) { C_struct(cx, &vs[..], false) @@ -772,7 +872,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let unit_ty = ety.sequence_element_type(cx.tcx()); let llunitty = type_of::type_of(cx, unit_ty); let n = cx.tcx().eval_repeat_count(count); - let unit_val = const_expr(cx, &**elem, param_substs, fn_args).0; + let unit_val = try!(const_expr(cx, &**elem, param_substs, fn_args, trueconst)).0; let vs = vec![unit_val; n]; if val_ty(unit_val) != llunitty { C_struct(cx, &vs[..], false) @@ -783,7 +883,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, hir::ExprPath(..) => { let def = cx.tcx().def_map.borrow().get(&e.id).unwrap().full_def(); match def { - def::DefLocal(id) => { + def::DefLocal(_, id) => { if let Some(val) = fn_args.and_then(|args| args.get(&id).cloned()) { val } else { @@ -794,7 +894,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val } def::DefConst(def_id) | def::DefAssociatedConst(def_id) => { - const_deref_ptr(cx, get_const_val(cx, def_id, e)) + const_deref_ptr(cx, try!(get_const_val(cx, def_id, e))) } def::DefVariant(enum_did, variant_did, _) => { let vinfo = cx.tcx().lookup_adt_def(enum_did).variant_with_id(variant_did); @@ -806,7 +906,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::VariantKind::Tuple => { expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val } - ty::VariantKind::Dict => { + ty::VariantKind::Struct => { cx.sess().span_bug(e.span, "path-expr refers to a dict variant!") } } @@ -830,7 +930,6 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let mut callee = &**callee; loop { callee = match callee.node { - hir::ExprParen(ref inner) => &**inner, hir::ExprBlock(ref block) => match block.expr { Some(ref tail) => &**tail, None => break, @@ -839,10 +938,17 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, }; } let def = cx.tcx().def_map.borrow()[&callee.id].full_def(); - let arg_vals = map_list(args); + let arg_vals = try!(map_list(args)); match def { def::DefFn(did, _) | def::DefMethod(did) => { - const_fn_call(cx, ExprId(callee.id), did, &arg_vals, param_substs) + try!(const_fn_call( + cx, + ExprId(callee.id), + did, + &arg_vals, + param_substs, + trueconst, + )) } def::DefStruct(_) => { if ety.is_simd() { @@ -864,24 +970,29 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } }, hir::ExprMethodCall(_, _, ref args) => { - let arg_vals = map_list(args); + let arg_vals = try!(map_list(args)); let method_call = ty::MethodCall::expr(e.id); let method_did = cx.tcx().tables.borrow().method_map[&method_call].def_id; - const_fn_call(cx, MethodCallKey(method_call), - method_did, &arg_vals, param_substs) + try!(const_fn_call(cx, MethodCallKey(method_call), + method_did, &arg_vals, param_substs, trueconst)) }, - hir::ExprParen(ref e) => const_expr(cx, &**e, param_substs, fn_args).0, hir::ExprBlock(ref block) => { match block.expr { - Some(ref expr) => const_expr(cx, &**expr, param_substs, fn_args).0, + Some(ref expr) => try!(const_expr( + cx, + &**expr, + param_substs, + fn_args, + trueconst, + )).0, None => C_nil(cx), } }, hir::ExprClosure(_, ref decl, ref body) => { match ety.sty { - ty::TyClosure(_, ref substs) => { + ty::TyClosure(def_id, ref substs) => { closure::trans_closure_expr(closure::Dest::Ignore(cx), decl, - body, e.id, substs); + body, e.id, def_id, substs); } _ => cx.sess().span_bug( @@ -892,20 +1003,27 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, }, _ => cx.sess().span_bug(e.span, "bad constant expression type in consts::const_expr"), - } + }) } + pub fn trans_static(ccx: &CrateContext, m: hir::Mutability, expr: &hir::Expr, id: ast::NodeId, - attrs: &Vec) - -> ValueRef { + attrs: &Vec) + -> Result { unsafe { let _icx = push_ctxt("trans_static"); let g = base::get_item_val(ccx, id); let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty()); - let (v, _) = const_expr(ccx, expr, empty_substs, None); + let (v, _) = try!(const_expr( + ccx, + expr, + empty_substs, + None, + TrueConst::Yes, + ).map_err(|e| e.into_inner())); // boolean SSA values are i1, but they have to be stored in i8 slots, // otherwise some LLVM optimization passes don't work as expected @@ -936,6 +1054,7 @@ pub fn trans_static(ccx: &CrateContext, ccx.statics_to_rauw().borrow_mut().push((g, new_g)); new_g }; + llvm::LLVMSetAlignment(g, type_of::align_of(ccx, ty)); llvm::LLVMSetInitializer(g, v); // As an optimization, all shared statics which do not have interior @@ -953,7 +1072,7 @@ pub fn trans_static(ccx: &CrateContext, "thread_local") { llvm::set_thread_local(g, true); } - g + Ok(g) } } @@ -962,6 +1081,9 @@ fn get_static_val<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, did: DefId, ty: Ty<'tcx>) -> ValueRef { - if did.is_local() { return base::get_item_val(ccx, did.node) } - base::trans_external_path(ccx, did, ty) + if let Some(node_id) = ccx.tcx().map.as_local_node_id(did) { + base::get_item_val(ccx, node_id) + } else { + base::trans_external_path(ccx, did, ty) + } } diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs index 94ce92ab97..b92e02fec5 100644 --- a/src/librustc_trans/trans/context.rs +++ b/src/librustc_trans/trans/context.rs @@ -838,7 +838,6 @@ fn declare_intrinsic(ccx: &CrateContext, key: &str) -> Option { ifn!("llvm.trap", fn() -> void); ifn!("llvm.debugtrap", fn() -> void); - ifn!("llvm.frameaddress", fn(t_i32) -> i8p); ifn!("llvm.powi.f32", fn(t_f32, t_i32) -> t_f32); ifn!("llvm.powi.f64", fn(t_f64, t_i32) -> t_f64); diff --git a/src/librustc_trans/trans/controlflow.rs b/src/librustc_trans/trans/controlflow.rs index 340eabf77d..5f83abc065 100644 --- a/src/librustc_trans/trans/controlflow.rs +++ b/src/librustc_trans/trans/controlflow.rs @@ -22,6 +22,7 @@ use trans::consts; use trans::debuginfo; use trans::debuginfo::{DebugLoc, ToDebugLoc}; use trans::expr; +use trans::machine; use trans; use middle::ty; @@ -305,7 +306,7 @@ pub fn trans_loop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pub fn trans_break_cont<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &hir::Expr, - opt_label: Option, + opt_label: Option, exit: usize) -> Block<'blk, 'tcx> { let _icx = push_ctxt("trans_break_cont"); @@ -338,14 +339,14 @@ pub fn trans_break_cont<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pub fn trans_break<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &hir::Expr, - label_opt: Option) + label_opt: Option) -> Block<'blk, 'tcx> { return trans_break_cont(bcx, expr, label_opt, cleanup::EXIT_BREAK); } pub fn trans_cont<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &hir::Expr, - label_opt: Option) + label_opt: Option) -> Block<'blk, 'tcx> { return trans_break_cont(bcx, expr, label_opt, cleanup::EXIT_LOOP); } @@ -401,7 +402,8 @@ pub fn trans_fail<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let filename = C_str_slice(ccx, filename); let line = C_u32(ccx, loc.line as u32); let expr_file_line_const = C_struct(ccx, &[v_str, filename, line], false); - let expr_file_line = consts::addr_of(ccx, expr_file_line_const, "panic_loc"); + let align = machine::llalign_of_min(ccx, val_ty(expr_file_line_const)); + let expr_file_line = consts::addr_of(ccx, expr_file_line_const, align, "panic_loc"); let args = vec!(expr_file_line); let did = langcall(bcx, Some(call_info.span), "", PanicFnLangItem); let bcx = callee::trans_lang_call(bcx, @@ -433,7 +435,8 @@ pub fn trans_fail_bounds_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let filename = C_str_slice(ccx, filename); let line = C_u32(ccx, loc.line as u32); let file_line_const = C_struct(ccx, &[filename, line], false); - let file_line = consts::addr_of(ccx, file_line_const, "panic_bounds_check_loc"); + let align = machine::llalign_of_min(ccx, val_ty(file_line_const)); + let file_line = consts::addr_of(ccx, file_line_const, align, "panic_bounds_check_loc"); let args = vec!(file_line, index, len); let did = langcall(bcx, Some(call_info.span), "", PanicBoundsCheckFnLangItem); let bcx = callee::trans_lang_call(bcx, diff --git a/src/librustc_trans/trans/debuginfo/create_scope_map.rs b/src/librustc_trans/trans/debuginfo/create_scope_map.rs index ca616b5622..7597d5f92a 100644 --- a/src/librustc_trans/trans/debuginfo/create_scope_map.rs +++ b/src/librustc_trans/trans/debuginfo/create_scope_map.rs @@ -49,7 +49,7 @@ pub fn create_scope_map(cx: &CrateContext, for arg in args { pat_util::pat_bindings(def_map, &*arg.pat, |_, node_id, _, path1| { scope_stack.push(ScopeStackEntry { scope_metadata: fn_metadata, - name: Some(path1.node.name) }); + name: Some(path1.node) }); scope_map.insert(node_id, fn_metadata); }) } @@ -322,13 +322,10 @@ fn walk_expr(cx: &CrateContext, hir::ExprCast(ref sub_exp, _) | hir::ExprAddrOf(_, ref sub_exp) | hir::ExprField(ref sub_exp, _) | - hir::ExprTupField(ref sub_exp, _) | - hir::ExprParen(ref sub_exp) => + hir::ExprTupField(ref sub_exp, _) => walk_expr(cx, &**sub_exp, scope_stack, scope_map), - hir::ExprBox(ref place, ref sub_expr) => { - place.as_ref().map( - |e| walk_expr(cx, &**e, scope_stack, scope_map)); + hir::ExprBox(ref sub_expr) => { walk_expr(cx, &**sub_expr, scope_stack, scope_map); } diff --git a/src/librustc_trans/trans/debuginfo/gdb.rs b/src/librustc_trans/trans/debuginfo/gdb.rs index 3d330fc1c7..03b58fb2c4 100644 --- a/src/librustc_trans/trans/debuginfo/gdb.rs +++ b/src/librustc_trans/trans/debuginfo/gdb.rs @@ -13,14 +13,14 @@ use llvm; use llvm::ValueRef; -use trans::common::{C_bytes, CrateContext}; +use trans::common::{C_bytes, CrateContext, C_i32}; use trans::declare; use trans::type_::Type; use session::config::NoDebugInfo; use std::ffi::CString; use std::ptr; -use rustc_front::attr; +use syntax::attr; /// Inserts a side-effect free instruction sequence that makes sure that the @@ -31,11 +31,21 @@ pub fn insert_reference_to_gdb_debug_scripts_section_global(ccx: &CrateContext) let gdb_debug_scripts_section_global = get_or_insert_gdb_debug_scripts_section_global(ccx); unsafe { + // Load just the first byte as that's all that's necessary to force + // LLVM to keep around the reference to the global. + let indices = [C_i32(ccx, 0), C_i32(ccx, 0)]; + let element = + llvm::LLVMBuildInBoundsGEP(ccx.raw_builder(), + gdb_debug_scripts_section_global, + indices.as_ptr(), + indices.len() as ::libc::c_uint, + empty.as_ptr()); let volative_load_instruction = llvm::LLVMBuildLoad(ccx.raw_builder(), - gdb_debug_scripts_section_global, + element, empty.as_ptr()); llvm::LLVMSetVolatile(volative_load_instruction, llvm::True); + llvm::LLVMSetAlignment(volative_load_instruction, 1); } } } @@ -44,11 +54,12 @@ pub fn insert_reference_to_gdb_debug_scripts_section_global(ccx: &CrateContext) /// section. pub fn get_or_insert_gdb_debug_scripts_section_global(ccx: &CrateContext) -> llvm::ValueRef { - let section_var_name = "__rustc_debug_gdb_scripts_section__"; + let c_section_var_name = "__rustc_debug_gdb_scripts_section__\0"; + let section_var_name = &c_section_var_name[..c_section_var_name.len()-1]; let section_var = unsafe { llvm::LLVMGetNamedGlobal(ccx.llmod(), - section_var_name.as_ptr() as *const _) + c_section_var_name.as_ptr() as *const _) }; if section_var == ptr::null_mut() { diff --git a/src/librustc_trans/trans/debuginfo/metadata.rs b/src/librustc_trans/trans/debuginfo/metadata.rs index a68eab953c..2e7b1f31ba 100644 --- a/src/librustc_trans/trans/debuginfo/metadata.rs +++ b/src/librustc_trans/trans/debuginfo/metadata.rs @@ -27,7 +27,6 @@ use middle::def_id::DefId; use middle::pat_util; use middle::subst::{self, Substs}; use rustc::front::map as hir_map; -use rustc_front; use rustc_front::hir; use trans::{type_of, adt, machine, monomorphize}; use trans::common::{self, CrateContext, FunctionContext, Block}; @@ -43,6 +42,7 @@ use std::ffi::CString; use std::path::Path; use std::ptr; use std::rc::Rc; +use syntax; use syntax::util::interner::Interner; use syntax::codemap::Span; use syntax::{ast, codemap}; @@ -324,8 +324,8 @@ impl<'tcx> TypeMap<'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 source_def_id = if def_id.is_local() { - match cx.external_srcs().borrow().get(&def_id.node).cloned() { + let source_def_id = if let Some(node_id) = cx.tcx().map.as_local_node_id(def_id) { + match cx.external_srcs().borrow().get(&node_id).cloned() { Some(source_def_id) => { // The given def_id identifies the inlined copy of a // type definition, let's take the source of the copy. @@ -346,7 +346,7 @@ impl<'tcx> TypeMap<'tcx> { output.push_str(crate_hash.as_str()); output.push_str("/"); - output.push_str(&format!("{:x}", def_id.node)); + output.push_str(&format!("{:x}", def_id.index.as_usize())); // Maybe check that there is no self type here. @@ -480,7 +480,7 @@ macro_rules! return_if_metadata_created_in_meantime { .find_metadata_for_unique_id($unique_type_id) { Some(metadata) => return MetadataCreationResult::new(metadata, true), None => { /* proceed normally */ } - }; + } ) } @@ -809,7 +809,7 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let mut type_map = debug_context(cx).type_map.borrow_mut(); if already_stored_in_typemap { - // Also make sure that we already have a TypeMap entry entry for the unique type id. + // Also make sure that we already have a TypeMap entry for the unique type id. let metadata_for_uid = match type_map.find_metadata_for_unique_id(unique_type_id) { Some(metadata) => metadata, None => { @@ -934,22 +934,22 @@ fn basic_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::TyBool => ("bool".to_string(), DW_ATE_boolean), ty::TyChar => ("char".to_string(), DW_ATE_unsigned_char), ty::TyInt(int_ty) => match int_ty { - hir::TyIs => ("isize".to_string(), DW_ATE_signed), - hir::TyI8 => ("i8".to_string(), DW_ATE_signed), - hir::TyI16 => ("i16".to_string(), DW_ATE_signed), - hir::TyI32 => ("i32".to_string(), DW_ATE_signed), - hir::TyI64 => ("i64".to_string(), DW_ATE_signed) + ast::TyIs => ("isize".to_string(), DW_ATE_signed), + ast::TyI8 => ("i8".to_string(), DW_ATE_signed), + ast::TyI16 => ("i16".to_string(), DW_ATE_signed), + ast::TyI32 => ("i32".to_string(), DW_ATE_signed), + ast::TyI64 => ("i64".to_string(), DW_ATE_signed) }, ty::TyUint(uint_ty) => match uint_ty { - hir::TyUs => ("usize".to_string(), DW_ATE_unsigned), - hir::TyU8 => ("u8".to_string(), DW_ATE_unsigned), - hir::TyU16 => ("u16".to_string(), DW_ATE_unsigned), - hir::TyU32 => ("u32".to_string(), DW_ATE_unsigned), - hir::TyU64 => ("u64".to_string(), DW_ATE_unsigned) + ast::TyUs => ("usize".to_string(), DW_ATE_unsigned), + ast::TyU8 => ("u8".to_string(), DW_ATE_unsigned), + ast::TyU16 => ("u16".to_string(), DW_ATE_unsigned), + ast::TyU32 => ("u32".to_string(), DW_ATE_unsigned), + ast::TyU64 => ("u64".to_string(), DW_ATE_unsigned) }, ty::TyFloat(float_ty) => match float_ty { - hir::TyF32 => ("f32".to_string(), DW_ATE_float), - hir::TyF64 => ("f64".to_string(), DW_ATE_float), + ast::TyF32 => ("f32".to_string(), DW_ATE_float), + ast::TyF64 => ("f64".to_string(), DW_ATE_float), }, _ => cx.sess().bug("debuginfo::basic_type_metadata - t is invalid type") }; @@ -1365,7 +1365,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { let sole_struct_member_description = MemberDescription { name: match non_null_variant.kind() { ty::VariantKind::Tuple => "__0".to_string(), - ty::VariantKind::Dict => { + ty::VariantKind::Struct => { non_null_variant.fields[0].name.to_string() } ty::VariantKind::Unit => unreachable!() @@ -1540,7 +1540,7 @@ fn describe_enum_variant<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, .map(|(i, _)| format!("__{}", i)) .collect() } - ty::VariantKind::Dict => { + ty::VariantKind::Struct => { variant.fields .iter() .map(|f| f.name.to_string()) @@ -1608,7 +1608,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, }) .collect(); - let discriminant_type_metadata = |inttype: rustc_front::attr::IntType| { + let discriminant_type_metadata = |inttype: syntax::attr::IntType| { let disr_type_key = (enum_def_id, inttype); let cached_discriminant_type_metadata = debug_context(cx).created_enum_disr_types .borrow() @@ -1858,8 +1858,8 @@ pub fn create_global_var_metadata(cx: &CrateContext, let (name, span) = match var_item { hir_map::NodeItem(item) => { match item.node { - hir::ItemStatic(..) => (item.ident.name, item.span), - hir::ItemConst(..) => (item.ident.name, item.span), + hir::ItemStatic(..) => (item.name, item.span), + hir::ItemConst(..) => (item.name, item.span), _ => { cx.sess() .span_bug(item.span, @@ -1887,7 +1887,8 @@ 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 type_metadata = type_metadata(cx, variable_type, span); - let namespace_node = namespace_for_item(cx, DefId::local(node_id)); + let node_def_id = cx.tcx().map.local_def_id(node_id); + let namespace_node = namespace_for_item(cx, node_def_id); let var_name = name.to_string(); let linkage_name = namespace_node.mangled_name_of_contained_item(&var_name[..]); @@ -1925,7 +1926,7 @@ pub fn create_local_var_metadata(bcx: Block, local: &hir::Local) { let def_map = &cx.tcx().def_map; let locals = bcx.fcx.lllocals.borrow(); - pat_util::pat_bindings(def_map, &*local.pat, |_, node_id, span, var_ident| { + pat_util::pat_bindings(def_map, &*local.pat, |_, node_id, span, var_name| { let datum = match locals.get(&node_id) { Some(datum) => datum, None => { @@ -1943,7 +1944,7 @@ pub fn create_local_var_metadata(bcx: Block, local: &hir::Local) { let scope_metadata = scope_metadata(bcx.fcx, node_id, span); declare_local(bcx, - var_ident.node.name, + var_name.node, datum.ty, scope_metadata, VariableAccess::DirectVariable { alloca: datum.val }, @@ -1975,7 +1976,7 @@ pub fn create_captured_var_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, None => { cx.sess().span_bug(span, "debuginfo::create_captured_var_metadata: node not found"); } - Some(hir_map::NodeLocal(pat)) | Some(hir_map::NodeArg(pat)) => { + Some(hir_map::NodeLocal(pat)) => { match pat.node { hir::PatIdent(_, ref path1, _) => { path1.node.name @@ -2105,7 +2106,7 @@ pub fn create_argument_metadata(bcx: Block, arg: &hir::Arg) { .fn_metadata; let locals = bcx.fcx.lllocals.borrow(); - pat_util::pat_bindings(def_map, &*arg.pat, |_, node_id, span, var_ident| { + pat_util::pat_bindings(def_map, &*arg.pat, |_, node_id, span, var_name| { let datum = match locals.get(&node_id) { Some(v) => v, None => { @@ -2132,7 +2133,7 @@ pub fn create_argument_metadata(bcx: Block, arg: &hir::Arg) { }; declare_local(bcx, - var_ident.node.name, + var_name.node, datum.ty, scope_metadata, VariableAccess::DirectVariable { alloca: datum.val }, diff --git a/src/librustc_trans/trans/debuginfo/mod.rs b/src/librustc_trans/trans/debuginfo/mod.rs index dbb1355c9e..a08f33c889 100644 --- a/src/librustc_trans/trans/debuginfo/mod.rs +++ b/src/librustc_trans/trans/debuginfo/mod.rs @@ -31,7 +31,6 @@ use middle::infer::normalize_associated_type; use middle::subst::{self, Substs}; use rustc_front; use rustc_front::hir; -use rustc_front::attr::IntType; use trans::common::{NodeIdAndSpan, CrateContext, FunctionContext, Block}; use trans; @@ -49,6 +48,7 @@ use std::rc::Rc; use syntax::codemap::{Span, Pos}; use syntax::{abi, ast, codemap}; +use syntax::attr::IntType; use syntax::parse::token::{self, special_idents}; pub mod gdb; @@ -242,7 +242,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, match item.node { hir::ItemFn(ref fn_decl, _, _, _, ref generics, ref top_level_block) => { - (item.ident.name, fn_decl, generics, top_level_block, item.span, true) + (item.name, fn_decl, generics, top_level_block, item.span, true) } _ => { cx.sess().span_bug(item.span, @@ -257,7 +257,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, return FunctionDebugContext::FunctionWithoutDebugInfo; } - (impl_item.ident.name, + (impl_item.name, &sig.decl, &sig.generics, body, @@ -296,7 +296,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, return FunctionDebugContext::FunctionWithoutDebugInfo; } - (trait_item.ident.name, + (trait_item.name, &sig.decl, &sig.generics, body, @@ -351,7 +351,8 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // somehow (storing a path in the hir_map, or construct a path using the // enclosing function). let (linkage_name, containing_scope) = if has_path { - let namespace_node = namespace_for_item(cx, DefId::local(fn_ast_id)); + let fn_ast_def_id = cx.tcx().map.local_def_id(fn_ast_id); + let namespace_node = namespace_for_item(cx, fn_ast_def_id); let linkage_name = namespace_node.mangled_name_of_contained_item( &function_name[..]); let containing_scope = namespace_node.scope; @@ -520,7 +521,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // Handle other generic parameters let actual_types = param_substs.types.get_slice(subst::FnSpace); - for (index, &hir::TyParam{ ident, .. }) in generics.ty_params.iter().enumerate() { + for (index, &hir::TyParam{ name, .. }) in generics.ty_params.iter().enumerate() { let actual_type = actual_types[index]; // Add actual type name to <...> clause of function name let actual_type_name = compute_debuginfo_type_name(cx, @@ -535,7 +536,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // Again, only create type information if full debuginfo is enabled if cx.sess().opts.debuginfo == FullDebugInfo { let actual_type_metadata = type_metadata(cx, actual_type, codemap::DUMMY_SP); - let name = CString::new(ident.name.as_str().as_bytes()).unwrap(); + let name = CString::new(name.as_str().as_bytes()).unwrap(); let param_metadata = unsafe { llvm::LLVMDIBuilderCreateTemplateTypeParameter( DIB(cx), diff --git a/src/librustc_trans/trans/debuginfo/type_names.rs b/src/librustc_trans/trans/debuginfo/type_names.rs index 425364407b..7400ec3cbc 100644 --- a/src/librustc_trans/trans/debuginfo/type_names.rs +++ b/src/librustc_trans/trans/debuginfo/type_names.rs @@ -18,7 +18,7 @@ use middle::subst::{self, Substs}; use middle::ty::{self, Ty}; use rustc_front::hir; - +use syntax::ast; // Compute the name of the type as it should be stored in debuginfo. Does not do // any caching, i.e. calling the function twice with the same type will also do @@ -43,18 +43,18 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::TyBool => output.push_str("bool"), ty::TyChar => output.push_str("char"), ty::TyStr => output.push_str("str"), - ty::TyInt(hir::TyIs) => output.push_str("isize"), - ty::TyInt(hir::TyI8) => output.push_str("i8"), - ty::TyInt(hir::TyI16) => output.push_str("i16"), - ty::TyInt(hir::TyI32) => output.push_str("i32"), - ty::TyInt(hir::TyI64) => output.push_str("i64"), - ty::TyUint(hir::TyUs) => output.push_str("usize"), - ty::TyUint(hir::TyU8) => output.push_str("u8"), - ty::TyUint(hir::TyU16) => output.push_str("u16"), - ty::TyUint(hir::TyU32) => output.push_str("u32"), - ty::TyUint(hir::TyU64) => output.push_str("u64"), - ty::TyFloat(hir::TyF32) => output.push_str("f32"), - ty::TyFloat(hir::TyF64) => output.push_str("f64"), + ty::TyInt(ast::TyIs) => output.push_str("isize"), + ty::TyInt(ast::TyI8) => output.push_str("i8"), + ty::TyInt(ast::TyI16) => output.push_str("i16"), + ty::TyInt(ast::TyI32) => output.push_str("i32"), + ty::TyInt(ast::TyI64) => output.push_str("i64"), + ty::TyUint(ast::TyUs) => output.push_str("usize"), + ty::TyUint(ast::TyU8) => output.push_str("u8"), + ty::TyUint(ast::TyU16) => output.push_str("u16"), + ty::TyUint(ast::TyU32) => output.push_str("u32"), + ty::TyUint(ast::TyU64) => output.push_str("u64"), + ty::TyFloat(ast::TyF32) => output.push_str("f32"), + ty::TyFloat(ast::TyF64) => output.push_str("f64"), ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { push_item_name(cx, def.did, qualified, output); diff --git a/src/librustc_trans/trans/debuginfo/utils.rs b/src/librustc_trans/trans/debuginfo/utils.rs index c019a0a950..276f9936ac 100644 --- a/src/librustc_trans/trans/debuginfo/utils.rs +++ b/src/librustc_trans/trans/debuginfo/utils.rs @@ -21,8 +21,6 @@ use trans::machine; use trans::common::{CrateContext, FunctionContext}; use trans::type_::Type; -use rustc_front::hir; - use syntax::codemap::Span; use syntax::{ast, codemap}; @@ -46,11 +44,11 @@ pub fn create_DIArray(builder: DIBuilderRef, arr: &[DIDescriptor]) -> DIArray { }; } -pub fn contains_nodebug_attribute(attributes: &[hir::Attribute]) -> bool { +pub fn contains_nodebug_attribute(attributes: &[ast::Attribute]) -> bool { attributes.iter().any(|attr| { - let meta_item: &hir::MetaItem = &*attr.node.value; + let meta_item: &ast::MetaItem = &*attr.node.value; match meta_item.node { - hir::MetaWord(ref value) => &value[..] == "no_debug", + ast::MetaWord(ref value) => &value[..] == "no_debug", _ => false } }) @@ -101,12 +99,9 @@ pub fn assert_type_for_node_id(cx: &CrateContext, pub fn get_namespace_and_span_for_item(cx: &CrateContext, def_id: DefId) -> (DIScope, Span) { let containing_scope = namespace_for_item(cx, def_id).scope; - let definition_span = if def_id.is_local() { - cx.tcx().map.span(def_id.node) - } else { - // For external items there is no span information - codemap::DUMMY_SP - }; + let definition_span = cx.tcx().map.def_id_span(def_id, codemap::DUMMY_SP /* (1) */ ); + + // (1) For external items there is no span information (containing_scope, definition_span) } diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 7d8996867c..6144de7109 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -83,7 +83,7 @@ use trans::type_::Type; use rustc_front; use rustc_front::hir; -use syntax::{ast, codemap}; +use syntax::{ast, ast_util, codemap}; use syntax::parse::token::InternedString; use syntax::ptr::P; use syntax::parse::token; @@ -119,7 +119,7 @@ pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, debuginfo::set_source_location(bcx.fcx, expr.id, expr.span); - if bcx.tcx().tables.borrow().adjustments.contains_key(&expr.id) { + if adjustment_required(bcx, expr) { // use trans, which may be less efficient but // which will perform the adjustments: let datum = unpack_datum!(bcx, trans(bcx, expr)); @@ -133,13 +133,25 @@ pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ) { if !qualif.intersects(check_const::ConstQualif::PREFER_IN_PLACE) { if let SaveIn(lldest) = dest { - let global = consts::get_const_expr_as_global(bcx.ccx(), expr, qualif, - bcx.fcx.param_substs); - // Cast pointer to destination, because constants - // have different types. - let lldest = PointerCast(bcx, lldest, val_ty(global)); - memcpy_ty(bcx, lldest, global, expr_ty_adjusted(bcx, expr)); - return bcx; + match consts::get_const_expr_as_global(bcx.ccx(), expr, qualif, + bcx.fcx.param_substs, + consts::TrueConst::No) { + Ok(global) => { + // Cast pointer to destination, because constants + // have different types. + let lldest = PointerCast(bcx, lldest, val_ty(global)); + memcpy_ty(bcx, lldest, global, expr_ty_adjusted(bcx, expr)); + return bcx; + }, + Err(consts::ConstEvalFailure::Runtime(_)) => { + // in case const evaluation errors, translate normally + // debug assertions catch the same errors + // see RFC 1229 + }, + Err(consts::ConstEvalFailure::Compiletime(_)) => { + return bcx; + }, + } } // Even if we don't have a value to emit, and the expression // doesn't have any side-effects, we still have to translate the @@ -221,48 +233,64 @@ pub fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, check_const::ConstQualif::NOT_CONST | check_const::ConstQualif::NEEDS_DROP ) { - let global = consts::get_const_expr_as_global(bcx.ccx(), expr, qualif, - bcx.fcx.param_substs); + match consts::get_const_expr_as_global(bcx.ccx(), expr, qualif, + bcx.fcx.param_substs, + consts::TrueConst::No) { + Ok(global) => { + if qualif.intersects(check_const::ConstQualif::HAS_STATIC_BORROWS) { + // Is borrowed as 'static, must return lvalue. + + // Cast pointer to global, because constants have different types. + let const_ty = expr_ty_adjusted(bcx, expr); + let llty = type_of::type_of(bcx.ccx(), const_ty); + let global = PointerCast(bcx, global, llty.ptr_to()); + let datum = Datum::new(global, const_ty, Lvalue::new("expr::trans")); + return DatumBlock::new(bcx, datum.to_expr_datum()); + } - if qualif.intersects(check_const::ConstQualif::HAS_STATIC_BORROWS) { - // Is borrowed as 'static, must return lvalue. + // Otherwise, keep around and perform adjustments, if needed. + let const_ty = if adjusted_global { + expr_ty_adjusted(bcx, expr) + } else { + expr_ty(bcx, expr) + }; - // Cast pointer to global, because constants have different types. - let const_ty = expr_ty_adjusted(bcx, expr); - let llty = type_of::type_of(bcx.ccx(), const_ty); - let global = PointerCast(bcx, global, llty.ptr_to()); - let datum = Datum::new(global, const_ty, Lvalue::new("expr::trans")); - return DatumBlock::new(bcx, datum.to_expr_datum()); + // This could use a better heuristic. + Some(if type_is_immediate(bcx.ccx(), const_ty) { + // Cast pointer to global, because constants have different types. + let llty = type_of::type_of(bcx.ccx(), const_ty); + let global = PointerCast(bcx, global, llty.ptr_to()); + // Maybe just get the value directly, instead of loading it? + immediate_rvalue(load_ty(bcx, global, const_ty), const_ty) + } else { + let scratch = alloc_ty(bcx, const_ty, "const"); + call_lifetime_start(bcx, scratch); + let lldest = if !const_ty.is_structural() { + // Cast pointer to slot, because constants have different types. + PointerCast(bcx, scratch, val_ty(global)) + } else { + // In this case, memcpy_ty calls llvm.memcpy after casting both + // source and destination to i8*, so we don't need any casts. + scratch + }; + memcpy_ty(bcx, lldest, global, const_ty); + Datum::new(scratch, const_ty, Rvalue::new(ByRef)) + }) + }, + Err(consts::ConstEvalFailure::Runtime(_)) => { + // in case const evaluation errors, translate normally + // debug assertions catch the same errors + // see RFC 1229 + None + }, + Err(consts::ConstEvalFailure::Compiletime(_)) => { + // generate a dummy llvm value + let const_ty = expr_ty(bcx, expr); + let llty = type_of::type_of(bcx.ccx(), const_ty); + let dummy = C_undef(llty.ptr_to()); + Some(Datum::new(dummy, const_ty, Rvalue::new(ByRef))) + }, } - - // Otherwise, keep around and perform adjustments, if needed. - let const_ty = if adjusted_global { - expr_ty_adjusted(bcx, expr) - } else { - expr_ty(bcx, expr) - }; - - // This could use a better heuristic. - Some(if type_is_immediate(bcx.ccx(), const_ty) { - // Cast pointer to global, because constants have different types. - let llty = type_of::type_of(bcx.ccx(), const_ty); - let global = PointerCast(bcx, global, llty.ptr_to()); - // Maybe just get the value directly, instead of loading it? - immediate_rvalue(load_ty(bcx, global, const_ty), const_ty) - } else { - let scratch = alloc_ty(bcx, const_ty, "const"); - call_lifetime_start(bcx, scratch); - let lldest = if !const_ty.is_structural() { - // Cast pointer to slot, because constants have different types. - PointerCast(bcx, scratch, val_ty(global)) - } else { - // In this case, memcpy_ty calls llvm.memcpy after casting both - // source and destination to i8*, so we don't need any casts. - scratch - }; - memcpy_ty(bcx, lldest, global, const_ty); - Datum::new(scratch, const_ty, Rvalue::new(ByRef)) - }) } else { None }; @@ -334,6 +362,37 @@ pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>, } } +fn adjustment_required<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + expr: &hir::Expr) -> bool { + let adjustment = match bcx.tcx().tables.borrow().adjustments.get(&expr.id).cloned() { + None => { return false; } + Some(adj) => adj + }; + + // Don't skip a conversion from Box to &T, etc. + if bcx.tcx().is_overloaded_autoderef(expr.id, 0) { + return true; + } + + match adjustment { + AdjustReifyFnPointer => { + // FIXME(#19925) once fn item types are + // zero-sized, we'll need to return true here + false + } + AdjustUnsafeFnPointer => { + // purely a type-level thing + false + } + AdjustDerefRef(ref adj) => { + // We are a bit paranoid about adjustments and thus might have a re- + // borrow here which merely derefs and then refs again (it might have + // a different region or mutability, but we don't care here). + !(adj.autoderefs == 1 && adj.autoref.is_some() && adj.unsize.is_none()) + } + } +} + /// Helper for trans that apply adjustments from `expr` to `datum`, which should be the unadjusted /// translation of `expr`. fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, @@ -533,7 +592,7 @@ fn coerce_unsized<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, Rvalue::new(ByRef))); } else { // Otherwise, simply copy the data from the source. - assert_eq!(src_ty, target_ty); + assert!(src_ty.is_phantom_data() || src_ty == target_ty); memcpy_ty(bcx, ll_target, ll_source, src_ty); } } @@ -630,14 +689,11 @@ fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let _icx = push_ctxt("trans_datum_unadjusted"); match expr.node { - hir::ExprParen(ref e) => { - trans(bcx, &**e) - } hir::ExprPath(..) => { trans_def(bcx, expr, bcx.def(expr.id)) } - hir::ExprField(ref base, ident) => { - trans_rec_field(bcx, &**base, ident.node.name) + hir::ExprField(ref base, name) => { + trans_rec_field(bcx, &**base, name.node) } hir::ExprTupField(ref base, idx) => { trans_rec_tup_field(bcx, &**base, idx.node) @@ -645,7 +701,7 @@ fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, hir::ExprIndex(ref base, ref idx) => { trans_index(bcx, expr, &**base, &**idx, MethodCall::expr(expr.id)) } - hir::ExprBox(_, ref contents) => { + hir::ExprBox(ref contents) => { // Special case for `Box` let box_ty = expr_ty(bcx, expr); let contents_ty = expr_ty(bcx, &**contents); @@ -895,13 +951,13 @@ fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let const_ty = expr_ty(bcx, ref_expr); // For external constants, we don't inline. - let val = if did.is_local() { + let val = if let Some(node_id) = bcx.tcx().map.as_local_node_id(did) { // Case 1. // The LLVM global has the type of its initializer, // which may not be equal to the enum's type for // non-C-like enums. - let val = base::get_item_val(bcx.ccx(), did.node); + let val = base::get_item_val(bcx.ccx(), node_id); let pty = type_of::type_of(bcx.ccx(), const_ty).ptr_to(); PointerCast(bcx, val, pty) } else { @@ -934,14 +990,11 @@ fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, debuginfo::set_source_location(bcx.fcx, expr.id, expr.span); match expr.node { - hir::ExprParen(ref e) => { - trans_into(bcx, &**e, Ignore) - } hir::ExprBreak(label_opt) => { - controlflow::trans_break(bcx, expr, label_opt.map(|l| l.node)) + controlflow::trans_break(bcx, expr, label_opt.map(|l| l.node.name)) } hir::ExprAgain(label_opt) => { - controlflow::trans_cont(bcx, expr, label_opt.map(|l| l.node)) + controlflow::trans_cont(bcx, expr, label_opt.map(|l| l.node.name)) } hir::ExprRet(ref ex) => { // Check to see if the return expression itself is reachable. @@ -1024,7 +1077,20 @@ fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } hir::ExprAssignOp(op, ref dst, ref src) => { - trans_assign_op(bcx, expr, op, &**dst, &**src) + let has_method_map = bcx.tcx() + .tables + .borrow() + .method_map + .contains_key(&MethodCall::expr(expr.id)); + + if has_method_map { + let dst = unpack_datum!(bcx, trans(bcx, &**dst)); + let src_datum = unpack_datum!(bcx, trans(bcx, &**src)); + trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), dst, + Some((src_datum, src.id)), None, false).bcx + } else { + trans_assign_op(bcx, expr, op, &**dst, &**src) + } } hir::ExprInlineAsm(ref a) => { asm::trans_inline_asm(bcx, a) @@ -1050,9 +1116,6 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, debuginfo::set_source_location(bcx.fcx, expr.id, expr.span); match expr.node { - hir::ExprParen(ref e) => { - trans_into(bcx, &**e, dest) - } hir::ExprPath(..) => { trans_def_dps_unadjusted(bcx, expr, bcx.def(expr.id), dest) } @@ -1079,7 +1142,7 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // trans. Shudder. fn make_field(field_name: &str, expr: P) -> hir::Field { hir::Field { - ident: codemap::dummy_spanned(token::str_to_ident(field_name)), + name: codemap::dummy_spanned(token::intern(field_name)), expr: expr, span: codemap::DUMMY_SP, } @@ -1140,7 +1203,7 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } hir::ExprLit(ref lit) => { match lit.node { - hir::LitStr(ref s, _) => { + ast::LitStr(ref s, _) => { tvec::trans_lit_str(bcx, expr, (*s).clone(), dest) } _ => { @@ -1160,14 +1223,23 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, SaveIn(lldest) => closure::Dest::SaveIn(bcx, lldest), Ignore => closure::Dest::Ignore(bcx.ccx()) }; - let substs = match expr_ty(bcx, expr).sty { - ty::TyClosure(_, ref substs) => substs, + + // NB. To get the id of the closure, we don't use + // `local_def_id(id)`, but rather we extract the closure + // def-id from the expr's type. This is because this may + // be an inlined expression from another crate, and we + // want to get the ORIGINAL closure def-id, since that is + // the key we need to find the closure-kind and + // closure-type etc. + let (def_id, substs) = match expr_ty(bcx, expr).sty { + ty::TyClosure(def_id, ref substs) => (def_id, substs), ref t => bcx.tcx().sess.span_bug( expr.span, &format!("closure expr without closure type: {:?}", t)), }; - closure::trans_closure_expr(dest, decl, body, expr.id, substs).unwrap_or(bcx) + + closure::trans_closure_expr(dest, decl, body, expr.id, def_id, substs).unwrap_or(bcx) } hir::ExprCall(ref f, ref args) => { if bcx.tcx().is_method_call(expr.id) { @@ -1216,8 +1288,11 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // Trait casts used to come this way, now they should be coercions. bcx.tcx().sess.span_bug(expr.span, "DPS expr_cast (residual trait cast?)") } - hir::ExprAssignOp(op, ref dst, ref src) => { - trans_assign_op(bcx, expr, op, &**dst, &**src) + hir::ExprAssignOp(op, _, _) => { + bcx.tcx().sess.span_bug( + expr.span, + &format!("augmented assignment `{}=` should always be a rvalue_stmt", + rustc_front::util::binop_to_string(op.node))) } _ => { bcx.tcx().sess.span_bug( @@ -1320,7 +1395,7 @@ pub fn trans_local_var<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let _icx = push_ctxt("trans_local_var"); match def { - def::DefUpvar(nid, _, _) => { + def::DefUpvar(_, nid, _, _) => { // Can't move upvars, so this is never a ZeroMemLastUse. let local_ty = node_id_type(bcx, nid); let lval = Lvalue::new_with_hint("expr::trans_local_var (upvar)", @@ -1334,7 +1409,7 @@ pub fn trans_local_var<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } } - def::DefLocal(nid) => { + def::DefLocal(_, nid) => { let datum = match bcx.fcx.lllocals.borrow().get(&nid) { Some(&v) => v, None => { @@ -1370,7 +1445,7 @@ fn trans_struct<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let mut need_base = vec![true; vinfo.fields.len()]; let numbered_fields = fields.iter().map(|field| { - let pos = vinfo.field_index(field.ident.node.name); + let pos = vinfo.field_index(field.name.node); need_base[pos] = false; (pos, &*field.expr) }).collect::>(); @@ -1549,7 +1624,7 @@ pub fn trans_adt<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, fn trans_immediate_lit<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &hir::Expr, - lit: &hir::Lit) + lit: &ast::Lit) -> DatumBlock<'blk, 'tcx, Expr> { // must not be a string constant, that is a RvalueDpsExpr let _icx = push_ctxt("trans_immediate_lit"); @@ -1611,9 +1686,6 @@ fn trans_unary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, }; immediate_rvalue_bcx(bcx, llneg, un_ty).to_expr_datumblock() } - hir::UnUniq => { - trans_uniq_expr(bcx, expr, un_ty, sub_expr, expr_ty(bcx, sub_expr)) - } hir::UnDeref => { let datum = unpack_datum!(bcx, trans(bcx, sub_expr)); deref_once(bcx, expr, datum, method_call) @@ -1656,16 +1728,6 @@ fn trans_uniq_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, immediate_rvalue_bcx(bcx, val, box_ty).to_expr_datumblock() } -fn ref_fat_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - lval: Datum<'tcx, Lvalue>) - -> DatumBlock<'blk, 'tcx, Expr> { - let dest_ty = bcx.tcx().mk_imm_ref(bcx.tcx().mk_region(ty::ReStatic), lval.ty); - let scratch = rvalue_scratch_datum(bcx, dest_ty, "__fat_ptr"); - memcpy_ty(bcx, scratch.val, lval.val, scratch.ty); - - DatumBlock::new(bcx, scratch.to_expr_datum()) -} - fn trans_addr_of<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &hir::Expr, subexpr: &hir::Expr) @@ -1673,12 +1735,13 @@ fn trans_addr_of<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let _icx = push_ctxt("trans_addr_of"); let mut bcx = bcx; let sub_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, subexpr, "addr_of")); + let ty = expr_ty(bcx, expr); if !type_is_sized(bcx.tcx(), sub_datum.ty) { - // DST lvalue, close to a fat pointer - ref_fat_ptr(bcx, sub_datum) + // Always generate an lvalue datum, because this pointer doesn't own + // the data and cleanup is scheduled elsewhere. + DatumBlock::new(bcx, Datum::new(sub_datum.val, ty, LvalueExpr(sub_datum.kind))) } else { // Sized value, ref to a thin pointer - let ty = expr_ty(bcx, expr); immediate_rvalue_bcx(bcx, sub_datum.val, ty).to_expr_datumblock() } } @@ -2381,8 +2444,8 @@ impl OverflowOpViaIntrinsic { bcx.ccx().get_intrinsic(&name) } fn to_intrinsic_name(&self, tcx: &ty::ctxt, ty: Ty) -> &'static str { - use rustc_front::hir::IntTy::*; - use rustc_front::hir::UintTy::*; + use syntax::ast::IntTy::*; + use syntax::ast::UintTy::*; use middle::ty::{TyInt, TyUint}; let new_sty = match ty.sty { @@ -2491,7 +2554,7 @@ impl OverflowOpViaInputCheck { // Note that the mask's value is derived from the LHS type // (since that is where the 32/64 distinction is relevant) but // the mask's type must match the RHS type (since they will - // both be fed into a and-binop) + // both be fed into an and-binop) let invert_mask = shift_mask_val(bcx, lhs_llty, rhs_llty, true); let outer_bits = And(bcx, rhs, invert_mask, binop_debug_loc); @@ -2714,7 +2777,7 @@ fn expr_kind(tcx: &ty::ctxt, expr: &hir::Expr) -> ExprKind { ExprKind::RvalueDps } - hir::ExprLit(ref lit) if rustc_front::util::lit_is_str(&**lit) => { + hir::ExprLit(ref lit) if ast_util::lit_is_str(&**lit) => { ExprKind::RvalueDps } @@ -2731,26 +2794,11 @@ fn expr_kind(tcx: &ty::ctxt, expr: &hir::Expr) -> ExprKind { hir::ExprLit(_) | // Note: LitStr is carved out above hir::ExprUnary(..) | - hir::ExprBox(None, _) | + hir::ExprBox(_) | hir::ExprAddrOf(..) | hir::ExprBinary(..) | hir::ExprCast(..) => { ExprKind::RvalueDatum } - - hir::ExprBox(Some(ref place), _) => { - // Special case `Box` for now: - let def_id = match tcx.def_map.borrow().get(&place.id) { - Some(def) => def.def_id(), - None => panic!("no def for place"), - }; - if tcx.lang_items.exchange_heap() == Some(def_id) { - ExprKind::RvalueDatum - } else { - ExprKind::RvalueDps - } - } - - hir::ExprParen(ref e) => expr_kind(tcx, &**e), } } diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index cbb092aa4e..95e9e8581b 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -27,20 +27,21 @@ use trans::monomorphize; use trans::type_::Type; use trans::type_of::*; use trans::type_of; +use middle::infer; use middle::ty::{self, Ty}; use middle::subst::Substs; -use rustc::front::map as hir_map; use std::cmp; +use std::iter::once; use libc::c_uint; use syntax::abi::{Cdecl, Aapcs, C, Win64, Abi}; use syntax::abi::{PlatformIntrinsic, RustIntrinsic, Rust, RustCall, Stdcall, Fastcall, System}; +use syntax::attr; use syntax::codemap::Span; use syntax::parse::token::{InternedString, special_idents}; use syntax::ast; use rustc_front::print::pprust; -use rustc_front::attr; use rustc_front::hir; /////////////////////////////////////////////////////////////////////////// @@ -188,7 +189,7 @@ pub fn get_extern_fn(ccx: &CrateContext, pub fn register_foreign_item_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, abi: Abi, fty: Ty<'tcx>, name: &str, - attrs: &[hir::Attribute])-> ValueRef { + attrs: &[ast::Attribute])-> ValueRef { debug!("register_foreign_item_fn(abi={:?}, \ ty={:?}, \ name={})", @@ -254,6 +255,7 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, _ => ccx.sess().bug("trans_native_call called on non-function type") }; let fn_sig = ccx.tcx().erase_late_bound_regions(fn_sig); + let fn_sig = infer::normalize_associated_type(ccx.tcx(), &fn_sig); let llsig = foreign_signature(ccx, &fn_sig, &passed_arg_tys[..]); let fn_type = cabi::compute_abi_info(ccx, &llsig.llarg_tys, @@ -558,8 +560,6 @@ pub fn register_rust_fn_with_foreign_abi(ccx: &CrateContext, -> ValueRef { let _icx = push_ctxt("foreign::register_foreign_fn"); - let tys = foreign_types_for_id(ccx, node_id); - let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys); let t = ccx.tcx().node_id_to_type(node_id); let cconv = match t.sty { ty::TyBareFn(_, ref fn_ty) => { @@ -567,6 +567,8 @@ pub fn register_rust_fn_with_foreign_abi(ccx: &CrateContext, } _ => panic!("expected bare fn in register_rust_fn_with_foreign_abi") }; + let tys = foreign_types_for_fn_ty(ccx, t); + let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys); let llfn = base::register_fn_llvmty(ccx, sp, sym, node_id, cconv, llfn_ty); add_argument_attributes(&tys, llfn); debug!("register_rust_fn_with_foreign_abi(node_id={}, llfn_ty={}, llfn={})", @@ -577,7 +579,7 @@ pub fn register_rust_fn_with_foreign_abi(ccx: &CrateContext, pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, decl: &hir::FnDecl, body: &hir::Block, - attrs: &[hir::Attribute], + attrs: &[ast::Attribute], llwrapfn: ValueRef, param_substs: &'tcx Substs<'tcx>, id: ast::NodeId, @@ -600,7 +602,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, decl: &hir::FnDecl, body: &hir::Block, param_substs: &'tcx Substs<'tcx>, - attrs: &[hir::Attribute], + attrs: &[ast::Attribute], id: ast::NodeId, hash: Option<&str>) -> ValueRef @@ -610,10 +612,12 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let t = tcx.node_id_to_type(id); let t = monomorphize::apply_param_substs(tcx, param_substs, &t); - let ps = ccx.tcx().map.with_path(id, |path| { - let abi = Some(hir_map::PathName(special_idents::clownshoe_abi.name)); - link::mangle(path.chain(abi), hash) - }); + let path = + tcx.map.def_path_from_id(id) + .into_iter() + .map(|e| e.data.as_interned_str()) + .chain(once(special_idents::clownshoe_abi.name.as_str())); + let ps = link::mangle(path, hash); // Compute the type that the function would have if it were just a // normal Rust function. This will be the type of the wrappee fn. @@ -908,7 +912,7 @@ pub fn link_name(i: &hir::ForeignItem) -> InternedString { Some(ln) => ln.clone(), None => match weak_lang_items::link_name(&i.attrs) { Some(name) => name, - None => i.ident.name.as_str(), + None => i.name.as_str(), } } } @@ -935,11 +939,6 @@ fn foreign_signature<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } } -fn foreign_types_for_id<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - id: ast::NodeId) -> ForeignTypes<'tcx> { - foreign_types_for_fn_ty(ccx, ccx.tcx().node_id_to_type(id)) -} - fn foreign_types_for_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> ForeignTypes<'tcx> { let fn_sig = match ty.sty { @@ -947,6 +946,7 @@ fn foreign_types_for_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, _ => ccx.sess().bug("foreign_types_for_fn_ty called on non-function type") }; let fn_sig = ccx.tcx().erase_late_bound_regions(fn_sig); + let fn_sig = infer::normalize_associated_type(ccx.tcx(), &fn_sig); let llsig = foreign_signature(ccx, &fn_sig, &fn_sig.inputs); let fn_ty = cabi::compute_abi_info(ccx, &llsig.llarg_tys, diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index 40a290a271..d7b6cb41a0 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -203,9 +203,9 @@ pub enum DropGlueKind<'tcx> { /// Skips the dtor, if any, for ty; drops the contents directly. /// Note that the dtor is only skipped at the most *shallow* /// level, namely, an `impl Drop for Ty` itself. So, for example, - /// if Ty is Newtype(S) then only the Drop impl for for Newtype - /// itself will be skipped, while the Drop impl for S, if any, - /// will be invoked. + /// if Ty is Newtype(S) then only the Drop impl for Newtype itself + /// will be skipped, while the Drop impl for S, if any, will be + /// invoked. TyContents(Ty<'tcx>), } diff --git a/src/librustc_trans/trans/inline.rs b/src/librustc_trans/trans/inline.rs index 22d624be6f..14e1ca7675 100644 --- a/src/librustc_trans/trans/inline.rs +++ b/src/librustc_trans/trans/inline.rs @@ -30,7 +30,8 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: DefId) // Already inline debug!("instantiate_inline({}): already inline as node id {}", ccx.tcx().item_path_str(fn_id), node_id); - return Some(DefId::local(node_id)); + let node_def_id = ccx.tcx().map.local_def_id(node_id); + return Some(node_def_id); } Some(&None) => { return None; // Not inlinable @@ -43,7 +44,7 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: DefId) let csearch_result = csearch::maybe_get_item_ast( ccx.tcx(), fn_id, - Box::new(|a,b,c,d| astencode::decode_inlined_item(a, b, c, d))); + Box::new(astencode::decode_inlined_item)); let inline_id = match csearch_result { csearch::FoundAst::NotFound => { @@ -109,18 +110,17 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: DefId) let ty_vs = &ccx.tcx().lookup_adt_def(parent_id).variants; assert_eq!(ast_vs.len(), ty_vs.len()); for (ast_v, ty_v) in ast_vs.iter().zip(ty_vs.iter()) { - if ty_v.did == fn_id { my_id = ast_v.node.id; } - ccx.external().borrow_mut().insert(ty_v.did, Some(ast_v.node.id)); + if ty_v.did == fn_id { my_id = ast_v.node.data.id(); } + ccx.external().borrow_mut().insert(ty_v.did, Some(ast_v.node.data.id())); } } hir::ItemStruct(ref struct_def, _) => { - match struct_def.ctor_id { - None => ccx.sess().bug("instantiate_inline: called on a \ - non-tuple struct"), - Some(ctor_id) => { - ccx.external().borrow_mut().insert(fn_id, Some(ctor_id)); - my_id = ctor_id; - } + if struct_def.is_struct() { + ccx.sess().bug("instantiate_inline: called on a \ + non-tuple struct") + } else { + ccx.external().borrow_mut().insert(fn_id, Some(struct_def.id())); + my_id = struct_def.id(); } } _ => ccx.sess().bug("instantiate_inline: item has a \ @@ -144,8 +144,9 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: DefId) // reuse that code, it needs to be able to look up the traits for // inlined items. let ty_trait_item = ccx.tcx().impl_or_trait_item(fn_id).clone(); + let trait_item_def_id = ccx.tcx().map.local_def_id(trait_item.id); ccx.tcx().impl_or_trait_items.borrow_mut() - .insert(DefId::local(trait_item.id), ty_trait_item); + .insert(trait_item_def_id, ty_trait_item); // If this is a default method, we can't look up the // impl type. But we aren't going to translate anyways, so @@ -185,12 +186,13 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: DefId) } }; - Some(DefId::local(inline_id)) + let inline_def_id = ccx.tcx().map.local_def_id(inline_id); + Some(inline_def_id) } pub fn get_local_instance(ccx: &CrateContext, fn_id: DefId) -> Option { - if fn_id.is_local() { + if let Some(_) = ccx.tcx().map.as_local_node_id(fn_id) { Some(fn_id) } else { instantiate_inline(ccx, fn_id) diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index bcfd44d883..a8d85ae17e 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -44,10 +44,13 @@ use syntax::ast; use syntax::ptr::P; use syntax::parse::token; +use rustc::session::Session; +use syntax::codemap::Span; + use std::cmp::Ordering; pub fn get_simple_intrinsic(ccx: &CrateContext, item: &hir::ForeignItem) -> Option { - let name = match &*item.ident.name.as_str() { + let name = match &*item.name.as_str() { "sqrtf32" => "llvm.sqrt.f32", "sqrtf64" => "llvm.sqrt.f64", "powif32" => "llvm.powi.f32", @@ -99,6 +102,10 @@ pub fn get_simple_intrinsic(ccx: &CrateContext, item: &hir::ForeignItem) -> Opti Some(ccx.get_intrinsic(&name)) } +pub fn span_transmute_size_error(a: &Session, b: Span, msg: &str) { + span_err!(a, b, E0512, "{}", msg); +} + /// Performs late verification that intrinsics are used correctly. At present, /// the only intrinsic that needs such verification is `transmute`. pub fn check_intrinsics(ccx: &CrateContext) { @@ -127,9 +134,8 @@ pub fn check_intrinsics(ccx: &CrateContext) { last_failing_id = Some(transmute_restriction.id); if transmute_restriction.original_from != transmute_restriction.substituted_from { - ccx.sess().span_err( - transmute_restriction.span, - &format!("transmute called on types with potentially different sizes: \ + span_transmute_size_error(ccx.sess(), transmute_restriction.span, + &format!("transmute called with differently sized types: \ {} (could be {} bit{}) to {} (could be {} bit{})", transmute_restriction.original_from, from_type_size as usize, @@ -138,9 +144,8 @@ pub fn check_intrinsics(ccx: &CrateContext) { to_type_size as usize, if to_type_size == 1 {""} else {"s"})); } else { - ccx.sess().span_err( - transmute_restriction.span, - &format!("transmute called on types with different sizes: \ + span_transmute_size_error(ccx.sess(), transmute_restriction.span, + &format!("transmute called with differently sized types: \ {} ({} bit{}) to {} ({} bit{})", transmute_restriction.original_from, from_type_size as usize, @@ -180,7 +185,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, _ => panic!("expected bare_fn in trans_intrinsic_call") }; let foreign_item = tcx.map.expect_foreign_item(node); - let name = foreign_item.ident.name.as_str(); + let name = foreign_item.name.as_str(); // For `transmute` we can just trans the input expr directly into dest if name == "transmute" { @@ -798,9 +803,9 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, (_, "return_address") => { if !fcx.caller_expects_out_pointer { - tcx.sess.span_err(call_info.span, - "invalid use of `return_address` intrinsic: function \ - does not use out pointer"); + span_err!(tcx.sess, call_info.span, E0510, + "invalid use of `return_address` intrinsic: function \ + does not use out pointer"); C_null(Type::i8p(ccx)) } else { PointerCast(bcx, llvm::get_param(fcx.llfn, 0), Type::i8p(ccx)) @@ -926,7 +931,8 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, (_, _) => { let intr = match Intrinsic::find(tcx, &name) { Some(intr) => intr, - None => ccx.sess().span_bug(foreign_item.span, "unknown intrinsic"), + None => ccx.sess().span_bug(foreign_item.span, + &format!("unknown intrinsic '{}'", name)), }; fn one(x: Vec) -> T { assert_eq!(x.len(), 1); @@ -1215,8 +1221,8 @@ fn try_intrinsic<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // MSVC's definition of the `rust_try` function. The exact implementation here // is a little different than the GNU (standard) version below, not only because // of the personality function but also because of the other fiddly bits about -// SEH. LLVM also currently requires us to structure this a very particular way -// as explained below. +// SEH. LLVM also currently requires us to structure this in a very particular +// way as explained below. // // Like with the GNU version we generate a shim wrapper fn trans_msvc_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, @@ -1439,6 +1445,10 @@ fn get_rust_try_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>, return rust_try } +fn span_invalid_monomorphization_error(a: &Session, b: Span, c: &str) { + span_err!(a, b, E0511, "{}", c); +} + fn generic_simd_intrinsic<'blk, 'tcx, 'a> (bcx: Block<'blk, 'tcx>, name: &str, @@ -1457,10 +1467,11 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> emit_error!($msg, ) }; ($msg: tt, $($fmt: tt)*) => { - bcx.sess().span_err(call_info.span, - &format!(concat!("invalid monomorphization of `{}` intrinsic: ", - $msg), - name, $($fmt)*)); + span_invalid_monomorphization_error( + bcx.sess(), call_info.span, + &format!(concat!("invalid monomorphization of `{}` intrinsic: ", + $msg), + name, $($fmt)*)); } } macro_rules! require { @@ -1552,7 +1563,16 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> None => bcx.sess().span_bug(call_info.span, "intrinsic call with unexpected argument shape"), }; - let vector = consts::const_expr(bcx.ccx(), vector, tcx.mk_substs(substs), None).0; + let vector = match consts::const_expr( + bcx.ccx(), + vector, + tcx.mk_substs(substs), + None, + consts::TrueConst::Yes, // this should probably help simd error reporting + ) { + Ok((vector, _)) => vector, + Err(err) => bcx.sess().span_fatal(call_info.span, &err.description()), + }; let indices: Option> = (0..n) .map(|i| { diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index 4b36734c67..2b711be5b0 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -38,10 +38,10 @@ use middle::ty::{self, Ty, HasTypeFlags}; use middle::ty::MethodCall; use syntax::ast; +use syntax::attr; use syntax::codemap::DUMMY_SP; use syntax::ptr::P; -use rustc_front::attr; use rustc_front::visit; use rustc_front::hir; @@ -53,7 +53,7 @@ const VTABLE_OFFSET: usize = 3; /// be generated once they are invoked with specific type parameters, /// see `trans::base::lval_static_fn()` or `trans::base::monomorphic_fn()`. pub fn trans_impl(ccx: &CrateContext, - name: ast::Ident, + name: ast::Name, impl_items: &[P], generics: &hir::Generics, id: ast::NodeId) { @@ -250,10 +250,10 @@ pub fn trans_static_method_callee<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, impl_self, rcvr_method)); - let mth_id = method_with_name(ccx, impl_did, mname); - trans_fn_ref_with_substs(ccx, mth_id, ExprId(expr_id), + let mth = tcx.get_impl_method(impl_did, callee_substs, mname); + trans_fn_ref_with_substs(ccx, mth.method.def_id, ExprId(expr_id), param_substs, - callee_substs) + mth.substs) } traits::VtableObject(ref data) => { let idx = traits::get_vtable_index_of_object_method(tcx, data, method_id); @@ -269,28 +269,6 @@ pub fn trans_static_method_callee<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } } -fn method_with_name(ccx: &CrateContext, impl_id: DefId, name: ast::Name) - -> DefId { - match ccx.impl_method_cache().borrow().get(&(impl_id, name)).cloned() { - Some(m) => return m, - None => {} - } - - let impl_items = ccx.tcx().impl_items.borrow(); - let impl_items = - impl_items.get(&impl_id) - .expect("could not find impl while translating"); - let meth_did = impl_items.iter() - .find(|&did| { - ccx.tcx().impl_or_trait_item(did.def_id()).name() == name - }).expect("could not find method while \ - translating"); - - ccx.impl_method_cache().borrow_mut().insert((impl_id, name), - meth_did.def_id()); - meth_did.def_id() -} - fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, method_call: MethodCall, self_expr: Option<&hir::Expr>, @@ -312,20 +290,19 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, item") } }; - let mth_id = method_with_name(bcx.ccx(), impl_did, mname); - // create a concatenated set of substitutions which includes // those from the impl and those from the method: let callee_substs = combine_impl_and_methods_tps( bcx, MethodCallKey(method_call), vtable_impl.substs); + let mth = bcx.tcx().get_impl_method(impl_did, callee_substs, mname); // translate the function let datum = trans_fn_ref_with_substs(bcx.ccx(), - mth_id, + mth.method.def_id, MethodCallKey(method_call), bcx.fcx.param_substs, - callee_substs); + mth.substs); Callee { bcx: bcx, data: Fn(datum.val), ty: datum.ty } } @@ -499,8 +476,7 @@ fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, /// } /// /// What is the value of `x` when `foo` is invoked with `T=SomeTrait`? -/// The answer is that it it is a shim function generate by this -/// routine: +/// The answer is that it is a shim function generated by this routine: /// /// fn shim(t: &SomeTrait) -> int { /// // ... call t.get() virtually ... @@ -674,7 +650,9 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, C_uint(ccx, align) ].into_iter().chain(methods).collect(); - let vtable = consts::addr_of(ccx, C_struct(ccx, &components, false), "vtable"); + let vtable_const = C_struct(ccx, &components, false); + let align = machine::llalign_of_pref(ccx, val_ty(vtable_const)); + let vtable = consts::addr_of(ccx, vtable_const, align, "vtable"); ccx.vtables().borrow_mut().insert(trait_ref, vtable); vtable @@ -738,22 +716,17 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // The substitutions we have are on the impl, so we grab // the method type from the impl to substitute into. - let impl_method_def_id = method_with_name(ccx, impl_id, name); - let impl_method_type = match tcx.impl_or_trait_item(impl_method_def_id) { - ty::MethodTraitItem(m) => m, - _ => ccx.sess().bug("should be a method, not other assoc item"), - }; + let mth = tcx.get_impl_method(impl_id, substs.clone(), name); - debug!("emit_vtable_methods: impl_method_type={:?}", - impl_method_type); + debug!("emit_vtable_methods: mth={:?}", mth); // If this is a default method, it's possible that it // relies on where clauses that do not hold for this // particular set of type parameters. Note that this // method could then never be called, so we do not want to // try and trans it, in that case. Issue #23435. - if tcx.provided_source(impl_method_def_id).is_some() { - let predicates = impl_method_type.predicates.predicates.subst(tcx, &substs); + if mth.is_provided { + let predicates = mth.method.predicates.predicates.subst(tcx, &mth.substs); if !normalize_and_test_predicates(ccx, predicates.into_vec()) { debug!("emit_vtable_methods: predicates do not hold"); return nullptr; @@ -761,10 +734,10 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } trans_fn_ref_with_substs(ccx, - impl_method_def_id, + mth.method.def_id, ExprId(0), param_substs, - substs.clone()).val + mth.substs).val }) .collect() } @@ -773,7 +746,7 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn opaque_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>, method_ty: &ty::BareFnTy<'tcx>) -> &'tcx ty::BareFnTy<'tcx> { let mut inputs = method_ty.sig.0.inputs.clone(); - inputs[0] = tcx.mk_mut_ptr(tcx.mk_mach_int(hir::TyI8)); + inputs[0] = tcx.mk_mut_ptr(tcx.mk_mach_int(ast::TyI8)); tcx.mk_bare_fn(ty::BareFnTy { unsafety: method_ty.unsafety, diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index 20c3f356b1..1f9116f749 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -28,17 +28,17 @@ use middle::ty::{self, HasTypeFlags, Ty}; use rustc::front::map as hir_map; use rustc_front::hir; -use rustc_front::attr; use syntax::abi; use syntax::ast; +use syntax::attr; use std::hash::{Hasher, Hash, SipHasher}; pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_id: DefId, psubsts: &'tcx subst::Substs<'tcx>, ref_id: Option) - -> (ValueRef, Ty<'tcx>, bool) { + -> (ValueRef, Ty<'tcx>, bool) { debug!("monomorphic_fn(\ fn_id={:?}, \ real_substs={:?}, \ @@ -49,6 +49,9 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, assert!(!psubsts.types.needs_infer() && !psubsts.types.has_param_types()); + // we can only monomorphize things in this crate (or inlined into it) + let fn_node_id = ccx.tcx().map.as_local_node_id(fn_id).unwrap(); + let _icx = push_ctxt("monomorphic_fn"); let hash_id = MonoId { @@ -82,7 +85,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let map_node = session::expect( ccx.sess(), - ccx.tcx().map.find(fn_id.node), + ccx.tcx().map.find(fn_node_id), || { format!("while monomorphizing {:?}, couldn't find it in \ the item map (may have attempted to monomorphize \ @@ -91,10 +94,10 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, }); if let hir_map::NodeForeignItem(_) = map_node { - let abi = ccx.tcx().map.get_foreign_abi(fn_id.node); + let abi = ccx.tcx().map.get_foreign_abi(fn_node_id); if abi != abi::RustIntrinsic && abi != abi::PlatformIntrinsic { // Foreign externs don't have to be monomorphized. - return (get_item_val(ccx, fn_id.node), mono_ty, true); + return (get_item_val(ccx, fn_node_id), mono_ty, true); } } @@ -107,11 +110,13 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, Some(&d) => d, None => 0 }; + debug!("monomorphic_fn: depth for fn_id={:?} is {:?}", fn_id, depth+1); + // Random cut-off -- code that needs to instantiate the same function // recursively more than thirty times can probably safely be assumed // to be causing an infinite expansion. if depth > ccx.sess().recursion_limit.get() { - ccx.sess().span_fatal(ccx.tcx().map.span(fn_id.node), + ccx.sess().span_fatal(ccx.tcx().map.span(fn_node_id), "reached the recursion limit during monomorphization"); } @@ -125,9 +130,8 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, mono_ty.hash(&mut state); hash = format!("h{}", state.finish()); - ccx.tcx().map.with_path(fn_id.node, |path| { - exported_name(path, &hash[..]) - }) + let path = ccx.tcx().map.def_path_from_id(fn_node_id); + exported_name(path, &hash[..]) }; debug!("monomorphize_fn mangled to {}", s); @@ -136,7 +140,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let mut hash_id = Some(hash_id); let mut mk_lldecl = |abi: abi::Abi| { let lldecl = if abi != abi::Rust { - foreign::decl_rust_fn_with_foreign_abi(ccx, mono_ty, &s[..]) + foreign::decl_rust_fn_with_foreign_abi(ccx, mono_ty, &s) } else { // FIXME(nagisa): perhaps needs a more fine grained selection? See // setup_lldecl below. @@ -146,7 +150,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ccx.monomorphized().borrow_mut().insert(hash_id.take().unwrap(), lldecl); lldecl }; - let setup_lldecl = |lldecl, attrs: &[hir::Attribute]| { + let setup_lldecl = |lldecl, attrs: &[ast::Attribute]| { base::update_linkage(ccx, lldecl, None, base::OriginalTranslation); attributes::from_fn_attrs(ccx, attrs, lldecl); @@ -178,10 +182,10 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, if needs_body { if abi != abi::Rust { foreign::trans_rust_fn_with_foreign_abi( - ccx, &**decl, &**body, &[], d, psubsts, fn_id.node, + ccx, &**decl, &**body, &[], d, psubsts, fn_node_id, Some(&hash[..])); } else { - trans_fn(ccx, &**decl, &**body, d, psubsts, fn_id.node, &[]); + trans_fn(ccx, &**decl, &**body, d, psubsts, fn_node_id, &[]); } } @@ -193,11 +197,11 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } } hir_map::NodeVariant(v) => { - let variant = inlined_variant_def(ccx, fn_id.node); - assert_eq!(v.node.name.name, variant.name); + let variant = inlined_variant_def(ccx, fn_node_id); + assert_eq!(v.node.name, variant.name); let d = mk_lldecl(abi::Rust); attributes::inline(d, attributes::InlineAttr::Hint); - trans_enum_variant(ccx, fn_id.node, variant.disr_val, psubsts, d); + trans_enum_variant(ccx, fn_node_id, variant.disr_val, psubsts, d); d } hir_map::NodeImplItem(impl_item) => { @@ -242,9 +246,11 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, hir_map::NodeStructCtor(struct_def) => { let d = mk_lldecl(abi::Rust); attributes::inline(d, attributes::InlineAttr::Hint); + if struct_def.is_struct() { + panic!("ast-mapped struct didn't have a ctor id") + } base::trans_tuple_struct(ccx, - struct_def.ctor_id.expect("ast-mapped tuple struct \ - didn't have a ctor id"), + struct_def.id(), psubsts, d); d @@ -256,7 +262,6 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, hir_map::NodeTyParam(..) | hir_map::NodeExpr(..) | hir_map::NodeStmt(..) | - hir_map::NodeArg(..) | hir_map::NodeBlock(..) | hir_map::NodePat(..) | hir_map::NodeLocal(..) => { diff --git a/src/librustc_trans/trans/tvec.rs b/src/librustc_trans/trans/tvec.rs index 8deaa045c8..c7e1af5853 100644 --- a/src/librustc_trans/trans/tvec.rs +++ b/src/librustc_trans/trans/tvec.rs @@ -30,6 +30,7 @@ use middle::ty::{self, Ty}; use rustc_front::hir; +use syntax::ast; use syntax::parse::token::InternedString; #[derive(Copy, Clone)] @@ -91,7 +92,7 @@ pub fn trans_slice_vec<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // Handle the "..." case (returns a slice since strings are always unsized): if let hir::ExprLit(ref lit) = content_expr.node { - if let hir::LitStr(ref s, _) = lit.node { + if let ast::LitStr(ref s, _) = lit.node { let scratch = rvalue_scratch_datum(bcx, vec_ty, ""); bcx = trans_lit_str(bcx, content_expr, @@ -172,7 +173,7 @@ fn write_content<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, match content_expr.node { hir::ExprLit(ref lit) => { match lit.node { - hir::LitStr(ref s, _) => { + ast::LitStr(ref s, _) => { match dest { Ignore => return bcx, SaveIn(lldest) => { @@ -268,7 +269,7 @@ fn elements_required(bcx: Block, content_expr: &hir::Expr) -> usize { match content_expr.node { hir::ExprLit(ref lit) => { match lit.node { - hir::LitStr(ref s, _) => s.len(), + ast::LitStr(ref s, _) => s.len(), _ => { bcx.tcx().sess.span_bug(content_expr.span, "unexpected evec content") diff --git a/src/librustc_trans/trans/type_.rs b/src/librustc_trans/trans/type_.rs index e0df6ec35c..c635d1ba23 100644 --- a/src/librustc_trans/trans/type_.rs +++ b/src/librustc_trans/trans/type_.rs @@ -17,7 +17,7 @@ use llvm::{Float, Double, X86_FP80, PPC_FP128, FP128}; use trans::context::CrateContext; use util::nodemap::FnvHashMap; -use rustc_front::hir; +use syntax::ast; use std::ffi::CString; use std::mem; @@ -125,30 +125,30 @@ impl Type { } } - pub fn int_from_ty(ccx: &CrateContext, t: hir::IntTy) -> Type { + pub fn int_from_ty(ccx: &CrateContext, t: ast::IntTy) -> Type { match t { - hir::TyIs => ccx.int_type(), - hir::TyI8 => Type::i8(ccx), - hir::TyI16 => Type::i16(ccx), - hir::TyI32 => Type::i32(ccx), - hir::TyI64 => Type::i64(ccx) + ast::TyIs => ccx.int_type(), + ast::TyI8 => Type::i8(ccx), + ast::TyI16 => Type::i16(ccx), + ast::TyI32 => Type::i32(ccx), + ast::TyI64 => Type::i64(ccx) } } - pub fn uint_from_ty(ccx: &CrateContext, t: hir::UintTy) -> Type { + pub fn uint_from_ty(ccx: &CrateContext, t: ast::UintTy) -> Type { match t { - hir::TyUs => ccx.int_type(), - hir::TyU8 => Type::i8(ccx), - hir::TyU16 => Type::i16(ccx), - hir::TyU32 => Type::i32(ccx), - hir::TyU64 => Type::i64(ccx) + ast::TyUs => ccx.int_type(), + ast::TyU8 => Type::i8(ccx), + ast::TyU16 => Type::i16(ccx), + ast::TyU32 => Type::i32(ccx), + ast::TyU64 => Type::i64(ccx) } } - pub fn float_from_ty(ccx: &CrateContext, t: hir::FloatTy) -> Type { + pub fn float_from_ty(ccx: &CrateContext, t: ast::FloatTy) -> Type { match t { - hir::TyF32 => Type::f32(ccx), - hir::TyF64 => Type::f64(ccx), + ast::TyF32 => Type::f32(ccx), + ast::TyF64 => Type::f64(ccx), } } diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs index 43e1ad8115..437c0d9cbc 100644 --- a/src/librustc_trans/trans/type_of.rs +++ b/src/librustc_trans/trans/type_of.rs @@ -21,7 +21,7 @@ use middle::ty::{self, RegionEscape, Ty}; use trans::type_::Type; use syntax::abi; -use rustc_front::hir; +use syntax::ast; // LLVM doesn't like objects that are too big. Issue #17913 fn ensure_array_fits_in_address_space<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, @@ -361,7 +361,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> let repr = adt::represent_type(cx, t); // Unboxed closures can have substitutions in all spaces // inherited from their environment, so we use entire - // contents of the VecPerParamSpace to to construct the llvm + // contents of the VecPerParamSpace to construct the llvm // name adt::incomplete_type_of(cx, &*repr, "closure") } @@ -379,7 +379,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> let unsized_part = cx.tcx().struct_tail(ty); let info_ty = match unsized_part.sty { ty::TyStr | ty::TyArray(..) | ty::TySlice(_) => { - Type::uint_from_ty(cx, hir::TyUs) + Type::uint_from_ty(cx, ast::TyUs) } ty::TyTrait(_) => Type::vtable_ptr(cx), _ => panic!("Unexpected type returned from \ diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 971ca329e6..34378445c6 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -52,7 +52,7 @@ use middle::astconv_util::{prim_ty_to_ty, prohibit_type_params, prohibit_project use middle::const_eval::{self, ConstVal}; use middle::const_eval::EvalHint::UncheckedExprHint; use middle::def; -use middle::def_id::{DefId, LOCAL_CRATE}; +use middle::def_id::DefId; use middle::resolve_lifetime as rl; use middle::privacy::{AllPublic, LastMod}; use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs, ParamSpace}; @@ -66,7 +66,6 @@ use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, use util::common::{ErrorReported, FN_OUTPUT_NAME}; use util::nodemap::FnvHashSet; -use std::slice; use syntax::{abi, ast}; use syntax::codemap::{Span, Pos}; use syntax::feature_gate::{GateIssue, emit_feature_err}; @@ -74,7 +73,7 @@ use syntax::parse::token; use rustc_front::print::pprust; use rustc_front::hir; - +use rustc_back::slice; pub trait AstConv<'tcx> { fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx>; @@ -167,12 +166,13 @@ pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &hir::Lifetime) } Some(&rl::DefLateBoundRegion(debruijn, id)) => { - ty::ReLateBound(debruijn, ty::BrNamed(DefId::local(id), lifetime.name)) + ty::ReLateBound(debruijn, ty::BrNamed(tcx.map.local_def_id(id), lifetime.name)) } Some(&rl::DefEarlyBoundRegion(space, index, id)) => { + let def_id = tcx.map.local_def_id(id); ty::ReEarlyBound(ty::EarlyBoundRegion { - param_id: id, + def_id: def_id, space: space, index: index, name: lifetime.name @@ -182,7 +182,7 @@ pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &hir::Lifetime) Some(&rl::DefFreeRegion(scope, id)) => { ty::ReFree(ty::FreeRegion { scope: tcx.region_maps.item_extent(scope.node_id), - bound_region: ty::BrNamed(DefId::local(id), + bound_region: ty::BrNamed(tcx.map.local_def_id(id), lifetime.name) }) } @@ -346,7 +346,7 @@ fn create_region_substs<'tcx>( { let tcx = this.tcx(); - // If the type is parameterized by the this region, then replace this + // If the type is parameterized by this region, then replace this // region with the current anon region binding (in other words, // whatever & would get replaced with). let expected_num_region_params = decl_generics.regions.len(TypeSpace); @@ -393,7 +393,7 @@ fn create_substs_for_ast_path<'tcx>( let tcx = this.tcx(); debug!("create_substs_for_ast_path(decl_generics={:?}, self_ty={:?}, \ - types_provided={:?}, region_substs={:?}", + types_provided={:?}, region_substs={:?})", decl_generics, self_ty, types_provided, region_substs); @@ -474,6 +474,9 @@ fn create_substs_for_ast_path<'tcx>( } } + debug!("create_substs_for_ast_path(decl_generics={:?}, self_ty={:?}) -> {:?}", + decl_generics, self_ty, substs); + substs } @@ -545,7 +548,7 @@ fn convert_angle_bracketed_parameters<'tcx>(this: &AstConv<'tcx>, let assoc_bindings: Vec<_> = data.bindings.iter() - .map(|b| ConvertedBinding { item_name: b.ident.name, + .map(|b| ConvertedBinding { item_name: b.name, ty: ast_ty_to_ty(this, rscope, &*b.ty), span: b.span }) .collect(); @@ -741,6 +744,7 @@ fn ast_path_to_poly_trait_ref<'a,'tcx>( poly_projections: &mut Vec>) -> ty::PolyTraitRef<'tcx> { + debug!("ast_path_to_poly_trait_ref(trait_segment={:?})", trait_segment); // The trait reference introduces a binding level here, so // we need to shift the `rscope`. It'd be nice if we could // do away with this rscope stuff and work this knowledge @@ -774,6 +778,8 @@ fn ast_path_to_poly_trait_ref<'a,'tcx>( poly_projections.extend(converted_bindings); } + debug!("ast_path_to_poly_trait_ref(trait_segment={:?}, projections={:?}) -> {:?}", + trait_segment, poly_projections, poly_trait_ref); poly_trait_ref } @@ -1103,7 +1109,18 @@ fn make_object_type<'tcx>(this: &AstConv<'tcx>, object.principal_trait_ref_with_self_ty(tcx, tcx.types.err); // ensure the super predicates and stop if we encountered an error - if this.ensure_super_predicates(span, object.principal_def_id()).is_err() { + if this.ensure_super_predicates(span, principal.def_id()).is_err() { + return tcx.types.err; + } + + // check that there are no gross object safety violations, + // most importantly, that the supertraits don't contain Self, + // to avoid ICE-s. + let object_safety_violations = + traits::astconv_object_safety_violations(tcx, principal.def_id()); + if !object_safety_violations.is_empty() { + traits::report_object_safety_error( + tcx, span, principal.def_id(), object_safety_violations, false); return tcx.types.err; } @@ -1220,7 +1237,7 @@ fn one_bound_for_assoc_type<'tcx>(tcx: &ty::ctxt<'tcx>, Ok(bounds[0].clone()) } -// Create a type from a a path to an associated type. +// Create a type from a path to an associated type. // For a path A::B::C::D, ty and ty_path_def are the type and def for A::B::C // and item_segment is the path segment for D. We return a type and a def for // the whole path. @@ -1246,7 +1263,7 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, (_, def::DefSelfTy(Some(trait_did), Some((impl_id, _)))) => { // `Self` in an impl of a trait - we have a concrete self type and a // trait reference. - let trait_ref = tcx.impl_trait_ref(DefId::local(impl_id)).unwrap(); + let trait_ref = tcx.impl_trait_ref(tcx.map.local_def_id(impl_id)).unwrap(); let trait_ref = if let Some(free_substs) = this.get_free_substs() { trait_ref.subst(tcx, free_substs) } else { @@ -1273,9 +1290,9 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, } } (&ty::TyParam(_), def::DefSelfTy(Some(trait_did), None)) => { - assert_eq!(trait_did.krate, LOCAL_CRATE); + let trait_node_id = tcx.map.as_local_node_id(trait_did).unwrap(); match find_bound_for_assoc_item(this, - trait_did.node, + trait_node_id, token::special_idents::type_self.name, assoc_name, span) { @@ -1284,9 +1301,9 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, } } (&ty::TyParam(_), def::DefTyParam(_, _, param_did, param_name)) => { - assert_eq!(param_did.krate, LOCAL_CRATE); + let param_node_id = tcx.map.as_local_node_id(param_did).unwrap(); match find_bound_for_assoc_item(this, - param_did.node, + param_node_id, param_name, assoc_name, span) { @@ -1307,15 +1324,15 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, let trait_did = bound.0.def_id; let ty = this.projected_ty_from_poly_trait_ref(span, bound, assoc_name); - let item_did = if trait_did.is_local() { + let item_did = if let Some(trait_id) = tcx.map.as_local_node_id(trait_did) { // `ty::trait_items` used below requires information generated // by type collection, which may be in progress at this point. - match tcx.map.expect_item(trait_did.node).node { + match tcx.map.expect_item(trait_id).node { hir::ItemTrait(_, _, _, ref trait_items) => { let item = trait_items.iter() - .find(|i| i.ident.name == assoc_name) + .find(|i| i.name == assoc_name) .expect("missing associated type"); - DefId::local(item.id) + tcx.map.local_def_id(item.id) } _ => unreachable!() } @@ -1489,11 +1506,12 @@ fn base_def_to_ty<'tcx>(this: &AstConv<'tcx>, // we don't have the trait information around, which is just sad. if !base_segments.is_empty() { + let id_node = tcx.map.as_local_node_id(id).unwrap(); span_err!(tcx.sess, span, E0247, "found module name used as a type: {}", - tcx.map.node_to_string(id.node)); + tcx.map.node_to_user_string(id_node)); return this.tcx().types.err; } @@ -1503,10 +1521,10 @@ fn base_def_to_ty<'tcx>(this: &AstConv<'tcx>, prim_ty_to_ty(tcx, base_segments, prim_ty) } _ => { - let node = def.def_id().node; + let id_node = tcx.map.as_local_node_id(def.def_id()).unwrap(); span_err!(tcx.sess, span, E0248, "found value `{}` used as a type", - tcx.map.path_to_string(node)); + tcx.map.path_to_string(id_node)); return this.tcx().types.err; } } @@ -1621,7 +1639,7 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, } else if let Some(hir::QSelf { position: 0, .. }) = *maybe_qself { // Create some fake resolution that can't possibly be a type. def::PathResolution { - base_def: def::DefMod(DefId::local(ast::CRATE_NODE_ID)), + base_def: def::DefMod(tcx.map.local_def_id(ast::CRATE_NODE_ID)), last_private: LastMod(AllPublic), depth: path.segments.len() } @@ -1655,7 +1673,7 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, } hir::TyFixedLengthVec(ref ty, ref e) => { let hint = UncheckedExprHint(tcx.types.usize); - match const_eval::eval_const_expr_partial(tcx, &e, hint) { + match const_eval::eval_const_expr_partial(tcx, &e, hint, None) { Ok(r) => { match r { ConstVal::Int(i) => @@ -1673,12 +1691,10 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, } } Err(ref r) => { - let subspan = - ast_ty.span.lo <= r.span.lo && r.span.hi <= ast_ty.span.hi; span_err!(tcx.sess, r.span, E0250, "array length constant evaluation error: {}", r.description()); - if !subspan { + if !ast_ty.span.contains(r.span) { span_note!(tcx.sess, ast_ty.span, "for array length here") } this.tcx().types.err @@ -1686,7 +1702,9 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, } } hir::TyTypeof(ref _e) => { - tcx.sess.span_bug(ast_ty.span, "typeof is reserved but unimplemented"); + span_err!(tcx.sess, ast_ty.span, E0516, + "`typeof` is a reserved keyword but unimplemented"); + tcx.types.err } hir::TyInfer => { // TyInfer also appears as the type of arguments or return diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 2ce06786db..2e0af6a5d8 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -9,7 +9,6 @@ // except according to those terms. use middle::def; -use middle::def_id::DefId; use middle::infer; use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding}; use middle::pat_util::pat_is_resolved_const; @@ -26,6 +25,7 @@ use util::nodemap::FnvHashMap; use std::cmp; use std::collections::hash_map::Entry::{Occupied, Vacant}; use syntax::ast; +use syntax::ext::mtwt; use syntax::codemap::{Span, Spanned}; use syntax::ptr::P; @@ -56,7 +56,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, // They can denote both statically and dynamically sized byte arrays let mut pat_ty = expr_ty; if let hir::ExprLit(ref lt) = lt.node { - if let hir::LitByteStr(_) = lt.node { + if let ast::LitByteStr(_) = lt.node { let expected_ty = structurally_resolved_type(fcx, pat.span, expected); if let ty::TyRef(_, mt) = expected_ty.sty { if let ty::TySlice(_) = mt.ty.sty { @@ -179,7 +179,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, // if there are multiple arms, make sure they all agree on // what the type of the binding `x` ought to be - let canon_id = *pcx.map.get(&path.node).unwrap(); + let canon_id = *pcx.map.get(&mtwt::resolve(path.node)).unwrap(); if canon_id != pat.id { let ct = fcx.local_ty(pat.span, canon_id); demand::eqtype(fcx, pat.span, ct, typ); @@ -202,9 +202,10 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let path_res = if let Some(&d) = tcx.def_map.borrow().get(&pat.id) { d } else if qself.position == 0 { + // This is just a sentinel for finish_resolving_def_to_ty. + let sentinel = fcx.tcx().map.local_def_id(ast::CRATE_NODE_ID); def::PathResolution { - // This is just a sentinel for finish_resolving_def_to_ty. - base_def: def::DefMod(DefId::local(ast::CRATE_NODE_ID)), + base_def: def::DefMod(sentinel), last_private: LastMod(AllPublic), depth: path.segments.len() } @@ -259,17 +260,30 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, } } hir::PatRegion(ref inner, mutbl) => { - let inner_ty = fcx.infcx().next_ty_var(); - - let mt = ty::TypeAndMut { ty: inner_ty, mutbl: mutbl }; - let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span)); - let rptr_ty = tcx.mk_ref(tcx.mk_region(region), mt); - + let expected = fcx.infcx().shallow_resolve(expected); if check_dereferencable(pcx, pat.span, expected, &**inner) { // `demand::subtype` would be good enough, but using // `eqtype` turns out to be equally general. See (*) // below for details. - demand::eqtype(fcx, pat.span, expected, rptr_ty); + + // Take region, inner-type from expected type if we + // can, to avoid creating needless variables. This + // also helps with the bad interactions of the given + // hack detailed in (*) below. + let (rptr_ty, inner_ty) = match expected.sty { + ty::TyRef(_, mt) if mt.mutbl == mutbl => { + (expected, mt.ty) + } + _ => { + let inner_ty = fcx.infcx().next_ty_var(); + let mt = ty::TypeAndMut { ty: inner_ty, mutbl: mutbl }; + let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span)); + let rptr_ty = tcx.mk_ref(tcx.mk_region(region), mt); + demand::eqtype(fcx, pat.span, expected, rptr_ty); + (rptr_ty, inner_ty) + } + }; + fcx.write_ty(pat.id, rptr_ty); check_pat(pcx, &**inner, inner_ty); } else { @@ -530,7 +544,7 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx hir::Pat, let tcx = pcx.fcx.ccx.tcx; let def = tcx.def_map.borrow().get(&pat.id).unwrap().full_def(); - let variant = match fcx.def_struct_variant(def) { + let variant = match fcx.def_struct_variant(def, path.span) { Some((_, variant)) => variant, None => { let name = pprust::path_to_string(path); @@ -706,25 +720,25 @@ pub fn check_struct_pat_fields<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, // Typecheck each field. for &Spanned { node: ref field, span } in fields { - let field_ty = match used_fields.entry(field.ident.name) { + let field_ty = match used_fields.entry(field.name) { Occupied(occupied) => { span_err!(tcx.sess, span, E0025, "field `{}` bound multiple times in the pattern", - field.ident); + field.name); span_note!(tcx.sess, *occupied.get(), "field `{}` previously bound here", - field.ident); + field.name); tcx.types.err } Vacant(vacant) => { vacant.insert(span); - field_map.get(&field.ident.name) + field_map.get(&field.name) .map(|f| pcx.fcx.field_ty(span, f, substs)) .unwrap_or_else(|| { span_err!(tcx.sess, span, E0026, "struct `{}` does not have a field named `{}`", tcx.item_path_str(variant.did), - field.ident); + field.name); tcx.types.err }) } diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 948b7dd156..dcecec7007 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -25,7 +25,8 @@ use super::UnresolvedTypeAction; use super::write_call; use CrateCtxt; -use middle::def_id::{DefId, LOCAL_CRATE}; +use metadata::cstore::LOCAL_CRATE; +use middle::def_id::DefId; use middle::infer; use middle::ty::{self, LvaluePreference, Ty}; use syntax::codemap::Span; diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 98c8c0a319..13e5e46ed2 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -49,7 +49,8 @@ use middle::ty::{self, Ty, HasTypeFlags}; use middle::ty::cast::{CastKind, CastTy}; use syntax::codemap::Span; use rustc_front::hir; -use rustc_front::hir::UintTy::TyU8; +use syntax::ast; +use syntax::ast::UintTy::TyU8; /// Reifies a cast check to be checked once we have full type information for @@ -245,7 +246,7 @@ impl<'tcx> CastCheck<'tcx> { (_, Int(Bool)) => Err(CastError::CastToBool), // * -> Char - (Int(U(hir::TyU8)), Int(Char)) => Ok(CastKind::U8CharCast), // u8-char-cast + (Int(U(ast::TyU8)), Int(Char)) => Ok(CastKind::U8CharCast), // u8-char-cast (_, Int(Char)) => Err(CastError::CastToChar), // prim -> float,ptr diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 82c898214c..4f7a639539 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -13,7 +13,6 @@ use super::{check_fn, Expectation, FnCtxt}; use astconv; -use middle::def_id::DefId; use middle::subst; use middle::ty::{self, ToPolyTraitRef, Ty}; use std::cmp; @@ -46,7 +45,7 @@ fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, decl: &'tcx hir::FnDecl, body: &'tcx hir::Block, expected_sig: Option>) { - let expr_def_id = DefId::local(expr.id); + let expr_def_id = fcx.tcx().map.local_def_id(expr.id); debug!("check_closure opt_kind={:?} expected_sig={:?}", opt_kind, diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 6d8b757d16..c46f386af2 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -169,8 +169,8 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, // Create a parameter environment that represents the implementation's // method. - let impl_param_env = - ty::ParameterEnvironment::for_item(tcx, impl_m.def_id.node); + let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap(); + let impl_param_env = ty::ParameterEnvironment::for_item(tcx, impl_m_node_id); // Create mapping from impl to skolemized. let impl_to_skol_substs = &impl_param_env.free_substs; @@ -428,8 +428,8 @@ pub fn compare_const_impl<'tcx>(tcx: &ty::ctxt<'tcx>, // Create a parameter environment that represents the implementation's // method. - let impl_param_env = - ty::ParameterEnvironment::for_item(tcx, impl_c.def_id.node); + let impl_c_node_id = tcx.map.as_local_node_id(impl_c.def_id).unwrap(); + let impl_param_env = ty::ParameterEnvironment::for_item(tcx, impl_c_node_id); // Create mapping from impl to skolemized. let impl_to_skol_substs = &impl_param_env.free_substs; diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index a8c77f863b..d68959b99b 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -10,7 +10,7 @@ use check::regionck::{self, Rcx}; -use middle::def_id::{DefId, LOCAL_CRATE}; +use middle::def_id::DefId; use middle::free_region::FreeRegionMap; use middle::infer; use middle::region; @@ -77,11 +77,12 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>( drop_impl_ty: &ty::Ty<'tcx>, self_type_did: DefId) -> Result<(), ()> { - assert!(drop_impl_did.is_local() && self_type_did.is_local()); + let drop_impl_node_id = tcx.map.as_local_node_id(drop_impl_did).unwrap(); + let self_type_node_id = tcx.map.as_local_node_id(self_type_did).unwrap(); // check that the impl type can be made to match the trait type. - let impl_param_env = ty::ParameterEnvironment::for_item(tcx, self_type_did.node); + let impl_param_env = ty::ParameterEnvironment::for_item(tcx, self_type_node_id); let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(impl_param_env), true); let named_type = tcx.lookup_item_type(self_type_did).ty; @@ -96,7 +97,7 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>( named_type, fresh_impl_self_ty) { span_err!(tcx.sess, drop_impl_span, E0366, "Implementations of Drop cannot be specialized"); - let item_span = tcx.map.span(self_type_did.node); + let item_span = tcx.map.span(self_type_node_id); tcx.sess.span_note(item_span, "Use same sequence of generic type and region \ parameters that is on the struct/enum definition"); @@ -110,7 +111,7 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>( } let free_regions = FreeRegionMap::new(); - infcx.resolve_regions_and_report_errors(&free_regions, drop_impl_did.node); + infcx.resolve_regions_and_report_errors(&free_regions, drop_impl_node_id); Ok(()) } @@ -158,7 +159,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( // absent. So we report an error that the Drop impl injected a // predicate that is not present on the struct definition. - assert_eq!(self_type_did.krate, LOCAL_CRATE); + let self_type_node_id = tcx.map.as_local_node_id(self_type_did).unwrap(); let drop_impl_span = tcx.map.def_id_span(drop_impl_did, codemap::DUMMY_SP); @@ -184,7 +185,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( for predicate in predicates { // (We do not need to worry about deep analysis of type // expressions etc because the Drop impls are already forced - // to take on a structure that is roughly a alpha-renaming of + // to take on a structure that is roughly an alpha-renaming of // the generic parameters of the item definition.) // This path now just checks *all* predicates via the direct @@ -195,7 +196,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( // repeated `contains` calls. if !assumptions_in_impl_context.contains(&predicate) { - let item_span = tcx.map.span(self_type_did.node); + let item_span = tcx.map.span(self_type_node_id); span_err!(tcx.sess, drop_impl_span, E0367, "The requirement `{}` is added only by the Drop impl.", predicate); tcx.sess.span_note(item_span, @@ -216,19 +217,16 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( /// /// ---- /// -/// The Drop Check Rule is the following: +/// The simplified (*) Drop Check Rule is the following: /// /// Let `v` be some value (either temporary or named) and 'a be some /// lifetime (scope). If the type of `v` owns data of type `D`, where /// -/// * (1.) `D` has a lifetime- or type-parametric Drop implementation, and -/// * (2.) the structure of `D` can reach a reference of type `&'a _`, and -/// * (3.) either: -/// * (A.) the Drop impl for `D` instantiates `D` at 'a directly, -/// i.e. `D<'a>`, or, -/// * (B.) the Drop impl for `D` has some type parameter with a -/// trait bound `T` where `T` is a trait that has at least -/// one method, +/// * (1.) `D` has a lifetime- or type-parametric Drop implementation, +/// (where that `Drop` implementation does not opt-out of +/// this check via the `unsafe_destructor_blind_to_params` +/// attribute), and +/// * (2.) the structure of `D` can reach a reference of type `&'a _`, /// /// then 'a must strictly outlive the scope of v. /// @@ -236,6 +234,35 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( /// /// This function is meant to by applied to the type for every /// expression in the program. +/// +/// ---- +/// +/// (*) The qualifier "simplified" is attached to the above +/// definition of the Drop Check Rule, because it is a simplification +/// of the original Drop Check rule, which attempted to prove that +/// some `Drop` implementations could not possibly access data even if +/// it was technically reachable, due to parametricity. +/// +/// However, (1.) parametricity on its own turned out to be a +/// necessary but insufficient condition, and (2.) future changes to +/// the language are expected to make it impossible to ensure that a +/// `Drop` implementation is actually parametric with respect to any +/// particular type parameter. (In particular, impl specialization is +/// expected to break the needed parametricity property beyond +/// repair.) +/// +/// Therefore we have scaled back Drop-Check to a more conservative +/// rule that does not attempt to deduce whether a `Drop` +/// implementation could not possible access data of a given lifetime; +/// instead Drop-Check now simply assumes that if a destructor has +/// access (direct or indirect) to a lifetime parameter, then that +/// lifetime must be forced to outlive that destructor's dynamic +/// extent. We then provide the `unsafe_destructor_blind_to_params` +/// attribute as a way for destructor implementations to opt-out of +/// this conservative assumption (and thus assume the obligation of +/// ensuring that they do not access data nor invoke methods of +/// values that have been previously dropped). +/// pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, typ: ty::Ty<'tcx>, span: Span, @@ -355,13 +382,18 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'tcx>( // borrowed data reachable via `typ` must outlive the parent // of `scope`. This is handled below. // - // However, there is an important special case: by - // parametricity, any generic type parameters have *no* trait - // bounds in the Drop impl can not be used in any way (apart - // from being dropped), and thus we can treat data borrowed - // via such type parameters remains unreachable. + // However, there is an important special case: for any Drop + // impl that is tagged as "blind" to their parameters, + // we assume that data borrowed via such type parameters + // remains unreachable via that Drop impl. + // + // For example, consider: + // + // ```rust + // #[unsafe_destructor_blind_to_params] + // impl Drop for Vec { ... } + // ``` // - // For example, consider `impl Drop for Vec { ... }`, // which does have to be able to drop instances of `T`, but // otherwise cannot read data from `T`. // @@ -369,16 +401,6 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'tcx>( // unbounded type parameter `T`, we must resume the recursive // analysis on `T` (since it would be ignored by // type_must_outlive). - // - // FIXME (pnkfelix): Long term, we could be smart and actually - // feed which generic parameters can be ignored *into* `fn - // type_must_outlive` (or some generalization thereof). But - // for the short term, it probably covers most cases of - // interest to just special case Drop impls where: (1.) there - // are no generic lifetime parameters and (2.) *all* generic - // type parameters are unbounded. If both conditions hold, we - // simply skip the `type_must_outlive` call entirely (but - // resume the recursive checking of the type-substructure). if has_dtor_of_interest(tcx, ty) { debug!("iterate_over_potentially_unsafe_regions_in_type \ {}ty: {} - is a dtorck type!", diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index e7c7b5831d..4afc610f63 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -13,7 +13,6 @@ use astconv::AstConv; use intrinsics; -use middle::def_id::DefId; use middle::subst; use middle::ty::FnSig; use middle::ty::{self, Ty}; @@ -22,6 +21,7 @@ use {CrateCtxt, require_same_types}; use std::collections::{HashMap}; use syntax::abi; +use syntax::ast; use syntax::attr::AttrMetaMethods; use syntax::codemap::Span; use syntax::parse::token; @@ -42,7 +42,7 @@ fn equate_intrinsic_type<'a, 'tcx>(tcx: &ty::ctxt<'tcx>, it: &hir::ForeignItem, variadic: false, }), })); - let i_ty = tcx.lookup_item_type(DefId::local(it.id)); + let i_ty = tcx.lookup_item_type(tcx.map.local_def_id(it.id)); let i_n_tps = i_ty.generics.types.len(subst::FnSpace); if i_n_tps != n_tps { span_err!(tcx.sess, it.span, E0094, @@ -72,7 +72,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) { } let tcx = ccx.tcx; - let name = it.ident.name.as_str(); + let name = it.name.as_str(); let (n_tps, inputs, output) = if name.starts_with("atomic_") { let split : Vec<&str> = name.split('_').collect(); assert!(split.len() >= 2, "Atomic intrinsic not correct format"); @@ -364,9 +364,9 @@ pub fn check_platform_intrinsic_type(ccx: &CrateCtxt, }; let tcx = ccx.tcx; - let i_ty = tcx.lookup_item_type(DefId::local(it.id)); + let i_ty = tcx.lookup_item_type(tcx.map.local_def_id(it.id)); let i_n_tps = i_ty.generics.types.len(subst::FnSpace); - let name = it.ident.name.as_str(); + let name = it.name.as_str(); let (n_tps, inputs, output) = match &*name { "simd_eq" | "simd_ne" | "simd_lt" | "simd_le" | "simd_gt" | "simd_ge" => { @@ -470,22 +470,22 @@ fn match_intrinsic_type_to_type<'tcx, 'a>( }, // (The width we pass to LLVM doesn't concern the type checker.) Integer(signed, bits, _llvm_width) => match (signed, bits, &t.sty) { - (true, 8, &ty::TyInt(hir::IntTy::TyI8)) | - (false, 8, &ty::TyUint(hir::UintTy::TyU8)) | - (true, 16, &ty::TyInt(hir::IntTy::TyI16)) | - (false, 16, &ty::TyUint(hir::UintTy::TyU16)) | - (true, 32, &ty::TyInt(hir::IntTy::TyI32)) | - (false, 32, &ty::TyUint(hir::UintTy::TyU32)) | - (true, 64, &ty::TyInt(hir::IntTy::TyI64)) | - (false, 64, &ty::TyUint(hir::UintTy::TyU64)) => {}, + (true, 8, &ty::TyInt(ast::IntTy::TyI8)) | + (false, 8, &ty::TyUint(ast::UintTy::TyU8)) | + (true, 16, &ty::TyInt(ast::IntTy::TyI16)) | + (false, 16, &ty::TyUint(ast::UintTy::TyU16)) | + (true, 32, &ty::TyInt(ast::IntTy::TyI32)) | + (false, 32, &ty::TyUint(ast::UintTy::TyU32)) | + (true, 64, &ty::TyInt(ast::IntTy::TyI64)) | + (false, 64, &ty::TyUint(ast::UintTy::TyU64)) => {}, _ => simple_error(&format!("`{}`", t), &format!("`{}{n}`", if signed {"i"} else {"u"}, n = bits)), }, Float(bits) => match (bits, &t.sty) { - (32, &ty::TyFloat(hir::FloatTy::TyF32)) | - (64, &ty::TyFloat(hir::FloatTy::TyF64)) => {}, + (32, &ty::TyFloat(ast::FloatTy::TyF32)) | + (64, &ty::TyFloat(ast::FloatTy::TyF64)) => {}, _ => simple_error(&format!("`{}`", t), &format!("`f{n}`", n = bits)), }, diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 454c11db26..72131627aa 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -103,22 +103,23 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // Unify the (adjusted) self type with what the method expects. self.unify_receivers(self_ty, method_self_ty); - // Add any trait/regions obligations specified on the method's type parameters. - self.add_obligations(&pick, &all_substs, &method_predicates); - - // Create the final `MethodCallee`. + // Create the method type let method_ty = pick.item.as_opt_method().unwrap(); let fty = self.tcx().mk_fn(None, self.tcx().mk_bare_fn(ty::BareFnTy { 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); + + // Create the final `MethodCallee`. let callee = ty::MethodCallee { def_id: pick.item.def_id(), ty: fty, substs: self.tcx().mk_substs(all_substs) }; - // If this is an `&mut self` method, bias the receiver // expression towards mutability (this will switch // e.g. `Deref` to `DerefMut` in overloaded derefs and so on). @@ -422,11 +423,11 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { } fn add_obligations(&mut self, - pick: &probe::Pick<'tcx>, + fty: Ty<'tcx>, all_substs: &subst::Substs<'tcx>, method_predicates: &ty::InstantiatedPredicates<'tcx>) { - debug!("add_obligations: pick={:?} all_substs={:?} method_predicates={:?}", - pick, + debug!("add_obligations: fty={:?} all_substs={:?} method_predicates={:?}", + fty, all_substs, method_predicates); @@ -439,6 +440,11 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { self.fcx.add_wf_bounds( all_substs, self.call_expr); + + // the function type must also be well-formed (this is not + // implied by the substs being well-formed because of inherent + // impls and late-bound regions - see issue #28609). + self.fcx.register_wf_obligation(fty, self.span, traits::MiscObligation); } /////////////////////////////////////////////////////////////////////////// @@ -468,7 +474,6 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { loop { let last = exprs[exprs.len() - 1]; match last.node { - hir::ExprParen(ref expr) | hir::ExprField(ref expr, _) | hir::ExprTupField(ref expr, _) | hir::ExprIndex(ref expr, _) | diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index edf1cc9b7e..e0ad51b4ea 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -255,6 +255,9 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, traits::ObligationCause::misc(span, fcx.body_id), &method_bounds); + // Also register an obligation for the method type being well-formed. + fcx.register_wf_obligation(fty, span, traits::MiscObligation); + // FIXME(#18653) -- Try to resolve obligations, giving us more // typing information, which can sometimes be needed to avoid // pathological region inference failures. diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index f65602d9aa..c63b081c73 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -319,51 +319,51 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { let lang_def_id = self.tcx().lang_items.mut_ptr_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); } - ty::TyInt(hir::TyI8) => { + ty::TyInt(ast::TyI8) => { let lang_def_id = self.tcx().lang_items.i8_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); } - ty::TyInt(hir::TyI16) => { + ty::TyInt(ast::TyI16) => { let lang_def_id = self.tcx().lang_items.i16_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); } - ty::TyInt(hir::TyI32) => { + ty::TyInt(ast::TyI32) => { let lang_def_id = self.tcx().lang_items.i32_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); } - ty::TyInt(hir::TyI64) => { + ty::TyInt(ast::TyI64) => { let lang_def_id = self.tcx().lang_items.i64_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); } - ty::TyInt(hir::TyIs) => { + ty::TyInt(ast::TyIs) => { let lang_def_id = self.tcx().lang_items.isize_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); } - ty::TyUint(hir::TyU8) => { + ty::TyUint(ast::TyU8) => { let lang_def_id = self.tcx().lang_items.u8_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); } - ty::TyUint(hir::TyU16) => { + ty::TyUint(ast::TyU16) => { let lang_def_id = self.tcx().lang_items.u16_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); } - ty::TyUint(hir::TyU32) => { + ty::TyUint(ast::TyU32) => { let lang_def_id = self.tcx().lang_items.u32_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); } - ty::TyUint(hir::TyU64) => { + ty::TyUint(ast::TyU64) => { let lang_def_id = self.tcx().lang_items.u64_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); } - ty::TyUint(hir::TyUs) => { + ty::TyUint(ast::TyUs) => { let lang_def_id = self.tcx().lang_items.usize_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); } - ty::TyFloat(hir::TyF32) => { + ty::TyFloat(ast::TyF32) => { let lang_def_id = self.tcx().lang_items.f32_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); } - ty::TyFloat(hir::TyF64) => { + ty::TyFloat(ast::TyF64) => { let lang_def_id = self.tcx().lang_items.f64_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 6961f3444d..f597820639 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -15,6 +15,7 @@ use CrateCtxt; use astconv::AstConv; use check::{self, FnCtxt}; +use front::map as hir_map; use middle::ty::{self, Ty, ToPolyTraitRef, ToPredicate, HasTypeFlags}; use middle::def; use middle::def_id::DefId; @@ -22,6 +23,7 @@ use middle::lang_items::FnOnceTraitLangItem; use middle::subst::Substs; use middle::traits::{Obligation, SelectionContext}; use metadata::{csearch, cstore, decoder}; +use util::nodemap::{FnvHashSet}; use syntax::ast; use syntax::codemap::Span; @@ -182,7 +184,14 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, CandidateSource::ImplSource(impl_did) => { // Provide the best span we can. Use the item, if local to crate, else // the impl, if local to crate (item may be defaulted), else the call site. - let item = impl_item(fcx.tcx(), impl_did, item_name).unwrap(); + let item = impl_item(fcx.tcx(), impl_did, item_name) + .or_else(|| { + trait_item( + fcx.tcx(), + fcx.tcx().impl_trait_ref(impl_did).unwrap().def_id, + item_name + ) + }).unwrap(); let impl_span = fcx.tcx().map.def_id_span(impl_did, span); let item_span = fcx.tcx().map.def_id_span(item.def_id(), impl_span); @@ -357,13 +366,11 @@ impl PartialOrd for TraitInfo { } impl Ord for TraitInfo { fn cmp(&self, other: &TraitInfo) -> Ordering { - // accessible traits are more important/relevant than - // inaccessible ones, local crates are more important than - // remote ones (local: cnum == 0), and NodeIds just for - // totality. + // local crates are more important than remote ones (local: + // cnum == 0), and otherwise we throw in the defid for totality - let lhs = (other.def_id.krate, other.def_id.node); - let rhs = (self.def_id.krate, self.def_id.node); + let lhs = (other.def_id.krate, other.def_id); + let rhs = (self.def_id.krate, self.def_id); lhs.cmp(&rhs) } } @@ -378,14 +385,16 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> { // Crate-local: // // meh. - struct Visitor<'a> { + struct Visitor<'a, 'tcx:'a> { + map: &'a hir_map::Map<'tcx>, traits: &'a mut AllTraitsVec, } - impl<'v, 'a> visit::Visitor<'v> for Visitor<'a> { + impl<'v, 'a, 'tcx> visit::Visitor<'v> for Visitor<'a, 'tcx> { fn visit_item(&mut self, i: &'v hir::Item) { match i.node { hir::ItemTrait(..) => { - self.traits.push(TraitInfo::new(DefId::local(i.id))); + let def_id = self.map.local_def_id(i.id); + self.traits.push(TraitInfo::new(def_id)); } _ => {} } @@ -393,11 +402,14 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> { } } visit::walk_crate(&mut Visitor { + map: &ccx.tcx.map, traits: &mut traits }, ccx.tcx.map.krate()); // Cross-crate: + let mut external_mods = FnvHashSet(); fn handle_external_def(traits: &mut AllTraitsVec, + external_mods: &mut FnvHashSet, ccx: &CrateCtxt, cstore: &cstore::CStore, dl: decoder::DefLike) { @@ -406,8 +418,12 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> { traits.push(TraitInfo::new(did)); } decoder::DlDef(def::DefMod(did)) => { + if !external_mods.insert(did) { + return; + } csearch::each_child_of_item(cstore, did, |dl, _, _| { - handle_external_def(traits, ccx, cstore, dl) + handle_external_def(traits, external_mods, + ccx, cstore, dl) }) } _ => {} @@ -416,7 +432,9 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> { let cstore = &ccx.tcx.sess.cstore; cstore.iter_crate_data(|cnum, _| { csearch::each_top_level_item_of_crate(cstore, cnum, |dl, _, _| { - handle_external_def(&mut traits, ccx, cstore, dl) + handle_external_def(&mut traits, + &mut external_mods, + ccx, cstore, dl) }) }); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index b07168966c..f085ce23e3 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -83,9 +83,10 @@ use self::TupleArgumentsFlag::*; use astconv::{self, ast_region_to_region, ast_ty_to_ty, AstConv, PathParamMode}; use check::_match::pat_ctxt; use fmt_macros::{Parser, Piece, Position}; +use metadata::cstore::LOCAL_CRATE; use middle::astconv_util::prohibit_type_params; use middle::def; -use middle::def_id::{DefId, LOCAL_CRATE}; +use middle::def_id::DefId; use middle::infer; use middle::infer::type_variable; use middle::pat_util::{self, pat_id_map}; @@ -114,10 +115,11 @@ use util::lev_distance::lev_distance; use std::cell::{Cell, Ref, RefCell}; use std::collections::{HashSet}; use std::mem::replace; -use std::slice; use syntax::abi; use syntax::ast; -use syntax::codemap::{self, Span}; +use syntax::attr; +use syntax::attr::AttrMetaMethods; +use syntax::codemap::{self, Span, Spanned}; use syntax::owned_slice::OwnedSlice; use syntax::parse::token::{self, InternedString}; use syntax::ptr::P; @@ -125,10 +127,9 @@ use syntax::ptr::P; use rustc_front::visit::{self, Visitor}; use rustc_front::hir; use rustc_front::hir::Visibility; -use rustc_front::attr; -use rustc_front::attr::AttrMetaMethods; use rustc_front::hir::{Item, ItemImpl}; use rustc_front::print::pprust; +use rustc_back::slice; mod assoc; pub mod dropck; @@ -268,7 +269,7 @@ impl UnsafetyState { (unsafety, blk.id, self.unsafe_push_count.checked_sub(1).unwrap()), hir::UnsafeBlock(..) => (hir::Unsafety::Unsafe, blk.id, self.unsafe_push_count), - hir::DefaultBlock => + hir::DefaultBlock | hir::PushUnstableBlock | hir:: PopUnstableBlock => (unsafety, self.def, self.unsafe_push_count), }; UnsafetyState{ def: def, @@ -376,6 +377,11 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> { hir::TyFixedLengthVec(_, ref expr) => { check_const_in_type(self.ccx, &**expr, self.ccx.tcx.types.usize); } + hir::TyBareFn(ref function_declaration) => { + visit::walk_fn_decl_nopat(self, &function_declaration.decl); + walk_list!(self, visit_lifetime_def, &function_declaration.lifetimes); + return + } _ => {} } @@ -560,6 +566,10 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { self.visit_ty(&**ty); check_expr_with_hint(self.fcx, &**count_expr, self.fcx.tcx().types.usize); } + hir::TyBareFn(ref function_declaration) => { + visit::walk_fn_decl_nopat(self, &function_declaration.decl); + walk_list!(self, visit_lifetime_def, &function_declaration.lifetimes); + } _ => visit::walk_ty(self, t) } } @@ -678,15 +688,15 @@ pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) { check_representable(tcx, span, id, "struct"); - if tcx.lookup_simd(DefId::local(id)) { + if tcx.lookup_simd(ccx.tcx.map.local_def_id(id)) { check_simd(tcx, span, id); } } pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { - debug!("check_item_type(it.id={}, it.ident={})", + debug!("check_item_type(it.id={}, it.name={})", it.id, - ccx.tcx.item_path_str(DefId::local(it.id))); + ccx.tcx.item_path_str(ccx.tcx.map.local_def_id(it.id))); let _indenter = indenter(); match it.node { // Consts can play a role in type-checking, so they are included here. @@ -700,8 +710,8 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { } hir::ItemFn(..) => {} // entirely within check_item_body hir::ItemImpl(_, _, _, _, _, ref impl_items) => { - debug!("ItemImpl {} with id {}", it.ident, it.id); - match ccx.tcx.impl_trait_ref(DefId::local(it.id)) { + debug!("ItemImpl {} with id {}", it.name, it.id); + match ccx.tcx.impl_trait_ref(ccx.tcx.map.local_def_id(it.id)) { Some(impl_trait_ref) => { check_impl_items_against_trait(ccx, it.span, @@ -732,7 +742,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { } } else { for item in &m.items { - let pty = ccx.tcx.lookup_item_type(DefId::local(item.id)); + let pty = ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(item.id)); if !pty.generics.types.is_empty() { span_err!(ccx.tcx.sess, item.span, E0044, "foreign items may not have type parameters"); @@ -752,20 +762,20 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { } pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { - debug!("check_item_body(it.id={}, it.ident={})", + debug!("check_item_body(it.id={}, it.name={})", it.id, - ccx.tcx.item_path_str(DefId::local(it.id))); + ccx.tcx.item_path_str(ccx.tcx.map.local_def_id(it.id))); let _indenter = indenter(); match it.node { hir::ItemFn(ref decl, _, _, _, _, ref body) => { - let fn_pty = ccx.tcx.lookup_item_type(DefId::local(it.id)); + let fn_pty = ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(it.id)); let param_env = ParameterEnvironment::for_item(ccx.tcx, it.id); check_bare_fn(ccx, &**decl, &**body, it.id, it.span, fn_pty.ty, param_env); } hir::ItemImpl(_, _, _, _, _, ref impl_items) => { - debug!("ItemImpl {} with id {}", it.ident, it.id); + debug!("ItemImpl {} with id {}", it.name, it.id); - let impl_pty = ccx.tcx.lookup_item_type(DefId::local(it.id)); + let impl_pty = ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(it.id)); for impl_item in impl_items { match impl_item.node { @@ -783,7 +793,7 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { } } hir::ItemTrait(_, _, _, ref trait_items) => { - let trait_def = ccx.tcx.lookup_trait_def(DefId::local(it.id)); + let trait_def = ccx.tcx.lookup_trait_def(ccx.tcx.map.local_def_id(it.id)); for trait_item in trait_items { match trait_item.node { hir::ConstTraitItem(_, Some(ref expr)) => { @@ -840,14 +850,14 @@ fn check_trait_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, Position::ArgumentNamed(s) if s == "Self" => (), // So is `{A}` if A is a type parameter Position::ArgumentNamed(s) => match types.iter().find(|t| { - t.ident.name == s + t.name.as_str() == s }) { Some(_) => (), None => { span_err!(ccx.tcx.sess, attr.span, E0230, "there is no type parameter \ {} on trait {}", - s, item.ident); + s, item.name); } }, // `{:1}` and `{}` are not to be used @@ -902,7 +912,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // Check existing impl methods to see if they are both present in trait // and compatible with trait signature for impl_item in impl_items { - let ty_impl_item = ccx.tcx.impl_or_trait_item(DefId::local(impl_item.id)); + let ty_impl_item = ccx.tcx.impl_or_trait_item(ccx.tcx.map.local_def_id(impl_item.id)); let ty_trait_item = trait_items.iter() .find(|ac| ac.name() == ty_impl_item.name()) .unwrap_or_else(|| { @@ -980,7 +990,6 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // Check for missing items from trait let provided_methods = tcx.provided_trait_methods(impl_trait_ref.def_id); - let associated_consts = tcx.associated_consts(impl_trait_ref.def_id); let mut missing_items = Vec::new(); let mut invalidated_items = Vec::new(); let associated_type_overridden = overridden_associated_type.is_some(); @@ -990,14 +999,13 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let is_implemented = impl_items.iter().any(|ii| { match ii.node { hir::ConstImplItem(..) => { - ii.ident.name == associated_const.name + ii.name == associated_const.name } _ => false, } }); - let is_provided = - associated_consts.iter().any(|ac| ac.default.is_some() && - ac.name == associated_const.name); + let is_provided = associated_const.has_value; + if !is_implemented { if !is_provided { missing_items.push(associated_const.name); @@ -1011,7 +1019,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_items.iter().any(|ii| { match ii.node { hir::MethodImplItem(..) => { - ii.ident.name == trait_method.name + ii.name == trait_method.name } _ => false, } @@ -1030,7 +1038,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let is_implemented = impl_items.iter().any(|ii| { match ii.node { hir::TypeImplItem(_) => { - ii.ident.name == associated_type.name + ii.name == associated_type.name } _ => false, } @@ -1060,7 +1068,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, span_err!(tcx.sess, invalidator.span, E0399, "the following trait items need to be reimplemented \ as `{}` was overridden: `{}`", - invalidator.ident, + invalidator.name, invalidated_items.iter() .map(|name| name.to_string()) .collect::>().join("`, `")) @@ -1310,9 +1318,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match self.inh.locals.borrow().get(&nid) { Some(&t) => t, None => { - self.tcx().sess.span_err( - span, - &format!("no type for local variable {}", nid)); + span_err!(self.tcx().sess, span, E0513, + "no type for local variable {}", + nid); self.tcx().types.err } } @@ -1456,7 +1464,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Return the dict-like variant corresponding to a given `Def`. pub fn def_struct_variant(&self, - def: def::Def) + def: def::Def, + span: Span) -> Option<(ty::AdtDef<'tcx>, ty::VariantDef<'tcx>)> { let (adt, variant) = match def { @@ -1475,13 +1484,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => return None }; - if let ty::VariantKind::Dict = variant.kind() { + let var_kind = variant.kind(); + if var_kind == ty::VariantKind::Struct { Some((adt, variant)) - } else { - None - } - } + } else if var_kind == ty::VariantKind::Unit { + if !self.tcx().sess.features.borrow().braced_empty_structs { + self.tcx().sess.span_err(span, "empty structs and enum variants \ + with braces are unstable"); + fileline_help!(self.tcx().sess, span, "add #![feature(braced_empty_structs)] to \ + the crate features to enable"); + } + Some((adt, variant)) + } else { + None + } + } pub fn write_nil(&self, node_id: ast::NodeId) { self.write_ty(node_id, self.tcx().mk_nil()); @@ -1549,21 +1567,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn to_ty(&self, ast_t: &hir::Ty) -> Ty<'tcx> { let t = ast_ty_to_ty(self, self, ast_t); - - // Generally speaking, we must check that types entered by the - // user are well-formed. This is not true for `_`, since those - // types are generated by inference. Now, you might think that - // we could as well generate a WF obligation -- but - // unfortunately that breaks code like `foo as *const _`, - // because those type variables wind up being unconstrained - // until very late. Nasty. Probably it'd be best to refactor - // that code path, but that's tricky because of - // defaults. Argh! - match ast_t.node { - hir::TyInfer => { } - _ => { self.register_wf_obligation(t, ast_t.span, traits::MiscObligation); } - } - + self.register_wf_obligation(t, ast_t.span, traits::MiscObligation); t } @@ -1816,7 +1820,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // There is a possibility that this algorithm will have to run an arbitrary number of times // to terminate so we bound it by the compiler's recursion limit. - for _ in (0..self.tcx().sess.recursion_limit.get()) { + for _ in 0..self.tcx().sess.recursion_limit.get() { // First we try to solve all obligations, it is possible that the last iteration // has made it possible to make more progress. self.select_obligations_where_possible(); @@ -1884,7 +1888,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // If there are no more fallbacks to apply at this point we have applied all possible - // defaults and type inference will procede as normal. + // defaults and type inference will proceed as normal. if unbound_tyvars.is_empty() { break; } @@ -1946,7 +1950,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .unwrap_or(type_variable::Default { ty: self.infcx().next_ty_var(), origin_span: codemap::DUMMY_SP, - def_id: DefId::local(0) // what do I put here? + def_id: self.tcx().map.local_def_id(0) // what do I put here? }); // This is to ensure that we elimnate any non-determinism from the error @@ -2228,7 +2232,7 @@ fn make_overloaded_lvalue_return_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, { match method { Some(method) => { - // extract method method return type, which will be &T; + // extract method return type, which will be &T; // all LB regions should have been instantiated during method lookup let ret_ty = method.ty.fn_ret(); let ret_ty = fcx.tcx().no_late_bound_regions(&ret_ty).unwrap().unwrap(); @@ -2311,7 +2315,7 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // First, try built-in indexing. match (adjusted_ty.builtin_index(), &index_ty.sty) { - (Some(ty), &ty::TyUint(hir::TyUs)) | (Some(ty), &ty::TyInfer(ty::IntVar(_))) => { + (Some(ty), &ty::TyUint(ast::TyUs)) | (Some(ty), &ty::TyInfer(ty::IntVar(_))) => { 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); @@ -2575,21 +2579,21 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let arg_ty = structurally_resolved_type(fcx, arg.span, fcx.expr_ty(&**arg)); match arg_ty.sty { - ty::TyFloat(hir::TyF32) => { + ty::TyFloat(ast::TyF32) => { fcx.type_error_message(arg.span, |t| { format!("can't pass an {} to variadic \ function, cast to c_double", t) }, arg_ty, None); } - ty::TyInt(hir::TyI8) | ty::TyInt(hir::TyI16) | ty::TyBool => { + ty::TyInt(ast::TyI8) | ty::TyInt(ast::TyI16) | ty::TyBool => { fcx.type_error_message(arg.span, |t| { format!("can't pass {} to variadic \ function, cast to c_int", t) }, arg_ty, None); } - ty::TyUint(hir::TyU8) | ty::TyUint(hir::TyU16) => { + ty::TyUint(ast::TyU8) | ty::TyUint(ast::TyU16) => { fcx.type_error_message(arg.span, |t| { format!("can't pass {} to variadic \ function, cast to c_uint", @@ -2618,23 +2622,23 @@ fn write_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // AST fragment checking fn check_lit<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - lit: &hir::Lit, + lit: &ast::Lit, expected: Expectation<'tcx>) -> Ty<'tcx> { let tcx = fcx.ccx.tcx; match lit.node { - hir::LitStr(..) => tcx.mk_static_str(), - hir::LitByteStr(ref v) => { + ast::LitStr(..) => tcx.mk_static_str(), + ast::LitByteStr(ref v) => { tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), tcx.mk_array(tcx.types.u8, v.len())) } - hir::LitByte(_) => tcx.types.u8, - hir::LitChar(_) => tcx.types.char, - hir::LitInt(_, hir::SignedIntLit(t, _)) => tcx.mk_mach_int(t), - hir::LitInt(_, hir::UnsignedIntLit(t)) => tcx.mk_mach_uint(t), - hir::LitInt(_, hir::UnsuffixedIntLit(_)) => { + ast::LitByte(_) => tcx.types.u8, + ast::LitChar(_) => tcx.types.char, + ast::LitInt(_, ast::SignedIntLit(t, _)) => tcx.mk_mach_int(t), + ast::LitInt(_, ast::UnsignedIntLit(t)) => tcx.mk_mach_uint(t), + ast::LitInt(_, ast::UnsuffixedIntLit(_)) => { let opt_ty = expected.to_option(fcx).and_then(|ty| { match ty.sty { ty::TyInt(_) | ty::TyUint(_) => Some(ty), @@ -2647,8 +2651,8 @@ fn check_lit<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, opt_ty.unwrap_or_else( || tcx.mk_int_var(fcx.infcx().next_int_var_id())) } - hir::LitFloat(_, t) => tcx.mk_mach_float(t), - hir::LitFloatUnsuffixed(_) => { + ast::LitFloat(_, t) => tcx.mk_mach_float(t), + ast::LitFloatUnsuffixed(_) => { let opt_ty = expected.to_option(fcx).and_then(|ty| { match ty.sty { ty::TyFloat(_) => Some(ty), @@ -2658,7 +2662,7 @@ fn check_lit<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, opt_ty.unwrap_or_else( || tcx.mk_float_var(fcx.infcx().next_float_var_id())) } - hir::LitBool(_) => tcx.types.bool + ast::LitBool(_) => tcx.types.bool } } @@ -2822,7 +2826,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // Checks a method call. fn check_method_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, expr: &'tcx hir::Expr, - method_name: hir::SpannedIdent, + method_name: Spanned, args: &'tcx [P], tps: &[P], expected: Expectation<'tcx>, @@ -2838,7 +2842,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let tps = tps.iter().map(|ast_ty| fcx.to_ty(&**ast_ty)).collect::>(); let fn_ty = match method::lookup(fcx, method_name.span, - method_name.node.name, + method_name.node, expr_t, tps, expr, @@ -2851,7 +2855,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } Err(error) => { method::report_error(fcx, method_name.span, expr_t, - method_name.node.name, Some(rcvr), error); + method_name.node, Some(rcvr), error); fcx.write_error(expr.id); fcx.tcx().types.err } @@ -2918,7 +2922,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, expr: &'tcx hir::Expr, lvalue_pref: LvaluePreference, base: &'tcx hir::Expr, - field: &hir::SpannedIdent) { + field: &Spanned) { let tcx = fcx.ccx.tcx; check_expr_with_lvalue_pref(fcx, base, lvalue_pref); let expr_t = structurally_resolved_type(fcx, expr.span, @@ -2935,7 +2939,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, ty::TyStruct(base_def, substs) => { debug!("struct named {:?}", base_t); base_def.struct_variant() - .find_field_named(field.node.name) + .find_field_named(field.node) .map(|f| fcx.field_ty(expr.span, f, substs)) } _ => None @@ -2950,7 +2954,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, None => {} } - if method::exists(fcx, field.span, field.node.name, expr_t, expr.id) { + if method::exists(fcx, field.span, field.node, expr_t, expr.id) { fcx.type_error_message( field.span, |actual| { @@ -2983,10 +2987,10 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // displays hints about the closest matches in field names fn suggest_field_names<'tcx>(variant: ty::VariantDef<'tcx>, - field: &hir::SpannedIdent, + field: &Spanned, tcx: &ty::ctxt<'tcx>, skip : Vec) { - let name = field.node.name.as_str(); + let name = field.node.as_str(); // only find fits with at least one matching letter let mut best_dist = name.len(); let mut best = None; @@ -3084,22 +3088,21 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, field: &hir::Field, skip_fields: &[hir::Field]) { fcx.type_error_message( - field.ident.span, + field.name.span, |actual| if let ty::TyEnum(..) = ty.sty { format!("struct variant `{}::{}` has no field named `{}`", - actual, variant.name.as_str(), field.ident.node) + actual, variant.name.as_str(), field.name.node) } else { format!("structure `{}` has no field named `{}`", - actual, field.ident.node) + actual, field.name.node) }, ty, None); // prevent all specified fields from being suggested - let skip_fields = skip_fields.iter().map(|ref x| x.ident.node.name.as_str()); - suggest_field_names(variant, &field.ident, fcx.tcx(), skip_fields.collect()); + let skip_fields = skip_fields.iter().map(|ref x| x.name.node.as_str()); + suggest_field_names(variant, &field.name, fcx.tcx(), skip_fields.collect()); } - fn check_expr_struct_fields<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, adt_ty: Ty<'tcx>, span: Span, @@ -3123,15 +3126,15 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, for field in ast_fields { let expected_field_type; - if let Some(v_field) = remaining_fields.remove(&field.ident.node.name) { + if let Some(v_field) = remaining_fields.remove(&field.name.node) { expected_field_type = fcx.field_ty(field.span, v_field, substs); } else { error_happened = true; expected_field_type = tcx.types.err; - if let Some(_) = variant.find_field_named(field.ident.node.name) { - span_err!(fcx.tcx().sess, field.ident.span, E0062, + if let Some(_) = variant.find_field_named(field.name.node) { + span_err!(fcx.tcx().sess, field.name.span, E0062, "field `{}` specified more than once", - field.ident.node); + field.name.node); } else { report_unknown_field(fcx, adt_ty, variant, field, ast_fields); } @@ -3184,7 +3187,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // Find the relevant variant let def = lookup_full_def(tcx, path.span, expr.id); - let (adt, variant) = match fcx.def_struct_variant(def) { + let (adt, variant) = match fcx.def_struct_variant(def, path.span) { Some((adt, variant)) => (adt, variant), None => { span_err!(fcx.tcx().sess, path.span, E0071, @@ -3215,31 +3218,16 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let tcx = fcx.ccx.tcx; let id = expr.id; match expr.node { - hir::ExprBox(ref opt_place, ref subexpr) => { - opt_place.as_ref().map(|place|check_expr(fcx, &**place)); - check_expr(fcx, &**subexpr); - - let mut checked = false; - opt_place.as_ref().map(|place| match place.node { - hir::ExprPath(None, ref path) => { - // FIXME(pcwalton): For now we hardcode the only permissible - // place: the exchange heap. - let definition = lookup_full_def(tcx, path.span, place.id); - let def_id = definition.def_id(); - let referent_ty = fcx.expr_ty(&**subexpr); - if tcx.lang_items.exchange_heap() == Some(def_id) { - fcx.write_ty(id, tcx.mk_box(referent_ty)); - checked = true - } - } - _ => {} - }); - - if !checked { - span_err!(tcx.sess, expr.span, E0066, - "only the exchange heap is currently supported"); - fcx.write_ty(id, tcx.types.err); - } + hir::ExprBox(ref subexpr) => { + let expected_inner = expected.to_option(fcx).map_or(NoExpectation, |ty| { + match ty.sty { + ty::TyBox(ty) => Expectation::rvalue_hint(tcx, ty), + _ => NoExpectation + } + }); + check_expr_with_expectation(fcx, subexpr, expected_inner); + let referent_ty = fcx.expr_ty(&**subexpr); + fcx.write_ty(id, tcx.mk_box(referent_ty)); } hir::ExprLit(ref lit) => { @@ -3253,24 +3241,14 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, op::check_binop_assign(fcx, expr, op, lhs, rhs); } hir::ExprUnary(unop, ref oprnd) => { - let expected_inner = expected.to_option(fcx).map_or(NoExpectation, |ty| { - match unop { - hir::UnUniq => match ty.sty { - ty::TyBox(ty) => { - Expectation::rvalue_hint(tcx, ty) - } - _ => { - NoExpectation - } - }, - hir::UnNot | hir::UnNeg => { - expected - } - hir::UnDeref => { - NoExpectation - } + let expected_inner = match unop { + hir::UnNot | hir::UnNeg => { + expected } - }); + hir::UnDeref => { + NoExpectation + } + }; let lvalue_pref = match unop { hir::UnDeref => lvalue_pref, _ => NoPreference @@ -3281,9 +3259,6 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, if !oprnd_t.references_error() { match unop { - hir::UnUniq => { - oprnd_t = tcx.mk_box(oprnd_t); - } hir::UnDeref => { oprnd_t = structurally_resolved_type(fcx, expr.span, oprnd_t); oprnd_t = match oprnd_t.builtin_deref(true, NoPreference) { @@ -3378,7 +3353,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } else if let Some(hir::QSelf { position: 0, .. }) = *maybe_qself { // Create some fake resolution that can't possibly be a type. def::PathResolution { - base_def: def::DefMod(DefId::local(ast::CRATE_NODE_ID)), + base_def: def::DefMod(tcx.map.local_def_id(ast::CRATE_NODE_ID)), last_private: LastMod(AllPublic), depth: path.segments.len() } @@ -3446,13 +3421,6 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } fcx.write_ty(id, fcx.infcx().next_diverging_ty_var()); } - hir::ExprParen(ref a) => { - check_expr_with_expectation_and_lvalue_pref(fcx, - &**a, - expected, - lvalue_pref); - fcx.write_ty(id, fcx.expr_ty(&**a)); - } hir::ExprAssign(ref lhs, ref rhs) => { check_expr_with_lvalue_pref(fcx, &**lhs, PreferMutLvalue); @@ -3515,8 +3483,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let ret_ty = fcx.expr_ty(expr); fcx.register_wf_obligation(ret_ty, expr.span, traits::MiscObligation); } - hir::ExprMethodCall(ident, ref tps, ref args) => { - check_method_call(fcx, expr, ident, &args[..], &tps[..], expected, lvalue_pref); + hir::ExprMethodCall(name, ref tps, ref args) => { + check_method_call(fcx, expr, name, &args[..], &tps[..], expected, lvalue_pref); let arg_tys = args.iter().map(|a| fcx.expr_ty(&**a)); let args_err = arg_tys.fold(false, |rest_err, a| rest_err || a.references_error()); if args_err { @@ -4137,7 +4105,7 @@ fn check_const<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, let inh = static_inherited_fields(ccx, &tables); let rty = ccx.tcx.node_id_to_type(id); let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(rty), e.id); - let declty = fcx.ccx.tcx.lookup_item_type(DefId::local(id)).ty; + let declty = fcx.ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(id)).ty; check_const_with_ty(&fcx, sp, e, declty); } @@ -4148,7 +4116,7 @@ fn check_const_with_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Gather locals in statics (because of block expressions). // This is technically unnecessary because locals in static items are forbidden, // but prevents type checking from blowing up before const checking can properly - // emit a error. + // emit an error. GatherLocalsVisitor { fcx: fcx }.visit_expr(e); check_expr_with_hint(fcx, e, declty); @@ -4226,22 +4194,22 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, fn disr_in_range(ccx: &CrateCtxt, ty: attr::IntType, disr: ty::Disr) -> bool { - fn uint_in_range(ccx: &CrateCtxt, ty: hir::UintTy, disr: ty::Disr) -> bool { + fn uint_in_range(ccx: &CrateCtxt, ty: ast::UintTy, disr: ty::Disr) -> bool { match ty { - hir::TyU8 => disr as u8 as Disr == disr, - hir::TyU16 => disr as u16 as Disr == disr, - hir::TyU32 => disr as u32 as Disr == disr, - hir::TyU64 => disr as u64 as Disr == disr, - hir::TyUs => uint_in_range(ccx, ccx.tcx.sess.target.uint_type, disr) + ast::TyU8 => disr as u8 as Disr == disr, + ast::TyU16 => disr as u16 as Disr == disr, + ast::TyU32 => disr as u32 as Disr == disr, + ast::TyU64 => disr as u64 as Disr == disr, + ast::TyUs => uint_in_range(ccx, ccx.tcx.sess.target.uint_type, disr) } } - fn int_in_range(ccx: &CrateCtxt, ty: hir::IntTy, disr: ty::Disr) -> bool { + fn int_in_range(ccx: &CrateCtxt, ty: ast::IntTy, disr: ty::Disr) -> bool { match ty { - hir::TyI8 => disr as i8 as Disr == disr, - hir::TyI16 => disr as i16 as Disr == disr, - hir::TyI32 => disr as i32 as Disr == disr, - hir::TyI64 => disr as i64 as Disr == disr, - hir::TyIs => int_in_range(ccx, ccx.tcx.sess.target.int_type, disr) + ast::TyI8 => disr as i8 as Disr == disr, + ast::TyI16 => disr as i16 as Disr == disr, + ast::TyI32 => disr as i32 as Disr == disr, + ast::TyI64 => disr as i64 as Disr == disr, + ast::TyIs => int_in_range(ccx, ccx.tcx.sess.target.int_type, disr) } } match ty { @@ -4270,7 +4238,7 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, } } - let def_id = DefId::local(id); + let def_id = ccx.tcx.map.local_def_id(id); let variants = &ccx.tcx.lookup_adt_def(def_id).variants; for (v, variant) in vs.iter().zip(variants.iter()) { @@ -4281,7 +4249,8 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, Some(i) => { span_err!(ccx.tcx.sess, v.span, E0081, "discriminant value `{}` already exists", disr_vals[i]); - span_note!(ccx.tcx.sess, ccx.tcx.map.span(variants[i].did.node), + let variant_i_node_id = ccx.tcx.map.as_local_node_id(variants[i].did).unwrap(); + span_note!(ccx.tcx.sess, ccx.tcx.map.span(variant_i_node_id), "conflicting discriminant here") } None => {} @@ -4308,8 +4277,8 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, } } - let hint = *ccx.tcx.lookup_repr_hints(DefId { krate: LOCAL_CRATE, node: id }) - .get(0).unwrap_or(&attr::ReprAny); + let def_id = ccx.tcx.map.local_def_id(id); + let hint = *ccx.tcx.lookup_repr_hints(def_id).get(0).unwrap_or(&attr::ReprAny); if hint != attr::ReprAny && vs.len() <= 1 { if vs.len() == 1 { @@ -4332,7 +4301,7 @@ fn type_scheme_and_predicates_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, defn: def::Def) -> (TypeScheme<'tcx>, GenericPredicates<'tcx>) { match defn { - def::DefLocal(nid) | def::DefUpvar(nid, _, _) => { + def::DefLocal(_, nid) | def::DefUpvar(_, nid, _, _) => { let typ = fcx.local_ty(sp, nid); (ty::TypeScheme { generics: ty::Generics::empty(), ty: typ }, ty::GenericPredicates::empty()) @@ -4350,7 +4319,6 @@ fn type_scheme_and_predicates_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, def::DefMod(..) | def::DefForeignMod(..) | def::DefUse(..) | - def::DefRegion(..) | def::DefLabel(..) | def::DefSelfTy(..) => { fcx.ccx.tcx.sess.span_bug(sp, &format!("expected value, found {:?}", defn)); @@ -4402,7 +4370,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // parameters permitted at present, but perhaps we will allow // them in the future.) // - // 1b. Reference to a enum variant or tuple-like struct: + // 1b. Reference to an enum variant or tuple-like struct: // // struct foo(...) // enum E { foo(...) } @@ -4521,7 +4489,6 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, def::DefForeignMod(..) | def::DefLocal(..) | def::DefUse(..) | - def::DefRegion(..) | def::DefLabel(..) | def::DefUpvar(..) => { segment_spaces = vec![None; segments.len()]; @@ -4953,7 +4920,7 @@ pub fn check_bounds_are_used<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, if !*b { span_err!(ccx.tcx.sess, span, E0091, "type parameter `{}` is unused", - tps[i].ident); + tps[i].name); } } } diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 07754e8506..0c65f68f02 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -17,10 +17,8 @@ use super::{ demand, method, FnCtxt, - structurally_resolved_type, }; use middle::def_id::DefId; -use middle::traits; use middle::ty::{Ty, HasTypeFlags, PreferMutLvalue}; use syntax::ast; use syntax::parse::token; @@ -34,34 +32,24 @@ pub fn check_binop_assign<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, lhs_expr: &'tcx hir::Expr, rhs_expr: &'tcx hir::Expr) { - let tcx = fcx.ccx.tcx; - check_expr_with_lvalue_pref(fcx, lhs_expr, PreferMutLvalue); - check_expr(fcx, rhs_expr); - let lhs_ty = structurally_resolved_type(fcx, lhs_expr.span, fcx.expr_ty(lhs_expr)); - let rhs_ty = structurally_resolved_type(fcx, rhs_expr.span, fcx.expr_ty(rhs_expr)); + let lhs_ty = fcx.resolve_type_vars_if_possible(fcx.expr_ty(lhs_expr)); + let (rhs_ty, return_ty) = + check_overloaded_binop(fcx, expr, lhs_expr, lhs_ty, rhs_expr, op, IsAssign::Yes); + let rhs_ty = fcx.resolve_type_vars_if_possible(rhs_ty); - if is_builtin_binop(lhs_ty, rhs_ty, op) { + if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && is_builtin_binop(lhs_ty, rhs_ty, op) { enforce_builtin_binop_types(fcx, lhs_expr, lhs_ty, rhs_expr, rhs_ty, op); fcx.write_nil(expr.id); } else { - // error types are considered "builtin" - assert!(!lhs_ty.references_error() || !rhs_ty.references_error()); - span_err!(tcx.sess, lhs_expr.span, E0368, - "binary assignment operation `{}=` cannot be applied to types `{}` and `{}`", - hir_util::binop_to_string(op.node), - lhs_ty, - rhs_ty); - fcx.write_error(expr.id); + fcx.write_ty(expr.id, return_ty); } let tcx = fcx.tcx(); if !tcx.expr_is_lval(lhs_expr) { span_err!(tcx.sess, lhs_expr.span, E0067, "invalid left-hand side expression"); } - - fcx.require_expr_have_sized_type(lhs_expr, traits::AssignmentLhsSized); } /// Check a potentially overloaded binary operator. @@ -95,7 +83,7 @@ pub fn check_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // overloaded. This is the way to be most flexible w/r/t // types that get inferred. let (rhs_ty, return_ty) = - check_overloaded_binop(fcx, expr, lhs_expr, lhs_ty, rhs_expr, op); + check_overloaded_binop(fcx, expr, lhs_expr, lhs_ty, rhs_expr, op, IsAssign::No); // Supply type inference hints if relevant. Probably these // hints should be enforced during select as part of the @@ -167,14 +155,16 @@ fn check_overloaded_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, lhs_expr: &'tcx hir::Expr, lhs_ty: Ty<'tcx>, rhs_expr: &'tcx hir::Expr, - op: hir::BinOp) + op: hir::BinOp, + is_assign: IsAssign) -> (Ty<'tcx>, Ty<'tcx>) { - debug!("check_overloaded_binop(expr.id={}, lhs_ty={:?})", + debug!("check_overloaded_binop(expr.id={}, lhs_ty={:?}, is_assign={:?})", expr.id, - lhs_ty); + lhs_ty, + is_assign); - let (name, trait_def_id) = name_and_trait_def_id(fcx, op); + let (name, trait_def_id) = name_and_trait_def_id(fcx, op, is_assign); // NB: As we have not yet type-checked the RHS, we don't have the // type at hand. Make a variable to represent it. The whole reason @@ -191,10 +181,38 @@ fn check_overloaded_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, Err(()) => { // error types are considered "builtin" if !lhs_ty.references_error() { - span_err!(fcx.tcx().sess, lhs_expr.span, E0369, - "binary operation `{}` cannot be applied to type `{}`", - hir_util::binop_to_string(op.node), - lhs_ty); + if let IsAssign::Yes = is_assign { + span_err!(fcx.tcx().sess, lhs_expr.span, E0368, + "binary assignment operation `{}=` cannot be applied to type `{}`", + hir_util::binop_to_string(op.node), + lhs_ty); + } else { + span_err!(fcx.tcx().sess, lhs_expr.span, E0369, + "binary operation `{}` cannot be applied to type `{}`", + hir_util::binop_to_string(op.node), + lhs_ty); + let missing_trait = match op.node { + hir::BiAdd => Some("std::ops::Add"), + hir::BiSub => Some("std::ops::Sub"), + hir::BiMul => Some("std::ops::Mul"), + hir::BiDiv => Some("std::ops::Div"), + hir::BiRem => Some("std::ops::Rem"), + hir::BiBitAnd => Some("std::ops::BitAnd"), + hir::BiBitOr => Some("std::ops::BitOr"), + hir::BiShl => Some("std::ops::Shl"), + hir::BiShr => Some("std::ops::Shr"), + hir::BiEq | hir::BiNe => Some("std::cmp::PartialEq"), + hir::BiLt | hir::BiLe | hir::BiGt | hir::BiGe => + Some("std::cmp::PartialOrd"), + _ => None + }; + + if let Some(missing_trait) = missing_trait { + span_note!(fcx.tcx().sess, lhs_expr.span, + "an implementation of `{}` might be missing for `{}`", + missing_trait, lhs_ty); + } + } } fcx.tcx().types.err } @@ -231,27 +249,51 @@ pub fn check_user_unop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } } -fn name_and_trait_def_id(fcx: &FnCtxt, op: hir::BinOp) -> (&'static str, Option) { +fn name_and_trait_def_id(fcx: &FnCtxt, + op: hir::BinOp, + is_assign: IsAssign) + -> (&'static str, Option) { let lang = &fcx.tcx().lang_items; - match op.node { - hir::BiAdd => ("add", lang.add_trait()), - hir::BiSub => ("sub", lang.sub_trait()), - hir::BiMul => ("mul", lang.mul_trait()), - hir::BiDiv => ("div", lang.div_trait()), - hir::BiRem => ("rem", lang.rem_trait()), - hir::BiBitXor => ("bitxor", lang.bitxor_trait()), - hir::BiBitAnd => ("bitand", lang.bitand_trait()), - hir::BiBitOr => ("bitor", lang.bitor_trait()), - hir::BiShl => ("shl", lang.shl_trait()), - hir::BiShr => ("shr", lang.shr_trait()), - hir::BiLt => ("lt", lang.ord_trait()), - hir::BiLe => ("le", lang.ord_trait()), - hir::BiGe => ("ge", lang.ord_trait()), - hir::BiGt => ("gt", lang.ord_trait()), - hir::BiEq => ("eq", lang.eq_trait()), - hir::BiNe => ("ne", lang.eq_trait()), - hir::BiAnd | hir::BiOr => { - fcx.tcx().sess.span_bug(op.span, "&& and || are not overloadable") + + if let IsAssign::Yes = is_assign { + match op.node { + hir::BiAdd => ("add_assign", lang.add_assign_trait()), + hir::BiSub => ("sub_assign", lang.sub_assign_trait()), + hir::BiMul => ("mul_assign", lang.mul_assign_trait()), + hir::BiDiv => ("div_assign", lang.div_assign_trait()), + hir::BiRem => ("rem_assign", lang.rem_assign_trait()), + hir::BiBitXor => ("bitxor_assign", lang.bitxor_assign_trait()), + hir::BiBitAnd => ("bitand_assign", lang.bitand_assign_trait()), + hir::BiBitOr => ("bitor_assign", lang.bitor_assign_trait()), + hir::BiShl => ("shl_assign", lang.shl_assign_trait()), + hir::BiShr => ("shr_assign", lang.shr_assign_trait()), + hir::BiLt | hir::BiLe | hir::BiGe | hir::BiGt | hir::BiEq | hir::BiNe | hir::BiAnd | + hir::BiOr => { + fcx.tcx().sess.span_bug(op.span, &format!("impossible assignment operation: {}=", + hir_util::binop_to_string(op.node))) + } + } + } else { + match op.node { + hir::BiAdd => ("add", lang.add_trait()), + hir::BiSub => ("sub", lang.sub_trait()), + hir::BiMul => ("mul", lang.mul_trait()), + hir::BiDiv => ("div", lang.div_trait()), + hir::BiRem => ("rem", lang.rem_trait()), + hir::BiBitXor => ("bitxor", lang.bitxor_trait()), + hir::BiBitAnd => ("bitand", lang.bitand_trait()), + hir::BiBitOr => ("bitor", lang.bitor_trait()), + hir::BiShl => ("shl", lang.shl_trait()), + hir::BiShr => ("shr", lang.shr_trait()), + hir::BiLt => ("lt", lang.ord_trait()), + hir::BiLe => ("le", lang.ord_trait()), + hir::BiGe => ("ge", lang.ord_trait()), + hir::BiGt => ("gt", lang.ord_trait()), + hir::BiEq => ("eq", lang.eq_trait()), + hir::BiNe => ("ne", lang.eq_trait()), + hir::BiAnd | hir::BiOr => { + fcx.tcx().sess.span_bug(op.span, "&& and || are not overloadable") + } } } } @@ -362,6 +404,13 @@ impl BinOpCategory { } } +/// Whether the binary operation is an assignment (`a += b`), or not (`a + b`) +#[derive(Clone, Copy, Debug)] +enum IsAssign { + No, + Yes, +} + /// Returns true if this is a built-in arithmetic operation (e.g. u32 /// + u32, i16x4 == i16x4) and false if these types would have to be /// overloaded to be legal. There are two reasons that we distinguish diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 155caaa8cb..7c6417e61d 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -77,7 +77,7 @@ //! borrowed pointer? I mean any data that is reached by first //! dereferencing a borrowed pointer and then either traversing //! interior offsets or boxes. We say that the guarantor -//! of such data it the region of the borrowed pointer that was +//! of such data is the region of the borrowed pointer that was //! traversed. This is essentially the same as the ownership //! relation, except that a borrowed pointer never owns its //! contents. @@ -592,6 +592,8 @@ fn visit_expr(rcx: &mut Rcx, expr: &hir::Expr) { }; substs_wf_in_scope(rcx, origin, &callee.substs, expr.span, expr_region); + type_must_outlive(rcx, infer::ExprTypeIsNotInScope(callee.ty, expr.span), + callee.ty, expr_region); } // Check any autoderefs or autorefs that appear. @@ -664,6 +666,8 @@ fn visit_expr(rcx: &mut Rcx, expr: &hir::Expr) { } } + debug!("regionck::visit_expr(e={:?}, repeating_scope={}) - visiting subexprs", + expr, rcx.repeating_scope); match expr.node { hir::ExprPath(..) => { rcx.fcx.opt_node_ty_substs(expr.id, |item_substs| { @@ -695,7 +699,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &hir::Expr) { hir::ExprAssignOp(_, ref lhs, ref rhs) => { if has_method_map { constrain_call(rcx, expr, Some(&**lhs), - Some(&**rhs).into_iter(), true); + Some(&**rhs).into_iter(), false); } visit::walk_expr(rcx, expr); @@ -1178,9 +1182,10 @@ fn link_fn_args(rcx: &Rcx, body_scope: CodeExtent, args: &[hir::Arg]) { let arg_ty = rcx.fcx.node_ty(arg.id); let re_scope = ty::ReScope(body_scope); let arg_cmt = mc.cat_rvalue(arg.id, arg.ty.span, re_scope, arg_ty); - debug!("arg_ty={:?} arg_cmt={:?}", + debug!("arg_ty={:?} arg_cmt={:?} arg={:?}", arg_ty, - arg_cmt); + arg_cmt, + arg); link_pattern(rcx, mc, arg_cmt, &*arg.pat); } } @@ -1523,9 +1528,10 @@ pub fn type_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, { let ty = rcx.resolve_type(ty); - debug!("type_must_outlive(ty={:?}, region={:?})", + debug!("type_must_outlive(ty={:?}, region={:?}, origin={:?})", ty, - region); + region, + origin); assert!(!ty.has_escaping_regions()); diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 10d7c4620e..78d493c8a7 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -43,7 +43,6 @@ use super::FnCtxt; use check::demand; -use middle::def_id::DefId; use middle::expr_use_visitor as euv; use middle::mem_categorization as mc; use middle::ty::{self, Ty}; @@ -130,7 +129,7 @@ impl<'a,'tcx> SeedBorrowKind<'a,'tcx> { capture_clause: hir::CaptureClause, _body: &hir::Block) { - let closure_def_id = DefId::local(expr.id); + let closure_def_id = self.tcx().map.local_def_id(expr.id); if !self.fcx.inh.tables.borrow().closure_kinds.contains_key(&closure_def_id) { self.closures_with_inferred_kinds.insert(expr.id); self.fcx.inh.tables.borrow_mut().closure_kinds @@ -141,7 +140,7 @@ impl<'a,'tcx> SeedBorrowKind<'a,'tcx> { self.tcx().with_freevars(expr.id, |freevars| { for freevar in freevars { - let var_node_id = freevar.def.local_node_id(); + let var_node_id = freevar.def.var_id(); let upvar_id = ty::UpvarId { var_id: var_node_id, closure_expr_id: expr.id }; debug!("seed upvar_id {:?}", upvar_id); @@ -229,7 +228,7 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> { // Now we must process and remove any deferred resolutions, // since we have a concrete closure kind. - let closure_def_id = DefId::local(id); + let closure_def_id = self.fcx.tcx().map.local_def_id(id); if self.closures_with_inferred_kinds.contains(&id) { let mut deferred_call_resolutions = self.fcx.remove_deferred_call_resolutions(closure_def_id); @@ -250,16 +249,16 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> { tcx.with_freevars(closure_id, |freevars| { freevars.iter() .map(|freevar| { - let freevar_def_id = freevar.def.def_id(); - let freevar_ty = self.fcx.node_ty(freevar_def_id.node); + let freevar_node_id = freevar.def.var_id(); + let freevar_ty = self.fcx.node_ty(freevar_node_id); let upvar_id = ty::UpvarId { - var_id: freevar_def_id.node, + var_id: freevar_node_id, closure_expr_id: closure_id }; let capture = self.fcx.infcx().upvar_capture(upvar_id).unwrap(); - debug!("freevar_def_id={:?} freevar_ty={:?} capture={:?}", - freevar_def_id, freevar_ty, capture); + debug!("freevar_node_id={:?} freevar_ty={:?} capture={:?}", + freevar_node_id, freevar_ty, capture); match capture { ty::UpvarCapture::ByValue => freevar_ty, @@ -483,7 +482,7 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> { return; } - let closure_def_id = DefId::local(closure_id); + let closure_def_id = self.fcx.tcx().map.local_def_id(closure_id); let closure_kinds = &mut self.fcx.inh.tables.borrow_mut().closure_kinds; let existing_kind = *closure_kinds.get(&closure_def_id).unwrap(); diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index 2c931e7830..e41b4de7ba 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -12,7 +12,6 @@ use astconv::AstConv; use check::{FnCtxt, Inherited, blank_fn_ctxt, regionck, wfcheck}; use constrained_type_params::{identify_constrained_type_params, Parameter}; use CrateCtxt; -use middle::def_id::DefId; use middle::region; use middle::subst::{self, TypeSpace, FnSpace, ParamSpace, SelfSpace}; use middle::traits; @@ -55,9 +54,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { /// the types first. fn check_item_well_formed(&mut self, item: &hir::Item) { let ccx = self.ccx; - debug!("check_item_well_formed(it.id={}, it.ident={})", + debug!("check_item_well_formed(it.id={}, it.name={})", item.id, - ccx.tcx.item_path_str(DefId::local(item.id))); + ccx.tcx.item_path_str(ccx.tcx.map.local_def_id(item.id))); match item.node { /// Right now we check that every default trait implementation @@ -81,7 +80,8 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { self.check_impl(item); } hir::ItemImpl(_, hir::ImplPolarity::Negative, _, Some(_), _, _) => { - let trait_ref = ccx.tcx.impl_trait_ref(DefId::local(item.id)).unwrap(); + let item_def_id = ccx.tcx.map.local_def_id(item.id); + let trait_ref = ccx.tcx.impl_trait_ref(item_def_id).unwrap(); ccx.tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id); match ccx.tcx.lang_items.to_builtin_kind(trait_ref.def_id) { Some(ty::BoundSend) | Some(ty::BoundSync) => {} @@ -103,7 +103,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { } hir::ItemStruct(ref struct_def, ref ast_generics) => { self.check_type_defn(item, |fcx| { - vec![struct_variant(fcx, &**struct_def)] + vec![struct_variant(fcx, struct_def)] }); self.check_variances_for_type_defn(item, ast_generics); @@ -117,9 +117,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { } hir::ItemTrait(_, _, _, ref items) => { let trait_predicates = - ccx.tcx.lookup_predicates(DefId::local(item.id)); + ccx.tcx.lookup_predicates(ccx.tcx.map.local_def_id(item.id)); reject_non_type_param_bounds(ccx.tcx, item.span, &trait_predicates); - if ccx.tcx.trait_has_default_impl(DefId::local(item.id)) { + if ccx.tcx.trait_has_default_impl(ccx.tcx.map.local_def_id(item.id)) { if !items.is_empty() { wfcheck::error_380(ccx, item.span); } @@ -133,7 +133,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { F: for<'fcx> FnMut(&mut CheckTypeWellFormedVisitor<'ccx, 'tcx>, &FnCtxt<'fcx, 'tcx>), { let ccx = self.ccx; - let item_def_id = DefId::local(item.id); + let item_def_id = ccx.tcx.map.local_def_id(item.id); let type_scheme = ccx.tcx.lookup_item_type(item_def_id); let type_predicates = ccx.tcx.lookup_predicates(item_def_id); reject_non_type_param_bounds(ccx.tcx, item.span, &type_predicates); @@ -194,7 +194,8 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { Some(&mut this.cache)); debug!("check_item_type at bounds_checker.scope: {:?}", bounds_checker.scope); - let type_scheme = fcx.tcx().lookup_item_type(DefId::local(item.id)); + let item_def_id = fcx.tcx().map.local_def_id(item.id); + let type_scheme = fcx.tcx().lookup_item_type(item_def_id); let item_ty = fcx.instantiate_type_scheme(item.span, &fcx.inh .infcx @@ -230,7 +231,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { // Similarly, obtain an "inside" reference to the trait // that the impl implements. - let trait_ref = match fcx.tcx().impl_trait_ref(DefId::local(item.id)) { + let trait_ref = match fcx.tcx().impl_trait_ref(fcx.tcx().map.local_def_id(item.id)) { None => { return; } Some(t) => { t } }; @@ -279,7 +280,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { item: &hir::Item, ast_generics: &hir::Generics) { - let item_def_id = DefId::local(item.id); + let item_def_id = self.tcx().map.local_def_id(item.id); let ty_predicates = self.tcx().lookup_predicates(item_def_id); let variances = self.tcx().item_variances(item_def_id); @@ -324,7 +325,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { -> ty::ParamTy { let name = match space { - TypeSpace => ast_generics.ty_params[index].ident.name, + TypeSpace => ast_generics.ty_params[index].name, SelfSpace => special_idents::type_self.name, FnSpace => self.tcx().sess.bug("Fn space occupied?"), }; @@ -431,7 +432,7 @@ impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> { match fk { FnKind::Closure | FnKind::ItemFn(..) => {} FnKind::Method(..) => { - match self.tcx().impl_or_trait_item(DefId::local(id)) { + match self.tcx().impl_or_trait_item(self.tcx().map.local_def_id(id)) { ty::ImplOrTraitItem::MethodTraitItem(ty_method) => { reject_shadowing_type_parameters(self.tcx(), span, &ty_method.generics) } @@ -444,7 +445,7 @@ impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> { fn visit_trait_item(&mut self, trait_item: &'v hir::TraitItem) { if let hir::MethodTraitItem(_, None) = trait_item.node { - match self.tcx().impl_or_trait_item(DefId::local(trait_item.id)) { + match self.tcx().impl_or_trait_item(self.tcx().map.local_def_id(trait_item.id)) { ty::ImplOrTraitItem::MethodTraitItem(ty_method) => { reject_non_type_param_bounds( self.tcx(), @@ -623,11 +624,10 @@ struct AdtField<'tcx> { } fn struct_variant<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - struct_def: &hir::StructDef) + struct_def: &hir::VariantData) -> AdtVariant<'tcx> { let fields = - struct_def.fields - .iter() + struct_def.fields().iter() .map(|field| { let field_ty = fcx.tcx().node_id_to_type(field.node.id); let field_ty = fcx.instantiate_type_scheme(field.span, @@ -646,41 +646,7 @@ fn enum_variants<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, enum_def: &hir::EnumDef) -> Vec> { enum_def.variants.iter() - .map(|variant| { - match variant.node.kind { - hir::TupleVariantKind(ref args) if !args.is_empty() => { - let ctor_ty = fcx.tcx().node_id_to_type(variant.node.id); - - // the regions in the argument types come from the - // enum def'n, and hence will all be early bound - let arg_tys = fcx.tcx().no_late_bound_regions(&ctor_ty.fn_args()).unwrap(); - AdtVariant { - fields: args.iter().enumerate().map(|(index, arg)| { - let arg_ty = arg_tys[index]; - let arg_ty = - fcx.instantiate_type_scheme(variant.span, - &fcx.inh - .infcx - .parameter_environment - .free_substs, - &arg_ty); - AdtField { - ty: arg_ty, - span: arg.ty.span - } - }).collect() - } - } - hir::TupleVariantKind(_) => { - AdtVariant { - fields: Vec::new() - } - } - hir::StructVariantKind(ref struct_def) => { - struct_variant(fcx, &**struct_def) - } - } - }) + .map(|variant| struct_variant(fcx, &variant.node.data)) .collect() } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 06dd80c57a..ab091472d2 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -61,9 +61,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { /// the types first. fn check_item_well_formed(&mut self, item: &hir::Item) { let ccx = self.ccx; - debug!("check_item_well_formed(it.id={}, it.ident={})", + debug!("check_item_well_formed(it.id={}, it.name={})", item.id, - ccx.tcx.item_path_str(DefId::local(item.id))); + ccx.tcx.item_path_str(ccx.tcx.map.local_def_id(item.id))); match item.node { /// Right now we check that every default trait implementation @@ -90,7 +90,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { hir::ItemImpl(_, hir::ImplPolarity::Negative, _, Some(_), _, _) => { // FIXME(#27579) what amount of WF checking do we need for neg impls? - let trait_ref = ccx.tcx.impl_trait_ref(DefId::local(item.id)).unwrap(); + let trait_ref = ccx.tcx.impl_trait_ref(ccx.tcx.map.local_def_id(item.id)).unwrap(); ccx.tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id); match ccx.tcx.lang_items.to_builtin_kind(trait_ref.def_id) { Some(ty::BoundSend) | Some(ty::BoundSync) => {} @@ -112,7 +112,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { } hir::ItemStruct(ref struct_def, ref ast_generics) => { self.check_type_defn(item, |fcx| { - vec![struct_variant(fcx, &**struct_def)] + vec![struct_variant(fcx, struct_def)] }); self.check_variances_for_type_defn(item, ast_generics); @@ -137,7 +137,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { let free_substs = &fcx.inh.infcx.parameter_environment.free_substs; let free_id = fcx.inh.infcx.parameter_environment.free_id; - let item = fcx.tcx().impl_or_trait_item(DefId::local(item_id)); + let item = fcx.tcx().impl_or_trait_item(fcx.tcx().map.local_def_id(item_id)); let mut implied_bounds = match item.container() { ty::TraitContainer(_) => vec![], @@ -216,7 +216,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { } let free_substs = &fcx.inh.infcx.parameter_environment.free_substs; - let predicates = fcx.tcx().lookup_predicates(DefId::local(item.id)); + let predicates = fcx.tcx().lookup_predicates(fcx.tcx().map.local_def_id(item.id)); let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates); this.check_where_clauses(fcx, item.span, &predicates); @@ -228,7 +228,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { item: &hir::Item, items: &[P]) { - let trait_def_id = DefId::local(item.id); + let trait_def_id = self.tcx().map.local_def_id(item.id); if self.ccx.tcx.trait_has_default_impl(trait_def_id) { if !items.is_empty() { @@ -251,7 +251,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { { self.with_item_fcx(item, |fcx, this| { let free_substs = &fcx.inh.infcx.parameter_environment.free_substs; - let type_scheme = fcx.tcx().lookup_item_type(DefId::local(item.id)); + let type_scheme = fcx.tcx().lookup_item_type(fcx.tcx().map.local_def_id(item.id)); let item_ty = fcx.instantiate_type_scheme(item.span, free_substs, &type_scheme.ty); let bare_fn_ty = match item_ty.sty { ty::TyBareFn(_, ref bare_fn_ty) => bare_fn_ty, @@ -260,7 +260,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { } }; - let predicates = fcx.tcx().lookup_predicates(DefId::local(item.id)); + let predicates = fcx.tcx().lookup_predicates(fcx.tcx().map.local_def_id(item.id)); let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates); let mut implied_bounds = vec![]; @@ -276,7 +276,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { debug!("check_item_type: {:?}", item); self.with_item_fcx(item, |fcx, this| { - let type_scheme = fcx.tcx().lookup_item_type(DefId::local(item.id)); + let type_scheme = fcx.tcx().lookup_item_type(fcx.tcx().map.local_def_id(item.id)); let item_ty = fcx.instantiate_type_scheme(item.span, &fcx.inh .infcx @@ -299,7 +299,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { self.with_item_fcx(item, |fcx, this| { let free_substs = &fcx.inh.infcx.parameter_environment.free_substs; - let item_def_id = DefId::local(item.id); + let item_def_id = fcx.tcx().map.local_def_id(item.id); match *ast_trait_ref { Some(ref ast_trait_ref) => { @@ -328,7 +328,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates); this.check_where_clauses(fcx, item.span, &predicates); - impl_implied_bounds(fcx, DefId::local(item.id), item.span) + impl_implied_bounds(fcx, fcx.tcx().map.local_def_id(item.id), item.span) }); } @@ -386,7 +386,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { item: &hir::Item, ast_generics: &hir::Generics) { - let item_def_id = DefId::local(item.id); + let item_def_id = self.tcx().map.local_def_id(item.id); let ty_predicates = self.tcx().lookup_predicates(item_def_id); let variances = self.tcx().item_variances(item_def_id); @@ -431,7 +431,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { -> ty::ParamTy { let name = match space { - TypeSpace => ast_generics.ty_params[index].ident.name, + TypeSpace => ast_generics.ty_params[index].name, SelfSpace => special_idents::type_self.name, FnSpace => self.tcx().sess.bug("Fn space occupied?"), }; @@ -521,11 +521,10 @@ struct AdtField<'tcx> { } fn struct_variant<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - struct_def: &hir::StructDef) + struct_def: &hir::VariantData) -> AdtVariant<'tcx> { let fields = - struct_def.fields - .iter() + struct_def.fields().iter() .map(|field| { let field_ty = fcx.tcx().node_id_to_type(field.node.id); let field_ty = fcx.instantiate_type_scheme(field.span, @@ -544,41 +543,7 @@ fn enum_variants<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, enum_def: &hir::EnumDef) -> Vec> { enum_def.variants.iter() - .map(|variant| { - match variant.node.kind { - hir::TupleVariantKind(ref args) if !args.is_empty() => { - let ctor_ty = fcx.tcx().node_id_to_type(variant.node.id); - - // the regions in the argument types come from the - // enum def'n, and hence will all be early bound - let arg_tys = fcx.tcx().no_late_bound_regions(&ctor_ty.fn_args()).unwrap(); - AdtVariant { - fields: args.iter().enumerate().map(|(index, arg)| { - let arg_ty = arg_tys[index]; - let arg_ty = - fcx.instantiate_type_scheme(variant.span, - &fcx.inh - .infcx - .parameter_environment - .free_substs, - &arg_ty); - AdtField { - ty: arg_ty, - span: arg.ty.span - } - }).collect() - } - } - hir::TupleVariantKind(_) => { - AdtVariant { - fields: Vec::new() - } - } - hir::StructVariantKind(ref struct_def) => { - struct_variant(fcx, &**struct_def) - } - } - }) + .map(|variant| struct_variant(fcx, &variant.node.data)) .collect() } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 6f8e064c9d..2c18a24515 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -17,7 +17,7 @@ use astconv::AstConv; use check::FnCtxt; use middle::def_id::DefId; use middle::pat_util; -use middle::ty::{self, Ty, MethodCall, MethodCallee}; +use middle::ty::{self, Ty, MethodCall, MethodCallee, HasTypeFlags}; use middle::ty::adjustment; use middle::ty::fold::{TypeFolder,TypeFoldable}; use middle::infer; @@ -91,24 +91,53 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { // we observe that something like `a+b` is (known to be) // operating on scalars, we clear the overload. fn fix_scalar_binary_expr(&mut self, e: &hir::Expr) { - if let hir::ExprBinary(ref op, ref lhs, ref rhs) = e.node { - let lhs_ty = self.fcx.node_ty(lhs.id); - let lhs_ty = self.fcx.infcx().resolve_type_vars_if_possible(&lhs_ty); - - let rhs_ty = self.fcx.node_ty(rhs.id); - let rhs_ty = self.fcx.infcx().resolve_type_vars_if_possible(&rhs_ty); - - if lhs_ty.is_scalar() && rhs_ty.is_scalar() { - self.fcx.inh.tables.borrow_mut().method_map.remove(&MethodCall::expr(e.id)); - - // weird but true: the by-ref binops put an - // adjustment on the lhs but not the rhs; the - // adjustment for rhs is kind of baked into the - // system. - if !hir_util::is_by_value_binop(op.node) { - self.fcx.inh.tables.borrow_mut().adjustments.remove(&lhs.id); + match e.node { + hir::ExprBinary(ref op, ref lhs, ref rhs) | + hir::ExprAssignOp(ref op, ref lhs, ref rhs) => { + let lhs_ty = self.fcx.node_ty(lhs.id); + let lhs_ty = self.fcx.infcx().resolve_type_vars_if_possible(&lhs_ty); + + let rhs_ty = self.fcx.node_ty(rhs.id); + let rhs_ty = self.fcx.infcx().resolve_type_vars_if_possible(&rhs_ty); + + if lhs_ty.is_scalar() && rhs_ty.is_scalar() { + self.fcx.inh.tables.borrow_mut().method_map.remove(&MethodCall::expr(e.id)); + + // weird but true: the by-ref binops put an + // adjustment on the lhs but not the rhs; the + // adjustment for rhs is kind of baked into the + // system. + match e.node { + hir::ExprBinary(..) => { + if !hir_util::is_by_value_binop(op.node) { + self.fcx.inh.tables.borrow_mut().adjustments.remove(&lhs.id); + } + }, + hir::ExprAssignOp(..) => { + self.fcx.inh.tables.borrow_mut().adjustments.remove(&lhs.id); + }, + _ => {}, + } + } else { + let tcx = self.tcx(); + + if let hir::ExprAssignOp(..) = e.node { + if + !tcx.sess.features.borrow().augmented_assignments && + !self.fcx.expr_ty(e).references_error() + { + tcx.sess.span_err( + e.span, + "overloaded augmented assignments are not stable"); + fileline_help!( + tcx.sess, e.span, + "add #![feature(augmented_assignments)] to the crate root \ + to enable"); + } + } } } + _ => {}, } } } @@ -196,6 +225,10 @@ impl<'cx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'tcx> { self.visit_ty(&**ty); write_ty_to_tcx(self.tcx(), count_expr.id, self.tcx().types.usize); } + hir::TyBareFn(ref function_declaration) => { + visit::walk_fn_decl_nopat(self, &function_declaration.decl); + walk_list!(self, visit_lifetime_def, &function_declaration.lifetimes); + } _ => visit::walk_ty(self, t) } } @@ -355,8 +388,8 @@ impl ResolveReason { tcx.expr_span(upvar_id.closure_expr_id) } ResolvingClosure(did) => { - if did.is_local() { - tcx.expr_span(did.node) + if let Some(node_id) = tcx.map.as_local_node_id(did) { + tcx.expr_span(node_id) } else { DUMMY_SP } diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 8cffac6732..b3ec10a894 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -16,16 +16,16 @@ // mappings. That mapping code resides here. -use middle::def_id::{DefId, LOCAL_CRATE}; +use middle::def_id::DefId; use middle::lang_items::UnsizeTraitLangItem; use middle::subst::{self, Subst}; use middle::traits; use middle::ty; use middle::ty::RegionEscape; -use middle::ty::{ImplContainer, ImplOrTraitItemId, ConstTraitItemId}; +use middle::ty::{ImplOrTraitItemId, ConstTraitItemId}; use middle::ty::{MethodTraitItemId, TypeTraitItemId, ParameterEnvironment}; use middle::ty::{Ty, TyBool, TyChar, TyEnum, TyError}; -use middle::ty::{TyParam, TypeScheme, TyRawPtr}; +use middle::ty::{TyParam, TyRawPtr}; use middle::ty::{TyRef, TyStruct, TyTrait, TyTuple}; use middle::ty::{TyStr, TyArray, TySlice, TyFloat, TyInfer, TyInt}; use middle::ty::{TyUint, TyClosure, TyBox, TyBareFn}; @@ -138,7 +138,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { fn check_implementation(&self, item: &Item) { let tcx = self.crate_context.tcx; - let impl_did = DefId::local(item.id); + let impl_did = tcx.map.local_def_id(item.id); let self_type = tcx.lookup_item_type(impl_did); // If there are no traits, then this implementation must have a @@ -149,7 +149,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { if let Some(trait_ref) = self.crate_context.tcx.impl_trait_ref(impl_did) { debug!("(checking implementation) adding impl for trait '{:?}', item '{}'", trait_ref, - item.ident); + item.name); enforce_trait_manually_implementable(self.crate_context.tcx, item.span, @@ -168,65 +168,6 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { tcx.impl_items.borrow_mut().insert(impl_did, impl_items); } - // Creates default method IDs and performs type substitutions for an impl - // and trait pair. Then, for each provided method in the trait, inserts a - // `ProvidedMethodInfo` instance into the `provided_method_sources` map. - fn instantiate_default_methods( - &self, - impl_id: DefId, - trait_ref: &ty::TraitRef<'tcx>, - all_impl_items: &mut Vec) { - let tcx = self.crate_context.tcx; - debug!("instantiate_default_methods(impl_id={:?}, trait_ref={:?})", - impl_id, trait_ref); - - let impl_type_scheme = tcx.lookup_item_type(impl_id); - - let prov = tcx.provided_trait_methods(trait_ref.def_id); - for trait_method in &prov { - // Synthesize an ID. - let new_id = tcx.sess.next_node_id(); - let new_did = DefId::local(new_id); - - debug!("new_did={:?} trait_method={:?}", new_did, trait_method); - - // Create substitutions for the various trait parameters. - let new_method_ty = - Rc::new(subst_receiver_types_in_method_ty( - tcx, - impl_id, - &impl_type_scheme, - trait_ref, - new_did, - &**trait_method, - Some(trait_method.def_id))); - - debug!("new_method_ty={:?}", new_method_ty); - all_impl_items.push(MethodTraitItemId(new_did)); - - // construct the polytype for the method based on the - // method_ty. it will have all the generics from the - // impl, plus its own. - let new_polytype = ty::TypeScheme { - generics: new_method_ty.generics.clone(), - ty: tcx.mk_fn(Some(new_did), - tcx.mk_bare_fn(new_method_ty.fty.clone())) - }; - debug!("new_polytype={:?}", new_polytype); - - tcx.register_item_type(new_did, new_polytype); - tcx.predicates.borrow_mut().insert(new_did, new_method_ty.predicates.clone()); - tcx.impl_or_trait_items - .borrow_mut() - .insert(new_did, ty::MethodTraitItem(new_method_ty)); - - // Pair the new synthesized ID up with the - // ID of the method. - self.crate_context.tcx.provided_method_sources.borrow_mut() - .insert(new_did, trait_method.def_id); - } - } - fn add_inherent_impl(&self, base_def_id: DefId, impl_def_id: DefId) { match self.inherent_impls.borrow().get(&base_def_id) { Some(implementation_list) => { @@ -252,27 +193,20 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { fn create_impl_from_item(&self, item: &Item) -> Vec { match item.node { ItemImpl(_, _, _, _, _, ref impl_items) => { - let mut items: Vec = - impl_items.iter().map(|impl_item| { + impl_items.iter().map(|impl_item| { + let impl_def_id = self.crate_context.tcx.map.local_def_id(impl_item.id); match impl_item.node { hir::ConstImplItem(..) => { - ConstTraitItemId(DefId::local(impl_item.id)) + ConstTraitItemId(impl_def_id) } hir::MethodImplItem(..) => { - MethodTraitItemId(DefId::local(impl_item.id)) + MethodTraitItemId(impl_def_id) } hir::TypeImplItem(_) => { - TypeTraitItemId(DefId::local(impl_item.id)) + TypeTraitItemId(impl_def_id) } } - }).collect(); - - let def_id = DefId::local(item.id); - if let Some(trait_ref) = self.crate_context.tcx.impl_trait_ref(def_id) { - self.instantiate_default_methods(def_id, &trait_ref, &mut items); - } - - items + }).collect() } _ => { self.crate_context.tcx.sess.span_bug(item.span, @@ -312,17 +246,15 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { } _ => { // Destructors only work on nominal types. - if impl_did.is_local() { - { - match tcx.map.find(impl_did.node) { - Some(hir_map::NodeItem(item)) => { - span_err!(tcx.sess, item.span, E0120, - "the Drop trait may only be implemented on structures"); - } - _ => { - tcx.sess.bug("didn't find impl in ast \ - map"); - } + if let Some(impl_node_id) = tcx.map.as_local_node_id(impl_did) { + match tcx.map.find(impl_node_id) { + Some(hir_map::NodeItem(item)) => { + span_err!(tcx.sess, item.span, E0120, + "the Drop trait may only be implemented on structures"); + } + _ => { + tcx.sess.bug("didn't find impl in ast \ + map"); } } } else { @@ -348,18 +280,20 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { debug!("check_implementations_of_copy: impl_did={:?}", impl_did); - if impl_did.krate != LOCAL_CRATE { + 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 - } + }; let self_type = tcx.lookup_item_type(impl_did); debug!("check_implementations_of_copy: self_type={:?} (bound)", self_type); - let span = tcx.map.span(impl_did.node); - let param_env = ParameterEnvironment::for_item(tcx, impl_did.node); + let span = tcx.map.span(impl_node_id); + let param_env = ParameterEnvironment::for_item(tcx, impl_node_id); let self_type = self_type.ty.subst(tcx, ¶m_env.free_substs); assert!(!self_type.has_escaping_regions()); @@ -417,11 +351,13 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { debug!("check_implementations_of_coerce_unsized: impl_did={:?}", impl_did); - if impl_did.krate != LOCAL_CRATE { + let impl_node_id = if let Some(n) = tcx.map.as_local_node_id(impl_did) { + n + } else { debug!("check_implementations_of_coerce_unsized(): impl not \ in this crate"); return; - } + }; let source = tcx.lookup_item_type(impl_did).ty; let trait_ref = self.crate_context.tcx.impl_trait_ref(impl_did).unwrap(); @@ -429,8 +365,8 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (bound)", source, target); - let span = tcx.map.span(impl_did.node); - let param_env = ParameterEnvironment::for_item(tcx, impl_did.node); + let span = tcx.map.span(impl_node_id); + let param_env = ParameterEnvironment::for_item(tcx, impl_node_id); let source = source.subst(tcx, ¶m_env.free_substs); let target = target.subst(tcx, ¶m_env.free_substs); assert!(!source.has_escaping_regions()); @@ -477,9 +413,16 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { 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)); - if infcx.sub_types(false, origin, b, a).is_ok() { + + 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 { + // Collect up all fields that were significantly changed + // i.e. those that contain T in coerce_unsized T -> U Some((i, a, b)) } }).collect::>(); @@ -523,7 +466,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { let mut fulfill_cx = infcx.fulfillment_cx.borrow_mut(); // Register an obligation for `A: Trait`. - let cause = traits::ObligationCause::misc(span, impl_did.node); + let cause = traits::ObligationCause::misc(span, impl_node_id); let predicate = traits::predicate_for_trait_def(tcx, cause, trait_def_id, 0, source, vec![target]); fulfill_cx.register_predicate_obligation(&infcx, predicate); @@ -537,7 +480,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { let mut free_regions = FreeRegionMap::new(); free_regions.relate_free_regions_from_predicates(tcx, &infcx.parameter_environment .caller_bounds); - infcx.resolve_regions_and_report_errors(&free_regions, impl_did.node); + infcx.resolve_regions_and_report_errors(&free_regions, impl_node_id); if let Some(kind) = kind { tcx.custom_coerce_unsized_kinds.borrow_mut().insert(impl_did, kind); @@ -568,55 +511,6 @@ fn enforce_trait_manually_implementable(tcx: &ty::ctxt, sp: Span, trait_def_id: "add `#![feature(unboxed_closures)]` to the crate attributes to enable"); } -fn subst_receiver_types_in_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>, - impl_id: DefId, - impl_type_scheme: &ty::TypeScheme<'tcx>, - trait_ref: &ty::TraitRef<'tcx>, - new_def_id: DefId, - method: &ty::Method<'tcx>, - provided_source: Option) - -> ty::Method<'tcx> -{ - let combined_substs = tcx.make_substs_for_receiver_types(trait_ref, method); - - debug!("subst_receiver_types_in_method_ty: combined_substs={:?}", - combined_substs); - - let method_predicates = method.predicates.subst(tcx, &combined_substs); - let mut method_generics = method.generics.subst(tcx, &combined_substs); - - // replace the type parameters declared on the trait with those - // from the impl - for &space in &[subst::TypeSpace, subst::SelfSpace] { - method_generics.types.replace( - space, - impl_type_scheme.generics.types.get_slice(space).to_vec()); - method_generics.regions.replace( - space, - impl_type_scheme.generics.regions.get_slice(space).to_vec()); - } - - debug!("subst_receiver_types_in_method_ty: method_generics={:?}", - method_generics); - - let method_fty = method.fty.subst(tcx, &combined_substs); - - debug!("subst_receiver_types_in_method_ty: method_ty={:?}", - method.fty); - - ty::Method::new( - method.name, - method_generics, - method_predicates, - method_fty, - method.explicit_self, - method.vis, - new_def_id, - ImplContainer(impl_id), - provided_source - ) -} - pub fn check_coherence(crate_context: &CrateCtxt) { CoherenceChecker { crate_context: crate_context, diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index 022f1e3646..f796f7fe9f 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -11,9 +11,11 @@ //! Orphan checker: every impl either implements a trait defined in this //! crate or pertains to a type defined in this crate. -use middle::def_id::{DefId, LOCAL_CRATE}; +use metadata::cstore::LOCAL_CRATE; +use middle::def_id::DefId; use middle::traits; use middle::ty; +use syntax::ast; use syntax::codemap::Span; use rustc_front::visit; use rustc_front::hir; @@ -62,7 +64,7 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { /// to prevent inundating the user with a bunch of similar error /// reports. fn check_item(&self, item: &hir::Item) { - let def_id = DefId::local(item.id); + let def_id = self.tcx.map.local_def_id(item.id); match item.node { hir::ItemImpl(_, _, _, None, _, _) => { // For inherent impls, self type must be a nominal type @@ -119,84 +121,84 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { "*mut T", item.span); } - ty::TyInt(hir::TyI8) => { + ty::TyInt(ast::TyI8) => { self.check_primitive_impl(def_id, self.tcx.lang_items.i8_impl(), "i8", "i8", item.span); } - ty::TyInt(hir::TyI16) => { + ty::TyInt(ast::TyI16) => { self.check_primitive_impl(def_id, self.tcx.lang_items.i16_impl(), "i16", "i16", item.span); } - ty::TyInt(hir::TyI32) => { + ty::TyInt(ast::TyI32) => { self.check_primitive_impl(def_id, self.tcx.lang_items.i32_impl(), "i32", "i32", item.span); } - ty::TyInt(hir::TyI64) => { + ty::TyInt(ast::TyI64) => { self.check_primitive_impl(def_id, self.tcx.lang_items.i64_impl(), "i64", "i64", item.span); } - ty::TyInt(hir::TyIs) => { + ty::TyInt(ast::TyIs) => { self.check_primitive_impl(def_id, self.tcx.lang_items.isize_impl(), "isize", "isize", item.span); } - ty::TyUint(hir::TyU8) => { + ty::TyUint(ast::TyU8) => { self.check_primitive_impl(def_id, self.tcx.lang_items.u8_impl(), "u8", "u8", item.span); } - ty::TyUint(hir::TyU16) => { + ty::TyUint(ast::TyU16) => { self.check_primitive_impl(def_id, self.tcx.lang_items.u16_impl(), "u16", "u16", item.span); } - ty::TyUint(hir::TyU32) => { + ty::TyUint(ast::TyU32) => { self.check_primitive_impl(def_id, self.tcx.lang_items.u32_impl(), "u32", "u32", item.span); } - ty::TyUint(hir::TyU64) => { + ty::TyUint(ast::TyU64) => { self.check_primitive_impl(def_id, self.tcx.lang_items.u64_impl(), "u64", "u64", item.span); } - ty::TyUint(hir::TyUs) => { + ty::TyUint(ast::TyUs) => { self.check_primitive_impl(def_id, self.tcx.lang_items.usize_impl(), "usize", "usize", item.span); } - ty::TyFloat(hir::TyF32) => { + ty::TyFloat(ast::TyF32) => { self.check_primitive_impl(def_id, self.tcx.lang_items.f32_impl(), "f32", "f32", item.span); } - ty::TyFloat(hir::TyF64) => { + ty::TyFloat(ast::TyF64) => { self.check_primitive_impl(def_id, self.tcx.lang_items.f64_impl(), "f64", diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index 55b5f665d1..706f28f9fe 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -11,7 +11,8 @@ //! Overlap: No two impls for the same trait are implemented for the //! same type. -use middle::def_id::{DefId, LOCAL_CRATE}; +use metadata::cstore::LOCAL_CRATE; +use middle::def_id::DefId; use middle::traits; use middle::ty; use middle::infer::{self, new_infer_ctxt}; @@ -111,7 +112,7 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> { } } else if impl2_def_id.krate != LOCAL_CRATE { Some((impl1_def_id, impl2_def_id)) - } else if impl1_def_id.node < impl2_def_id.node { + } else if impl1_def_id < impl2_def_id { Some((impl1_def_id, impl2_def_id)) } else { Some((impl2_def_id, impl1_def_id)) @@ -164,8 +165,8 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> { } fn span_of_impl(&self, impl_did: DefId) -> Span { - assert_eq!(impl_did.krate, LOCAL_CRATE); - self.tcx.map.span(impl_did.node) + let node_id = self.tcx.map.as_local_node_id(impl_did).unwrap(); + self.tcx.map.span(node_id) } } @@ -177,20 +178,20 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OverlapChecker<'cx, 'tcx> { // look for another default impl; note that due to the // general orphan/coherence rules, it must always be // in this crate. - let impl_def_id = DefId::local(item.id); + let impl_def_id = self.tcx.map.local_def_id(item.id); let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap(); let prev_default_impl = self.default_impls.insert(trait_ref.def_id, item.id); match prev_default_impl { Some(prev_id) => { self.report_overlap_error(trait_ref.def_id, impl_def_id, - DefId::local(prev_id)); + self.tcx.map.local_def_id(prev_id)); } None => { } } } hir::ItemImpl(_, _, _, Some(_), ref self_ty, _) => { - let impl_def_id = DefId::local(item.id); + let impl_def_id = self.tcx.map.local_def_id(item.id); let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap(); let trait_def_id = trait_ref.def_id; match trait_ref.self_ty().sty { diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs index b739709e62..f7b10b9001 100644 --- a/src/librustc_typeck/coherence/unsafety.rs +++ b/src/librustc_typeck/coherence/unsafety.rs @@ -11,7 +11,6 @@ //! Unsafety checker: every impl either implements a trait defined in this //! crate or pertains to a type defined in this crate. -use middle::def_id::DefId; use middle::ty; use rustc_front::visit; use rustc_front::hir; @@ -30,7 +29,7 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> { fn check_unsafety_coherence(&mut self, item: &'v hir::Item, unsafety: hir::Unsafety, polarity: hir::ImplPolarity) { - match self.tcx.impl_trait_ref(DefId::local(item.id)) { + match self.tcx.impl_trait_ref(self.tcx.map.local_def_id(item.id)) { None => { // Inherent impl. match unsafety { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index f7520ed54b..2b46dbeecb 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -66,7 +66,7 @@ There are some shortcomings in this design: use astconv::{self, AstConv, ty_of_arg, ast_ty_to_ty, ast_region_to_region}; use middle::def; -use middle::def_id::{DefId, LOCAL_CRATE}; +use middle::def_id::DefId; use constrained_type_params as ctp; use middle::lang_items::SizedTraitLangItem; use middle::free_region::FreeRegionMap; @@ -93,12 +93,12 @@ use std::rc::Rc; use syntax::abi; use syntax::ast; +use syntax::attr; use syntax::codemap::Span; use syntax::parse::token::special_idents; use syntax::ptr::P; use rustc_front::hir; use rustc_front::visit; -use rustc_front::attr; use rustc_front::print::pprust; /////////////////////////////////////////////////////////////////////////// @@ -198,7 +198,7 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> { } fn method_ty(&self, method_id: ast::NodeId) -> Rc> { - let def_id = DefId::local(method_id); + let def_id = self.tcx.map.local_def_id(method_id); match *self.tcx.impl_or_trait_items.borrow().get(&def_id).unwrap() { ty::MethodTraitItem(ref mty) => mty.clone(), _ => { @@ -316,16 +316,16 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> { { let tcx = self.tcx; - if trait_id.krate != LOCAL_CRATE { - return tcx.lookup_trait_def(trait_id) - } - - let item = match tcx.map.get(trait_id.node) { - hir_map::NodeItem(item) => item, - _ => tcx.sess.bug(&format!("get_trait_def({:?}): not an item", trait_id)) - }; + if let Some(trait_id) = tcx.map.as_local_node_id(trait_id) { + let item = match tcx.map.get(trait_id) { + hir_map::NodeItem(item) => item, + _ => tcx.sess.bug(&format!("get_trait_def({:?}): not an item", trait_id)) + }; - trait_def_of_item(self, &*item) + trait_def_of_item(self, &*item) + } else { + tcx.lookup_trait_def(trait_id) + } } /// Ensure that the (transitive) super predicates for @@ -402,8 +402,8 @@ impl<'a, 'tcx> AstConv<'tcx> for ItemCtxt<'a, 'tcx> { assoc_name: ast::Name) -> bool { - if trait_def_id.is_local() { - trait_defines_associated_type_named(self.ccx, trait_def_id.node, assoc_name) + if let Some(trait_id) = self.tcx().map.as_local_node_id(trait_def_id) { + trait_defines_associated_type_named(self.ccx, trait_id, assoc_name) } else { let trait_def = self.tcx().lookup_trait_def(trait_def_id); trait_def.associated_type_names.contains(&assoc_name) @@ -507,7 +507,7 @@ impl<'tcx> GetTypeParameterBounds<'tcx> for ty::GenericPredicates<'tcx> { /// Find bounds from hir::Generics. This requires scanning through the /// AST. We do this to avoid having to convert *all* the bounds, which /// would create artificial cycles. Instead we can only convert the -/// bounds for those a type parameter `X` if `X::Foo` is used. +/// bounds for a type parameter `X` if `X::Foo` is used. impl<'tcx> GetTypeParameterBounds<'tcx> for hir::Generics { fn get_type_parameter_bounds(&self, astconv: &AstConv<'tcx>, @@ -558,10 +558,10 @@ fn is_param<'tcx>(tcx: &ty::ctxt<'tcx>, let path_res = *tcx.def_map.borrow().get(&ast_ty.id).unwrap(); match path_res.base_def { def::DefSelfTy(Some(def_id), None) => { - path_res.depth == 0 && def_id.node == param_id + path_res.depth == 0 && def_id == tcx.map.local_def_id(param_id) } def::DefTyParam(_, _, def_id, _) => { - path_res.depth == 0 && def_id == DefId::local(param_id) + path_res.depth == 0 && def_id == tcx.map.local_def_id(param_id) } _ => { false @@ -577,7 +577,7 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, container: ImplOrTraitItemContainer, sig: &hir::MethodSig, id: ast::NodeId, - ident: ast::Ident, + name: ast::Name, vis: hir::Visibility, untransformed_rcvr_ty: Ty<'tcx>, rcvr_ty_generics: &ty::Generics<'tcx>, @@ -591,21 +591,20 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, astconv::ty_of_method(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)), sig, untransformed_rcvr_ty); - let def_id = DefId::local(id); - let ty_method = ty::Method::new(ident.name, + let def_id = ccx.tcx.map.local_def_id(id); + let ty_method = ty::Method::new(name, ty_generics, ty_generic_predicates, fty, explicit_self_category, vis, def_id, - container, - None); + container); let fty = ccx.tcx.mk_fn(Some(def_id), ccx.tcx.mk_bare_fn(ty_method.fty.clone())); debug!("method {} (id {}) has type {:?}", - ident, id, fty); + name, id, fty); ccx.tcx.register_item_type(def_id, TypeScheme { generics: ty_method.generics.clone(), ty: fty @@ -632,57 +631,56 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, write_ty_to_tcx(ccx.tcx, v.node.id, tt); /* add the field to the tcache */ - ccx.tcx.register_item_type(DefId::local(v.node.id), + ccx.tcx.register_item_type(ccx.tcx.map.local_def_id(v.node.id), ty::TypeScheme { generics: struct_generics.clone(), ty: tt }); - ccx.tcx.predicates.borrow_mut().insert(DefId::local(v.node.id), + ccx.tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(v.node.id), struct_predicates.clone()); } fn convert_associated_const<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, container: ImplOrTraitItemContainer, - ident: ast::Ident, + name: ast::Name, id: ast::NodeId, vis: hir::Visibility, ty: ty::Ty<'tcx>, - default: Option<&hir::Expr>) + has_value: bool) { - ccx.tcx.predicates.borrow_mut().insert(DefId::local(id), + ccx.tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(id), ty::GenericPredicates::empty()); write_ty_to_tcx(ccx.tcx, id, ty); - let default_id = default.map(|expr| DefId::local(expr.id)); let associated_const = Rc::new(ty::AssociatedConst { - name: ident.name, + name: name, vis: vis, - def_id: DefId::local(id), + def_id: ccx.tcx.map.local_def_id(id), container: container, ty: ty, - default: default_id, + has_value: has_value }); ccx.tcx.impl_or_trait_items.borrow_mut() - .insert(DefId::local(id), ty::ConstTraitItem(associated_const)); + .insert(ccx.tcx.map.local_def_id(id), ty::ConstTraitItem(associated_const)); } fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, container: ImplOrTraitItemContainer, - ident: ast::Ident, + name: ast::Name, id: ast::NodeId, vis: hir::Visibility, ty: Option>) { let associated_type = Rc::new(ty::AssociatedType { - name: ident.name, + name: name, vis: vis, ty: ty, - def_id: DefId::local(id), + def_id: ccx.tcx.map.local_def_id(id), container: container }); ccx.tcx.impl_or_trait_items.borrow_mut() - .insert(DefId::local(id), ty::TypeTraitItem(associated_type)); + .insert(ccx.tcx.map.local_def_id(id), ty::TypeTraitItem(associated_type)); } fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>, @@ -691,7 +689,7 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>, untransformed_rcvr_ty: Ty<'tcx>, rcvr_ty_generics: &ty::Generics<'tcx>, rcvr_ty_predicates: &ty::GenericPredicates<'tcx>) - where I: Iterator + where I: Iterator { debug!("convert_methods(untransformed_rcvr_ty={:?}, rcvr_ty_generics={:?}, \ rcvr_ty_predicates={:?})", @@ -699,12 +697,12 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>, rcvr_ty_generics, rcvr_ty_predicates); - for (sig, id, ident, vis, _span) in methods { + for (sig, id, name, vis, _span) in methods { convert_method(ccx, container, sig, id, - ident, + name, vis, untransformed_rcvr_ty, rcvr_ty_generics, @@ -743,7 +741,7 @@ fn ensure_no_ty_param_bounds(ccx: &CrateCtxt, fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { let tcx = ccx.tcx; - debug!("convert: item {} with id {}", it.ident, it.id); + debug!("convert: item {} with id {}", it.name, it.id); match it.node { // These don't define types. hir::ItemExternCrate(_) | hir::ItemUse(_) | @@ -753,7 +751,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { let (scheme, predicates) = convert_typed_item(ccx, it); write_ty_to_tcx(tcx, it.id, scheme.ty); convert_enum_variant_types(ccx, - tcx.lookup_adt_def_master(DefId::local(it.id)), + tcx.lookup_adt_def_master(ccx.tcx.map.local_def_id(it.id)), scheme, predicates, &enum_definition.variants); @@ -767,7 +765,8 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { tcx.record_trait_has_default_impl(trait_ref.def_id); - tcx.impl_trait_refs.borrow_mut().insert(DefId::local(it.id), Some(trait_ref)); + tcx.impl_trait_refs.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id), + Some(trait_ref)); } hir::ItemImpl(_, _, ref generics, @@ -784,21 +783,21 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { let selfty = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, &**selfty); write_ty_to_tcx(tcx, it.id, selfty); - tcx.register_item_type(DefId::local(it.id), + tcx.register_item_type(ccx.tcx.map.local_def_id(it.id), TypeScheme { generics: ty_generics.clone(), ty: selfty }); - tcx.predicates.borrow_mut().insert(DefId::local(it.id), + tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id), ty_predicates.clone()); if let &Some(ref ast_trait_ref) = opt_trait_ref { tcx.impl_trait_refs.borrow_mut().insert( - DefId::local(it.id), + ccx.tcx.map.local_def_id(it.id), Some(astconv::instantiate_mono_trait_ref(&ccx.icx(&ty_predicates), &ExplicitRscope, ast_trait_ref, Some(selfty))) ); } else { - tcx.impl_trait_refs.borrow_mut().insert(DefId::local(it.id), None); + tcx.impl_trait_refs.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id), None); } @@ -823,7 +822,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { hir::TypeImplItem(_) => &mut seen_type_items, _ => &mut seen_value_items, }; - if !seen_items.insert(impl_item.ident.name) { + if !seen_items.insert(impl_item.name) { let desc = match impl_item.node { hir::ConstImplItem(_, _) => "associated constant", hir::TypeImplItem(_) => "associated type", @@ -837,18 +836,18 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { span_err!(tcx.sess, impl_item.span, E0201, "duplicate {}", desc); } - if let hir::ConstImplItem(ref ty, ref expr) = impl_item.node { + if let hir::ConstImplItem(ref ty, _) = impl_item.node { let ty = ccx.icx(&ty_predicates) .to_ty(&ExplicitRscope, &*ty); - tcx.register_item_type(DefId::local(impl_item.id), + tcx.register_item_type(ccx.tcx.map.local_def_id(impl_item.id), TypeScheme { generics: ty_generics.clone(), ty: ty, }); - convert_associated_const(ccx, ImplContainer(DefId::local(it.id)), - impl_item.ident, impl_item.id, + convert_associated_const(ccx, ImplContainer(ccx.tcx.map.local_def_id(it.id)), + impl_item.name, impl_item.id, impl_item.vis.inherit_from(parent_visibility), - ty, Some(&*expr)); + ty, true /* has_value */); } } @@ -862,8 +861,8 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { let typ = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, ty); - convert_associated_type(ccx, ImplContainer(DefId::local(it.id)), - impl_item.ident, impl_item.id, impl_item.vis, + convert_associated_type(ccx, ImplContainer(ccx.tcx.map.local_def_id(it.id)), + impl_item.name, impl_item.id, impl_item.vis, Some(typ)); } } @@ -875,13 +874,13 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { // { fn foo(); }` is public, but private in `impl { fn // foo(); }`). let method_vis = ii.vis.inherit_from(parent_visibility); - Some((sig, ii.id, ii.ident, method_vis, ii.span)) + Some((sig, ii.id, ii.name, method_vis, ii.span)) } else { None } }); convert_methods(ccx, - ImplContainer(DefId::local(it.id)), + ImplContainer(ccx.tcx.map.local_def_id(it.id)), methods, selfty, &ty_generics, @@ -901,15 +900,15 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { enforce_impl_params_are_constrained(tcx, generics, - DefId::local(it.id), + ccx.tcx.map.local_def_id(it.id), impl_items); }, hir::ItemTrait(_, _, _, ref trait_items) => { let trait_def = trait_def_of_item(ccx, it); let _: Result<(), ErrorReported> = // any error is already reported, can ignore - ccx.ensure_super_predicates(it.span, DefId::local(it.id)); + ccx.ensure_super_predicates(it.span, ccx.tcx.map.local_def_id(it.id)); convert_trait_predicates(ccx, it); - let trait_predicates = tcx.lookup_predicates(DefId::local(it.id)); + let trait_predicates = tcx.lookup_predicates(ccx.tcx.map.local_def_id(it.id)); debug!("convert: trait_bounds={:?}", trait_predicates); @@ -919,14 +918,18 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { hir::ConstTraitItem(ref ty, ref default) => { let ty = ccx.icx(&trait_predicates) .to_ty(&ExplicitRscope, ty); - tcx.register_item_type(DefId::local(trait_item.id), + tcx.register_item_type(ccx.tcx.map.local_def_id(trait_item.id), TypeScheme { generics: trait_def.generics.clone(), ty: ty, }); - convert_associated_const(ccx, TraitContainer(DefId::local(it.id)), - trait_item.ident, trait_item.id, - hir::Public, ty, default.as_ref().map(|d| &**d)); + convert_associated_const(ccx, + TraitContainer(ccx.tcx.map.local_def_id(it.id)), + trait_item.name, + trait_item.id, + hir::Public, + ty, + default.is_some()) } _ => {} } @@ -940,8 +943,11 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { |ty| ccx.icx(&trait_predicates).to_ty(&ExplicitRscope, &ty) }); - convert_associated_type(ccx, TraitContainer(DefId::local(it.id)), - trait_item.ident, trait_item.id, hir::Public, + convert_associated_type(ccx, + TraitContainer(ccx.tcx.map.local_def_id(it.id)), + trait_item.name, + trait_item.id, + hir::Public, typ); } _ => {} @@ -953,12 +959,12 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { hir::MethodTraitItem(ref sig, _) => sig, _ => return None, }; - Some((sig, ti.id, ti.ident, hir::Inherited, ti.span)) + Some((sig, ti.id, ti.name, hir::Inherited, ti.span)) }); // Run convert_methods on the trait methods. convert_methods(ccx, - TraitContainer(DefId::local(it.id)), + TraitContainer(ccx.tcx.map.local_def_id(it.id)), methods, tcx.mk_self_type(), &trait_def.generics, @@ -966,7 +972,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { // Add an entry mapping let trait_item_def_ids = Rc::new(trait_items.iter().map(|trait_item| { - let def_id = DefId::local(trait_item.id); + let def_id = ccx.tcx.map.local_def_id(trait_item.id); match trait_item.node { hir::ConstTraitItem(..) => { ty::ConstTraitItemId(def_id) @@ -979,7 +985,8 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { } } }).collect()); - tcx.trait_item_def_ids.borrow_mut().insert(DefId::local(it.id), trait_item_def_ids); + tcx.trait_item_def_ids.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id), + trait_item_def_ids); // This must be done after `collect_trait_methods` so that // we have a method type stored for every method. @@ -1000,14 +1007,15 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { let (scheme, predicates) = convert_typed_item(ccx, it); write_ty_to_tcx(tcx, it.id, scheme.ty); - let variant = tcx.lookup_adt_def_master(DefId::local(it.id)).struct_variant(); + let it_def_id = ccx.tcx.map.local_def_id(it.id); + let variant = tcx.lookup_adt_def_master(it_def_id).struct_variant(); - for (f, ty_f) in struct_def.fields.iter().zip(variant.fields.iter()) { + for (f, ty_f) in struct_def.fields().iter().zip(variant.fields.iter()) { convert_field(ccx, &scheme.generics, &predicates, f, ty_f) } - if let Some(ctor_id) = struct_def.ctor_id { - convert_variant_ctor(tcx, ctor_id, variant, scheme, predicates); + if !struct_def.is_struct() { + convert_variant_ctor(tcx, struct_def.id(), variant, scheme, predicates); } }, hir::ItemTy(_, ref generics) => { @@ -1031,21 +1039,21 @@ fn convert_variant_ctor<'a, 'tcx>(tcx: &ty::ctxt<'tcx>, scheme: ty::TypeScheme<'tcx>, predicates: ty::GenericPredicates<'tcx>) { let ctor_ty = match variant.kind() { - VariantKind::Unit | VariantKind::Dict => scheme.ty, + VariantKind::Unit | VariantKind::Struct => scheme.ty, VariantKind::Tuple => { let inputs: Vec<_> = variant.fields .iter() .map(|field| field.unsubst_ty()) .collect(); - tcx.mk_ctor_fn(DefId::local(ctor_id), + tcx.mk_ctor_fn(tcx.map.local_def_id(ctor_id), &inputs[..], scheme.ty) } }; write_ty_to_tcx(tcx, ctor_id, ctor_ty); - tcx.predicates.borrow_mut().insert(DefId::local(ctor_id), predicates); - tcx.register_item_type(DefId::local(ctor_id), + tcx.predicates.borrow_mut().insert(tcx.map.local_def_id(ctor_id), predicates); + tcx.register_item_type(tcx.map.local_def_id(ctor_id), TypeScheme { generics: scheme.generics, ty: ctor_ty @@ -1057,32 +1065,17 @@ fn convert_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, scheme: ty::TypeScheme<'tcx>, predicates: ty::GenericPredicates<'tcx>, variants: &[P]) { - let tcx = ccx.tcx; - let icx = ccx.icx(&predicates); - // fill the field types for (variant, ty_variant) in variants.iter().zip(def.variants.iter()) { - match variant.node.kind { - hir::TupleVariantKind(ref args) => { - let rs = ExplicitRscope; - let input_tys: Vec<_> = args.iter().map(|va| icx.to_ty(&rs, &*va.ty)).collect(); - for (field, &ty) in ty_variant.fields.iter().zip(input_tys.iter()) { - field.fulfill_ty(ty); - } - } - - hir::StructVariantKind(ref struct_def) => { - for (f, ty_f) in struct_def.fields.iter().zip(ty_variant.fields.iter()) { - convert_field(ccx, &scheme.generics, &predicates, f, ty_f) - } - } - }; + for (f, ty_f) in variant.node.data.fields().iter().zip(ty_variant.fields.iter()) { + convert_field(ccx, &scheme.generics, &predicates, f, ty_f) + } // Convert the ctor, if any. This also registers the variant as // an item. convert_variant_ctor( - tcx, - variant.node.id, + ccx.tcx, + variant.node.data.id(), ty_variant, scheme.clone(), predicates.clone() @@ -1094,23 +1087,23 @@ fn convert_struct_variant<'tcx>(tcx: &ty::ctxt<'tcx>, did: DefId, name: ast::Name, disr_val: ty::Disr, - def: &hir::StructDef) -> ty::VariantDefData<'tcx, 'tcx> { + def: &hir::VariantData) -> ty::VariantDefData<'tcx, 'tcx> { let mut seen_fields: FnvHashMap = FnvHashMap(); - let fields = def.fields.iter().map(|f| { - let fid = DefId::local(f.node.id); + let fields = def.fields().iter().map(|f| { + let fid = tcx.map.local_def_id(f.node.id); match f.node.kind { - hir::NamedField(ident, vis) => { - let dup_span = seen_fields.get(&ident.name).cloned(); + hir::NamedField(name, vis) => { + let dup_span = seen_fields.get(&name).cloned(); if let Some(prev_span) = dup_span { span_err!(tcx.sess, f.span, E0124, "field `{}` is already declared", - ident.name); + name); span_note!(tcx.sess, prev_span, "previously declared here"); } else { - seen_fields.insert(ident.name, f.span); + seen_fields.insert(name, f.span); } - ty::FieldDefData::new(fid, ident.name, vis) + ty::FieldDefData::new(fid, name, vis) }, hir::UnnamedField(vis) => { ty::FieldDefData::new(fid, special_idents::unnamed_field.name, vis) @@ -1127,15 +1120,20 @@ fn convert_struct_variant<'tcx>(tcx: &ty::ctxt<'tcx>, fn convert_struct_def<'tcx>(tcx: &ty::ctxt<'tcx>, it: &hir::Item, - def: &hir::StructDef) + def: &hir::VariantData) -> ty::AdtDefMaster<'tcx> { - let did = DefId::local(it.id); + let did = tcx.map.local_def_id(it.id); + let ctor_id = if !def.is_struct() { + tcx.map.local_def_id(def.id()) + } else { + did + }; tcx.intern_adt_def( did, ty::AdtKind::Struct, - vec![convert_struct_variant(tcx, did, it.ident.name, 0, def)] + vec![convert_struct_variant(tcx, ctor_id, it.name, 0, def)] ) } @@ -1150,7 +1148,7 @@ fn convert_enum_def<'tcx>(tcx: &ty::ctxt<'tcx>, debug!("disr expr, checking {}", pprust::expr_to_string(e)); let hint = UncheckedExprHint(repr_ty); - match const_eval::eval_const_expr_partial(tcx, e, hint) { + match const_eval::eval_const_expr_partial(tcx, e, hint, None) { Ok(ConstVal::Int(val)) => Some(val as ty::Disr), Ok(ConstVal::Uint(val)) => Some(val as ty::Disr), Ok(_) => { @@ -1165,9 +1163,12 @@ fn convert_enum_def<'tcx>(tcx: &ty::ctxt<'tcx>, None }, Err(err) => { - span_err!(tcx.sess, err.span, E0080, - "constant evaluation error: {}", - err.description()); + span_err!(tcx.sess, err.span, E0080, + "constant evaluation error: {}", + err.description()); + if !e.span.contains(err.span) { + tcx.sess.span_note(e.span, "for enum discriminant here"); + } None } } @@ -1195,7 +1196,7 @@ fn convert_enum_def<'tcx>(tcx: &ty::ctxt<'tcx>, if let Some(prev_disr_val) = prev_disr_val { let result = repr_type.disr_incr(prev_disr_val); if let None = result { - report_discrim_overflow(tcx, v.span, &v.node.name.name.as_str(), + report_discrim_overflow(tcx, v.span, &v.node.name.as_str(), repr_type, prev_disr_val); } result @@ -1208,29 +1209,11 @@ fn convert_enum_def<'tcx>(tcx: &ty::ctxt<'tcx>, disr: ty::Disr) -> ty::VariantDefData<'tcx, 'tcx> { - let did = DefId::local(v.node.id); - let name = v.node.name.name; - match v.node.kind { - hir::TupleVariantKind(ref va) => { - ty::VariantDefData { - did: did, - name: name, - disr_val: disr, - fields: va.iter().map(|&hir::VariantArg { id, .. }| { - ty::FieldDefData::new( - DefId::local(id), - special_idents::unnamed_field.name, - hir::Visibility::Public - ) - }).collect() - } - } - hir::StructVariantKind(ref def) => { - convert_struct_variant(tcx, did, name, disr, &def) - } - } + let did = tcx.map.local_def_id(v.node.data.id()); + let name = v.node.name; + convert_struct_variant(tcx, did, name, disr, &v.node.data) } - let did = DefId::local(it.id); + let did = tcx.map.local_def_id(it.id); let repr_hints = tcx.lookup_repr_hints(did); let (repr_type, repr_type_ty) = tcx.enum_repr_type(repr_hints.get(0)); let mut prev_disr = None; @@ -1244,7 +1227,7 @@ fn convert_enum_def<'tcx>(tcx: &ty::ctxt<'tcx>, prev_disr = Some(disr); v }).collect(); - tcx.intern_adt_def(DefId::local(it.id), ty::AdtKind::Enum, variants) + tcx.intern_adt_def(tcx.map.local_def_id(it.id), ty::AdtKind::Enum, variants) } /// Ensures that the super-predicates of the trait with def-id @@ -1262,19 +1245,19 @@ fn ensure_super_predicates_step(ccx: &CrateCtxt, debug!("ensure_super_predicates_step(trait_def_id={:?})", trait_def_id); - if trait_def_id.krate != LOCAL_CRATE { + let trait_node_id = if let Some(n) = tcx.map.as_local_node_id(trait_def_id) { + n + } else { // If this trait comes from an external crate, then all of the // supertraits it may depend on also must come from external // crates, and hence all of them already have their // super-predicates "converted" (and available from crate // meta-data), so there is no need to transitively test them. return Vec::new(); - } + }; let superpredicates = tcx.super_predicates.borrow().get(&trait_def_id).cloned(); let superpredicates = superpredicates.unwrap_or_else(|| { - let trait_node_id = trait_def_id.node; - let item = match ccx.tcx.map.get(trait_node_id) { hir_map::NodeItem(item) => item, _ => ccx.tcx.sess.bug(&format!("trait_node_id {} is not an item", trait_node_id)) @@ -1317,7 +1300,7 @@ fn ensure_super_predicates_step(ccx: &CrateCtxt, predicates: VecPerParamSpace::new(superbounds, vec![], vec![]) }; debug!("superpredicates for trait {:?} = {:?}", - DefId::local(item.id), + tcx.map.local_def_id(item.id), superpredicates); tcx.super_predicates.borrow_mut().insert(trait_def_id, superpredicates.clone()); @@ -1340,7 +1323,7 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item) -> &'tcx ty::TraitDef<'tcx> { - let def_id = DefId::local(it.id); + let def_id = ccx.tcx.map.local_def_id(it.id); let tcx = ccx.tcx; if let Some(def) = tcx.trait_defs.borrow().get(&def_id) { @@ -1369,7 +1352,7 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let associated_type_names: Vec<_> = items.iter().filter_map(|trait_item| { match trait_item.node { - hir::TypeTraitItem(..) => Some(trait_item.ident.name), + hir::TypeTraitItem(..) => Some(trait_item.name), _ => None, } }).collect(); @@ -1404,7 +1387,7 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, .iter() .enumerate() .map(|(i, def)| ty::ReEarlyBound(ty::EarlyBoundRegion { - param_id: def.lifetime.id, + def_id: tcx.map.local_def_id(def.lifetime.id), space: TypeSpace, index: i as u32, name: def.lifetime.name @@ -1417,7 +1400,7 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, .iter() .enumerate() .map(|(i, def)| tcx.mk_param(TypeSpace, - i as u32, def.ident.name)) + i as u32, def.name)) .collect(); // ...and also create the `Self` parameter. @@ -1444,7 +1427,7 @@ fn trait_defines_associated_type_named(ccx: &CrateCtxt, trait_items.iter().any(|trait_item| { match trait_item.node { - hir::TypeTraitItem(..) => trait_item.ident.name == assoc_name, + hir::TypeTraitItem(..) => trait_item.name == assoc_name, _ => false, } }) @@ -1454,7 +1437,7 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item) let tcx = ccx.tcx; let trait_def = trait_def_of_item(ccx, it); - let def_id = DefId::local(it.id); + let def_id = ccx.tcx.map.local_def_id(it.id); let (generics, items) = match it.node { hir::ItemTrait(_, ref generics, _, ref items) => (generics, items), @@ -1511,7 +1494,7 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item) }; let assoc_ty = ccx.tcx.mk_projection(self_trait_ref, - trait_item.ident.name); + trait_item.name); let bounds = compute_bounds(&ccx.icx(&(ast_generics, trait_predicates)), assoc_ty, @@ -1528,23 +1511,23 @@ fn type_scheme_of_def_id<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, def_id: DefId) -> ty::TypeScheme<'tcx> { - if def_id.krate != LOCAL_CRATE { - return ccx.tcx.lookup_item_type(def_id); - } - - match ccx.tcx.map.find(def_id.node) { - Some(hir_map::NodeItem(item)) => { - type_scheme_of_item(ccx, &*item) - } - Some(hir_map::NodeForeignItem(foreign_item)) => { - let abi = ccx.tcx.map.get_foreign_abi(def_id.node); - type_scheme_of_foreign_item(ccx, &*foreign_item, abi) - } - x => { - ccx.tcx.sess.bug(&format!("unexpected sort of node \ - in get_item_type_scheme(): {:?}", - x)); + if let Some(node_id) = ccx.tcx.map.as_local_node_id(def_id) { + match ccx.tcx.map.find(node_id) { + Some(hir_map::NodeItem(item)) => { + type_scheme_of_item(ccx, &*item) + } + Some(hir_map::NodeForeignItem(foreign_item)) => { + let abi = ccx.tcx.map.get_foreign_abi(node_id); + type_scheme_of_foreign_item(ccx, &*foreign_item, abi) + } + x => { + ccx.tcx.sess.bug(&format!("unexpected sort of node \ + in get_item_type_scheme(): {:?}", + x)); + } } + } else { + ccx.tcx.lookup_item_type(def_id) } } @@ -1553,7 +1536,7 @@ fn type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, -> ty::TypeScheme<'tcx> { memoized(&ccx.tcx.tcache, - DefId::local(it.id), + ccx.tcx.map.local_def_id(it.id), |_| compute_type_scheme_of_item(ccx, it)) } @@ -1570,7 +1553,7 @@ fn compute_type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, hir::ItemFn(ref decl, unsafety, _, abi, ref generics, _) => { let ty_generics = ty_generics_for_fn(ccx, generics, &ty::Generics::empty()); let tofd = astconv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &**decl); - let ty = tcx.mk_fn(Some(DefId::local(it.id)), tcx.mk_bare_fn(tofd)); + let ty = tcx.mk_fn(Some(ccx.tcx.map.local_def_id(it.id)), tcx.mk_bare_fn(tofd)); ty::TypeScheme { ty: ty, generics: ty_generics } } hir::ItemTy(ref t, ref generics) => { @@ -1645,12 +1628,12 @@ fn convert_typed_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } }; - let prev_predicates = tcx.predicates.borrow_mut().insert(DefId::local(it.id), + let prev_predicates = tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id), predicates.clone()); assert!(prev_predicates.is_none()); // Debugging aid. - if tcx.has_attr(DefId::local(it.id), "rustc_object_lifetime_default") { + if tcx.has_attr(ccx.tcx.map.local_def_id(it.id), "rustc_object_lifetime_default") { let object_lifetime_default_reprs: String = scheme.generics.types.iter() .map(|t| match t.object_lifetime_default { @@ -1673,7 +1656,7 @@ fn type_scheme_of_foreign_item<'a, 'tcx>( -> ty::TypeScheme<'tcx> { memoized(&ccx.tcx.tcache, - DefId::local(it.id), + ccx.tcx.map.local_def_id(it.id), |_| compute_type_scheme_of_foreign_item(ccx, it, abi)) } @@ -1718,7 +1701,8 @@ fn convert_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } }; - let prev_predicates = tcx.predicates.borrow_mut().insert(DefId::local(it.id), predicates); + let prev_predicates = tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id), + predicates); assert!(prev_predicates.is_none()); } @@ -1742,7 +1726,7 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, -> ty::Generics<'tcx> { debug!("ty_generics_for_trait(trait_id={:?}, substs={:?})", - DefId::local(trait_id), substs); + ccx.tcx.map.local_def_id(trait_id), substs); let mut generics = ty_generics_for_type_or_impl(ccx, ast_generics); @@ -1758,8 +1742,8 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, space: SelfSpace, index: 0, name: special_idents::type_self.name, - def_id: DefId::local(param_id), - default_def_id: DefId::local(parent), + def_id: ccx.tcx.map.local_def_id(param_id), + default_def_id: ccx.tcx.map.local_def_id(parent), default: None, object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault, }; @@ -1862,7 +1846,7 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, // type parameter (e.g., ``). for (index, param) in ast_generics.ty_params.iter().enumerate() { let index = index as u32; - let param_ty = ty::ParamTy::new(space, index, param.ident.name).to_ty(ccx.tcx); + let param_ty = ty::ParamTy::new(space, index, param.name).to_ty(ccx.tcx); let bounds = compute_bounds(&ccx.icx(&(base_predicates, ast_generics)), param_ty, ¶m.bounds, @@ -1878,9 +1862,10 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, let early_lifetimes = early_bound_lifetimes_from_generics(space, ast_generics); for (index, param) in early_lifetimes.iter().enumerate() { let index = index as u32; + let def_id = tcx.map.local_def_id(param.lifetime.id); let region = ty::ReEarlyBound(ty::EarlyBoundRegion { - param_id: param.lifetime.id, + def_id: def_id, space: space, index: index, name: param.lifetime.name @@ -1966,7 +1951,7 @@ fn ty_generics<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, let def = ty::RegionParameterDef { name: l.lifetime.name, space: space, index: i as u32, - def_id: DefId::local(l.lifetime.id), + def_id: ccx.tcx.map.local_def_id(l.lifetime.id), bounds: bounds }; result.regions.push(space, def); } @@ -2033,9 +2018,9 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, let def = ty::TypeParameterDef { space: space, index: index, - name: param.ident.name, - def_id: DefId::local(param.id), - default_def_id: DefId::local(parent), + name: param.name, + def_id: ccx.tcx.map.local_def_id(param.id), + default_def_id: ccx.tcx.map.local_def_id(parent), default: default, object_lifetime_default: object_lifetime_default, }; @@ -2378,9 +2363,10 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( tcx.fold_regions(value, &mut false, |region, _| { match region { ty::ReEarlyBound(data) => { - let def_id = DefId::local(data.param_id); - ty::ReFree(ty::FreeRegion { scope: scope, - bound_region: ty::BrNamed(def_id, data.name) }) + ty::ReFree(ty::FreeRegion { + scope: scope, + bound_region: ty::BrNamed(data.def_id, data.name) + }) } _ => region } @@ -2415,7 +2401,7 @@ fn enforce_impl_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>, for (index, ty_param) in ast_generics.ty_params.iter().enumerate() { let param_ty = ty::ParamTy { space: TypeSpace, idx: index as u32, - name: ty_param.ident.name }; + name: ty_param.name }; if !input_parameters.contains(&ctp::Parameter::Type(param_ty)) { report_unused_parameter(tcx, ty_param.span, "type", ¶m_ty.to_string()); } @@ -2425,7 +2411,7 @@ fn enforce_impl_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>, let lifetimes_in_associated_types: HashSet<_> = impl_items.iter() - .map(|item| tcx.impl_or_trait_item(DefId::local(item.id))) + .map(|item| tcx.impl_or_trait_item(tcx.map.local_def_id(item.id))) .filter_map(|item| match item { ty::TypeTraitItem(ref assoc_ty) => assoc_ty.ty, ty::ConstTraitItem(..) | ty::MethodTraitItem(..) => None @@ -2438,7 +2424,8 @@ fn enforce_impl_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>, .collect(); for (index, lifetime_def) in ast_generics.lifetimes.iter().enumerate() { - let region = ty::EarlyBoundRegion { param_id: lifetime_def.lifetime.id, + let def_id = tcx.map.local_def_id(lifetime_def.lifetime.id); + let region = ty::EarlyBoundRegion { def_id: def_id, space: TypeSpace, index: index as u32, name: lifetime_def.lifetime.name }; diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 78eaedfbd1..4f39ed43b4 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -109,7 +109,7 @@ fn main(){ "##, E0026: r##" -This error indicates that a struct pattern attempted to extract a non-existant +This error indicates that a struct pattern attempted to extract a non-existent field from a struct. Struct fields are identified by the name used before the colon `:` so struct patterns should resemble the declaration of the struct type being matched. @@ -1308,8 +1308,8 @@ extern "rust-intrinsic" { "##, E0101: r##" -You hit this error because the compiler the compiler lacks information -to determine a type for this expression. Erroneous code example: +You hit this error because the compiler lacks the information to +determine a type for this expression. Erroneous code example: ``` fn main() { @@ -1390,8 +1390,7 @@ enum Bar { A(u8), B(&bool), } // error enum Bar<'a> { A(u8), B(&'a bool), } // correct type MyStr = &str; // error -type MyStr<'a> = &'a str; //correct - +type MyStr<'a> = &'a str; // correct ``` Lifetime elision is a special, limited kind of inference for lifetimes in @@ -1779,6 +1778,58 @@ fn(isize, *const *const u8) -> isize; ``` "##, +E0163: r##" +This error means that an attempt was made to match an enum variant as a +struct type when the variant isn't a struct type: + +``` +enum Foo { B(u32) } + +fn bar(foo: Foo) -> u32 { + match foo { + Foo::B{i} => i // error 0163 + } +} +``` + +Try using `()` instead: + +``` +fn bar(foo: Foo) -> u32 { + match foo { + Foo::B(i) => i + } +} +``` +"##, + +E0164: r##" + +This error means that an attempt was made to match a struct type enum +variant as a non-struct type: + +``` +enum Foo { B{ i: u32 } } + +fn bar(foo: Foo) -> u32 { + match foo { + Foo::B(i) => i // error 0164 + } +} +``` + +Try using `{}` instead: + +``` +fn bar(foo: Foo) -> u32 { + match foo { + Foo::B{i} => i + } +} +``` +"##, + + E0166: r##" This error means that the compiler found a return expression in a function marked as diverging. A function diverges if it has `!` in the place of the @@ -1958,8 +2009,8 @@ wrapped type `T` implements `Clone`. The `where` clause is important because some types will not implement `Clone`, and thus will not get this method. In our erroneous example, however, we're referencing a single concrete type. -Since we know for certain that Wrapper implements Clone, there's no reason -to also specify it in a `where` clause. +Since we know for certain that `Wrapper` implements `Clone`, there's no +reason to also specify it in a `where` clause. "##, E0194: r##" @@ -2297,8 +2348,8 @@ For information on the design of the orphan rules, see [RFC 1023]. "##, E0211: r##" -You used an intrinsic function which doesn't correspond to its -definition. Erroneous code example: +You used a function or type which doesn't fit the requirements for where it was +used. Erroneous code examples: ``` #![feature(intrinsics)] @@ -2306,15 +2357,71 @@ definition. Erroneous code example: extern "rust-intrinsic" { fn size_of(); // error: intrinsic has wrong type } + +// or: + +fn main() -> i32 { 0 } +// error: main function expects type: `fn() {main}`: expected (), found i32 + +// or: + +let x = 1u8; +match x { + 0u8...3i8 => (), + // error: mismatched types in range: expected u8, found i8 + _ => () +} + +// or: + +use std::rc::Rc; +struct Foo; + +impl Foo { + fn x(self: Rc) {} + // error: mismatched self type: expected `Foo`: expected struct + // `Foo`, found struct `alloc::rc::Rc` +} ``` -Please check the function definition. Example: +For the first code example, please check the function definition. Example: ``` #![feature(intrinsics)] extern "rust-intrinsic" { - fn size_of() -> usize; + fn size_of() -> usize; // ok! +} +``` + +The second case example is a bit particular : the main function must always +have this definition: + +``` +fn main(); +``` + +They never take parameters and never return types. + +For the third example, when you match, all patterns must have the same type +as the type you're matching on. Example: + +``` +let x = 1u8; +match x { + 0u8...3u8 => (), // ok! + _ => () +} +``` + +And finally, for the last example, only `Box`, `&Self`, `Self`, +or `&mut Self` work as explicit self parameters. Example: + +``` +struct Foo; + +impl Foo { + fn x(self: Box) {} // ok! } ``` "##, @@ -2529,7 +2636,7 @@ In this example, we're attempting to take a type of `Foo::Bar` in the do_something function. This is not legal: `Foo::Bar` is a value of type `Foo`, not a distinct static type. Likewise, it's not legal to attempt to `impl Foo::Bar`: instead, you must `impl Foo` and then pattern match to specify -behaviour for specific enum variants. +behavior for specific enum variants. "##, E0249: r##" @@ -2862,14 +2969,27 @@ impl Drop for MyStructWrapper { E0368: r##" This error indicates that a binary assignment operator like `+=` or `^=` was -applied to the wrong types. For example: +applied to a type that doesn't support it. For example: + +``` +let mut x = 12f32; // error: binary operation `<<` cannot be applied to + // type `f32` +x <<= 2; ``` -let mut x: u16 = 5; -x ^= true; // error, `^=` cannot be applied to types `u16` and `bool` -x += (); // error, `+=` cannot be applied to types `u16` and `()` + +To fix this error, please check that this type implements this binary +operation. Example: + +``` +let x = 12u32; // the `u32` type does implement the `ShlAssign` trait + +x <<= 2; // ok! ``` +It is also possible to overload most operators for your own type by +implementing the `[OP]Assign` traits from `std::ops`. + Another problem you might be facing is this: suppose you've overloaded the `+` operator for some type `Foo` by implementing the `std::ops::Add` trait for `Foo`, but you find that using `+=` does not work, as in this example: @@ -2889,15 +3009,12 @@ impl Add for Foo { fn main() { let mut x: Foo = Foo(5); - x += Foo(7); // error, `+= cannot be applied to types `Foo` and `Foo` + x += Foo(7); // error, `+= cannot be applied to the type `Foo` } ``` -This is because the binary assignment operators currently do not work off of -traits, so it is not possible to overload them. See [RFC 953] for a proposal -to change this. - -[RFC 953]: https://github.com/rust-lang/rfcs/pull/953 +This is because `AddAssign` is not automatically implemented, so you need to +manually implement it for your type. "##, E0369: r##" @@ -3269,6 +3386,25 @@ extern "platform-intrinsic" { ``` "##, +E0516: r##" +The `typeof` keyword is currently reserved but unimplemented. +Erroneous code example: + +``` +fn main() { + let x: typeof(92) = 92; +} +``` + +Try using type inference instead. Example: + +``` +fn main() { + let x = 92; +} +``` +"##, + } register_diagnostics! { @@ -3283,8 +3419,6 @@ register_diagnostics! { // E0129, // E0141, // E0159, // use of trait `{}` as struct constructor - E0163, - E0164, E0167, // E0168, // E0173, // manual implementations of unboxed closure traits are experimental @@ -3292,7 +3426,7 @@ register_diagnostics! { E0182, E0183, // E0187, // can't infer the kind of the closure -// E0188, // can not cast a immutable reference to a mutable pointer +// E0188, // can not cast an immutable reference to a mutable pointer // E0189, // deprecated: can only cast a boxed pointer to a boxed object // E0190, // deprecated: can only cast a &-pointer to an &-object E0196, // cannot determine a type for this closure @@ -3344,5 +3478,6 @@ register_diagnostics! { // type because its default value `{}` references the type `Self`" E0399, // trait items need to be implemented because the associated // type `{}` was overridden - E0436, // functional record update requires a struct + E0436, // functional record update requires a struct + E0513 // no type for local variable .. } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index a11cd54b65..1a52df31f3 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -81,10 +81,8 @@ This API is completely unstable and subject to change. #![feature(iter_cmp)] #![feature(iter_arith)] #![feature(quote)] -#![feature(ref_slice)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] -#![feature(slice_splits)] #![feature(staged_api)] #![feature(vec_push_all)] #![feature(cell_extras)] @@ -97,21 +95,22 @@ extern crate fmt_macros; extern crate rustc; extern crate rustc_platform_intrinsics as intrinsics; extern crate rustc_front; +extern crate rustc_back; +pub use rustc::front; pub use rustc::lint; pub use rustc::metadata; pub use rustc::middle; pub use rustc::session; pub use rustc::util; +use front::map as hir_map; use middle::def; -use middle::def_id::DefId; use middle::infer; use middle::subst; use middle::ty::{self, Ty, HasTypeFlags}; use session::config; use util::common::time; -use rustc::front::map as hir_map; use rustc_front::hir; use syntax::codemap::Span; @@ -239,7 +238,8 @@ fn check_main_fn_ty(ccx: &CrateCtxt, } _ => () } - let se_ty = tcx.mk_fn(Some(DefId::local(main_id)), tcx.mk_bare_fn(ty::BareFnTy { + let main_def_id = tcx.map.local_def_id(main_id); + let se_ty = tcx.mk_fn(Some(main_def_id), tcx.mk_bare_fn(ty::BareFnTy { unsafety: hir::Unsafety::Normal, abi: abi::Rust, sig: ty::Binder(ty::FnSig { @@ -285,7 +285,8 @@ fn check_start_fn_ty(ccx: &CrateCtxt, _ => () } - let se_ty = tcx.mk_fn(Some(DefId::local(start_id)), tcx.mk_bare_fn(ty::BareFnTy { + let se_ty = tcx.mk_fn(Some(ccx.tcx.map.local_def_id(start_id)), + tcx.mk_bare_fn(ty::BareFnTy { unsafety: hir::Unsafety::Normal, abi: abi::Rust, sig: ty::Binder(ty::FnSig { diff --git a/src/librustc_typeck/variance.rs b/src/librustc_typeck/variance.rs index 229c52a4e5..8152e685d8 100644 --- a/src/librustc_typeck/variance.rs +++ b/src/librustc_typeck/variance.rs @@ -266,7 +266,7 @@ use self::ParamKind::*; use arena; use arena::TypedArena; -use middle::def_id::{DefId, LOCAL_CRATE}; +use middle::def_id::DefId; use middle::resolve_lifetime as rl; use middle::subst; use middle::subst::{ParamSpace, FnSpace, TypeSpace, SelfSpace, VecPerParamSpace}; @@ -403,10 +403,10 @@ fn lang_items(tcx: &ty::ctxt) -> Vec<(ast::NodeId,Vec)> { ]; - all.into_iter() + all.into_iter() // iterating over (Option, Variance) .filter(|&(ref d,_)| d.is_some()) - .filter(|&(ref d,_)| d.as_ref().unwrap().is_local()) - .map(|(d, v)| (d.unwrap().node, v)) + .map(|(d, v)| (d.unwrap(), v)) // (DefId, Variance) + .filter_map(|(d, v)| tcx.map.as_local_node_id(d).map(|n| (n, v))) // (NodeId, Variance) .collect() } @@ -451,9 +451,10 @@ impl<'a, 'tcx> TermsContext<'a, 'tcx> { // "invalid item id" from "item id with no // parameters". if self.num_inferred() == inferreds_on_entry { + let item_def_id = self.tcx.map.local_def_id(item_id); let newly_added = self.tcx.item_variance_map.borrow_mut().insert( - DefId::local(item_id), + item_def_id, self.empty_variances.clone()).is_none(); assert!(newly_added); } @@ -486,7 +487,7 @@ impl<'a, 'tcx> TermsContext<'a, 'tcx> { param_id={}, \ inf_index={:?}, \ initial_variance={:?})", - self.tcx.item_path_str(DefId::local(item_id)), + self.tcx.item_path_str(self.tcx.map.local_def_id(item_id)), item_id, kind, space, index, param_id, inf_index, initial_variance); } @@ -596,8 +597,8 @@ fn add_constraints_from_crate<'a, 'tcx>(terms_cx: TermsContext<'a, 'tcx>, impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { - let did = DefId::local(item.id); let tcx = self.terms_cx.tcx; + let did = tcx.map.local_def_id(item.id); debug!("visit_item item={}", tcx.map.node_to_string(item.id)); @@ -739,11 +740,11 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { -> VarianceTermPtr<'a> { assert_eq!(param_def_id.krate, item_def_id.krate); - if param_def_id.is_local() { + if let Some(param_node_id) = self.tcx().map.as_local_node_id(param_def_id) { // Parameter on an item defined within current crate: // variance not yet inferred, so return a symbolic // variance. - let InferredIndex(index) = self.inferred_index(param_def_id.node); + let InferredIndex(index) = self.inferred_index(param_node_id); self.terms_cx.inferred_infos[index].term } else { // Parameter on an item defined within another crate: @@ -922,8 +923,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { ty::TyParam(ref data) => { let def_id = generics.types.get(data.space, data.idx as usize).def_id; - assert_eq!(def_id.krate, LOCAL_CRATE); - match self.terms_cx.inferred_map.get(&def_id.node) { + let node_id = self.tcx().map.as_local_node_id(def_id).unwrap(); + match self.terms_cx.inferred_map.get(&node_id) { Some(&index) => { self.add_constraint(index, variance); } @@ -1011,8 +1012,9 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { variance: VarianceTermPtr<'a>) { match region { ty::ReEarlyBound(ref data) => { - if self.is_to_be_inferred(data.param_id) { - let index = self.inferred_index(data.param_id); + let node_id = self.tcx().map.as_local_node_id(data.def_id).unwrap(); + if self.is_to_be_inferred(node_id) { + let index = self.inferred_index(node_id); self.add_constraint(index, variance); } } @@ -1163,7 +1165,7 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> { item_id, item_variances); - let item_def_id = DefId::local(item_id); + let item_def_id = tcx.map.local_def_id(item_id); // For unit testing: check for a special "rustc_variance" // attribute and report an error with various results if found. diff --git a/src/librustc_unicode/char.rs b/src/librustc_unicode/char.rs index e08b324410..2fb15ff2ac 100644 --- a/src/librustc_unicode/char.rs +++ b/src/librustc_unicode/char.rs @@ -49,7 +49,9 @@ pub struct ToLowercase(CaseMappingIter); #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for ToLowercase { type Item = char; - fn next(&mut self) -> Option { self.0.next() } + fn next(&mut self) -> Option { + self.0.next() + } } /// An iterator over the uppercase mapping of a given character, returned from @@ -61,7 +63,9 @@ pub struct ToUppercase(CaseMappingIter); #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for ToUppercase { type Item = char; - fn next(&mut self) -> Option { self.0.next() } + fn next(&mut self) -> Option { + self.0.next() + } } @@ -69,7 +73,7 @@ enum CaseMappingIter { Three(char, char, char), Two(char, char), One(char), - Zero + Zero, } impl CaseMappingIter { @@ -110,57 +114,130 @@ impl Iterator for CaseMappingIter { #[stable(feature = "rust1", since = "1.0.0")] #[lang = "char"] impl char { - /// Checks if a `char` parses as a numeric digit in the given radix. + /// Checks if a `char` is a digit in the given radix. + /// + /// A 'radix' here is sometimes also called a 'base'. A radix of two + /// indicates a binary number, a radix of ten, decimal, and a radix of + /// sixteen, hexicdecimal, to give some common values. Arbitrary + /// radicum are supported. /// /// Compared to `is_numeric()`, this function only recognizes the characters /// `0-9`, `a-z` and `A-Z`. /// - /// # Return value + /// 'Digit' is defined to be only the following characters: /// - /// Returns `true` if `c` is a valid digit under `radix`, and `false` - /// otherwise. + /// * `0-9` + /// * `a-z` + /// * `A-Z` + /// + /// For a more comprehensive understanding of 'digit', see [`is_numeric()`][is_numeric]. + /// + /// [is_numeric]: #method.is_numeric /// /// # Panics /// - /// Panics if given a radix > 36. + /// Panics if given a radix larger than 36. /// /// # Examples /// + /// Basic usage: + /// /// ``` - /// let c = '1'; + /// let d = '1'; /// - /// assert!(c.is_digit(10)); + /// assert!(d.is_digit(10)); /// - /// assert!('f'.is_digit(16)); + /// let d = 'f'; + /// + /// assert!(d.is_digit(16)); + /// assert!(!d.is_digit(10)); + /// ``` + /// + /// Passing a large radix, causing a panic: + /// + /// ``` + /// use std::thread; + /// + /// let result = thread::spawn(|| { + /// let d = '1'; + /// + /// // this panics + /// d.is_digit(37); + /// }).join(); + /// + /// assert!(result.is_err()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_digit(self, radix: u32) -> bool { C::is_digit(self, radix) } + pub fn is_digit(self, radix: u32) -> bool { + C::is_digit(self, radix) + } - /// Converts a character to the corresponding digit. + /// Converts a `char` to a digit in the given radix. + /// + /// A 'radix' here is sometimes also called a 'base'. A radix of two + /// indicates a binary number, a radix of ten, decimal, and a radix of + /// sixteen, hexicdecimal, to give some common values. Arbitrary + /// radicum are supported. + /// + /// 'Digit' is defined to be only the following characters: + /// + /// * `0-9` + /// * `a-z` + /// * `A-Z` /// - /// # Return value + /// # Failure /// - /// If `c` is between '0' and '9', the corresponding value between 0 and - /// 9. If `c` is 'a' or 'A', 10. If `c` is 'b' or 'B', 11, etc. Returns - /// none if the character does not refer to a digit in the given radix. + /// Returns `None` if the `char` does not refer to a digit in the given radix. /// /// # Panics /// - /// Panics if given a radix outside the range [0..36]. + /// Panics if given a radix larger than 36. /// /// # Examples /// + /// Basic usage: + /// + /// ``` + /// let d = '1'; + /// + /// assert_eq!(d.to_digit(10), Some(1)); + /// + /// let d = 'f'; + /// + /// assert_eq!(d.to_digit(16), Some(15)); + /// ``` + /// + /// Passing a non-digit results in failure: + /// + /// ``` + /// let d = 'f'; + /// + /// assert_eq!(d.to_digit(10), None); + /// + /// let d = 'z'; + /// + /// assert_eq!(d.to_digit(16), None); + /// ``` + /// + /// Passing a large radix, causing a panic: + /// /// ``` - /// let c = '1'; + /// use std::thread; /// - /// assert_eq!(c.to_digit(10), Some(1)); + /// let result = thread::spawn(|| { + /// let d = '1'; /// - /// assert_eq!('f'.to_digit(16), Some(15)); + /// d.to_digit(37); + /// }).join(); + /// + /// assert!(result.is_err()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn to_digit(self, radix: u32) -> Option { C::to_digit(self, radix) } + pub fn to_digit(self, radix: u32) -> Option { + C::to_digit(self, radix) + } /// Returns an iterator that yields the hexadecimal Unicode escape of a /// character, as `char`s. @@ -193,23 +270,33 @@ impl char { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn escape_unicode(self) -> EscapeUnicode { C::escape_unicode(self) } + pub fn escape_unicode(self) -> EscapeUnicode { + C::escape_unicode(self) + } - /// Returns an iterator that yields the 'default' ASCII and - /// C++11-like literal escape of a character, as `char`s. + /// Returns an iterator that yields the literal escape code of a `char`. /// /// The default is chosen with a bias toward producing literals that are /// legal in a variety of languages, including C++11 and similar C-family /// languages. The exact rules are: /// - /// * Tab, CR and LF are escaped as '\t', '\r' and '\n' respectively. - /// * Single-quote, double-quote and backslash chars are backslash- - /// escaped. - /// * Any other chars in the range [0x20,0x7e] are not escaped. - /// * Any other chars are given hex Unicode escapes; see `escape_unicode`. + /// * Tab is escaped as `\t`. + /// * Carriage return is escaped as `\r`. + /// * Line feed is escaped as `\n`. + /// * Single quote is escaped as `\'`. + /// * Double quote is escaped as `\"`. + /// * Backslash is escaped as `\\`. + /// * Any character in the 'printable ASCII' range `0x20` .. `0x7e` + /// inclusive is not escaped. + /// * All other characters are given hexadecimal Unicode escapes; see + /// [`escape_unicode`][escape_unicode]. + /// + /// [escape_unicode]: #method.escape_unicode /// /// # Examples /// + /// Basic usage: + /// /// ``` /// for i in '"'.escape_default() { /// println!("{}", i); @@ -232,35 +319,82 @@ impl char { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn escape_default(self) -> EscapeDefault { C::escape_default(self) } + pub fn escape_default(self) -> EscapeDefault { + C::escape_default(self) + } - /// Returns the number of bytes this character would need if encoded in - /// UTF-8. + /// Returns the number of bytes this `char` would need if encoded in UTF-8. + /// + /// That number of bytes is always between 1 and 4, inclusive. /// /// # Examples /// + /// Basic usage: + /// /// ``` - /// let n = 'ß'.len_utf8(); + /// let len = 'A'.len_utf8(); + /// assert_eq!(len, 1); + /// + /// let len = 'ß'.len_utf8(); + /// assert_eq!(len, 2); + /// + /// let len = 'ℝ'.len_utf8(); + /// assert_eq!(len, 3); /// - /// assert_eq!(n, 2); + /// let len = '💣'.len_utf8(); + /// assert_eq!(len, 4); + /// ``` + /// + /// The `&str` type guarantees that its contents are UTF-8, and so we can compare the length it + /// would take if each code point was represented as a `char` vs in the `&str` itself: + /// + /// ``` + /// // as chars + /// let eastern = '東'; + /// let capitol = '京'; + /// + /// // both can be represented as three bytes + /// assert_eq!(3, eastern.len_utf8()); + /// assert_eq!(3, capitol.len_utf8()); + /// + /// // as a &str, these two are encoded in UTF-8 + /// let tokyo = "東京"; + /// + /// let len = eastern.len_utf8() + capitol.len_utf8(); + /// + /// // we can see that they take six bytes total... + /// assert_eq!(6, tokyo.len()); + /// + /// // ... just like the &str + /// assert_eq!(len, tokyo.len()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn len_utf8(self) -> usize { C::len_utf8(self) } + pub fn len_utf8(self) -> usize { + C::len_utf8(self) + } - /// Returns the number of 16-bit code units this character would need if + /// Returns the number of 16-bit code units this `char` would need if /// encoded in UTF-16. /// + /// See the documentation for [`len_utf8()`][len_utf8] for more explanation + /// of this concept. This function is a mirror, but for UTF-16 instead of + /// UTF-8. + /// /// # Examples /// /// ``` /// let n = 'ß'.len_utf16(); - /// /// assert_eq!(n, 1); + /// + /// let len = '💣'.len_utf16(); + /// assert_eq!(len, 2); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn len_utf16(self) -> usize { C::len_utf16(self) } + pub fn len_utf16(self) -> usize { + C::len_utf16(self) + } /// Encodes this character as UTF-8 into the provided byte buffer, and then /// returns the number of bytes written. @@ -342,32 +476,50 @@ impl char { C::encode_utf16(self, dst) } - /// Returns whether the specified character is considered a Unicode - /// alphabetic code point. + /// Returns true if this `char` is an alphabetic code point, and false if not. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let c = 'a'; + /// + /// assert!(c.is_alphabetic()); + /// + /// let c = '京'; + /// assert!(c.is_alphabetic()); + /// + /// let c = '💝'; + /// // love is many things, but it is not alphabetic + /// assert!(!c.is_alphabetic()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn is_alphabetic(self) -> bool { match self { - 'a' ... 'z' | 'A' ... 'Z' => true, + 'a'...'z' | 'A'...'Z' => true, c if c > '\x7f' => derived_property::Alphabetic(c), - _ => false + _ => false, } } - /// Returns whether the specified character satisfies the 'XID_Start' - /// Unicode property. + /// Returns true if this `char` satisfies the 'XID_Start' Unicode property, and false + /// otherwise. /// /// 'XID_Start' is a Unicode Derived Property specified in /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications), - /// mostly similar to ID_Start but modified for closure under NFKx. + /// mostly similar to `ID_Start` but modified for closure under `NFKx`. #[unstable(feature = "unicode", reason = "mainly needed for compiler internals", issue = "0")] #[inline] - pub fn is_xid_start(self) -> bool { derived_property::XID_Start(self) } + pub fn is_xid_start(self) -> bool { + derived_property::XID_Start(self) + } - /// Returns whether the specified `char` satisfies the 'XID_Continue' - /// Unicode property. + /// Returns true if this `char` satisfies the 'XID_Continue' Unicode property, and false + /// otherwise. /// /// 'XID_Continue' is a Unicode Derived Property specified in /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications), @@ -376,93 +528,249 @@ impl char { reason = "mainly needed for compiler internals", issue = "0")] #[inline] - pub fn is_xid_continue(self) -> bool { derived_property::XID_Continue(self) } + pub fn is_xid_continue(self) -> bool { + derived_property::XID_Continue(self) + } - /// Indicates whether a character is in lowercase. + /// Returns true if this `char` is lowercase, and false otherwise. /// - /// This is defined according to the terms of the Unicode Derived Core + /// 'Lowercase' is defined according to the terms of the Unicode Derived Core /// Property `Lowercase`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let c = 'a'; + /// assert!(c.is_lowercase()); + /// + /// let c = 'δ'; + /// assert!(c.is_lowercase()); + /// + /// let c = 'A'; + /// assert!(!c.is_lowercase()); + /// + /// let c = 'Δ'; + /// assert!(!c.is_lowercase()); + /// + /// // The various Chinese scripts do not have case, and so: + /// let c = '中'; + /// assert!(!c.is_lowercase()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn is_lowercase(self) -> bool { match self { - 'a' ... 'z' => true, + 'a'...'z' => true, c if c > '\x7f' => derived_property::Lowercase(c), - _ => false + _ => false, } } - /// Indicates whether a character is in uppercase. + /// Returns true if this `char` is uppercase, and false otherwise. /// - /// This is defined according to the terms of the Unicode Derived Core + /// 'Uppercase' is defined according to the terms of the Unicode Derived Core /// Property `Uppercase`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let c = 'a'; + /// assert!(!c.is_uppercase()); + /// + /// let c = 'δ'; + /// assert!(!c.is_uppercase()); + /// + /// let c = 'A'; + /// assert!(c.is_uppercase()); + /// + /// let c = 'Δ'; + /// assert!(c.is_uppercase()); + /// + /// // The various Chinese scripts do not have case, and so: + /// let c = '中'; + /// assert!(!c.is_uppercase()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn is_uppercase(self) -> bool { match self { - 'A' ... 'Z' => true, + 'A'...'Z' => true, c if c > '\x7f' => derived_property::Uppercase(c), - _ => false + _ => false, } } - /// Indicates whether a character is whitespace. + /// Returns true if this `char` is whitespace, and false otherwise. + /// + /// 'Whitespace' is defined according to the terms of the Unicode Derived Core + /// Property `White_Space`. + /// + /// # Examples /// - /// Whitespace is defined in terms of the Unicode Property `White_Space`. + /// Basic usage: + /// + /// ``` + /// let c = ' '; + /// assert!(c.is_whitespace()); + /// + /// // a non-breaking space + /// let c = '\u{A0}'; + /// assert!(c.is_whitespace()); + /// + /// let c = '越'; + /// assert!(!c.is_whitespace()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn is_whitespace(self) -> bool { match self { - ' ' | '\x09' ... '\x0d' => true, + ' ' | '\x09'...'\x0d' => true, c if c > '\x7f' => property::White_Space(c), - _ => false + _ => false, } } - /// Indicates whether a character is alphanumeric. + /// Returns true if this `char` is alphanumeric, and false otherwise. /// - /// Alphanumericness is defined in terms of the Unicode General Categories + /// 'Alphanumeric'-ness is defined in terms of the Unicode General Categories /// 'Nd', 'Nl', 'No' and the Derived Core Property 'Alphabetic'. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let c = 'Ù£'; + /// assert!(c.is_alphanumeric()); + /// + /// let c = '7'; + /// assert!(c.is_alphanumeric()); + /// + /// let c = '৬'; + /// assert!(c.is_alphanumeric()); + /// + /// let c = 'K'; + /// assert!(c.is_alphanumeric()); + /// + /// let c = 'و'; + /// assert!(c.is_alphanumeric()); + /// + /// let c = '藏'; + /// assert!(c.is_alphanumeric()); + /// + /// let c = '¾'; + /// assert!(!c.is_alphanumeric()); + /// + /// let c = '①'; + /// assert!(!c.is_alphanumeric()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn is_alphanumeric(self) -> bool { self.is_alphabetic() || self.is_numeric() } - /// Indicates whether a character is a control code point. + /// Returns true if this `char` is a control code point, and false otherwise. /// - /// Control code points are defined in terms of the Unicode General + /// 'Control code point' is defined in terms of the Unicode General /// Category `Cc`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// // U+009C, STRING TERMINATOR + /// let c = 'œ'; + /// assert!(c.is_control()); + /// + /// let c = 'q'; + /// assert!(!c.is_control()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_control(self) -> bool { general_category::Cc(self) } + pub fn is_control(self) -> bool { + general_category::Cc(self) + } - /// Indicates whether the character is numeric (Nd, Nl, or No). + /// Returns true if this `char` is numeric, and false otherwise. + /// + /// 'Numeric'-ness is defined in terms of the Unicode General Categories + /// 'Nd', 'Nl', 'No'. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let c = 'Ù£'; + /// assert!(c.is_numeric()); + /// + /// let c = '7'; + /// assert!(c.is_numeric()); + /// + /// let c = '৬'; + /// assert!(c.is_numeric()); + /// + /// let c = 'K'; + /// assert!(!c.is_numeric()); + /// + /// let c = 'و'; + /// assert!(!c.is_numeric()); + /// + /// let c = '藏'; + /// assert!(!c.is_numeric()); + /// + /// let c = '¾'; + /// assert!(!c.is_numeric()); + /// + /// let c = '①'; + /// assert!(!c.is_numeric()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn is_numeric(self) -> bool { match self { - '0' ... '9' => true, + '0'...'9' => true, c if c > '\x7f' => general_category::N(c), - _ => false + _ => false, } } - /// Converts a character to its lowercase equivalent. + /// Returns an iterator that yields the lowercase equivalent of a `char`. /// - /// This performs complex unconditional mappings with no tailoring. - /// See `to_uppercase()` for references and more information. + /// If no conversion is possible then an iterator with just the input character is returned. /// - /// # Return value + /// This performs complex unconditional mappings with no tailoring: it maps + /// one Unicode character to its lowercase equivalent according to the + /// [Unicode database] and the additional complex mappings + /// [`SpecialCasing.txt`]. Conditional mappings (based on context or + /// language) are not considered here. /// - /// Returns an iterator which yields the characters corresponding to the - /// lowercase equivalent of the character. If no conversion is possible then - /// an iterator with just the input character is returned. + /// For a full reference, see [here][reference]. + /// + /// [Unicode database]: ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt + /// + /// [`SpecialCasing.txt`]: ftp://ftp.unicode.org/Public/UNIDATA/SpecialCasing.txt + /// + /// [reference]: http://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G33992 /// /// # Examples /// + /// Basic usage: + /// /// ``` - /// assert_eq!(Some('c'), 'C'.to_lowercase().next()); + /// let c = 'c'; + /// + /// assert_eq!(c.to_uppercase().next(), Some('C')); + /// + /// // Japanese scripts do not have case, and so: + /// let c = 'å±±'; + /// assert_eq!(c.to_uppercase().next(), Some('å±±')); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -470,33 +778,63 @@ impl char { ToLowercase(CaseMappingIter::new(conversions::to_lower(self))) } - /// Converts a character to its uppercase equivalent. - /// - /// This performs complex unconditional mappings with no tailoring: - /// it maps one Unicode character to its uppercase equivalent - /// according to the Unicode database [1] - /// and the additional complex mappings [`SpecialCasing.txt`]. - /// Conditional mappings (based on context or language) are not considered here. + /// Returns an iterator that yields the uppercase equivalent of a `char`. /// - /// A full reference can be found here [2]. + /// If no conversion is possible then an iterator with just the input character is returned. /// - /// # Return value + /// This performs complex unconditional mappings with no tailoring: it maps + /// one Unicode character to its uppercase equivalent according to the + /// [Unicode database] and the additional complex mappings + /// [`SpecialCasing.txt`]. Conditional mappings (based on context or + /// language) are not considered here. /// - /// Returns an iterator which yields the characters corresponding to the - /// uppercase equivalent of the character. If no conversion is possible then - /// an iterator with just the input character is returned. + /// For a full reference, see [here][reference]. /// - /// [1]: ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt + /// [Unicode database]: ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt /// /// [`SpecialCasing.txt`]: ftp://ftp.unicode.org/Public/UNIDATA/SpecialCasing.txt /// - /// [2]: http://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G33992 + /// [reference]: http://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G33992 /// /// # Examples /// + /// Basic usage: + /// + /// ``` + /// let c = 'c'; + /// assert_eq!(c.to_uppercase().next(), Some('C')); + /// + /// // Japanese does not have case, and so: + /// let c = 'å±±'; + /// assert_eq!(c.to_uppercase().next(), Some('å±±')); + /// ``` + /// + /// In Turkish, the equivalent of 'i' in Latin has five forms instead of two: + /// + /// * 'Dotless': I / ı, sometimes written ï + /// * 'Dotted': Ä° / i + /// + /// Note that the lowercase dotted 'i' is the same as the Latin. Therefore: + /// + /// ``` + /// let i = 'i'; + /// + /// let upper_i = i.to_uppercase().next(); + /// ``` + /// + /// The value of `upper_i` here relies on the language of the text: if we're + /// in `en-US`, it should be `Some('I')`, but if we're in `tr_TR`, it should + /// be `Some('Ä°')`. `to_uppercase()` does not take this into account, and so: + /// /// ``` - /// assert_eq!(Some('C'), 'c'.to_uppercase().next()); + /// let i = 'i'; + /// + /// let upper_i = i.to_uppercase().next(); + /// + /// assert_eq!(Some('I'), upper_i); /// ``` + /// + /// holds across languages. #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn to_uppercase(self) -> ToUppercase { @@ -504,15 +842,17 @@ impl char { } } -/// An iterator that decodes UTF-16 encoded codepoints from an iterator of `u16`s. +/// An iterator that decodes UTF-16 encoded code points from an iterator of `u16`s. #[unstable(feature = "decode_utf16", reason = "recently exposed", issue = "27830")] #[derive(Clone)] -pub struct DecodeUtf16 where I: Iterator { +pub struct DecodeUtf16 + where I: Iterator +{ iter: I, buf: Option, } -/// Create an iterator over the UTF-16 encoded codepoints in `iterable`, +/// Create an iterator over the UTF-16 encoded code points in `iterable`, /// returning unpaired surrogates as `Err`s. /// /// # Examples @@ -558,7 +898,7 @@ pub struct DecodeUtf16 where I: Iterator { /// ``` #[unstable(feature = "decode_utf16", reason = "recently exposed", issue = "27830")] #[inline] -pub fn decode_utf16>(iterable: I) -> DecodeUtf16 { +pub fn decode_utf16>(iterable: I) -> DecodeUtf16 { DecodeUtf16 { iter: iterable.into_iter(), buf: None, @@ -574,8 +914,8 @@ impl> Iterator for DecodeUtf16 { Some(buf) => buf, None => match self.iter.next() { Some(u) => u, - None => return None - } + None => return None, + }, }; if u < 0xD800 || 0xDFFF < u { @@ -588,13 +928,13 @@ impl> Iterator for DecodeUtf16 { let u2 = match self.iter.next() { Some(u2) => u2, // eof - None => return Some(Err(u)) + None => return Some(Err(u)), }; if u2 < 0xDC00 || u2 > 0xDFFF { // not a trailing surrogate so we're not a valid // surrogate pair, so rewind to redecode u2 next time. self.buf = Some(u2); - return Some(Err(u)) + return Some(Err(u)); } // all ok, so lets decode it. @@ -612,7 +952,8 @@ impl> Iterator for DecodeUtf16 { } } -/// U+FFFD REPLACEMENT CHARACTER (�) is used in Unicode to represent a decoding error. -/// It can occur, for example, when giving ill-formed UTF-8 bytes to `String::from_utf8_lossy`. +/// `U+FFFD REPLACEMENT CHARACTER` (�) is used in Unicode to represent a decoding error. +/// It can occur, for example, when giving ill-formed UTF-8 bytes to +/// [`String::from_utf8_lossy`](../string/struct.String.html#method.from_utf8_lossy). #[unstable(feature = "decode_utf16", reason = "recently added", issue = "27830")] pub const REPLACEMENT_CHARACTER: char = '\u{FFFD}'; diff --git a/src/librustc_unicode/lib.rs b/src/librustc_unicode/lib.rs index 4f0aa69d77..467c974690 100644 --- a/src/librustc_unicode/lib.rs +++ b/src/librustc_unicode/lib.rs @@ -34,7 +34,6 @@ test(no_crate_inject))] #![no_std] -#![feature(char_from_unchecked)] #![feature(core_char_ext)] #![feature(core_slice_ext)] #![feature(core_str_ext)] diff --git a/src/librustc_unicode/u_str.rs b/src/librustc_unicode/u_str.rs index 67333c98fc..2347cdebf2 100644 --- a/src/librustc_unicode/u_str.rs +++ b/src/librustc_unicode/u_str.rs @@ -10,8 +10,8 @@ //! Unicode-intensive string manipulations. //! -//! This module provides functionality to `str` that requires the Unicode methods provided by the -//! unicode parts of the CharExt trait. +//! This module provides functionality to `str` that requires the Unicode +//! methods provided by the unicode parts of the CharExt trait. use char::{DecodeUtf16, decode_utf16}; use core::char; @@ -40,20 +40,28 @@ pub trait UnicodeStr { impl UnicodeStr for str { #[inline] fn split_whitespace(&self) -> SplitWhitespace { - fn is_not_empty(s: &&str) -> bool { !s.is_empty() } + fn is_not_empty(s: &&str) -> bool { + !s.is_empty() + } let is_not_empty: fn(&&str) -> bool = is_not_empty; // coerce to fn pointer - fn is_whitespace(c: char) -> bool { c.is_whitespace() } + fn is_whitespace(c: char) -> bool { + c.is_whitespace() + } let is_whitespace: fn(char) -> bool = is_whitespace; // coerce to fn pointer SplitWhitespace { inner: self.split(is_whitespace).filter(is_not_empty) } } #[inline] - fn is_whitespace(&self) -> bool { self.chars().all(|c| c.is_whitespace()) } + fn is_whitespace(&self) -> bool { + self.chars().all(|c| c.is_whitespace()) + } #[inline] - fn is_alphanumeric(&self) -> bool { self.chars().all(|c| c.is_alphanumeric()) } + fn is_alphanumeric(&self) -> bool { + self.chars().all(|c| c.is_alphanumeric()) + } #[inline] fn trim(&self) -> &str { @@ -111,8 +119,9 @@ pub fn is_utf16(v: &[u16]) -> bool { Some(_) => {} None => { let u2 = next!(false); - if u < 0xD7FF || u > 0xDBFF || - u2 < 0xDC00 || u2 > 0xDFFF { return false; } + if u < 0xD7FF || u > 0xDBFF || u2 < 0xDC00 || u2 > 0xDFFF { + return false; + } } } } @@ -125,7 +134,7 @@ pub fn is_utf16(v: &[u16]) -> bool { #[allow(deprecated)] #[derive(Clone)] pub struct Utf16Items<'a> { - decoder: DecodeUtf16>> + decoder: DecodeUtf16>>, } /// The possibilities for values decoded from a `u16` stream. @@ -137,7 +146,7 @@ pub enum Utf16Item { /// A valid codepoint. ScalarValue(char), /// An invalid surrogate without its pair. - LoneSurrogate(u16) + LoneSurrogate(u16), } #[allow(deprecated)] @@ -148,7 +157,7 @@ impl Utf16Item { pub fn to_char_lossy(&self) -> char { match *self { Utf16Item::ScalarValue(c) => c, - Utf16Item::LoneSurrogate(_) => '\u{FFFD}' + Utf16Item::LoneSurrogate(_) => '\u{FFFD}', } } } @@ -160,9 +169,11 @@ impl<'a> Iterator for Utf16Items<'a> { type Item = Utf16Item; fn next(&mut self) -> Option { - self.decoder.next().map(|result| match result { - Ok(c) => Utf16Item::ScalarValue(c), - Err(s) => Utf16Item::LoneSurrogate(s), + self.decoder.next().map(|result| { + match result { + Ok(c) => Utf16Item::ScalarValue(c), + Err(s) => Utf16Item::LoneSurrogate(s), + } }) } @@ -209,13 +220,18 @@ pub fn utf16_items<'a>(v: &'a [u16]) -> Utf16Items<'a> { #[derive(Clone)] pub struct Utf16Encoder { chars: I, - extra: u16 + extra: u16, } impl Utf16Encoder { /// Create a UTF-16 encoder from any `char` iterator. - pub fn new(chars: I) -> Utf16Encoder where I: Iterator { - Utf16Encoder { chars: chars, extra: 0 } + pub fn new(chars: I) -> Utf16Encoder + where I: Iterator + { + Utf16Encoder { + chars: chars, + extra: 0, + } } } @@ -233,7 +249,9 @@ impl Iterator for Utf16Encoder where I: Iterator { let mut buf = [0; 2]; self.chars.next().map(|ch| { let n = CharExt::encode_utf16(ch, &mut buf).unwrap_or(0); - if n == 2 { self.extra = buf[1]; } + if n == 2 { + self.extra = buf[1]; + } buf[0] }) } @@ -251,8 +269,12 @@ impl Iterator for Utf16Encoder where I: Iterator { impl<'a> Iterator for SplitWhitespace<'a> { type Item = &'a str; - fn next(&mut self) -> Option<&'a str> { self.inner.next() } + fn next(&mut self) -> Option<&'a str> { + self.inner.next() + } } impl<'a> DoubleEndedIterator for SplitWhitespace<'a> { - fn next_back(&mut self) -> Option<&'a str> { self.inner.next_back() } + 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 c9af86f06d..ee772411c4 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -13,7 +13,7 @@ use std::collections::HashSet; use syntax::ast; -use rustc_front::attr::AttrMetaMethods; +use syntax::attr::AttrMetaMethods; use rustc_front::hir; use rustc::metadata::csearch; @@ -43,7 +43,7 @@ use super::{Clean, ToSource}; /// /// The returned value is `None` if the `id` could not be inlined, and `Some` /// of a vector of items if it was successfully expanded. -pub fn try_inline(cx: &DocContext, id: ast::NodeId, into: Option) +pub fn try_inline(cx: &DocContext, id: ast::NodeId, into: Option) -> Option> { let tcx = match cx.tcx_opt() { Some(tcx) => tcx, @@ -317,10 +317,11 @@ pub fn build_impl(cx: &DocContext, ty::ConstTraitItem(ref assoc_const) => { let did = assoc_const.def_id; let type_scheme = tcx.lookup_item_type(did); - let default = match assoc_const.default { - Some(_) => Some(const_eval::lookup_const_by_id(tcx, did, None) - .unwrap().span.to_src(cx)), - None => None, + let default = if assoc_const.has_value { + Some(const_eval::lookup_const_by_id(tcx, did, None) + .unwrap().span.to_src(cx)) + } else { + None }; Some(clean::Item { name: Some(assoc_const.name.clean(cx)), @@ -339,9 +340,6 @@ pub fn build_impl(cx: &DocContext, if method.vis != hir::Public && associated_trait.is_none() { return None } - if method.provided_source.is_some() { - return None - } let mut item = method.clean(cx); item.inner = match item.inner.clone() { clean::TyMethodItem(clean::TyMethod { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 7ef359787e..75144ff27b 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -27,6 +27,8 @@ pub use self::FunctionRetTy::*; use syntax; use syntax::abi; use syntax::ast; +use syntax::attr; +use syntax::attr::{AttributeMethods, AttrMetaMethods}; use syntax::codemap; use syntax::codemap::{DUMMY_SP, Pos, Spanned}; use syntax::parse::token::{self, InternedString, special_idents}; @@ -37,15 +39,12 @@ use rustc::metadata::cstore; use rustc::metadata::csearch; use rustc::metadata::decoder; use rustc::middle::def; -use rustc::middle::def_id::{DefId, LOCAL_CRATE}; +use rustc::middle::def_id::{DefId, DefIndex}; use rustc::middle::subst::{self, ParamSpace, VecPerParamSpace}; use rustc::middle::ty; use rustc::middle::stability; use rustc_front::hir; -use rustc_front::attr; -use rustc_front::attr::{AttributeMethods, AttrMetaMethods}; -use rustc_front::lowering::unlower_attribute; use std::collections::HashMap; use std::path::PathBuf; @@ -143,8 +142,7 @@ impl<'a, 'tcx> Clean for visit_ast::RustdocVisitor<'a, 'tcx> { // Figure out the name of this crate let input = &cx.input; - let attrs: Vec<_> = self.attrs.iter().map(|a| unlower_attribute(a)).collect(); - let name = link::find_crate_name(None, &attrs, input); + let name = link::find_crate_name(None, &self.attrs, input); // Clean the crate, translating the entire libsyntax AST to one that is // understood by rustdoc. @@ -155,7 +153,7 @@ impl<'a, 'tcx> Clean for visit_ast::RustdocVisitor<'a, 'tcx> { // // Note that this loop only searches the top-level items of the crate, // and this is intentional. If we were to search the entire crate for an - // item tagged with `#[doc(primitive)]` then we we would also have to + // item tagged with `#[doc(primitive)]` then we would also have to // search the entirety of external modules for items tagged // `#[doc(primitive)]`, which is a pretty inefficient process (decoding // all that metadata unconditionally). @@ -190,7 +188,7 @@ impl<'a, 'tcx> Clean for visit_ast::RustdocVisitor<'a, 'tcx> { attrs: child.attrs.clone(), visibility: Some(hir::Public), stability: None, - def_id: DefId::local(prim.to_node_id()), + def_id: DefId::local(prim.to_def_index()), inner: PrimitiveItem(prim), }); } @@ -326,8 +324,8 @@ impl Item { match self.stability { Some(ref s) => { let mut base = match s.level { - attr::Unstable => "unstable".to_string(), - attr::Stable => String::new(), + stability::Unstable => "unstable".to_string(), + stability::Stable => String::new(), }; if !s.deprecated_since.is_empty() { base.push_str(" deprecated"); @@ -421,7 +419,7 @@ impl Clean for doctree::Module { source: whence.clean(cx), visibility: self.vis.clean(cx), stability: self.stab.clean(cx), - def_id: DefId::local(self.id), + def_id: cx.map.local_def_id(self.id), inner: ModuleItem(Module { is_crate: self.is_crate, items: items @@ -437,21 +435,21 @@ pub enum Attribute { NameValue(String, String) } -impl Clean for hir::MetaItem { +impl Clean for ast::MetaItem { fn clean(&self, cx: &DocContext) -> Attribute { match self.node { - hir::MetaWord(ref s) => Word(s.to_string()), - hir::MetaList(ref s, ref l) => { + ast::MetaWord(ref s) => Word(s.to_string()), + ast::MetaList(ref s, ref l) => { List(s.to_string(), l.clean(cx)) } - hir::MetaNameValue(ref s, ref v) => { + ast::MetaNameValue(ref s, ref v) => { NameValue(s.to_string(), lit_to_string(v)) } } } } -impl Clean for hir::Attribute { +impl Clean for ast::Attribute { fn clean(&self, cx: &DocContext) -> Attribute { self.with_desugared_doc(|a| a.node.value.clean(cx)) } @@ -475,13 +473,13 @@ impl attr::AttrMetaMethods for Attribute { _ => None, } } - fn meta_item_list<'a>(&'a self) -> Option<&'a [P]> { None } + fn meta_item_list<'a>(&'a self) -> Option<&'a [P]> { None } fn span(&self) -> codemap::Span { unimplemented!() } } impl<'a> attr::AttrMetaMethods for &'a Attribute { fn name(&self) -> InternedString { (**self).name() } fn value_str(&self) -> Option { (**self).value_str() } - fn meta_item_list(&self) -> Option<&[P]> { None } + fn meta_item_list(&self) -> Option<&[P]> { None } fn span(&self) -> codemap::Span { unimplemented!() } } @@ -496,8 +494,8 @@ pub struct TyParam { impl Clean for hir::TyParam { fn clean(&self, cx: &DocContext) -> TyParam { TyParam { - name: self.ident.clean(cx), - did: DefId { krate: LOCAL_CRATE, node: self.id }, + name: self.name.clean(cx), + did: cx.map.local_def_id(self.id), bounds: self.bounds.clean(cx), default: self.default.clean(cx), } @@ -1089,7 +1087,7 @@ impl Clean for doctree::Function { source: self.whence.clean(cx), visibility: self.vis.clean(cx), stability: self.stab.clean(cx), - def_id: DefId::local(self.id), + def_id: cx.map.local_def_id(self.id), inner: FunctionItem(Function { decl: self.decl.clean(cx), generics: self.generics.clean(cx), @@ -1139,10 +1137,10 @@ impl<'tcx> Clean for ty::FnOutput<'tcx> { impl<'a, 'tcx> Clean for (DefId, &'a ty::PolyFnSig<'tcx>) { fn clean(&self, cx: &DocContext) -> FnDecl { let (did, sig) = *self; - let mut names = if did.node != 0 { - csearch::get_method_arg_names(&cx.tcx().sess.cstore, did).into_iter() + let mut names = if let Some(_) = cx.map.as_local_node_id(did) { + vec![].into_iter() } else { - Vec::new().into_iter() + csearch::get_method_arg_names(&cx.tcx().sess.cstore, did).into_iter() }.peekable(); if names.peek().map(|s| &**s) == Some("self") { let _ = names.next(); @@ -1212,7 +1210,7 @@ impl Clean for doctree::Trait { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - def_id: DefId::local(self.id), + def_id: cx.map.local_def_id(self.id), visibility: self.vis.clean(cx), stability: self.stab.clean(cx), inner: TraitItem(Trait { @@ -1259,12 +1257,12 @@ impl Clean for hir::TraitItem { } }; Item { - name: Some(self.ident.clean(cx)), + name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.span.clean(cx), - def_id: DefId::local(self.id), + def_id: cx.map.local_def_id(self.id), visibility: None, - stability: get_stability(cx, DefId::local(self.id)), + stability: get_stability(cx, cx.map.local_def_id(self.id)), inner: inner } } @@ -1292,12 +1290,12 @@ impl Clean for hir::ImplItem { }, true), }; Item { - name: Some(self.ident.clean(cx)), + name: Some(self.name.clean(cx)), source: self.span.clean(cx), attrs: self.attrs.clean(cx), - def_id: DefId::local(self.id), + def_id: cx.map.local_def_id(self.id), visibility: self.vis.clean(cx), - stability: get_stability(cx, DefId::local(self.id)), + stability: get_stability(cx, cx.map.local_def_id(self.id)), inner: inner } } @@ -1561,8 +1559,9 @@ impl PrimitiveType { /// Creates a rustdoc-specific node id for primitive types. /// /// These node ids are generally never used by the AST itself. - pub fn to_node_id(&self) -> ast::NodeId { - u32::MAX - 1 - (*self as u32) + pub fn to_def_index(&self) -> DefIndex { + let x = u32::MAX - 1 - (*self as u32); + DefIndex::new(x as usize) } } @@ -1585,7 +1584,7 @@ impl Clean for hir::Ty { let mut trait_path = p.clone(); trait_path.segments.pop(); Type::QPath { - name: p.segments.last().unwrap().identifier.clean(cx), + name: p.segments.last().unwrap().identifier.name.clean(cx), self_type: box qself.ty.clean(cx), trait_: box resolve_type(cx, trait_path.clean(cx), self.id) } @@ -1626,18 +1625,18 @@ impl<'tcx> Clean for ty::Ty<'tcx> { match self.sty { ty::TyBool => Primitive(Bool), ty::TyChar => Primitive(Char), - ty::TyInt(hir::TyIs) => Primitive(Isize), - ty::TyInt(hir::TyI8) => Primitive(I8), - ty::TyInt(hir::TyI16) => Primitive(I16), - ty::TyInt(hir::TyI32) => Primitive(I32), - ty::TyInt(hir::TyI64) => Primitive(I64), - ty::TyUint(hir::TyUs) => Primitive(Usize), - ty::TyUint(hir::TyU8) => Primitive(U8), - ty::TyUint(hir::TyU16) => Primitive(U16), - ty::TyUint(hir::TyU32) => Primitive(U32), - ty::TyUint(hir::TyU64) => Primitive(U64), - ty::TyFloat(hir::TyF32) => Primitive(F32), - ty::TyFloat(hir::TyF64) => Primitive(F64), + ty::TyInt(ast::TyIs) => Primitive(Isize), + ty::TyInt(ast::TyI8) => Primitive(I8), + ty::TyInt(ast::TyI16) => Primitive(I16), + ty::TyInt(ast::TyI32) => Primitive(I32), + ty::TyInt(ast::TyI64) => Primitive(I64), + ty::TyUint(ast::TyUs) => Primitive(Usize), + ty::TyUint(ast::TyU8) => Primitive(U8), + ty::TyUint(ast::TyU16) => Primitive(U16), + ty::TyUint(ast::TyU32) => Primitive(U32), + ty::TyUint(ast::TyU64) => Primitive(U64), + ty::TyFloat(ast::TyF32) => Primitive(F32), + ty::TyFloat(ast::TyF64) => Primitive(F64), ty::TyStr => Primitive(Str), ty::TyBox(t) => { let box_did = cx.tcx_opt().and_then(|tcx| { @@ -1661,7 +1660,7 @@ impl<'tcx> Clean for ty::Ty<'tcx> { type_params: Vec::new(), where_predicates: Vec::new() }, - decl: (DefId::local(0), &fty.sig).clean(cx), + decl: (cx.map.local_def_id(0), &fty.sig).clean(cx), abi: fty.abi.to_string(), }), ty::TyStruct(def, substs) | @@ -1729,8 +1728,8 @@ impl Clean for hir::StructField { attrs: self.node.attrs.clean(cx), source: self.span.clean(cx), visibility: Some(vis), - stability: get_stability(cx, DefId::local(self.node.id)), - def_id: DefId::local(self.node.id), + stability: get_stability(cx, cx.map.local_def_id(self.node.id)), + def_id: cx.map.local_def_id(self.node.id), inner: StructFieldItem(TypedStructField(self.node.ty.clean(cx))), } } @@ -1746,7 +1745,7 @@ impl<'tcx> Clean for ty::FieldDefData<'tcx, 'static> { let (name, attrs) = if self.name == unnamed_field.name { (None, None) } else { - (Some(self.name), Some(attr_map.get(&self.did.node).unwrap())) + (Some(self.name), Some(attr_map.get(&self.did).unwrap())) }; Item { @@ -1783,7 +1782,7 @@ impl Clean for doctree::Struct { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - def_id: DefId::local(self.id), + def_id: cx.map.local_def_id(self.id), visibility: self.vis.clean(cx), stability: self.stab.clean(cx), inner: StructItem(Struct { @@ -1806,11 +1805,11 @@ pub struct VariantStruct { pub fields_stripped: bool, } -impl Clean for ::rustc_front::hir::StructDef { +impl Clean for ::rustc_front::hir::VariantData { fn clean(&self, cx: &DocContext) -> VariantStruct { VariantStruct { struct_type: doctree::struct_type_from_def(self), - fields: self.fields.clean(cx), + fields: self.fields().iter().map(|x| x.clean(cx)).collect(), fields_stripped: false, } } @@ -1829,7 +1828,7 @@ impl Clean for doctree::Enum { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - def_id: DefId::local(self.id), + def_id: cx.map.local_def_id(self.id), visibility: self.vis.clean(cx), stability: self.stab.clean(cx), inner: EnumItem(Enum { @@ -1852,11 +1851,11 @@ impl Clean for doctree::Variant { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - visibility: self.vis.clean(cx), + visibility: None, stability: self.stab.clean(cx), - def_id: DefId::local(self.id), + def_id: cx.map.local_def_id(self.def.id()), inner: VariantItem(Variant { - kind: self.kind.clean(cx), + kind: struct_def_to_variant_kind(&self.def, cx), }), } } @@ -1872,7 +1871,7 @@ impl<'tcx> Clean for ty::VariantDefData<'tcx, 'static> { self.fields.iter().map(|f| f.unsubst_ty().clean(cx)).collect() ) } - ty::VariantKind::Dict => { + ty::VariantKind::Struct => { StructVariant(VariantStruct { struct_type: doctree::Plain, fields_stripped: false, @@ -1918,18 +1917,13 @@ pub enum VariantKind { StructVariant(VariantStruct), } -impl Clean for hir::VariantKind { - fn clean(&self, cx: &DocContext) -> VariantKind { - match self { - &hir::TupleVariantKind(ref args) => { - if args.is_empty() { - CLikeVariant - } else { - TupleVariant(args.iter().map(|x| x.ty.clean(cx)).collect()) - } - }, - &hir::StructVariantKind(ref sd) => StructVariant(sd.clean(cx)), - } +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.node.ty.clean(cx)).collect()) } } @@ -2046,7 +2040,7 @@ pub struct PathSegment { impl Clean for hir::PathSegment { fn clean(&self, cx: &DocContext) -> PathSegment { PathSegment { - name: self.identifier.clean(cx), + name: self.identifier.name.clean(cx), params: self.parameters.clean(cx) } } @@ -2066,12 +2060,6 @@ fn path_to_string(p: &hir::Path) -> String { s } -impl Clean for ast::Ident { - fn clean(&self, _: &DocContext) -> String { - self.to_string() - } -} - impl Clean for ast::Name { fn clean(&self, _: &DocContext) -> String { self.to_string() @@ -2090,7 +2078,7 @@ impl Clean for doctree::Typedef { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - def_id: DefId::local(self.id.clone()), + def_id: cx.map.local_def_id(self.id.clone()), visibility: self.vis.clean(cx), stability: self.stab.clean(cx), inner: TypedefItem(Typedef { @@ -2141,7 +2129,7 @@ impl Clean for doctree::Static { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - def_id: DefId::local(self.id), + def_id: cx.map.local_def_id(self.id), visibility: self.vis.clean(cx), stability: self.stab.clean(cx), inner: StaticItem(Static { @@ -2165,7 +2153,7 @@ impl Clean for doctree::Constant { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - def_id: DefId::local(self.id), + def_id: cx.map.local_def_id(self.id), visibility: self.vis.clean(cx), stability: self.stab.clean(cx), inner: ConstantItem(Constant { @@ -2239,7 +2227,7 @@ impl Clean> for doctree::Impl { name: None, attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - def_id: DefId::local(self.id), + def_id: cx.map.local_def_id(self.id), visibility: self.vis.clean(cx), stability: self.stab.clean(cx), inner: ImplItem(Impl { @@ -2321,7 +2309,7 @@ impl Clean for doctree::DefaultImpl { name: None, attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - def_id: DefId::local(self.id), + def_id: cx.map.local_def_id(self.id), visibility: Some(hir::Public), stability: None, inner: DefaultImplItem(DefaultImpl { @@ -2338,7 +2326,7 @@ impl Clean for doctree::ExternCrate { name: None, attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - def_id: DefId::local(0), + def_id: cx.map.local_def_id(0), visibility: self.vis.clean(cx), stability: None, inner: ExternCrateItem(self.name.clean(cx), self.path.clone()) @@ -2388,14 +2376,14 @@ impl Clean> for doctree::Import { (ret, ImportList(resolve_use_source(cx, p.clean(cx), self.id), remaining)) } - hir::ViewPathSimple(i, ref p) => { + hir::ViewPathSimple(name, ref p) => { if !denied { - match inline::try_inline(cx, self.id, Some(i)) { + match inline::try_inline(cx, self.id, Some(name)) { Some(items) => return items, None => {} } } - (vec![], SimpleImport(i.clean(cx), + (vec![], SimpleImport(name.clean(cx), resolve_use_source(cx, p.clean(cx), self.id))) } }; @@ -2403,7 +2391,7 @@ impl Clean> for doctree::Import { name: None, attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - def_id: DefId::local(0), + def_id: cx.map.local_def_id(0), visibility: self.vis.clean(cx), stability: None, inner: ImportItem(inner) @@ -2486,12 +2474,12 @@ impl Clean for hir::ForeignItem { } }; Item { - name: Some(self.ident.clean(cx)), + name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.span.clean(cx), - def_id: DefId::local(self.id), + def_id: cx.map.local_def_id(self.id), visibility: self.vis.clean(cx), - stability: get_stability(cx, DefId::local(self.id)), + stability: get_stability(cx, cx.map.local_def_id(self.id)), inner: inner, } } @@ -2515,11 +2503,11 @@ impl ToSource for syntax::codemap::Span { } } -fn lit_to_string(lit: &hir::Lit) -> String { +fn lit_to_string(lit: &ast::Lit) -> String { match lit.node { - hir::LitStr(ref st, _) => st.to_string(), - hir::LitByteStr(ref data) => format!("{:?}", data), - hir::LitByte(b) => { + ast::LitStr(ref st, _) => st.to_string(), + ast::LitByteStr(ref data) => format!("{:?}", data), + ast::LitByte(b) => { let mut res = String::from("b'"); for c in (b as char).escape_default() { res.push(c); @@ -2527,11 +2515,11 @@ fn lit_to_string(lit: &hir::Lit) -> String { res.push('\''); res }, - hir::LitChar(c) => format!("'{}'", c), - hir::LitInt(i, _t) => i.to_string(), - hir::LitFloat(ref f, _t) => f.to_string(), - hir::LitFloatUnsuffixed(ref f) => f.to_string(), - hir::LitBool(b) => b.to_string(), + ast::LitChar(c) => format!("'{}'", c), + ast::LitInt(i, _t) => i.to_string(), + ast::LitFloat(ref f, _t) => f.to_string(), + ast::LitFloatUnsuffixed(ref f) => f.to_string(), + ast::LitBool(b) => b.to_string(), } } @@ -2549,7 +2537,7 @@ fn name_from_pat(p: &hir::Pat) -> String { PatStruct(ref name, ref fields, etc) => { format!("{} {{ {}{} }}", path_to_string(name), fields.iter().map(|&Spanned { node: ref fp, .. }| - format!("{}: {}", fp.ident, name_from_pat(&*fp.pat))) + format!("{}: {}", fp.name, name_from_pat(&*fp.pat))) .collect::>().join(", "), if etc { ", ..." } else { "" } ) @@ -2578,34 +2566,36 @@ fn name_from_pat(p: &hir::Pat) -> String { fn resolve_type(cx: &DocContext, path: Path, id: ast::NodeId) -> Type { + debug!("resolve_type({:?},{:?})", path, id); let tcx = match cx.tcx_opt() { Some(tcx) => tcx, // If we're extracting tests, this return value doesn't matter. None => return Primitive(Bool), }; - debug!("searching for {} in defmap", id); let def = match tcx.def_map.borrow().get(&id) { Some(k) => k.full_def(), None => panic!("unresolved id not in defmap") }; + debug!("resolve_type: def={:?}", def); + let is_generic = match def { def::DefPrimTy(p) => match p { hir::TyStr => return Primitive(Str), hir::TyBool => return Primitive(Bool), hir::TyChar => return Primitive(Char), - hir::TyInt(hir::TyIs) => return Primitive(Isize), - hir::TyInt(hir::TyI8) => return Primitive(I8), - hir::TyInt(hir::TyI16) => return Primitive(I16), - hir::TyInt(hir::TyI32) => return Primitive(I32), - hir::TyInt(hir::TyI64) => return Primitive(I64), - hir::TyUint(hir::TyUs) => return Primitive(Usize), - hir::TyUint(hir::TyU8) => return Primitive(U8), - hir::TyUint(hir::TyU16) => return Primitive(U16), - hir::TyUint(hir::TyU32) => return Primitive(U32), - hir::TyUint(hir::TyU64) => return Primitive(U64), - hir::TyFloat(hir::TyF32) => return Primitive(F32), - hir::TyFloat(hir::TyF64) => return Primitive(F64), + hir::TyInt(ast::TyIs) => return Primitive(Isize), + hir::TyInt(ast::TyI8) => return Primitive(I8), + hir::TyInt(ast::TyI16) => return Primitive(I16), + hir::TyInt(ast::TyI32) => return Primitive(I32), + hir::TyInt(ast::TyI64) => return Primitive(I64), + hir::TyUint(ast::TyUs) => return Primitive(Usize), + hir::TyUint(ast::TyU8) => return Primitive(U8), + hir::TyUint(ast::TyU16) => return Primitive(U16), + hir::TyUint(ast::TyU32) => return Primitive(U32), + hir::TyUint(ast::TyU64) => return Primitive(U64), + hir::TyFloat(ast::TyF32) => return Primitive(F32), + hir::TyFloat(ast::TyF64) => return Primitive(F64), }, def::DefSelfTy(..) if path.segments.len() == 1 => { return Generic(special_idents::type_self.name.to_string()); @@ -2618,6 +2608,8 @@ fn resolve_type(cx: &DocContext, } fn register_def(cx: &DocContext, def: def::Def) -> DefId { + debug!("register_def({:?})", def); + let (did, kind) = match def { def::DefFn(i, _) => (i, TypeFunction), def::DefTy(i, false) => (i, TypeTypedef), @@ -2627,6 +2619,8 @@ fn register_def(cx: &DocContext, def: def::Def) -> DefId { def::DefMod(i) => (i, TypeModule), def::DefStatic(i, _) => (i, TypeStatic), def::DefVariant(i, _, _) => (i, TypeEnum), + def::DefSelfTy(Some(def_id), _) => (def_id, TypeTrait), + def::DefSelfTy(_, Some((impl_id, _))) => return cx.map.local_def_id(impl_id), _ => return def.def_id() }; if did.is_local() { return did } @@ -2669,7 +2663,7 @@ impl Clean for doctree::Macro { source: self.whence.clean(cx), visibility: hir::Public.clean(cx), stability: self.stab.clean(cx), - def_id: DefId::local(self.id), + def_id: cx.map.local_def_id(self.id), inner: MacroItem(Macro { source: self.whence.to_src(cx), imported_from: self.imported_from.clean(cx), @@ -2680,7 +2674,7 @@ impl Clean for doctree::Macro { #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Stability { - pub level: attr::StabilityLevel, + pub level: stability::StabilityLevel, pub feature: String, pub since: String, pub deprecated_since: String, @@ -2691,32 +2685,36 @@ pub struct Stability { impl Clean for attr::Stability { fn clean(&self, _: &DocContext) -> Stability { Stability { - level: self.level, + level: stability::StabilityLevel::from_attr_level(&self.level), feature: self.feature.to_string(), - since: self.since.as_ref().map_or("".to_string(), - |interned| interned.to_string()), - deprecated_since: self.deprecated_since.as_ref().map_or("".to_string(), - |istr| istr.to_string()), - reason: self.reason.as_ref().map_or("".to_string(), - |interned| interned.to_string()), - issue: self.issue, + since: match self.level { + attr::Stable {ref since} => since.to_string(), + _ => "".to_string(), + }, + deprecated_since: match self.depr { + Some(attr::Deprecation {ref since, ..}) => since.to_string(), + _=> "".to_string(), + }, + reason: { + if let Some(ref depr) = self.depr { + depr.reason.to_string() + } else if let attr::Unstable {reason: Some(ref reason), ..} = self.level { + reason.to_string() + } else { + "".to_string() + } + }, + issue: match self.level { + attr::Unstable {issue, ..} => Some(issue), + _ => None, + } } } } impl<'a> Clean for &'a attr::Stability { - fn clean(&self, _: &DocContext) -> Stability { - Stability { - level: self.level, - feature: self.feature.to_string(), - since: self.since.as_ref().map_or("".to_string(), - |interned| interned.to_string()), - deprecated_since: self.deprecated_since.as_ref().map_or("".to_string(), - |istr| istr.to_string()), - reason: self.reason.as_ref().map_or("".to_string(), - |interned| interned.to_string()), - issue: self.issue, - } + fn clean(&self, dc: &DocContext) -> Stability { + (**self).clean(dc) } } @@ -2842,7 +2840,7 @@ pub struct TypeBinding { impl Clean for hir::TypeBinding { fn clean(&self, cx: &DocContext) -> TypeBinding { TypeBinding { - name: self.ident.clean(cx), + name: self.name.clean(cx), ty: self.ty.clean(cx) } } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 63468dd55f..4955951d36 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -13,13 +13,13 @@ use rustc_lint; use rustc_driver::{driver, target_features}; use rustc::session::{self, config}; use rustc::middle::def_id::DefId; -use rustc::middle::{privacy, ty}; +use rustc::middle::ty; use rustc::front::map as hir_map; use rustc::lint; +use rustc::util::nodemap::DefIdSet; use rustc_trans::back::link; use rustc_resolve as resolve; -use rustc_front::lowering::lower_crate; -use rustc_front::hir; +use rustc_front::lowering::{lower_crate, LoweringContext}; use syntax::{ast, codemap, diagnostic}; use syntax::feature_gate::UnstableFeatures; @@ -37,14 +37,14 @@ pub use rustc::session::search_paths::SearchPaths; /// Are we generating documentation (`Typed`) or tests (`NotTyped`)? pub enum MaybeTyped<'a, 'tcx: 'a> { Typed(&'a ty::ctxt<'tcx>), - NotTyped(session::Session) + NotTyped(&'a session::Session) } pub type ExternalPaths = RefCell, clean::TypeKind)>>>; pub struct DocContext<'a, 'tcx: 'a> { - pub krate: &'tcx hir::Crate, + pub map: &'a hir_map::Map<'tcx>, pub maybe_typed: MaybeTyped<'a, 'tcx>, pub input: Input, pub external_paths: ExternalPaths, @@ -77,8 +77,8 @@ impl<'b, 'tcx> DocContext<'b, 'tcx> { } pub struct CrateAnalysis { - pub exported_items: privacy::ExportedItems, - pub public_items: privacy::PublicItems, + pub exported_items: DefIdSet, + pub public_items: DefIdSet, pub external_paths: ExternalPaths, pub external_typarams: RefCell>>, pub inlined: RefCell>>, @@ -135,21 +135,32 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec, externs: Externs, let krate = driver::assign_node_ids(&sess, krate); // Lower ast -> hir. - let mut hir_forest = hir_map::Forest::new(lower_crate(&krate)); + let lcx = LoweringContext::new(&sess, Some(&krate)); + let mut hir_forest = hir_map::Forest::new(lower_crate(&lcx, &krate)); let arenas = ty::CtxtArenas::new(); let hir_map = driver::make_map(&sess, &mut hir_forest); - driver::phase_3_run_analysis_passes(sess, + driver::phase_3_run_analysis_passes(&sess, hir_map, - &krate, &arenas, - name, + &name, resolve::MakeGlobMap::No, |tcx, analysis| { let ty::CrateAnalysis { exported_items, public_items, .. } = analysis; + // Convert from a NodeId set to a DefId set since we don't always have easy access + // to the map from defid -> nodeid + let exported_items: DefIdSet = + exported_items.into_iter() + .map(|n| tcx.map.local_def_id(n)) + .collect(); + let public_items: DefIdSet = + public_items.into_iter() + .map(|n| tcx.map.local_def_id(n)) + .collect(); + let ctxt = DocContext { - krate: tcx.map.krate(), + map: &tcx.map, maybe_typed: Typed(tcx), input: input, external_traits: RefCell::new(Some(HashMap::new())), @@ -159,7 +170,7 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec, externs: Externs, populated_crate_impls: RefCell::new(HashSet::new()), deref_trait_did: Cell::new(None), }; - debug!("crate: {:?}", ctxt.krate); + debug!("crate: {:?}", ctxt.map.krate()); let mut analysis = CrateAnalysis { exported_items: exported_items, @@ -172,7 +183,7 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec, externs: Externs, let krate = { let mut v = RustdocVisitor::new(&ctxt, Some(&analysis)); - v.visit(ctxt.krate); + v.visit(ctxt.map.krate()); v.clean(&ctxt) }; @@ -184,5 +195,5 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec, externs: Externs, *analysis.inlined.borrow_mut() = map; analysis.deref_trait_did = ctxt.deref_trait_did.get(); (krate, analysis) - }).1 + }) } diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 5140cca03e..9550109fe9 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -17,14 +17,14 @@ use syntax; use syntax::codemap::Span; use syntax::abi; use syntax::ast; -use syntax::ast::{Ident, NodeId}; +use syntax::ast::{Name, NodeId}; +use syntax::attr; use syntax::ptr::P; use rustc_front::hir; -use rustc_front::attr; pub struct Module { - pub name: Option, - pub attrs: Vec, + pub name: Option, + pub attrs: Vec, pub where_outer: Span, pub where_inner: Span, pub extern_crates: Vec, @@ -48,7 +48,7 @@ pub struct Module { } impl Module { - pub fn new(name: Option) -> Module { + pub fn new(name: Option) -> Module { Module { name : name, id: 0, @@ -98,9 +98,9 @@ pub struct Struct { pub stab: Option, pub id: NodeId, pub struct_type: StructType, - pub name: Ident, + pub name: Name, pub generics: hir::Generics, - pub attrs: Vec, + pub attrs: Vec, pub fields: Vec, pub whence: Span, } @@ -110,27 +110,25 @@ pub struct Enum { pub stab: Option, pub variants: Vec, pub generics: hir::Generics, - pub attrs: Vec, + pub attrs: Vec, pub id: NodeId, pub whence: Span, - pub name: Ident, + pub name: Name, } pub struct Variant { - pub name: Ident, - pub attrs: Vec, - pub kind: hir::VariantKind, - pub id: ast::NodeId, - pub vis: hir::Visibility, + pub name: Name, + pub attrs: Vec, + pub def: hir::VariantData, pub stab: Option, pub whence: Span, } pub struct Function { pub decl: hir::FnDecl, - pub attrs: Vec, + pub attrs: Vec, pub id: NodeId, - pub name: Ident, + pub name: Name, pub vis: hir::Visibility, pub stab: Option, pub unsafety: hir::Unsafety, @@ -143,9 +141,9 @@ pub struct Function { pub struct Typedef { pub ty: P, pub gen: hir::Generics, - pub name: Ident, + pub name: Name, pub id: ast::NodeId, - pub attrs: Vec, + pub attrs: Vec, pub whence: Span, pub vis: hir::Visibility, pub stab: Option, @@ -156,8 +154,8 @@ pub struct Static { pub type_: P, pub mutability: hir::Mutability, pub expr: P, - pub name: Ident, - pub attrs: Vec, + pub name: Name, + pub attrs: Vec, pub vis: hir::Visibility, pub stab: Option, pub id: ast::NodeId, @@ -167,8 +165,8 @@ pub struct Static { pub struct Constant { pub type_: P, pub expr: P, - pub name: Ident, - pub attrs: Vec, + pub name: Name, + pub attrs: Vec, pub vis: hir::Visibility, pub stab: Option, pub id: ast::NodeId, @@ -177,11 +175,11 @@ pub struct Constant { pub struct Trait { pub unsafety: hir::Unsafety, - pub name: Ident, + pub name: Name, pub items: Vec>, //should be TraitItem pub generics: hir::Generics, pub bounds: Vec, - pub attrs: Vec, + pub attrs: Vec, pub id: ast::NodeId, pub whence: Span, pub vis: hir::Visibility, @@ -195,7 +193,7 @@ pub struct Impl { pub trait_: Option, pub for_: P, pub items: Vec>, - pub attrs: Vec, + pub attrs: Vec, pub whence: Span, pub vis: hir::Visibility, pub stab: Option, @@ -206,39 +204,39 @@ pub struct DefaultImpl { pub unsafety: hir::Unsafety, pub trait_: hir::TraitRef, pub id: ast::NodeId, - pub attrs: Vec, + pub attrs: Vec, pub whence: Span, } pub struct Macro { - pub name: Ident, + pub name: Name, pub id: ast::NodeId, - pub attrs: Vec, + pub attrs: Vec, pub whence: Span, pub stab: Option, - pub imported_from: Option, + pub imported_from: Option, } pub struct ExternCrate { - pub name: Ident, + pub name: Name, pub path: Option, pub vis: hir::Visibility, - pub attrs: Vec, + pub attrs: Vec, pub whence: Span, } pub struct Import { pub id: NodeId, pub vis: hir::Visibility, - pub attrs: Vec, + pub attrs: Vec, pub node: hir::ViewPath_, pub whence: Span, } -pub fn struct_type_from_def(sd: &hir::StructDef) -> StructType { - if sd.ctor_id.is_some() { +pub fn struct_type_from_def(sd: &hir::VariantData) -> StructType { + if !sd.is_struct() { // We are in a tuple-struct - match sd.fields.len() { + match sd.fields().len() { 0 => Unit, 1 => Newtype, _ => Tuple diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 947ae3abd8..d12c5d2c6f 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -18,9 +18,9 @@ use std::fmt; use std::iter::repeat; -use rustc::middle::def_id::{DefId, LOCAL_CRATE}; +use rustc::metadata::cstore::LOCAL_CRATE; +use rustc::middle::def_id::{CRATE_DEF_INDEX, DefId}; use syntax::abi::Abi; -use syntax::ast; use rustc_front::hir; use clean; @@ -386,7 +386,7 @@ fn primitive_link(f: &mut fmt::Formatter, Some(&cnum) => { let path = &m.paths[&DefId { krate: cnum, - node: ast::CRATE_NODE_ID, + index: CRATE_DEF_INDEX, }]; let loc = match m.extern_locations[&cnum] { (_, render::Remote(ref s)) => Some(s.to_string()), diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index c98a54e451..f68e82501e 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -207,9 +207,7 @@ fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> { /// /// Any leading or trailing whitespace will be trimmed. fn collapse_whitespace(s: &str) -> String { - s.split(|c: char| c.is_whitespace()).filter(|s| { - !s.is_empty() - }).collect::>().join(" ") + s.split_whitespace().collect::>().join(" ") } thread_local!(static USED_HEADER_MAP: RefCell> = { @@ -277,25 +275,44 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { // Extract the text provided let s = if text.is_null() { - "".to_string() + "".to_owned() } else { let s = unsafe { (*text).as_bytes() }; - str::from_utf8(s).unwrap().to_string() + str::from_utf8(&s).unwrap().to_owned() }; - // Transform the contents of the header into a hyphenated string - let id = s.split_whitespace().map(|s| s.to_ascii_lowercase()) - .collect::>().join("-"); - + // Discard '', '' tags and some escaped characters, + // transform the contents of the header into a hyphenated string + // without non-alphanumeric characters other than '-' and '_'. + // // This is a terrible hack working around how hoedown gives us rendered // html for text rather than the raw text. + let mut id = s.clone(); + let repl_sub = vec!["", "", "", "", + "", "", + "<", ">", "&", "'", """]; + for sub in repl_sub { + id = id.replace(sub, ""); + } + let id = id.chars().filter_map(|c| { + if c.is_alphanumeric() || c == '-' || c == '_' { + if c.is_ascii() { + Some(c.to_ascii_lowercase()) + } else { + Some(c) + } + } else if c.is_whitespace() && c.is_ascii() { + Some('-') + } else { + None + } + }).collect::(); let opaque = unsafe { (*data).opaque as *mut hoedown_html_renderer_state }; let opaque = unsafe { &mut *((*opaque).opaque as *mut MyOpaque) }; // Make sure our hyphenated ID is unique for this page let id = USED_HEADER_MAP.with(|map| { - let id = id.replace("", "").replace("", "").to_string(); let id = match map.borrow_mut().get_mut(&id) { None => id, Some(a) => { *a += 1; format!("{}-{}", id, *a - 1) } @@ -304,22 +321,15 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { id }); - let sec = match opaque.toc_builder { - Some(ref mut builder) => { - builder.push(level as u32, s.clone(), id.clone()) - } - None => {""} - }; + + let sec = opaque.toc_builder.as_mut().map_or("".to_owned(), |builder| { + format!("{} ", builder.push(level as u32, s.clone(), id.clone())) + }); // Render the HTML - let text = format!(r##"{sec}{}"##, - s, lvl = level, id = id, - sec = if sec.is_empty() { - sec.to_string() - } else { - format!("{} ", sec) - }); + let text = format!("\ + {sec}{}", + s, lvl = level, id = id, sec = sec); let text = CString::new(text).unwrap(); unsafe { hoedown_buffer_puts(ob, text.as_ptr()) } @@ -333,7 +343,7 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { _: *const hoedown_renderer_data, ) -> libc::c_int { let content = if text.is_null() { - "".to_string() + "".to_owned() } else { let bytes = unsafe { (*text).as_bytes() }; let s = str::from_utf8(bytes).unwrap(); @@ -367,10 +377,9 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { hoedown_html_renderer_free(renderer); - let mut ret = match opaque.toc_builder { - Some(b) => write!(w, "", b.into_toc()), - None => Ok(()) - }; + let mut ret = opaque.toc_builder.map_or(Ok(()), |builder| { + write!(w, "", builder.into_toc()) + }); if ret.is_ok() { let buf = (*ob).as_bytes(); @@ -404,7 +413,7 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) { stripped_filtered_line(l).unwrap_or(l) }); let text = lines.collect::>().join("\n"); - tests.add_test(text.to_string(), + tests.add_test(text.to_owned(), block_info.should_panic, block_info.no_run, block_info.ignore, block_info.test_harness); } @@ -560,10 +569,7 @@ pub fn plain_summary_line(md: &str) -> String { md.len() as libc::size_t); hoedown_document_free(document); let plain_slice = (*ob).as_bytes(); - let plain = match str::from_utf8(plain_slice) { - Ok(s) => s.to_string(), - Err(_) => "".to_string(), - }; + let plain = str::from_utf8(plain_slice).unwrap_or("").to_owned(); hoedown_buffer_free(ob); plain } @@ -572,7 +578,7 @@ pub fn plain_summary_line(md: &str) -> String { #[cfg(test)] mod tests { use super::{LangString, Markdown}; - use super::{collapse_whitespace, plain_summary_line}; + use super::plain_summary_line; #[test] fn test_lang_string_parse() { @@ -607,6 +613,27 @@ mod tests { format!("{}", Markdown(markdown)); } + #[test] + fn test_header() { + fn t(input: &str, expect: &str) { + let output = format!("{}", Markdown(input)); + assert_eq!(output, expect); + } + + t("# Foo bar", "\n

    \ + Foo bar

    "); + t("## Foo-bar_baz qux", "\n

    Foo-bar_baz qux

    "); + t("### **Foo** *bar* baz!?!& -_qux_-%", + "\n

    \ + Foo \ + bar baz!?!& -_qux_-%

    "); + t("####**Foo?** & \\*bar?!* _`baz`_ ❤ #qux", + "\n

    \ + Foo? & *bar?!* \ + baz ❤ #qux

    "); + } + #[test] fn test_plain_summary_line() { fn t(input: &str, expect: &str) { @@ -620,18 +647,4 @@ mod tests { t("# top header", "top header"); t("## header", "header"); } - - #[test] - fn test_collapse_whitespace() { - fn t(input: &str, expected: &str) { - let actual = collapse_whitespace(input); - assert_eq!(actual, expected); - } - - t("foo", "foo"); - t("foo bar baz", "foo bar baz"); - t(" foo bar", "foo bar"); - t("\tfoo bar\nbaz", "foo bar baz"); - t("foo bar \n baz\t\tqux\n", "foo bar baz qux"); - } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 86b268001a..49228ac91f 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -39,7 +39,8 @@ use std::cell::RefCell; use std::cmp::Ordering; use std::collections::{BTreeMap, HashMap, HashSet}; use std::default::Default; -use std::fmt; +use std::error; +use std::fmt::{self, Display, Formatter}; use std::fs::{self, File}; use std::io::prelude::*; use std::io::{self, BufWriter, BufReader}; @@ -53,9 +54,11 @@ use externalfiles::ExternalHtml; use serialize::json::{self, ToJson}; use syntax::{abi, ast}; -use rustc::middle::def_id::{DefId, LOCAL_CRATE}; -use rustc::util::nodemap::NodeSet; -use rustc_front::{hir, attr}; +use rustc::metadata::cstore::LOCAL_CRATE; +use rustc::middle::def_id::{CRATE_DEF_INDEX, DefId}; +use rustc::middle::stability; +use rustc::util::nodemap::DefIdSet; +use rustc_front::hir; use clean::{self, SelfTy}; use doctree; @@ -143,6 +146,42 @@ impl Impl { } } +#[derive(Debug)] +pub struct Error { + file: PathBuf, + error: io::Error, +} + +impl error::Error for Error { + fn description(&self) -> &str { + self.error.description() + } +} + +impl Display for Error { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "\"{}\": {}", self.file.display(), self.error) + } +} + +impl Error { + pub fn new(e: io::Error, file: &Path) -> Error { + Error { + file: file.to_path_buf(), + error: e, + } + } +} + +macro_rules! try_err { + ($e:expr, $file:expr) => ({ + match $e { + Ok(e) => e, + Err(e) => return Err(Error::new(e, $file)), + } + }) +} + /// This cache is used to store information about the `clean::Crate` being /// rendered in order to provide more useful documentation. This contains /// information like all implementors of a trait, all traits a type implements, @@ -205,7 +244,7 @@ pub struct Cache { search_index: Vec, privmod: bool, remove_priv: bool, - public_items: NodeSet, + public_items: DefIdSet, deref_trait_did: Option, // In rare case where a structure is defined in one module but implemented @@ -213,7 +252,7 @@ pub struct Cache { // then the fully qualified name of the structure isn't presented in `paths` // yet when its implementation methods are being indexed. Caches such methods // and their parent id here and indexes them at the end of crate parsing. - orphan_methods: Vec<(ast::NodeId, clean::Item)>, + orphan_methods: Vec<(DefId, clean::Item)>, } /// Helper struct to render all source code to HTML pages @@ -308,7 +347,7 @@ thread_local!(pub static CURRENT_LOCATION_KEY: RefCell> = pub fn run(mut krate: clean::Crate, external_html: &ExternalHtml, dst: PathBuf, - passes: HashSet) -> io::Result<()> { + passes: HashSet) -> Result<(), Error> { let src_root = match krate.src.parent() { Some(p) => p.to_path_buf(), None => PathBuf::new(), @@ -331,7 +370,7 @@ pub fn run(mut krate: clean::Crate, issue_tracker_base_url: None, }; - try!(mkdir(&cx.dst)); + try_err!(mkdir(&cx.dst), &cx.dst); // Crawl the crate attributes looking for attributes which control how we're // going to emit HTML @@ -377,7 +416,7 @@ pub fn run(mut krate: clean::Crate, let analysis = ::ANALYSISKEY.with(|a| a.clone()); let analysis = analysis.borrow(); let public_items = analysis.as_ref().map(|a| a.public_items.clone()); - let public_items = public_items.unwrap_or(NodeSet()); + let public_items = public_items.unwrap_or(DefIdSet()); let paths: HashMap, ItemType)> = analysis.as_ref().map(|a| { let paths = a.external_paths.borrow_mut().take().unwrap(); @@ -412,7 +451,7 @@ pub fn run(mut krate: clean::Crate, for &(n, ref e) in &krate.externs { cache.extern_locations.insert(n, (e.name.clone(), extern_location(e, &cx.dst))); - let did = DefId { krate: n, node: ast::CRATE_NODE_ID }; + let did = DefId { krate: n, index: CRATE_DEF_INDEX }; cache.paths.insert(did, (vec![e.name.to_string()], ItemType::Module)); } @@ -433,7 +472,7 @@ pub fn run(mut krate: clean::Crate, krate = cache.fold_crate(krate); // Build our search index - let index = try!(build_index(&krate, &mut cache)); + let index = build_index(&krate, &mut cache); // Freeze the cache now that the index has been built. Put an Arc into TLS // for future parallelization opportunities @@ -448,7 +487,7 @@ pub fn run(mut krate: clean::Crate, cx.krate(krate) } -fn build_index(krate: &clean::Crate, cache: &mut Cache) -> io::Result { +fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { // Build the search index from the collected metadata let mut nodeid_to_pathid = HashMap::new(); let mut pathid_to_nodeid = Vec::new(); @@ -459,8 +498,7 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> io::Result { // Attach all orphan methods to the type's definition if the type // has since been learned. - for &(pid, ref item) in orphan_methods { - let did = DefId::local(pid); + for &(did, ref item) in orphan_methods { match paths.get(&did) { Some(&(ref fqp, _)) => { // Needed to determine `self` type. @@ -476,7 +514,7 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> io::Result { }, None => {} } - }; + } // Reduce `NodeId` in paths into smaller sequential numbers, // and prune the paths that do not appear in the index. @@ -497,7 +535,7 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> io::Result { // Collect the index into a string let mut w = io::Cursor::new(Vec::new()); - try!(write!(&mut w, r#"searchIndex['{}'] = {{"items":["#, krate.name)); + write!(&mut w, r#"searchIndex['{}'] = {{"items":["#, krate.name).unwrap(); let mut lastpath = "".to_string(); for (i, item) in cache.search_index.iter().enumerate() { @@ -511,74 +549,91 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> io::Result { }; if i > 0 { - try!(write!(&mut w, ",")); + write!(&mut w, ",").unwrap(); } - try!(write!(&mut w, r#"[{},"{}","{}",{}"#, - item.ty as usize, item.name, path, - item.desc.to_json().to_string())); + write!(&mut w, r#"[{},"{}","{}",{}"#, + item.ty as usize, item.name, path, + item.desc.to_json().to_string()).unwrap(); match item.parent { Some(nodeid) => { let pathid = *nodeid_to_pathid.get(&nodeid).unwrap(); - try!(write!(&mut w, ",{}", pathid)); + write!(&mut w, ",{}", pathid).unwrap(); } - None => try!(write!(&mut w, ",null")) + None => write!(&mut w, ",null").unwrap() } match item.search_type { - Some(ref t) => try!(write!(&mut w, ",{}", t)), - None => try!(write!(&mut w, ",null")) + Some(ref t) => write!(&mut w, ",{}", t).unwrap(), + None => write!(&mut w, ",null").unwrap() } - try!(write!(&mut w, "]")); + write!(&mut w, "]").unwrap(); } - try!(write!(&mut w, r#"],"paths":["#)); + write!(&mut w, r#"],"paths":["#).unwrap(); for (i, &did) in pathid_to_nodeid.iter().enumerate() { let &(ref fqp, short) = cache.paths.get(&did).unwrap(); if i > 0 { - try!(write!(&mut w, ",")); + write!(&mut w, ",").unwrap(); } - try!(write!(&mut w, r#"[{},"{}"]"#, - short as usize, *fqp.last().unwrap())); + write!(&mut w, r#"[{},"{}"]"#, + short as usize, *fqp.last().unwrap()).unwrap(); } - try!(write!(&mut w, "]}};")); + write!(&mut w, "]}};").unwrap(); - Ok(String::from_utf8(w.into_inner()).unwrap()) + String::from_utf8(w.into_inner()).unwrap() } fn write_shared(cx: &Context, krate: &clean::Crate, cache: &Cache, - search_index: String) -> io::Result<()> { + search_index: String) -> Result<(), Error> { // Write out the shared files. Note that these are shared among all rustdoc // docs placed in the output directory, so this needs to be a synchronized // operation with respect to all other rustdocs running around. - try!(mkdir(&cx.dst)); + try_err!(mkdir(&cx.dst), &cx.dst); let _lock = ::flock::Lock::new(&cx.dst.join(".lock")); // Add all the static files. These may already exist, but we just // overwrite them anyway to make sure that they're fresh and up-to-date. try!(write(cx.dst.join("jquery.js"), include_bytes!("static/jquery-2.1.4.min.js"))); - try!(write(cx.dst.join("main.js"), include_bytes!("static/main.js"))); - try!(write(cx.dst.join("playpen.js"), include_bytes!("static/playpen.js"))); - try!(write(cx.dst.join("main.css"), include_bytes!("static/main.css"))); + try!(write(cx.dst.join("main.js"), + include_bytes!("static/main.js"))); + try!(write(cx.dst.join("playpen.js"), + include_bytes!("static/playpen.js"))); + try!(write(cx.dst.join("main.css"), + include_bytes!("static/main.css"))); try!(write(cx.dst.join("normalize.css"), include_bytes!("static/normalize.css"))); try!(write(cx.dst.join("FiraSans-Regular.woff"), include_bytes!("static/FiraSans-Regular.woff"))); try!(write(cx.dst.join("FiraSans-Medium.woff"), include_bytes!("static/FiraSans-Medium.woff"))); + try!(write(cx.dst.join("FiraSans-LICENSE.txt"), + include_bytes!("static/FiraSans-LICENSE.txt"))); try!(write(cx.dst.join("Heuristica-Italic.woff"), include_bytes!("static/Heuristica-Italic.woff"))); + try!(write(cx.dst.join("Heuristica-LICENSE.txt"), + include_bytes!("static/Heuristica-LICENSE.txt"))); try!(write(cx.dst.join("SourceSerifPro-Regular.woff"), include_bytes!("static/SourceSerifPro-Regular.woff"))); try!(write(cx.dst.join("SourceSerifPro-Bold.woff"), include_bytes!("static/SourceSerifPro-Bold.woff"))); + try!(write(cx.dst.join("SourceSerifPro-LICENSE.txt"), + include_bytes!("static/SourceSerifPro-LICENSE.txt"))); try!(write(cx.dst.join("SourceCodePro-Regular.woff"), include_bytes!("static/SourceCodePro-Regular.woff"))); try!(write(cx.dst.join("SourceCodePro-Semibold.woff"), include_bytes!("static/SourceCodePro-Semibold.woff"))); + try!(write(cx.dst.join("SourceCodePro-LICENSE.txt"), + include_bytes!("static/SourceCodePro-LICENSE.txt"))); + try!(write(cx.dst.join("LICENSE-MIT.txt"), + include_bytes!("static/LICENSE-MIT.txt"))); + try!(write(cx.dst.join("LICENSE-APACHE.txt"), + include_bytes!("static/LICENSE-APACHE.txt"))); + try!(write(cx.dst.join("COPYRIGHT.txt"), + include_bytes!("static/COPYRIGHT.txt"))); fn collect(path: &Path, krate: &str, key: &str) -> io::Result> { @@ -600,18 +655,18 @@ fn write_shared(cx: &Context, // Update the search index let dst = cx.dst.join("search-index.js"); - let all_indexes = try!(collect(&dst, &krate.name, "searchIndex")); - let mut w = try!(File::create(&dst)); - try!(writeln!(&mut w, "var searchIndex = {{}};")); - try!(writeln!(&mut w, "{}", search_index)); + let all_indexes = try_err!(collect(&dst, &krate.name, "searchIndex"), &dst); + let mut w = try_err!(File::create(&dst), &dst); + try_err!(writeln!(&mut w, "var searchIndex = {{}};"), &dst); + try_err!(writeln!(&mut w, "{}", search_index), &dst); for index in &all_indexes { - try!(writeln!(&mut w, "{}", *index)); + try_err!(writeln!(&mut w, "{}", *index), &dst); } - try!(writeln!(&mut w, "initSearch(searchIndex);")); + try_err!(writeln!(&mut w, "initSearch(searchIndex);"), &dst); // Update the list of all implementors for traits let dst = cx.dst.join("implementors"); - try!(mkdir(&dst)); + try_err!(mkdir(&dst), &dst); for (&did, imps) in &cache.implementors { // Private modules can leak through to this phase of rustdoc, which // could contain implementations for otherwise private types. In some @@ -628,51 +683,53 @@ fn write_shared(cx: &Context, let mut mydst = dst.clone(); for part in &remote_path[..remote_path.len() - 1] { mydst.push(part); - try!(mkdir(&mydst)); + try_err!(mkdir(&mydst), &mydst); } mydst.push(&format!("{}.{}.js", remote_item_type.to_static_str(), remote_path[remote_path.len() - 1])); - let all_implementors = try!(collect(&mydst, &krate.name, - "implementors")); + let all_implementors = try_err!(collect(&mydst, &krate.name, + "implementors"), + &mydst); - try!(mkdir(mydst.parent().unwrap())); - let mut f = BufWriter::new(try!(File::create(&mydst))); - try!(writeln!(&mut f, "(function() {{var implementors = {{}};")); + try_err!(mkdir(mydst.parent().unwrap()), + &mydst.parent().unwrap().to_path_buf()); + let mut f = BufWriter::new(try_err!(File::create(&mydst), &mydst)); + try_err!(writeln!(&mut f, "(function() {{var implementors = {{}};"), &mydst); for implementor in &all_implementors { - try!(write!(&mut f, "{}", *implementor)); + try_err!(write!(&mut f, "{}", *implementor), &mydst); } - try!(write!(&mut f, r"implementors['{}'] = [", krate.name)); + try_err!(write!(&mut f, r"implementors['{}'] = [", krate.name), &mydst); for imp in imps { // If the trait and implementation are in the same crate, then // there's no need to emit information about it (there's inlining // going on). If they're in different crates then the crate defining // the trait will be interested in our implementation. if imp.def_id.krate == did.krate { continue } - try!(write!(&mut f, r#""{}","#, imp.impl_)); + try_err!(write!(&mut f, r#""{}","#, imp.impl_), &mydst); } - try!(writeln!(&mut f, r"];")); - try!(writeln!(&mut f, "{}", r" + try_err!(writeln!(&mut f, r"];"), &mydst); + try_err!(writeln!(&mut f, "{}", r" if (window.register_implementors) { window.register_implementors(implementors); } else { window.pending_implementors = implementors; } - ")); - try!(writeln!(&mut f, r"}})()")); + "), &mydst); + try_err!(writeln!(&mut f, r"}})()"), &mydst); } Ok(()) } fn render_sources(cx: &mut Context, - krate: clean::Crate) -> io::Result { + krate: clean::Crate) -> Result { info!("emitting source files"); let dst = cx.dst.join("src"); - try!(mkdir(&dst)); + try_err!(mkdir(&dst), &dst); let dst = dst.join(&krate.name); - try!(mkdir(&dst)); + try_err!(mkdir(&dst), &dst); let mut folder = SourceCollector { dst: dst, seen: HashSet::new(), @@ -685,8 +742,8 @@ fn render_sources(cx: &mut Context, /// Writes the entire contents of a string to a destination, not attempting to /// catch any errors. -fn write(dst: PathBuf, contents: &[u8]) -> io::Result<()> { - try!(File::create(&dst)).write_all(contents) +fn write(dst: PathBuf, contents: &[u8]) -> Result<(), Error> { + Ok(try_err!(try_err!(File::create(&dst), &dst).write_all(contents), &dst)) } /// Makes a directory on the filesystem, failing the thread if an error occurs and @@ -835,7 +892,6 @@ impl<'a> SourceCollector<'a> { fname.push(".html"); cur.push(&fname[..]); let mut w = BufWriter::new(try!(File::create(&cur))); - let title = format!("{} -- source", cur.file_name().unwrap() .to_string_lossy()); let desc = format!("Source to the Rust file `{}`.", filename); @@ -968,7 +1024,7 @@ impl DocFolder for Cache { if parent.is_local() { // We have a parent, but we don't know where they're // defined yet. Wait for later to index this item. - self.orphan_methods.push((parent.node, item.clone())) + self.orphan_methods.push((parent, item.clone())) } } _ => {} @@ -994,10 +1050,11 @@ impl DocFolder for Cache { // `public_items` map, so we can skip inserting into the // paths map if there was already an entry present and we're // not a public item. - let id = item.def_id.node; - if !self.paths.contains_key(&item.def_id) || - !item.def_id.is_local() || - self.public_items.contains(&id) { + if + !self.paths.contains_key(&item.def_id) || + !item.def_id.is_local() || + self.public_items.contains(&item.def_id) + { self.paths.insert(item.def_id, (self.stack.clone(), shortty(&item))); } @@ -1033,7 +1090,7 @@ impl DocFolder for Cache { ref t => { match t.primitive_type() { Some(prim) => { - let did = DefId::local(prim.to_node_id()); + let did = DefId::local(prim.to_def_index()); self.parent_stack.push(did); true } @@ -1078,8 +1135,8 @@ impl DocFolder for Cache { ref t => { t.primitive_type().and_then(|t| { self.primitive_locations.get(&t).map(|n| { - let id = t.to_node_id(); - DefId { krate: *n, node: id } + let id = t.to_def_index(); + DefId { krate: *n, index: id } }) }) } @@ -1151,7 +1208,7 @@ impl Context { /// /// This currently isn't parallelized, but it'd be pretty easy to add /// parallelization to this function. - fn krate(self, mut krate: clean::Crate) -> io::Result<()> { + fn krate(self, mut krate: clean::Crate) -> Result<(), Error> { let mut item = match krate.module.take() { Some(i) => i, None => return Ok(()) @@ -1177,7 +1234,7 @@ impl Context { /// all sub-items which need to be rendered. /// /// The rendering driver uses this closure to queue up more work. - fn item(&mut self, item: clean::Item, mut f: F) -> io::Result<()> where + fn item(&mut self, item: clean::Item, mut f: F) -> Result<(), Error> where F: FnMut(&mut Context, clean::Item), { fn render(w: File, cx: &Context, it: &clean::Item, @@ -1264,9 +1321,9 @@ impl Context { let mut item = Some(item); self.recurse(name, |this| { let item = item.take().unwrap(); - let dst = this.dst.join("index.html"); - let dst = try!(File::create(&dst)); - try!(render(dst, this, &item, false)); + let joint_dst = this.dst.join("index.html"); + let dst = try_err!(File::create(&joint_dst), &joint_dst); + try_err!(render(dst, this, &item, false), &joint_dst); let m = match item.inner { clean::ModuleItem(m) => m, @@ -1277,9 +1334,9 @@ impl Context { { let items = this.build_sidebar_items(&m); let js_dst = this.dst.join("sidebar-items.js"); - let mut js_out = BufWriter::new(try!(File::create(&js_dst))); - try!(write!(&mut js_out, "initSidebarItems({});", - json::as_json(&items))); + let mut js_out = BufWriter::new(try_err!(File::create(&js_dst), &js_dst)); + try_err!(write!(&mut js_out, "initSidebarItems({});", + json::as_json(&items)), &js_dst); } for item in m.items { @@ -1292,9 +1349,11 @@ impl Context { // Things which don't have names (like impls) don't get special // pages dedicated to them. _ if item.name.is_some() => { - let dst = self.dst.join(&item_path(&item)); - let dst = try!(File::create(&dst)); - render(dst, self, &item, true) + let joint_dst = self.dst.join(&item_path(&item)); + + let dst = try_err!(File::create(&joint_dst), &joint_dst); + try_err!(render(dst, self, &item, true), &joint_dst); + Ok(()) } _ => Ok(()) @@ -1420,7 +1479,7 @@ impl<'a> Item<'a> { root = root, path = path[..path.len() - 1].join("/"), file = item_path(self.item), - goto = self.item.def_id.node)) + goto = self.item.def_id.index.as_usize())) } } } @@ -1480,7 +1539,7 @@ impl<'a> fmt::Display for Item<'a> { Some(l) => { try!(write!(fmt, "[src]", - self.item.def_id.node, l, "goto source code")); + self.item.def_id.index.as_usize(), l, "goto source code")); } None => {} } @@ -1593,8 +1652,8 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, let s1 = i1.stability.as_ref().map(|s| s.level); let s2 = i2.stability.as_ref().map(|s| s.level); match (s1, s2) { - (Some(attr::Unstable), Some(attr::Stable)) => return Ordering::Greater, - (Some(attr::Stable), Some(attr::Unstable)) => return Ordering::Less, + (Some(stability::Unstable), Some(stability::Stable)) => return Ordering::Greater, + (Some(stability::Stable), Some(stability::Unstable)) => return Ordering::Less, _ => {} } i1.name.cmp(&i2.name) @@ -1709,7 +1768,7 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Optio String::new() }; format!("Deprecated{}{}", since, Markdown(&reason)) - } else if stab.level == attr::Unstable { + } else if stab.level == stability::Unstable { let unstable_extra = if show_reason { match (!stab.feature.is_empty(), &cx.issue_tracker_base_url, stab.issue) { (true, &Some(ref tracker_url), Some(issue_no)) => @@ -2336,7 +2395,7 @@ fn render_deref_methods(w: &mut fmt::Formatter, cx: &Context, impl_: &Impl) -> f _ => { if let Some(prim) = target.primitive_type() { if let Some(c) = cache().primitive_locations.get(&prim) { - let did = DefId { krate: *c, node: prim.to_node_id() }; + let did = DefId { krate: *c, index: prim.to_def_index() }; try!(render_assoc_items(w, cx, did, what)); } } diff --git a/src/librustdoc/html/static/COPYRIGHT.txt b/src/librustdoc/html/static/COPYRIGHT.txt new file mode 100644 index 0000000000..2e430789ef --- /dev/null +++ b/src/librustdoc/html/static/COPYRIGHT.txt @@ -0,0 +1,64 @@ +These documentation pages include resources by third parties. This copyright +file applies only to those resources. The following third party resources are +included, and carry their own copyright notices and license terms: + +* Fira Sans (FiraSans-Regular.woff, FiraSans-Medium.woff): + + Copyright (c) 2014, Mozilla Foundation https://mozilla.org/ + with Reserved Font Name Fira Sans. + + Copyright (c) 2014, Telefonica S.A. + + Licensed under the SIL Open Font License, Version 1.1. + See FiraSans-LICENSE.txt. + +* Heuristica (Heuristica-Italic.woff): + + Copyright 1989, 1991 Adobe Systems Incorporated. All rights reserved. + Utopia is either a registered trademark or trademark of Adobe Systems + Incorporated in the United States and/or other countries. Used under + license. + + Copyright 2006 Han The Thanh, Vntopia font family, http://vntex.sf.net + + Copyright (c) 2008-2012, Andrey V. Panov (panov@canopus.iacp.dvo.ru), + with Reserved Font Name Heuristica. + + Licensed under the SIL Open Font License, Version 1.1. + See Heuristica-LICENSE.txt. + +* jQuery (jquery-2.1.4.min.js): + + Copyright 2005, 2015 jQuery Foundation, Inc. + Licensed under the MIT license (see LICENSE-MIT.txt). + +* main.css, main.js, and playpen.js: + + Copyright 2015 The Rust Developers. + Licensed under the Apache License, Version 2.0 (see LICENSE-APACHE.txt) or + the MIT license (LICENSE-MIT.txt) at your option. + +* normalize.css: + + Copyright (c) Nicolas Gallagher and Jonathan Neal. + Licensed under the MIT license (see LICENSE-MIT.txt). + +* Source Code Pro (SourceCodePro-Regular.woff, SourceCodePro-Semibold.woff): + + Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), + with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark + of Adobe Systems Incorporated in the United States and/or other countries. + + Licensed under the SIL Open Font License, Version 1.1. + See SourceCodePro-LICENSE.txt. + +* Source Serif Pro (SourceSerifPro-Regular.woff, SourceSerifPro-Bold.woff): + + Copyright 2014 Adobe Systems Incorporated (http://www.adobe.com/), with + Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of + Adobe Systems Incorporated in the United States and/or other countries. + + Licensed under the SIL Open Font License, Version 1.1. + See SourceSerifPro-LICENSE.txt. + +This copyright file is intended to be distributed with rustdoc output. diff --git a/src/librustdoc/html/static/LICENSE-APACHE.txt b/src/librustdoc/html/static/LICENSE-APACHE.txt new file mode 100644 index 0000000000..16fe87b06e --- /dev/null +++ b/src/librustdoc/html/static/LICENSE-APACHE.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/librustdoc/html/static/LICENSE-MIT.txt b/src/librustdoc/html/static/LICENSE-MIT.txt new file mode 100644 index 0000000000..31aa79387f --- /dev/null +++ b/src/librustdoc/html/static/LICENSE-MIT.txt @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/librustdoc/html/static/main.css b/src/librustdoc/html/static/main.css index e6b653cbd5..5e27eab857 100644 --- a/src/librustdoc/html/static/main.css +++ b/src/librustdoc/html/static/main.css @@ -9,6 +9,8 @@ * option. This file may not be copied, modified, or distributed * except according to those terms. */ + +/* See FiraSans-LICENSE.txt for the Fira Sans license. */ @font-face { font-family: 'Fira Sans'; font-style: normal; @@ -21,6 +23,9 @@ font-weight: 500; src: local('Fira Sans Medium'), url("FiraSans-Medium.woff") format('woff'); } + +/* See SourceSerifPro-LICENSE.txt for the Source Serif Pro license and + * Heuristica-LICENSE.txt for the Heuristica license. */ @font-face { font-family: 'Source Serif Pro'; font-style: normal; @@ -39,6 +44,8 @@ font-weight: 700; src: local('Source Serif Pro Bold'), url("SourceSerifPro-Bold.woff") format('woff'); } + +/* See SourceCodePro-LICENSE.txt for the Source Code Pro license. */ @font-face { font-family: 'Source Code Pro'; font-style: normal; @@ -552,14 +559,17 @@ pre.rust .lifetime { color: #B76514; } .rusttest { display: none; } pre.rust { position: relative; } -.test-arrow { +a.test-arrow { display: inline-block; position: absolute; - top: 0; - right: 10px; - font-size: 150%; - -webkit-transform: scaleX(-1); - transform: scaleX(-1); + + background-color: #4e8bca; + color: #f5f5f5; + padding: 5px 10px 5px 10px; + border-radius: 5px; + font-size: 130%; + top: 5px; + right: 5px; } .methods .section-header { diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 9d84d4ea3c..5a6d761683 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -54,7 +54,8 @@ } function browserSupportsHistoryApi() { - return window.history && typeof window.history.pushState === "function"; + return document.location.protocol != "file:" && + window.history && typeof window.history.pushState === "function"; } function highlightSourceLines(ev) { @@ -132,7 +133,7 @@ $(document).on("keypress", handleShortcut); $(document).on("keydown", handleShortcut); $(document).on("click", function(ev) { - if (!$(e.target).closest("#help > div").length) { + if (!$(ev.target).closest("#help > div").length) { $("#help").addClass("hidden"); $("body").removeClass("blur"); } @@ -385,6 +386,9 @@ if ((aaa.item.ty === TY_PRIMITIVE) && (bbb.item.ty !== TY_PRIMITIVE)) { return -1; } + if ((bbb.item.ty === TY_PRIMITIVE) && (aaa.item.ty !== TY_PRIMITIVE)) { + return 1; + } // sort by description (no description goes later) a = (aaa.item.desc === ''); @@ -511,7 +515,6 @@ var $active = $results.filter('.highlighted'); if (e.which === 38) { // up - e.preventDefault(); if (!$active.length || !$active.prev()) { return; } @@ -519,7 +522,6 @@ $active.prev().addClass('highlighted'); $active.removeClass('highlighted'); } else if (e.which === 40) { // down - e.preventDefault(); if (!$active.length) { $results.first().addClass('highlighted'); } else if ($active.next().length) { @@ -527,7 +529,6 @@ $active.removeClass('highlighted'); } } else if (e.which === 13) { // return - e.preventDefault(); if ($active.length) { document.location.href = $active.find('a').prop('href'); } @@ -571,6 +572,10 @@ displayPath = item.path + '::'; href = rootPath + item.path.replace(/::/g, '/') + '/index.html'; + } else if (type === "primitive") { + displayPath = ""; + href = rootPath + item.path.replace(/::/g, '/') + + '/' + type + '.' + name + '.html'; } else if (item.parent !== undefined) { var myparent = item.parent; var anchor = '#' + type + '.' + name; @@ -714,11 +719,29 @@ } function startSearch() { - var keyUpTimeout; - $('.do-search').on('click', search); - $('.search-input').on('keyup', function() { - clearTimeout(keyUpTimeout); - keyUpTimeout = setTimeout(search, 500); + var searchTimeout; + $(".search-input").on("keyup input",function() { + clearTimeout(searchTimeout); + if ($(this).val().length === 0) { + window.history.replaceState("", "std - Rust", "?search="); + $('#main.content').removeClass('hidden'); + $('#search.content').addClass('hidden'); + } else { + searchTimeout = setTimeout(search, 500); + } + }); + $('.search-form').on('submit', function(e){ + e.preventDefault(); + clearTimeout(searchTimeout); + search(); + }); + $('.search-input').on('change paste', function(e) { + // Do NOT e.preventDefault() here. It will prevent pasting. + clearTimeout(searchTimeout); + // zero-timeout necessary here because at the time of event handler execution the + // pasted content is not in the input field yet. Shouldn’t make any difference for + // change, though. + setTimeout(search, 0); }); // Push and pop states are used to add search results to the browser diff --git a/src/librustdoc/html/static/playpen.js b/src/librustdoc/html/static/playpen.js index ef8bdf5e2c..8f8a753b06 100644 --- a/src/librustdoc/html/static/playpen.js +++ b/src/librustdoc/html/static/playpen.js @@ -12,6 +12,8 @@ /*globals $: true, rootPath: true */ document.addEventListener('DOMContentLoaded', function() { + 'use strict'; + if (!window.playgroundUrl) { return; } @@ -26,8 +28,8 @@ document.addEventListener('DOMContentLoaded', function() { } var a = document.createElement('a'); - a.textContent = '⇱'; a.setAttribute('class', 'test-arrow'); + a.textContent = 'Run'; var code = el.previousElementSibling.textContent; diff --git a/src/librustdoc/html/toc.rs b/src/librustdoc/html/toc.rs index 8f3e63820d..53be8b5bc0 100644 --- a/src/librustdoc/html/toc.rs +++ b/src/librustdoc/html/toc.rs @@ -55,8 +55,8 @@ pub struct TocBuilder { /// strictly increasing (i.e. chain[0].level < chain[1].level < /// ...) with each entry being the most recent occurrence of a /// heading with that level (it doesn't include the most recent - /// occurrences of every level, just, if *is* in `chain` then is is - /// the most recent one). + /// occurrences of every level, just, if it *is* in `chain` then + /// it is the most recent one). /// /// We also have `chain[0].level <= top_level.entries[last]`. chain: Vec diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index efe5a73fad..db0da3764b 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -24,7 +24,6 @@ #![feature(box_syntax)] #![feature(dynamic_lib)] #![feature(libc)] -#![feature(path_ext)] #![feature(path_relative_from)] #![feature(rustc_private)] #![feature(set_stdio)] @@ -211,7 +210,7 @@ pub fn main_args(args: &[String]) -> isize { for &(name, _, description) in PASSES { println!("{:>20} - {}", name, description); } - println!("{}", "\nDefault passes for rustdoc:"); // FIXME: #9970 + println!("\nDefault passes for rustdoc:"); for &name in DEFAULT_PASSES { println!("{:>20}", name); } diff --git a/src/librustdoc/passes.rs b/src/librustdoc/passes.rs index 8a57a50bde..1957f1efa4 100644 --- a/src/librustdoc/passes.rs +++ b/src/librustdoc/passes.rs @@ -8,12 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::collections::HashSet; -use rustc::util::nodemap::NodeSet; +use rustc::util::nodemap::DefIdSet; use std::cmp; use std::string::String; use std::usize; -use syntax::ast; use rustc_front::hir; use clean; @@ -24,18 +22,18 @@ use fold::DocFolder; /// Strip items marked `#[doc(hidden)]` pub fn strip_hidden(krate: clean::Crate) -> plugins::PluginResult { - let mut stripped = HashSet::new(); + let mut stripped = DefIdSet(); // strip all #[doc(hidden)] items let krate = { struct Stripper<'a> { - stripped: &'a mut HashSet - }; + stripped: &'a mut DefIdSet + } impl<'a> fold::DocFolder for Stripper<'a> { fn fold_item(&mut self, i: Item) -> Option { if i.is_hidden_from_doc() { debug!("found one in strip_hidden; removing"); - self.stripped.insert(i.def_id.node); + self.stripped.insert(i.def_id); // use a dedicated hidden item for given item type if any match i.inner { @@ -61,8 +59,8 @@ pub fn strip_hidden(krate: clean::Crate) -> plugins::PluginResult { // strip any traits implemented on stripped items let krate = { struct ImplStripper<'a> { - stripped: &'a mut HashSet - }; + stripped: &'a mut DefIdSet + } impl<'a> fold::DocFolder for ImplStripper<'a> { fn fold_item(&mut self, i: Item) -> Option { if let clean::ImplItem(clean::Impl{ @@ -70,12 +68,12 @@ pub fn strip_hidden(krate: clean::Crate) -> plugins::PluginResult { ref trait_, .. }) = i.inner { // Impls for stripped types don't need to exist - if self.stripped.contains(&did.node) { + if self.stripped.contains(&did) { return None; } // Impls of stripped traits also don't need to exist if let Some(clean::ResolvedPath { did, .. }) = *trait_ { - if self.stripped.contains(&did.node) { + if self.stripped.contains(&did) { return None; } } @@ -94,7 +92,7 @@ pub fn strip_hidden(krate: clean::Crate) -> plugins::PluginResult { /// crate, specified by the `xcrate` flag. pub fn strip_private(mut krate: clean::Crate) -> plugins::PluginResult { // This stripper collects all *retained* nodes. - let mut retained = HashSet::new(); + let mut retained = DefIdSet(); let analysis = super::ANALYSISKEY.with(|a| a.clone()); let analysis = analysis.borrow(); let analysis = analysis.as_ref().unwrap(); @@ -118,8 +116,8 @@ pub fn strip_private(mut krate: clean::Crate) -> plugins::PluginResult { } struct Stripper<'a> { - retained: &'a mut HashSet, - exported_items: &'a NodeSet, + retained: &'a mut DefIdSet, + exported_items: &'a DefIdSet, } impl<'a> fold::DocFolder for Stripper<'a> { @@ -132,7 +130,7 @@ impl<'a> fold::DocFolder for Stripper<'a> { clean::VariantItem(..) | clean::MethodItem(..) | clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) => { if i.def_id.is_local() { - if !self.exported_items.contains(&i.def_id.node) { + if !self.exported_items.contains(&i.def_id) { return None; } // Traits are in exported_items even when they're totally private. @@ -143,8 +141,7 @@ impl<'a> fold::DocFolder for Stripper<'a> { } clean::ConstantItem(..) => { - if i.def_id.is_local() && - !self.exported_items.contains(&i.def_id.node) { + if i.def_id.is_local() && !self.exported_items.contains(&i.def_id) { return None; } } @@ -171,8 +168,7 @@ impl<'a> fold::DocFolder for Stripper<'a> { clean::ImplItem(clean::Impl{ for_: clean::ResolvedPath{ did, .. }, .. }) => { - if did.is_local() && - !self.exported_items.contains(&did.node) { + if did.is_local() && !self.exported_items.contains(&did) { return None; } } @@ -205,7 +201,7 @@ impl<'a> fold::DocFolder for Stripper<'a> { }; let i = if fastreturn { - self.retained.insert(i.def_id.node); + self.retained.insert(i.def_id); return Some(i); } else { self.fold_item_recur(i) @@ -220,7 +216,7 @@ impl<'a> fold::DocFolder for Stripper<'a> { i.doc_value().is_none() => None, clean::ImplItem(ref i) if i.items.is_empty() => None, _ => { - self.retained.insert(i.def_id.node); + self.retained.insert(i.def_id); Some(i) } } @@ -231,14 +227,13 @@ impl<'a> fold::DocFolder for Stripper<'a> { } // This stripper discards all private impls of traits -struct ImplStripper<'a>(&'a HashSet); +struct ImplStripper<'a>(&'a DefIdSet); impl<'a> fold::DocFolder for ImplStripper<'a> { fn fold_item(&mut self, i: Item) -> Option { if let clean::ImplItem(ref imp) = i.inner { match imp.trait_ { Some(clean::ResolvedPath{ did, .. }) => { - let ImplStripper(s) = *self; - if did.is_local() && !s.contains(&did.node) { + if did.is_local() && !self.0.contains(&did) { return None; } } diff --git a/src/librustdoc/plugins.rs b/src/librustdoc/plugins.rs index a81787dad7..7292ea5377 100644 --- a/src/librustdoc/plugins.rs +++ b/src/librustdoc/plugins.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(deprecated)] + use clean; use std::dynamic_lib as dl; diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 95215cf2d5..cbaff95dfd 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(deprecated)] + use std::cell::{RefCell, Cell}; use std::collections::{HashSet, HashMap}; use std::dynamic_lib::DynamicLibrary; @@ -22,10 +24,11 @@ use std::sync::{Arc, Mutex}; use testing; use rustc_lint; +use rustc::front::map as hir_map; use rustc::session::{self, config}; -use rustc::session::config::get_unstable_features_setting; +use rustc::session::config::{get_unstable_features_setting, OutputType}; use rustc::session::search_paths::{SearchPaths, PathKind}; -use rustc_front::lowering::lower_crate; +use rustc_front::lowering::{lower_crate, LoweringContext}; use rustc_back::tempdir::TempDir; use rustc_driver::{driver, Compilation}; use syntax::codemap::CodeMap; @@ -82,13 +85,17 @@ pub fn run(input: &str, "rustdoc-test", None) .expect("phase_2_configure_and_expand aborted in rustdoc!"); let krate = driver::assign_node_ids(&sess, krate); - let krate = lower_crate(&krate); + let lcx = LoweringContext::new(&sess, Some(&krate)); + let krate = lower_crate(&lcx, &krate); let opts = scrape_test_config(&krate); + let mut forest = hir_map::Forest::new(krate); + let map = hir_map::map_crate(&mut forest); + let ctx = core::DocContext { - krate: &krate, - maybe_typed: core::NotTyped(sess), + map: &map, + maybe_typed: core::NotTyped(&sess), input: input, external_paths: RefCell::new(Some(HashMap::new())), external_traits: RefCell::new(None), @@ -99,7 +106,7 @@ pub fn run(input: &str, }; let mut v = RustdocVisitor::new(&ctx, None); - v.visit(ctx.krate); + v.visit(ctx.map.krate()); let mut krate = v.clean(&ctx); match crate_name { Some(name) => krate.name = name, @@ -124,8 +131,8 @@ pub fn run(input: &str, // Look for #![doc(test(no_crate_inject))], used by crates in the std facade fn scrape_test_config(krate: &::rustc_front::hir::Crate) -> TestOptions { - use rustc_front::attr::AttrMetaMethods; - use rustc_front::print::pprust; + use syntax::attr::AttrMetaMethods; + use syntax::print::pprust; let mut opts = TestOptions { no_crate_inject: false, @@ -163,13 +170,15 @@ fn runtest(test: &str, cratename: &str, libs: SearchPaths, // never wrap the test in `fn main() { ... }` let test = maketest(test, Some(cratename), as_test_harness, opts); let input = config::Input::Str(test.to_string()); + let mut outputs = HashMap::new(); + outputs.insert(OutputType::Exe, None); let sessopts = config::Options { maybe_sysroot: Some(env::current_exe().unwrap().parent().unwrap() .parent().unwrap().to_path_buf()), search_paths: libs, crate_types: vec!(config::CrateTypeExecutable), - output_types: vec!(config::OutputTypeExe), + output_types: outputs, externs: externs, cg: config::CodegenOptions { prefer_dynamic: true, diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 978b572ac9..b6c93bf00a 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -16,14 +16,13 @@ use std::mem; use syntax::abi; use syntax::ast; +use syntax::attr; +use syntax::attr::AttrMetaMethods; use syntax::codemap::Span; use rustc::front::map as hir_map; -use rustc::middle::def_id::DefId; use rustc::middle::stability; -use rustc_front::attr; -use rustc_front::attr::AttrMetaMethods; use rustc_front::hir; use core; @@ -39,7 +38,7 @@ use doctree::*; pub struct RustdocVisitor<'a, 'tcx: 'a> { pub module: Module, - pub attrs: Vec, + pub attrs: Vec, pub cx: &'a core::DocContext<'a, 'tcx>, pub analysis: Option<&'a core::CrateAnalysis>, view_item_stack: HashSet, @@ -63,8 +62,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } fn stability(&self, id: ast::NodeId) -> Option { - self.cx.tcx_opt().and_then( - |tcx| stability::lookup(tcx, DefId::local(id)).map(|x| x.clone())) + self.cx.tcx_opt().and_then(|tcx| { + self.cx.map.opt_local_def_id(id) + .and_then(|def_id| stability::lookup(tcx, def_id)) + .cloned() + }) } pub fn visit(&mut self, krate: &hir::Crate) { @@ -82,8 +84,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { self.module.is_crate = true; } - pub fn visit_struct_def(&mut self, item: &hir::Item, - name: ast::Ident, sd: &hir::StructDef, + pub fn visit_variant_data(&mut self, item: &hir::Item, + name: ast::Name, sd: &hir::VariantData, generics: &hir::Generics) -> Struct { debug!("Visiting struct"); let struct_type = struct_type_from_def(&*sd); @@ -95,13 +97,13 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { stab: self.stability(item.id), attrs: item.attrs.clone(), generics: generics.clone(), - fields: sd.fields.clone(), + fields: sd.fields().iter().cloned().collect(), whence: item.span } } pub fn visit_enum_def(&mut self, it: &hir::Item, - name: ast::Ident, def: &hir::EnumDef, + name: ast::Name, def: &hir::EnumDef, params: &hir::Generics) -> Enum { debug!("Visiting enum"); Enum { @@ -109,10 +111,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { variants: def.variants.iter().map(|v| Variant { name: v.node.name, attrs: v.node.attrs.clone(), - vis: v.node.vis, - stab: self.stability(v.node.id), - id: v.node.id, - kind: v.node.kind.clone(), + stab: self.stability(v.node.data.id()), + def: v.node.data.clone(), whence: v.span, }).collect(), vis: it.vis, @@ -125,7 +125,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } pub fn visit_fn(&mut self, item: &hir::Item, - name: ast::Ident, fd: &hir::FnDecl, + name: ast::Name, fd: &hir::FnDecl, unsafety: &hir::Unsafety, constness: hir::Constness, abi: &abi::Abi, @@ -146,10 +146,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } } - pub fn visit_mod_contents(&mut self, span: Span, attrs: Vec , + pub fn visit_mod_contents(&mut self, span: Span, attrs: Vec , vis: hir::Visibility, id: ast::NodeId, m: &hir::Mod, - name: Option) -> Module { + name: Option) -> Module { let mut om = Module::new(name); om.where_outer = span; om.where_inner = m.inner; @@ -200,23 +200,25 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } - fn resolve_id(&mut self, id: ast::NodeId, renamed: Option, + fn resolve_id(&mut self, id: ast::NodeId, renamed: Option, glob: bool, om: &mut Module, please_inline: bool) -> bool { let tcx = match self.cx.tcx_opt() { Some(tcx) => tcx, None => return false }; let def = tcx.def_map.borrow()[&id].def_id(); - if !def.is_local() { return false } + let def_node_id = match tcx.map.as_local_node_id(def) { + Some(n) => n, None => return false + }; let analysis = match self.analysis { Some(analysis) => analysis, None => return false }; - if !please_inline && analysis.public_items.contains(&def.node) { + if !please_inline && analysis.public_items.contains(&def) { return false } - if !self.view_item_stack.insert(def.node) { return false } + if !self.view_item_stack.insert(def_node_id) { return false } - let ret = match tcx.map.get(def.node) { + let ret = match tcx.map.get(def_node_id) { hir_map::NodeItem(it) => { if glob { let prev = mem::replace(&mut self.inlining_from_glob, true); @@ -237,14 +239,14 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } _ => false, }; - self.view_item_stack.remove(&id); + self.view_item_stack.remove(&def_node_id); return ret; } pub fn visit_item(&mut self, item: &hir::Item, - renamed: Option, om: &mut Module) { + renamed: Option, om: &mut Module) { debug!("Visiting item {:?}", item); - let name = renamed.unwrap_or(item.ident); + let name = renamed.unwrap_or(item.name); match item.node { hir::ItemExternCrate(ref p) => { let path = match *p { @@ -296,7 +298,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { hir::ItemEnum(ref ed, ref gen) => om.enums.push(self.visit_enum_def(item, name, ed, gen)), hir::ItemStruct(ref sd, ref gen) => - om.structs.push(self.visit_struct_def(item, name, &**sd, gen)), + om.structs.push(self.visit_variant_data(item, name, sd, gen)), hir::ItemFn(ref fd, ref unsafety, constness, ref abi, ref gen, _) => om.fns.push(self.visit_fn(item, name, &**fd, unsafety, constness, abi, gen)), @@ -399,7 +401,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { Macro { id: def.id, attrs: def.attrs.clone(), - name: def.ident, + name: def.name, whence: def.span, stab: self.stability(def.id), imported_from: def.imported_from, diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 4bcaa4b5db..452feed3cd 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -76,8 +76,7 @@ //! Create a struct called `TestStruct` and serialize and deserialize it to and from JSON using the //! serialization API, using the derived serialization code. //! -//! ```notrust -//! // FIXME(#19470): this cannot be ```rust``` because it fails orphan checking at the moment +//! ```rust //! extern crate serialize; //! use serialize::json; //! @@ -111,8 +110,7 @@ //! //! ### Simple example of `ToJson` usage //! -//! ```notrust -//! // FIXME(#19470): this cannot be ```rust``` because it fails orphan checking at the moment +//! ```rust //! extern crate serialize; //! use serialize::json::{self, ToJson, Json}; //! @@ -151,8 +149,7 @@ //! //! ### Verbose example of `ToJson` usage //! -//! ```notrust -//! // FIXME(#19470): this cannot be ```rust``` because it fails orphan checking at the moment +//! ```rust //! extern crate serialize; //! use std::collections::BTreeMap; //! use serialize::json::{self, Json, ToJson}; diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 4ad8fce812..7c6add8033 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -207,7 +207,7 @@ fn test_resize_policy() { /// The hashes are all keyed by the thread-local random number generator /// on creation by default. This means that the ordering of the keys is /// randomized, but makes the tables more resistant to -/// denial-of-service attacks (Hash DoS). This behaviour can be +/// denial-of-service attacks (Hash DoS). This behavior can be /// overridden with one of the constructors. /// /// It is required that the keys implement the `Eq` and `Hash` traits, although @@ -324,7 +324,7 @@ fn search_hashed(table: M, F: FnMut(&K) -> bool, { // This is the only function where capacity can be zero. To avoid - // undefined behaviour when Bucket::new gets the raw bucket in this + // undefined behavior when Bucket::new gets the raw bucket in this // case, immediately return the appropriate search result. if table.capacity() == 0 { return TableRef(table); @@ -1101,8 +1101,14 @@ impl HashMap self.search_mut(k).map(|bucket| bucket.into_mut_refs().1) } - /// Inserts a key-value pair into the map. If the key already had a value - /// present in the map, that value is returned. Otherwise, `None` is returned. + /// Inserts a key-value pair into the map. + /// + /// If the map did not have this key present, `None` is returned. + /// + /// If the map did have this key present, that value is returned, and the + /// entry is not updated. See the [module-level documentation] for more. + /// + /// [module-level documentation]: index.html#insert-and-complex-keys /// /// # Examples /// diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index 7264b5827c..1f6b349399 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -540,8 +540,14 @@ impl HashSet other.is_subset(self) } - /// Adds a value to the set. Returns `true` if the value was not already - /// present in the set. + /// Adds a value to the set. + /// + /// If the set did not have a value present, `true` is returned. + /// + /// If the set did have this key present, that value is returned, and the + /// entry is not updated. See the [module-level documentation] for more. + /// + /// [module-level documentation]: index.html#insert-and-complex-keys /// /// # Examples /// diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index f8bd791f68..e8796dd10b 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -958,7 +958,7 @@ impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> { impl<'a, K: 'a, V: 'a> Drop for Drain<'a, K, V> { fn drop(&mut self) { - for _ in self.by_ref() {} + for _ in self {} } } @@ -999,6 +999,7 @@ impl Clone for RawTable { } impl Drop for RawTable { + #[unsafe_destructor_blind_to_params] fn drop(&mut self) { if self.capacity == 0 || self.capacity == mem::POST_DROP_USIZE { return; diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index 83e28e39a7..71d9fbfaa3 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -332,8 +332,8 @@ //! ``` //! use std::collections::btree_map::BTreeMap; //! -//! // A client of the bar. They have an id and a blood alcohol level. -//! struct Person { id: u32, blood_alcohol: f32 } +//! // A client of the bar. They have a blood alcohol level. +//! struct Person { blood_alcohol: f32 } //! //! // All the orders made to the bar, by client id. //! let orders = vec![1,2,1,2,3,4,1,2,2,3,4,1,1,1]; @@ -344,7 +344,7 @@ //! for id in orders { //! // If this is the first time we've seen this customer, initialize them //! // with no blood alcohol. Otherwise, just retrieve them. -//! let person = blood_alcohol.entry(id).or_insert(Person{id: id, blood_alcohol: 0.0}); +//! let person = blood_alcohol.entry(id).or_insert(Person { blood_alcohol: 0.0 }); //! //! // Reduce their blood alcohol level. It takes time to order and drink a beer! //! person.blood_alcohol *= 0.9; @@ -352,13 +352,59 @@ //! // Check if they're sober enough to have another beer. //! if person.blood_alcohol > 0.3 { //! // Too drunk... for now. -//! println!("Sorry {}, I have to cut you off", person.id); +//! println!("Sorry {}, I have to cut you off", id); //! } else { //! // Have another! //! person.blood_alcohol += 0.1; //! } //! } //! ``` +//! +//! # Insert and complex keys +//! +//! If we have a more complex key, calls to `insert()` will +//! not update the value of the key. For example: +//! +//! ``` +//! use std::cmp::Ordering; +//! use std::collections::BTreeMap; +//! use std::hash::{Hash, Hasher}; +//! +//! #[derive(Debug)] +//! struct Foo { +//! a: u32, +//! b: &'static str, +//! } +//! +//! // we will compare `Foo`s by their `a` value only. +//! impl PartialEq for Foo { +//! fn eq(&self, other: &Self) -> bool { self.a == other.a } +//! } +//! +//! impl Eq for Foo {} +//! +//! // we will hash `Foo`s by their `a` value only. +//! impl Hash for Foo { +//! fn hash(&self, h: &mut H) { self.a.hash(h); } +//! } +//! +//! impl PartialOrd for Foo { +//! fn partial_cmp(&self, other: &Self) -> Option { self.a.partial_cmp(&other.a) } +//! } +//! +//! impl Ord for Foo { +//! fn cmp(&self, other: &Self) -> Ordering { self.a.cmp(&other.a) } +//! } +//! +//! let mut map = BTreeMap::new(); +//! map.insert(Foo { a: 1, b: "baz" }, ()); +//! +//! // We already have a Foo with an a of 1, so this will be updating the value. +//! map.insert(Foo { a: 1, b: "xyz" }, ()); +//! +//! // ... but the key hasn't changed. b is still "baz", not "xyz" +//! assert_eq!(map.keys().next().unwrap().b, "baz"); +//! ``` #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/dynamic_lib.rs b/src/libstd/dynamic_lib.rs index 7801662ff2..684a300560 100644 --- a/src/libstd/dynamic_lib.rs +++ b/src/libstd/dynamic_lib.rs @@ -16,13 +16,14 @@ reason = "API has not been scrutinized and is highly likely to \ either disappear or change", issue = "27810")] +#![deprecated(since = "1.5.0", reason = "replaced with crates.io crates")] #![allow(missing_docs)] +#![allow(deprecated)] use prelude::v1::*; use env; use ffi::{CString, OsString}; -use mem; use path::{Path, PathBuf}; pub struct DynamicLibrary { @@ -114,7 +115,7 @@ impl DynamicLibrary { // the destructor does not run. match maybe_symbol_value { Err(err) => Err(err), - Ok(symbol_value) => Ok(mem::transmute(symbol_value)) + Ok(symbol_value) => Ok(symbol_value as *mut T) } } } diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 3447d1683a..1f6761b54c 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -260,6 +260,12 @@ impl Error for VarError { /// - [Austin Group Bugzilla](http://austingroupbugs.net/view.php?id=188) /// - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=15607#c2) /// +/// # Panics +/// +/// This function may panic if `key` is empty, contains an ASCII equals sign +/// `'='` or the NUL character `'\0'`, or when the value contains the NUL +/// character. +/// /// # Examples /// /// ``` @@ -292,6 +298,12 @@ fn _set_var(k: &OsStr, v: &OsStr) { /// - [Austin Group Bugzilla](http://austingroupbugs.net/view.php?id=188) /// - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=15607#c2) /// +/// # Panics +/// +/// This function may panic if `key` is empty, contains an ASCII equals sign +/// `'='` or the NUL character `'\0'`, or when the value contains the NUL +/// character. +/// /// # Examples /// /// ``` @@ -416,7 +428,10 @@ impl Error for JoinPathsError { /// Returns the value of the 'HOME' environment variable if it is /// set and not equal to the empty string. Otherwise, returns the value of the /// 'USERPROFILE' environment variable if it is set and not equal to the empty -/// string. +/// string. If both do not exist, [`GetUserProfileDirectory`][msdn] is used to +/// return the appropriate path. +/// +/// [msdn]: https://msdn.microsoft.com/en-us/library/windows/desktop/bb762280(v=vs.85).aspx /// /// # Examples /// @@ -442,7 +457,11 @@ pub fn home_dir() -> Option { /// /// On Windows, returns the value of, in order, the 'TMP', 'TEMP', /// 'USERPROFILE' environment variable if any are set and not the empty -/// string. Otherwise, tmpdir returns the path to the Windows directory. +/// string. Otherwise, tmpdir returns the path to the Windows directory. This +/// behavior is identical to that of [GetTempPath][msdn], which this function +/// uses internally. +/// +/// [msdn]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa364992(v=vs.85).aspx /// /// ``` /// use std::env; diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 7c9c2066ae..89427f7851 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -23,7 +23,7 @@ use ops::Deref; use option::Option::{self, Some, None}; use result::Result::{self, Ok, Err}; use slice; -use str; +use str::{self, Utf8Error}; use string::String; use vec::Vec; @@ -151,6 +151,15 @@ pub struct CStr { #[stable(feature = "rust1", since = "1.0.0")] pub struct NulError(usize, Vec); +/// An error returned from `CString::into_string` to indicate that a UTF-8 error +/// was encountered during the conversion. +#[derive(Clone, PartialEq, Debug)] +#[unstable(feature = "cstring_into", reason = "recently added", issue = "29157")] +pub struct IntoStringError { + inner: CString, + error: Utf8Error, +} + impl CString { /// Creates a new C-compatible string from a container of bytes. /// @@ -206,7 +215,7 @@ impl CString { /// Retakes ownership of a CString that was transferred to C. /// /// The only appropriate argument is a pointer obtained by calling - /// `into_ptr`. The length of the string will be recalculated + /// `into_raw`. The length of the string will be recalculated /// using the pointer. #[unstable(feature = "cstr_memory2", reason = "recently added", issue = "27769")] @@ -245,16 +254,48 @@ impl CString { /// Transfers ownership of the string to a C caller. /// /// The pointer must be returned to Rust and reconstituted using - /// `from_ptr` to be properly deallocated. Specifically, one + /// `from_raw` to be properly deallocated. Specifically, one /// should *not* use the standard C `free` function to deallocate /// this string. /// - /// Failure to call `from_ptr` will lead to a memory leak. + /// Failure to call `from_raw` will lead to a memory leak. #[stable(feature = "cstr_memory", since = "1.4.0")] pub fn into_raw(self) -> *mut libc::c_char { Box::into_raw(self.inner) as *mut libc::c_char } + /// Converts the `CString` into a `String` if it contains valid Unicode data. + /// + /// On failure, ownership of the original `CString` is returned. + #[unstable(feature = "cstring_into", reason = "recently added", issue = "29157")] + pub fn into_string(self) -> Result { + String::from_utf8(self.into_bytes()) + .map_err(|e| IntoStringError { + error: e.utf8_error(), + inner: unsafe { CString::from_vec_unchecked(e.into_bytes()) }, + }) + } + + /// Returns the underlying byte buffer. + /// + /// The returned buffer does **not** contain the trailing nul separator and + /// it is guaranteed to not have any interior nul bytes. + #[unstable(feature = "cstring_into", reason = "recently added", issue = "29157")] + pub fn into_bytes(self) -> Vec { + // FIXME: Once this method becomes stable, add an `impl Into> for CString` + let mut vec = self.inner.into_vec(); + let _nul = vec.pop(); + debug_assert_eq!(_nul, Some(0u8)); + vec + } + + /// Equivalent to the `into_bytes` function except that the returned vector + /// includes the trailing nul byte. + #[unstable(feature = "cstring_into", reason = "recently added", issue = "29157")] + pub fn into_bytes_with_nul(self) -> Vec { + self.inner.into_vec() + } + /// Returns the contents of this `CString` as a slice of bytes. /// /// The returned slice does **not** contain the trailing nul separator and @@ -336,6 +377,35 @@ impl From for io::Error { } } +impl IntoStringError { + /// Consumes this error, returning original `CString` which generated the + /// error. + #[unstable(feature = "cstring_into", reason = "recently added", issue = "29157")] + pub fn into_cstring(self) -> CString { + self.inner + } + + /// Access the underlying UTF-8 error that was the cause of this error. + #[unstable(feature = "cstring_into", reason = "recently added", issue = "29157")] + pub fn utf8_error(&self) -> Utf8Error { + self.error + } +} + +#[unstable(feature = "cstring_into", reason = "recently added", issue = "29157")] +impl Error for IntoStringError { + fn description(&self) -> &str { + Error::description(&self.error) + } +} + +#[unstable(feature = "cstring_into", reason = "recently added", issue = "29157")] +impl fmt::Display for IntoStringError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.error, f) + } +} + impl CStr { /// Casts a raw C string to a safe C string wrapper. /// diff --git a/src/libstd/ffi/mod.rs b/src/libstd/ffi/mod.rs index dfe706e077..bfd6ab5228 100644 --- a/src/libstd/ffi/mod.rs +++ b/src/libstd/ffi/mod.rs @@ -13,7 +13,7 @@ #![stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")] -pub use self::c_str::{CString, CStr, NulError}; +pub use self::c_str::{CString, CStr, NulError, IntoStringError}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::os_str::{OsString, OsStr}; diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index a3d509ba0f..6178f1bbb8 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -60,6 +60,7 @@ pub struct File { /// represents known metadata about a file such as its permissions, size, /// modification times, etc. #[stable(feature = "rust1", since = "1.0.0")] +#[derive(Clone)] pub struct Metadata(fs_imp::FileAttr); /// Iterator over the entries in a directory. @@ -954,8 +955,21 @@ pub fn read_link>(path: P) -> io::Result { /// Returns the canonical form of a path with all intermediate components /// normalized and symbolic links resolved. -#[unstable(feature = "fs_canonicalize", reason = "recently added API", - issue = "27706")] +/// +/// This function may return an error in situations like where the path does not +/// exist, a component in the path is not a directory, or an I/O error happens. +/// +/// # Examples +/// +/// ``` +/// use std::fs; +/// +/// # fn foo() -> std::io::Result<()> { +/// let path = try!(fs::canonicalize("../a/../foo.txt")); +/// # Ok(()) +/// # } +/// ``` +#[stable(feature = "fs_canonicalize", since = "1.5.0")] pub fn canonicalize>(path: P) -> io::Result { fs_imp::canonicalize(path.as_ref()) } @@ -1157,11 +1171,12 @@ impl Iterator for WalkDir { } /// Utility methods for paths. -#[unstable(feature = "path_ext", +#[unstable(feature = "path_ext_deprecated", reason = "The precise set of methods exposed on this trait may \ change and some methods may be removed. For stable code, \ see the std::fs::metadata function.", issue = "27725")] +#[deprecated(since = "1.5.0", reason = "replaced with inherent methods")] pub trait PathExt { /// Gets information on the file, directory, etc at this path. /// @@ -1214,6 +1229,7 @@ pub trait PathExt { fn is_dir(&self) -> bool; } +#[allow(deprecated)] impl PathExt for Path { fn metadata(&self) -> io::Result { metadata(self) } fn symlink_metadata(&self) -> io::Result { symlink_metadata(self) } @@ -2083,6 +2099,15 @@ mod tests { check!(fs::create_dir_all(&path.join("a/"))); } + #[test] + fn canonicalize_works_simple() { + let tmpdir = tmpdir(); + let tmpdir = fs::canonicalize(tmpdir.path()).unwrap(); + let file = tmpdir.join("test"); + File::create(&file).unwrap(); + assert_eq!(fs::canonicalize(&file).unwrap(), file); + } + #[test] #[cfg(not(windows))] fn realpath_works() { @@ -2152,4 +2177,10 @@ mod tests { } } } + + #[test] + fn read_dir_not_found() { + let res = fs::read_dir("/path/that/does/not/exist"); + assert_eq!(res.err().unwrap().kind(), ErrorKind::NotFound); + } } diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 90bcbe7fe8..acab63315e 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -546,7 +546,7 @@ impl IntoInnerError { /// let stream = match stream.into_inner() { /// Ok(s) => s, /// Err(e) => { - /// // Here, e is a IntoInnerError, let's re-examine the buffer: + /// // Here, e is an IntoInnerError, let's re-examine the buffer: /// let buffer = e.into_inner(); /// /// // do stuff to try to recover diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index 9590f0b7aa..e4f00c4874 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -69,7 +69,7 @@ use slice; /// use std::io::Cursor; /// let mut buff = Cursor::new(vec![0; 15]); /// -/// write_ten_bytes(&mut buff).unwrap(); +/// write_ten_bytes_at_end(&mut buff).unwrap(); /// /// assert_eq!(&buff.get_ref()[5..15], &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); /// } @@ -192,67 +192,43 @@ impl Cursor { pub fn set_position(&mut self, pos: u64) { self.pos = pos; } } -macro_rules! seek { - () => { - fn seek(&mut self, style: SeekFrom) -> io::Result { - let pos = match style { - SeekFrom::Start(n) => { self.pos = n; return Ok(n) } - SeekFrom::End(n) => self.inner.len() as i64 + n, - SeekFrom::Current(n) => self.pos as i64 + n, - }; - - if pos < 0 { - Err(Error::new(ErrorKind::InvalidInput, - "invalid seek to a negative position")) - } else { - self.pos = pos as u64; - Ok(self.pos) - } +#[stable(feature = "rust1", since = "1.0.0")] +impl io::Seek for Cursor where T: AsRef<[u8]> { + fn seek(&mut self, style: SeekFrom) -> io::Result { + let pos = match style { + SeekFrom::Start(n) => { self.pos = n; return Ok(n) } + SeekFrom::End(n) => self.inner.as_ref().len() as i64 + n, + SeekFrom::Current(n) => self.pos as i64 + n, + }; + + if pos < 0 { + Err(Error::new(ErrorKind::InvalidInput, + "invalid seek to a negative position")) + } else { + self.pos = pos as u64; + Ok(self.pos) } } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a> io::Seek for Cursor<&'a [u8]> { seek!(); } -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> io::Seek for Cursor<&'a mut [u8]> { seek!(); } -#[stable(feature = "rust1", since = "1.0.0")] -impl io::Seek for Cursor> { seek!(); } - -macro_rules! read { - () => { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let n = try!(Read::read(&mut try!(self.fill_buf()), buf)); - self.pos += n as u64; - Ok(n) - } +impl Read for Cursor where T: AsRef<[u8]> { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let n = try!(Read::read(&mut try!(self.fill_buf()), buf)); + self.pos += n as u64; + Ok(n) } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Read for Cursor<&'a [u8]> { read!(); } -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Read for Cursor<&'a mut [u8]> { read!(); } -#[stable(feature = "rust1", since = "1.0.0")] -impl Read for Cursor> { read!(); } - -macro_rules! buffer { - () => { - fn fill_buf(&mut self) -> io::Result<&[u8]> { - let amt = cmp::min(self.pos, self.inner.len() as u64); - Ok(&self.inner[(amt as usize)..]) - } - fn consume(&mut self, amt: usize) { self.pos += amt as u64; } +impl BufRead for Cursor where T: AsRef<[u8]> { + fn fill_buf(&mut self) -> io::Result<&[u8]> { + let amt = cmp::min(self.pos, self.inner.as_ref().len() as u64); + Ok(&self.inner.as_ref()[(amt as usize)..]) } + fn consume(&mut self, amt: usize) { self.pos += amt as u64; } } -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> BufRead for Cursor<&'a [u8]> { buffer!(); } -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> BufRead for Cursor<&'a mut [u8]> { buffer!(); } -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> BufRead for Cursor> { buffer!(); } - #[stable(feature = "rust1", since = "1.0.0")] impl<'a> Write for Cursor<&'a mut [u8]> { fn write(&mut self, data: &[u8]) -> io::Result { @@ -289,6 +265,16 @@ impl Write for Cursor> { fn flush(&mut self) -> io::Result<()> { Ok(()) } } +#[stable(feature = "cursor_box_slice", since = "1.5.0")] +impl Write for Cursor> { + fn write(&mut self, buf: &[u8]) -> io::Result { + let pos = cmp::min(self.pos, self.inner.len() as u64); + let amt = try!((&mut self.inner[(pos as usize)..]).write(buf)); + self.pos += amt as u64; + Ok(amt) + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } +} #[cfg(test)] mod tests { @@ -316,6 +302,24 @@ mod tests { assert_eq!(&writer.get_ref()[..], b); } + #[test] + fn test_box_slice_writer() { + let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice()); + assert_eq!(writer.position(), 0); + assert_eq!(writer.write(&[0]).unwrap(), 1); + assert_eq!(writer.position(), 1); + assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); + assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); + assert_eq!(writer.position(), 8); + assert_eq!(writer.write(&[]).unwrap(), 0); + assert_eq!(writer.position(), 8); + + assert_eq!(writer.write(&[8, 9]).unwrap(), 1); + assert_eq!(writer.write(&[10]).unwrap(), 0); + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; + assert_eq!(&**writer.get_ref(), b); + } + #[test] fn test_buf_writer() { let mut buf = [0 as u8; 9]; @@ -397,6 +401,28 @@ mod tests { assert_eq!(reader.read(&mut buf).unwrap(), 0); } + #[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 buf = []; + assert_eq!(reader.read(&mut buf).unwrap(), 0); + assert_eq!(reader.position(), 0); + let mut buf = [0]; + assert_eq!(reader.read(&mut buf).unwrap(), 1); + assert_eq!(reader.position(), 1); + let b: &[_] = &[0]; + assert_eq!(buf, b); + let mut buf = [0; 4]; + assert_eq!(reader.read(&mut buf).unwrap(), 4); + assert_eq!(reader.position(), 5); + let b: &[_] = &[1, 2, 3, 4]; + assert_eq!(buf, b); + assert_eq!(reader.read(&mut buf).unwrap(), 3); + let b: &[_] = &[5, 6, 7]; + assert_eq!(&buf[..3], b); + assert_eq!(reader.read(&mut buf).unwrap(), 0); + } + #[test] fn read_to_end() { let mut reader = Cursor::new(vec!(0, 1, 2, 3, 4, 5, 6, 7)); @@ -483,6 +509,10 @@ mod tests { let mut r = Cursor::new(&mut buf[..]); assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); assert_eq!(r.write(&[3]).unwrap(), 0); + + let mut r = Cursor::new(vec![10].into_boxed_slice()); + assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); + assert_eq!(r.write(&[3]).unwrap(), 0); } #[test] @@ -497,6 +527,9 @@ mod tests { 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()); + assert!(r.seek(SeekFrom::End(-2)).is_err()); } #[test] diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index 773f9ac6a1..6f18aad623 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -17,9 +17,8 @@ use option::Option::{self, Some, None}; use result; use sys; -/// A specialized [`Result`][result] type for I/O operations. -/// -/// [result]: ../result/enum.Result.html +/// A specialized [`Result`](../result/enum.Result.html) type for I/O +/// operations. /// /// This type is broadly used across `std::io` for any operation which may /// produce an error. diff --git a/src/libstd/io/impls.rs b/src/libstd/io/impls.rs index 79013000fe..5b587dd921 100644 --- a/src/libstd/io/impls.rs +++ b/src/libstd/io/impls.rs @@ -238,7 +238,7 @@ mod tests { b.iter(|| { let mut rd = &buf[..]; - for _ in (0 .. 8) { + for _ in 0..8 { let _ = rd.read(&mut dst); test::black_box(&dst); } @@ -252,7 +252,7 @@ mod tests { b.iter(|| { let mut wr = &mut buf[..]; - for _ in (0 .. 8) { + for _ in 0..8 { let _ = wr.write_all(&src); test::black_box(&wr); } @@ -266,7 +266,7 @@ mod tests { b.iter(|| { let mut rd = &buf[..]; - for _ in (0 .. 8) { + for _ in 0..8 { let _ = rd.read(&mut dst); test::black_box(&dst); } @@ -280,7 +280,7 @@ mod tests { b.iter(|| { let mut wr = &mut buf[..]; - for _ in (0 .. 8) { + for _ in 0..8 { let _ = wr.write_all(&src); test::black_box(&wr); } diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 54869807ca..ebe50a6e2b 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -20,11 +20,11 @@ //! //! # Read and Write //! -//! Because they are traits, they're 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 somtimes even `Vec`s. For example, `Read` -//! adds a `read()` method, which we can use on `File`s: +//! 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 +//! example, `Read` adds a `read()` method, which we can use on `File`s: //! //! ``` //! use std::io; @@ -111,7 +111,7 @@ //! # } //! ``` //! -//! `BufWriter` doesn't add any new ways of writing, it just buffers every call +//! `BufWriter` doesn't add any new ways of writing; it just buffers every call //! to [`write()`][write]: //! //! ``` @@ -165,7 +165,7 @@ //! # } //! ``` //! -//! Of course, using `io::stdout()` directly is less comon than something like +//! Of course, using `io::stdout()` directly is less common than something like //! `println!`. //! //! ## Iterator types @@ -234,7 +234,7 @@ //! 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 -//! to read the line and print it, so we use use `()`. +//! to read the line and print it, so we use `()`. //! //! [result]: type.Result.html //! [try]: macro.try!.html @@ -370,6 +370,13 @@ fn read_to_end(r: &mut R, buf: &mut Vec) -> Result /// throughout `std::io` take and provide types which implement the `Read` /// trait. /// +/// Please note that each call to `read` may involve a system call, and +/// therefore, using something that implements [`BufRead`][bufread], such as +/// [`BufReader`][bufreader], will be more efficient. +/// +/// [bufread]: trait.BufRead.html +/// [bufreader]: struct.BufReader.html +/// /// # Examples /// /// [`File`][file]s implement `Read`: diff --git a/src/libstd/io/prelude.rs b/src/libstd/io/prelude.rs index db5c1da8a4..f8fbe485c9 100644 --- a/src/libstd/io/prelude.rs +++ b/src/libstd/io/prelude.rs @@ -21,4 +21,5 @@ #![stable(feature = "rust1", since = "1.0.0")] pub use super::{Read, Write, BufRead, Seek}; +#[allow(deprecated)] pub use fs::PathExt; diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index c2110ef1d8..31b881bebf 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -146,7 +146,7 @@ pub struct Stdin { inner: Arc>>>, } -/// A locked reference to the a `Stdin` handle. +/// A locked reference to the `Stdin` handle. /// /// This handle implements both the `Read` and `BufRead` traits and is /// constructed via the `lock` method on `Stdin`. @@ -323,7 +323,7 @@ pub struct Stdout { inner: Arc>>>>, } -/// A locked reference to the a `Stdout` handle. +/// A locked reference to the `Stdout` handle. /// /// This handle implements the `Write` trait and is constructed via the `lock` /// method on `Stdout`. @@ -430,7 +430,7 @@ pub struct Stderr { inner: Arc>>>, } -/// A locked reference to the a `Stderr` handle. +/// A locked reference to the `Stderr` handle. /// /// This handle implements the `Write` trait and is constructed via the `lock` /// method on `Stderr`. diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 774d13966b..93d1ce168b 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -18,7 +18,7 @@ //! language primitives](#primitives), [standard macros](#macros), //! [I/O](io/index.html) and [multithreading](thread/index.html), among //! [many other -//! things](#what-is-in-the-standard-library-documentation?). +//! things](#what-is-in-the-standard-library-documentation). //! //! `std` is available to all Rust crates by default, just as if each //! one contained an `extern crate std` import at the [crate @@ -137,7 +137,7 @@ //! not. //! //! Slices can only be handled through some kind of *pointer*, and as -//! such come in many flavours such as: +//! such come in many flavors such as: //! //! * `&[T]` - *shared slice* //! * `&mut [T]` - *mutable slice* @@ -199,12 +199,17 @@ test(no_crate_inject, attr(deny(warnings))), test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))] +// SNAP 1af31d4 +#![allow(unused_features)] +// SNAP 1af31d4 +#![allow(unused_attributes)] + #![feature(alloc)] #![feature(allow_internal_unstable)] #![feature(associated_consts)] #![feature(borrow_state)] #![feature(box_syntax)] -#![feature(char_from_unchecked)] +#![feature(cfg_target_vendor)] #![feature(char_internals)] #![feature(clone_from_slice)] #![feature(collections)] @@ -219,7 +224,6 @@ #![feature(heap_api)] #![feature(int_error_internals)] #![feature(into_cow)] -#![feature(iter_order)] #![feature(lang_items)] #![feature(libc)] #![feature(linkage, thread_local, asm)] @@ -240,16 +244,16 @@ #![feature(unboxed_closures)] #![feature(unicode)] #![feature(unique)] +#![feature(dropck_parametricity)] #![feature(unsafe_no_drop_flag, filling_drop)] #![feature(decode_utf16)] #![feature(unwind_attributes)] #![feature(vec_push_all)] -#![feature(vec_resize)] #![feature(wrapping)] #![feature(zero_one)] #![cfg_attr(windows, feature(str_utf16))] -#![cfg_attr(test, feature(float_from_str_radix, range_inclusive, float_extras, hash_default))] -#![cfg_attr(test, feature(test, rustc_private, float_consts))] +#![cfg_attr(test, feature(float_from_str_radix, range_inclusive, float_extras))] +#![cfg_attr(test, feature(test, rustc_private))] #![cfg_attr(target_env = "msvc", feature(link_args))] // Don't link to std. We are std. diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index a0c3f013f2..a88ddb997f 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -68,6 +68,10 @@ macro_rules! panic { /// necessary to use `io::stdout().flush()` to ensure the output is emitted /// immediately. /// +/// # Panics +/// +/// Panics if writing to `io::stdout()` fails. +/// /// # Examples /// /// ``` @@ -94,11 +98,15 @@ macro_rules! print { ($($arg:tt)*) => ($crate::io::_print(format_args!($($arg)*))); } -/// Macro for printing to the standard output. +/// Macro for printing to the standard output, with a newline. /// /// Use the `format!` syntax to write data to the standard output. /// See `std::fmt` for more information. /// +/// # Panics +/// +/// Panics if writing to `io::stdout()` fails. +/// /// # Examples /// /// ``` diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 09aea50cfb..827a3eb9bf 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -22,7 +22,7 @@ use libc; use sys_common::{AsInner, FromInner}; use net::{hton, ntoh}; -/// An IP address, either a IPv4 or IPv6 address. +/// An IP address, either an IPv4 or IPv6 address. #[unstable(feature = "ip_addr", reason = "recent addition", issue = "27801")] #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, PartialOrd, Ord)] pub enum IpAddr { @@ -594,10 +594,18 @@ mod tests { fn test_from_str_socket_addr() { assert_eq!(Ok(sa4(Ipv4Addr::new(77, 88, 21, 11), 80)), "77.88.21.11:80".parse()); + assert_eq!(Ok(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80)), + "77.88.21.11:80".parse()); assert_eq!(Ok(sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53)), "[2a02:6b8:0:1::1]:53".parse()); + assert_eq!(Ok(SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, + 0, 0, 0, 1), 53, 0, 0)), + "[2a02:6b8:0:1::1]:53".parse()); assert_eq!(Ok(sa6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22)), "[::127.0.0.1]:22".parse()); + assert_eq!(Ok(SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, + 0x7F00, 1), 22, 0, 0)), + "[::127.0.0.1]:22".parse()); // without port let none: Option = "127.0.0.1".parse().ok(); diff --git a/src/libstd/net/parser.rs b/src/libstd/net/parser.rs index f0b35bbc38..1619dac78c 100644 --- a/src/libstd/net/parser.rs +++ b/src/libstd/net/parser.rs @@ -267,30 +267,42 @@ impl<'a> Parser<'a> { self.read_or(&mut [Box::new(ipv4_addr), Box::new(ipv6_addr)]) } - fn read_socket_addr(&mut self) -> Option { + fn read_socket_addr_v4(&mut self) -> Option { + let ip_addr = |p: &mut Parser| p.read_ipv4_addr(); + let colon = |p: &mut Parser| p.read_given_char(':'); + let port = |p: &mut Parser| { + p.read_number(10, 5, 0x10000).map(|n| n as u16) + }; + + self.read_seq_3(ip_addr, colon, port).map(|t| { + let (ip, _, port): (Ipv4Addr, char, u16) = t; + SocketAddrV4::new(ip, port) + }) + } + + fn read_socket_addr_v6(&mut self) -> Option { let ip_addr = |p: &mut Parser| { - let ipv4_p = |p: &mut Parser| p.read_ip_addr(); - let ipv6_p = |p: &mut Parser| { - let open_br = |p: &mut Parser| p.read_given_char('['); - let ip_addr = |p: &mut Parser| p.read_ipv6_addr(); - let clos_br = |p: &mut Parser| p.read_given_char(']'); - p.read_seq_3::(open_br, ip_addr, clos_br) - .map(|t| match t { (_, ip, _) => IpAddr::V6(ip) }) - }; - p.read_or(&mut [Box::new(ipv4_p), Box::new(ipv6_p)]) + let open_br = |p: &mut Parser| p.read_given_char('['); + let ip_addr = |p: &mut Parser| p.read_ipv6_addr(); + let clos_br = |p: &mut Parser| p.read_given_char(']'); + p.read_seq_3(open_br, ip_addr, clos_br).map(|t| t.1) }; let colon = |p: &mut Parser| p.read_given_char(':'); - let port = |p: &mut Parser| p.read_number(10, 5, 0x10000).map(|n| n as u16); + let port = |p: &mut Parser| { + p.read_number(10, 5, 0x10000).map(|n| n as u16) + }; - // host, colon, port self.read_seq_3(ip_addr, colon, port).map(|t| { - let (ip, _, port): (IpAddr, char, u16) = t; - match ip { - IpAddr::V4(ip) => SocketAddr::V4(SocketAddrV4::new(ip, port)), - IpAddr::V6(ip) => SocketAddr::V6(SocketAddrV6::new(ip, port, 0, 0)), - } + let (ip, _, port): (Ipv6Addr, char, u16) = t; + SocketAddrV6::new(ip, port, 0, 0) }) } + + fn read_socket_addr(&mut self) -> Option { + let v4 = |p: &mut Parser| p.read_socket_addr_v4().map(SocketAddr::V4); + let v6 = |p: &mut Parser| p.read_socket_addr_v6().map(SocketAddr::V6); + self.read_or(&mut [Box::new(v4), Box::new(v6)]) + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -326,6 +338,28 @@ impl FromStr for Ipv6Addr { } } +#[stable(feature = "socket_addr_from_str", since = "1.5.0")] +impl FromStr for SocketAddrV4 { + type Err = AddrParseError; + fn from_str(s: &str) -> Result { + match Parser::new(s).read_till_eof(|p| p.read_socket_addr_v4()) { + Some(s) => Ok(s), + None => Err(AddrParseError(())), + } + } +} + +#[stable(feature = "socket_addr_from_str", since = "1.5.0")] +impl FromStr for SocketAddrV6 { + type Err = AddrParseError; + fn from_str(s: &str) -> Result { + match Parser::new(s).read_till_eof(|p| p.read_socket_addr_v6()) { + Some(s) => Ok(s), + None => Err(AddrParseError(())), + } + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl FromStr for SocketAddr { type Err = AddrParseError; diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 5c17ffb9c2..93a056faf5 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -235,7 +235,7 @@ impl TcpListener { /// to this listener. The port allocated can be queried via the /// `socket_addr` function. /// - /// The address type can be any implementer of `ToSocketAddrs` trait. See + /// The address type can be any implementor of `ToSocketAddrs` trait. See /// its documentation for concrete examples. #[stable(feature = "rust1", since = "1.0.0")] pub fn bind(addr: A) -> io::Result { @@ -373,39 +373,28 @@ mod tests { } #[test] - fn connect_ip4_loopback() { - let addr = next_test_ip4(); - let acceptor = t!(TcpListener::bind(&addr)); - - let _t = thread::spawn(move|| { - let mut stream = t!(TcpStream::connect(&("127.0.0.1", addr.port()))); - t!(stream.write(&[44])); - }); - - let mut stream = t!(acceptor.accept()).0; - let mut buf = [0]; - t!(stream.read(&mut buf)); - assert!(buf[0] == 44); - } - - #[test] - fn connect_ip6_loopback() { - let addr = next_test_ip6(); - let acceptor = t!(TcpListener::bind(&addr)); + fn connect_loopback() { + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); - let _t = thread::spawn(move|| { - let mut stream = t!(TcpStream::connect(&("::1", addr.port()))); - t!(stream.write(&[66])); - }); + let _t = thread::spawn(move|| { + let host = match addr { + SocketAddr::V4(..) => "127.0.0.1", + SocketAddr::V6(..) => "::1", + }; + let mut stream = t!(TcpStream::connect(&(host, addr.port()))); + t!(stream.write(&[66])); + }); - let mut stream = t!(acceptor.accept()).0; - let mut buf = [0]; - t!(stream.read(&mut buf)); - assert!(buf[0] == 66); + let mut stream = t!(acceptor.accept()).0; + let mut buf = [0]; + t!(stream.read(&mut buf)); + assert!(buf[0] == 66); + }) } #[test] - fn smoke_test_ip6() { + fn smoke_test() { each_ip(&mut |addr| { let acceptor = t!(TcpListener::bind(&addr)); @@ -425,7 +414,7 @@ mod tests { } #[test] - fn read_eof_ip4() { + fn read_eof() { each_ip(&mut |addr| { let acceptor = t!(TcpListener::bind(&addr)); @@ -470,7 +459,7 @@ mod tests { } #[test] - fn multiple_connect_serial_ip4() { + fn multiple_connect_serial() { each_ip(&mut |addr| { let max = 10; let acceptor = t!(TcpListener::bind(&addr)); @@ -527,7 +516,7 @@ mod tests { } #[test] - fn multiple_connect_interleaved_lazy_schedule_ip4() { + fn multiple_connect_interleaved_lazy_schedule() { const MAX: usize = 10; each_ip(&mut |addr| { let acceptor = t!(TcpListener::bind(&addr)); @@ -560,7 +549,7 @@ mod tests { } #[test] - fn socket_and_peer_name_ip4() { + fn socket_and_peer_name() { each_ip(&mut |addr| { let listener = t!(TcpListener::bind(&addr)); let so_name = t!(listener.local_addr()); diff --git a/src/libstd/net/test.rs b/src/libstd/net/test.rs index c6d839d55a..9665fd7228 100644 --- a/src/libstd/net/test.rs +++ b/src/libstd/net/test.rs @@ -47,7 +47,9 @@ pub fn tsa(a: A) -> Result, String> { // it is running in and assigns a port range based on it. fn base_port() -> u16 { let cwd = env::current_dir().unwrap(); - let dirs = ["32-opt", "32-nopt", "64-opt", "64-nopt", "64-opt-vg", + let dirs = ["32-opt", "32-nopt", + "musl-64-opt", "cross-opt", + "64-opt", "64-nopt", "64-opt-vg", "64-debug-opt", "all-opt", "snap3", "dist"]; dirs.iter().enumerate().find(|&(_, dir)| { cwd.to_str().unwrap().contains(dir) diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index 9e4d38e461..0d3d15401f 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -185,14 +185,13 @@ mod tests { } } - // FIXME #11530 this fails on android because tests are run as root - #[cfg_attr(any(windows, target_os = "android"), ignore)] #[test] fn bind_error() { - let addr = SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), 1); - match UdpSocket::bind(&addr) { + match UdpSocket::bind("1.1.1.1:9999") { Ok(..) => panic!(), - Err(e) => assert_eq!(e.kind(), ErrorKind::PermissionDenied), + Err(e) => { + assert_eq!(e.kind(), ErrorKind::AddrNotAvailable) + } } } diff --git a/src/libstd/os/android/raw.rs b/src/libstd/os/android/raw.rs index cad80c5514..391ca16f69 100644 --- a/src/libstd/os/android/raw.rs +++ b/src/libstd/os/android/raw.rs @@ -39,6 +39,7 @@ mod arch { pub type time_t = i32; #[repr(C)] + #[derive(Clone)] #[stable(feature = "raw_ext", since = "1.1.0")] pub struct stat { #[stable(feature = "raw_ext", since = "1.1.0")] @@ -108,6 +109,7 @@ mod arch { 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")] diff --git a/src/libstd/os/bitrig/raw.rs b/src/libstd/os/bitrig/raw.rs index 2427a4e409..45e46b252a 100644 --- a/src/libstd/os/bitrig/raw.rs +++ b/src/libstd/os/bitrig/raw.rs @@ -26,6 +26,7 @@ use os::unix::raw::{uid_t, gid_t}; #[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")] diff --git a/src/libstd/os/dragonfly/raw.rs b/src/libstd/os/dragonfly/raw.rs index 1c265fa62f..cb692b0662 100644 --- a/src/libstd/os/dragonfly/raw.rs +++ b/src/libstd/os/dragonfly/raw.rs @@ -26,6 +26,7 @@ use os::unix::raw::{uid_t, gid_t}; #[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")] diff --git a/src/libstd/os/freebsd/raw.rs b/src/libstd/os/freebsd/raw.rs index 65390aee0e..2dc9a02615 100644 --- a/src/libstd/os/freebsd/raw.rs +++ b/src/libstd/os/freebsd/raw.rs @@ -33,6 +33,7 @@ mod arch { #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i32; #[repr(C)] + #[derive(Clone)] #[stable(feature = "raw_ext", since = "1.1.0")] pub struct stat { #[stable(feature = "raw_ext", since = "1.1.0")] @@ -91,6 +92,7 @@ mod arch { #[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")] @@ -138,4 +140,3 @@ mod arch { } } - diff --git a/src/libstd/os/ios/raw.rs b/src/libstd/os/ios/raw.rs index a9803f50b7..aeb3e993a7 100644 --- a/src/libstd/os/ios/raw.rs +++ b/src/libstd/os/ios/raw.rs @@ -25,6 +25,7 @@ use os::unix::raw::{uid_t, gid_t}; #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = c_long; #[repr(C)] +#[derive(Clone)] #[stable(feature = "raw_ext", since = "1.1.0")] pub struct stat { #[stable(feature = "raw_ext", since = "1.1.0")] diff --git a/src/libstd/os/linux/raw.rs b/src/libstd/os/linux/raw.rs index 3275ce07b4..d7abdef6b0 100644 --- a/src/libstd/os/linux/raw.rs +++ b/src/libstd/os/linux/raw.rs @@ -35,6 +35,7 @@ mod arch { #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i32; #[repr(C)] + #[derive(Clone)] #[stable(feature = "raw_ext", since = "1.1.0")] pub struct stat { #[stable(feature = "raw_ext", since = "1.1.0")] @@ -95,6 +96,7 @@ mod arch { #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i32; #[repr(C)] + #[derive(Clone)] #[stable(feature = "raw_ext", since = "1.1.0")] pub struct stat { #[stable(feature = "raw_ext", since = "1.1.0")] @@ -154,6 +156,7 @@ mod arch { #[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")] @@ -211,6 +214,7 @@ mod arch { #[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")] diff --git a/src/libstd/os/macos/raw.rs b/src/libstd/os/macos/raw.rs index dbc1b8c726..4abd6f2d4d 100644 --- a/src/libstd/os/macos/raw.rs +++ b/src/libstd/os/macos/raw.rs @@ -25,6 +25,7 @@ use os::unix::raw::{uid_t, gid_t}; #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = c_long; #[repr(C)] +#[derive(Clone)] #[stable(feature = "raw_ext", since = "1.1.0")] pub struct stat { #[stable(feature = "raw_ext", since = "1.1.0")] diff --git a/src/libstd/os/nacl/raw.rs b/src/libstd/os/nacl/raw.rs index d811b94c84..8289843768 100644 --- a/src/libstd/os/nacl/raw.rs +++ b/src/libstd/os/nacl/raw.rs @@ -34,6 +34,7 @@ mod arch { #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i32; #[repr(C)] + #[derive(Clone)] #[stable(feature = "raw_ext", since = "1.1.0")] pub struct stat { #[stable(feature = "raw_ext", since = "1.1.0")] @@ -94,6 +95,7 @@ mod arch { #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i32; #[repr(C)] + #[derive(Clone)] #[stable(feature = "raw_ext", since = "1.1.0")] pub struct stat { #[stable(feature = "raw_ext", since = "1.1.0")] @@ -153,6 +155,7 @@ mod arch { #[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")] @@ -210,6 +213,7 @@ mod arch { #[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")] diff --git a/src/libstd/os/netbsd/raw.rs b/src/libstd/os/netbsd/raw.rs index f9898dfbdb..882d08c660 100644 --- a/src/libstd/os/netbsd/raw.rs +++ b/src/libstd/os/netbsd/raw.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! NetBSD/OpenBSD-specific raw type definitions +//! NetBSD-specific raw type definitions #![stable(feature = "raw_ext", since = "1.1.0")] @@ -17,7 +17,7 @@ use os::unix::raw::{uid_t, gid_t}; #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = i64; #[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u32; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = i32; +#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64; #[stable(feature = "raw_ext", since = "1.1.0")] pub type fflags_t = u32; #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; #[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32; @@ -26,6 +26,7 @@ use os::unix::raw::{uid_t, gid_t}; #[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")] @@ -55,6 +56,10 @@ pub struct stat { #[stable(feature = "raw_ext", since = "1.1.0")] pub st_ctime_nsec: c_long, #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_birthtime: time_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_birthtime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] pub st_size: off_t, #[stable(feature = "raw_ext", since = "1.1.0")] pub st_blocks: blkcnt_t, @@ -64,8 +69,5 @@ pub struct stat { pub st_flags: fflags_t, #[stable(feature = "raw_ext", since = "1.1.0")] pub st_gen: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_birthtime: time_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_birthtime_nsec: c_long, + st_spare: [u32; 2], } diff --git a/src/libstd/os/openbsd/raw.rs b/src/libstd/os/openbsd/raw.rs index 79ca901ade..1cc0eedfcd 100644 --- a/src/libstd/os/openbsd/raw.rs +++ b/src/libstd/os/openbsd/raw.rs @@ -26,6 +26,7 @@ use os::unix::raw::{uid_t, gid_t}; #[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")] diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 9715939d64..2b2af350c9 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -12,11 +12,15 @@ use prelude::v1::*; use io::prelude::*; use any::Any; +use cell::Cell; use cell::RefCell; +use intrinsics; use sys::stdio::Stderr; use sys_common::backtrace; use sys_common::thread_info; -use sys_common::unwind; +use sys_common::util; + +thread_local! { pub static PANIC_COUNT: Cell = Cell::new(0) } thread_local! { pub static LOCAL_STDERR: RefCell>> = { @@ -24,7 +28,8 @@ thread_local! { } } -pub fn on_panic(obj: &(Any+Send), file: &'static str, line: u32) { +fn log_panic(obj: &(Any+Send), file: &'static str, line: u32, + log_backtrace: bool) { let msg = match obj.downcast_ref::<&'static str>() { Some(s) => *s, None => match obj.downcast_ref::() { @@ -35,37 +40,59 @@ pub fn on_panic(obj: &(Any+Send), file: &'static str, line: u32) { let mut err = Stderr::new().ok(); let thread = thread_info::current_thread(); let name = thread.as_ref().and_then(|t| t.name()).unwrap_or(""); + + let write = |err: &mut ::io::Write| { + let _ = writeln!(err, "thread '{}' panicked at '{}', {}:{}", + name, msg, file, line); + if log_backtrace { + let _ = backtrace::write(err); + } + }; + let prev = LOCAL_STDERR.with(|s| s.borrow_mut().take()); match (prev, err.as_mut()) { (Some(mut stderr), _) => { - // FIXME: what to do when the thread printing panics? - let _ = writeln!(stderr, - "thread '{}' panicked at '{}', {}:{}\n", - name, msg, file, line); - if backtrace::log_enabled() { - let _ = backtrace::write(&mut *stderr); - } + write(&mut *stderr); let mut s = Some(stderr); LOCAL_STDERR.with(|slot| { *slot.borrow_mut() = s.take(); }); } - (None, Some(ref mut err)) => { - let _ = writeln!(err, "thread '{}' panicked at '{}', {}:{}", - name, msg, file, line); - if backtrace::log_enabled() { - let _ = backtrace::write(err); - } - } + (None, Some(ref mut err)) => { write(err) } _ => {} } +} - // If this is a double panic, make sure that we printed a backtrace - // for this panic. - match err { - Some(ref mut err) if unwind::panicking() && !backtrace::log_enabled() => { - let _ = backtrace::write(err); - } - _ => {} +pub fn on_panic(obj: &(Any+Send), file: &'static str, line: u32) { + let panics = PANIC_COUNT.with(|s| { + let count = s.get() + 1; + s.set(count); + count + }); + + // If this is the third nested call, on_panic triggered the last panic, + // otherwise the double-panic check would have aborted the process. + // Even if it is likely that on_panic was unable to log the backtrace, + // abort immediately to avoid infinite recursion, so that attaching a + // debugger provides a useable stacktrace. + if panics >= 3 { + util::dumb_print(format_args!("thread panicked while processing \ + panic. aborting.")); + unsafe { intrinsics::abort() } + } + + // If this is a double panic, make sure that we print a backtrace + // for this panic. Otherwise only print it if logging is enabled. + let log_backtrace = panics >= 2 || backtrace::log_enabled(); + log_panic(obj, file, line, log_backtrace); + + if panics >= 2 { + // If a thread panics while it's already unwinding then we + // have limited options. Currently our preference is to + // just abort. In the future we may consider resuming + // unwinding or otherwise exiting the thread cleanly. + util::dumb_print(format_args!("thread panicked while panicking. \ + aborting.")); + unsafe { intrinsics::abort() } } } diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 8eb5d1f272..fe12b67123 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -101,12 +101,14 @@ use ascii::*; use borrow::{Borrow, IntoCow, ToOwned, Cow}; use cmp; +use fmt; +use fs; +use io; use iter; use mem; use ops::{self, Deref}; use string::String; use vec::Vec; -use fmt; use ffi::{OsStr, OsString}; @@ -351,7 +353,6 @@ impl<'a> Prefix<'a> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn is_separator(c: char) -> bool { - use ascii::*; c.is_ascii() && is_sep_byte(c as u8) } @@ -1292,7 +1293,7 @@ impl Path { /// use std::path::Path; /// /// let path_str = Path::new("foo.txt").to_str(); - //// assert_eq!(path_str, Some("foo.txt")); + /// assert_eq!(path_str, Some("foo.txt")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn to_str(&self) -> Option<&str> { @@ -1690,6 +1691,81 @@ impl Path { pub fn display(&self) -> Display { Display { path: self } } + + + /// Gets information on the file, directory, etc at this path. + /// + /// Consult the `fs::metadata` documentation for more info. + /// + /// This call preserves identical runtime/error semantics with + /// `fs::metadata`. + #[stable(feature = "path_ext", since = "1.5.0")] + pub fn metadata(&self) -> io::Result { + fs::metadata(self) + } + + /// Gets information on the file, directory, etc at this path. + /// + /// Consult the `fs::symlink_metadata` documentation for more info. + /// + /// This call preserves identical runtime/error semantics with + /// `fs::symlink_metadata`. + #[stable(feature = "path_ext", since = "1.5.0")] + pub fn symlink_metadata(&self) -> io::Result { + fs::symlink_metadata(self) + } + + /// Returns the canonical form of a path, normalizing all components and + /// eliminate all symlinks. + /// + /// This call preserves identical runtime/error semantics with + /// `fs::canonicalize`. + #[stable(feature = "path_ext", since = "1.5.0")] + pub fn canonicalize(&self) -> io::Result { + fs::canonicalize(self) + } + + /// Reads the symlink at this path. + /// + /// For more information see `fs::read_link`. + #[stable(feature = "path_ext", since = "1.5.0")] + pub fn read_link(&self) -> io::Result { + fs::read_link(self) + } + + /// Reads the directory at this path. + /// + /// For more information see `fs::read_dir`. + #[stable(feature = "path_ext", since = "1.5.0")] + pub fn read_dir(&self) -> io::Result { + fs::read_dir(self) + } + + /// Boolean value indicator whether the underlying file exists on the local + /// filesystem. Returns false in exactly the cases where `fs::stat` fails. + #[stable(feature = "path_ext", since = "1.5.0")] + pub fn exists(&self) -> bool { + fs::metadata(self).is_ok() + } + + /// Whether the underlying implementation (be it a file path, or something + /// else) points at a "regular file" on the FS. Will return false for paths + /// to non-existent locations or directories or other non-regular files + /// (named pipes, etc). Follows links when making this determination. + #[stable(feature = "path_ext", since = "1.5.0")] + pub fn is_file(&self) -> bool { + fs::metadata(self).map(|m| m.is_file()).unwrap_or(false) + } + + /// Whether the underlying implementation (be it a file path, or something + /// else) is pointing at a directory in the underlying FS. Will return + /// false for paths to non-existent locations or if the item is not a + /// directory (eg files, named pipes, etc). Follows links when making this + /// determination. + #[stable(feature = "path_ext", since = "1.5.0")] + pub fn is_dir(&self) -> bool { + fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false) + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/prelude/mod.rs b/src/libstd/prelude/mod.rs index 8257817280..08227cfb35 100644 --- a/src/libstd/prelude/mod.rs +++ b/src/libstd/prelude/mod.rs @@ -74,7 +74,7 @@ //! [`Eq`](../cmp/trait.Eq.html), //! [`Ord`](../cmp/trait.Ord.html) //! }. -//! The comparision traits, which implement the comparison operators +//! The comparison traits, which implement the comparison operators //! and are often seen in trait bounds. //! * `std::convert::`{ //! [`AsRef`](../convert/trait.AsRef.html), @@ -84,7 +84,7 @@ //! }. //! Generic conversions, used by savvy API authors to create //! overloaded methods. -//! * `std::default::`[`Default`](../default/trait.Default). +//! * `std::default::`[`Default`](../default/trait.Default.html). //! Types that have default values. //! * `std::iter::`{ //! [`Iterator`](../iter/trait.Iterator.html), diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index f2ae168e56..7d62d477a0 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -411,7 +411,7 @@ mod prim_isize { } #[doc(primitive = "usize")] // -/// The pointer-sized signed integer type. +/// The pointer-sized unsigned integer type. /// /// *[See also the `std::usize` module](usize/index.html).* /// diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 5f5d5a6900..9d03022bb8 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -75,7 +75,7 @@ impl IntoInner for Child { fn into_inner(self) -> imp::Process { self.handle } } -/// A handle to a child procesess's stdin +/// A handle to a child process's stdin #[stable(feature = "process", since = "1.0.0")] pub struct ChildStdin { inner: AnonPipe @@ -100,7 +100,7 @@ impl IntoInner for ChildStdin { fn into_inner(self) -> AnonPipe { self.inner } } -/// A handle to a child procesess's stdout +/// A handle to a child process's stdout #[stable(feature = "process", since = "1.0.0")] pub struct ChildStdout { inner: AnonPipe @@ -121,7 +121,7 @@ impl IntoInner for ChildStdout { fn into_inner(self) -> AnonPipe { self.inner } } -/// A handle to a child procesess's stderr +/// A handle to a child process's stderr #[stable(feature = "process", since = "1.0.0")] pub struct ChildStderr { inner: AnonPipe @@ -630,12 +630,15 @@ mod tests { fn signal_reported_right() { use os::unix::process::ExitStatusExt; - let p = Command::new("/bin/sh").arg("-c").arg("kill -9 $$").spawn(); - assert!(p.is_ok()); - let mut p = p.unwrap(); + let mut p = Command::new("/bin/sh") + .arg("-c").arg("read a") + .stdin(Stdio::piped()) + .spawn().unwrap(); + p.kill().unwrap(); match p.wait().unwrap().signal() { Some(9) => {}, - result => panic!("not terminated by signal 9 (instead, {:?})", result), + result => panic!("not terminated by signal 9 (instead, {:?})", + result), } } diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index 851726d91c..1b32515e9f 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -21,12 +21,12 @@ use time::Duration; /// A type indicating whether a timed wait on a condition variable returned /// due to a time out or not. #[derive(Debug, PartialEq, Eq, Copy, Clone)] -#[unstable(feature = "wait_timeout", reason = "newly added", issue = "27772")] +#[stable(feature = "wait_timeout", since = "1.5.0")] pub struct WaitTimeoutResult(bool); impl WaitTimeoutResult { /// Returns whether the wait was known to have timed out. - #[unstable(feature = "wait_timeout", reason = "newly added", issue = "27772")] + #[stable(feature = "wait_timeout", since = "1.5.0")] pub fn timed_out(&self) -> bool { self.0 } @@ -189,8 +189,7 @@ impl Condvar { /// /// Like `wait`, the lock specified will be re-acquired when this function /// returns, regardless of whether the timeout elapsed or not. - #[unstable(feature = "wait_timeout", reason = "waiting for Duration", - issue = "27772")] + #[stable(feature = "wait_timeout", since = "1.5.0")] pub fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>, dur: Duration) -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)> { diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 8c5cec969a..a0d0147296 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -427,7 +427,7 @@ impl UnsafeFlavor for Receiver { /// use std::sync::mpsc::channel; /// use std::thread; /// -/// // tx is is the sending half (tx for transmission), and rx is the receiving +/// // tx is the sending half (tx for transmission), and rx is the receiving /// // half (rx for receiving). /// let (tx, rx) = channel(); /// diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 846a97b547..c0cd6d127d 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -13,7 +13,9 @@ use prelude::v1::*; use cell::UnsafeCell; use fmt; use marker; +use mem; use ops::{Deref, DerefMut}; +use ptr; use sys_common::mutex as sys; use sys_common::poison::{self, TryLockError, TryLockResult, LockResult}; @@ -243,14 +245,61 @@ impl Mutex { pub fn is_poisoned(&self) -> bool { self.inner.poison.get() } + + /// Consumes this mutex, returning the underlying data. + /// + /// # Failure + /// + /// If another user of this mutex panicked while holding the mutex, then + /// this call will return an error instead. + #[unstable(feature = "mutex_into_inner", reason = "recently added", issue = "28968")] + pub fn into_inner(self) -> LockResult where T: Sized { + // We know statically that there are no outstanding references to + // `self` so there's no need to lock the inner StaticMutex. + // + // To get the inner value, we'd like to call `data.into_inner()`, + // but because `Mutex` impl-s `Drop`, we can't move out of it, so + // we'll have to destructure it manually instead. + unsafe { + // Like `let Mutex { inner, data } = self`. + let (inner, data) = { + let Mutex { ref inner, ref data } = self; + (ptr::read(inner), ptr::read(data)) + }; + mem::forget(self); + inner.lock.destroy(); // Keep in sync with the `Drop` impl. + + poison::map_result(inner.poison.borrow(), |_| data.into_inner()) + } + } + + /// Returns a mutable reference to the underlying data. + /// + /// Since this call borrows the `Mutex` mutably, no actual locking needs to + /// take place---the mutable borrow statically guarantees no locks exist. + /// + /// # Failure + /// + /// If another user of this mutex panicked while holding the mutex, then + /// this call will return an error instead. + #[unstable(feature = "mutex_get_mut", reason = "recently added", issue = "28968")] + pub fn get_mut(&mut self) -> LockResult<&mut T> { + // We know statically that there are no other references to `self`, so + // there's no need to lock the inner StaticMutex. + let data = unsafe { &mut *self.data.get() }; + poison::map_result(self.inner.poison.borrow(), |_| data ) + } } #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Mutex { + #[unsafe_destructor_blind_to_params] fn drop(&mut self) { // This is actually safe b/c we know that there is no further usage of // this mutex (it's up to the user to arrange for a mutex to get // dropped, that's not our job) + // + // IMPORTANT: This code must be kept in sync with `Mutex::into_inner`. unsafe { self.inner.lock.destroy() } } } @@ -371,10 +420,14 @@ mod tests { use sync::mpsc::channel; use sync::{Arc, Mutex, StaticMutex, Condvar}; + use sync::atomic::{AtomicUsize, Ordering}; use thread; struct Packet(Arc<(Mutex, Condvar)>); + #[derive(Eq, PartialEq, Debug)] + struct NonCopy(i32); + unsafe impl Send for Packet {} unsafe impl Sync for Packet {} @@ -435,6 +488,69 @@ mod tests { *m.try_lock().unwrap() = (); } + #[test] + fn test_into_inner() { + let m = Mutex::new(NonCopy(10)); + assert_eq!(m.into_inner().unwrap(), NonCopy(10)); + } + + #[test] + fn test_into_inner_drop() { + struct Foo(Arc); + impl Drop for Foo { + fn drop(&mut self) { + self.0.fetch_add(1, Ordering::SeqCst); + } + } + let num_drops = Arc::new(AtomicUsize::new(0)); + let m = Mutex::new(Foo(num_drops.clone())); + assert_eq!(num_drops.load(Ordering::SeqCst), 0); + { + let _inner = m.into_inner().unwrap(); + assert_eq!(num_drops.load(Ordering::SeqCst), 0); + } + assert_eq!(num_drops.load(Ordering::SeqCst), 1); + } + + #[test] + fn test_into_inner_poison() { + let m = Arc::new(Mutex::new(NonCopy(10))); + let m2 = m.clone(); + let _ = thread::spawn(move || { + let _lock = m2.lock().unwrap(); + panic!("test panic in inner thread to poison mutex"); + }).join(); + + assert!(m.is_poisoned()); + match Arc::try_unwrap(m).unwrap().into_inner() { + Err(e) => assert_eq!(e.into_inner(), NonCopy(10)), + Ok(x) => panic!("into_inner of poisoned Mutex is Ok: {:?}", x), + } + } + + #[test] + fn test_get_mut() { + let mut m = Mutex::new(NonCopy(10)); + *m.get_mut().unwrap() = NonCopy(20); + assert_eq!(m.into_inner().unwrap(), NonCopy(20)); + } + + #[test] + fn test_get_mut_poison() { + let m = Arc::new(Mutex::new(NonCopy(10))); + let m2 = m.clone(); + let _ = thread::spawn(move || { + let _lock = m2.lock().unwrap(); + panic!("test panic in inner thread to poison mutex"); + }).join(); + + assert!(m.is_poisoned()); + match Arc::try_unwrap(m).unwrap().get_mut() { + Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)), + Ok(x) => panic!("get_mut of poisoned Mutex is Ok: {:?}", x), + } + } + #[test] fn test_mutex_arc_condvar() { let packet = Packet(Arc::new((Mutex::new(false), Condvar::new()))); @@ -536,16 +652,15 @@ mod tests { assert_eq!(*lock, 2); } - // FIXME(#25351) needs deeply nested coercions of DST structs. - // #[test] - // fn test_mutex_unsized() { - // let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]); - // { - // let b = &mut *mutex.lock().unwrap(); - // b[0] = 4; - // b[2] = 5; - // } - // let comp: &[i32] = &[4, 2, 5]; - // assert_eq!(&*mutex.lock().unwrap(), comp); - // } + #[test] + fn test_mutex_unsized() { + let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]); + { + let b = &mut *mutex.lock().unwrap(); + b[0] = 4; + b[2] = 5; + } + let comp: &[i32] = &[4, 2, 5]; + assert_eq!(&*mutex.lock().unwrap(), comp); + } } diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index 7210328fad..750c9e30c5 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -13,7 +13,9 @@ use prelude::v1::*; use cell::UnsafeCell; use fmt; use marker; +use mem; use ops::{Deref, DerefMut}; +use ptr; use sys_common::poison::{self, LockResult, TryLockError, TryLockResult}; use sys_common::rwlock as sys; @@ -260,11 +262,61 @@ impl RwLock { pub fn is_poisoned(&self) -> bool { self.inner.poison.get() } + + /// Consumes this `RwLock`, returning the underlying data. + /// + /// # Failure + /// + /// 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 only be returned if the lock would have otherwise been + /// acquired. + #[unstable(feature = "rwlock_into_inner", reason = "recently added", issue = "28968")] + pub fn into_inner(self) -> LockResult where T: Sized { + // We know statically that there are no outstanding references to + // `self` so there's no need to lock the inner StaticRwLock. + // + // To get the inner value, we'd like to call `data.into_inner()`, + // but because `RwLock` impl-s `Drop`, we can't move out of it, so + // we'll have to destructure it manually instead. + unsafe { + // Like `let RwLock { inner, data } = self`. + let (inner, data) = { + let RwLock { ref inner, ref data } = self; + (ptr::read(inner), ptr::read(data)) + }; + mem::forget(self); + inner.lock.destroy(); // Keep in sync with the `Drop` impl. + + poison::map_result(inner.poison.borrow(), |_| data.into_inner()) + } + } + + /// Returns a mutable reference to the underlying data. + /// + /// Since this call borrows the `RwLock` mutably, no actual locking needs to + /// take place---the mutable borrow statically guarantees no locks exist. + /// + /// # Failure + /// + /// 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 only be returned if the lock would have otherwise been + /// acquired. + #[unstable(feature = "rwlock_get_mut", reason = "recently added", issue = "28968")] + pub fn get_mut(&mut self) -> LockResult<&mut T> { + // We know statically that there are no other references to `self`, so + // there's no need to lock the inner StaticRwLock. + let data = unsafe { &mut *self.data.get() }; + poison::map_result(self.inner.poison.borrow(), |_| data ) + } } #[stable(feature = "rust1", since = "1.0.0")] impl Drop for RwLock { + #[unsafe_destructor_blind_to_params] fn drop(&mut self) { + // IMPORTANT: This code needs to be kept in sync with `RwLock::into_inner`. unsafe { self.inner.lock.destroy() } } } @@ -426,6 +478,10 @@ mod tests { use sync::mpsc::channel; use thread; use sync::{Arc, RwLock, StaticRwLock, TryLockError}; + use sync::atomic::{AtomicUsize, Ordering}; + + #[derive(Eq, PartialEq, Debug)] + struct NonCopy(i32); #[test] fn smoke() { @@ -578,18 +634,17 @@ mod tests { assert_eq!(*lock, 2); } - // FIXME(#25351) needs deeply nested coercions of DST structs. - // #[test] - // fn test_rwlock_unsized() { - // let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]); - // { - // let b = &mut *rw.write().unwrap(); - // b[0] = 4; - // b[2] = 5; - // } - // let comp: &[i32] = &[4, 2, 5]; - // assert_eq!(&*rw.read().unwrap(), comp); - // } + #[test] + fn test_rwlock_unsized() { + let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]); + { + let b = &mut *rw.write().unwrap(); + b[0] = 4; + b[2] = 5; + } + let comp: &[i32] = &[4, 2, 5]; + assert_eq!(&*rw.read().unwrap(), comp); + } #[test] fn test_rwlock_try_write() { @@ -607,4 +662,67 @@ mod tests { drop(read_guard); } + + #[test] + fn test_into_inner() { + let m = RwLock::new(NonCopy(10)); + assert_eq!(m.into_inner().unwrap(), NonCopy(10)); + } + + #[test] + fn test_into_inner_drop() { + struct Foo(Arc); + impl Drop for Foo { + fn drop(&mut self) { + self.0.fetch_add(1, Ordering::SeqCst); + } + } + let num_drops = Arc::new(AtomicUsize::new(0)); + let m = RwLock::new(Foo(num_drops.clone())); + assert_eq!(num_drops.load(Ordering::SeqCst), 0); + { + let _inner = m.into_inner().unwrap(); + assert_eq!(num_drops.load(Ordering::SeqCst), 0); + } + assert_eq!(num_drops.load(Ordering::SeqCst), 1); + } + + #[test] + fn test_into_inner_poison() { + let m = Arc::new(RwLock::new(NonCopy(10))); + let m2 = m.clone(); + let _ = thread::spawn(move || { + let _lock = m2.write().unwrap(); + panic!("test panic in inner thread to poison RwLock"); + }).join(); + + assert!(m.is_poisoned()); + match Arc::try_unwrap(m).unwrap().into_inner() { + Err(e) => assert_eq!(e.into_inner(), NonCopy(10)), + Ok(x) => panic!("into_inner of poisoned RwLock is Ok: {:?}", x), + } + } + + #[test] + fn test_get_mut() { + let mut m = RwLock::new(NonCopy(10)); + *m.get_mut().unwrap() = NonCopy(20); + assert_eq!(m.into_inner().unwrap(), NonCopy(20)); + } + + #[test] + fn test_get_mut_poison() { + let m = Arc::new(RwLock::new(NonCopy(10))); + let m2 = m.clone(); + let _ = thread::spawn(move || { + let _lock = m2.write().unwrap(); + panic!("test panic in inner thread to poison RwLock"); + }).join(); + + assert!(m.is_poisoned()); + match Arc::try_unwrap(m).unwrap().get_mut() { + Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)), + Ok(x) => panic!("get_mut of poisoned RwLock is Ok: {:?}", x), + } + } } diff --git a/src/libstd/sys/common/libunwind.rs b/src/libstd/sys/common/libunwind.rs index c6bffb0f73..da7ebbf4ed 100644 --- a/src/libstd/sys/common/libunwind.rs +++ b/src/libstd/sys/common/libunwind.rs @@ -108,10 +108,18 @@ extern {} #[link(name = "unwind", kind = "static")] extern {} -#[cfg(any(target_os = "android", target_os = "netbsd", target_os = "openbsd"))] +#[cfg(any(target_os = "android", target_os = "openbsd"))] #[link(name = "gcc")] extern {} +#[cfg(all(target_os = "netbsd", not(target_vendor = "rumprun")))] +#[link(name = "gcc")] +extern {} + +#[cfg(all(target_os = "netbsd", target_vendor = "rumprun"))] +#[link(name = "unwind")] +extern {} + #[cfg(target_os = "dragonfly")] #[link(name = "gcc_pic")] extern {} diff --git a/src/libstd/sys/common/unwind/mod.rs b/src/libstd/sys/common/unwind/mod.rs index 738681c3cf..d87ab56d4e 100644 --- a/src/libstd/sys/common/unwind/mod.rs +++ b/src/libstd/sys/common/unwind/mod.rs @@ -64,9 +64,8 @@ use prelude::v1::*; use any::Any; use boxed; -use cell::Cell; use cmp; -use panicking; +use panicking::{self,PANIC_COUNT}; use fmt; use intrinsics; use mem; @@ -82,8 +81,18 @@ use sys_common::mutex::Mutex; #[path = "seh.rs"] #[doc(hidden)] pub mod imp; +// stage0: i686-pc-windows-gnu +#[cfg(all(stage0, windows, target_arch = "x86_64", target_env = "gnu"))] +#[path = "seh64_gnu.rs"] #[doc(hidden)] +pub mod imp; + +// stage0: x86_64-pc-windows-msvc +#[cfg(all(stage0, windows, target_arch = "x86_64", target_env = "msvc"))] +#[path = "seh.rs"] #[doc(hidden)] +pub mod imp; + // x86_64-pc-windows-* -#[cfg(all(windows, target_arch = "x86_64"))] +#[cfg(all(not(stage0), windows, target_arch = "x86_64"))] #[path = "seh64_gnu.rs"] #[doc(hidden)] pub mod imp; @@ -92,25 +101,6 @@ pub mod imp; #[path = "gcc.rs"] #[doc(hidden)] pub mod imp; -pub type Callback = fn(msg: &(Any + Send), file: &'static str, line: u32); - -// Variables used for invoking callbacks when a thread starts to unwind. -// -// For more information, see below. -const MAX_CALLBACKS: usize = 16; -static CALLBACKS: [atomic::AtomicUsize; MAX_CALLBACKS] = - [atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0), - atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0), - atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0), - atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0), - atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0), - atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0), - atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0), - atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0)]; -static CALLBACK_CNT: atomic::AtomicUsize = atomic::AtomicUsize::new(0); - -thread_local! { static PANICKING: Cell = Cell::new(false) } - /// Invoke a closure, capturing the cause of panic if one occurs. /// /// This function will return `Ok(())` if the closure did not panic, and will @@ -148,15 +138,17 @@ pub unsafe fn try(f: F) -> Result<(), Box> { // care of exposing correctly. unsafe fn inner_try(f: fn(*mut u8), data: *mut u8) -> Result<(), Box> { - let prev = PANICKING.with(|s| s.get()); - PANICKING.with(|s| s.set(false)); - let ep = intrinsics::try(f, data); - PANICKING.with(|s| s.set(prev)); - if ep.is_null() { - Ok(()) - } else { - Err(imp::cleanup(ep)) - } + PANIC_COUNT.with(|s| { + let prev = s.get(); + s.set(0); + let ep = intrinsics::try(f, data); + s.set(prev); + if ep.is_null() { + Ok(()) + } else { + Err(imp::cleanup(ep)) + } + }) } fn try_fn(opt_closure: *mut u8) { @@ -176,7 +168,7 @@ pub unsafe fn try(f: F) -> Result<(), Box> { /// Determines whether the current thread is unwinding because of panic. pub fn panicking() -> bool { - PANICKING.with(|s| s.get()) + PANIC_COUNT.with(|s| s.get() != 0) } // An uninlined, unmangled function upon which to slap yer breakpoints @@ -244,83 +236,11 @@ pub fn begin_unwind(msg: M, file_line: &(&'static str, u32)) -> ! #[inline(never)] #[cold] // this is the slow path, please never inline this fn begin_unwind_inner(msg: Box, file_line: &(&'static str, u32)) -> ! { - // Make sure the default failure handler is registered before we look at the - // callbacks. We also use a raw sys-based mutex here instead of a - // `std::sync` one as accessing TLS can cause weird recursive problems (and - // we don't need poison checking). - unsafe { - static LOCK: Mutex = Mutex::new(); - static mut INIT: bool = false; - LOCK.lock(); - if !INIT { - register(panicking::on_panic); - INIT = true; - } - LOCK.unlock(); - } + let (file, line) = *file_line; - // First, invoke call the user-defined callbacks triggered on thread panic. - // - // By the time that we see a callback has been registered (by reading - // MAX_CALLBACKS), the actual callback itself may have not been stored yet, - // so we just chalk it up to a race condition and move on to the next - // callback. Additionally, CALLBACK_CNT may briefly be higher than - // MAX_CALLBACKS, so we're sure to clamp it as necessary. - let callbacks = { - let amt = CALLBACK_CNT.load(Ordering::SeqCst); - &CALLBACKS[..cmp::min(amt, MAX_CALLBACKS)] - }; - for cb in callbacks { - match cb.load(Ordering::SeqCst) { - 0 => {} - n => { - let f: Callback = unsafe { mem::transmute(n) }; - let (file, line) = *file_line; - f(&*msg, file, line); - } - } - }; + // First, invoke the default panic handler. + panicking::on_panic(&*msg, file, line); - // Now that we've run all the necessary unwind callbacks, we actually - // perform the unwinding. - if panicking() { - // If a thread panics while it's already unwinding then we - // have limited options. Currently our preference is to - // just abort. In the future we may consider resuming - // unwinding or otherwise exiting the thread cleanly. - super::util::dumb_print(format_args!("thread panicked while panicking. \ - aborting.")); - unsafe { intrinsics::abort() } - } - PANICKING.with(|s| s.set(true)); + // Finally, perform the unwinding. rust_panic(msg); } - -/// Register a callback to be invoked when a thread unwinds. -/// -/// This is an unsafe and experimental API which allows for an arbitrary -/// callback to be invoked when a thread panics. This callback is invoked on both -/// the initial unwinding and a double unwinding if one occurs. Additionally, -/// the local `Thread` will be in place for the duration of the callback, and -/// the callback must ensure that it remains in place once the callback returns. -/// -/// Only a limited number of callbacks can be registered, and this function -/// returns whether the callback was successfully registered or not. It is not -/// currently possible to unregister a callback once it has been registered. -pub unsafe fn register(f: Callback) -> bool { - match CALLBACK_CNT.fetch_add(1, Ordering::SeqCst) { - // The invocation code has knowledge of this window where the count has - // been incremented, but the callback has not been stored. We're - // guaranteed that the slot we're storing into is 0. - n if n < MAX_CALLBACKS => { - let prev = CALLBACKS[n].swap(mem::transmute(f), Ordering::SeqCst); - rtassert!(prev == 0); - true - } - // If we accidentally bumped the count too high, pull it back. - _ => { - CALLBACK_CNT.store(MAX_CALLBACKS, Ordering::SeqCst); - false - } - } -} diff --git a/src/libstd/sys/common/wtf8.rs b/src/libstd/sys/common/wtf8.rs index 633e7d78a9..271aba680a 100644 --- a/src/libstd/sys/common/wtf8.rs +++ b/src/libstd/sys/common/wtf8.rs @@ -31,7 +31,6 @@ use core::str::next_code_point; use ascii::*; use borrow::Cow; use char; -use cmp; use fmt; use hash::{Hash, Hasher}; use iter::FromIterator; @@ -147,13 +146,13 @@ impl fmt::Debug for Wtf8Buf { } impl Wtf8Buf { - /// Creates an new, empty WTF-8 string. + /// Creates a new, empty WTF-8 string. #[inline] pub fn new() -> Wtf8Buf { Wtf8Buf { bytes: Vec::new() } } - /// Creates an new, empty WTF-8 string with pre-allocated capacity for `n` bytes. + /// Creates a new, empty WTF-8 string with pre-allocated capacity for `n` bytes. #[inline] pub fn with_capacity(n: usize) -> Wtf8Buf { Wtf8Buf { bytes: Vec::with_capacity(n) } @@ -375,6 +374,7 @@ impl Extend for Wtf8Buf { /// /// Similar to `&str`, but can additionally contain surrogate code points /// if they’re not in a surrogate pair. +#[derive(Eq, Ord, PartialEq, PartialOrd)] pub struct Wtf8 { bytes: [u8] } @@ -383,36 +383,6 @@ impl AsInner<[u8]> for Wtf8 { fn as_inner(&self) -> &[u8] { &self.bytes } } -// FIXME: https://github.com/rust-lang/rust/issues/18805 -impl PartialEq for Wtf8 { - fn eq(&self, other: &Wtf8) -> bool { self.bytes.eq(&other.bytes) } -} - -// FIXME: https://github.com/rust-lang/rust/issues/18805 -impl Eq for Wtf8 {} - -// FIXME: https://github.com/rust-lang/rust/issues/18738 -impl PartialOrd for Wtf8 { - #[inline] - fn partial_cmp(&self, other: &Wtf8) -> Option { - self.bytes.partial_cmp(&other.bytes) - } - #[inline] - fn lt(&self, other: &Wtf8) -> bool { self.bytes.lt(&other.bytes) } - #[inline] - fn le(&self, other: &Wtf8) -> bool { self.bytes.le(&other.bytes) } - #[inline] - fn gt(&self, other: &Wtf8) -> bool { self.bytes.gt(&other.bytes) } - #[inline] - fn ge(&self, other: &Wtf8) -> bool { self.bytes.ge(&other.bytes) } -} - -// FIXME: https://github.com/rust-lang/rust/issues/18738 -impl Ord for Wtf8 { - #[inline] - fn cmp(&self, other: &Wtf8) -> cmp::Ordering { self.bytes.cmp(&other.bytes) } -} - /// Format the slice with double quotes, /// and surrogates as `\u` followed by four hexadecimal digits. /// Example: `"a\u{D800}"` for a slice with code points [U+0061, U+D800] @@ -1049,7 +1019,7 @@ mod tests { fn wtf8buf_from_iterator() { fn f(values: &[u32]) -> Wtf8Buf { values.iter().map(|&c| CodePoint::from_u32(c).unwrap()).collect::() - }; + } assert_eq!(f(&[0x61, 0xE9, 0x20, 0x1F4A9]).bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); assert_eq!(f(&[0xD83D, 0xDCA9]).bytes, b"\xF0\x9F\x92\xA9"); // Magic! @@ -1068,7 +1038,7 @@ mod tests { let mut string = initial.iter().map(c).collect::(); string.extend(extended.iter().map(c)); string - }; + } assert_eq!(e(&[0x61, 0xE9], &[0x20, 0x1F4A9]).bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); diff --git a/src/libstd/sys/unix/c.rs b/src/libstd/sys/unix/c.rs index eeecf7f50f..051b3d8897 100644 --- a/src/libstd/sys/unix/c.rs +++ b/src/libstd/sys/unix/c.rs @@ -61,9 +61,10 @@ pub const _SC_GETPW_R_SIZE_MAX: libc::c_int = 70; target_os = "dragonfly"))] pub const _SC_GETPW_R_SIZE_MAX: libc::c_int = 71; #[cfg(any(target_os = "bitrig", - target_os = "netbsd", target_os = "openbsd"))] pub const _SC_GETPW_R_SIZE_MAX: libc::c_int = 101; +#[cfg(target_os = "netbsd")] +pub const _SC_GETPW_R_SIZE_MAX: libc::c_int = 48; #[cfg(target_os = "android")] pub const _SC_GETPW_R_SIZE_MAX: libc::c_int = 0x0048; @@ -131,26 +132,31 @@ extern { pub fn raise(signum: libc::c_int) -> libc::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__sigaction14")] pub fn sigaction(signum: libc::c_int, act: *const sigaction, oldact: *mut sigaction) -> libc::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__sigaltstack14")] pub fn sigaltstack(ss: *const sigaltstack, oss: *mut sigaltstack) -> libc::c_int; #[cfg(not(target_os = "android"))] + #[cfg_attr(target_os = "netbsd", link_name = "__sigemptyset14")] pub fn sigemptyset(set: *mut sigset_t) -> libc::c_int; pub fn pthread_sigmask(how: libc::c_int, set: *const sigset_t, oldset: *mut sigset_t) -> libc::c_int; #[cfg(not(target_os = "ios"))] + #[cfg_attr(target_os = "netbsd", link_name = "__getpwuid_r50")] pub fn getpwuid_r(uid: libc::uid_t, pwd: *mut passwd, buf: *mut libc::c_char, buflen: libc::size_t, result: *mut *mut passwd) -> libc::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__utimes50")] pub fn utimes(filename: *const libc::c_char, times: *const libc::timeval) -> libc::c_int; pub fn gai_strerror(errcode: libc::c_int) -> *const libc::c_char; @@ -347,12 +353,12 @@ mod signal_os { #[cfg(any(target_os = "macos", target_os = "ios"))] pub type sigset_t = u32; - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd"))] #[repr(C)] pub struct sigset_t { bits: [u32; 4], } - #[cfg(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"))] + #[cfg(any(target_os = "bitrig", target_os = "openbsd"))] pub type sigset_t = libc::c_uint; // This structure has more fields, but we're not all that interested in diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs index 46ab83199f..5ef37ae51c 100644 --- a/src/libstd/sys/unix/ext/fs.rs +++ b/src/libstd/sys/unix/ext/fs.rs @@ -178,21 +178,23 @@ impl MetadataExt for fs::Metadata { } /// Add special unix types (block/char device, fifo and socket) -#[unstable(feature = "file_type_ext", reason = "recently added API", - issue = "27796")] +#[stable(feature = "file_type_ext", since = "1.5.0")] pub trait FileTypeExt { /// Returns whether this file type is a block device. + #[stable(feature = "file_type_ext", since = "1.5.0")] fn is_block_device(&self) -> bool; /// Returns whether this file type is a char device. + #[stable(feature = "file_type_ext", since = "1.5.0")] fn is_char_device(&self) -> bool; /// Returns whether this file type is a fifo. + #[stable(feature = "file_type_ext", since = "1.5.0")] fn is_fifo(&self) -> bool; /// Returns whether this file type is a socket. + #[stable(feature = "file_type_ext", since = "1.5.0")] fn is_socket(&self) -> bool; } -#[unstable(feature = "file_type_ext", reason = "recently added API", - issue = "27796")] +#[stable(feature = "file_type_ext", since = "1.5.0")] impl FileTypeExt for fs::FileType { fn is_block_device(&self) -> bool { self.as_inner().is(libc::S_IFBLK) } fn is_char_device(&self) -> bool { self.as_inner().is(libc::S_IFCHR) } diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs index 81980ea25f..dcfa376c81 100644 --- a/src/libstd/sys/unix/ext/process.rs +++ b/src/libstd/sys/unix/ext/process.rs @@ -39,7 +39,7 @@ pub trait CommandExt { /// This is not enough to create a daemon process. The *init* process should /// be the child reaper of a daemon. This can be achieved if the parent /// process exit. Moreover, a daemon should not have a controlling terminal. - /// To acheive this, a session leader (the child) must spawn another process + /// To achieve this, a session leader (the child) must spawn another process /// (the daemon) in the same session. #[unstable(feature = "process_session_leader", reason = "recently added", issue = "27811")] diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 0eebe5af91..c2145ac875 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -27,6 +27,7 @@ use vec::Vec; pub struct File(FileDesc); +#[derive(Clone)] pub struct FileAttr { stat: raw::stat, } @@ -542,7 +543,7 @@ pub fn canonicalize(p: &Path) -> io::Result { } pub fn copy(from: &Path, to: &Path) -> io::Result { - use fs::{File, PathExt, set_permissions}; + use fs::{File, set_permissions}; if !from.is_file() { return Err(Error::new(ErrorKind::InvalidInput, "the source path is not an existing regular file")) diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index 964bc08ff4..3a88f36399 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -49,7 +49,7 @@ pub mod time; pub mod stdio; pub fn init() { - // By default, some platforms will send a *signal* when a EPIPE error + // By default, some platforms will send a *signal* when an EPIPE error // would otherwise be delivered. This runtime doesn't install a SIGPIPE // handler, causing it to kill the program, which isn't exactly what we // want! diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 94c4d04ea3..59b385b948 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -187,10 +187,10 @@ pub fn current_exe() -> io::Result { unsafe { use libc::funcs::bsd44::*; use libc::consts::os::extra::*; - let mut mib = vec![CTL_KERN as c_int, - KERN_PROC as c_int, - KERN_PROC_PATHNAME as c_int, - -1 as c_int]; + let mut mib = [CTL_KERN as c_int, + KERN_PROC as c_int, + KERN_PROC_PATHNAME as c_int, + -1 as c_int]; let mut sz: libc::size_t = 0; let err = sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint, ptr::null_mut(), &mut sz, ptr::null_mut(), @@ -213,7 +213,12 @@ pub fn current_exe() -> io::Result { ::fs::read_link("/proc/curproc/file") } -#[cfg(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"))] +#[cfg(target_os = "netbsd")] +pub fn current_exe() -> io::Result { + ::fs::read_link("/proc/curproc/exe") +} + +#[cfg(any(target_os = "bitrig", target_os = "openbsd"))] pub fn current_exe() -> io::Result { use sync::StaticMutex; static LOCK: StaticMutex = StaticMutex::new(); @@ -338,7 +343,7 @@ pub fn args() -> Args { let args = objc_msgSend(info, arguments_sel); let cnt: usize = mem::transmute(objc_msgSend(args, count_sel)); - for i in (0..cnt) { + 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)); diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs index 12ca31ce5e..7f50e75f6f 100644 --- a/src/libstd/sys/unix/process.rs +++ b/src/libstd/sys/unix/process.rs @@ -450,8 +450,18 @@ mod tests { use slice; use sys::{self, c, cvt, pipe}; + macro_rules! t { + ($e:expr) => { + match $e { + Ok(t) => t, + Err(e) => panic!("received error for `{}`: {}", stringify!($e), e), + } + } + } + #[cfg(not(target_os = "android"))] extern { + #[cfg_attr(target_os = "netbsd", link_name = "__sigaddset14")] fn sigaddset(set: *mut c::sigset_t, signum: libc::c_int) -> libc::c_int; } @@ -472,24 +482,26 @@ mod tests { unsafe { // Test to make sure that a signal mask does not get inherited. let cmd = Command::new(OsStr::new("cat")); - let (stdin_read, stdin_write) = sys::pipe::anon_pipe().unwrap(); - let (stdout_read, stdout_write) = sys::pipe::anon_pipe().unwrap(); + let (stdin_read, stdin_write) = t!(sys::pipe::anon_pipe()); + let (stdout_read, stdout_write) = t!(sys::pipe::anon_pipe()); let mut set: c::sigset_t = mem::uninitialized(); let mut old_set: c::sigset_t = mem::uninitialized(); - cvt(c::sigemptyset(&mut set)).unwrap(); - cvt(sigaddset(&mut set, libc::SIGINT)).unwrap(); - cvt(c::pthread_sigmask(c::SIG_SETMASK, &set, &mut old_set)).unwrap(); + t!(cvt(c::sigemptyset(&mut set))); + t!(cvt(sigaddset(&mut set, libc::SIGINT))); + t!(cvt(c::pthread_sigmask(c::SIG_SETMASK, &set, &mut old_set))); - let cat = Process::spawn(&cmd, Stdio::Raw(stdin_read.raw()), - Stdio::Raw(stdout_write.raw()), - Stdio::None).unwrap(); + let cat = t!(Process::spawn(&cmd, Stdio::Raw(stdin_read.raw()), + Stdio::Raw(stdout_write.raw()), + Stdio::None)); drop(stdin_read); drop(stdout_write); - cvt(c::pthread_sigmask(c::SIG_SETMASK, &old_set, ptr::null_mut())).unwrap(); + t!(cvt(c::pthread_sigmask(c::SIG_SETMASK, &old_set, + ptr::null_mut()))); - cvt(libc::funcs::posix88::signal::kill(cat.id() as libc::pid_t, libc::SIGINT)).unwrap(); + t!(cvt(libc::funcs::posix88::signal::kill(cat.id() as libc::pid_t, + libc::SIGINT))); // We need to wait until SIGINT is definitely delivered. The // easiest way is to write something to cat, and try to read it // back: if SIGINT is unmasked, it'll get delivered when cat is @@ -503,7 +515,7 @@ mod tests { assert!(ret == 0); } - cat.wait().unwrap(); + t!(cat.wait()); } } } diff --git a/src/libstd/sys/unix/stack_overflow.rs b/src/libstd/sys/unix/stack_overflow.rs index 441313bc63..f5fd11b61b 100644 --- a/src/libstd/sys/unix/stack_overflow.rs +++ b/src/libstd/sys/unix/stack_overflow.rs @@ -34,7 +34,7 @@ impl Drop for Handler { #[cfg(any(target_os = "linux", target_os = "macos", target_os = "bitrig", - target_os = "netbsd", + all(target_os = "netbsd", not(target_vendor = "rumprun")), target_os = "openbsd"))] mod imp { use super::Handler; @@ -143,7 +143,7 @@ mod imp { #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "bitrig", - target_os = "netbsd", + all(target_os = "netbsd", not(target_vendor = "rumprun")), target_os = "openbsd")))] mod imp { use ptr; diff --git a/src/libstd/sys/unix/sync.rs b/src/libstd/sys/unix/sync.rs index 4e49b6473c..954bfbb6b1 100644 --- a/src/libstd/sys/unix/sync.rs +++ b/src/libstd/sys/unix/sync.rs @@ -40,6 +40,7 @@ extern { pub fn pthread_cond_signal(cond: *mut pthread_cond_t) -> libc::c_int; pub fn pthread_cond_broadcast(cond: *mut pthread_cond_t) -> libc::c_int; pub fn pthread_cond_destroy(cond: *mut pthread_cond_t) -> libc::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__gettimeofday50")] pub fn gettimeofday(tp: *mut libc::timeval, tz: *mut libc::c_void) -> libc::c_int; @@ -55,7 +56,6 @@ extern { #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", - target_os = "netbsd", target_os = "openbsd"))] mod os { use libc; @@ -249,3 +249,67 @@ mod os { }; pub const PTHREAD_MUTEX_RECURSIVE: libc::c_int = 1; } + +#[cfg(target_os = "netbsd")] +mod os { + use libc; + + // size of the type minus width of the magic and alignment field + #[cfg(target_arch = "x86_64")] + const __PTHREAD_MUTEX_SIZE__: usize = 48 - 4 - 8; + + #[cfg(target_arch = "x86_64")] + const __PTHREAD_MUTEXATTR_SIZE__: usize = 16 - 8; // no magic field + + #[cfg(target_arch = "x86_64")] + const __PTHREAD_COND_SIZE__: usize = 40 - 4 - 8; + + #[cfg(target_arch = "x86_64")] + const __PTHREAD_RWLOCK_SIZE__: usize = 64 - 4 - 8; + + const _PTHREAD_MUTEX_MAGIC_INIT: libc::c_uint = 0x33330003; + const _PTHREAD_COND_MAGIC_INIT: libc::c_uint = 0x55550005; + const _PTHREAD_RWLOCK_MAGIC_INIT: libc::c_uint = 0x99990009; + + #[repr(C)] + pub struct pthread_mutex_t { + __magic: libc::c_uint, + __opaque: [u8; __PTHREAD_MUTEX_SIZE__], + __align: libc::c_longlong, + } + #[repr(C)] + pub struct pthread_mutexattr_t { + __opaque: [u8; __PTHREAD_MUTEXATTR_SIZE__], + __align: libc::c_longlong, + } + #[repr(C)] + pub struct pthread_cond_t { + __magic: libc::c_uint, + __opaque: [u8; __PTHREAD_COND_SIZE__], + __align: libc::c_longlong, + } + #[repr(C)] + pub struct pthread_rwlock_t { + __magic: libc::c_uint, + __opaque: [u8; __PTHREAD_RWLOCK_SIZE__], + __align: libc::c_longlong, + } + + pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { + __magic: _PTHREAD_MUTEX_MAGIC_INIT, + __opaque: [0; __PTHREAD_MUTEX_SIZE__], + __align: 0, + }; + pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t { + __magic: _PTHREAD_COND_MAGIC_INIT, + __opaque: [0; __PTHREAD_COND_SIZE__], + __align: 0, + }; + pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t { + __magic: _PTHREAD_RWLOCK_MAGIC_INIT, + __opaque: [0; __PTHREAD_RWLOCK_SIZE__], + __align: 0, + }; + + pub const PTHREAD_MUTEX_RECURSIVE: libc::c_int = 2; +} diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 268ec7fe35..b7968e9344 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -102,7 +102,6 @@ impl Thread { #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", - target_os = "netbsd", target_os = "openbsd"))] pub fn set_name(name: &str) { extern { @@ -126,6 +125,21 @@ impl Thread { } } + #[cfg(target_os = "netbsd")] + pub fn set_name(name: &str) { + extern { + fn pthread_setname_np(thread: libc::pthread_t, + name: *const libc::c_char, + arg: *mut libc::c_void) -> libc::c_int; + } + let cname = CString::new(&b"%s"[..]).unwrap(); + let carg = CString::new(name).unwrap(); + unsafe { + pthread_setname_np(pthread_self(), cname.as_ptr(), + carg.as_ptr() as *mut libc::c_void); + } + } + pub fn sleep(dur: Duration) { let mut ts = libc::timespec { tv_sec: dur.as_secs() as libc::time_t, @@ -160,7 +174,7 @@ impl Drop for Thread { #[cfg(all(not(target_os = "linux"), not(target_os = "macos"), not(target_os = "bitrig"), - not(target_os = "netbsd"), + not(all(target_os = "netbsd", not(target_vendor = "rumprun"))), not(target_os = "openbsd")))] pub mod guard { pub unsafe fn current() -> Option { None } @@ -171,7 +185,7 @@ pub mod guard { #[cfg(any(target_os = "linux", target_os = "macos", target_os = "bitrig", - target_os = "netbsd", + all(target_os = "netbsd", not(target_vendor = "rumprun")), target_os = "openbsd"))] #[allow(unused_imports)] pub mod guard { @@ -191,13 +205,12 @@ pub mod guard { #[cfg(any(target_os = "macos", target_os = "bitrig", - target_os = "netbsd", target_os = "openbsd"))] unsafe fn get_stack_start() -> Option<*mut libc::c_void> { current().map(|s| s as *mut libc::c_void) } - #[cfg(any(target_os = "linux", target_os = "android"))] + #[cfg(any(target_os = "linux", target_os = "android", target_os = "netbsd"))] unsafe fn get_stack_start() -> Option<*mut libc::c_void> { use super::pthread_attr_init; @@ -263,7 +276,7 @@ pub mod guard { pthread_get_stacksize_np(pthread_self())) as usize) } - #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "bitrig"))] + #[cfg(any(target_os = "openbsd", target_os = "bitrig"))] pub unsafe fn current() -> Option { #[repr(C)] struct stack_t { @@ -290,7 +303,7 @@ pub mod guard { }) } - #[cfg(any(target_os = "linux", target_os = "android"))] + #[cfg(any(target_os = "linux", target_os = "android", target_os = "netbsd"))] pub unsafe fn current() -> Option { use super::pthread_attr_init; @@ -307,13 +320,17 @@ pub mod guard { let mut size = 0; assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, &mut size), 0); - ret = Some(stackaddr as usize + guardsize as usize); + ret = if cfg!(target_os = "netbsd") { + Some(stackaddr as usize) + } else { + Some(stackaddr as usize + guardsize as usize) + }; } assert_eq!(pthread_attr_destroy(&mut attr), 0); ret } - #[cfg(any(target_os = "linux", target_os = "android"))] + #[cfg(any(target_os = "linux", target_os = "android", target_os = "netbsd"))] extern { fn pthread_getattr_np(native: libc::pthread_t, attr: *mut libc::pthread_attr_t) -> libc::c_int; @@ -339,6 +356,7 @@ pub mod guard { // but that caused Debian to detect an unnecessarily strict versioned // dependency on libc6 (#23628). #[cfg(target_os = "linux")] +#[allow(deprecated)] fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize { use dynamic_lib::DynamicLibrary; use sync::Once; diff --git a/src/libstd/sys/unix/time.rs b/src/libstd/sys/unix/time.rs index db0d0f1506..73b6687758 100644 --- a/src/libstd/sys/unix/time.rs +++ b/src/libstd/sys/unix/time.rs @@ -86,7 +86,9 @@ mod inner { #[link(name = "rt")] extern {} + extern { + #[cfg_attr(target_os = "netbsd", link_name = "__clock_gettime50")] fn clock_gettime(clk_id: libc::c_int, tp: *mut libc::timespec) -> libc::c_int; } diff --git a/src/libstd/sys/windows/backtrace.rs b/src/libstd/sys/windows/backtrace.rs index 9534a107d1..b562e772b9 100644 --- a/src/libstd/sys/windows/backtrace.rs +++ b/src/libstd/sys/windows/backtrace.rs @@ -22,7 +22,7 @@ //! copy of that function in my mingw install (maybe it was broken?). Instead, //! this takes the route of using StackWalk64 in order to walk the stack. -#![allow(dead_code)] +#![allow(dead_code, deprecated)] use io::prelude::*; diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index 30c7e5a52b..a9eb4db2f5 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -83,6 +83,8 @@ pub const EXCEPTION_CONTINUE_SEARCH: LONG = 0; pub const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15; pub const EXCEPTION_STACK_OVERFLOW: DWORD = 0xc00000fd; +pub const ERROR_PATH_NOT_FOUND: libc::c_int = 3; + #[repr(C)] #[cfg(target_arch = "x86")] pub struct WSADATA { @@ -182,6 +184,7 @@ pub struct CONSOLE_SCREEN_BUFFER_INFO { pub type PCONSOLE_SCREEN_BUFFER_INFO = *mut CONSOLE_SCREEN_BUFFER_INFO; #[repr(C)] +#[derive(Clone)] pub struct WIN32_FILE_ATTRIBUTE_DATA { pub dwFileAttributes: libc::DWORD, pub ftCreationTime: libc::FILETIME, diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index e9d98b36a4..fb2456564e 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -27,6 +27,7 @@ use vec::Vec; pub struct File { handle: Handle } +#[derive(Clone)] pub struct FileAttr { data: c::WIN32_FILE_ATTRIBUTE_DATA, reparse_tag: libc::DWORD, @@ -583,6 +584,8 @@ fn get_path(f: &File) -> io::Result { pub fn canonicalize(p: &Path) -> io::Result { let mut opts = OpenOptions::new(); opts.read(true); + // This flag is so we can open directories too + opts.flags_and_attributes(c::FILE_FLAG_BACKUP_SEMANTICS); let f = try!(File::open(p, &opts)); get_path(&f) } diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 04bb5e5ea3..4df3c561ab 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -51,6 +51,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { libc::ERROR_ALREADY_EXISTS => ErrorKind::AlreadyExists, libc::ERROR_BROKEN_PIPE => ErrorKind::BrokenPipe, libc::ERROR_FILE_NOT_FOUND => ErrorKind::NotFound, + c::ERROR_PATH_NOT_FOUND => ErrorKind::NotFound, libc::ERROR_NO_DATA => ErrorKind::BrokenPipe, libc::ERROR_OPERATION_ABORTED => ErrorKind::TimedOut, @@ -75,8 +76,8 @@ fn to_utf16_os(s: &OsStr) -> Vec { v } -// Many Windows APIs follow a pattern of where we hand the a buffer and then -// they will report back to us how large the buffer should be or how many bytes +// Many Windows APIs follow a pattern of where we hand a buffer and then they +// will report back to us how large the buffer should be or how many bytes // currently reside in the buffer. This function is an abstraction over these // functions by making them easier to call. // diff --git a/src/libstd/sys/windows/mutex.rs b/src/libstd/sys/windows/mutex.rs index 277c3d14c0..b770156582 100644 --- a/src/libstd/sys/windows/mutex.rs +++ b/src/libstd/sys/windows/mutex.rs @@ -22,7 +22,7 @@ //! more details. //! //! 3. While CriticalSection is fair and SRWLock is not, the current Rust policy -//! is there there are no guarantees of fairness. +//! is that there are no guarantees of fairness. //! //! The downside of this approach, however, is that SRWLock is not available on //! Windows XP, so we continue to have a fallback implementation where diff --git a/src/libstd/sys/windows/printing/gnu.rs b/src/libstd/sys/windows/printing/gnu.rs index 8d3c93bb7b..e27bef0b1e 100644 --- a/src/libstd/sys/windows/printing/gnu.rs +++ b/src/libstd/sys/windows/printing/gnu.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(deprecated)] + use dynamic_lib::DynamicLibrary; use io; use io::prelude::*; diff --git a/src/libstd/sys/windows/printing/msvc.rs b/src/libstd/sys/windows/printing/msvc.rs index 81d19374fe..6f1db5df7d 100644 --- a/src/libstd/sys/windows/printing/msvc.rs +++ b/src/libstd/sys/windows/printing/msvc.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(deprecated)] + use sys_common::backtrace::{output, output_fileline}; use ffi::CStr; use dynamic_lib::DynamicLibrary; diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 43c23ec8a4..9b8f63997b 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -162,7 +162,6 @@ use prelude::v1::*; -use alloc::boxed::FnBox; use any::Any; use cell::UnsafeCell; use fmt; @@ -249,16 +248,6 @@ impl Builder { pub fn spawn(self, f: F) -> io::Result> where F: FnOnce() -> T, F: Send + 'static, T: Send + 'static { - unsafe { - self.spawn_inner(Box::new(f)).map(JoinHandle) - } - } - - // NB: this function is unsafe as the lifetime parameter of the code to run - // in the new thread is not tied into the return value, and the return - // value must not outlast that lifetime. - unsafe fn spawn_inner<'a, T: Send>(self, f: Box T + Send + 'a>) - -> io::Result> { let Builder { name, stack_size } = self; let stack_size = stack_size.unwrap_or(util::min_stack()); @@ -266,29 +255,34 @@ impl Builder { let my_thread = Thread::new(name); let their_thread = my_thread.clone(); - let my_packet = Arc::new(UnsafeCell::new(None)); + let my_packet : Arc>>> + = Arc::new(UnsafeCell::new(None)); let their_packet = my_packet.clone(); let main = move || { if let Some(name) = their_thread.name() { imp::Thread::set_name(name); } - thread_info::set(imp::guard::current(), their_thread); - let mut output = None; - let try_result = { - let ptr = &mut output; - unwind::try(move || *ptr = Some(f())) - }; - *their_packet.get() = Some(try_result.map(|()| { - output.unwrap() - })); + unsafe { + thread_info::set(imp::guard::current(), their_thread); + let mut output = None; + let try_result = { + let ptr = &mut output; + unwind::try(move || *ptr = Some(f())) + }; + *their_packet.get() = Some(try_result.map(|()| { + output.unwrap() + })); + } }; - Ok(JoinInner { - native: Some(try!(imp::Thread::new(stack_size, Box::new(main)))), + Ok(JoinHandle(JoinInner { + native: unsafe { + Some(try!(imp::Thread::new(stack_size, Box::new(main)))) + }, thread: my_thread, packet: Packet(my_packet), - }) + })) } } diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index 2135b85103..d18d7cbecf 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -47,7 +47,7 @@ pub struct Duration { } impl Duration { - /// Crates a new `Duration` from the specified number of seconds and + /// Creates a new `Duration` from the specified number of seconds and /// additional nanosecond precision. /// /// If the nanoseconds is greater than 1 billion (the number of nanoseconds diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index bf8c67c7ae..7b3c33d53a 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -10,8 +10,6 @@ // The Rust abstract syntax tree. -pub use self::AsmDialect::*; -pub use self::AttrStyle::*; pub use self::BindingMode::*; pub use self::BinOp_::*; pub use self::BlockCheckMode::*; @@ -28,7 +26,6 @@ pub use self::Item_::*; pub use self::KleeneOp::*; pub use self::Lit_::*; pub use self::LitIntType::*; -pub use self::Mac_::*; pub use self::MacStmtStyle::*; pub use self::MetaItem_::*; pub use self::Mutability::*; @@ -47,7 +44,6 @@ pub use self::TyParamBound::*; pub use self::UintTy::*; pub use self::UnOp::*; pub use self::UnsafeSource::*; -pub use self::VariantKind::*; pub use self::ViewPath_::*; pub use self::Visibility::*; pub use self::PathParameters::*; @@ -67,42 +63,42 @@ use ptr::P; use std::fmt; use std::rc::Rc; +use std::borrow::Cow; +use std::hash::{Hash, Hasher}; use serialize::{Encodable, Decodable, Encoder, Decoder}; -// FIXME #6993: in librustc, uses of "ident" should be replaced -// by just "Name". +/// A name is a part of an identifier, representing a string or gensym. It's +/// the result of interning. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Name(pub u32); + +/// A SyntaxContext represents a chain of macro-expandings +/// and renamings. Each macro expansion corresponds to +/// a fresh u32. This u32 is a reference to a table stored +// in thread-local storage. +// The special value EMPTY_CTXT is used to indicate an empty +// syntax context. +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +pub struct SyntaxContext(pub u32); /// An identifier contains a Name (index into the interner /// table) and a SyntaxContext to track renaming and -/// macro expansion per Flatt et al., "Macros -/// That Work Together" -#[derive(Clone, Copy, Hash, PartialOrd, Eq, Ord)] +/// macro expansion per Flatt et al., "Macros That Work Together" +#[derive(Clone, Copy, Eq)] pub struct Ident { pub name: Name, pub ctxt: SyntaxContext } -impl Ident { - /// Construct an identifier with the given name and an empty context: - pub fn new(name: Name) -> Ident { Ident {name: name, ctxt: EMPTY_CTXT}} -} - -impl fmt::Debug for Ident { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}#{}", self.name, self.ctxt) - } -} - -impl fmt::Display for Ident { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self.name, f) +impl Name { + pub fn as_str(self) -> token::InternedString { + token::InternedString::new_from_name(self) } } impl fmt::Debug for Name { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let Name(nm) = *self; - write!(f, "{}({})", self, nm) + write!(f, "{}({})", self, self.0) } } @@ -112,89 +108,89 @@ impl fmt::Display for Name { } } -impl PartialEq for Ident { - fn eq(&self, other: &Ident) -> bool { - if self.ctxt == other.ctxt { - self.name == other.name - } else { - // IF YOU SEE ONE OF THESE FAILS: it means that you're comparing - // idents that have different contexts. You can't fix this without - // knowing whether the comparison should be hygienic or non-hygienic. - // if it should be non-hygienic (most things are), just compare the - // 'name' fields of the idents. Or, even better, replace the idents - // with Name's. - // - // On the other hand, if the comparison does need to be hygienic, - // one example and its non-hygienic counterpart would be: - // syntax::parse::token::Token::mtwt_eq - // syntax::ext::tt::macro_parser::token_name_eq - panic!("not allowed to compare these idents: {:?}, {:?}. \ - Probably related to issue \\#6993", self, other); - } +impl Encodable for Name { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_str(&self.as_str()) } } -/// A SyntaxContext represents a chain of macro-expandings -/// and renamings. Each macro expansion corresponds to -/// a fresh u32 +impl Decodable for Name { + fn decode(d: &mut D) -> Result { + Ok(token::intern(&try!(d.read_str())[..])) + } +} -// I'm representing this syntax context as an index into -// a table, in order to work around a compiler bug -// that's causing unreleased memory to cause core dumps -// and also perhaps to save some work in destructor checks. -// the special uint '0' will be used to indicate an empty -// syntax context. +pub const EMPTY_CTXT : SyntaxContext = SyntaxContext(0); -// this uint is a reference to a table stored in thread-local -// storage. -pub type SyntaxContext = u32; -pub const EMPTY_CTXT : SyntaxContext = 0; -pub const ILLEGAL_CTXT : SyntaxContext = 1; +impl Ident { + pub fn new(name: Name, ctxt: SyntaxContext) -> Ident { + Ident {name: name, ctxt: ctxt} + } + pub fn with_empty_ctxt(name: Name) -> Ident { + Ident {name: name, ctxt: EMPTY_CTXT} + } +} -/// A name is a part of an identifier, representing a string or gensym. It's -/// the result of interning. -#[derive(Eq, Ord, PartialEq, PartialOrd, Hash, - RustcEncodable, RustcDecodable, Clone, Copy)] -pub struct Name(pub u32); +impl PartialEq for Ident { + fn eq(&self, other: &Ident) -> bool { + if self.ctxt != other.ctxt { + // There's no one true way to compare Idents. They can be compared + // non-hygienically `id1.name == id2.name`, hygienically + // `mtwt::resolve(id1) == mtwt::resolve(id2)`, or even member-wise + // `(id1.name, id1.ctxt) == (id2.name, id2.ctxt)` depending on the situation. + // Ideally, PartialEq should not be implemented for Ident at all, but that + // would be too impractical, because many larger structures (Token, in particular) + // including Idents as their parts derive PartialEq and use it for non-hygienic + // comparisons. That's why PartialEq is implemented and defaults to non-hygienic + // comparison. Hash is implemented too and is consistent with PartialEq, i.e. only + // the name of Ident is hashed. Still try to avoid comparing idents in your code + // (especially as keys in hash maps), use one of the three methods listed above + // explicitly. + // + // If you see this panic, then some idents from different contexts were compared + // non-hygienically. It's likely a bug. Use one of the three comparison methods + // listed above explicitly. -impl> PartialEq for Name { - fn eq(&self, other: &T) -> bool { - self.as_str() == other.as_ref() + panic!("idents with different contexts are compared with operator `==`: \ + {:?}, {:?}.", self, other); + } + + self.name == other.name } } -impl Name { - pub fn as_str(&self) -> token::InternedString { - token::InternedString::new_from_name(*self) +impl Hash for Ident { + fn hash(&self, state: &mut H) { + self.name.hash(state) } +} - pub fn usize(&self) -> usize { - let Name(nm) = *self; - nm as usize +impl fmt::Debug for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}#{}", self.name, self.ctxt.0) } +} - pub fn ident(&self) -> Ident { - Ident { name: *self, ctxt: 0 } +impl fmt::Display for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.name, f) } } -/// A mark represents a unique id associated with a macro expansion -pub type Mrk = u32; - impl Encodable for Ident { fn encode(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_str(&self.name.as_str()) + self.name.encode(s) } } impl Decodable for Ident { fn decode(d: &mut D) -> Result { - Ok(str_to_ident(&try!(d.read_str())[..])) + Ok(Ident::with_empty_ctxt(try!(Name::decode(d)))) } } -/// Function name (not all functions have names) -pub type FnIdent = Option; +/// A mark represents a unique id associated with a macro expansion +pub type Mrk = u32; #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)] pub struct Lifetime { @@ -378,6 +374,11 @@ pub const CRATE_NODE_ID: NodeId = 0; /// small, positive ids. pub const DUMMY_NODE_ID: NodeId = !0; +pub trait NodeIdAssigner { + fn next_node_id(&self) -> NodeId; + fn peek_node_id(&self) -> NodeId; +} + /// The AST represents all type param bounds as types. /// typeck::collect::compute_bounds matches these against /// the "special" built-in traits (see middle::lang_items) and @@ -671,8 +672,6 @@ pub type BinOp = Spanned; #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] pub enum UnOp { - /// The `box` operator - UnUniq, /// The `*` operator for dereferencing UnDeref, /// The `!` operator for logical inversion @@ -687,7 +686,8 @@ pub type Stmt = Spanned; impl fmt::Debug for Stmt { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "stmt({}: {})", - ast_util::stmt_id(self), + ast_util::stmt_id(self) + .map_or(Cow::Borrowed(""),|id|Cow::Owned(id.to_string())), pprust::stmt_to_string(self)) } } @@ -764,8 +764,6 @@ pub type SpannedIdent = Spanned; pub enum BlockCheckMode { DefaultBlock, UnsafeBlock(UnsafeSource), - PushUnsafeBlock(UnsafeSource), - PopUnsafeBlock(UnsafeSource), } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] @@ -790,8 +788,10 @@ impl fmt::Debug for Expr { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum Expr_ { + /// A `box x` expression. + ExprBox(P), /// First expr is the place; second expr is the value. - ExprBox(Option>, P), + ExprInPlace(P, P), /// An array (`[a, b, c, d]`) ExprVec(Vec>), /// A function call @@ -832,19 +832,16 @@ pub enum Expr_ { /// /// This is desugared to a `match` expression. ExprIfLet(P, P, P, Option>), - // FIXME #6993: change to Option ... or not, if these are hygienic. /// A while loop, with an optional label /// /// `'label: while expr { block }` ExprWhile(P, P, Option), - // FIXME #6993: change to Option ... or not, if these are hygienic. /// A while-let loop, with an optional label /// /// `'label: while let pat = expr { block }` /// /// This is desugared to a combination of `loop` and `match` expressions. ExprWhileLet(P, P, P, Option), - // FIXME #6993: change to Option ... or not, if these are hygienic. /// A for loop, with an optional label /// /// `'label: for pat in expr { block }` @@ -854,11 +851,9 @@ pub enum Expr_ { /// Conditionless loop (can be exited with break, continue, or return) /// /// `'label: loop { block }` - // FIXME #6993: change to Option ... or not, if these are hygienic. ExprLoop(P, Option), - /// A `match` block, with a source that indicates whether or not it is - /// the result of a desugaring, and if so, which kind. - ExprMatch(P, Vec, MatchSource), + /// A `match` block. + ExprMatch(P, Vec), /// A closure (for example, `move |a, b, c| {a + b + c}`) ExprClosure(CaptureClause, P, P), /// A block (`{ ... }`) @@ -937,14 +932,6 @@ pub struct QSelf { pub position: usize } -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] -pub enum MatchSource { - Normal, - IfLetDesugar { contains_else_clause: bool }, - WhileLetDesugar, - ForLoopDesugar, -} - #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] pub enum CaptureClause { CaptureByValue, @@ -1038,8 +1025,8 @@ impl TokenTree { match *self { TtToken(_, token::DocComment(name)) => { match doc_comment_style(&name.as_str()) { - AttrOuter => 2, - AttrInner => 3 + AttrStyle::Outer => 2, + AttrStyle::Inner => 3 } } TtToken(_, token::SpecialVarNt(..)) => 2, @@ -1060,7 +1047,7 @@ impl TokenTree { TtToken(sp, token::Pound) } (&TtToken(sp, token::DocComment(name)), 1) - if doc_comment_style(&name.as_str()) == AttrInner => { + if doc_comment_style(&name.as_str()) == AttrStyle::Inner => { TtToken(sp, token::Not) } (&TtToken(sp, token::DocComment(name)), _) => { @@ -1132,12 +1119,13 @@ pub type Mac = Spanned; /// is being invoked, and the vector of token-trees contains the source /// of the macro invocation. /// -/// There's only one flavor, now, so this could presumably be simplified. +/// NB: the additional ident for a macro_rules-style macro is actually +/// stored in the enclosing item. Oog. #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub enum Mac_ { - // NB: the additional ident for a macro_rules-style macro is actually - // stored in the enclosing item. Oog. - MacInvocTT(Path, Vec, SyntaxContext), // new macro-invocation +pub struct Mac_ { + pub path: Path, + pub tts: Vec, + pub ctxt: SyntaxContext, } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] @@ -1213,13 +1201,6 @@ pub struct MutTy { pub mutbl: Mutability, } -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub struct TypeField { - pub ident: Ident, - pub mt: MutTy, - pub span: Span, -} - /// Represents a method's signature in a trait declaration, /// or in an implementation. #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] @@ -1440,8 +1421,8 @@ pub enum Ty_ { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] pub enum AsmDialect { - AsmAtt, - AsmIntel + Att, + Intel, } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] @@ -1587,20 +1568,6 @@ pub struct ForeignMod { pub items: Vec>, } -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub struct VariantArg { - pub ty: P, - pub id: NodeId, -} - -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub enum VariantKind { - /// Tuple variant, e.g. `Foo(A, B)` - TupleVariantKind(Vec), - /// Struct variant, e.g. `Foo {x: A, y: B}` - StructVariantKind(P), -} - #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct EnumDef { pub variants: Vec>, @@ -1610,11 +1577,9 @@ pub struct EnumDef { pub struct Variant_ { pub name: Ident, pub attrs: Vec, - pub kind: VariantKind, - pub id: NodeId, + pub data: VariantData, /// Explicit discriminant, eg `Foo = 1` pub disr_expr: Option>, - pub vis: Visibility, } pub type Variant = Spanned; @@ -1641,6 +1606,13 @@ impl PathListItem_ { } } + pub fn name(&self) -> Option { + match *self { + PathListIdent { name, .. } => Some(name), + PathListMod { .. } => None, + } + } + pub fn rename(&self) -> Option { match *self { PathListIdent { rename, .. } | PathListMod { rename, .. } => rename @@ -1677,8 +1649,8 @@ pub type Attribute = Spanned; /// distinguished for pretty-printing. #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] pub enum AttrStyle { - AttrOuter, - AttrInner, + Outer, + Inner, } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] @@ -1766,13 +1738,45 @@ impl StructFieldKind { } } +/// Fields and Ids of enum variants and structs +/// +/// For enum variants: `NodeId` represents both an Id of the variant itself (relevant for all +/// variant kinds) and an Id of the variant's constructor (not relevant for `Struct`-variants). +/// One shared Id can be successfully used for these two purposes. +/// Id of the whole enum lives in `Item`. +/// +/// For structs: `NodeId` represents an Id of the structure's constructor, so it is not actually +/// used for `Struct`-structs (but still presents). Structures don't have an analogue of "Id of +/// the variant itself" from enum variants. +/// Id of the whole struct lives in `Item`. #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub struct StructDef { - /// Fields, not including ctor - pub fields: Vec, - /// ID of the constructor. This is only used for tuple- or enum-like - /// structs. - pub ctor_id: Option, +pub enum VariantData { + Struct(Vec, NodeId), + Tuple(Vec, NodeId), + Unit(NodeId), +} + +impl VariantData { + pub fn fields(&self) -> &[StructField] { + match *self { + VariantData::Struct(ref fields, _) | VariantData::Tuple(ref fields, _) => fields, + _ => &[], + } + } + pub fn id(&self) -> NodeId { + match *self { + VariantData::Struct(_, id) | VariantData::Tuple(_, id) | VariantData::Unit(id) => id + } + } + pub fn is_struct(&self) -> bool { + if let VariantData::Struct(..) = *self { true } else { false } + } + pub fn is_tuple(&self) -> bool { + if let VariantData::Tuple(..) = *self { true } else { false } + } + pub fn is_unit(&self) -> bool { + if let VariantData::Unit(..) = *self { true } else { false } + } } /* @@ -1816,7 +1820,7 @@ pub enum Item_ { /// An enum definition, e.g. `enum Foo {C, D}` ItemEnum(EnumDef, Generics), /// A struct definition, e.g. `struct Foo {x: A}` - ItemStruct(P, Generics), + ItemStruct(VariantData, Generics), /// Represents a Trait Declaration ItemTrait(Unsafety, Generics, diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index d024ff117f..8c3360512d 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -28,12 +28,12 @@ pub fn path_name_i(idents: &[Ident]) -> String { idents.iter().map(|i| i.to_string()).collect::>().join("::") } -pub fn stmt_id(s: &Stmt) -> NodeId { +pub fn stmt_id(s: &Stmt) -> Option { match s.node { - StmtDecl(_, id) => id, - StmtExpr(_, id) => id, - StmtSemi(_, id) => id, - StmtMac(..) => panic!("attempted to analyze unexpanded stmt") + StmtDecl(_, id) => Some(id), + StmtExpr(_, id) => Some(id), + StmtSemi(_, id) => Some(id), + StmtMac(..) => None, } } @@ -101,10 +101,9 @@ pub fn is_by_value_unop(u: UnOp) -> bool { pub fn unop_to_string(op: UnOp) -> &'static str { match op { - UnUniq => "box() ", - UnDeref => "*", - UnNot => "!", - UnNeg => "-", + UnDeref => "*", + UnNot => "!", + UnNeg => "-", } } @@ -361,11 +360,6 @@ impl<'a, 'v, O: IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> { } } } - ItemEnum(ref enum_definition, _) => { - for variant in &enum_definition.variants { - self.operation.visit_id(variant.node.id) - } - } _ => {} } @@ -385,7 +379,8 @@ impl<'a, 'v, O: IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> { } fn visit_stmt(&mut self, statement: &Stmt) { - self.operation.visit_id(ast_util::stmt_id(statement)); + self.operation + .visit_id(ast_util::stmt_id(statement).expect("attempted to visit unexpanded stmt")); visit::walk_stmt(self, statement) } @@ -457,13 +452,13 @@ impl<'a, 'v, O: IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> { visit::walk_struct_field(self, struct_field) } - fn visit_struct_def(&mut self, - struct_def: &StructDef, + fn visit_variant_data(&mut self, + struct_def: &VariantData, _: ast::Ident, _: &ast::Generics, - id: NodeId) { - self.operation.visit_id(id); - struct_def.ctor_id.map(|ctor_id| self.operation.visit_id(ctor_id)); + _: NodeId, + _: Span) { + self.operation.visit_id(struct_def.id()); visit::walk_struct_def(self, struct_def); } @@ -477,12 +472,12 @@ impl<'a, 'v, O: IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> { visit::walk_impl_item(self, ii); } - fn visit_lifetime_ref(&mut self, lifetime: &Lifetime) { + fn visit_lifetime(&mut self, lifetime: &Lifetime) { self.operation.visit_id(lifetime.id); } fn visit_lifetime_def(&mut self, def: &LifetimeDef) { - self.visit_lifetime_ref(&def.lifetime); + self.visit_lifetime(&def.lifetime); } fn visit_trait_ref(&mut self, trait_ref: &TraitRef) { @@ -529,12 +524,6 @@ pub fn compute_id_range_for_fn_body(fk: FnKind, id_visitor.operation.result } -/// Returns true if the given struct def is tuple-like; i.e. that its fields -/// are unnamed. -pub fn struct_def_is_tuple_like(struct_def: &ast::StructDef) -> bool { - struct_def.ctor_id.is_some() -} - /// Returns true if the given pattern consists solely of an identifier /// and false otherwise. pub fn pat_is_ident(pat: P) -> bool { @@ -577,21 +566,21 @@ mod tests { use ast::*; use super::*; - fn ident_to_segment(id : &Ident) -> PathSegment { - PathSegment {identifier: id.clone(), + fn ident_to_segment(id: Ident) -> PathSegment { + PathSegment {identifier: id, parameters: PathParameters::none()} } #[test] fn idents_name_eq_test() { assert!(segments_name_eq( - &[Ident{name:Name(3),ctxt:4}, Ident{name:Name(78),ctxt:82}] - .iter().map(ident_to_segment).collect::>(), - &[Ident{name:Name(3),ctxt:104}, Ident{name:Name(78),ctxt:182}] - .iter().map(ident_to_segment).collect::>())); + &[Ident::new(Name(3),SyntaxContext(4)), Ident::new(Name(78),SyntaxContext(82))] + .iter().cloned().map(ident_to_segment).collect::>(), + &[Ident::new(Name(3),SyntaxContext(104)), Ident::new(Name(78),SyntaxContext(182))] + .iter().cloned().map(ident_to_segment).collect::>())); assert!(!segments_name_eq( - &[Ident{name:Name(3),ctxt:4}, Ident{name:Name(78),ctxt:82}] - .iter().map(ident_to_segment).collect::>(), - &[Ident{name:Name(3),ctxt:104}, Ident{name:Name(77),ctxt:182}] - .iter().map(ident_to_segment).collect::>())); + &[Ident::new(Name(3),SyntaxContext(4)), Ident::new(Name(78),SyntaxContext(82))] + .iter().cloned().map(ident_to_segment).collect::>(), + &[Ident::new(Name(3),SyntaxContext(104)), Ident::new(Name(77),SyntaxContext(182))] + .iter().cloned().map(ident_to_segment).collect::>())); } } diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 7540c2ff83..eeb832d48b 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -27,7 +27,6 @@ use ptr::P; use std::cell::{RefCell, Cell}; use std::collections::HashSet; -use std::fmt; thread_local! { static USED_ATTRS: RefCell> = RefCell::new(Vec::new()) @@ -156,7 +155,7 @@ impl AttributeMethods for Attribute { InternedString::new("doc"), token::intern_and_get_ident(&strip_doc_comment_decoration( &comment))); - if self.node.style == ast::AttrOuter { + if self.node.style == ast::AttrStyle::Outer { f(&mk_attr_outer(self.node.id, meta)) } else { f(&mk_attr_inner(self.node.id, meta)) @@ -203,7 +202,7 @@ pub fn mk_attr_id() -> AttrId { pub fn mk_attr_inner(id: AttrId, item: P) -> Attribute { dummy_spanned(Attribute_ { id: id, - style: ast::AttrInner, + style: ast::AttrStyle::Inner, value: item, is_sugared_doc: false, }) @@ -213,7 +212,7 @@ pub fn mk_attr_inner(id: AttrId, item: P) -> Attribute { pub fn mk_attr_outer(id: AttrId, item: P) -> Attribute { dummy_spanned(Attribute_ { id: id, - style: ast::AttrOuter, + style: ast::AttrStyle::Outer, value: item, is_sugared_doc: false, }) @@ -323,7 +322,6 @@ pub enum InlineAttr { /// Determine what `#[inline]` attribute is present in `attrs`, if any. pub fn find_inline_attr(diagnostic: Option<&SpanHandler>, attrs: &[Attribute]) -> InlineAttr { - // FIXME (#2809)---validate the usage of #[inline] and #[inline] attrs.iter().fold(InlineAttr::None, |ia,attr| { match attr.node.value.node { MetaWord(ref n) if *n == "inline" => { @@ -383,174 +381,223 @@ pub fn cfg_matches(diagnostic: &SpanHandler, cfgs: &[P], cfg: &ast::Me } } -/// Represents the #[deprecated] and friends attributes. +/// Represents the #[stable], #[unstable] and #[deprecated] attributes. #[derive(RustcEncodable, RustcDecodable, Clone, Debug, PartialEq, Eq, Hash)] pub struct Stability { pub level: StabilityLevel, pub feature: InternedString, - pub since: Option, - pub deprecated_since: Option, - // The reason for the current stability level. If deprecated, the - // reason for deprecation. - pub reason: Option, - // The relevant rust-lang issue - pub issue: Option + pub depr: Option, } /// The available stability levels. -#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Copy, Eq, Hash)] +#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)] pub enum StabilityLevel { - Unstable, - Stable, + // Reason for the current stability level and the relevant rust-lang issue + Unstable { reason: Option, issue: u32 }, + Stable { since: InternedString }, } -impl fmt::Display for StabilityLevel { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(self, f) - } +#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)] +pub struct Deprecation { + pub since: InternedString, + pub reason: InternedString, } -fn find_stability_generic<'a, - AM: AttrMetaMethods, - I: Iterator> - (diagnostic: &SpanHandler, attrs: I, item_sp: Span) - -> (Option, Vec<&'a AM>) { +impl StabilityLevel { + pub fn is_unstable(&self) -> bool { if let Unstable {..} = *self { true } else { false }} + pub fn is_stable(&self) -> bool { if let Stable {..} = *self { true } else { false }} +} +fn find_stability_generic<'a, I>(diagnostic: &SpanHandler, + attrs_iter: I, + item_sp: Span) + -> Option + where I: Iterator +{ let mut stab: Option = None; - let mut deprecated: Option<(Option, Option)> = None; - let mut used_attrs: Vec<&'a AM> = vec![]; + let mut depr: Option = None; - 'outer: for attr in attrs { + 'outer: for attr in attrs_iter { let tag = attr.name(); - let tag = &tag[..]; + let tag = &*tag; if tag != "deprecated" && tag != "unstable" && tag != "stable" { continue // not a stability level } - used_attrs.push(attr); - - let (feature, since, reason, issue) = match attr.meta_item_list() { - Some(metas) => { - let mut feature = None; - let mut since = None; - let mut reason = None; - let mut issue = None; - for meta in metas { - match &*meta.name() { - "feature" => { - match meta.value_str() { - Some(v) => feature = Some(v), - None => { - diagnostic.span_err(meta.span, "incorrect meta item"); - continue 'outer; - } + mark_used(attr); + + if let Some(metas) = attr.meta_item_list() { + let get = |meta: &MetaItem, item: &mut Option| { + if item.is_some() { + diagnostic.span_err(meta.span, &format!("multiple '{}' items", + meta.name())); + return false + } + if let Some(v) = meta.value_str() { + *item = Some(v); + true + } else { + diagnostic.span_err(meta.span, "incorrect meta item"); + false + } + }; + + match tag { + "deprecated" => { + if depr.is_some() { + diagnostic.span_err(item_sp, "multiple deprecated attributes"); + break + } + + let mut since = None; + let mut reason = None; + for meta in metas { + match &*meta.name() { + "since" => if !get(meta, &mut since) { continue 'outer }, + "reason" => if !get(meta, &mut reason) { continue 'outer }, + _ => { + diagnostic.span_err(meta.span, &format!("unknown meta item '{}'", + meta.name())); + continue 'outer } } - "since" => { - match meta.value_str() { - Some(v) => since = Some(v), - None => { - diagnostic.span_err(meta.span, "incorrect meta item"); - continue 'outer; - } - } + } + + match (since, reason) { + (Some(since), Some(reason)) => { + depr = Some(Deprecation { + since: since, + reason: reason, + }) } - "reason" => { - match meta.value_str() { - Some(v) => reason = Some(v), - None => { - diagnostic.span_err(meta.span, "incorrect meta item"); - continue 'outer; - } - } + (None, _) => { + diagnostic.span_err(attr.span(), "missing 'since'"); + continue } - "issue" => { - match meta.value_str().and_then(|s| s.parse().ok()) { - Some(v) => issue = Some(v), - None => { - diagnostic.span_err(meta.span, "incorrect meta item"); - continue 'outer; - } - } + _ => { + diagnostic.span_err(attr.span(), "missing 'reason'"); + continue } - _ => {} } } - (feature, since, reason, issue) - } - None => { - diagnostic.span_err(attr.span(), "incorrect stability attribute type"); - continue - } - }; + "unstable" => { + if stab.is_some() { + diagnostic.span_err(item_sp, "multiple stability levels"); + break + } - // Deprecated tags don't require feature names - if feature == None && tag != "deprecated" { - diagnostic.span_err(attr.span(), "missing 'feature'"); - } + let mut feature = None; + let mut reason = None; + let mut issue = None; + for meta in metas { + match &*meta.name() { + "feature" => if !get(meta, &mut feature) { continue 'outer }, + "reason" => if !get(meta, &mut reason) { continue 'outer }, + "issue" => if !get(meta, &mut issue) { continue 'outer }, + _ => { + diagnostic.span_err(meta.span, &format!("unknown meta item '{}'", + meta.name())); + continue 'outer + } + } + } - // Unstable tags don't require a version - if since == None && tag != "unstable" { - diagnostic.span_err(attr.span(), "missing 'since'"); - } + match (feature, reason, issue) { + (Some(feature), reason, Some(issue)) => { + stab = Some(Stability { + level: Unstable { + reason: reason, + issue: { + if let Ok(issue) = issue.parse() { + issue + } else { + diagnostic.span_err(attr.span(), "incorrect 'issue'"); + continue + } + } + }, + feature: feature, + depr: None, + }) + } + (None, _, _) => { + diagnostic.span_err(attr.span(), "missing 'feature'"); + continue + } + _ => { + diagnostic.span_err(attr.span(), "missing 'issue'"); + continue + } + } + } + "stable" => { + if stab.is_some() { + diagnostic.span_err(item_sp, "multiple stability levels"); + break + } - if tag == "unstable" || tag == "stable" { - if stab.is_some() { - diagnostic.span_err(item_sp, "multiple stability levels"); - } + let mut feature = None; + let mut since = None; + for meta in metas { + match &*meta.name() { + "feature" => if !get(meta, &mut feature) { continue 'outer }, + "since" => if !get(meta, &mut since) { continue 'outer }, + _ => { + diagnostic.span_err(meta.span, &format!("unknown meta item '{}'", + meta.name())); + continue 'outer + } + } + } - let level = match tag { - "unstable" => Unstable, - "stable" => Stable, + match (feature, since) { + (Some(feature), Some(since)) => { + stab = Some(Stability { + level: Stable { + since: since, + }, + feature: feature, + depr: None, + }) + } + (None, _) => { + diagnostic.span_err(attr.span(), "missing 'feature'"); + continue + } + _ => { + diagnostic.span_err(attr.span(), "missing 'since'"); + continue + } + } + } _ => unreachable!() - }; - - stab = Some(Stability { - level: level, - feature: feature.unwrap_or(intern_and_get_ident("bogus")), - since: since, - deprecated_since: None, - reason: reason, - issue: issue, - }); - } else { // "deprecated" - if deprecated.is_some() { - diagnostic.span_err(item_sp, "multiple deprecated attributes"); } - - deprecated = Some((since, reason)); + } else { + diagnostic.span_err(attr.span(), "incorrect stability attribute type"); + continue } } // Merge the deprecation info into the stability info - if deprecated.is_some() { - match stab { - Some(ref mut s) => { - let (since, reason) = deprecated.unwrap(); - s.deprecated_since = since; - s.reason = reason; - } - None => { - diagnostic.span_err(item_sp, "deprecated attribute must be paired with \ - either stable or unstable attribute"); + if let Some(depr) = depr { + if let Some(ref mut stab) = stab { + if let Unstable {reason: ref mut reason @ None, ..} = stab.level { + *reason = Some(depr.reason.clone()) } + stab.depr = Some(depr); + } else { + diagnostic.span_err(item_sp, "deprecated attribute must be paired with \ + either stable or unstable attribute"); } - } else if stab.as_ref().map_or(false, |s| s.level == Unstable && s.issue.is_none()) { - // non-deprecated unstable items need to point to issues. - diagnostic.span_err(item_sp, - "non-deprecated unstable items need to point \ - to an issue with `issue = \"NNN\"`"); } - (stab, used_attrs) + stab } /// Find the first stability attribute. `None` if none exists. pub fn find_stability(diagnostic: &SpanHandler, attrs: &[Attribute], item_sp: Span) -> Option { - let (s, used) = find_stability_generic(diagnostic, attrs.iter(), item_sp); - for used in used { mark_used(used) } - return s; + find_stability_generic(diagnostic, attrs.iter(), item_sp) } pub fn require_unique_names(diagnostic: &SpanHandler, metas: &[P]) { diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 56a15ce895..a73fd4534c 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -29,7 +29,6 @@ use std::io::{self, Read}; use serialize::{Encodable, Decodable, Encoder, Decoder}; -use parse::token::intern; use ast::Name; // _____________________________________________________________________________ @@ -142,6 +141,10 @@ impl Span { pub fn substitute_dummy(self, other: Span) -> Span { if self == DUMMY_SP { other } else { self } } + + pub fn contains(self, other: Span) -> bool { + self.lo <= other.lo && other.hi <= self.hi + } } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] @@ -265,28 +268,8 @@ pub enum ExpnFormat { MacroAttribute(Name), /// e.g. `format!()` MacroBang(Name), - /// Syntax sugar expansion performed by the compiler (libsyntax::expand). - CompilerExpansion(CompilerExpansionFormat), -} - -#[derive(Clone, Copy, Hash, Debug, PartialEq, Eq)] -pub enum CompilerExpansionFormat { - IfLet, - PlacementIn, - WhileLet, - ForLoop, } -impl CompilerExpansionFormat { - pub fn name(self) -> &'static str { - match self { - CompilerExpansionFormat::IfLet => "if let expansion", - CompilerExpansionFormat::PlacementIn => "placement-in expansion", - CompilerExpansionFormat::WhileLet => "while let expansion", - CompilerExpansionFormat::ForLoop => "for loop expansion", - } - } -} #[derive(Clone, Hash, Debug)] pub struct NameAndSpan { /// The format with which the macro was invoked. @@ -306,7 +289,6 @@ impl NameAndSpan { match self.format { ExpnFormat::MacroAttribute(s) => s, ExpnFormat::MacroBang(s) => s, - ExpnFormat::CompilerExpansion(ce) => intern(ce.name()), } } } @@ -1011,7 +993,7 @@ impl CodeMap { let span_comes_from_this_expansion = info.callee.span.map_or(span == info.call_site, |mac_span| { - mac_span.lo <= span.lo && span.hi <= mac_span.hi + mac_span.contains(span) }); debug!("span_allows_unstable: span: {:?} call_site: {:?} callee: {:?}", @@ -1083,7 +1065,6 @@ pub struct MalformedCodemapPositions { #[cfg(test)] mod tests { use super::*; - use std::rc::Rc; #[test] fn t1 () { diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index faf0b51c8d..aa674bdbcf 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -140,21 +140,14 @@ fn fold_item_underscore(cx: &mut Context, item: ast::Item_) -> ast::Item_ if !(cx.in_cfg)(&v.node.attrs) { None } else { - Some(v.map(|Spanned {node: ast::Variant_ {id, name, attrs, kind, - disr_expr, vis}, span}| { + Some(v.map(|Spanned {node: ast::Variant_ {name, attrs, data, + disr_expr}, span}| { Spanned { node: ast::Variant_ { - id: id, name: name, attrs: attrs, - kind: match kind { - ast::TupleVariantKind(..) => kind, - ast::StructVariantKind(def) => { - ast::StructVariantKind(fold_struct(cx, def)) - } - }, + data: fold_struct(cx, data), disr_expr: disr_expr, - vis: vis }, span: span } @@ -171,17 +164,22 @@ fn fold_item_underscore(cx: &mut Context, item: ast::Item_) -> ast::Item_ fold::noop_fold_item_underscore(item, cx) } -fn fold_struct(cx: &mut Context, def: P) -> P where +fn fold_struct(cx: &mut Context, vdata: ast::VariantData) -> ast::VariantData where F: FnMut(&[ast::Attribute]) -> bool { - def.map(|ast::StructDef { fields, ctor_id }| { - ast::StructDef { - fields: fields.into_iter().filter(|m| { + match vdata { + ast::VariantData::Struct(fields, id) => { + ast::VariantData::Struct(fields.into_iter().filter(|m| { (cx.in_cfg)(&m.node.attrs) - }).collect(), - ctor_id: ctor_id, + }).collect(), id) } - }) + ast::VariantData::Tuple(fields, id) => { + ast::VariantData::Tuple(fields.into_iter().filter(|m| { + (cx.in_cfg)(&m.node.attrs) + }).collect(), id) + } + ast::VariantData::Unit(id) => ast::VariantData::Unit(id) + } } fn retain_stmt(cx: &mut Context, stmt: &ast::Stmt) -> bool where @@ -226,10 +224,10 @@ fn fold_expr(cx: &mut Context, expr: P) -> P where fold::noop_fold_expr(ast::Expr { id: id, node: match node { - ast::ExprMatch(m, arms, source) => { + ast::ExprMatch(m, arms) => { ast::ExprMatch(m, arms.into_iter() .filter(|a| (cx.in_cfg)(&a.attrs)) - .collect(), source) + .collect()) } _ => node }, diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index c177eb1f00..2a8cdf138b 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -737,7 +737,6 @@ impl EmitterWriter { let (pre, post) = match ei.callee.format { codemap::MacroAttribute(..) => ("#[", "]"), codemap::MacroBang(..) => ("", "!"), - codemap::CompilerExpansion(..) => ("", ""), }; // Don't print recursive invocations if ei.call_site != last_span { @@ -842,7 +841,7 @@ pub fn expect(diag: &SpanHandler, opt: Option, msg: M) -> T where #[cfg(test)] mod test { use super::{EmitterWriter, Level}; - use codemap::{mk_sp, CodeMap, BytePos}; + use codemap::{mk_sp, CodeMap}; use std::sync::{Arc, Mutex}; use std::io::{self, Write}; use std::str::from_utf8; diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs index 6c3bee3f48..a276765e21 100644 --- a/src/libsyntax/diagnostics/plugin.rs +++ b/src/libsyntax/diagnostics/plugin.rs @@ -138,7 +138,7 @@ pub fn expand_register_diagnostic<'cx>(ecx: &'cx mut ExtCtxt, )); } }); - let sym = Ident::new(token::gensym(&format!( + let sym = Ident::with_empty_ctxt(token::gensym(&format!( "__register_diagnostic_{}", code ))); MacEager::items(SmallVector::many(vec![ diff --git a/src/libsyntax/entry.rs b/src/libsyntax/entry.rs index 2b4df3186d..ddc4443a77 100644 --- a/src/libsyntax/entry.rs +++ b/src/libsyntax/entry.rs @@ -28,7 +28,7 @@ pub fn entry_point_type(item: &Item, depth: usize) -> EntryPointType { EntryPointType::Start } else if attr::contains_name(&item.attrs, "main") { EntryPointType::MainAttr - } else if item.ident.name == "main" { + } else if item.ident.name.as_str() == "main" { if depth == 1 { // This is a top-level function so can be 'main' EntryPointType::MainNamed diff --git a/src/libsyntax/ext/asm.rs b/src/libsyntax/ext/asm.rs index f1aa8139ec..d2b416f541 100644 --- a/src/libsyntax/ext/asm.rs +++ b/src/libsyntax/ext/asm.rs @@ -22,6 +22,7 @@ use feature_gate; use parse::token::{intern, InternedString}; use parse::token; use ptr::P; +use syntax::ast::AsmDialect; enum State { Asm, @@ -65,7 +66,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) let mut clobs = Vec::new(); let mut volatile = false; let mut alignstack = false; - let mut dialect = ast::AsmAtt; + let mut dialect = AsmDialect::Att; let mut state = Asm; @@ -178,7 +179,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) } else if option == "alignstack" { alignstack = true; } else if option == "intel" { - dialect = ast::AsmIntel; + dialect = AsmDialect::Intel; } else { cx.span_warn(p.last_span, "unrecognized option"); } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 775d47a8c0..a248f839d7 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -13,7 +13,7 @@ pub use self::SyntaxExtension::*; use ast; use ast::Name; use codemap; -use codemap::{CodeMap, Span, ExpnId, ExpnInfo, NO_EXPANSION, CompilerExpansion}; +use codemap::{CodeMap, Span, ExpnId, ExpnInfo, NO_EXPANSION}; use ext; use ext::expand; use ext::tt::macro_rules; @@ -544,12 +544,6 @@ fn initial_syntax_expander_table<'feat>(ecfg: &expand::ExpansionConfig<'feat>) syntax_expanders.insert(intern("cfg"), builtin_normal_expander( ext::cfg::expand_cfg)); - syntax_expanders.insert(intern("push_unsafe"), - builtin_normal_expander( - ext::pushpop_safe::expand_push_unsafe)); - syntax_expanders.insert(intern("pop_unsafe"), - builtin_normal_expander( - ext::pushpop_safe::expand_pop_unsafe)); syntax_expanders.insert(intern("trace_macros"), builtin_normal_expander( ext::trace_macros::expand_trace_macros)); @@ -593,14 +587,14 @@ impl<'a> ExtCtxt<'a> { } } - #[unstable(feature = "rustc_private")] + #[unstable(feature = "rustc_private", issue = "0")] #[deprecated(since = "1.0.0", reason = "Replaced with `expander().fold_expr()`")] pub fn expand_expr(&mut self, e: P) -> P { self.expander().fold_expr(e) } - /// Returns a `Folder` for deeply expanding all macros in a AST node. + /// Returns a `Folder` for deeply expanding all macros in an AST node. pub fn expander<'b>(&'b mut self) -> expand::MacroExpander<'b, 'a> { expand::MacroExpander::new(self) } @@ -646,15 +640,12 @@ impl<'a> ExtCtxt<'a> { loop { if self.codemap().with_expn_info(expn_id, |info| { info.map_or(None, |i| { - if i.callee.name() == "include" { + if i.callee.name().as_str() == "include" { // Stop going up the backtrace once include! is encountered return None; } expn_id = i.call_site.expn_id; - match i.callee.format { - CompilerExpansion(..) => (), - _ => last_macro = Some(i.call_site), - } + last_macro = Some(i.call_site); return Some(()); }) }).is_none() { @@ -899,9 +890,9 @@ impl SyntaxEnv { unreachable!() } - pub fn find(&self, k: &Name) -> Option> { + pub fn find(&self, k: Name) -> Option> { for frame in self.chain.iter().rev() { - match frame.map.get(k) { + match frame.map.get(&k) { Some(v) => return Some(v.clone()), None => {} } diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 771ac85ef1..16a5eb05c4 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -73,7 +73,6 @@ pub trait AstBuilder { fn ty_vars(&self, ty_params: &OwnedSlice) -> Vec> ; fn ty_vars_global(&self, ty_params: &OwnedSlice) -> Vec> ; - fn ty_field_imm(&self, span: Span, name: Ident, ty: P) -> ast::TypeField; fn typaram(&self, span: Span, @@ -248,9 +247,9 @@ pub trait AstBuilder { fn item_struct_poly(&self, span: Span, name: Ident, - struct_def: ast::StructDef, + struct_def: ast::VariantData, generics: Generics) -> P; - fn item_struct(&self, span: Span, name: Ident, struct_def: ast::StructDef) -> P; + fn item_struct(&self, span: Span, name: Ident, struct_def: ast::VariantData) -> P; fn item_mod(&self, span: Span, inner_span: Span, name: Ident, attrs: Vec, @@ -443,14 +442,6 @@ impl<'a> AstBuilder for ExtCtxt<'a> { Vec::new())) } - fn ty_field_imm(&self, span: Span, name: Ident, ty: P) -> ast::TypeField { - ast::TypeField { - ident: name, - mt: ast::MutTy { ty: ty, mutbl: ast::MutImmutable }, - span: span, - } - } - fn ty_infer(&self, span: Span) -> P { self.ty(span, ast::TyInfer) } @@ -877,7 +868,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } fn expr_match(&self, span: Span, arg: P, arms: Vec) -> P { - self.expr(span, ast::ExprMatch(arg, arms, ast::MatchSource::Normal)) + self.expr(span, ast::ExprMatch(arg, arms)) } fn expr_if(&self, span: Span, cond: P, @@ -1002,18 +993,27 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } fn variant(&self, span: Span, name: Ident, tys: Vec> ) -> ast::Variant { - let args = tys.into_iter().map(|ty| { - ast::VariantArg { ty: ty, id: ast::DUMMY_NODE_ID } + let fields: Vec<_> = tys.into_iter().map(|ty| { + Spanned { span: ty.span, node: ast::StructField_ { + ty: ty, + kind: ast::UnnamedField(ast::Inherited), + attrs: Vec::new(), + id: ast::DUMMY_NODE_ID, + }} }).collect(); + let vdata = if fields.is_empty() { + ast::VariantData::Unit(ast::DUMMY_NODE_ID) + } else { + ast::VariantData::Tuple(fields, ast::DUMMY_NODE_ID) + }; + respan(span, ast::Variant_ { name: name, attrs: Vec::new(), - kind: ast::TupleVariantKind(args), - id: ast::DUMMY_NODE_ID, + data: vdata, disr_expr: None, - vis: ast::Public }) } @@ -1030,7 +1030,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } fn item_struct(&self, span: Span, name: Ident, - struct_def: ast::StructDef) -> P { + struct_def: ast::VariantData) -> P { self.item_struct_poly( span, name, @@ -1040,8 +1040,8 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } fn item_struct_poly(&self, span: Span, name: Ident, - struct_def: ast::StructDef, generics: Generics) -> P { - self.item(span, name, Vec::new(), ast::ItemStruct(P(struct_def), generics)) + struct_def: ast::VariantData, generics: Generics) -> P { + self.item(span, name, Vec::new(), ast::ItemStruct(struct_def, generics)) } fn item_mod(&self, span: Span, inner_span: Span, name: Ident, @@ -1089,7 +1089,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn attribute(&self, sp: Span, mi: P) -> ast::Attribute { respan(sp, ast::Attribute_ { id: attr::mk_attr_id(), - style: ast::AttrOuter, + style: ast::AttrStyle::Outer, value: mi, is_sugared_doc: false, }) diff --git a/src/libsyntax/ext/deriving/show.rs b/src/libsyntax/ext/deriving/debug.rs similarity index 99% rename from src/libsyntax/ext/deriving/show.rs rename to src/libsyntax/ext/deriving/debug.rs index 4d70ca1ebf..537375f708 100644 --- a/src/libsyntax/ext/deriving/show.rs +++ b/src/libsyntax/ext/deriving/debug.rs @@ -18,7 +18,7 @@ use ext::deriving::generic::ty::*; use parse::token; use ptr::P; -pub fn expand_deriving_show(cx: &mut ExtCtxt, +pub fn expand_deriving_debug(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Annotatable, diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index 9fc2745cf9..5c6e2fce8a 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -174,9 +174,9 @@ //! A static method on the types above would result in, //! //! ```{.text} -//! StaticStruct(, Named(vec![(, )])) +//! StaticStruct(, Named(vec![(, )])) //! -//! StaticStruct(, Unnamed(vec![])) +//! StaticStruct(, Unnamed(vec![])) //! //! StaticEnum(, //! vec![(, , Unnamed(vec![])), @@ -194,7 +194,7 @@ use std::vec; use abi::Abi; use abi; use ast; -use ast::{EnumDef, Expr, Ident, Generics, StructDef}; +use ast::{EnumDef, Expr, Ident, Generics, VariantData}; use ast_util; use attr; use attr::AttrMetaMethods; @@ -317,7 +317,7 @@ pub enum SubstructureFields<'a> { EnumNonMatchingCollapsed(Vec, &'a [P], &'a [Ident]), /// A static method where `Self` is a struct. - StaticStruct(&'a ast::StructDef, StaticFields), + StaticStruct(&'a ast::VariantData, StaticFields), /// A static method where `Self` is an enum. StaticEnum(&'a ast::EnumDef, Vec<(Ident, Span, StaticFields)>), } @@ -417,7 +417,7 @@ impl<'a> TraitDef<'a> { let mut attrs = newitem.attrs.clone(); attrs.extend(item.attrs.iter().filter(|a| { match &a.name()[..] { - "allow" | "warn" | "deny" | "forbid" => true, + "allow" | "warn" | "deny" | "forbid" | "stable" | "unstable" => true, _ => false, } }).cloned()); @@ -649,10 +649,10 @@ impl<'a> TraitDef<'a> { fn expand_struct_def(&self, cx: &mut ExtCtxt, - struct_def: &'a StructDef, + struct_def: &'a VariantData, type_ident: Ident, generics: &Generics) -> P { - let field_tys: Vec> = struct_def.fields.iter() + let field_tys: Vec> = struct_def.fields().iter() .map(|field| field.node.ty.clone()) .collect(); @@ -700,16 +700,8 @@ impl<'a> TraitDef<'a> { let mut field_tys = Vec::new(); for variant in &enum_def.variants { - match variant.node.kind { - ast::VariantKind::TupleVariantKind(ref args) => { - field_tys.extend(args.iter() - .map(|arg| arg.ty.clone())); - } - ast::VariantKind::StructVariantKind(ref args) => { - field_tys.extend(args.fields.iter() - .map(|field| field.node.ty.clone())); - } - } + field_tys.extend(variant.node.data.fields().iter() + .map(|field| field.node.ty.clone())); } let methods = self.methods.iter().map(|method_def| { @@ -935,7 +927,7 @@ impl<'a> MethodDef<'a> { fn expand_struct_method_body<'b>(&self, cx: &mut ExtCtxt, trait_: &TraitDef<'b>, - struct_def: &'b StructDef, + struct_def: &'b VariantData, type_ident: Ident, self_args: &[P], nonself_args: &[P]) @@ -1004,7 +996,7 @@ impl<'a> MethodDef<'a> { fn expand_static_struct_method_body(&self, cx: &mut ExtCtxt, trait_: &TraitDef, - struct_def: &StructDef, + struct_def: &VariantData, type_ident: Ident, self_args: &[P], nonself_args: &[P]) @@ -1413,14 +1405,7 @@ impl<'a> MethodDef<'a> { -> P { let summary = enum_def.variants.iter().map(|v| { let ident = v.node.name; - let summary = match v.node.kind { - ast::TupleVariantKind(ref args) => { - Unnamed(args.iter().map(|va| trait_.set_expn_info(cx, va.ty.span)).collect()) - } - ast::StructVariantKind(ref struct_def) => { - trait_.summarise_struct(cx, &**struct_def) - } - }; + let summary = trait_.summarise_struct(cx, &v.node.data); (ident, v.span, summary) }).collect(); self.call_substructure_method(cx, trait_, type_ident, @@ -1456,10 +1441,10 @@ impl<'a> TraitDef<'a> { fn summarise_struct(&self, cx: &mut ExtCtxt, - struct_def: &StructDef) -> StaticFields { + struct_def: &VariantData) -> StaticFields { let mut named_idents = Vec::new(); let mut just_spans = Vec::new(); - for field in struct_def.fields.iter(){ + for field in struct_def.fields(){ let sp = self.set_expn_info(cx, field.span); match field.node.kind { ast::NamedField(ident, _) => named_idents.push((ident, sp)), @@ -1492,13 +1477,13 @@ impl<'a> TraitDef<'a> { fn create_struct_pattern(&self, cx: &mut ExtCtxt, struct_path: ast::Path, - struct_def: &'a StructDef, + struct_def: &'a VariantData, prefix: &str, mutbl: ast::Mutability) -> (P, Vec<(Span, Option, P, &'a [ast::Attribute])>) { - if struct_def.fields.is_empty() { + if struct_def.fields().is_empty() { return (cx.pat_enum(self.span, struct_path, vec![]), vec![]); } @@ -1506,7 +1491,7 @@ impl<'a> TraitDef<'a> { let mut ident_expr = Vec::new(); let mut struct_type = Unknown; - for (i, struct_field) in struct_def.fields.iter().enumerate() { + for (i, struct_field) in struct_def.fields().iter().enumerate() { let sp = self.set_expn_info(cx, struct_field.span); let opt_id = match struct_field.node.kind { ast::NamedField(ident, _) if (struct_type == Unknown || @@ -1560,34 +1545,7 @@ impl<'a> TraitDef<'a> { -> (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]); - match variant.node.kind { - ast::TupleVariantKind(ref variant_args) => { - if variant_args.is_empty() { - return (cx.pat_enum(variant.span, variant_path, vec![]), vec![]); - } - - let mut paths = Vec::new(); - let mut ident_expr: Vec<(_, _, _, &'a [ast::Attribute])> = Vec::new(); - for (i, va) in variant_args.iter().enumerate() { - let sp = self.set_expn_info(cx, va.ty.span); - let ident = cx.ident_of(&format!("{}_{}", prefix, i)); - let path1 = codemap::Spanned{span: sp, node: ident}; - paths.push(path1); - let expr_path = cx.expr_path(cx.path_ident(sp, ident)); - let val = cx.expr(sp, ast::ExprParen(cx.expr_deref(sp, expr_path))); - ident_expr.push((sp, None, val, &[])); - } - - let subpats = self.create_subpatterns(cx, paths, mutbl); - - (cx.pat_enum(variant.span, variant_path, subpats), - ident_expr) - } - ast::StructVariantKind(ref struct_def) => { - self.create_struct_pattern(cx, variant_path, &**struct_def, - prefix, mutbl) - } - } + self.create_struct_pattern(cx, variant_path, &variant.node.data, prefix, mutbl) } } diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs index c7f582854a..d26bb794c8 100644 --- a/src/libsyntax/ext/deriving/mod.rs +++ b/src/libsyntax/ext/deriving/mod.rs @@ -60,7 +60,7 @@ pub mod clone; pub mod encodable; pub mod decodable; pub mod hash; -pub mod show; +pub mod debug; pub mod default; pub mod primitive; @@ -173,7 +173,7 @@ derive_traits! { "PartialOrd" => partial_ord::expand_deriving_partial_ord, "Ord" => ord::expand_deriving_ord, - "Debug" => show::expand_deriving_show, + "Debug" => debug::expand_deriving_debug, "Default" => default::expand_deriving_default, @@ -184,7 +184,6 @@ derive_traits! { "Copy" => bounds::expand_deriving_copy, // deprecated - "Show" => show::expand_deriving_show, "Encodable" => encodable::expand_deriving_encodable, "Decodable" => decodable::expand_deriving_decodable, } @@ -192,7 +191,6 @@ derive_traits! { #[inline] // because `name` is a compile-time constant fn warn_if_deprecated(ecx: &mut ExtCtxt, sp: Span, name: &str) { if let Some(replacement) = match name { - "Show" => Some("Debug"), "Encodable" => Some("RustcEncodable"), "Decodable" => Some("RustcDecodable"), _ => None, diff --git a/src/libsyntax/ext/deriving/primitive.rs b/src/libsyntax/ext/deriving/primitive.rs index 5d3cc50557..07b5877835 100644 --- a/src/libsyntax/ext/deriving/primitive.rs +++ b/src/libsyntax/ext/deriving/primitive.rs @@ -94,45 +94,35 @@ fn cs_from(name: &str, cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure let mut arms = Vec::new(); for variant in &enum_def.variants { - match variant.node.kind { - ast::TupleVariantKind(ref args) => { - if !args.is_empty() { - cx.span_err(trait_span, - "`FromPrimitive` cannot be derived for \ - enum variants with arguments"); - return cx.expr_fail(trait_span, - InternedString::new("")); - } - let span = variant.span; + let def = &variant.node.data; + if !def.is_unit() { + cx.span_err(trait_span, "`FromPrimitive` cannot be derived \ + for enums with non-unit variants"); + return cx.expr_fail(trait_span, + InternedString::new("")); + } - // expr for `$n == $variant as $name` - let path = cx.path(span, vec![substr.type_ident, variant.node.name]); - let variant = cx.expr_path(path); - let ty = cx.ty_ident(span, cx.ident_of(name)); - let cast = cx.expr_cast(span, variant.clone(), ty); - let guard = cx.expr_binary(span, ast::BiEq, n.clone(), cast); + let span = variant.span; - // expr for `Some($variant)` - let body = cx.expr_some(span, variant); + // expr for `$n == $variant as $name` + let path = cx.path(span, vec![substr.type_ident, variant.node.name]); + let variant = cx.expr_path(path); + let ty = cx.ty_ident(span, cx.ident_of(name)); + let cast = cx.expr_cast(span, variant.clone(), ty); + let guard = cx.expr_binary(span, ast::BiEq, n.clone(), cast); - // arm for `_ if $guard => $body` - let arm = ast::Arm { - attrs: vec!(), - pats: vec!(cx.pat_wild(span)), - guard: Some(guard), - body: body, - }; + // expr for `Some($variant)` + let body = cx.expr_some(span, variant); - arms.push(arm); - } - ast::StructVariantKind(_) => { - cx.span_err(trait_span, - "`FromPrimitive` cannot be derived for enums \ - with struct variants"); - return cx.expr_fail(trait_span, - InternedString::new("")); - } - } + // arm for `_ if $guard => $body` + let arm = ast::Arm { + attrs: vec!(), + pats: vec!(cx.pat_wild(span)), + guard: Some(guard), + body: body, + }; + + arms.push(arm); } // arm for `_ => None` diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 1991124ae2..b1b4605d5e 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -9,7 +9,7 @@ // except according to those terms. use ast::{Block, Crate, DeclLocal, ExprMac, PatMac}; -use ast::{Local, Ident, MacInvocTT}; +use ast::{Local, Ident, Mac_}; use ast::{ItemMac, MacStmtWithSemicolon, Mrk, Stmt, StmtDecl, StmtMac}; use ast::{StmtExpr, StmtSemi}; use ast::TokenTree; @@ -20,53 +20,20 @@ use attr; use attr::AttrMetaMethods; use codemap; use codemap::{Span, Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute}; -use codemap::{CompilerExpansion, CompilerExpansionFormat}; use ext::base::*; use feature_gate::{self, Features, GatedCfg}; use fold; use fold::*; use parse; use parse::token::{fresh_mark, fresh_name, intern}; -use parse::token; use ptr::P; use util::small_vector::SmallVector; use visit; use visit::Visitor; use std_inject; -// Given suffix ["b","c","d"], returns path `::std::b::c::d` when -// `fld.cx.use_std`, and `::core::b::c::d` otherwise. -fn mk_core_path(fld: &mut MacroExpander, - span: Span, - suffix: &[&'static str]) -> ast::Path { - let idents = fld.cx.std_path(suffix); - fld.cx.path_global(span, idents) -} pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { - fn push_compiler_expansion(fld: &mut MacroExpander, span: Span, - expansion_type: CompilerExpansionFormat) { - fld.cx.bt_push(ExpnInfo { - call_site: span, - callee: NameAndSpan { - format: CompilerExpansion(expansion_type), - - // This does *not* mean code generated after - // `push_compiler_expansion` is automatically exempt - // from stability lints; must also tag such code with - // an appropriate span from `fld.cx.backtrace()`. - allow_internal_unstable: true, - - span: None, - }, - }); - } - - // Sets the expn_id so that we can use unstable methods. - fn allow_unstable(fld: &mut MacroExpander, span: Span) -> Span { - Span { expn_id: fld.cx.backtrace(), ..span } - } - let expr_span = e.span; return e.and_then(|ast::Expr {id, node, span}| match node { @@ -94,265 +61,39 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { }) } - // Desugar ExprBox: `in (PLACE) EXPR` - ast::ExprBox(Some(placer), value_expr) => { - // to: - // - // let p = PLACE; - // let mut place = Placer::make_place(p); - // let raw_place = Place::pointer(&mut place); - // push_unsafe!({ - // std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR )); - // InPlace::finalize(place) - // }) - + ast::ExprInPlace(placer, value_expr) => { // Ensure feature-gate is enabled feature_gate::check_for_placement_in( fld.cx.ecfg.features, &fld.cx.parse_sess.span_diagnostic, expr_span); - push_compiler_expansion(fld, expr_span, CompilerExpansionFormat::PlacementIn); - - let value_span = value_expr.span; - let placer_span = placer.span; - - let placer_expr = fld.fold_expr(placer); + let placer = fld.fold_expr(placer); let value_expr = fld.fold_expr(value_expr); - - let placer_ident = token::gensym_ident("placer"); - let agent_ident = token::gensym_ident("place"); - let p_ptr_ident = token::gensym_ident("p_ptr"); - - let placer = fld.cx.expr_ident(span, placer_ident); - let agent = fld.cx.expr_ident(span, agent_ident); - let p_ptr = fld.cx.expr_ident(span, p_ptr_ident); - - let make_place = ["ops", "Placer", "make_place"]; - let place_pointer = ["ops", "Place", "pointer"]; - let move_val_init = ["intrinsics", "move_val_init"]; - let inplace_finalize = ["ops", "InPlace", "finalize"]; - - let make_call = |fld: &mut MacroExpander, p, args| { - // We feed in the `expr_span` because codemap's span_allows_unstable - // allows the call_site span to inherit the `allow_internal_unstable` - // setting. - let span_unstable = allow_unstable(fld, expr_span); - let path = mk_core_path(fld, span_unstable, p); - let path = fld.cx.expr_path(path); - let expr_span_unstable = allow_unstable(fld, span); - fld.cx.expr_call(expr_span_unstable, path, args) - }; - - let stmt_let = |fld: &mut MacroExpander, bind, expr| { - fld.cx.stmt_let(placer_span, false, bind, expr) - }; - let stmt_let_mut = |fld: &mut MacroExpander, bind, expr| { - fld.cx.stmt_let(placer_span, true, bind, expr) - }; - - // let placer = ; - let s1 = stmt_let(fld, placer_ident, placer_expr); - - // let mut place = Placer::make_place(placer); - let s2 = { - let call = make_call(fld, &make_place, vec![placer]); - stmt_let_mut(fld, agent_ident, call) - }; - - // let p_ptr = Place::pointer(&mut place); - let s3 = { - let args = vec![fld.cx.expr_mut_addr_of(placer_span, agent.clone())]; - let call = make_call(fld, &place_pointer, args); - stmt_let(fld, p_ptr_ident, call) - }; - - // pop_unsafe!(EXPR)); - let pop_unsafe_expr = pop_unsafe_expr(fld.cx, value_expr, value_span); - - // push_unsafe!({ - // ptr::write(p_ptr, pop_unsafe!()); - // InPlace::finalize(place) - // }) - let expr = { - let call_move_val_init = StmtSemi(make_call( - fld, &move_val_init, vec![p_ptr, pop_unsafe_expr]), ast::DUMMY_NODE_ID); - let call_move_val_init = codemap::respan(value_span, call_move_val_init); - - let call = make_call(fld, &inplace_finalize, vec![agent]); - Some(push_unsafe_expr(fld.cx, vec![P(call_move_val_init)], call, span)) - }; - - let block = fld.cx.block_all(span, vec![s1, s2, s3], expr); - let result = fld.cx.expr_block(block); - fld.cx.bt_pop(); - result + fld.cx.expr(span, ast::ExprInPlace(placer, value_expr)) } - // Issue #22181: - // Eventually a desugaring for `box EXPR` - // (similar to the desugaring above for `in PLACE BLOCK`) - // should go here, desugaring - // - // to: - // - // let mut place = BoxPlace::make_place(); - // let raw_place = Place::pointer(&mut place); - // let value = $value; - // unsafe { - // ::std::ptr::write(raw_place, value); - // Boxed::finalize(place) - // } - // - // But for now there are type-inference issues doing that. - ast::ExprWhile(cond, body, opt_ident) => { let cond = fld.fold_expr(cond); let (body, opt_ident) = expand_loop_block(body, opt_ident, fld); fld.cx.expr(span, ast::ExprWhile(cond, body, opt_ident)) } - // Desugar ExprWhileLet - // From: `[opt_ident]: while let = ` ast::ExprWhileLet(pat, expr, body, opt_ident) => { - // to: - // - // [opt_ident]: loop { - // match { - // => , - // _ => break - // } - // } - - push_compiler_expansion(fld, span, CompilerExpansionFormat::WhileLet); - - // ` => ` - let pat_arm = { - let body_expr = fld.cx.expr_block(body); - fld.cx.arm(pat.span, vec![pat], body_expr) - }; - - // `_ => break` - let break_arm = { - let pat_under = fld.cx.pat_wild(span); - let break_expr = fld.cx.expr_break(span); - fld.cx.arm(span, vec![pat_under], break_expr) - }; - - // `match { ... }` - let arms = vec![pat_arm, break_arm]; - let match_expr = fld.cx.expr(span, - ast::ExprMatch(expr, arms, ast::MatchSource::WhileLetDesugar)); - - // `[opt_ident]: loop { ... }` - let loop_block = fld.cx.block_expr(match_expr); - let (loop_block, opt_ident) = expand_loop_block(loop_block, opt_ident, fld); - let result = fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident)); - fld.cx.bt_pop(); - result - } - - // Desugar ExprIfLet - // From: `if let = []` - ast::ExprIfLet(pat, expr, body, mut elseopt) => { - // to: - // - // match { - // => , - // [_ if => ,] - // _ => [ | ()] - // } - - push_compiler_expansion(fld, span, CompilerExpansionFormat::IfLet); - - // ` => ` - let pat_arm = { - let body_expr = fld.cx.expr_block(body); - fld.cx.arm(pat.span, vec![pat], body_expr) - }; - - // `[_ if => ,]` - let else_if_arms = { - let mut arms = vec![]; - loop { - let elseopt_continue = elseopt - .and_then(|els| els.and_then(|els| match els.node { - // else if - ast::ExprIf(cond, then, elseopt) => { - let pat_under = fld.cx.pat_wild(span); - arms.push(ast::Arm { - attrs: vec![], - pats: vec![pat_under], - guard: Some(cond), - body: fld.cx.expr_block(then) - }); - elseopt.map(|elseopt| (elseopt, true)) - } - _ => Some((P(els), false)) - })); - match elseopt_continue { - Some((e, true)) => { - elseopt = Some(e); - } - Some((e, false)) => { - elseopt = Some(e); - break; - } - None => { - elseopt = None; - break; - } - } - } - arms - }; - - let contains_else_clause = elseopt.is_some(); - - // `_ => [ | ()]` - let else_arm = { - let pat_under = fld.cx.pat_wild(span); - let else_expr = elseopt.unwrap_or_else(|| fld.cx.expr_tuple(span, vec![])); - fld.cx.arm(span, vec![pat_under], else_expr) - }; - - let mut arms = Vec::with_capacity(else_if_arms.len() + 2); - arms.push(pat_arm); - arms.extend(else_if_arms); - arms.push(else_arm); - - let match_expr = fld.cx.expr(span, - ast::ExprMatch(expr, arms, - ast::MatchSource::IfLetDesugar { - contains_else_clause: contains_else_clause, - })); - let result = fld.fold_expr(match_expr); - fld.cx.bt_pop(); - result - } + let pat = fld.fold_pat(pat); + let expr = fld.fold_expr(expr); + + // Hygienic renaming of the body. + let ((body, opt_ident), mut rewritten_pats) = + rename_in_scope(vec![pat], + fld, + (body, opt_ident), + |rename_fld, fld, (body, opt_ident)| { + expand_loop_block(rename_fld.fold_block(body), opt_ident, fld) + }); + assert!(rewritten_pats.len() == 1); - // Desugar support for ExprIfLet in the ExprIf else position - ast::ExprIf(cond, blk, elseopt) => { - let elseopt = elseopt.map(|els| els.and_then(|els| match els.node { - ast::ExprIfLet(..) => { - push_compiler_expansion(fld, span, CompilerExpansionFormat::IfLet); - // wrap the if-let expr in a block - let span = els.span; - let blk = P(ast::Block { - stmts: vec![], - expr: Some(P(els)), - id: ast::DUMMY_NODE_ID, - rules: ast::DefaultBlock, - span: span - }); - let result = fld.cx.expr_block(blk); - fld.cx.bt_pop(); - result - } - _ => P(els) - })); - let if_expr = fld.cx.expr(span, ast::ExprIf(cond, blk, elseopt)); - if_expr.map(|e| noop_fold_expr(e, fld)) + fld.cx.expr(span, ast::ExprWhileLet(rewritten_pats.remove(0), expr, body, opt_ident)) } ast::ExprLoop(loop_block, opt_ident) => { @@ -360,102 +101,39 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident)) } - // Desugar ExprForLoop - // From: `[opt_ident]: for in ` ast::ExprForLoop(pat, head, body, opt_ident) => { - // to: - // - // { - // let result = match ::std::iter::IntoIterator::into_iter() { - // mut iter => { - // [opt_ident]: loop { - // match ::std::iter::Iterator::next(&mut iter) { - // ::std::option::Option::Some() => , - // ::std::option::Option::None => break - // } - // } - // } - // }; - // result - // } - - push_compiler_expansion(fld, span, CompilerExpansionFormat::ForLoop); - - let span = fld.new_span(span); + let pat = fld.fold_pat(pat); + + // Hygienic renaming of the for loop body (for loop binds its pattern). + let ((body, opt_ident), mut rewritten_pats) = + rename_in_scope(vec![pat], + fld, + (body, opt_ident), + |rename_fld, fld, (body, opt_ident)| { + expand_loop_block(rename_fld.fold_block(body), opt_ident, fld) + }); + assert!(rewritten_pats.len() == 1); - // expand let head = fld.fold_expr(head); + fld.cx.expr(span, ast::ExprForLoop(rewritten_pats.remove(0), head, body, opt_ident)) + } - let iter = token::gensym_ident("iter"); - - let pat_span = fld.new_span(pat.span); - // `::std::option::Option::Some() => ` - let pat_arm = { - let body_expr = fld.cx.expr_block(body); - let pat = fld.fold_pat(pat); - let some_pat = fld.cx.pat_some(pat_span, pat); - - fld.cx.arm(pat_span, vec![some_pat], body_expr) - }; - - // `::std::option::Option::None => break` - let break_arm = { - let break_expr = fld.cx.expr_break(span); - - fld.cx.arm(span, vec![fld.cx.pat_none(span)], break_expr) - }; - - // `match ::std::iter::Iterator::next(&mut iter) { ... }` - let match_expr = { - let next_path = { - let strs = fld.cx.std_path(&["iter", "Iterator", "next"]); - - fld.cx.path_global(span, strs) - }; - let ref_mut_iter = fld.cx.expr_mut_addr_of(span, fld.cx.expr_ident(span, iter)); - let next_expr = - fld.cx.expr_call(span, fld.cx.expr_path(next_path), vec![ref_mut_iter]); - let arms = vec![pat_arm, break_arm]; - - fld.cx.expr(pat_span, - ast::ExprMatch(next_expr, arms, ast::MatchSource::ForLoopDesugar)) - }; - - // `[opt_ident]: loop { ... }` - let loop_block = fld.cx.block_expr(match_expr); - let (loop_block, opt_ident) = expand_loop_block(loop_block, opt_ident, fld); - let loop_expr = fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident)); - - // `mut iter => { ... }` - let iter_arm = { - let iter_pat = - fld.cx.pat_ident_binding_mode(span, iter, ast::BindByValue(ast::MutMutable)); - fld.cx.arm(span, vec![iter_pat], loop_expr) - }; - - // `match ::std::iter::IntoIterator::into_iter() { ... }` - let into_iter_expr = { - let into_iter_path = { - let strs = fld.cx.std_path(&["iter", "IntoIterator", - "into_iter"]); - - fld.cx.path_global(span, strs) - }; + ast::ExprIfLet(pat, sub_expr, body, else_opt) => { + let pat = fld.fold_pat(pat); - fld.cx.expr_call(span, fld.cx.expr_path(into_iter_path), vec![head]) - }; - - let match_expr = fld.cx.expr_match(span, into_iter_expr, vec![iter_arm]); + // Hygienic renaming of the body. + let (body, mut rewritten_pats) = + rename_in_scope(vec![pat], + fld, + body, + |rename_fld, fld, body| { + fld.fold_block(rename_fld.fold_block(body)) + }); + assert!(rewritten_pats.len() == 1); - // `{ let result = ...; result }` - let result_ident = token::gensym_ident("result"); - let result = fld.cx.expr_block( - fld.cx.block_all( - span, - vec![fld.cx.stmt_let(span, false, result_ident, match_expr)], - Some(fld.cx.expr_ident(span, result_ident)))); - fld.cx.bt_pop(); - result + let else_opt = else_opt.map(|else_opt| fld.fold_expr(else_opt)); + let sub_expr = fld.fold_expr(sub_expr); + fld.cx.expr(span, ast::ExprIfLet(rewritten_pats.remove(0), sub_expr, body, else_opt)) } ast::ExprClosure(capture_clause, fn_decl, block) => { @@ -475,25 +153,6 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { }, fld)) } }); - - fn push_unsafe_expr(cx: &mut ExtCtxt, stmts: Vec>, - expr: P, span: Span) - -> P { - let rules = ast::PushUnsafeBlock(ast::CompilerGenerated); - cx.expr_block(P(ast::Block { - rules: rules, span: span, id: ast::DUMMY_NODE_ID, - stmts: stmts, expr: Some(expr), - })) - } - - fn pop_unsafe_expr(cx: &mut ExtCtxt, expr: P, span: Span) - -> P { - let rules = ast::PopUnsafeBlock(ast::CompilerGenerated); - cx.expr_block(P(ast::Block { - rules: rules, span: span, id: ast::DUMMY_NODE_ID, - stmts: vec![], expr: Some(expr), - })) - } } /// Expand a (not-ident-style) macro invocation. Returns the result @@ -509,78 +168,75 @@ fn expand_mac_invoc(mac: ast::Mac, F: for<'a> FnOnce(Box) -> Option, G: FnOnce(T, Mrk) -> T, { - match mac.node { - // it would almost certainly be cleaner to pass the whole - // macro invocation in, rather than pulling it apart and - // marking the tts and the ctxt separately. This also goes - // for the other three macro invocation chunks of code - // in this file. - // Token-tree macros: - MacInvocTT(pth, tts, _) => { - if pth.segments.len() > 1 { - fld.cx.span_err(pth.span, - "expected macro name without module \ - separators"); - // let compilation continue - return None; - } - let extname = pth.segments[0].identifier.name; - match fld.cx.syntax_env.find(&extname) { - None => { - fld.cx.span_err( - pth.span, - &format!("macro undefined: '{}!'", - &extname)); + // it would almost certainly be cleaner to pass the whole + // macro invocation in, rather than pulling it apart and + // marking the tts and the ctxt separately. This also goes + // for the other three macro invocation chunks of code + // in this file. + + let Mac_ { path: pth, tts, .. } = mac.node; + if pth.segments.len() > 1 { + fld.cx.span_err(pth.span, + "expected macro name without module \ + separators"); + // let compilation continue + return None; + } + let extname = pth.segments[0].identifier.name; + match fld.cx.syntax_env.find(extname) { + None => { + fld.cx.span_err( + pth.span, + &format!("macro undefined: '{}!'", + &extname)); - // let compilation continue - None - } - Some(rc) => match *rc { - NormalTT(ref expandfun, exp_span, allow_internal_unstable) => { - fld.cx.bt_push(ExpnInfo { - call_site: span, - callee: NameAndSpan { - format: MacroBang(extname), - span: exp_span, - allow_internal_unstable: allow_internal_unstable, - }, - }); - let fm = fresh_mark(); - let marked_before = mark_tts(&tts[..], fm); - - // The span that we pass to the expanders we want to - // be the root of the call stack. That's the most - // relevant span and it's the actual invocation of - // the macro. - let mac_span = fld.cx.original_span(); - - let opt_parsed = { - let expanded = expandfun.expand(fld.cx, - mac_span, - &marked_before[..]); - parse_thunk(expanded) - }; - let parsed = match opt_parsed { - Some(e) => e, - None => { - fld.cx.span_err( - pth.span, - &format!("non-expression macro in expression position: {}", - extname - )); - return None; - } - }; - Some(mark_thunk(parsed,fm)) - } - _ => { + // let compilation continue + None + } + Some(rc) => match *rc { + NormalTT(ref expandfun, exp_span, allow_internal_unstable) => { + fld.cx.bt_push(ExpnInfo { + call_site: span, + callee: NameAndSpan { + format: MacroBang(extname), + span: exp_span, + allow_internal_unstable: allow_internal_unstable, + }, + }); + let fm = fresh_mark(); + let marked_before = mark_tts(&tts[..], fm); + + // The span that we pass to the expanders we want to + // be the root of the call stack. That's the most + // relevant span and it's the actual invocation of + // the macro. + let mac_span = fld.cx.original_span(); + + let opt_parsed = { + let expanded = expandfun.expand(fld.cx, + mac_span, + &marked_before[..]); + parse_thunk(expanded) + }; + let parsed = match opt_parsed { + Some(e) => e, + None => { fld.cx.span_err( pth.span, - &format!("'{}' is not a tt-style macro", - extname)); - None + &format!("non-expression macro in expression position: {}", + extname + )); + return None; } - } + }; + Some(mark_thunk(parsed,fm)) + } + _ => { + fld.cx.span_err( + pth.span, + &format!("'{}' is not a tt-style macro", + extname)); + None } } } @@ -596,7 +252,7 @@ fn expand_loop_block(loop_block: P, fld: &mut MacroExpander) -> (P, Option) { match opt_ident { Some(label) => { - let new_label = fresh_name(&label); + let new_label = fresh_name(label); let rename = (label, new_label); // The rename *must not* be added to the pending list of current @@ -663,7 +319,7 @@ fn contains_macro_use(fld: &mut MacroExpander, attrs: &[ast::Attribute]) -> bool if attr.check_name("macro_escape") { fld.cx.span_warn(attr.span, "macro_escape is a deprecated synonym for macro_use"); is_use = true; - if let ast::AttrInner = attr.node.style { + if let ast::AttrStyle::Inner = attr.node.style { fld.cx.fileline_help(attr.span, "consider an outer attribute, \ #[macro_use] mod ..."); } @@ -684,19 +340,15 @@ fn contains_macro_use(fld: &mut MacroExpander, attrs: &[ast::Attribute]) -> bool // logic as for expression-position macro invocations. pub fn expand_item_mac(it: P, fld: &mut MacroExpander) -> SmallVector> { - let (extname, path_span, tts) = match it.node { - ItemMac(codemap::Spanned { - node: MacInvocTT(ref pth, ref tts, _), - .. - }) => { - (pth.segments[0].identifier.name, pth.span, (*tts).clone()) - } + let (extname, path_span, tts, span, attrs, ident) = it.and_then(|it| match it.node { + ItemMac(codemap::Spanned { node: Mac_ { path, tts, .. }, .. }) => + (path.segments[0].identifier.name, path.span, tts, it.span, it.attrs, it.ident), _ => fld.cx.span_bug(it.span, "invalid item macro invocation") - }; + }); let fm = fresh_mark(); let items = { - let expanded = match fld.cx.syntax_env.find(&extname) { + let expanded = match fld.cx.syntax_env.find(extname) { None => { fld.cx.span_err(path_span, &format!("macro undefined: '{}!'", @@ -706,48 +358,48 @@ pub fn expand_item_mac(it: P, } Some(rc) => match *rc { - NormalTT(ref expander, span, allow_internal_unstable) => { - if it.ident.name != parse::token::special_idents::invalid.name { + NormalTT(ref expander, tt_span, allow_internal_unstable) => { + if ident.name != parse::token::special_idents::invalid.name { fld.cx .span_err(path_span, &format!("macro {}! expects no ident argument, given '{}'", extname, - it.ident)); + ident)); return SmallVector::zero(); } fld.cx.bt_push(ExpnInfo { - call_site: it.span, + call_site: span, callee: NameAndSpan { format: MacroBang(extname), - span: span, + span: tt_span, allow_internal_unstable: allow_internal_unstable, } }); // mark before expansion: let marked_before = mark_tts(&tts[..], fm); - expander.expand(fld.cx, it.span, &marked_before[..]) + expander.expand(fld.cx, span, &marked_before[..]) } - IdentTT(ref expander, span, allow_internal_unstable) => { - if it.ident.name == parse::token::special_idents::invalid.name { + IdentTT(ref expander, tt_span, allow_internal_unstable) => { + if ident.name == parse::token::special_idents::invalid.name { fld.cx.span_err(path_span, &format!("macro {}! expects an ident argument", extname)); return SmallVector::zero(); } fld.cx.bt_push(ExpnInfo { - call_site: it.span, + call_site: span, callee: NameAndSpan { format: MacroBang(extname), - span: span, + span: tt_span, allow_internal_unstable: allow_internal_unstable, } }); // mark before expansion: let marked_tts = mark_tts(&tts[..], fm); - expander.expand(fld.cx, it.span, it.ident, marked_tts) + expander.expand(fld.cx, span, ident, marked_tts) } MacroRulesTT => { - if it.ident.name == parse::token::special_idents::invalid.name { + if ident.name == parse::token::special_idents::invalid.name { fld.cx.span_err(path_span, &format!("macro_rules! expects an ident argument") ); @@ -755,7 +407,7 @@ pub fn expand_item_mac(it: P, } fld.cx.bt_push(ExpnInfo { - call_site: it.span, + call_site: span, callee: NameAndSpan { format: MacroBang(extname), span: None, @@ -767,7 +419,7 @@ pub fn expand_item_mac(it: P, }); // DON'T mark before expansion. - let allow_internal_unstable = attr::contains_name(&it.attrs, + let allow_internal_unstable = attr::contains_name(&attrs, "allow_internal_unstable"); // ensure any #[allow_internal_unstable]s are @@ -777,18 +429,19 @@ pub fn expand_item_mac(it: P, feature_gate::emit_feature_err( &fld.cx.parse_sess.span_diagnostic, "allow_internal_unstable", - it.span, + span, feature_gate::GateIssue::Language, feature_gate::EXPLAIN_ALLOW_INTERNAL_UNSTABLE) } + let export = attr::contains_name(&attrs, "macro_export"); let def = ast::MacroDef { - ident: it.ident, - attrs: it.attrs.clone(), + ident: ident, + attrs: attrs, id: ast::DUMMY_NODE_ID, - span: it.span, + span: span, imported_from: None, - export: attr::contains_name(&it.attrs, "macro_export"), + export: export, use_locally: true, allow_internal_unstable: allow_internal_unstable, body: tts, @@ -800,7 +453,7 @@ pub fn expand_item_mac(it: P, return SmallVector::zero(); } _ => { - fld.cx.span_err(it.span, + fld.cx.span_err(span, &format!("{}! is not legal in item position", extname)); return SmallVector::zero(); @@ -898,7 +551,7 @@ fn expand_non_macro_stmt(Spanned {node, span: stmt_span}: Stmt, fld: &mut MacroE // generate fresh names, push them to a new pending list let idents = pattern_bindings(&*expanded_pat); let mut new_pending_renames = - idents.iter().map(|ident| (*ident, fresh_name(ident))).collect(); + idents.iter().map(|ident| (*ident, fresh_name(*ident))).collect(); // rewrite the pattern using the new names (the old // ones have already been applied): let rewritten_pat = { @@ -954,18 +607,18 @@ fn expand_arm(arm: ast::Arm, fld: &mut MacroExpander) -> ast::Arm { if expanded_pats.is_empty() { panic!("encountered match arm with 0 patterns"); } - // all of the pats must have the same set of bindings, so use the - // first one to extract them and generate new names: - let idents = pattern_bindings(&*expanded_pats[0]); - let new_renames = idents.into_iter().map(|id| (id, fresh_name(&id))).collect(); - // apply the renaming, but only to the PatIdents: - let mut rename_pats_fld = PatIdentRenamer{renames:&new_renames}; - let rewritten_pats = expanded_pats.move_map(|pat| rename_pats_fld.fold_pat(pat)); + // apply renaming and then expansion to the guard and the body: - let mut rename_fld = IdentRenamer{renames:&new_renames}; - let rewritten_guard = - arm.guard.map(|g| fld.fold_expr(rename_fld.fold_expr(g))); - let rewritten_body = fld.fold_expr(rename_fld.fold_expr(arm.body)); + let ((rewritten_guard, rewritten_body), rewritten_pats) = + rename_in_scope(expanded_pats, + fld, + (arm.guard, arm.body), + |rename_fld, fld, (ag, ab)|{ + let rewritten_guard = ag.map(|g| fld.fold_expr(rename_fld.fold_expr(g))); + let rewritten_body = fld.fold_expr(rename_fld.fold_expr(ab)); + (rewritten_guard, rewritten_body) + }); + ast::Arm { attrs: fold::fold_attrs(arm.attrs, fld), pats: rewritten_pats, @@ -974,6 +627,25 @@ fn expand_arm(arm: ast::Arm, fld: &mut MacroExpander) -> ast::Arm { } } +fn rename_in_scope(pats: Vec>, + fld: &mut MacroExpander, + x: X, + f: F) + -> (X, Vec>) + where F: Fn(&mut IdentRenamer, &mut MacroExpander, X) -> X +{ + // all of the pats must have the same set of bindings, so use the + // first one to extract them and generate new names: + let idents = pattern_bindings(&*pats[0]); + let new_renames = idents.into_iter().map(|id| (id, fresh_name(id))).collect(); + // apply the renaming, but only to the PatIdents: + let mut rename_pats_fld = PatIdentRenamer{renames:&new_renames}; + let rewritten_pats = pats.move_map(|pat| rename_pats_fld.fold_pat(pat)); + + let mut rename_fld = IdentRenamer{ renames:&new_renames }; + (f(&mut rename_fld, fld, x), rewritten_pats) +} + /// A visitor that extracts the PatIdent (binding) paths /// from a given thingy and puts them in a mutable /// array @@ -1059,11 +731,7 @@ fn expand_pat(p: P, fld: &mut MacroExpander) -> P { } p.map(|ast::Pat {node, span, ..}| { let (pth, tts) = match node { - PatMac(mac) => match mac.node { - MacInvocTT(pth, tts, _) => { - (pth, tts) - } - }, + PatMac(mac) => (mac.node.path, mac.node.tts), _ => unreachable!() }; if pth.segments.len() > 1 { @@ -1071,7 +739,7 @@ fn expand_pat(p: P, fld: &mut MacroExpander) -> P { return DummyResult::raw_pat(span); } let extname = pth.segments[0].identifier.name; - let marked_after = match fld.cx.syntax_env.find(&extname) { + let marked_after = match fld.cx.syntax_env.find(extname) { None => { fld.cx.span_err(pth.span, &format!("macro undefined: '{}!'", @@ -1144,10 +812,7 @@ pub struct IdentRenamer<'a> { impl<'a> Folder for IdentRenamer<'a> { fn fold_ident(&mut self, id: Ident) -> Ident { - Ident { - name: id.name, - ctxt: mtwt::apply_renames(self.renames, id.ctxt), - } + Ident::new(id.name, mtwt::apply_renames(self.renames, id.ctxt)) } fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { fold::noop_fold_mac(mac, self) @@ -1171,8 +836,8 @@ impl<'a> Folder for PatIdentRenamer<'a> { pat.map(|ast::Pat {id, node, span}| match node { ast::PatIdent(binding_mode, Spanned{span: sp, node: ident}, sub) => { - let new_ident = Ident{name: ident.name, - ctxt: mtwt::apply_renames(self.renames, ident.ctxt)}; + let new_ident = Ident::new(ident.name, + mtwt::apply_renames(self.renames, ident.ctxt)); let new_node = ast::PatIdent(binding_mode, Spanned{span: self.new_span(sp), node: new_ident}, @@ -1264,7 +929,7 @@ macro_rules! partition { fld: &MacroExpander) -> (Vec, Vec) { attrs.iter().cloned().partition(|attr| { - match fld.cx.syntax_env.find(&intern(&attr.name())) { + match fld.cx.syntax_env.find(intern(&attr.name())) { Some(rc) => match *rc { $variant(..) => true, _ => false @@ -1286,7 +951,7 @@ fn expand_decorators(a: Annotatable, { for attr in a.attrs() { let mname = intern(&attr.name()); - match fld.cx.syntax_env.find(&mname) { + match fld.cx.syntax_env.find(mname) { Some(rc) => match *rc { MultiDecorator(ref dec) => { attr::mark_used(&attr); @@ -1337,7 +1002,7 @@ fn expand_item_multi_modifier(mut it: Annotatable, for attr in &modifiers { let mname = intern(&attr.name()); - match fld.cx.syntax_env.find(&mname) { + match fld.cx.syntax_env.find(mname) { Some(rc) => match *rc { MultiModifier(ref mac) => { attr::mark_used(attr); @@ -1417,7 +1082,7 @@ fn expand_and_rename_fn_decl_and_block(fn_decl: P, block: P Ident { - ast::Ident { - name: id.name, - ctxt: mtwt::apply_mark(self.mark, id.ctxt) - } + ast::Ident::new(id.name, mtwt::apply_mark(self.mark, id.ctxt)) } fn fold_mac(&mut self, Spanned {node, span}: ast::Mac) -> ast::Mac { Spanned { - node: match node { - MacInvocTT(path, tts, ctxt) => { - MacInvocTT(self.fold_path(path), - self.fold_tts(&tts[..]), - mtwt::apply_mark(self.mark, ctxt)) - } + node: Mac_ { + path: self.fold_path(node.path), + tts: self.fold_tts(&node.tts), + ctxt: mtwt::apply_mark(self.mark, node.ctxt), }, span: span, } @@ -2116,7 +1776,7 @@ foo_module!(); // find the xx binding let bindings = crate_bindings(&cr); let cxbinds: Vec<&ast::Ident> = - bindings.iter().filter(|b| b.name == "xx").collect(); + bindings.iter().filter(|b| b.name.as_str() == "xx").collect(); let cxbinds: &[&ast::Ident] = &cxbinds[..]; let cxbind = match (cxbinds.len(), cxbinds.get(0)) { (1, Some(b)) => *b, @@ -2128,7 +1788,7 @@ foo_module!(); // the xx binding should bind all of the xx varrefs: for (idx,v) in varrefs.iter().filter(|p| { p.segments.len() == 1 - && p.segments[0].identifier.name == "xx" + && p.segments[0].identifier.name.as_str() == "xx" }).enumerate() { if mtwt::resolve(v.segments[0].identifier) != resolved_binding { println!("uh oh, xx binding didn't match xx varref:"); diff --git a/src/libsyntax/ext/mtwt.rs b/src/libsyntax/ext/mtwt.rs index ce83b84efe..7ac0e8c64c 100644 --- a/src/libsyntax/ext/mtwt.rs +++ b/src/libsyntax/ext/mtwt.rs @@ -35,7 +35,9 @@ use std::collections::HashMap; pub struct SCTable { table: RefCell>, mark_memo: RefCell>, - rename_memo: RefCell>, + // The pair (Name,SyntaxContext) is actually one Ident, but it needs to be hashed and + // compared as pair (name, ctxt) and not as an Ident + rename_memo: RefCell>, } #[derive(PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy, Clone)] @@ -66,8 +68,9 @@ pub fn apply_mark(m: Mrk, ctxt: SyntaxContext) -> SyntaxContext { /// Extend a syntax context with a given mark and sctable (explicit memoization) fn apply_mark_internal(m: Mrk, ctxt: SyntaxContext, table: &SCTable) -> SyntaxContext { let key = (ctxt, m); - * table.mark_memo.borrow_mut().entry(key) - .or_insert_with(|| idx_push(&mut *table.table.borrow_mut(), Mark(m, ctxt))) + *table.mark_memo.borrow_mut().entry(key).or_insert_with(|| { + SyntaxContext(idx_push(&mut *table.table.borrow_mut(), Mark(m, ctxt))) + }) } /// Extend a syntax context with a given rename @@ -81,10 +84,11 @@ fn apply_rename_internal(id: Ident, to: Name, ctxt: SyntaxContext, table: &SCTable) -> SyntaxContext { - let key = (ctxt, id, to); + let key = (ctxt, (id.name, id.ctxt), to); - * table.rename_memo.borrow_mut().entry(key) - .or_insert_with(|| idx_push(&mut *table.table.borrow_mut(), Rename(id, to, ctxt))) + *table.rename_memo.borrow_mut().entry(key).or_insert_with(|| { + SyntaxContext(idx_push(&mut *table.table.borrow_mut(), Rename(id, to, ctxt))) + }) } /// Apply a list of renamings to a context @@ -185,20 +189,20 @@ fn resolve_internal(id: Ident, } let resolved = { - let result = (*table.table.borrow())[id.ctxt as usize]; + let result = (*table.table.borrow())[id.ctxt.0 as usize]; match result { EmptyCtxt => id.name, // ignore marks here: Mark(_,subctxt) => - resolve_internal(Ident{name:id.name, ctxt: subctxt}, + resolve_internal(Ident::new(id.name, subctxt), table, resolve_table), // do the rename if necessary: Rename(Ident{name, ctxt}, toname, subctxt) => { let resolvedfrom = - resolve_internal(Ident{name:name, ctxt:ctxt}, + resolve_internal(Ident::new(name, ctxt), table, resolve_table); let resolvedthis = - resolve_internal(Ident{name:id.name, ctxt:subctxt}, + resolve_internal(Ident::new(id.name, subctxt), table, resolve_table); if (resolvedthis == resolvedfrom) && (marksof_internal(ctxt, resolvedthis, table) @@ -229,7 +233,7 @@ fn marksof_internal(ctxt: SyntaxContext, let mut result = Vec::new(); let mut loopvar = ctxt; loop { - let table_entry = (*table.table.borrow())[loopvar as usize]; + let table_entry = (*table.table.borrow())[loopvar.0 as usize]; match table_entry { EmptyCtxt => { return result; @@ -256,7 +260,7 @@ fn marksof_internal(ctxt: SyntaxContext, /// FAILS when outside is not a mark. pub fn outer_mark(ctxt: SyntaxContext) -> Mrk { with_sctable(|sctable| { - match (*sctable.table.borrow())[ctxt as usize] { + match (*sctable.table.borrow())[ctxt.0 as usize] { Mark(mrk, _) => mrk, _ => panic!("can't retrieve outer mark when outside is not a mark") } @@ -302,7 +306,7 @@ mod tests { } fn id(n: u32, s: SyntaxContext) -> Ident { - Ident {name: Name(n), ctxt: s} + Ident::new(Name(n), s) } // because of the SCTable, I now need a tidy way of @@ -328,7 +332,7 @@ mod tests { let mut result = Vec::new(); loop { let table = table.table.borrow(); - match (*table)[sc as usize] { + match (*table)[sc.0 as usize] { EmptyCtxt => {return result;}, Mark(mrk,tail) => { result.push(M(mrk)); @@ -349,15 +353,15 @@ mod tests { fn test_unfold_refold(){ let mut t = new_sctable_internal(); - let test_sc = vec!(M(3),R(id(101,0),Name(14)),M(9)); - assert_eq!(unfold_test_sc(test_sc.clone(),EMPTY_CTXT,&mut t),4); + let test_sc = vec!(M(3),R(id(101,EMPTY_CTXT),Name(14)),M(9)); + assert_eq!(unfold_test_sc(test_sc.clone(),EMPTY_CTXT,&mut t),SyntaxContext(4)); { let table = t.table.borrow(); - assert!((*table)[2] == Mark(9,0)); - assert!((*table)[3] == Rename(id(101,0),Name(14),2)); - assert!((*table)[4] == Mark(3,3)); + assert!((*table)[2] == Mark(9,EMPTY_CTXT)); + assert!((*table)[3] == Rename(id(101,EMPTY_CTXT),Name(14),SyntaxContext(2))); + assert!((*table)[4] == Mark(3,SyntaxContext(3))); } - assert_eq!(refold_test_sc(4,&t),test_sc); + assert_eq!(refold_test_sc(SyntaxContext(4),&t),test_sc); } // extend a syntax context with a sequence of marks given @@ -371,11 +375,11 @@ mod tests { #[test] fn unfold_marks_test() { let mut t = new_sctable_internal(); - assert_eq!(unfold_marks(vec!(3,7),EMPTY_CTXT,&mut t),3); + assert_eq!(unfold_marks(vec!(3,7),EMPTY_CTXT,&mut t),SyntaxContext(3)); { let table = t.table.borrow(); - assert!((*table)[2] == Mark(7,0)); - assert!((*table)[3] == Mark(3,2)); + assert!((*table)[2] == Mark(7,EMPTY_CTXT)); + assert!((*table)[3] == Mark(3,SyntaxContext(2))); } } @@ -396,7 +400,7 @@ mod tests { assert_eq! (marksof_internal (ans, stopname,&t), [16]);} // rename where stop doesn't match: { let chain = vec!(M(9), - R(id(name1.usize() as u32, + R(id(name1.0, apply_mark_internal (4, EMPTY_CTXT,&mut t)), Name(100101102)), M(14)); @@ -405,7 +409,7 @@ mod tests { // rename where stop does match { let name1sc = apply_mark_internal(4, EMPTY_CTXT, &mut t); let chain = vec!(M(9), - R(id(name1.usize() as u32, name1sc), + R(id(name1.0, name1sc), stopname), M(14)); let ans = unfold_test_sc(chain,EMPTY_CTXT,&mut t); @@ -474,10 +478,10 @@ mod tests { #[test] fn hashing_tests () { let mut t = new_sctable_internal(); - assert_eq!(apply_mark_internal(12,EMPTY_CTXT,&mut t),2); - assert_eq!(apply_mark_internal(13,EMPTY_CTXT,&mut t),3); + assert_eq!(apply_mark_internal(12,EMPTY_CTXT,&mut t),SyntaxContext(2)); + assert_eq!(apply_mark_internal(13,EMPTY_CTXT,&mut t),SyntaxContext(3)); // using the same one again should result in the same index: - assert_eq!(apply_mark_internal(12,EMPTY_CTXT,&mut t),2); + assert_eq!(apply_mark_internal(12,EMPTY_CTXT,&mut t),SyntaxContext(2)); // I'm assuming that the rename table will behave the same.... } @@ -496,10 +500,10 @@ mod tests { #[test] fn new_resolves_test() { - let renames = vec!((Ident{name:Name(23),ctxt:EMPTY_CTXT},Name(24)), - (Ident{name:Name(29),ctxt:EMPTY_CTXT},Name(29))); + let renames = vec!((Ident::with_empty_ctxt(Name(23)),Name(24)), + (Ident::with_empty_ctxt(Name(29)),Name(29))); let new_ctxt1 = apply_renames(&renames,EMPTY_CTXT); - assert_eq!(resolve(Ident{name:Name(23),ctxt:new_ctxt1}),Name(24)); - assert_eq!(resolve(Ident{name:Name(29),ctxt:new_ctxt1}),Name(29)); + assert_eq!(resolve(Ident::new(Name(23),new_ctxt1)),Name(24)); + assert_eq!(resolve(Ident::new(Name(29),new_ctxt1)),Name(29)); } } diff --git a/src/libsyntax/ext/pushpop_safe.rs b/src/libsyntax/ext/pushpop_safe.rs deleted file mode 100644 index a67d550d3c..0000000000 --- a/src/libsyntax/ext/pushpop_safe.rs +++ /dev/null @@ -1,94 +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. - -/* - * The compiler code necessary to support the `push_unsafe!` and - * `pop_unsafe!` macros. - * - * This is a hack to allow a kind of "safety hygiene", where a macro - * can generate code with an interior expression that inherits the - * safety of some outer context. - * - * For example, in: - * - * ```rust - * fn foo() { push_unsafe!( { EXPR_1; pop_unsafe!( EXPR_2 ) } ) } - * ``` - * - * the `EXPR_1` is considered to be in an `unsafe` context, - * but `EXPR_2` is considered to be in a "safe" (i.e. checked) context. - * - * For comparison, in: - * - * ```rust - * fn foo() { unsafe { push_unsafe!( { EXPR_1; pop_unsafe!( EXPR_2 ) } ) } } - * ``` - * - * both `EXPR_1` and `EXPR_2` are considered to be in `unsafe` - * contexts. - * - */ - -use ast; -use codemap::Span; -use ext::base::*; -use ext::base; -use ext::build::AstBuilder; -use feature_gate; -use ptr::P; - -enum PushPop { Push, Pop } - -pub fn expand_push_unsafe<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> Box { - expand_pushpop_unsafe(cx, sp, tts, PushPop::Push) -} - -pub fn expand_pop_unsafe<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> Box { - expand_pushpop_unsafe(cx, sp, tts, PushPop::Pop) -} - -fn expand_pushpop_unsafe<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree], - pp: PushPop) -> Box { - feature_gate::check_for_pushpop_syntax( - cx.ecfg.features, &cx.parse_sess.span_diagnostic, sp); - - let mut exprs = match get_exprs_from_tts(cx, sp, tts) { - Some(exprs) => exprs.into_iter(), - None => return DummyResult::expr(sp), - }; - - let expr = match (exprs.next(), exprs.next()) { - (Some(expr), None) => expr, - _ => { - let msg = match pp { - PushPop::Push => "push_unsafe! takes 1 arguments", - PushPop::Pop => "pop_unsafe! takes 1 arguments", - }; - cx.span_err(sp, msg); - return DummyResult::expr(sp); - } - }; - - let source = ast::UnsafeSource::CompilerGenerated; - let check_mode = match pp { - PushPop::Push => ast::BlockCheckMode::PushUnsafeBlock(source), - PushPop::Pop => ast::BlockCheckMode::PopUnsafeBlock(source), - }; - - MacEager::expr(cx.expr_block(P(ast::Block { - stmts: vec![], - expr: Some(expr), - id: ast::DUMMY_NODE_ID, - rules: check_mode, - span: sp - }))) -} diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index b816829719..e5fd15559e 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -187,7 +187,7 @@ pub mod rt { let mut r = vec![]; // FIXME: The spans could be better r.push(ast::TtToken(self.span, token::Pound)); - if self.node.style == ast::AttrInner { + if self.node.style == ast::AttrStyle::Inner { r.push(ast::TtToken(self.span, token::Not)); } r.push(ast::TtDelimited(self.span, Rc::new(ast::Delimited { @@ -464,7 +464,7 @@ fn expr_mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P { ($name: expr, $suffix: expr, $($args: expr),*) => {{ let inner = cx.expr_call(sp, mk_token_path(cx, sp, $name), vec![$($args),*]); let suffix = match $suffix { - Some(name) => cx.expr_some(sp, mk_name(cx, sp, ast::Ident::new(name))), + Some(name) => cx.expr_some(sp, mk_name(cx, sp, ast::Ident::with_empty_ctxt(name))), None => cx.expr_none(sp) }; cx.expr_call(sp, mk_token_path(cx, sp, "Literal"), vec![inner, suffix]) @@ -489,31 +489,32 @@ fn expr_mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P { } token::Literal(token::Byte(i), suf) => { - let e_byte = mk_name(cx, sp, i.ident()); + let e_byte = mk_name(cx, sp, ast::Ident::with_empty_ctxt(i)); return mk_lit!("Byte", suf, e_byte); } token::Literal(token::Char(i), suf) => { - let e_char = mk_name(cx, sp, i.ident()); + let e_char = mk_name(cx, sp, ast::Ident::with_empty_ctxt(i)); return mk_lit!("Char", suf, e_char); } token::Literal(token::Integer(i), suf) => { - let e_int = mk_name(cx, sp, i.ident()); + let e_int = mk_name(cx, sp, ast::Ident::with_empty_ctxt(i)); return mk_lit!("Integer", suf, e_int); } token::Literal(token::Float(fident), suf) => { - let e_fident = mk_name(cx, sp, fident.ident()); + let e_fident = mk_name(cx, sp, ast::Ident::with_empty_ctxt(fident)); return mk_lit!("Float", suf, e_fident); } token::Literal(token::Str_(ident), suf) => { - return mk_lit!("Str_", suf, mk_name(cx, sp, ident.ident())) + return mk_lit!("Str_", suf, mk_name(cx, sp, ast::Ident::with_empty_ctxt(ident))) } token::Literal(token::StrRaw(ident, n), suf) => { - return mk_lit!("StrRaw", suf, mk_name(cx, sp, ident.ident()), cx.expr_usize(sp, n)) + return mk_lit!("StrRaw", suf, mk_name(cx, sp, ast::Ident::with_empty_ctxt(ident)), + cx.expr_usize(sp, n)) } token::Ident(ident, style) => { @@ -535,7 +536,7 @@ fn expr_mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P { token::DocComment(ident) => { return cx.expr_call(sp, mk_token_path(cx, sp, "DocComment"), - vec!(mk_name(cx, sp, ident.ident()))); + vec!(mk_name(cx, sp, ast::Ident::with_empty_ctxt(ident)))); } token::MatchNt(name, kind, namep, kindp) => { diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index f6513cc3e2..8dec9ae1e9 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -32,7 +32,7 @@ //! As it processes them, it fills up `eof_eis` with items that would be valid if //! the macro invocation is now over, `bb_eis` with items that are waiting on //! a Rust nonterminal like `$e:expr`, and `next_eis` with items that are waiting -//! on the a particular token. Most of the logic concerns moving the · through the +//! on a particular token. Most of the logic concerns moving the · through the //! repetitions indicated by Kleene stars. It only advances or calls out to the //! real Rust parser when no `cur_eis` items remain //! @@ -79,7 +79,7 @@ pub use self::ParseResult::*; use self::TokenTreeOrTokenTreeVec::*; use ast; -use ast::{TokenTree, Ident}; +use ast::{TokenTree, Name}; use ast::{TtDelimited, TtSequence, TtToken}; use codemap::{BytePos, mk_sp, Span}; use codemap; @@ -202,9 +202,9 @@ pub enum NamedMatch { } pub fn nameize(p_s: &ParseSess, ms: &[TokenTree], res: &[Rc]) - -> HashMap> { + -> HashMap> { fn n_rec(p_s: &ParseSess, m: &TokenTree, res: &[Rc], - ret_val: &mut HashMap>, idx: &mut usize) { + ret_val: &mut HashMap>, idx: &mut usize) { match m { &TtSequence(_, ref seq) => { for next_m in &seq.tts { @@ -217,7 +217,7 @@ pub fn nameize(p_s: &ParseSess, ms: &[TokenTree], res: &[Rc]) } } &TtToken(sp, MatchNt(bind_name, _, _, _)) => { - match ret_val.entry(bind_name) { + match ret_val.entry(bind_name.name) { Vacant(spot) => { spot.insert(res[*idx].clone()); *idx += 1; @@ -246,7 +246,7 @@ pub enum ParseResult { Error(codemap::Span, String) } -pub type NamedParseResult = ParseResult>>; +pub type NamedParseResult = ParseResult>>; pub type PositionalParseResult = ParseResult>>; /// Perform a token equality check, ignoring syntax context (that is, an diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index d728fa59bd..cce4450b29 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -282,7 +282,7 @@ pub fn compile<'cx>(cx: &'cx mut ExtCtxt, }; // Extract the arguments: - let lhses = match **argument_map.get(&lhs_nm).unwrap() { + let lhses = match **argument_map.get(&lhs_nm.name).unwrap() { MatchedSeq(ref s, _) => /* FIXME (#2543) */ (*s).clone(), _ => cx.span_bug(def.span, "wrong-structured lhs") }; @@ -291,7 +291,7 @@ pub fn compile<'cx>(cx: &'cx mut ExtCtxt, check_lhs_nt_follows(cx, &**lhs, def.span); } - let rhses = match **argument_map.get(&rhs_nm).unwrap() { + let rhses = match **argument_map.get(&rhs_nm.name).unwrap() { MatchedSeq(ref s, _) => /* FIXME (#2543) */ (*s).clone(), _ => cx.span_bug(def.span, "wrong-structured rhs") }; @@ -497,7 +497,7 @@ fn is_in_follow(_: &ExtCtxt, tok: &Token, frag: &str) -> Result { Ok(true) }, "block" => { - // anything can follow block, the braces provide a easy boundary to + // anything can follow block, the braces provide an easy boundary to // maintain Ok(true) }, @@ -510,14 +510,14 @@ fn is_in_follow(_: &ExtCtxt, tok: &Token, frag: &str) -> Result { "pat" => { match *tok { FatArrow | Comma | Eq => Ok(true), - Ident(i, _) if i.name == "if" || i.name == "in" => Ok(true), + Ident(i, _) if i.name.as_str() == "if" || i.name.as_str() == "in" => Ok(true), _ => Ok(false) } }, "path" | "ty" => { match *tok { Comma | FatArrow | Colon | Eq | Gt | Semi => Ok(true), - Ident(i, _) if i.name == "as" => Ok(true), + Ident(i, _) if i.name.as_str() == "as" => Ok(true), _ => Ok(false) } }, diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index b07bd09963..d1e48eda4f 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -10,7 +10,7 @@ use self::LockstepIterSize::*; use ast; -use ast::{TokenTree, TtDelimited, TtToken, TtSequence, Ident}; +use ast::{TokenTree, TtDelimited, TtToken, TtSequence, Ident, Name}; use codemap::{Span, DUMMY_SP}; use diagnostic::SpanHandler; use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal}; @@ -38,7 +38,7 @@ pub struct TtReader<'a> { /// the unzipped tree: stack: Vec, /* for MBE-style macro transcription */ - interpolations: HashMap>, + interpolations: HashMap>, imported_from: Option, // Some => return imported_from as the next token @@ -56,7 +56,7 @@ pub struct TtReader<'a> { /// `src` contains no `TtSequence`s, `MatchNt`s or `SubstNt`s, `interp` can /// (and should) be None. pub fn new_tt_reader<'a>(sp_diag: &'a SpanHandler, - interp: Option>>, + interp: Option>>, imported_from: Option, src: Vec) -> TtReader<'a> { @@ -70,7 +70,7 @@ pub fn new_tt_reader<'a>(sp_diag: &'a SpanHandler, /// `src` contains no `TtSequence`s, `MatchNt`s or `SubstNt`s, `interp` can /// (and should) be None. pub fn new_tt_reader_with_doc_flag<'a>(sp_diag: &'a SpanHandler, - interp: Option>>, + interp: Option>>, imported_from: Option, src: Vec, desugar_doc_comments: bool) @@ -117,7 +117,7 @@ fn lookup_cur_matched_by_matched(r: &TtReader, start: Rc) -> Rc Option> { - let matched_opt = r.interpolations.get(&name).cloned(); + let matched_opt = r.interpolations.get(&name.name).cloned(); matched_opt.map(|s| lookup_cur_matched_by_matched(r, s)) } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index abc0410295..a0c089aff2 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -35,7 +35,7 @@ use codemap::{CodeMap, Span}; use diagnostic::SpanHandler; use visit; use visit::{FnKind, Visitor}; -use parse::token::{self, InternedString}; +use parse::token::InternedString; use std::ascii::AsciiExt; use std::cmp; @@ -81,8 +81,8 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Option, Status ("associated_types", "1.0.0", None, Accepted), ("visible_private_types", "1.0.0", None, Active), ("slicing_syntax", "1.0.0", None, Accepted), - ("box_syntax", "1.0.0", None, Active), - ("placement_in_syntax", "1.0.0", None, Active), + ("box_syntax", "1.0.0", Some(27779), Active), + ("placement_in_syntax", "1.0.0", Some(27779), Active), ("pushpop_unsafe", "1.2.0", None, Active), ("on_unimplemented", "1.0.0", None, Active), ("simd_ffi", "1.0.0", None, Active), @@ -136,6 +136,10 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Option, Status // switch to Accepted; see RFC 320) ("unsafe_no_drop_flag", "1.0.0", None, Active), + // Allows using the unsafe_destructor_blind_to_params attribute; + // RFC 1238 + ("dropck_parametricity", "1.3.0", Some(28498), Active), + // Allows the use of custom attributes; RFC 572 ("custom_attribute", "1.0.0", None, Active), @@ -191,6 +195,21 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Option, Status // allow `#[unwind]` ("unwind_attributes", "1.4.0", None, Active), + + // allow empty structs and enum variants with braces + ("braced_empty_structs", "1.5.0", None, Active), + + // allow overloading augmented assignment operations like `a += b` + ("augmented_assignments", "1.5.0", None, Active), + + // allow `#[no_debug]` + ("no_debug", "1.5.0", None, Active), + + // allow `#[omit_gdb_pretty_printer_section]` + ("omit_gdb_pretty_printer_section", "1.5.0", None, Active), + + // Allows cfg(target_vendor = "..."). + ("cfg_target_vendor", "1.5.0", None, Active), ]; // (changing above list without updating src/doc/reference.md makes @cmr sad) @@ -314,11 +333,21 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat ("link_section", Whitelisted, Ungated), ("no_builtins", Whitelisted, Ungated), ("no_mangle", Whitelisted, Ungated), - ("no_debug", Whitelisted, Ungated), - ("omit_gdb_pretty_printer_section", Whitelisted, Ungated), + ("no_debug", Whitelisted, Gated("no_debug", + "the `#[no_debug]` attribute \ + is an experimental feature")), + ("omit_gdb_pretty_printer_section", Whitelisted, Gated("omit_gdb_pretty_printer_section", + "the `#[omit_gdb_pretty_printer_section]` \ + attribute is just used for the Rust test \ + suite")), ("unsafe_no_drop_flag", Whitelisted, Gated("unsafe_no_drop_flag", "unsafe_no_drop_flag has unstable semantics \ and may be removed in the future")), + ("unsafe_destructor_blind_to_params", + Normal, + Gated("dropck_parametricity", + "unsafe_destructor_blind_to_params has unstable semantics \ + and may be removed in the future")), ("unwind", Whitelisted, Gated("unwind_attributes", "#[unwind] is experimental")), // used in resolve @@ -360,6 +389,7 @@ macro_rules! cfg_fn { const GATED_CFGS: &'static [(&'static str, &'static str, fn(&Features) -> bool)] = &[ // (name in cfg, feature, function to check if the feature is enabled) ("target_feature", "cfg_target_feature", cfg_fn!(|x| x.cfg_target_feature)), + ("target_vendor", "cfg_target_vendor", cfg_fn!(|x| x.cfg_target_vendor)), ]; #[derive(Debug, Eq, PartialEq)] @@ -454,6 +484,9 @@ pub struct Features { pub default_type_parameter_fallback: bool, pub type_macros: bool, pub cfg_target_feature: bool, + pub cfg_target_vendor: bool, + pub augmented_assignments: bool, + pub braced_empty_structs: bool, } impl Features { @@ -482,6 +515,9 @@ impl Features { default_type_parameter_fallback: false, type_macros: false, cfg_target_feature: false, + cfg_target_vendor: false, + augmented_assignments: false, + braced_empty_structs: false, } } } @@ -647,8 +683,8 @@ struct MacroVisitor<'a> { impl<'a, 'v> Visitor<'v> for MacroVisitor<'a> { fn visit_mac(&mut self, mac: &ast::Mac) { - let ast::MacInvocTT(ref path, _, _) = mac.node; - let id = path.segments.last().unwrap().identifier; + let path = &mac.node.path; + let name = path.segments.last().unwrap().identifier.name.as_str(); // Issue 22234: If you add a new case here, make sure to also // add code to catch the macro during or after expansion. @@ -658,19 +694,19 @@ impl<'a, 'v> Visitor<'v> for MacroVisitor<'a> { // catch uses of these macros within conditionally-compiled // code, e.g. `#[cfg]`-guarded functions. - if id == token::str_to_ident("asm") { + if name == "asm" { self.context.gate_feature("asm", path.span, EXPLAIN_ASM); } - else if id == token::str_to_ident("log_syntax") { + else if name == "log_syntax" { self.context.gate_feature("log_syntax", path.span, EXPLAIN_LOG_SYNTAX); } - else if id == token::str_to_ident("trace_macros") { + else if name == "trace_macros" { self.context.gate_feature("trace_macros", path.span, EXPLAIN_TRACE_MACROS); } - else if id == token::str_to_ident("concat_idents") { + else if name == "concat_idents" { self.context.gate_feature("concat_idents", path.span, EXPLAIN_CONCAT_IDENTS); } } @@ -688,11 +724,11 @@ impl<'a, 'v> Visitor<'v> for MacroVisitor<'a> { // But we keep these checks as a pre-expansion check to catch // uses in e.g. conditionalized code. - if let ast::ExprBox(None, _) = e.node { + if let ast::ExprBox(_) = e.node { self.context.gate_feature("box_syntax", e.span, EXPLAIN_BOX_SYNTAX); } - if let ast::ExprBox(Some(_), _) = e.node { + if let ast::ExprInPlace(..) = e.node { self.context.gate_feature("placement_in_syntax", e.span, EXPLAIN_PLACEMENT_IN); } @@ -701,7 +737,7 @@ impl<'a, 'v> Visitor<'v> for MacroVisitor<'a> { } struct PostExpansionVisitor<'a> { - context: &'a Context<'a> + context: &'a Context<'a>, } impl<'a> PostExpansionVisitor<'a> { @@ -821,6 +857,21 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { visit::walk_item(self, i); } + fn visit_variant_data(&mut self, s: &'v ast::VariantData, _: ast::Ident, + _: &'v ast::Generics, _: ast::NodeId, span: Span) { + if s.fields().is_empty() { + if s.is_struct() { + self.gate_feature("braced_empty_structs", span, + "empty structs and enum variants with braces are unstable"); + } else if s.is_tuple() { + self.context.span_handler.span_err(span, "empty tuple structs and enum variants \ + are not allowed, use unit structs and \ + enum variants instead"); + } + } + visit::walk_struct_def(self, s) + } + fn visit_foreign_item(&mut self, i: &ast::ForeignItem) { let links_to_llvm = match attr::first_attr_value_str_by_name(&i.attrs, "link_name") { @@ -837,7 +888,7 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { fn visit_expr(&mut self, e: &ast::Expr) { match e.node { - ast::ExprBox(..) | ast::ExprUnary(ast::UnOp::UnUniq, _) => { + ast::ExprBox(_) => { self.gate_feature("box_syntax", e.span, "box expression syntax is experimental; \ @@ -1034,6 +1085,9 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, default_type_parameter_fallback: cx.has_feature("default_type_parameter_fallback"), type_macros: cx.has_feature("type_macros"), cfg_target_feature: cx.has_feature("cfg_target_feature"), + cfg_target_vendor: cx.has_feature("cfg_target_vendor"), + augmented_assignments: cx.has_feature("augmented_assignments"), + braced_empty_structs: cx.has_feature("braced_empty_structs"), } } @@ -1064,8 +1118,7 @@ pub enum UnstableFeatures { /// Errors are bypassed for bootstrapping. This is required any time /// during the build that feature-related lints are set to warn or above /// because the build turns on warnings-as-errors and uses lots of unstable - /// features. As a result, this this is always required for building Rust - /// itself. + /// features. As a result, this is always required for building Rust itself. Cheat } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 0cfddc9857..be910285db 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -231,8 +231,8 @@ pub trait Folder : Sized { noop_fold_poly_trait_ref(p, self) } - fn fold_struct_def(&mut self, struct_def: P) -> P { - noop_fold_struct_def(struct_def, self) + fn fold_variant_data(&mut self, vdata: VariantData) -> VariantData { + noop_fold_variant_data(vdata, self) } fn fold_lifetimes(&mut self, lts: Vec) -> Vec { @@ -271,10 +271,6 @@ pub trait Folder : Sized { noop_fold_opt_lifetime(o_lt, self) } - fn fold_variant_arg(&mut self, va: VariantArg) -> VariantArg { - noop_fold_variant_arg(va, self) - } - fn fold_opt_bounds(&mut self, b: Option>) -> Option> { noop_fold_opt_bounds(b, self) @@ -450,22 +446,12 @@ pub fn noop_fold_foreign_mod(ForeignMod {abi, items}: ForeignMod, } pub fn noop_fold_variant(v: P, fld: &mut T) -> P { - v.map(|Spanned {node: Variant_ {id, name, attrs, kind, disr_expr, vis}, span}| Spanned { + v.map(|Spanned {node: Variant_ {name, attrs, data, disr_expr}, span}| Spanned { node: Variant_ { - id: fld.new_id(id), name: name, attrs: fold_attrs(attrs, fld), - kind: match kind { - TupleVariantKind(variant_args) => { - TupleVariantKind(variant_args.move_map(|x| - fld.fold_variant_arg(x))) - } - StructVariantKind(struct_def) => { - StructVariantKind(fld.fold_struct_def(struct_def)) - } - }, + data: fld.fold_variant_data(data), disr_expr: disr_expr.map(|e| fld.fold_expr(e)), - vis: vis, }, span: fld.new_span(span), }) @@ -568,10 +554,10 @@ pub fn noop_fold_explicit_self(Spanned {span, node}: ExplicitSelf, fl pub fn noop_fold_mac(Spanned {node, span}: Mac, fld: &mut T) -> Mac { Spanned { - node: match node { - MacInvocTT(p, tts, ctxt) => { - MacInvocTT(fld.fold_path(p), fld.fold_tts(&tts), ctxt) - } + node: Mac_ { + path: fld.fold_path(node.path), + tts: fld.fold_tts(&node.tts), + ctxt: node.ctxt, }, span: fld.new_span(span) } @@ -828,11 +814,18 @@ pub fn noop_fold_where_predicate( } } -pub fn noop_fold_struct_def(struct_def: P, fld: &mut T) -> P { - struct_def.map(|StructDef { fields, ctor_id }| StructDef { - fields: fields.move_map(|f| fld.fold_struct_field(f)), - ctor_id: ctor_id.map(|cid| fld.new_id(cid)), - }) +pub fn noop_fold_variant_data(vdata: VariantData, fld: &mut T) -> VariantData { + match vdata { + ast::VariantData::Struct(fields, id) => { + ast::VariantData::Struct(fields.move_map(|f| fld.fold_struct_field(f)), + fld.new_id(id)) + } + ast::VariantData::Tuple(fields, id) => { + ast::VariantData::Tuple(fields.move_map(|f| fld.fold_struct_field(f)), + fld.new_id(id)) + } + ast::VariantData::Unit(id) => ast::VariantData::Unit(fld.new_id(id)) + } } pub fn noop_fold_trait_ref(p: TraitRef, fld: &mut T) -> TraitRef { @@ -893,14 +886,6 @@ fn noop_fold_bounds(bounds: TyParamBounds, folder: &mut T) bounds.move_map(|bound| folder.fold_ty_param_bound(bound)) } -fn noop_fold_variant_arg(VariantArg {id, ty}: VariantArg, folder: &mut T) - -> VariantArg { - VariantArg { - id: folder.new_id(id), - ty: folder.fold_ty(ty) - } -} - pub fn noop_fold_block(b: P, folder: &mut T) -> P { b.map(|Block {id, stmts, expr, rules, span}| Block { id: folder.new_id(id), @@ -946,7 +931,7 @@ pub fn noop_fold_item_underscore(i: Item_, folder: &mut T) -> Item_ { folder.fold_generics(generics)) } ItemStruct(struct_def, generics) => { - let struct_def = folder.fold_struct_def(struct_def); + let struct_def = folder.fold_variant_data(struct_def); ItemStruct(struct_def, folder.fold_generics(generics)) } ItemDefaultImpl(unsafety, ref trait_ref) => { @@ -1189,8 +1174,11 @@ pub fn noop_fold_expr(Expr {id, node, span}: Expr, folder: &mut T) -> Expr { id: folder.new_id(id), node: match node { - ExprBox(p, e) => { - ExprBox(p.map(|e|folder.fold_expr(e)), folder.fold_expr(e)) + ExprBox(e) => { + ExprBox(folder.fold_expr(e)) + } + ExprInPlace(p, e) => { + ExprInPlace(folder.fold_expr(p), folder.fold_expr(e)) } ExprVec(exprs) => { ExprVec(exprs.move_map(|x| folder.fold_expr(x))) @@ -1254,10 +1242,9 @@ pub fn noop_fold_expr(Expr {id, node, span}: Expr, folder: &mut T) -> ExprLoop(folder.fold_block(body), opt_ident.map(|i| folder.fold_ident(i))) } - ExprMatch(expr, arms, source) => { + ExprMatch(expr, arms) => { ExprMatch(folder.fold_expr(expr), - arms.move_map(|x| folder.fold_arm(x)), - source) + arms.move_map(|x| folder.fold_arm(x))) } ExprClosure(capture_clause, decl, body) => { ExprClosure(capture_clause, diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index d1c862ad40..9adef08771 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -29,7 +29,6 @@ #![feature(drain)] #![feature(filling_drop)] #![feature(libc)] -#![feature(ref_slice)] #![feature(rustc_private)] #![feature(set_stdio)] #![feature(staged_api)] @@ -37,7 +36,6 @@ #![feature(str_escape)] #![feature(unicode)] #![feature(vec_push_all)] -#![feature(vec_resize)] extern crate fmt_macros; extern crate serialize; @@ -121,7 +119,6 @@ pub mod ext { pub mod log_syntax; pub mod mtwt; pub mod quote; - pub mod pushpop_safe; pub mod source_util; pub mod trace_macros; diff --git a/src/libsyntax/owned_slice.rs b/src/libsyntax/owned_slice.rs index 25f1f9b848..83369689a9 100644 --- a/src/libsyntax/owned_slice.rs +++ b/src/libsyntax/owned_slice.rs @@ -12,6 +12,7 @@ use std::default::Default; use std::fmt; use std::iter::{IntoIterator, FromIterator}; use std::ops::Deref; +use std::slice; use std::vec; use serialize::{Encodable, Decodable, Encoder, Decoder}; @@ -82,6 +83,14 @@ impl FromIterator for OwnedSlice { } } +impl<'a, T> IntoIterator for &'a OwnedSlice { + type Item = &'a T; + type IntoIter = slice::Iter<'a, T>; + fn into_iter(self) -> Self::IntoIter { + self.data.into_iter() + } +} + impl Encodable for OwnedSlice { fn encode(&self, s: &mut S) -> Result<(), S::Error> { Encodable::encode(&**self, s) diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index 18588c5935..219360093d 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -40,11 +40,11 @@ impl<'a> ParserAttr for Parser<'a> { token::DocComment(s) => { let attr = ::attr::mk_sugared_doc_attr( attr::mk_attr_id(), - self.id_to_interned_str(s.ident()), + self.id_to_interned_str(ast::Ident::with_empty_ctxt(s)), self.span.lo, self.span.hi ); - if attr.node.style != ast::AttrOuter { + if attr.node.style != ast::AttrStyle::Outer { panic!(self.fatal("expected outer comment")); } attrs.push(attr); @@ -79,9 +79,9 @@ impl<'a> ParserAttr for Parser<'a> { self.fileline_help(span, "place inner attribute at the top of the module or block"); } - ast::AttrInner + ast::AttrStyle::Inner } else { - ast::AttrOuter + ast::AttrStyle::Outer }; panictry!(self.expect(&token::OpenDelim(token::Bracket))); @@ -101,7 +101,7 @@ impl<'a> ParserAttr for Parser<'a> { panictry!(self.bump()); self.span_warn(span, "this inner attribute syntax is deprecated. \ The new syntax is `#![foo]`, with a bang and no semicolon"); - style = ast::AttrInner; + style = ast::AttrStyle::Inner; } return Spanned { @@ -131,16 +131,15 @@ impl<'a> ParserAttr for Parser<'a> { } let attr = self.parse_attribute(true); - assert!(attr.node.style == ast::AttrInner); + assert!(attr.node.style == ast::AttrStyle::Inner); attrs.push(attr); } token::DocComment(s) => { // we need to get the position of this token before we bump. let Span { lo, hi, .. } = self.span; - let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), - self.id_to_interned_str(s.ident()), - lo, hi); - if attr.node.style == ast::AttrInner { + let str = self.id_to_interned_str(ast::Ident::with_empty_ctxt(s)); + let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), str, lo, hi); + if attr.node.style == ast::AttrStyle::Inner { attrs.push(attr); panictry!(self.bump()); } else { diff --git a/src/libsyntax/parse/lexer/comments.rs b/src/libsyntax/parse/lexer/comments.rs index 9033208fbd..137996a35e 100644 --- a/src/libsyntax/parse/lexer/comments.rs +++ b/src/libsyntax/parse/lexer/comments.rs @@ -52,9 +52,9 @@ pub fn is_doc_comment(s: &str) -> bool { pub fn doc_comment_style(comment: &str) -> ast::AttrStyle { assert!(is_doc_comment(comment)); if comment.starts_with("//!") || comment.starts_with("/*!") { - ast::AttrInner + ast::AttrStyle::Inner } else { - ast::AttrOuter + ast::AttrStyle::Outer } } diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index a0e170b4ac..490822b934 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -1385,8 +1385,9 @@ pub fn is_doc_comment(s: &str) -> bool { } pub fn is_block_doc_comment(s: &str) -> bool { - let res = (s.starts_with("/**") && *s.as_bytes().get(3).unwrap_or(&b' ') != b'*') - || s.starts_with("/*!"); + let res = ((s.starts_with("/**") && *s.as_bytes().get(3).unwrap_or(&b' ') != b'*') + || s.starts_with("/*!")) + && s.len() >= 5; // Prevent `/**/` from being parsed as a doc comment debug!("is {:?} a doc comment? {}", s, res); res } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 269f8bdd98..5beec702f8 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -744,8 +744,8 @@ mod tests { Some(&ast::TtToken(_, token::Ident(name_zip, token::Plain))), Some(&ast::TtDelimited(_, ref macro_delimed)), ) - if name_macro_rules.name == "macro_rules" - && name_zip.name == "zip" => { + if name_macro_rules.name.as_str() == "macro_rules" + && name_zip.name.as_str() == "zip" => { let tts = ¯o_delimed.tts[..]; match (tts.len(), tts.get(0), tts.get(1), tts.get(2)) { ( @@ -763,7 +763,7 @@ mod tests { Some(&ast::TtToken(_, token::Ident(ident, token::Plain))), ) if first_delimed.delim == token::Paren - && ident.name == "a" => {}, + && ident.name.as_str() == "a" => {}, _ => panic!("value 3: {:?}", **first_delimed), } let tts = &second_delimed.tts[..]; @@ -774,7 +774,7 @@ mod tests { Some(&ast::TtToken(_, token::Ident(ident, token::Plain))), ) if second_delimed.delim == token::Paren - && ident.name == "a" => {}, + && ident.name.as_str() == "a" => {}, _ => panic!("value 4: {:?}", **second_delimed), } }, @@ -1090,10 +1090,7 @@ mod tests { "foo!( fn main() { body } )".to_string(), vec![], &sess); let tts = match expr.node { - ast::ExprMac(ref mac) => { - let ast::MacInvocTT(_, ref tts, _) = mac.node; - tts.clone() - } + ast::ExprMac(ref mac) => mac.node.tts.clone(), _ => panic!("not a macro"), }; diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 8d50cc099b..e153f1665e 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -22,7 +22,7 @@ use ast::{Decl, DeclItem, DeclLocal, DefaultBlock, DefaultReturn}; use ast::{UnDeref, BiDiv, EMPTY_CTXT, EnumDef, ExplicitSelf}; use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain}; use ast::{ExprAssign, ExprAssignOp, ExprBinary, ExprBlock, ExprBox}; -use ast::{ExprBreak, ExprCall, ExprCast}; +use ast::{ExprBreak, ExprCall, ExprCast, ExprInPlace}; use ast::{ExprField, ExprTupField, ExprClosure, ExprIf, ExprIfLet, ExprIndex}; use ast::{ExprLit, ExprLoop, ExprMac, ExprRange}; use ast::{ExprMethodCall, ExprParen, ExprPath}; @@ -37,7 +37,7 @@ use ast::{LifetimeDef, Lit, Lit_}; use ast::{LitBool, LitChar, LitByte, LitByteStr}; use ast::{LitStr, LitInt, Local}; use ast::{MacStmtWithBraces, MacStmtWithSemicolon, MacStmtWithoutBraces}; -use ast::{MutImmutable, MutMutable, Mac_, MacInvocTT, MatchSource}; +use ast::{MutImmutable, MutMutable, Mac_}; use ast::{MutTy, BiMul, Mutability}; use ast::{MethodImplItem, NamedField, UnNeg, NoReturn, UnNot}; use ast::{Pat, PatBox, PatEnum, PatIdent, PatLit, PatQPath, PatMac, PatRange}; @@ -45,16 +45,16 @@ use ast::{PatRegion, PatStruct, PatTup, PatVec, PatWild, PatWildMulti}; use ast::PatWildSingle; use ast::{PolyTraitRef, QSelf}; use ast::{Return, BiShl, BiShr, Stmt, StmtDecl}; -use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField}; -use ast::{StructVariantKind, BiSub, StrStyle}; +use ast::{StmtExpr, StmtSemi, StmtMac, VariantData, StructField}; +use ast::{BiSub, StrStyle}; use ast::{SelfExplicit, SelfRegion, SelfStatic, SelfValue}; use ast::{Delimited, SequenceRepetition, TokenTree, TraitItem, TraitRef}; use ast::{TtDelimited, TtSequence, TtToken}; -use ast::{TupleVariantKind, Ty, Ty_, TypeBinding}; +use ast::{Ty, Ty_, TypeBinding}; use ast::{TyMac}; use ast::{TyFixedLengthVec, TyBareFn, TyTypeof, TyInfer}; use ast::{TyParam, TyParamBound, TyParen, TyPath, TyPolyTraitRef, TyPtr}; -use ast::{TyRptr, TyTup, TyU32, TyVec, UnUniq}; +use ast::{TyRptr, TyTup, TyU32, TyVec}; use ast::{TypeImplItem, TypeTraitItem}; use ast::{UnnamedField, UnsafeBlock}; use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple}; @@ -422,7 +422,7 @@ impl<'a> Parser<'a> { this_token_str))) } } else { - self.expect_one_of(slice::ref_slice(t), &[]) + self.expect_one_of(unsafe { slice::from_raw_parts(t, 1) }, &[]) } } @@ -1263,7 +1263,7 @@ impl<'a> Parser<'a> { pub fn parse_ret_ty(&mut self) -> PResult { if try!(self.eat(&token::RArrow) ){ if try!(self.eat(&token::Not) ){ - Ok(NoReturn(self.span)) + Ok(NoReturn(self.last_span)) } else { Ok(Return(try!(self.parse_ty_nopanic()))) } @@ -1381,7 +1381,7 @@ impl<'a> Parser<'a> { seq_sep_none(), |p| p.parse_token_tree())); let hi = self.span.hi; - TyMac(spanned(lo, hi, MacInvocTT(path, tts, EMPTY_CTXT))) + TyMac(spanned(lo, hi, Mac_ { path: path, tts: tts, ctxt: EMPTY_CTXT })) } else { // NAMED TYPE TyPath(None, path) @@ -1583,11 +1583,11 @@ impl<'a> Parser<'a> { let lo = self.span.lo; let literal = P(try!(self.parse_lit())); - let hi = self.span.hi; + let hi = self.last_span.hi; let expr = self.mk_expr(lo, hi, ExprLit(literal)); if minus_present { - let minus_hi = self.span.hi; + let minus_hi = self.last_span.hi; let unary = self.mk_unary(UnNeg, expr); Ok(self.mk_expr(minus_lo, minus_hi, unary)) } else { @@ -1595,8 +1595,21 @@ impl<'a> Parser<'a> { } } - // QUALIFIED PATH `::IDENT[::]` - // Assumes that the leading `<` has been parsed already. + /// Parses qualified path. + /// + /// Assumes that the leading `<` has been parsed already. + /// + /// Qualifed paths are a part of the universal function call + /// syntax (UFCS). + /// + /// `qualified_path = ::path` + /// + /// See `parse_path` for `mode` meaning. + /// + /// # Examples: + /// + /// `::a` + /// `::F::a::` pub fn parse_qualified_path(&mut self, mode: PathParsingMode) -> PResult<(QSelf, ast::Path)> { let span = self.last_span; @@ -2203,9 +2216,7 @@ impl<'a> Parser<'a> { return Ok(self.mk_mac_expr(lo, hi, - MacInvocTT(pth, - tts, - EMPTY_CTXT))); + Mac_ { path: pth, tts: tts, ctxt: EMPTY_CTXT })); } if self.check(&token::OpenDelim(token::Brace)) { // This is a struct literal, unless we're prohibited @@ -2231,14 +2242,6 @@ impl<'a> Parser<'a> { &[token::CloseDelim(token::Brace)])); } - if fields.is_empty() && base.is_none() { - let last_span = self.last_span; - self.span_err(last_span, - "structure literal must either \ - have at least one field or use \ - structure update syntax"); - } - hi = self.span.hi; try!(self.expect(&token::CloseDelim(token::Brace))); ex = ExprStruct(pth, fields, base); @@ -2627,76 +2630,19 @@ impl<'a> Parser<'a> { hi = e.span.hi; ex = ExprAddrOf(m, e); } - token::Ident(_, _) => { - if !self.check_keyword(keywords::Box) && !self.check_keyword(keywords::In) { - return self.parse_dot_or_call_expr(); - } - - let lo = self.span.lo; - let keyword_hi = self.span.hi; - - let is_in = self.token.is_keyword(keywords::In); - try!(self.bump()); - - if is_in { + token::Ident(..) if self.token.is_keyword(keywords::In) => { + try!(self.bump()); let place = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL)); let blk = try!(self.parse_block()); hi = blk.span.hi; let blk_expr = self.mk_expr(blk.span.lo, blk.span.hi, ExprBlock(blk)); - ex = ExprBox(Some(place), blk_expr); - return Ok(self.mk_expr(lo, hi, ex)); - } - - // FIXME (#22181) Remove `box (PLACE) EXPR` support - // entirely after next release (enabling `(box (EXPR))`), - // since it will be replaced by `in PLACE { EXPR }`, ... - // - // ... but for now: check for a place: `box(PLACE) EXPR`. - - if try!(self.eat(&token::OpenDelim(token::Paren))) { - let box_span = mk_sp(lo, self.last_span.hi); - self.span_warn(box_span, - "deprecated syntax; use the `in` keyword now \ - (e.g. change `box () ` to \ - `in { }`)"); - - // Continue supporting `box () EXPR` (temporarily) - if !try!(self.eat(&token::CloseDelim(token::Paren))) { - let place = try!(self.parse_expr_nopanic()); - try!(self.expect(&token::CloseDelim(token::Paren))); - // Give a suggestion to use `box()` when a parenthesised expression is used - if !self.token.can_begin_expr() { - let span = self.span; - let this_token_to_string = self.this_token_to_string(); - self.span_err(span, - &format!("expected expression, found `{}`", - this_token_to_string)); - - // Spanning just keyword avoids constructing - // printout of arg expression (which starts - // with parenthesis, as established above). - - let box_span = mk_sp(lo, keyword_hi); - self.span_suggestion(box_span, - "try using `box ()` instead:", - format!("box ()")); - self.abort_if_errors(); - } - let subexpression = try!(self.parse_prefix_expr()); - hi = subexpression.span.hi; - ex = ExprBox(Some(place), subexpression); - return Ok(self.mk_expr(lo, hi, ex)); - } - } - - // Otherwise, we use the unique pointer default. - let subexpression = try!(self.parse_prefix_expr()); - hi = subexpression.span.hi; - - // FIXME (pnkfelix): After working out kinks with box - // desugaring, should be `ExprBox(None, subexpression)` - // instead. - ex = self.mk_unary(UnUniq, subexpression); + ex = ExprInPlace(place, blk_expr); + } + token::Ident(..) if self.token.is_keyword(keywords::Box) => { + try!(self.bump()); + let subexpression = try!(self.parse_prefix_expr()); + hi = subexpression.span.hi; + ex = ExprBox(subexpression); } _ => return self.parse_dot_or_call_expr() } @@ -2994,7 +2940,7 @@ impl<'a> Parser<'a> { } let hi = self.span.hi; try!(self.bump()); - return Ok(self.mk_expr(lo, hi, ExprMatch(discriminant, arms, MatchSource::Normal))); + return Ok(self.mk_expr(lo, hi, ExprMatch(discriminant, arms))); } pub fn parse_arm_nopanic(&mut self) -> PResult { @@ -3250,6 +3196,10 @@ impl<'a> Parser<'a> { // Parse &pat / &mut pat try!(self.expect_and()); let mutbl = try!(self.parse_mutability()); + if let token::Lifetime(ident) = self.token { + return Err(self.fatal(&format!("unexpected lifetime `{}` in pattern", ident))); + } + let subpat = try!(self.parse_pat_nopanic()); pat = PatRegion(subpat, mutbl); } @@ -3297,7 +3247,7 @@ impl<'a> Parser<'a> { let delim = try!(self.expect_open_delim()); let tts = try!(self.parse_seq_to_end(&token::CloseDelim(delim), seq_sep_none(), |p| p.parse_token_tree())); - let mac = MacInvocTT(path, tts, EMPTY_CTXT); + let mac = Mac_ { path: path, tts: tts, ctxt: EMPTY_CTXT }; pat = PatMac(codemap::Spanned {node: mac, span: self.span}); } else { // Parse ident @ pat @@ -3326,12 +3276,9 @@ impl<'a> Parser<'a> { } token::OpenDelim(token::Brace) => { if qself.is_some() { - let span = self.span; - self.span_err(span, - "unexpected `{` after qualified path"); - self.abort_if_errors(); + return Err(self.fatal("unexpected `{` after qualified path")); } - // Parse struct pattern + // Parse struct pattern try!(self.bump()); let (fields, etc) = try!(self.parse_pat_fields()); try!(self.bump()); @@ -3339,10 +3286,7 @@ impl<'a> Parser<'a> { } token::OpenDelim(token::Paren) => { if qself.is_some() { - let span = self.span; - self.span_err(span, - "unexpected `(` after qualified path"); - self.abort_if_errors(); + return Err(self.fatal("unexpected `(` after qualified path")); } // Parse tuple struct or enum pattern if self.look_ahead(1, |t| *t == token::DotDot) { @@ -3360,13 +3304,13 @@ impl<'a> Parser<'a> { pat = PatEnum(path, Some(args)); } } - _ if qself.is_some() => { - // Parse qualified path - pat = PatQPath(qself.unwrap(), path); - } _ => { - // Parse nullary enum - pat = PatEnum(path, Some(vec![])); + pat = match qself { + // Parse qualified path + Some(qself) => PatQPath(qself, path), + // Parse nullary enum + None => PatEnum(path, Some(vec![])) + }; } } } @@ -3565,7 +3509,7 @@ impl<'a> Parser<'a> { spanned(lo, hi, StmtMac(P(spanned(lo, hi, - MacInvocTT(pth, tts, EMPTY_CTXT))), + Mac_ { path: pth, tts: tts, ctxt: EMPTY_CTXT })), style)) } else { // if it has a special ident, it's definitely an item @@ -3584,7 +3528,8 @@ impl<'a> Parser<'a> { P(spanned(lo, hi, DeclItem( self.mk_item( lo, hi, id /*id is good here*/, - ItemMac(spanned(lo, hi, MacInvocTT(pth, tts, EMPTY_CTXT))), + ItemMac(spanned(lo, hi, + Mac_ { path: pth, tts: tts, ctxt: EMPTY_CTXT })), Inherited, Vec::new(/*no attrs*/))))), ast::DUMMY_NODE_ID)) } @@ -4435,7 +4380,8 @@ impl<'a> Parser<'a> { /// true if we are looking at `const ID`, false for things like `const fn` etc pub fn is_const_item(&mut self) -> bool { self.token.is_keyword(keywords::Const) && - !self.look_ahead(1, |t| t.is_keyword(keywords::Fn)) + !self.look_ahead(1, |t| t.is_keyword(keywords::Fn)) && + !self.look_ahead(1, |t| t.is_keyword(keywords::Unsafe)) } /// parses all the "front matter" for a `fn` declaration, up to @@ -4443,14 +4389,15 @@ impl<'a> Parser<'a> { /// /// - `const fn` /// - `unsafe fn` + /// - `const unsafe fn` /// - `extern fn` /// - etc pub fn parse_fn_front_matter(&mut self) -> PResult<(ast::Constness, ast::Unsafety, abi::Abi)> { let is_const_fn = try!(self.eat_keyword(keywords::Const)); + let unsafety = try!(self.parse_unsafety()); let (constness, unsafety, abi) = if is_const_fn { - (Constness::Const, Unsafety::Normal, abi::Rust) + (Constness::Const, unsafety, abi::Rust) } else { - let unsafety = try!(self.parse_unsafety()); let abi = if try!(self.eat_keyword(keywords::Extern)) { try!(self.parse_opt_abi()).unwrap_or(abi::C) } else { @@ -4532,7 +4479,7 @@ impl<'a> Parser<'a> { let tts = try!(self.parse_seq_to_end(&token::CloseDelim(delim), seq_sep_none(), |p| p.parse_token_tree())); - let m_ = ast::MacInvocTT(pth, tts, EMPTY_CTXT); + let m_ = Mac_ { path: pth, tts: tts, ctxt: EMPTY_CTXT }; let m: ast::Mac = codemap::Spanned { node: m_, span: mk_sp(self.span.lo, self.span.hi) }; @@ -4706,54 +4653,41 @@ impl<'a> Parser<'a> { // Otherwise if we look ahead and see a paren we parse a tuple-style // struct. - let (fields, ctor_id) = if self.token.is_keyword(keywords::Where) { + let vdata = if self.token.is_keyword(keywords::Where) { generics.where_clause = try!(self.parse_where_clause()); if try!(self.eat(&token::Semi)) { // If we see a: `struct Foo where T: Copy;` style decl. - (Vec::new(), Some(ast::DUMMY_NODE_ID)) + VariantData::Unit(ast::DUMMY_NODE_ID) } else { // If we see: `struct Foo where T: Copy { ... }` - (try!(self.parse_record_struct_body(&class_name)), None) + VariantData::Struct(try!(self.parse_record_struct_body()), ast::DUMMY_NODE_ID) } // No `where` so: `struct Foo;` } else if try!(self.eat(&token::Semi) ){ - (Vec::new(), Some(ast::DUMMY_NODE_ID)) + VariantData::Unit(ast::DUMMY_NODE_ID) // Record-style struct definition } else if self.token == token::OpenDelim(token::Brace) { - let fields = try!(self.parse_record_struct_body(&class_name)); - (fields, None) + VariantData::Struct(try!(self.parse_record_struct_body()), ast::DUMMY_NODE_ID) // Tuple-style struct definition with optional where-clause. } else if self.token == token::OpenDelim(token::Paren) { - let fields = try!(self.parse_tuple_struct_body(&class_name, &mut generics)); - (fields, Some(ast::DUMMY_NODE_ID)) + VariantData::Tuple(try!(self.parse_tuple_struct_body(&mut generics)), + ast::DUMMY_NODE_ID) } else { let token_str = self.this_token_to_string(); return Err(self.fatal(&format!("expected `where`, `{{`, `(`, or `;` after struct \ name, found `{}`", token_str))) }; - Ok((class_name, - ItemStruct(P(ast::StructDef { - fields: fields, - ctor_id: ctor_id, - }), generics), - None)) + Ok((class_name, ItemStruct(vdata, generics), None)) } - pub fn parse_record_struct_body(&mut self, - class_name: &ast::Ident) -> PResult> { + pub fn parse_record_struct_body(&mut self) -> PResult> { let mut fields = Vec::new(); if try!(self.eat(&token::OpenDelim(token::Brace)) ){ while self.token != token::CloseDelim(token::Brace) { fields.push(try!(self.parse_struct_decl_field(true))); } - if fields.is_empty() { - return Err(self.fatal(&format!("unit-like struct definition should be \ - written as `struct {};`", - class_name))); - } - try!(self.bump()); } else { let token_str = self.this_token_to_string(); @@ -4766,7 +4700,6 @@ impl<'a> Parser<'a> { } pub fn parse_tuple_struct_body(&mut self, - class_name: &ast::Ident, generics: &mut ast::Generics) -> PResult> { // This is the case where we find `struct Foo(T) where T: Copy;` @@ -4787,12 +4720,6 @@ impl<'a> Parser<'a> { Ok(spanned(lo, p.span.hi, struct_field_)) })); - if fields.is_empty() { - return Err(self.fatal(&format!("unit-like struct definition should be \ - written as `struct {};`", - class_name))); - } - generics.where_clause = try!(self.parse_where_clause()); try!(self.expect(&token::Semi)); Ok(fields) @@ -4858,7 +4785,7 @@ impl<'a> Parser<'a> { let hi = if self.span == codemap::DUMMY_SP { inner_lo } else { - self.span.lo + self.last_span.hi }; Ok(ast::Mod { @@ -5052,9 +4979,8 @@ impl<'a> Parser<'a> { } /// Parse a function declaration from a foreign module - fn parse_item_foreign_fn(&mut self, vis: ast::Visibility, + fn parse_item_foreign_fn(&mut self, vis: ast::Visibility, lo: BytePos, attrs: Vec) -> PResult> { - let lo = self.span.lo; try!(self.expect_keyword(keywords::Fn)); let (ident, mut generics) = try!(self.parse_fn_header()); @@ -5073,10 +4999,8 @@ impl<'a> Parser<'a> { } /// Parse a static item from a foreign module - fn parse_item_foreign_static(&mut self, vis: ast::Visibility, + fn parse_item_foreign_static(&mut self, vis: ast::Visibility, lo: BytePos, attrs: Vec) -> PResult> { - let lo = self.span.lo; - try!(self.expect_keyword(keywords::Static)); let mutbl = try!(self.eat_keyword(keywords::Mut)); @@ -5185,17 +5109,14 @@ impl<'a> Parser<'a> { /// Parse a structure-like enum variant definition /// this should probably be renamed or refactored... - fn parse_struct_def(&mut self) -> PResult> { + fn parse_struct_def(&mut self) -> PResult { let mut fields: Vec = Vec::new(); while self.token != token::CloseDelim(token::Brace) { fields.push(try!(self.parse_struct_decl_field(false))); } try!(self.bump()); - Ok(P(StructDef { - fields: fields, - ctor_id: None, - })) + Ok(VariantData::Struct(fields, ast::DUMMY_NODE_ID)) } /// Parse the part of an "enum" decl following the '{' @@ -5207,25 +5128,13 @@ impl<'a> Parser<'a> { let variant_attrs = self.parse_outer_attributes(); let vlo = self.span.lo; - let vis = try!(self.parse_visibility()); - - let ident; - let kind; - let mut args = Vec::new(); + let struct_def; let mut disr_expr = None; - ident = try!(self.parse_ident()); + let ident = try!(self.parse_ident()); if try!(self.eat(&token::OpenDelim(token::Brace)) ){ // Parse a struct variant. all_nullary = false; - let start_span = self.span; - let struct_def = try!(self.parse_struct_def()); - if struct_def.fields.is_empty() { - self.span_err(start_span, - &format!("unit-like struct variant should be written \ - without braces, as `{},`", - ident)); - } - kind = StructVariantKind(struct_def); + struct_def = try!(self.parse_struct_def()); } else if self.check(&token::OpenDelim(token::Paren)) { all_nullary = false; let arg_tys = try!(self.parse_enum_variant_seq( @@ -5234,28 +5143,29 @@ impl<'a> Parser<'a> { seq_sep_trailing_allowed(token::Comma), |p| p.parse_ty_sum() )); + let mut fields = Vec::new(); for ty in arg_tys { - args.push(ast::VariantArg { + fields.push(Spanned { span: ty.span, node: ast::StructField_ { ty: ty, + kind: ast::UnnamedField(ast::Inherited), + attrs: Vec::new(), id: ast::DUMMY_NODE_ID, - }); + }}); } - kind = TupleVariantKind(args); + struct_def = ast::VariantData::Tuple(fields, ast::DUMMY_NODE_ID); } else if try!(self.eat(&token::Eq) ){ disr_expr = Some(try!(self.parse_expr_nopanic())); any_disr = disr_expr.as_ref().map(|expr| expr.span); - kind = TupleVariantKind(args); + struct_def = ast::VariantData::Unit(ast::DUMMY_NODE_ID); } else { - kind = TupleVariantKind(Vec::new()); + struct_def = ast::VariantData::Unit(ast::DUMMY_NODE_ID); } let vr = ast::Variant_ { name: ident, attrs: variant_attrs, - kind: kind, - id: ast::DUMMY_NODE_ID, + data: struct_def, disr_expr: disr_expr, - vis: vis, }; variants.push(P(spanned(vlo, self.last_span.hi, vr))); @@ -5392,11 +5302,18 @@ impl<'a> Parser<'a> { return Ok(Some(item)); } if try!(self.eat_keyword(keywords::Const) ){ - if self.check_keyword(keywords::Fn) { + if self.check_keyword(keywords::Fn) + || (self.check_keyword(keywords::Unsafe) + && self.look_ahead(1, |t| t.is_keyword(keywords::Fn))) { // CONST FUNCTION ITEM + let unsafety = if try!(self.eat_keyword(keywords::Unsafe) ){ + Unsafety::Unsafe + } else { + Unsafety::Normal + }; try!(self.bump()); let (ident, item_, extra_attrs) = - try!(self.parse_item_fn(Unsafety::Normal, Constness::Const, abi::Rust)); + try!(self.parse_item_fn(unsafety, Constness::Const, abi::Rust)); let last_span = self.last_span; let item = self.mk_item(lo, last_span.hi, @@ -5576,11 +5493,11 @@ impl<'a> Parser<'a> { if self.check_keyword(keywords::Static) { // FOREIGN STATIC ITEM - return Ok(Some(try!(self.parse_item_foreign_static(visibility, attrs)))); + return Ok(Some(try!(self.parse_item_foreign_static(visibility, lo, attrs)))); } if self.check_keyword(keywords::Fn) || self.check_keyword(keywords::Unsafe) { // FOREIGN FUNCTION ITEM - return Ok(Some(try!(self.parse_item_foreign_fn(visibility, attrs)))); + return Ok(Some(try!(self.parse_item_foreign_fn(visibility, lo, attrs)))); } // FIXME #5668: this will occur for a macro invocation: @@ -5628,7 +5545,7 @@ impl<'a> Parser<'a> { seq_sep_none(), |p| p.parse_token_tree())); // single-variant-enum... : - let m = ast::MacInvocTT(pth, tts, EMPTY_CTXT); + let m = Mac_ { path: pth, tts: tts, ctxt: EMPTY_CTXT }; let m: ast::Mac = codemap::Spanned { node: m, span: mk_sp(self.span.lo, self.span.hi) }; @@ -5803,10 +5720,10 @@ impl<'a> Parser<'a> { Option)>> { let ret = match self.token { token::Literal(token::Str_(s), suf) => { - (self.id_to_interned_str(s.ident()), ast::CookedStr, suf) + (self.id_to_interned_str(ast::Ident::with_empty_ctxt(s)), ast::CookedStr, suf) } token::Literal(token::StrRaw(s, n), suf) => { - (self.id_to_interned_str(s.ident()), ast::RawStr(n), suf) + (self.id_to_interned_str(ast::Ident::with_empty_ctxt(s)), ast::RawStr(n), suf) } _ => return Ok(None) }; diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index a392872f75..ba24dc3c0a 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -453,7 +453,7 @@ macro_rules! declare_special_idents_and_keywords {( #[allow(non_upper_case_globals)] pub const $si_static: ast::Ident = ast::Ident { name: ast::Name($si_name), - ctxt: 0, + ctxt: ast::EMPTY_CTXT, }; )* } @@ -462,7 +462,7 @@ macro_rules! declare_special_idents_and_keywords {( use ast; $( #[allow(non_upper_case_globals)] - pub const $si_static: ast::Name = ast::Name($si_name); + pub const $si_static: ast::Name = ast::Name($si_name); )* } @@ -729,19 +729,19 @@ pub fn gensym(s: &str) -> ast::Name { /// Maps a string to an identifier with an empty syntax context. #[inline] pub fn str_to_ident(s: &str) -> ast::Ident { - ast::Ident::new(intern(s)) + ast::Ident::with_empty_ctxt(intern(s)) } /// Maps a string to a gensym'ed identifier. #[inline] pub fn gensym_ident(s: &str) -> ast::Ident { - ast::Ident::new(gensym(s)) + ast::Ident::with_empty_ctxt(gensym(s)) } // create a fresh name that maps to the same string as the old one. // note that this guarantees that str_ptr_eq(ident_to_string(src),interner_get(fresh_name(src))); // that is, that the new name and the old one are connected to ptr_eq strings. -pub fn fresh_name(src: &ast::Ident) -> ast::Name { +pub fn fresh_name(src: ast::Ident) -> ast::Name { let interner = get_ident_interner(); interner.gensym_copy(src.name) // following: debug version. Could work in final except that it's incompatible with @@ -753,7 +753,7 @@ pub fn fresh_name(src: &ast::Ident) -> ast::Name { // create a fresh mark. pub fn fresh_mark() -> ast::Mrk { - gensym("mark").usize() as u32 + gensym("mark").0 } #[cfg(test)] @@ -763,7 +763,7 @@ mod tests { use ext::mtwt; fn mark_ident(id : ast::Ident, m : ast::Mrk) -> ast::Ident { - ast::Ident { name: id.name, ctxt:mtwt::apply_mark(m, id.ctxt) } + ast::Ident::new(id.name, mtwt::apply_mark(m, id.ctxt)) } #[test] fn mtwt_token_eq_test() { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 555fdc1ff8..87cecdba28 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -54,8 +54,8 @@ impl PpAnn for NoAnn {} #[derive(Copy, Clone)] pub struct CurrentCommentAndLiteral { - cur_cmnt: usize, - cur_lit: usize, + pub cur_cmnt: usize, + pub cur_lit: usize, } pub struct State<'a> { @@ -297,7 +297,7 @@ pub fn token_to_string(tok: &Token) -> String { token::NtBlock(ref e) => block_to_string(&**e), token::NtStmt(ref e) => stmt_to_string(&**e), token::NtPat(ref e) => pat_to_string(&**e), - token::NtIdent(ref e, _) => ident_to_string(&**e), + token::NtIdent(ref e, _) => ident_to_string(**e), token::NtTT(ref e) => tt_to_string(&**e), token::NtArm(ref e) => arm_to_string(&*e), token::NtImplItem(ref e) => impl_item_to_string(&**e), @@ -376,8 +376,8 @@ pub fn path_to_string(p: &ast::Path) -> String { to_string(|s| s.print_path(p, false, 0)) } -pub fn ident_to_string(id: &ast::Ident) -> String { - to_string(|s| s.print_ident(*id)) +pub fn ident_to_string(id: ast::Ident) -> String { + to_string(|s| s.print_ident(id)) } pub fn fun_to_string(decl: &ast::FnDecl, @@ -450,43 +450,368 @@ fn needs_parentheses(expr: &ast::Expr) -> bool { } } -impl<'a> State<'a> { - pub fn ibox(&mut self, u: usize) -> io::Result<()> { - self.boxes.push(pp::Breaks::Inconsistent); - pp::ibox(&mut self.s, u) +pub trait PrintState<'a> { + fn writer(&mut self) -> &mut pp::Printer<'a>; + fn boxes(&mut self) -> &mut Vec; + fn comments(&mut self) -> &mut Option>; + fn cur_cmnt_and_lit(&mut self) -> &mut CurrentCommentAndLiteral; + fn literals(&self) -> &Option>; + + fn word_space(&mut self, w: &str) -> io::Result<()> { + try!(word(self.writer(), w)); + space(self.writer()) } - pub fn end(&mut self) -> io::Result<()> { - self.boxes.pop().unwrap(); - pp::end(&mut self.s) + fn popen(&mut self) -> io::Result<()> { word(self.writer(), "(") } + + fn pclose(&mut self) -> io::Result<()> { word(self.writer(), ")") } + + fn is_begin(&mut self) -> bool { + match self.writer().last_token() { + pp::Token::Begin(_) => true, + _ => false, + } } - pub fn cbox(&mut self, u: usize) -> io::Result<()> { - self.boxes.push(pp::Breaks::Consistent); - pp::cbox(&mut self.s, u) + fn is_end(&mut self) -> bool { + match self.writer().last_token() { + pp::Token::End => true, + _ => false, + } + } + + // is this the beginning of a line? + fn is_bol(&mut self) -> bool { + self.writer().last_token().is_eof() || self.writer().last_token().is_hardbreak_tok() + } + + fn hardbreak_if_not_bol(&mut self) -> io::Result<()> { + if !self.is_bol() { + try!(hardbreak(self.writer())) + } + Ok(()) } // "raw box" - pub fn rbox(&mut self, u: usize, b: pp::Breaks) -> io::Result<()> { - self.boxes.push(b); - pp::rbox(&mut self.s, u, b) + fn rbox(&mut self, u: usize, b: pp::Breaks) -> io::Result<()> { + self.boxes().push(b); + pp::rbox(self.writer(), u, b) } - pub fn nbsp(&mut self) -> io::Result<()> { word(&mut self.s, " ") } + fn ibox(&mut self, u: usize) -> io::Result<()> { + self.boxes().push(pp::Breaks::Inconsistent); + pp::ibox(self.writer(), u) + } - pub fn word_nbsp(&mut self, w: &str) -> io::Result<()> { - try!(word(&mut self.s, w)); - self.nbsp() + fn end(&mut self) -> io::Result<()> { + self.boxes().pop().unwrap(); + pp::end(self.writer()) } - pub fn word_space(&mut self, w: &str) -> io::Result<()> { - try!(word(&mut self.s, w)); - space(&mut self.s) + fn commasep(&mut self, b: Breaks, elts: &[T], mut op: F) -> io::Result<()> + where F: FnMut(&mut Self, &T) -> io::Result<()>, + { + try!(self.rbox(0, b)); + let mut first = true; + for elt in elts { + if first { first = false; } else { try!(self.word_space(",")); } + try!(op(self, elt)); + } + self.end() + } + + fn next_lit(&mut self, pos: BytePos) -> Option { + let mut cur_lit = self.cur_cmnt_and_lit().cur_lit; + + let mut result = None; + + if let &Some(ref lits) = self.literals() + { + while cur_lit < lits.len() { + let ltrl = (*lits)[cur_lit].clone(); + if ltrl.pos > pos { break; } + cur_lit += 1; + if ltrl.pos == pos { + result = Some(ltrl); + break; + } + } + } + + self.cur_cmnt_and_lit().cur_lit = cur_lit; + result + } + + 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 + } + } + Ok(()) + } + + fn print_comment(&mut self, + cmnt: &comments::Comment) -> io::Result<()> { + match cmnt.style { + comments::Mixed => { + assert_eq!(cmnt.lines.len(), 1); + try!(zerobreak(self.writer())); + try!(word(self.writer(), &cmnt.lines[0])); + zerobreak(self.writer()) + } + comments::Isolated => { + try!(self.hardbreak_if_not_bol()); + for line in &cmnt.lines { + // Don't print empty lines because they will end up as trailing + // whitespace + if !line.is_empty() { + try!(word(self.writer(), &line[..])); + } + try!(hardbreak(self.writer())); + } + Ok(()) + } + comments::Trailing => { + try!(word(self.writer(), " ")); + if cmnt.lines.len() == 1 { + try!(word(self.writer(), &cmnt.lines[0])); + hardbreak(self.writer()) + } else { + try!(self.ibox(0)); + for line in &cmnt.lines { + if !line.is_empty() { + try!(word(self.writer(), &line[..])); + } + try!(hardbreak(self.writer())); + } + self.end() + } + } + comments::BlankLine => { + // We need to do at least one, possibly two hardbreaks. + let is_semi = match self.writer().last_token() { + pp::Token::String(s, _) => ";" == s, + _ => false + }; + if is_semi || self.is_begin() || self.is_end() { + try!(hardbreak(self.writer())); + } + hardbreak(self.writer()) + } + } + } + + fn next_comment(&mut self) -> Option { + let cur_cmnt = self.cur_cmnt_and_lit().cur_cmnt; + match *self.comments() { + Some(ref cmnts) => { + if cur_cmnt < cmnts.len() { + Some(cmnts[cur_cmnt].clone()) + } else { + None + } + } + _ => None + } + } + + fn print_literal(&mut self, lit: &ast::Lit) -> io::Result<()> { + try!(self.maybe_print_comment(lit.span.lo)); + match self.next_lit(lit.span.lo) { + Some(ref ltrl) => { + return word(self.writer(), &(*ltrl).lit); + } + _ => () + } + match lit.node { + ast::LitStr(ref st, style) => self.print_string(&st, style), + ast::LitByte(byte) => { + let mut res = String::from("b'"); + res.extend(ascii::escape_default(byte).map(|c| c as char)); + res.push('\''); + word(self.writer(), &res[..]) + } + ast::LitChar(ch) => { + let mut res = String::from("'"); + res.extend(ch.escape_default()); + res.push('\''); + word(self.writer(), &res[..]) + } + ast::LitInt(i, t) => { + match t { + ast::SignedIntLit(st, ast::Plus) => { + word(self.writer(), + &ast_util::int_ty_to_string(st, Some(i as i64))) + } + ast::SignedIntLit(st, ast::Minus) => { + let istr = ast_util::int_ty_to_string(st, Some(-(i as i64))); + word(self.writer(), + &format!("-{}", istr)) + } + ast::UnsignedIntLit(ut) => { + word(self.writer(), &ast_util::uint_ty_to_string(ut, Some(i))) + } + ast::UnsuffixedIntLit(ast::Plus) => { + word(self.writer(), &format!("{}", i)) + } + ast::UnsuffixedIntLit(ast::Minus) => { + word(self.writer(), &format!("-{}", i)) + } + } + } + ast::LitFloat(ref f, t) => { + word(self.writer(), + &format!( + "{}{}", + &f, + &ast_util::float_ty_to_string(t))) + } + ast::LitFloatUnsuffixed(ref f) => word(self.writer(), &f[..]), + ast::LitBool(val) => { + if val { word(self.writer(), "true") } else { word(self.writer(), "false") } + } + ast::LitByteStr(ref v) => { + let mut escaped: String = String::new(); + for &ch in v.iter() { + escaped.extend(ascii::escape_default(ch) + .map(|c| c as char)); + } + word(self.writer(), &format!("b\"{}\"", escaped)) + } + } + } + + fn print_string(&mut self, st: &str, + style: ast::StrStyle) -> io::Result<()> { + let st = match style { + ast::CookedStr => { + (format!("\"{}\"", st.escape_default())) + } + ast::RawStr(n) => { + (format!("r{delim}\"{string}\"{delim}", + delim=repeat("#", n), + string=st)) + } + }; + word(self.writer(), &st[..]) + } + + fn print_inner_attributes(&mut self, + attrs: &[ast::Attribute]) -> io::Result<()> { + let mut count = 0; + for attr in attrs { + match attr.node.style { + ast::AttrStyle::Inner => { + try!(self.print_attribute(attr)); + count += 1; + } + _ => {/* fallthrough */ } + } + } + if count > 0 { + try!(self.hardbreak_if_not_bol()); + } + Ok(()) + } + + fn print_outer_attributes(&mut self, + attrs: &[ast::Attribute]) -> io::Result<()> { + let mut count = 0; + for attr in attrs { + match attr.node.style { + ast::AttrStyle::Outer => { + try!(self.print_attribute(attr)); + count += 1; + } + _ => {/* fallthrough */ } + } + } + if count > 0 { + try!(self.hardbreak_if_not_bol()); + } + Ok(()) } - pub fn popen(&mut self) -> io::Result<()> { word(&mut self.s, "(") } + fn print_attribute(&mut self, attr: &ast::Attribute) -> io::Result<()> { + try!(self.hardbreak_if_not_bol()); + try!(self.maybe_print_comment(attr.span.lo)); + if attr.node.is_sugared_doc { + word(self.writer(), &attr.value_str().unwrap()) + } else { + match attr.node.style { + ast::AttrStyle::Inner => try!(word(self.writer(), "#![")), + ast::AttrStyle::Outer => try!(word(self.writer(), "#[")), + } + try!(self.print_meta_item(&*attr.meta())); + word(self.writer(), "]") + } + } - pub fn pclose(&mut self) -> io::Result<()> { word(&mut self.s, ")") } + fn print_meta_item(&mut self, item: &ast::MetaItem) -> io::Result<()> { + try!(self.ibox(indent_unit)); + match item.node { + ast::MetaWord(ref name) => { + try!(word(self.writer(), &name)); + } + ast::MetaNameValue(ref name, ref value) => { + try!(self.word_space(&name[..])); + try!(self.word_space("=")); + try!(self.print_literal(value)); + } + ast::MetaList(ref name, ref items) => { + try!(word(self.writer(), &name)); + try!(self.popen()); + try!(self.commasep(Consistent, + &items[..], + |s, i| s.print_meta_item(&**i))); + try!(self.pclose()); + } + } + self.end() + } +} + +impl<'a> PrintState<'a> for State<'a> { + fn writer(&mut self) -> &mut pp::Printer<'a> { + &mut self.s + } + + fn boxes(&mut self) -> &mut Vec { + &mut self.boxes + } + + fn comments(&mut self) -> &mut Option> { + &mut self.comments + } + + fn cur_cmnt_and_lit(&mut self) -> &mut CurrentCommentAndLiteral { + &mut self.cur_cmnt_and_lit + } + + fn literals(&self) -> &Option> { + &self.literals + } +} + +impl<'a> State<'a> { + pub fn cbox(&mut self, u: usize) -> io::Result<()> { + self.boxes.push(pp::Breaks::Consistent); + pp::cbox(&mut self.s, u) + } + + pub fn nbsp(&mut self) -> io::Result<()> { word(&mut self.s, " ") } + + pub fn word_nbsp(&mut self, w: &str) -> io::Result<()> { + try!(word(&mut self.s, w)); + self.nbsp() + } pub fn head(&mut self, w: &str) -> io::Result<()> { // outer-box is consistent @@ -523,25 +848,6 @@ impl<'a> State<'a> { self.bclose_(span, indent_unit) } - pub fn is_begin(&mut self) -> bool { - match self.s.last_token() { - pp::Token::Begin(_) => true, - _ => false, - } - } - - pub fn is_end(&mut self) -> bool { - match self.s.last_token() { - pp::Token::End => true, - _ => false, - } - } - - // is this the beginning of a line? - pub fn is_bol(&mut self) -> bool { - self.s.last_token().is_eof() || self.s.last_token().is_hardbreak_tok() - } - pub fn in_cbox(&self) -> bool { match self.boxes.last() { Some(&last_box) => last_box == pp::Breaks::Consistent, @@ -549,12 +855,6 @@ impl<'a> State<'a> { } } - pub fn hardbreak_if_not_bol(&mut self) -> io::Result<()> { - if !self.is_bol() { - try!(hardbreak(&mut self.s)) - } - Ok(()) - } pub fn space_if_not_bol(&mut self) -> io::Result<()> { if !self.is_bol() { try!(space(&mut self.s)); } Ok(()) @@ -584,17 +884,6 @@ impl<'a> State<'a> { word(&mut self.s, "*/") } - pub fn commasep(&mut self, b: Breaks, elts: &[T], mut op: F) -> io::Result<()> where - F: FnMut(&mut State, &T) -> io::Result<()>, - { - try!(self.rbox(0, b)); - let mut first = true; - for elt in elts { - if first { first = false; } else { try!(self.word_space(",")); } - try!(op(self, elt)); - } - self.end() - } pub fn commasep_cmnt(&mut self, @@ -933,7 +1222,7 @@ impl<'a> State<'a> { } ast::ItemStruct(ref struct_def, ref generics) => { try!(self.head(&visibility_qualified(item.vis,"struct"))); - try!(self.print_struct(&**struct_def, generics, item.ident, item.span)); + try!(self.print_struct(&struct_def, generics, item.ident, item.span, true)); } ast::ItemDefaultImpl(unsafety, ref trait_ref) => { @@ -1017,16 +1306,14 @@ impl<'a> State<'a> { } try!(self.bclose(item.span)); } - // I think it's reasonable to hide the context here: - ast::ItemMac(codemap::Spanned { node: ast::MacInvocTT(ref pth, ref tts, _), - ..}) => { + ast::ItemMac(codemap::Spanned { ref node, .. }) => { try!(self.print_visibility(item.vis)); - try!(self.print_path(pth, false, 0)); + try!(self.print_path(&node.path, false, 0)); try!(word(&mut self.s, "! ")); try!(self.print_ident(item.ident)); try!(self.cbox(indent_unit)); try!(self.popen()); - try!(self.print_tts(&tts[..])); + try!(self.print_tts(&node.tts[..])); try!(self.pclose()); try!(word(&mut self.s, ";")); try!(self.end()); @@ -1097,17 +1384,18 @@ impl<'a> State<'a> { } pub fn print_struct(&mut self, - struct_def: &ast::StructDef, + struct_def: &ast::VariantData, generics: &ast::Generics, ident: ast::Ident, - span: codemap::Span) -> io::Result<()> { + span: codemap::Span, + print_finalizer: bool) -> io::Result<()> { try!(self.print_ident(ident)); try!(self.print_generics(generics)); - if ast_util::struct_def_is_tuple_like(struct_def) { - if !struct_def.fields.is_empty() { + if !struct_def.is_struct() { + if struct_def.is_tuple() { try!(self.popen()); try!(self.commasep( - Inconsistent, &struct_def.fields, + Inconsistent, struct_def.fields(), |s, field| { match field.node.kind { ast::NamedField(..) => panic!("unexpected named field"), @@ -1122,7 +1410,9 @@ impl<'a> State<'a> { try!(self.pclose()); } try!(self.print_where_clause(&generics.where_clause)); - try!(word(&mut self.s, ";")); + if print_finalizer { + try!(word(&mut self.s, ";")); + } try!(self.end()); self.end() // close the outer-box } else { @@ -1131,7 +1421,7 @@ impl<'a> State<'a> { try!(self.bopen()); try!(self.hardbreak_if_not_bol()); - for field in &struct_def.fields { + for field in struct_def.fields() { match field.node.kind { ast::UnnamedField(..) => panic!("unexpected unnamed field"), ast::NamedField(ident, visibility) => { @@ -1217,24 +1507,9 @@ impl<'a> State<'a> { } pub fn print_variant(&mut self, v: &ast::Variant) -> io::Result<()> { - try!(self.print_visibility(v.node.vis)); - match v.node.kind { - ast::TupleVariantKind(ref args) => { - try!(self.print_ident(v.node.name)); - if !args.is_empty() { - try!(self.popen()); - try!(self.commasep(Consistent, - &args[..], - |s, arg| s.print_type(&*arg.ty))); - try!(self.pclose()); - } - } - ast::StructVariantKind(ref struct_def) => { - try!(self.head("")); - let generics = ast_util::empty_generics(); - try!(self.print_struct(&**struct_def, &generics, v.node.name, v.span)); - } - } + try!(self.head("")); + let generics = ast_util::empty_generics(); + try!(self.print_struct(&v.node.data, &generics, v.node.name, v.span, false)); match v.node.disr_expr { Some(ref d) => { try!(space(&mut self.s)); @@ -1310,14 +1585,13 @@ impl<'a> State<'a> { ast::TypeImplItem(ref ty) => { try!(self.print_associated_type(ii.ident, None, Some(ty))); } - ast::MacImplItem(codemap::Spanned { node: ast::MacInvocTT(ref pth, ref tts, _), - ..}) => { + ast::MacImplItem(codemap::Spanned { ref node, .. }) => { // code copied from ItemMac: - try!(self.print_path(pth, false, 0)); + try!(self.print_path(&node.path, false, 0)); try!(word(&mut self.s, "! ")); try!(self.cbox(indent_unit)); try!(self.popen()); - try!(self.print_tts(&tts[..])); + try!(self.print_tts(&node.tts[..])); try!(self.pclose()); try!(word(&mut self.s, ";")); try!(self.end()) @@ -1326,58 +1600,6 @@ impl<'a> State<'a> { self.ann.post(self, NodeSubItem(ii.id)) } - pub fn print_outer_attributes(&mut self, - attrs: &[ast::Attribute]) -> io::Result<()> { - let mut count = 0; - for attr in attrs { - match attr.node.style { - ast::AttrOuter => { - try!(self.print_attribute(attr)); - count += 1; - } - _ => {/* fallthrough */ } - } - } - if count > 0 { - try!(self.hardbreak_if_not_bol()); - } - Ok(()) - } - - pub fn print_inner_attributes(&mut self, - attrs: &[ast::Attribute]) -> io::Result<()> { - let mut count = 0; - for attr in attrs { - match attr.node.style { - ast::AttrInner => { - try!(self.print_attribute(attr)); - count += 1; - } - _ => {/* fallthrough */ } - } - } - if count > 0 { - try!(self.hardbreak_if_not_bol()); - } - Ok(()) - } - - pub fn print_attribute(&mut self, attr: &ast::Attribute) -> io::Result<()> { - try!(self.hardbreak_if_not_bol()); - try!(self.maybe_print_comment(attr.span.lo)); - if attr.node.is_sugared_doc { - word(&mut self.s, &attr.value_str().unwrap()) - } else { - match attr.node.style { - ast::AttrInner => try!(word(&mut self.s, "#![")), - ast::AttrOuter => try!(word(&mut self.s, "#[")), - } - try!(self.print_meta_item(&*attr.meta())); - word(&mut self.s, "]") - } - } - - pub fn print_stmt(&mut self, st: &ast::Stmt) -> io::Result<()> { try!(self.maybe_print_comment(st.span.lo)); match st.node { @@ -1437,8 +1659,8 @@ impl<'a> State<'a> { attrs: &[ast::Attribute], close_box: bool) -> io::Result<()> { match blk.rules { - ast::UnsafeBlock(..) | ast::PushUnsafeBlock(..) => try!(self.word_space("unsafe")), - ast::DefaultBlock | ast::PopUnsafeBlock(..) => () + ast::UnsafeBlock(..) => try!(self.word_space("unsafe")), + ast::DefaultBlock => () } try!(self.maybe_print_comment(blk.span.lo)); try!(self.ann.pre(self, NodeBlock(blk))); @@ -1528,23 +1750,18 @@ impl<'a> State<'a> { pub fn print_mac(&mut self, m: &ast::Mac, delim: token::DelimToken) -> io::Result<()> { - match m.node { - // I think it's reasonable to hide the ctxt here: - ast::MacInvocTT(ref pth, ref tts, _) => { - try!(self.print_path(pth, false, 0)); - try!(word(&mut self.s, "!")); - match delim { - token::Paren => try!(self.popen()), - token::Bracket => try!(word(&mut self.s, "[")), - token::Brace => try!(self.bopen()), - } - try!(self.print_tts(tts)); - match delim { - token::Paren => self.pclose(), - token::Bracket => word(&mut self.s, "]"), - token::Brace => self.bclose(m.span), - } - } + try!(self.print_path(&m.node.path, false, 0)); + try!(word(&mut self.s, "!")); + match delim { + token::Paren => try!(self.popen()), + token::Bracket => try!(word(&mut self.s, "[")), + token::Brace => try!(self.bopen()), + } + try!(self.print_tts(&m.node.tts)); + match delim { + token::Paren => self.pclose(), + token::Bracket => word(&mut self.s, "]"), + token::Brace => self.bclose(m.span), } } @@ -1582,13 +1799,12 @@ impl<'a> State<'a> { Ok(()) } - fn print_expr_box(&mut self, - place: &Option>, - expr: &ast::Expr) -> io::Result<()> { - try!(word(&mut self.s, "box")); - try!(word(&mut self.s, "(")); - try!(place.as_ref().map_or(Ok(()), |e|self.print_expr(&**e))); - try!(self.word_space(")")); + fn print_expr_in_place(&mut self, + place: &ast::Expr, + expr: &ast::Expr) -> io::Result<()> { + try!(self.word_space("in")); + try!(self.print_expr(place)); + try!(space(&mut self.s)); self.print_expr(expr) } @@ -1617,34 +1833,34 @@ impl<'a> State<'a> { fields: &[ast::Field], wth: &Option>) -> io::Result<()> { try!(self.print_path(path, true, 0)); - if !(fields.is_empty() && wth.is_none()) { - try!(word(&mut self.s, "{")); - try!(self.commasep_cmnt( - Consistent, - &fields[..], - |s, field| { - try!(s.ibox(indent_unit)); - try!(s.print_ident(field.ident.node)); - try!(s.word_space(":")); - try!(s.print_expr(&*field.expr)); - s.end() - }, - |f| f.span)); - match *wth { - Some(ref expr) => { - try!(self.ibox(indent_unit)); - if !fields.is_empty() { - try!(word(&mut self.s, ",")); - try!(space(&mut self.s)); - } - try!(word(&mut self.s, "..")); - try!(self.print_expr(&**expr)); - try!(self.end()); + try!(word(&mut self.s, "{")); + try!(self.commasep_cmnt( + Consistent, + &fields[..], + |s, field| { + try!(s.ibox(indent_unit)); + try!(s.print_ident(field.ident.node)); + try!(s.word_space(":")); + try!(s.print_expr(&*field.expr)); + s.end() + }, + |f| f.span)); + match *wth { + Some(ref expr) => { + try!(self.ibox(indent_unit)); + if !fields.is_empty() { + try!(word(&mut self.s, ",")); + try!(space(&mut self.s)); } - _ => try!(word(&mut self.s, ",")), + try!(word(&mut self.s, "..")); + try!(self.print_expr(&**expr)); + try!(self.end()); + } + _ => if !fields.is_empty() { + try!(word(&mut self.s, ",")) } - try!(word(&mut self.s, "}")); } + try!(word(&mut self.s, "}")); Ok(()) } @@ -1719,8 +1935,12 @@ impl<'a> State<'a> { try!(self.ibox(indent_unit)); try!(self.ann.pre(self, NodeExpr(expr))); match expr.node { - ast::ExprBox(ref place, ref expr) => { - try!(self.print_expr_box(place, &**expr)); + ast::ExprBox(ref expr) => { + try!(self.word_space("box")); + try!(self.print_expr(expr)); + } + ast::ExprInPlace(ref place, ref expr) => { + try!(self.print_expr_in_place(place, expr)); } ast::ExprVec(ref exprs) => { try!(self.print_expr_vec(&exprs[..])); @@ -1813,7 +2033,7 @@ impl<'a> State<'a> { try!(space(&mut self.s)); try!(self.print_block(&**blk)); } - ast::ExprMatch(ref expr, ref arms, _) => { + ast::ExprMatch(ref expr, ref arms) => { try!(self.cbox(indent_unit)); try!(self.ibox(4)); try!(self.word_nbsp("match")); @@ -1980,7 +2200,7 @@ impl<'a> State<'a> { if a.alignstack { options.push("alignstack"); } - if a.dialect == ast::AsmDialect::AsmIntel { + if a.dialect == ast::AsmDialect::Intel { options.push("intel"); } @@ -2620,35 +2840,11 @@ impl<'a> State<'a> { Ok(()) } - pub fn print_meta_item(&mut self, item: &ast::MetaItem) -> io::Result<()> { - try!(self.ibox(indent_unit)); - match item.node { - ast::MetaWord(ref name) => { - try!(word(&mut self.s, &name)); - } - ast::MetaNameValue(ref name, ref value) => { - try!(self.word_space(&name[..])); - try!(self.word_space("=")); - try!(self.print_literal(value)); - } - ast::MetaList(ref name, ref items) => { - try!(word(&mut self.s, &name)); - try!(self.popen()); - try!(self.commasep(Consistent, - &items[..], - |s, i| s.print_meta_item(&**i))); - try!(self.pclose()); - } - } - self.end() - } - pub fn print_view_path(&mut self, vp: &ast::ViewPath) -> io::Result<()> { match vp.node { ast::ViewPathSimple(ident, ref path) => { try!(self.print_path(path, false, 0)); - // FIXME(#6993) can't compare identifiers directly here if path.segments.last().unwrap().identifier.name != ident.name { try!(space(&mut self.s)); @@ -2832,181 +3028,6 @@ impl<'a> State<'a> { Ok(()) } - pub fn print_literal(&mut self, lit: &ast::Lit) -> io::Result<()> { - try!(self.maybe_print_comment(lit.span.lo)); - match self.next_lit(lit.span.lo) { - Some(ref ltrl) => { - return word(&mut self.s, &(*ltrl).lit); - } - _ => () - } - match lit.node { - ast::LitStr(ref st, style) => self.print_string(&st, style), - ast::LitByte(byte) => { - let mut res = String::from("b'"); - res.extend(ascii::escape_default(byte).map(|c| c as char)); - res.push('\''); - word(&mut self.s, &res[..]) - } - ast::LitChar(ch) => { - let mut res = String::from("'"); - res.extend(ch.escape_default()); - res.push('\''); - word(&mut self.s, &res[..]) - } - ast::LitInt(i, t) => { - match t { - ast::SignedIntLit(st, ast::Plus) => { - word(&mut self.s, - &ast_util::int_ty_to_string(st, Some(i as i64))) - } - ast::SignedIntLit(st, ast::Minus) => { - let istr = ast_util::int_ty_to_string(st, Some(-(i as i64))); - word(&mut self.s, - &format!("-{}", istr)) - } - ast::UnsignedIntLit(ut) => { - word(&mut self.s, &ast_util::uint_ty_to_string(ut, Some(i))) - } - ast::UnsuffixedIntLit(ast::Plus) => { - word(&mut self.s, &format!("{}", i)) - } - ast::UnsuffixedIntLit(ast::Minus) => { - word(&mut self.s, &format!("-{}", i)) - } - } - } - ast::LitFloat(ref f, t) => { - word(&mut self.s, - &format!( - "{}{}", - &f, - &ast_util::float_ty_to_string(t))) - } - ast::LitFloatUnsuffixed(ref f) => word(&mut self.s, &f[..]), - ast::LitBool(val) => { - if val { word(&mut self.s, "true") } else { word(&mut self.s, "false") } - } - ast::LitByteStr(ref v) => { - let mut escaped: String = String::new(); - for &ch in v.iter() { - escaped.extend(ascii::escape_default(ch) - .map(|c| c as char)); - } - word(&mut self.s, &format!("b\"{}\"", escaped)) - } - } - } - - pub fn next_lit(&mut self, pos: BytePos) -> Option { - match self.literals { - Some(ref lits) => { - while self.cur_cmnt_and_lit.cur_lit < lits.len() { - let ltrl = (*lits)[self.cur_cmnt_and_lit.cur_lit].clone(); - if ltrl.pos > pos { return None; } - self.cur_cmnt_and_lit.cur_lit += 1; - if ltrl.pos == pos { return Some(ltrl); } - } - None - } - _ => None - } - } - - pub 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 - } - } - Ok(()) - } - - pub fn print_comment(&mut self, - cmnt: &comments::Comment) -> io::Result<()> { - match cmnt.style { - comments::Mixed => { - assert_eq!(cmnt.lines.len(), 1); - try!(zerobreak(&mut self.s)); - try!(word(&mut self.s, &cmnt.lines[0])); - zerobreak(&mut self.s) - } - comments::Isolated => { - try!(self.hardbreak_if_not_bol()); - for line in &cmnt.lines { - // Don't print empty lines because they will end up as trailing - // whitespace - if !line.is_empty() { - try!(word(&mut self.s, &line[..])); - } - try!(hardbreak(&mut self.s)); - } - Ok(()) - } - comments::Trailing => { - try!(word(&mut self.s, " ")); - if cmnt.lines.len() == 1 { - try!(word(&mut self.s, &cmnt.lines[0])); - hardbreak(&mut self.s) - } else { - try!(self.ibox(0)); - for line in &cmnt.lines { - if !line.is_empty() { - try!(word(&mut self.s, &line[..])); - } - try!(hardbreak(&mut self.s)); - } - self.end() - } - } - comments::BlankLine => { - // We need to do at least one, possibly two hardbreaks. - let is_semi = match self.s.last_token() { - pp::Token::String(s, _) => ";" == s, - _ => false - }; - if is_semi || self.is_begin() || self.is_end() { - try!(hardbreak(&mut self.s)); - } - hardbreak(&mut self.s) - } - } - } - - pub fn print_string(&mut self, st: &str, - style: ast::StrStyle) -> io::Result<()> { - let st = match style { - ast::CookedStr => { - (format!("\"{}\"", st.escape_default())) - } - ast::RawStr(n) => { - (format!("r{delim}\"{string}\"{delim}", - delim=repeat("#", n), - string=st)) - } - }; - word(&mut self.s, &st[..]) - } - - pub fn next_comment(&mut self) -> Option { - match self.comments { - Some(ref cmnts) => { - if self.cur_cmnt_and_lit.cur_cmnt < cmnts.len() { - Some(cmnts[self.cur_cmnt_and_lit.cur_cmnt].clone()) - } else { - None - } - } - _ => None - } - } - pub fn print_opt_abi_and_extern_if_nondefault(&mut self, opt_abi: Option) -> io::Result<()> { @@ -3037,13 +3058,14 @@ impl<'a> State<'a> { abi: abi::Abi, vis: ast::Visibility) -> io::Result<()> { try!(word(&mut self.s, &visibility_qualified(vis, ""))); - try!(self.print_unsafety(unsafety)); match constness { ast::Constness::NotConst => {} ast::Constness::Const => try!(self.word_nbsp("const")) } + try!(self.print_unsafety(unsafety)); + if abi != abi::Rust { try!(self.word_nbsp("extern")); try!(self.word_nbsp(&abi.to_string())); @@ -3096,14 +3118,12 @@ mod tests { name: ident, attrs: Vec::new(), // making this up as I go.... ? - kind: ast::TupleVariantKind(Vec::new()), - id: 0, + data: ast::VariantData::Unit(ast::DUMMY_NODE_ID), disr_expr: None, - vis: ast::Public, }); let varstr = variant_to_string(&var); - assert_eq!(varstr, "pub principal_skinner"); + assert_eq!(varstr, "principal_skinner"); } #[test] diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index d6974abd39..345adff234 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -154,7 +154,7 @@ impl fold::Folder for PreludeInjector { span: self.span, node: ast::Attribute_ { id: attr::mk_attr_id(), - style: ast::AttrOuter, + style: ast::AttrStyle::Outer, value: P(ast::MetaItem { span: self.span, node: ast::MetaWord(special_idents::prelude_import.name.as_str()), diff --git a/src/libsyntax/util/interner.rs b/src/libsyntax/util/interner.rs index 7ae9e4646e..6e9c161293 100644 --- a/src/libsyntax/util/interner.rs +++ b/src/libsyntax/util/interner.rs @@ -69,7 +69,7 @@ impl Interner { pub fn get(&self, idx: Name) -> T { let vect = self.vect.borrow(); - (*vect)[idx.usize()].clone() + (*vect)[idx.0 as usize].clone() } pub fn len(&self) -> usize { @@ -196,13 +196,13 @@ impl StrInterner { let new_idx = Name(self.len() as u32); // leave out of map to avoid colliding let mut vect = self.vect.borrow_mut(); - let existing = (*vect)[idx.usize()].clone(); + let existing = (*vect)[idx.0 as usize].clone(); vect.push(existing); new_idx } pub fn get(&self, idx: Name) -> RcStr { - (*self.vect.borrow())[idx.usize()].clone() + (*self.vect.borrow())[idx.0 as usize].clone() } pub fn len(&self) -> usize { diff --git a/src/libsyntax/util/small_vector.rs b/src/libsyntax/util/small_vector.rs index 5353d12b67..d65e37fd2a 100644 --- a/src/libsyntax/util/small_vector.rs +++ b/src/libsyntax/util/small_vector.rs @@ -65,7 +65,6 @@ impl SmallVector { result } One(ref v) => { - // FIXME: Could be replaced with `slice::ref_slice(v)` when it is stable. unsafe { slice::from_raw_parts(v, 1) } } Many(ref vs) => vs @@ -129,7 +128,7 @@ impl SmallVector { } /// Deprecated: use `into_iter`. - #[unstable(feature = "rustc_private")] + #[unstable(feature = "rustc_private", issue = "0")] #[deprecated(since = "1.0.0", reason = "use into_iter")] pub fn move_iter(self) -> IntoIter { self.into_iter() diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 8365a7375c..1614d7d451 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -1,4 +1,4 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -25,10 +25,7 @@ use abi::Abi; use ast::*; -use ast; use codemap::Span; -use ptr::P; -use owned_slice::OwnedSlice; #[derive(Copy, Clone, PartialEq, Eq)] pub enum FnKind<'a> { @@ -56,7 +53,7 @@ pub trait Visitor<'v> : Sized { // Nothing to do. } fn visit_ident(&mut self, span: Span, ident: Ident) { - self.visit_name(span, ident.name); + walk_ident(self, span, ident); } fn visit_mod(&mut self, m: &'v Mod, _s: Span, _n: NodeId) { walk_mod(self, m) } fn visit_foreign_item(&mut self, i: &'v ForeignItem) { walk_foreign_item(self, i) } @@ -83,32 +80,20 @@ pub trait Visitor<'v> : Sized { fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef, m: &'v TraitBoundModifier) { walk_poly_trait_ref(self, t, m) } - fn visit_struct_def(&mut self, s: &'v StructDef, _: Ident, _: &'v Generics, _: NodeId) { + fn visit_variant_data(&mut self, s: &'v VariantData, _: Ident, + _: &'v Generics, _: NodeId, _: Span) { walk_struct_def(self, s) } fn visit_struct_field(&mut self, s: &'v StructField) { walk_struct_field(self, s) } fn visit_enum_def(&mut self, enum_definition: &'v EnumDef, - generics: &'v Generics) { - walk_enum_def(self, enum_definition, generics) + generics: &'v Generics, item_id: NodeId, _: Span) { + walk_enum_def(self, enum_definition, generics, item_id) } - - fn visit_variant(&mut self, v: &'v Variant, g: &'v Generics) { walk_variant(self, v, g) } - - /// Visits an optional reference to a lifetime. The `span` is the span of some surrounding - /// reference should opt_lifetime be None. - fn visit_opt_lifetime_ref(&mut self, - _span: Span, - opt_lifetime: &'v Option) { - match *opt_lifetime { - Some(ref l) => self.visit_lifetime_ref(l), - None => () - } - } - fn visit_lifetime_bound(&mut self, lifetime: &'v Lifetime) { - walk_lifetime_bound(self, lifetime) + fn visit_variant(&mut self, v: &'v Variant, g: &'v Generics, item_id: NodeId) { + walk_variant(self, v, g, item_id) } - fn visit_lifetime_ref(&mut self, lifetime: &'v Lifetime) { - walk_lifetime_ref(self, lifetime) + fn visit_lifetime(&mut self, lifetime: &'v Lifetime) { + walk_lifetime(self, lifetime) } fn visit_lifetime_def(&mut self, lifetime: &'v LifetimeDef) { walk_lifetime_def(self, lifetime) @@ -124,9 +109,12 @@ pub trait Visitor<'v> : Sized { // definition in your trait impl: // visit::walk_mac(self, _mac) } - fn visit_path(&mut self, path: &'v Path, _id: ast::NodeId) { + fn visit_path(&mut self, path: &'v Path, _id: NodeId) { walk_path(self, path) } + fn visit_path_list_item(&mut self, prefix: &'v Path, item: &'v PathListItem) { + walk_path_list_item(self, prefix, item) + } fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v PathSegment) { walk_path_segment(self, path_span, path_segment) } @@ -137,53 +125,88 @@ pub trait Visitor<'v> : Sized { walk_assoc_type_binding(self, type_binding) } fn visit_attribute(&mut self, _attr: &'v Attribute) {} + fn visit_macro_def(&mut self, macro_def: &'v MacroDef) { + walk_macro_def(self, macro_def) + } } -pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate) { - visitor.visit_mod(&krate.module, krate.span, CRATE_NODE_ID); - for attr in &krate.attrs { - visitor.visit_attribute(attr); +#[macro_export] +macro_rules! walk_list { + ($visitor: expr, $method: ident, $list: expr) => { + for elem in $list { + $visitor.$method(elem) + } + }; + ($visitor: expr, $method: ident, $list: expr, $($extra_args: expr),*) => { + for elem in $list { + $visitor.$method(elem, $($extra_args,)*) + } } } -pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod) { - for item in &module.items { - visitor.visit_item(&**item) +pub fn walk_opt_name<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_name: Option) { + for name in opt_name { + visitor.visit_name(span, name); } } -pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) { - visitor.visit_pat(&*local.pat); - walk_ty_opt(visitor, &local.ty); - walk_expr_opt(visitor, &local.init); +pub fn walk_opt_ident<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_ident: Option) { + for ident in opt_ident { + visitor.visit_ident(span, ident); + } } -pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V, - lifetime_def: &'v LifetimeDef) { - visitor.visit_name(lifetime_def.lifetime.span, lifetime_def.lifetime.name); - for bound in &lifetime_def.bounds { - visitor.visit_lifetime_bound(bound); - } +pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, ident: Ident) { + visitor.visit_name(span, ident.name); +} + +pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate) { + visitor.visit_mod(&krate.module, krate.span, CRATE_NODE_ID); + walk_list!(visitor, visit_attribute, &krate.attrs); + walk_list!(visitor, visit_macro_def, &krate.exported_macros); +} + +pub fn walk_macro_def<'v, V: Visitor<'v>>(visitor: &mut V, macro_def: &'v MacroDef) { + visitor.visit_ident(macro_def.span, macro_def.ident); + walk_opt_ident(visitor, macro_def.span, macro_def.imported_from); + walk_list!(visitor, visit_attribute, ¯o_def.attrs); } -pub fn walk_lifetime_bound<'v, V: Visitor<'v>>(visitor: &mut V, - lifetime_ref: &'v Lifetime) { - visitor.visit_lifetime_ref(lifetime_ref) +pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod) { + walk_list!(visitor, visit_item, &module.items); } -pub fn walk_lifetime_ref<'v, V: Visitor<'v>>(visitor: &mut V, - lifetime_ref: &'v Lifetime) { - visitor.visit_name(lifetime_ref.span, lifetime_ref.name) +pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) { + visitor.visit_pat(&local.pat); + walk_list!(visitor, visit_ty, &local.ty); + walk_list!(visitor, visit_expr, &local.init); +} + +pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) { + visitor.visit_name(lifetime.span, lifetime.name); +} + +pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V, + lifetime_def: &'v LifetimeDef) { + visitor.visit_lifetime(&lifetime_def.lifetime); + walk_list!(visitor, visit_lifetime, &lifetime_def.bounds); } pub fn walk_explicit_self<'v, V: Visitor<'v>>(visitor: &mut V, explicit_self: &'v ExplicitSelf) { match explicit_self.node { - SelfStatic | SelfValue(_) => {}, - SelfRegion(ref lifetime, _, _) => { - visitor.visit_opt_lifetime_ref(explicit_self.span, lifetime) + SelfStatic => {}, + SelfValue(ident) => { + visitor.visit_ident(explicit_self.span, ident) + } + SelfRegion(ref opt_lifetime, _, ident) => { + visitor.visit_ident(explicit_self.span, ident); + walk_list!(visitor, visit_lifetime, opt_lifetime); + } + SelfExplicit(ref typ, ident) => { + visitor.visit_ident(explicit_self.span, ident); + visitor.visit_ty(typ) } - SelfExplicit(ref typ, _) => visitor.visit_ty(&**typ), } } @@ -192,7 +215,7 @@ pub fn walk_poly_trait_ref<'v, V>(visitor: &mut V, _modifier: &'v TraitBoundModifier) where V: Visitor<'v> { - walk_lifetime_decls_helper(visitor, &trait_ref.bound_lifetimes); + walk_list!(visitor, visit_lifetime_def, &trait_ref.bound_lifetimes); visitor.visit_trait_ref(&trait_ref.trait_ref); } @@ -206,7 +229,9 @@ pub fn walk_trait_ref<'v,V>(visitor: &mut V, pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { visitor.visit_ident(item.span, item.ident); match item.node { - ItemExternCrate(..) => {} + ItemExternCrate(opt_name) => { + walk_opt_name(visitor, item.span, opt_name) + } ItemUse(ref vp) => { match vp.node { ViewPathSimple(ident, ref path) => { @@ -217,38 +242,26 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { visitor.visit_path(path, item.id); } ViewPathList(ref prefix, ref list) => { - for id in list { - match id.node { - PathListIdent { name, rename, .. } => { - visitor.visit_ident(id.span, name); - if let Some(ident) = rename { - visitor.visit_ident(id.span, ident); - } - } - PathListMod { rename, .. } => { - if let Some(ident) = rename { - visitor.visit_ident(id.span, ident); - } - } + if !list.is_empty() { + for item in list { + visitor.visit_path_list_item(prefix, item) } + } else { + visitor.visit_path(prefix, item.id); } - - // Note that the `prefix` here is not a complete - // path, so we don't use `visit_path`. - walk_path(visitor, prefix); } } } ItemStatic(ref typ, _, ref expr) | ItemConst(ref typ, ref expr) => { - visitor.visit_ty(&**typ); - visitor.visit_expr(&**expr); + visitor.visit_ty(typ); + visitor.visit_expr(expr); } ItemFn(ref declaration, unsafety, constness, abi, ref generics, ref body) => { visitor.visit_fn(FnKind::ItemFn(item.ident, generics, unsafety, constness, abi, item.vis), - &**declaration, - &**body, + declaration, + body, item.span, item.id) } @@ -256,126 +269,80 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { visitor.visit_mod(module, item.span, item.id) } ItemForeignMod(ref foreign_module) => { - for foreign_item in &foreign_module.items { - visitor.visit_foreign_item(&**foreign_item) - } + walk_list!(visitor, visit_foreign_item, &foreign_module.items); } ItemTy(ref typ, ref type_parameters) => { - visitor.visit_ty(&**typ); + visitor.visit_ty(typ); visitor.visit_generics(type_parameters) } ItemEnum(ref enum_definition, ref type_parameters) => { visitor.visit_generics(type_parameters); - visitor.visit_enum_def(enum_definition, type_parameters) + visitor.visit_enum_def(enum_definition, type_parameters, item.id, item.span) } ItemDefaultImpl(_, ref trait_ref) => { visitor.visit_trait_ref(trait_ref) } ItemImpl(_, _, ref type_parameters, - ref trait_reference, + ref opt_trait_reference, ref typ, ref impl_items) => { visitor.visit_generics(type_parameters); - match *trait_reference { - Some(ref trait_reference) => visitor.visit_trait_ref(trait_reference), - None => () - } - visitor.visit_ty(&**typ); - for impl_item in impl_items { - visitor.visit_impl_item(impl_item); - } + walk_list!(visitor, visit_trait_ref, opt_trait_reference); + visitor.visit_ty(typ); + walk_list!(visitor, visit_impl_item, impl_items); } ItemStruct(ref struct_definition, ref generics) => { visitor.visit_generics(generics); - visitor.visit_struct_def(&**struct_definition, - item.ident, - generics, - item.id) + visitor.visit_variant_data(struct_definition, item.ident, + generics, item.id, item.span); } ItemTrait(_, ref generics, ref bounds, ref methods) => { visitor.visit_generics(generics); - walk_ty_param_bounds_helper(visitor, bounds); - for method in methods { - visitor.visit_trait_item(method) - } + walk_list!(visitor, visit_ty_param_bound, bounds); + walk_list!(visitor, visit_trait_item, methods); } ItemMac(ref mac) => visitor.visit_mac(mac), } - for attr in &item.attrs { - visitor.visit_attribute(attr); - } + walk_list!(visitor, visit_attribute, &item.attrs); } pub fn walk_enum_def<'v, V: Visitor<'v>>(visitor: &mut V, enum_definition: &'v EnumDef, - generics: &'v Generics) { - for variant in &enum_definition.variants { - visitor.visit_variant(&**variant, generics); - } + generics: &'v Generics, + item_id: NodeId) { + walk_list!(visitor, visit_variant, &enum_definition.variants, generics, item_id); } pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V, variant: &'v Variant, - generics: &'v Generics) { + generics: &'v Generics, + item_id: NodeId) { visitor.visit_ident(variant.span, variant.node.name); - - match variant.node.kind { - TupleVariantKind(ref variant_arguments) => { - for variant_argument in variant_arguments { - visitor.visit_ty(&*variant_argument.ty) - } - } - StructVariantKind(ref struct_definition) => { - visitor.visit_struct_def(&**struct_definition, - variant.node.name, - generics, - variant.node.id) - } - } - match variant.node.disr_expr { - Some(ref expr) => visitor.visit_expr(&**expr), - None => () - } - for attr in &variant.node.attrs { - visitor.visit_attribute(attr); - } -} - -pub fn skip_ty<'v, V: Visitor<'v>>(_: &mut V, _: &'v Ty) { - // Empty! -} - -pub fn walk_ty_opt<'v, V: Visitor<'v>>(visitor: &mut V, optional_type: &'v Option>) { - match *optional_type { - Some(ref ty) => visitor.visit_ty(&**ty), - None => () - } + visitor.visit_variant_data(&variant.node.data, variant.node.name, + generics, item_id, variant.span); + walk_list!(visitor, visit_expr, &variant.node.disr_expr); + walk_list!(visitor, visit_attribute, &variant.node.attrs); } pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { match typ.node { TyVec(ref ty) | TyParen(ref ty) => { - visitor.visit_ty(&**ty) + visitor.visit_ty(ty) } TyPtr(ref mutable_type) => { - visitor.visit_ty(&*mutable_type.ty) + visitor.visit_ty(&mutable_type.ty) } - TyRptr(ref lifetime, ref mutable_type) => { - visitor.visit_opt_lifetime_ref(typ.span, lifetime); - visitor.visit_ty(&*mutable_type.ty) + TyRptr(ref opt_lifetime, ref mutable_type) => { + walk_list!(visitor, visit_lifetime, opt_lifetime); + visitor.visit_ty(&mutable_type.ty) } TyTup(ref tuple_element_types) => { - for tuple_element_type in tuple_element_types { - visitor.visit_ty(&**tuple_element_type) - } + walk_list!(visitor, visit_ty, tuple_element_types); } TyBareFn(ref function_declaration) => { - for argument in &function_declaration.decl.inputs { - visitor.visit_ty(&*argument.ty) - } - walk_fn_ret_ty(visitor, &function_declaration.decl.output); - walk_lifetime_decls_helper(visitor, &function_declaration.lifetimes); + walk_fn_decl(visitor, &function_declaration.decl); + walk_list!(visitor, visit_lifetime_def, &function_declaration.lifetimes); } TyPath(ref maybe_qself, ref path) => { if let Some(ref qself) = *maybe_qself { @@ -384,18 +351,18 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { visitor.visit_path(path, typ.id); } TyObjectSum(ref ty, ref bounds) => { - visitor.visit_ty(&**ty); - walk_ty_param_bounds_helper(visitor, bounds); + visitor.visit_ty(ty); + walk_list!(visitor, visit_ty_param_bound, bounds); } TyFixedLengthVec(ref ty, ref expression) => { - visitor.visit_ty(&**ty); - visitor.visit_expr(&**expression) + visitor.visit_ty(ty); + visitor.visit_expr(expression) } TyPolyTraitRef(ref bounds) => { - walk_ty_param_bounds_helper(visitor, bounds) + walk_list!(visitor, visit_ty_param_bound, bounds); } TyTypeof(ref expression) => { - visitor.visit_expr(&**expression) + visitor.visit_expr(expression) } TyInfer => {} TyMac(ref mac) => { @@ -404,19 +371,22 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { } } -pub fn walk_lifetime_decls_helper<'v, V: Visitor<'v>>(visitor: &mut V, - lifetimes: &'v Vec) { - for l in lifetimes { - visitor.visit_lifetime_def(l); - } -} - pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path) { for segment in &path.segments { visitor.visit_path_segment(path.span, segment); } } +pub fn walk_path_list_item<'v, V: Visitor<'v>>(visitor: &mut V, prefix: &'v Path, + item: &'v PathListItem) { + for segment in &prefix.segments { + visitor.visit_path_segment(prefix.span, segment); + } + + walk_opt_ident(visitor, item.span, item.node.name()); + walk_opt_ident(visitor, item.span, item.node.rename()); +} + pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V, path_span: Span, segment: &'v PathSegment) { @@ -428,24 +398,14 @@ pub fn walk_path_parameters<'v, V: Visitor<'v>>(visitor: &mut V, _path_span: Span, path_parameters: &'v PathParameters) { match *path_parameters { - ast::AngleBracketedParameters(ref data) => { - for typ in data.types.iter() { - visitor.visit_ty(&**typ); - } - for lifetime in &data.lifetimes { - visitor.visit_lifetime_ref(lifetime); - } - for binding in data.bindings.iter() { - visitor.visit_assoc_type_binding(&**binding); - } + AngleBracketedParameters(ref data) => { + walk_list!(visitor, visit_ty, &data.types); + walk_list!(visitor, visit_lifetime, &data.lifetimes); + walk_list!(visitor, visit_assoc_type_binding, &data.bindings); } - ast::ParenthesizedParameters(ref data) => { - for typ in &data.inputs { - visitor.visit_ty(&**typ); - } - if let Some(ref typ) = data.output { - visitor.visit_ty(&**typ); - } + ParenthesizedParameters(ref data) => { + walk_list!(visitor, visit_ty, &data.inputs); + walk_list!(visitor, visit_ty, &data.output); } } } @@ -453,17 +413,15 @@ pub fn walk_path_parameters<'v, V: Visitor<'v>>(visitor: &mut V, pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V, type_binding: &'v TypeBinding) { visitor.visit_ident(type_binding.span, type_binding.ident); - visitor.visit_ty(&*type_binding.ty); + visitor.visit_ty(&type_binding.ty); } pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { match pattern.node { - PatEnum(ref path, ref children) => { + PatEnum(ref path, ref opt_children) => { visitor.visit_path(path, pattern.id); - if let Some(ref children) = *children { - for child in children { - visitor.visit_pat(&*child) - } + if let Some(ref children) = *opt_children { + walk_list!(visitor, visit_pat, children); } } PatQPath(ref qself, ref path) => { @@ -473,41 +431,31 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { PatStruct(ref path, ref fields, _) => { visitor.visit_path(path, pattern.id); for field in fields { - visitor.visit_pat(&*field.node.pat) + visitor.visit_ident(field.span, field.node.ident); + visitor.visit_pat(&field.node.pat) } } PatTup(ref tuple_elements) => { - for tuple_element in tuple_elements { - visitor.visit_pat(&**tuple_element) - } + walk_list!(visitor, visit_pat, tuple_elements); } PatBox(ref subpattern) | PatRegion(ref subpattern, _) => { - visitor.visit_pat(&**subpattern) + visitor.visit_pat(subpattern) } PatIdent(_, ref pth1, ref optional_subpattern) => { visitor.visit_ident(pth1.span, pth1.node); - match *optional_subpattern { - None => {} - Some(ref subpattern) => visitor.visit_pat(&**subpattern), - } + walk_list!(visitor, visit_pat, optional_subpattern); } - PatLit(ref expression) => visitor.visit_expr(&**expression), + PatLit(ref expression) => visitor.visit_expr(expression), PatRange(ref lower_bound, ref upper_bound) => { - visitor.visit_expr(&**lower_bound); - visitor.visit_expr(&**upper_bound) + visitor.visit_expr(lower_bound); + visitor.visit_expr(upper_bound) } PatWild(_) => (), - PatVec(ref prepattern, ref slice_pattern, ref postpatterns) => { - for prepattern in prepattern { - visitor.visit_pat(&**prepattern) - } - if let Some(ref slice_pattern) = *slice_pattern { - visitor.visit_pat(&**slice_pattern) - } - for postpattern in postpatterns { - visitor.visit_pat(&**postpattern) - } + PatVec(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); } PatMac(ref mac) => visitor.visit_mac(mac), } @@ -519,22 +467,13 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, match foreign_item.node { ForeignItemFn(ref function_declaration, ref generics) => { - walk_fn_decl(visitor, &**function_declaration); + walk_fn_decl(visitor, function_declaration); visitor.visit_generics(generics) } - ForeignItemStatic(ref typ, _) => visitor.visit_ty(&**typ), - } - - for attr in &foreign_item.attrs { - visitor.visit_attribute(attr); + ForeignItemStatic(ref typ, _) => visitor.visit_ty(typ), } -} -pub fn walk_ty_param_bounds_helper<'v, V: Visitor<'v>>(visitor: &mut V, - bounds: &'v OwnedSlice) { - for bound in bounds.iter() { - visitor.visit_ty_param_bound(bound) - } + walk_list!(visitor, visit_attribute, &foreign_item.attrs); } pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, @@ -544,41 +483,40 @@ pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, visitor.visit_poly_trait_ref(typ, modifier); } RegionTyParamBound(ref lifetime) => { - visitor.visit_lifetime_bound(lifetime); + visitor.visit_lifetime(lifetime); } } } pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics) { - for param in generics.ty_params.iter() { + for param in &generics.ty_params { visitor.visit_ident(param.span, param.ident); - walk_ty_param_bounds_helper(visitor, ¶m.bounds); - walk_ty_opt(visitor, ¶m.default); + walk_list!(visitor, visit_ty_param_bound, ¶m.bounds); + walk_list!(visitor, visit_ty, ¶m.default); } - walk_lifetime_decls_helper(visitor, &generics.lifetimes); + walk_list!(visitor, visit_lifetime_def, &generics.lifetimes); for predicate in &generics.where_clause.predicates { match predicate { - &ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ref bounded_ty, + &WherePredicate::BoundPredicate(WhereBoundPredicate{ref bounded_ty, ref bounds, + ref bound_lifetimes, ..}) => { - visitor.visit_ty(&**bounded_ty); - walk_ty_param_bounds_helper(visitor, bounds); + visitor.visit_ty(bounded_ty); + walk_list!(visitor, visit_ty_param_bound, bounds); + walk_list!(visitor, visit_lifetime_def, bound_lifetimes); } - &ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{ref lifetime, + &WherePredicate::RegionPredicate(WhereRegionPredicate{ref lifetime, ref bounds, ..}) => { - visitor.visit_lifetime_ref(lifetime); - - for bound in bounds { - visitor.visit_lifetime_ref(bound); - } + visitor.visit_lifetime(lifetime); + walk_list!(visitor, visit_lifetime, bounds); } - &ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{id, + &WherePredicate::EqPredicate(WhereEqPredicate{id, ref path, ref ty, ..}) => { visitor.visit_path(path, id); - visitor.visit_ty(&**ty); + visitor.visit_ty(ty); } } } @@ -586,25 +524,20 @@ pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics pub fn walk_fn_ret_ty<'v, V: Visitor<'v>>(visitor: &mut V, ret_ty: &'v FunctionRetTy) { if let Return(ref output_ty) = *ret_ty { - visitor.visit_ty(&**output_ty) + visitor.visit_ty(output_ty) } } pub fn walk_fn_decl<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl) { for argument in &function_declaration.inputs { - visitor.visit_pat(&*argument.pat); - visitor.visit_ty(&*argument.ty) + visitor.visit_pat(&argument.pat); + visitor.visit_ty(&argument.ty) } walk_fn_ret_ty(visitor, &function_declaration.output) } -pub fn walk_fn<'v, V: Visitor<'v>>(visitor: &mut V, - function_kind: FnKind<'v>, - function_declaration: &'v FnDecl, - function_body: &'v Block, - _span: Span) { - walk_fn_decl(visitor, function_declaration); - +pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, + function_kind: FnKind<'v>) { match function_kind { FnKind::ItemFn(_, generics, _, _, _, _) => { visitor.visit_generics(generics); @@ -613,23 +546,27 @@ pub fn walk_fn<'v, V: Visitor<'v>>(visitor: &mut V, visitor.visit_generics(&sig.generics); visitor.visit_explicit_self(&sig.explicit_self); } - FnKind::Closure(..) => {} + FnKind::Closure => {} } +} +pub fn walk_fn<'v, V: Visitor<'v>>(visitor: &mut V, + function_kind: FnKind<'v>, + function_declaration: &'v FnDecl, + function_body: &'v Block, + _span: Span) { + walk_fn_decl(visitor, function_declaration); + walk_fn_kind(visitor, function_kind); visitor.visit_block(function_body) } pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem) { visitor.visit_ident(trait_item.span, trait_item.ident); - for attr in &trait_item.attrs { - visitor.visit_attribute(attr); - } + walk_list!(visitor, visit_attribute, &trait_item.attrs); match trait_item.node { ConstTraitItem(ref ty, ref default) => { visitor.visit_ty(ty); - if let Some(ref expr) = *default { - visitor.visit_expr(expr); - } + walk_list!(visitor, visit_expr, default); } MethodTraitItem(ref sig, None) => { visitor.visit_explicit_self(&sig.explicit_self); @@ -641,17 +578,15 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai body, trait_item.span, trait_item.id); } TypeTraitItem(ref bounds, ref default) => { - walk_ty_param_bounds_helper(visitor, bounds); - walk_ty_opt(visitor, default); + walk_list!(visitor, visit_ty_param_bound, bounds); + walk_list!(visitor, visit_ty, default); } } } pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplItem) { visitor.visit_ident(impl_item.span, impl_item.ident); - for attr in &impl_item.attrs { - visitor.visit_attribute(attr); - } + walk_list!(visitor, visit_attribute, &impl_item.attrs); match impl_item.node { ConstImplItem(ref ty, ref expr) => { visitor.visit_ty(ty); @@ -671,60 +606,36 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt } pub fn walk_struct_def<'v, V: Visitor<'v>>(visitor: &mut V, - struct_definition: &'v StructDef) { - for field in &struct_definition.fields { - visitor.visit_struct_field(field) - } + struct_definition: &'v VariantData) { + walk_list!(visitor, visit_struct_field, struct_definition.fields()); } pub fn walk_struct_field<'v, V: Visitor<'v>>(visitor: &mut V, struct_field: &'v StructField) { - if let NamedField(name, _) = struct_field.node.kind { - visitor.visit_ident(struct_field.span, name); - } - - visitor.visit_ty(&*struct_field.node.ty); - - for attr in &struct_field.node.attrs { - visitor.visit_attribute(attr); - } + walk_opt_ident(visitor, struct_field.span, struct_field.node.ident()); + visitor.visit_ty(&struct_field.node.ty); + walk_list!(visitor, visit_attribute, &struct_field.node.attrs); } pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block) { - for statement in &block.stmts { - visitor.visit_stmt(&**statement) - } - walk_expr_opt(visitor, &block.expr) + walk_list!(visitor, visit_stmt, &block.stmts); + walk_list!(visitor, visit_expr, &block.expr); } pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt) { match statement.node { - StmtDecl(ref declaration, _) => visitor.visit_decl(&**declaration), + StmtDecl(ref declaration, _) => visitor.visit_decl(declaration), StmtExpr(ref expression, _) | StmtSemi(ref expression, _) => { - visitor.visit_expr(&**expression) + visitor.visit_expr(expression) } - StmtMac(ref mac, _) => visitor.visit_mac(&**mac), + StmtMac(ref mac, _) => visitor.visit_mac(mac), } } pub fn walk_decl<'v, V: Visitor<'v>>(visitor: &mut V, declaration: &'v Decl) { match declaration.node { - DeclLocal(ref local) => visitor.visit_local(&**local), - DeclItem(ref item) => visitor.visit_item(&**item), - } -} - -pub fn walk_expr_opt<'v, V: Visitor<'v>>(visitor: &mut V, - optional_expression: &'v Option>) { - match *optional_expression { - None => {} - Some(ref expression) => visitor.visit_expr(&**expression), - } -} - -pub fn walk_exprs<'v, V: Visitor<'v>>(visitor: &mut V, expressions: &'v [P]) { - for expression in expressions { - visitor.visit_expr(&**expression) + DeclLocal(ref local) => visitor.visit_local(local), + DeclItem(ref item) => visitor.visit_item(item), } } @@ -734,114 +645,118 @@ pub fn walk_mac<'v, V: Visitor<'v>>(_: &mut V, _: &'v Mac) { pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { match expression.node { - ExprBox(ref place, ref subexpression) => { - place.as_ref().map(|e|visitor.visit_expr(&**e)); - visitor.visit_expr(&**subexpression) + ExprBox(ref subexpression) => { + visitor.visit_expr(subexpression) + } + ExprInPlace(ref place, ref subexpression) => { + visitor.visit_expr(place); + visitor.visit_expr(subexpression) } ExprVec(ref subexpressions) => { - walk_exprs(visitor, subexpressions) + walk_list!(visitor, visit_expr, subexpressions); } ExprRepeat(ref element, ref count) => { - visitor.visit_expr(&**element); - visitor.visit_expr(&**count) + visitor.visit_expr(element); + visitor.visit_expr(count) } ExprStruct(ref path, ref fields, ref optional_base) => { visitor.visit_path(path, expression.id); for field in fields { - visitor.visit_expr(&*field.expr) + visitor.visit_ident(field.ident.span, field.ident.node); + visitor.visit_expr(&field.expr) } - walk_expr_opt(visitor, optional_base) + walk_list!(visitor, visit_expr, optional_base); } ExprTup(ref subexpressions) => { - for subexpression in subexpressions { - visitor.visit_expr(&**subexpression) - } + walk_list!(visitor, visit_expr, subexpressions); } ExprCall(ref callee_expression, ref arguments) => { - for argument in arguments { - visitor.visit_expr(&**argument) - } - visitor.visit_expr(&**callee_expression) + walk_list!(visitor, visit_expr, arguments); + visitor.visit_expr(callee_expression) } - ExprMethodCall(_, ref types, ref arguments) => { - walk_exprs(visitor, arguments); - for typ in types { - visitor.visit_ty(&**typ) - } + ExprMethodCall(ref ident, ref types, ref arguments) => { + visitor.visit_ident(ident.span, ident.node); + walk_list!(visitor, visit_expr, arguments); + walk_list!(visitor, visit_ty, types); } ExprBinary(_, ref left_expression, ref right_expression) => { - visitor.visit_expr(&**left_expression); - visitor.visit_expr(&**right_expression) + visitor.visit_expr(left_expression); + visitor.visit_expr(right_expression) } ExprAddrOf(_, ref subexpression) | ExprUnary(_, ref subexpression) => { - visitor.visit_expr(&**subexpression) + visitor.visit_expr(subexpression) } ExprLit(_) => {} ExprCast(ref subexpression, ref typ) => { - visitor.visit_expr(&**subexpression); - visitor.visit_ty(&**typ) + visitor.visit_expr(subexpression); + visitor.visit_ty(typ) } ExprIf(ref head_expression, ref if_block, ref optional_else) => { - visitor.visit_expr(&**head_expression); - visitor.visit_block(&**if_block); - walk_expr_opt(visitor, optional_else) + visitor.visit_expr(head_expression); + visitor.visit_block(if_block); + walk_list!(visitor, visit_expr, optional_else); } - ExprWhile(ref subexpression, ref block, _) => { - visitor.visit_expr(&**subexpression); - visitor.visit_block(&**block) + ExprWhile(ref subexpression, ref block, opt_ident) => { + visitor.visit_expr(subexpression); + visitor.visit_block(block); + walk_opt_ident(visitor, expression.span, opt_ident) } ExprIfLet(ref pattern, ref subexpression, ref if_block, ref optional_else) => { - visitor.visit_pat(&**pattern); - visitor.visit_expr(&**subexpression); - visitor.visit_block(&**if_block); - walk_expr_opt(visitor, optional_else); - } - ExprWhileLet(ref pattern, ref subexpression, ref block, _) => { - visitor.visit_pat(&**pattern); - visitor.visit_expr(&**subexpression); - visitor.visit_block(&**block); - } - ExprForLoop(ref pattern, ref subexpression, ref block, _) => { - visitor.visit_pat(&**pattern); - visitor.visit_expr(&**subexpression); - visitor.visit_block(&**block) - } - ExprLoop(ref block, _) => visitor.visit_block(&**block), - ExprMatch(ref subexpression, ref arms, _) => { - visitor.visit_expr(&**subexpression); - for arm in arms { - visitor.visit_arm(arm) - } + visitor.visit_pat(pattern); + visitor.visit_expr(subexpression); + visitor.visit_block(if_block); + walk_list!(visitor, visit_expr, optional_else); + } + ExprWhileLet(ref pattern, ref subexpression, ref block, opt_ident) => { + visitor.visit_pat(pattern); + visitor.visit_expr(subexpression); + visitor.visit_block(block); + walk_opt_ident(visitor, expression.span, opt_ident) + } + ExprForLoop(ref pattern, ref subexpression, ref block, opt_ident) => { + visitor.visit_pat(pattern); + visitor.visit_expr(subexpression); + visitor.visit_block(block); + walk_opt_ident(visitor, expression.span, opt_ident) + } + ExprLoop(ref block, opt_ident) => { + visitor.visit_block(block); + walk_opt_ident(visitor, expression.span, opt_ident) + } + ExprMatch(ref subexpression, ref arms) => { + visitor.visit_expr(subexpression); + walk_list!(visitor, visit_arm, arms); } ExprClosure(_, ref function_declaration, ref body) => { visitor.visit_fn(FnKind::Closure, - &**function_declaration, - &**body, + function_declaration, + body, expression.span, expression.id) } - ExprBlock(ref block) => visitor.visit_block(&**block), + ExprBlock(ref block) => visitor.visit_block(block), ExprAssign(ref left_hand_expression, ref right_hand_expression) => { - visitor.visit_expr(&**right_hand_expression); - visitor.visit_expr(&**left_hand_expression) + visitor.visit_expr(right_hand_expression); + visitor.visit_expr(left_hand_expression) } ExprAssignOp(_, ref left_expression, ref right_expression) => { - visitor.visit_expr(&**right_expression); - visitor.visit_expr(&**left_expression) + visitor.visit_expr(right_expression); + visitor.visit_expr(left_expression) } - ExprField(ref subexpression, _) => { - visitor.visit_expr(&**subexpression); + ExprField(ref subexpression, ref ident) => { + visitor.visit_expr(subexpression); + visitor.visit_ident(ident.span, ident.node); } ExprTupField(ref subexpression, _) => { - visitor.visit_expr(&**subexpression); + visitor.visit_expr(subexpression); } ExprIndex(ref main_expression, ref index_expression) => { - visitor.visit_expr(&**main_expression); - visitor.visit_expr(&**index_expression) + visitor.visit_expr(main_expression); + visitor.visit_expr(index_expression) } ExprRange(ref start, ref end) => { - walk_expr_opt(visitor, start); - walk_expr_opt(visitor, end) + walk_list!(visitor, visit_expr, start); + walk_list!(visitor, visit_expr, end); } ExprPath(ref maybe_qself, ref path) => { if let Some(ref qself) = *maybe_qself { @@ -849,22 +764,24 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { } visitor.visit_path(path, expression.id) } - ExprBreak(_) | ExprAgain(_) => {} + ExprBreak(ref opt_sp_ident) | ExprAgain(ref opt_sp_ident) => { + for sp_ident in opt_sp_ident { + visitor.visit_ident(sp_ident.span, sp_ident.node); + } + } ExprRet(ref optional_expression) => { - walk_expr_opt(visitor, optional_expression) + walk_list!(visitor, visit_expr, optional_expression); } ExprMac(ref mac) => visitor.visit_mac(mac), ExprParen(ref subexpression) => { - visitor.visit_expr(&**subexpression) + visitor.visit_expr(subexpression) } ExprInlineAsm(ref ia) => { - for input in &ia.inputs { - let (_, ref input) = *input; - visitor.visit_expr(&**input) + for &(_, ref input) in &ia.inputs { + visitor.visit_expr(&input) } - for output in &ia.outputs { - let (_, ref output, _) = *output; - visitor.visit_expr(&**output) + for &(_, ref output, _) in &ia.outputs { + visitor.visit_expr(&output) } } } @@ -873,12 +790,8 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { } pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm) { - for pattern in &arm.pats { - visitor.visit_pat(&**pattern) - } - walk_expr_opt(visitor, &arm.guard); - visitor.visit_expr(&*arm.body); - for attr in &arm.attrs { - visitor.visit_attribute(attr); - } + walk_list!(visitor, visit_pat, &arm.pats); + walk_list!(visitor, visit_expr, &arm.guard); + visitor.visit_expr(&arm.body); + walk_list!(visitor, visit_attribute, &arm.attrs); } diff --git a/src/libterm/lib.rs b/src/libterm/lib.rs index 8bf8044f81..ced3a7d47d 100644 --- a/src/libterm/lib.rs +++ b/src/libterm/lib.rs @@ -57,7 +57,6 @@ #![deny(missing_docs)] #![feature(box_syntax)] -#![feature(path_ext)] #![feature(rustc_private)] #![feature(staged_api)] #![feature(str_char)] diff --git a/src/libterm/terminfo/searcher.rs b/src/libterm/terminfo/searcher.rs index 16062060df..0e05ac53bc 100644 --- a/src/libterm/terminfo/searcher.rs +++ b/src/libterm/terminfo/searcher.rs @@ -102,7 +102,7 @@ fn test_get_dbpath_for_term() { fn x(t: &str) -> String { let p = get_dbpath_for_term(t).expect("no terminfo entry found"); p.to_str().unwrap().to_string() - }; + } assert!(x("screen") == "/usr/share/terminfo/s/screen"); assert!(get_dbpath_for_term("") == None); env::set_var("TERMINFO_DIRS", ":"); diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index ad00bb6673..cfe7577953 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -924,7 +924,7 @@ pub fn filter_tests(opts: &TestOpts, tests: Vec) -> Vec= size) return tmp_i; + if (bt < span_nb && i >= size) return tmp_i; } /* skipping a link */ else if (data[i] == '[') { diff --git a/src/rt/hoedown/src/version.h b/src/rt/hoedown/src/version.h index 71b0e6a5ae..d3247b681d 100644 --- a/src/rt/hoedown/src/version.h +++ b/src/rt/hoedown/src/version.h @@ -12,10 +12,10 @@ extern "C" { * CONSTANTS * *************/ -#define HOEDOWN_VERSION "3.0.4" +#define HOEDOWN_VERSION "3.0.5" #define HOEDOWN_VERSION_MAJOR 3 #define HOEDOWN_VERSION_MINOR 0 -#define HOEDOWN_VERSION_REVISION 4 +#define HOEDOWN_VERSION_REVISION 5 /************* diff --git a/src/rt/rust_test_helpers.c b/src/rt/rust_test_helpers.c index 8824cef2a8..f7895d694c 100644 --- a/src/rt/rust_test_helpers.c +++ b/src/rt/rust_test_helpers.c @@ -218,3 +218,7 @@ uint64_t get_y(struct S s) { uint64_t get_z(struct S s) { return s.z; } + +uint64_t get_c_many_params(void *a, void *b, void *c, void *d, struct quad f) { + return f.c; +} diff --git a/src/rustbook/build.rs b/src/rustbook/build.rs index aca0db4e1a..4b6d67d2d2 100644 --- a/src/rustbook/build.rs +++ b/src/rustbook/build.rs @@ -23,8 +23,6 @@ use error::{err, CliResult, CommandResult}; use book; use book::{Book, BookItem}; -use javascript; - use rustdoc; struct Build; @@ -82,7 +80,7 @@ fn write_toc(book: &Book, current_page: &BookItem, out: &mut Write) -> io::Resul } fn render(book: &Book, tgt: &Path) -> CliResult<()> { - let tmp = try!(TempDir::new("rust-book")); + let tmp = try!(TempDir::new("rustbook")); for (_section, item) in book.iter() { let out_path = match item.path.parent() { @@ -113,26 +111,28 @@ fn render(book: &Book, tgt: &Path) -> CliResult<()> { // write the prelude to a temporary HTML file for rustdoc inclusion let prelude = tmp.path().join("prelude.html"); { - let mut toc = BufWriter::new(try!(File::create(&prelude))); - try!(writeln!(&mut toc, r#""#)); - let _ = write_toc(book, &item, &mut toc); - try!(writeln!(&mut toc, "
    ")); - try!(writeln!(&mut toc, "
    ")); + let mut buffer = BufWriter::new(try!(File::create(&prelude))); + try!(writeln!(&mut buffer, r#" + "#)); + let _ = write_toc(book, &item, &mut buffer); + try!(writeln!(&mut buffer, "
    ")); + try!(writeln!(&mut buffer, "
    ")); } // write the postlude to a temporary HTML file for rustdoc inclusion let postlude = tmp.path().join("postlude.html"); { - let mut toc = BufWriter::new(try!(File::create(&postlude))); - try!(toc.write_all(javascript::JAVASCRIPT.as_bytes())); - try!(writeln!(&mut toc, "
    ")); + let mut buffer = BufWriter::new(try!(File::create(&postlude))); + try!(writeln!(&mut buffer, "")); + try!(writeln!(&mut buffer, "")); + try!(writeln!(&mut buffer, "
    ")); } try!(fs::create_dir_all(&out_path)); @@ -144,7 +144,7 @@ fn render(book: &Book, tgt: &Path) -> CliResult<()> { format!("--html-before-content={}", prelude.display()), format!("--html-after-content={}", postlude.display()), format!("--markdown-playground-url=https://play.rust-lang.org"), - format!("--markdown-css={}", item.path_to_root.join("rust-book.css").display()), + format!("--markdown-css={}", item.path_to_root.join("rustbook.css").display()), "--markdown-no-toc".to_string(), ]; let output_result = rustdoc::main_args(rustdoc_args); @@ -199,10 +199,10 @@ impl Subcommand for Build { let css = include_bytes!("static/rustbook.css"); let js = include_bytes!("static/rustbook.js"); - let mut css_file = try!(File::create(tgt.join("rust-book.css"))); + let mut css_file = try!(File::create(tgt.join("rustbook.css"))); try!(css_file.write_all(css)); - let mut js_file = try!(File::create(tgt.join("rust-book.js"))); + let mut js_file = try!(File::create(tgt.join("rustbook.js"))); try!(js_file.write_all(js)); diff --git a/src/rustbook/help.rs b/src/rustbook/help.rs index 995d2f2494..c90c2b9360 100644 --- a/src/rustbook/help.rs +++ b/src/rustbook/help.rs @@ -36,7 +36,7 @@ impl Subcommand for Help { } pub fn usage() { - println!("Usage: rust-book []"); + println!("Usage: rustbook []"); println!(""); println!("The must be one of:"); println!(" help Print this message."); diff --git a/src/rustbook/main.rs b/src/rustbook/main.rs index 81f8c8c40f..d23e868eea 100644 --- a/src/rustbook/main.rs +++ b/src/rustbook/main.rs @@ -35,11 +35,8 @@ mod build; mod serve; mod test; -mod javascript; - static EXIT_STATUS: AtomicIsize = ATOMIC_ISIZE_INIT; -#[cfg(not(test))] // thanks #12327 fn main() { let mut term = Term::new(); let cmd: Vec<_> = env::args().collect(); diff --git a/src/rustbook/static/rustbook.css b/src/rustbook/static/rustbook.css index 6b9e7aa58f..ba0151fa2e 100644 --- a/src/rustbook/static/rustbook.css +++ b/src/rustbook/static/rustbook.css @@ -1,5 +1,5 @@ /** - * Copyright 2013 The Rust Project Developers. See the COPYRIGHT + * Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT * file at the top-level directory of this distribution and at * http://rust-lang.org/COPYRIGHT. * @@ -10,12 +10,11 @@ * except according to those terms. */ -@import url("../rust.css"); +@import url('../rust.css'); body { - max-width:none; - font: 16px/1.4 'Source Serif Pro', Georgia, Times, 'Times New Roman', serif; - line-height: 1.6; + max-width: none; + font: 16px/1.6 'Source Serif Pro', Georgia, Times, 'Times New Roman', serif; color: #333; } @@ -28,68 +27,64 @@ h1, h2, h3, h4, h5, h6 { @media only screen { #toc { position: fixed; - left: 0px; - top: 0px; - bottom: 0px; + top: 0; + left: 0; + bottom: 0; width: 300px; overflow-y: auto; - border-right: 1px solid rgba(0, 0, 0, 0.07); - padding: 10px 10px; + border-right: 1px solid #e8e8e8; + padding: 0 15px; font-size: 14px; - box-sizing: border-box; - -webkit-overflow-scrolling: touch; background-color: #fafafa; - color: #364149; + -webkit-overflow-scrolling: touch; } #page-wrapper { position: absolute; - left: 310px; - right: 0px; - top: 0px; - box-sizing: border-box; - background: none repeat scroll 0% 0% #FFF; + top: 0; + left: 300px; + right: 0; + padding: 0 15px; -webkit-overflow-scrolling: touch; } } @media only print { - #toc, #nav, #menu-bar { + #toc, #nav { display: none; } } -@media only screen and (max-width: 1060px) { +@media only screen and (max-width: 1023px) { #toc { width: 100%; - margin-right: 0; top: 40px; } + #page-wrapper { top: 40px; - left: 15px; - padding-right: 15px; + left: 0; } + .mobile-hidden { display: none; } } #page { - margin-left: auto; - margin-right:auto; + margin: 0 auto; max-width: 750px; padding-bottom: 50px; } .chapter { - list-style: none outside none; - padding-left: 0px; + list-style: none; + padding-left: 0; line-height: 30px; } .section { - list-style: none outside none; + list-style: none; padding-left: 20px; line-height: 40px; } @@ -105,28 +100,21 @@ h1, h2, h3, h4, h5, h6 { padding: 5px 0; } -.chapter li a.active { - color: #008cff; -} - +.chapter li a.active, .chapter li a:hover { color: #008cff; text-decoration: none; } #toggle-nav { - height: 20px; - width: 30px; - padding: 3px 3px 0 3px; -} - -#toggle-nav { + cursor: pointer; margin-top: 5px; width: 30px; height: 30px; - background-color: #FFF; + background-color: #fff; border: 1px solid #666; - border-radius: 3px 3px 3px 3px; + border-radius: 3px; + padding: 3px 3px 0 3px; } .sr-only { @@ -151,7 +139,7 @@ h1, h2, h3, h4, h5, h6 { } pre { - padding: 16px; + padding: 11px; overflow: auto; font-size: 85%; line-height: 1.45; @@ -160,10 +148,6 @@ pre { border-radius: 3px; } -.nav-previous-next { - margin-top: 60px; -} - .left { float: left; } diff --git a/src/rustbook/static/rustbook.js b/src/rustbook/static/rustbook.js index fdefab2875..d8ab15260e 100644 --- a/src/rustbook/static/rustbook.js +++ b/src/rustbook/static/rustbook.js @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,66 +8,71 @@ // 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(event) { +document.addEventListener('DOMContentLoaded', function() { + 'use strict'; - document.getElementById("toggle-nav").onclick = toggleNav; + document.getElementById('toggle-nav').onclick = function(e) { + var toc = document.getElementById('toc'); + var pagewrapper = document.getElementById('page-wrapper'); + toggleClass(toc, 'mobile-hidden'); + toggleClass(pagewrapper, 'mobile-hidden'); + }; - function toggleNav() { - var toc = document.getElementById("toc"); - var pagewrapper = document.getElementById("page-wrapper"); - toggleClass(toc, "mobile-hidden"); - toggleClass(pagewrapper, "mobile-hidden"); - } + function toggleClass(el, className) { + // from http://youmightnotneedjquery.com/ + if (el.classList) { + el.classList.toggle(className); + } else { + var classes = el.className.split(' '); + var existingIndex = classes.indexOf(className); - function toggleClass(el, className) { - // from http://youmightnotneedjquery.com/ - if (el.classList) { - el.classList.toggle(className); - } else { - var classes = el.className.split(' '); - var existingIndex = classes.indexOf(className); + if (existingIndex >= 0) { + classes.splice(existingIndex, 1); + } else { + classes.push(className); + } - if (existingIndex >= 0) { - classes.splice(existingIndex, 1); - } else { - classes.push(className); - } - - el.className = classes.join(' '); - } - } + el.className = classes.join(' '); + } + } - // The below code is used to add prev and next navigation links to the bottom - // of each of the sections. - // It works by extracting the current page based on the url and iterates over - // the menu links until it finds the menu item for the current page. We then - // create a copy of the preceding and following menu links and add the - // correct css class and insert them into the bottom of the page. - var toc = document.getElementById('toc').getElementsByTagName('a'); - var href = document.location.pathname.split('/').pop(); - if (href === 'index.html' || href === '') { - href = 'README.html'; - } + // The below code is used to add prev and next navigation links to the + // bottom of each of the sections. + // It works by extracting the current page based on the url and iterates + // over the menu links until it finds the menu item for the current page. We + // then create a copy of the preceding and following menu links and add the + // correct css class and insert them into the bottom of the page. + var toc = document.getElementById('toc').getElementsByTagName('a'); + var href = document.location.pathname.split('/').pop(); - for (var i = 0; i < toc.length; i++) { - if (toc[i].attributes.href.value.split('/').pop() === href) { - var nav = document.createElement('p'); - if (i > 0) { - var prevNode = toc[i-1].cloneNode(true); - prevNode.className = 'left'; - prevNode.setAttribute('rel', 'prev'); - nav.appendChild(prevNode); - } - if (i < toc.length - 1) { - var nextNode = toc[i+1].cloneNode(true); - nextNode.className = 'right'; - nextNode.setAttribute('rel', 'next'); - nav.appendChild(nextNode); - } - document.getElementById('page').appendChild(nav); - break; + if (href === 'index.html' || href === '') { + href = 'README.html'; } - } + for (var i = 0; i < toc.length; i++) { + if (toc[i].attributes.href.value.split('/').pop() === href) { + var nav = document.createElement('p'); + + if (i > 0) { + var prevNode = toc[i-1].cloneNode(true); + prevNode.className = 'left'; + prevNode.setAttribute('rel', 'prev'); + nav.appendChild(prevNode); + } + + if (i < toc.length - 1) { + var nextNode = toc[i+1].cloneNode(true); + nextNode.className = 'right'; + nextNode.setAttribute('rel', 'next'); + nav.appendChild(nextNode); + } + + document.getElementById('page').appendChild(nav); + + break; + } + } }); diff --git a/src/rustbook/subcommand.rs b/src/rustbook/subcommand.rs index 5a8e1f695a..a66c2b4f30 100644 --- a/src/rustbook/subcommand.rs +++ b/src/rustbook/subcommand.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Common API for all rust-book subcommands. +//! Common API for all rustbook subcommands. use error::CliResult; use error::CommandResult; diff --git a/src/rustllvm/ArchiveWrapper.cpp b/src/rustllvm/ArchiveWrapper.cpp index a40f0a245d..2cf6277e05 100644 --- a/src/rustllvm/ArchiveWrapper.cpp +++ b/src/rustllvm/ArchiveWrapper.cpp @@ -163,12 +163,20 @@ LLVMRustWriteArchive(char *Dst, auto Member = NewMembers[i]; assert(Member->name); if (Member->filename) { +#if LLVM_VERSION_MINOR >= 8 + Members.push_back(NewArchiveIterator(Member->filename)); +#else Members.push_back(NewArchiveIterator(Member->filename, Member->name)); +#endif } else { Members.push_back(NewArchiveIterator(Member->child, Member->name)); } } +#if LLVM_VERSION_MINOR >= 8 + auto pair = writeArchive(Dst, Members, WriteSymbtab, Kind, true, false); +#else auto pair = writeArchive(Dst, Members, WriteSymbtab, Kind, true); +#endif if (!pair.second) return 0; LLVMRustSetLastError(pair.second.message().c_str()); diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 6513fdfd2f..b27a622136 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -49,7 +49,9 @@ LLVMInitializePasses() { initializeVectorization(Registry); initializeIPO(Registry); initializeAnalysis(Registry); +#if LLVM_VERSION_MINOR <= 7 initializeIPA(Registry); +#endif initializeTransformUtils(Registry); initializeInstCombine(Registry); initializeInstrumentation(Registry); @@ -250,7 +252,7 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, #endif PM->run(*unwrap(M)); - // Apparently `addPassesToEmitFile` adds an pointer to our on-the-stack output + // Apparently `addPassesToEmitFile` adds a pointer to our on-the-stack output // stream (OS), so the only real safe place to delete this is here? Don't we // wish this was written in Rust? delete PM; @@ -335,8 +337,7 @@ LLVMRustSetDataLayoutFromTargetMachine(LLVMModuleRef Module, LLVMTargetMachineRef TMR) { TargetMachine *Target = unwrap(TMR); #if LLVM_VERSION_MINOR >= 7 - if (const DataLayout *DL = Target->getDataLayout()) - unwrap(Module)->setDataLayout(*DL); + unwrap(Module)->setDataLayout(Target->createDataLayout()); #elif LLVM_VERSION_MINOR >= 6 if (const DataLayout *DL = Target->getSubtargetImpl()->getDataLayout()) unwrap(Module)->setDataLayout(DL); diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 5007af0e77..5a9c096e5f 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -320,7 +320,9 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateSubroutineType( LLVMMetadataRef File, LLVMMetadataRef ParameterTypes) { return wrap(Builder->createSubroutineType( +#if LLVM_VERSION_MINOR <= 7 unwrapDI(File), +#endif #if LLVM_VERSION_MINOR >= 7 DITypeRefArray(unwrap(ParameterTypes)))); #elif LLVM_VERSION_MINOR >= 6 @@ -502,11 +504,27 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateVariable( )); } #endif +#if LLVM_VERSION_MINOR >= 8 + if (Tag == 0x100) { // DW_TAG_auto_variable + return wrap(Builder->createAutoVariable( + unwrapDI(Scope), Name, + unwrapDI(File), + LineNo, + unwrapDI(Ty), AlwaysPreserve, Flags)); + } else { + return wrap(Builder->createParameterVariable( + unwrapDI(Scope), Name, ArgNo, + unwrapDI(File), + LineNo, + unwrapDI(Ty), AlwaysPreserve, Flags)); + } +#else return wrap(Builder->createLocalVariable(Tag, unwrapDI(Scope), Name, unwrapDI(File), LineNo, unwrapDI(Ty), AlwaysPreserve, Flags, ArgNo)); +#endif } extern "C" LLVMMetadataRef LLVMDIBuilderCreateArrayType( @@ -951,10 +969,5 @@ LLVMRustBuildLandingPad(LLVMBuilderRef Builder, unsigned NumClauses, const char* Name, LLVMValueRef F) { -#if LLVM_VERSION_MINOR >= 7 - unwrap(F)->setPersonalityFn(unwrap(PersFn)); - return LLVMBuildLandingPad(Builder, Ty, NumClauses, Name); -#else return LLVMBuildLandingPad(Builder, Ty, PersFn, NumClauses, Name); -#endif } diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-auto-clean-trigger index df9dc8bc84..4ef1fbb506 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. -2015-09-11 +2015-12-02 diff --git a/src/test/auxiliary/augmented_assignments.rs b/src/test/auxiliary/augmented_assignments.rs new file mode 100644 index 0000000000..9577e1ff0c --- /dev/null +++ b/src/test/auxiliary/augmented_assignments.rs @@ -0,0 +1,22 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(augmented_assignments)] +#![feature(op_assign_traits)] + +use std::ops::AddAssign; + +pub struct Int(i32); + +impl AddAssign for Int { + fn add_assign(&mut self, _: i32) { + unimplemented!(); + } +} diff --git a/src/test/auxiliary/cross_crate_spans.rs b/src/test/auxiliary/cross_crate_spans.rs index d9be03c094..9b6b6221bd 100644 --- a/src/test/auxiliary/cross_crate_spans.rs +++ b/src/test/auxiliary/cross_crate_spans.rs @@ -11,6 +11,7 @@ #![crate_type = "rlib"] #![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] // no-prefer-dynamic diff --git a/src/test/auxiliary/inherited_stability.rs b/src/test/auxiliary/inherited_stability.rs index f4e6f6d751..60477288f7 100644 --- a/src/test/auxiliary/inherited_stability.rs +++ b/src/test/auxiliary/inherited_stability.rs @@ -29,7 +29,7 @@ pub mod stable_mod { #[unstable(feature = "test_feature", issue = "0")] pub mod unstable_mod { #[stable(feature = "test_feature", since = "1.0.0")] - #[deprecated(since = "1.0.0")] + #[deprecated(since = "1.0.0", reason = "text")] pub fn deprecated() {} pub fn unstable() {} diff --git a/src/test/auxiliary/issue-2380.rs b/src/test/auxiliary/issue-2380.rs index 96f33f97a6..cfebc4abaa 100644 --- a/src/test/auxiliary/issue-2380.rs +++ b/src/test/auxiliary/issue-2380.rs @@ -22,5 +22,5 @@ pub trait i pub fn f() -> Box+'static> { impl i for () { } - box() () as Box+'static> + box () as Box+'static> } diff --git a/src/test/auxiliary/issue-29181.rs b/src/test/auxiliary/issue-29181.rs new file mode 100644 index 0000000000..361f1ea550 --- /dev/null +++ b/src/test/auxiliary/issue-29181.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. + +#![crate_type="lib"] + +pub mod foo { + pub use super::*; +} diff --git a/src/test/auxiliary/lint_for_crate.rs b/src/test/auxiliary/lint_for_crate.rs index 708fcafcb5..7ae161a86a 100644 --- a/src/test/auxiliary/lint_for_crate.rs +++ b/src/test/auxiliary/lint_for_crate.rs @@ -15,10 +15,12 @@ #[macro_use] extern crate rustc; extern crate rustc_front; +extern crate syntax; -use rustc::lint::{Context, LintPass, LintPassObject, LintArray}; +use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LateLintPassObject, LintArray}; use rustc::plugin::Registry; -use rustc_front::{hir, attr}; +use rustc_front::hir; +use syntax::attr; declare_lint!(CRATE_NOT_OKAY, Warn, "crate not marked with #![crate_okay]"); @@ -28,8 +30,10 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(CRATE_NOT_OKAY) } +} - fn check_crate(&mut self, cx: &Context, krate: &hir::Crate) { +impl LateLintPass for Pass { + fn check_crate(&mut self, cx: &LateContext, krate: &hir::Crate) { if !attr::contains_name(&krate.attrs, "crate_okay") { cx.span_lint(CRATE_NOT_OKAY, krate.span, "crate is not marked with #![crate_okay]"); @@ -39,5 +43,5 @@ impl LintPass for Pass { #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { - reg.register_lint_pass(box Pass as LintPassObject); + reg.register_late_lint_pass(box Pass as LateLintPassObject); } diff --git a/src/test/auxiliary/lint_group_plugin_test.rs b/src/test/auxiliary/lint_group_plugin_test.rs index adc194fa45..81bd76211c 100644 --- a/src/test/auxiliary/lint_group_plugin_test.rs +++ b/src/test/auxiliary/lint_group_plugin_test.rs @@ -20,7 +20,7 @@ extern crate rustc_front; extern crate rustc; use rustc_front::hir; -use rustc::lint::{Context, LintPass, LintPassObject, LintArray}; +use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LateLintPassObject, LintArray}; use rustc::plugin::Registry; declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'"); @@ -33,9 +33,11 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(TEST_LINT, PLEASE_LINT) } +} - fn check_item(&mut self, cx: &Context, it: &hir::Item) { - match &*it.ident.name.as_str() { +impl LateLintPass for Pass { + fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { + match &*it.name.as_str() { "lintme" => cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'"), "pleaselintme" => cx.span_lint(PLEASE_LINT, it.span, "item is named 'pleaselintme'"), _ => {} @@ -45,6 +47,6 @@ impl LintPass for Pass { #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { - reg.register_lint_pass(box Pass as LintPassObject); + reg.register_late_lint_pass(box Pass as LateLintPassObject); reg.register_lint_group("lint_me", vec![TEST_LINT, PLEASE_LINT]); } diff --git a/src/test/auxiliary/lint_output_format.rs b/src/test/auxiliary/lint_output_format.rs index 51fad3ce3c..8794119a86 100644 --- a/src/test/auxiliary/lint_output_format.rs +++ b/src/test/auxiliary/lint_output_format.rs @@ -15,7 +15,7 @@ #![unstable(feature = "test_feature", issue = "0")] #[stable(feature = "test_feature", since = "1.0.0")] -#[deprecated(since = "1.0.0")] +#[deprecated(since = "1.0.0", reason = "text")] pub fn foo() -> usize { 20 } diff --git a/src/test/auxiliary/lint_plugin_test.rs b/src/test/auxiliary/lint_plugin_test.rs index e6f91db230..a0036745d9 100644 --- a/src/test/auxiliary/lint_plugin_test.rs +++ b/src/test/auxiliary/lint_plugin_test.rs @@ -13,15 +13,16 @@ #![feature(plugin_registrar)] #![feature(box_syntax, rustc_private)] -extern crate rustc_front; +extern crate syntax; // Load rustc as a plugin to get macros #[macro_use] extern crate rustc; -use rustc::lint::{Context, LintPass, LintPassObject, LintArray}; +use rustc::lint::{EarlyContext, LintContext, LintPass, EarlyLintPass, + EarlyLintPassObject, LintArray}; use rustc::plugin::Registry; -use rustc_front::hir; +use syntax::ast; declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'"); struct Pass; @@ -30,9 +31,11 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(TEST_LINT) } +} - fn check_item(&mut self, cx: &Context, it: &hir::Item) { - if it.ident.name == "lintme" { +impl EarlyLintPass for Pass { + fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) { + if it.ident.name.as_str() == "lintme" { cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'"); } } @@ -40,5 +43,5 @@ impl LintPass for Pass { #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { - reg.register_lint_pass(box Pass as LintPassObject); + reg.register_early_lint_pass(box Pass as EarlyLintPassObject); } diff --git a/src/test/auxiliary/lint_stability.rs b/src/test/auxiliary/lint_stability.rs index 60097393a2..260361634a 100644 --- a/src/test/auxiliary/lint_stability.rs +++ b/src/test/auxiliary/lint_stability.rs @@ -14,14 +14,14 @@ #![stable(feature = "lint_stability", since = "1.0.0")] #[stable(feature = "test_feature", since = "1.0.0")] -#[deprecated(since = "1.0.0")] +#[deprecated(since = "1.0.0", reason = "text")] pub fn deprecated() {} #[stable(feature = "test_feature", since = "1.0.0")] #[deprecated(since = "1.0.0", reason = "text")] pub fn deprecated_text() {} #[unstable(feature = "test_feature", issue = "0")] -#[deprecated(since = "1.0.0")] +#[deprecated(since = "1.0.0", reason = "text")] pub fn deprecated_unstable() {} #[unstable(feature = "test_feature", issue = "0")] #[deprecated(since = "1.0.0", reason = "text")] @@ -34,7 +34,7 @@ pub fn unstable_text() {} #[stable(feature = "rust1", since = "1.0.0")] pub fn stable() {} -#[stable(feature = "rust1", since = "1.0.0", reason = "text")] +#[stable(feature = "rust1", since = "1.0.0")] pub fn stable_text() {} #[stable(feature = "rust1", since = "1.0.0")] @@ -42,14 +42,14 @@ pub struct MethodTester; impl MethodTester { #[stable(feature = "test_feature", since = "1.0.0")] - #[deprecated(since = "1.0.0")] + #[deprecated(since = "1.0.0", reason = "text")] pub fn method_deprecated(&self) {} #[stable(feature = "test_feature", since = "1.0.0")] #[deprecated(since = "1.0.0", reason = "text")] pub fn method_deprecated_text(&self) {} #[unstable(feature = "test_feature", issue = "0")] - #[deprecated(since = "1.0.0")] + #[deprecated(since = "1.0.0", reason = "text")] pub fn method_deprecated_unstable(&self) {} #[unstable(feature = "test_feature", issue = "0")] #[deprecated(since = "1.0.0", reason = "text")] @@ -62,21 +62,21 @@ impl MethodTester { #[stable(feature = "rust1", since = "1.0.0")] pub fn method_stable(&self) {} - #[stable(feature = "rust1", since = "1.0.0", reason = "text")] + #[stable(feature = "rust1", since = "1.0.0")] pub fn method_stable_text(&self) {} } #[stable(feature = "test_feature", since = "1.0.0")] pub trait Trait { #[stable(feature = "test_feature", since = "1.0.0")] - #[deprecated(since = "1.0.0")] + #[deprecated(since = "1.0.0", reason = "text")] fn trait_deprecated(&self) {} #[stable(feature = "test_feature", since = "1.0.0")] #[deprecated(since = "1.0.0", reason = "text")] fn trait_deprecated_text(&self) {} #[unstable(feature = "test_feature", issue = "0")] - #[deprecated(since = "1.0.0")] + #[deprecated(since = "1.0.0", reason = "text")] fn trait_deprecated_unstable(&self) {} #[unstable(feature = "test_feature", issue = "0")] #[deprecated(since = "1.0.0", reason = "text")] @@ -89,7 +89,7 @@ pub trait Trait { #[stable(feature = "rust1", since = "1.0.0")] fn trait_stable(&self) {} - #[stable(feature = "rust1", since = "1.0.0", reason = "text")] + #[stable(feature = "rust1", since = "1.0.0")] fn trait_stable_text(&self) {} } @@ -99,12 +99,12 @@ impl Trait for MethodTester {} pub trait UnstableTrait { fn dummy(&self) { } } #[stable(feature = "test_feature", since = "1.0.0")] -#[deprecated(since = "1.0.0")] +#[deprecated(since = "1.0.0", reason = "text")] pub struct DeprecatedStruct { #[stable(feature = "test_feature", since = "1.0.0")] pub i: isize } #[unstable(feature = "test_feature", issue = "0")] -#[deprecated(since = "1.0.0")] +#[deprecated(since = "1.0.0", reason = "text")] pub struct DeprecatedUnstableStruct { #[stable(feature = "test_feature", since = "1.0.0")] pub i: isize } @@ -118,10 +118,10 @@ pub struct StableStruct { } #[stable(feature = "test_feature", since = "1.0.0")] -#[deprecated(since = "1.0.0")] +#[deprecated(since = "1.0.0", reason = "text")] pub struct DeprecatedUnitStruct; #[unstable(feature = "test_feature", issue = "0")] -#[deprecated(since = "1.0.0")] +#[deprecated(since = "1.0.0", reason = "text")] pub struct DeprecatedUnstableUnitStruct; #[unstable(feature = "test_feature", issue = "0")] pub struct UnstableUnitStruct; @@ -131,10 +131,10 @@ pub struct StableUnitStruct; #[stable(feature = "test_feature", since = "1.0.0")] pub enum Enum { #[stable(feature = "test_feature", since = "1.0.0")] - #[deprecated(since = "1.0.0")] + #[deprecated(since = "1.0.0", reason = "text")] DeprecatedVariant, #[unstable(feature = "test_feature", issue = "0")] - #[deprecated(since = "1.0.0")] + #[deprecated(since = "1.0.0", reason = "text")] DeprecatedUnstableVariant, #[unstable(feature = "test_feature", issue = "0")] UnstableVariant, @@ -144,10 +144,10 @@ pub enum Enum { } #[stable(feature = "test_feature", since = "1.0.0")] -#[deprecated(since = "1.0.0")] +#[deprecated(since = "1.0.0", reason = "text")] pub struct DeprecatedTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub isize); #[unstable(feature = "test_feature", issue = "0")] -#[deprecated(since = "1.0.0")] +#[deprecated(since = "1.0.0", reason = "text")] pub struct DeprecatedUnstableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub isize); #[unstable(feature = "test_feature", issue = "0")] pub struct UnstableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub isize); diff --git a/src/test/auxiliary/lint_stability_fields.rs b/src/test/auxiliary/lint_stability_fields.rs index b45af89dd3..44b4abd38b 100644 --- a/src/test/auxiliary/lint_stability_fields.rs +++ b/src/test/auxiliary/lint_stability_fields.rs @@ -18,7 +18,7 @@ pub struct Stable { pub inherit: u8, // it's a lie (stable doesn't inherit) #[unstable(feature = "test_feature", issue = "0")] pub override1: u8, - #[deprecated(since = "1.0.0")] + #[deprecated(since = "1.0.0", reason = "text")] #[unstable(feature = "test_feature", issue = "0")] pub override2: u8, } @@ -27,14 +27,14 @@ pub struct Stable { pub struct Stable2(#[stable(feature = "rust1", since = "1.0.0")] pub u8, #[unstable(feature = "test_feature", issue = "0")] pub u8, #[unstable(feature = "test_feature", issue = "0")] - #[deprecated(since = "1.0.0")] pub u8); + #[deprecated(since = "1.0.0", reason = "text")] pub u8); #[unstable(feature = "test_feature", issue = "0")] pub struct Unstable { pub inherit: u8, #[stable(feature = "rust1", since = "1.0.0")] pub override1: u8, - #[deprecated(since = "1.0.0")] + #[deprecated(since = "1.0.0", reason = "text")] #[unstable(feature = "test_feature", issue = "0")] pub override2: u8, } @@ -43,10 +43,10 @@ pub struct Unstable { pub struct Unstable2(pub u8, #[stable(feature = "rust1", since = "1.0.0")] pub u8, #[unstable(feature = "test_feature", issue = "0")] - #[deprecated(since = "1.0.0")] pub u8); + #[deprecated(since = "1.0.0", reason = "text")] pub u8); #[unstable(feature = "test_feature", issue = "0")] -#[deprecated(feature = "rust1", since = "1.0.0")] +#[deprecated(since = "1.0.0", reason = "text")] pub struct Deprecated { pub inherit: u8, #[stable(feature = "rust1", since = "1.0.0")] @@ -56,7 +56,7 @@ pub struct Deprecated { } #[unstable(feature = "test_feature", issue = "0")] -#[deprecated(feature = "rust1", since = "1.0.0")] +#[deprecated(since = "1.0.0", reason = "text")] pub struct Deprecated2(pub u8, #[stable(feature = "rust1", since = "1.0.0")] pub u8, #[unstable(feature = "test_feature", issue = "0")] pub u8); diff --git a/src/test/auxiliary/procedural_mbe_matching.rs b/src/test/auxiliary/procedural_mbe_matching.rs index 8c7ad2293e..296d1e431f 100644 --- a/src/test/auxiliary/procedural_mbe_matching.rs +++ b/src/test/auxiliary/procedural_mbe_matching.rs @@ -33,7 +33,7 @@ fn expand_mbe_matches(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) let mac_expr = match TokenTree::parse(cx, &mbe_matcher[..], args) { Success(map) => { - match (&*map[&str_to_ident("matched")], &*map[&str_to_ident("pat")]) { + match (&*map[&str_to_ident("matched").name], &*map[&str_to_ident("pat").name]) { (&MatchedNonterminal(NtExpr(ref matched_expr)), &MatchedSeq(ref pats, seq_sp)) => { let pats: Vec> = pats.iter().map(|pat_nt| diff --git a/src/test/auxiliary/sepcomp_cci_lib.rs b/src/test/auxiliary/sepcomp_cci_lib.rs index d62b987140..c57d161d8f 100644 --- a/src/test/auxiliary/sepcomp_cci_lib.rs +++ b/src/test/auxiliary/sepcomp_cci_lib.rs @@ -13,5 +13,4 @@ pub fn cci_fn() -> usize { 1200 } -#[inline] -pub static CCI_STATIC: usize = 34; +pub const CCI_CONST: usize = 34; diff --git a/src/test/auxiliary/xcrate_static_addresses.rs b/src/test/auxiliary/xcrate_static_addresses.rs index 652f11a71e..d0da80e31b 100644 --- a/src/test/auxiliary/xcrate_static_addresses.rs +++ b/src/test/auxiliary/xcrate_static_addresses.rs @@ -8,13 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[inline(never)] pub static global: isize = 3; -#[inline(never)] static global0: isize = 4; -#[inline(never)] pub static global2: &'static isize = &global0; pub fn verify_same(a: &'static isize) { diff --git a/src/test/bench/core-map.rs b/src/test/bench/core-map.rs index ebb8036bac..a72e348c72 100644 --- a/src/test/bench/core-map.rs +++ b/src/test/bench/core-map.rs @@ -126,8 +126,7 @@ fn main() { println!("{} keys", n_keys); - // FIXME: #9970 - println!("{}", "\nBTreeMap:"); + println!("\nBTreeMap:"); { let mut map: BTreeMap = BTreeMap::new(); @@ -145,8 +144,7 @@ fn main() { vector(&mut map, n_keys, &rand); } - // FIXME: #9970 - println!("{}", "\nHashMap:"); + println!("\nHashMap:"); { let mut map: HashMap = HashMap::new(); diff --git a/src/test/bench/shootout-fasta-redux.rs b/src/test/bench/shootout-fasta-redux.rs index 963a007c68..6d64c50b82 100644 --- a/src/test/bench/shootout-fasta-redux.rs +++ b/src/test/bench/shootout-fasta-redux.rs @@ -39,198 +39,338 @@ // OF THE POSSIBILITY OF SUCH DAMAGE. use std::cmp::min; -use std::env; -use std::io; -use std::io::prelude::*; +use std::io::{self, Write}; +use std::sync::{Arc, Mutex}; +use std::thread; + const LINE_LEN: usize = 60; + +const BLOCK_LINES: usize = 512; +const BLOCK_THOROUGHPUT: usize = LINE_LEN * BLOCK_LINES; +const BLOCK_LEN: usize = BLOCK_THOROUGHPUT + BLOCK_LINES; + +const STDIN_BUF: usize = (LINE_LEN + 1) * 1024; const LOOKUP_SIZE: usize = 4 * 1024; const LOOKUP_SCALE: f32 = (LOOKUP_SIZE - 1) as f32; -// Random number generator constants -const IM: u32 = 139968; -const IA: u32 = 3877; -const IC: u32 = 29573; - -const ALU: &'static str = "GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTG\ - GGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGA\ - GACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAA\ - AATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAAT\ - CCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAAC\ - CCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTG\ - CACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA"; - -const NULL_AMINO_ACID: AminoAcid = AminoAcid { c: ' ' as u8, p: 0.0 }; - -static IUB: [AminoAcid;15] = [ - AminoAcid { c: 'a' as u8, p: 0.27 }, - AminoAcid { c: 'c' as u8, p: 0.12 }, - AminoAcid { c: 'g' as u8, p: 0.12 }, - AminoAcid { c: 't' as u8, p: 0.27 }, - AminoAcid { c: 'B' as u8, p: 0.02 }, - AminoAcid { c: 'D' as u8, p: 0.02 }, - AminoAcid { c: 'H' as u8, p: 0.02 }, - AminoAcid { c: 'K' as u8, p: 0.02 }, - AminoAcid { c: 'M' as u8, p: 0.02 }, - AminoAcid { c: 'N' as u8, p: 0.02 }, - AminoAcid { c: 'R' as u8, p: 0.02 }, - AminoAcid { c: 'S' as u8, p: 0.02 }, - AminoAcid { c: 'V' as u8, p: 0.02 }, - AminoAcid { c: 'W' as u8, p: 0.02 }, - AminoAcid { c: 'Y' as u8, p: 0.02 }, -]; - -static HOMO_SAPIENS: [AminoAcid;4] = [ - AminoAcid { c: 'a' as u8, p: 0.3029549426680 }, - AminoAcid { c: 'c' as u8, p: 0.1979883004921 }, - AminoAcid { c: 'g' as u8, p: 0.1975473066391 }, - AminoAcid { c: 't' as u8, p: 0.3015094502008 }, -]; - -fn sum_and_scale(a: &'static [AminoAcid]) -> Vec { - let mut p = 0f32; - let mut result: Vec = a.iter().map(|a_i| { - p += a_i.p; - AminoAcid { c: a_i.c, p: p * LOOKUP_SCALE } - }).collect(); - let result_len = result.len(); - result[result_len - 1].p = LOOKUP_SCALE; - result -} +const ALU: &'static [u8] = + b"GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG\ + GAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGA\ + CCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAAT\ + ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA\ + GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG\ + AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC\ + AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA"; + +const IUB: &'static [(u8, f32)] = + &[(b'a', 0.27), (b'c', 0.12), (b'g', 0.12), + (b't', 0.27), (b'B', 0.02), (b'D', 0.02), + (b'H', 0.02), (b'K', 0.02), (b'M', 0.02), + (b'N', 0.02), (b'R', 0.02), (b'S', 0.02), + (b'V', 0.02), (b'W', 0.02), (b'Y', 0.02)]; + +const HOMOSAPIENS: &'static [(u8, f32)] = + &[(b'a', 0.3029549426680), + (b'c', 0.1979883004921), + (b'g', 0.1975473066391), + (b't', 0.3015094502008)]; + +// We need a specific Rng, +// so implement this manually + +const MODULUS: u32 = 139968; +const MULTIPLIER: u32 = 3877; +const ADDITIVE: u32 = 29573; + +// Why doesn't rust already have this? +// Algorithm directly taken from Wikipedia +fn powmod(mut base: u64, mut exponent: u32, modulus: u64) -> u64 { + let mut ret = 1; + base %= modulus; -#[derive(Copy, Clone)] -struct AminoAcid { - c: u8, - p: f32, + while exponent > 0 { + if exponent & 1 == 1 { + ret *= base; + ret %= modulus; + } + exponent >>= 1; + base *= base; + base %= modulus; + } + + ret } -struct RepeatFasta<'a, W:'a> { - alu: &'static str, - out: &'a mut W +// Just a typical LCRNG +pub struct Rng { + last: u32 } -impl<'a, W: Write> RepeatFasta<'a, W> { - fn new(alu: &'static str, w: &'a mut W) -> RepeatFasta<'a, W> { - RepeatFasta { alu: alu, out: w } +impl Rng { + pub fn new() -> Rng { + Rng { last: 42 } } - fn make(&mut self, n: usize) -> io::Result<()> { - let alu_len = self.alu.len(); - let mut buf = vec![0; alu_len + LINE_LEN]; - let alu: &[u8] = self.alu.as_bytes(); + pub fn max_value() -> u32 { + MODULUS - 1 + } - for (slot, val) in buf.iter_mut().zip(alu) { - *slot = *val; - } - let buf_len = buf.len(); - for (slot, val) in buf[alu_len..buf_len].iter_mut().zip(&alu[..LINE_LEN]) { - *slot = *val; - } + pub fn normalize(p: f32) -> u32 { + (p * MODULUS as f32).floor() as u32 + } - let mut pos = 0; - let mut bytes; - let mut n = n; - while n > 0 { - bytes = min(LINE_LEN, n); - try!(self.out.write_all(&buf[pos..pos + bytes])); - try!(self.out.write_all(&[b'\n'])); - pos += bytes; - if pos > alu_len { - pos -= alu_len; - } - n -= bytes; - } - Ok(()) + pub fn gen(&mut self) -> u32 { + self.last = (self.last * MULTIPLIER + ADDITIVE) % MODULUS; + self.last } -} -fn make_lookup(a: &[AminoAcid]) -> [AminoAcid;LOOKUP_SIZE] { - let mut lookup = [ NULL_AMINO_ACID;LOOKUP_SIZE ]; - let mut j = 0; - for (i, slot) in lookup.iter_mut().enumerate() { - while a[j].p < (i as f32) { - j += 1; - } - *slot = a[j]; + // This allows us to fast-forward the RNG, + // allowing us to run it in parallel. + pub fn future(&self, n: u32) -> Rng { + let a = MULTIPLIER as u64; + let b = ADDITIVE as u64; + let m = MODULUS as u64; + + // (a^n - 1) mod (a-1) m + // x_k = ((a^n x_0 mod m) + --------------------- b) mod m + // a - 1 + // + // Since (a - 1) divides (a^n - 1) mod (a-1) m, + // the subtraction does not overflow and thus can be non-modular. + // + let new_seed = + (powmod(a, n, m) * self.last as u64) % m + + (powmod(a, n, (a-1) * m) - 1) / (a-1) * b; + + Rng { last: (new_seed % m) as u32 } } - lookup } -struct RandomFasta<'a, W:'a> { - seed: u32, - lookup: [AminoAcid;LOOKUP_SIZE], - out: &'a mut W, + +// This will end up keeping track of threads, like +// in the other multithreaded Rust version, in +// order to keep writes in order. +// +// This is stolen from another multithreaded Rust +// implementation, although that implementation +// was not able to parallelize the RNG itself. +struct BlockSubmitter { + writer: W, + pub waiting_on: usize, } -impl<'a, W: Write> RandomFasta<'a, W> { - fn new(w: &'a mut W, a: &[AminoAcid]) -> RandomFasta<'a, W> { - RandomFasta { - seed: 42, - out: w, - lookup: make_lookup(a), +impl BlockSubmitter { + fn submit(&mut self, data: &[u8], block_num: usize) -> Option> { + if block_num == self.waiting_on { + self.waiting_on += 1; + Some(self.submit_async(data)) + } + else { + None } } - fn rng(&mut self, max: f32) -> f32 { - self.seed = (self.seed * IA + IC) % IM; - (max * self.seed as f32) / (IM as f32) + fn submit_async(&mut self, data: &[u8]) -> io::Result<()> { + self.writer.write_all(data) } +} + + +// For repeating strings as output +fn fasta_static( + writer: &mut W, + header: &[u8], + data: &[u8], + mut n: usize +) -> io::Result<()> +{ + // The aim here is to print a short(ish) string cyclically + // with line breaks as appropriate. + // + // The secret technique is to repeat the string such that + // any wanted line is a single offset in the string. + // + // This technique is stolen from the Haskell version. + + try!(writer.write_all(header)); - fn nextc(&mut self) -> u8 { - let r = self.rng(LOOKUP_SCALE); - for i in (r as usize..LOOKUP_SIZE) { - if self.lookup[i].p >= r { - return self.lookup[i].c; + // Maximum offset is data.len(), + // Maximum read len is LINE_LEN + let stream = data.iter().cloned().cycle(); + let mut extended: Vec = stream.take(data.len() + LINE_LEN + 1).collect(); + + let mut offset = 0; + while n > 0 { + let write_len = min(LINE_LEN, n); + let end = offset + write_len; + n -= write_len; + + let tmp = extended[end]; + extended[end] = b'\n'; + try!(writer.write_all(&extended[offset..end + 1])); + extended[end] = tmp; + + offset = end; + offset %= data.len(); + } + + Ok(()) +} + + +// For RNG streams as output +fn fasta( + submitter: &Arc>>, + header: &[u8], + table: &'static [(u8, f32)], + rng: &mut Rng, + n: usize +) -> io::Result<()> +{ + // Here the lookup table is part of the algorithm and needs the + // original probabilities (scaled with the LOOKUP_SCALE), because + // Isaac says so :-) + fn sum_and_scale(a: &'static [(u8, f32)]) -> Vec<(u8, f32)> { + let mut p = 0f32; + let mut result: Vec<(u8, f32)> = a.iter().map(|e| { + p += e.1; + (e.0, p * LOOKUP_SCALE) + }).collect(); + let result_len = result.len(); + result[result_len - 1].1 = LOOKUP_SCALE; + result + } + + fn make_lookup(a: &[(u8, f32)]) -> [(u8, f32); LOOKUP_SIZE] { + let mut lookup = [(0, 0f32); LOOKUP_SIZE]; + let mut j = 0; + for (i, slot) in lookup.iter_mut().enumerate() { + while a[j].1 < (i as f32) { + j += 1; } + *slot = a[j]; } - unreachable!(); + lookup + } + + { + try!(submitter.lock().unwrap().submit_async(header)); + } + + let lookup_table = Arc::new(make_lookup(&sum_and_scale(table))); + + let thread_count = 4; + let mut threads = Vec::new(); + for block_num in (0..thread_count) { + let offset = BLOCK_THOROUGHPUT * block_num; + + let local_submitter = submitter.clone(); + let local_lookup_table = lookup_table.clone(); + let local_rng = rng.future(offset as u32); + + threads.push(thread::spawn(move || { + gen_block( + local_submitter, + local_lookup_table, + local_rng, + n.saturating_sub(offset), + block_num, + thread_count + ) + })); + } + + for thread in threads { + try!(thread.join().unwrap()); } - fn make(&mut self, n: usize) -> io::Result<()> { - let lines = n / LINE_LEN; - let chars_left = n % LINE_LEN; - let mut buf = [0;LINE_LEN + 1]; + *rng = rng.future(n as u32); - for _ in 0..lines { - for i in 0..LINE_LEN { - buf[i] = self.nextc(); + Ok(()) +} + +// A very optimized writer. +// I have a feeling a simpler version wouldn't slow +// things down too much, though, since the RNG +// is the really heavy hitter. +fn gen_block( + submitter: Arc>>, + lookup_table: Arc<[(u8, f32)]>, + mut rng: Rng, + mut length: usize, + mut block_num: usize, + block_stride: usize, +) -> io::Result<()> +{ + // Include newlines in block + length += length / LINE_LEN; + let block: &mut [u8] = &mut [b'\n'; BLOCK_LEN]; + + while length > 0 { + { + let gen_into = &mut block[..min(length, BLOCK_LEN)]; + + // Write random numbers, skipping newlines + for (i, byte) in gen_into.iter_mut().enumerate() { + if (i + 1) % (LINE_LEN + 1) != 0 { + let p = rng.gen() as f32 * (LOOKUP_SCALE / MODULUS as f32); + *byte = lookup_table[p as usize..LOOKUP_SIZE].iter().find( + |le| le.1 >= p).unwrap().0; + } } - buf[LINE_LEN] = '\n' as u8; - try!(self.out.write(&buf)); } - for i in 0..chars_left { - buf[i] = self.nextc(); + + let write_out = { + if length >= BLOCK_LEN { &mut *block } + else if length % (LINE_LEN + 1) == 0 { &mut block[..length] } + else { &mut block[..length + 1] } + }; + + *write_out.last_mut().unwrap() = b'\n'; + loop { + // Make sure to release lock before calling `yield_now` + let res = { submitter.lock().unwrap().submit(write_out, block_num) }; + + match res { + Some(result) => { try!(result); break; } + None => std::thread::yield_now() + } } - self.out.write_all(&buf[..chars_left]) + block_num += block_stride; + rng = rng.future((BLOCK_THOROUGHPUT * (block_stride - 1)) as u32); + length = length.saturating_sub(BLOCK_LEN * (block_stride - 1)); + + length = length.saturating_sub(BLOCK_LEN); } + + Ok(()) } -fn main() { - let mut args = env::args(); - let n = if args.len() > 1 { - args.nth(1).unwrap().parse::().unwrap() - } else { - 5 - }; +fn run(writer: W) -> io::Result<()> { + let n = std::env::args_os().nth(1) + .and_then(|s| s.into_string().ok()) + .and_then(|n| n.parse().ok()) + .unwrap_or(1000); - let stdout = io::stdout(); - let mut out = stdout.lock(); + let rng = &mut Rng::new(); - out.write_all(b">ONE Homo sapiens alu\n").unwrap(); - { - let mut repeat = RepeatFasta::new(ALU, &mut out); - repeat.make(n * 2).unwrap(); - } + // Use automatic buffering for the static version... + let mut writer = io::BufWriter::with_capacity(STDIN_BUF, writer); + try!(fasta_static(&mut writer, b">ONE Homo sapiens alu\n", ALU, n * 2)); + + // ...but the dynamic version does its own buffering already + let writer = try!(writer.into_inner()); + let submitter = Arc::new(Mutex::new(BlockSubmitter { writer: writer, waiting_on: 0 })); - out.write_all(b">TWO IUB ambiguity codes\n").unwrap(); - let iub = sum_and_scale(&IUB); - let mut random = RandomFasta::new(&mut out, &iub); - random.make(n * 3).unwrap(); + { submitter.lock().unwrap().waiting_on = 0; } + try!(fasta(&submitter, b">TWO IUB ambiguity codes\n", &IUB, rng, n * 3)); + { submitter.lock().unwrap().waiting_on = 0; } + try!(fasta(&submitter, b">THREE Homo sapiens frequency\n", &HOMOSAPIENS, rng, n * 5)); - random.out.write_all(b">THREE Homo sapiens frequency\n").unwrap(); - let homo_sapiens = sum_and_scale(&HOMO_SAPIENS); - random.lookup = make_lookup(&homo_sapiens); - random.make(n * 5).unwrap(); + Ok(()) +} - random.out.write_all(b"\n").unwrap(); +fn main() { + run(io::stdout()).unwrap() } diff --git a/src/test/bench/shootout-fasta.rs b/src/test/bench/shootout-fasta.rs index accf525b4e..a5731f150c 100644 --- a/src/test/bench/shootout-fasta.rs +++ b/src/test/bench/shootout-fasta.rs @@ -39,114 +39,332 @@ // OF THE POSSIBILITY OF SUCH DAMAGE. use std::cmp::min; -use std::env; -use std::fs::File; -use std::io::{self, BufWriter}; -use std::io::prelude::*; +use std::io::{self, Write}; +use std::sync::{Arc, Mutex}; +use std::thread; -const LINE_LENGTH: usize = 60; -const IM: u32 = 139968; -struct MyRandom { +const LINE_LEN: usize = 60; + +const BLOCK_LINES: usize = 512; +const BLOCK_THOROUGHPUT: usize = LINE_LEN * BLOCK_LINES; +const BLOCK_LEN: usize = BLOCK_THOROUGHPUT + BLOCK_LINES; + +const STDIN_BUF: usize = (LINE_LEN + 1) * 1024; + + +const ALU: &'static [u8] = + b"GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG\ + GAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGA\ + CCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAAT\ + ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA\ + GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG\ + AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC\ + AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA"; + +const IUB: &'static [(u8, f32)] = + &[(b'a', 0.27), (b'c', 0.12), (b'g', 0.12), + (b't', 0.27), (b'B', 0.02), (b'D', 0.02), + (b'H', 0.02), (b'K', 0.02), (b'M', 0.02), + (b'N', 0.02), (b'R', 0.02), (b'S', 0.02), + (b'V', 0.02), (b'W', 0.02), (b'Y', 0.02)]; + +const HOMOSAPIENS: &'static [(u8, f32)] = + &[(b'a', 0.3029549426680), + (b'c', 0.1979883004921), + (b'g', 0.1975473066391), + (b't', 0.3015094502008)]; + + +// We need a specific Rng, +// so implement this manually +const MODULUS: u32 = 139968; +const MULTIPLIER: u32 = 3877; +const ADDITIVE: u32 = 29573; + +// Why doesn't rust already have this? +// Algorithm directly taken from Wikipedia +fn powmod(mut base: u64, mut exponent: u32, modulus: u64) -> u64 { + let mut ret = 1; + base %= modulus; + + while exponent > 0 { + if exponent & 1 == 1 { + ret *= base; + ret %= modulus; + } + exponent >>= 1; + base *= base; + base %= modulus; + } + + ret +} + +// Just a typical LCRNG +pub struct Rng { last: u32 } -impl MyRandom { - fn new() -> MyRandom { MyRandom { last: 42 } } - fn normalize(p: f32) -> u32 {(p * IM as f32).floor() as u32} - fn gen(&mut self) -> u32 { - self.last = (self.last * 3877 + 29573) % IM; + +impl Rng { + pub fn new() -> Rng { + Rng { last: 42 } + } + + pub fn max_value() -> u32 { + MODULUS - 1 + } + + pub fn normalize(p: f32) -> u32 { + (p * MODULUS as f32).floor() as u32 + } + + pub fn gen(&mut self) -> u32 { + self.last = (self.last * MULTIPLIER + ADDITIVE) % MODULUS; self.last } + + // This allows us to fast-forward the RNG, + // allowing us to run it in parallel. + pub fn future(&self, n: u32) -> Rng { + let a = MULTIPLIER as u64; + let b = ADDITIVE as u64; + let m = MODULUS as u64; + + // (a^n - 1) mod (a-1) m + // x_k = ((a^n x_0 mod m) + --------------------- b) mod m + // a - 1 + // + // Since (a - 1) divides (a^n - 1) mod (a-1) m, + // the subtraction does not overflow and thus can be non-modular. + // + let new_seed = + (powmod(a, n, m) * self.last as u64) % m + + (powmod(a, n, (a-1) * m) - 1) / (a-1) * b; + + Rng { last: (new_seed % m) as u32 } + } } -struct AAGen<'a> { - rng: &'a mut MyRandom, - data: Vec<(u32, u8)> + +// This will end up keeping track of threads, like +// in the other multithreaded Rust version, in +// order to keep writes in order. +// +// This is stolen from another multithreaded Rust +// implementation, although that implementation +// was not able to parallelize the RNG itself. +struct BlockSubmitter { + writer: W, + pub waiting_on: usize, } -impl<'a> AAGen<'a> { - fn new<'b>(rng: &'b mut MyRandom, aa: &[(char, f32)]) -> AAGen<'b> { - let mut cum = 0.; - let data = aa.iter() - .map(|&(ch, p)| { cum += p; (MyRandom::normalize(cum), ch as u8) }) - .collect(); - AAGen { rng: rng, data: data } + +impl BlockSubmitter { + fn submit(&mut self, data: &[u8], block_num: usize) -> Option> { + if block_num == self.waiting_on { + self.waiting_on += 1; + Some(self.submit_async(data)) + } + else { + None + } } -} -impl<'a> Iterator for AAGen<'a> { - type Item = u8; - - fn next(&mut self) -> Option { - let r = self.rng.gen(); - self.data.iter() - .skip_while(|pc| pc.0 < r) - .map(|&(_, c)| c) - .next() + + fn submit_async(&mut self, data: &[u8]) -> io::Result<()> { + self.writer.write_all(data) } } -fn make_fasta>( - wr: &mut W, header: &str, mut it: I, mut n: usize) - -> io::Result<()> + +// For repeating strings as output +fn fasta_static( + writer: &mut W, + header: &[u8], + data: &[u8], + mut n: usize +) -> io::Result<()> { - try!(wr.write(header.as_bytes())); - let mut line = [0; LINE_LENGTH + 1]; + // The aim here is to print a short(ish) string cyclically + // with line breaks as appropriate. + // + // The secret technique is to repeat the string such that + // any wanted line is a single offset in the string. + // + // This technique is stolen from the Haskell version. + + try!(writer.write_all(header)); + + // Maximum offset is data.len(), + // Maximum read len is LINE_LEN + let stream = data.iter().cloned().cycle(); + let mut extended: Vec = stream.take(data.len() + LINE_LEN + 1).collect(); + + let mut offset = 0; while n > 0 { - let nb = min(LINE_LENGTH, n); - for i in 0..nb { - line[i] = it.next().unwrap(); + let write_len = min(LINE_LEN, n); + let end = offset + write_len; + n -= write_len; + + let tmp = extended[end]; + extended[end] = b'\n'; + try!(writer.write_all(&extended[offset..end + 1])); + extended[end] = tmp; + + offset = end; + offset %= data.len(); + } + + Ok(()) +} + + +// For RNG streams as output +fn fasta( + submitter: &Arc>>, + header: &[u8], + table: &[(u8, f32)], + rng: &mut Rng, + n: usize +) -> io::Result<()> +{ + // There's another secret technique in use here: + // we generate a lookup table to cache search of the + // aa buffer. + // + // The secret technique used is stolen from Haskell's + // implementation, and is the main secret to the Haskell + // implementation's speed. + fn gen_lookup_table(aa: &[(u8, f32)]) -> Vec { + let mut table = Vec::with_capacity(Rng::max_value() as usize + 1); + + let mut cumulative_prob = 0.0; + let mut cumulative_norm = 0; + + for &(byte, prob) in aa { + let last_norm = cumulative_norm; + cumulative_prob += prob; + cumulative_norm = min(Rng::max_value(), Rng::normalize(cumulative_prob)) + 1; + + table.extend((0..cumulative_norm - last_norm).map(|_| byte)); } - n -= nb; - line[nb] = '\n' as u8; - try!(wr.write(&line[..nb+1])); + + table + } + + { + try!(submitter.lock().unwrap().submit_async(header)); } + + let lookup_table = Arc::new(gen_lookup_table(table)); + + let thread_count = 4; // avoid external dependency + let mut threads = Vec::new(); + for block_num in (0..thread_count) { + let offset = BLOCK_THOROUGHPUT * block_num; + + let local_submitter = submitter.clone(); + let local_lookup_table = lookup_table.clone(); + let local_rng = rng.future(offset as u32); + + threads.push(thread::spawn(move || { + gen_block( + local_submitter, + local_lookup_table, + local_rng, + n.saturating_sub(offset), + block_num, + thread_count + ) + })); + } + + for thread in threads { + try!(thread.join().unwrap()); + } + + *rng = rng.future(n as u32); + Ok(()) } -fn run(writer: &mut W) -> io::Result<()> { - let mut args = env::args(); - let n = if env::var_os("RUST_BENCH").is_some() { - 25000000 - } else if args.len() <= 1 { - 1000 - } else { - args.nth(1).unwrap().parse().unwrap() - }; - - let rng = &mut MyRandom::new(); - let alu = - "GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG\ - GAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGA\ - CCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAAT\ - ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA\ - GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG\ - AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC\ - AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA"; - let iub = &[('a', 0.27), ('c', 0.12), ('g', 0.12), - ('t', 0.27), ('B', 0.02), ('D', 0.02), - ('H', 0.02), ('K', 0.02), ('M', 0.02), - ('N', 0.02), ('R', 0.02), ('S', 0.02), - ('V', 0.02), ('W', 0.02), ('Y', 0.02)]; - let homosapiens = &[('a', 0.3029549426680), - ('c', 0.1979883004921), - ('g', 0.1975473066391), - ('t', 0.3015094502008)]; - - try!(make_fasta(writer, ">ONE Homo sapiens alu\n", - alu.as_bytes().iter().cycle().cloned(), n * 2)); - try!(make_fasta(writer, ">TWO IUB ambiguity codes\n", - AAGen::new(rng, iub), n * 3)); - try!(make_fasta(writer, ">THREE Homo sapiens frequency\n", - AAGen::new(rng, homosapiens), n * 5)); - - writer.flush() +// A very optimized writer. +// I have a feeling a simpler version wouldn't slow +// things down too much, though, since the RNG +// is the really heavy hitter. +fn gen_block( + submitter: Arc>>, + lookup_table: Arc>, + mut rng: Rng, + mut length: usize, + mut block_num: usize, + block_stride: usize, +) -> io::Result<()> +{ + // Include newlines in block + length += length / LINE_LEN; + let block: &mut [u8] = &mut [b'\n'; BLOCK_LEN]; + + while length > 0 { + { + let gen_into = &mut block[..min(length, BLOCK_LEN)]; + + // Write random numbers, skipping newlines + for (i, byte) in gen_into.iter_mut().enumerate() { + if (i + 1) % (LINE_LEN + 1) != 0 { + *byte = lookup_table[rng.gen() as usize]; + } + } + } + + let write_out = { + if length >= BLOCK_LEN { &mut *block } + else if length % (LINE_LEN + 1) == 0 { &mut block[..length] } + else { &mut block[..length + 1] } + }; + + *write_out.last_mut().unwrap() = b'\n'; + loop { + match submitter.lock().unwrap().submit(write_out, block_num) { + Some(result) => { try!(result); break; } + None => std::thread::yield_now() + } + } + block_num += block_stride; + rng = rng.future((BLOCK_THOROUGHPUT * (block_stride - 1)) as u32); + length = length.saturating_sub(BLOCK_LEN * (block_stride - 1)); + + length = length.saturating_sub(BLOCK_LEN); + } + + Ok(()) } + +fn run(writer: W) -> io::Result<()> { + let n = std::env::args_os().nth(1) + .and_then(|s| s.into_string().ok()) + .and_then(|n| n.parse().ok()) + .unwrap_or(1000); + + let rng = &mut Rng::new(); + + // Use automatic buffering for the static version... + let mut writer = io::BufWriter::with_capacity(STDIN_BUF, writer); + try!(fasta_static(&mut writer, b">ONE Homo sapiens alu\n", ALU, n * 2)); + + // ...but the dynamic version does its own buffering already + let writer = try!(writer.into_inner()); + let submitter = Arc::new(Mutex::new(BlockSubmitter { writer: writer, waiting_on: 0 })); + + { submitter.lock().unwrap().waiting_on = 0; } + try!(fasta(&submitter, b">TWO IUB ambiguity codes\n", &IUB, rng, n * 3)); + { submitter.lock().unwrap().waiting_on = 0; } + try!(fasta(&submitter, b">THREE Homo sapiens frequency\n", &HOMOSAPIENS, rng, n * 5)); + + Ok(()) +} + + fn main() { - let res = if env::var_os("RUST_BENCH").is_some() { - let mut file = BufWriter::new(File::create("./shootout-fasta.data").unwrap()); - run(&mut file) - } else { - run(&mut io::stdout()) - }; - res.unwrap() + run(io::stdout()).unwrap() } diff --git a/src/test/bench/shootout-mandelbrot.rs b/src/test/bench/shootout-mandelbrot.rs index 232d6b414f..21ac23253c 100644 --- a/src/test/bench/shootout-mandelbrot.rs +++ b/src/test/bench/shootout-mandelbrot.rs @@ -192,7 +192,7 @@ fn write_line(init_i: f64, vec_init_r: &[f64], res: &mut Vec) { i += 2; } - res.push(cur_byte^-1); + res.push(cur_byte^!0); } } diff --git a/src/test/bench/shootout-nbody.rs b/src/test/bench/shootout-nbody.rs index 5ba678ce18..1a9ea8bff0 100644 --- a/src/test/bench/shootout-nbody.rs +++ b/src/test/bench/shootout-nbody.rs @@ -39,134 +39,175 @@ // OF THE POSSIBILITY OF SUCH DAMAGE. use std::mem; +use std::ops::{Add, Sub, Mul}; const PI: f64 = 3.141592653589793; const SOLAR_MASS: f64 = 4.0 * PI * PI; const YEAR: f64 = 365.24; const N_BODIES: usize = 5; +const N_PAIRS: usize = N_BODIES * (N_BODIES - 1) / 2; -static BODIES: [Planet;N_BODIES] = [ +const BODIES: [Planet; N_BODIES] = [ // Sun Planet { - x: 0.0, y: 0.0, z: 0.0, - vx: 0.0, vy: 0.0, vz: 0.0, + pos: Vec3(0.0, 0.0, 0.0), + vel: Vec3(0.0, 0.0, 0.0), mass: SOLAR_MASS, }, // Jupiter Planet { - x: 4.84143144246472090e+00, - y: -1.16032004402742839e+00, - z: -1.03622044471123109e-01, - vx: 1.66007664274403694e-03 * YEAR, - vy: 7.69901118419740425e-03 * YEAR, - vz: -6.90460016972063023e-05 * YEAR, + pos: Vec3(4.84143144246472090e+00, + -1.16032004402742839e+00, + -1.03622044471123109e-01), + vel: Vec3(1.66007664274403694e-03 * YEAR, + 7.69901118419740425e-03 * YEAR, + -6.90460016972063023e-05 * YEAR), mass: 9.54791938424326609e-04 * SOLAR_MASS, }, // Saturn Planet { - x: 8.34336671824457987e+00, - y: 4.12479856412430479e+00, - z: -4.03523417114321381e-01, - vx: -2.76742510726862411e-03 * YEAR, - vy: 4.99852801234917238e-03 * YEAR, - vz: 2.30417297573763929e-05 * YEAR, + pos: Vec3(8.34336671824457987e+00, + 4.12479856412430479e+00, + -4.03523417114321381e-01), + vel: Vec3(-2.76742510726862411e-03 * YEAR, + 4.99852801234917238e-03 * YEAR, + 2.30417297573763929e-05 * YEAR), mass: 2.85885980666130812e-04 * SOLAR_MASS, }, // Uranus Planet { - x: 1.28943695621391310e+01, - y: -1.51111514016986312e+01, - z: -2.23307578892655734e-01, - vx: 2.96460137564761618e-03 * YEAR, - vy: 2.37847173959480950e-03 * YEAR, - vz: -2.96589568540237556e-05 * YEAR, + pos: Vec3(1.28943695621391310e+01, + -1.51111514016986312e+01, + -2.23307578892655734e-01), + vel: Vec3(2.96460137564761618e-03 * YEAR, + 2.37847173959480950e-03 * YEAR, + -2.96589568540237556e-05 * YEAR), mass: 4.36624404335156298e-05 * SOLAR_MASS, }, // Neptune Planet { - x: 1.53796971148509165e+01, - y: -2.59193146099879641e+01, - z: 1.79258772950371181e-01, - vx: 2.68067772490389322e-03 * YEAR, - vy: 1.62824170038242295e-03 * YEAR, - vz: -9.51592254519715870e-05 * YEAR, + pos: Vec3(1.53796971148509165e+01, + -2.59193146099879641e+01, + 1.79258772950371181e-01), + vel: Vec3(2.68067772490389322e-03 * YEAR, + 1.62824170038242295e-03 * YEAR, + -9.51592254519715870e-05 * YEAR), mass: 5.15138902046611451e-05 * SOLAR_MASS, }, ]; -#[derive(Copy, Clone)] +/// A 3d Vector type with oveloaded operators to improve readability. +#[derive(Clone, Copy)] +struct Vec3(pub f64, pub f64, pub f64); + +impl Vec3 { + fn zero() -> Self { Vec3(0.0, 0.0, 0.0) } + + fn norm(&self) -> f64 { self.squared_norm().sqrt() } + + fn squared_norm(&self) -> f64 { + self.0 * self.0 + self.1 * self.1 + self.2 * self.2 + } +} + +impl Add for Vec3 { + type Output = Self; + fn add(self, rhs: Self) -> Self { + Vec3(self.0 + rhs.0, self.1 + rhs.1, self.2 + rhs.2) + } +} + +impl Sub for Vec3 { + type Output = Self; + fn sub(self, rhs: Self) -> Self { + Vec3(self.0 - rhs.0, self.1 - rhs.1, self.2 - rhs.2) + } +} + +impl Mul for Vec3 { + type Output = Self; + fn mul(self, rhs: f64) -> Self { + Vec3(self.0 * rhs, self.1 * rhs, self.2 * rhs) + } +} + +#[derive(Clone, Copy)] struct Planet { - x: f64, y: f64, z: f64, - vx: f64, vy: f64, vz: f64, + pos: Vec3, + vel: Vec3, mass: f64, } -fn advance(bodies: &mut [Planet;N_BODIES], dt: f64, steps: isize) { - for _ in 0..steps { - let mut b_slice: &mut [_] = bodies; - loop { - let bi = match shift_mut_ref(&mut b_slice) { - Some(bi) => bi, - None => break - }; - for bj in &mut *b_slice { - let dx = bi.x - bj.x; - let dy = bi.y - bj.y; - let dz = bi.z - bj.z; - - let d2 = dx * dx + dy * dy + dz * dz; - let mag = dt / (d2 * d2.sqrt()); - - let massj_mag = bj.mass * mag; - bi.vx -= dx * massj_mag; - bi.vy -= dy * massj_mag; - bi.vz -= dz * massj_mag; - - let massi_mag = bi.mass * mag; - bj.vx += dx * massi_mag; - bj.vy += dy * massi_mag; - bj.vz += dz * massi_mag; - } - bi.x += dt * bi.vx; - bi.y += dt * bi.vy; - bi.z += dt * bi.vz; +/// Computes all pairwise position differences between the planets. +fn pairwise_diffs(bodies: &[Planet; N_BODIES], diff: &mut [Vec3; N_PAIRS]) { + let mut bodies = bodies.iter(); + let mut diff = diff.iter_mut(); + while let Some(bi) = bodies.next() { + for bj in bodies.clone() { + *diff.next().unwrap() = bi.pos - bj.pos; + } + } +} + +/// Computes the magnitude of the force between each pair of planets. +fn magnitudes(diff: &[Vec3; N_PAIRS], dt: f64, mag: &mut [f64; N_PAIRS]) { + for (mag, diff) in mag.iter_mut().zip(diff.iter()) { + let d2 = diff.squared_norm(); + *mag = dt / (d2 * d2.sqrt()); + } +} + +/// Updates the velocities of the planets by computing their gravitational +/// accelerations and performing one step of Euler integration. +fn update_velocities(bodies: &mut [Planet; N_BODIES], dt: f64, + diff: &mut [Vec3; N_PAIRS], mag: &mut [f64; N_PAIRS]) { + pairwise_diffs(bodies, diff); + magnitudes(&diff, dt, mag); + + let mut bodies = &mut bodies[..]; + let mut mag = mag.iter(); + let mut diff = diff.iter(); + while let Some(bi) = shift_mut_ref(&mut bodies) { + for bj in bodies.iter_mut() { + let diff = *diff.next().unwrap(); + let mag = *mag.next().unwrap(); + bi.vel = bi.vel - diff * (bj.mass * mag); + bj.vel = bj.vel + diff * (bi.mass * mag); } } } -fn energy(bodies: &[Planet;N_BODIES]) -> f64 { +/// Advances the solar system by one timestep by first updating the +/// velocities and then integrating the positions using the updated velocities. +/// +/// Note: the `diff` & `mag` arrays are effectively scratch space. They're +/// provided as arguments to avoid re-zeroing them every time `advance` is +/// called. +fn advance(mut bodies: &mut [Planet; N_BODIES], dt: f64, + diff: &mut [Vec3; N_PAIRS], mag: &mut [f64; N_PAIRS]) { + update_velocities(bodies, dt, diff, mag); + for body in bodies.iter_mut() { + body.pos = body.pos + body.vel * dt; + } +} + +/// Computes the total energy of the solar system. +fn energy(bodies: &[Planet; N_BODIES]) -> f64 { let mut e = 0.0; let mut bodies = bodies.iter(); - loop { - let bi = match bodies.next() { - Some(bi) => bi, - None => break - }; - e += (bi.vx * bi.vx + bi.vy * bi.vy + bi.vz * bi.vz) * bi.mass / 2.0; - for bj in bodies.clone() { - let dx = bi.x - bj.x; - let dy = bi.y - bj.y; - let dz = bi.z - bj.z; - let dist = (dx * dx + dy * dy + dz * dz).sqrt(); - e -= bi.mass * bj.mass / dist; - } + while let Some(bi) = bodies.next() { + e += bi.vel.squared_norm() * bi.mass / 2.0 + - bi.mass * bodies.clone() + .map(|bj| bj.mass / (bi.pos - bj.pos).norm()) + .fold(0.0, |a, b| a + b); } e } -fn offset_momentum(bodies: &mut [Planet;N_BODIES]) { - let mut px = 0.0; - let mut py = 0.0; - let mut pz = 0.0; - for bi in bodies.iter() { - px += bi.vx * bi.mass; - py += bi.vy * bi.mass; - pz += bi.vz * bi.mass; - } - let sun = &mut bodies[0]; - sun.vx = - px / SOLAR_MASS; - sun.vy = - py / SOLAR_MASS; - sun.vz = - pz / SOLAR_MASS; +/// Offsets the sun's velocity to make the overall momentum of the system zero. +fn offset_momentum(bodies: &mut [Planet; N_BODIES]) { + let p = bodies.iter().fold(Vec3::zero(), |v, b| v + b.vel * b.mass); + bodies[0].vel = p * (-1.0 / bodies[0].mass); } fn main() { @@ -178,11 +219,15 @@ fn main() { .unwrap_or(1000) }; let mut bodies = BODIES; + let mut diff = [Vec3::zero(); N_PAIRS]; + let mut mag = [0.0f64; N_PAIRS]; offset_momentum(&mut bodies); println!("{:.9}", energy(&bodies)); - advance(&mut bodies, 0.01, n); + for _ in 0..n { + advance(&mut bodies, 0.01, &mut diff, &mut mag); + } println!("{:.9}", energy(&bodies)); } diff --git a/src/test/codegen/adjustments.rs b/src/test/codegen/adjustments.rs new file mode 100644 index 0000000000..a61fa84398 --- /dev/null +++ b/src/test/codegen/adjustments.rs @@ -0,0 +1,39 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +// Hack to get the correct size for the length part in slices +// CHECK: @helper([[USIZE:i[0-9]+]]) +#[no_mangle] +fn helper(_: usize) { +} + +// CHECK-LABEL: @no_op_slice_adjustment +#[no_mangle] +pub fn no_op_slice_adjustment(x: &[u8]) -> &[u8] { + // We used to generate an extra alloca and memcpy for the block's trailing expression value, so + // check that we copy directly to the return value slot +// CHECK: [[SRC:%[0-9]+]] = bitcast { i8*, [[USIZE]] }* %x to +// CHECK: [[DST:%[0-9]+]] = bitcast { i8*, [[USIZE]] }* %sret_slot to i8* +// CHECK: call void @llvm.memcpy.{{.*}}(i8* [[DST]], i8* [[SRC]], + { x } +} + +// CHECK-LABEL: @no_op_slice_adjustment2 +#[no_mangle] +pub fn no_op_slice_adjustment2(x: &[u8]) -> &[u8] { + // We used to generate an extra alloca and memcpy for the function's return value, so check + // that there's no memcpy (the slice is written to sret_slot element-wise) +// CHECK-NOT: call void @llvm.memcpy. + no_op_slice_adjustment(x) +} diff --git a/src/test/codegen/coercions.rs b/src/test/codegen/coercions.rs index 2a136d7024..c8c9f5b407 100644 --- a/src/test/codegen/coercions.rs +++ b/src/test/codegen/coercions.rs @@ -10,6 +10,8 @@ // compile-flags: -C no-prepopulate-passes +#![crate_type = "lib"] + static X: i32 = 5; // CHECK-LABEL: @raw_ptr_to_raw_ptr_noop diff --git a/src/test/codegen/consts.rs b/src/test/codegen/consts.rs new file mode 100644 index 0000000000..6b4e626df9 --- /dev/null +++ b/src/test/codegen/consts.rs @@ -0,0 +1,66 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +// Below, these constants are defined as enum variants that by itself would +// have a lower alignment than the enum type. Ensure that we mark them +// correctly with the higher alignment of the enum. + +// CHECK: @STATIC = {{.*}}, align 4 + +// This checks the constants from inline_enum_const +// CHECK: @const{{[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: @const{{[0-9]+}} = {{.*}}, align 4 + +#[derive(Copy, Clone)] + +// repr(i16) is required for the {low,high}_align_const test +#[repr(i16)] +pub enum E { + A(A), + B(B), +} + +#[no_mangle] +pub static STATIC: E = E::A(0); + +// CHECK-LABEL: @static_enum_const +#[no_mangle] +pub fn static_enum_const() -> E { + STATIC +} + +// CHECK-LABEL: @inline_enum_const +#[no_mangle] +pub fn inline_enum_const() -> E { + E::A(0) +} + +// CHECK-LABEL: @low_align_const +#[no_mangle] +pub fn low_align_const() -> E { +// Check that low_align_const and high_align_const use the same constant +// CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{[0-9]+}}, i8* {{.*}} [[LOW_HIGH:@const[0-9]+]] + E::A(0) +} + +// CHECK-LABEL: @high_align_const +#[no_mangle] +pub fn high_align_const() -> E { +// Check that low_align_const and high_align_const use the same constant +// CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{[0-9]}}, i8* {{.*}} [[LOW_HIGH]] + E::A(0) +} diff --git a/src/test/codegen/extern-functions.rs b/src/test/codegen/extern-functions.rs index 4c30b5ce02..ff9d54e67e 100644 --- a/src/test/codegen/extern-functions.rs +++ b/src/test/codegen/extern-functions.rs @@ -10,6 +10,7 @@ // compile-flags: -C no-prepopulate-passes +#![crate_type = "lib"] #![feature(unwind_attributes)] extern { diff --git a/src/test/codegen/function-arguments.rs b/src/test/codegen/function-arguments.rs index 7706c97380..90ced88324 100644 --- a/src/test/codegen/function-arguments.rs +++ b/src/test/codegen/function-arguments.rs @@ -10,6 +10,7 @@ // compile-flags: -C no-prepopulate-passes +#![crate_type = "lib"] #![feature(allocator)] pub struct S { diff --git a/src/test/codegen/gdb_debug_script_load.rs b/src/test/codegen/gdb_debug_script_load.rs new file mode 100644 index 0000000000..efaca29752 --- /dev/null +++ b/src/test/codegen/gdb_debug_script_load.rs @@ -0,0 +1,25 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-tidy-linelength +// ignore-windows +// ignore-macos + +// compile-flags: -g -C no-prepopulate-passes + +#![feature(start)] + +// CHECK-LABEL: @main +// CHECK: load volatile i8, i8* getelementptr inbounds ([[B:\[[0-9]* x i8\]]], [[B]]* @__rustc_debug_gdb_scripts_section__, i32 0, i32 0), align 1 + +#[start] +fn start(_: isize, _: *const *const u8) -> isize { + return 0; +} diff --git a/src/test/codegen/link_section.rs b/src/test/codegen/link_section.rs index 99b43552b0..5ad3854c05 100644 --- a/src/test/codegen/link_section.rs +++ b/src/test/codegen/link_section.rs @@ -10,6 +10,8 @@ // compile-flags: -C no-prepopulate-passes +#![crate_type = "lib"] + // CHECK: @VAR1 = constant i32 1, section ".test_one" #[no_mangle] #[link_section = ".test_one"] diff --git a/src/test/codegen/loads.rs b/src/test/codegen/loads.rs index b51da69fef..21f23b6ea1 100644 --- a/src/test/codegen/loads.rs +++ b/src/test/codegen/loads.rs @@ -10,6 +10,8 @@ // compile-flags: -C no-prepopulate-passes +#![crate_type = "lib"] + pub struct Bytes { a: u8, b: u8, diff --git a/src/test/codegen/match.rs b/src/test/codegen/match.rs new file mode 100644 index 0000000000..ac47f6082e --- /dev/null +++ b/src/test/codegen/match.rs @@ -0,0 +1,30 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +pub enum E { + A, + B, +} + +// CHECK-LABEL: @exhaustive_match +#[no_mangle] +pub fn exhaustive_match(e: E) { +// CHECK: switch{{.*}}, label %[[DEFAULT:[a-zA-Z0-9_]+]] +// CHECK: [[DEFAULT]]: +// CHECK-NEXT: unreachable + match e { + E::A => (), + E::B => (), + } +} diff --git a/src/test/codegen/refs.rs b/src/test/codegen/refs.rs new file mode 100644 index 0000000000..08eec0045f --- /dev/null +++ b/src/test/codegen/refs.rs @@ -0,0 +1,30 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +// Hack to get the correct size for the length part in slices +// CHECK: @helper([[USIZE:i[0-9]+]]) +#[no_mangle] +fn helper(_: usize) { +} + +// CHECK-LABEL: @ref_dst +#[no_mangle] +pub fn ref_dst(s: &[u8]) { + // We used to generate an extra alloca and memcpy to ref the dst, so check that we copy + // directly to the alloca for "x" +// CHECK: [[SRC:%[0-9]+]] = bitcast { i8*, [[USIZE]] }* %s to i8* +// CHECK: [[DST:%[0-9]+]] = bitcast { i8*, [[USIZE]] }* %x to i8* +// CHECK: call void @llvm.memcpy.{{.*}}(i8* [[DST]], i8* [[SRC]], + let x = &*s; +} diff --git a/src/test/codegen/stores.rs b/src/test/codegen/stores.rs index 72862ea8b6..5d2d47e1bf 100644 --- a/src/test/codegen/stores.rs +++ b/src/test/codegen/stores.rs @@ -10,6 +10,8 @@ // compile-flags: -C no-prepopulate-passes +#![crate_type = "lib"] + pub struct Bytes { a: u8, b: u8, diff --git a/src/test/compile-fail/assignment-operator-unimplemented.rs b/src/test/compile-fail/assignment-operator-unimplemented.rs index fef27af595..5b24c6bd79 100644 --- a/src/test/compile-fail/assignment-operator-unimplemented.rs +++ b/src/test/compile-fail/assignment-operator-unimplemented.rs @@ -13,5 +13,5 @@ struct Foo; fn main() { let mut a = Foo; let ref b = Foo; - a += *b; //~ Error: binary assignment operation `+=` cannot be applied to types `Foo` and `Foo` + a += *b; //~ Error: binary assignment operation `+=` cannot be applied to type `Foo` } diff --git a/src/test/compile-fail/associated-types-invalid-trait-ref-issue-18865.rs b/src/test/compile-fail/associated-types-invalid-trait-ref-issue-18865.rs index b6c4d59c84..d48cff405a 100644 --- a/src/test/compile-fail/associated-types-invalid-trait-ref-issue-18865.rs +++ b/src/test/compile-fail/associated-types-invalid-trait-ref-issue-18865.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test that we report an error if the trait ref in an qualified type +// Test that we report an error if the trait ref in a qualified type // uses invalid type arguments. trait Foo { diff --git a/src/test/compile-fail/attr-usage-inline.rs b/src/test/compile-fail/attr-usage-inline.rs new file mode 100644 index 0000000000..c6b9b01633 --- /dev/null +++ b/src/test/compile-fail/attr-usage-inline.rs @@ -0,0 +1,19 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(dead_code)] + +#[inline] +fn f() {} + +#[inline] //~ ERROR: attribute should be applied to function +struct S; + +fn main() {} diff --git a/src/test/compile-fail/attr-usage-repr.rs b/src/test/compile-fail/attr-usage-repr.rs new file mode 100644 index 0000000000..9bad6a8389 --- /dev/null +++ b/src/test/compile-fail/attr-usage-repr.rs @@ -0,0 +1,41 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(dead_code)] +#![feature(repr_simd)] + +#[repr(C)] //~ ERROR: attribute should be applied to struct or enum +fn f() {} + +#[repr(C)] +struct SExtern(f64, f64); + +#[repr(packed)] +struct SPacked(f64, f64); + +#[repr(simd)] +struct SSimd(f64, f64); + +#[repr(i8)] //~ ERROR: attribute should be applied to enum +struct SInt(f64, f64); + +#[repr(C)] +enum EExtern { A, B } + +#[repr(packed)] //~ ERROR: attribute should be applied to struct +enum EPacked { A, B } + +#[repr(simd)] //~ ERROR: attribute should be applied to struct +enum ESimd { A, B } + +#[repr(i8)] +enum EInt { A, B } + +fn main() {} diff --git a/src/test/compile-fail/augmented-assignments-feature-gate-cross.rs b/src/test/compile-fail/augmented-assignments-feature-gate-cross.rs new file mode 100644 index 0000000000..c26d6cf4fe --- /dev/null +++ b/src/test/compile-fail/augmented-assignments-feature-gate-cross.rs @@ -0,0 +1,25 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:augmented_assignments.rs + +// Test that the feature gate is needed when using augmented assignments that were overloaded in +// another crate + +extern crate augmented_assignments; + +use augmented_assignments::Int; + +fn main() { + let mut x = Int(0); + x += 1; + //~^ error: overloaded augmented assignments are not stable + // | help: add #![feature(augmented_assignments)] to the crate root to enable +} diff --git a/src/test/compile-fail/augmented-assignments-feature-gate.rs b/src/test/compile-fail/augmented-assignments-feature-gate.rs new file mode 100644 index 0000000000..0db8f9858f --- /dev/null +++ b/src/test/compile-fail/augmented-assignments-feature-gate.rs @@ -0,0 +1,26 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::ops::AddAssign; + +struct Int(i32); + +impl AddAssign for Int { + fn add_assign(&mut self, _: i32) { + unimplemented!() + } +} + +fn main() { + let mut x = Int(0); + x += 1; + //~^ error: overloaded augmented assignments are not stable + // | help: add #![feature(augmented_assignments)] to the crate root to enable +} diff --git a/src/test/compile-fail/augmented-assignments-trait.rs b/src/test/compile-fail/augmented-assignments-trait.rs new file mode 100644 index 0000000000..83e8d1f3b3 --- /dev/null +++ b/src/test/compile-fail/augmented-assignments-trait.rs @@ -0,0 +1,24 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::ops::AddAssign; +//~^ error: use of unstable library feature 'op_assign_traits' + +struct Int(i32); + +impl AddAssign for Int { + //~^ error: use of unstable library feature 'op_assign_traits' + fn add_assign(&mut self, _: Int) { + //~^ error: use of unstable library feature 'op_assign_traits' + unimplemented!() + } +} + +fn main() {} diff --git a/src/test/compile-fail/augmented-assignments.rs b/src/test/compile-fail/augmented-assignments.rs new file mode 100644 index 0000000000..ee64171fd8 --- /dev/null +++ b/src/test/compile-fail/augmented-assignments.rs @@ -0,0 +1,33 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(augmented_assignments)] + +use std::ops::AddAssign; + +struct Int(i32); + +impl AddAssign for Int { + fn add_assign(&mut self, _: Int) { + unimplemented!() + } +} + +fn main() { + let mut x = Int(1); + x //~ error: use of moved value: `x` + += + x; //~ note: `x` moved here because it has type `Int`, which is non-copyable + + let y = Int(2); + y //~ error: cannot borrow immutable local variable `y` as mutable + += + Int(1); +} diff --git a/src/test/compile-fail/autoderef-full-lval.rs b/src/test/compile-fail/autoderef-full-lval.rs index 2c5749e0d5..0d666a4920 100644 --- a/src/test/compile-fail/autoderef-full-lval.rs +++ b/src/test/compile-fail/autoderef-full-lval.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(unknown_features)] #![feature(box_syntax)] struct clam { diff --git a/src/test/compile-fail/borrow-tuple-fields.rs b/src/test/compile-fail/borrow-tuple-fields.rs index b1abbad525..f3417fafe9 100644 --- a/src/test/compile-fail/borrow-tuple-fields.rs +++ b/src/test/compile-fail/borrow-tuple-fields.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(unknown_features)] #![feature(box_syntax)] struct Foo(Box, isize); diff --git a/src/test/compile-fail/borrowck-argument.rs b/src/test/compile-fail/borrowck-argument.rs new file mode 100644 index 0000000000..3230689e53 --- /dev/null +++ b/src/test/compile-fail/borrowck-argument.rs @@ -0,0 +1,43 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[derive(Copy, Clone)] +struct S; + +impl S { + fn mutate(&mut self) { + } +} + +fn func(arg: S) { + arg.mutate(); //~ ERROR: cannot borrow immutable argument +} + +impl S { + fn method(&self, arg: S) { + arg.mutate(); //~ ERROR: cannot borrow immutable argument + } +} + +trait T { + fn default(&self, arg: S) { + arg.mutate(); //~ ERROR: cannot borrow immutable argument + } +} + +impl T for S {} + +fn main() { + let s = S; + func(s); + s.method(s); + s.default(s); + (|arg: S| { arg.mutate() })(s); //~ ERROR: cannot borrow immutable argument +} diff --git a/src/test/compile-fail/borrowck-borrow-overloaded-auto-deref-mut.rs b/src/test/compile-fail/borrowck-borrow-overloaded-auto-deref-mut.rs index dd278faa0d..497b0e63ed 100644 --- a/src/test/compile-fail/borrowck-borrow-overloaded-auto-deref-mut.rs +++ b/src/test/compile-fail/borrowck-borrow-overloaded-auto-deref-mut.rs @@ -111,12 +111,9 @@ fn assign_field4<'a>(x: &'a mut Own) { x.y = 3; //~ ERROR cannot borrow } -// FIXME(eddyb) #12825 This shouldn't attempt to call deref_mut. -/* fn deref_imm_method(x: Own) { let __isize = x.get(); } -*/ fn deref_mut_method1(x: Own) { x.set(0, 0); //~ ERROR cannot borrow diff --git a/src/test/compile-fail/borrowck-closures-unique.rs b/src/test/compile-fail/borrowck-closures-unique.rs index 9410181659..3646a68f06 100644 --- a/src/test/compile-fail/borrowck-closures-unique.rs +++ b/src/test/compile-fail/borrowck-closures-unique.rs @@ -43,7 +43,7 @@ fn d(x: &mut isize) { } fn e(x: &mut isize) { - let c1 = || x = panic!(); //~ ERROR closure cannot assign to immutable local variable + let c1 = || x = panic!(); //~ ERROR closure cannot assign to immutable argument } fn main() { diff --git a/src/test/compile-fail/borrowck-lend-flow-if.rs b/src/test/compile-fail/borrowck-lend-flow-if.rs index a0a6e54e94..a6ce36a550 100644 --- a/src/test/compile-fail/borrowck-lend-flow-if.rs +++ b/src/test/compile-fail/borrowck-lend-flow-if.rs @@ -23,8 +23,7 @@ fn for_func(_f: F) where F: FnOnce() -> bool { panic!() } fn produce() -> T { panic!(); } fn inc(v: &mut Box) { - *v = box() (**v + 1); - //~^ WARN deprecated syntax + *v = box (**v + 1); } fn pre_freeze_cond() { diff --git a/src/test/compile-fail/borrowck-lend-flow-loop.rs b/src/test/compile-fail/borrowck-lend-flow-loop.rs index 9356eeda60..f09e7ffd7e 100644 --- a/src/test/compile-fail/borrowck-lend-flow-loop.rs +++ b/src/test/compile-fail/borrowck-lend-flow-loop.rs @@ -22,8 +22,7 @@ fn cond() -> bool { panic!() } fn produce() -> T { panic!(); } fn inc(v: &mut Box) { - *v = box() (**v + 1); - //~^ WARN deprecated syntax + *v = box (**v + 1); } fn loop_overarching_alias_mut() { diff --git a/src/test/compile-fail/borrowck-lend-flow.rs b/src/test/compile-fail/borrowck-lend-flow.rs index c3dcddf858..1ed779cfaa 100644 --- a/src/test/compile-fail/borrowck-lend-flow.rs +++ b/src/test/compile-fail/borrowck-lend-flow.rs @@ -23,8 +23,7 @@ fn for_func(_f: F) where F: FnOnce() -> bool { panic!() } fn produce() -> T { panic!(); } fn inc(v: &mut Box) { - *v = box() (**v + 1); - //~^ WARN deprecated syntax + *v = box (**v + 1); } fn pre_freeze() { diff --git a/src/test/compile-fail/borrowck-loan-in-overloaded-op.rs b/src/test/compile-fail/borrowck-loan-in-overloaded-op.rs index 558475c28d..a9079cfc27 100644 --- a/src/test/compile-fail/borrowck-loan-in-overloaded-op.rs +++ b/src/test/compile-fail/borrowck-loan-in-overloaded-op.rs @@ -22,8 +22,7 @@ impl Add for foo { fn add(self, f: foo) -> foo { let foo(box i) = self; let foo(box j) = f; - foo(box() (i + j)) - //~^ WARN deprecated syntax + foo(box (i + j)) } } diff --git a/src/test/borrowck-loan-of-static-data-issue-27616.rs b/src/test/compile-fail/borrowck-loan-of-static-data-issue-27616.rs similarity index 100% rename from src/test/borrowck-loan-of-static-data-issue-27616.rs rename to src/test/compile-fail/borrowck-loan-of-static-data-issue-27616.rs diff --git a/src/test/compile-fail/borrowck-mut-borrow-linear-errors.rs b/src/test/compile-fail/borrowck-mut-borrow-linear-errors.rs new file mode 100644 index 0000000000..38e0e27a7b --- /dev/null +++ b/src/test/compile-fail/borrowck-mut-borrow-linear-errors.rs @@ -0,0 +1,28 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test to ensure we only report an error for the first issued loan that +// conflicts with a new loan, as opposed to every issued loan. This keeps us +// down to O(n) errors (for n problem lines), instead of O(n^2) errors. + +fn main() { + let mut x = 1; + let mut addr; + loop { + match 1 { + 1 => { addr = &mut x; } + //~^ ERROR cannot borrow `x` as mutable more than once at a time + 2 => { addr = &mut x; } + //~^ ERROR cannot borrow `x` as mutable more than once at a time + _ => { addr = &mut x; } + //~^ ERROR cannot borrow `x` as mutable more than once at a time + } + } +} diff --git a/src/test/compile-fail/borrowck-unboxed-closures.rs b/src/test/compile-fail/borrowck-unboxed-closures.rs index 3eca850e49..1c12ca9c1d 100644 --- a/src/test/compile-fail/borrowck-unboxed-closures.rs +++ b/src/test/compile-fail/borrowck-unboxed-closures.rs @@ -17,7 +17,7 @@ fn a isize>(mut f: F) { } fn b isize>(f: F) { - f(1, 2); //~ ERROR cannot borrow immutable local variable + f(1, 2); //~ ERROR cannot borrow immutable argument } fn c isize>(f: F) { diff --git a/src/test/compile-fail/cast-as-bool.rs b/src/test/compile-fail/cast-as-bool.rs index 92cbbaa1cb..52a4950022 100644 --- a/src/test/compile-fail/cast-as-bool.rs +++ b/src/test/compile-fail/cast-as-bool.rs @@ -9,7 +9,7 @@ // except according to those terms. fn main() { - let u = (5 as bool); + let u = 5 as bool; //~^ ERROR cannot cast as `bool` //~^^ HELP compare with zero instead } diff --git a/src/test/compile-fail/const-err.rs b/src/test/compile-fail/const-err.rs new file mode 100644 index 0000000000..be67e06d99 --- /dev/null +++ b/src/test/compile-fail/const-err.rs @@ -0,0 +1,36 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[allow(exceeding_bitshifts)] +#[deny(const_err)] + +fn black_box(_: T) { + unimplemented!() +} + +const BLA: u8 = 200u8 + 200u8; +//~^ ERROR attempted to add with overflow + +fn main() { + let a = -std::i8::MIN; + //~^ WARN attempted to negate with overflow + let b = 200u8 + 200u8 + 200u8; + //~^ WARN attempted to add with overflow + //~^^ WARN attempted to add with overflow + let c = 200u8 * 4; + //~^ WARN attempted to mul with overflow + let d = 42u8 - (42u8 + 1); + //~^ WARN attempted to sub with overflow + let _e = BLA; + black_box(a); + black_box(b); + black_box(c); + black_box(d); +} diff --git a/src/test/compile-fail/const-eval-overflow.rs b/src/test/compile-fail/const-eval-overflow.rs index f991e5328c..daa60955ad 100644 --- a/src/test/compile-fail/const-eval-overflow.rs +++ b/src/test/compile-fail/const-eval-overflow.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(negate_unsigned)] - #![allow(unused_imports)] #![feature(negate_unsigned)] diff --git a/src/test/compile-fail/const-eval-span.rs b/src/test/compile-fail/const-eval-span.rs new file mode 100644 index 0000000000..3e75afcda6 --- /dev/null +++ b/src/test/compile-fail/const-eval-span.rs @@ -0,0 +1,24 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that error in constant evaluation of enum discriminant +// provides the context for what caused the evaluation. + +struct S(i32); + +const CONSTANT: S = S(0); +//~^ ERROR: constant evaluation error: non-constant path in constant expression [E0080] + +enum E { + V = CONSTANT, + //~^ NOTE: for enum discriminant here +} + +fn main() {} diff --git a/src/test/compile-fail/const-fn-destructuring-arg.rs b/src/test/compile-fail/const-fn-destructuring-arg.rs new file mode 100644 index 0000000000..1642c04106 --- /dev/null +++ b/src/test/compile-fail/const-fn-destructuring-arg.rs @@ -0,0 +1,18 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// test that certain things are disallowed in const fn signatures + +#![feature(const_fn)] + +// no destructuring +const fn i((a, b): (u32, u32)) -> u32 { a + b } //~ ERROR: E0022 + +fn main() {} diff --git a/src/test/compile-fail/const-fn-stability-calls-2.rs b/src/test/compile-fail/const-fn-stability-calls-2.rs index dd9a415311..59e0db7b35 100644 --- a/src/test/compile-fail/const-fn-stability-calls-2.rs +++ b/src/test/compile-fail/const-fn-stability-calls-2.rs @@ -17,5 +17,5 @@ extern crate const_fn_lib; use const_fn_lib::foo; fn main() { - let x: [usize; foo()] = []; //~ ERROR unsupported constant expr + let x: [usize; foo()] = []; //~ ERROR non-constant path in constant expr } diff --git a/src/test/compile-fail/const-len-underflow-separate-spans.rs b/src/test/compile-fail/const-len-underflow-separate-spans.rs index cd021a0d3b..786c72b66f 100644 --- a/src/test/compile-fail/const-len-underflow-separate-spans.rs +++ b/src/test/compile-fail/const-len-underflow-separate-spans.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Check that an constant-evaluation underflow highlights the correct +// Check that a constant-evaluation underflow highlights the correct // spot (where the underflow occurred), while also providing the // overall context for what caused the evaluation. diff --git a/src/test/compile-fail/const-len-underflow-subspans.rs b/src/test/compile-fail/const-len-underflow-subspans.rs index a31da11467..020717dc1e 100644 --- a/src/test/compile-fail/const-len-underflow-subspans.rs +++ b/src/test/compile-fail/const-len-underflow-subspans.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Check that an constant-evaluation underflow highlights the correct +// Check that a constant-evaluation underflow highlights the correct // spot (where the underflow occurred). const ONE: usize = 1; diff --git a/src/test/compile-fail/feature-gate-pushpop-unsafe.rs b/src/test/compile-fail/const-slice-oob.rs similarity index 74% rename from src/test/compile-fail/feature-gate-pushpop-unsafe.rs rename to src/test/compile-fail/const-slice-oob.rs index e317b4c7d4..519c4917c7 100644 --- a/src/test/compile-fail/feature-gate-pushpop-unsafe.rs +++ b/src/test/compile-fail/const-slice-oob.rs @@ -8,7 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +const FOO: &'static[u32] = &[1, 2, 3]; +const BAR: u32 = FOO[5]; //~ ERROR const index-expr is out of bounds + fn main() { - let c = push_unsafe!('c'); //~ ERROR push/pop_unsafe macros are experimental - let c = pop_unsafe!('c'); //~ ERROR push/pop_unsafe macros are experimental + let _ = BAR; } diff --git a/src/test/compile-fail/deriving-primitive.rs b/src/test/compile-fail/deriving-primitive.rs index 6e9b120aa6..e8e37d8804 100644 --- a/src/test/compile-fail/deriving-primitive.rs +++ b/src/test/compile-fail/deriving-primitive.rs @@ -23,12 +23,12 @@ struct B(isize); #[derive(FromPrimitive)] enum C { Foo(isize), Bar(usize) } -//~^^ ERROR `FromPrimitive` cannot be derived for enum variants with arguments -//~^^^ ERROR `FromPrimitive` cannot be derived for enum variants with arguments +//~^^ ERROR `FromPrimitive` cannot be derived for enums with non-unit variants +//~^^^ ERROR `FromPrimitive` cannot be derived for enums with non-unit variants #[derive(FromPrimitive)] enum D { Baz { x: isize } } -//~^^ ERROR `FromPrimitive` cannot be derived for enums with struct variants -//~^^^ ERROR `FromPrimitive` cannot be derived for enums with struct variants +//~^^ ERROR `FromPrimitive` cannot be derived for enums with non-unit variants +//~^^^ ERROR `FromPrimitive` cannot be derived for enums with non-unit variants pub fn main() {} diff --git a/src/test/compile-fail/dropck_arr_cycle_checked.rs b/src/test/compile-fail/dropck_arr_cycle_checked.rs index 19f790ddc9..9cfeaca6df 100644 --- a/src/test/compile-fail/dropck_arr_cycle_checked.rs +++ b/src/test/compile-fail/dropck_arr_cycle_checked.rs @@ -19,7 +19,6 @@ use std::cell::Cell; use id::Id; mod s { - #![allow(unstable)] use std::sync::atomic::{AtomicUsize, Ordering}; static S_COUNT: AtomicUsize = AtomicUsize::new(0); diff --git a/src/test/compile-fail/dropck_tarena_cycle_checked.rs b/src/test/compile-fail/dropck_tarena_cycle_checked.rs index 584e5eabf0..d36293a484 100644 --- a/src/test/compile-fail/dropck_tarena_cycle_checked.rs +++ b/src/test/compile-fail/dropck_tarena_cycle_checked.rs @@ -16,7 +16,6 @@ // which is a reduction of this code to more directly show the reason // for the error message we see here.) -#![allow(unstable)] #![feature(const_fn)] extern crate arena; @@ -26,7 +25,6 @@ use std::cell::Cell; use id::Id; mod s { - #![allow(unstable)] use std::sync::atomic::{AtomicUsize, Ordering}; static S_COUNT: AtomicUsize = AtomicUsize::new(0); diff --git a/src/test/compile-fail/dropck_tarena_unsound_drop.rs b/src/test/compile-fail/dropck_tarena_unsound_drop.rs index 7a204e6143..6cbed34c7a 100644 --- a/src/test/compile-fail/dropck_tarena_unsound_drop.rs +++ b/src/test/compile-fail/dropck_tarena_unsound_drop.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Check that a arena (TypedArena) cannot carry elements whose drop +// Check that an arena (TypedArena) cannot carry elements whose drop // methods might access borrowed data of lifetime that does not // strictly outlive the arena itself. // @@ -19,8 +19,6 @@ // (Also compare against dropck_tarena_cycle_checked.rs, from which // this was reduced to better understand its error message.) -#![allow(unstable)] - extern crate arena; use arena::TypedArena; @@ -32,7 +30,7 @@ struct CheckId { v: T } // In the code below, the impl of HasId for `&'a usize` does not // actually access the borrowed data, but the point is that the // interface to CheckId does not (and cannot) know that, and therefore -// when encountering the a value V of type CheckId, we must +// when encountering a value V of type CheckId, we must // conservatively force the type S to strictly outlive V. impl Drop for CheckId { fn drop(&mut self) { diff --git a/src/test/compile-fail/dropck_trait_cycle_checked.rs b/src/test/compile-fail/dropck_trait_cycle_checked.rs index 6e0679da94..e701718028 100644 --- a/src/test/compile-fail/dropck_trait_cycle_checked.rs +++ b/src/test/compile-fail/dropck_trait_cycle_checked.rs @@ -9,7 +9,7 @@ // except according to those terms. // Reject mixing cyclic structure and Drop when using trait -// objects to hide the the cross-references. +// objects to hide the cross-references. // // (Compare against compile-fail/dropck_vec_cycle_checked.rs) diff --git a/src/test/compile-fail/dropck_vec_cycle_checked.rs b/src/test/compile-fail/dropck_vec_cycle_checked.rs index bc33ff8399..caf25e68d5 100644 --- a/src/test/compile-fail/dropck_vec_cycle_checked.rs +++ b/src/test/compile-fail/dropck_vec_cycle_checked.rs @@ -18,7 +18,6 @@ use std::cell::Cell; use id::Id; mod s { - #![allow(unstable)] use std::sync::atomic::{AtomicUsize, Ordering}; static S_COUNT: AtomicUsize = AtomicUsize::new(0); diff --git a/src/test/compile-fail/for-expn-2.rs b/src/test/compile-fail/dupe-symbols-8.rs similarity index 78% rename from src/test/compile-fail/for-expn-2.rs rename to src/test/compile-fail/dupe-symbols-8.rs index ce2315f3a3..3c0e545e19 100644 --- a/src/test/compile-fail/for-expn-2.rs +++ b/src/test/compile-fail/dupe-symbols-8.rs @@ -7,12 +7,17 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// +// error-pattern:already defined -// Test that we get an expansion stack for `for` loops. -// error-pattern:in this expansion of for loop expansion +#![allow(warnings)] fn main() { - for t in &foo { + { + extern fn fail() {} + } + { + extern fn fail() {} } } diff --git a/src/test/compile-fail/empty-comment.rs b/src/test/compile-fail/empty-comment.rs new file mode 100644 index 0000000000..5c521a5f30 --- /dev/null +++ b/src/test/compile-fail/empty-comment.rs @@ -0,0 +1,17 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// `/**/` was previously regarded as a doc comment because it starts with `/**` and ends with `*/`. +// This could break some internal logic that assumes the length of a doc comment is at least 5, +// leading to an ICE. + +fn main() { + println!(/**/); //~ ERROR unexpected end +} diff --git a/src/test/compile-fail/empty-struct-braces-expr.rs b/src/test/compile-fail/empty-struct-braces-expr.rs new file mode 100644 index 0000000000..67167086b9 --- /dev/null +++ b/src/test/compile-fail/empty-struct-braces-expr.rs @@ -0,0 +1,26 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Can't use empty braced struct as constant or constructor function + +#![feature(braced_empty_structs)] + +struct Empty1 {} + +enum E { + Empty2 {} +} + +fn main() { + let e1 = Empty1; //~ ERROR `Empty1` is the name of a struct or struct variant + let e1 = Empty1(); //~ ERROR `Empty1` is the name of a struct or struct variant + let e2 = E::Empty2; //~ ERROR `E::Empty2` is the name of a struct or struct variant + let e2 = E::Empty2(); //~ ERROR `E::Empty2` is the name of a struct or struct variant +} diff --git a/src/test/compile-fail/empty-struct-braces-gate-1.rs b/src/test/compile-fail/empty-struct-braces-gate-1.rs new file mode 100644 index 0000000000..a131b46e1c --- /dev/null +++ b/src/test/compile-fail/empty-struct-braces-gate-1.rs @@ -0,0 +1,23 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Feature gate test for empty struct with braces +// Can't define an empty braced struct + +struct Empty1 {} //~ ERROR empty structs and enum variants with braces are unstable +struct Empty2; + +enum E { + Empty4 {}, //~ ERROR empty structs and enum variants with braces are unstable + Empty5, +} + +fn main() { +} diff --git a/src/test/compile-fail/empty-struct-braces-gate-2.rs b/src/test/compile-fail/empty-struct-braces-gate-2.rs new file mode 100644 index 0000000000..c1b73bdc96 --- /dev/null +++ b/src/test/compile-fail/empty-struct-braces-gate-2.rs @@ -0,0 +1,49 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Feature gate test for empty struct with braces +// Can't use braced expressions and patterns with structs defined without braces + +struct Empty2; + +enum E { + Empty5, +} + +fn main() { + let e2: Empty2 = Empty2 {}; //~ ERROR empty structs and enum variants with braces are unstable + let e2: Empty2 = Empty2; + // Issue #28692 + // let e5: E = E::Empty5 {}; // ERROR empty structs and enum variants with braces are unstable + let e5: E = E::Empty5; + + match e2 { + Empty2 {} => {} //~ ERROR empty structs and enum variants with braces are unstable + } + match e2 { + Empty2 => {} + } + match e2 { + Empty2 { .. } => {} //~ ERROR empty structs and enum variants with braces are unstable + } + // Issue #28692 + // match e5 { + // E::Empty5 {} => {} // ERROR empty structs and enum variants with braces are unstable + // } + match e5 { + E::Empty5 => {} + } + // Issue #28692 + // match e5 { + // E::Empty5 { .. } => {} // ERROR empty structs and enum variants with braces are unstable + // } + + let e22 = Empty2 { ..e2 }; //~ ERROR empty structs and enum variants with braces are unstable +} diff --git a/src/test/compile-fail/empty-struct-braces-pat-1.rs b/src/test/compile-fail/empty-struct-braces-pat-1.rs new file mode 100644 index 0000000000..e095f69ed7 --- /dev/null +++ b/src/test/compile-fail/empty-struct-braces-pat-1.rs @@ -0,0 +1,33 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Can't use empty braced struct as constant pattern + +#![deny(warnings)] +#![feature(braced_empty_structs)] + +struct Empty1 {} + +enum E { + Empty2 {} +} + +fn main() { + let e1 = Empty1 {}; + let e2 = E::Empty2 {}; + + // Issue #28692 + // match e1 { + // Empty1 => () // ERROR incorrect error + // } + match e2 { + E::Empty2 => () //~ ERROR `E::Empty2` does not name a non-struct variant or a tuple struct + } +} diff --git a/src/test/compile-fail/empty-struct-braces-pat-2.rs b/src/test/compile-fail/empty-struct-braces-pat-2.rs new file mode 100644 index 0000000000..0e7152ec89 --- /dev/null +++ b/src/test/compile-fail/empty-struct-braces-pat-2.rs @@ -0,0 +1,39 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Can't use empty braced struct as enum pattern + +#![feature(braced_empty_structs)] + +struct Empty1 {} + +enum E { + Empty2 {} +} + +fn main() { + let e1 = Empty1 {}; + let e2 = E::Empty2 {}; + + // Rejected by parser as yet + // match e1 { + // Empty1() => () // ERROR unresolved enum variant, struct or const `Empty1` + // } + match e1 { + Empty1(..) => () //~ ERROR unresolved enum variant, struct or const `Empty1` + } + // Issue #28692 + // match e2 { + // E::Empty2() => () // ERROR unresolved enum variant, struct or const `Empty2` + // } + // match e2 { + // E::Empty2(..) => () // ERROR unresolved enum variant, struct or const `Empty2` + // } +} diff --git a/src/test/compile-fail/empty-struct-unit-expr.rs b/src/test/compile-fail/empty-struct-unit-expr.rs new file mode 100644 index 0000000000..199065665b --- /dev/null +++ b/src/test/compile-fail/empty-struct-unit-expr.rs @@ -0,0 +1,24 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Can't use unit struct as constructor function + +#![feature(braced_empty_structs)] + +struct Empty1; + +enum E { + Empty2 +} + +fn main() { + let e1 = Empty1(); //~ ERROR expected function, found `Empty1` + let e2 = E::Empty2(); //~ ERROR expected function, found `E` +} 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..966a2780f9 --- /dev/null +++ b/src/test/compile-fail/empty-struct-unit-pat.rs @@ -0,0 +1,40 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Can't use unit struct as enum pattern + +#![feature(braced_empty_structs)] + +FIXME //~ ERROR expected item, found `FIXME` + +struct Empty1; + +enum E { + Empty2 +} + +fn main() { + let e1 = Empty1; + let e2 = E::Empty2; + + // Issue #28692 + // match e1 { + // Empty1() => () // ERROR variable `Empty1` should have a snake case name + // } + // match e1 { + // Empty1(..) => () // ERROR variable `Empty1` should have a snake case name + // } + // match e2 { + // E::Empty2() => () // ERROR variable `Empty2` should have a snake case name + // } + // match e2 { + // E::Empty2(..) => () // ERROR variable `Empty2` should have a snake case name + // } +} diff --git a/src/test/compile-fail/feature-gate-box-expr.rs b/src/test/compile-fail/feature-gate-box-expr.rs index ace1b39966..f1bb5c0dea 100644 --- a/src/test/compile-fail/feature-gate-box-expr.rs +++ b/src/test/compile-fail/feature-gate-box-expr.rs @@ -19,8 +19,4 @@ fn main() { let x = box 'c'; //~ ERROR box expression syntax is experimental println!("x: {}", x); - - let x = box () 'c'; //~ ERROR box expression syntax is experimental - //~^ WARN deprecated syntax - println!("x: {}", x); } diff --git a/src/test/compile-fail/feature-gate-cfg-target-vendor.rs b/src/test/compile-fail/feature-gate-cfg-target-vendor.rs new file mode 100644 index 0000000000..e68a84d355 --- /dev/null +++ b/src/test/compile-fail/feature-gate-cfg-target-vendor.rs @@ -0,0 +1,21 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[cfg(target_vendor = "x")] //~ ERROR `cfg(target_vendor)` is experimental +#[cfg_attr(target_vendor = "x", x)] //~ ERROR `cfg(target_vendor)` is experimental +struct Foo(u64, u64); + +#[cfg(not(any(all(target_vendor = "x"))))] //~ ERROR `cfg(target_vendor)` is experimental +fn foo() {} + +fn main() { + cfg!(target_vendor = "x"); + //~^ ERROR `cfg(target_vendor)` is experimental and subject to change +} diff --git a/src/test/compile-fail/feature-gate-dropck-ugeh.rs b/src/test/compile-fail/feature-gate-dropck-ugeh.rs new file mode 100644 index 0000000000..aa479a987a --- /dev/null +++ b/src/test/compile-fail/feature-gate-dropck-ugeh.rs @@ -0,0 +1,40 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Ensure that attempts to use the unsafe attribute are feature-gated. + +// Example adapted from RFC 1238 text (just left out the feature gate). + +// https://github.com/rust-lang/rfcs/blob/master/text/1238-nonparametric-dropck.md +// #example-of-the-unguarded-escape-hatch + +// #![feature(dropck_parametricity)] + +use std::cell::Cell; + +struct Concrete<'a>(u32, Cell>>); + +struct Foo { data: Vec } + +impl Drop for Foo { + #[unsafe_destructor_blind_to_params] // This is the UGEH attribute + //~^ ERROR unsafe_destructor_blind_to_params has unstable semantics + fn drop(&mut self) { } +} + +fn main() { + let mut foo = Foo { data: Vec::new() }; + foo.data.push(Concrete(0, Cell::new(None))); + foo.data.push(Concrete(0, Cell::new(None))); + + foo.data[0].1.set(Some(&foo.data[1])); + foo.data[1].1.set(Some(&foo.data[0])); +} + diff --git a/src/test/run-pass/feature-gate-negate-unsigned.rs b/src/test/compile-fail/feature-gate-negate-unsigned.rs similarity index 67% rename from src/test/run-pass/feature-gate-negate-unsigned.rs rename to src/test/compile-fail/feature-gate-negate-unsigned.rs index 95c8e62be5..b1c73fab4f 100644 --- a/src/test/run-pass/feature-gate-negate-unsigned.rs +++ b/src/test/compile-fail/feature-gate-negate-unsigned.rs @@ -18,21 +18,21 @@ impl std::ops::Neg for S { } const _MAX: usize = -1; -//~^ WARN unary negation of unsigned integers will be feature gated in the future +//~^ ERROR unary negation of unsigned integers may be removed in the future fn main() { let a = -1; - //~^ WARN unary negation of unsigned integers will be feature gated in the future + //~^ ERROR unary negation of unsigned integers may be removed in the future let _b : u8 = a; // for infering variable a to u8. -a; - //~^ WARN unary negation of unsigned integers will be feature gated in the future + //~^ ERROR unary negation of unsigned integers may be removed in the future let _d = -1u8; - //~^ WARN unary negation of unsigned integers will be feature gated in the future + //~^ ERROR unary negation of unsigned integers may be removed in the future for _ in -10..10u8 {} - //~^ WARN unary negation of unsigned integers will be feature gated in the future + //~^ ERROR unary negation of unsigned integers may be removed in the future -S; // should not trigger the gate; issue 26840 } diff --git a/src/test/compile-fail/feature-gate-no-debug.rs b/src/test/compile-fail/feature-gate-no-debug.rs new file mode 100644 index 0000000000..e185056026 --- /dev/null +++ b/src/test/compile-fail/feature-gate-no-debug.rs @@ -0,0 +1,12 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[no_debug] //~ ERROR the `#[no_debug]` attribute is +fn main() {} diff --git a/src/test/compile-fail/feature-gate-omit-gdb-pretty-printer-section.rs b/src/test/compile-fail/feature-gate-omit-gdb-pretty-printer-section.rs new file mode 100644 index 0000000000..a837a7f213 --- /dev/null +++ b/src/test/compile-fail/feature-gate-omit-gdb-pretty-printer-section.rs @@ -0,0 +1,12 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[omit_gdb_pretty_printer_section] //~ ERROR the `#[omit_gdb_pretty_printer_section]` attribute is +fn main() {} diff --git a/src/test/compile-fail/feature-gate-placement-expr.rs b/src/test/compile-fail/feature-gate-placement-expr.rs index 7c75605d57..47a25bf637 100644 --- a/src/test/compile-fail/feature-gate-placement-expr.rs +++ b/src/test/compile-fail/feature-gate-placement-expr.rs @@ -19,10 +19,6 @@ fn main() { use std::boxed::HEAP; - let x = box (HEAP) 'c'; //~ ERROR placement-in expression syntax is experimental - //~^ WARN deprecated syntax - println!("x: {}", x); - let x = in HEAP { 'c' }; //~ ERROR placement-in expression syntax is experimental println!("x: {}", x); } diff --git a/src/test/compile-fail/feature-gated-feature-in-macro-arg.rs b/src/test/compile-fail/feature-gated-feature-in-macro-arg.rs index 54bdaf011c..ae342af4a5 100644 --- a/src/test/compile-fail/feature-gated-feature-in-macro-arg.rs +++ b/src/test/compile-fail/feature-gated-feature-in-macro-arg.rs @@ -8,14 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME #20661: format_args! emits calls to the unstable std::fmt::rt -// module, so the compiler has some hacks to make that possible -// (in span_is_internal). Unnfortunately those hacks defeat this -// particular scenario of checking feature gates in arguments to -// println!(). - -// ignore-test - // tests that input to a macro is checked for use of gated features. If this // test succeeds due to the acceptance of a feature, pick a new feature to // test. Not ideal, but oh well :( diff --git a/src/test/compile-fail/for-loop-hygiene.rs b/src/test/compile-fail/for-loop-hygiene.rs index ff6f848ab5..f06882875f 100644 --- a/src/test/compile-fail/for-loop-hygiene.rs +++ b/src/test/compile-fail/for-loop-hygiene.rs @@ -11,8 +11,6 @@ // for-loops are expanded in the front end, and use an `iter` ident in their expansion. Check that // `iter` is not accessible inside the for loop. -#![allow(unstable)] - fn main() { for _ in 0..10 { iter.next(); //~ error: unresolved name `iter` diff --git a/src/test/compile-fail/for-loop-refutable-pattern-error-message.rs b/src/test/compile-fail/for-loop-refutable-pattern-error-message.rs index ab6dc2bab3..81c4db6862 100644 --- a/src/test/compile-fail/for-loop-refutable-pattern-error-message.rs +++ b/src/test/compile-fail/for-loop-refutable-pattern-error-message.rs @@ -9,7 +9,5 @@ // except according to those terms. fn main() { - for - &1 //~ ERROR refutable pattern in `for` loop binding - in [1].iter() {} + for &1 in [1].iter() {} //~ ERROR refutable pattern in `for` loop binding } diff --git a/src/test/compile-fail/invalid-path-in-const.rs b/src/test/compile-fail/invalid-path-in-const.rs new file mode 100644 index 0000000000..3c4ad5a56e --- /dev/null +++ b/src/test/compile-fail/invalid-path-in-const.rs @@ -0,0 +1,14 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + fn f(a: [u8; u32::DOESNOTEXIST]) {} + //~^ ERROR unresolved path in constant expression +} diff --git a/src/test/compile-fail/issue-14084.rs b/src/test/compile-fail/issue-14084.rs index 26ed9d8c26..6b19cb0b68 100644 --- a/src/test/compile-fail/issue-14084.rs +++ b/src/test/compile-fail/issue-14084.rs @@ -12,7 +12,6 @@ #![feature(placement_in_syntax)] fn main() { - box ( () ) 0; + in () { 0 }; //~^ ERROR: the trait `core::ops::Placer<_>` is not implemented - //~| WARN deprecated syntax } diff --git a/src/test/compile-fail/issue-15167.rs b/src/test/compile-fail/issue-15167.rs index a1663772ba..898e6be6fc 100644 --- a/src/test/compile-fail/issue-15167.rs +++ b/src/test/compile-fail/issue-15167.rs @@ -16,4 +16,17 @@ fn main() -> (){ for n in 0..1 { println!("{}", f!()); //~ ERROR unresolved name `n` } + + if let Some(n) = None { + println!("{}", f!()); //~ ERROR unresolved name `n` + } + + if false { + } else if let Some(n) = None { + println!("{}", f!()); //~ ERROR unresolved name `n` + } + + while let Some(n) = None { + println!("{}", f!()); //~ ERROR unresolved name `n` + } } diff --git a/src/test/compile-fail/issue-15381.rs b/src/test/compile-fail/issue-15381.rs index 653ba165e7..ec29a84f44 100644 --- a/src/test/compile-fail/issue-15381.rs +++ b/src/test/compile-fail/issue-15381.rs @@ -13,10 +13,8 @@ fn main() { let values: Vec = vec![1,2,3,4,5,6,7,8]; - for - [x,y,z] -//~^ ERROR refutable pattern in `for` loop binding: `[]` not covered - in values.chunks(3).filter(|&xs| xs.len() == 3) { + for [x,y,z] in values.chunks(3).filter(|&xs| xs.len() == 3) { + //~^ ERROR refutable pattern in `for` loop binding: `[]` not covered println!("y={}", y); } } diff --git a/src/test/compile-fail/issue-16819.rs b/src/test/compile-fail/issue-16819.rs new file mode 100644 index 0000000000..065b29d29a --- /dev/null +++ b/src/test/compile-fail/issue-16819.rs @@ -0,0 +1,18 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct TS ( //~ ERROR empty tuple structs and enum variants are not allowed + #[cfg(untrue)] + int, +); + +fn main() { + let s = S; +} diff --git a/src/test/compile-fail/issue-17283.rs b/src/test/compile-fail/issue-17283.rs index a481fec6bf..c7d6443663 100644 --- a/src/test/compile-fail/issue-17283.rs +++ b/src/test/compile-fail/issue-17283.rs @@ -11,6 +11,8 @@ // Test that the parser does not attempt to parse struct literals // within assignments in if expressions. +#![allow(unused_parens)] + struct Foo { foo: usize } diff --git a/src/test/compile-fail/issue-17337.rs b/src/test/compile-fail/issue-17337.rs index ff640793af..501f6eb4de 100644 --- a/src/test/compile-fail/issue-17337.rs +++ b/src/test/compile-fail/issue-17337.rs @@ -15,8 +15,8 @@ struct Foo; impl Foo { - #[unstable(feature = "test_feature")] - #[deprecated(since = "1.0.0")] + #[unstable(feature = "test_feature", issue = "0")] + #[deprecated(since = "1.0.0", reason = "text")] fn foo(self) {} } diff --git a/src/test/compile-fail/issue-17904-2.rs b/src/test/compile-fail/issue-17904-2.rs index a33ec23a16..a15ccb71aa 100644 --- a/src/test/compile-fail/issue-17904-2.rs +++ b/src/test/compile-fail/issue-17904-2.rs @@ -9,7 +9,7 @@ // except according to those terms. // Test that we can parse a unit struct with a where clause, even if -// it leads to a error later on since `T` is unused. +// it leads to an error later on since `T` is unused. struct Foo where T: Copy; //~ ERROR parameter `T` is never used diff --git a/src/test/compile-fail/issue-18959.rs b/src/test/compile-fail/issue-18959.rs index 95176da902..5f6216a898 100644 --- a/src/test/compile-fail/issue-18959.rs +++ b/src/test/compile-fail/issue-18959.rs @@ -22,6 +22,7 @@ fn foo(b: &Bar) { b.foo(&0) //~^ ERROR the trait `Foo` is not implemented for the type `Bar` //~| ERROR E0038 + //~| WARNING E0038 } fn main() { diff --git a/src/test/compile-fail/issue-1920-2.rs b/src/test/compile-fail/issue-1920-2.rs index 57eb82a156..c73a173506 100644 --- a/src/test/compile-fail/issue-1920-2.rs +++ b/src/test/compile-fail/issue-1920-2.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Test that when a crate is linked under another name that that name is used in global paths +//! Test that when a crate is linked under another name that name is used in global paths extern crate core as bar; diff --git a/src/test/compile-fail/issue-21546.rs b/src/test/compile-fail/issue-21546.rs new file mode 100644 index 0000000000..bb1bcd4e87 --- /dev/null +++ b/src/test/compile-fail/issue-21546.rs @@ -0,0 +1,65 @@ +// 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. + +// Also works as a test for #14564 + +#[allow(non_snake_case)] +mod Foo { } +//~^ NOTE first definition of type or module `Foo` + +#[allow(dead_code)] +struct Foo; +//~^ WARNING duplicate definition of type or module `Foo` + + +#[allow(non_snake_case)] +mod Bar { } +//~^ NOTE first definition of type or module `Bar` + +#[allow(dead_code)] +struct Bar(i32); +//~^ WARNING duplicate definition of type or module `Bar` + + +#[allow(dead_code)] +struct Baz(i32); +//~^ NOTE first definition of type or module + +#[allow(non_snake_case)] +mod Baz { } +//~^ WARNING duplicate definition of type or module `Baz` + + +#[allow(dead_code)] +struct Qux { x: bool } +//~^ NOTE first definition of type or module + +#[allow(non_snake_case)] +mod Qux { } +//~^ WARNING duplicate definition of type or module `Qux` + + +#[allow(dead_code)] +struct Quux; +//~^ NOTE first definition of type or module + +#[allow(non_snake_case)] +mod Quux { } +//~^ WARNING duplicate definition of type or module `Quux` + + +#[allow(dead_code)] +enum Corge { A, B } + +#[allow(non_snake_case)] +mod Corge { } +//~^ ERROR duplicate definition of type or module `Corge` + +fn main() { } diff --git a/src/test/compile-fail/issue-22599.rs b/src/test/compile-fail/issue-22599.rs new file mode 100644 index 0000000000..b9ea358329 --- /dev/null +++ b/src/test/compile-fail/issue-22599.rs @@ -0,0 +1,20 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![deny(unused_variables)] + +fn f(_: i32) {} + +fn main() { + let mut v = 0; + f(v); + v = match 0 { a => 0 }; //~ ERROR: unused variable: `a` + f(v); +} diff --git a/src/test/compile-fail/issue-22872.rs b/src/test/compile-fail/issue-22872.rs deleted file mode 100644 index 86982284ac..0000000000 --- a/src/test/compile-fail/issue-22872.rs +++ /dev/null @@ -1,36 +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. - -trait Wrap<'b> { - fn foo(&'b mut self); -} - -struct Wrapper

    (P); - -impl<'b, P> Wrap<'b> for Wrapper

    -where P: Process<'b>, -

    >::Item: Iterator { - fn foo(&mut self) {} -} - - -pub trait Process<'a> { - type Item; - fn bar(&'a self); -} - -fn push_process

    (process: P) where P: Process<'static> { - let _: Box Wrap<'b>> = Box::new(Wrapper(process)); - //~^ ERROR the trait `for<'b> Process<'b>` is not implemented for the type `P` [E0277] - //~| ERROR the trait `for<'b> core::iter::Iterator` is not implemented for the type - //~| ERROR cannot infer an appropriate lifetime for lifetime parameter `'b` due to conflicting -} - -fn main() {} diff --git a/src/test/compile-fail/issue-23046.rs b/src/test/compile-fail/issue-23046.rs index 8c83c4cefd..dba9c32f9b 100644 --- a/src/test/compile-fail/issue-23046.rs +++ b/src/test/compile-fail/issue-23046.rs @@ -24,7 +24,7 @@ pub fn let_<'var, VAR, F: for<'v: 'var> Fn(Expr<'v, VAR>) -> Expr<'v, VAR>> } fn main() { - let ex = (|x| { + let ex = |x| { let_(add(x,x), |y| { //~ ERROR unable to infer enough type information about `_` - let_(add(x, x), |x|x)})}); + let_(add(x, x), |x|x)})}; } diff --git a/src/test/compile-fail/issue-23543.rs b/src/test/compile-fail/issue-23543.rs new file mode 100644 index 0000000000..4ed44154c4 --- /dev/null +++ b/src/test/compile-fail/issue-23543.rs @@ -0,0 +1,21 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub trait A: Copy {} + +struct Foo; + +pub trait D { + fn f(self) + where T: A; + //~^ ERROR associated type bindings are not allowed here [E0229] +} + +fn main() {} diff --git a/src/test/compile-fail/issue-23544.rs b/src/test/compile-fail/issue-23544.rs new file mode 100644 index 0000000000..1d7c218704 --- /dev/null +++ b/src/test/compile-fail/issue-23544.rs @@ -0,0 +1,19 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub trait A: Copy {} + +pub trait D { + fn f(self) + where T: A; + //~^ ERROR associated type bindings are not allowed here [E0229] +} + +fn main() {} diff --git a/src/test/compile-fail/issue-23729.rs b/src/test/compile-fail/issue-23729.rs index 3d77d171ac..f98cf6575d 100644 --- a/src/test/compile-fail/issue-23729.rs +++ b/src/test/compile-fail/issue-23729.rs @@ -26,7 +26,7 @@ fn main() { self.pos += 1; Some(next_val) } else { - let next_val = (self.mem[0] + self.mem[1]); + let next_val = self.mem[0] + self.mem[1]; self.mem[0] = self.mem[1]; self.mem[1] = next_val; Some(next_val) diff --git a/src/test/compile-fail/issue-25145.rs b/src/test/compile-fail/issue-25145.rs new file mode 100644 index 0000000000..e8a9c8d2ea --- /dev/null +++ b/src/test/compile-fail/issue-25145.rs @@ -0,0 +1,22 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(associated_consts)] + +struct S; + +impl S { + const N: usize = 3; +} + +static STUFF: [u8; S::N] = [0; S::N]; +//~^ ERROR array length constant evaluation error: unresolved path in constant expression + +fn main() {} diff --git a/src/test/compile-fail/issue-26056.rs b/src/test/compile-fail/issue-26056.rs new file mode 100644 index 0000000000..4e9cbc4f28 --- /dev/null +++ b/src/test/compile-fail/issue-26056.rs @@ -0,0 +1,33 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait MapLookup { + type MapValue; +} + +impl MapLookup for K { + type MapValue = K; +} + +trait Map: MapLookup<::Key> { + type Key; +} + +impl Map for K { + type Key = K; +} + + +fn main() { + let _ = &() + as &Map; + //~^ ERROR the trait `Map` cannot be made into an object + //~| NOTE the trait cannot use `Self` as a type parameter +} diff --git a/src/test/compile-fail/issue-26459.rs b/src/test/compile-fail/issue-26459.rs new file mode 100644 index 0000000000..48eda91fba --- /dev/null +++ b/src/test/compile-fail/issue-26459.rs @@ -0,0 +1,16 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + match 'a' { + char{ch} => true + //~^ ERROR `char` does not name a struct or a struct variant + }; +} diff --git a/src/test/compile-fail/issue-26886.rs b/src/test/compile-fail/issue-26886.rs new file mode 100644 index 0000000000..c849716f21 --- /dev/null +++ b/src/test/compile-fail/issue-26886.rs @@ -0,0 +1,17 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::sync::{self, Arc}; //~ NOTE previous import + //~^ NOTE previous import +use std::sync::Arc; //~ ERROR a type named +use std::sync; //~ ERROR a module named + +fn main() { +} diff --git a/src/test/compile-fail/issue-26905.rs b/src/test/compile-fail/issue-26905.rs new file mode 100644 index 0000000000..3b8fac832a --- /dev/null +++ b/src/test/compile-fail/issue-26905.rs @@ -0,0 +1,34 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(unsize, coerce_unsized)] + +// Verfies that non-PhantomData ZSTs still cause coercions to fail. +// They might have additional semantics that we don't want to bulldoze. + +use std::marker::{Unsize, PhantomData}; +use std::ops::CoerceUnsized; + +struct NotPhantomData(PhantomData); + +struct MyRc { + _ptr: *const T, + _boo: NotPhantomData, +} + +impl, U: ?Sized> CoerceUnsized> for MyRc{ } //~ERROR + +fn main() { + let data = [1, 2, 3]; + let iter = data.iter(); + let x = MyRc { _ptr: &iter, _boo: NotPhantomData(PhantomData) }; + let _y: MyRc> = x; +} + diff --git a/src/test/compile-fail/issue-27831.rs b/src/test/compile-fail/issue-27831.rs index 336368cf8a..3cdb370f0e 100644 --- a/src/test/compile-fail/issue-27831.rs +++ b/src/test/compile-fail/issue-27831.rs @@ -22,8 +22,8 @@ fn main() { let Foo { .. } = x; //~ ERROR `Foo` does not name a struct let x = Bar; - Bar { ..x }; //~ ERROR `Bar` does not name a structure - let Bar { .. } = x; //~ ERROR `Bar` does not name a struct + Bar { ..x }; //~ ERROR empty structs and enum variants with braces are unstable + let Bar { .. } = x; //~ ERROR empty structs and enum variants with braces are unstable match Enum::Bar { Enum::Bar { .. } //~ ERROR `Enum::Bar` does not name a struct diff --git a/src/test/compile-fail/issue-27895.rs b/src/test/compile-fail/issue-27895.rs new file mode 100644 index 0000000000..959818b49c --- /dev/null +++ b/src/test/compile-fail/issue-27895.rs @@ -0,0 +1,21 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let i = 5; + let index = 6; + + match i { + 0...index => println!("winner"), + //~^ ERROR paths in constants may only refer to constants or functions + //~| ERROR non-constant path in constant expression + _ => println!("hello"), + } +} diff --git a/src/test/compile-fail/issue-28075.rs b/src/test/compile-fail/issue-28075.rs new file mode 100644 index 0000000000..d75f5f606a --- /dev/null +++ b/src/test/compile-fail/issue-28075.rs @@ -0,0 +1,25 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Unstable entities should be caught in import lists + +// aux-build:lint_stability.rs + +#![allow(unused_imports)] + +extern crate lint_stability; + +use lint_stability::{unstable, deprecated}; //~ ERROR use of unstable library feature 'test_feature' +//~^ WARNING use of deprecated item + +use lint_stability::unstable::{self as u}; //~ ERROR use of unstable library feature 'test_feature' + +fn main() { +} diff --git a/src/test/compile-fail/issue-28388-1.rs b/src/test/compile-fail/issue-28388-1.rs new file mode 100644 index 0000000000..ef97b400b0 --- /dev/null +++ b/src/test/compile-fail/issue-28388-1.rs @@ -0,0 +1,15 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Prefix in imports with empty braces should be resolved and checked privacy, stability, etc. + +use foo::{}; //~ ERROR failed to resolve. foo + +fn main() {} diff --git a/src/test/compile-fail/issue-28388-2.rs b/src/test/compile-fail/issue-28388-2.rs new file mode 100644 index 0000000000..837dc67c80 --- /dev/null +++ b/src/test/compile-fail/issue-28388-2.rs @@ -0,0 +1,19 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Prefix in imports with empty braces should be resolved and checked privacy, stability, etc. + +mod m { + mod n {} +} + +use m::n::{}; //~ ERROR module `n` is private + +fn main() {} diff --git a/src/test/compile-fail/issue-28388-3.rs b/src/test/compile-fail/issue-28388-3.rs new file mode 100644 index 0000000000..0cb669f5f8 --- /dev/null +++ b/src/test/compile-fail/issue-28388-3.rs @@ -0,0 +1,20 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Prefix in imports with empty braces should be resolved and checked privacy, stability, etc. + +// aux-build:lint_stability.rs + +extern crate lint_stability; + +use lint_stability::UnstableStruct::{}; //~ ERROR use of unstable library feature 'test_feature' +use lint_stability::StableStruct::{}; // OK + +fn main() {} diff --git a/src/test/compile-fail/issue-28433.rs b/src/test/compile-fail/issue-28433.rs new file mode 100644 index 0000000000..3ca2213087 --- /dev/null +++ b/src/test/compile-fail/issue-28433.rs @@ -0,0 +1,21 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum bird { + pub duck, + //~^ ERROR: expected identifier, found keyword `pub` + //~^^ ERROR: expected + goose +} + + +fn main() { + let y = bird::goose; +} diff --git a/src/test/compile-fail/issue-3993-2.rs b/src/test/compile-fail/issue-28472.rs similarity index 60% rename from src/test/compile-fail/issue-3993-2.rs rename to src/test/compile-fail/issue-28472.rs index 9d9e91a141..23827c55a1 100644 --- a/src/test/compile-fail/issue-3993-2.rs +++ b/src/test/compile-fail/issue-28472.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,16 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use zoo::bird::{duck, goose}; +// Check that the visibility modifier is included in the span of foreign items. -mod zoo { - pub enum bird { - pub duck, //~ ERROR: unnecessary `pub` visibility - goose - } -} +extern { + fn foo(); + + pub //~ ERROR duplicate definition + fn foo(); + pub //~ ERROR duplicate definition + static mut foo: u32; +} fn main() { - let y = goose; } diff --git a/src/test/compile-fail/issue-28576.rs b/src/test/compile-fail/issue-28576.rs new file mode 100644 index 0000000000..bd7186708a --- /dev/null +++ b/src/test/compile-fail/issue-28576.rs @@ -0,0 +1,22 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub trait Foo { + type Assoc; +} + +pub trait Bar: Foo { + fn new(&self, b: & + Bar //~ ERROR the trait `Bar` cannot be made into an object + + ); +} + +fn main() {} diff --git a/src/test/compile-fail/issue-28776.rs b/src/test/compile-fail/issue-28776.rs new file mode 100644 index 0000000000..ce06c8bf22 --- /dev/null +++ b/src/test/compile-fail/issue-28776.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. + +use std::ptr; + +fn main() { + (&ptr::write)(1 as *mut _, 42); //~ ERROR E0133 +} diff --git a/src/test/compile-fail/issue-28837.rs b/src/test/compile-fail/issue-28837.rs new file mode 100644 index 0000000000..c7cf63bf2c --- /dev/null +++ b/src/test/compile-fail/issue-28837.rs @@ -0,0 +1,60 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct A; + +fn main() { + let a = A; + + a + a; //~ ERROR binary operation `+` cannot be applied to type `A` + //~^ NOTE an implementation of `std::ops::Add` might be missing for `A` + + a - a; //~ ERROR binary operation `-` cannot be applied to type `A` + //~^ NOTE an implementation of `std::ops::Sub` might be missing for `A` + + a * a; //~ ERROR binary operation `*` cannot be applied to type `A` + //~^ NOTE an implementation of `std::ops::Mul` might be missing for `A` + + a / a; //~ ERROR binary operation `/` cannot be applied to type `A` + //~^ NOTE an implementation of `std::ops::Div` might be missing for `A` + + a % a; //~ ERROR binary operation `%` cannot be applied to type `A` + //~^ NOTE an implementation of `std::ops::Rem` might be missing for `A` + + a & a; //~ ERROR binary operation `&` cannot be applied to type `A` + //~^ NOTE an implementation of `std::ops::BitAnd` might be missing for `A` + + a | a; //~ ERROR binary operation `|` cannot be applied to type `A` + //~^ NOTE an implementation of `std::ops::BitOr` might be missing for `A` + + a << a; //~ ERROR binary operation `<<` cannot be applied to type `A` + //~^ NOTE an implementation of `std::ops::Shl` might be missing for `A` + + a >> a; //~ ERROR binary operation `>>` cannot be applied to type `A` + //~^ NOTE an implementation of `std::ops::Shr` might be missing for `A` + + a == a; //~ ERROR binary operation `==` cannot be applied to type `A` + //~^ NOTE an implementation of `std::cmp::PartialEq` might be missing for `A` + + a != a; //~ ERROR binary operation `!=` cannot be applied to type `A` + //~^ NOTE an implementation of `std::cmp::PartialEq` might be missing for `A` + + a < a; //~ ERROR binary operation `<` cannot be applied to type `A` + //~^ NOTE an implementation of `std::cmp::PartialOrd` might be missing for `A` + + a <= a; //~ ERROR binary operation `<=` cannot be applied to type `A` + //~^ NOTE an implementation of `std::cmp::PartialOrd` might be missing for `A` + + a > a; //~ ERROR binary operation `>` cannot be applied to type `A` + //~^ NOTE an implementation of `std::cmp::PartialOrd` might be missing for `A` + + a >= a; //~ ERROR binary operation `>=` cannot be applied to type `A` + //~^ NOTE an implementation of `std::cmp::PartialOrd` might be missing for `A` +} diff --git a/src/test/compile-fail/issue-29106.rs b/src/test/compile-fail/issue-29106.rs new file mode 100644 index 0000000000..1872c62e36 --- /dev/null +++ b/src/test/compile-fail/issue-29106.rs @@ -0,0 +1,34 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::rc::Rc; +use std::sync::Arc; + +struct Foo<'a>(&'a String); + +impl<'a> Drop for Foo<'a> { + fn drop(&mut self) { + println!("{:?}", self.0); + } +} + +fn main() { + { + let (y, x); + x = "alive".to_string(); + 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 + } +} diff --git a/src/test/compile-fail/issue-29161.rs b/src/test/compile-fail/issue-29161.rs new file mode 100644 index 0000000000..1821f5717c --- /dev/null +++ b/src/test/compile-fail/issue-29161.rs @@ -0,0 +1,26 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +mod a { + struct A; + + impl Default for A { + pub fn default() -> A { + //~^ ERROR E0449 + A; + } + } +} + + +fn main() { + a::A::default(); + //~^ ERROR method `default` is inaccessible + } diff --git a/src/test/compile-fail/issue-29181.rs b/src/test/compile-fail/issue-29181.rs new file mode 100644 index 0000000000..2fcec51912 --- /dev/null +++ b/src/test/compile-fail/issue-29181.rs @@ -0,0 +1,17 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:issue-29181.rs + +extern crate issue_29181 as foo; + +fn main() { + 0.homura(); //~ ERROR no method named `homura` found +} diff --git a/src/test/parse-fail/struct-no-fields.rs b/src/test/compile-fail/issue-29184.rs similarity index 77% rename from src/test/parse-fail/struct-no-fields.rs rename to src/test/compile-fail/issue-29184.rs index fa5065b763..98fe12c1b9 100644 --- a/src/test/parse-fail/struct-no-fields.rs +++ b/src/test/compile-fail/issue-29184.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only - -struct Foo {} -//~^ ERROR: unit-like struct definition should be written as `struct Foo;` - -fn main() {} +fn main() { + let x: typeof(92) = 92; //~ ERROR `typeof` is a reserved keyword +} diff --git a/src/test/compile-fail/issue-6801.rs b/src/test/compile-fail/issue-6801.rs index 8261862c5f..792d27c179 100644 --- a/src/test/compile-fail/issue-6801.rs +++ b/src/test/compile-fail/issue-6801.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Creating a stack closure which references an box and then +// Creating a stack closure which references a box and then // transferring ownership of the box before invoking the stack // closure results in a crash. diff --git a/src/test/compile-fail/issue-8460-const.rs b/src/test/compile-fail/issue-8460-const.rs index 9c2e8d278a..95921556c7 100644 --- a/src/test/compile-fail/issue-8460-const.rs +++ b/src/test/compile-fail/issue-8460-const.rs @@ -8,48 +8,50 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![deny(const_err)] + use std::{isize, i8, i16, i32, i64}; use std::thread; fn main() { assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err()); - //~^ ERROR attempted to divide with overflow in a constant expression + //~^ ERROR attempted to divide with overflow assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err()); - //~^ ERROR attempted to divide with overflow in a constant expression + //~^ ERROR attempted to divide with overflow assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err()); - //~^ ERROR attempted to divide with overflow in a constant expression + //~^ ERROR attempted to divide with overflow assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err()); - //~^ ERROR attempted to divide with overflow in a constant expression + //~^ ERROR attempted to divide with overflow assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err()); - //~^ ERROR attempted to divide with overflow in a constant expression + //~^ ERROR attempted to divide with overflow assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err()); - //~^ ERROR attempted to divide by zero in a constant expression + //~^ ERROR attempted to divide by zero assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err()); - //~^ ERROR attempted to divide by zero in a constant expression + //~^ ERROR attempted to divide by zero assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err()); - //~^ ERROR attempted to divide by zero in a constant expression + //~^ ERROR attempted to divide by zero assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err()); - //~^ ERROR attempted to divide by zero in a constant expression + //~^ ERROR attempted to divide by zero assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err()); - //~^ ERROR attempted to divide by zero in a constant expression + //~^ ERROR attempted to divide by zero assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err()); - //~^ ERROR attempted remainder with overflow in a constant expression + //~^ ERROR attempted remainder with overflow assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err()); - //~^ ERROR attempted remainder with overflow in a constant expression + //~^ ERROR attempted remainder with overflow assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err()); - //~^ ERROR attempted remainder with overflow in a constant expression + //~^ ERROR attempted remainder with overflow assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err()); - //~^ ERROR attempted remainder with overflow in a constant expression + //~^ ERROR attempted remainder with overflow assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err()); - //~^ ERROR attempted remainder with overflow in a constant expression + //~^ ERROR attempted remainder with overflow assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err()); - //~^ ERROR attempted remainder with a divisor of zero in a constant expression + //~^ ERROR attempted remainder with a divisor of zero assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err()); - //~^ ERROR attempted remainder with a divisor of zero in a constant expression + //~^ ERROR attempted remainder with a divisor of zero assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err()); - //~^ ERROR attempted remainder with a divisor of zero in a constant expression + //~^ ERROR attempted remainder with a divisor of zero assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err()); - //~^ ERROR attempted remainder with a divisor of zero in a constant expression + //~^ ERROR attempted remainder with a divisor of zero assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err()); - //~^ ERROR attempted remainder with a divisor of zero in a constant expression + //~^ ERROR attempted remainder with a divisor of zero } diff --git a/src/test/compile-fail/issue28498-reject-ex1.rs b/src/test/compile-fail/issue28498-reject-ex1.rs new file mode 100644 index 0000000000..cee7c57c20 --- /dev/null +++ b/src/test/compile-fail/issue28498-reject-ex1.rs @@ -0,0 +1,48 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Example taken from RFC 1238 text + +// https://github.com/rust-lang/rfcs/blob/master/text/1238-nonparametric-dropck.md +// #examples-of-code-that-will-start-to-be-rejected + +// Compare against test/run-pass/issue28498-must-work-ex2.rs + +use std::cell::Cell; + +struct Concrete<'a>(u32, Cell>>); + +struct Foo { data: Vec } + +fn potentially_specialized_wrt_t(t: &T) { + // Hypothetical code that does one thing for generic T and then is + // specialized for T == Concrete (and the specialized form can + // then access a reference held in concrete tuple). + // + // (We don't have specialization yet, but we want to allow for it + // in the future.) +} + +impl Drop for Foo { + fn drop(&mut self) { + potentially_specialized_wrt_t(&self.data[0]) + } +} + +fn main() { + let mut foo = Foo { data: Vec::new() }; + foo.data.push(Concrete(0, Cell::new(None))); + 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 +} diff --git a/src/test/compile-fail/issue28498-reject-lifetime-param.rs b/src/test/compile-fail/issue28498-reject-lifetime-param.rs new file mode 100644 index 0000000000..92028c7a81 --- /dev/null +++ b/src/test/compile-fail/issue28498-reject-lifetime-param.rs @@ -0,0 +1,48 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Demonstrate that having a lifetime param causes dropck to reject code +// that might indirectly access previously dropped value. +// +// Compare with run-pass/issue28498-ugeh-with-lifetime-param.rs + +#[derive(Debug)] +struct ScribbleOnDrop(String); + +impl Drop for ScribbleOnDrop { + fn drop(&mut self) { + self.0 = format!("DROPPED"); + } +} + +struct Foo<'a>(u32, &'a ScribbleOnDrop); + +impl<'a> Drop for Foo<'a> { + fn drop(&mut self) { + // Use of `unsafe_destructor_blind_to_params` is unsound, + // because destructor accesses borrowed data in `self.1` + // and we must force that to strictly outlive `self`. + println!("Dropping Foo({}, {:?})", self.0, self.1); + } +} + +fn main() { + let (last_dropped, foo0); + let (foo1, first_dropped); + + 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); +} diff --git a/src/test/compile-fail/issue28498-reject-passed-to-fn.rs b/src/test/compile-fail/issue28498-reject-passed-to-fn.rs new file mode 100644 index 0000000000..27378b1e0b --- /dev/null +++ b/src/test/compile-fail/issue28498-reject-passed-to-fn.rs @@ -0,0 +1,50 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Demonstrate that a type param in negative position causes dropck to reject code +// that might indirectly access previously dropped value. +// +// Compare with run-pass/issue28498-ugeh-with-passed-to-fn.rs + +#[derive(Debug)] +struct ScribbleOnDrop(String); + +impl Drop for ScribbleOnDrop { + fn drop(&mut self) { + self.0 = format!("DROPPED"); + } +} + +struct Foo(u32, T, Box fn(&'r T) -> String>); + +impl Drop for Foo { + fn drop(&mut self) { + // Use of `unsafe_destructor_blind_to_params` is unsound, + // because we pass `T` to the callback in `self.2` + // below, and thus potentially read from borrowed data. + println!("Dropping Foo({}, {})", self.0, (self.2)(&self.1)); + } +} + +fn callback(s: & &ScribbleOnDrop) -> String { format!("{:?}", s) } + +fn main() { + let (last_dropped, foo0); + let (foo1, first_dropped); + + 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); +} diff --git a/src/test/compile-fail/issue28498-reject-trait-bound.rs b/src/test/compile-fail/issue28498-reject-trait-bound.rs new file mode 100644 index 0000000000..3904d68ba1 --- /dev/null +++ b/src/test/compile-fail/issue28498-reject-trait-bound.rs @@ -0,0 +1,50 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Demonstrate that having a trait bound causes dropck to reject code +// that might indirectly access previously dropped value. +// +// Compare with run-pass/issue28498-ugeh-with-trait-bound.rs + +use std::fmt; + +#[derive(Debug)] +struct ScribbleOnDrop(String); + +impl Drop for ScribbleOnDrop { + fn drop(&mut self) { + self.0 = format!("DROPPED"); + } +} + +struct Foo(u32, T); + +impl Drop for Foo { + fn drop(&mut self) { + // Use of `unsafe_destructor_blind_to_params` is unsound, + // because we access `T` fmt method when we pass `self.1` + // below, and thus potentially read from borrowed data. + println!("Dropping Foo({}, {:?})", self.0, self.1); + } +} + +fn main() { + let (last_dropped, foo0); + let (foo1, first_dropped); + + 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); +} diff --git a/src/test/compile-fail/lint-output-format.rs b/src/test/compile-fail/lint-output-format.rs index d95ed7f10b..c22ad3182d 100644 --- a/src/test/compile-fail/lint-output-format.rs +++ b/src/test/compile-fail/lint-output-format.rs @@ -14,7 +14,8 @@ #![feature(foo)] //~ ERROR unused or unknown feature extern crate lint_output_format; //~ ERROR use of unstable library feature -use lint_output_format::{foo, bar}; +use lint_output_format::{foo, bar}; //~ ERROR use of unstable library feature +//~^ WARNING use of deprecated item: text, fn main() { let _x = foo(); //~ WARNING #[warn(deprecated)] on by default diff --git a/src/test/compile-fail/lint-stability-fields.rs b/src/test/compile-fail/lint-stability-fields.rs index 7e675ca0bc..11f6411968 100644 --- a/src/test/compile-fail/lint-stability-fields.rs +++ b/src/test/compile-fail/lint-stability-fields.rs @@ -189,7 +189,7 @@ mod this_crate { inherit: u8, #[unstable(feature = "test_feature", issue = "0")] override1: u8, - #[deprecated(since = "1.0.0")] + #[deprecated(since = "1.0.0", reason = "text")] #[unstable(feature = "test_feature", issue = "0")] override2: u8, } @@ -198,14 +198,14 @@ mod this_crate { struct Stable2(u8, #[stable(feature = "rust1", since = "1.0.0")] u8, #[unstable(feature = "test_feature", issue = "0")] - #[deprecated(since = "1.0.0")] u8); + #[deprecated(since = "1.0.0", reason = "text")] u8); #[unstable(feature = "test_feature", issue = "0")] struct Unstable { inherit: u8, #[stable(feature = "rust1", since = "1.0.0")] override1: u8, - #[deprecated(since = "1.0.0")] + #[deprecated(since = "1.0.0", reason = "text")] #[unstable(feature = "test_feature", issue = "0")] override2: u8, } @@ -214,10 +214,10 @@ mod this_crate { struct Unstable2(u8, #[stable(feature = "rust1", since = "1.0.0")] u8, #[unstable(feature = "test_feature", issue = "0")] - #[deprecated(since = "1.0.0")] u8); + #[deprecated(since = "1.0.0", reason = "text")] u8); #[unstable(feature = "test_feature", issue = "0")] - #[deprecated(feature = "rust1", since = "1.0.0")] + #[deprecated(since = "1.0.0", reason = "text")] struct Deprecated { inherit: u8, #[stable(feature = "rust1", since = "1.0.0")] @@ -227,7 +227,7 @@ mod this_crate { } #[unstable(feature = "test_feature", issue = "0")] - #[deprecated(feature = "rust1", since = "1.0.0")] + #[deprecated(since = "1.0.0", reason = "text")] struct Deprecated2(u8, #[stable(feature = "rust1", since = "1.0.0")] u8, #[unstable(feature = "test_feature", issue = "0")] u8); diff --git a/src/test/compile-fail/lint-stability.rs b/src/test/compile-fail/lint-stability.rs index 6cc73ded97..864aafe5a6 100644 --- a/src/test/compile-fail/lint-stability.rs +++ b/src/test/compile-fail/lint-stability.rs @@ -258,7 +258,7 @@ mod inheritance { mod this_crate { #[unstable(feature = "test_feature", issue = "0")] - #[deprecated(since = "1.0.0")] + #[deprecated(since = "1.0.0", reason = "text")] pub fn deprecated() {} #[unstable(feature = "test_feature", issue = "0")] #[deprecated(since = "1.0.0", reason = "text")] @@ -271,7 +271,7 @@ mod this_crate { #[stable(feature = "rust1", since = "1.0.0")] pub fn stable() {} - #[stable(feature = "rust1", since = "1.0.0", reason = "text")] + #[stable(feature = "rust1", since = "1.0.0")] pub fn stable_text() {} #[stable(feature = "rust1", since = "1.0.0")] @@ -279,7 +279,7 @@ mod this_crate { impl MethodTester { #[unstable(feature = "test_feature", issue = "0")] - #[deprecated(since = "1.0.0")] + #[deprecated(since = "1.0.0", reason = "text")] pub fn method_deprecated(&self) {} #[unstable(feature = "test_feature", issue = "0")] #[deprecated(since = "1.0.0", reason = "text")] @@ -292,13 +292,13 @@ mod this_crate { #[stable(feature = "rust1", since = "1.0.0")] pub fn method_stable(&self) {} - #[stable(feature = "rust1", since = "1.0.0", reason = "text")] + #[stable(feature = "rust1", since = "1.0.0")] pub fn method_stable_text(&self) {} } pub trait Trait { #[unstable(feature = "test_feature", issue = "0")] - #[deprecated(since = "1.0.0")] + #[deprecated(since = "1.0.0", reason = "text")] fn trait_deprecated(&self) {} #[unstable(feature = "test_feature", issue = "0")] #[deprecated(since = "1.0.0", reason = "text")] @@ -311,14 +311,14 @@ mod this_crate { #[stable(feature = "rust1", since = "1.0.0")] fn trait_stable(&self) {} - #[stable(feature = "rust1", since = "1.0.0", reason = "text")] + #[stable(feature = "rust1", since = "1.0.0")] fn trait_stable_text(&self) {} } impl Trait for MethodTester {} #[unstable(feature = "test_feature", issue = "0")] - #[deprecated(since = "1.0.0")] + #[deprecated(since = "1.0.0", reason = "text")] pub struct DeprecatedStruct { #[stable(feature = "test_feature", since = "1.0.0")] i: isize } @@ -332,7 +332,7 @@ mod this_crate { } #[unstable(feature = "test_feature", issue = "0")] - #[deprecated(since = "1.0.0")] + #[deprecated(since = "1.0.0", reason = "text")] pub struct DeprecatedUnitStruct; #[unstable(feature = "test_feature", issue = "0")] pub struct UnstableUnitStruct; @@ -341,7 +341,7 @@ mod this_crate { pub enum Enum { #[unstable(feature = "test_feature", issue = "0")] - #[deprecated(since = "1.0.0")] + #[deprecated(since = "1.0.0", reason = "text")] DeprecatedVariant, #[unstable(feature = "test_feature", issue = "0")] UnstableVariant, @@ -351,7 +351,7 @@ mod this_crate { } #[unstable(feature = "test_feature", issue = "0")] - #[deprecated(since = "1.0.0")] + #[deprecated(since = "1.0.0", reason = "text")] pub struct DeprecatedTupleStruct(isize); #[unstable(feature = "test_feature", issue = "0")] pub struct UnstableTupleStruct(isize); @@ -472,7 +472,7 @@ mod this_crate { } #[unstable(feature = "test_feature", issue = "0")] - #[deprecated(since = "1.0.0")] + #[deprecated(since = "1.0.0", reason = "text")] fn test_fn_body() { fn fn_in_body() {} fn_in_body(); @@ -480,7 +480,7 @@ mod this_crate { impl MethodTester { #[unstable(feature = "test_feature", issue = "0")] - #[deprecated(since = "1.0.0")] + #[deprecated(since = "1.0.0", reason = "text")] fn test_method_body(&self) { fn fn_in_body() {} fn_in_body(); @@ -488,7 +488,7 @@ mod this_crate { } #[unstable(feature = "test_feature", issue = "0")] - #[deprecated(since = "1.0.0")] + #[deprecated(since = "1.0.0", reason = "text")] pub trait DeprecatedTrait { fn dummy(&self) { } } diff --git a/src/test/compile-fail/lint-visible-private-types.rs b/src/test/compile-fail/lint-visible-private-types.rs index c6dc3b70be..d34738282e 100644 --- a/src/test/compile-fail/lint-visible-private-types.rs +++ b/src/test/compile-fail/lint-visible-private-types.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(visible_private_types)] #![allow(dead_code)] #![crate_type="lib"] diff --git a/src/test/compile-fail/loop-does-not-diverge.rs b/src/test/compile-fail/loop-does-not-diverge.rs index 12de4a714e..cd320ba148 100644 --- a/src/test/compile-fail/loop-does-not-diverge.rs +++ b/src/test/compile-fail/loop-does-not-diverge.rs @@ -18,5 +18,5 @@ fn forever() -> ! { } fn main() { - if (1 == 2) { forever(); } + if 1 == 2 { forever(); } } diff --git a/src/test/compile-fail/moves-based-on-type-tuple.rs b/src/test/compile-fail/moves-based-on-type-tuple.rs index e1d462d170..a4d3e3ee02 100644 --- a/src/test/compile-fail/moves-based-on-type-tuple.rs +++ b/src/test/compile-fail/moves-based-on-type-tuple.rs @@ -11,8 +11,7 @@ #![feature(box_syntax)] fn dup(x: Box) -> Box<(Box,Box)> { - box() (x, x) //~ ERROR use of moved value - //~^ WARN deprecated syntax + box (x, x) //~ ERROR use of moved value } fn main() { dup(box 3); diff --git a/src/test/compile-fail/object-safety-issue-22040.rs b/src/test/compile-fail/object-safety-issue-22040.rs index de419a259a..06d2441d3c 100644 --- a/src/test/compile-fail/object-safety-issue-22040.rs +++ b/src/test/compile-fail/object-safety-issue-22040.rs @@ -20,12 +20,13 @@ trait Expr: Debug + PartialEq { #[derive(Debug)] struct SExpr<'x> { elements: Vec>, + //~^ ERROR E0038 } impl<'x> PartialEq for SExpr<'x> { fn eq(&self, other:&SExpr<'x>) -> bool { println!("L1: {} L2: {}", self.elements.len(), other.elements.len()); - //~^ ERROR E0038 + let result = self.elements.len() == other.elements.len(); println!("Got compare {}", result); @@ -44,8 +45,8 @@ impl <'x> Expr for SExpr<'x> { } fn main() { - let a: Box = Box::new(SExpr::new()); //~ ERROR E0038 - let b: Box = Box::new(SExpr::new()); //~ ERROR E0038 + let a: Box = Box::new(SExpr::new()); + let b: Box = Box::new(SExpr::new()); // assert_eq!(a , b); } diff --git a/src/test/compile-fail/object-safety-supertrait-mentions-Self.rs b/src/test/compile-fail/object-safety-supertrait-mentions-Self.rs index ba82635a40..0a79ec30e4 100644 --- a/src/test/compile-fail/object-safety-supertrait-mentions-Self.rs +++ b/src/test/compile-fail/object-safety-supertrait-mentions-Self.rs @@ -23,9 +23,9 @@ fn make_bar>(t: &T) -> &Bar { } fn make_baz(t: &T) -> &Baz { + //~^ ERROR E0038 + //~| NOTE the trait cannot use `Self` as a type parameter in the supertrait listing t - //~^ ERROR E0038 - //~| NOTE the trait cannot use `Self` as a type parameter in the supertrait listing } fn main() { diff --git a/src/test/compile-fail/packed-struct-generic-transmute.rs b/src/test/compile-fail/packed-struct-generic-transmute.rs index 82425d2c22..2c345e6c8a 100644 --- a/src/test/compile-fail/packed-struct-generic-transmute.rs +++ b/src/test/compile-fail/packed-struct-generic-transmute.rs @@ -13,7 +13,7 @@ // the error points to the start of the file, not the line with the // transmute -// error-pattern: transmute called on types with different size +// error-pattern: transmute called with differently sized types use std::mem; diff --git a/src/test/compile-fail/packed-struct-transmute.rs b/src/test/compile-fail/packed-struct-transmute.rs index 1b164709ac..94f2522f3e 100644 --- a/src/test/compile-fail/packed-struct-transmute.rs +++ b/src/test/compile-fail/packed-struct-transmute.rs @@ -13,7 +13,7 @@ // the error points to the start of the file, not the line with the // transmute -// error-pattern: transmute called on types with different size +// error-pattern: transmute called with differently sized types use std::mem; diff --git a/src/test/compile-fail/placement-expr-unsafe.rs b/src/test/compile-fail/placement-expr-unsafe.rs new file mode 100644 index 0000000000..50a840e6c9 --- /dev/null +++ b/src/test/compile-fail/placement-expr-unsafe.rs @@ -0,0 +1,24 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that placement in respects unsafe code checks. + +#![feature(box_heap)] +#![feature(placement_in_syntax)] + +fn main() { + use std::boxed::HEAP; + + let p: *const i32 = &42; + let _ = in HEAP { *p }; //~ ERROR requires unsafe + + let p: *const _ = &HEAP; + let _ = in *p { 42 }; //~ ERROR requires unsafe +} diff --git a/src/test/compile-fail/placement-expr-unstable.rs b/src/test/compile-fail/placement-expr-unstable.rs new file mode 100644 index 0000000000..d981b71a81 --- /dev/null +++ b/src/test/compile-fail/placement-expr-unstable.rs @@ -0,0 +1,27 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that placement in respects unstable code checks. + +#![feature(placement_in_syntax)] +#![feature(core)] + +extern crate core; + +fn main() { + use std::boxed::HEAP; //~ ERROR use of unstable library feature + + let _ = in HEAP { //~ ERROR use of unstable library feature + ::core::raw::Slice { //~ ERROR use of unstable library feature + data: &42, //~ ERROR use of unstable library feature + len: 1 //~ ERROR use of unstable library feature + } + }; +} diff --git a/src/test/compile-fail/privacy-ufcs.rs b/src/test/compile-fail/privacy-ufcs.rs new file mode 100644 index 0000000000..ccb379c717 --- /dev/null +++ b/src/test/compile-fail/privacy-ufcs.rs @@ -0,0 +1,24 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test to ensure private traits are inaccessible with UFCS angle-bracket syntax. + +mod foo { + trait Bar { + fn baz() {} + } + + impl Bar for i32 {} +} + +fn main() { + ::baz(); //~ERROR method `baz` is inaccessible + //~^NOTE: trait `Bar` is private +} diff --git a/src/test/compile-fail/pushpop-unsafe-rejects.rs b/src/test/compile-fail/pushpop-unsafe-rejects.rs deleted file mode 100644 index 72c065ae71..0000000000 --- a/src/test/compile-fail/pushpop-unsafe-rejects.rs +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Basic sanity check for `push_unsafe!(EXPR)` and -// `pop_unsafe!(EXPR)`: we can call unsafe code when there are a -// positive number of pushes in the stack, or if we are within a -// normal `unsafe` block, but otherwise cannot. - -#![feature(pushpop_unsafe)] - -static mut X: i32 = 0; - -unsafe fn f() { X += 1; return; } -fn g() { unsafe { X += 1_000; } return; } - -fn main() { - push_unsafe!( { - f(); pop_unsafe!({ - f() //~ ERROR: call to unsafe function - }) - } ); - - push_unsafe!({ - f(); - pop_unsafe!({ - g(); - f(); //~ ERROR: call to unsafe function - }) - } ); - - push_unsafe!({ - g(); pop_unsafe!({ - unsafe { - f(); - } - f(); //~ ERROR: call to unsafe function - }) - }); - - - // Note: For implementation simplicity the compiler just - // ICE's if you underflow the push_unsafe stack. - // - // Thus all of the following cases cause an ICE. - // - // (The "ERROR" notes are from an earlier version - // that used saturated arithmetic rather than checked - // arithmetic.) - - // pop_unsafe!{ g() }; - // - // push_unsafe!({ - // pop_unsafe!(pop_unsafe!{ g() }) - // }); - // - // push_unsafe!({ - // g(); - // pop_unsafe!(pop_unsafe!({ - // f() // ERROR: call to unsafe function - // })) - // }); - // - // pop_unsafe!({ - // f(); // ERROR: call to unsafe function - // }) - -} diff --git a/src/test/compile-fail/regions-outlives-projection-container-hrtb.rs b/src/test/compile-fail/regions-outlives-projection-container-hrtb.rs index b8c4a7f8a8..ec0631a881 100644 --- a/src/test/compile-fail/regions-outlives-projection-container-hrtb.rs +++ b/src/test/compile-fail/regions-outlives-projection-container-hrtb.rs @@ -37,7 +37,7 @@ pub struct WithHrAssoc } fn with_assoc<'a,'b>() { - // We get an error because beacuse 'b:'a does not hold: + // We get an error because 'b:'a does not hold: let _: &'a WithHrAssoc> = loop { }; //~^ ERROR reference has a longer lifetime diff --git a/src/test/compile-fail/stability-attribute-sanity-2.rs b/src/test/compile-fail/stability-attribute-sanity-2.rs new file mode 100644 index 0000000000..cdeff7afe1 --- /dev/null +++ b/src/test/compile-fail/stability-attribute-sanity-2.rs @@ -0,0 +1,25 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// More checks that stability attributes are used correctly + +#![feature(staged_api)] +#![staged_api] + +#[stable(feature = "a", feature = "b", since = "1.0.0")] //~ ERROR multiple 'feature' items +fn f1() { } + +#[stable(feature = "a", sinse = "1.0.0")] //~ ERROR unknown meta item 'sinse' +fn f2() { } + +#[unstable(feature = "a", issue = "no")] //~ ERROR incorrect 'issue' +fn f3() { } + +fn main() { } diff --git a/src/test/compile-fail/stability-attribute-sanity.rs b/src/test/compile-fail/stability-attribute-sanity.rs index 00c5be0f21..f71e66ded7 100644 --- a/src/test/compile-fail/stability-attribute-sanity.rs +++ b/src/test/compile-fail/stability-attribute-sanity.rs @@ -14,22 +14,19 @@ #![staged_api] mod bogus_attribute_types_1 { - #[stable(feature = "a", since = "a", reason)] //~ ERROR incorrect meta item + #[stable(feature = "a", since = "a", reason)] //~ ERROR unknown meta item 'reason' fn f1() { } - #[stable(feature = "a", since, reason = "a")] //~ ERROR incorrect meta item + #[stable(feature = "a", since)] //~ ERROR incorrect meta item fn f2() { } - #[stable(feature, since = "a", reason = "a")] //~ ERROR incorrect meta item + #[stable(feature, since = "a")] //~ ERROR incorrect meta item fn f3() { } - #[stable(feature = "a", since = "a", reason(b))] //~ ERROR incorrect meta item - fn f4() { } - - #[stable(feature = "a", since(b), reason = "a")] //~ ERROR incorrect meta item + #[stable(feature = "a", since(b))] //~ ERROR incorrect meta item fn f5() { } - #[stable(feature(b), since = "a", reason = "a")] //~ ERROR incorrect meta item + #[stable(feature(b), since = "a")] //~ ERROR incorrect meta item fn f6() { } } @@ -56,11 +53,11 @@ mod bogus_attribute_types_2 { } mod missing_feature_names { - #[unstable(since = "a", issue = "0")] //~ ERROR missing 'feature' + #[unstable(issue = "0")] //~ ERROR missing 'feature' fn f1() { } - #[unstable(feature = "a")] - fn f2() { } //~ ERROR need to point to an issue + #[unstable(feature = "a")] //~ ERROR missing 'issue' + fn f2() { } #[stable(since = "a")] //~ ERROR missing 'feature' fn f3() { } @@ -75,12 +72,12 @@ mod missing_version { fn f2() { } } -#[unstable(feature = "a", since = "b", issue = "0")] +#[unstable(feature = "a", issue = "0")] #[stable(feature = "a", since = "b")] fn multiple1() { } //~ ERROR multiple stability levels -#[unstable(feature = "a", since = "b", issue = "0")] -#[unstable(feature = "a", since = "b", issue = "0")] +#[unstable(feature = "a", issue = "0")] +#[unstable(feature = "a", issue = "0")] fn multiple2() { } //~ ERROR multiple stability levels #[stable(feature = "a", since = "b")] @@ -88,12 +85,12 @@ fn multiple2() { } //~ ERROR multiple stability levels fn multiple3() { } //~ ERROR multiple stability levels #[stable(feature = "a", since = "b")] -#[deprecated(since = "b")] -#[deprecated(since = "b")] +#[deprecated(since = "b", reason = "text")] +#[deprecated(since = "b", reason = "text")] fn multiple4() { } //~ ERROR multiple deprecated attributes //~^ ERROR Invalid stability or deprecation version found -#[deprecated(since = "a")] +#[deprecated(since = "a", reason = "text")] fn deprecated_without_unstable_or_stable() { } //~ ERROR deprecated attribute must be paired fn main() { } diff --git a/src/test/parse-fail/struct-no-fields-enumlike.rs b/src/test/compile-fail/struct-no-fields-enumlike.rs similarity index 80% rename from src/test/parse-fail/struct-no-fields-enumlike.rs rename to src/test/compile-fail/struct-no-fields-enumlike.rs index 19a395806d..6bdbae1e4b 100644 --- a/src/test/parse-fail/struct-no-fields-enumlike.rs +++ b/src/test/compile-fail/struct-no-fields-enumlike.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 - -struct Foo(); //~ ERROR unit-like struct definition should be written as `struct Foo;` +struct Foo(); //~ ERROR empty tuple structs and enum variants are not allowed fn main() {} diff --git a/src/test/compile-fail/trait-not-accessible.rs b/src/test/compile-fail/trait-not-accessible.rs new file mode 100644 index 0000000000..21668fcfea --- /dev/null +++ b/src/test/compile-fail/trait-not-accessible.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. + +mod m { + trait Priv { + fn f(&self) {} + } + impl Priv for super::S {} + pub trait Pub: Priv {} +} + +struct S; +impl m::Pub for S {} + +fn g(arg: T) { + arg.f(); //~ ERROR: source trait is private +} + +fn main() { + g(S); +} diff --git a/src/test/compile-fail/trait-test-2.rs b/src/test/compile-fail/trait-test-2.rs index b11cbde292..13fe314fbc 100644 --- a/src/test/compile-fail/trait-test-2.rs +++ b/src/test/compile-fail/trait-test-2.rs @@ -21,4 +21,5 @@ fn main() { //~^ ERROR E0038 //~| ERROR E0038 //~| ERROR E0277 + //~| WARNING E0038 } diff --git a/src/test/compile-fail/transmute-different-sizes.rs b/src/test/compile-fail/transmute-different-sizes.rs index 918589b8fd..df87a7bbdc 100644 --- a/src/test/compile-fail/transmute-different-sizes.rs +++ b/src/test/compile-fail/transmute-different-sizes.rs @@ -16,12 +16,12 @@ use std::mem::transmute; unsafe fn f() { let _: i8 = transmute(16i16); - //~^ ERROR transmute called on types with different sizes + //~^ ERROR transmute called with differently sized types } unsafe fn g(x: &T) { let _: i8 = transmute(x); - //~^ ERROR transmute called on types with potentially different sizes + //~^ ERROR transmute called with differently sized types } fn main() {} diff --git a/src/test/compile-fail/transmute-fat-pointers.rs b/src/test/compile-fail/transmute-fat-pointers.rs index 31456853e1..f7324247f3 100644 --- a/src/test/compile-fail/transmute-fat-pointers.rs +++ b/src/test/compile-fail/transmute-fat-pointers.rs @@ -15,11 +15,11 @@ use std::mem::transmute; fn a(x: &[T]) -> &U { - unsafe { transmute(x) } //~ ERROR transmute called on types with potentially different sizes + unsafe { transmute(x) } //~ ERROR transmute called with differently sized types } fn b(x: &T) -> &U { - unsafe { transmute(x) } //~ ERROR transmute called on types with potentially different sizes + unsafe { transmute(x) } //~ ERROR transmute called with differently sized types } fn c(x: &T) -> &U { @@ -31,11 +31,11 @@ fn d(x: &[T]) -> &[U] { } fn e(x: &T) -> &U { - unsafe { transmute(x) } //~ ERROR transmute called on types with potentially different sizes + unsafe { transmute(x) } //~ ERROR transmute called with differently sized types } fn f(x: &T) -> &U { - unsafe { transmute(x) } //~ ERROR transmute called on types with potentially different sizes + unsafe { transmute(x) } //~ ERROR transmute called with differently sized types } fn main() { } diff --git a/src/test/compile-fail/transmute-impl.rs b/src/test/compile-fail/transmute-impl.rs index a77a37a77e..55cebbd6cf 100644 --- a/src/test/compile-fail/transmute-impl.rs +++ b/src/test/compile-fail/transmute-impl.rs @@ -26,7 +26,7 @@ impl Foo { fn n(x: &T) -> &isize { // Not OK here, because T : Sized is not in scope. - unsafe { transmute(x) } //~ ERROR transmute called on types with potentially different sizes + unsafe { transmute(x) } //~ ERROR transmute called with differently sized types } } diff --git a/src/test/compile-fail/transmute-imut-to-mut.rs b/src/test/compile-fail/transmute-imut-to-mut.rs index 2e076337f5..62db4c5d36 100644 --- a/src/test/compile-fail/transmute-imut-to-mut.rs +++ b/src/test/compile-fail/transmute-imut-to-mut.rs @@ -17,4 +17,3 @@ fn main() { //~^ ERROR mutating transmuted &mut T from &T may cause undefined behavior } - diff --git a/src/test/compile-fail/unboxed-closures-recursive-fn-using-fn-mut.rs b/src/test/compile-fail/unboxed-closures-recursive-fn-using-fn-mut.rs index 2dcd7a97d8..23306823c7 100644 --- a/src/test/compile-fail/unboxed-closures-recursive-fn-using-fn-mut.rs +++ b/src/test/compile-fail/unboxed-closures-recursive-fn-using-fn-mut.rs @@ -12,7 +12,7 @@ use std::marker::PhantomData; -// A erroneous variant of `run-pass/unboxed_closures-infer-recursive-fn.rs` +// An erroneous variant of `run-pass/unboxed_closures-infer-recursive-fn.rs` // where we attempt to perform mutation in the recursive function. This fails to compile // because it winds up requiring `FnMut` which enforces linearity. diff --git a/src/test/compile-fail/unsafe-const-fn.rs b/src/test/compile-fail/unsafe-const-fn.rs new file mode 100644 index 0000000000..24ac41ce88 --- /dev/null +++ b/src/test/compile-fail/unsafe-const-fn.rs @@ -0,0 +1,24 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// A quick test of 'unsafe const fn' functionality + +#![feature(const_fn)] + +const unsafe fn dummy(v: u32) -> u32 { + !v +} + +const VAL: u32 = dummy(0xFFFF); //~ ERROR E0133 + +fn main() { + assert_eq!(VAL, 0xFFFF0000); +} + diff --git a/src/test/compile-fail/useless-priv.rs b/src/test/compile-fail/useless-pub.rs similarity index 91% rename from src/test/compile-fail/useless-priv.rs rename to src/test/compile-fail/useless-pub.rs index 59964d0df9..fb6cdf7fa5 100644 --- a/src/test/compile-fail/useless-priv.rs +++ b/src/test/compile-fail/useless-pub.rs @@ -9,7 +9,6 @@ // except according to those terms. struct A { pub i: isize } -pub enum C { pub Variant } //~ ERROR: unnecessary `pub` pub trait E { fn foo(&self); diff --git a/src/test/compile-fail/variance-regions-direct.rs b/src/test/compile-fail/variance-regions-direct.rs index 319b81bde3..bb452eecbf 100644 --- a/src/test/compile-fail/variance-regions-direct.rs +++ b/src/test/compile-fail/variance-regions-direct.rs @@ -48,7 +48,7 @@ struct Test5<'a, 'b:'a> { //~ ERROR regions=[[+, o];[];[]] // Invariance is a trap from which NO ONE CAN ESCAPE. // In other words, even though the `&'b isize` occurs in -// a argument list (which is contravariant), that +// an argument list (which is contravariant), that // argument list occurs in an invariant context. #[rustc_variance] diff --git a/src/test/compile-fail/variance-trait-bounds.rs b/src/test/compile-fail/variance-trait-bounds.rs index 222d8338aa..b6f197987b 100644 --- a/src/test/compile-fail/variance-trait-bounds.rs +++ b/src/test/compile-fail/variance-trait-bounds.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(bivariance)] #![allow(dead_code)] #![feature(rustc_attrs)] diff --git a/src/test/compile-fail/variance-types.rs b/src/test/compile-fail/variance-types.rs index e407ebe345..2fd8bf20c7 100644 --- a/src/test/compile-fail/variance-types.rs +++ b/src/test/compile-fail/variance-types.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(bivariance)] #![allow(dead_code)] #![feature(rustc_attrs)] diff --git a/src/test/compile-fail/vec-must-not-hide-type-from-dropck.rs b/src/test/compile-fail/vec-must-not-hide-type-from-dropck.rs index 3752895968..c8f4326bb2 100644 --- a/src/test/compile-fail/vec-must-not-hide-type-from-dropck.rs +++ b/src/test/compile-fail/vec-must-not-hide-type-from-dropck.rs @@ -29,7 +29,6 @@ use std::cell::Cell; use id::Id; mod s { - #![allow(unstable)] use std::sync::atomic::{AtomicUsize, Ordering}; static S_COUNT: AtomicUsize = AtomicUsize::new(0); diff --git a/src/test/compile-fail/wf-method-late-bound-regions.rs b/src/test/compile-fail/wf-method-late-bound-regions.rs new file mode 100644 index 0000000000..b9d292fd15 --- /dev/null +++ b/src/test/compile-fail/wf-method-late-bound-regions.rs @@ -0,0 +1,33 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// A method's receiver must be well-formed, even if it has late-bound regions. +// Because of this, a method's substs being well-formed does not imply that +// the method's implied bounds are met. + +struct Foo<'b>(Option<&'b ()>); + +trait Bar<'b> { + fn xmute<'a>(&'a self, u: &'b u32) -> &'a u32; +} + +impl<'b> Bar<'b> for Foo<'b> { + fn xmute<'a>(&'a self, u: &'b u32) -> &'a u32 { u } +} + +fn main() { + let f = Foo(None); + let f2 = f; + let dangling = { + let pointer = Box::new(42); + f2.xmute(&pointer) //~ ERROR `pointer` does not live long enough + }; + println!("{}", dangling); +} diff --git a/src/test/compile-fail/wf-misc-methods-issue-28609.rs b/src/test/compile-fail/wf-misc-methods-issue-28609.rs new file mode 100644 index 0000000000..055c86a03a --- /dev/null +++ b/src/test/compile-fail/wf-misc-methods-issue-28609.rs @@ -0,0 +1,84 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// check that misc. method calls are well-formed + +use std::marker::PhantomData; +use std::ops::{Deref, Shl}; + +#[derive(Copy, Clone)] +struct S<'a, 'b: 'a> { + marker: PhantomData<&'a &'b ()>, + bomb: Option<&'b u32> +} + +type S2<'a> = S<'a, 'a>; + +impl<'a, 'b> S<'a, 'b> { + fn transmute_inherent(&self, a: &'b u32) -> &'a u32 { + a + } +} + +fn return_dangling_pointer_inherent(s: S2) -> &u32 { + let s = s; + s.transmute_inherent(&mut 42) //~ ERROR does not live long enough +} + +impl<'a, 'b> Deref for S<'a, 'b> { + type Target = &'a u32; + fn deref(&self) -> &&'a u32 { + self.bomb.as_ref().unwrap() + } +} + +fn return_dangling_pointer_coerce(s: S2) -> &u32 { + let four = 4; + let mut s = s; + s.bomb = Some(&four); //~ ERROR does not live long enough + &s +} + +fn return_dangling_pointer_unary_op(s: S2) -> &u32 { + let four = 4; + let mut s = s; + s.bomb = Some(&four); //~ ERROR does not live long enough + &*s +} + +impl<'a, 'b> Shl<&'b u32> for S<'a, 'b> { + type Output = &'a u32; + fn shl(self, t: &'b u32) -> &'a u32 { t } +} + +fn return_dangling_pointer_binary_op(s: S2) -> &u32 { + let s = s; + s << &mut 3 //~ ERROR does not live long enough +} + +fn return_dangling_pointer_method(s: S2) -> &u32 { + let s = s; + s.shl(&mut 3) //~ ERROR does not live long enough +} + +fn return_dangling_pointer_ufcs(s: S2) -> &u32 { + let s = s; + S2::shl(s, &mut 3) //~ ERROR does not live long enough +} + +fn main() { + let s = S { marker: PhantomData, bomb: None }; + let _inherent_dp = return_dangling_pointer_inherent(s); + let _coerce_dp = return_dangling_pointer_coerce(s); + let _unary_dp = return_dangling_pointer_unary_op(s); + let _binary_dp = return_dangling_pointer_binary_op(s); + let _method_dp = return_dangling_pointer_method(s); + let _ufcs_dp = return_dangling_pointer_ufcs(s); +} diff --git a/src/test/compile-fail/wf-static-method.rs b/src/test/compile-fail/wf-static-method.rs new file mode 100644 index 0000000000..6c6522fe65 --- /dev/null +++ b/src/test/compile-fail/wf-static-method.rs @@ -0,0 +1,64 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// check that static methods don't get to assume their trait-ref +// is well-formed. +// FIXME(#27579): this is just a bug. However, our checking with +// static inherent methods isn't quite working - need to +// fix that before removing the check. + +trait Foo<'a, 'b, T>: Sized { + fn make_me() -> Self { loop {} } + fn static_evil(u: &'b u32) -> &'a u32; +} + +struct Evil<'a, 'b: 'a>(Option<&'a &'b ()>); + +impl<'a, 'b> Foo<'a, 'b, Evil<'a, 'b>> for () { + fn make_me() -> Self { } + fn static_evil(u: &'b u32) -> &'a u32 { + u //~ ERROR cannot infer an appropriate lifetime + } +} + +struct IndirectEvil<'a, 'b: 'a>(Option<&'a &'b ()>); + +impl<'a, 'b> Foo<'a, 'b, ()> for IndirectEvil<'a, 'b> { + fn make_me() -> Self { IndirectEvil(None) } + fn static_evil(u: &'b u32) -> &'a u32 { + let me = Self::make_me(); //~ ERROR lifetime bound not satisfied + loop {} // (`me` could be used for the lifetime transmute). + } +} + +impl<'a, 'b> Evil<'a, 'b> { + fn inherent_evil(u: &'b u32) -> &'a u32 { + u //~ ERROR cannot infer an appropriate lifetime + } +} + +// while static methods don't get to *assume* this, we still +// *check* that they hold. + +fn evil<'a, 'b>(b: &'b u32) -> &'a u32 { + <()>::static_evil(b) //~ ERROR cannot infer an appropriate lifetime +} + +fn indirect_evil<'a, 'b>(b: &'b u32) -> &'a u32 { + ::static_evil(b) + //~^ ERROR cannot infer an appropriate lifetime +} + +fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 { + ::inherent_evil(b) // bug? shouldn't this be an error +} + + +fn main() {} diff --git a/src/test/debuginfo/associated-types.rs b/src/test/debuginfo/associated-types.rs index d203806c08..ebaad663bb 100644 --- a/src/test/debuginfo/associated-types.rs +++ b/src/test/debuginfo/associated-types.rs @@ -80,6 +80,7 @@ #![allow(unused_variables)] #![allow(dead_code)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] trait TraitWithAssocType { diff --git a/src/test/debuginfo/basic-types-globals-metadata.rs b/src/test/debuginfo/basic-types-globals-metadata.rs index 1aabd549ca..8818063ddf 100644 --- a/src/test/debuginfo/basic-types-globals-metadata.rs +++ b/src/test/debuginfo/basic-types-globals-metadata.rs @@ -44,6 +44,7 @@ #![allow(unused_variables)] #![allow(dead_code)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] // N.B. These are `mut` only so they don't constant fold away. diff --git a/src/test/debuginfo/basic-types-globals.rs b/src/test/debuginfo/basic-types-globals.rs index f0c187fd22..ccf9508a38 100644 --- a/src/test/debuginfo/basic-types-globals.rs +++ b/src/test/debuginfo/basic-types-globals.rs @@ -49,6 +49,7 @@ // gdb-command:continue #![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] // N.B. These are `mut` only so they don't constant fold away. diff --git a/src/test/debuginfo/basic-types-metadata.rs b/src/test/debuginfo/basic-types-metadata.rs index 3b662ae026..1a6b605d9d 100644 --- a/src/test/debuginfo/basic-types-metadata.rs +++ b/src/test/debuginfo/basic-types-metadata.rs @@ -64,6 +64,7 @@ // gdb-command:continue #![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] fn main() { diff --git a/src/test/debuginfo/basic-types-mut-globals.rs b/src/test/debuginfo/basic-types-mut-globals.rs index 4094c2e9b1..4ebd0c9577 100644 --- a/src/test/debuginfo/basic-types-mut-globals.rs +++ b/src/test/debuginfo/basic-types-mut-globals.rs @@ -82,6 +82,7 @@ // gdb-check:$28 = 9.25 #![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] static mut B: bool = false; diff --git a/src/test/debuginfo/basic-types.rs b/src/test/debuginfo/basic-types.rs index c9144b18b2..9980108328 100644 --- a/src/test/debuginfo/basic-types.rs +++ b/src/test/debuginfo/basic-types.rs @@ -87,6 +87,7 @@ // lldb-check:[...]$12 = 3.5 #![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] fn main() { diff --git a/src/test/debuginfo/borrowed-basic.rs b/src/test/debuginfo/borrowed-basic.rs index b0f06bb8a7..bada77b662 100644 --- a/src/test/debuginfo/borrowed-basic.rs +++ b/src/test/debuginfo/borrowed-basic.rs @@ -108,6 +108,7 @@ // lldb-check:[...]$12 = 3.5 #![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] fn main() { diff --git a/src/test/debuginfo/borrowed-c-style-enum.rs b/src/test/debuginfo/borrowed-c-style-enum.rs index ecc70f4d77..c80783ef31 100644 --- a/src/test/debuginfo/borrowed-c-style-enum.rs +++ b/src/test/debuginfo/borrowed-c-style-enum.rs @@ -40,6 +40,7 @@ // lldb-check:[...]$2 = TheC #![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] enum ABC { TheA, TheB, TheC } diff --git a/src/test/debuginfo/borrowed-enum.rs b/src/test/debuginfo/borrowed-enum.rs index 732383b5e4..b21574e328 100644 --- a/src/test/debuginfo/borrowed-enum.rs +++ b/src/test/debuginfo/borrowed-enum.rs @@ -39,6 +39,7 @@ // lldb-check:[...]$2 = TheOnlyCase(4820353753753434) #![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] // The first element is to ensure proper alignment, irrespective of the machines word size. Since diff --git a/src/test/debuginfo/borrowed-struct.rs b/src/test/debuginfo/borrowed-struct.rs index 70c24fc2ab..ab41185cb7 100644 --- a/src/test/debuginfo/borrowed-struct.rs +++ b/src/test/debuginfo/borrowed-struct.rs @@ -64,6 +64,7 @@ #![allow(unused_variables)] #![feature(box_syntax)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] struct SomeStruct { diff --git a/src/test/debuginfo/borrowed-tuple.rs b/src/test/debuginfo/borrowed-tuple.rs index add9bdcead..e3da3934f6 100644 --- a/src/test/debuginfo/borrowed-tuple.rs +++ b/src/test/debuginfo/borrowed-tuple.rs @@ -42,6 +42,7 @@ #![allow(unused_variables)] #![feature(box_syntax)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] fn main() { @@ -49,7 +50,7 @@ fn main() { let stack_val_ref: &(i16, f32) = &stack_val; let ref_to_unnamed: &(i16, f32) = &(-15, -20f32); - let unique_val: Box<(i16, f32)> = box() (-17, -22f32); + let unique_val: Box<(i16, f32)> = box (-17, -22f32); let unique_val_ref: &(i16, f32) = &*unique_val; zzz(); // #break diff --git a/src/test/debuginfo/borrowed-unique-basic.rs b/src/test/debuginfo/borrowed-unique-basic.rs index d8ce3af478..88af94c536 100644 --- a/src/test/debuginfo/borrowed-unique-basic.rs +++ b/src/test/debuginfo/borrowed-unique-basic.rs @@ -112,6 +112,7 @@ #![allow(unused_variables)] #![feature(box_syntax)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] fn main() { diff --git a/src/test/debuginfo/box.rs b/src/test/debuginfo/box.rs index e5f4306b24..106d0b243e 100644 --- a/src/test/debuginfo/box.rs +++ b/src/test/debuginfo/box.rs @@ -32,11 +32,12 @@ #![allow(unused_variables)] #![feature(box_syntax)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] fn main() { let a = box 1; - let b = box() (2, 3.5f64); + let b = box (2, 3.5f64); zzz(); // #break } diff --git a/src/test/debuginfo/boxed-struct.rs b/src/test/debuginfo/boxed-struct.rs index 9c6e197e65..dd543405e4 100644 --- a/src/test/debuginfo/boxed-struct.rs +++ b/src/test/debuginfo/boxed-struct.rs @@ -35,6 +35,7 @@ #![allow(unused_variables)] #![feature(box_syntax)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] struct StructWithSomePadding { diff --git a/src/test/debuginfo/by-value-non-immediate-argument.rs b/src/test/debuginfo/by-value-non-immediate-argument.rs index 1e89d0e31b..a329ef6d0e 100644 --- a/src/test/debuginfo/by-value-non-immediate-argument.rs +++ b/src/test/debuginfo/by-value-non-immediate-argument.rs @@ -70,6 +70,7 @@ // lldb-check:[...]$6 = Case1 { x: 0, y: 8970181431921507452 } // lldb-command:continue +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] #[derive(Clone)] 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 39da48f9e7..a768bfdd16 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 @@ -45,6 +45,7 @@ // lldb-check:[...]$2 = (4444.5, 5555, 6666, 7777.5) // lldb-command:continue +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] trait Trait { diff --git a/src/test/debuginfo/c-style-enum-in-composite.rs b/src/test/debuginfo/c-style-enum-in-composite.rs index 562b0d588f..83a22edc96 100644 --- a/src/test/debuginfo/c-style-enum-in-composite.rs +++ b/src/test/debuginfo/c-style-enum-in-composite.rs @@ -64,6 +64,7 @@ // lldb-check:[...]$6 = (StructWithDrop { a: OneHundred, b: Vienna }, 9) #![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] use self::AnEnum::{OneHundred, OneThousand, OneMillion}; diff --git a/src/test/debuginfo/c-style-enum.rs b/src/test/debuginfo/c-style-enum.rs index 3024ca0fe6..4eec26d335 100644 --- a/src/test/debuginfo/c-style-enum.rs +++ b/src/test/debuginfo/c-style-enum.rs @@ -99,6 +99,7 @@ #![allow(unused_variables)] #![allow(dead_code)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] use self::AutoDiscriminant::{One, Two, Three}; diff --git a/src/test/debuginfo/closure-in-generic-function.rs b/src/test/debuginfo/closure-in-generic-function.rs index 448e157a25..5335e0bfa4 100644 --- a/src/test/debuginfo/closure-in-generic-function.rs +++ b/src/test/debuginfo/closure-in-generic-function.rs @@ -46,6 +46,7 @@ // lldb-command:continue #![feature(box_syntax)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] fn some_generic_fun(a: T1, b: T2) -> (T2, T1) { diff --git a/src/test/debuginfo/constant-debug-locs.rs b/src/test/debuginfo/constant-debug-locs.rs index ec5a6fa3d3..04e19b30fd 100644 --- a/src/test/debuginfo/constant-debug-locs.rs +++ b/src/test/debuginfo/constant-debug-locs.rs @@ -13,6 +13,7 @@ // compile-flags:-g #![allow(dead_code, unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] #![feature(const_fn)] #![feature(static_mutex)] diff --git a/src/test/debuginfo/constant-in-match-pattern.rs b/src/test/debuginfo/constant-in-match-pattern.rs index 785778e62f..fb40400a44 100644 --- a/src/test/debuginfo/constant-in-match-pattern.rs +++ b/src/test/debuginfo/constant-in-match-pattern.rs @@ -13,6 +13,7 @@ // compile-flags:-g #![allow(dead_code, unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] // This test makes sure that the compiler doesn't crash when trying to assign diff --git a/src/test/debuginfo/cross-crate-spans.rs b/src/test/debuginfo/cross-crate-spans.rs index ce6ef080c1..544fe2c66d 100644 --- a/src/test/debuginfo/cross-crate-spans.rs +++ b/src/test/debuginfo/cross-crate-spans.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] // min-lldb-version: 310 @@ -20,7 +21,7 @@ extern crate cross_crate_spans; // === GDB TESTS =================================================================================== -// gdb-command:break cross_crate_spans.rs:23 +// gdb-command:break cross_crate_spans.rs:24 // gdb-command:run // gdb-command:print result @@ -43,7 +44,7 @@ extern crate cross_crate_spans; // === LLDB TESTS ================================================================================== -// lldb-command:b cross_crate_spans.rs:23 +// lldb-command:b cross_crate_spans.rs:24 // lldb-command:run // lldb-command:print result diff --git a/src/test/debuginfo/destructured-fn-argument.rs b/src/test/debuginfo/destructured-fn-argument.rs index 5d330e16a1..954a7abe63 100644 --- a/src/test/debuginfo/destructured-fn-argument.rs +++ b/src/test/debuginfo/destructured-fn-argument.rs @@ -312,6 +312,7 @@ #![allow(unused_variables)] #![feature(box_patterns)] #![feature(box_syntax)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] use self::Univariant::Unit; @@ -432,7 +433,7 @@ fn main() { managed_box(&(34, 35)); borrowed_pointer(&(36, 37)); contained_borrowed_pointer((&38, 39)); - unique_pointer(box() (40, 41, 42)); + unique_pointer(box (40, 41, 42)); ref_binding((43, 44, 45)); ref_binding_in_tuple((46, (47, 48))); ref_binding_in_struct(Struct { a: 49, b: 50 }); diff --git a/src/test/debuginfo/destructured-for-loop-variable.rs b/src/test/debuginfo/destructured-for-loop-variable.rs index ad04f97fb0..a34d5d6adb 100644 --- a/src/test/debuginfo/destructured-for-loop-variable.rs +++ b/src/test/debuginfo/destructured-for-loop-variable.rs @@ -154,6 +154,7 @@ #![allow(unused_variables)] #![feature(box_patterns)] #![feature(box_syntax)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] struct Struct { diff --git a/src/test/debuginfo/destructured-local.rs b/src/test/debuginfo/destructured-local.rs index 632f17bd20..a43e4546d4 100644 --- a/src/test/debuginfo/destructured-local.rs +++ b/src/test/debuginfo/destructured-local.rs @@ -245,6 +245,7 @@ #![allow(unused_variables)] #![feature(box_patterns)] #![feature(box_syntax)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] use self::Univariant::Unit; @@ -303,7 +304,7 @@ fn main() { let (&cc, _) = (&38, 39); // unique pointer - let box dd = box() (40, 41, 42); + let box dd = box (40, 41, 42); // ref binding let ref ee = (43, 44, 45); diff --git a/src/test/debuginfo/evec-in-struct.rs b/src/test/debuginfo/evec-in-struct.rs index 1a9b9f73cb..8624a0cba0 100644 --- a/src/test/debuginfo/evec-in-struct.rs +++ b/src/test/debuginfo/evec-in-struct.rs @@ -50,6 +50,7 @@ // lldb-check:[...]$4 = StructPaddedAtEnd { x: [22, 23], y: [24, 25] } #![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] struct NoPadding1 { diff --git a/src/test/debuginfo/extern-c-fn.rs b/src/test/debuginfo/extern-c-fn.rs index 9e73417e7d..c93db41dc5 100644 --- a/src/test/debuginfo/extern-c-fn.rs +++ b/src/test/debuginfo/extern-c-fn.rs @@ -44,6 +44,7 @@ #![allow(unused_variables)] #![allow(dead_code)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] diff --git a/src/test/debuginfo/function-arg-initialization.rs b/src/test/debuginfo/function-arg-initialization.rs index a1ca59caa3..d007b50755 100644 --- a/src/test/debuginfo/function-arg-initialization.rs +++ b/src/test/debuginfo/function-arg-initialization.rs @@ -224,6 +224,7 @@ #![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] fn immediate_args(a: isize, b: bool, c: f64) { diff --git a/src/test/debuginfo/function-arguments.rs b/src/test/debuginfo/function-arguments.rs index 21c2cc09a9..c8f2e385a6 100644 --- a/src/test/debuginfo/function-arguments.rs +++ b/src/test/debuginfo/function-arguments.rs @@ -45,6 +45,7 @@ // lldb-command:continue +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] fn main() { diff --git a/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs b/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs index d9cca5eb31..b5b6ca7572 100644 --- a/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs +++ b/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs @@ -247,6 +247,7 @@ // lldb-command:continue #![allow(dead_code, unused_assignments, unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] #[no_stack_check] diff --git a/src/test/debuginfo/function-prologue-stepping-regular.rs b/src/test/debuginfo/function-prologue-stepping-regular.rs index b34f1af01f..529a8cd635 100644 --- a/src/test/debuginfo/function-prologue-stepping-regular.rs +++ b/src/test/debuginfo/function-prologue-stepping-regular.rs @@ -126,6 +126,7 @@ // lldb-command:continue #![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] fn immediate_args(a: isize, b: bool, c: f64) { 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 ae290e228c..3115b3f7e7 100644 --- a/src/test/debuginfo/generic-enum-with-different-disr-sizes.rs +++ b/src/test/debuginfo/generic-enum-with-different-disr-sizes.rs @@ -62,6 +62,7 @@ #![allow(unused_variables)] #![allow(dead_code)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] // This test case makes sure that we get correct type descriptions for the enum diff --git a/src/test/debuginfo/generic-function.rs b/src/test/debuginfo/generic-function.rs index 890133c58c..415dd36212 100644 --- a/src/test/debuginfo/generic-function.rs +++ b/src/test/debuginfo/generic-function.rs @@ -69,6 +69,7 @@ // lldb-check:[...]$8 = ((5, Struct { a: 6, b: 7.5 }), (Struct { a: 6, b: 7.5 }, 5)) // lldb-command:continue +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] #[derive(Clone)] diff --git a/src/test/debuginfo/generic-functions-nested.rs b/src/test/debuginfo/generic-functions-nested.rs index 5f9236038b..79ae007a50 100644 --- a/src/test/debuginfo/generic-functions-nested.rs +++ b/src/test/debuginfo/generic-functions-nested.rs @@ -70,6 +70,7 @@ // lldb-command:continue +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] fn outer(a: TA) { diff --git a/src/test/debuginfo/generic-method-on-generic-struct.rs b/src/test/debuginfo/generic-method-on-generic-struct.rs index 14df15242d..968cb2e159 100644 --- a/src/test/debuginfo/generic-method-on-generic-struct.rs +++ b/src/test/debuginfo/generic-method-on-generic-struct.rs @@ -112,6 +112,7 @@ // lldb-command:continue #![feature(box_syntax)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] #[derive(Copy, Clone)] diff --git a/src/test/debuginfo/generic-static-method-on-struct-and-enum.rs b/src/test/debuginfo/generic-static-method-on-struct-and-enum.rs index f24b221cce..603365089e 100644 --- a/src/test/debuginfo/generic-static-method-on-struct-and-enum.rs +++ b/src/test/debuginfo/generic-static-method-on-struct-and-enum.rs @@ -31,6 +31,7 @@ // gdb-command:continue +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] struct Struct { diff --git a/src/test/debuginfo/generic-struct-style-enum.rs b/src/test/debuginfo/generic-struct-style-enum.rs index caed4bd181..991404f56e 100644 --- a/src/test/debuginfo/generic-struct-style-enum.rs +++ b/src/test/debuginfo/generic-struct-style-enum.rs @@ -29,6 +29,7 @@ // gdb-check:$4 = {{a = -1}} +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] use self::Regular::{Case1, Case2, Case3}; diff --git a/src/test/debuginfo/generic-struct.rs b/src/test/debuginfo/generic-struct.rs index a459badfa8..92a67a2344 100644 --- a/src/test/debuginfo/generic-struct.rs +++ b/src/test/debuginfo/generic-struct.rs @@ -41,6 +41,7 @@ // lldb-check:[...]$3 = AGenericStruct> { key: 6.5, value: AGenericStruct { key: 7, value: 8.5 } } +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] struct AGenericStruct { diff --git a/src/test/debuginfo/generic-tuple-style-enum.rs b/src/test/debuginfo/generic-tuple-style-enum.rs index 83340c83dc..e2727fbe7d 100644 --- a/src/test/debuginfo/generic-tuple-style-enum.rs +++ b/src/test/debuginfo/generic-tuple-style-enum.rs @@ -47,6 +47,7 @@ // lldb-command:print univariant // lldb-check:[...]$3 = TheOnlyCase(-1) +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] use self::Regular::{Case1, Case2, Case3}; diff --git a/src/test/debuginfo/include_string.rs b/src/test/debuginfo/include_string.rs index 1dead6c273..2c75349e5c 100644 --- a/src/test/debuginfo/include_string.rs +++ b/src/test/debuginfo/include_string.rs @@ -35,6 +35,7 @@ // lldb-command:continue #![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] // This test case makes sure that debug info does not ICE when include_str is diff --git a/src/test/debuginfo/issue12886.rs b/src/test/debuginfo/issue12886.rs index b259efc9ca..c30ee92dc5 100644 --- a/src/test/debuginfo/issue12886.rs +++ b/src/test/debuginfo/issue12886.rs @@ -16,9 +16,10 @@ // gdb-command:run // gdb-command:next -// gdb-check:[...]34[...]s +// gdb-check:[...]35[...]s // gdb-command:continue +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] // IF YOU MODIFY THIS FILE, BE CAREFUL TO ADAPT THE LINE NUMBERS IN THE DEBUGGER COMMANDS diff --git a/src/test/debuginfo/issue22656.rs b/src/test/debuginfo/issue22656.rs index af518797d1..a971e06ed5 100644 --- a/src/test/debuginfo/issue22656.rs +++ b/src/test/debuginfo/issue22656.rs @@ -30,6 +30,7 @@ #![allow(unused_variables)] #![allow(dead_code)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] struct ZeroSizedStruct; diff --git a/src/test/debuginfo/lexical-scope-in-for-loop.rs b/src/test/debuginfo/lexical-scope-in-for-loop.rs index dceb436310..e99e241411 100644 --- a/src/test/debuginfo/lexical-scope-in-for-loop.rs +++ b/src/test/debuginfo/lexical-scope-in-for-loop.rs @@ -85,6 +85,7 @@ // lldb-check:[...]$6 = 1000000 // lldb-command:continue +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] fn main() { diff --git a/src/test/debuginfo/lexical-scope-in-if.rs b/src/test/debuginfo/lexical-scope-in-if.rs index 08a762fc4e..42e288321e 100644 --- a/src/test/debuginfo/lexical-scope-in-if.rs +++ b/src/test/debuginfo/lexical-scope-in-if.rs @@ -133,6 +133,7 @@ // lldb-check:[...]$15 = -1 // lldb-command:continue +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] fn main() { diff --git a/src/test/debuginfo/lexical-scope-in-match.rs b/src/test/debuginfo/lexical-scope-in-match.rs index 228799848c..597d9837aa 100644 --- a/src/test/debuginfo/lexical-scope-in-match.rs +++ b/src/test/debuginfo/lexical-scope-in-match.rs @@ -125,6 +125,7 @@ // lldb-check:[...]$17 = 232 // lldb-command:continue +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] struct Struct { diff --git a/src/test/debuginfo/lexical-scope-in-stack-closure.rs b/src/test/debuginfo/lexical-scope-in-stack-closure.rs index c0b65fbb22..0a8d3b61a8 100644 --- a/src/test/debuginfo/lexical-scope-in-stack-closure.rs +++ b/src/test/debuginfo/lexical-scope-in-stack-closure.rs @@ -69,6 +69,7 @@ // lldb-check:[...]$5 = false // lldb-command:continue +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] fn main() { diff --git a/src/test/debuginfo/lexical-scope-in-unconditional-loop.rs b/src/test/debuginfo/lexical-scope-in-unconditional-loop.rs index 868cea29a7..e55088afd7 100644 --- a/src/test/debuginfo/lexical-scope-in-unconditional-loop.rs +++ b/src/test/debuginfo/lexical-scope-in-unconditional-loop.rs @@ -131,6 +131,7 @@ // lldb-check:[...]$12 = 2 // lldb-command:continue +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] fn main() { diff --git a/src/test/debuginfo/lexical-scope-in-unique-closure.rs b/src/test/debuginfo/lexical-scope-in-unique-closure.rs index 5bae2aa7ae..70dece865e 100644 --- a/src/test/debuginfo/lexical-scope-in-unique-closure.rs +++ b/src/test/debuginfo/lexical-scope-in-unique-closure.rs @@ -70,6 +70,7 @@ // lldb-command:continue +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] fn main() { diff --git a/src/test/debuginfo/lexical-scope-in-while.rs b/src/test/debuginfo/lexical-scope-in-while.rs index b5f43e7d21..38d8b75a64 100644 --- a/src/test/debuginfo/lexical-scope-in-while.rs +++ b/src/test/debuginfo/lexical-scope-in-while.rs @@ -131,6 +131,7 @@ // lldb-check:[...]$12 = 2 // lldb-command:continue +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] fn main() { diff --git a/src/test/debuginfo/lexical-scope-with-macro.rs b/src/test/debuginfo/lexical-scope-with-macro.rs index 1dd738c6d5..a00d0f74f1 100644 --- a/src/test/debuginfo/lexical-scope-with-macro.rs +++ b/src/test/debuginfo/lexical-scope-with-macro.rs @@ -110,6 +110,7 @@ // lldb-command:continue +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] macro_rules! trivial { diff --git a/src/test/debuginfo/lexical-scopes-in-block-expression.rs b/src/test/debuginfo/lexical-scopes-in-block-expression.rs index 1d406af10a..841786f930 100644 --- a/src/test/debuginfo/lexical-scopes-in-block-expression.rs +++ b/src/test/debuginfo/lexical-scopes-in-block-expression.rs @@ -348,6 +348,7 @@ #![allow(unused_variables)] #![allow(unused_assignments)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] static mut MUT_INT: isize = 0; diff --git a/src/test/debuginfo/limited-debuginfo.rs b/src/test/debuginfo/limited-debuginfo.rs index ea7d150164..3d21def395 100644 --- a/src/test/debuginfo/limited-debuginfo.rs +++ b/src/test/debuginfo/limited-debuginfo.rs @@ -29,6 +29,7 @@ #![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] struct Struct { diff --git a/src/test/debuginfo/method-on-enum.rs b/src/test/debuginfo/method-on-enum.rs index 77a11db8ba..6437b3bb90 100644 --- a/src/test/debuginfo/method-on-enum.rs +++ b/src/test/debuginfo/method-on-enum.rs @@ -113,6 +113,7 @@ // lldb-command:continue #![feature(box_syntax)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] #[derive(Copy, Clone)] diff --git a/src/test/debuginfo/method-on-generic-struct.rs b/src/test/debuginfo/method-on-generic-struct.rs index f76f8c8cad..5b697f859d 100644 --- a/src/test/debuginfo/method-on-generic-struct.rs +++ b/src/test/debuginfo/method-on-generic-struct.rs @@ -113,6 +113,7 @@ #![feature(box_syntax)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] #[derive(Copy, Clone)] diff --git a/src/test/debuginfo/method-on-struct.rs b/src/test/debuginfo/method-on-struct.rs index 28885d0ad9..3bf2e775e7 100644 --- a/src/test/debuginfo/method-on-struct.rs +++ b/src/test/debuginfo/method-on-struct.rs @@ -113,6 +113,7 @@ #![feature(box_syntax)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] #[derive(Copy, Clone)] diff --git a/src/test/debuginfo/method-on-trait.rs b/src/test/debuginfo/method-on-trait.rs index b69a385673..5ce4a7905a 100644 --- a/src/test/debuginfo/method-on-trait.rs +++ b/src/test/debuginfo/method-on-trait.rs @@ -113,6 +113,7 @@ #![feature(box_syntax)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] #[derive(Copy, Clone)] diff --git a/src/test/debuginfo/method-on-tuple-struct.rs b/src/test/debuginfo/method-on-tuple-struct.rs index 4ea0fd4447..d8644a3934 100644 --- a/src/test/debuginfo/method-on-tuple-struct.rs +++ b/src/test/debuginfo/method-on-tuple-struct.rs @@ -113,6 +113,7 @@ #![feature(box_syntax)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] #[derive(Copy, Clone)] diff --git a/src/test/debuginfo/multiple-functions-equal-var-names.rs b/src/test/debuginfo/multiple-functions-equal-var-names.rs index 5fe0c13e5e..71ba1bcea3 100644 --- a/src/test/debuginfo/multiple-functions-equal-var-names.rs +++ b/src/test/debuginfo/multiple-functions-equal-var-names.rs @@ -44,6 +44,7 @@ // lldb-check:[...]$2 = 30303 #![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] fn function_one() { diff --git a/src/test/debuginfo/multiple-functions.rs b/src/test/debuginfo/multiple-functions.rs index 3179a8050d..7a1b7b19d9 100644 --- a/src/test/debuginfo/multiple-functions.rs +++ b/src/test/debuginfo/multiple-functions.rs @@ -44,6 +44,7 @@ // lldb-check:[...]$2 = 30303 #![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] fn function_one() { diff --git a/src/test/debuginfo/name-shadowing-and-scope-nesting.rs b/src/test/debuginfo/name-shadowing-and-scope-nesting.rs index 5553d7e496..462e1c59ae 100644 --- a/src/test/debuginfo/name-shadowing-and-scope-nesting.rs +++ b/src/test/debuginfo/name-shadowing-and-scope-nesting.rs @@ -93,6 +93,7 @@ // lldb-check:[...]$11 = 20 // lldb-command:continue +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] fn main() { diff --git a/src/test/debuginfo/nil-enum.rs b/src/test/debuginfo/nil-enum.rs index 44d7c2b1ad..81399ec590 100644 --- a/src/test/debuginfo/nil-enum.rs +++ b/src/test/debuginfo/nil-enum.rs @@ -22,6 +22,7 @@ // gdb-check:$2 = {} #![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] enum ANilEnum {} diff --git a/src/test/debuginfo/no-debug-attribute.rs b/src/test/debuginfo/no-debug-attribute.rs index f39e8ee222..6bdd68d5e2 100644 --- a/src/test/debuginfo/no-debug-attribute.rs +++ b/src/test/debuginfo/no-debug-attribute.rs @@ -23,6 +23,8 @@ // gdb-command:continue #![allow(unused_variables)] +#![feature(no_debug)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] fn function_with_debuginfo() { diff --git a/src/test/debuginfo/option-like-enum.rs b/src/test/debuginfo/option-like-enum.rs index fba21d9a55..f103294a94 100644 --- a/src/test/debuginfo/option-like-enum.rs +++ b/src/test/debuginfo/option-like-enum.rs @@ -79,6 +79,7 @@ // lldb-check:[...]$9 = Nope +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] // If a struct has exactly two variants, one of them is empty, and the other one diff --git a/src/test/debuginfo/packed-struct-with-destructor.rs b/src/test/debuginfo/packed-struct-with-destructor.rs index 8b2f34a990..9d37cb3012 100644 --- a/src/test/debuginfo/packed-struct-with-destructor.rs +++ b/src/test/debuginfo/packed-struct-with-destructor.rs @@ -73,6 +73,7 @@ #![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] #[repr(packed)] diff --git a/src/test/debuginfo/packed-struct.rs b/src/test/debuginfo/packed-struct.rs index 9f3b7baf83..e86e963f38 100644 --- a/src/test/debuginfo/packed-struct.rs +++ b/src/test/debuginfo/packed-struct.rs @@ -59,6 +59,7 @@ // lldb-check:[...]$5 = 40 #![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] #[repr(packed)] diff --git a/src/test/debuginfo/recursive-enum.rs b/src/test/debuginfo/recursive-enum.rs index ef1092efa1..3094bdeac8 100644 --- a/src/test/debuginfo/recursive-enum.rs +++ b/src/test/debuginfo/recursive-enum.rs @@ -17,6 +17,7 @@ // is taken from issue #11083. #![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] pub struct Window<'a> { diff --git a/src/test/debuginfo/recursive-struct.rs b/src/test/debuginfo/recursive-struct.rs index 4772ee10ff..ea067d5bff 100644 --- a/src/test/debuginfo/recursive-struct.rs +++ b/src/test/debuginfo/recursive-struct.rs @@ -69,6 +69,7 @@ #![allow(unused_variables)] #![feature(box_syntax)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] use self::Opt::{Empty, Val}; diff --git a/src/test/debuginfo/self-in-default-method.rs b/src/test/debuginfo/self-in-default-method.rs index f16f236a0c..6d3f93c5d5 100644 --- a/src/test/debuginfo/self-in-default-method.rs +++ b/src/test/debuginfo/self-in-default-method.rs @@ -112,6 +112,7 @@ // lldb-command:continue #![feature(box_syntax)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] #[derive(Copy, Clone)] diff --git a/src/test/debuginfo/self-in-generic-default-method.rs b/src/test/debuginfo/self-in-generic-default-method.rs index 56de877016..aea3bae4bf 100644 --- a/src/test/debuginfo/self-in-generic-default-method.rs +++ b/src/test/debuginfo/self-in-generic-default-method.rs @@ -112,6 +112,7 @@ // lldb-command:continue #![feature(box_syntax)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] #[derive(Copy, Clone)] diff --git a/src/test/debuginfo/shadowed-argument.rs b/src/test/debuginfo/shadowed-argument.rs index 4d74e6f108..baf782b7e6 100644 --- a/src/test/debuginfo/shadowed-argument.rs +++ b/src/test/debuginfo/shadowed-argument.rs @@ -58,6 +58,7 @@ // lldb-command:continue +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] fn a_function(x: bool, y: bool) { diff --git a/src/test/debuginfo/shadowed-variable.rs b/src/test/debuginfo/shadowed-variable.rs index 630999677a..4883853f72 100644 --- a/src/test/debuginfo/shadowed-variable.rs +++ b/src/test/debuginfo/shadowed-variable.rs @@ -57,6 +57,7 @@ // lldb-check:[...]$5 = 20 // lldb-command:continue +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] fn main() { diff --git a/src/test/debuginfo/simd.rs b/src/test/debuginfo/simd.rs index 6bc8892a83..24eb407612 100644 --- a/src/test/debuginfo/simd.rs +++ b/src/test/debuginfo/simd.rs @@ -41,6 +41,7 @@ // gdb-command:continue #![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] #![feature(core_simd)] diff --git a/src/test/debuginfo/simple-lexical-scope.rs b/src/test/debuginfo/simple-lexical-scope.rs index c1dae7a6d6..5f9a4fd080 100644 --- a/src/test/debuginfo/simple-lexical-scope.rs +++ b/src/test/debuginfo/simple-lexical-scope.rs @@ -78,6 +78,7 @@ // lldb-command:continue +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] fn main() { diff --git a/src/test/debuginfo/simple-struct.rs b/src/test/debuginfo/simple-struct.rs index 36007c1093..d25cd4d7c0 100644 --- a/src/test/debuginfo/simple-struct.rs +++ b/src/test/debuginfo/simple-struct.rs @@ -96,6 +96,7 @@ #![allow(unused_variables)] #![allow(dead_code)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] struct NoPadding16 { diff --git a/src/test/debuginfo/simple-tuple.rs b/src/test/debuginfo/simple-tuple.rs index 29bf9c5e41..1b85ecc537 100644 --- a/src/test/debuginfo/simple-tuple.rs +++ b/src/test/debuginfo/simple-tuple.rs @@ -91,6 +91,7 @@ #![allow(unused_variables)] #![allow(dead_code)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] static mut NO_PADDING_8: (i8, u8) = (-50, 50); diff --git a/src/test/debuginfo/static-method-on-struct-and-enum.rs b/src/test/debuginfo/static-method-on-struct-and-enum.rs index 59fe96f995..dab4ab515d 100644 --- a/src/test/debuginfo/static-method-on-struct-and-enum.rs +++ b/src/test/debuginfo/static-method-on-struct-and-enum.rs @@ -53,6 +53,7 @@ // lldb-check:[...]$4 = 5 // lldb-command:continue +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] struct Struct { diff --git a/src/test/debuginfo/struct-in-enum.rs b/src/test/debuginfo/struct-in-enum.rs index e200a497f5..98b90de600 100644 --- a/src/test/debuginfo/struct-in-enum.rs +++ b/src/test/debuginfo/struct-in-enum.rs @@ -41,6 +41,7 @@ // lldb-check:[...]$2 = TheOnlyCase(Struct { x: 123, y: 456, z: 789 }) #![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] use self::Regular::{Case1, Case2}; diff --git a/src/test/debuginfo/struct-in-struct.rs b/src/test/debuginfo/struct-in-struct.rs index 8bccb041c9..76a1613c23 100644 --- a/src/test/debuginfo/struct-in-struct.rs +++ b/src/test/debuginfo/struct-in-struct.rs @@ -56,6 +56,7 @@ // lldb-check:[...]$7 = Tree { x: Simple { x: 25 }, y: InternalPaddingParent { x: InternalPadding { x: 26, y: 27 }, y: InternalPadding { x: 28, y: 29 }, z: InternalPadding { x: 30, y: 31 } }, z: BagInBag { x: Bag { x: Simple { x: 32 } } } } #![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] struct Simple { diff --git a/src/test/debuginfo/struct-style-enum.rs b/src/test/debuginfo/struct-style-enum.rs index 43cb48d16b..3376fc9bbd 100644 --- a/src/test/debuginfo/struct-style-enum.rs +++ b/src/test/debuginfo/struct-style-enum.rs @@ -48,6 +48,7 @@ // lldb-check:[...]$3 = TheOnlyCase { a: -1 } #![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] use self::Regular::{Case1, Case2, Case3}; diff --git a/src/test/debuginfo/struct-with-destructor.rs b/src/test/debuginfo/struct-with-destructor.rs index 4c2c9d06ae..ad8731997a 100644 --- a/src/test/debuginfo/struct-with-destructor.rs +++ b/src/test/debuginfo/struct-with-destructor.rs @@ -44,6 +44,7 @@ // lldb-check:[...]$3 = NestedOuter { a: NestedInner { a: WithDestructor { x: 7890, y: 9870 } } } #![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] struct NoDestructor { diff --git a/src/test/debuginfo/trait-pointers.rs b/src/test/debuginfo/trait-pointers.rs index 3054f646b9..193cd419ba 100644 --- a/src/test/debuginfo/trait-pointers.rs +++ b/src/test/debuginfo/trait-pointers.rs @@ -16,6 +16,7 @@ #![allow(unused_variables)] #![feature(box_syntax)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] trait Trait { diff --git a/src/test/debuginfo/tuple-in-struct.rs b/src/test/debuginfo/tuple-in-struct.rs index 04119956f1..1a7fde766f 100644 --- a/src/test/debuginfo/tuple-in-struct.rs +++ b/src/test/debuginfo/tuple-in-struct.rs @@ -42,6 +42,7 @@ // gdb-check:$10 = {x = {__0 = {__0 = 40, __1 = 41, __2 = 42}, __1 = {__0 = 43, __1 = 44}}, y = {__0 = 45, __1 = 46, __2 = 47, __3 = 48}} #![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] struct NoPadding1 { diff --git a/src/test/debuginfo/tuple-in-tuple.rs b/src/test/debuginfo/tuple-in-tuple.rs index e981091303..a514b69a2d 100644 --- a/src/test/debuginfo/tuple-in-tuple.rs +++ b/src/test/debuginfo/tuple-in-tuple.rs @@ -56,6 +56,7 @@ // lldb-check:[...]$6 = ((21, 22), 23) #![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] fn main() { diff --git a/src/test/debuginfo/tuple-struct.rs b/src/test/debuginfo/tuple-struct.rs index 5e4e849457..a2ca8c2237 100644 --- a/src/test/debuginfo/tuple-struct.rs +++ b/src/test/debuginfo/tuple-struct.rs @@ -62,6 +62,7 @@ // structs. +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] struct NoPadding16(u16, i16); diff --git a/src/test/debuginfo/tuple-style-enum.rs b/src/test/debuginfo/tuple-style-enum.rs index 48c47c5115..52f171434b 100644 --- a/src/test/debuginfo/tuple-style-enum.rs +++ b/src/test/debuginfo/tuple-style-enum.rs @@ -48,6 +48,7 @@ // lldb-check:[...]$3 = TheOnlyCase(-1) #![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] use self::Regular::{Case1, Case2, Case3}; diff --git a/src/test/debuginfo/type-names.rs b/src/test/debuginfo/type-names.rs index 4eae074120..3db3e9d311 100644 --- a/src/test/debuginfo/type-names.rs +++ b/src/test/debuginfo/type-names.rs @@ -175,6 +175,7 @@ #![feature(box_syntax)] #![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] use self::Enum1::{Variant1, Variant2}; diff --git a/src/test/debuginfo/unique-enum.rs b/src/test/debuginfo/unique-enum.rs index 0252e3b54f..bbf13ec756 100644 --- a/src/test/debuginfo/unique-enum.rs +++ b/src/test/debuginfo/unique-enum.rs @@ -42,6 +42,7 @@ #![allow(unused_variables)] #![feature(box_syntax)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] // The first element is to ensure proper alignment, irrespective of the machines word size. Since diff --git a/src/test/debuginfo/unreachable-locals.rs b/src/test/debuginfo/unreachable-locals.rs index 63536b1383..4c4210ea13 100644 --- a/src/test/debuginfo/unreachable-locals.rs +++ b/src/test/debuginfo/unreachable-locals.rs @@ -13,6 +13,7 @@ // compile-flags:-g #![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] // No need to actually run the debugger, just make sure that the compiler can diff --git a/src/test/debuginfo/var-captured-in-nested-closure.rs b/src/test/debuginfo/var-captured-in-nested-closure.rs index d576aff8b1..7090377e5d 100644 --- a/src/test/debuginfo/var-captured-in-nested-closure.rs +++ b/src/test/debuginfo/var-captured-in-nested-closure.rs @@ -79,6 +79,7 @@ #![allow(unused_variables)] #![feature(box_syntax)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] struct Struct { diff --git a/src/test/debuginfo/var-captured-in-sendable-closure.rs b/src/test/debuginfo/var-captured-in-sendable-closure.rs index 2b27f938b3..aa269edadd 100644 --- a/src/test/debuginfo/var-captured-in-sendable-closure.rs +++ b/src/test/debuginfo/var-captured-in-sendable-closure.rs @@ -41,6 +41,7 @@ #![allow(unused_variables)] #![feature(unboxed_closures, box_syntax)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] struct Struct { diff --git a/src/test/debuginfo/var-captured-in-stack-closure.rs b/src/test/debuginfo/var-captured-in-stack-closure.rs index 54ef42b48f..6def5cf285 100644 --- a/src/test/debuginfo/var-captured-in-stack-closure.rs +++ b/src/test/debuginfo/var-captured-in-stack-closure.rs @@ -71,6 +71,7 @@ #![feature(unboxed_closures, box_syntax)] #![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] struct Struct { diff --git a/src/test/debuginfo/vec-slices.rs b/src/test/debuginfo/vec-slices.rs index 87fd2e9a65..0d396c885e 100644 --- a/src/test/debuginfo/vec-slices.rs +++ b/src/test/debuginfo/vec-slices.rs @@ -77,6 +77,7 @@ // lldb-check:[...]$5 = &[AStruct { x: 10, y: 11, z: 12 }, AStruct { x: 13, y: 14, z: 15 }] #![allow(dead_code, unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] struct AStruct { diff --git a/src/test/debuginfo/vec.rs b/src/test/debuginfo/vec.rs index f7bdf1bd3f..c9827a02fc 100644 --- a/src/test/debuginfo/vec.rs +++ b/src/test/debuginfo/vec.rs @@ -28,6 +28,7 @@ // lldb-check:[...]$0 = [1, 2, 3] #![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] static mut VECT: [i32; 3] = [1, 2, 3]; diff --git a/src/test/parse-fail/lifetime-in-pattern.rs b/src/test/parse-fail/lifetime-in-pattern.rs new file mode 100644 index 0000000000..8802497ae1 --- /dev/null +++ b/src/test/parse-fail/lifetime-in-pattern.rs @@ -0,0 +1,16 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn test(&'a str) { + //~^ ERROR unexpected lifetime `'a` in pattern +} + +fn main() { +} diff --git a/src/test/parse-fail/struct-no-fields-2.rs b/src/test/parse-fail/struct-no-fields-2.rs deleted file mode 100644 index 1e6169f285..0000000000 --- a/src/test/parse-fail/struct-no-fields-2.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// compile-flags: -Z parse-only - -struct Foo; - -fn f2() { - let _end_stmt = Foo { }; - //~^ ERROR: structure literal must either have at least one field -} - -fn main() {} diff --git a/src/test/parse-fail/struct-no-fields-3.rs b/src/test/parse-fail/struct-no-fields-3.rs deleted file mode 100644 index 8e72151ffe..0000000000 --- a/src/test/parse-fail/struct-no-fields-3.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// compile-flags: -Z parse-only - -struct Foo; - -fn g3() { - let _mid_tuple = (Foo { }, 2); - //~^ ERROR: structure literal must either have at least one field -} - -fn main() {} diff --git a/src/test/parse-fail/struct-no-fields-4.rs b/src/test/parse-fail/struct-no-fields-4.rs deleted file mode 100644 index 6e55baf06c..0000000000 --- a/src/test/parse-fail/struct-no-fields-4.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// compile-flags: -Z parse-only - -struct Foo; - -fn h4() { - let _end_of_tuple = (3, Foo { }); - //~^ ERROR: structure literal must either have at least one field -} - -fn main() {} diff --git a/src/test/parse-fail/struct-no-fields-5.rs b/src/test/parse-fail/struct-no-fields-5.rs deleted file mode 100644 index 5f92d98606..0000000000 --- a/src/test/parse-fail/struct-no-fields-5.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// compile-flags: -Z parse-only - -struct Foo; - -fn i5() { - let _end_of_block = { Foo { } }; - //~^ ERROR: structure literal must either have at least one field -} - -fn main() {} diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index 6398c76d0a..835f7fc96c 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -27,10 +27,9 @@ pub fn bar() { let _: [(); (1 as usize)] = ([(() as ())] as [(); 1]); let _ = - (((&((([(1 as i32), (2 as i32), (3 as i32)] as [i32; 3])) as [i32; 3]) - as &[i32; 3]) as *const _ as *const [i32; 3]) as - *const [i32; (3 as usize)] as *const [i32; 3]); - + (((&([(1 as i32), (2 as i32), (3 as i32)] as [i32; 3]) as &[i32; 3]) + as *const _ as *const [i32; 3]) as *const [i32; (3 as usize)] as + *const [i32; 3]); diff --git a/src/test/run-fail/issue-18576.rs b/src/test/run-fail/issue-18576.rs index 0b82a0d8d8..e326949458 100644 --- a/src/test/run-fail/issue-18576.rs +++ b/src/test/run-fail/issue-18576.rs @@ -11,7 +11,7 @@ // error-pattern:stop // #18576 -// Make sure that an calling extern function pointer in an unreachable +// Make sure that calling an extern function pointer in an unreachable // context doesn't cause an LLVM assertion #[allow(unreachable_code)] diff --git a/src/test/run-fail/issue-28934.rs b/src/test/run-fail/issue-28934.rs new file mode 100644 index 0000000000..2f437c7a81 --- /dev/null +++ b/src/test/run-fail/issue-28934.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: issue had to do with "givens" in region inference, +// which were not being considered during the contraction phase. + +// error-pattern:explicit panic + +struct Parser<'i: 't, 't>(&'i u8, &'t u8); + +impl<'i, 't> Parser<'i, 't> { + fn parse_nested_block(&mut self, parse: F) -> Result + where for<'tt> F: FnOnce(&mut Parser<'i, 'tt>) -> T { panic!() } + + fn expect_exhausted(&mut self) -> Result<(), ()> { Ok(()) } +} + +fn main() { + let x = 0u8; + Parser(&x, &x).parse_nested_block(|input| input.expect_exhausted()).unwrap(); +} diff --git a/src/test/run-fail/overflowing-add.rs b/src/test/run-fail/overflowing-add.rs index cd13b817c2..6c6a41fa6f 100644 --- a/src/test/run-fail/overflowing-add.rs +++ b/src/test/run-fail/overflowing-add.rs @@ -11,9 +11,7 @@ // error-pattern:thread '

    ' panicked at 'arithmetic operation overflowed' // compile-flags: -C debug-assertions -// (Work around constant-evaluation) -fn value() -> u8 { 200 } fn main() { - let _x = value() + value() + value(); + 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 5415915338..62935bacce 100644 --- a/src/test/run-fail/overflowing-lsh-1.rs +++ b/src/test/run-fail/overflowing-lsh-1.rs @@ -11,9 +11,8 @@ // error-pattern:thread '
    ' panicked at 'shift operation overflowed' // compile-flags: -C debug-assertions -// (Work around constant-evaluation) -fn id(x: T) -> T { x } +#![warn(exceeding_bitshifts)] fn main() { - let _x = 1_i32 << id(32); + let _x = 1_i32 << 32; } diff --git a/src/test/run-fail/overflowing-lsh-2.rs b/src/test/run-fail/overflowing-lsh-2.rs index fd3e801457..f6e6cb105c 100644 --- a/src/test/run-fail/overflowing-lsh-2.rs +++ b/src/test/run-fail/overflowing-lsh-2.rs @@ -11,9 +11,8 @@ // error-pattern:thread '
    ' panicked at 'shift operation overflowed' // compile-flags: -C debug-assertions -// (Work around constant-evaluation) -fn id(x: T) -> T { x } +#![warn(exceeding_bitshifts)] fn main() { - let _x = 1 << id(-1); + let _x = 1 << -1; } diff --git a/src/test/run-fail/overflowing-lsh-3.rs b/src/test/run-fail/overflowing-lsh-3.rs index 58914bab3f..a70f31954c 100644 --- a/src/test/run-fail/overflowing-lsh-3.rs +++ b/src/test/run-fail/overflowing-lsh-3.rs @@ -11,9 +11,8 @@ // error-pattern:thread '
    ' panicked at 'shift operation overflowed' // compile-flags: -C debug-assertions -// (Work around constant-evaluation) -fn id(x: T) -> T { x } +#![warn(exceeding_bitshifts)] fn main() { - let _x = 1_u64 << id(64); + let _x = 1_u64 << 64; } diff --git a/src/test/run-fail/overflowing-lsh-4.rs b/src/test/run-fail/overflowing-lsh-4.rs index ed25876cec..571feaeb94 100644 --- a/src/test/run-fail/overflowing-lsh-4.rs +++ b/src/test/run-fail/overflowing-lsh-4.rs @@ -14,12 +14,11 @@ // This function is checking that our automatic truncation does not // sidestep the overflow checking. -// (Work around constant-evaluation) -fn id(x: T) -> T { x } +#![warn(exceeding_bitshifts)] fn main() { // this signals overflow when checking is on - let x = 1_i8 << id(17); + let x = 1_i8 << 17; // ... but when checking is off, the fallback will truncate the // input to its lower three bits (= 1). Note that this is *not* diff --git a/src/test/run-fail/overflowing-mul.rs b/src/test/run-fail/overflowing-mul.rs index 5d2f539624..a413a6f0ab 100644 --- a/src/test/run-fail/overflowing-mul.rs +++ b/src/test/run-fail/overflowing-mul.rs @@ -11,9 +11,6 @@ // error-pattern:thread '
    ' panicked at 'arithmetic operation overflowed' // compile-flags: -C debug-assertions -// (Work around constant-evaluation) -fn value() -> u8 { 200 } - fn main() { - let x = value() * 4; + let x = 200u8 * 4; } diff --git a/src/test/run-fail/overflowing-neg.rs b/src/test/run-fail/overflowing-neg.rs index cdb74c7d7e..7891d1ce9b 100644 --- a/src/test/run-fail/overflowing-neg.rs +++ b/src/test/run-fail/overflowing-neg.rs @@ -11,9 +11,6 @@ // error-pattern:thread '
    ' panicked at 'attempted to negate with overflow' // compile-flags: -C debug-assertions -// (Work around constant-evaluation) -fn value() -> i8 { std::i8::MIN } - fn main() { - let _x = -value(); + let _x = -std::i8::MIN; } diff --git a/src/test/run-fail/overflowing-rsh-1.rs b/src/test/run-fail/overflowing-rsh-1.rs index c36a16f18f..b58eaf7f83 100644 --- a/src/test/run-fail/overflowing-rsh-1.rs +++ b/src/test/run-fail/overflowing-rsh-1.rs @@ -11,9 +11,8 @@ // error-pattern:thread '
    ' panicked at 'shift operation overflowed' // compile-flags: -C debug-assertions -// (Work around constant-evaluation) -fn id(x: T) -> T { x } +#![warn(exceeding_bitshifts)] fn main() { - let _x = -1_i32 >> id(32); + let _x = -1_i32 >> 32; } diff --git a/src/test/run-fail/overflowing-rsh-2.rs b/src/test/run-fail/overflowing-rsh-2.rs index f619ebe9fb..40b468a6ad 100644 --- a/src/test/run-fail/overflowing-rsh-2.rs +++ b/src/test/run-fail/overflowing-rsh-2.rs @@ -11,9 +11,8 @@ // error-pattern:thread '
    ' panicked at 'shift operation overflowed' // compile-flags: -C debug-assertions -// (Work around constant-evaluation) -fn id(x: T) -> T { x } +#![warn(exceeding_bitshifts)] fn main() { - let _x = -1_i32 >> id(-1); + let _x = -1_i32 >> -1; } diff --git a/src/test/run-fail/overflowing-rsh-3.rs b/src/test/run-fail/overflowing-rsh-3.rs index c261e195fd..afe6a908cb 100644 --- a/src/test/run-fail/overflowing-rsh-3.rs +++ b/src/test/run-fail/overflowing-rsh-3.rs @@ -11,9 +11,8 @@ // error-pattern:thread '
    ' panicked at 'shift operation overflowed' // compile-flags: -C debug-assertions -// (Work around constant-evaluation) -fn id(x: T) -> T { x } +#![warn(exceeding_bitshifts)] fn main() { - let _x = -1_i64 >> id(64); + let _x = -1_i64 >> 64; } diff --git a/src/test/run-fail/overflowing-rsh-4.rs b/src/test/run-fail/overflowing-rsh-4.rs index 6e79a13d4e..585186575f 100644 --- a/src/test/run-fail/overflowing-rsh-4.rs +++ b/src/test/run-fail/overflowing-rsh-4.rs @@ -14,12 +14,11 @@ // This function is checking that our (type-based) automatic // truncation does not sidestep the overflow checking. -// (Work around constant-evaluation) -fn id(x: T) -> T { x } +#![warn(exceeding_bitshifts)] fn main() { // this signals overflow when checking is on - let x = 2_i8 >> id(17); + let x = 2_i8 >> 17; // ... but when checking is off, the fallback will truncate the // input to its lower three bits (= 1). Note that this is *not* diff --git a/src/test/run-fail/overflowing-sub.rs b/src/test/run-fail/overflowing-sub.rs index b089dccbaa..ece4d37c36 100644 --- a/src/test/run-fail/overflowing-sub.rs +++ b/src/test/run-fail/overflowing-sub.rs @@ -11,9 +11,6 @@ // error-pattern:thread '
    ' panicked at 'arithmetic operation overflowed' // compile-flags: -C debug-assertions -// (Work around constant-evaluation) -fn value() -> u8 { 42 } - fn main() { - let _x = value() - (value() + 1); + let _x = 42u8 - (42u8 + 1); } diff --git a/src/test/run-make/allow-non-lint-warnings-cmdline/1 b/src/test/run-make/allow-non-lint-warnings-cmdline/1 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/test/run-make/allow-warnings-cmdline-stability/1 b/src/test/run-make/allow-warnings-cmdline-stability/1 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/test/run-make/archive-duplicate-names/Makefile b/src/test/run-make/archive-duplicate-names/Makefile index 72c2d389e2..5202e6dea5 100644 --- a/src/test/run-make/archive-duplicate-names/Makefile +++ b/src/test/run-make/archive-duplicate-names/Makefile @@ -3,8 +3,8 @@ all: mkdir $(TMPDIR)/a mkdir $(TMPDIR)/b - $(CC) -c -o $(TMPDIR)/a/foo.o foo.c - $(CC) -c -o $(TMPDIR)/b/foo.o bar.c + $(call COMPILE_OBJ,$(TMPDIR)/a/foo.o,foo.c) + $(call COMPILE_OBJ,$(TMPDIR)/b/foo.o,bar.c) ar crus $(TMPDIR)/libfoo.a $(TMPDIR)/a/foo.o $(TMPDIR)/b/foo.o $(RUSTC) foo.rs $(RUSTC) bar.rs diff --git a/src/test/run-make/bare-outfile/Makefile b/src/test/run-make/bare-outfile/Makefile index 97d09c837c..baa4c1c023 100644 --- a/src/test/run-make/bare-outfile/Makefile +++ b/src/test/run-make/bare-outfile/Makefile @@ -1,4 +1,6 @@ -include ../tools.mk all: - $(rustc) -o foo foo.rs + cp foo.rs $(TMPDIR) + cd $(TMPDIR) && $(RUSTC) -o foo foo.rs + $(call RUN,foo) diff --git a/src/test/run-make/c-dynamic-dylib/cfoo.c b/src/test/run-make/c-dynamic-dylib/cfoo.c index 113717a776..a975549354 100644 --- a/src/test/run-make/c-dynamic-dylib/cfoo.c +++ b/src/test/run-make/c-dynamic-dylib/cfoo.c @@ -1,2 +1,5 @@ // ignore-license +#ifdef _WIN32 +__declspec(dllexport) +#endif int foo() { return 0; } diff --git a/src/test/run-make/c-dynamic-rlib/cfoo.c b/src/test/run-make/c-dynamic-rlib/cfoo.c index 113717a776..b2849326a7 100644 --- a/src/test/run-make/c-dynamic-rlib/cfoo.c +++ b/src/test/run-make/c-dynamic-rlib/cfoo.c @@ -1,2 +1,6 @@ // ignore-license + +#ifdef _WIN32 +__declspec(dllexport) +#endif int foo() { return 0; } diff --git a/src/test/run-make/c-link-to-rust-dylib/Makefile b/src/test/run-make/c-link-to-rust-dylib/Makefile index 2a6cc03948..7b2130cd4e 100644 --- a/src/test/run-make/c-link-to-rust-dylib/Makefile +++ b/src/test/run-make/c-link-to-rust-dylib/Makefile @@ -1,10 +1,17 @@ -include ../tools.mk -HOST_LIB_DIR=$(TMPDIR)/../../../stage$(RUST_BUILD_STAGE)/lib - -all: - $(RUSTC) foo.rs - $(CC) bar.c -lfoo -o $(call RUN_BINFILE,bar) $(call RPATH_LINK_SEARCH,$(HOST_LIB_DIR)) -Wl,-rpath,$(TMPDIR) $(EXTRACFLAGS) +all: $(TMPDIR)/$(call BIN,bar) $(call RUN,bar) $(call REMOVE_DYLIBS,foo) $(call FAIL,bar) + +ifdef IS_MSVC +$(TMPDIR)/$(call BIN,bar): $(call DYLIB,foo) + $(CC) bar.c $(TMPDIR)/foo.lib $(call OUT_EXE,bar) +else +$(TMPDIR)/$(call BIN,bar): $(call DYLIB,foo) + $(CC) bar.c -lfoo -o $(call RUN_BINFILE,bar) -L $(TMPDIR) +endif + +$(call DYLIB,foo): foo.rs + $(RUSTC) foo.rs diff --git a/src/test/run-make/c-link-to-rust-staticlib/Makefile b/src/test/run-make/c-link-to-rust-staticlib/Makefile index 2b927e3e4a..3d44b3c256 100644 --- a/src/test/run-make/c-link-to-rust-staticlib/Makefile +++ b/src/test/run-make/c-link-to-rust-staticlib/Makefile @@ -1,12 +1,12 @@ -include ../tools.mk -EXTRAFLAGS := $(EXTRACFLAGS) - # FIXME: ignore freebsd ifneq ($(shell uname),FreeBSD) all: $(RUSTC) foo.rs - $(CC) bar.c -lfoo -o $(call RUN_BINFILE,bar) $(EXTRAFLAGS) $(EXTRACXXFLAGS) + cp $(TMPDIR)/libfoo.a $(call NATIVE_STATICLIB,foo2) + $(CC) bar.c $(call NATIVE_STATICLIB,foo2) $(call OUT_EXE,bar) \ + $(EXTRACFLAGS) $(EXTRACXXFLAGS) $(call RUN,bar) rm $(call STATICLIB,foo*) $(call RUN,bar) diff --git a/src/test/run-make/c-static-dylib/Makefile b/src/test/run-make/c-static-dylib/Makefile index 9914e12d56..f88786857c 100644 --- a/src/test/run-make/c-static-dylib/Makefile +++ b/src/test/run-make/c-static-dylib/Makefile @@ -1,9 +1,9 @@ -include ../tools.mk -all: $(call STATICLIB,cfoo) +all: $(call NATIVE_STATICLIB,cfoo) $(RUSTC) foo.rs -C prefer-dynamic $(RUSTC) bar.rs - rm $(TMPDIR)/$(call STATICLIB_GLOB,cfoo) + rm $(call NATIVE_STATICLIB,cfoo) $(call RUN,bar) $(call REMOVE_DYLIBS,foo) $(call FAIL,bar) diff --git a/src/test/run-make/c-static-rlib/Makefile b/src/test/run-make/c-static-rlib/Makefile index 02b24ef984..be22b2728f 100644 --- a/src/test/run-make/c-static-rlib/Makefile +++ b/src/test/run-make/c-static-rlib/Makefile @@ -1,8 +1,8 @@ -include ../tools.mk -all: $(call STATICLIB,cfoo) +all: $(call NATIVE_STATICLIB,cfoo) $(RUSTC) foo.rs $(RUSTC) bar.rs $(call REMOVE_RLIBS,foo) - rm $(TMPDIR)/$(call STATICLIB_GLOB,cfoo) + rm $(call NATIVE_STATICLIB,cfoo) $(call RUN,bar) diff --git a/src/test/run-make/compile-stdin/Makefile b/src/test/run-make/compile-stdin/Makefile new file mode 100644 index 0000000000..1442224cf9 --- /dev/null +++ b/src/test/run-make/compile-stdin/Makefile @@ -0,0 +1,5 @@ +-include ../tools.mk + +all: + echo 'fn main(){}' | $(RUSTC) - + $(call RUN,rust_out) diff --git a/src/test/run-make/crate-name-priority/Makefile b/src/test/run-make/crate-name-priority/Makefile index 2fe5183243..17ecb33ab2 100644 --- a/src/test/run-make/crate-name-priority/Makefile +++ b/src/test/run-make/crate-name-priority/Makefile @@ -7,5 +7,5 @@ all: rm $(TMPDIR)/$(call BIN,bar) $(RUSTC) foo1.rs rm $(TMPDIR)/$(call BIN,foo) - $(RUSTC) foo1.rs -o $(TMPDIR)/bar1 + $(RUSTC) foo1.rs -o $(TMPDIR)/$(call BIN,bar1) rm $(TMPDIR)/$(call BIN,bar1) diff --git a/src/test/run-make/dep-info/Makefile b/src/test/run-make/dep-info/Makefile index a1828cd1f5..9b79d1af52 100644 --- a/src/test/run-make/dep-info/Makefile +++ b/src/test/run-make/dep-info/Makefile @@ -7,9 +7,10 @@ ifneq ($(shell uname),FreeBSD) ifndef IS_WINDOWS all: - $(RUSTC) --emit dep-info,link --crate-type=lib lib.rs + cp *.rs $(TMPDIR) + $(RUSTC) --emit dep-info,link --crate-type=lib $(TMPDIR)/lib.rs sleep 2 - touch foo.rs + touch $(TMPDIR)/foo.rs -rm -f $(TMPDIR)/done $(MAKE) -drf Makefile.foo sleep 2 @@ -17,6 +18,11 @@ all: pwd $(MAKE) -drf Makefile.foo rm $(TMPDIR)/done && exit 1 || exit 0 + + # When a source file is deleted `make` should still work + rm $(TMPDIR)/bar.rs + cp $(TMPDIR)/lib2.rs $(TMPDIR)/lib.rs + $(MAKE) -drf Makefile.foo else all: diff --git a/src/test/run-make/issue-12446/bar.rs b/src/test/run-make/dep-info/lib2.rs similarity index 85% rename from src/test/run-make/issue-12446/bar.rs rename to src/test/run-make/dep-info/lib2.rs index cd41058744..1b70fb4eb4 100644 --- a/src/test/run-make/issue-12446/bar.rs +++ b/src/test/run-make/dep-info/lib2.rs @@ -8,11 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern crate foo; +#![crate_name = "foo"] -#[link(name = "foo")] -extern {} - -fn main() { - foo::foo(); -} +pub mod foo; diff --git a/src/test/run-make/execution-engine/test.rs b/src/test/run-make/execution-engine/test.rs index a7c6f5225a..f4031a3aaa 100644 --- a/src/test/run-make/execution-engine/test.rs +++ b/src/test/run-make/execution-engine/test.rs @@ -31,7 +31,7 @@ use rustc::middle::ty; use rustc::session::config::{self, basic_options, build_configuration, Input, Options}; use rustc::session::build_session; use rustc_driver::driver; -use rustc_front::lowering::lower_crate; +use rustc_front::lowering::{lower_crate, LoweringContext}; use rustc_resolve::MakeGlobMap; use libc::c_void; @@ -223,12 +223,13 @@ fn compile_program(input: &str, sysroot: PathBuf) .expect("phase_2 returned `None`"); let krate = driver::assign_node_ids(&sess, krate); - let mut hir_forest = ast_map::Forest::new(lower_crate(&krate)); + let lcx = LoweringContext::new(&sess, Some(&krate)); + let mut hir_forest = ast_map::Forest::new(lower_crate(&lcx, &krate)); let arenas = ty::CtxtArenas::new(); let ast_map = driver::make_map(&sess, &mut hir_forest); driver::phase_3_run_analysis_passes( - sess, ast_map, &krate, &arenas, id, MakeGlobMap::No, |tcx, analysis| { + &sess, ast_map, &arenas, &id, MakeGlobMap::No, |tcx, analysis| { let trans = driver::phase_4_translate_to_llvm(tcx, analysis); @@ -246,7 +247,7 @@ fn compile_program(input: &str, sysroot: PathBuf) let modp = llmod as usize; (modp, deps) - }).1 + }) }).unwrap(); match handle.join() { diff --git a/src/test/run-make/extern-fn-generic/Makefile b/src/test/run-make/extern-fn-generic/Makefile index a325acbf68..cf897dba1f 100644 --- a/src/test/run-make/extern-fn-generic/Makefile +++ b/src/test/run-make/extern-fn-generic/Makefile @@ -1,8 +1,6 @@ -include ../tools.mk -all: - $(CC) -std=c99 test.c -c -o $(TMPDIR)/test.o - $(AR) rcs $(TMPDIR)/libtest.a $(TMPDIR)/test.o - $(RUSTC) testcrate.rs -L $(TMPDIR) - $(RUSTC) test.rs -L $(TMPDIR) +all: $(call NATIVE_STATICLIB,test) + $(RUSTC) testcrate.rs + $(RUSTC) test.rs $(call RUN,test) || exit 1 diff --git a/src/test/run-make/extern-fn-mangle/Makefile b/src/test/run-make/extern-fn-mangle/Makefile index ea6971853f..042048ec25 100644 --- a/src/test/run-make/extern-fn-mangle/Makefile +++ b/src/test/run-make/extern-fn-mangle/Makefile @@ -1,7 +1,5 @@ -include ../tools.mk -all: - $(CC) -std=c99 test.c -c -o $(TMPDIR)/test.o - $(AR) rcs $(TMPDIR)/libtest.a $(TMPDIR)/test.o - $(RUSTC) test.rs -L $(TMPDIR) +all: $(call NATIVE_STATICLIB,test) + $(RUSTC) test.rs $(call RUN,test) || exit 1 diff --git a/src/test/run-make/extern-fn-struct-passing-abi/Makefile b/src/test/run-make/extern-fn-struct-passing-abi/Makefile new file mode 100644 index 0000000000..042048ec25 --- /dev/null +++ b/src/test/run-make/extern-fn-struct-passing-abi/Makefile @@ -0,0 +1,5 @@ +-include ../tools.mk + +all: $(call NATIVE_STATICLIB,test) + $(RUSTC) test.rs + $(call RUN,test) || exit 1 diff --git a/src/test/run-make/extern-fn-struct-passing-abi/test.c b/src/test/run-make/extern-fn-struct-passing-abi/test.c new file mode 100644 index 0000000000..4253767ee7 --- /dev/null +++ b/src/test/run-make/extern-fn-struct-passing-abi/test.c @@ -0,0 +1,260 @@ +// 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. + +#include +#include + +struct Rect { + int32_t a; + int32_t b; + int32_t c; + int32_t d; +}; + +struct BiggerRect { + struct Rect s; + int32_t a; + int32_t b; +}; + +struct FloatRect { + int32_t a; + int32_t b; + double c; +}; + +struct Huge { + int32_t a; + int32_t b; + int32_t c; + int32_t d; + int32_t e; +}; + +// System V x86_64 ABI: +// a, b, c, d, e should be in registers +// s should be byval pointer +// +// Win64 ABI: +// a, b, c, d should be in registers +// e should be on the stack +// s should be byval pointer +void byval_rect(int32_t a, int32_t b, int32_t c, int32_t d, int32_t e, struct Rect s) { + assert(a == 1); + assert(b == 2); + assert(c == 3); + assert(d == 4); + assert(e == 5); + assert(s.a == 553); + assert(s.b == 554); + assert(s.c == 555); + assert(s.d == 556); +} + +// System V x86_64 ABI: +// a, b, c, d, e, f should be in registers +// s should be byval pointer on the stack +// +// Win64 ABI: +// a, b, c, d should be in registers +// e, f should be on the stack +// s should be byval pointer on the stack +void byval_many_rect(int32_t a, int32_t b, int32_t c, int32_t d, int32_t e, + int32_t f, struct Rect s) { + assert(a == 1); + assert(b == 2); + assert(c == 3); + assert(d == 4); + assert(e == 5); + assert(f == 6); + assert(s.a == 553); + assert(s.b == 554); + assert(s.c == 555); + assert(s.d == 556); +} + +// System V x86_64 ABI: +// a, b, c, d, e, f, g should be in sse registers +// s should be split across 2 registers +// t should be byval pointer +// +// Win64 ABI: +// a, b, c, d should be in sse registers +// e, f, g should be on the stack +// s should be on the stack (treated as 2 i64's) +// t should be on the stack (treated as an i64 and a double) +void byval_rect_floats(float a, float b, double c, float d, float e, + float f, double g, struct Rect s, struct FloatRect t) { + assert(a == 1.); + assert(b == 2.); + assert(c == 3.); + assert(d == 4.); + assert(e == 5.); + assert(f == 6.); + assert(g == 7.); + assert(s.a == 553); + assert(s.b == 554); + assert(s.c == 555); + assert(s.d == 556); + assert(t.a == 3489); + assert(t.b == 3490); + assert(t.c == 8.); +} + +// System V x86_64 ABI: +// a, b, d, e, f should be in registers +// c passed via sse registers +// s should be byval pointer +// +// Win64 ABI: +// a, b, d should be in registers +// c passed via sse registers +// e, f should be on the stack +// s should be byval pointer +void byval_rect_with_float(int32_t a, int32_t b, float c, int32_t d, + int32_t e, int32_t f, struct Rect s) { + assert(a == 1); + assert(b == 2); + assert(c == 3.); + assert(d == 4); + assert(e == 5); + assert(f == 6); + assert(s.a == 553); + assert(s.b == 554); + assert(s.c == 555); + assert(s.d == 556); +} + +// System V x86_64 & Win64 ABI: +// a, b should be in registers +// s should be split across 2 integer registers +void split_rect(int32_t a, int32_t b, struct Rect s) { + assert(a == 1); + assert(b == 2); + assert(s.a == 553); + assert(s.b == 554); + assert(s.c == 555); + assert(s.d == 556); +} + +// System V x86_64 & Win64 ABI: +// a, b should be in sse registers +// s should be split across integer & sse registers +void split_rect_floats(float a, float b, struct FloatRect s) { + assert(a == 1.); + assert(b == 2.); + assert(s.a == 3489); + assert(s.b == 3490); + assert(s.c == 8.); +} + +// System V x86_64 ABI: +// a, b, d, f should be in registers +// c, e passed via sse registers +// s should be split across 2 registers +// +// Win64 ABI: +// a, b, d should be in registers +// c passed via sse registers +// e, f should be on the stack +// s should be on the stack (treated as 2 i64's) +void split_rect_with_floats(int32_t a, int32_t b, float c, + int32_t d, float e, int32_t f, struct Rect s) { + assert(a == 1); + assert(b == 2); + assert(c == 3.); + assert(d == 4); + assert(e == 5.); + assert(f == 6); + assert(s.a == 553); + assert(s.b == 554); + assert(s.c == 555); + assert(s.d == 556); +} + +// System V x86_64 & Win64 ABI: +// a, b, c should be in registers +// s should be split across 2 registers +// t should be a byval pointer +void split_and_byval_rect(int32_t a, int32_t b, int32_t c, struct Rect s, struct Rect t) { + assert(a == 1); + assert(b == 2); + assert(c == 3); + assert(s.a == 553); + assert(s.b == 554); + assert(s.c == 555); + assert(s.d == 556); + assert(t.a == 553); + assert(t.b == 554); + assert(t.c == 555); + assert(t.d == 556); +} + +// System V x86_64 & Win64 ABI: +// a, b should in registers +// s and return should be split across 2 registers +struct Rect split_ret_byval_struct(int32_t a, int32_t b, struct Rect s) { + assert(a == 1); + assert(b == 2); + assert(s.a == 553); + assert(s.b == 554); + assert(s.c == 555); + assert(s.d == 556); + return s; +} + +// System V x86_64 & Win64 ABI: +// a, b, c, d should be in registers +// return should be in a hidden sret pointer +// s should be a byval pointer +struct BiggerRect sret_byval_struct(int32_t a, int32_t b, int32_t c, int32_t d, struct Rect s) { + assert(a == 1); + assert(b == 2); + assert(c == 3); + assert(d == 4); + assert(s.a == 553); + assert(s.b == 554); + assert(s.c == 555); + assert(s.d == 556); + + struct BiggerRect t; + t.s = s; t.a = 27834; t.b = 7657; + return t; +} + +// System V x86_64 & Win64 ABI: +// a, b should be in registers +// return should be in a hidden sret pointer +// s should be split across 2 registers +struct BiggerRect sret_split_struct(int32_t a, int32_t b, struct Rect s) { + assert(a == 1); + assert(b == 2); + assert(s.a == 553); + assert(s.b == 554); + assert(s.c == 555); + assert(s.d == 556); + + struct BiggerRect t; + t.s = s; t.a = 27834; t.b = 7657; + return t; +} + +// System V x86_64 & Win64 ABI: +// s should be byval pointer (since sizeof(s) > 16) +// return should in a hidden sret pointer +struct Huge huge_struct(struct Huge s) { + assert(s.a == 5647); + assert(s.b == 5648); + assert(s.c == 5649); + assert(s.d == 5650); + assert(s.e == 5651); + + return s; +} diff --git a/src/test/run-make/extern-fn-struct-passing-abi/test.rs b/src/test/run-make/extern-fn-struct-passing-abi/test.rs new file mode 100644 index 0000000000..b91362b8ed --- /dev/null +++ b/src/test/run-make/extern-fn-struct-passing-abi/test.rs @@ -0,0 +1,98 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Passing structs via FFI should work regardless of whether +// they get passed in multiple registers, byval pointers or the stack + +#[derive(Clone, Copy, Debug, PartialEq)] +#[repr(C)] +struct Rect { + a: i32, + b: i32, + c: i32, + d: i32 +} + +#[derive(Clone, Copy, Debug, PartialEq)] +#[repr(C)] +struct BiggerRect { + s: Rect, + a: i32, + b: i32 +} + +#[derive(Clone, Copy, Debug, PartialEq)] +#[repr(C)] +struct FloatRect { + a: i32, + b: i32, + c: f64 +} + +#[derive(Clone, Copy, Debug, PartialEq)] +#[repr(C)] +struct Huge { + a: i32, + b: i32, + c: i32, + d: i32, + e: i32 +} + +#[link(name = "test", kind = "static")] +extern { + fn byval_rect(a: i32, b: i32, c: i32, d: i32, e: i32, s: Rect); + + fn byval_many_rect(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32, s: Rect); + + fn byval_rect_floats(a: f32, b: f32, c: f64, d: f32, e: f32, + f: f32, g: f64, s: Rect, t: FloatRect); + + fn byval_rect_with_float(a: i32, b: i32, c: f32, d: i32, e: i32, f: i32, s: Rect); + + fn split_rect(a: i32, b: i32, s: Rect); + + fn split_rect_floats(a: f32, b: f32, s: FloatRect); + + fn split_rect_with_floats(a: i32, b: i32, c: f32, d: i32, e: f32, f: i32, s: Rect); + + fn split_and_byval_rect(a: i32, b: i32, c: i32, s: Rect, t: Rect); + + fn split_ret_byval_struct(a: i32, b: i32, s: Rect) -> Rect; + + fn sret_byval_struct(a: i32, b: i32, c: i32, d: i32, s: Rect) -> BiggerRect; + + fn sret_split_struct(a: i32, b: i32, s: Rect) -> BiggerRect; + + fn huge_struct(s: Huge) -> Huge; +} + +fn main() { + let s = Rect { a: 553, b: 554, c: 555, d: 556 }; + let t = BiggerRect { s: s, a: 27834, b: 7657 }; + let u = FloatRect { a: 3489, b: 3490, c: 8. }; + let v = Huge { a: 5647, b: 5648, c: 5649, d: 5650, e: 5651 }; + + unsafe { + byval_rect(1, 2, 3, 4, 5, s); + byval_many_rect(1, 2, 3, 4, 5, 6, s); + byval_rect_floats(1., 2., 3., 4., 5., 6., 7., s, u); + byval_rect_with_float(1, 2, 3.0, 4, 5, 6, s); + split_rect(1, 2, s); + split_rect_floats(1., 2., u); + split_rect_with_floats(1, 2, 3.0, 4, 5.0, 6, s); + split_and_byval_rect(1, 2, 3, s, s); + split_rect(1, 2, s); + assert_eq!(huge_struct(v), v); + assert_eq!(split_ret_byval_struct(1, 2, s), s); + assert_eq!(sret_byval_struct(1, 2, 3, 4, s), t); + assert_eq!(sret_split_struct(1, 2, s), t); + } +} diff --git a/src/test/run-make/extern-fn-with-packed-struct/Makefile b/src/test/run-make/extern-fn-with-packed-struct/Makefile index ea6971853f..042048ec25 100644 --- a/src/test/run-make/extern-fn-with-packed-struct/Makefile +++ b/src/test/run-make/extern-fn-with-packed-struct/Makefile @@ -1,7 +1,5 @@ -include ../tools.mk -all: - $(CC) -std=c99 test.c -c -o $(TMPDIR)/test.o - $(AR) rcs $(TMPDIR)/libtest.a $(TMPDIR)/test.o - $(RUSTC) test.rs -L $(TMPDIR) +all: $(call NATIVE_STATICLIB,test) + $(RUSTC) test.rs $(call RUN,test) || exit 1 diff --git a/src/test/run-make/extern-fn-with-packed-struct/test.c b/src/test/run-make/extern-fn-with-packed-struct/test.c index 121e48e84e..506954fca4 100644 --- a/src/test/run-make/extern-fn-with-packed-struct/test.c +++ b/src/test/run-make/extern-fn-with-packed-struct/test.c @@ -1,11 +1,21 @@ // ignore-license // Pragma needed cause of gcc bug on windows: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52991 + +#ifdef _MSC_VER +#pragma pack(push,1) +struct Foo { + char a; + short b; + char c; +}; +#else #pragma pack(1) struct __attribute__((packed)) Foo { char a; short b; char c; }; +#endif struct Foo foo(struct Foo foo) { return foo; diff --git a/src/test/run-make/extern-fn-with-union/Makefile b/src/test/run-make/extern-fn-with-union/Makefile index a325acbf68..cf897dba1f 100644 --- a/src/test/run-make/extern-fn-with-union/Makefile +++ b/src/test/run-make/extern-fn-with-union/Makefile @@ -1,8 +1,6 @@ -include ../tools.mk -all: - $(CC) -std=c99 test.c -c -o $(TMPDIR)/test.o - $(AR) rcs $(TMPDIR)/libtest.a $(TMPDIR)/test.o - $(RUSTC) testcrate.rs -L $(TMPDIR) - $(RUSTC) test.rs -L $(TMPDIR) +all: $(call NATIVE_STATICLIB,test) + $(RUSTC) testcrate.rs + $(RUSTC) test.rs $(call RUN,test) || exit 1 diff --git a/src/test/run-make/interdependent-c-libraries/Makefile b/src/test/run-make/interdependent-c-libraries/Makefile index cf7683479f..1268022e37 100644 --- a/src/test/run-make/interdependent-c-libraries/Makefile +++ b/src/test/run-make/interdependent-c-libraries/Makefile @@ -8,7 +8,7 @@ # correct to complete the linkage. If passed as "-lfoo -lbar", then the 'foo' # library will be stripped out, and the linkage will fail. -all: $(call STATICLIB,foo) $(call STATICLIB,bar) +all: $(call NATIVE_STATICLIB,foo) $(call NATIVE_STATICLIB,bar) $(RUSTC) foo.rs $(RUSTC) bar.rs $(RUSTC) main.rs -Z print-link-args diff --git a/src/test/run-make/invalid-staticlib/Makefile b/src/test/run-make/invalid-staticlib/Makefile new file mode 100644 index 0000000000..d4aa6d5e72 --- /dev/null +++ b/src/test/run-make/invalid-staticlib/Makefile @@ -0,0 +1,5 @@ +-include ../tools.mk + +all: + touch $(TMPDIR)/libfoo.a + echo | $(RUSTC) - --crate-type=rlib -lstatic=foo 2>&1 | grep "failed to add native library" diff --git a/src/test/run-make/issue-12446/Makefile b/src/test/run-make/issue-12446/Makefile deleted file mode 100644 index e864ee0058..0000000000 --- a/src/test/run-make/issue-12446/Makefile +++ /dev/null @@ -1,6 +0,0 @@ --include ../tools.mk - -all: $(call STATICLIB,foo) - $(RUSTC) foo.rs - $(RUSTC) bar.rs - $(call RUN,bar) diff --git a/src/test/run-make/issue-12446/foo.c b/src/test/run-make/issue-12446/foo.c deleted file mode 100644 index 186a0046e8..0000000000 --- a/src/test/run-make/issue-12446/foo.c +++ /dev/null @@ -1,2 +0,0 @@ -// ignore-license -void some_c_symbol() {} diff --git a/src/test/run-make/issue-14500/Makefile b/src/test/run-make/issue-14500/Makefile index 6ea3cf48ff..bd94db0952 100644 --- a/src/test/run-make/issue-14500/Makefile +++ b/src/test/run-make/issue-14500/Makefile @@ -13,5 +13,5 @@ endif all: $(RUSTC) foo.rs --crate-type=rlib $(RUSTC) bar.rs --crate-type=staticlib -C lto -L. -o $(TMPDIR)/libbar.a - $(CC) foo.c -lbar -o $(call RUN_BINFILE,foo) $(EXTRACFLAGS) + $(CC) foo.c $(TMPDIR)/libbar.a $(EXTRACFLAGS) $(call OUT_EXE,foo) $(call RUN,foo) diff --git a/src/test/run-make/issue-14698/Makefile b/src/test/run-make/issue-14698/Makefile new file mode 100644 index 0000000000..28502f67e0 --- /dev/null +++ b/src/test/run-make/issue-14698/Makefile @@ -0,0 +1,4 @@ +-include ../tools.mk + +all: + TMP=fake TMPDIR=fake $(RUSTC) foo.rs 2>&1 | grep "couldn't create a temp dir:" diff --git a/src/test/run-make/issue-14698/foo.rs b/src/test/run-make/issue-14698/foo.rs new file mode 100644 index 0000000000..7dc79f2043 --- /dev/null +++ b/src/test/run-make/issue-14698/foo.rs @@ -0,0 +1,11 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() {} diff --git a/src/test/run-make/issue-15460/Makefile b/src/test/run-make/issue-15460/Makefile index bc5e9b7286..846805686a 100644 --- a/src/test/run-make/issue-15460/Makefile +++ b/src/test/run-make/issue-15460/Makefile @@ -1,6 +1,6 @@ -include ../tools.mk -all: $(TMPDIR)/libfoo.a +all: $(call NATIVE_STATICLIB,foo) $(RUSTC) foo.rs -C extra-filename=-383hf8 -C prefer-dynamic $(RUSTC) bar.rs $(call RUN,bar) diff --git a/src/test/run-make/issue-15460/foo.c b/src/test/run-make/issue-15460/foo.c index 2895ad473b..fdf595b574 100644 --- a/src/test/run-make/issue-15460/foo.c +++ b/src/test/run-make/issue-15460/foo.c @@ -1,2 +1,6 @@ // ignore-license + +#ifdef _WIN32 +__declspec(dllexport) +#endif void foo() {} diff --git a/src/test/run-make/issue-15460/foo.rs b/src/test/run-make/issue-15460/foo.rs index 6917fa5557..8b96fe3682 100644 --- a/src/test/run-make/issue-15460/foo.rs +++ b/src/test/run-make/issue-15460/foo.rs @@ -8,9 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(linked_from)] #![crate_type = "dylib"] #[link(name = "foo", kind = "static")] +#[linked_from = "foo"] extern { pub fn foo(); } diff --git a/src/test/run-make/issue-19371/foo.rs b/src/test/run-make/issue-19371/foo.rs index 8745cbecf9..bd8c735df3 100644 --- a/src/test/run-make/issue-19371/foo.rs +++ b/src/test/run-make/issue-19371/foo.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_private, path, convert)] +#![feature(rustc_private)] extern crate rustc; extern crate rustc_driver; @@ -16,7 +16,7 @@ extern crate rustc_lint; extern crate syntax; use rustc::session::{build_session, Session}; -use rustc::session::config::{basic_options, build_configuration, Input, OutputTypeExe}; +use rustc::session::config::{basic_options, build_configuration, Input, OutputType}; use rustc_driver::driver::{compile_input, CompileController}; use syntax::diagnostics::registry::Registry; @@ -46,7 +46,7 @@ fn main() { fn basic_sess(sysroot: PathBuf) -> Session { let mut opts = basic_options(); - opts.output_types = vec![OutputTypeExe]; + opts.output_types.insert(OutputType::Exe, None); opts.maybe_sysroot = Some(sysroot); let descriptions = Registry::new(&rustc::DIAGNOSTICS); diff --git a/src/test/run-make/issue-25581/Makefile b/src/test/run-make/issue-25581/Makefile index ea6971853f..042048ec25 100644 --- a/src/test/run-make/issue-25581/Makefile +++ b/src/test/run-make/issue-25581/Makefile @@ -1,7 +1,5 @@ -include ../tools.mk -all: - $(CC) -std=c99 test.c -c -o $(TMPDIR)/test.o - $(AR) rcs $(TMPDIR)/libtest.a $(TMPDIR)/test.o - $(RUSTC) test.rs -L $(TMPDIR) +all: $(call NATIVE_STATICLIB,test) + $(RUSTC) test.rs $(call RUN,test) || exit 1 diff --git a/src/test/run-make/issue-26092/Makefile b/src/test/run-make/issue-26092/Makefile index 1e66e3a538..0d94c99a39 100644 --- a/src/test/run-make/issue-26092/Makefile +++ b/src/test/run-make/issue-26092/Makefile @@ -2,4 +2,4 @@ all: $(RUSTC) -o "" blank.rs 2>&1 | \ - grep 'No such file or directory' + grep -i 'No such file or directory' diff --git a/src/test/run-make/issue-28595/Makefile b/src/test/run-make/issue-28595/Makefile new file mode 100644 index 0000000000..61e9d0c654 --- /dev/null +++ b/src/test/run-make/issue-28595/Makefile @@ -0,0 +1,6 @@ +-include ../tools.mk + +all: $(call NATIVE_STATICLIB,a) $(call NATIVE_STATICLIB,b) + $(RUSTC) a.rs + $(RUSTC) b.rs + $(call RUN,b) diff --git a/src/test/run-make/issue-28595/a.c b/src/test/run-make/issue-28595/a.c new file mode 100644 index 0000000000..feacd7bc31 --- /dev/null +++ b/src/test/run-make/issue-28595/a.c @@ -0,0 +1,11 @@ +// 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. + +void a(void) {} diff --git a/src/test/run-make/issue-28595/a.rs b/src/test/run-make/issue-28595/a.rs new file mode 100644 index 0000000000..7377a9f341 --- /dev/null +++ b/src/test/run-make/issue-28595/a.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. + +#![crate_type = "rlib"] + +#[link(name = "a", kind = "static")] +extern { + pub fn a(); +} diff --git a/src/test/run-pass/issue-14564.rs b/src/test/run-make/issue-28595/b.c similarity index 90% rename from src/test/run-pass/issue-14564.rs rename to src/test/run-make/issue-28595/b.c index a661437a44..de81fbcaa6 100644 --- a/src/test/run-pass/issue-14564.rs +++ b/src/test/run-make/issue-28595/b.c @@ -8,8 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -mod Foo { } -struct Foo; -impl Foo { } +extern void a(void); + +void b(void) { + a(); +} -fn main() { } diff --git a/src/test/run-make/issue-28595/b.rs b/src/test/run-make/issue-28595/b.rs new file mode 100644 index 0000000000..37ff346c3f --- /dev/null +++ b/src/test/run-make/issue-28595/b.rs @@ -0,0 +1,21 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate a; + +#[link(name = "b", kind = "static")] +extern { + pub fn b(); +} + + +fn main() { + unsafe { b(); } +} diff --git a/src/test/run-make/link-path-order/Makefile b/src/test/run-make/link-path-order/Makefile index 116c7ae991..eeea0e3714 100644 --- a/src/test/run-make/link-path-order/Makefile +++ b/src/test/run-make/link-path-order/Makefile @@ -6,10 +6,12 @@ CORRECT_DIR=$(TMPDIR)/correct WRONG_DIR=$(TMPDIR)/wrong -all: $(TMPDIR)/libcorrect.a $(TMPDIR)/libwrong.a +F := $(call NATIVE_STATICLIB_FILE,foo) + +all: $(call NATIVE_STATICLIB,correct) $(call NATIVE_STATICLIB,wrong) mkdir -p $(CORRECT_DIR) $(WRONG_DIR) - mv $(TMPDIR)/libcorrect.a $(CORRECT_DIR)/libfoo.a - mv $(TMPDIR)/libwrong.a $(WRONG_DIR)/libfoo.a + mv $(call NATIVE_STATICLIB,correct) $(CORRECT_DIR)/$(F) + mv $(call NATIVE_STATICLIB,wrong) $(WRONG_DIR)/$(F) $(RUSTC) main.rs -o $(TMPDIR)/should_succeed -L $(CORRECT_DIR) -L $(WRONG_DIR) $(call RUN,should_succeed) $(RUSTC) main.rs -o $(TMPDIR)/should_fail -L $(WRONG_DIR) -L $(CORRECT_DIR) diff --git a/src/test/run-make/linkage-attr-on-static/Makefile b/src/test/run-make/linkage-attr-on-static/Makefile index 1871a5bbdc..4befbe1446 100644 --- a/src/test/run-make/linkage-attr-on-static/Makefile +++ b/src/test/run-make/linkage-attr-on-static/Makefile @@ -1,7 +1,5 @@ -include ../tools.mk -all: - $(CC) foo.c -c -o $(TMPDIR)/foo.o - $(AR) rcs $(TMPDIR)/libfoo.a $(TMPDIR)/foo.o - $(RUSTC) bar.rs -lfoo -L $(TMPDIR) +all: $(call NATIVE_STATICLIB,foo) + $(RUSTC) bar.rs $(call RUN,bar) || exit 1 diff --git a/src/test/run-make/linkage-attr-on-static/bar.rs b/src/test/run-make/linkage-attr-on-static/bar.rs index 6125421bde..274401c448 100644 --- a/src/test/run-make/linkage-attr-on-static/bar.rs +++ b/src/test/run-make/linkage-attr-on-static/bar.rs @@ -14,6 +14,7 @@ #[linkage = "external"] static BAZ: i32 = 21; +#[link(name = "foo", kind = "static")] extern { fn what() -> i32; } diff --git a/src/test/run-make/linker-output-non-utf8/Makefile b/src/test/run-make/linker-output-non-utf8/Makefile new file mode 100644 index 0000000000..98fe83f45e --- /dev/null +++ b/src/test/run-make/linker-output-non-utf8/Makefile @@ -0,0 +1,24 @@ +-include ../tools.mk + +# Make sure we don't ICE if the linker prints a non-UTF-8 error message. + +ifdef IS_WINDOWS +# ignore windows + +# This does not work in its current form on windows, possibly due to +# gcc bugs or something about valid Windows paths. See issue #29151 +# for more information. +all: + +else + +# The zzz it to allow humans to tab complete or glob this thing. +bad_dir := $(TMPDIR)/zzz$$'\xff' + +all: + $(RUSTC) library.rs + mkdir $(bad_dir) + mv $(TMPDIR)/liblibrary.a $(bad_dir) + LIBRARY_PATH=$(bad_dir) $(RUSTC) exec.rs 2>&1 | grep this_symbol_not_defined + +endif diff --git a/src/test/run-make/linker-output-non-utf8/exec.rs b/src/test/run-make/linker-output-non-utf8/exec.rs new file mode 100644 index 0000000000..1c03eb479f --- /dev/null +++ b/src/test/run-make/linker-output-non-utf8/exec.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. + +#[link(name="library")] +extern "C" { + fn foo(); +} + +fn main() { unsafe { foo(); } } diff --git a/src/test/run-make/linker-output-non-utf8/library.rs b/src/test/run-make/linker-output-non-utf8/library.rs new file mode 100644 index 0000000000..194be26424 --- /dev/null +++ b/src/test/run-make/linker-output-non-utf8/library.rs @@ -0,0 +1,20 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "staticlib"] + +extern "C" { + fn this_symbol_not_defined(); +} + +#[no_mangle] +pub extern "C" fn foo() { + unsafe { this_symbol_not_defined(); } +} diff --git a/src/test/run-make/lto-smoke-c/Makefile b/src/test/run-make/lto-smoke-c/Makefile index 6165afbeb2..72c161abe9 100644 --- a/src/test/run-make/lto-smoke-c/Makefile +++ b/src/test/run-make/lto-smoke-c/Makefile @@ -5,5 +5,7 @@ CC := $(CC:-g=) all: $(RUSTC) foo.rs -C lto - $(CC) bar.c -lfoo -o $(call RUN_BINFILE,bar) $(EXTRACFLAGS) $(EXTRACXXFLAGS) + $(CC) bar.c $(TMPDIR)/libfoo.a \ + $(call OUT_EXE,bar) \ + $(EXTRACFLAGS) $(EXTRACXXFLAGS) $(call RUN,bar) diff --git a/src/test/run-make/no-duplicate-libs/Makefile b/src/test/run-make/no-duplicate-libs/Makefile index fdb6048dc4..3f6a28c251 100644 --- a/src/test/run-make/no-duplicate-libs/Makefile +++ b/src/test/run-make/no-duplicate-libs/Makefile @@ -1,7 +1,12 @@ -include ../tools.mk +ifdef IS_MSVC +# FIXME(#27979) +all: +else all: $(RUSTC) foo.rs $(RUSTC) bar.rs $(RUSTC) main.rs $(call RUN,main) +endif diff --git a/src/test/run-make/no-duplicate-libs/bar.c b/src/test/run-make/no-duplicate-libs/bar.c deleted file mode 100644 index a7b02a2f10..0000000000 --- a/src/test/run-make/no-duplicate-libs/bar.c +++ /dev/null @@ -1,4 +0,0 @@ -// ignore-license -extern void foo(); - -void bar() { foo(); } diff --git a/src/test/run-make/no-duplicate-libs/foo.c b/src/test/run-make/no-duplicate-libs/foo.c deleted file mode 100644 index 2895ad473b..0000000000 --- a/src/test/run-make/no-duplicate-libs/foo.c +++ /dev/null @@ -1,2 +0,0 @@ -// ignore-license -void foo() {} diff --git a/src/test/run-make/output-type-permutations/Makefile b/src/test/run-make/output-type-permutations/Makefile index 4efbd9ee48..b4b2e827e9 100644 --- a/src/test/run-make/output-type-permutations/Makefile +++ b/src/test/run-make/output-type-permutations/Makefile @@ -4,12 +4,14 @@ all: $(RUSTC) foo.rs --crate-type=rlib,dylib,staticlib $(call REMOVE_RLIBS,bar) $(call REMOVE_DYLIBS,bar) - rm $(TMPDIR)/$(call STATICLIB_GLOB,bar) + rm $(TMPDIR)/libbar.a + rm -f $(TMPDIR)/bar.{exp,lib,pdb} # Check that $(TMPDIR) is empty. [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] $(RUSTC) foo.rs --crate-type=bin rm $(TMPDIR)/$(call BIN,bar) + rm -f $(TMPDIR)/bar.pdb [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] $(RUSTC) foo.rs --emit=asm,llvm-ir,llvm-bc,obj,link @@ -18,49 +20,91 @@ all: rm $(TMPDIR)/bar.s rm $(TMPDIR)/bar.o rm $(TMPDIR)/$(call BIN,bar) + rm -f $(TMPDIR)/bar.pdb [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] - $(RUSTC) foo.rs --emit=asm -o $(TMPDIR)/foo + $(RUSTC) foo.rs --emit asm -o $(TMPDIR)/foo + rm $(TMPDIR)/foo + $(RUSTC) foo.rs --emit asm=$(TMPDIR)/foo rm $(TMPDIR)/foo [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] - $(RUSTC) foo.rs --emit=llvm-bc -o $(TMPDIR)/foo + $(RUSTC) foo.rs --emit llvm-bc -o $(TMPDIR)/foo + rm $(TMPDIR)/foo + $(RUSTC) foo.rs --emit llvm-bc=$(TMPDIR)/foo rm $(TMPDIR)/foo [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] - $(RUSTC) foo.rs --emit=llvm-ir -o $(TMPDIR)/foo + $(RUSTC) foo.rs --emit llvm-ir -o $(TMPDIR)/foo + rm $(TMPDIR)/foo + $(RUSTC) foo.rs --emit llvm-ir=$(TMPDIR)/foo rm $(TMPDIR)/foo [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] - $(RUSTC) foo.rs --emit=obj -o $(TMPDIR)/foo + $(RUSTC) foo.rs --emit obj -o $(TMPDIR)/foo + rm $(TMPDIR)/foo + $(RUSTC) foo.rs --emit obj=$(TMPDIR)/foo rm $(TMPDIR)/foo [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] - $(RUSTC) foo.rs --emit=link -o $(TMPDIR)/foo + $(RUSTC) foo.rs --emit link -o $(TMPDIR)/$(call BIN,foo) rm $(TMPDIR)/$(call BIN,foo) + $(RUSTC) foo.rs --emit link=$(TMPDIR)/$(call BIN,foo) + rm $(TMPDIR)/$(call BIN,foo) + rm -f $(TMPDIR)/foo.pdb [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] $(RUSTC) foo.rs --crate-type=rlib -o $(TMPDIR)/foo rm $(TMPDIR)/foo + $(RUSTC) foo.rs --crate-type=rlib --emit link=$(TMPDIR)/foo + rm $(TMPDIR)/foo [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] - $(RUSTC) foo.rs --crate-type=dylib -o $(TMPDIR)/foo - rm $(TMPDIR)/$(call BIN,foo) # FIXME 13794 + $(RUSTC) foo.rs --crate-type=dylib -o $(TMPDIR)/$(call BIN,foo) + rm $(TMPDIR)/$(call BIN,foo) + $(RUSTC) foo.rs --crate-type=dylib --emit link=$(TMPDIR)/$(call BIN,foo) + rm $(TMPDIR)/$(call BIN,foo) + rm -f $(TMPDIR)/foo.{exp,lib,pdb} [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] $(RUSTC) foo.rs --crate-type=staticlib -o $(TMPDIR)/foo rm $(TMPDIR)/foo + $(RUSTC) foo.rs --crate-type=staticlib --emit link=$(TMPDIR)/foo + rm $(TMPDIR)/foo [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] - $(RUSTC) foo.rs --crate-type=bin -o $(TMPDIR)/foo + $(RUSTC) foo.rs --crate-type=bin -o $(TMPDIR)/$(call BIN,foo) rm $(TMPDIR)/$(call BIN,foo) + $(RUSTC) foo.rs --crate-type=bin --emit link=$(TMPDIR)/$(call BIN,foo) + rm $(TMPDIR)/$(call BIN,foo) + rm -f $(TMPDIR)/foo.pdb + [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] + + $(RUSTC) foo.rs --emit llvm-ir=$(TMPDIR)/ir \ + --emit link \ + --crate-type=rlib + rm $(TMPDIR)/ir + rm $(TMPDIR)/libbar.rlib + [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] + + $(RUSTC) foo.rs --emit asm=$(TMPDIR)/asm \ + --emit llvm-ir=$(TMPDIR)/ir \ + --emit llvm-bc=$(TMPDIR)/bc \ + --emit obj=$(TMPDIR)/obj \ + --emit link=$(TMPDIR)/link \ + --crate-type=staticlib + rm $(TMPDIR)/asm + rm $(TMPDIR)/ir + rm $(TMPDIR)/bc + rm $(TMPDIR)/obj + rm $(TMPDIR)/link [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] $(RUSTC) foo.rs --emit=asm,llvm-ir,llvm-bc,obj,link --crate-type=staticlib rm $(TMPDIR)/bar.ll rm $(TMPDIR)/bar.s rm $(TMPDIR)/bar.o - rm $(TMPDIR)/$(call STATICLIB_GLOB,bar) + rm $(TMPDIR)/libbar.a mv $(TMPDIR)/bar.bc $(TMPDIR)/foo.bc # Don't check that the $(TMPDIR) is empty - we left `foo.bc` for later # comparison. diff --git a/src/test/run-make/relocation-model/Makefile b/src/test/run-make/relocation-model/Makefile index 2fcdd32bfc..b22f34fa35 100644 --- a/src/test/run-make/relocation-model/Makefile +++ b/src/test/run-make/relocation-model/Makefile @@ -1,15 +1,21 @@ -include ../tools.mk -all: +all: others $(RUSTC) -C relocation-model=dynamic-no-pic foo.rs $(call RUN,foo) $(RUSTC) -C relocation-model=default foo.rs $(call RUN,foo) + $(RUSTC) -C relocation-model=default --crate-type=dylib foo.rs + $(RUSTC) -C relocation-model=dynamic-no-pic --crate-type=dylib foo.rs + +ifdef IS_MSVC +# FIXME(#28026) +others: +else +others: $(RUSTC) -C relocation-model=static foo.rs $(call RUN,foo) - - $(RUSTC) -C relocation-model=default --crate-type=dylib foo.rs $(RUSTC) -C relocation-model=static --crate-type=dylib foo.rs - $(RUSTC) -C relocation-model=dynamic-no-pic --crate-type=dylib foo.rs +endif diff --git a/src/test/run-make/save-analysis/Makefile b/src/test/run-make/save-analysis/Makefile index 701bdee110..7296fb9cc5 100644 --- a/src/test/run-make/save-analysis/Makefile +++ b/src/test/run-make/save-analysis/Makefile @@ -1,6 +1,6 @@ -include ../tools.mk all: code krate2: krate2.rs - $(RUSTC) $< + $(RUSTC) $< code: foo.rs krate2 $(RUSTC) foo.rs -Zsave-analysis diff --git a/src/test/run-make/save-analysis/foo.rs b/src/test/run-make/save-analysis/foo.rs index 4981ea475d..3e4ba5af80 100644 --- a/src/test/run-make/save-analysis/foo.rs +++ b/src/test/run-make/save-analysis/foo.rs @@ -339,8 +339,27 @@ fn main() { // foo if let SomeEnum::Strings(..) = s7 { println!("hello!"); } + + for i in 0..5 { + foo_foo(i); + } + + if let Some(x) = None { + foo_foo(x); + } + + if false { + } else if let Some(y) = None { + foo_foo(y); + } + + while let Some(z) = None { + foo_foo(z); + } } +fn foo_foo(_: i32) {} + impl Iterator for nofields { type Item = (usize, usize); diff --git a/src/test/run-make/static-dylib-by-default/Makefile b/src/test/run-make/static-dylib-by-default/Makefile index 1505e679af..8bd05dc201 100644 --- a/src/test/run-make/static-dylib-by-default/Makefile +++ b/src/test/run-make/static-dylib-by-default/Makefile @@ -1,9 +1,16 @@ -include ../tools.mk +TO_LINK := $(call DYLIB,bar) +ifdef IS_MSVC +LINK_ARG = $(TO_LINK:dll=lib) +else +LINK_ARG = $(TO_LINK) +endif + all: $(RUSTC) foo.rs $(RUSTC) bar.rs - $(CC) main.c -o $(call RUN_BINFILE,main) -lbar $(EXTRACFLAGS) + $(CC) main.c $(call OUT_EXE,main) $(LINK_ARG) $(EXTRACFLAGS) rm $(TMPDIR)/*.rlib rm $(call DYLIB,foo) $(call RUN,main) diff --git a/src/test/run-make/tools.mk b/src/test/run-make/tools.mk index 223296286b..23af568697 100644 --- a/src/test/run-make/tools.mk +++ b/src/test/run-make/tools.mk @@ -7,7 +7,7 @@ TARGET_RPATH_ENV = \ BARE_RUSTC := $(HOST_RPATH_ENV) $(RUSTC) RUSTC := $(BARE_RUSTC) --out-dir $(TMPDIR) -L $(TMPDIR) -CC := $(CC) -L $(TMPDIR) +#CC := $(CC) -L $(TMPDIR) HTMLDOCCK := $(PYTHON) $(S)/src/etc/htmldocck.py # This is the name of the binary we will generate and run; use this @@ -19,8 +19,6 @@ RUN_BINFILE = $(TMPDIR)/$(1) # variable before running the binary. RLIB_GLOB = lib$(1)*.rlib -STATICLIB = $(TMPDIR)/lib$(1).a -STATICLIB_GLOB = lib$(1)*.a BIN = $(1) UNAME = $(shell uname) @@ -33,27 +31,48 @@ RUN = $(TARGET_RPATH_ENV) $(RUN_BINFILE) FAIL = $(TARGET_RPATH_ENV) $(RUN_BINFILE) && exit 1 || exit 0 DYLIB_GLOB = lib$(1)*.dylib DYLIB = $(TMPDIR)/lib$(1).dylib -RPATH_LINK_SEARCH = +STATICLIB = $(TMPDIR)/lib$(1).a +STATICLIB_GLOB = lib$(1)*.a else ifdef IS_WINDOWS RUN = PATH="$(PATH):$(TARGET_RPATH_DIR)" $(RUN_BINFILE) FAIL = PATH="$(PATH):$(TARGET_RPATH_DIR)" $(RUN_BINFILE) && exit 1 || exit 0 DYLIB_GLOB = $(1)*.dll DYLIB = $(TMPDIR)/$(1).dll +STATICLIB = $(TMPDIR)/$(1).lib +STATICLIB_GLOB = $(1)*.lib BIN = $(1).exe -RPATH_LINK_SEARCH = else RUN = $(TARGET_RPATH_ENV) $(RUN_BINFILE) FAIL = $(TARGET_RPATH_ENV) $(RUN_BINFILE) && exit 1 || exit 0 DYLIB_GLOB = lib$(1)*.so DYLIB = $(TMPDIR)/lib$(1).so -RPATH_LINK_SEARCH = -Wl,-rpath-link=$(1) +STATICLIB = $(TMPDIR)/lib$(1).a +STATICLIB_GLOB = lib$(1)*.a +endif endif + +ifdef IS_MSVC +COMPILE_OBJ = $(CC) -c -Fo:`cygpath -w $(1)` $(2) +NATIVE_STATICLIB_FILE = $(1).lib +NATIVE_STATICLIB = $(TMPDIR)/$(call NATIVE_STATICLIB_FILE,$(1)) +OUT_EXE=-Fe:`cygpath -w $(TMPDIR)/$(call BIN,$(1))` \ + -Fo:`cygpath -w $(TMPDIR)/$(1).obj` +else +COMPILE_OBJ = $(CC) -c -o $(1) $(2) +NATIVE_STATICLIB_FILE = lib$(1).a +NATIVE_STATICLIB = $(call STATICLIB,$(1)) +OUT_EXE=-o $(TMPDIR)/$(1) endif + # Extra flags needed to compile a working executable with the standard library ifdef IS_WINDOWS +ifdef IS_MSVC + EXTRACFLAGS := ws2_32.lib userenv.lib shell32.lib advapi32.lib +else EXTRACFLAGS := -lws2_32 -luserenv +endif else ifeq ($(UNAME),Darwin) else @@ -66,6 +85,11 @@ ifeq ($(UNAME),Bitrig) else ifeq ($(UNAME),OpenBSD) EXTRACFLAGS := -lm -lpthread + # extend search lib for found estdc++ if build using gcc from + # ports under OpenBSD. This is needed for: + # - run-make/execution-engine + # - run-make/issue-19371 + RUSTC := $(RUSTC) -L/usr/local/lib else EXTRACFLAGS := -lm -lrt -ldl -lpthread EXTRACXXFLAGS := -lstdc++ @@ -80,12 +104,20 @@ REMOVE_RLIBS = rm $(TMPDIR)/$(call RLIB_GLOB,$(1)) %.a: %.o ar crus $@ $< +%.lib: lib%.o + ar crus $@ $< %.dylib: %.o $(CC) -dynamiclib -Wl,-dylib -o $@ $< %.so: %.o $(CC) -o $@ $< -shared + +ifdef IS_MSVC +%.dll: lib%.o + $(CC) $< -link -dll -out:`cygpath -w $@` +else %.dll: lib%.o $(CC) -o $@ $< -shared +endif $(TMPDIR)/lib%.o: %.c - $(CC) -c -o $@ $< + $(call COMPILE_OBJ,$@,$<) diff --git a/src/test/run-pass-fulldeps/rename-directory.rs b/src/test/run-pass-fulldeps/rename-directory.rs index 2bec41f3ee..f107e10428 100644 --- a/src/test/run-pass-fulldeps/rename-directory.rs +++ b/src/test/run-pass-fulldeps/rename-directory.rs @@ -13,12 +13,12 @@ // ignore-cross-compile -#![feature(rustc_private, path_ext)] +#![feature(rustc_private)] extern crate rustc_back; use std::ffi::CString; -use std::fs::{self, File, PathExt}; +use std::fs::{self, File}; use rustc_back::tempdir::TempDir; fn rename_directory() { diff --git a/src/test/run-pass/arr_cycle.rs b/src/test/run-pass/arr_cycle.rs index 80434f36b4..400458b614 100644 --- a/src/test/run-pass/arr_cycle.rs +++ b/src/test/run-pass/arr_cycle.rs @@ -10,7 +10,7 @@ use std::cell::Cell; -#[derive(Show)] +#[derive(Debug)] struct B<'a> { a: [Cell>>; 2] } diff --git a/src/test/run-pass/augmented-assignments.rs b/src/test/run-pass/augmented-assignments.rs new file mode 100644 index 0000000000..eb4c1dbb0b --- /dev/null +++ b/src/test/run-pass/augmented-assignments.rs @@ -0,0 +1,164 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(augmented_assignments)] +#![feature(op_assign_traits)] + +use std::mem; +use std::ops::{ + AddAssign, BitAndAssign, BitOrAssign, BitXorAssign, DivAssign, Index, MulAssign, RemAssign, + ShlAssign, ShrAssign, SubAssign, +}; + +#[derive(Debug, PartialEq)] +struct Int(i32); + +struct Slice([i32]); + +impl Slice { + fn new(slice: &mut [i32]) -> &mut Slice { + unsafe { + mem::transmute(slice) + } + } +} + +fn main() { + let mut x = Int(1); + + x += Int(2); + assert_eq!(x, Int(0b11)); + + x &= Int(0b01); + assert_eq!(x, Int(0b01)); + + x |= Int(0b10); + assert_eq!(x, Int(0b11)); + + x ^= Int(0b01); + assert_eq!(x, Int(0b10)); + + x /= Int(2); + assert_eq!(x, Int(1)); + + x *= Int(3); + assert_eq!(x, Int(3)); + + x %= Int(2); + assert_eq!(x, Int(1)); + + // overloaded RHS + x <<= 1u8; + assert_eq!(x, Int(2)); + + x <<= 1u16; + assert_eq!(x, Int(4)); + + x >>= 1u8; + assert_eq!(x, Int(2)); + + x >>= 1u16; + assert_eq!(x, Int(1)); + + x -= Int(1); + assert_eq!(x, Int(0)); + + // indexed LHS + let mut v = vec![Int(1), Int(2)]; + v[0] += Int(2); + assert_eq!(v[0], Int(3)); + + // unsized RHS + let mut array = [0, 1, 2]; + *Slice::new(&mut array) += 1; + assert_eq!(array[0], 1); + assert_eq!(array[1], 2); + assert_eq!(array[2], 3); +} + +impl AddAssign for Int { + fn add_assign(&mut self, rhs: Int) { + self.0 += rhs.0; + } +} + +impl BitAndAssign for Int { + fn bitand_assign(&mut self, rhs: Int) { + self.0 &= rhs.0; + } +} + +impl BitOrAssign for Int { + fn bitor_assign(&mut self, rhs: Int) { + self.0 |= rhs.0; + } +} + +impl BitXorAssign for Int { + fn bitxor_assign(&mut self, rhs: Int) { + self.0 ^= rhs.0; + } +} + +impl DivAssign for Int { + fn div_assign(&mut self, rhs: Int) { + self.0 /= rhs.0; + } +} + +impl MulAssign for Int { + fn mul_assign(&mut self, rhs: Int) { + self.0 *= rhs.0; + } +} + +impl RemAssign for Int { + fn rem_assign(&mut self, rhs: Int) { + self.0 %= rhs.0; + } +} + +impl ShlAssign for Int { + fn shl_assign(&mut self, rhs: u8) { + self.0 <<= rhs; + } +} + +impl ShlAssign for Int { + fn shl_assign(&mut self, rhs: u16) { + self.0 <<= rhs; + } +} + +impl ShrAssign for Int { + fn shr_assign(&mut self, rhs: u8) { + self.0 >>= rhs; + } +} + +impl ShrAssign for Int { + fn shr_assign(&mut self, rhs: u16) { + self.0 >>= rhs; + } +} + +impl SubAssign for Int { + fn sub_assign(&mut self, rhs: Int) { + self.0 -= rhs.0; + } +} + +impl AddAssign for Slice { + fn add_assign(&mut self, rhs: i32) { + for lhs in &mut self.0 { + *lhs += rhs; + } + } +} diff --git a/src/test/run-pass/autoderef-method-on-trait.rs b/src/test/run-pass/autoderef-method-on-trait.rs index 40acb6eb9f..5c5364de6a 100644 --- a/src/test/run-pass/autoderef-method-on-trait.rs +++ b/src/test/run-pass/autoderef-method-on-trait.rs @@ -21,6 +21,6 @@ impl double for usize { } pub fn main() { - let x: Box<_> = box() (box 3usize as Box); + let x: Box<_> = box (box 3usize as Box); assert_eq!(x.double(), 6); } diff --git a/src/test/run-pass/borrowck-rvalues-mutable.rs b/src/test/run-pass/borrowck-rvalues-mutable.rs index 045e8d952a..93cb0cb0af 100644 --- a/src/test/run-pass/borrowck-rvalues-mutable.rs +++ b/src/test/run-pass/borrowck-rvalues-mutable.rs @@ -39,5 +39,5 @@ pub fn main() { assert_eq!(v, 22); let v = Counter::new(22).inc().inc().get(); - assert_eq!(v, 24);; + assert_eq!(v, 24); } diff --git a/src/test/run-pass/cfg-target-vendor.rs b/src/test/run-pass/cfg-target-vendor.rs new file mode 100644 index 0000000000..787ae5289d --- /dev/null +++ b/src/test/run-pass/cfg-target-vendor.rs @@ -0,0 +1,19 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(cfg_target_vendor)] + +#[cfg(target_vendor = "unknown")] +pub fn main() { +} + +#[cfg(not(target_vendor = "unknown"))] +pub fn main() { +} diff --git a/src/test/run-pass/const-adt-align-mismatch.rs b/src/test/run-pass/const-adt-align-mismatch.rs index 5377d9a62b..46cd708a13 100644 --- a/src/test/run-pass/const-adt-align-mismatch.rs +++ b/src/test/run-pass/const-adt-align-mismatch.rs @@ -10,7 +10,7 @@ use std::mem; -#[derive(PartialEq, Show)] +#[derive(PartialEq, Debug)] enum Foo { A(u32), Bar([u16; 4]), diff --git a/src/test/run-pass/const-fn-const-eval.rs b/src/test/run-pass/const-fn-const-eval.rs new file mode 100644 index 0000000000..77c70fe7f6 --- /dev/null +++ b/src/test/run-pass/const-fn-const-eval.rs @@ -0,0 +1,19 @@ +// 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. + +#![feature(const_fn)] + +const fn add(x: usize, y: usize) -> usize { + x + y +} + +const ARR: [i32; add(1, 2)] = [5, 6, 7]; + +pub fn main() {} diff --git a/src/test/run-pass/const-unsafe-fn.rs b/src/test/run-pass/const-unsafe-fn.rs new file mode 100644 index 0000000000..2511cfd042 --- /dev/null +++ b/src/test/run-pass/const-unsafe-fn.rs @@ -0,0 +1,31 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// A quick test of 'unsafe const fn' functionality + +#![feature(const_fn)] + +const unsafe fn dummy(v: u32) -> u32 { + !v +} + +struct Type; +impl Type { + const unsafe fn new() -> Type { + Type + } +} + +const VAL: u32 = unsafe { dummy(0xFFFF) }; +const TYPE_INST: Type = unsafe { Type::new() }; + +fn main() { + assert_eq!(VAL, 0xFFFF0000); +} diff --git a/src/test/run-pass/core-run-destroy.rs b/src/test/run-pass/core-run-destroy.rs index 83ce0db365..d6b6d673ca 100644 --- a/src/test/run-pass/core-run-destroy.rs +++ b/src/test/run-pass/core-run-destroy.rs @@ -30,26 +30,25 @@ macro_rules! t { ($e:expr) => (match $e { Ok(e) => e, Err(e) => panic!("error: {}", e) }) } +#[test] fn test_destroy_once() { let mut p = sleeper(); - match p.kill() { - Ok(()) => {} - Err(e) => panic!("error: {}", e), - } + t!(p.kill()); } #[cfg(unix)] pub fn sleeper() -> Child { - Command::new("sleep").arg("1000").spawn().unwrap() + t!(Command::new("sleep").arg("1000").spawn()) } #[cfg(windows)] pub fn sleeper() -> Child { // There's a `timeout` command on windows, but it doesn't like having // its output piped, so instead just ping ourselves a few times with // gaps in between so we're sure this process is alive for awhile - Command::new("ping").arg("127.0.0.1").arg("-n").arg("1000").spawn().unwrap() + t!(Command::new("ping").arg("127.0.0.1").arg("-n").arg("1000").spawn()) } +#[test] fn test_destroy_twice() { let mut p = sleeper(); t!(p.kill()); // this shouldn't crash... @@ -58,21 +57,20 @@ fn test_destroy_twice() { #[test] fn test_destroy_actually_kills() { - #[cfg(all(unix,not(target_os="android")))] - static BLOCK_COMMAND: &'static str = "cat"; - - #[cfg(all(unix,target_os="android"))] - static BLOCK_COMMAND: &'static str = "/system/bin/cat"; - - #[cfg(windows)] - static BLOCK_COMMAND: &'static str = "cmd"; + let cmd = if cfg!(windows) { + "cmd" + } else if cfg!(target_os = "android") { + "/system/bin/cat" + } else { + "cat" + }; // this process will stay alive indefinitely trying to read from stdin - let mut p = Command::new(BLOCK_COMMAND) - .stdin(Stdio::piped()) - .spawn().unwrap(); + let mut p = t!(Command::new(cmd) + .stdin(Stdio::piped()) + .spawn()); - p.kill().unwrap(); + t!(p.kill()); // Don't let this test time out, this should be quick let (tx, rx) = channel(); @@ -82,7 +80,7 @@ fn test_destroy_actually_kills() { process::exit(1); } }); - let code = p.wait().unwrap().code(); + let code = t!(p.wait()).code(); if cfg!(windows) { assert!(code.is_some()); } else { diff --git a/src/test/run-pass/crate-method-reexport-grrrrrrr.rs b/src/test/run-pass/crate-method-reexport-grrrrrrr.rs index 43507f0cb0..028b3f43e2 100644 --- a/src/test/run-pass/crate-method-reexport-grrrrrrr.rs +++ b/src/test/run-pass/crate-method-reexport-grrrrrrr.rs @@ -24,7 +24,7 @@ extern crate crate_method_reexport_grrrrrrr2; pub fn main() { use crate_method_reexport_grrrrrrr2::rust::add; use crate_method_reexport_grrrrrrr2::rust::cx; - let x: Box<_> = box () (); + let x: Box<_> = box (); x.cx(); let y = (); y.add("hi".to_string()); diff --git a/src/test/run-pass/deprecated-derive.rs b/src/test/run-pass/deprecated-derive.rs index 494d62c773..69a7f888bb 100644 --- a/src/test/run-pass/deprecated-derive.rs +++ b/src/test/run-pass/deprecated-derive.rs @@ -8,8 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[derive(Show)] -//~^ WARNING derive(Show) is deprecated +#![feature(rustc_private)] + +extern crate serialize; + +#[derive(Encodable)] +//~^ WARNING derive(Encodable) is deprecated in favor of derive(RustcEncodable) struct Test1; fn main() { } diff --git a/src/test/run-pass/dropck_legal_cycles.rs b/src/test/run-pass/dropck_legal_cycles.rs index 2770260a10..a31df0fd93 100644 --- a/src/test/run-pass/dropck_legal_cycles.rs +++ b/src/test/run-pass/dropck_legal_cycles.rs @@ -24,9 +24,92 @@ // through the collection, for every collection type that supports // this. -#![feature(vecmap)] +// HIGH LEVEL DESCRIPTION OF THE TEST ARCHITECTURE +// ----------------------------------------------- +// +// We pick a data structure and want to make a cyclic construction +// from it. Each test of interest is labelled starting with "Cycle N: +// { ... }" where N is the test number and the "..."`is filled in with +// a graphviz-style description of the graph structure that the +// author believes is being made. So "{ a -> b, b -> (c,d), (c,d) -> e }" +// describes a line connected to a diamond: +// +// c +// / \ +// a - b e +// \ / +// d +// +// (Note that the above directed graph is actually acyclic.) +// +// The different graph structures are often composed of different data +// types. Some may be built atop `Vec`, others atop `HashMap`, etc. +// +// For each graph structure, we actually *confirm* that a cycle exists +// (as a safe-guard against a test author accidentally leaving it out) +// by traversing each graph and "proving" that a cycle exists within it. +// +// To do this, while trying to keep the code uniform (despite working +// with different underlying collection and smart-pointer types), we +// have a standard traversal API: +// +// 1. every node in the graph carries a `mark` (a u32, init'ed to 0). +// +// 2. every node provides a method to visit its children +// +// 3. a traversal attmepts to visit the nodes of the graph and prove that +// it sees the same node twice. It does this by setting the mark of each +// node to a fresh non-zero value, and if it sees the current mark, it +// "knows" that it must have found a cycle, and stops attempting further +// traversal. +// +// 4. each traversal is controlled by a bit-string that tells it which child +// it visit when it can take different paths. As a simple example, +// in a binary tree, 0 could mean "left" (and 1, "right"), so that +// "00010" means "left, left, left, right, left". (In general it will +// read as many bits as it needs to choose one child.) +// +// The graphs in this test are all meant to be very small, and thus +// short bitstrings of less than 64 bits should always suffice. +// +// (An earlier version of this test infrastructure simply had any +// given traversal visit all children it encountered, in a +// depth-first manner; one problem with this approach is that an +// acyclic graph can still have sharing, which would then be treated +// as a repeat mark and reported as a detected cycle.) +// +// The travseral code is a little more complicated because it has been +// programmed in a somewhat defensive manner. For example it also has +// a max threshold for the number of nodes it will visit, to guard +// against scenarios where the nodes are not correctly setting their +// mark when asked. There are various other methods not discussed here +// that are for aiding debugging the test when it runs, such as the +// `name` method that all nodes provide. +// +// So each test: +// +// 1. allocates the nodes in the graph, +// +// 2. sets up the links in the graph, +// +// 3. clones the "ContextData" +// +// 4. chooses a new current mark value for this test +// +// 5. initiates a traversal, potentially from multiple starting points +// (aka "roots"), with a given control-string (potentially a +// different string for each root). if it does start from a +// distinct root, then such a test should also increment the +// current mark value, so that this traversal is considered +// distinct from the prior one on this graph structure. +// +// Note that most of the tests work with the default control string +// of all-zeroes. +// +// 6. assert that the context confirms that it actually saw a cycle (since a traversal +// might have terminated, e.g. on a tree structure that contained no cycles). -use std::cell::Cell; +use std::cell::{Cell, RefCell}; use std::cmp::Ordering; use std::collections::BinaryHeap; use std::collections::HashMap; @@ -35,6 +118,8 @@ use std::collections::VecDeque; use std::collections::btree_map::BTreeMap; use std::collections::btree_set::BTreeSet; use std::hash::{Hash, Hasher}; +use std::rc::Rc; +use std::sync::{Arc, RwLock, Mutex}; const PRINT: bool = false; @@ -47,8 +132,28 @@ pub fn main() { skipped: 0, curr_mark: 0, saw_prev_marked: false, + control_bits: 0, }; + // SANITY CHECK FOR TEST SUITE (thus unnumbered) + // Not a cycle: { v[0] -> (v[1], v[2]), v[1] -> v[3], v[2] -> v[3] }; + let v: Vec = vec![Named::new("s0"), + Named::new("s1"), + Named::new("s2"), + Named::new("s3")]; + v[0].next.set((Some(&v[1]), Some(&v[2]))); + v[1].next.set((Some(&v[3]), None)); + v[2].next.set((Some(&v[3]), None)); + v[3].next.set((None, None)); + + let mut c = c_orig.clone(); + c.curr_mark = 10; + assert!(!c.saw_prev_marked); + v[0].descend_into_self(&mut c); + assert!(!c.saw_prev_marked); // <-- different from below, b/c acyclic above + + if PRINT { println!(""); } + // Cycle 1: { v[0] -> v[1], v[1] -> v[0] }; // does not exercise `v` itself let v: Vec = vec![Named::new("s0"), @@ -59,7 +164,7 @@ pub fn main() { let mut c = c_orig.clone(); c.curr_mark = 10; assert!(!c.saw_prev_marked); - v[0].for_each_child(&mut c); + v[0].descend_into_self(&mut c); assert!(c.saw_prev_marked); if PRINT { println!(""); } @@ -72,7 +177,7 @@ pub fn main() { let mut c = c_orig.clone(); c.curr_mark = 20; assert!(!c.saw_prev_marked); - v.for_each_child(&mut c); + v.descend_into_self(&mut c); assert!(c.saw_prev_marked); if PRINT { println!(""); } @@ -93,7 +198,7 @@ pub fn main() { for (key, _) in h.iter() { c.curr_mark += 1; c.saw_prev_marked = false; - key.for_each_child(&mut c); + key.descend_into_self(&mut c); assert!(c.saw_prev_marked); } @@ -115,7 +220,7 @@ pub fn main() { for (key, _) in h.iter() { c.curr_mark += 1; c.saw_prev_marked = false; - key.for_each_child(&mut c); + key.descend_into_self(&mut c); assert!(c.saw_prev_marked); // break; } @@ -133,7 +238,7 @@ pub fn main() { let mut c = c_orig.clone(); c.curr_mark = 50; assert!(!c.saw_prev_marked); - vd[0].for_each_child(&mut c); + vd[0].descend_into_self(&mut c); assert!(c.saw_prev_marked); if PRINT { println!(""); } @@ -148,7 +253,7 @@ pub fn main() { let mut c = c_orig.clone(); c.curr_mark = 60; assert!(!c.saw_prev_marked); - vd[0].for_each_child(&mut c); + vd[0].descend_into_self(&mut c); assert!(c.saw_prev_marked); if PRINT { println!(""); } @@ -163,7 +268,7 @@ pub fn main() { let mut c = c_orig.clone(); c.curr_mark = 70; assert!(!c.saw_prev_marked); - vm[&0].for_each_child(&mut c); + vm[&0].descend_into_self(&mut c); assert!(c.saw_prev_marked); if PRINT { println!(""); } @@ -181,7 +286,7 @@ pub fn main() { for e in &ll { c.curr_mark += 1; c.saw_prev_marked = false; - e.for_each_child(&mut c); + e.descend_into_self(&mut c); assert!(c.saw_prev_marked); // break; } @@ -201,7 +306,7 @@ pub fn main() { for b in &bh { c.curr_mark += 1; c.saw_prev_marked = false; - b.for_each_child(&mut c); + b.descend_into_self(&mut c); assert!(c.saw_prev_marked); // break; } @@ -222,7 +327,7 @@ pub fn main() { for (k, _) in &btm { c.curr_mark += 1; c.saw_prev_marked = false; - k.for_each_child(&mut c); + k.descend_into_self(&mut c); assert!(c.saw_prev_marked); // break; } @@ -242,10 +347,98 @@ pub fn main() { for b in &bts { c.curr_mark += 1; c.saw_prev_marked = false; - b.for_each_child(&mut c); + b.descend_into_self(&mut c); assert!(c.saw_prev_marked); // break; } + + if PRINT { println!(""); } + + // Cycle 11: { rc0 -> (rc1, rc2), rc1 -> (), rc2 -> rc0 } + let (rc0, rc1, rc2): (RCRC, RCRC, RCRC); + rc0 = RCRC::new("rcrc0"); + rc1 = RCRC::new("rcrc1"); + rc2 = RCRC::new("rcrc2"); + rc0.0.borrow_mut().children.0 = Some(&rc1); + rc0.0.borrow_mut().children.1 = Some(&rc2); + rc2.0.borrow_mut().children.0 = Some(&rc0); + + let mut c = c_orig.clone(); + c.control_bits = 0b1; + c.curr_mark = 110; + assert!(!c.saw_prev_marked); + rc0.descend_into_self(&mut c); + assert!(c.saw_prev_marked); + + if PRINT { println!(""); } + + // We want to take the previous Rc case and generalize it to Arc. + // + // We can use refcells if we're single-threaded (as this test is). + // If one were to generalize these constructions to a + // multi-threaded context, then it might seem like we could choose + // between either a RwLock or a Mutex to hold the owned arcs on + // each node. + // + // Part of the point of this test is to actually confirm that the + // cycle exists by traversing it. We can do that just fine with an + // RwLock (since we can grab the child pointers in read-only + // mode), but we cannot lock a std::sync::Mutex to guard reading + // from each node via the same pattern, since once you hit the + // cycle, you'll be trying to acquring the same lock twice. + // (We deal with this by exiting the traversal early if try_lock fails.) + + // Cycle 12: { arc0 -> (arc1, arc2), arc1 -> (), arc2 -> arc0 }, refcells + let (arc0, arc1, arc2): (ARCRC, ARCRC, ARCRC); + arc0 = ARCRC::new("arcrc0"); + arc1 = ARCRC::new("arcrc1"); + arc2 = ARCRC::new("arcrc2"); + arc0.0.borrow_mut().children.0 = Some(&arc1); + arc0.0.borrow_mut().children.1 = Some(&arc2); + arc2.0.borrow_mut().children.0 = Some(&arc0); + + let mut c = c_orig.clone(); + c.control_bits = 0b1; + c.curr_mark = 110; + assert!(!c.saw_prev_marked); + arc0.descend_into_self(&mut c); + assert!(c.saw_prev_marked); + + if PRINT { println!(""); } + + // Cycle 13: { arc0 -> (arc1, arc2), arc1 -> (), arc2 -> arc0 }, rwlocks + let (arc0, arc1, arc2): (ARCRW, ARCRW, ARCRW); + arc0 = ARCRW::new("arcrw0"); + arc1 = ARCRW::new("arcrw1"); + arc2 = ARCRW::new("arcrw2"); + arc0.0.write().unwrap().children.0 = Some(&arc1); + arc0.0.write().unwrap().children.1 = Some(&arc2); + arc2.0.write().unwrap().children.0 = Some(&arc0); + + let mut c = c_orig.clone(); + c.control_bits = 0b1; + c.curr_mark = 110; + assert!(!c.saw_prev_marked); + arc0.descend_into_self(&mut c); + assert!(c.saw_prev_marked); + + if PRINT { println!(""); } + + // Cycle 14: { arc0 -> (arc1, arc2), arc1 -> (), arc2 -> arc0 }, mutexs + let (arc0, arc1, arc2): (ARCM, ARCM, ARCM); + arc0 = ARCM::new("arcm0"); + arc1 = ARCM::new("arcm1"); + arc2 = ARCM::new("arcm2"); + arc0.1.lock().unwrap().children.0 = Some(&arc1); + arc0.1.lock().unwrap().children.1 = Some(&arc2); + arc2.1.lock().unwrap().children.0 = Some(&arc0); + + let mut c = c_orig.clone(); + c.control_bits = 0b1; + c.curr_mark = 110; + assert!(!c.saw_prev_marked); + arc0.descend_into_self(&mut c); + assert!(c.saw_prev_marked); } trait Named { @@ -276,6 +469,26 @@ impl<'a> Marked for S<'a> { fn set_mark(&self, mark: u32) { self.mark.set(mark); } } +struct S2<'a> { + name: &'static str, + mark: Cell, + next: Cell<(Option<&'a S2<'a>>, Option<&'a S2<'a>>)>, +} + +impl<'a> Named for S2<'a> { + fn new<'b>(name: &'static str) -> S2<'b> { + S2 { name: name, mark: Cell::new(0), next: Cell::new((None, None)) } + } + fn name(&self) -> &str { self.name } +} + +impl<'a> Marked for S2<'a> { + fn mark(&self) -> u32 { self.mark.get() } + fn set_mark(&self, mark: u32) { + self.mark.set(mark); + } +} + struct V<'a> { name: &'static str, mark: Cell, @@ -549,8 +762,168 @@ impl<'a> Ord for BTS<'a> { } } +#[derive(Clone)] +struct RCRCData<'a> { + name: &'static str, + mark: Cell, + children: (Option<&'a RCRC<'a>>, Option<&'a RCRC<'a>>), +} +#[derive(Clone)] +struct RCRC<'a>(Rc>>); + +impl<'a> Named for RCRC<'a> { + fn new(name: &'static str) -> Self { + RCRC(Rc::new(RefCell::new(RCRCData { + name: name, mark: Cell::new(0), children: (None, None), }))) + } + fn name(&self) -> &str { self.0.borrow().name } +} + +impl<'a> Marked for RCRC<'a> { + fn mark(&self) -> u32 { self.0.borrow().mark.get() } + fn set_mark(&self, mark: u32) { self.0.borrow().mark.set(mark); } +} + +impl<'a> Children<'a> for RCRC<'a> { + fn count_children(&self) -> usize { 2 } + fn descend_one_child(&self, context: &mut C, index: usize) + where C: Context + PrePost, Self: Sized + { + let children = &self.0.borrow().children; + let child = match index { + 0 => if let Some(child) = children.0 { child } else { return; }, + 1 => if let Some(child) = children.1 { child } else { return; }, + _ => panic!("bad children"), + }; + // println!("S2 {} descending into child {} at index {}", self.name, child.name, index); + child.descend_into_self(context); + } +} +#[derive(Clone)] +struct ARCRCData<'a> { + name: &'static str, + mark: Cell, + children: (Option<&'a ARCRC<'a>>, Option<&'a ARCRC<'a>>), +} +#[derive(Clone)] +struct ARCRC<'a>(Arc>>); + +impl<'a> Named for ARCRC<'a> { + fn new(name: &'static str) -> Self { + ARCRC(Arc::new(RefCell::new(ARCRCData { + name: name, mark: Cell::new(0), children: (None, None), }))) + } + fn name(&self) -> &str { self.0.borrow().name } +} + +impl<'a> Marked for ARCRC<'a> { + fn mark(&self) -> u32 { self.0.borrow().mark.get() } + fn set_mark(&self, mark: u32) { self.0.borrow().mark.set(mark); } +} + +impl<'a> Children<'a> for ARCRC<'a> { + fn count_children(&self) -> usize { 2 } + fn descend_one_child(&self, context: &mut C, index: usize) + where C: Context + PrePost, Self: Sized + { + let children = &self.0.borrow().children; + match index { + 0 => if let Some(ref child) = children.0 { + child.descend_into_self(context); + }, + 1 => if let Some(ref child) = children.1 { + child.descend_into_self(context); + }, + _ => panic!("bad children!"), + } + } +} + +#[derive(Clone)] +struct ARCMData<'a> { + mark: Cell, + children: (Option<&'a ARCM<'a>>, Option<&'a ARCM<'a>>), +} + +#[derive(Clone)] +struct ARCM<'a>(&'static str, Arc>>); + +impl<'a> Named for ARCM<'a> { + fn new(name: &'static str) -> Self { + ARCM(name, Arc::new(Mutex::new(ARCMData { + mark: Cell::new(0), children: (None, None), }))) + } + fn name(&self) -> &str { self.0 } +} + +impl<'a> Marked for ARCM<'a> { + fn mark(&self) -> u32 { self.1.lock().unwrap().mark.get() } + fn set_mark(&self, mark: u32) { self.1.lock().unwrap().mark.set(mark); } +} + +impl<'a> Children<'a> for ARCM<'a> { + fn count_children(&self) -> usize { 2 } + fn descend_one_child(&self, context: &mut C, index: usize) + where C: Context + PrePost, Self: Sized + { + let ref children = if let Ok(data) = self.1.try_lock() { + data.children + } else { return; }; + match index { + 0 => if let Some(ref child) = children.0 { + child.descend_into_self(context); + }, + 1 => if let Some(ref child) = children.1 { + child.descend_into_self(context); + }, + _ => panic!("bad children!"), + } + } +} + +#[derive(Clone)] +struct ARCRWData<'a> { + name: &'static str, + mark: Cell, + children: (Option<&'a ARCRW<'a>>, Option<&'a ARCRW<'a>>), +} + +#[derive(Clone)] +struct ARCRW<'a>(Arc>>); + +impl<'a> Named for ARCRW<'a> { + fn new(name: &'static str) -> Self { + ARCRW(Arc::new(RwLock::new(ARCRWData { + name: name, mark: Cell::new(0), children: (None, None), }))) + } + fn name(&self) -> &str { self.0.read().unwrap().name } +} + +impl<'a> Marked for ARCRW<'a> { + fn mark(&self) -> u32 { self.0.read().unwrap().mark.get() } + fn set_mark(&self, mark: u32) { self.0.read().unwrap().mark.set(mark); } +} + +impl<'a> Children<'a> for ARCRW<'a> { + fn count_children(&self) -> usize { 2 } + fn descend_one_child(&self, context: &mut C, index: usize) + where C: Context + PrePost, Self: Sized + { + let children = &self.0.read().unwrap().children; + match index { + 0 => if let Some(ref child) = children.0 { + child.descend_into_self(context); + }, + 1 => if let Some(ref child) = children.1 { + child.descend_into_self(context); + }, + _ => panic!("bad children!"), + } + } +} trait Context { + fn next_index(&mut self, len: usize) -> usize; fn should_act(&self) -> bool; fn increase_visited(&mut self); fn increase_skipped(&mut self); @@ -565,9 +938,17 @@ trait PrePost { } trait Children<'a> { - fn for_each_child(&self, context: &mut C) + fn count_children(&self) -> usize; + fn descend_one_child(&self, context: &mut C, index: usize) where C: Context + PrePost, Self: Sized; + fn next_child(&self, context: &mut C) + where C: Context + PrePost, Self: Sized + { + let index = context.next_index(self.count_children()); + self.descend_one_child(context, index); + } + fn descend_into_self(&self, context: &mut C) where C: Context + PrePost, Self: Sized { @@ -575,7 +956,7 @@ trait Children<'a> { if context.should_act() { context.increase_visited(); context.increase_depth(); - self.for_each_child(context); + self.next_child(context); context.decrease_depth(); } else { context.hit_limit(self); @@ -594,51 +975,73 @@ trait Children<'a> { } impl<'a> Children<'a> for S<'a> { - fn for_each_child(&self, context: &mut C) - where C: Context + PrePost> + fn count_children(&self) -> usize { 1 } + fn descend_one_child(&self, context: &mut C, _: usize) + where C: Context + PrePost, Self: Sized { + self.descend(&self.next, context); + } +} + +impl<'a> Children<'a> for S2<'a> { + fn count_children(&self) -> usize { 2 } + fn descend_one_child(&self, context: &mut C, index: usize) + where C: Context + PrePost, Self: Sized { - self.descend(&self.next, context); + let children = self.next.get(); + let child = match index { + 0 => if let Some(child) = children.0 { child } else { return; }, + 1 => if let Some(child) = children.1 { child } else { return; }, + _ => panic!("bad children"), + }; + // println!("S2 {} descending into child {} at index {}", self.name, child.name, index); + child.descend_into_self(context); } } impl<'a> Children<'a> for V<'a> { - fn for_each_child(&self, context: &mut C) - where C: Context + PrePost> + fn count_children(&self) -> usize { self.contents.len() } + fn descend_one_child(&self, context: &mut C, index: usize) + where C: Context + PrePost, Self: Sized { - for r in &self.contents { - self.descend(r, context); + if let Some(child) = self.contents[index].get() { + child.descend_into_self(context); } } } impl<'a> Children<'a> for H<'a> { - fn for_each_child(&self, context: &mut C) - where C: Context + PrePost> + fn count_children(&self) -> usize { 1 } + fn descend_one_child(&self, context: &mut C, _: usize) + where C: Context + PrePost, Self: Sized { self.descend(&self.next, context); } } impl<'a> Children<'a> for HM<'a> { - fn for_each_child(&self, context: &mut C) - where C: Context + PrePost> + fn count_children(&self) -> usize { + if let Some(m) = self.contents.get() { 2 * m.iter().count() } else { 0 } + } + fn descend_one_child(&self, context: &mut C, index: usize) + where C: Context + PrePost, Self: Sized { if let Some(ref hm) = self.contents.get() { - for (k, v) in hm.iter() { - for r in &[k, v] { - r.descend_into_self(context); - } + for (k, v) in hm.iter().nth(index / 2) { + [k, v][index % 2].descend_into_self(context); } } } } impl<'a> Children<'a> for VD<'a> { - fn for_each_child(&self, context: &mut C) - where C: Context + PrePost> + fn count_children(&self) -> usize { + if let Some(d) = self.contents.get() { d.iter().count() } else { 0 } + } + fn descend_one_child(&self, context: &mut C, index: usize) + where C: Context + PrePost, Self: Sized { if let Some(ref vd) = self.contents.get() { - for r in vd.iter() { + for r in vd.iter().nth(index) { r.descend_into_self(context); } } @@ -646,11 +1049,14 @@ impl<'a> Children<'a> for VD<'a> { } impl<'a> Children<'a> for VM<'a> { - fn for_each_child(&self, context: &mut C) + fn count_children(&self) -> usize { + if let Some(m) = self.contents.get() { m.iter().count() } else { 0 } + } + fn descend_one_child(&self, context: &mut C, index: usize) where C: Context + PrePost> { if let Some(ref vd) = self.contents.get() { - for (_idx, r) in vd.iter() { + for (_idx, r) in vd.iter().nth(index) { r.descend_into_self(context); } } @@ -658,11 +1064,14 @@ impl<'a> Children<'a> for VM<'a> { } impl<'a> Children<'a> for LL<'a> { - fn for_each_child(&self, context: &mut C) + fn count_children(&self) -> usize { + if let Some(l) = self.contents.get() { l.iter().count() } else { 0 } + } + fn descend_one_child(&self, context: &mut C, index: usize) where C: Context + PrePost> { if let Some(ref ll) = self.contents.get() { - for r in ll.iter() { + for r in ll.iter().nth(index) { r.descend_into_self(context); } } @@ -670,11 +1079,14 @@ impl<'a> Children<'a> for LL<'a> { } impl<'a> Children<'a> for BH<'a> { - fn for_each_child(&self, context: &mut C) + fn count_children(&self) -> usize { + if let Some(h) = self.contents.get() { h.iter().count() } else { 0 } + } + fn descend_one_child(&self, context: &mut C, index: usize) where C: Context + PrePost> { if let Some(ref bh) = self.contents.get() { - for r in bh.iter() { + for r in bh.iter().nth(index) { r.descend_into_self(context); } } @@ -682,25 +1094,29 @@ impl<'a> Children<'a> for BH<'a> { } impl<'a> Children<'a> for BTM<'a> { - fn for_each_child(&self, context: &mut C) + fn count_children(&self) -> usize { + if let Some(m) = self.contents.get() { 2 * m.iter().count() } else { 0 } + } + fn descend_one_child(&self, context: &mut C, index: usize) where C: Context + PrePost> { if let Some(ref bh) = self.contents.get() { - for (k, v) in bh.iter() { - for r in &[k, v] { - r.descend_into_self(context); - } + for (k, v) in bh.iter().nth(index / 2) { + [k, v][index % 2].descend_into_self(context); } } } } impl<'a> Children<'a> for BTS<'a> { - fn for_each_child(&self, context: &mut C) + fn count_children(&self) -> usize { + if let Some(s) = self.contents.get() { s.iter().count() } else { 0 } + } + fn descend_one_child(&self, context: &mut C, index: usize) where C: Context + PrePost> { if let Some(ref bh) = self.contents.get() { - for r in bh.iter() { + for r in bh.iter().nth(index) { r.descend_into_self(context); } } @@ -716,9 +1132,27 @@ struct ContextData { skipped: usize, curr_mark: u32, saw_prev_marked: bool, + control_bits: u64, } impl Context for ContextData { + fn next_index(&mut self, len: usize) -> usize { + if len < 2 { return 0; } + let mut pow2 = len.next_power_of_two(); + let _pow2_orig = pow2; + let mut idx = 0; + let mut bits = self.control_bits; + while pow2 > 1 { + idx = (idx << 1) | (bits & 1) as usize; + bits = bits >> 1; + pow2 = pow2 >> 1; + } + idx = idx % len; + // println!("next_index({} [{:b}]) says {}, pre(bits): {:b} post(bits): {:b}", + // len, _pow2_orig, idx, self.control_bits, bits); + self.control_bits = bits; + return idx; + } fn should_act(&self) -> bool { self.curr_depth < self.max_depth && self.visited < self.max_visits } diff --git a/src/test/run-pass/dropck_tarena_sound_drop.rs b/src/test/run-pass/dropck_tarena_sound_drop.rs index b0c4f4ca27..db30bfbf74 100644 --- a/src/test/run-pass/dropck_tarena_sound_drop.rs +++ b/src/test/run-pass/dropck_tarena_sound_drop.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Check that a arena (TypedArena) can carry elements whose drop +// Check that an arena (TypedArena) can carry elements whose drop // methods might access borrowed data, as long as the borrowed data // has lifetime that strictly outlives the arena itself. // diff --git a/src/test/run-pass/empty-struct-braces.rs b/src/test/run-pass/empty-struct-braces.rs new file mode 100644 index 0000000000..f2fbf2dd33 --- /dev/null +++ b/src/test/run-pass/empty-struct-braces.rs @@ -0,0 +1,88 @@ +// 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. + +// Empty struct defined with braces add names into type namespace +// Empty struct defined without braces add names into both type and value namespaces + +#![feature(braced_empty_structs)] + +struct Empty1 {} +struct Empty2; +struct Empty3 {} +const Empty3: Empty3 = Empty3 {}; + +enum E { + Empty4 {}, + Empty5, +} + +fn main() { + let e1: Empty1 = Empty1 {}; + let e2: Empty2 = Empty2 {}; + let e2: Empty2 = Empty2; + let e3: Empty3 = Empty3 {}; + let e3: Empty3 = Empty3; + let e4: E = E::Empty4 {}; + // let e5: E = E::Empty5 {}; // Issue #28692 + let e5: E = E::Empty5; + + match e1 { + Empty1 {} => {} + } + match e2 { + Empty2 {} => {} + } + match e3 { + Empty3 {} => {} + } + match e4 { + E::Empty4 {} => {} + _ => {} + } + // Issue #28692 + // match e5 { + // E::Empty5 {} => {} + // _ => {} + // } + + match e1 { + Empty1 { .. } => {} + } + match e2 { + Empty2 { .. } => {} + } + match e3 { + Empty3 { .. } => {} + } + match e4 { + E::Empty4 { .. } => {} + _ => {} + } + // Issue #28692 + // match e5 { + // E::Empty5 { .. } => {} + // _ => {} + // } + + match e2 { + Empty2 => {} + } + match e3 { + Empty3 => {} + } + match e5 { + E::Empty5 => {} + _ => {} + } + + let e11: Empty1 = Empty1 { ..e1 }; + let e22: Empty2 = Empty2 { ..e2 }; + let e33: Empty3 = Empty3 { ..e3 }; +} diff --git a/src/test/run-pass/ifmt.rs b/src/test/run-pass/ifmt.rs index c8adb6ccc0..2cc033b8a4 100644 --- a/src/test/run-pass/ifmt.rs +++ b/src/test/run-pass/ifmt.rs @@ -74,6 +74,10 @@ pub fn main() { t!(format!("{:?}", 10_usize), "10"); t!(format!("{:?}", "true"), "\"true\""); t!(format!("{:?}", "foo\nbar"), "\"foo\\nbar\""); + t!(format!("{:?}", "foo\n\"bar\"\r\n\'baz\'\t\\qux\\"), + r#""foo\n\"bar\"\r\n\'baz\'\t\\qux\\""#); + t!(format!("{:?}", "foo\0bar\x01baz\u{3b1}q\u{75}x"), + r#""foo\u{0}bar\u{1}baz\u{3b1}qux""#); t!(format!("{:o}", 10_usize), "12"); t!(format!("{:x}", 10_usize), "a"); t!(format!("{:X}", 10_usize), "A"); diff --git a/src/test/run-pass/impl-inherent-non-conflict.rs b/src/test/run-pass/impl-inherent-non-conflict.rs index 0d43f1ca70..209b4acb09 100644 --- a/src/test/run-pass/impl-inherent-non-conflict.rs +++ b/src/test/run-pass/impl-inherent-non-conflict.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Ensure that an user-defined type admits multiple inherent methods +// Ensure that a user-defined type admits multiple inherent methods // with the same name, which can be called on values that have a // precise enough type to allow distinguishing between the methods. diff --git a/src/test/run-pass/issue-10767.rs b/src/test/run-pass/issue-10767.rs index 9d680d1962..b5ef6020b5 100644 --- a/src/test/run-pass/issue-10767.rs +++ b/src/test/run-pass/issue-10767.rs @@ -16,5 +16,5 @@ pub fn main() { fn f() { }; - let _: Box = box() (f as fn()); + let _: Box = box (f as fn()); } diff --git a/src/test/run-pass/issue-11047.rs b/src/test/run-pass/issue-11047.rs new file mode 100644 index 0000000000..1d97d579a6 --- /dev/null +++ b/src/test/run-pass/issue-11047.rs @@ -0,0 +1,35 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that static methods can be invoked on `type` aliases + +#![allow(unused_variables)] + +pub mod foo { + pub mod bar { + pub mod baz { + pub struct Qux; + + impl Qux { + pub fn new() {} + } + } + } +} + +fn main() { + + type Ham = foo::bar::baz::Qux; + let foo = foo::bar::baz::Qux::new(); // invoke directly + let bar = Ham::new(); // invoke via type alias + + type StringVec = Vec; + let sv = StringVec::new(); +} diff --git a/src/test/run-pass/issue-11577.rs b/src/test/run-pass/issue-11577.rs index 81588e8ef7..c1997fac74 100644 --- a/src/test/run-pass/issue-11577.rs +++ b/src/test/run-pass/issue-11577.rs @@ -1,4 +1,3 @@ - // 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. diff --git a/src/test/run-pass/issue-14919.rs b/src/test/run-pass/issue-14919.rs index 371e926ab1..d3c9fe9161 100644 --- a/src/test/run-pass/issue-14919.rs +++ b/src/test/run-pass/issue-14919.rs @@ -59,5 +59,5 @@ fn match_indices<'a, M, T: IntoMatcher<'a, M>>(s: &'a str, from: T) -> MatchIndi fn main() { let s = "abcbdef"; match_indices(s, |c: char| c == 'b') - .collect::>(); + .collect::>(); } diff --git a/src/test/run-pass/issue-16819.rs b/src/test/run-pass/issue-16819.rs new file mode 100644 index 0000000000..a9abb99696 --- /dev/null +++ b/src/test/run-pass/issue-16819.rs @@ -0,0 +1,22 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//`#[cfg]` on struct field permits empty unusable struct + +#![feature(braced_empty_structs)] + +struct S { + #[cfg(untrue)] + a: int, +} + +fn main() { + let s = S {}; +} diff --git a/src/test/run-pass/issue-17336.rs b/src/test/run-pass/issue-17336.rs new file mode 100644 index 0000000000..ce04237081 --- /dev/null +++ b/src/test/run-pass/issue-17336.rs @@ -0,0 +1,17 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[allow(dead_code)] +fn check(a: &str) { + let x = a as *const str; + x == x; +} + +fn main() {} diff --git a/src/test/run-pass/issue-21410.rs b/src/test/run-pass/issue-21410.rs new file mode 100644 index 0000000000..bc525ba54c --- /dev/null +++ b/src/test/run-pass/issue-21410.rs @@ -0,0 +1,15 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn g(_: F) where F: FnOnce(Option) {} + +fn main() { + g(|_| { }); +} diff --git a/src/test/run-pass/issue-21922.rs b/src/test/run-pass/issue-21922.rs new file mode 100644 index 0000000000..2f538b365e --- /dev/null +++ b/src/test/run-pass/issue-21922.rs @@ -0,0 +1,26 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::ops::Add; +fn show(z: i32) { + println!("{}", z) +} +fn main() { + let x = 23; + let y = 42; + show(Add::add( x, y)); + show(Add::add( x, &y)); + show(Add::add(&x, y)); + show(Add::add(&x, &y)); + show( x + y); + show( x + &y); + show(&x + y); + show(&x + &y); +} diff --git a/src/test/run-pass/issue-22403.rs b/src/test/run-pass/issue-22403.rs new file mode 100644 index 0000000000..7bd66e5a83 --- /dev/null +++ b/src/test/run-pass/issue-22403.rs @@ -0,0 +1,15 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let x = Box::new([1, 2, 3]); + let y = x as Box<[i32]>; + println!("y: {:?}", y); +} diff --git a/src/test/run-pass/issue-22781.rs b/src/test/run-pass/issue-22781.rs new file mode 100644 index 0000000000..1aa32f2014 --- /dev/null +++ b/src/test/run-pass/issue-22781.rs @@ -0,0 +1,23 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::collections::HashMap; +use std::collections::hash_map::Entry::Vacant; + +pub fn foo() { + type F = Box; + let mut map: HashMap<(), F> = HashMap::new(); + let x: &mut F = match map.entry(()) { + Vacant(_) => unimplemented!(), + _ => unimplemented!() + }; +} + +fn main() {} diff --git a/src/test/run-pass/issue-22814.rs b/src/test/run-pass/issue-22814.rs new file mode 100644 index 0000000000..6afcd77074 --- /dev/null +++ b/src/test/run-pass/issue-22814.rs @@ -0,0 +1,22 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Test {} + +macro_rules! test { +( $($name:ident)+) => ( + impl<$($name: Test),*> Test for ($($name,)*) { + } +) +} + +test!(A B C); + +fn main() {} diff --git a/src/test/run-pass/issue-23036.rs b/src/test/run-pass/issue-23036.rs new file mode 100644 index 0000000000..0ed4126e6c --- /dev/null +++ b/src/test/run-pass/issue-23036.rs @@ -0,0 +1,18 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::collections::HashMap; +use std::path::Path; + +fn main() { + let mut map = HashMap::new(); + map.insert(Path::new("a"), 0); + map.get(Path::new("a")); +} diff --git a/src/test/run-pass/issue-23891.rs b/src/test/run-pass/issue-23891.rs new file mode 100644 index 0000000000..55536de912 --- /dev/null +++ b/src/test/run-pass/issue-23891.rs @@ -0,0 +1,20 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +macro_rules! id { + ($s: pat) => ($s); +} + +fn main() { + match (Some(123), Some(456)) { + (id!(Some(a)), _) | (_, id!(Some(a))) => println!("{}", a), + _ => (), + } +} diff --git a/src/test/run-pass/issue-24085.rs b/src/test/run-pass/issue-24085.rs index 3617b0d3a5..fde32cb902 100644 --- a/src/test/run-pass/issue-24085.rs +++ b/src/test/run-pass/issue-24085.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Regression test for #24085. Errors were occuring in region +// Regression test for #24085. Errors were occurring in region // inference due to the requirement that `'a:b'`, which was getting // incorrectly translated in connection with the closure below. diff --git a/src/test/run-pass/issue-24389.rs b/src/test/run-pass/issue-24389.rs new file mode 100644 index 0000000000..41599fa3e6 --- /dev/null +++ b/src/test/run-pass/issue-24389.rs @@ -0,0 +1,20 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(dead_code)] + +struct Foo; + +impl Foo { + fn new() -> Self { Foo } + fn bar() { Self::new(); } +} + +fn main() {} diff --git a/src/test/run-pass/issue-24533.rs b/src/test/run-pass/issue-24533.rs new file mode 100644 index 0000000000..440a418478 --- /dev/null +++ b/src/test/run-pass/issue-24533.rs @@ -0,0 +1,32 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::slice::Iter; +use std::io::{Error, ErrorKind, Result}; +use std::vec::*; + +fn foo(it: &mut Iter) -> Result { + Ok(*it.next().unwrap()) +} + +fn bar() -> Result { + let data: Vec = Vec::new(); + + if true { + return Err(Error::new(ErrorKind::NotFound, "msg")); + } + + let mut it = data.iter(); + foo(&mut it) +} + +fn main() { + bar(); +} diff --git a/src/test/run-pass/issue-24805-dropck-itemless.rs b/src/test/run-pass/issue-24805-dropck-itemless.rs index 4512bcc200..9fa4820229 100644 --- a/src/test/run-pass/issue-24805-dropck-itemless.rs +++ b/src/test/run-pass/issue-24805-dropck-itemless.rs @@ -13,6 +13,8 @@ #![allow(non_camel_case_types)] +#![feature(dropck_parametricity)] + trait UserDefined { } impl UserDefined for i32 { } @@ -26,7 +28,10 @@ impl<'a, T> UserDefined for &'a T { } macro_rules! impl_drop { ($Bound:ident, $Id:ident) => { struct $Id(T); - impl Drop for $Id { fn drop(&mut self) { } } + impl Drop for $Id { + #[unsafe_destructor_blind_to_params] + fn drop(&mut self) { } + } } } diff --git a/src/test/run-pass/issue-24956.rs b/src/test/run-pass/issue-24956.rs new file mode 100644 index 0000000000..501b713d52 --- /dev/null +++ b/src/test/run-pass/issue-24956.rs @@ -0,0 +1,20 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Foo(bool); +const NEW_FALSE: bool = false; +const STATIC_FOO: Foo = Foo(NEW_FALSE); + +pub fn main() { + match (Foo(false)) { + STATIC_FOO => 3, + _ => 11 + }; +} diff --git a/src/test/run-pass/issue-24972.rs b/src/test/run-pass/issue-24972.rs new file mode 100644 index 0000000000..ae7eb84d3e --- /dev/null +++ b/src/test/run-pass/issue-24972.rs @@ -0,0 +1,36 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(rustc_private)] + +extern crate serialize; + +use serialize::{Encodable, Decodable}; +use std::fmt::Display; + +pub trait Entity : Decodable + Encodable + Sized { + type Key: Clone + Decodable + Encodable + ToString + Display + Eq + Ord + Sized; + + fn id(&self) -> Self::Key; + + fn find_by_id(id: Self::Key) -> Option; +} + +pub struct DbRef { + pub id: E::Key, +} + +impl DbRef where E: Entity { + fn get(self) -> Option { + E::find_by_id(self.id) + } +} + +fn main() {} diff --git a/src/test/run-pass/issue-25439.rs b/src/test/run-pass/issue-25439.rs new file mode 100644 index 0000000000..88c48f42c5 --- /dev/null +++ b/src/test/run-pass/issue-25439.rs @@ -0,0 +1,19 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Helper<'a, F: 'a>(&'a F); + +fn fix(f: F) -> i32 where F: Fn(Helper, i32) -> i32 { + f(Helper(&f), 8) +} + +fn main() { + fix(|_, x| x); +} diff --git a/src/test/run-pass/issue-25693.rs b/src/test/run-pass/issue-25693.rs new file mode 100644 index 0000000000..aee89befda --- /dev/null +++ b/src/test/run-pass/issue-25693.rs @@ -0,0 +1,30 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub trait Paramters { type SelfRef; } + +struct RP<'a> { _marker: std::marker::PhantomData<&'a ()> } +struct BP; + +impl<'a> Paramters for RP<'a> { type SelfRef = &'a X>; } +impl Paramters for BP { type SelfRef = Box>; } + +pub struct Y; +pub enum X { + Nothing, + SameAgain(P::SelfRef, Y) +} + +fn main() { + let bnil: Box> = Box::new(X::Nothing); + let bx: Box> = Box::new(X::SameAgain(bnil, Y)); + let rnil: X = X::Nothing; + let rx: X = X::SameAgain(&rnil, Y); +} diff --git a/src/test/run-pass/issue-26095.rs b/src/test/run-pass/issue-26095.rs new file mode 100644 index 0000000000..f34685c693 --- /dev/null +++ b/src/test/run-pass/issue-26095.rs @@ -0,0 +1,30 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(associated_consts)] + +trait HasNumber { + const Number: usize; +} + +enum One {} +enum Two {} + +enum Foo {} + +impl HasNumber for One { + const Number: usize = 1; +} + +impl HasNumber for Two { + const Number: usize = 2; +} + +fn main() {} diff --git a/src/test/run-pass/issue-26905.rs b/src/test/run-pass/issue-26905.rs new file mode 100644 index 0000000000..0ad193bb28 --- /dev/null +++ b/src/test/run-pass/issue-26905.rs @@ -0,0 +1,31 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(unsize, coerce_unsized)] + +// Verfies that PhantomData is ignored for DST coercions + +use std::marker::{Unsize, PhantomData}; +use std::ops::CoerceUnsized; + +struct MyRc { + _ptr: *const T, + _boo: PhantomData, +} + +impl, U: ?Sized> CoerceUnsized> for MyRc{ } + +fn main() { + let data = [1, 2, 3]; + let iter = data.iter(); + let x = MyRc { _ptr: &iter, _boo: PhantomData }; + let _y: MyRc> = x; +} + diff --git a/src/test/run-pass/issue-27105.rs b/src/test/run-pass/issue-27105.rs new file mode 100644 index 0000000000..3836ad089a --- /dev/null +++ b/src/test/run-pass/issue-27105.rs @@ -0,0 +1,24 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::cell::RefCell; +use std::rc::Rc; + +pub struct Callbacks { + callbacks: Vec>>, +} + +impl Callbacks { + pub fn register(&mut self, callback: F) { + self.callbacks.push(Rc::new(RefCell::new(callback))); + } +} + +fn main() {} diff --git a/src/test/run-pass/issue-27320.rs b/src/test/run-pass/issue-27320.rs new file mode 100644 index 0000000000..dde1d3bfe9 --- /dev/null +++ b/src/test/run-pass/issue-27320.rs @@ -0,0 +1,21 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +macro_rules! piece( + ($piece:pat) => ($piece); +); + +enum Piece {A, B} + +fn main() { + match Piece::A { + piece!(pt@ Piece::A) | piece!(pt@ Piece::B) => {} + } +} diff --git a/src/test/run-pass/issue-28189.rs b/src/test/run-pass/issue-28189.rs new file mode 100644 index 0000000000..0e624a7785 --- /dev/null +++ b/src/test/run-pass/issue-28189.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. + +struct S(T) where [T; (||{}, 1).1]: Copy; + +fn main() { + +} diff --git a/src/test/run-pass/issue-28279.rs b/src/test/run-pass/issue-28279.rs new file mode 100644 index 0000000000..ae40ce44d1 --- /dev/null +++ b/src/test/run-pass/issue-28279.rs @@ -0,0 +1,30 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::rc::Rc; + +fn test1() -> Rc Fn(&'a usize) + 'static> { + if let Some(_) = Some(1) { + loop{} + } else { + loop{} + } +} + +fn test2() -> *mut for<'a> Fn(&'a usize) + 'static { + if let Some(_) = Some(1) { + loop{} + } else { + loop{} + } +} + +fn main() {} + diff --git a/src/test/run-pass/issue-28561.rs b/src/test/run-pass/issue-28561.rs new file mode 100644 index 0000000000..8c73830f4d --- /dev/null +++ b/src/test/run-pass/issue-28561.rs @@ -0,0 +1,120 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[derive(Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +struct Array { + f00: [T; 00], + f01: [T; 01], + f02: [T; 02], + f03: [T; 03], + f04: [T; 04], + f05: [T; 05], + f06: [T; 06], + f07: [T; 07], + f08: [T; 08], + f09: [T; 09], + f10: [T; 10], + f11: [T; 11], + f12: [T; 12], + f13: [T; 13], + f14: [T; 14], + f15: [T; 15], + f16: [T; 16], + f17: [T; 17], + f18: [T; 18], + f19: [T; 19], + f20: [T; 20], + f21: [T; 21], + f22: [T; 22], + f23: [T; 23], + f24: [T; 24], + f25: [T; 25], + f26: [T; 26], + f27: [T; 27], + f28: [T; 28], + f29: [T; 29], + f30: [T; 30], + f31: [T; 31], + f32: [T; 32], +} + +// FIXME(#7622): merge with `Array` once `[T; N]: Clone` where `T: Clone` +#[derive(Clone, Copy)] +struct CopyArray { + f00: [T; 00], + f01: [T; 01], + f02: [T; 02], + f03: [T; 03], + f04: [T; 04], + f05: [T; 05], + f06: [T; 06], + f07: [T; 07], + f08: [T; 08], + f09: [T; 09], + f10: [T; 10], + f11: [T; 11], + f12: [T; 12], + f13: [T; 13], + f14: [T; 14], + f15: [T; 15], + f16: [T; 16], + f17: [T; 17], + f18: [T; 18], + f19: [T; 19], + f20: [T; 20], + f21: [T; 21], + f22: [T; 22], + f23: [T; 23], + f24: [T; 24], + f25: [T; 25], + f26: [T; 26], + f27: [T; 27], + f28: [T; 28], + f29: [T; 29], + f30: [T; 30], + f31: [T; 31], + f32: [T; 32], +} + +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +struct Fn { + f00: fn(), + f01: fn(A), + f02: fn(A, B), + f03: fn(A, B, C), + f04: fn(A, B, C, D), + f05: fn(A, B, C, D, E), + f06: fn(A, B, C, D, E, F), + f07: fn(A, B, C, D, E, F, G), + f08: fn(A, B, C, D, E, F, G, H), + f09: fn(A, B, C, D, E, F, G, H, I), + f10: fn(A, B, C, D, E, F, G, H, I, J), + f11: fn(A, B, C, D, E, F, G, H, I, J, K), + f12: fn(A, B, C, D, E, F, G, H, I, J, K, L), +} + +#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +struct Tuple { + f00: (), + f01: (A), + f02: (A, B), + f03: (A, B, C), + f04: (A, B, C, D), + f05: (A, B, C, D, E), + f06: (A, B, C, D, E, F), + f07: (A, B, C, D, E, F, G), + f08: (A, B, C, D, E, F, G, H), + f09: (A, B, C, D, E, F, G, H, I), + f10: (A, B, C, D, E, F, G, H, I, J), + f11: (A, B, C, D, E, F, G, H, I, J, K), + f12: (A, B, C, D, E, F, G, H, I, J, K, L), +} + +fn main() {} diff --git a/src/test/run-pass/issue-28676.rs b/src/test/run-pass/issue-28676.rs new file mode 100644 index 0000000000..b8d43c392d --- /dev/null +++ b/src/test/run-pass/issue-28676.rs @@ -0,0 +1,40 @@ +// 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. +// + +#[derive(Copy, Clone)] +pub struct Quad { a: u64, b: u64, c: u64, d: u64 } + +mod rustrt { + use super::Quad; + + #[link(name = "rust_test_helpers")] + extern { + pub fn get_c_many_params(_: *const (), _: *const (), + _: *const (), _: *const (), f: Quad) -> u64; + } +} + +fn test() { + unsafe { + let null = std::ptr::null(); + let q = Quad { + a: 1, + b: 2, + c: 3, + d: 4 + }; + assert_eq!(rustrt::get_c_many_params(null, null, null, null, q), q.c); + } +} + +pub fn main() { + test(); +} diff --git a/src/test/run-make/issue-12446/foo.rs b/src/test/run-pass/issue-28822.rs similarity index 81% rename from src/test/run-make/issue-12446/foo.rs rename to src/test/run-pass/issue-28822.rs index 11c61169de..5a010f2be7 100644 --- a/src/test/run-make/issue-12446/foo.rs +++ b/src/test/run-pass/issue-28822.rs @@ -8,12 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![crate_type = "rlib"] +#![feature(const_fn)] -extern { - fn some_c_symbol(); -} +fn main() {} -pub fn foo() { - unsafe { some_c_symbol() } -} +const fn size_ofs(_: usize) {} +const fn size_ofs2(_foo: usize) {} diff --git a/src/test/run-pass/issue-28839.rs b/src/test/run-pass/issue-28839.rs new file mode 100644 index 0000000000..a101229662 --- /dev/null +++ b/src/test/run-pass/issue-28839.rs @@ -0,0 +1,24 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-pretty : (#23623) problems with newlines before // comments + +pub struct Foo; + +pub fn get_foo2<'a>(foo: &'a mut Option<&'a mut Foo>) -> &'a mut Foo { + match foo { + // Ensure that this is not considered a move, but rather a reborrow. + &mut Some(ref mut x) => *x, + &mut None => panic!(), + } +} + +fn main() { +} diff --git a/src/test/run-pass/issue-28936.rs b/src/test/run-pass/issue-28936.rs new file mode 100644 index 0000000000..2a932cd775 --- /dev/null +++ b/src/test/run-pass/issue-28936.rs @@ -0,0 +1,36 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub type Session = i32; +pub struct StreamParser<'a, T> { + _tokens: T, + _session: &'a mut Session, +} + +impl<'a, T> StreamParser<'a, T> { + pub fn thing(&mut self) -> bool { true } +} + +pub fn parse_stream, U, F>( + _session: &mut Session, _tokens: T, _f: F) -> U + where F: Fn(&mut StreamParser) -> U { panic!(); } + +pub fn thing(session: &mut Session) { + let mut stream = vec!(1, 2, 3).into_iter(); + + let _b = parse_stream(session, + stream.by_ref(), + // replacing the above with the following fixes it + //&mut stream, + |p| p.thing()); + +} + +fn main() {} diff --git a/src/test/run-pass/issue-28983.rs b/src/test/run-pass/issue-28983.rs new file mode 100644 index 0000000000..658e9e14ee --- /dev/null +++ b/src/test/run-pass/issue-28983.rs @@ -0,0 +1,31 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Test { type T; } + +impl Test for u32 { + type T = i32; +} + +pub mod export { + #[no_mangle] + pub extern "C" fn issue_28983(t: ::T) -> i32 { t*3 } +} + +// to test both exporting and importing functions, import +// a function from ourselves. +extern "C" { + fn issue_28983(t: ::T) -> i32; +} + +fn main() { + assert_eq!(export::issue_28983(2), 6); + assert_eq!(unsafe { issue_28983(3) }, 9); +} diff --git a/src/test/run-pass/issue-28999.rs b/src/test/run-pass/issue-28999.rs new file mode 100644 index 0000000000..87112ef171 --- /dev/null +++ b/src/test/run-pass/issue-28999.rs @@ -0,0 +1,20 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub struct Xyz<'a, V> { + pub v: (V, &'a u32), +} + +pub fn eq<'a, 's, 't, V>(this: &'s Xyz<'a, V>, other: &'t Xyz<'a, V>) -> bool + where V: PartialEq { + this.v == other.v +} + +fn main() {} diff --git a/src/test/run-pass/issue-29037.rs b/src/test/run-pass/issue-29037.rs new file mode 100644 index 0000000000..dc1d67cc64 --- /dev/null +++ b/src/test/run-pass/issue-29037.rs @@ -0,0 +1,32 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This test ensures that each pointer type `P` is covariant in `X`. + +use std::rc::Rc; +use std::sync::Arc; + +fn a<'r>(x: Box<&'static str>) -> Box<&'r str> { + x +} + +fn b<'r, 'w>(x: &'w &'static str) -> &'w &'r str { + x +} + +fn c<'r>(x: Arc<&'static str>) -> Arc<&'r str> { + x +} + +fn d<'r>(x: Rc<&'static str>) -> Rc<&'r str> { + x +} + +fn main() {} diff --git a/src/test/parse-fail/struct-variant-no-fields.rs b/src/test/run-pass/issue-29048.rs similarity index 66% rename from src/test/parse-fail/struct-variant-no-fields.rs rename to src/test/run-pass/issue-29048.rs index 68cf661e21..48f4327d3e 100644 --- a/src/test/parse-fail/struct-variant-no-fields.rs +++ b/src/test/run-pass/issue-29048.rs @@ -8,8 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only - -enum Foo { - Bar {} //~ ERROR unit-like struct variant should be written without braces, as `Bar,` +pub struct Chan; +pub struct ChanSelect<'c, T> { + chans: Vec<(&'c Chan, T)>, +} +impl<'c, T> ChanSelect<'c, T> { + pub fn add_recv_ret(&mut self, chan: &'c Chan, ret: T) + { + self.chans.push((chan, ret)); + } } +fn main() {} diff --git a/src/test/run-pass/issue-29166.rs b/src/test/run-pass/issue-29166.rs new file mode 100644 index 0000000000..193f977ff9 --- /dev/null +++ b/src/test/run-pass/issue-29166.rs @@ -0,0 +1,30 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This test ensures that vec.into_iter does not overconstrain element lifetime. + +pub fn main() { + original_report(); + revision_1(); + revision_2(); +} + +fn original_report() { + drop(vec![&()].into_iter()) +} + +fn revision_1() { + // below is what above `vec!` expands into at time of this writing. + drop(<[_]>::into_vec(::std::boxed::Box::new([&()])).into_iter()) +} + +fn revision_2() { + drop((match (Vec::new(), &()) { (mut v, b) => { v.push(b); v } }).into_iter()) +} diff --git a/src/test/run-pass/issue-2935.rs b/src/test/run-pass/issue-2935.rs index fd8e1e6b03..511344a792 100644 --- a/src/test/run-pass/issue-2935.rs +++ b/src/test/run-pass/issue-2935.rs @@ -28,7 +28,7 @@ pub fn main() { // let y = box ({a: 4}); // let z = box ({a: 4} as it); // let z = box ({a: true} as it); - let z: Box<_> = box () (box true as Box); + let z: Box<_> = box (box true as Box); // x.f(); // y.f(); // (*z).f(); diff --git a/src/test/run-pass/issue-29746.rs b/src/test/run-pass/issue-29746.rs new file mode 100644 index 0000000000..61c601ac6a --- /dev/null +++ b/src/test/run-pass/issue-29746.rs @@ -0,0 +1,45 @@ +// 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. + +// zip!(a1,a2,a3,a4) is equivalent to: +// a1.zip(a2).zip(a3).zip(a4).map(|(((x1,x2),x3),x4)| (x1,x2,x3,x4)) +macro_rules! zip { + // Entry point + ([$a:expr, $b:expr, $($rest:expr),*]) => { + zip!([$($rest),*], $a.zip($b), (x,y), [x,y]) + }; + + // Intermediate steps to build the zipped expression, the match pattern, and + // and the output tuple of the closure, using macro hygene to repeatedly + // introduce new variables named 'x'. + ([$a:expr, $($rest:expr),*], $zip:expr, $pat:pat, [$($flat:expr),*]) => { + zip!([$($rest),*], $zip.zip($a), ($pat,x), [$($flat),*, x]) + }; + + // Final step + ([], $zip:expr, $pat:pat, [$($flat:expr),+]) => { + $zip.map(|$pat| ($($flat),+)) + }; + + // Comma + ([$a:expr], $zip:expr, $pat:pat, [$($flat:expr),*]) => { + zip!([$a,], $zip, $pat, [$($flat),*]) + }; +} + +fn main() { + let p1 = vec![1i32, 2].into_iter(); + let p2 = vec!["10", "20"].into_iter(); + let p3 = vec![100u16, 200].into_iter(); + let p4 = vec![1000i64, 2000].into_iter(); + + let e = zip!([p1,p2,p3,p4]).collect::>(); + assert_eq!(e[0], (1i32,"10",100u16,1000i64)); +} diff --git a/src/test/parse-fail/parenthesized-box-expr-message.rs b/src/test/run-pass/issue-30081.rs similarity index 54% rename from src/test/parse-fail/parenthesized-box-expr-message.rs rename to src/test/run-pass/issue-30081.rs index 3cf3685d5b..13e9daa788 100644 --- a/src/test/parse-fail/parenthesized-box-expr-message.rs +++ b/src/test/run-pass/issue-30081.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,12 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// This used to segfault #30081 + +pub enum Instruction { + Increment(i8), + Loop(Box>), +} fn main() { - box (1 + 1) - //~^ HELP try using `box ()` instead: - //~| SUGGESTION box () (1 + 1) - //~| WARN deprecated syntax - ; //~ ERROR expected expression, found `;` + let instrs: Option<(u8, Box)> = None; + instrs.into_iter() + .map(|(_, instr)| instr) + .map(|instr| match *instr { _other => {} }) + .last(); } diff --git a/src/test/run-pass/issue-5060.rs b/src/test/run-pass/issue-5060.rs index 5726f236e2..21e3343f44 100644 --- a/src/test/run-pass/issue-5060.rs +++ b/src/test/run-pass/issue-5060.rs @@ -16,8 +16,7 @@ macro_rules! print_hd_tl { print!("{}", stringify!($field_tl)); print!(", "); )+ - // FIXME: #9970 - print!("{}", "]\n"); + print!("]\n"); }) } diff --git a/src/test/run-pass/issue28498-must-work-ex1.rs b/src/test/run-pass/issue28498-must-work-ex1.rs new file mode 100644 index 0000000000..83a978d57b --- /dev/null +++ b/src/test/run-pass/issue28498-must-work-ex1.rs @@ -0,0 +1,27 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Example taken from RFC 1238 text + +// https://github.com/rust-lang/rfcs/blob/master/text/1238-nonparametric-dropck.md +// #examples-of-code-that-must-continue-to-work + +use std::cell::Cell; + +struct Concrete<'a>(u32, Cell>>); + +fn main() { + let mut data = Vec::new(); + data.push(Concrete(0, Cell::new(None))); + data.push(Concrete(0, Cell::new(None))); + + data[0].1.set(Some(&data[1])); + data[1].1.set(Some(&data[0])); +} diff --git a/src/test/run-pass/issue28498-must-work-ex2.rs b/src/test/run-pass/issue28498-must-work-ex2.rs new file mode 100644 index 0000000000..93652a1b61 --- /dev/null +++ b/src/test/run-pass/issue28498-must-work-ex2.rs @@ -0,0 +1,30 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Example taken from RFC 1238 text + +// https://github.com/rust-lang/rfcs/blob/master/text/1238-nonparametric-dropck.md +// #examples-of-code-that-must-continue-to-work + +use std::cell::Cell; + +struct Concrete<'a>(u32, Cell>>); + +struct Foo { data: Vec } + +fn main() { + let mut foo = Foo { data: Vec::new() }; + foo.data.push(Concrete(0, Cell::new(None))); + foo.data.push(Concrete(0, Cell::new(None))); + + foo.data[0].1.set(Some(&foo.data[1])); + foo.data[1].1.set(Some(&foo.data[0])); +} + diff --git a/src/test/run-pass/issue28498-ugeh-ex1.rs b/src/test/run-pass/issue28498-ugeh-ex1.rs new file mode 100644 index 0000000000..b07831f552 --- /dev/null +++ b/src/test/run-pass/issue28498-ugeh-ex1.rs @@ -0,0 +1,37 @@ +// 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. + +// Example taken from RFC 1238 text + +// https://github.com/rust-lang/rfcs/blob/master/text/1238-nonparametric-dropck.md +// #example-of-the-unguarded-escape-hatch + +#![feature(dropck_parametricity)] +use std::cell::Cell; + +struct Concrete<'a>(u32, Cell>>); + +struct Foo { data: Vec } + +impl Drop for Foo { + // Below is the UGEH attribute + #[unsafe_destructor_blind_to_params] + fn drop(&mut self) { } +} + +fn main() { + let mut foo = Foo { data: Vec::new() }; + foo.data.push(Concrete(0, Cell::new(None))); + foo.data.push(Concrete(0, Cell::new(None))); + + foo.data[0].1.set(Some(&foo.data[1])); + foo.data[1].1.set(Some(&foo.data[0])); +} + diff --git a/src/test/run-pass/issue28498-ugeh-with-lifetime-param.rs b/src/test/run-pass/issue28498-ugeh-with-lifetime-param.rs new file mode 100644 index 0000000000..19be2568e4 --- /dev/null +++ b/src/test/run-pass/issue28498-ugeh-with-lifetime-param.rs @@ -0,0 +1,48 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Demonstrate the use of the unguarded escape hatch with a lifetime param +// to assert that destructor will not access any dead data. +// +// Compare with compile-fail/issue28498-reject-lifetime-param.rs + +#![feature(dropck_parametricity)] + +#[derive(Debug)] +struct ScribbleOnDrop(String); + +impl Drop for ScribbleOnDrop { + fn drop(&mut self) { + self.0 = format!("DROPPED"); + } +} + +struct Foo<'a>(u32, &'a ScribbleOnDrop); + +impl<'a> Drop for Foo<'a> { + #[unsafe_destructor_blind_to_params] + fn drop(&mut self) { + // Use of `unsafe_destructor_blind_to_params` is sound, + // because destructor never accesses `self.1`. + println!("Dropping Foo({}, _)", self.0); + } +} + +fn main() { + let (last_dropped, foo0); + let (foo1, first_dropped); + + last_dropped = ScribbleOnDrop(format!("last")); + first_dropped = ScribbleOnDrop(format!("first")); + foo0 = Foo(0, &last_dropped); + foo1 = Foo(1, &first_dropped); + + println!("foo0.1: {:?} foo1.1: {:?}", foo0.1, foo1.1); +} diff --git a/src/test/run-pass/issue28498-ugeh-with-passed-to-fn.rs b/src/test/run-pass/issue28498-ugeh-with-passed-to-fn.rs new file mode 100644 index 0000000000..bb430ea3e3 --- /dev/null +++ b/src/test/run-pass/issue28498-ugeh-with-passed-to-fn.rs @@ -0,0 +1,56 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Demonstrate the use of the unguarded escape hatch with a type param in negative position +// to assert that destructor will not access any dead data. +// +// Compare with compile-fail/issue28498-reject-lifetime-param.rs + +// Demonstrate that a type param in negative position causes dropck to reject code +// that might indirectly access previously dropped value. +// +// Compare with run-pass/issue28498-ugeh-with-passed-to-fn.rs + +#![feature(dropck_parametricity)] + +#[derive(Debug)] +struct ScribbleOnDrop(String); + +impl Drop for ScribbleOnDrop { + fn drop(&mut self) { + self.0 = format!("DROPPED"); + } +} + +struct Foo(u32, T, Box fn(&'r T) -> String>); + +impl Drop for Foo { + #[unsafe_destructor_blind_to_params] + fn drop(&mut self) { + // Use of `unsafe_destructor_blind_to_params` is sound, + // because destructor never passes a `self.1` to the callback + // (in `self.2`) despite having it available. + println!("Dropping Foo({}, _)", self.0); + } +} + +fn callback(s: & &ScribbleOnDrop) -> String { format!("{:?}", s) } + +fn main() { + let (last_dropped, foo0); + let (foo1, first_dropped); + + last_dropped = ScribbleOnDrop(format!("last")); + first_dropped = ScribbleOnDrop(format!("first")); + foo0 = Foo(0, &last_dropped, Box::new(callback)); + foo1 = Foo(1, &first_dropped, Box::new(callback)); + + println!("foo0.1: {:?} foo1.1: {:?}", foo0.1, foo1.1); +} diff --git a/src/test/run-pass/issue28498-ugeh-with-trait-bound.rs b/src/test/run-pass/issue28498-ugeh-with-trait-bound.rs new file mode 100644 index 0000000000..2e9633b3a2 --- /dev/null +++ b/src/test/run-pass/issue28498-ugeh-with-trait-bound.rs @@ -0,0 +1,51 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Demonstrate the use of the unguarded escape hatch with a trait bound +// to assert that destructor will not access any dead data. +// +// Compare with compile-fail/issue28498-reject-trait-bound.rs + +#![feature(dropck_parametricity)] + +use std::fmt; + +#[derive(Debug)] +struct ScribbleOnDrop(String); + +impl Drop for ScribbleOnDrop { + fn drop(&mut self) { + self.0 = format!("DROPPED"); + } +} + +struct Foo(u32, T); + +impl Drop for Foo { + #[unsafe_destructor_blind_to_params] + fn drop(&mut self) { + // Use of `unsafe_destructor_blind_to_params` is sound, + // because destructor never accesses the `Debug::fmt` method + // of `T`, despite having it available. + println!("Dropping Foo({}, _)", self.0); + } +} + +fn main() { + let (last_dropped, foo0); + let (foo1, first_dropped); + + last_dropped = ScribbleOnDrop(format!("last")); + first_dropped = ScribbleOnDrop(format!("first")); + foo0 = Foo(0, &last_dropped); + foo1 = Foo(1, &first_dropped); + + println!("foo0.1: {:?} foo1.1: {:?}", foo0.1, foo1.1); +} diff --git a/src/test/run-pass/lambda-var-hygiene.rs b/src/test/run-pass/lambda-var-hygiene.rs index e5bdca1a06..ae5bf71d15 100644 --- a/src/test/run-pass/lambda-var-hygiene.rs +++ b/src/test/run-pass/lambda-var-hygiene.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-test #9383 - // shouldn't affect evaluation of $ex: macro_rules! bad_macro { ($ex:expr) => ({(|_x| { $ex }) (9) }) diff --git a/src/test/run-pass/new-box-syntax.rs b/src/test/run-pass/new-box-syntax.rs index da57e8682c..34687c6ca1 100644 --- a/src/test/run-pass/new-box-syntax.rs +++ b/src/test/run-pass/new-box-syntax.rs @@ -31,10 +31,10 @@ struct Structure { } pub fn main() { - let x: Box = box(HEAP) 2; + let x: Box = in HEAP { 2 }; let y: Box = box 2; - let b: Box = box()(1 + 2); - let c = box()(3 + 4); + let b: Box = box (1 + 2); + let c = box (3 + 4); let s: Box = box Structure { x: 3, diff --git a/src/test/run-pass/pushpop-unsafe-okay.rs b/src/test/run-pass/pushpop-unsafe-okay.rs deleted file mode 100644 index fc402d4136..0000000000 --- a/src/test/run-pass/pushpop-unsafe-okay.rs +++ /dev/null @@ -1,56 +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. - -// Basic sanity check for `push_unsafe!(EXPR)` and -// `pop_unsafe!(EXPR)`: we can call unsafe code when there are a -// positive number of pushes in the stack, or if we are within a -// normal `unsafe` block, but otherwise cannot. - -// ignore-pretty because the `push_unsafe!` and `pop_unsafe!` macros -// are not integrated with the pretty-printer. - -#![feature(pushpop_unsafe)] - -static mut X: i32 = 0; - -unsafe fn f() { X += 1; return; } -fn g() { unsafe { X += 1_000; } return; } - -fn check_reset_x(x: i32) -> bool { - #![allow(unused_parens)] // dont you judge my style choices! - unsafe { - let ret = (x == X); - X = 0; - ret - } -} - -fn main() { - // double-check test infrastructure - assert!(check_reset_x(0)); - unsafe { f(); } - assert!(check_reset_x(1)); - assert!(check_reset_x(0)); - { g(); } - assert!(check_reset_x(1000)); - assert!(check_reset_x(0)); - unsafe { f(); g(); g(); } - assert!(check_reset_x(2001)); - - push_unsafe!( { f(); pop_unsafe!( g() ) } ); - assert!(check_reset_x(1_001)); - push_unsafe!( { g(); pop_unsafe!( unsafe { f(); f(); } ) } ); - assert!(check_reset_x(1_002)); - - unsafe { push_unsafe!( { f(); pop_unsafe!( { f(); f(); } ) } ); } - assert!(check_reset_x(3)); - push_unsafe!( { f(); push_unsafe!( { pop_unsafe!( { f(); f(); f(); } ) } ); } ); - assert!(check_reset_x(4)); -} diff --git a/src/test/run-pass/regions-early-bound-trait-param.rs b/src/test/run-pass/regions-early-bound-trait-param.rs index 72a214f4c9..4ba04aa709 100644 --- a/src/test/run-pass/regions-early-bound-trait-param.rs +++ b/src/test/run-pass/regions-early-bound-trait-param.rs @@ -83,7 +83,7 @@ impl<'s> Trait<'s> for (isize,isize) { impl<'t> MakerTrait for Box+'static> { fn mk() -> Box+'static> { - let tup: Box<(isize, isize)> = box() (4,5); + let tup: Box<(isize, isize)> = box (4,5); tup as Box } } diff --git a/src/test/run-pass/sepcomp-cci.rs b/src/test/run-pass/sepcomp-cci.rs index a1c5ad113c..d3d3de0e2c 100644 --- a/src/test/run-pass/sepcomp-cci.rs +++ b/src/test/run-pass/sepcomp-cci.rs @@ -16,23 +16,23 @@ extern crate sepcomp_cci_lib; -use sepcomp_cci_lib::{cci_fn, CCI_STATIC}; +use sepcomp_cci_lib::{cci_fn, CCI_CONST}; fn call1() -> usize { - cci_fn() + CCI_STATIC + cci_fn() + CCI_CONST } mod a { - use sepcomp_cci_lib::{cci_fn, CCI_STATIC}; + use sepcomp_cci_lib::{cci_fn, CCI_CONST}; pub fn call2() -> usize { - cci_fn() + CCI_STATIC + cci_fn() + CCI_CONST } } mod b { - use sepcomp_cci_lib::{cci_fn, CCI_STATIC}; + use sepcomp_cci_lib::{cci_fn, CCI_CONST}; pub fn call3() -> usize { - cci_fn() + CCI_STATIC + cci_fn() + CCI_CONST } } diff --git a/src/test/run-pass/shift-near-oflo.rs b/src/test/run-pass/shift-near-oflo.rs index 4ff058f336..542e8de9e5 100644 --- a/src/test/run-pass/shift-near-oflo.rs +++ b/src/test/run-pass/shift-near-oflo.rs @@ -13,9 +13,6 @@ // Check that we do *not* overflow on a number of edge cases. // (compare with test/run-fail/overflowing-{lsh,rsh}*.rs) -// (Work around constant-evaluation) -fn id(x: T) -> T { x } - fn main() { test_left_shift(); test_right_shift(); @@ -26,34 +23,34 @@ fn test_left_shift() { macro_rules! tests { ($iN:ty, $uN:ty, $max_rhs:expr, $expect_i:expr, $expect_u:expr) => { { - let x = (1 as $iN) << id(0); + let x = (1 as $iN) << 0; assert_eq!(x, 1); - let x = (1 as $uN) << id(0); + let x = (1 as $uN) << 0; assert_eq!(x, 1); - let x = (1 as $iN) << id($max_rhs); + let x = (1 as $iN) << $max_rhs; assert_eq!(x, $expect_i); - let x = (1 as $uN) << id($max_rhs); + let x = (1 as $uN) << $max_rhs; assert_eq!(x, $expect_u); // high-order bits on LHS are silently discarded without panic. - let x = (3 as $iN) << id($max_rhs); + let x = (3 as $iN) << $max_rhs; assert_eq!(x, $expect_i); - let x = (3 as $uN) << id($max_rhs); + let x = (3 as $uN) << $max_rhs; assert_eq!(x, $expect_u); } } } - let x = 1_i8 << id(0); + let x = 1_i8 << 0; assert_eq!(x, 1); - let x = 1_u8 << id(0); + let x = 1_u8 << 0; assert_eq!(x, 1); - let x = 1_i8 << id(7); + let x = 1_i8 << 7; assert_eq!(x, std::i8::MIN); - let x = 1_u8 << id(7); + let x = 1_u8 << 7; assert_eq!(x, 0x80); // high-order bits on LHS are silently discarded without panic. - let x = 3_i8 << id(7); + let x = 3_i8 << 7; assert_eq!(x, std::i8::MIN); - let x = 3_u8 << id(7); + let x = 3_u8 << 7; assert_eq!(x, 0x80); // above is (approximately) expanded from: @@ -71,23 +68,23 @@ fn test_right_shift() { ($iN:ty, $uN:ty, $max_rhs:expr, $signbit_i:expr, $highbit_i:expr, $highbit_u:expr) => { { - let x = (1 as $iN) >> id(0); + let x = (1 as $iN) >> 0; assert_eq!(x, 1); - let x = (1 as $uN) >> id(0); + let x = (1 as $uN) >> 0; assert_eq!(x, 1); - let x = ($highbit_i) >> id($max_rhs-1); + let x = ($highbit_i) >> $max_rhs-1; assert_eq!(x, 1); - let x = ($highbit_u) >> id($max_rhs); + let x = ($highbit_u) >> $max_rhs; assert_eq!(x, 1); // sign-bit is carried by arithmetic right shift - let x = ($signbit_i) >> id($max_rhs); + let x = ($signbit_i) >> $max_rhs; assert_eq!(x, -1); // low-order bits on LHS are silently discarded without panic. - let x = ($highbit_i + 1) >> id($max_rhs-1); + let x = ($highbit_i + 1) >> $max_rhs-1; assert_eq!(x, 1); - let x = ($highbit_u + 1) >> id($max_rhs); + let x = ($highbit_u + 1) >> $max_rhs; assert_eq!(x, 1); - let x = ($signbit_i + 1) >> id($max_rhs); + let x = ($signbit_i + 1) >> $max_rhs; assert_eq!(x, -1); } } } diff --git a/src/test/run-pass/sync-send-iterators-in-libcollections.rs b/src/test/run-pass/sync-send-iterators-in-libcollections.rs index 8160fe56fd..7fa592105c 100644 --- a/src/test/run-pass/sync-send-iterators-in-libcollections.rs +++ b/src/test/run-pass/sync-send-iterators-in-libcollections.rs @@ -93,7 +93,8 @@ fn main() { } all_sync_send!(EnumSet::::new(), iter); - all_sync_send!(VecDeque::::new(), iter, iter_mut, drain, into_iter); + all_sync_send!(VecDeque::::new(), iter, iter_mut, into_iter); + is_sync_send!(VecDeque::::new(), drain(..)); all_sync_send!(Vec::::new(), into_iter); is_sync_send!(Vec::::new(), drain(..)); diff --git a/src/test/run-pass/trait-object-generics.rs b/src/test/run-pass/trait-object-generics.rs index 15a8a2e83e..33bee3ea06 100644 --- a/src/test/run-pass/trait-object-generics.rs +++ b/src/test/run-pass/trait-object-generics.rs @@ -49,6 +49,6 @@ impl Trait for () { } pub fn main() { - let a = box() () as Box>; + let a = box () as Box>; assert_eq!(a.method(Type::Constant((1, 2))), 0); } diff --git a/src/test/run-pass/unary-minus-suffix-inference.rs b/src/test/run-pass/unary-minus-suffix-inference.rs index 9d685e0263..fdb70fe248 100644 --- a/src/test/run-pass/unary-minus-suffix-inference.rs +++ b/src/test/run-pass/unary-minus-suffix-inference.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(negate_unsigned)] + pub fn main() { let a = 1; let a_neg: i8 = -a; diff --git a/src/test/run-pass/vec_cycle.rs b/src/test/run-pass/vec_cycle.rs index 65522bd95d..d5da8b35b6 100644 --- a/src/test/run-pass/vec_cycle.rs +++ b/src/test/run-pass/vec_cycle.rs @@ -10,7 +10,7 @@ use std::cell::Cell; -#[derive(Show)] +#[derive(Debug)] struct C<'a> { v: Vec>>>, } diff --git a/src/test/run-pass/vec_cycle_wrapped.rs b/src/test/run-pass/vec_cycle_wrapped.rs index f179df90b3..56480268a0 100644 --- a/src/test/run-pass/vec_cycle_wrapped.rs +++ b/src/test/run-pass/vec_cycle_wrapped.rs @@ -10,12 +10,12 @@ use std::cell::Cell; -#[derive(Show)] +#[derive(Debug)] struct Refs<'a> { v: Vec>>>, } -#[derive(Show)] +#[derive(Debug)] struct C<'a> { refs: Refs<'a>, } diff --git a/src/test/run-pass/wrapping-int-api.rs b/src/test/run-pass/wrapping-int-api.rs index 48eea12062..5470ad93e1 100644 --- a/src/test/run-pass/wrapping-int-api.rs +++ b/src/test/run-pass/wrapping-int-api.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(num_wrapping)] - // Test inherent wrapping_* methods for {i,u}{size,8,16,32,64}. use std::{i8, i16, i32, i64, isize}; diff --git a/src/test/run-pass/x86stdcall2.rs b/src/test/run-pass/x86stdcall2.rs index c9742b0645..f3bf5d9c68 100644 --- a/src/test/run-pass/x86stdcall2.rs +++ b/src/test/run-pass/x86stdcall2.rs @@ -10,7 +10,7 @@ #![feature(std_misc)] -pub type HANDLE = u32; +pub type HANDLE = usize; pub type DWORD = u32; pub type SIZE_T = u32; pub type LPVOID = usize; diff --git a/src/test/rustdoc/hidden-line.rs b/src/test/rustdoc/hidden-line.rs index af67f7e2c1..e05d51c2ba 100644 --- a/src/test/rustdoc/hidden-line.rs +++ b/src/test/rustdoc/hidden-line.rs @@ -12,8 +12,6 @@ /// retained. /// /// ```rust -/// mod to_make_deriving_work { // FIXME #4913 -/// /// # #[derive(PartialEq)] // invisible /// # struct Foo; // invisible /// @@ -24,8 +22,6 @@ /// let x = Bar(Foo); /// assert_eq!(x, x); // check that the derivings worked /// } -/// -/// } /// ``` pub fn foo() {} -- 2.39.5