]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #24865 - bluss:range-size, r=alexcrichton
authorbors <bors@rust-lang.org>
Wed, 29 Apr 2015 00:15:22 +0000 (00:15 +0000)
committerbors <bors@rust-lang.org>
Wed, 29 Apr 2015 00:15:22 +0000 (00:15 +0000)
core: Fix size_hint for signed integer `Range<T>` iterators

There was an overflow bug in .size_hint() for signed iterators, which
produced an hilariously incorrect size or an overflow panic.

Incorrect size is a serious bug since the iterators are marked
ExactSizeIterator. (And leads to abort() on (-1i8..127).collect() when
the collection tries to preallocate too much).

> (-1i8..127).size_hint()
(18446744073709551488, Some(18446744073709551488))

Bug found using quickcheck.

Fixes #24851

322 files changed:
configure
mk/cfg/aarch64-apple-ios.mk
mk/cfg/aarch64-linux-android.mk
mk/cfg/aarch64-unknown-linux-gnu.mk
mk/cfg/arm-linux-androideabi.mk
mk/cfg/arm-unknown-linux-gnueabi.mk
mk/cfg/arm-unknown-linux-gnueabihf.mk
mk/cfg/armv7-apple-ios.mk
mk/cfg/armv7s-apple-ios.mk
mk/cfg/i386-apple-ios.mk
mk/cfg/i686-apple-darwin.mk
mk/cfg/i686-pc-windows-gnu.mk
mk/cfg/i686-unknown-linux-gnu.mk
mk/cfg/mips-unknown-linux-gnu.mk
mk/cfg/mipsel-unknown-linux-gnu.mk
mk/cfg/powerpc-unknown-linux-gnu.mk
mk/cfg/x86_64-apple-darwin.mk
mk/cfg/x86_64-apple-ios.mk
mk/cfg/x86_64-pc-windows-gnu.mk
mk/cfg/x86_64-unknown-bitrig.mk
mk/cfg/x86_64-unknown-dragonfly.mk
mk/cfg/x86_64-unknown-freebsd.mk
mk/cfg/x86_64-unknown-linux-gnu.mk
mk/cfg/x86_64-unknown-linux-musl.mk [new file with mode: 0644]
mk/cfg/x86_64-unknown-openbsd.mk
mk/crates.mk
mk/main.mk
mk/prepare.mk
mk/rt.mk
mk/rustllvm.mk
mk/target.mk
mk/tests.mk
src/compiletest/header.rs
src/compiletest/runtest.rs
src/compiletest/util.rs
src/doc/grammar.md
src/doc/reference.md
src/doc/style/testing/unit.md
src/doc/trpl/README.md
src/doc/trpl/SUMMARY.md
src/doc/trpl/closures.md
src/doc/trpl/const-and-static.md
src/doc/trpl/deref-coercions.md
src/doc/trpl/documentation.md
src/doc/trpl/getting-started.md
src/doc/trpl/glossary.md
src/doc/trpl/hello-cargo.md
src/doc/trpl/method-syntax.md
src/doc/trpl/mutability.md
src/doc/trpl/operators-and-overloading.md
src/doc/trpl/primitive-types.md
src/doc/trpl/testing.md
src/doc/trpl/trait-objects.md
src/doc/trpl/traits.md
src/doc/trpl/ufcs.md
src/doc/trpl/variable-bindings.md
src/doc/trpl/vectors.md
src/grammar/parser-lalr.y
src/liballoc/heap.rs
src/libcollections/binary_heap.rs
src/libcollections/fmt.rs
src/libcollections/lib.rs
src/libcollections/linked_list.rs
src/libcollections/range.rs [new file with mode: 0644]
src/libcollections/string.rs
src/libcollections/vec.rs
src/libcollections/vec_deque.rs
src/libcollections/vec_map.rs
src/libcollectionstest/lib.rs
src/libcollectionstest/vec.rs
src/libcore/atomic.rs
src/libcore/cell.rs
src/libcore/convert.rs
src/libcore/iter.rs
src/libcore/slice.rs
src/libcoretest/num/mod.rs
src/libcoretest/slice.rs
src/liblibc/lib.rs
src/librand/chacha.rs
src/librand/distributions/exponential.rs
src/librand/distributions/gamma.rs
src/librand/isaac.rs
src/librand/reseeding.rs
src/librustc/lib.rs
src/librustc/metadata/csearch.rs
src/librustc/metadata/decoder.rs
src/librustc/metadata/encoder.rs
src/librustc/middle/astencode.rs
src/librustc/middle/cfg/construct.rs
src/librustc/middle/check_const.rs
src/librustc/middle/check_match.rs
src/librustc/middle/check_static_recursion.rs
src/librustc/middle/const_eval.rs
src/librustc/middle/dead.rs
src/librustc/middle/def.rs
src/librustc/middle/expr_use_visitor.rs
src/librustc/middle/free_region.rs [new file with mode: 0644]
src/librustc/middle/implicator.rs [new file with mode: 0644]
src/librustc/middle/infer/error_reporting.rs
src/librustc/middle/infer/mod.rs
src/librustc/middle/infer/region_inference/mod.rs
src/librustc/middle/mem_categorization.rs
src/librustc/middle/pat_util.rs
src/librustc/middle/reachable.rs
src/librustc/middle/region.rs
src/librustc/middle/traits/mod.rs
src/librustc/middle/traits/object_safety.rs
src/librustc/middle/traits/project.rs
src/librustc/middle/traits/util.rs
src/librustc/middle/ty.rs
src/librustc/session/config.rs
src/librustc/session/mod.rs
src/librustc/util/ppaux.rs
src/librustc_back/fs.rs
src/librustc_back/rpath.rs
src/librustc_back/target/aarch64_apple_ios.rs
src/librustc_back/target/aarch64_linux_android.rs
src/librustc_back/target/aarch64_unknown_linux_gnu.rs
src/librustc_back/target/arm_linux_androideabi.rs
src/librustc_back/target/arm_unknown_linux_gnueabi.rs
src/librustc_back/target/arm_unknown_linux_gnueabihf.rs
src/librustc_back/target/armv7_apple_ios.rs
src/librustc_back/target/armv7s_apple_ios.rs
src/librustc_back/target/i386_apple_ios.rs
src/librustc_back/target/i686_apple_darwin.rs
src/librustc_back/target/i686_pc_windows_gnu.rs
src/librustc_back/target/i686_unknown_dragonfly.rs
src/librustc_back/target/i686_unknown_linux_gnu.rs
src/librustc_back/target/linux_base.rs
src/librustc_back/target/mips_unknown_linux_gnu.rs
src/librustc_back/target/mipsel_unknown_linux_gnu.rs
src/librustc_back/target/mod.rs
src/librustc_back/target/powerpc_unknown_linux_gnu.rs
src/librustc_back/target/x86_64_apple_darwin.rs
src/librustc_back/target/x86_64_apple_ios.rs
src/librustc_back/target/x86_64_pc_windows_gnu.rs
src/librustc_back/target/x86_64_unknown_bitrig.rs
src/librustc_back/target/x86_64_unknown_dragonfly.rs
src/librustc_back/target/x86_64_unknown_freebsd.rs
src/librustc_back/target/x86_64_unknown_linux_gnu.rs
src/librustc_back/target/x86_64_unknown_linux_musl.rs [new file with mode: 0644]
src/librustc_back/target/x86_64_unknown_openbsd.rs
src/librustc_borrowck/borrowck/mod.rs
src/librustc_data_structures/graph/mod.rs
src/librustc_data_structures/graph/test.rs [deleted file]
src/librustc_data_structures/graph/tests.rs [new file with mode: 0644]
src/librustc_data_structures/unify/mod.rs
src/librustc_data_structures/unify/test.rs [deleted file]
src/librustc_data_structures/unify/tests.rs [new file with mode: 0644]
src/librustc_driver/pretty.rs
src/librustc_driver/test.rs
src/librustc_lint/builtin.rs
src/librustc_privacy/lib.rs
src/librustc_resolve/build_reduced_graph.rs
src/librustc_resolve/lib.rs
src/librustc_trans/back/link.rs
src/librustc_trans/save/mod.rs
src/librustc_trans/trans/_match.rs
src/librustc_trans/trans/adt.rs
src/librustc_trans/trans/base.rs
src/librustc_trans/trans/callee.rs
src/librustc_trans/trans/cleanup.rs
src/librustc_trans/trans/consts.rs
src/librustc_trans/trans/context.rs
src/librustc_trans/trans/debuginfo.rs
src/librustc_trans/trans/glue.rs
src/librustc_trans/trans/inline.rs
src/librustc_trans/trans/meth.rs
src/librustc_trans/trans/monomorphize.rs
src/librustc_typeck/astconv.rs
src/librustc_typeck/check/_match.rs
src/librustc_typeck/check/compare_method.rs
src/librustc_typeck/check/dropck.rs
src/librustc_typeck/check/implicator.rs [deleted file]
src/librustc_typeck/check/method/confirm.rs
src/librustc_typeck/check/method/mod.rs
src/librustc_typeck/check/method/probe.rs
src/librustc_typeck/check/method/suggest.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/regionck.rs
src/librustc_typeck/coherence/mod.rs
src/librustc_typeck/collect.rs
src/librustc_typeck/diagnostics.rs
src/librustdoc/clean/inline.rs
src/librustdoc/clean/mod.rs
src/librustdoc/html/item_type.rs
src/librustdoc/html/render.rs
src/librustdoc/html/static/main.css
src/librustdoc/html/static/main.js
src/librustdoc/html/toc.rs
src/librustdoc/passes.rs
src/libstd/dynamic_lib.rs
src/libstd/io/stdio.rs
src/libstd/io/util.rs
src/libstd/panicking.rs
src/libstd/path.rs
src/libstd/rand/os.rs
src/libstd/rand/reader.rs
src/libstd/rt/backtrace.rs
src/libstd/rt/libunwind.rs
src/libstd/rtdeps.rs
src/libstd/sync/future.rs
src/libstd/sync/mpsc/mod.rs
src/libstd/sync/mpsc/select.rs
src/libstd/sync/mpsc/spsc_queue.rs
src/libstd/sync/mutex.rs
src/libstd/sync/once.rs
src/libstd/sys/common/net2.rs
src/libstd/sys/common/remutex.rs
src/libstd/sys/common/thread_info.rs
src/libstd/sys/unix/ext.rs
src/libstd/sys/unix/stack_overflow.rs
src/libstd/sys/unix/thread.rs
src/libstd/sys/unix/time.rs
src/libstd/sys/windows/ext.rs
src/libstd/sys/windows/process2.rs
src/libstd/thread/local.rs
src/libstd/thread/mod.rs
src/libsyntax/ast.rs
src/libsyntax/ast_map/blocks.rs
src/libsyntax/ast_map/mod.rs
src/libsyntax/ast_util.rs
src/libsyntax/codemap.rs
src/libsyntax/ext/expand.rs
src/libsyntax/ext/quote.rs
src/libsyntax/feature_gate.rs
src/libsyntax/fold.rs
src/libsyntax/parse/lexer/comments.rs
src/libsyntax/parse/lexer/mod.rs
src/libsyntax/parse/mod.rs
src/libsyntax/parse/parser.rs
src/libsyntax/parse/token.rs
src/libsyntax/print/pprust.rs
src/libsyntax/util/parser_testing.rs
src/libsyntax/util/small_vector.rs
src/libsyntax/visit.rs
src/libterm/terminfo/parm.rs
src/libterm/terminfo/parser/compiled.rs
src/rustbook/javascript.rs
src/test/auxiliary/associated-const-cc-lib.rs [new file with mode: 0644]
src/test/auxiliary/macro_crate_test.rs
src/test/bench/noise.rs
src/test/bench/shootout-reverse-complement.rs
src/test/compile-fail-fulldeps/macro-crate-cannot-read-embedded-ident.rs [deleted file]
src/test/compile-fail-fulldeps/qquote.rs [new file with mode: 0644]
src/test/compile-fail/associated-const-dead-code.rs [new file with mode: 0644]
src/test/compile-fail/associated-const-impl-wrong-type.rs [new file with mode: 0644]
src/test/compile-fail/associated-const-private-impl.rs [new file with mode: 0644]
src/test/compile-fail/associated-const-upper-case-lint.rs [new file with mode: 0644]
src/test/compile-fail/feature-gate-negate-unsigned.rs [new file with mode: 0644]
src/test/compile-fail/feature-gate-on-unimplemented.rs [new file with mode: 0644]
src/test/compile-fail/feature-gate-optin-builtin-traits.rs [new file with mode: 0644]
src/test/compile-fail/feature-gate-plugin.rs [new file with mode: 0644]
src/test/compile-fail/feature-gate-rustc-attrs.rs [new file with mode: 0644]
src/test/compile-fail/feature-gate-rustc-diagnostic-macros.rs [new file with mode: 0644]
src/test/compile-fail/feature-gate-slice-patterns.rs [new file with mode: 0644]
src/test/compile-fail/gated-associated_consts.rs [new file with mode: 0644]
src/test/compile-fail/gated-box-patterns.rs [deleted file]
src/test/compile-fail/gated-simd-ffi.rs [deleted file]
src/test/compile-fail/impl-wrong-item-for-trait.rs [new file with mode: 0644]
src/test/compile-fail/issue-20616-1.rs [new file with mode: 0644]
src/test/compile-fail/issue-20616-2.rs [new file with mode: 0644]
src/test/compile-fail/issue-20616-3.rs [new file with mode: 0644]
src/test/compile-fail/issue-20616-4.rs [new file with mode: 0644]
src/test/compile-fail/issue-20616-5.rs [new file with mode: 0644]
src/test/compile-fail/issue-20616-6.rs [new file with mode: 0644]
src/test/compile-fail/issue-20616-7.rs [new file with mode: 0644]
src/test/compile-fail/issue-20616-8.rs [new file with mode: 0644]
src/test/compile-fail/issue-20616-9.rs [new file with mode: 0644]
src/test/compile-fail/issue-22673.rs [new file with mode: 0644]
src/test/compile-fail/issue-22897.rs [new file with mode: 0644]
src/test/compile-fail/issue-23041.rs [new file with mode: 0644]
src/test/compile-fail/issue-23253.rs [new file with mode: 0644]
src/test/compile-fail/issue-23966.rs [new file with mode: 0644]
src/test/compile-fail/issue-24013.rs [new file with mode: 0644]
src/test/compile-fail/issue-24895-copy-clone-dropck.rs [new file with mode: 0644]
src/test/compile-fail/method-path-in-pattern.rs [new file with mode: 0644]
src/test/compile-fail/method-resolvable-path-in-pattern.rs [new file with mode: 0644]
src/test/compile-fail/region-bound-extra-bound-in-impl.rs [new file with mode: 0644]
src/test/compile-fail/region-bound-extra-bound-in-inherent-impl.rs [new file with mode: 0644]
src/test/compile-fail/region-bound-same-bounds-in-trait-and-impl.rs [new file with mode: 0644]
src/test/compile-fail/regions-bound-missing-bound-in-impl.rs
src/test/parse-fail/brace-after-qualified-path-in-match.rs [new file with mode: 0644]
src/test/parse-fail/issue-20711-2.rs
src/test/parse-fail/issue-20711.rs
src/test/parse-fail/issue-21153.rs
src/test/parse-fail/paren-after-qualified-path-in-match.rs [new file with mode: 0644]
src/test/parse-fail/qquote-1.rs [deleted file]
src/test/parse-fail/qquote-2.rs [deleted file]
src/test/parse-fail/removed-syntax-static-fn.rs
src/test/parse-fail/trait-pub-assoc-const.rs [new file with mode: 0644]
src/test/parse-fail/trait-pub-assoc-ty.rs
src/test/parse-fail/trait-pub-method.rs
src/test/run-fail-fulldeps/qquote.rs [new file with mode: 0644]
src/test/run-make/cannot-read-embedded-idents/Makefile [deleted file]
src/test/run-make/cannot-read-embedded-idents/create_and_compile.rs [deleted file]
src/test/run-pass-fulldeps/issue-13560.rs
src/test/run-pass-fulldeps/qquote.rs
src/test/run-pass/associated-const-cross-crate-defaults.rs [new file with mode: 0644]
src/test/run-pass/associated-const-cross-crate.rs [new file with mode: 0644]
src/test/run-pass/associated-const-in-global-const.rs [new file with mode: 0644]
src/test/run-pass/associated-const-inherent-impl.rs [new file with mode: 0644]
src/test/run-pass/associated-const-marks-live-code.rs [new file with mode: 0644]
src/test/run-pass/associated-const-match-patterns.rs [new file with mode: 0644]
src/test/run-pass/associated-const-overwrite-default.rs [new file with mode: 0644]
src/test/run-pass/associated-const-public-impl.rs [new file with mode: 0644]
src/test/run-pass/associated-const-resolution-order.rs [new file with mode: 0644]
src/test/run-pass/associated-const-self-type.rs [new file with mode: 0644]
src/test/run-pass/associated-const-ufcs-infer-trait.rs [new file with mode: 0644]
src/test/run-pass/associated-const-use-default.rs [new file with mode: 0644]
src/test/run-pass/associated-const-use-impl-of-same-trait.rs [new file with mode: 0644]
src/test/run-pass/associated-const.rs [new file with mode: 0644]
src/test/run-pass/issue-12133-3.rs
src/test/run-pass/issue-16597.rs
src/test/run-pass/issue-20616.rs [new file with mode: 0644]
src/test/run-pass/issue-23433.rs [new file with mode: 0644]
src/test/run-pass/issue-23611-enum-swap-in-drop.rs [new file with mode: 0644]
src/test/run-pass/issue-24313.rs [new file with mode: 0644]
src/test/run-pass/linkage-visibility.rs
src/test/run-pass/out-of-stack-new-thread-no-split.rs
src/test/run-pass/sepcomp-extern.rs
src/test/run-pass/sync-send-iterators-in-libcollections.rs

index fc8d57999ffde2415fb36319bcca40f0194cd1ad..f4e1d41276aa959cfd98e94f64a24ef0bc8c34db 100755 (executable)
--- a/configure
+++ b/configure
@@ -583,6 +583,7 @@ valopt jemalloc-root "" "set directory where libjemalloc_pic.a is located"
 valopt build "${DEFAULT_BUILD}" "GNUs ./configure syntax LLVM build triple"
 valopt android-cross-path "/opt/ndk_standalone" "Android NDK standalone path"
 valopt release-channel "dev" "the name of the release channel to build"
+valopt musl-root "/usr/local" "MUSL root installation directory"
 
 # Many of these are saved below during the "writing configuration" step
 # (others are conditionally saved).
@@ -659,9 +660,10 @@ if [ -n "$CFG_ENABLE_DEBUG" ]; then
         CFG_DISABLE_OPTIMIZE=1
         CFG_DISABLE_OPTIMIZE_CXX=1
     fi
-    CFG_ENABLE_LLVM_ASSERTIONS=1
     CFG_ENABLE_DEBUG_ASSERTIONS=1
     CFG_ENABLE_DEBUG_JEMALLOC=1
+    CFG_ENABLE_DEBUGINFO=1
+    CFG_ENABLE_LLVM_ASSERTIONS=1
 fi
 
 # OK, now write the debugging options
@@ -1057,6 +1059,13 @@ do
             fi
             ;;
 
+
+        *-musl)
+            if [ ! -f $CFG_MUSL_ROOT/lib/libc.a ]
+            then
+                err "musl libc $CFG_MUSL_ROOT/lib/libc.a not found"
+            fi
+            ;;
         *)
             ;;
     esac
@@ -1143,6 +1152,7 @@ do
     make_dir $h/test/run-pass-valgrind
     make_dir $h/test/run-pass-fulldeps
     make_dir $h/test/run-fail
+    make_dir $h/test/run-fail-fulldeps
     make_dir $h/test/compile-fail
     make_dir $h/test/parse-fail
     make_dir $h/test/compile-fail-fulldeps
index 0219ab960579bb81239b8df362a522c7e4615834..7767129a5e21821e60e477205e0ec446b15b3237 100644 (file)
@@ -20,16 +20,12 @@ CFG_GCCISH_CFLAGS_aarch64-apple-ios := -Wall -Werror -fPIC $(CFG_IOS_SDK_FLAGS_a
 CFG_GCCISH_CXXFLAGS_aarch64-apple-ios := -fno-rtti $(CFG_IOS_SDK_FLAGS_aarch64-apple-ios) -I$(CFG_IOS_SDK_aarch64-apple-ios)/usr/include/c++/4.2.1
 CFG_GCCISH_LINK_FLAGS_aarch64-apple-ios := -lpthread -syslibroot $(CFG_IOS_SDK_aarch64-apple-ios) -Wl,-no_compact_unwind
 CFG_GCCISH_DEF_FLAG_aarch64-apple-ios := -Wl,-exported_symbols_list,
-CFG_GCCISH_PRE_LIB_FLAGS_aarch64-apple-ios :=
-CFG_GCCISH_POST_LIB_FLAGS_aarch64-apple-ios :=
-CFG_DEF_SUFFIX_aarch64-apple-ios := .darwin.def
 CFG_LLC_FLAGS_aarch64-apple-ios := -mattr=+neon,+cyclone,+fp-armv8
 CFG_INSTALL_NAME_aarch64-apple-ios = -Wl,-install_name,@rpath/$(1)
 CFG_LIBUV_LINK_FLAGS_aarch64-apple-ios =
 CFG_EXE_SUFFIX_aarch64-apple-ios :=
 CFG_WINDOWSY_aarch64-apple-ios :=
 CFG_UNIXY_aarch64-apple-ios := 1
-CFG_PATH_MUNGE_aarch64-apple-ios := true
 CFG_LDPATH_aarch64-apple-ios :=
 CFG_RUN_aarch64-apple-ios = $(2)
 CFG_RUN_TARG_aarch64-apple-ios = $(call CFG_RUN_aarch64-apple-ios,,$(2))
index a6f7f2ba1d66eb592e98cf844ce1c6a856b9c390..d7a1405c3d0a87036bf199887ee3fea99f6c4497 100644 (file)
@@ -13,15 +13,11 @@ CFG_GCCISH_CFLAGS_aarch64-linux-android := -Wall -g -fPIC -D__aarch64__ -DANDROI
 CFG_GCCISH_CXXFLAGS_aarch64-linux-android := -fno-rtti $(CXXFLAGS)
 CFG_GCCISH_LINK_FLAGS_aarch64-linux-android := -shared -fPIC -ldl -g -lm -lsupc++
 CFG_GCCISH_DEF_FLAG_aarch64-linux-android := -Wl,--export-dynamic,--dynamic-list=
-CFG_GCCISH_PRE_LIB_FLAGS_aarch64-linux-android := -Wl,-whole-archive
-CFG_GCCISH_POST_LIB_FLAGS_aarch64-linux-android := -Wl,-no-whole-archive
-CFG_DEF_SUFFIX_aarch64-linux-android := .android.def
 CFG_LLC_FLAGS_aarch64-linux-android :=
 CFG_INSTALL_NAME_aarch64-linux-android =
 CFG_EXE_SUFFIX_aarch64-linux-android :=
 CFG_WINDOWSY_aarch64-linux-android :=
 CFG_UNIXY_aarch64-linux-android := 1
-CFG_PATH_MUNGE_aarch64-linux-android := true
 CFG_LDPATH_aarch64-linux-android :=
 CFG_RUN_aarch64-linux-android=
 CFG_RUN_TARG_aarch64-linux-android=
index fade026654960e764ecfb3fcceec880e197c7d52..6637423e4951a9826c7b3004d1c939a4713cad47 100644 (file)
@@ -13,15 +13,11 @@ CFG_GCCISH_CFLAGS_aarch64-unknown-linux-gnu := -Wall -g -fPIC -D__aarch64__ $(CF
 CFG_GCCISH_CXXFLAGS_aarch64-unknown-linux-gnu := -fno-rtti $(CXXFLAGS)
 CFG_GCCISH_LINK_FLAGS_aarch64-unknown-linux-gnu := -shared -fPIC -g
 CFG_GCCISH_DEF_FLAG_aarch64-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list=
-CFG_GCCISH_PRE_LIB_FLAGS_aarch64-unknown-linux-gnu := -Wl,-whole-archive
-CFG_GCCISH_POST_LIB_FLAGS_aarch64-unknown-linux-gnu := -Wl,-no-whole-archive
-CFG_DEF_SUFFIX_aarch64-unknown-linux-gnu := .linux.def
 CFG_LLC_FLAGS_aarch64-unknown-linux-gnu :=
 CFG_INSTALL_NAME_aarch64-unknown-linux-gnu =
 CFG_EXE_SUFFIX_aarch64-unknown-linux-gnu :=
 CFG_WINDOWSY_aarch64-unknown-linux-gnu :=
 CFG_UNIXY_aarch64-unknown-linux-gnu := 1
-CFG_PATH_MUNGE_aarch64-unknown-linux-gnu := true
 CFG_LDPATH_aarch64-unknown-linux-gnu :=
 CFG_RUN_aarch64-unknown-linux-gnu=$(2)
 CFG_RUN_TARG_aarch64-unknown-linux-gnu=$(call CFG_RUN_aarch64-unknown-linux-gnu,,$(2))
index 471220e2b6618ae08bb6726c0489b39ed3b5c358..fdd38ba75fe585e02d9491b2a154dcee786eec8b 100644 (file)
@@ -12,15 +12,11 @@ CFG_GCCISH_CFLAGS_arm-linux-androideabi := -Wall -g -fPIC -D__arm__ -DANDROID -D
 CFG_GCCISH_CXXFLAGS_arm-linux-androideabi := -fno-rtti $(CXXFLAGS)
 CFG_GCCISH_LINK_FLAGS_arm-linux-androideabi := -shared -fPIC -ldl -g -lm -lsupc++
 CFG_GCCISH_DEF_FLAG_arm-linux-androideabi := -Wl,--export-dynamic,--dynamic-list=
-CFG_GCCISH_PRE_LIB_FLAGS_arm-linux-androideabi := -Wl,-whole-archive
-CFG_GCCISH_POST_LIB_FLAGS_arm-linux-androideabi := -Wl,-no-whole-archive
-CFG_DEF_SUFFIX_arm-linux-androideabi := .android.def
 CFG_LLC_FLAGS_arm-linux-androideabi :=
 CFG_INSTALL_NAME_arm-linux-androideabi =
 CFG_EXE_SUFFIX_arm-linux-androideabi :=
 CFG_WINDOWSY_arm-linux-androideabi :=
 CFG_UNIXY_arm-linux-androideabi := 1
-CFG_PATH_MUNGE_arm-linux-androideabi := true
 CFG_LDPATH_arm-linux-androideabi :=
 CFG_RUN_arm-linux-androideabi=
 CFG_RUN_TARG_arm-linux-androideabi=
index b4c604b26bae04eda24ecf4b801c37fc55489e67..9a91097458e90fdd101dbafc0d51e777935b78ad 100644 (file)
@@ -13,15 +13,11 @@ CFG_GCCISH_CFLAGS_arm-unknown-linux-gnueabi := -Wall -g -fPIC -D__arm__ -mfpu=vf
 CFG_GCCISH_CXXFLAGS_arm-unknown-linux-gnueabi := -fno-rtti $(CXXFLAGS)
 CFG_GCCISH_LINK_FLAGS_arm-unknown-linux-gnueabi := -shared -fPIC -g
 CFG_GCCISH_DEF_FLAG_arm-unknown-linux-gnueabi := -Wl,--export-dynamic,--dynamic-list=
-CFG_GCCISH_PRE_LIB_FLAGS_arm-unknown-linux-gnueabi := -Wl,-whole-archive
-CFG_GCCISH_POST_LIB_FLAGS_arm-unknown-linux-gnueabi := -Wl,-no-whole-archive
-CFG_DEF_SUFFIX_arm-unknown-linux-gnueabi := .linux.def
 CFG_LLC_FLAGS_arm-unknown-linux-gnueabi :=
 CFG_INSTALL_NAME_arm-unknown-linux-gnueabi =
 CFG_EXE_SUFFIX_arm-unknown-linux-gnueabi :=
 CFG_WINDOWSY_arm-unknown-linux-gnueabi :=
 CFG_UNIXY_arm-unknown-linux-gnueabi := 1
-CFG_PATH_MUNGE_arm-unknown-linux-gnueabi := true
 CFG_LDPATH_arm-unknown-linux-gnueabi :=
 CFG_RUN_arm-unknown-linux-gnueabi=$(2)
 CFG_RUN_TARG_arm-unknown-linux-gnueabi=$(call CFG_RUN_arm-unknown-linux-gnueabi,,$(2))
index 4f02de0f6b5e67893d589ffea47831a22b6a3d38..0bd661ea00db22a8b2484b8f98da1bc97e993438 100644 (file)
@@ -13,15 +13,11 @@ CFG_GCCISH_CFLAGS_arm-unknown-linux-gnueabihf := -Wall -g -fPIC -D__arm__ $(CFLA
 CFG_GCCISH_CXXFLAGS_arm-unknown-linux-gnueabihf := -fno-rtti $(CXXFLAGS)
 CFG_GCCISH_LINK_FLAGS_arm-unknown-linux-gnueabihf := -shared -fPIC -g
 CFG_GCCISH_DEF_FLAG_arm-unknown-linux-gnueabihf := -Wl,--export-dynamic,--dynamic-list=
-CFG_GCCISH_PRE_LIB_FLAGS_arm-unknown-linux-gnueabihf := -Wl,-whole-archive
-CFG_GCCISH_POST_LIB_FLAGS_arm-unknown-linux-gnueabihf := -Wl,-no-whole-archive
-CFG_DEF_SUFFIX_arm-unknown-linux-gnueabihf := .linux.def
 CFG_LLC_FLAGS_arm-unknown-linux-gnueabihf :=
 CFG_INSTALL_NAME_ar,-unknown-linux-gnueabihf =
 CFG_EXE_SUFFIX_arm-unknown-linux-gnueabihf :=
 CFG_WINDOWSY_arm-unknown-linux-gnueabihf :=
 CFG_UNIXY_arm-unknown-linux-gnueabihf := 1
-CFG_PATH_MUNGE_arm-unknown-linux-gnueabihf := true
 CFG_LDPATH_arm-unknown-linux-gnueabihf :=
 CFG_RUN_arm-unknown-linux-gnueabihf=$(2)
 CFG_RUN_TARG_arm-unknown-linux-gnueabihf=$(call CFG_RUN_arm-unknown-linux-gnueabihf,,$(2))
index aee4e64addfc1834040be1717ca8379d63ea781f..d4696976574e94c52252701a8559f7ac0fbd6b62 100644 (file)
@@ -19,15 +19,11 @@ CFG_GCCISH_CFLAGS_armv7-apple-ios := -Wall -Werror -g -fPIC $(CFG_IOS_SDK_FLAGS_
 CFG_GCCISH_CXXFLAGS_armv7-apple-ios := -fno-rtti $(CFG_IOS_SDK_FLAGS_armv7-apple-ios) -I$(CFG_IOS_SDK_armv7-apple-ios)/usr/include/c++/4.2.1
 CFG_GCCISH_LINK_FLAGS_armv7-apple-ios := -lpthread -syslibroot $(CFG_IOS_SDK_armv7-apple-ios) -Wl,-no_compact_unwind
 CFG_GCCISH_DEF_FLAG_armv7-apple-ios := -Wl,-exported_symbols_list,
-CFG_GCCISH_PRE_LIB_FLAGS_armv7-apple-ios :=
-CFG_GCCISH_POST_LIB_FLAGS_armv7-apple-ios :=
-CFG_DEF_SUFFIX_armv7-apple-ios := .darwin.def
 CFG_LLC_FLAGS_armv7-apple-ios := -mattr=+vfp3,+v7,+neon -march=arm
 CFG_INSTALL_NAME_armv7-apple-ios = -Wl,-install_name,@rpath/$(1)
 CFG_EXE_SUFFIX_armv7-apple-ios :=
 CFG_WINDOWSY_armv7-apple-ios :=
 CFG_UNIXY_armv7-apple-ios := 1
-CFG_PATH_MUNGE_armv7-apple-ios := true
 CFG_LDPATH_armv7-apple-ios :=
 CFG_RUN_armv7-apple-ios = $(2)
 CFG_RUN_TARG_armv7-apple-ios = $(call CFG_RUN_armv7-apple-ios,,$(2))
index 7540bd44de878211e1b540e05465c8d1c23358e4..96ca07648949ff500c50b8bfac253527a1564658 100644 (file)
@@ -19,15 +19,11 @@ CFG_GCCISH_CFLAGS_armv7s-apple-ios := -Wall -Werror -g -fPIC $(CFG_IOS_SDK_FLAGS
 CFG_GCCISH_CXXFLAGS_armv7s-apple-ios := -fno-rtti $(CFG_IOS_SDK_FLAGS_armv7s-apple-ios) -I$(CFG_IOS_SDK_armv7s-apple-ios)/usr/include/c++/4.2.1
 CFG_GCCISH_LINK_FLAGS_armv7s-apple-ios := -lpthread -syslibroot $(CFG_IOS_SDK_armv7s-apple-ios) -Wl,-no_compact_unwind
 CFG_GCCISH_DEF_FLAG_armv7s-apple-ios := -Wl,-exported_symbols_list,
-CFG_GCCISH_PRE_LIB_FLAGS_armv7s-apple-ios :=
-CFG_GCCISH_POST_LIB_FLAGS_armv7s-apple-ios :=
-CFG_DEF_SUFFIX_armv7s-apple-ios := .darwin.def
 CFG_LLC_FLAGS_armv7s-apple-ios := -mattr=+vfp4,+v7,+neon
 CFG_INSTALL_NAME_armv7s-apple-ios = -Wl,-install_name,@rpath/$(1)
 CFG_EXE_SUFFIX_armv7s-apple-ios :=
 CFG_WINDOWSY_armv7s-apple-ios :=
 CFG_UNIXY_armv7s-apple-ios := 1
-CFG_PATH_MUNGE_armv7s-apple-ios := true
 CFG_LDPATH_armv7s-apple-ios :=
 CFG_RUN_armv7s-apple-ios = $(2)
 CFG_RUN_TARG_armv7s-apple-ios = $(call CFG_RUN_armv7s-apple-ios,,$(2))
index e84bf49d4079a39830b28f95f958e3caf1bc4c21..373e2e3b65d15e6d7e39e724ede7498f2a532bf0 100644 (file)
@@ -18,15 +18,11 @@ CFG_GCCISH_CFLAGS_i386-apple-ios := -Wall -Werror -g -fPIC -m32 $(CFG_IOSSIM_FLA
 CFG_GCCISH_CXXFLAGS_i386-apple-ios := -fno-rtti $(CFG_IOSSIM_FLAGS_i386-apple-ios) -I$(CFG_IOSSIM_SDK_i386-apple-ios)/usr/include/c++/4.2.1
 CFG_GCCISH_LINK_FLAGS_i386-apple-ios := -lpthread -m32 -Wl,-no_compact_unwind -m32 -Wl,-syslibroot $(CFG_IOSSIM_SDK_i386-apple-ios)
 CFG_GCCISH_DEF_FLAG_i386-apple-ios := -Wl,-exported_symbols_list,
-CFG_GCCISH_PRE_LIB_FLAGS_i386-apple-ios :=
-CFG_GCCISH_POST_LIB_FLAGS_i386-apple-ios :=
-CFG_DEF_SUFFIX_i386-apple-ios := .darwin.def
 CFG_LLC_FLAGS_i386-apple-ios =
 CFG_INSTALL_NAME_i386-apple-ios = -Wl,-install_name,@rpath/$(1)
 CFG_EXE_SUFFIX_i386-apple-ios :=
 CFG_WINDOWSY_i386-apple-ios :=
 CFG_UNIXY_i386-apple-ios := 1
-CFG_PATH_MUNGE_i386-apple-ios = :true
 CFG_LDPATH_i386-apple-ios =
 CFG_RUN_i386-apple-ios = $(2)
 CFG_RUN_TARG_i386-apple-ios = $(call CFG_RUN_i386-apple-ios,,$(2))
index e935ce053e02aa273b0423522cd427446d89a326..7ebb492bb21fe1c9d8a50dd4ac697529d85223dc 100644 (file)
@@ -12,15 +12,11 @@ CFG_GCCISH_CFLAGS_i686-apple-darwin := -Wall -Werror -g -fPIC -m32 -arch i386 $(
 CFG_GCCISH_CXXFLAGS_i686-apple-darwin := -fno-rtti $(CXXFLAGS)
 CFG_GCCISH_LINK_FLAGS_i686-apple-darwin := -dynamiclib -pthread  -framework CoreServices -m32
 CFG_GCCISH_DEF_FLAG_i686-apple-darwin := -Wl,-exported_symbols_list,
-CFG_GCCISH_PRE_LIB_FLAGS_i686-apple-darwin :=
-CFG_GCCISH_POST_LIB_FLAGS_i686-apple-darwin :=
-CFG_DEF_SUFFIX_i686-apple-darwin := .darwin.def
 CFG_LLC_FLAGS_i686-apple-darwin :=
 CFG_INSTALL_NAME_i686-apple-darwin = -Wl,-install_name,@rpath/$(1)
 CFG_EXE_SUFFIX_i686-apple-darwin :=
 CFG_WINDOWSY_i686-apple-darwin :=
 CFG_UNIXY_i686-apple-darwin := 1
-CFG_PATH_MUNGE_i686-apple-darwin := true
 CFG_LDPATH_i686-apple-darwin :=
 CFG_RUN_i686-apple-darwin=$(2)
 CFG_RUN_TARG_i686-apple-darwin=$(call CFG_RUN_i686-apple-darwin,,$(2))
index 357a321688bcace7c9ac062e4b1a65ba0297fbba..174671a9a8812a3370888a2b7730cab3d6f952d6 100644 (file)
@@ -13,15 +13,11 @@ CFG_GCCISH_CFLAGS_i686-pc-windows-gnu := -Wall -Werror -g -m32 -D_WIN32_WINNT=0x
 CFG_GCCISH_CXXFLAGS_i686-pc-windows-gnu := -fno-rtti $(CXXFLAGS)
 CFG_GCCISH_LINK_FLAGS_i686-pc-windows-gnu := -shared -g -m32
 CFG_GCCISH_DEF_FLAG_i686-pc-windows-gnu :=
-CFG_GCCISH_PRE_LIB_FLAGS_i686-pc-windows-gnu :=
-CFG_GCCISH_POST_LIB_FLAGS_i686-pc-windows-gnu :=
-CFG_DEF_SUFFIX_i686-pc-windows-gnu := .windows.def
 CFG_LLC_FLAGS_i686-pc-windows-gnu :=
 CFG_INSTALL_NAME_i686-pc-windows-gnu =
 CFG_EXE_SUFFIX_i686-pc-windows-gnu := .exe
 CFG_WINDOWSY_i686-pc-windows-gnu := 1
 CFG_UNIXY_i686-pc-windows-gnu :=
-CFG_PATH_MUNGE_i686-pc-windows-gnu :=
 CFG_LDPATH_i686-pc-windows-gnu :=
 CFG_RUN_i686-pc-windows-gnu=$(2)
 CFG_RUN_TARG_i686-pc-windows-gnu=$(call CFG_RUN_i686-pc-windows-gnu,,$(2))
index 1cc9c143e8d470860a269334b94929f10bcfc934..88c0907f63b2ac8f8be2e4d30078d31fe75db184 100644 (file)
@@ -12,15 +12,11 @@ CFG_GCCISH_CFLAGS_i686-unknown-linux-gnu := -Wall -Werror -g -fPIC -m32 $(CFLAGS
 CFG_GCCISH_CXXFLAGS_i686-unknown-linux-gnu := -fno-rtti $(CXXFLAGS)
 CFG_GCCISH_LINK_FLAGS_i686-unknown-linux-gnu := -shared -fPIC -ldl -pthread  -lrt -g -m32
 CFG_GCCISH_DEF_FLAG_i686-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list=
-CFG_GCCISH_PRE_LIB_FLAGS_i686-unknown-linux-gnu := -Wl,-whole-archive
-CFG_GCCISH_POST_LIB_FLAGS_i686-unknown-linux-gnu := -Wl,-no-whole-archive
-CFG_DEF_SUFFIX_i686-unknown-linux-gnu := .linux.def
 CFG_LLC_FLAGS_i686-unknown-linux-gnu :=
 CFG_INSTALL_NAME_i686-unknown-linux-gnu =
 CFG_EXE_SUFFIX_i686-unknown-linux-gnu =
 CFG_WINDOWSY_i686-unknown-linux-gnu :=
 CFG_UNIXY_i686-unknown-linux-gnu := 1
-CFG_PATH_MUNGE_i686-unknown-linux-gnu := true
 CFG_LDPATH_i686-unknown-linux-gnu :=
 CFG_RUN_i686-unknown-linux-gnu=$(2)
 CFG_RUN_TARG_i686-unknown-linux-gnu=$(call CFG_RUN_i686-unknown-linux-gnu,,$(2))
index c5d84966f8526f332b2a19b3d3ab3c00e1eb88b7..ba5f6d0e756343af7fb01c1b2e398d9644f56018 100644 (file)
@@ -12,15 +12,11 @@ CFG_GCCISH_CFLAGS_mips-unknown-linux-gnu := -Wall -g -fPIC -mips32r2 -msoft-floa
 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=
-CFG_GCCISH_PRE_LIB_FLAGS_mips-unknown-linux-gnu := -Wl,-whole-archive
-CFG_GCCISH_POST_LIB_FLAGS_mips-unknown-linux-gnu := -Wl,-no-whole-archive
-CFG_DEF_SUFFIX_mips-unknown-linux-gnu := .linux.def
 CFG_LLC_FLAGS_mips-unknown-linux-gnu :=
 CFG_INSTALL_NAME_mips-unknown-linux-gnu =
 CFG_EXE_SUFFIX_mips-unknown-linux-gnu :=
 CFG_WINDOWSY_mips-unknown-linux-gnu :=
 CFG_UNIXY_mips-unknown-linux-gnu := 1
-CFG_PATH_MUNGE_mips-unknown-linux-gnu := true
 CFG_LDPATH_mips-unknown-linux-gnu :=
 CFG_RUN_mips-unknown-linux-gnu=
 CFG_RUN_TARG_mips-unknown-linux-gnu=
index eb2f300abffd8072665fab3d8c68ac8a527ee6e9..539038c7434606dfc4825052af1a35a431445096 100644 (file)
@@ -12,15 +12,11 @@ CFG_GCCISH_CFLAGS_mipsel-unknown-linux-gnu := -Wall -g -fPIC -mips32 -mabi=32 $(
 CFG_GCCISH_CXXFLAGS_mipsel-unknown-linux-gnu := -fno-rtti $(CXXFLAGS)
 CFG_GCCISH_LINK_FLAGS_mipsel-unknown-linux-gnu := -shared -fPIC -g -mips32
 CFG_GCCISH_DEF_FLAG_mipsel-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list=
-CFG_GCCISH_PRE_LIB_FLAGS_mipsel-unknown-linux-gnu := -Wl,-whole-archive
-CFG_GCCISH_POST_LIB_FLAGS_mipsel-unknown-linux-gnu := -Wl,-no-whole-archive
-CFG_DEF_SUFFIX_mipsel-unknown-linux-gnu := .linux.def
 CFG_LLC_FLAGS_mipsel-unknown-linux-gnu :=
 CFG_INSTALL_NAME_mipsel-unknown-linux-gnu =
 CFG_EXE_SUFFIX_mipsel-unknown-linux-gnu :=
 CFG_WINDOWSY_mipsel-unknown-linux-gnu :=
 CFG_UNIXY_mipsel-unknown-linux-gnu := 1
-CFG_PATH_MUNGE_mipsel-unknown-linux-gnu := true
 CFG_LDPATH_mipsel-unknown-linux-gnu :=
 CFG_RUN_mipsel-unknown-linux-gnu=
 CFG_RUN_TARG_mipsel-unknown-linux-gnu=
index fd37bd663f7dddb96e0222062d0c0e713e8ea0e6..dda957673eba665d15ab266a29e89a76336d370c 100644 (file)
@@ -13,15 +13,11 @@ CFG_GCCISH_CFLAGS_powerpc-unknown-linux-gnu := -Wall -Werror -g -fPIC -m32 $(CFL
 CFG_GCCISH_CXXFLAGS_powerpc-unknown-linux-gnu := -fno-rtti $(CXXFLAGS)
 CFG_GCCISH_LINK_FLAGS_powerpc-unknown-linux-gnu := -shared -fPIC -ldl -pthread  -lrt -g -m32
 CFG_GCCISH_DEF_FLAG_powerpc-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list=
-CFG_GCCISH_PRE_LIB_FLAGS_powerpc-unknown-linux-gnu := -Wl,-whole-archive
-CFG_GCCISH_POST_LIB_FLAGS_powerpc-unknown-linux-gnu := -Wl,-no-whole-archive
-CFG_DEF_SUFFIX_powerpc-unknown-linux-gnu := .linux.def
 CFG_LLC_FLAGS_powerpc-unknown-linux-gnu :=
 CFG_INSTALL_NAME_powerpc-unknown-linux-gnu =
 CFG_EXE_SUFFIX_powerpc-unknown-linux-gnu =
 CFG_WINDOWSY_powerpc-unknown-linux-gnu :=
 CFG_UNIXY_powerpc-unknown-linux-gnu := 1
-CFG_PATH_MUNGE_powerpc-unknown-linux-gnu := true
 CFG_LDPATH_powerpc-unknown-linux-gnu :=
 CFG_RUN_powerpc-unknown-linux-gnu=$(2)
 CFG_RUN_TARG_powerpc-unknown-linux-gnu=$(call CFG_RUN_powerpc-unknown-linux-gnu,,$(2))
index dbd67542ab75a08c994c27454a6189ba8297ef3c..4c68d3dcf37b4424b10e06ae845bfb30e2950d57 100644 (file)
@@ -12,15 +12,11 @@ CFG_GCCISH_CFLAGS_x86_64-apple-darwin := -Wall -Werror -g -fPIC -m64 -arch x86_6
 CFG_GCCISH_CXXFLAGS_x86_64-apple-darwin := -fno-rtti $(CXXFLAGS)
 CFG_GCCISH_LINK_FLAGS_x86_64-apple-darwin := -dynamiclib -pthread  -framework CoreServices -m64
 CFG_GCCISH_DEF_FLAG_x86_64-apple-darwin := -Wl,-exported_symbols_list,
-CFG_GCCISH_PRE_LIB_FLAGS_x86_64-apple-darwin :=
-CFG_GCCISH_POST_LIB_FLAGS_x86_64-apple-darwin :=
-CFG_DEF_SUFFIX_x86_64-apple-darwin := .darwin.def
 CFG_LLC_FLAGS_x86_64-apple-darwin :=
 CFG_INSTALL_NAME_x86_64-apple-darwin = -Wl,-install_name,@rpath/$(1)
 CFG_EXE_SUFFIX_x86_64-apple-darwin :=
 CFG_WINDOWSY_x86_64-apple-darwin :=
 CFG_UNIXY_x86_64-apple-darwin := 1
-CFG_PATH_MUNGE_x86_64-apple-darwin := true
 CFG_LDPATH_x86_64-apple-darwin :=
 CFG_RUN_x86_64-apple-darwin=$(2)
 CFG_RUN_TARG_x86_64-apple-darwin=$(call CFG_RUN_x86_64-apple-darwin,,$(2))
index b3f05a895a49fe0f65c912ac9997a59270fb1744..dd6080fdb0bab1ecc872a8fd9e0f1160bf37a477 100644 (file)
@@ -20,16 +20,12 @@ CFG_GCCISH_CFLAGS_x86_64-apple-ios := -Wall -Werror -fPIC $(CFG_IOSSIM_FLAGS_x86
 CFG_GCCISH_CXXFLAGS_x86_64-apple-ios := -fno-rtti $(CFG_IOSSIM_FLAGS_x86_64-apple-ios) -I$(CFG_IOSSIM_SDK_x86_64-apple-ios)/usr/include/c++/4.2.1
 CFG_GCCISH_LINK_FLAGS_x86_64-apple-ios := -lpthread -Wl,-no_compact_unwind -m64 -Wl,-syslibroot $(CFG_IOSSIM_SDK_x86_64-apple-ios)
 CFG_GCCISH_DEF_FLAG_x86_64-apple-ios := -Wl,-exported_symbols_list,
-CFG_GCCISH_PRE_LIB_FLAGS_x86_64-apple-ios :=
-CFG_GCCISH_POST_LIB_FLAGS_x86_64-apple-ios :=
-CFG_DEF_SUFFIX_x86_64-apple-ios := .darwin.def
 CFG_LLC_FLAGS_x86_64-apple-ios :=
 CFG_INSTALL_NAME_x86_64-apple-ios = -Wl,-install_name,@rpath/$(1)
 CFG_LIBUV_LINK_FLAGS_x86_64-apple-ios :=
 CFG_EXE_SUFFIX_x86_64-apple-ios :=
 CFG_WINDOWSY_x86_64-apple-ios :=
 CFG_UNIXY_x86_64-apple-ios := 1
-CFG_PATH_MUNGE_x86_64-apple-ios := true
 CFG_LDPATH_x86_64-apple-ios :=
 CFG_RUN_x86_64-apple-ios = $(2)
 CFG_RUN_TARG_x86_64-apple-ios = $(call CFG_RUN_x86_64-apple-ios,,$(2))
index e9e5f04ea54336a3a2737c80f65b850a0ed24773..4118ea26c072b0e13587bcc293d38a5c55b56329 100644 (file)
@@ -13,15 +13,11 @@ CFG_GCCISH_CFLAGS_x86_64-pc-windows-gnu := -Wall -Werror -g -m64 -D_WIN32_WINNT=
 CFG_GCCISH_CXXFLAGS_x86_64-pc-windows-gnu := -fno-rtti $(CXXFLAGS)
 CFG_GCCISH_LINK_FLAGS_x86_64-pc-windows-gnu := -shared -g -m64
 CFG_GCCISH_DEF_FLAG_x86_64-pc-windows-gnu :=
-CFG_GCCISH_PRE_LIB_FLAGS_x86_64-pc-windows-gnu :=
-CFG_GCCISH_POST_LIB_FLAGS_x86_64-pc-windows-gnu :=
-CFG_DEF_SUFFIX_x86_64-pc-windows-gnu := .windows.def
 CFG_LLC_FLAGS_x86_64-pc-windows-gnu :=
 CFG_INSTALL_NAME_x86_64-pc-windows-gnu =
 CFG_EXE_SUFFIX_x86_64-pc-windows-gnu := .exe
 CFG_WINDOWSY_x86_64-pc-windows-gnu := 1
 CFG_UNIXY_x86_64-pc-windows-gnu :=
-CFG_PATH_MUNGE_x86_64-pc-windows-gnu :=
 CFG_LDPATH_x86_64-pc-windows-gnu :=
 CFG_RUN_x86_64-pc-windows-gnu=$(2)
 CFG_RUN_TARG_x86_64-pc-windows-gnu=$(call CFG_RUN_x86_64-pc-windows-gnu,,$(2))
index ad34988cb1bc00369ca1f92826a066715e05590a..dd6d19f7491bb688d8f7c588392afd18c9a6a4c5 100644 (file)
@@ -11,15 +11,11 @@ CFG_JEMALLOC_CFLAGS_x86_64-unknown-bitrig := -m64 -I/usr/include $(CFLAGS)
 CFG_GCCISH_CFLAGS_x86_64-unknown-bitrig := -Wall -Werror -fPIC -m64 -I/usr/include $(CFLAGS)
 CFG_GCCISH_LINK_FLAGS_x86_64-unknown-bitrig := -shared -pic -pthread -m64 $(LDFLAGS)
 CFG_GCCISH_DEF_FLAG_x86_64-unknown-bitrig := -Wl,--export-dynamic,--dynamic-list=
-CFG_GCCISH_PRE_LIB_FLAGS_x86_64-unknown-bitrig := -Wl,-pic -Wl,-whole-archive
-CFG_GCCISH_POST_LIB_FLAGS_x86_64-unknown-bitrig := -Wl,-no-whole-archive
-CFG_DEF_SUFFIX_x86_64-unknown-bitrig := .bsd.def
 CFG_LLC_FLAGS_x86_64-unknown-bitrig :=
 CFG_INSTALL_NAME_x86_64-unknown-bitrig =
 CFG_EXE_SUFFIX_x86_64-unknown-bitrig :=
 CFG_WINDOWSY_x86_64-unknown-bitrig :=
 CFG_UNIXY_x86_64-unknown-bitrig := 1
-CFG_PATH_MUNGE_x86_64-unknown-bitrig :=
 CFG_LDPATH_x86_64-unknown-bitrig :=
 CFG_RUN_x86_64-unknown-bitrig=$(2)
 CFG_RUN_TARG_x86_64-unknown-bitrig=$(call CFG_RUN_x86_64-unknown-bitrig,,$(2))
index 9665b5c7802729b09b84e531e2e7a4c99e98930b..4015293826e1a884e2a2c9975908ec09e17ef6eb 100644 (file)
@@ -11,15 +11,11 @@ CFG_JEMALLOC_CFLAGS_x86_64-unknown-dragonfly := -m64 -I/usr/include -I/usr/local
 CFG_GCCISH_CFLAGS_x86_64-unknown-dragonfly := -Wall -Werror -g -fPIC -m64 -I/usr/include -I/usr/local/include $(CFLAGS)
 CFG_GCCISH_LINK_FLAGS_x86_64-unknown-dragonfly := -shared -fPIC -g -pthread  -lrt -m64
 CFG_GCCISH_DEF_FLAG_x86_64-unknown-dragonfly := -Wl,--export-dynamic,--dynamic-list=
-CFG_GCCISH_PRE_LIB_FLAGS_x86_64-unknown-dragonfly := -Wl,-whole-archive
-CFG_GCCISH_POST_LIB_FLAGS_x86_64-unknown-dragonfly := -Wl,-no-whole-archive
-CFG_DEF_SUFFIX_x86_64-unknown-dragonfly := .bsd.def
 CFG_LLC_FLAGS_x86_64-unknown-dragonfly :=
 CFG_INSTALL_NAME_x86_64-unknown-dragonfly =
 CFG_EXE_SUFFIX_x86_64-unknown-dragonfly :=
 CFG_WINDOWSY_x86_64-unknown-dragonfly :=
 CFG_UNIXY_x86_64-unknown-dragonfly := 1
-CFG_PATH_MUNGE_x86_64-unknown-dragonfly :=
 CFG_LDPATH_x86_64-unknown-dragonfly :=
 CFG_RUN_x86_64-unknown-dragonfly=$(2)
 CFG_RUN_TARG_x86_64-unknown-dragonfly=$(call CFG_RUN_x86_64-unknown-dragonfly,,$(2))
index 4e847ea78a717e13f258003aa3b56447a837cc29..1bd43168b4f692cf7283560803446569a275ac95 100644 (file)
@@ -11,15 +11,11 @@ CFG_JEMALLOC_CFLAGS_x86_64-unknown-freebsd := -I/usr/local/include $(CFLAGS)
 CFG_GCCISH_CFLAGS_x86_64-unknown-freebsd := -Wall -Werror -g -fPIC -I/usr/local/include $(CFLAGS)
 CFG_GCCISH_LINK_FLAGS_x86_64-unknown-freebsd := -shared -fPIC -g -pthread  -lrt
 CFG_GCCISH_DEF_FLAG_x86_64-unknown-freebsd := -Wl,--export-dynamic,--dynamic-list=
-CFG_GCCISH_PRE_LIB_FLAGS_x86_64-unknown-freebsd := -Wl,-whole-archive
-CFG_GCCISH_POST_LIB_FLAGS_x86_64-unknown-freebsd := -Wl,-no-whole-archive
-CFG_DEF_SUFFIX_x86_64-unknown-freebsd := .bsd.def
 CFG_LLC_FLAGS_x86_64-unknown-freebsd :=
 CFG_INSTALL_NAME_x86_64-unknown-freebsd =
 CFG_EXE_SUFFIX_x86_64-unknown-freebsd :=
 CFG_WINDOWSY_x86_64-unknown-freebsd :=
 CFG_UNIXY_x86_64-unknown-freebsd := 1
-CFG_PATH_MUNGE_x86_64-unknown-freebsd :=
 CFG_LDPATH_x86_64-unknown-freebsd :=
 CFG_RUN_x86_64-unknown-freebsd=$(2)
 CFG_RUN_TARG_x86_64-unknown-freebsd=$(call CFG_RUN_x86_64-unknown-freebsd,,$(2))
index e5866094ee84f7b181fc0de2f8c86d4210c5f881..044c687c9fc4c871cb3510dfbf8f7b3e3121caf4 100644 (file)
@@ -12,15 +12,11 @@ CFG_GCCISH_CFLAGS_x86_64-unknown-linux-gnu := -Wall -Werror -g -fPIC -m64
 CFG_GCCISH_CXXFLAGS_x86_64-unknown-linux-gnu := -fno-rtti
 CFG_GCCISH_LINK_FLAGS_x86_64-unknown-linux-gnu := -shared -fPIC -ldl -pthread  -lrt -g -m64
 CFG_GCCISH_DEF_FLAG_x86_64-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list=
-CFG_GCCISH_PRE_LIB_FLAGS_x86_64-unknown-linux-gnu := -Wl,-whole-archive
-CFG_GCCISH_POST_LIB_FLAGS_x86_64-unknown-linux-gnu := -Wl,-no-whole-archive
-CFG_DEF_SUFFIX_x86_64-unknown-linux-gnu := .linux.def
 CFG_LLC_FLAGS_x86_64-unknown-linux-gnu :=
 CFG_INSTALL_NAME_x86_64-unknown-linux-gnu =
 CFG_EXE_SUFFIX_x86_64-unknown-linux-gnu =
 CFG_WINDOWSY_x86_64-unknown-linux-gnu :=
 CFG_UNIXY_x86_64-unknown-linux-gnu := 1
-CFG_PATH_MUNGE_x86_64-unknown-linux-gnu := true
 CFG_LDPATH_x86_64-unknown-linux-gnu :=
 CFG_RUN_x86_64-unknown-linux-gnu=$(2)
 CFG_RUN_TARG_x86_64-unknown-linux-gnu=$(call CFG_RUN_x86_64-unknown-linux-gnu,,$(2))
diff --git a/mk/cfg/x86_64-unknown-linux-musl.mk b/mk/cfg/x86_64-unknown-linux-musl.mk
new file mode 100644 (file)
index 0000000..b3dea6f
--- /dev/null
@@ -0,0 +1,27 @@
+# x86_64-unknown-linux-musl configuration
+CC_x86_64-unknown-linux-musl=$(CFG_MUSL_ROOT)/bin/musl-gcc
+CXX_x86_64-unknown-linux-musl=notaprogram
+CPP_x86_64-unknown-linux-musl=$(CFG_MUSL_ROOT)/bin/musl-gcc -E
+AR_x86_64-unknown-linux-musl=$(AR)
+CFG_LIB_NAME_x86_64-unknown-linux-musl=lib$(1).so
+CFG_STATIC_LIB_NAME_x86_64-unknown-linux-musl=lib$(1).a
+CFG_LIB_GLOB_x86_64-unknown-linux-musl=lib$(1)-*.so
+CFG_JEMALLOC_CFLAGS_x86_64-unknown-linux-musl := -m64
+CFG_GCCISH_CFLAGS_x86_64-unknown-linux-musl := -Wall -Werror -g -fPIC -m64
+CFG_GCCISH_CXXFLAGS_x86_64-unknown-linux-musl :=
+CFG_GCCISH_LINK_FLAGS_x86_64-unknown-linux-musl :=
+CFG_GCCISH_DEF_FLAG_x86_64-unknown-linux-musl :=
+CFG_LLC_FLAGS_x86_64-unknown-linux-musl :=
+CFG_INSTALL_NAME_x86_64-unknown-linux-musl =
+CFG_EXE_SUFFIX_x86_64-unknown-linux-musl =
+CFG_WINDOWSY_x86_64-unknown-linux-musl :=
+CFG_UNIXY_x86_64-unknown-linux-musl := 1
+CFG_LDPATH_x86_64-unknown-linux-musl :=
+CFG_RUN_x86_64-unknown-linux-musl=$(2)
+CFG_RUN_TARG_x86_64-unknown-linux-musl=$(call CFG_RUN_x86_64-unknown-linux-musl,,$(2))
+CFG_GNU_TRIPLE_x86_64-unknown-linux-musl := x86_64-unknown-linux-musl
+
+NATIVE_DEPS_libc_T_x86_64-unknown-linux-musl += libc.a
+NATIVE_DEPS_std_T_x86_64-unknown-linux-musl += libunwind.a \
+       crt1.o crti.o crtn.o
+INSTALLED_OBJECTS_x86_64-unknown-linux-musl += crt1.o crti.o crtn.o
index 582d75c3eaf09dba7313d4f91336b11490746c37..261616ecf1fdaea8c14cff20c9bf49c7c44d1c30 100644 (file)
@@ -11,15 +11,11 @@ CFG_JEMALLOC_CFLAGS_x86_64-unknown-openbsd := -m64 -I/usr/include $(CFLAGS)
 CFG_GCCISH_CFLAGS_x86_64-unknown-openbsd := -Wall -Werror -g -fPIC -m64 -I/usr/include $(CFLAGS)
 CFG_GCCISH_LINK_FLAGS_x86_64-unknown-openbsd := -shared -fPIC -g -pthread -m64
 CFG_GCCISH_DEF_FLAG_x86_64-unknown-openbsd := -Wl,--export-dynamic,--dynamic-list=
-CFG_GCCISH_PRE_LIB_FLAGS_x86_64-unknown-openbsd := -Wl,-whole-archive
-CFG_GCCISH_POST_LIB_FLAGS_x86_64-unknown-openbsd := -Wl,-no-whole-archive
-CFG_DEF_SUFFIX_x86_64-unknown-openbsd := .bsd.def
 CFG_LLC_FLAGS_x86_64-unknown-openbsd :=
 CFG_INSTALL_NAME_x86_64-unknown-openbsd =
 CFG_EXE_SUFFIX_x86_64-unknown-openbsd :=
 CFG_WINDOWSY_x86_64-unknown-openbsd :=
 CFG_UNIXY_x86_64-unknown-openbsd := 1
-CFG_PATH_MUNGE_x86_64-unknown-openbsd :=
 CFG_LDPATH_x86_64-unknown-openbsd :=
 CFG_RUN_x86_64-unknown-openbsd=$(2)
 CFG_RUN_TARG_x86_64-unknown-openbsd=$(call CFG_RUN_x86_64-unknown-openbsd,,$(2))
index e7c6a716f4cfcde236b5db33b02194fa8043c213..367c25a8a6d495f5281ae94980101e70b699f0b2 100644 (file)
@@ -123,6 +123,9 @@ ONLY_RLIB_rustc_bitflags := 1
 # Documented-by-default crates
 DOC_CRATES := std alloc collections core libc rustc_unicode
 
+# Installed objects/libraries by default
+INSTALLED_OBJECTS := libmorestack.a libcompiler-rt.a
+
 ################################################################################
 # You should not need to edit below this line
 ################################################################################
index c1ce1051d0a86ca7c7d34275b091197016ea1495..9ac96aa90f6b9b9a1035b40994bbbfeb6f7784cd 100644 (file)
@@ -399,8 +399,10 @@ endif
 # Prerequisites for using the stageN compiler to build target artifacts
 TSREQ$(1)_T_$(2)_H_$(3) = \
        $$(HSREQ$(1)_H_$(3)) \
-       $$(TLIB$(1)_T_$(2)_H_$(3))/libmorestack.a \
-       $$(TLIB$(1)_T_$(2)_H_$(3))/libcompiler-rt.a
+       $$(foreach obj,$$(INSTALLED_OBJECTS),\
+               $$(TLIB$(1)_T_$(2)_H_$(3))/$$(obj)) \
+       $$(foreach obj,$$(INSTALLED_OBJECTS_$(2)),\
+               $$(TLIB$(1)_T_$(2)_H_$(3))/$$(obj))
 
 # Prerequisites for a working stageN compiler and libraries, for a specific
 # target
index 4ded8a7916b9ba4d386d61f3d5198fffc5109063..1382d160e13999063b3ac7674ab95c0de600854b 100644 (file)
@@ -140,8 +140,8 @@ prepare-target-$(2)-host-$(3)-$(1)-$(4): prepare-maybe-clean-$(4) \
           $$(if $$(findstring $(2),$$(CFG_HOST)), \
             $$(foreach crate,$$(HOST_CRATES), \
               $$(call PREPARE_LIB,$$(call CFG_LIB_GLOB_$(2),$$(crate)))),) \
-          $$(call PREPARE_LIB,libmorestack.a) \
-          $$(call PREPARE_LIB,libcompiler-rt.a),),),)
+         $$(foreach object,$$(INSTALLED_OBJECTS) $$(INSTALLED_OBJECTS_$(2)),\
+           $$(call PREPARE_LIB,$$(object))),),),)
 endef
 
 define INSTALL_GDB_DEBUGGER_SCRIPTS_COMMANDS
index 70abce8b4606751f1bda548dcd97a31f0661fecc..bd6578d3b724b9baeffaab93ac7d40fa81215747 100644 (file)
--- a/mk/rt.mk
+++ b/mk/rt.mk
@@ -74,7 +74,8 @@ $$(RT_OUTPUT_DIR_$(1))/%.o: $(S)src/rt/%.ll $$(MKFILE_DEPS) \
        @mkdir -p $$(@D)
        @$$(call E, compile: $$@)
        $$(Q)$$(LLC_$$(CFG_BUILD)) $$(CFG_LLC_FLAGS_$(1)) \
-           -filetype=obj -mtriple=$$(CFG_LLVM_TARGET_$(1)) -relocation-model=pic -o $$@ $$<
+           -filetype=obj -mtriple=$$(CFG_LLVM_TARGET_$(1)) \
+           -relocation-model=pic -o $$@ $$<
 
 $$(RT_OUTPUT_DIR_$(1))/%.o: $(S)src/rt/%.c $$(MKFILE_DEPS)
        @mkdir -p $$(@D)
@@ -110,6 +111,11 @@ $$(RT_OUTPUT_DIR_$(1))/$$(NATIVE_$(2)_$(1)): $$(OBJS_$(2)_$(1))
        @$$(call E, link: $$@)
        $$(Q)$$(AR_$(1)) rcs $$@ $$^
 
+ifeq ($$(findstring windows,$(1)),windows)
+$$(RT_OUTPUT_DIR_$(1))/lib$(2).a: $$(RT_OUTPUT_DIR_$(1))/$$(NATIVE_$(2)_$(1))
+       $$(Q)cp $$^ $$@
+endif
+
 endef
 
 $(foreach target,$(CFG_TARGET), \
@@ -221,7 +227,7 @@ COMPRT_DEPS := $(wildcard \
               $(S)src/compiler-rt/*/*/*/*)
 endif
 
-COMPRT_NAME_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),compiler-rt)
+COMPRT_NAME_$(1) := libcompiler-rt.a
 COMPRT_LIB_$(1) := $$(RT_OUTPUT_DIR_$(1))/$$(COMPRT_NAME_$(1))
 COMPRT_BUILD_DIR_$(1) := $$(RT_OUTPUT_DIR_$(1))/compiler-rt
 
@@ -312,6 +318,19 @@ endif # endif for windowsy
 endif # endif for ios
 endif # endif for darwin
 
+################################################################################
+# libc/libunwind for musl
+#
+# When we're building a musl-like target we're going to link libc/libunwind
+# statically into the standard library and liblibc, so we need to make sure
+# they're in a location that we can find
+################################################################################
+
+ifeq ($$(findstring musl,$(1)),musl)
+$$(RT_OUTPUT_DIR_$(1))/%: $$(CFG_MUSL_ROOT)/lib/%
+       cp $$^ $$@
+endif
+
 endef
 
 # Instantiate template for all stages/targets
index 44225020811c0470848bb5130b4f022e970b6142..363022e8781d08bfd28ef2ca213374409a8e4010 100644 (file)
@@ -25,8 +25,6 @@ endif
 RUSTLLVM_OBJS_CS_$(1) := $$(addprefix rustllvm/, \
        ExecutionEngineWrapper.cpp RustWrapper.cpp PassWrapper.cpp)
 
-RUSTLLVM_DEF_$(1) := $(1)/rustllvm/rustllvm$(CFG_DEF_SUFFIX_$(1))
-
 RUSTLLVM_INCS_$(1) = $$(LLVM_EXTRA_INCDIRS_$(1)) \
                      -iquote $$(LLVM_INCDIR_$(1)) \
                      -iquote $$(S)src/rustllvm/include
index 8cc74a9cbfb76f81b77d67843c569725bf7da40c..319f44fd35b77c1058c4627b77640cf913ffc09f 100644 (file)
@@ -35,7 +35,9 @@ CRATE_FULLDEPS_$(1)_T_$(2)_H_$(3)_$(4) := \
                $$(foreach dep,$$(RUST_DEPS_$(4)), \
                  $$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$$(dep)) \
                $$(foreach dep,$$(NATIVE_DEPS_$(4)), \
-                 $$(RT_OUTPUT_DIR_$(2))/$$(call CFG_STATIC_LIB_NAME_$(2),$$(dep)))
+                 $$(RT_OUTPUT_DIR_$(2))/$$(call CFG_STATIC_LIB_NAME_$(2),$$(dep))) \
+               $$(foreach dep,$$(NATIVE_DEPS_$(4)_T_$(2)), \
+                 $$(RT_OUTPUT_DIR_$(2))/$$(dep))
 endef
 
 $(foreach host,$(CFG_HOST), \
@@ -143,14 +145,7 @@ $$(TBIN$(1)_T_$(2)_H_$(3))/:
 $$(TLIB$(1)_T_$(2)_H_$(3))/:
        mkdir -p $$@
 
-$$(TLIB$(1)_T_$(2)_H_$(3))/libcompiler-rt.a: \
-           $$(RT_OUTPUT_DIR_$(2))/$$(call CFG_STATIC_LIB_NAME_$(2),compiler-rt) \
-           | $$(TLIB$(1)_T_$(2)_H_$(3))/ $$(SNAPSHOT_RUSTC_POST_CLEANUP)
-       @$$(call E, cp: $$@)
-       $$(Q)cp $$< $$@
-
-$$(TLIB$(1)_T_$(2)_H_$(3))/libmorestack.a: \
-           $$(RT_OUTPUT_DIR_$(2))/$$(call CFG_STATIC_LIB_NAME_$(2),morestack) \
+$$(TLIB$(1)_T_$(2)_H_$(3))/%: $$(RT_OUTPUT_DIR_$(2))/% \
            | $$(TLIB$(1)_T_$(2)_H_$(3))/ $$(SNAPSHOT_RUSTC_POST_CLEANUP)
        @$$(call E, cp: $$@)
        $$(Q)cp $$< $$@
index 5d100958edc92296565b17a382efd439fcfd3fd4..3c4818f65dade1a6335d57105f2456bec484793f 100644 (file)
@@ -304,6 +304,7 @@ check-stage$(1)-T-$(2)-H-$(3)-exec: \
        check-stage$(1)-T-$(2)-H-$(3)-pfail-exec \
     check-stage$(1)-T-$(2)-H-$(3)-rpass-valgrind-exec \
     check-stage$(1)-T-$(2)-H-$(3)-rpass-full-exec \
+    check-stage$(1)-T-$(2)-H-$(3)-rfail-full-exec \
        check-stage$(1)-T-$(2)-H-$(3)-cfail-full-exec \
        check-stage$(1)-T-$(2)-H-$(3)-rmake-exec \
        check-stage$(1)-T-$(2)-H-$(3)-rustdocck-exec \
@@ -345,6 +346,7 @@ check-stage$(1)-T-$(2)-H-$(3)-pretty-exec: \
     check-stage$(1)-T-$(2)-H-$(3)-pretty-rpass-valgrind-exec \
        check-stage$(1)-T-$(2)-H-$(3)-pretty-rpass-full-exec \
        check-stage$(1)-T-$(2)-H-$(3)-pretty-rfail-exec \
+       check-stage$(1)-T-$(2)-H-$(3)-pretty-rfail-full-exec \
        check-stage$(1)-T-$(2)-H-$(3)-pretty-bench-exec \
        check-stage$(1)-T-$(2)-H-$(3)-pretty-pretty-exec
 
@@ -464,6 +466,7 @@ $(foreach host,$(CFG_HOST), \
 RPASS_RS := $(wildcard $(S)src/test/run-pass/*.rs)
 RPASS_VALGRIND_RS := $(wildcard $(S)src/test/run-pass-valgrind/*.rs)
 RPASS_FULL_RS := $(wildcard $(S)src/test/run-pass-fulldeps/*.rs)
+RFAIL_FULL_RS := $(wildcard $(S)src/test/run-fail-fulldeps/*.rs)
 CFAIL_FULL_RS := $(wildcard $(S)src/test/compile-fail-fulldeps/*.rs)
 RFAIL_RS := $(wildcard $(S)src/test/run-fail/*.rs)
 CFAIL_RS := $(wildcard $(S)src/test/compile-fail/*.rs)
@@ -483,6 +486,7 @@ PERF_RS := $(wildcard $(S)src/test/bench/*.rs)
 RPASS_TESTS := $(RPASS_RS)
 RPASS_VALGRIND_TESTS := $(RPASS_VALGRIND_RS)
 RPASS_FULL_TESTS := $(RPASS_FULL_RS)
+RFAIL_FULL_TESTS := $(RFAIL_FULL_RS)
 CFAIL_FULL_TESTS := $(CFAIL_FULL_RS)
 RFAIL_TESTS := $(RFAIL_RS)
 CFAIL_TESTS := $(CFAIL_RS)
@@ -510,6 +514,11 @@ CTEST_BUILD_BASE_rpass-full = run-pass-fulldeps
 CTEST_MODE_rpass-full = run-pass
 CTEST_RUNTOOL_rpass-full = $(CTEST_RUNTOOL)
 
+CTEST_SRC_BASE_rfail-full = run-fail-fulldeps
+CTEST_BUILD_BASE_rfail-full = run-fail-fulldeps
+CTEST_MODE_rfail-full = run-fail
+CTEST_RUNTOOL_rfail-full = $(CTEST_RUNTOOL)
+
 CTEST_SRC_BASE_cfail-full = compile-fail-fulldeps
 CTEST_BUILD_BASE_cfail-full = compile-fail-fulldeps
 CTEST_MODE_cfail-full = compile-fail
@@ -661,6 +670,7 @@ endif
 CTEST_DEPS_rpass_$(1)-T-$(2)-H-$(3) = $$(RPASS_TESTS)
 CTEST_DEPS_rpass-valgrind_$(1)-T-$(2)-H-$(3) = $$(RPASS_VALGRIND_TESTS)
 CTEST_DEPS_rpass-full_$(1)-T-$(2)-H-$(3) = $$(RPASS_FULL_TESTS) $$(CSREQ$(1)_T_$(3)_H_$(3)) $$(SREQ$(1)_T_$(2)_H_$(3))
+CTEST_DEPS_rfail-full_$(1)-T-$(2)-H-$(3) = $$(RFAIL_FULL_TESTS) $$(CSREQ$(1)_T_$(3)_H_$(3)) $$(SREQ$(1)_T_$(2)_H_$(3))
 CTEST_DEPS_cfail-full_$(1)-T-$(2)-H-$(3) = $$(CFAIL_FULL_TESTS) $$(CSREQ$(1)_T_$(3)_H_$(3)) $$(SREQ$(1)_T_$(2)_H_$(3))
 CTEST_DEPS_rfail_$(1)-T-$(2)-H-$(3) = $$(RFAIL_TESTS)
 CTEST_DEPS_cfail_$(1)-T-$(2)-H-$(3) = $$(CFAIL_TESTS)
@@ -737,7 +747,7 @@ endif
 
 endef
 
-CTEST_NAMES = rpass rpass-valgrind rpass-full cfail-full rfail cfail pfail \
+CTEST_NAMES = rpass rpass-valgrind rpass-full rfail-full cfail-full rfail cfail pfail \
        bench perf debuginfo-gdb debuginfo-lldb codegen rustdocck
 
 $(foreach host,$(CFG_HOST), \
@@ -746,22 +756,26 @@ $(foreach host,$(CFG_HOST), \
    $(eval $(foreach name,$(CTEST_NAMES), \
    $(eval $(call DEF_RUN_COMPILETEST,$(stage),$(target),$(host),$(name))))))))))
 
-PRETTY_NAMES = pretty-rpass pretty-rpass-valgrind pretty-rpass-full pretty-rfail pretty-bench pretty-pretty
+PRETTY_NAMES = pretty-rpass pretty-rpass-valgrind pretty-rpass-full pretty-rfail-full pretty-rfail \
+    pretty-bench pretty-pretty
 PRETTY_DEPS_pretty-rpass = $(RPASS_TESTS)
 PRETTY_DEPS_pretty-rpass-valgrind = $(RPASS_VALGRIND_TESTS)
 PRETTY_DEPS_pretty-rpass-full = $(RPASS_FULL_TESTS)
+PRETTY_DEPS_pretty-rfail-full = $(RFAIL_FULL_TESTS)
 PRETTY_DEPS_pretty-rfail = $(RFAIL_TESTS)
 PRETTY_DEPS_pretty-bench = $(BENCH_TESTS)
 PRETTY_DEPS_pretty-pretty = $(PRETTY_TESTS)
 PRETTY_DIRNAME_pretty-rpass = run-pass
 PRETTY_DIRNAME_pretty-rpass-valgrind = run-pass-valgrind
 PRETTY_DIRNAME_pretty-rpass-full = run-pass-fulldeps
+PRETTY_DIRNAME_pretty-rfail-full = run-fail-fulldeps
 PRETTY_DIRNAME_pretty-rfail = run-fail
 PRETTY_DIRNAME_pretty-bench = bench
 PRETTY_DIRNAME_pretty-pretty = pretty
 
 define DEF_PRETTY_FULLDEPS
 PRETTY_DEPS$(1)_T_$(2)_H_$(3)_pretty-rpass-full = $$(CSREQ$(1)_T_$(3)_H_$(3))
+PRETTY_DEPS$(1)_T_$(2)_H_$(3)_pretty-rfail-full = $$(CSREQ$(1)_T_$(3)_H_$(3))
 endef
 
 $(foreach host,$(CFG_HOST), \
@@ -901,6 +915,7 @@ TEST_GROUPS = \
        rpass \
     rpass-valgrind \
        rpass-full \
+       rfail-full \
        cfail-full \
        rfail \
        cfail \
@@ -918,6 +933,7 @@ TEST_GROUPS = \
        pretty-rpass \
     pretty-rpass-valgrind \
        pretty-rpass-full \
+       pretty-rfail-full \
        pretty-rfail \
        pretty-bench \
        pretty-pretty \
index f5505b6e83a6738dd073b68513a4ef5755a339e4..a648e51497e79dbcc726065863d61807733a50fd 100644 (file)
@@ -170,6 +170,9 @@ fn ignore_stage(config: &Config) -> String {
         format!("ignore-{}",
                 config.stage_id.split('-').next().unwrap())
     }
+    fn ignore_env(config: &Config) -> String {
+        format!("ignore-{}", util::get_env(&config.target).unwrap_or("<unknown>"))
+    }
     fn ignore_gdb(config: &Config, line: &str) -> bool {
         if config.mode != common::DebugInfoGdb {
             return false;
@@ -231,6 +234,7 @@ fn ignore_lldb(config: &Config, line: &str) -> bool {
         !parse_name_directive(ln, &ignore_target(config)) &&
         !parse_name_directive(ln, &ignore_architecture(config)) &&
         !parse_name_directive(ln, &ignore_stage(config)) &&
+        !parse_name_directive(ln, &ignore_env(config)) &&
         !(config.mode == common::Pretty && parse_name_directive(ln, "ignore-pretty")) &&
         !(config.target != config.host && parse_name_directive(ln, "ignore-cross-compile")) &&
         !ignore_gdb(config, ln) &&
index 3d4aebad9d69f7d9965de858b7c8601033338047..33d4f761eea841ee7730abd6f3b98bd02f9a523a 100644 (file)
@@ -1233,7 +1233,20 @@ fn compose_and_run_compiler(config: &Config, props: &TestProps,
         let mut crate_type = if aux_props.no_prefer_dynamic {
             Vec::new()
         } else {
-            vec!("--crate-type=dylib".to_string())
+            // We primarily compile all auxiliary libraries as dynamic libraries
+            // to avoid code size bloat and large binaries as much as possible
+            // for the test suite (otherwise including libstd statically in all
+            // executables takes up quite a bit of space).
+            //
+            // For targets like MUSL, however, there is no support for dynamic
+            // libraries so we just go back to building a normal library. Note,
+            // however, that if the library is built with `force_host` then it's
+            // ok to be a dylib as the host should always support dylibs.
+            if config.target.contains("musl") && !aux_props.force_host {
+                vec!("--crate-type=lib".to_string())
+            } else {
+                vec!("--crate-type=dylib".to_string())
+            }
         };
         crate_type.extend(extra_link_args.clone().into_iter());
         let aux_args =
index a8b26cb3ef76835a5fb498ca76a347eabcfee5e8..184d62db45114682d21ffe8303424c89e7f5405e 100644 (file)
@@ -60,6 +60,10 @@ pub fn get_arch(triple: &str) -> &'static str {
     panic!("Cannot determine Architecture from triple");
 }
 
+pub fn get_env(triple: &str) -> Option<&str> {
+    triple.split('-').nth(3)
+}
+
 pub fn make_new_path(path: &str) -> String {
     assert!(cfg!(windows));
     // Windows just uses PATH as the library search path, so we have to
index 3d9a5bafbd71ea2dba50df0c8c52d4fccd053edb..cceab31c61db1da60b0887face14d1492b33e557 100644 (file)
@@ -96,12 +96,16 @@ explicit codepoint lists. [^inputformat]
 ## Special Unicode Productions
 
 The following productions in the Rust grammar are defined in terms of Unicode
-properties: `ident`, `non_null`, `non_star`, `non_eol`, `non_slash_or_star`,
-`non_single_quote` and `non_double_quote`.
+properties: `ident`, `non_null`, `non_eol`, `non_single_quote` and
+`non_double_quote`.
 
 ### Identifiers
 
-The `ident` production is any nonempty Unicode string of the following form:
+The `ident` production is any nonempty Unicode[^non_ascii_idents] string of
+the following form:
+
+[^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`
@@ -118,8 +122,6 @@ Some productions are defined by exclusion of particular Unicode characters:
 
 - `non_null` is any single Unicode character aside from `U+0000` (null)
 - `non_eol` is `non_null` restricted to exclude `U+000A` (`'\n'`)
-- `non_star` is `non_null` restricted to exclude `U+002A` (`*`)
-- `non_slash_or_star` is `non_null` restricted to exclude `U+002F` (`/`) and `U+002A` (`*`)
 - `non_single_quote` is `non_null` restricted to exclude `U+0027`  (`'`)
 - `non_double_quote` is `non_null` restricted to exclude `U+0022` (`"`)
 
@@ -152,19 +154,19 @@ token : simple_token | ident | literal | symbol | whitespace token ;
 
 <p id="keyword-table-marker"></p>
 
-|          |          |          |          |        |
-|----------|----------|----------|----------|--------|
-| abstract | alignof  | as       | become   | box    |
-| break    | const    | continue | crate    | do     |
-| else     | enum     | extern   | false    | final  |
-| fn       | for      | if       | impl     | in     |
-| let      | loop     | match    | mod      | move   |
-| mut      | offsetof | once     | override | priv   |
-| proc     | pub      | pure     | ref      | return |
-| sizeof   | static   | self     | struct   | super  |
-| true     | trait    | type     | typeof   | unsafe |
-| unsized  | use      | virtual  | where    | while  |
-| yield    |          |          |          |        |
+|          |          |          |          |         |
+|----------|----------|----------|----------|---------|
+| abstract | alignof  | as       | become   | box     |
+| break    | const    | continue | crate    | do      |
+| else     | enum     | extern   | false    | final   |
+| fn       | for      | if       | impl     | in      |
+| let      | loop     | macro    | match    | mod     |
+| move     | mut      | offsetof | override | priv    |
+| proc     | pub      | pure     | ref      | return  |
+| Self     | self     | sizeof   | static   | struct  |
+| super    | trait    | true     | type     | typeof  |
+| unsafe   | unsized  | use      | virtual  | where   |
+| while    | yield    |          |          |         |
 
 
 Each of these keywords has special meaning in its grammar, and all of them are
@@ -524,6 +526,15 @@ array_elems : [expr [',' expr]*] | [expr ',' ".." expr] ;
 idx_expr : expr '[' expr ']' ;
 ```
 
+### Range expressions
+
+```antlr
+range_expr : expr ".." expr |
+             expr ".." |
+             ".." expr |
+             ".." ;
+```
+
 ### Unary operator expressions
 
 **FIXME:** grammar?
@@ -610,7 +621,7 @@ lambda_expr : '|' ident_list '|' expr ;
 ### While loops
 
 ```antlr
-while_expr : "while" no_struct_literal_expr '{' block '}' ;
+while_expr : [ lifetime ':' ] "while" no_struct_literal_expr '{' block '}' ;
 ```
 
 ### Infinite loops
@@ -634,7 +645,7 @@ continue_expr : "continue" [ lifetime ];
 ### For expressions
 
 ```antlr
-for_expr : "for" pat "in" no_struct_literal_expr '{' block '}' ;
+for_expr : [ lifetime ':' ] "for" pat "in" no_struct_literal_expr '{' block '}' ;
 ```
 
 ### If expressions
index 1cedbf299c327949f370b08dc2bda99e5467591b..a71f8cf4250a6465f5ce6a0799f409a509032f30 100644 (file)
@@ -29,41 +29,6 @@ You may also be interested in the [grammar].
 
 # Notation
 
-Rust's grammar is defined over Unicode code points, each conventionally denoted
-`U+XXXX`, for 4 or more hexadecimal digits `X`. _Most_ of Rust's grammar is
-confined to the ASCII range of Unicode, and is described in this document by a
-dialect of Extended Backus-Naur Form (EBNF), specifically a dialect of EBNF
-supported by common automated LL(k) parsing tools such as `llgen`, rather than
-the dialect given in ISO 14977. The dialect can be defined self-referentially
-as follows:
-
-```{.ebnf .notation}
-grammar : rule + ;
-rule    : nonterminal ':' productionrule ';' ;
-productionrule : production [ '|' production ] * ;
-production : term * ;
-term : element repeats ;
-element : LITERAL | IDENTIFIER | '[' productionrule ']' ;
-repeats : [ '*' | '+' ] NUMBER ? | NUMBER ? | '?' ;
-```
-
-Where:
-
-- Whitespace in the grammar is ignored.
-- Square brackets are used to group rules.
-- `LITERAL` is a single printable ASCII character, or an escaped hexadecimal
-  ASCII code of the form `\xQQ`, in single quotes, denoting the corresponding
-  Unicode code point `U+00QQ`.
-- `IDENTIFIER` is a nonempty string of ASCII letters and underscores.
-- The `repeat` forms apply to the adjacent `element`, and are as follows:
-  - `?` means zero or one repetition
-  - `*` means zero or more repetitions
-  - `+` means one or more repetitions
-  - NUMBER trailing a repeat symbol gives a maximum repetition count
-  - NUMBER on its own gives an exact repetition count
-
-This EBNF dialect should hopefully be familiar to many readers.
-
 ## Unicode productions
 
 A few productions in Rust's grammar permit Unicode code points outside the ASCII
@@ -100,15 +65,12 @@ explicit code point lists. [^inputformat]
   provided to the grammar verifier, restricted to ASCII range, when verifying the
   grammar in this document.
 
-## Special Unicode Productions
-
-The following productions in the Rust grammar are defined in terms of Unicode
-properties: `ident`, `non_null`, `non_star`, `non_eol`, `non_slash_or_star`,
-`non_single_quote` and `non_double_quote`.
+## Identifiers
 
-### Identifiers
+An identifier is any nonempty Unicode[^non_ascii_idents] string of the following form:
 
-The `ident` production is any nonempty Unicode string of the following form:
+[^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`
@@ -119,54 +81,34 @@ that does _not_ occur in the set of [keywords](#keywords).
 > character ranges used to form the more familiar C and Java language-family
 > identifiers.
 
-### Delimiter-restricted productions
-
-Some productions are defined by exclusion of particular Unicode characters:
-
-- `non_null` is any single Unicode character aside from `U+0000` (null)
-- `non_eol` is `non_null` restricted to exclude `U+000A` (`'\n'`)
-- `non_star` is `non_null` restricted to exclude `U+002A` (`*`)
-- `non_slash_or_star` is `non_null` restricted to exclude `U+002F` (`/`) and `U+002A` (`*`)
-- `non_single_quote` is `non_null` restricted to exclude `U+0027`  (`'`)
-- `non_double_quote` is `non_null` restricted to exclude `U+0022` (`"`)
-
 ## Comments
 
-```{.ebnf .gram}
-comment : block_comment | line_comment ;
-block_comment : "/*" block_comment_body * "*/" ;
-block_comment_body : [block_comment | character] * ;
-line_comment : "//" non_eol * ;
-```
-
-Comments in Rust code follow the general C++ style of line and block-comment
-forms. Nested block comments are supported.
+Comments in Rust code follow the general C++ style of line (`//`) and
+block (`/* ... */`) comment forms. Nested block comments are supported.
 
 Line comments beginning with exactly _three_ slashes (`///`), and block
 comments beginning with exactly one repeated asterisk in the block-open
 sequence (`/**`), are interpreted as a special syntax for `doc`
 [attributes](#attributes). That is, they are equivalent to writing
-`#[doc="..."]` around the body of the comment (this includes the comment
-characters themselves, i.e. `/// Foo` turns into `#[doc="/// Foo"]`).
+`#[doc="..."]` around the body of the comment, i.e., `/// Foo` turns into
+`#[doc="Foo"]`.
 
 Line comments beginning with `//!` and block comments beginning with `/*!` are
 doc comments that apply to the parent of the comment, rather than the item
 that follows.  That is, they are equivalent to writing `#![doc="..."]` around
-the body of the comment. `//!` comments are usually used to display
-information on the crate index page.
+the body of the comment. `//!` comments are usually used to document
+modules that occupy a source file.
 
 Non-doc comments are interpreted as a form of whitespace.
 
 ## Whitespace
 
-```{.ebnf .gram}
-whitespace_char : '\x20' | '\x09' | '\x0a' | '\x0d' ;
-whitespace : [ whitespace_char | comment ] + ;
-```
+Whitespace is any non-empty string containing any the following characters:
 
-The `whitespace_char` production is any nonempty Unicode string consisting of
-any of the following Unicode characters: `U+0020` (space, `' '`), `U+0009`
-(tab, `'\t'`), `U+000A` (LF, `'\n'`), `U+000D` (CR, `'\r'`).
+- `U+0020` (space, `' '`)
+- `U+0009` (tab, `'\t'`)
+- `U+000A` (LF, `'\n'`)
+- `U+000D` (CR, `'\r'`)
 
 Rust is a "free-form" language, meaning that all forms of whitespace serve only
 to separate _tokens_ in the grammar, and have no semantic significance.
@@ -176,41 +118,11 @@ with any other legal whitespace element, such as a single space character.
 
 ## Tokens
 
-```{.ebnf .gram}
-simple_token : keyword | unop | binop ;
-token : simple_token | ident | literal | symbol | whitespace token ;
-```
-
 Tokens are primitive productions in the grammar defined by regular
 (non-recursive) languages. "Simple" tokens are given in [string table
 production](#string-table-productions) form, and occur in the rest of the
 grammar as double-quoted strings. Other tokens have exact rules given.
 
-### Keywords
-
-<p id="keyword-table-marker"></p>
-
-|          |          |          |          |         |
-|----------|----------|----------|----------|---------|
-| abstract | alignof  | as       | become   | box     |
-| break    | const    | continue | crate    | do      |
-| else     | enum     | extern   | false    | final   |
-| fn       | for      | if       | impl     | in      |
-| let      | loop     | macro    | match    | mod     |
-| move     | mut      | offsetof | override | priv    |
-| proc     | pub      | pure     | ref      | return  |
-| Self     | self     | sizeof   | static   | struct  |
-| super    | trait    | true     | type     | typeof  |
-| unsafe   | unsized  | use      | virtual  | where   |
-| while    | yield    |          |          |         |
-
-
-Each of these keywords has special meaning in its grammar, and all of them are
-excluded from the `ident` rule.
-
-Note that some of these keywords are reserved, and do not currently do
-anything.
-
 ### Literals
 
 A literal is an expression consisting of a single token, rather than a sequence
@@ -218,11 +130,6 @@ of tokens, that immediately and directly denotes the value it evaluates to,
 rather than referring to it by name or some other evaluation rule. A literal is
 a form of constant expression, so is evaluated (primarily) at compile time.
 
-```{.ebnf .gram}
-lit_suffix : ident;
-literal : [ string_lit | char_lit | byte_string_lit | byte_lit | num_lit ] lit_suffix ?;
-```
-
 The optional suffix is only used for certain numeric literals, but is
 reserved for future extension, that is, the above gives the lexical
 grammar, but a Rust parser will reject everything but the 12 special
@@ -275,32 +182,6 @@ cases mentioned in [Number literals](#number-literals) below.
 
 #### Character and string literals
 
-```{.ebnf .gram}
-char_lit : '\x27' char_body '\x27' ;
-string_lit : '"' string_body * '"' | 'r' raw_string ;
-
-char_body : non_single_quote
-          | '\x5c' [ '\x27' | common_escape | unicode_escape ] ;
-
-string_body : non_double_quote
-            | '\x5c' [ '\x22' | common_escape | unicode_escape ] ;
-raw_string : '"' raw_string_body '"' | '#' raw_string '#' ;
-
-common_escape : '\x5c'
-              | 'n' | 'r' | 't' | '0'
-              | 'x' hex_digit 2
-
-unicode_escape : 'u' '{' hex_digit+ 6 '}';
-
-hex_digit : 'a' | 'b' | 'c' | 'd' | 'e' | 'f'
-          | 'A' | 'B' | 'C' | 'D' | 'E' | 'F'
-          | dec_digit ;
-oct_digit : '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' ;
-dec_digit : '0' | nonzero_dec ;
-nonzero_dec: '1' | '2' | '3' | '4'
-           | '5' | '6' | '7' | '8' | '9' ;
-```
-
 ##### Character literals
 
 A _character literal_ is a single Unicode character enclosed within two
@@ -311,13 +192,13 @@ which must be _escaped_ by a preceding `U+005C` character (`\`).
 
 A _string literal_ is a sequence of any Unicode characters enclosed within two
 `U+0022` (double-quote) characters, with the exception of `U+0022` itself,
-which must be _escaped_ by a preceding `U+005C` character (`\`), or a _raw
-string literal_.
+which must be _escaped_ by a preceding `U+005C` character (`\`).
 
-A multi-line string literal may be defined by terminating each line with a
-`U+005C` character (`\`) immediately before the newline. This causes the
-`U+005C` character, the newline, and all whitespace at the beginning of the
-next line to be ignored.
+Line-break characters are allowed in string literals. Normally they represent
+themselves (i.e. no translation), but as a special exception, when a `U+005C`
+character (`\`) occurs immediately before the newline, the `U+005C` character,
+the newline, and all whitespace at the beginning of the next line are ignored.
+Thus `a` and `b` are equal:
 
 ```rust
 let a = "foobar";
@@ -349,11 +230,10 @@ following forms:
 
 Raw string literals do not process any escapes. They start with the character
 `U+0072` (`r`), followed by zero or more of the character `U+0023` (`#`) and a
-`U+0022` (double-quote) character. The _raw string body_ is not defined in the
-EBNF grammar above: it can contain any sequence of Unicode characters and is
-terminated only by another `U+0022` (double-quote) character, followed by the
-same number of `U+0023` (`#`) characters that preceded the opening `U+0022`
-(double-quote) character.
+`U+0022` (double-quote) character. The _raw string body_ can contain any sequence
+of Unicode characters and is terminated only by another `U+0022` (double-quote)
+character, followed by the same number of `U+0023` (`#`) characters that preceded
+the opening `U+0022` (double-quote) character.
 
 All Unicode characters contained in the raw string body represent themselves,
 the characters `U+0022` (double-quote) (except when followed by at least as
@@ -375,26 +255,14 @@ r##"foo #"# bar"##;                // foo #"# bar
 
 #### Byte and byte string literals
 
-```{.ebnf .gram}
-byte_lit : "b\x27" byte_body '\x27' ;
-byte_string_lit : "b\x22" string_body * '\x22' | "br" raw_byte_string ;
-
-byte_body : ascii_non_single_quote
-          | '\x5c' [ '\x27' | common_escape ] ;
-
-byte_string_body : ascii_non_double_quote
-            | '\x5c' [ '\x22' | common_escape ] ;
-raw_byte_string : '"' raw_byte_string_body '"' | '#' raw_byte_string '#' ;
-
-```
-
 ##### Byte literals
 
 A _byte literal_ is a single ASCII character (in the `U+0000` to `U+007F`
-range) enclosed within two `U+0027` (single-quote) characters, with the
-exception of `U+0027` itself, which must be _escaped_ by a preceding U+005C
-character (`\`), or a single _escape_. It is equivalent to a `u8` unsigned
-8-bit integer _number literal_.
+range) or a single _escape_ preceded by the characters `U+0062` (`b`) and
+`U+0027` (single-quote), and followed by the character `U+0027`. If the character
+`U+0027` is present within the literal, it must be _escaped_ by a preceding
+`U+005C` (`\`) character. It is equivalent to a `u8` unsigned 8-bit integer
+_number literal_.
 
 ##### Byte string literals
 
@@ -403,7 +271,7 @@ preceded by the characters `U+0062` (`b`) and `U+0022` (double-quote), and
 followed by the character `U+0022`. If the character `U+0022` is present within
 the literal, it must be _escaped_ by a preceding `U+005C` (`\`) character.
 Alternatively, a byte string literal can be a _raw byte string literal_, defined
-below. A byte string literal is equivalent to a `&'static [u8]` borrowed array
+below. A byte string literal of length `n` is equivalent to a `&'static [u8; n]` borrowed fixed-sized array
 of unsigned 8-bit integers.
 
 Some additional _escapes_ are available in either byte or non-raw byte string
@@ -424,11 +292,10 @@ following forms:
 Raw byte string literals do not process any escapes. They start with the
 character `U+0062` (`b`), followed by `U+0072` (`r`), followed by zero or more
 of the character `U+0023` (`#`), and a `U+0022` (double-quote) character. The
-_raw string body_ is not defined in the EBNF grammar above: it can contain any
-sequence of ASCII characters and is terminated only by another `U+0022`
-(double-quote) character, followed by the same number of `U+0023` (`#`)
-characters that preceded the opening `U+0022` (double-quote) character. A raw
-byte string literal can not contain any non-ASCII byte.
+_raw string body_ can contain any sequence of ASCII characters and is terminated
+only by another `U+0022` (double-quote) character, followed by the same number of
+`U+0023` (`#`) characters that preceded the opening `U+0022` (double-quote)
+character. A raw byte string literal can not contain any non-ASCII byte.
 
 All characters contained in the raw string body represent their ASCII encoding,
 the characters `U+0022` (double-quote) (except when followed by at least as
@@ -450,19 +317,6 @@ b"\\x52"; br"\x52";                  // \x52
 
 #### Number literals
 
-```{.ebnf .gram}
-num_lit : nonzero_dec [ dec_digit | '_' ] * float_suffix ?
-        | '0' [       [ dec_digit | '_' ] * float_suffix ?
-              | 'b'   [ '1' | '0' | '_' ] +
-              | 'o'   [ oct_digit | '_' ] +
-              | 'x'   [ hex_digit | '_' ] +  ] ;
-
-float_suffix : [ exponent | '.' dec_lit exponent ? ] ? ;
-
-exponent : ['E' | 'e'] ['-' | '+' ] ? dec_lit ;
-dec_lit : [ dec_digit | '_' ] + ;
-```
-
 A _number literal_ is either an _integer literal_ or a _floating-point
 literal_. The grammar for recognizing the two kinds of literals is mixed.
 
@@ -512,11 +366,19 @@ A _floating-point literal_ has one of two forms:
   optionally followed by another decimal literal, with an optional _exponent_.
 * A single _decimal literal_ followed by an _exponent_.
 
-By default, a floating-point literal has a generic type, and, like integer
-literals, the type must be uniquely determined from the context. There are two valid
+Like integer literals, a floating-point literal may be followed by a
+suffix, so long as the pre-suffix part does not end with `U+002E` (`.`).
+The suffix forcibly sets the type of the literal. There are two valid
 _floating-point suffixes_, `f32` and `f64` (the 32-bit and 64-bit floating point
 types), which explicitly determine the type of the literal.
 
+The type of an _unsuffixed_ floating-point literal is determined by type
+inference. If a floating-point type can be _uniquely_ determined from the
+surrounding program context, the unsuffixed floating-point literal has that type.
+If the program context underconstrains the type, it defaults to double-precision `f64`;
+if the program context overconstrains the type, it is considered a static type
+error.
+
 Examples of floating-point literals of various forms:
 
 ```
@@ -540,12 +402,6 @@ The two values of the boolean type are written `true` and `false`.
 
 ### Symbols
 
-```{.ebnf .gram}
-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
 completeness as the set of remaining miscellaneous printable tokens that do not
@@ -555,16 +411,6 @@ operators](#binary-operator-expressions), or [keywords](#keywords).
 
 ## Paths
 
-```{.ebnf .gram}
-expr_path : [ "::" ] ident [ "::" expr_path_tail ] + ;
-expr_path_tail : '<' type_expr [ ',' type_expr ] + '>'
-               | expr_path ;
-
-type_path : ident [ type_path_tail ] + ;
-type_path_tail : '<' type_expr [ ',' type_expr ] + '>'
-               | "::" type_path ;
-```
-
 A _path_ is a sequence of one or more path components _logically_ separated by
 a namespace qualifier (`::`). If a path consists of only one component, it may
 refer to either an [item](#items) or a [variable](#variables) in a local control
@@ -660,19 +506,6 @@ Users of `rustc` can define new syntax extensions in two ways:
 
 ## Macros
 
-```{.ebnf .gram}
-expr_macro_rules : "macro_rules" '!' ident '(' macro_rule * ')' ;
-macro_rule : '(' matcher * ')' "=>" '(' transcriber * ')' ';' ;
-matcher : '(' matcher * ')' | '[' matcher * ']'
-        | '{' matcher * '}' | '$' ident ':' ident
-        | '$' '(' matcher * ')' sep_token? [ '*' | '+' ]
-        | non_special_token ;
-transcriber : '(' transcriber * ')' | '[' transcriber * ']'
-            | '{' transcriber * '}' | '$' ident
-            | '$' '(' transcriber * ')' sep_token? [ '*' | '+' ]
-            | non_special_token ;
-```
-
 `macro_rules` allows users to define syntax extension in a declarative way.  We
 call such extensions "macros by example" or simply "macros" — to be distinguished
 from the "procedural macros" defined in [compiler plugins][plugin].
@@ -811,12 +644,6 @@ Crates contain [items](#items), each of which may have some number of
 
 ## Items
 
-```{.ebnf .gram}
-item : extern_crate_decl | use_decl | mod_item | fn_item | type_item
-     | struct_item | enum_item | static_item | trait_item | impl_item
-     | extern_block ;
-```
-
 An _item_ is a component of a crate. Items are organized within a crate by a
 nested set of [modules](#modules). Every crate has a single "outermost"
 anonymous module; all further items within the crate have [paths](#paths)
@@ -863,11 +690,6 @@ no notion of type abstraction: there are no first-class "forall" types.
 
 ### Modules
 
-```{.ebnf .gram}
-mod_item : "mod" ident ( ';' | '{' mod '}' );
-mod : item * ;
-```
-
 A module is a container for zero or more [items](#items).
 
 A _module item_ is a module, surrounded in braces, named, and prefixed with the
@@ -928,11 +750,6 @@ mod thread {
 
 ##### Extern crate declarations
 
-```{.ebnf .gram}
-extern_crate_decl : "extern" "crate" crate_name
-crate_name: ident | ( string_lit "as" ident )
-```
-
 An _`extern crate` declaration_ specifies a dependency on an external crate.
 The external crate is then bound into the declaring scope as the `ident`
 provided in the `extern_crate_decl`.
@@ -958,17 +775,6 @@ extern crate std as ruststd; // linking to 'std' under another name
 
 ##### Use declarations
 
-```{.ebnf .gram}
-use_decl : "pub" ? "use" [ path "as" ident
-                          | path_glob ] ;
-
-path_glob : ident [ "::" [ path_glob
-                          | '*' ] ] ?
-          | '{' path_item [ ',' path_item ] * '}' ;
-
-path_item : ident | "self" ;
-```
-
 A _use declaration_ creates one or more local name bindings synonymous with
 some other [path](#paths). Usually a `use` declaration is used to shorten the
 path required to refer to a module item. These declarations may appear at the
@@ -1413,10 +1219,6 @@ it were `Bar(i32)`, this is disallowed.
 
 ### Constant items
 
-```{.ebnf .gram}
-const_item : "const" ident ':' type '=' expr ';' ;
-```
-
 A *constant item* is a named _constant value_ which is not associated with a
 specific memory location in the program. Constants are essentially inlined
 wherever they are used, meaning that they are copied directly into the relevant
@@ -1453,10 +1255,6 @@ const BITS_N_STRINGS: BitsNStrings<'static> = BitsNStrings {
 
 ### Static items
 
-```{.ebnf .gram}
-static_item : "static" ident ':' type '=' expr ';' ;
-```
-
 A *static item* is similar to a *constant*, except that it represents a precise
 memory location in the program. A static is never "inlined" at the usage site,
 and all references to it refer to the same memory location. Static items have
@@ -1711,11 +1509,6 @@ impl Seq<bool> for u32 {
 
 ### External blocks
 
-```{.ebnf .gram}
-extern_block_item : "extern" '{' extern_block '}' ;
-extern_block : [ foreign_fn ] * ;
-```
-
 External blocks form the basis for Rust's foreign function interface.
 Declarations in an external block describe symbols in external, non-Rust
 libraries.
@@ -1915,13 +1708,6 @@ the namespace hierarchy as it normally would.
 
 ## Attributes
 
-```{.ebnf .gram}
-attribute : '#' '!' ? '[' meta_item ']' ;
-meta_item : ident [ '=' literal
-                  | '(' meta_seq ')' ] ? ;
-meta_seq : meta_item [ ',' meta_seq ] ? ;
-```
-
 Any item declaration may have an _attribute_ applied to it. Attributes in Rust
 are modeled on Attributes in ECMA-335, with the syntax coming from ECMA-334
 (C#). An attribute is a general, free-form metadatum that is interpreted
@@ -2188,7 +1974,7 @@ For any lint check `C`:
 
 The lint checks supported by the compiler can be found via `rustc -W help`,
 along with their default settings.  [Compiler
-plugins](book/plugins.html#lint-plugins) can provide additional lint checks.
+plugins](book/compiler-plugins.html#lint-plugins) can provide additional lint checks.
 
 ```{.ignore}
 mod m1 {
@@ -2349,7 +2135,10 @@ The currently implemented features of the reference compiler are:
           semantics are likely to change, so this macro usage must be opted
           into.
 
-* `associated_types` - Allows type aliases in traits. Experimental.
+* `associated_consts` - Allows constants to be defined in `impl` and `trait`
+                        blocks, so that they can be associated with a type or
+                        trait in a similar manner to methods and associated
+                        types.
 
 * `box_patterns` - Allows `box` patterns, the exact semantics of which
                    is subject to change.
@@ -2503,7 +2292,7 @@ The currently implemented features of the reference compiler are:
                               terms of encapsulation).
 
 If a feature is promoted to a language feature, then all existing programs will
-start to receive compilation warnings about #[feature] directives which enabled
+start to receive compilation warnings about `#![feature]` directives which enabled
 the new feature (because the directive is no longer necessary). However, if a
 feature is decided to be removed from the language, errors will be issued (if
 there isn't a parser error first). The directive in this case is no longer
@@ -2554,11 +2343,6 @@ in meaning to declaring the item outside the statement block.
 
 #### Variable declarations
 
-```{.ebnf .gram}
-let_decl : "let" pat [':' type ] ? [ init ] ? ';' ;
-init : [ '=' ] expr ;
-```
-
 A _variable declaration_ introduces a new set of variable, given by a pattern. The
 pattern may be followed by a type annotation, and/or an initializer expression.
 When no type annotation is given, the compiler will infer the type, or signal
@@ -2649,7 +2433,7 @@ parentheses. They are used to create [tuple-typed](#tuple-types) values.
 ```{.tuple}
 (0,);
 (0.0, 4.5);
-("a", 4us, true);
+("a", 4usize, true);
 ```
 
 ### Unit expressions
@@ -2659,15 +2443,6 @@ the same name.
 
 ### Structure expressions
 
-```{.ebnf .gram}
-struct_expr : expr_path '{' ident ':' expr
-                      [ ',' ident ':' expr ] *
-                      [ ".." expr ] '}' |
-              expr_path '(' expr
-                      [ ',' expr ] * ')' |
-              expr_path ;
-```
-
 There are several forms of structure expressions. A _structure expression_
 consists of the [path](#paths) of a [structure item](#structures), followed by
 a brace-enclosed list of one or more comma-separated name-value pairs,
@@ -2718,11 +2493,6 @@ Point3d {y: 0, z: 10, .. base};
 
 ### Block expressions
 
-```{.ebnf .gram}
-block_expr : '{' [ stmt ';' | item ] *
-                 [ expr ] '}' ;
-```
-
 A _block expression_ is similar to a module in terms of the declarations that
 are possible. Each block conceptually introduces a new namespace scope. Use
 items can bring new names into scopes and declared items are in scope for only
@@ -2745,10 +2515,6 @@ assert_eq!(5, x);
 
 ### Method-call expressions
 
-```{.ebnf .gram}
-method_call_expr : expr '.' ident paren_expr_list ;
-```
-
 A _method call_ consists of an expression followed by a single dot, an
 identifier, and a parenthesized expression-list. Method calls are resolved to
 methods on specific traits, either statically dispatching to a method if the
@@ -2757,10 +2523,6 @@ the left-hand-side expression is an indirect [trait object](#trait-objects).
 
 ### Field expressions
 
-```{.ebnf .gram}
-field_expr : expr '.' ident ;
-```
-
 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
@@ -2781,12 +2543,6 @@ automatically dereferenced to make the field access possible.
 
 ### Array expressions
 
-```{.ebnf .gram}
-array_expr : '[' "mut" ? array_elems? ']' ;
-
-array_elems : [expr [',' expr]*] | [expr ';' expr] ;
-```
-
 An [array](#array,-and-slice-types) _expression_ is written by enclosing zero
 or more comma-separated expressions of uniform type in square brackets.
 
@@ -2803,10 +2559,6 @@ constant expression that can be evaluated at compile time, such as a
 
 ### Index expressions
 
-```{.ebnf .gram}
-idx_expr : expr '[' expr ']' ;
-```
-
 [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
@@ -2823,13 +2575,6 @@ _panicked state_.
 
 ### Range expressions
 
-```{.ebnf .gram}
-range_expr : expr ".." expr |
-             expr ".." |
-             ".." expr |
-             ".." ;
-```
-
 The `..` operator will construct an object of one of the `std::ops::Range` variants.
 
 ```
@@ -2872,10 +2617,6 @@ before the expression they apply to.
 
 ### Binary operator expressions
 
-```{.ebnf .gram}
-binop_expr : expr binop expr ;
-```
-
 Binary operators expressions are given in terms of [operator
 precedence](#operator-precedence).
 
@@ -3036,10 +2777,6 @@ An expression enclosed in parentheses evaluates to the result of the enclosed
 expression. Parentheses can be used to explicitly specify evaluation order
 within an expression.
 
-```{.ebnf .gram}
-paren_expr : '(' expr ')' ;
-```
-
 An example of a parenthesized expression:
 
 ```
@@ -3049,12 +2786,6 @@ let x: i32 = (2 + 3) * 4;
 
 ### Call expressions
 
-```{.ebnf .gram}
-expr_list : [ expr [ ',' expr ]* ] ? ;
-paren_expr_list : '(' expr_list ')' ;
-call_expr : expr paren_expr_list ;
-```
-
 A _call expression_ invokes a function, providing zero or more input variables
 and an optional location to move the function's output into. If the function
 eventually returns, then the expression completes.
@@ -3070,11 +2801,6 @@ let pi: Result<f32, _> = "3.14".parse();
 
 ### Lambda expressions
 
-```{.ebnf .gram}
-ident_list : [ ident [ ',' ident ]* ] ? ;
-lambda_expr : '|' ident_list '|' expr ;
-```
-
 A _lambda expression_ (sometimes called an "anonymous function expression")
 defines a function and denotes it as a value, in a single expression. A lambda
 expression is a pipe-symbol-delimited (`|`) list of identifiers followed by an
@@ -3118,10 +2844,6 @@ ten_times(|j| println!("hello, {}", j));
 
 A `loop` expression denotes an infinite loop.
 
-```{.ebnf .gram}
-loop_expr : [ lifetime ':' ] "loop" '{' block '}';
-```
-
 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
@@ -3131,10 +2853,6 @@ expressions](#continue-expressions).
 
 ### Break expressions
 
-```{.ebnf .gram}
-break_expr : "break" [ lifetime ];
-```
-
 A `break` expression has an optional _label_. If the label is absent, then
 executing a `break` expression immediately terminates the innermost loop
 enclosing it. It is only permitted in the body of a loop. If the label is
@@ -3143,10 +2861,6 @@ be the innermost label enclosing the `break` expression, but must enclose it.
 
 ### Continue expressions
 
-```{.ebnf .gram}
-continue_expr : "continue" [ lifetime ];
-```
-
 A `continue` expression has an optional _label_. If the label is absent, then
 executing a `continue` expression immediately terminates the current iteration
 of the innermost loop enclosing it, returning control to the loop *head*. In
@@ -3160,10 +2874,6 @@ A `continue` expression is only permitted in the body of a loop.
 
 ### While loops
 
-```{.ebnf .gram}
-while_expr : [ lifetime ':' ] "while" no_struct_literal_expr '{' block '}' ;
-```
-
 A `while` loop begins by evaluating the boolean loop conditional expression.
 If the loop conditional expression evaluates to `true`, the loop body block
 executes and control returns to the loop conditional expression. If the loop
@@ -3187,26 +2897,22 @@ loops](#infinite-loops), [break expressions](#break-expressions), and
 
 ### For expressions
 
-```{.ebnf .gram}
-for_expr : [ lifetime ':' ] "for" pat "in" no_struct_literal_expr '{' block '}' ;
-```
-
 A `for` expression is a syntactic construct for looping over elements provided
-by an implementation of `std::iter::Iterator`.
+by an implementation of `std::iter::IntoIterator`.
 
 An example of a for loop over the contents of an array:
 
 ```
 # type Foo = i32;
-# fn bar(f: Foo) { }
+# fn bar(f: &Foo) { }
 # let a = 0;
 # let b = 0;
 # let c = 0;
 
 let v: &[Foo] = &[a, b, c];
 
-for e in v.iter() {
-    bar(*e);
+for e in v {
+    bar(e);
 }
 ```
 
@@ -3226,14 +2932,6 @@ loops](#infinite-loops), [break expressions](#break-expressions), and
 
 ### If expressions
 
-```{.ebnf .gram}
-if_expr : "if" no_struct_literal_expr '{' block '}'
-          else_tail ? ;
-
-else_tail : "else" [ if_expr | if_let_expr
-                   | '{' block '}' ] ;
-```
-
 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
 number of `else if` conditions and blocks, and an optional trailing `else`
@@ -3246,14 +2944,6 @@ if` condition is evaluated. If all `if` and `else if` conditions evaluate to
 
 ### Match expressions
 
-```{.ebnf .gram}
-match_expr : "match" no_struct_literal_expr '{' match_arm * '}' ;
-
-match_arm : attribute * match_pat "=>" [ expr "," | '{' block '}' ] ;
-
-match_pat : pat [ '|' pat ] * [ "if" expr ] ? ;
-```
-
 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,
@@ -3370,12 +3060,6 @@ let message = match maybe_digit {
 
 ### If let expressions
 
-```{.ebnf .gram}
-if_let_expr : "if" "let" pat '=' expr '{' block '}'
-               else_tail ? ;
-else_tail : "else" [ if_expr | if_let_expr | '{' block '}' ] ;
-```
-
 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
 expression on the right hand side of the let statement matches the pattern, the corresponding
@@ -3383,10 +3067,6 @@ block will execute, otherwise flow proceeds to the first `else` block that follo
 
 ### While let loops
 
-```{.ebnf .gram}
-while_let_expr : "while" "let" pat '=' expr '{' block '}' ;
-```
-
 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
 expression on the right hand side of the let statement matches the pattern, the
@@ -3395,10 +3075,6 @@ Otherwise, the while expression completes.
 
 ### Return expressions
 
-```{.ebnf .gram}
-return_expr : "return" expr ? ;
-```
-
 Return expressions are denoted with the keyword `return`. Evaluating a `return`
 expression moves its argument into the designated output location for the
 current function call, destroys the current function activation frame, and
@@ -3430,17 +3106,10 @@ User-defined types have limited capabilities.
 
 The primitive types are the following:
 
-* The "unit" type `()`, having the single "unit" value `()` (occasionally called
-  "nil"). [^unittype]
 * The boolean type `bool` with values `true` and `false`.
 * The machine types.
 * The machine-dependent integer and floating-point types.
 
-[^unittype]: The "unit" value `()` is *not* a sentinel "null pointer" value for
-    reference variables; the "unit" type is the implicit return type from functions
-    otherwise lacking a return type, and can be used in other contexts (such as
-    message-sending or type-parametric code) as a zero-size type.]
-
 #### Machine types
 
 The machine types are the following:
@@ -3481,7 +3150,7 @@ UTF-32 string.
 A value of type `str` is a Unicode string, represented as an array of 8-bit
 unsigned bytes holding a sequence of UTF-8 code points. Since `str` is of
 unknown size, it is not a _first-class_ type, but can only be instantiated
-through a pointer type, such as `&str` or `String`.
+through a pointer type, such as `&str`.
 
 ### Tuple types
 
@@ -3537,7 +3206,7 @@ to an array or slice is always bounds-checked.
 A `struct` *type* is a heterogeneous product of other types, called the
 *fields* of the type.[^structtype]
 
-[^structtype]: `struct` types are analogous `struct` types in C,
+[^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.
 
@@ -3551,7 +3220,7 @@ a corresponding struct *expression*; the resulting `struct` value will always
 have the same memory layout.
 
 The fields of a `struct` may be qualified by [visibility
-modifiers](#re-exporting-and-visibility), to allow access to data in a
+modifiers](#visibility-and-privacy), to allow access to data in a
 structure outside a module.
 
 A _tuple struct_ type is just like a structure type, except that the fields are
@@ -3619,18 +3288,18 @@ varieties of pointer in Rust:
 
 * References (`&`)
   : These point to memory _owned by some other value_.
-    A reference type is written `&type` for some lifetime-variable `f`,
-    or just `&'a type` when you need an explicit lifetime.
+    A reference type is written `&type`,
+    or `&'a type` when you need to specify an explicit lifetime.
     Copying a reference is a "shallow" operation:
     it involves only copying the pointer itself.
-    Releasing a reference typically has no effect on the value it points to,
-    with the exception of temporary values, which are released when the last
-    reference to them is released.
+    Releasing a reference has no effect on the value it points to,
+    but a reference of a temporary value will keep it alive during the scope
+    of the reference itself.
 
 * Raw pointers (`*`)
   : Raw pointers are pointers without safety or liveness guarantees.
     Raw pointers are written as `*const T` or `*mut T`,
-    for example `*const int` means a raw pointer to an integer.
+    for example `*const i32` means a raw pointer to a 32-bit integer.
     Copying or dropping a raw pointer has no effect on the lifecycle of any
     other value. Dereferencing a raw pointer or converting it to any other
     pointer type is an [`unsafe` operation](#unsafe-functions).
@@ -3663,38 +3332,26 @@ x = bo(5,7);
 
 ### Closure types
 
-```{.ebnf .notation}
-closure_type := [ 'unsafe' ] [ '<' lifetime-list '>' ] '|' arg-list '|'
-                [ ':' bound-list ] [ '->' type ]
-lifetime-list := lifetime | lifetime ',' lifetime-list
-arg-list := ident ':' type | ident ':' type ',' arg-list
-bound-list := bound | bound '+' bound-list
-bound := path | lifetime
-```
-
-The type of a closure mapping an input of type `A` to an output of type `B` is
-`|A| -> B`. A closure with no arguments or return values has type `||`.
+A [lambda expression](#lambda-expressions) produces a closure value with
+a unique, anonymous type that cannot be written out.
 
-An example of creating and calling a closure:
+Depending on the requirements of the closure, its type implements one or
+more of the closure traits:
 
-```rust
-let captured_var = 10;
+* `FnOnce`
+  : The closure can be called once. A closure called as `FnOnce`
+    can move out values from its environment.
 
-let closure_no_args = || println!("captured_var={}", captured_var);
+* `FnMut`
+  : The closure can be called multiple times as mutable. A closure called as
+    `FnMut` can mutate values from its environment. `FnMut` implies
+    `FnOnce`.
 
-let closure_args = |arg: i32| -> i32 {
-  println!("captured_var={}, arg={}", captured_var, arg);
-  arg // Note lack of semicolon after 'arg'
-};
+* `Fn`
+  : The closure can be called multiple times through a shared reference.
+    A closure called as `Fn` can neither move out from nor mutate values
+    from its environment. `Fn` implies `FnMut` and `FnOnce`.
 
-fn call_closure<F: Fn(), G: Fn(i32) -> i32>(c1: F, c2: G) {
-  c1();
-  c2(2);
-}
-
-call_closure(closure_no_args, closure_args);
-
-```
 
 ### Trait objects
 
@@ -3741,19 +3398,19 @@ Within the body of an item that has type parameter declarations, the names of
 its type parameters are types:
 
 ```ignore
-fn map<A: Clone, B: Clone>(f: |A| -> B, xs: &[A]) -> Vec<B> {
+fn to_vec<A: Clone>(xs: &[A]) -> Vec<A> {
     if xs.is_empty() {
        return vec![];
     }
-    let first: B = f(xs[0].clone());
-    let mut rest: Vec<B> = map(f, xs.slice(1, xs.len()));
+    let first: A = xs[0].clone();
+    let mut rest: Vec<A> = to_vec(&xs[1..]);
     rest.insert(0, first);
-    return rest;
+    rest
 }
 ```
 
-Here, `first` has type `B`, referring to `map`'s `B` type parameter; and `rest`
-has type `Vec<B>`, a vector type with element type `B`.
+Here, `first` has type `A`, referring to `to_vec`'s `A` type parameter; and `rest`
+has type `Vec<A>`, a vector with element type `A`.
 
 ### Self types
 
@@ -3990,4 +3647,4 @@ that have since been removed):
   pattern syntax
 
 [ffi]: book/ffi.html
-[plugin]: book/plugins.html
+[plugin]: book/compiler-plugins.html
index 813660d8fdfb945e90196b3c5518d27688e71ce3..dbbe9fc3ac6da92602304f64de31b07afa01e80a 100644 (file)
@@ -1,10 +1,10 @@
 % Unit testing
 
-Unit tests should live in a `test` submodule at the bottom of the module they
-test. Mark the `test` submodule with `#[cfg(test)]` so it is only compiled when
+Unit tests should live in a `tests` submodule at the bottom of the module they
+test. Mark the `tests` submodule with `#[cfg(test)]` so it is only compiled when
 testing.
 
-The `test` module should contain:
+The `tests` module should contain:
 
 * Imports needed only for testing.
 * Functions marked with `#[test]` striving for full coverage of the parent module's
@@ -17,7 +17,7 @@ For example:
 // Excerpt from std::str
 
 #[cfg(test)]
-mod test {
+mod tests {
     #[test]
     fn test_eq() {
         assert!((eq(&"".to_owned(), &"".to_owned())));
index 01ef88dde227024c54e050e502f4ed06577025f3..a892f67d571af9bd9c7cb221c74be5c15177ed4d 100644 (file)
@@ -8,7 +8,7 @@ good at: embedding in other languages, programs with specific space and time
 requirements, and writing low-level code, like device drivers and operating
 systems. It improves on current languages targeting this space by having a
 number of compile-time safety checks that produce no runtime overhead, while
-eliminating all data races. Rust also aims to achieve ‘zero-cost abstrations’
+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.
index 7ce74e86fef63450f2cd002d2aecec07a7dcd7eb..695dc42cb6418a7d9694fe07f48235009bcf8c5d 100644 (file)
@@ -36,7 +36,6 @@
     * [Strings](strings.md)
     * [Generics](generics.md)
     * [Traits](traits.md)
-    * [Operators and Overloading](operators-and-overloading.md)
     * [Drop](drop.md)
     * [if let](if-let.md)
     * [Trait Objects](trait-objects.md)
@@ -50,6 +49,7 @@
     * [Casting between types](casting-between-types.md)
     * [Associated Types](associated-types.md)
     * [Unsized Types](unsized-types.md)
+    * [Operators and Overloading](operators-and-overloading.md)
     * [Deref coercions](deref-coercions.md)
     * [Macros](macros.md)
     * [Raw Pointers](raw-pointers.md)
index 604dcb739df63812f18e56600fd1978bddc991b8..d7fa84761e5271e770d29d671b46c23f555e0ac5 100644 (file)
@@ -294,7 +294,7 @@ 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
-dispatch into the closure. That’s pretty neat. In many langauges, closures are
+dispatch into the closure. That’s pretty neat. In many languages, closures are
 inherently heap allocated, and will always involve dynamic dispatch. In Rust,
 we can stack allocate our closure environment, and statically dispatch the
 call. This happens quite often with iterators and their adapters, which often
index a9d33ccf1f30ddc5c1eb1743712a1d29a1295fbb..57cbb6213963a9dff2fe4688912122767926c59b 100644 (file)
@@ -66,6 +66,8 @@ unsafe {
 }
 ```
 
+[unsafe]: unsafe.html
+
 Furthermore, any type stored in a `static` must be `Sync`.
 
 # Initializing
index afacd3040552175b17eaed7b74d87697150ae917..b7011100971a88a8a4b96bad37bf7934a9714080 100644 (file)
@@ -1,3 +1,119 @@
 % `Deref` coercions
 
-Coming soon!
+The standard library provides a special trait, [`Deref`][deref]. It’s normally
+used to overload `*`, the dereference operator:
+
+```rust
+use std::ops::Deref;
+
+struct DerefExample<T> {
+    value: T,
+}
+
+impl<T> Deref for DerefExample<T> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        &self.value
+    }
+}
+
+fn main() {
+    let x = DerefExample { value: 'a' };
+    assert_eq!('a', *x);
+}
+```
+
+[deref]: ../std/ops/trait.Deref.html
+
+This is useful for writing custom pointer types. However, there’s a language
+feature related to `Deref`: ‘deref coercions’. Here’s the rule: If you have a
+type `U`, and it implements `Deref<Target=T>`, values of `&U` will
+automatically coerce to a `&T`. Here’s an example:
+
+```rust
+fn foo(s: &str) {
+    // borrow a string for a second
+}
+
+// String implements Deref<Target=str>
+let owned = "Hello".to_string();
+
+// therefore, this works:
+foo(&owned);
+```
+
+Using an ampersand in front of a value takes a reference to it. So `owned` is a
+`String`, `&owned` is an `&String`, and since `impl Deref<Target=str> for
+String`, `&String` will deref to `&str`, which `foo()` takes.
+
+That’s it. This rule is one of the only places in which Rust does an automatic
+conversion for you, but it adds a lot of flexibility. For example, the `Rc<T>`
+type implements `Deref<Target=T>`, so this works:
+
+```rust
+use std::rc::Rc;
+
+fn foo(s: &str) {
+    // borrow a string for a second
+}
+
+// String implements Deref<Target=str>
+let owned = "Hello".to_string();
+let counted = Rc::new(owned);
+
+// therefore, this works:
+foo(&counted);
+```
+
+All we’ve done is wrap our `String` in an `Rc<T>`. But we can now pass the
+`Rc<String>` around anywhere we’d have a `String`. The signature of `foo`
+didn’t change, but works just as well with either type. This example has two
+conversions: `Rc<String>` to `String` and then `String` to `&str`. Rust will do
+this as many times as possible until the types match.
+
+Another very common implementation provided by the standard library is:
+
+```rust
+fn foo(s: &[i32]) {
+    // borrow a slice for a second
+}
+
+// Vec<T> implements Deref<Target=[T]>
+let owned = vec![1, 2, 3];
+
+foo(&owned);
+```
+
+Vectors can `Deref` to a slice.
+
+## Deref and method calls
+
+`Deref` will also kick in when calling a method. In other words, these are
+the same two things in Rust:
+
+```rust
+struct Foo;
+
+impl Foo {
+    fn foo(&self) { println!("Foo"); }
+}
+
+let f = Foo;
+
+f.foo();
+```
+
+Even though `f` isn’t a reference, and `foo` takes `&self`, this works.
+That’s because these things are the same:
+
+```rust,ignore
+f.foo();
+(&f).foo();
+(&&f).foo();
+(&&&&&&&&f).foo();
+```
+
+A value of type `&&&&&&&&&&&&&&&&Foo` can still have methods defined on `Foo`
+called, because the compiler will insert as many * operations as necessary to
+get it right. And since it’s inserting `*`s, that uses `Deref`.
index 732521a0c6064d99ee74d9a5894410c64bf2553e..b28343e7fb94c75f7acd8d654bad07c4098720b1 100644 (file)
@@ -556,7 +556,7 @@ This sets a few different options, with a logo, favicon, and a root URL.
 
 ## Generation options
 
-`rustdoc` also contains a few other options on the command line, for further customiziation:
+`rustdoc` also contains a few other options on the command line, for further customization:
 
 - `--html-in-header FILE`: includes the contents of FILE at the end of the
   `<head>...</head>` section.
index 555d40e65970618b2ed122362da5a15ec8159599..d0825e543f2c288c678515ad8115d17b28ed1b0d 100644 (file)
@@ -1,5 +1,5 @@
 % Getting Started
 
 This first section of the book will get you going with Rust and its tooling.
-First, we’ll install Rust. Then: the classic ‘Hello World’ program. Finally,
+First, we’ll install Rust. Then, the classic ‘Hello World’ program. Finally,
 we’ll talk about Cargo, Rust’s build system and package manager.
index 97898324847e4ab770ead3d437b1c48b9f02d446..9845fcbdcd173ec3d6b3543bb2fba9689cf5727e 100644 (file)
@@ -19,7 +19,7 @@ In the example above `x` and `y` have arity 2. `z` has arity 3.
 
 When a compiler is compiling your program, it does a number of different
 things. One of the things that it does is turn the text of your program into an
-'abstract syntax tree,' or 'AST.' This tree is a representation of the
+‘abstract syntax tree’, or‘AST’. This tree is a representation of the
 structure of your program. For example, `2 + 3` can be turned into a tree:
 
 ```text
index 6967532a44735199cbd29c9d532de914ce51b8b4..d547451fccec2e551193a062e906c5da3de7971d 100644 (file)
@@ -32,6 +32,13 @@ $ mkdir src
 $ mv main.rs src/main.rs
 ```
 
+Note that since we're creating an executable, we used `main.rs`. If we
+want to make a library instead, we should use `lib.rs`.
+Custom file locations for the entry point can be specified
+with a [`[[lib]]` or `[[bin]]`][crates-custom] key in the TOML file described below.
+
+[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
index 5853f3d679c5f5231f185af1d1d940eed1a30c70..1445d39fe873876f48632571c306282c8f1eb155 100644 (file)
@@ -18,7 +18,7 @@ foo.bar().baz();
 Luckily, as you may have guessed with the leading question, you can! Rust provides
 the ability to use this ‘method call syntax’ via the `impl` keyword.
 
-## Method calls
+# Method calls
 
 Here’s how it works:
 
@@ -83,7 +83,7 @@ impl Circle {
 }
 ```
 
-## Chaining method calls
+# Chaining method calls
 
 So, now we know how to call a method, such as `foo.bar()`. But what about our
 original example, `foo.bar().baz()`? This is called ‘method chaining’, and we
@@ -127,7 +127,7 @@ fn grow(&self) -> Circle {
 We just say we’re returning a `Circle`. With this method, we can grow a new
 circle to any arbitrary size.
 
-## Static methods
+# Static methods
 
 You can also define methods that do not take a `self` parameter. Here’s a
 pattern that’s very common in Rust code:
@@ -158,7 +158,7 @@ This ‘static method’ builds a new `Circle` for us. Note that static methods
 are called with the `Struct::method()` syntax, rather than the `ref.method()`
 syntax.
 
-## Builder Pattern
+# Builder Pattern
 
 Let’s say that we want our users to be able to create Circles, but we will
 allow them to only set the properties they care about. Otherwise, the `x`
index ccb03c7f85f693a873d4d91a566b929c18d49426..816bfb17970619374a2147deddecc16fad7cb920 100644 (file)
@@ -1,3 +1,179 @@
 % Mutability
 
-Coming Soon
+Mutability, the ability to change something, works a bit differently in Rust
+than in other languages. The first aspect of mutability is its non-default
+status:
+
+```rust,ignore
+let x = 5;
+x = 6; // error!
+```
+
+We can introduce mutability with the `mut` keyword:
+
+```rust
+let mut x = 5;
+
+x = 6; // no problem!
+```
+
+This is a mutable [variable binding][vb]. When a binding is mutable, it means
+you’re allowed to change what the binding points to. So in the above example,
+it’s not so much that the value at `x` is changing, but that the binding
+changed from one `i32` to another.
+
+[vb]: variable-bindings.html
+
+If you want to change what the binding points to, you’ll need a [mutable reference][mr]:
+
+```rust
+let mut x = 5;
+let y = &mut x;
+```
+
+[mr]: references-and-borrowing.html
+
+`y` is an immutable binding to a mutable reference, which means that you can’t
+bind `y` to something else (`y = &mut z`), but you can mutate the thing that’s
+bound to `y`. (`*y = 5`) A subtle distinction.
+
+Of course, if you need both:
+
+```rust
+let mut x = 5;
+let mut y = &mut x;
+```
+
+Now `y` can be bound to another value, and the value it’s referencing can be
+changed.
+
+It’s important to note that `mut` is part of a [pattern][pattern], so you
+can do things like this:
+
+```rust
+let (mut x, y) = (5, 6);
+
+fn foo(mut x: i32) {
+# }
+```
+
+[pattern]: patterns.html
+
+# Interior vs. Exterior Mutability
+
+However, when we say something is ‘immutable’ in Rust, that doesn’t mean that
+it’s not able to be changed: We mean something has ‘exterior mutability’. Consider,
+for example, [`Arc<T>`][arc]:
+
+```rust
+use std::sync::Arc;
+
+let x = Arc::new(5);
+let y = x.clone();
+```
+
+[arc]: ../std/sync/struct.Arc.html
+
+When we call `clone()`, the `Arc<T>` needs to update the reference count. Yet
+we’ve not used any `mut`s here, `x` is an immutable binding, and we didn’t take
+`&mut 5` or anything. So what gives?
+
+To this, we have to go back to the core of Rust’s guiding philosophy, memory
+safety, and the mechanism by which Rust guarantees it, the
+[ownership][ownership] system, and more specifically, [borrowing][borrowing]:
+
+> You may have one or the other of these two kinds of borrows, but not both at
+> the same time:
+> 
+> * 0 to N references (`&T`) to a resource.
+> * exactly one mutable reference (`&mut T`)
+
+[ownership]: ownership.html
+[borrowing]: borrowing.html#The-Rules
+
+So, that’s the real definition of ‘immutability’: is this safe to have two
+pointers to? In `Arc<T>`’s case, yes: the mutation is entirely contained inside
+the structure itself. It’s not user facing. For this reason, it hands out `&T`
+with `clone()`. If it handed out `&mut T`s, though, that would be a problem.
+
+Other types, like the ones in the [`std::cell`][stdcell] module, have the
+opposite: interior mutability. For example:
+
+```rust
+use std::cell::RefCell;
+
+let x = RefCell::new(42);
+
+let y = x.borrow_mut();
+```
+
+[stdcell]: ../std/cell/index.html
+
+RefCell hands out `&mut` references to what’s inside of it with the
+`borrow_mut()` method. Isn’t that dangerous? What if we do:
+
+```rust,ignore
+use std::cell::RefCell;
+
+let x = RefCell::new(42);
+
+let y = x.borrow_mut();
+let z = x.borrow_mut();
+# (y, z);
+```
+
+This will in fact panic, at runtime. This is what `RefCell` does: it enforces
+Rust’s borrowing rules at runtime, and `panic!`s if they’re violated. This
+allows us to get around another aspect of Rust’s mutability rules. Let’s talk
+about it first.
+
+## Field-level mutability
+
+Mutability is a property of either a borrow (`&mut`) or a binding (`let mut`).
+This means that, for example, you cannot have a [`struct`][struct] with
+some fields mutable and some immutable:
+
+```rust,ignore
+struct Point {
+    x: i32,
+    mut y: i32, // nope
+}
+```
+
+The mutability of a struct is in its binding:
+
+```rust,ignore
+struct Point {
+    x: i32,
+    y: i32,
+}
+
+let mut a = Point { x: 5, y: 6 };
+
+a.x = 10;
+
+let b = Point { x: 5, y: 6};
+
+b.x = 10; // error: cannot assign to immutable field `b.x`
+```
+
+[struct]: structs.html
+
+However, by using `Cell<T>`, you can emulate field-level mutability:
+
+```
+use std::cell::Cell;
+
+struct Point {
+    x: i32,
+    y: Cell<i32>,
+}
+
+let mut point = Point { x: 5, y: Cell::new(6) };
+
+point.y.set(7);
+
+println!("y: {:?}", point.y);
+```
+
+This will print `y: Cell { value: 7 }`. We’ve successfully updated `y`.
index f6f9d5cae19213d54ae53a5559e3ec5c2684a4ef..6a594659c37d27617cc7899c542de54977c21f9a 100644 (file)
@@ -1,3 +1,83 @@
 % Operators and Overloading
 
-Coming soon!
+Rust allows for a limited form of operator overloading. There are certain
+operators that are able to be overloaded. To support a particular operator
+between types, there’s a specific trait that you can implement, which then
+overloads the operator.
+
+For example, the `+` operator can be overloaded with the `Add` trait:
+
+```rust
+use std::ops::Add;
+
+#[derive(Debug)]
+struct Point {
+    x: i32,
+    y: i32,
+}
+
+impl Add for Point {
+    type Output = Point;
+
+    fn add(self, other: Point) -> Point {
+        Point { x: self.x + other.x, y: self.y + other.y }
+    }
+}
+
+fn main() {
+    let p1 = Point { x: 1, y: 0 };
+    let p2 = Point { x: 2, y: 3 };
+
+    let p3 = p1 + p2;
+
+    println!("{:?}", p3);
+}
+```
+
+In `main`, we can use `+` on our two `Point`s, since we’ve implemented
+`Add<Output=Point>` for `Point`.
+
+There are a number of operators that can be overloaded this way, and all of
+their associated traits live in the [`std::ops`][stdops] module. Check out its
+documentation for the full list.
+
+[stdops]: ../std/ops/index.html
+
+Implementing these traits follows a pattern. Let’s look at [`Add`][add] in more
+detail:
+
+```rust
+# mod foo {
+pub trait Add<RHS = Self> {
+    type Output;
+
+    fn add(self, rhs: RHS) -> Self::Output;
+}
+# }
+```
+
+[add]: ../std/ops/trait.Add.html
+
+There’s three types in total involved here: the type you `impl Add` for, `RHS`,
+which defaults to `Self`, and `Output`. For an expression `let z = x + y`, `x`
+is the `Self` type, `y` is the RHS, and `z` is the `Self::Output` type.
+
+```rust
+# struct Point;
+# use std::ops::Add;
+impl Add<i32> for Point {
+    type Output = f64;
+
+    fn add(self, rhs: i32) -> f64 {
+        // add an i32 to a Point and get an f64
+# 1.0
+    }
+}
+```
+
+will let you do this:
+
+```rust,ignore
+let p: Point = // ...
+let x: f64 = p + 2i32;
+```
index e4af03869d1d85e2c9e0c976b900f9acb0715a21..aca6e327c3bce07f5d0626faaa162b9ba7623d40 100644 (file)
@@ -62,14 +62,14 @@ let y = 1.0; // y has type f64
 Here’s a list of the different numeric types, with links to their documentation
 in the standard library:
 
+* [i8](../std/primitive.i8.html)
 * [i16](../std/primitive.i16.html)
 * [i32](../std/primitive.i32.html)
 * [i64](../std/primitive.i64.html)
-* [i8](../std/primitive.i8.html)
+* [u8](../std/primitive.u8.html)
 * [u16](../std/primitive.u16.html)
 * [u32](../std/primitive.u32.html)
 * [u64](../std/primitive.u64.html)
-* [u8](../std/primitive.u8.html)
 * [isize](../std/primitive.isize.html)
 * [usize](../std/primitive.usize.html)
 * [f32](../std/primitive.f32.html)
@@ -82,12 +82,12 @@ Let’s go over them by category:
 Integer types come in two varieties: signed and unsigned. To understand the
 difference, let’s consider a number with four bits of size. A signed, four-bit
 number would let you store numbers from `-8` to `+7`. Signed numbers use
\80\98twoâ\80\99s compliment representationâ\80\99. An unsigned four bit number, since it does
\80\9ctwoâ\80\99s compliment representationâ\80\9d. An unsigned four bit number, since it does
 not need to store negatives, can store values from `0` to `+15`.
 
 Unsigned types use a `u` for their category, and signed types use `i`. The `i`
 is for ‘integer’. So `u8` is an eight-bit unsigned number, and `i8` is an
-eight-bit signed number. 
+eight-bit signed number.
 
 ## Fixed size types
 
@@ -103,7 +103,7 @@ and unsigned varieties. This makes for two types: `isize` and `usize`.
 
 ## Floating-point types
 
-Rust also two floating point types: `f32` and `f64`. These correspond to 
+Rust also has two floating point types: `f32` and `f64`. These correspond to
 IEEE-754 single and double precision numbers.
 
 # Arrays
@@ -241,8 +241,8 @@ println!("x is {}", x);
 Remember [before][let] when I said the left-hand side of a `let` statement was more
 powerful than just assigning a binding? Here we are. We can put a pattern on
 the left-hand side of the `let`, and if it matches up to the right-hand side,
-we can assign multiple bindings at once. In this case, `let` "destructures,"
-or "breaks up," the tuple, and assigns the bits to three bindings.
+we can assign multiple bindings at once. In this case, `let` “destructures”
+or “breaks up” the tuple, and assigns the bits to three bindings.
 
 [let]: variable-bindings.html
 
index 8cf126cad95fbd7e4813c92e10bc52367c17b391..45f87a6740597c6ac892c8732b3df881b16d7b42 100644 (file)
@@ -219,10 +219,10 @@ fn it_works() {
 This is a very common use of `assert_eq!`: call some function with
 some known arguments and compare it to the expected output.
 
-# The `test` module
+# The `tests` module
 
 There is one way in which our existing example is not idiomatic: it's
-missing the test module. The idiomatic way of writing our example
+missing the `tests` module. The idiomatic way of writing our example
 looks like this:
 
 ```{rust,ignore}
@@ -231,7 +231,7 @@ pub fn add_two(a: i32) -> i32 {
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use super::add_two;
 
     #[test]
@@ -241,7 +241,7 @@ mod test {
 }
 ```
 
-There's a few changes here. The first is the introduction of a `mod test` with
+There's a few changes here. The first is the introduction of a `mod tests` with
 a `cfg` attribute. The module allows us to group all of our tests together, and
 to also define helper functions if needed, that don't become a part of the rest
 of our crate. The `cfg` attribute only compiles our test code if we're
@@ -260,7 +260,7 @@ pub fn add_two(a: i32) -> i32 {
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use super::*;
 
     #[test]
@@ -279,7 +279,7 @@ $ cargo test
      Running target/adder-91b3e234d4ed382a
 
 running 1 test
-test test::it_works ... ok
+test tests::it_works ... ok
 
 test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
 
@@ -292,7 +292,7 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
 
 It works!
 
-The current convention is to use the `test` module to hold your "unit-style"
+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
@@ -325,7 +325,7 @@ $ cargo test
      Running target/adder-91b3e234d4ed382a
 
 running 1 test
-test test::it_works ... ok
+test tests::it_works ... ok
 
 test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
 
@@ -346,7 +346,7 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
 Now we have three sections: our previous test is also run, as well as our new
 one.
 
-That's all there is to the `tests` directory. The `test` module isn't needed
+That's all there is to the `tests` directory. The `tests` module isn't needed
 here, since the whole thing is focused on tests.
 
 Let's finally check out that third section: documentation tests.
@@ -382,7 +382,7 @@ pub fn add_two(a: i32) -> i32 {
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use super::*;
 
     #[test]
@@ -405,7 +405,7 @@ $ cargo test
      Running target/adder-91b3e234d4ed382a
 
 running 1 test
-test test::it_works ... ok
+test tests::it_works ... ok
 
 test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
 
index 52f8cb335a93a0c8eb92953a2432a836320c2755..c01129057418cf1af9db4d73fb37ed52d4133f19 100644 (file)
@@ -155,7 +155,7 @@ A function that takes a trait object is not specialized to each of the types
 that implements `Foo`: only one copy is generated, often (but not always)
 resulting in less code bloat. However, this comes at the cost of requiring
 slower virtual function calls, and effectively inhibiting any chance of
-inlining and related optimisations from occurring.
+inlining and related optimizations from occurring.
 
 ### Why pointers?
 
index 3e77d3c603bac90909a481f68df961c545b4f566..ea5d2ed711fed0f0aac66be1db7c909014ff5339 100644 (file)
@@ -184,7 +184,7 @@ won’t have its methods:
 ```rust,ignore
 let mut f = std::fs::File::open("foo.txt").ok().expect("Couldn’t open foo.txt");
 let result = f.write("whatever".as_bytes());
-# result.unwrap(); // ignore the erorr
+# result.unwrap(); // ignore the error
 ```
 
 Here’s the error:
@@ -203,7 +203,7 @@ use std::io::Write;
 
 let mut f = std::fs::File::open("foo.txt").ok().expect("Couldn’t open foo.txt");
 let result = f.write("whatever".as_bytes());
-# result.unwrap(); // ignore the erorr
+# result.unwrap(); // ignore the error
 ```
 
 This will compile without error.
index 2d5c742ddb8482312a2ee0661f46808b694c8c50..2353c63a606af070be774e1e9bb2ccb5de1142f5 100644 (file)
@@ -89,7 +89,7 @@ not, and so we need to pass an explicit `&b`.
 The form of UFCS we just talked about:
 
 ```rust,ignore
-Type::method(args);
+Trait::method(args);
 ```
 
 Is a short-hand. There’s an expanded form of this that’s needed in some
index d971e557a9a2edba517ad91e859e4b8675f46ea3..2166c046897f0a56da8c299dbd95a737a3dda291 100644 (file)
@@ -1,6 +1,6 @@
 % Variable Bindings
 
-Vitually every non-’Hello World’ Rust program uses *variable bindings*. They
+Virtually every non-'Hello World’ Rust program uses *variable bindings*. They
 look like this:
 
 ```rust
index 965cb218c699a1ecec1a4d5a2ed3dc9b675a9b21..6170bdb86eaa3a7843dc89af9a47260395cdb778 100644 (file)
@@ -1,8 +1,9 @@
 % Vectors
 
 A ‘vector’ is a dynamic or ‘growable’ array, implemented as the standard
-library type [`Vec<T>`][vec]. That `<T>` is a [generic][generic], meaning we
-can have vectors of any type. Vectors always allocate their data on the heap.
+library type [`Vec<T>`][vec]. The `T` means that we can have vectors
+of any type (see the chapter on [generics][generic] for more).
+Vectors always allocate their data on the heap.
 You can create them with the `vec!` macro:
 
 ```rust
@@ -56,3 +57,4 @@ Vectors have many more useful methods, which you can read about in [their
 API documentation][vec].
 
 [vec]: ../std/vec/index.html
+[generic]: generics.html
index 6c3fd186cd423bdea36260cc459fe361602eb0e2..27e15bc2f0eeaa044a8e7a8dd301e232c28e3b3e 100644 (file)
@@ -505,10 +505,20 @@ trait_items
 ;
 
 trait_item
-: trait_type
+: trait_const
+| trait_type
 | trait_method
 ;
 
+trait_const
+: maybe_outer_attrs CONST ident maybe_const_default ';' { $$ = mk_node("ConstTraitItem", 3, $1, $3, $4); }
+;
+
+maybe_const_default
+: '=' expr { $$ = mk_node("ConstDefault", 1, $2); }
+| %empty   { $$ = mk_none(); }
+;
+
 trait_type
 : maybe_outer_attrs TYPE ty_param ';' { $$ = mk_node("TypeTraitItem", 2, $1, $3); }
 ;
@@ -611,7 +621,16 @@ impl_items
 impl_item
 : impl_method
 | item_macro
-| trait_type
+| impl_const
+| impl_type
+;
+
+impl_const
+: attrs_and_vis item_const { $$ = mk_node("ImplConst", 1, $1, $2); }
+;
+
+impl_type
+: attrs_and_vis TYPE ident generic_params '=' ty_sum ';'  { $$ = mk_node("ImplType", 4, $1, $3, $4, $6); }
 ;
 
 item_fn
index 4c7441b1d2a654534289d69fe672e6364d6657fa..86a04a0687a5bb11b92aa8748c5556f24b520709 100644 (file)
@@ -211,7 +211,9 @@ fn je_malloc_stats_print(write_cb: Option<extern "C" fn(cbopaque: *mut c_void,
     }
 
     // -lpthread needs to occur after -ljemalloc, the earlier argument isn't enough
-    #[cfg(all(not(windows), not(target_os = "android")))]
+    #[cfg(all(not(windows),
+              not(target_os = "android"),
+              not(target_env = "musl")))]
     #[link(name = "pthread")]
     extern {}
 
@@ -384,7 +386,7 @@ pub fn stats_print() {}
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     extern crate test;
     use self::test::Bencher;
     use boxed::Box;
index 0f05e5796aa15fb044a173337e989472b7449982..af7112a5cb4e30147c7a3228eb3832c3d89c4e80 100644 (file)
@@ -546,7 +546,7 @@ pub fn is_empty(&self) -> bool { self.len() == 0 }
     #[unstable(feature = "collections",
                reason = "matches collection reform specification, waiting for dust to settle")]
     pub fn drain(&mut self) -> Drain<T> {
-        Drain { iter: self.data.drain() }
+        Drain { iter: self.data.drain(..) }
     }
 
     /// Drops all items from the binary heap.
index 2b502b2227ef343449971c36363ee0d94cfafe68..4480a7d7e0a09fbe2be418082d6a9b9ee8b32f6f 100644 (file)
 //!
 //! ## Precision
 //!
-//! For non-numeric types, this can be considered a "maximum width". If the
-//! resulting string is longer than this width, then it is truncated down to
-//! this many characters and only those are emitted.
+//! For non-numeric types, this can be considered a "maximum width". If the resulting string is
+//! longer than this width, then it is truncated down to this many characters and only those are
+//! emitted.
 //!
 //! For integral types, this has no meaning currently.
 //!
-//! For floating-point types, this indicates how many digits after the decimal
-//! point should be printed.
+//! For floating-point types, this indicates how many digits after the decimal point should be
+//! printed.
+//!
+//! There are three possible ways to specify the desired `precision`:
+//!
+//! There are three possible ways to specify the desired `precision`:
+//! 1. An integer `.N`,
+//! 2. an integer followed by dollar sign `.N$`, or
+//! 3. an asterisk `.*`.
+//!
+//! The first specification, `.N`, means the integer `N` itself is the precision.
+//!
+//! The second, `.N$`, means use format *argument* `N` (which must be a `usize`) as the precision.
+//!
+//! Finally,  `.*` means that this `{...}` is associated with *two* format inputs rather than one:
+//! the first input holds the `usize` precision, and the second holds the value to print.  Note
+//! that in this case, if one uses the format string `{<arg>:<spec>.*}`, then the `<arg>` part
+//! refers to the *value* to print, and the `precision` must come in the input preceding `<arg>`.
+//!
+//! For example, these:
+//!
+//! ```
+//! // Hello {arg 0 (x)} is {arg 1 (0.01} with precision specified inline (5)}
+//! println!("Hello {0} is {1:.5}", "x", 0.01);
+//!
+//! // Hello {arg 1 (x)} is {arg 2 (0.01} with precision specified in arg 0 (5)}
+//! println!("Hello {1} is {2:.0$}", 5, "x", 0.01);
+//!
+//! // Hello {arg 0 (x)} is {arg 2 (0.01} with precision specified in arg 1 (5)}
+//! println!("Hello {0} is {2:.1$}", "x", 5, 0.01);
+//!
+//! // Hello {next arg (x)} is {second of next two args (0.01} with precision
+//! //                          specified in first of next two args (5)}
+//! println!("Hello {} is {:.*}",    "x", 5, 0.01);
+//!
+//! // Hello {next arg (x)} is {arg 2 (0.01} with precision
+//! //                          specified in its predecessor (5)}
+//! println!("Hello {} is {2:.*}",   "x", 5, 0.01);
+//! ```
+//!
+//! All print the same thing:
+//!
+//! ```text
+//! Hello x is 0.01000
+//! ```
+//!
+//! While these:
+//!
+//! ```
+//! println!("{}, `{name:.*}` has 3 fractional digits", "Hello", 3, name=1234.56);
+//! println!("{}, `{name:.*}` has 3 characters", "Hello", 3, name="1234.56");
+//! ```
+//!
+//! print two significantly different things:
+//!
+//! ```text
+//! Hello, `1234.560` has 3 fractional digits
+//! Hello, `123` has 3 characters
+//! ```
 //!
 //! # Escaping
 //!
index 0ea8975bbde1f4b81b447dd09f2454875c30395f..ae2ad7751aab764b31780c6d59a8a1af75202fe1 100644 (file)
@@ -42,7 +42,8 @@
 #![feature(slice_patterns)]
 #![feature(debug_builders)]
 #![feature(utf8_error)]
-#![cfg_attr(test, feature(rand, rustc_private, test, hash, collections))]
+#![cfg_attr(test, feature(rand, rustc_private, test, hash, collections,
+                          collections_drain, collections_range))]
 #![cfg_attr(test, allow(deprecated))] // rand
 
 #![feature(no_std)]
@@ -82,6 +83,7 @@
 pub mod enum_set;
 pub mod fmt;
 pub mod linked_list;
+pub mod range;
 pub mod slice;
 pub mod str;
 pub mod string;
index deb1476c23f096375fce6fd7cfeb919e5e322ed4..c73a6f9b324a3698aa7b16063ee31aa4e958a702 100644 (file)
@@ -933,7 +933,7 @@ fn hash<H: Hasher>(&self, state: &mut H) {
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use std::clone::Clone;
     use std::iter::{Iterator, IntoIterator};
     use std::option::Option::{Some, None, self};
diff --git a/src/libcollections/range.rs b/src/libcollections/range.rs
new file mode 100644 (file)
index 0000000..6ab1439
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+#![unstable(feature = "collections_range", reason = "was just added")]
+
+//! Range syntax.
+
+use core::option::Option::{self, None, Some};
+use core::ops::{RangeFull, Range, RangeTo, RangeFrom};
+
+/// **RangeArgument** is implemented by Rust's built-in range types, produced
+/// by range syntax like `..`, `a..`, `..b` or `c..d`.
+pub trait RangeArgument<T> {
+    /// Start index (inclusive)
+    ///
+    /// Return start value if present, else `None`.
+    fn start(&self) -> Option<&T> { None }
+
+    /// End index (exclusive)
+    ///
+    /// Return end value if present, else `None`.
+    fn end(&self) -> Option<&T> { None }
+}
+
+
+impl<T> RangeArgument<T> for RangeFull {}
+
+impl<T> RangeArgument<T> for RangeFrom<T> {
+    fn start(&self) -> Option<&T> { Some(&self.start) }
+}
+
+impl<T> RangeArgument<T> for RangeTo<T> {
+    fn end(&self) -> Option<&T> { Some(&self.end) }
+}
+
+impl<T> RangeArgument<T> for Range<T> {
+    fn start(&self) -> Option<&T> { Some(&self.start) }
+    fn end(&self) -> Option<&T> { Some(&self.end) }
+}
index a37a26ef22ac3af2852ebeb9c106fa799a3445cc..be6405dc85a1498fcbffba5194c8397c1754ebd9 100644 (file)
@@ -951,12 +951,13 @@ fn deref<'b>(&'b self) -> &'b String {
 /// # #![feature(collections)]
 /// use std::string::as_string;
 ///
-/// fn string_consumer(s: String) {
-///     assert_eq!(s, "foo".to_string());
+/// // Let's pretend we have a function that requires `&String`
+/// fn string_consumer(s: &String) {
+///     assert_eq!(s, "foo");
 /// }
 ///
-/// let string = as_string("foo").clone();
-/// string_consumer(string);
+/// // Provide a `&String` from a `&str` without allocating
+/// string_consumer(&as_string("foo"));
 /// ```
 #[unstable(feature = "collections")]
 pub fn as_string<'a>(x: &'a str) -> DerefString<'a> {
index 526150915a705a0fb0289774776e5aae88c03b42..f42c48681a92652cbc7e52add6732b34822a5d9d 100644 (file)
@@ -69,6 +69,8 @@
 
 use borrow::{Cow, IntoCow};
 
+use super::range::RangeArgument;
+
 // FIXME- fix places which assume the max vector allowed has memory usize::MAX.
 static MAX_MEMORY_SIZE: usize = isize::MAX as usize;
 
 /// stack.push(2);
 /// stack.push(3);
 ///
-/// loop {
-///     let top = match stack.pop() {
-///         None => break, // empty
-///         Some(x) => x,
-///     };
+/// while let Some(top) = stack.pop() {
 ///     // Prints 3, 2, 1
 ///     println!("{}", top);
 /// }
@@ -540,7 +538,7 @@ pub fn insert(&mut self, index: usize, element: T) {
     ///
     /// # Panics
     ///
-    /// Panics if `i` is out of bounds.
+    /// Panics if `index` is out of bounds.
     ///
     /// # Examples
     ///
@@ -718,36 +716,61 @@ pub fn append(&mut self, other: &mut Self) {
         unsafe { other.set_len(0); }
     }
 
-    /// Creates a draining iterator that clears the `Vec` and iterates over
-    /// the removed items from start to end.
+    /// Create a draining iterator that removes the specified range in the vector
+    /// 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 vector,
+    /// if the `Drain` value is leaked.
+    ///
+    /// # 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
     ///
     /// ```
-    /// # #![feature(collections)]
-    /// let mut v = vec!["a".to_string(), "b".to_string()];
-    /// for s in v.drain() {
-    ///     // s has type String, not &String
-    ///     println!("{}", s);
-    /// }
-    /// assert!(v.is_empty());
+    /// # #![feature(collections_drain, collections_range)]
+    ///
+    /// // Draining using `..` clears the whole vector.
+    /// let mut v = vec![1, 2, 3];
+    /// let u: Vec<_> = v.drain(..).collect();
+    /// assert_eq!(v, &[]);
+    /// assert_eq!(u, &[1, 2, 3]);
     /// ```
-    #[inline]
-    #[unstable(feature = "collections",
-               reason = "matches collection reform specification, waiting for dust to settle")]
-    pub fn drain(&mut self) -> Drain<T> {
+    #[unstable(feature = "collections_drain",
+               reason = "recently added, matches RFC")]
+    pub fn drain<R>(&mut self, range: R) -> Drain<T> where R: RangeArgument<usize> {
+        // Memory safety
+        //
+        // When the Drain is first created, it shortens the length of
+        // the source vector to make sure no uninitalized 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, remaining tail of the vec is copied back to cover
+        // the hole, and the vector length is restored to the new length.
+        //
+        let len = self.len();
+        let start = *range.start().unwrap_or(&0);
+        let end = *range.end().unwrap_or(&len);
+        assert!(start <= end);
+        assert!(end <= len);
+
         unsafe {
-            let begin = *self.ptr as *const T;
-            let end = if mem::size_of::<T>() == 0 {
-                (*self.ptr as usize + self.len()) as *const T
-            } else {
-                (*self.ptr).offset(self.len() as isize) as *const T
-            };
-            self.set_len(0);
+            // set self.vec length's to start, to be safe in case Drain is leaked
+            self.set_len(start);
+            // Use the borrow in the IterMut to indicate borrowing behavior of the
+            // whole Drain iterator (like &mut T).
+            let range_slice = slice::from_raw_parts_mut(
+                                        self.as_mut_ptr().offset(start as isize),
+                                        end - start);
             Drain {
-                ptr: begin,
-                end: end,
-                marker: PhantomData,
+                tail_start: end,
+                tail_len: len - end,
+                iter: range_slice.iter_mut(),
+                vec: self as *mut _,
             }
         }
     }
@@ -1799,14 +1822,16 @@ fn drop(&mut self) {
     }
 }
 
-/// An iterator that drains a vector.
-#[unsafe_no_drop_flag]
-#[unstable(feature = "collections",
-           reason = "recently added as part of collections reform 2")]
-pub struct Drain<'a, T:'a> {
-    ptr: *const T,
-    end: *const T,
-    marker: PhantomData<&'a T>,
+/// A draining iterator for `Vec<T>`.
+#[unstable(feature = "collections_drain", reason = "recently added")]
+pub struct Drain<'a, T: 'a> {
+    /// Index of tail to preserve
+    tail_start: usize,
+    /// Length of tail
+    tail_len: usize,
+    /// Current remaining range to remove
+    iter: slice::IterMut<'a, T>,
+    vec: *mut Vec<T>,
 }
 
 unsafe impl<'a, T: Sync> Sync for Drain<'a, T> {}
@@ -1818,34 +1843,15 @@ impl<'a, T> Iterator for Drain<'a, T> {
 
     #[inline]
     fn next(&mut self) -> Option<T> {
-        unsafe {
-            if self.ptr == self.end {
-                None
-            } else {
-                if mem::size_of::<T>() == 0 {
-                    // purposefully don't use 'ptr.offset' because for
-                    // vectors with 0-size elements this would return the
-                    // same pointer.
-                    self.ptr = mem::transmute(self.ptr as usize + 1);
-
-                    // Use a non-null pointer value
-                    Some(ptr::read(EMPTY as *mut T))
-                } else {
-                    let old = self.ptr;
-                    self.ptr = self.ptr.offset(1);
-
-                    Some(ptr::read(old))
-                }
+        self.iter.next().map(|elt|
+            unsafe {
+                ptr::read(elt as *const _)
             }
-        }
+        )
     }
 
-    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
-        let diff = (self.end as usize) - (self.ptr as usize);
-        let size = mem::size_of::<T>();
-        let exact = diff / (if size == 0 {1} else {size});
-        (exact, Some(exact))
+        self.iter.size_hint()
     }
 }
 
@@ -1853,41 +1859,40 @@ fn size_hint(&self) -> (usize, Option<usize>) {
 impl<'a, T> DoubleEndedIterator for Drain<'a, T> {
     #[inline]
     fn next_back(&mut self) -> Option<T> {
-        unsafe {
-            if self.end == self.ptr {
-                None
-            } else {
-                if mem::size_of::<T>() == 0 {
-                    // See above for why 'ptr.offset' isn't used
-                    self.end = mem::transmute(self.end as usize - 1);
-
-                    // Use a non-null pointer value
-                    Some(ptr::read(EMPTY as *mut T))
-                } else {
-                    self.end = self.end.offset(-1);
-
-                    Some(ptr::read(self.end))
-                }
+        self.iter.next_back().map(|elt|
+            unsafe {
+                ptr::read(elt as *const _)
             }
-        }
+        )
     }
 }
 
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> ExactSizeIterator for Drain<'a, T> {}
-
 #[unsafe_destructor]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T> Drop for Drain<'a, T> {
     fn drop(&mut self) {
-        // self.ptr == self.end == mem::POST_DROP_USIZE if drop has already been called,
-        // so we can use #[unsafe_no_drop_flag].
+        // exhaust self first
+        while let Some(_) = self.next() { }
 
-        // destroy the remaining elements
-        for _x in self.by_ref() {}
+        if self.tail_len > 0 {
+            unsafe {
+                let source_vec = &mut *self.vec;
+                // memmove back untouched tail, update to new length
+                let start = source_vec.len();
+                let tail = self.tail_start;
+                let src = source_vec.as_ptr().offset(tail as isize);
+                let dst = source_vec.as_mut_ptr().offset(start as isize);
+                ptr::copy(src, dst, self.tail_len);
+                source_vec.set_len(start + self.tail_len);
+            }
+        }
     }
 }
 
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T> ExactSizeIterator for Drain<'a, T> {}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Conversion from &[T] to &Vec<T>
 ////////////////////////////////////////////////////////////////////////////////
@@ -1919,6 +1924,22 @@ fn drop(&mut self) {
 }
 
 /// Converts a slice to a wrapper type providing a `&Vec<T>` reference.
+///
+/// # Examples
+///
+/// ```
+/// # #![feature(collections)]
+/// use std::vec::as_vec;
+///
+/// // Let's pretend we have a function that requires `&Vec<i32>`
+/// fn vec_consumer(s: &Vec<i32>) {
+///     assert_eq!(s, &[1, 2, 3]);
+/// }
+///
+/// // Provide a `&Vec<i32>` from a `&[i32]` without allocating
+/// let values = [1, 2, 3];
+/// vec_consumer(&as_vec(&values));
+/// ```
 #[unstable(feature = "collections")]
 pub fn as_vec<'a, T>(x: &'a [T]) -> DerefVec<'a, T> {
     unsafe {
index bbe7830b4238c5fe2518e388f3c326d4ea949070..61369b30dea1797c25d954883c5f988fee433de7 100644 (file)
@@ -1772,7 +1772,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use core::iter::{Iterator, self};
     use core::option::Option::Some;
 
index d473504d5445470e676f4cce2e142f6c90215115..6ff819fc87cdbd0c3d702a608f786b4e63c1e43c 100644 (file)
@@ -418,7 +418,7 @@ fn filter<A>((i, v): (usize, Option<A>)) -> Option<(usize, A)> {
         }
         let filter: fn((usize, Option<V>)) -> Option<(usize, V)> = filter; // coerce to fn ptr
 
-        Drain { iter: self.v.drain().enumerate().filter_map(filter) }
+        Drain { iter: self.v.drain(..).enumerate().filter_map(filter) }
     }
 
     /// Returns the number of elements in the map.
index 5c109dc8104f21492347aa57d7a549d1a5028a10..935cfb762c2444d83cbaab94dbb224b8d613550a 100644 (file)
@@ -10,6 +10,7 @@
 
 #![feature(box_syntax)]
 #![feature(collections)]
+#![feature(collections_drain)]
 #![feature(core)]
 #![feature(hash)]
 #![feature(rand)]
index 2923bea982845e25139c8377ceca3e3d2aa03f6e..7d3b156a7cc4db3b69a43674bf813be860830cb3 100644 (file)
@@ -460,7 +460,7 @@ fn test_move_items_zero_sized() {
 fn test_drain_items() {
     let mut vec = vec![1, 2, 3];
     let mut vec2 = vec![];
-    for i in vec.drain() {
+    for i in vec.drain(..) {
         vec2.push(i);
     }
     assert_eq!(vec, []);
@@ -471,7 +471,7 @@ fn test_drain_items() {
 fn test_drain_items_reverse() {
     let mut vec = vec![1, 2, 3];
     let mut vec2 = vec![];
-    for i in vec.drain().rev() {
+    for i in vec.drain(..).rev() {
         vec2.push(i);
     }
     assert_eq!(vec, []);
@@ -482,13 +482,43 @@ fn test_drain_items_reverse() {
 fn test_drain_items_zero_sized() {
     let mut vec = vec![(), (), ()];
     let mut vec2 = vec![];
-    for i in vec.drain() {
+    for i in vec.drain(..) {
         vec2.push(i);
     }
     assert_eq!(vec, []);
     assert_eq!(vec2, [(), (), ()]);
 }
 
+#[test]
+#[should_panic]
+fn test_drain_out_of_bounds() {
+    let mut v = vec![1, 2, 3, 4, 5];
+    v.drain(5..6);
+}
+
+#[test]
+fn test_drain_range() {
+    let mut v = vec![1, 2, 3, 4, 5];
+    for _ in v.drain(4..) {
+    }
+    assert_eq!(v, &[1, 2, 3, 4]);
+
+    let mut v: Vec<_> = (1..6).map(|x| x.to_string()).collect();
+    for _ in v.drain(1..4) {
+    }
+    assert_eq!(v, &[1.to_string(), 5.to_string()]);
+
+    let mut v: Vec<_> = (1..6).map(|x| x.to_string()).collect();
+    for _ in v.drain(1..4).rev() {
+    }
+    assert_eq!(v, &[1.to_string(), 5.to_string()]);
+
+    let mut v: Vec<_> = vec![(); 5];
+    for _ in v.drain(1..4).rev() {
+    }
+    assert_eq!(v, &[(), ()]);
+}
+
 #[test]
 fn test_into_boxed_slice() {
     let xs = vec![1, 2, 3];
index 02f9ee506f990f625caa9ff8f612da0f5d3590b3..bcbf31617eeb6aedda8e38e804168a42a33c0cfc 100644 (file)
@@ -129,6 +129,12 @@ pub struct AtomicPtr<T> {
     _marker: PhantomData<*mut T>,
 }
 
+impl<T> Default for AtomicPtr<T> {
+    fn default() -> AtomicPtr<T> {
+        AtomicPtr::new(::ptr::null_mut())
+    }
+}
+
 unsafe impl<T> Sync for AtomicPtr<T> {}
 
 /// Atomic memory orderings
index df0de234b9a16ef9bc5ce6f2032d6c42bea77008..b4b25258bbfd63d9683d4201308553db1011eb34 100644 (file)
@@ -417,7 +417,7 @@ pub fn borrow<'a>(&'a self) -> Ref<'a, T> {
     ///
     /// let result = thread::spawn(move || {
     ///    let c = RefCell::new(5);
-    ///    let m = c.borrow_mut();
+    ///    let m = c.borrow();
     ///
     ///    let b = c.borrow_mut(); // this causes a panic
     /// }).join();
index 1c1ad5fd33fb8bdfbaf142e4244853db5b469170..d3de77a9241e3f7dbab05cbe77f2b89ccba5c647 100644 (file)
@@ -11,7 +11,7 @@
 //! Traits for conversions between types.
 //!
 //! The traits in this module provide a general way to talk about conversions from one type to
-//! another. They follow the standard Rust conventions of `as`/`to`/`into`/`from`.
+//! another. They follow the standard Rust conventions of `as`/`into`/`from`.
 //!
 //! Like many traits, these are often used as bounds for generic functions, to support arguments of
 //! multiple types.
@@ -83,10 +83,8 @@ pub trait Into<T>: Sized {
 /// `String` implements `From<&str>`:
 ///
 /// ```
-/// let s = "hello";
 /// let string = "hello".to_string();
-///
-/// let other_string: String = From::from(s);
+/// let other_string = String::from("hello");
 ///
 /// assert_eq!(string, other_string);
 /// ```
index 5e98dd8b7df06092009e1daf6ec0ce05ed37241f..0fa27a4312d5760948c12ce5dcc6df8bf3918241 100644 (file)
@@ -179,8 +179,8 @@ fn chain<U>(self, other: U) -> Chain<Self, U::IntoIter> where
 
     /// Creates an iterator that iterates over both this and the specified
     /// iterators simultaneously, yielding the two elements as pairs. When
-    /// either iterator returns `None`, all further invocations of next() will
-    /// return `None`.
+    /// either iterator returns `None`, all further invocations of `next()`
+    /// will return `None`.
     ///
     /// # Examples
     ///
index 1e96d761d405a948e3db12b02f4f45f18ca27c19..38e66c5a3d6a2460e4e474a41f7e0c78a0ffb287 100644 (file)
@@ -625,6 +625,36 @@ fn into_iter(self) -> IterMut<'a, T> {
     }
 }
 
+#[inline(always)]
+fn size_from_ptr<T>(_: *const T) -> usize {
+    mem::size_of::<T>()
+}
+
+
+// Use macro to be generic over const/mut
+macro_rules! slice_offset {
+    ($ptr:expr, $by:expr) => {{
+        let ptr = $ptr;
+        if size_from_ptr(ptr) == 0 {
+            transmute(ptr as usize + $by)
+        } else {
+            ptr.offset($by)
+        }
+    }};
+}
+
+macro_rules! slice_ref {
+    ($ptr:expr) => {{
+        let ptr = $ptr;
+        if size_from_ptr(ptr) == 0 {
+            // Use a non-null pointer value
+            &mut *(1 as *mut _)
+        } else {
+            transmute(ptr)
+        }
+    }};
+}
+
 // The shared definition of the `Iter` and `IterMut` iterators
 macro_rules! iterator {
     (struct $name:ident -> $ptr:ty, $elem:ty) => {
@@ -641,20 +671,9 @@ fn next(&mut self) -> Option<$elem> {
                     if self.ptr == self.end {
                         None
                     } else {
-                        if mem::size_of::<T>() == 0 {
-                            // purposefully don't use 'ptr.offset' because for
-                            // vectors with 0-size elements this would return the
-                            // same pointer.
-                            self.ptr = transmute(self.ptr as usize + 1);
-
-                            // Use a non-null pointer value
-                            Some(&mut *(1 as *mut _))
-                        } else {
-                            let old = self.ptr;
-                            self.ptr = self.ptr.offset(1);
-
-                            Some(transmute(old))
-                        }
+                        let old = self.ptr;
+                        self.ptr = slice_offset!(self.ptr, 1);
+                        Some(slice_ref!(old))
                     }
                 }
             }
@@ -666,6 +685,22 @@ fn size_hint(&self) -> (usize, Option<usize>) {
                 let exact = diff / (if size == 0 {1} else {size});
                 (exact, Some(exact))
             }
+
+            #[inline]
+            fn count(self) -> usize {
+                self.size_hint().0
+            }
+
+            #[inline]
+            fn nth(&mut self, n: usize) -> Option<$elem> {
+                // Call helper method. Can't put the definition here because mut versus const.
+                self.iter_nth(n)
+            }
+
+            #[inline]
+            fn last(mut self) -> Option<$elem> {
+                self.next_back()
+            }
         }
 
         #[stable(feature = "rust1", since = "1.0.0")]
@@ -679,17 +714,8 @@ fn next_back(&mut self) -> Option<$elem> {
                     if self.end == self.ptr {
                         None
                     } else {
-                        if mem::size_of::<T>() == 0 {
-                            // See above for why 'ptr.offset' isn't used
-                            self.end = transmute(self.end as usize - 1);
-
-                            // Use a non-null pointer value
-                            Some(&mut *(1 as *mut _))
-                        } else {
-                            self.end = self.end.offset(-1);
-
-                            Some(transmute(self.end))
-                        }
+                        self.end = slice_offset!(self.end, -1);
+                        Some(slice_ref!(self.end))
                     }
                 }
             }
@@ -785,6 +811,20 @@ impl<'a, T> Iter<'a, T> {
     pub fn as_slice(&self) -> &'a [T] {
         make_slice!(T => &'a [T]: self.ptr, self.end)
     }
+
+    // Helper function for Iter::nth
+    fn iter_nth(&mut self, n: usize) -> Option<&'a T> {
+        match self.as_slice().get(n) {
+            Some(elem_ref) => unsafe {
+                self.ptr = slice_offset!(elem_ref as *const _, 1);
+                Some(slice_ref!(elem_ref))
+            },
+            None => {
+                self.ptr = self.end;
+                None
+            }
+        }
+    }
 }
 
 iterator!{struct Iter -> *const T, &'a T}
@@ -914,6 +954,20 @@ impl<'a, T> IterMut<'a, T> {
     pub fn into_slice(self) -> &'a mut [T] {
         make_mut_slice!(T => &'a mut [T]: self.ptr, self.end)
     }
+
+    // Helper function for IterMut::nth
+    fn iter_nth(&mut self, n: usize) -> Option<&'a mut T> {
+        match make_mut_slice!(T => &'a mut [T]: self.ptr, self.end).get_mut(n) {
+            Some(elem_ref) => unsafe {
+                self.ptr = slice_offset!(elem_ref as *mut _, 1);
+                Some(slice_ref!(elem_ref))
+            },
+            None => {
+                self.ptr = self.end;
+                None
+            }
+        }
+    }
 }
 
 iterator!{struct IterMut -> *mut T, &'a mut T}
index 85ca547da85260bfda02b72c8644362ae853e46f..0ea9f8afb4e532c140a89d882beaf68b59da42d3 100644 (file)
@@ -45,7 +45,7 @@ pub fn test_num<T>(ten: T, two: T) where
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use core::option::Option;
     use core::option::Option::{Some, None};
     use core::num::Float;
index fe73b3b44079503544c6dead2a334b86f0877f99..7c884a73ce05bd4a83e86cc29cb3baef47ad6ba1 100644 (file)
@@ -82,3 +82,34 @@ macro_rules! test {
     test!([1u8,2,3]);
     test!([(),(),()]);
 }
+
+#[test]
+fn test_iterator_nth() {
+    let v: &[_] = &[0, 1, 2, 3, 4];
+    for i in 0..v.len() {
+        assert_eq!(v.iter().nth(i).unwrap(), &v[i]);
+    }
+    assert_eq!(v.iter().nth(v.len()), None);
+
+    let mut iter = v.iter();
+    assert_eq!(iter.nth(2).unwrap(), &v[2]);
+    assert_eq!(iter.nth(1).unwrap(), &v[4]);
+}
+
+#[test]
+fn test_iterator_last() {
+    let v: &[_] = &[0, 1, 2, 3, 4];
+    assert_eq!(v.iter().last().unwrap(), &4);
+    assert_eq!(v[..1].iter().last().unwrap(), &0);
+}
+
+#[test]
+fn test_iterator_count() {
+    let v: &[_] = &[0, 1, 2, 3, 4];
+    assert_eq!(v.iter().count(), 5);
+
+    let mut iter2 = v.iter();
+    iter2.next();
+    iter2.next();
+    assert_eq!(iter2.count(), 3);
+}
index 4fbcdaa378e25cef101fcc258c5b695266fa536a..999e7c643e576b0b4aa0a3d9f977fc133d75af88 100644 (file)
 
 // 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, all(target_os = "nacl", test))))]
+#[cfg(not(any(windows, target_env = "musl", all(target_os = "nacl", test))))]
 #[link(name = "c")]
 #[link(name = "m")]
 extern {}
 
+#[cfg(all(target_env = "musl", not(test)))]
+#[link(name = "c", kind = "static")]
+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.
index 9cd3b74e1552d95adef258408645af0715a20bd6..bcb827cb471cacac023c650ae81a78d147ec83d7 100644 (file)
@@ -202,7 +202,7 @@ fn rand<R: Rng>(other: &mut R) -> ChaChaRng {
 
 
 #[cfg(test)]
-mod test {
+mod tests {
     use std::prelude::v1::*;
 
     use core::iter::order;
index 5ba6d8912f2672bcf73c58b0863f54fd18a87167..f46d35a33db1a034b2b6190faedf084180b26fa0 100644 (file)
@@ -82,7 +82,7 @@ fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use std::prelude::v1::*;
 
     use distributions::{Sample, IndependentSample};
index f37093c6db85bf20a19ad67f428284177f7b575d..2951563934b3c412d273bf4ef91394806fbb41ee 100644 (file)
@@ -276,7 +276,7 @@ fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use std::prelude::v1::*;
 
     use distributions::{Sample, IndependentSample};
index a7f7889783f70b775d40791d669efb547023a4bb..22fe46a8bd83a20e9f78a1a81ec2f47fcfc28c37 100644 (file)
@@ -510,7 +510,7 @@ fn rand<R: Rng>(other: &mut R) -> Isaac64Rng {
 
 
 #[cfg(test)]
-mod test {
+mod tests {
     use std::prelude::v1::*;
 
     use core::iter::order;
index ea084b2816dd1f349e8a38ff0073841a91cfb498..bb0b13c43756b474cd1603a2d07b329dbdfadd7d 100644 (file)
@@ -120,7 +120,7 @@ fn default() -> ReseedWithDefault { ReseedWithDefault }
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use std::prelude::v1::*;
 
     use core::iter::{order, repeat};
index 9093b3b9f5c91b8169b9a6c198c96cbbb248036a..d4012f2057b5dac8306e189e3401d6bc9b6a981c 100644 (file)
@@ -106,8 +106,10 @@ pub mod middle {
     pub mod entry;
     pub mod expr_use_visitor;
     pub mod fast_reject;
+    pub mod free_region;
     pub mod intrinsicck;
     pub mod infer;
+    pub mod implicator;
     pub mod lang_items;
     pub mod liveness;
     pub mod mem_categorization;
index d528e38d341cfe099a80acf0f37d039e9bc3c107..93056d949dbb07bfde8188d0823058ae0899c788 100644 (file)
@@ -175,6 +175,13 @@ pub fn get_provided_trait_methods<'tcx>(tcx: &ty::ctxt<'tcx>,
     decoder::get_provided_trait_methods(cstore.intr.clone(), &*cdata, def.node, tcx)
 }
 
+pub fn get_associated_consts<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId)
+                                   -> Vec<Rc<ty::AssociatedConst<'tcx>>> {
+    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: ast::DefId)
                           -> Option<ast::Name> {
     let cdata = cstore.get_crate_data(def.krate);
index cbd542567709c13f9b114d9949b1fc62784de9d3..f03a2d342d7be0d567562ab380070d4f4d3ffc48 100644 (file)
@@ -305,7 +305,25 @@ fn item_to_def_like(item: rbml::Doc, did: ast::DefId, cnum: ast::CrateNum)
     -> DefLike {
     let fam = item_family(item);
     match fam {
-        Constant  => DlDef(def::DefConst(did)),
+        Constant  => {
+            // Check whether we have an associated const item.
+            if item_sort(item) == Some('C') {
+                // Check whether the associated const is from a trait or impl.
+                // See the comment for methods below.
+                let provenance = if reader::maybe_get_doc(
+                      item, tag_item_trait_parent_sort).is_some() {
+                    def::FromTrait(item_reqd_and_translated_parent_item(cnum,
+                                                                        item))
+                } else {
+                    def::FromImpl(item_reqd_and_translated_parent_item(cnum,
+                                                                       item))
+                };
+                DlDef(def::DefAssociatedConst(did, provenance))
+            } else {
+                // Regular const item.
+                DlDef(def::DefConst(did))
+            }
+        }
         ImmStatic => DlDef(def::DefStatic(did, false)),
         MutStatic => DlDef(def::DefStatic(did, true)),
         Struct    => DlDef(def::DefStruct(did)),
@@ -826,6 +844,7 @@ pub fn get_impl_items(cdata: Cmd, impl_id: ast::NodeId)
                         tag_item_impl_item, |doc| {
         let def_id = item_def_id(doc, cdata);
         match item_sort(doc) {
+            Some('C') => impl_items.push(ty::ConstTraitItemId(def_id)),
             Some('r') | Some('p') => {
                 impl_items.push(ty::MethodTraitItemId(def_id))
             }
@@ -877,6 +896,18 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc<IdentInterner>,
     let vis = item_visibility(method_doc);
 
     match item_sort(method_doc) {
+        Some('C') => {
+            let ty = doc_type(method_doc, tcx, cdata);
+            let default = get_provided_source(method_doc, cdata);
+            ty::ConstTraitItem(Rc::new(ty::AssociatedConst {
+                name: name,
+                ty: ty,
+                vis: vis,
+                def_id: def_id,
+                container: container,
+                default: default,
+            }))
+        }
         Some('r') | Some('p') => {
             let generics = doc_generics(method_doc, tcx, cdata, tag_method_ty_generics);
             let predicates = doc_predicates(method_doc, tcx, cdata, tag_method_ty_generics);
@@ -914,6 +945,7 @@ pub fn get_trait_item_def_ids(cdata: Cmd, id: ast::NodeId)
     reader::tagged_docs(item, tag_item_trait_item, |mth| {
         let def_id = item_def_id(mth, cdata);
         match item_sort(mth) {
+            Some('C') => result.push(ty::ConstTraitItemId(def_id)),
             Some('r') | Some('p') => {
                 result.push(ty::MethodTraitItemId(def_id));
             }
@@ -951,11 +983,8 @@ pub fn get_provided_trait_methods<'tcx>(intr: Rc<IdentInterner>,
                                                     cdata,
                                                     did.node,
                                                     tcx);
-            match trait_item {
-                ty::MethodTraitItem(ref method) => {
-                    result.push((*method).clone())
-                }
-                ty::TypeTraitItem(_) => {}
+            if let ty::MethodTraitItem(ref method) = trait_item {
+                result.push((*method).clone())
             }
         }
         true
@@ -964,6 +993,36 @@ pub fn get_provided_trait_methods<'tcx>(intr: Rc<IdentInterner>,
     return result;
 }
 
+pub fn get_associated_consts<'tcx>(intr: Rc<IdentInterner>,
+                                   cdata: Cmd,
+                                   id: ast::NodeId,
+                                   tcx: &ty::ctxt<'tcx>)
+                                   -> Vec<Rc<ty::AssociatedConst<'tcx>>> {
+    let data = cdata.data();
+    let item = lookup_item(id, data);
+    let mut result = Vec::new();
+
+    for &tag in &[tag_item_trait_item, tag_item_impl_item] {
+        reader::tagged_docs(item, tag, |ac_id| {
+            let did = item_def_id(ac_id, cdata);
+            let ac_doc = lookup_item(did.node, data);
+
+            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 {
+                    result.push((*ac).clone())
+                }
+            }
+            true
+        });
+    }
+
+    return result;
+}
+
 pub fn get_type_name_if_impl(cdata: Cmd,
                              node_id: ast::NodeId) -> Option<ast::Name> {
     let item = lookup_item(node_id, cdata.data());
index 29270bd6c624bac0aa02705a1526f09742da3be3..bcbb350fc34ee7b12489c9d0ee23dd771865d7a1 100644 (file)
@@ -378,14 +378,11 @@ fn encode_reexported_static_base_methods(ecx: &EncodeContext,
                     let impl_item = ty::impl_or_trait_item(
                         ecx.tcx,
                         method_did.def_id());
-                    match impl_item {
-                        ty::MethodTraitItem(ref m) => {
-                            encode_reexported_static_method(rbml_w,
-                                                            exp,
-                                                            m.def_id,
-                                                            m.name);
-                        }
-                        ty::TypeTraitItem(_) => {}
+                    if let ty::MethodTraitItem(ref m) = impl_item {
+                        encode_reexported_static_method(rbml_w,
+                                                        exp,
+                                                        m.def_id,
+                                                        m.name);
                     }
                 }
             }
@@ -802,6 +799,43 @@ fn encode_method_ty_fields<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
     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>) {
+    debug!("encode_info_for_associated_const({:?},{:?})",
+           associated_const.def_id,
+           token::get_name(associated_const.name));
+
+    rbml_w.start_tag(tag_items_data_item);
+
+    encode_def_id(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, local_def(parent_id));
+    encode_item_sort(rbml_w, 'C');
+
+    encode_bounds_and_type_for_item(rbml_w, ecx, associated_const.def_id.local_id());
+
+    let stab = stability::lookup(ecx.tcx, associated_const.def_id);
+    encode_stability(rbml_w, stab);
+
+    let elem = ast_map::PathName(associated_const.name);
+    encode_path(rbml_w, impl_path.chain(Some(elem).into_iter()));
+
+    if let Some(ii) = impl_item_opt {
+        encode_attributes(rbml_w, &ii.attrs);
+        encode_inlined_item(ecx, rbml_w, IIImplItemRef(local_def(parent_id), ii));
+    }
+
+    rbml_w.end_tag();
+}
+
 fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
                                     rbml_w: &mut Encoder,
                                     m: &ty::Method<'tcx>,
@@ -1195,6 +1229,10 @@ fn add_to_index(item: &ast::Item, rbml_w: &mut Encoder,
         for &item_def_id in items {
             rbml_w.start_tag(tag_item_impl_item);
             match item_def_id {
+                ty::ConstTraitItemId(item_def_id) => {
+                    encode_def_id(rbml_w, item_def_id);
+                    encode_item_sort(rbml_w, 'C');
+                }
                 ty::MethodTraitItemId(item_def_id) => {
                     encode_def_id(rbml_w, item_def_id);
                     encode_item_sort(rbml_w, 'r');
@@ -1232,6 +1270,14 @@ fn add_to_index(item: &ast::Item, rbml_w: &mut Encoder,
             });
 
             match ty::impl_or_trait_item(tcx, trait_item_def_id.def_id()) {
+                ty::ConstTraitItem(ref associated_const) => {
+                    encode_info_for_associated_const(ecx,
+                                                     rbml_w,
+                                                     &*associated_const,
+                                                     path.clone(),
+                                                     item.id,
+                                                     ast_item)
+                }
                 ty::MethodTraitItem(ref method_type) => {
                     encode_info_for_method(ecx,
                                            rbml_w,
@@ -1276,6 +1322,10 @@ fn add_to_index(item: &ast::Item, rbml_w: &mut Encoder,
         for &method_def_id in &*ty::trait_item_def_ids(tcx, def_id) {
             rbml_w.start_tag(tag_item_trait_item);
             match method_def_id {
+                ty::ConstTraitItemId(const_def_id) => {
+                    encode_def_id(rbml_w, const_def_id);
+                    encode_item_sort(rbml_w, 'C');
+                }
                 ty::MethodTraitItemId(method_def_id) => {
                     encode_def_id(rbml_w, method_def_id);
                     encode_item_sort(rbml_w, 'r');
@@ -1321,6 +1371,25 @@ fn add_to_index(item: &ast::Item, rbml_w: &mut Encoder,
                 ty::impl_or_trait_item(tcx, item_def_id.def_id());
             let is_nonstatic_method;
             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_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).into_iter()));
+
+                    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());
+
+                    is_nonstatic_method = false;
+                }
                 ty::MethodTraitItem(method_ty) => {
                     let method_def_id = item_def_id.def_id();
 
@@ -1365,6 +1434,10 @@ fn add_to_index(item: &ast::Item, rbml_w: &mut Encoder,
             let trait_item = &*ms[i];
             encode_attributes(rbml_w, &trait_item.attrs);
             match trait_item.node {
+                ast::ConstTraitItem(_, _) => {
+                    encode_inlined_item(ecx, rbml_w,
+                                        IITraitItemRef(def_id, trait_item));
+                }
                 ast::MethodTraitItem(ref sig, ref body) => {
                     // If this is a static method, we've already
                     // encoded this.
@@ -1384,9 +1457,7 @@ fn add_to_index(item: &ast::Item, rbml_w: &mut Encoder,
                     encode_method_argument_names(rbml_w, &sig.decl);
                 }
 
-                ast::TypeTraitItem(..) => {
-                    encode_item_sort(rbml_w, 't');
-                }
+                ast::TypeTraitItem(..) => {}
             }
 
             rbml_w.end_tag();
index ee8373279d976f9f4d95c76cbba2a566121b93f2..3ef22ba8158b0ce69f93e622627cfcc7591cd59e 100644 (file)
@@ -465,6 +465,9 @@ fn tr(&self, dcx: &DecodeContext) -> def::Def {
           def::DefForeignMod(did) => { def::DefForeignMod(did.tr(dcx)) }
           def::DefStatic(did, m) => { def::DefStatic(did.tr(dcx), m) }
           def::DefConst(did) => { def::DefConst(did.tr(dcx)) }
+          def::DefAssociatedConst(did, p) => {
+              def::DefAssociatedConst(did.tr(dcx), p.map(|did2| did2.tr(dcx)))
+          }
           def::DefLocal(nid) => { def::DefLocal(dcx.tr_id(nid)) }
           def::DefVariant(e_did, v_did, is_s) => {
             def::DefVariant(e_did.tr(dcx), v_did.tr(dcx), is_s)
@@ -1835,29 +1838,31 @@ fn decode_item_ast(par_doc: rbml::Doc) -> ast::Item {
 }
 
 #[cfg(test)]
-trait fake_ext_ctxt {
+trait FakeExtCtxt {
+    fn call_site(&self) -> codemap::Span;
     fn cfg(&self) -> ast::CrateConfig;
-    fn parse_sess<'a>(&'a self) -> &'a parse::ParseSess;
-    fn call_site(&self) -> Span;
     fn ident_of(&self, st: &str) -> ast::Ident;
+    fn name_of(&self, st: &str) -> ast::Name;
+    fn parse_sess(&self) -> &parse::ParseSess;
 }
 
 #[cfg(test)]
-impl fake_ext_ctxt for parse::ParseSess {
-    fn cfg(&self) -> ast::CrateConfig {
-        Vec::new()
-    }
-    fn parse_sess<'a>(&'a self) -> &'a parse::ParseSess { self }
-    fn call_site(&self) -> Span {
+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
+            expn_id: codemap::NO_EXPANSION,
         }
     }
+    fn cfg(&self) -> ast::CrateConfig { Vec::new() }
     fn ident_of(&self, st: &str) -> ast::Ident {
-        token::str_to_ident(st)
+        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 }
 }
 
 #[cfg(test)]
@@ -1883,7 +1888,7 @@ fn test_basic() {
         fn foo() {}
     ));
 }
-/* NOTE: When there's a snapshot, update this (yay quasiquoter!)
+
 #[test]
 fn test_smalltalk() {
     let cx = mk_ctxt();
@@ -1891,7 +1896,6 @@ fn test_smalltalk() {
         fn foo() -> isize { 3 + 4 } // first smalltalk program ever executed.
     ));
 }
-*/
 
 #[test]
 fn test_more() {
index 359a1a486c9da7cabb5666f45cbc71de2ba607e5..a7950a701f8c4fce0c96045d6ca81dcfa2c24db2 100644 (file)
@@ -105,6 +105,7 @@ fn pat(&mut self, pat: &ast::Pat, pred: CFGIndex) -> CFGIndex {
         match pat.node {
             ast::PatIdent(_, _, None) |
             ast::PatEnum(_, None) |
+            ast::PatQPath(..) |
             ast::PatLit(..) |
             ast::PatRange(..) |
             ast::PatWild(_) => {
index ee9d1e015539e337a18a19ca066d6ddb197b2610..80326229618c23d05a28312c194c8506cc6675a6 100644 (file)
@@ -223,6 +223,28 @@ fn visit_item(&mut self, i: &ast::Item) {
         }
     }
 
+    fn visit_trait_item(&mut self, t: &'v ast::TraitItem) {
+        match t.node {
+            ast::ConstTraitItem(_, ref default) => {
+                if let Some(ref expr) = *default {
+                    self.global_expr(Mode::Const, &*expr);
+                } else {
+                    visit::walk_trait_item(self, t);
+                }
+            }
+            _ => self.with_mode(Mode::Var, |v| visit::walk_trait_item(v, t)),
+        }
+    }
+
+    fn visit_impl_item(&mut self, i: &'v ast::ImplItem) {
+        match i.node {
+            ast::ConstImplItem(_, ref expr) => {
+                self.global_expr(Mode::Const, &*expr);
+            }
+            _ => self.with_mode(Mode::Var, |v| visit::walk_impl_item(v, i)),
+        }
+    }
+
     fn visit_fn(&mut self,
                 fk: visit::FnKind<'v>,
                 fd: &'v ast::FnDecl,
@@ -468,13 +490,16 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
                         Mode::Var => v.add_qualif(NOT_CONST)
                     }
                 }
-                Some(def::DefConst(did)) => {
-                    if let Some(expr) = const_eval::lookup_const_by_id(v.tcx, did) {
+                Some(def::DefConst(did)) |
+                Some(def::DefAssociatedConst(did, _)) => {
+                    if let Some(expr) = const_eval::lookup_const_by_id(v.tcx, did,
+                                                                       Some(e.id)) {
                         let inner = v.global_expr(Mode::Const, expr);
                         v.add_qualif(inner);
                     } else {
-                        v.tcx.sess.span_bug(e.span, "DefConst doesn't point \
-                                                     to an ItemConst");
+                        v.tcx.sess.span_bug(e.span,
+                                            "DefConst or DefAssociatedConst \
+                                             doesn't point to a constant");
                     }
                 }
                 def => {
index 912854a6d7dfbb7470ece68ce8f483da1eefdc0c..a5ea3629abc84ad8fcce386d44764463b80bbd74 100644 (file)
@@ -439,10 +439,11 @@ fn visit_id(&mut self, node_id: NodeId) {
 impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> {
     fn fold_pat(&mut self, pat: P<Pat>) -> P<Pat> {
         return match pat.node {
-            ast::PatIdent(..) | ast::PatEnum(..) => {
+            ast::PatIdent(..) | ast::PatEnum(..) | ast::PatQPath(..) => {
                 let def = self.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def());
                 match def {
-                    Some(DefConst(did)) => match lookup_const_by_id(self.tcx, did) {
+                    Some(DefAssociatedConst(did, _)) |
+                    Some(DefConst(did)) => match lookup_const_by_id(self.tcx, did, Some(pat.id)) {
                         Some(const_expr) => {
                             const_expr_to_pat(self.tcx, const_expr, pat.span).map(|new_pat| {
 
@@ -746,7 +747,7 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat,
     match pat.node {
         ast::PatIdent(..) =>
             match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
-                Some(DefConst(..)) =>
+                Some(DefConst(..)) | Some(DefAssociatedConst(..)) =>
                     cx.tcx.sess.span_bug(pat.span, "const pattern should've \
                                                     been rewritten"),
                 Some(DefStruct(_)) => vec!(Single),
@@ -755,15 +756,18 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat,
             },
         ast::PatEnum(..) =>
             match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
-                Some(DefConst(..)) =>
+                Some(DefConst(..)) | Some(DefAssociatedConst(..)) =>
                     cx.tcx.sess.span_bug(pat.span, "const pattern should've \
                                                     been rewritten"),
                 Some(DefVariant(_, id, _)) => vec!(Variant(id)),
                 _ => vec!(Single)
             },
+        ast::PatQPath(..) =>
+            cx.tcx.sess.span_bug(pat.span, "const pattern should've \
+                                            been rewritten"),
         ast::PatStruct(..) =>
             match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
-                Some(DefConst(..)) =>
+                Some(DefConst(..)) | Some(DefAssociatedConst(..)) =>
                     cx.tcx.sess.span_bug(pat.span, "const pattern should've \
                                                     been rewritten"),
                 Some(DefVariant(_, id, _)) => vec!(Variant(id)),
@@ -861,7 +865,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
         ast::PatIdent(_, _, _) => {
             let opt_def = cx.tcx.def_map.borrow().get(&pat_id).map(|d| d.full_def());
             match opt_def {
-                Some(DefConst(..)) =>
+                Some(DefConst(..)) | Some(DefAssociatedConst(..)) =>
                     cx.tcx.sess.span_bug(pat_span, "const pattern should've \
                                                     been rewritten"),
                 Some(DefVariant(_, id, _)) => if *constructor == Variant(id) {
@@ -876,7 +880,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
         ast::PatEnum(_, ref args) => {
             let def = cx.tcx.def_map.borrow().get(&pat_id).unwrap().full_def();
             match def {
-                DefConst(..) =>
+                DefConst(..) | DefAssociatedConst(..) =>
                     cx.tcx.sess.span_bug(pat_span, "const pattern should've \
                                                     been rewritten"),
                 DefVariant(_, id, _) if *constructor != Variant(id) => None,
@@ -890,11 +894,16 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
             }
         }
 
+        ast::PatQPath(_, _) => {
+            cx.tcx.sess.span_bug(pat_span, "const pattern should've \
+                                            been rewritten")
+        }
+
         ast::PatStruct(_, ref pattern_fields, _) => {
             // Is this a struct or an enum variant?
             let def = cx.tcx.def_map.borrow().get(&pat_id).unwrap().full_def();
             let class_id = match def {
-                DefConst(..) =>
+                DefConst(..) | DefAssociatedConst(..) =>
                     cx.tcx.sess.span_bug(pat_span, "const pattern should've \
                                                     been rewritten"),
                 DefVariant(_, variant_id, _) => if *constructor == Variant(variant_id) {
index b97978fc03fff33ae23e04c0cb05595511f2d380..a521c4531c9a7e50e932eb81596c520754e0618d 100644 (file)
 // recursively.
 
 use session::Session;
-use middle::def::{DefStatic, DefConst, DefMap};
+use middle::def::{DefStatic, DefConst, DefAssociatedConst, DefMap};
 
 use syntax::ast;
 use syntax::{ast_util, ast_map};
+use syntax::codemap::Span;
 use syntax::visit::Visitor;
 use syntax::visit;
 
@@ -26,8 +27,43 @@ struct CheckCrateVisitor<'a, 'ast: 'a> {
 }
 
 impl<'v, 'a, 'ast> Visitor<'v> for CheckCrateVisitor<'a, 'ast> {
-    fn visit_item(&mut self, i: &ast::Item) {
-        check_item(self, i);
+    fn visit_item(&mut self, it: &ast::Item) {
+        match it.node {
+            ast::ItemStatic(_, _, ref expr) |
+            ast::ItemConst(_, ref expr) => {
+                let mut recursion_visitor =
+                    CheckItemRecursionVisitor::new(self, &it.span);
+                recursion_visitor.visit_item(it);
+                visit::walk_expr(self, &*expr)
+            },
+            _ => visit::walk_item(self, it)
+        }
+    }
+
+    fn visit_trait_item(&mut self, ti: &ast::TraitItem) {
+        match ti.node {
+            ast::ConstTraitItem(_, ref default) => {
+                if let Some(ref expr) = *default {
+                    let mut recursion_visitor =
+                        CheckItemRecursionVisitor::new(self, &ti.span);
+                    recursion_visitor.visit_trait_item(ti);
+                    visit::walk_expr(self, &*expr)
+                }
+            }
+            _ => visit::walk_trait_item(self, ti)
+        }
+    }
+
+    fn visit_impl_item(&mut self, ii: &ast::ImplItem) {
+        match ii.node {
+            ast::ConstImplItem(_, ref expr) => {
+                let mut recursion_visitor =
+                    CheckItemRecursionVisitor::new(self, &ii.span);
+                recursion_visitor.visit_impl_item(ii);
+                visit::walk_expr(self, &*expr)
+            }
+            _ => visit::walk_impl_item(self, ii)
+        }
     }
 }
 
@@ -44,51 +80,48 @@ pub fn check_crate<'ast>(sess: &Session,
     sess.abort_if_errors();
 }
 
-fn check_item(v: &mut CheckCrateVisitor, it: &ast::Item) {
-    match it.node {
-        ast::ItemStatic(_, _, ref ex) |
-        ast::ItemConst(_, ref ex) => {
-            check_item_recursion(v.sess, v.ast_map, v.def_map, it);
-            visit::walk_expr(v, &**ex)
-        },
-        _ => visit::walk_item(v, it)
-    }
-}
-
 struct CheckItemRecursionVisitor<'a, 'ast: 'a> {
-    root_it: &'a ast::Item,
+    root_span: &'a Span,
     sess: &'a Session,
     ast_map: &'a ast_map::Map<'ast>,
     def_map: &'a DefMap,
     idstack: Vec<ast::NodeId>
 }
 
-// Make sure a const item doesn't recursively refer to itself
-// FIXME: Should use the dependency graph when it's available (#1356)
-pub fn check_item_recursion<'a>(sess: &'a Session,
-                                ast_map: &'a ast_map::Map,
-                                def_map: &'a DefMap,
-                                it: &'a ast::Item) {
-
-    let mut visitor = CheckItemRecursionVisitor {
-        root_it: it,
-        sess: sess,
-        ast_map: ast_map,
-        def_map: def_map,
-        idstack: Vec::new()
-    };
-    visitor.visit_item(it);
+impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> {
+    fn new(v: &CheckCrateVisitor<'a, 'ast>, span: &'a Span)
+           -> CheckItemRecursionVisitor<'a, 'ast> {
+        CheckItemRecursionVisitor {
+            root_span: span,
+            sess: v.sess,
+            ast_map: v.ast_map,
+            def_map: v.def_map,
+            idstack: Vec::new()
+        }
+    }
+    fn with_item_id_pushed<F>(&mut self, id: ast::NodeId, f: F)
+          where F: Fn(&mut Self) {
+        if self.idstack.iter().any(|x| x == &(id)) {
+            span_err!(self.sess, *self.root_span, E0265, "recursive constant");
+            return;
+        }
+        self.idstack.push(id);
+        f(self);
+        self.idstack.pop();
+    }
 }
 
 impl<'a, 'ast, 'v> Visitor<'v> for CheckItemRecursionVisitor<'a, 'ast> {
     fn visit_item(&mut self, it: &ast::Item) {
-        if self.idstack.iter().any(|x| x == &(it.id)) {
-            span_err!(self.sess, self.root_it.span, E0265, "recursive constant");
-            return;
-        }
-        self.idstack.push(it.id);
-        visit::walk_item(self, it);
-        self.idstack.pop();
+        self.with_item_id_pushed(it.id, |v| visit::walk_item(v, it));
+    }
+
+    fn visit_trait_item(&mut self, ti: &ast::TraitItem) {
+        self.with_item_id_pushed(ti.id, |v| visit::walk_trait_item(v, ti));
+    }
+
+    fn visit_impl_item(&mut self, ii: &ast::ImplItem) {
+        self.with_item_id_pushed(ii.id, |v| visit::walk_impl_item(v, ii));
     }
 
     fn visit_expr(&mut self, e: &ast::Expr) {
@@ -96,11 +129,16 @@ fn visit_expr(&mut self, e: &ast::Expr) {
             ast::ExprPath(..) => {
                 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
                             ast_util::is_local(def_id) => {
                         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(_) => {},
                           _ => {
                             span_err!(self.sess, e.span, E0266,
index 2c6ffb3281fcb4922cd173710578565938bf65d3..916874f1c51a8ec2eeb24e79ed30e60c89f1b367 100644 (file)
 use self::ErrKind::*;
 
 use metadata::csearch;
-use middle::{astencode, def};
+use middle::{astencode, def, infer, subst, traits};
 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::ppaux::Repr;
 
 use syntax::ast::{self, Expr};
 use syntax::codemap::Span;
@@ -39,8 +40,9 @@
 fn lookup_const<'a>(tcx: &'a ty::ctxt, e: &Expr) -> Option<&'a Expr> {
     let opt_def = tcx.def_map.borrow().get(&e.id).map(|d| d.full_def());
     match opt_def {
-        Some(def::DefConst(def_id)) => {
-            lookup_const_by_id(tcx, def_id)
+        Some(def::DefConst(def_id)) |
+        Some(def::DefAssociatedConst(def_id, _)) => {
+            lookup_const_by_id(tcx, def_id, Some(e.id))
         }
         Some(def::DefVariant(enum_def, variant_def, _)) => {
             lookup_variant_by_id(tcx, enum_def, variant_def)
@@ -101,14 +103,46 @@ fn variant_expr<'a>(variants: &'a [P<ast::Variant>], id: ast::NodeId)
     }
 }
 
-pub fn lookup_const_by_id<'a>(tcx: &'a ty::ctxt, def_id: ast::DefId)
-                          -> Option<&'a Expr> {
+pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
+                                        def_id: ast::DefId,
+                                        maybe_ref_id: Option<ast::NodeId>)
+                                        -> Option<&'tcx Expr> {
     if ast_util::is_local(def_id) {
         match tcx.map.find(def_id.node) {
             None => None,
             Some(ast_map::NodeItem(it)) => match it.node {
                 ast::ItemConst(_, ref const_expr) => {
-                    Some(&**const_expr)
+                    Some(&*const_expr)
+                }
+                _ => None
+            },
+            Some(ast_map::NodeTraitItem(ti)) => match ti.node {
+                ast::ConstTraitItem(_, _) => {
+                    match maybe_ref_id {
+                        // If we have a trait item, and we know the expression
+                        // that's the source of the obligation to resolve it,
+                        // `resolve_trait_associated_const` will select an impl
+                        // or the default.
+                        Some(ref_id) => {
+                            let trait_id = ty::trait_of_item(tcx, def_id)
+                                              .unwrap();
+                            resolve_trait_associated_const(tcx, ti, trait_id,
+                                                           ref_id)
+                        }
+                        // Technically, without knowing anything about the
+                        // expression that generates the obligation, we could
+                        // still return the default if there is one. However,
+                        // it's safer to return `None` than to return some value
+                        // that may differ from what you would get from
+                        // correctly selecting an impl.
+                        None => None
+                    }
+                }
+                _ => None
+            },
+            Some(ast_map::NodeImplItem(ii)) => match ii.node {
+                ast::ConstImplItem(_, ref expr) => {
+                    Some(&*expr)
                 }
                 _ => None
             },
@@ -122,16 +156,44 @@ pub fn lookup_const_by_id<'a>(tcx: &'a ty::ctxt, def_id: ast::DefId)
             }
             None => {}
         }
+        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))) {
             csearch::FoundAst::Found(&ast::IIItem(ref item)) => match item.node {
                 ast::ItemConst(_, ref const_expr) => Some(const_expr.id),
                 _ => None
             },
+            csearch::FoundAst::Found(&ast::IITraitItem(trait_id, ref ti)) => match ti.node {
+                ast::ConstTraitItem(_, _) => {
+                    used_ref_id = true;
+                    match maybe_ref_id {
+                        // As mentioned in the comments above for in-crate
+                        // constants, we only try to find the expression for
+                        // a trait-associated const if the caller gives us
+                        // the expression that refers to it.
+                        Some(ref_id) => {
+                            resolve_trait_associated_const(tcx, ti, trait_id,
+                                                           ref_id).map(|e| e.id)
+                        }
+                        None => None
+                    }
+                }
+                _ => None
+            },
+            csearch::FoundAst::Found(&ast::IIImplItem(_, ref ii)) => match ii.node {
+                ast::ConstImplItem(_, ref expr) => Some(expr.id),
+                _ => None
+            },
             _ => None
         };
-        tcx.extern_const_statics.borrow_mut().insert(def_id,
-                                                     expr_id.unwrap_or(ast::DUMMY_NODE_ID));
+        // If we used the reference expression, particularly to choose an impl
+        // of a trait-associated const, don't cache that, because the next
+        // lookup with the same def_id may yield a different result.
+        if !used_ref_id {
+            tcx.extern_const_statics
+               .borrow_mut().insert(def_id,
+                                    expr_id.unwrap_or(ast::DUMMY_NODE_ID));
+        }
         expr_id.map(|id| tcx.map.expect_expr(id))
     }
 }
@@ -755,7 +817,35 @@ fn fromb(b: bool) -> const_val { const_int(b as i64) }
                           _ => (None, None)
                       }
                   } else {
-                      (lookup_const_by_id(tcx, def_id), None)
+                      (lookup_const_by_id(tcx, def_id, Some(e.id)), None)
+                  }
+              }
+              Some(def::DefAssociatedConst(def_id, provenance)) => {
+                  if ast_util::is_local(def_id) {
+                      match provenance {
+                          def::FromTrait(trait_id) => match tcx.map.find(def_id.node) {
+                              Some(ast_map::NodeTraitItem(ti)) => match ti.node {
+                                  ast::ConstTraitItem(ref ty, _) => {
+                                      (resolve_trait_associated_const(tcx, ti,
+                                                                      trait_id, e.id),
+                                       Some(&**ty))
+                                  }
+                                  _ => (None, None)
+                              },
+                              _ => (None, None)
+                          },
+                          def::FromImpl(_) => match tcx.map.find(def_id.node) {
+                              Some(ast_map::NodeImplItem(ii)) => match ii.node {
+                                  ast::ConstImplItem(ref ty, ref expr) => {
+                                      (Some(&**expr), Some(&**ty))
+                                  }
+                                  _ => (None, None)
+                              },
+                              _ => (None, None)
+                          },
+                      }
+                  } else {
+                      (lookup_const_by_id(tcx, def_id, Some(e.id)), None)
                   }
               }
               Some(def::DefVariant(enum_def, variant_def, _)) => {
@@ -833,6 +923,71 @@ fn fromb(b: bool) -> const_val { const_int(b as i64) }
     Ok(result)
 }
 
+fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
+                                                ti: &'tcx ast::TraitItem,
+                                                trait_id: ast::DefId,
+                                                ref_id: ast::NodeId)
+                                                -> Option<&'tcx Expr>
+{
+    let rcvr_substs = ty::node_id_item_substs(tcx, ref_id).substs;
+    let subst::SeparateVecsPerParamSpace {
+        types: rcvr_type,
+        selfs: rcvr_self,
+        fns: _,
+    } = rcvr_substs.types.split();
+    let trait_substs =
+        subst::Substs::erased(subst::VecPerParamSpace::new(rcvr_type,
+                                                           rcvr_self,
+                                                           Vec::new()));
+    let trait_substs = tcx.mk_substs(trait_substs);
+    debug!("resolve_trait_associated_const: trait_substs={}",
+           trait_substs.repr(tcx));
+    let trait_ref = ty::Binder(Rc::new(ty::TraitRef { def_id: trait_id,
+                                                      substs: trait_substs }));
+
+    ty::populate_implementations_for_trait_if_necessary(tcx, trait_ref.def_id());
+    let infcx = infer::new_infer_ctxt(tcx);
+
+    let param_env = ty::empty_parameter_environment(tcx);
+    let mut selcx = traits::SelectionContext::new(&infcx, &param_env);
+    let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
+                                             trait_ref.to_poly_trait_predicate());
+    let selection = match selcx.select(&obligation) {
+        Ok(Some(vtable)) => vtable,
+        // Still ambiguous, so give up and let the caller decide whether this
+        // expression is really needed yet. Some associated constant values
+        // can't be evaluated until monomorphization is done in trans.
+        Ok(None) => {
+            return None
+        }
+        Err(e) => {
+            tcx.sess.span_bug(ti.span,
+                              &format!("Encountered error `{}` when trying \
+                                        to select an implementation for \
+                                        constant trait item reference.",
+                                       e.repr(tcx)))
+        }
+    };
+
+    match selection {
+        traits::VtableImpl(ref impl_data) => {
+            match ty::associated_consts(tcx, impl_data.impl_def_id)
+                     .iter().find(|ic| ic.name == ti.ident.name) {
+                Some(ic) => lookup_const_by_id(tcx, ic.def_id, None),
+                None => match ti.node {
+                    ast::ConstTraitItem(_, Some(ref expr)) => Some(&*expr),
+                    _ => None,
+                },
+            }
+        }
+        _ => {
+            tcx.sess.span_bug(
+                ti.span,
+                &format!("resolve_trait_associated_const: unexpected vtable type"))
+        }
+    }
+}
+
 fn cast_const<'tcx>(tcx: &ty::ctxt<'tcx>, val: const_val, ty: Ty) -> CastResult {
     macro_rules! convert_val {
         ($intermediate_ty:ty, $const_type:ident, $target_ty:ty) => {
index 2befbf9924577dd7a61905074daa235922e2a2f6..1aa2ca9115d2f61429d3d62b36921c1254138db2 100644 (file)
@@ -72,7 +72,7 @@ fn check_def_id(&mut self, def_id: ast::DefId) {
     fn lookup_and_handle_definition(&mut self, id: &ast::NodeId) {
         self.tcx.def_map.borrow().get(id).map(|def| {
             match def.full_def() {
-                def::DefConst(_) => {
+                def::DefConst(_) | def::DefAssociatedConst(..) => {
                     self.check_def_id(def.def_id())
                 }
                 _ if self.ignore_non_const_paths => (),
@@ -114,14 +114,7 @@ fn lookup_and_handle_method(&mut self, id: ast::NodeId,
                         let trait_item = ty::trait_item(self.tcx,
                                                         trait_ref.def_id,
                                                         index);
-                        match trait_item {
-                            ty::MethodTraitItem(method) => {
-                                self.check_def_id(method.def_id);
-                            }
-                            ty::TypeTraitItem(typedef) => {
-                                self.check_def_id(typedef.def_id);
-                            }
-                        }
+                        self.check_def_id(trait_item.def_id());
                     }
                 }
             }
@@ -353,6 +346,7 @@ fn visit_item(&mut self, item: &ast::Item) {
             ast::ItemTrait(_, _, _, ref trait_items) => {
                 for trait_item in trait_items {
                     match trait_item.node {
+                        ast::ConstTraitItem(_, Some(_)) |
                         ast::MethodTraitItem(_, Some(_)) => {
                             if has_allow_dead_code_or_lang_attr(&trait_item.attrs) {
                                 self.worklist.push(trait_item.id);
@@ -365,6 +359,7 @@ fn visit_item(&mut self, item: &ast::Item) {
             ast::ItemImpl(_, _, _, ref opt_trait, _, ref impl_items) => {
                 for impl_item in impl_items {
                     match impl_item.node {
+                        ast::ConstImplItem(..) |
                         ast::MethodImplItem(..) => {
                             if opt_trait.is_some() ||
                                     has_allow_dead_code_or_lang_attr(&impl_item.attrs) {
@@ -406,7 +401,7 @@ fn create_and_seed_worklist(tcx: &ty::ctxt,
         None => ()
     }
 
-    // Seed implemented trait methods
+    // Seed implemented trait items
     let mut life_seeder = LifeSeeder {
         worklist: worklist
     };
@@ -487,7 +482,7 @@ fn symbol_is_live(&mut self, id: ast::NodeId,
                              |ctor| self.live_symbols.contains(&ctor)) {
             return true;
         }
-        // If it's a type whose methods are live, then it's live, too.
+        // If it's a type whose items are live, then it's live, too.
         // This is done to handle the case where, for example, the static
         // method of a private type is used, but the type itself is never
         // called directly.
@@ -557,21 +552,6 @@ fn visit_foreign_item(&mut self, fi: &ast::ForeignItem) {
         visit::walk_foreign_item(self, fi);
     }
 
-    fn visit_fn(&mut self, fk: visit::FnKind<'v>,
-                _: &'v ast::FnDecl, block: &'v ast::Block,
-                span: codemap::Span, id: ast::NodeId) {
-        // Have to warn method here because methods are not ast::Item
-        match fk {
-            visit::FkMethod(name, _, _) => {
-                if !self.symbol_is_live(id, None) {
-                    self.warn_dead_code(id, span, name.name, "method");
-                }
-            }
-            _ => ()
-        }
-        visit::walk_block(self, block);
-    }
-
     fn visit_struct_field(&mut self, field: &ast::StructField) {
         if self.should_warn_about_field(&field.node) {
             self.warn_dead_code(field.node.id, field.span,
@@ -581,12 +561,37 @@ fn visit_struct_field(&mut self, field: &ast::StructField) {
         visit::walk_struct_field(self, field);
     }
 
-    // Overwrite so that we don't warn the trait method itself.
-    fn visit_trait_item(&mut self, trait_method: &ast::TraitItem) {
-        match trait_method.node {
+    fn visit_impl_item(&mut self, impl_item: &ast::ImplItem) {
+        match impl_item.node {
+            ast::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");
+                }
+                visit::walk_expr(self, expr)
+            }
+            ast::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");
+                }
+                visit::walk_block(self, body)
+            }
+            ast::TypeImplItem(..) |
+            ast::MacImplItem(..) => {}
+        }
+    }
+
+    // Overwrite so that we don't warn the trait item itself.
+    fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) {
+        match trait_item.node {
+            ast::ConstTraitItem(_, Some(ref expr)) => {
+                visit::walk_expr(self, expr)
+            }
             ast::MethodTraitItem(_, Some(ref body)) => {
                 visit::walk_block(self, body)
             }
+            ast::ConstTraitItem(_, None) |
             ast::MethodTraitItem(_, None) |
             ast::TypeTraitItem(..) => {}
         }
index f0b359088549b05333b2e01efba7ed1e9c5820ea..bce246fa4af866dbd2ec1f974dbdd4158ee5f0f0 100644 (file)
@@ -28,6 +28,7 @@ pub enum Def {
     DefForeignMod(ast::DefId),
     DefStatic(ast::DefId, bool /* is_mutbl */),
     DefConst(ast::DefId),
+    DefAssociatedConst(ast::DefId /* const */, MethodProvenance),
     DefLocal(ast::NodeId),
     DefVariant(ast::DefId /* enum */, ast::DefId /* variant */, bool /* is_structure */),
     DefTy(ast::DefId, bool /* is_enum */),
@@ -140,7 +141,8 @@ pub fn def_id(&self) -> ast::DefId {
             DefFn(id, _) | DefMod(id) | DefForeignMod(id) | DefStatic(id, _) |
             DefVariant(_, id, _) | DefTy(id, _) | DefAssociatedTy(_, id) |
             DefTyParam(_, _, id, _) | DefUse(id) | DefStruct(id) | DefTrait(id) |
-            DefMethod(id, _) | DefConst(id) | DefSelfTy(Some(id), None)=> {
+            DefMethod(id, _) | DefConst(id) | DefAssociatedConst(id, _) |
+            DefSelfTy(Some(id), None)=> {
                 id
             }
             DefLocal(id) |
index 5235bbdf9cf00f67479357b1752b8824a9a0a03f..d740d24e23672d9016e8c76a9a9f8f60884733e1 100644 (file)
@@ -234,7 +234,7 @@ fn from_method_id(tcx: &ty::ctxt, method_id: ast::DefId)
             ty::MethodTraitItem(ref method_descriptor) => {
                 (*method_descriptor).clone()
             }
-            ty::TypeTraitItem(_) => {
+            _ => {
                 tcx.sess.bug("overloaded call method wasn't in method map")
             }
         };
@@ -1147,7 +1147,8 @@ fn walk_pat(&mut self,
             let tcx = typer.tcx();
 
             match pat.node {
-                ast::PatEnum(_, _) | ast::PatIdent(_, _, None) | ast::PatStruct(..) => {
+                ast::PatEnum(_, _) | ast::PatQPath(..) |
+                ast::PatIdent(_, _, None) | ast::PatStruct(..) => {
                     match def_map.get(&pat.id).map(|d| d.full_def()) {
                         None => {
                             // no definition found: pat is not a
@@ -1183,6 +1184,7 @@ fn walk_pat(&mut self,
                         }
 
                         Some(def::DefConst(..)) |
+                        Some(def::DefAssociatedConst(..)) |
                         Some(def::DefLocal(..)) => {
                             // This is a leaf (i.e. identifier binding
                             // or constant value to match); thus no
diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs
new file mode 100644 (file)
index 0000000..0c8a956
--- /dev/null
@@ -0,0 +1,127 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! This file defines
+
+use middle::implicator::Implication;
+use middle::ty::{self, FreeRegion};
+use util::common::can_reach;
+use util::nodemap::FnvHashMap;
+use util::ppaux::Repr;
+
+#[derive(Clone)]
+pub struct FreeRegionMap {
+    /// `free_region_map` maps from a free region `a` to a list of
+    /// free regions `bs` such that `a <= b for all b in bs`
+    map: FnvHashMap<FreeRegion, Vec<FreeRegion>>,
+}
+
+impl FreeRegionMap {
+    pub fn new() -> FreeRegionMap {
+        FreeRegionMap { map: FnvHashMap() }
+    }
+
+    pub fn relate_free_regions_from_implications<'tcx>(&mut self,
+                                                       tcx: &ty::ctxt<'tcx>,
+                                                       implications: &[Implication<'tcx>])
+    {
+        for implication in implications {
+            debug!("implication: {}", implication.repr(tcx));
+            match *implication {
+                Implication::RegionSubRegion(_, ty::ReFree(free_a), ty::ReFree(free_b)) => {
+                    self.relate_free_regions(free_a, free_b);
+                }
+                Implication::RegionSubRegion(..) |
+                Implication::RegionSubClosure(..) |
+                Implication::RegionSubGeneric(..) |
+                Implication::Predicate(..) => {
+                }
+            }
+        }
+    }
+
+    pub fn relate_free_regions_from_predicates<'tcx>(&mut self,
+                                                     tcx: &ty::ctxt<'tcx>,
+                                                     predicates: &[ty::Predicate<'tcx>]) {
+        debug!("relate_free_regions_from_predicates(predicates={})", predicates.repr(tcx));
+        for predicate in predicates {
+            match *predicate {
+                ty::Predicate::Projection(..) |
+                ty::Predicate::Trait(..) |
+                ty::Predicate::Equate(..) |
+                ty::Predicate::TypeOutlives(..) => {
+                    // No region bounds here
+                }
+                ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => {
+                    match (r_a, r_b) {
+                        (ty::ReFree(fr_a), ty::ReFree(fr_b)) => {
+                            // Record that `'a:'b`. Or, put another way, `'b <= 'a`.
+                            self.relate_free_regions(fr_b, fr_a);
+                        }
+                        _ => {
+                            // All named regions are instantiated with free regions.
+                            tcx.sess.bug(
+                                &format!("record_region_bounds: non free region: {} / {}",
+                                         r_a.repr(tcx),
+                                         r_b.repr(tcx)));
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    pub fn relate_free_regions(&mut self, sub: FreeRegion, sup: FreeRegion) {
+        let mut sups = self.map.entry(sub).or_insert(Vec::new());
+        if !sups.contains(&sup) {
+            sups.push(sup);
+        }
+    }
+
+    /// Determines whether two free regions have a subregion relationship
+    /// by walking the graph encoded in `map`.  Note that
+    /// it is possible that `sub != sup` and `sub <= sup` and `sup <= sub`
+    /// (that is, the user can give two different names to the same lifetime).
+    pub fn sub_free_region(&self, sub: FreeRegion, sup: FreeRegion) -> bool {
+        can_reach(&self.map, sub, sup)
+    }
+
+    /// Determines whether one region is a subregion of another.  This is intended to run *after
+    /// inference* and sadly the logic is somewhat duplicated with the code in infer.rs.
+    pub fn is_subregion_of(&self,
+                           tcx: &ty::ctxt,
+                           sub_region: ty::Region,
+                           super_region: ty::Region)
+                           -> bool {
+        debug!("is_subregion_of(sub_region={:?}, super_region={:?})",
+               sub_region, super_region);
+
+        sub_region == super_region || {
+            match (sub_region, super_region) {
+                (ty::ReEmpty, _) |
+                (_, ty::ReStatic) =>
+                    true,
+
+                (ty::ReScope(sub_scope), ty::ReScope(super_scope)) =>
+                    tcx.region_maps.is_subscope_of(sub_scope, super_scope),
+
+                (ty::ReScope(sub_scope), ty::ReFree(ref fr)) =>
+                    tcx.region_maps.is_subscope_of(sub_scope, fr.scope.to_code_extent()),
+
+                (ty::ReFree(sub_fr), ty::ReFree(super_fr)) =>
+                    self.sub_free_region(sub_fr, super_fr),
+
+                _ =>
+                    false,
+            }
+        }
+    }
+}
+
diff --git a/src/librustc/middle/implicator.rs b/src/librustc/middle/implicator.rs
new file mode 100644 (file)
index 0000000..0d6a1df
--- /dev/null
@@ -0,0 +1,487 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// #![warn(deprecated_mode)]
+
+use middle::infer::{InferCtxt, GenericKind};
+use middle::subst::Substs;
+use middle::traits;
+use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
+use middle::ty_fold::{TypeFoldable, TypeFolder};
+
+use std::rc::Rc;
+use syntax::ast;
+use syntax::codemap::Span;
+
+use util::common::ErrorReported;
+use util::nodemap::FnvHashSet;
+use util::ppaux::Repr;
+
+// Helper functions related to manipulating region types.
+
+pub enum Implication<'tcx> {
+    RegionSubRegion(Option<Ty<'tcx>>, ty::Region, ty::Region),
+    RegionSubGeneric(Option<Ty<'tcx>>, ty::Region, GenericKind<'tcx>),
+    RegionSubClosure(Option<Ty<'tcx>>, ty::Region, ast::DefId, &'tcx Substs<'tcx>),
+    Predicate(ast::DefId, ty::Predicate<'tcx>),
+}
+
+struct Implicator<'a, 'tcx: 'a> {
+    infcx: &'a InferCtxt<'a,'tcx>,
+    closure_typer: &'a (ty::ClosureTyper<'tcx>+'a),
+    body_id: ast::NodeId,
+    stack: Vec<(ty::Region, Option<Ty<'tcx>>)>,
+    span: Span,
+    out: Vec<Implication<'tcx>>,
+    visited: FnvHashSet<Ty<'tcx>>,
+}
+
+/// This routine computes the well-formedness constraints that must hold for the type `ty` to
+/// appear in a context with lifetime `outer_region`
+pub fn implications<'a,'tcx>(
+    infcx: &'a InferCtxt<'a,'tcx>,
+    closure_typer: &ty::ClosureTyper<'tcx>,
+    body_id: ast::NodeId,
+    ty: Ty<'tcx>,
+    outer_region: ty::Region,
+    span: Span)
+    -> Vec<Implication<'tcx>>
+{
+    debug!("implications(body_id={}, ty={}, outer_region={})",
+           body_id,
+           ty.repr(closure_typer.tcx()),
+           outer_region.repr(closure_typer.tcx()));
+
+    let mut stack = Vec::new();
+    stack.push((outer_region, None));
+    let mut wf = Implicator { closure_typer: closure_typer,
+                              infcx: infcx,
+                              body_id: body_id,
+                              span: span,
+                              stack: stack,
+                              out: Vec::new(),
+                              visited: FnvHashSet() };
+    wf.accumulate_from_ty(ty);
+    debug!("implications: out={}", wf.out.repr(closure_typer.tcx()));
+    wf.out
+}
+
+impl<'a, 'tcx> Implicator<'a, 'tcx> {
+    fn tcx(&self) -> &'a ty::ctxt<'tcx> {
+        self.infcx.tcx
+    }
+
+    fn accumulate_from_ty(&mut self, ty: Ty<'tcx>) {
+        debug!("accumulate_from_ty(ty={})",
+               ty.repr(self.tcx()));
+
+        // When expanding out associated types, we can visit a cyclic
+        // set of types. Issue #23003.
+        if !self.visited.insert(ty) {
+            return;
+        }
+
+        match ty.sty {
+            ty::ty_bool |
+            ty::ty_char |
+            ty::ty_int(..) |
+            ty::ty_uint(..) |
+            ty::ty_float(..) |
+            ty::ty_bare_fn(..) |
+            ty::ty_err |
+            ty::ty_str => {
+                // No borrowed content reachable here.
+            }
+
+            ty::ty_closure(def_id, substs) => {
+                let &(r_a, opt_ty) = self.stack.last().unwrap();
+                self.out.push(Implication::RegionSubClosure(opt_ty, r_a, def_id, substs));
+            }
+
+            ty::ty_trait(ref t) => {
+                let required_region_bounds =
+                    object_region_bounds(self.tcx(), &t.principal, t.bounds.builtin_bounds);
+                self.accumulate_from_object_ty(ty, t.bounds.region_bound, required_region_bounds)
+            }
+
+            ty::ty_enum(def_id, substs) |
+            ty::ty_struct(def_id, substs) => {
+                let item_scheme = ty::lookup_item_type(self.tcx(), def_id);
+                self.accumulate_from_adt(ty, def_id, &item_scheme.generics, substs)
+            }
+
+            ty::ty_vec(t, _) |
+            ty::ty_ptr(ty::mt { ty: t, .. }) |
+            ty::ty_uniq(t) => {
+                self.accumulate_from_ty(t)
+            }
+
+            ty::ty_rptr(r_b, mt) => {
+                self.accumulate_from_rptr(ty, *r_b, mt.ty);
+            }
+
+            ty::ty_param(p) => {
+                self.push_param_constraint_from_top(p);
+            }
+
+            ty::ty_projection(ref data) => {
+                // `<T as TraitRef<..>>::Name`
+
+                self.push_projection_constraint_from_top(data);
+            }
+
+            ty::ty_tup(ref tuptys) => {
+                for &tupty in tuptys {
+                    self.accumulate_from_ty(tupty);
+                }
+            }
+
+            ty::ty_infer(_) => {
+                // This should not happen, BUT:
+                //
+                //   Currently we uncover region relationships on
+                //   entering the fn check. We should do this after
+                //   the fn check, then we can call this case a bug().
+            }
+        }
+    }
+
+    fn accumulate_from_rptr(&mut self,
+                            ty: Ty<'tcx>,
+                            r_b: ty::Region,
+                            ty_b: Ty<'tcx>) {
+        // We are walking down a type like this, and current
+        // position is indicated by caret:
+        //
+        //     &'a &'b ty_b
+        //         ^
+        //
+        // At this point, top of stack will be `'a`. We must
+        // require that `'a <= 'b`.
+
+        self.push_region_constraint_from_top(r_b);
+
+        // Now we push `'b` onto the stack, because it must
+        // constrain any borrowed content we find within `T`.
+
+        self.stack.push((r_b, Some(ty)));
+        self.accumulate_from_ty(ty_b);
+        self.stack.pop().unwrap();
+    }
+
+    /// Pushes a constraint that `r_b` must outlive the top region on the stack.
+    fn push_region_constraint_from_top(&mut self,
+                                       r_b: ty::Region) {
+
+        // Indicates that we have found borrowed content with a lifetime
+        // of at least `r_b`. This adds a constraint that `r_b` must
+        // outlive the region `r_a` on top of the stack.
+        //
+        // As an example, imagine walking a type like:
+        //
+        //     &'a &'b T
+        //         ^
+        //
+        // when we hit the inner pointer (indicated by caret), `'a` will
+        // be on top of stack and `'b` will be the lifetime of the content
+        // we just found. So we add constraint that `'a <= 'b`.
+
+        let &(r_a, opt_ty) = self.stack.last().unwrap();
+        self.push_sub_region_constraint(opt_ty, r_a, r_b);
+    }
+
+    /// Pushes a constraint that `r_a <= r_b`, due to `opt_ty`
+    fn push_sub_region_constraint(&mut self,
+                                  opt_ty: Option<Ty<'tcx>>,
+                                  r_a: ty::Region,
+                                  r_b: ty::Region) {
+        self.out.push(Implication::RegionSubRegion(opt_ty, r_a, r_b));
+    }
+
+    /// Pushes a constraint that `param_ty` must outlive the top region on the stack.
+    fn push_param_constraint_from_top(&mut self,
+                                      param_ty: ty::ParamTy) {
+        let &(region, opt_ty) = self.stack.last().unwrap();
+        self.push_param_constraint(region, opt_ty, param_ty);
+    }
+
+    /// Pushes a constraint that `projection_ty` must outlive the top region on the stack.
+    fn push_projection_constraint_from_top(&mut self,
+                                           projection_ty: &ty::ProjectionTy<'tcx>) {
+        let &(region, opt_ty) = self.stack.last().unwrap();
+        self.out.push(Implication::RegionSubGeneric(
+            opt_ty, region, GenericKind::Projection(projection_ty.clone())));
+    }
+
+    /// Pushes a constraint that `region <= param_ty`, due to `opt_ty`
+    fn push_param_constraint(&mut self,
+                             region: ty::Region,
+                             opt_ty: Option<Ty<'tcx>>,
+                             param_ty: ty::ParamTy) {
+        self.out.push(Implication::RegionSubGeneric(
+            opt_ty, region, GenericKind::Param(param_ty)));
+    }
+
+    fn accumulate_from_adt(&mut self,
+                           ty: Ty<'tcx>,
+                           def_id: ast::DefId,
+                           _generics: &ty::Generics<'tcx>,
+                           substs: &Substs<'tcx>)
+    {
+        let predicates =
+            ty::lookup_predicates(self.tcx(), def_id).instantiate(self.tcx(), substs);
+        let predicates = match self.fully_normalize(&predicates) {
+            Ok(predicates) => predicates,
+            Err(ErrorReported) => { return; }
+        };
+
+        for predicate in predicates.predicates.as_slice() {
+            match *predicate {
+                ty::Predicate::Trait(ref data) => {
+                    self.accumulate_from_assoc_types_transitive(data);
+                }
+                ty::Predicate::Equate(..) => { }
+                ty::Predicate::Projection(..) => { }
+                ty::Predicate::RegionOutlives(ref data) => {
+                    match ty::no_late_bound_regions(self.tcx(), data) {
+                        None => { }
+                        Some(ty::OutlivesPredicate(r_a, r_b)) => {
+                            self.push_sub_region_constraint(Some(ty), r_b, r_a);
+                        }
+                    }
+                }
+                ty::Predicate::TypeOutlives(ref data) => {
+                    match ty::no_late_bound_regions(self.tcx(), data) {
+                        None => { }
+                        Some(ty::OutlivesPredicate(ty_a, r_b)) => {
+                            self.stack.push((r_b, Some(ty)));
+                            self.accumulate_from_ty(ty_a);
+                            self.stack.pop().unwrap();
+                        }
+                    }
+                }
+            }
+        }
+
+        let obligations = predicates.predicates
+                                    .into_iter()
+                                    .map(|pred| Implication::Predicate(def_id, pred));
+        self.out.extend(obligations);
+
+        let variances = ty::item_variances(self.tcx(), def_id);
+
+        for (&region, &variance) in substs.regions().iter().zip(variances.regions.iter()) {
+            match variance {
+                ty::Contravariant | ty::Invariant => {
+                    // If any data with this lifetime is reachable
+                    // within, it must be at least contravariant.
+                    self.push_region_constraint_from_top(region)
+                }
+                ty::Covariant | ty::Bivariant => { }
+            }
+        }
+
+        for (&ty, &variance) in substs.types.iter().zip(variances.types.iter()) {
+            match variance {
+                ty::Covariant | ty::Invariant => {
+                    // If any data of this type is reachable within,
+                    // it must be at least covariant.
+                    self.accumulate_from_ty(ty);
+                }
+                ty::Contravariant | ty::Bivariant => { }
+            }
+        }
+    }
+
+    /// Given that there is a requirement that `Foo<X> : 'a`, where
+    /// `Foo` is declared like `struct Foo<T> where T : SomeTrait`,
+    /// this code finds all the associated types defined in
+    /// `SomeTrait` (and supertraits) and adds a requirement that `<X
+    /// as SomeTrait>::N : 'a` (where `N` is some associated type
+    /// defined in `SomeTrait`). This rule only applies to
+    /// trait-bounds that are not higher-ranked, because we cannot
+    /// project out of a HRTB. This rule helps code using associated
+    /// types to compile, see Issue #22246 for an example.
+    fn accumulate_from_assoc_types_transitive(&mut self,
+                                              data: &ty::PolyTraitPredicate<'tcx>)
+    {
+        debug!("accumulate_from_assoc_types_transitive({})",
+               data.repr(self.tcx()));
+
+        for poly_trait_ref in traits::supertraits(self.tcx(), data.to_poly_trait_ref()) {
+            match ty::no_late_bound_regions(self.tcx(), &poly_trait_ref) {
+                Some(trait_ref) => { self.accumulate_from_assoc_types(trait_ref); }
+                None => { }
+            }
+        }
+    }
+
+    fn accumulate_from_assoc_types(&mut self,
+                                   trait_ref: Rc<ty::TraitRef<'tcx>>)
+    {
+        debug!("accumulate_from_assoc_types({})",
+               trait_ref.repr(self.tcx()));
+
+        let trait_def_id = trait_ref.def_id;
+        let trait_def = ty::lookup_trait_def(self.tcx(), trait_def_id);
+        let assoc_type_projections: Vec<_> =
+            trait_def.associated_type_names
+                     .iter()
+                     .map(|&name| ty::mk_projection(self.tcx(), trait_ref.clone(), name))
+                     .collect();
+        debug!("accumulate_from_assoc_types: assoc_type_projections={}",
+               assoc_type_projections.repr(self.tcx()));
+        let tys = match self.fully_normalize(&assoc_type_projections) {
+            Ok(tys) => { tys }
+            Err(ErrorReported) => { return; }
+        };
+        for ty in tys {
+            self.accumulate_from_ty(ty);
+        }
+    }
+
+    fn accumulate_from_object_ty(&mut self,
+                                 ty: Ty<'tcx>,
+                                 region_bound: ty::Region,
+                                 required_region_bounds: Vec<ty::Region>)
+    {
+        // Imagine a type like this:
+        //
+        //     trait Foo { }
+        //     trait Bar<'c> : 'c { }
+        //
+        //     &'b (Foo+'c+Bar<'d>)
+        //         ^
+        //
+        // In this case, the following relationships must hold:
+        //
+        //     'b <= 'c
+        //     'd <= 'c
+        //
+        // The first conditions is due to the normal region pointer
+        // rules, which say that a reference cannot outlive its
+        // referent.
+        //
+        // The final condition may be a bit surprising. In particular,
+        // you may expect that it would have been `'c <= 'd`, since
+        // usually lifetimes of outer things are conservative
+        // approximations for inner things. However, it works somewhat
+        // differently with trait objects: here the idea is that if the
+        // user specifies a region bound (`'c`, in this case) it is the
+        // "master bound" that *implies* that bounds from other traits are
+        // all met. (Remember that *all bounds* in a type like
+        // `Foo+Bar+Zed` must be met, not just one, hence if we write
+        // `Foo<'x>+Bar<'y>`, we know that the type outlives *both* 'x and
+        // 'y.)
+        //
+        // Note: in fact we only permit builtin traits, not `Bar<'d>`, I
+        // am looking forward to the future here.
+
+        // The content of this object type must outlive
+        // `bounds.region_bound`:
+        let r_c = region_bound;
+        self.push_region_constraint_from_top(r_c);
+
+        // And then, in turn, to be well-formed, the
+        // `region_bound` that user specified must imply the
+        // region bounds required from all of the trait types:
+        for &r_d in &required_region_bounds {
+            // Each of these is an instance of the `'c <= 'b`
+            // constraint above
+            self.out.push(Implication::RegionSubRegion(Some(ty), r_d, r_c));
+        }
+    }
+
+    fn fully_normalize<T>(&self, value: &T) -> Result<T,ErrorReported>
+        where T : TypeFoldable<'tcx> + ty::HasProjectionTypes + Clone + Repr<'tcx>
+    {
+        let value =
+            traits::fully_normalize(self.infcx,
+                                    self.closure_typer,
+                                    traits::ObligationCause::misc(self.span, self.body_id),
+                                    value);
+        match value {
+            Ok(value) => Ok(value),
+            Err(errors) => {
+                // I don't like reporting these errors here, but I
+                // don't know where else to report them just now. And
+                // I don't really expect errors to arise here
+                // frequently. I guess the best option would be to
+                // propagate them out.
+                traits::report_fulfillment_errors(self.infcx, &errors);
+                Err(ErrorReported)
+            }
+        }
+    }
+}
+
+/// Given an object type like `SomeTrait+Send`, computes the lifetime
+/// bounds that must hold on the elided self type. These are derived
+/// from the declarations of `SomeTrait`, `Send`, and friends -- if
+/// they declare `trait SomeTrait : 'static`, for example, then
+/// `'static` would appear in the list. The hard work is done by
+/// `ty::required_region_bounds`, see that for more information.
+pub fn object_region_bounds<'tcx>(
+    tcx: &ty::ctxt<'tcx>,
+    principal: &ty::PolyTraitRef<'tcx>,
+    others: ty::BuiltinBounds)
+    -> Vec<ty::Region>
+{
+    // Since we don't actually *know* the self type for an object,
+    // this "open(err)" serves as a kind of dummy standin -- basically
+    // a skolemized type.
+    let open_ty = ty::mk_infer(tcx, ty::FreshTy(0));
+
+    // Note that we preserve the overall binding levels here.
+    assert!(!open_ty.has_escaping_regions());
+    let substs = tcx.mk_substs(principal.0.substs.with_self_ty(open_ty));
+    let trait_refs = vec!(ty::Binder(Rc::new(ty::TraitRef::new(principal.0.def_id, substs))));
+
+    let param_bounds = ty::ParamBounds {
+        region_bounds: Vec::new(),
+        builtin_bounds: others,
+        trait_bounds: trait_refs,
+        projection_bounds: Vec::new(), // not relevant to computing region bounds
+    };
+
+    let predicates = ty::predicates(tcx, open_ty, &param_bounds);
+    ty::required_region_bounds(tcx, open_ty, predicates)
+}
+
+impl<'tcx> Repr<'tcx> for Implication<'tcx> {
+    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
+        match *self {
+            Implication::RegionSubRegion(_, ref r_a, ref r_b) => {
+                format!("RegionSubRegion({}, {})",
+                        r_a.repr(tcx),
+                        r_b.repr(tcx))
+            }
+
+            Implication::RegionSubGeneric(_, ref r, ref p) => {
+                format!("RegionSubGeneric({}, {})",
+                        r.repr(tcx),
+                        p.repr(tcx))
+            }
+
+            Implication::RegionSubClosure(_, ref a, ref b, ref c) => {
+                format!("RegionSubClosure({}, {}, {})",
+                        a.repr(tcx),
+                        b.repr(tcx),
+                        c.repr(tcx))
+            }
+
+            Implication::Predicate(ref def_id, ref p) => {
+                format!("Predicate({}, {})",
+                        def_id.repr(tcx),
+                        p.repr(tcx))
+            }
+        }
+    }
+}
index 3dbbcce27b6eac3382a6dce15767ab790dee0a0f..22e3376e09ea8f4a46ba4cd8bcabd84c597b8412 100644 (file)
@@ -843,8 +843,8 @@ fn give_suggestion(&self, same_regions: &[SameRegions]) {
                                   Some(&sig.explicit_self.node),
                                   item.span))
                         }
-                        ast::TypeImplItem(_) => None,
-                        ast::MacImplItem(_) => self.tcx.sess.bug("unexpanded macro")
+                        ast::MacImplItem(_) => self.tcx.sess.bug("unexpanded macro"),
+                        _ => None,
                     }
                 },
                 ast_map::NodeTraitItem(item) => {
@@ -1723,8 +1723,8 @@ fn lifetimes_in_scope(tcx: &ty::ctxt,
                         taken.push_all(&sig.generics.lifetimes);
                         Some(ii.id)
                     }
-                    ast::TypeImplItem(_) => None,
-                    ast::MacImplItem(_) => tcx.sess.bug("unexpanded macro")
+                    ast::MacImplItem(_) => tcx.sess.bug("unexpanded macro"),
+                    _ => None,
                 }
             }
             _ => None
index b0921a266f39f9c14a5eaa038b0162ae75d1cbf1..63e4a5c8a2a4aed77adb22daf7868afc5134a85b 100644 (file)
@@ -22,6 +22,7 @@
 pub use self::freshen::TypeFreshener;
 pub use self::region_inference::GenericKind;
 
+use middle::free_region::FreeRegionMap;
 use middle::subst;
 use middle::subst::Substs;
 use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, UnconstrainedNumeric};
@@ -855,8 +856,10 @@ pub fn fresh_bound_region(&self, debruijn: ty::DebruijnIndex) -> ty::Region {
         self.region_vars.new_bound(debruijn)
     }
 
-    pub fn resolve_regions_and_report_errors(&self, subject_node_id: ast::NodeId) {
-        let errors = self.region_vars.resolve_regions(subject_node_id);
+    pub fn resolve_regions_and_report_errors(&self,
+                                             free_regions: &FreeRegionMap,
+                                             subject_node_id: ast::NodeId) {
+        let errors = self.region_vars.resolve_regions(free_regions, subject_node_id);
         self.report_region_errors(&errors); // see error_reporting.rs
     }
 
index e76468131e04d973cf6e6935fd15313de298875a..9de362fe360a625d2b2db0aaa7c41ff8ac8072cb 100644 (file)
@@ -21,6 +21,7 @@
 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};
@@ -711,19 +712,19 @@ fn consider_adding_directed_edge(result_set: &mut Vec<Region>,
     /// fixed-point iteration to find region values which satisfy all
     /// constraints, assuming such values can be found; if they cannot,
     /// errors are reported.
-    pub fn resolve_regions(&self, subject_node: ast::NodeId) -> Vec<RegionResolutionError<'tcx>> {
+    pub fn resolve_regions(&self,
+                           free_regions: &FreeRegionMap,
+                           subject_node: ast::NodeId)
+                           -> Vec<RegionResolutionError<'tcx>>
+    {
         debug!("RegionVarBindings: resolve_regions()");
         let mut errors = vec!();
-        let v = self.infer_variable_values(&mut errors, subject_node);
+        let v = self.infer_variable_values(free_regions, &mut errors, subject_node);
         *self.values.borrow_mut() = Some(v);
         errors
     }
 
-    fn is_subregion_of(&self, sub: Region, sup: Region) -> bool {
-        self.tcx.region_maps.is_subregion_of(sub, sup)
-    }
-
-    fn lub_concrete_regions(&self, a: Region, b: Region) -> Region {
+    fn lub_concrete_regions(&self, free_regions: &FreeRegionMap, a: Region, b: Region) -> Region {
         match (a, b) {
           (ReLateBound(..), _) |
           (_, ReLateBound(..)) |
@@ -781,7 +782,7 @@ fn lub_concrete_regions(&self, a: Region, b: Region) -> Region {
           }
 
           (ReFree(ref a_fr), ReFree(ref b_fr)) => {
-             self.lub_free_regions(a_fr, b_fr)
+             self.lub_free_regions(free_regions, a_fr, b_fr)
           }
 
           // For these types, we cannot define any additional
@@ -796,23 +797,25 @@ fn lub_concrete_regions(&self, a: Region, b: Region) -> Region {
     /// Computes a region that encloses both free region arguments. Guarantee that if the same two
     /// regions are given as argument, in any order, a consistent result is returned.
     fn lub_free_regions(&self,
+                        free_regions: &FreeRegionMap,
                         a: &FreeRegion,
                         b: &FreeRegion)
                         -> ty::Region
     {
         return match a.cmp(b) {
-            Less => helper(self, a, b),
-            Greater => helper(self, b, a),
+            Less => helper(self, free_regions, a, b),
+            Greater => helper(self, free_regions, b, a),
             Equal => ty::ReFree(*a)
         };
 
-        fn helper(this: &RegionVarBindings,
+        fn helper(_this: &RegionVarBindings,
+                  free_regions: &FreeRegionMap,
                   a: &FreeRegion,
                   b: &FreeRegion) -> ty::Region
         {
-            if this.tcx.region_maps.sub_free_region(*a, *b) {
+            if free_regions.sub_free_region(*a, *b) {
                 ty::ReFree(*b)
-            } else if this.tcx.region_maps.sub_free_region(*b, *a) {
+            } else if free_regions.sub_free_region(*b, *a) {
                 ty::ReFree(*a)
             } else {
                 ty::ReStatic
@@ -821,6 +824,7 @@ fn helper(this: &RegionVarBindings,
     }
 
     fn glb_concrete_regions(&self,
+                            free_regions: &FreeRegionMap,
                             a: Region,
                             b: Region)
                             -> RelateResult<'tcx, Region>
@@ -878,7 +882,7 @@ fn glb_concrete_regions(&self,
             }
 
             (ReFree(ref a_fr), ReFree(ref b_fr)) => {
-                self.glb_free_regions(a_fr, b_fr)
+                self.glb_free_regions(free_regions, a_fr, b_fr)
             }
 
             // For these types, we cannot define any additional
@@ -898,23 +902,25 @@ fn glb_concrete_regions(&self,
     /// 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, a, b),
-            Greater => helper(self, b, a),
+            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 this.tcx.region_maps.sub_free_region(*a, *b) {
+            if free_regions.sub_free_region(*a, *b) {
                 Ok(ty::ReFree(*a))
-            } else if this.tcx.region_maps.sub_free_region(*b, *a) {
+            } else if free_regions.sub_free_region(*b, *a) {
                 Ok(ty::ReFree(*b))
             } else {
                 this.intersect_scopes(ty::ReFree(*a), ty::ReFree(*b),
@@ -970,6 +976,7 @@ struct RegionAndOrigin<'tcx> {
 
 impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
     fn infer_variable_values(&self,
+                             free_regions: &FreeRegionMap,
                              errors: &mut Vec<RegionResolutionError<'tcx>>,
                              subject: ast::NodeId) -> Vec<VarValue>
     {
@@ -980,12 +987,13 @@ fn infer_variable_values(&self,
         debug!("----() End constraint listing {:?}---", self.dump_constraints());
         graphviz::maybe_print_constraints_for(self, subject);
 
-        self.expansion(&mut var_data);
-        self.contraction(&mut var_data);
+        self.expansion(free_regions, &mut var_data);
+        self.contraction(free_regions, &mut var_data);
         let values =
-            self.extract_values_and_collect_conflicts(&var_data[..],
+            self.extract_values_and_collect_conflicts(free_regions,
+                                                      &var_data[..],
                                                       errors);
-        self.collect_concrete_region_errors(&values, errors);
+        self.collect_concrete_region_errors(free_regions, &values, errors);
         values
     }
 
@@ -1009,7 +1017,7 @@ fn dump_constraints(&self) {
         }
     }
 
-    fn expansion(&self, var_data: &mut [VarData]) {
+    fn expansion(&self, free_regions: &FreeRegionMap, var_data: &mut [VarData]) {
         self.iterate_until_fixed_point("Expansion", |constraint| {
             debug!("expansion: constraint={} origin={}",
                    constraint.repr(self.tcx),
@@ -1020,14 +1028,14 @@ fn expansion(&self, var_data: &mut [VarData]) {
             match *constraint {
               ConstrainRegSubVar(a_region, b_vid) => {
                 let b_data = &mut var_data[b_vid.index as usize];
-                self.expand_node(a_region, b_vid, b_data)
+                self.expand_node(free_regions, a_region, b_vid, b_data)
               }
               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(a_region, b_vid, b_node)
+                    self.expand_node(free_regions, a_region, b_vid, b_node)
                   }
                 }
               }
@@ -1040,6 +1048,7 @@ fn expansion(&self, var_data: &mut [VarData]) {
     }
 
     fn expand_node(&self,
+                   free_regions: &FreeRegionMap,
                    a_region: Region,
                    b_vid: RegionVid,
                    b_data: &mut VarData)
@@ -1072,7 +1081,7 @@ fn expand_node(&self,
           }
 
           Value(cur_region) => {
-            let lub = self.lub_concrete_regions(a_region, cur_region);
+            let lub = self.lub_concrete_regions(free_regions, a_region, cur_region);
             if lub == cur_region {
                 return false;
             }
@@ -1093,6 +1102,7 @@ fn expand_node(&self,
     }
 
     fn contraction(&self,
+                   free_regions: &FreeRegionMap,
                    var_data: &mut [VarData]) {
         self.iterate_until_fixed_point("Contraction", |constraint| {
             debug!("contraction: constraint={} origin={}",
@@ -1111,19 +1121,20 @@ fn contraction(&self,
                   NoValue | ErrorValue => false,
                   Value(b_region) => {
                     let a_data = &mut var_data[a_vid.index as usize];
-                    self.contract_node(a_vid, a_data, b_region)
+                    self.contract_node(free_regions, a_vid, a_data, b_region)
                   }
                 }
               }
               ConstrainVarSubReg(a_vid, b_region) => {
                 let a_data = &mut var_data[a_vid.index as usize];
-                self.contract_node(a_vid, a_data, b_region)
+                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)
@@ -1143,19 +1154,23 @@ fn contract_node(&self,
 
             Value(a_region) => {
                 match a_data.classification {
-                    Expanding => check_node(self, a_vid, a_data, a_region, b_region),
-                    Contracting => adjust_node(self, a_vid, a_data, a_region, b_region),
+                    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),
                 }
             }
         };
 
         fn check_node(this: &RegionVarBindings,
+                      free_regions: &FreeRegionMap,
                       a_vid: RegionVid,
                       a_data: &mut VarData,
                       a_region: Region,
                       b_region: Region)
-                      -> bool {
-            if !this.is_subregion_of(a_region, b_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.repr(this.tcx),
@@ -1166,12 +1181,13 @@ fn check_node(this: &RegionVarBindings,
         }
 
         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(a_region, b_region) {
+            match this.glb_concrete_regions(free_regions, a_region, b_region) {
                 Ok(glb) => {
                     if glb == a_region {
                         false
@@ -1197,6 +1213,7 @@ fn adjust_node(this: &RegionVarBindings,
     }
 
     fn collect_concrete_region_errors(&self,
+                                      free_regions: &FreeRegionMap,
                                       values: &Vec<VarValue>,
                                       errors: &mut Vec<RegionResolutionError<'tcx>>)
     {
@@ -1204,7 +1221,7 @@ fn collect_concrete_region_errors(&self,
         for verify in &*self.verifys.borrow() {
             match *verify {
                 VerifyRegSubReg(ref origin, sub, sup) => {
-                    if self.is_subregion_of(sub, sup) {
+                    if free_regions.is_subregion_of(self.tcx, sub, sup) {
                         continue;
                     }
 
@@ -1222,7 +1239,7 @@ fn collect_concrete_region_errors(&self,
                     let sub = normalize(values, sub);
                     if sups.iter()
                            .map(|&sup| normalize(values, sup))
-                           .any(|sup| self.is_subregion_of(sub, sup))
+                           .any(|sup| free_regions.is_subregion_of(self.tcx, sub, sup))
                     {
                         continue;
                     }
@@ -1239,6 +1256,7 @@ fn collect_concrete_region_errors(&self,
 
     fn extract_values_and_collect_conflicts(
         &self,
+        free_regions: &FreeRegionMap,
         var_data: &[VarData],
         errors: &mut Vec<RegionResolutionError<'tcx>>)
         -> Vec<VarValue>
@@ -1304,12 +1322,12 @@ fn extract_values_and_collect_conflicts(
                     match var_data[idx].classification {
                         Expanding => {
                             self.collect_error_for_expanding_node(
-                                graph, var_data, &mut dup_vec,
+                                free_regions, graph, var_data, &mut dup_vec,
                                 node_vid, errors);
                         }
                         Contracting => {
                             self.collect_error_for_contracting_node(
-                                graph, var_data, &mut dup_vec,
+                                free_regions, graph, var_data, &mut dup_vec,
                                 node_vid, errors);
                         }
                     }
@@ -1355,13 +1373,13 @@ fn construct_graph(&self) -> RegionGraph {
         return graph;
     }
 
-    fn collect_error_for_expanding_node(
-        &self,
-        graph: &RegionGraph,
-        var_data: &[VarData],
-        dup_vec: &mut [u32],
-        node_idx: RegionVid,
-        errors: &mut Vec<RegionResolutionError<'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<RegionResolutionError<'tcx>>)
     {
         // Errors in expanding nodes result from a lower-bound that is
         // not contained by an upper-bound.
@@ -1394,8 +1412,9 @@ fn free_regions_first(a: &RegionAndOrigin,
 
         for lower_bound in &lower_bounds {
             for upper_bound in &upper_bounds {
-                if !self.is_subregion_of(lower_bound.region,
-                                         upper_bound.region) {
+                if !free_regions.is_subregion_of(self.tcx,
+                                                 lower_bound.region,
+                                                 upper_bound.region) {
                     debug!("pushing SubSupConflict sub: {:?} sup: {:?}",
                            lower_bound.region, upper_bound.region);
                     errors.push(SubSupConflict(
@@ -1420,6 +1439,7 @@ fn free_regions_first(a: &RegionAndOrigin,
 
     fn collect_error_for_contracting_node(
         &self,
+        free_regions: &FreeRegionMap,
         graph: &RegionGraph,
         var_data: &[VarData],
         dup_vec: &mut [u32],
@@ -1438,7 +1458,8 @@ fn collect_error_for_contracting_node(
 
         for upper_bound_1 in &upper_bounds {
             for upper_bound_2 in &upper_bounds {
-                match self.glb_concrete_regions(upper_bound_1.region,
+                match self.glb_concrete_regions(free_regions,
+                                                upper_bound_1.region,
                                                 upper_bound_2.region) {
                   Ok(_) => {}
                   Err(_) => {
index 003306fe558a1b5d2c9413987f71ab21d1b890f4..587194bafada48acfa17742614d982f44821f933 100644 (file)
@@ -589,7 +589,7 @@ pub fn cat_def(&self,
 
         match def {
           def::DefStruct(..) | def::DefVariant(..) | def::DefConst(..) |
-          def::DefFn(..) | def::DefMethod(..) => {
+          def::DefAssociatedConst(..) | def::DefFn(..) | def::DefMethod(..) => {
                 Ok(self.cat_rvalue_node(id, span, expr_ty))
           }
           def::DefMod(_) | def::DefForeignMod(_) | def::DefUse(_) |
@@ -1286,7 +1286,7 @@ fn cat_pattern_<F>(&self, cmt: cmt<'tcx>, pat: &ast::Pat, op: &mut F)
                         try!(self.cat_pattern_(cmt_field, &**subpat, op));
                     }
                 }
-                Some(def::DefConst(..)) => {
+                Some(def::DefConst(..)) | Some(def::DefAssociatedConst(..)) => {
                     for subpat in subpats {
                         try!(self.cat_pattern_(cmt.clone(), &**subpat, op));
                     }
@@ -1299,6 +1299,10 @@ fn cat_pattern_<F>(&self, cmt: cmt<'tcx>, pat: &ast::Pat, op: &mut F)
             }
           }
 
+          ast::PatQPath(..) => {
+              // Lone constant: ignore
+          }
+
           ast::PatIdent(_, _, Some(ref subpat)) => {
               try!(self.cat_pattern_(cmt, &**subpat, op));
           }
index 12b56562c84d6b825087ef50c0aab5bf4d0caa31..27a30f5cf253cf97da67691b72b29ec2863119cc 100644 (file)
@@ -30,7 +30,7 @@ pub fn pat_id_map(dm: &DefMap, pat: &ast::Pat) -> PatIdMap {
 
 pub fn pat_is_refutable(dm: &DefMap, pat: &ast::Pat) -> bool {
     match pat.node {
-        ast::PatLit(_) | ast::PatRange(_, _) => true,
+        ast::PatLit(_) | ast::PatRange(_, _) | ast::PatQPath(..) => true,
         ast::PatEnum(_, _) |
         ast::PatIdent(_, _, None) |
         ast::PatStruct(..) => {
@@ -60,9 +60,25 @@ pub fn pat_is_variant_or_struct(dm: &DefMap, pat: &ast::Pat) -> bool {
 
 pub fn pat_is_const(dm: &DefMap, pat: &ast::Pat) -> bool {
     match pat.node {
-        ast::PatIdent(_, _, None) | ast::PatEnum(..) => {
+        ast::PatIdent(_, _, None) | ast::PatEnum(..) | ast::PatQPath(..) => {
             match dm.borrow().get(&pat.id).map(|d| d.full_def()) {
-                Some(DefConst(..)) => true,
+                Some(DefConst(..)) | Some(DefAssociatedConst(..)) => true,
+                _ => false
+            }
+        }
+        _ => false
+    }
+}
+
+// Same as above, except that partially-resolved defs cause `false` to be
+// returned instead of a panic.
+pub fn pat_is_resolved_const(dm: &DefMap, pat: &ast::Pat) -> bool {
+    match pat.node {
+        ast::PatIdent(_, _, None) | ast::PatEnum(..) | ast::PatQPath(..) => {
+            match dm.borrow().get(&pat.id)
+                    .and_then(|d| if d.depth == 0 { Some(d.base_def) }
+                                  else { None } ) {
+                Some(DefConst(..)) | Some(DefAssociatedConst(..)) => true,
                 _ => false
             }
         }
index 1bd45b5fc86017cd5a8afea2c994c2e181397d9e..b532dc88df4cb5c939c6935ddd20bd1edbd2fba8 100644 (file)
@@ -113,7 +113,7 @@ fn visit_expr(&mut self, expr: &ast::Expr) {
                             // 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::DefConst(..) | def::DefAssociatedConst(..) => {
                                 self.worklist.push(def_id.node);
                             }
 
@@ -183,12 +183,14 @@ fn def_id_represents_local_inlined_item(&self, def_id: ast::DefId) -> bool {
             }
             Some(ast_map::NodeTraitItem(trait_method)) => {
                 match trait_method.node {
+                    ast::ConstTraitItem(_, ref default) => default.is_some(),
                     ast::MethodTraitItem(_, ref body) => body.is_some(),
                     ast::TypeTraitItem(..) => false,
                 }
             }
             Some(ast_map::NodeImplItem(impl_item)) => {
                 match impl_item.node {
+                    ast::ConstImplItem(..) => true,
                     ast::MethodImplItem(ref sig, _) => {
                         if generics_require_inlining(&sig.generics) ||
                                 attr::requests_inline(&impl_item.attrs) {
@@ -303,9 +305,13 @@ fn propagate_node(&mut self, node: &ast_map::Node,
             }
             ast_map::NodeTraitItem(trait_method) => {
                 match trait_method.node {
+                    ast::ConstTraitItem(_, None) |
                     ast::MethodTraitItem(_, None) => {
                         // Keep going, nothing to get exported
                     }
+                    ast::ConstTraitItem(_, Some(ref expr)) => {
+                        self.visit_expr(&*expr);
+                    }
                     ast::MethodTraitItem(_, Some(ref body)) => {
                         visit::walk_block(self, body);
                     }
@@ -314,6 +320,9 @@ fn propagate_node(&mut self, node: &ast_map::Node,
             }
             ast_map::NodeImplItem(impl_item) => {
                 match impl_item.node {
+                    ast::ConstImplItem(_, ref expr) => {
+                        self.visit_expr(&*expr);
+                    }
                     ast::MethodImplItem(ref sig, ref body) => {
                         let did = self.tcx.map.get_parent_did(search_item);
                         if method_might_be_inlined(self.tcx, sig, impl_item, did) {
index 2f7296051c566cb14ab0d40612e9113c5b3425c3..2c510b5f1d3b5d79d7b313dc67851cc15c0b0fa2 100644 (file)
@@ -17,9 +17,8 @@
 //! `middle/typeck/infer/region_inference.rs`
 
 use session::Session;
-use middle::ty::{self, Ty, FreeRegion};
+use middle::ty::{self, Ty};
 use util::nodemap::{FnvHashMap, FnvHashSet, NodeMap};
-use util::common::can_reach;
 
 use std::cell::RefCell;
 use syntax::codemap::{self, Span};
@@ -234,14 +233,6 @@ pub struct RegionMaps {
     /// which that variable is declared.
     var_map: RefCell<NodeMap<CodeExtent>>,
 
-    /// `free_region_map` maps from a free region `a` to a list of
-    /// free regions `bs` such that `a <= b for all b in bs`
-    ///
-    /// NB. the free region map is populated during type check as we
-    /// check each function. See the function `relate_free_regions`
-    /// for more information.
-    free_region_map: RefCell<FnvHashMap<FreeRegion, Vec<FreeRegion>>>,
-
     /// `rvalue_scopes` includes entries for those expressions whose cleanup scope is
     /// larger than the default. The map goes from the expression id
     /// to the cleanup scope id. For rvalues not present in this
@@ -390,13 +381,6 @@ pub fn each_var_scope<E>(&self, mut e:E) where E: FnMut(&ast::NodeId, &CodeExten
             e(child, parent)
         }
     }
-    pub fn each_encl_free_region<E>(&self, mut e:E) where E: FnMut(&FreeRegion, &FreeRegion) {
-        for (child, parents) in self.free_region_map.borrow().iter() {
-            for parent in parents.iter() {
-                e(child, parent)
-            }
-        }
-    }
     pub fn each_rvalue_scope<E>(&self, mut e:E) where E: FnMut(&ast::NodeId, &CodeExtent) {
         for (child, parent) in self.rvalue_scopes.borrow().iter() {
             e(child, parent)
@@ -408,21 +392,6 @@ pub fn each_terminating_scope<E>(&self, mut e:E) where E: FnMut(&CodeExtent) {
         }
     }
 
-    pub fn relate_free_regions(&self, sub: FreeRegion, sup: FreeRegion) {
-        match self.free_region_map.borrow_mut().get_mut(&sub) {
-            Some(sups) => {
-                if !sups.iter().any(|x| x == &sup) {
-                    sups.push(sup);
-                }
-                return;
-            }
-            None => {}
-        }
-
-        debug!("relate_free_regions(sub={:?}, sup={:?})", sub, sup);
-        self.free_region_map.borrow_mut().insert(sub, vec!(sup));
-    }
-
     /// Records that `sub_fn` is defined within `sup_fn`. These ids
     /// should be the id of the block that is the fn body, which is
     /// also the root of the region hierarchy for that fn.
@@ -567,56 +536,6 @@ pub fn is_subscope_of(&self,
         return true;
     }
 
-    /// Determines whether two free regions have a subregion relationship
-    /// by walking the graph encoded in `free_region_map`.  Note that
-    /// it is possible that `sub != sup` and `sub <= sup` and `sup <= sub`
-    /// (that is, the user can give two different names to the same lifetime).
-    pub fn sub_free_region(&self, sub: FreeRegion, sup: FreeRegion) -> bool {
-        can_reach(&*self.free_region_map.borrow(), sub, sup)
-    }
-
-    /// Determines whether one region is a subregion of another.  This is intended to run *after
-    /// inference* and sadly the logic is somewhat duplicated with the code in infer.rs.
-    pub fn is_subregion_of(&self,
-                           sub_region: ty::Region,
-                           super_region: ty::Region)
-                           -> bool {
-        debug!("is_subregion_of(sub_region={:?}, super_region={:?})",
-               sub_region, super_region);
-
-        sub_region == super_region || {
-            match (sub_region, super_region) {
-                (ty::ReEmpty, _) |
-                (_, ty::ReStatic) => {
-                    true
-                }
-
-                (ty::ReScope(sub_scope), ty::ReScope(super_scope)) => {
-                    self.is_subscope_of(sub_scope, super_scope)
-                }
-
-                (ty::ReScope(sub_scope), ty::ReFree(ref fr)) => {
-                    self.is_subscope_of(sub_scope, fr.scope.to_code_extent())
-                }
-
-                (ty::ReFree(sub_fr), ty::ReFree(super_fr)) => {
-                    self.sub_free_region(sub_fr, super_fr)
-                }
-
-                (ty::ReEarlyBound(data_a), ty::ReEarlyBound(data_b)) => {
-                    // This case is used only to make sure that explicitly-
-                    // specified `Self` types match the real self type in
-                    // implementations. Yuck.
-                    data_a == data_b
-                }
-
-                _ => {
-                    false
-                }
-            }
-        }
-    }
-
     /// Finds the nearest common ancestor (if any) of two scopes.  That is, finds the smallest
     /// scope which is greater than or equal to both `scope_a` and `scope_b`.
     pub fn nearest_common_ancestor(&self,
@@ -1291,7 +1210,6 @@ pub fn resolve_crate(sess: &Session, krate: &ast::Crate) -> RegionMaps {
     let maps = RegionMaps {
         scope_map: RefCell::new(FnvHashMap()),
         var_map: RefCell::new(NodeMap()),
-        free_region_map: RefCell::new(FnvHashMap()),
         rvalue_scopes: RefCell::new(NodeMap()),
         terminating_scopes: RefCell::new(FnvHashSet()),
         fn_tree: RefCell::new(NodeMap()),
index 8809abdd70e62b10d664263917bdab2ed643f5b6..b221c4bb685a8e501f40d48d806ff526964cedb6 100644 (file)
@@ -15,6 +15,7 @@
 pub use self::Vtable::*;
 pub use self::ObligationCauseCode::*;
 
+use middle::free_region::FreeRegionMap;
 use middle::subst;
 use middle::ty::{self, HasProjectionTypes, Ty};
 use middle::ty_fold::TypeFoldable;
@@ -424,7 +425,8 @@ pub fn normalize_param_env_or_error<'a,'tcx>(unnormalized_env: ty::ParameterEnvi
         }
     };
 
-    infcx.resolve_regions_and_report_errors(body_id);
+    let free_regions = FreeRegionMap::new();
+    infcx.resolve_regions_and_report_errors(&free_regions, body_id);
     let predicates = match infcx.fully_resolve(&predicates) {
         Ok(predicates) => predicates,
         Err(fixup_err) => {
index a2ff86cd065901d4115458f6a4fb323bde8541cb..3d6ed3c34406118fdea3f0bedfc381d78e7e7c6e 100644 (file)
@@ -100,9 +100,7 @@ fn object_safety_violations_for_trait<'tcx>(tcx: &ty::ctxt<'tcx>,
                         .map(|code| ObjectSafetyViolation::Method(m.clone(), code))
                         .into_iter()
                 }
-                ty::TypeTraitItem(_) => {
-                    None.into_iter()
-                }
+                _ => None.into_iter(),
             }
         })
         .collect();
index 7488b8f046e74eff8215258fe5127b4c99895384..9cdae21868ed3393ec4493ca2c7cb06fce921c80 100644 (file)
@@ -863,7 +863,7 @@ fn confirm_impl_candidate<'cx,'tcx>(
     for impl_item in impl_items {
         let assoc_type = match *impl_or_trait_items_map.get(&impl_item.def_id()).unwrap() {
             ty::TypeTraitItem(ref assoc_type) => assoc_type.clone(),
-            ty::MethodTraitItem(..) => { continue; }
+            ty::ConstTraitItem(..) | ty::MethodTraitItem(..) => { continue; }
         };
 
         if assoc_type.name != obligation.predicate.item_name {
index ddf941198eb0f86ee491e159107efe8e392d8d9b..6ecff3b7faabe9178064a6676be5deaf85124cf5 100644 (file)
@@ -434,7 +434,7 @@ pub fn get_vtable_index_of_object_method<'tcx>(tcx: &ty::ctxt<'tcx>,
         for trait_item in &**trait_items {
             match *trait_item {
                 ty::MethodTraitItem(_) => method_count += 1,
-                ty::TypeTraitItem(_) => {}
+                _ => {}
             }
         }
     }
@@ -445,14 +445,14 @@ pub fn get_vtable_index_of_object_method<'tcx>(tcx: &ty::ctxt<'tcx>,
     for trait_item in trait_items.iter().take(method_offset_in_trait) {
         match *trait_item {
             ty::MethodTraitItem(_) => method_count += 1,
-            ty::TypeTraitItem(_) => {}
+            _ => {}
         }
     }
 
     // the item at the offset we were given really ought to be a method
     assert!(match trait_items[method_offset_in_trait] {
         ty::MethodTraitItem(_) => true,
-        ty::TypeTraitItem(_) => false
+        _ => false
     });
 
     method_count
index 2c94399f92138c981f0ca805b039bbb7f404cd26..f172815a4d1437734225dd399aea80ad4c07f16b 100644 (file)
 use middle::const_eval;
 use middle::def::{self, DefMap, ExportMap};
 use middle::dependency_format;
+use middle::free_region::FreeRegionMap;
 use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
 use middle::mem_categorization as mc;
 use middle::region;
 use middle::resolve_lifetime;
 use middle::infer;
 use middle::pat_util;
+use middle::region::RegionMaps;
 use middle::stability;
 use middle::subst::{self, ParamSpace, Subst, Substs, VecPerParamSpace};
 use middle::traits;
@@ -78,7 +80,7 @@
 use collections::enum_set::{EnumSet, CLike};
 use std::collections::{HashMap, HashSet};
 use syntax::abi;
-use syntax::ast::{CrateNum, DefId, ItemTrait, LOCAL_CRATE};
+use syntax::ast::{CrateNum, DefId, ItemImpl, ItemTrait, LOCAL_CRATE};
 use syntax::ast::{MutImmutable, MutMutable, Name, NamedField, NodeId};
 use syntax::ast::{StmtExpr, StmtSemi, StructField, UnnamedField, Visibility};
 use syntax::ast_util::{self, is_local, lit_is_str, local_def};
@@ -131,6 +133,7 @@ pub fn id(&self) -> ast::DefId {
 
 #[derive(Clone, Debug)]
 pub enum ImplOrTraitItem<'tcx> {
+    ConstTraitItem(Rc<AssociatedConst<'tcx>>),
     MethodTraitItem(Rc<Method<'tcx>>),
     TypeTraitItem(Rc<AssociatedType>),
 }
@@ -138,6 +141,9 @@ pub enum ImplOrTraitItem<'tcx> {
 impl<'tcx> ImplOrTraitItem<'tcx> {
     fn id(&self) -> ImplOrTraitItemId {
         match *self {
+            ConstTraitItem(ref associated_const) => {
+                ConstTraitItemId(associated_const.def_id)
+            }
             MethodTraitItem(ref method) => MethodTraitItemId(method.def_id),
             TypeTraitItem(ref associated_type) => {
                 TypeTraitItemId(associated_type.def_id)
@@ -147,6 +153,7 @@ fn id(&self) -> ImplOrTraitItemId {
 
     pub fn def_id(&self) -> ast::DefId {
         match *self {
+            ConstTraitItem(ref associated_const) => associated_const.def_id,
             MethodTraitItem(ref method) => method.def_id,
             TypeTraitItem(ref associated_type) => associated_type.def_id,
         }
@@ -154,13 +161,23 @@ pub fn def_id(&self) -> ast::DefId {
 
     pub fn name(&self) -> ast::Name {
         match *self {
+            ConstTraitItem(ref associated_const) => associated_const.name,
             MethodTraitItem(ref method) => method.name,
             TypeTraitItem(ref associated_type) => associated_type.name,
         }
     }
 
+    pub fn vis(&self) -> ast::Visibility {
+        match *self {
+            ConstTraitItem(ref associated_const) => associated_const.vis,
+            MethodTraitItem(ref method) => method.vis,
+            TypeTraitItem(ref associated_type) => associated_type.vis,
+        }
+    }
+
     pub fn container(&self) -> ImplOrTraitItemContainer {
         match *self {
+            ConstTraitItem(ref associated_const) => associated_const.container,
             MethodTraitItem(ref method) => method.container,
             TypeTraitItem(ref associated_type) => associated_type.container,
         }
@@ -169,13 +186,14 @@ pub fn container(&self) -> ImplOrTraitItemContainer {
     pub fn as_opt_method(&self) -> Option<Rc<Method<'tcx>>> {
         match *self {
             MethodTraitItem(ref m) => Some((*m).clone()),
-            TypeTraitItem(_) => None
+            _ => None,
         }
     }
 }
 
 #[derive(Clone, Copy, Debug)]
 pub enum ImplOrTraitItemId {
+    ConstTraitItemId(ast::DefId),
     MethodTraitItemId(ast::DefId),
     TypeTraitItemId(ast::DefId),
 }
@@ -183,6 +201,7 @@ pub enum ImplOrTraitItemId {
 impl ImplOrTraitItemId {
     pub fn def_id(&self) -> ast::DefId {
         match *self {
+            ConstTraitItemId(def_id) => def_id,
             MethodTraitItemId(def_id) => def_id,
             TypeTraitItemId(def_id) => def_id,
         }
@@ -236,6 +255,16 @@ pub fn container_id(&self) -> ast::DefId {
     }
 }
 
+#[derive(Clone, Copy, Debug)]
+pub struct AssociatedConst<'tcx> {
+    pub name: ast::Name,
+    pub ty: Ty<'tcx>,
+    pub vis: ast::Visibility,
+    pub def_id: ast::DefId,
+    pub container: ImplOrTraitItemContainer,
+    pub default: Option<ast::DefId>,
+}
+
 #[derive(Clone, Copy, Debug)]
 pub struct AssociatedType {
     pub name: ast::Name,
@@ -620,7 +649,14 @@ pub struct ctxt<'tcx> {
 
     pub named_region_map: resolve_lifetime::NamedRegionMap,
 
-    pub region_maps: middle::region::RegionMaps,
+    pub region_maps: RegionMaps,
+
+    // For each fn declared in the local crate, type check stores the
+    // free-region relationships that were deduced from its where
+    // clauses and parameter types. These are then read-again by
+    // borrowck. (They are not used during trans, and hence are not
+    // serialized or needed for cross-crate fns.)
+    free_region_maps: RefCell<NodeMap<FreeRegionMap>>,
 
     /// Stores the types for various nodes in the AST.  Note that this table
     /// is not guaranteed to be populated until after typeck.  See
@@ -795,6 +831,15 @@ pub fn node_types(&self) -> Ref<NodeMap<Ty<'tcx>>> { self.node_types.borrow() }
     pub fn node_type_insert(&self, id: NodeId, ty: Ty<'tcx>) {
         self.node_types.borrow_mut().insert(id, ty);
     }
+
+    pub fn store_free_region_map(&self, id: NodeId, map: FreeRegionMap) {
+        self.free_region_maps.borrow_mut()
+                             .insert(id, map);
+    }
+
+    pub fn free_region_map(&self, id: NodeId) -> FreeRegionMap {
+        self.free_region_maps.borrow()[&id].clone()
+    }
 }
 
 // Flags that we track on types. These flags are propagated upwards
@@ -2273,6 +2318,16 @@ pub fn for_item(cx: &'a ctxt<'tcx>, id: NodeId) -> ParameterEnvironment<'a, 'tcx
         match cx.map.find(id) {
             Some(ast_map::NodeImplItem(ref impl_item)) => {
                 match impl_item.node {
+                    ast::ConstImplItem(_, _) => {
+                        let def_id = ast_util::local_def(id);
+                        let scheme = lookup_item_type(cx, def_id);
+                        let predicates = lookup_predicates(cx, def_id);
+                        construct_parameter_environment(cx,
+                                                        impl_item.span,
+                                                        &scheme.generics,
+                                                        &predicates,
+                                                        id)
+                    }
                     ast::MethodImplItem(_, ref body) => {
                         let method_def_id = ast_util::local_def(id);
                         match ty::impl_or_trait_item(cx, method_def_id) {
@@ -2286,11 +2341,10 @@ pub fn for_item(cx: &'a ctxt<'tcx>, id: NodeId) -> ParameterEnvironment<'a, 'tcx
                                     method_bounds,
                                     body.id)
                             }
-                            TypeTraitItem(_) => {
+                            _ => {
                                 cx.sess
                                   .bug("ParameterEnvironment::for_item(): \
-                                        can't create a parameter environment \
-                                        for type trait items")
+                                        got non-method item from impl method?!")
                             }
                         }
                     }
@@ -2304,6 +2358,25 @@ pub fn for_item(cx: &'a ctxt<'tcx>, id: NodeId) -> ParameterEnvironment<'a, 'tcx
             }
             Some(ast_map::NodeTraitItem(trait_item)) => {
                 match trait_item.node {
+                    ast::ConstTraitItem(_, ref default) => {
+                        match *default {
+                            Some(_) => {
+                                let def_id = ast_util::local_def(id);
+                                let scheme = lookup_item_type(cx, def_id);
+                                let predicates = lookup_predicates(cx, def_id);
+                                construct_parameter_environment(cx,
+                                                                trait_item.span,
+                                                                &scheme.generics,
+                                                                &predicates,
+                                                                id)
+                            }
+                            None => {
+                                cx.sess.bug("ParameterEnvironment::from_item(): \
+                                             can't create a parameter environment \
+                                             for const trait items without defaults")
+                            }
+                        }
+                    }
                     ast::MethodTraitItem(_, None) => {
                         cx.sess.span_bug(trait_item.span,
                                          "ParameterEnvironment::for_item():
@@ -2324,11 +2397,11 @@ pub fn for_item(cx: &'a ctxt<'tcx>, id: NodeId) -> ParameterEnvironment<'a, 'tcx
                                     method_bounds,
                                     body.id)
                             }
-                            TypeTraitItem(_) => {
+                            _ => {
                                 cx.sess
                                   .bug("ParameterEnvironment::for_item(): \
-                                        can't create a parameter environment \
-                                        for type trait items")
+                                        got non-method item from provided \
+                                        method?!")
                             }
                         }
                     }
@@ -2546,7 +2619,7 @@ pub fn mk_ctxt<'tcx>(s: Session,
                      named_region_map: resolve_lifetime::NamedRegionMap,
                      map: ast_map::Map<'tcx>,
                      freevars: RefCell<FreevarMap>,
-                     region_maps: middle::region::RegionMaps,
+                     region_maps: RegionMaps,
                      lang_items: middle::lang_items::LanguageItems,
                      stability: stability::Index) -> ctxt<'tcx>
 {
@@ -2561,11 +2634,12 @@ pub fn mk_ctxt<'tcx>(s: Session,
         region_interner: RefCell::new(FnvHashMap()),
         types: common_types,
         named_region_map: named_region_map,
+        region_maps: region_maps,
+        free_region_maps: RefCell::new(FnvHashMap()),
         item_variance_map: RefCell::new(DefIdMap()),
         variance_computed: Cell::new(false),
         sess: s,
         def_map: def_map,
-        region_maps: region_maps,
         node_types: RefCell::new(FnvHashMap()),
         item_substs: RefCell::new(NodeMap()),
         impl_trait_refs: RefCell::new(NodeMap()),
@@ -4700,7 +4774,8 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
                 def::DefUpvar(..) |
                 def::DefLocal(..) => LvalueExpr,
 
-                def::DefConst(..) => RvalueDatumExpr,
+                def::DefConst(..) |
+                def::DefAssociatedConst(..) => RvalueDatumExpr,
 
                 def => {
                     tcx.sess.span_bug(
@@ -5051,10 +5126,10 @@ pub fn provided_trait_methods<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId)
                 if let ast::MethodTraitItem(_, Some(_)) = ti.node {
                     match impl_or_trait_item(cx, ast_util::local_def(ti.id)) {
                         MethodTraitItem(m) => Some(m),
-                        TypeTraitItem(_) => {
+                        _ => {
                             cx.sess.bug("provided_trait_methods(): \
-                                         associated type found from \
-                                         looking up ProvidedMethod?!")
+                                         non-method item found from \
+                                         looking up provided method?!")
                         }
                     }
                 } else {
@@ -5069,6 +5144,52 @@ pub fn provided_trait_methods<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId)
     }
 }
 
+pub fn associated_consts<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId)
+                               -> Vec<Rc<AssociatedConst<'tcx>>> {
+    if is_local(id) {
+        match cx.map.expect_item(id.node).node {
+            ItemTrait(_, _, _, ref tis) => {
+                tis.iter().filter_map(|ti| {
+                    if let ast::ConstTraitItem(_, _) = ti.node {
+                        match impl_or_trait_item(cx, ast_util::local_def(ti.id)) {
+                            ConstTraitItem(ac) => Some(ac),
+                            _ => {
+                                cx.sess.bug("associated_consts(): \
+                                             non-const item found from \
+                                             looking up a constant?!")
+                            }
+                        }
+                    } else {
+                        None
+                    }
+                }).collect()
+            }
+            ItemImpl(_, _, _, _, _, ref iis) => {
+                iis.iter().filter_map(|ii| {
+                    if let ast::ConstImplItem(_, _) = ii.node {
+                        match impl_or_trait_item(cx, ast_util::local_def(ii.id)) {
+                            ConstTraitItem(ac) => Some(ac),
+                            _ => {
+                                cx.sess.bug("associated_consts(): \
+                                             non-const item found from \
+                                             looking up a constant?!")
+                            }
+                        }
+                    } else {
+                        None
+                    }
+                }).collect()
+            }
+            _ => {
+                cx.sess.bug(&format!("associated_consts: `{:?}` is not a trait \
+                                      or impl", id))
+            }
+        }
+    } else {
+        csearch::get_associated_consts(cx, id)
+    }
+}
+
 /// Helper for looking things up in the various maps that are populated during
 /// typeck::collect (e.g., `cx.impl_or_trait_items`, `cx.tcache`, etc).  All of
 /// these share the pattern that if the id is local, it should have been loaded
@@ -5155,7 +5276,7 @@ pub fn is_associated_type(cx: &ctxt, id: ast::DefId) -> bool {
                 Some(ref item) => {
                     match **item {
                         TypeTraitItem(_) => true,
-                        MethodTraitItem(_) => false,
+                        _ => false,
                     }
                 }
                 None => false,
@@ -6169,7 +6290,7 @@ pub fn populate_implementations_for_type_if_necessary(tcx: &ctxt,
                            .insert(method_def_id, source);
                     }
                 }
-                TypeTraitItem(_) => {}
+                _ => {}
             }
         }
 
@@ -6221,7 +6342,7 @@ pub fn populate_implementations_for_trait_if_necessary(
                             .insert(method_def_id, source);
                     }
                 }
-                TypeTraitItem(_) => {}
+                _ => {}
             }
         }
 
@@ -6537,14 +6658,6 @@ pub fn construct_parameter_environment<'a,'tcx>(
     let bounds = liberate_late_bound_regions(tcx, free_id_outlive, &ty::Binder(bounds));
     let predicates = bounds.predicates.into_vec();
 
-    //
-    // Compute region bounds. For now, these relations are stored in a
-    // global table on the tcx, so just enter them there. I'm not
-    // crazy about this scheme, but it's convenient, at least.
-    //
-
-    record_region_bounds(tcx, &*predicates);
-
     debug!("construct_parameter_environment: free_id={:?} free_subst={:?} predicates={:?}",
            free_id,
            free_substs.repr(tcx),
@@ -6573,37 +6686,7 @@ pub fn construct_parameter_environment<'a,'tcx>(
     };
 
     let cause = traits::ObligationCause::misc(span, free_id);
-    return traits::normalize_param_env_or_error(unnormalized_env, cause);
-
-    fn record_region_bounds<'tcx>(tcx: &ty::ctxt<'tcx>, predicates: &[ty::Predicate<'tcx>]) {
-        debug!("record_region_bounds(predicates={:?})", predicates.repr(tcx));
-
-        for predicate in predicates {
-            match *predicate {
-                Predicate::Projection(..) |
-                Predicate::Trait(..) |
-                Predicate::Equate(..) |
-                Predicate::TypeOutlives(..) => {
-                    // No region bounds here
-                }
-                Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => {
-                    match (r_a, r_b) {
-                        (ty::ReFree(fr_a), ty::ReFree(fr_b)) => {
-                            // Record that `'a:'b`. Or, put another way, `'b <= 'a`.
-                            tcx.region_maps.relate_free_regions(fr_b, fr_a);
-                        }
-                        _ => {
-                            // All named regions are instantiated with free regions.
-                            tcx.sess.bug(
-                                &format!("record_region_bounds: non free region: {} / {}",
-                                         r_a.repr(tcx),
-                                         r_b.repr(tcx)));
-                        }
-                    }
-                }
-            }
-        }
-    }
+    traits::normalize_param_env_or_error(unnormalized_env, cause)
 }
 
 impl BorrowKind {
index f4ea069447fdfc5124a232cac8fe6cea9f5644ee..072761f2754b3723fed2c29ee2d3f623c314a404 100644 (file)
@@ -621,6 +621,7 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
     let arch = &sess.target.target.arch;
     let wordsz = &sess.target.target.target_pointer_width;
     let os = &sess.target.target.target_os;
+    let env = &sess.target.target.target_env;
 
     let fam = match sess.target.target.options.is_like_windows {
         true  => InternedString::new("windows"),
@@ -634,8 +635,8 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
          mk(InternedString::new("target_family"), fam),
          mk(InternedString::new("target_arch"), intern(arch)),
          mk(InternedString::new("target_endian"), intern(end)),
-         mk(InternedString::new("target_pointer_width"),
-            intern(wordsz))
+         mk(InternedString::new("target_pointer_width"), intern(wordsz)),
+         mk(InternedString::new("target_env"), intern(env)),
     ];
     if sess.opts.debug_assertions {
         ret.push(attr::mk_word_item(InternedString::new("debug_assertions")));
@@ -1111,7 +1112,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
 
     use session::config::{build_configuration, optgroups, build_session_options};
     use session::build_session;
index 500af5fc772f5ca2d6e18046f8f83ed94f80a560..14bc19dffd5d0b6f307856c23ccdf8814b74fdf9 100644 (file)
@@ -57,6 +57,8 @@ pub struct Session {
     pub crate_metadata: RefCell<Vec<String>>,
     pub features: RefCell<feature_gate::Features>,
 
+    pub delayed_span_bug: RefCell<Option<(codemap::Span, String)>>,
+
     /// The maximum recursion limit for potentially infinitely recursive
     /// operations such as auto-dereference and monomorphization.
     pub recursion_limit: Cell<usize>,
@@ -114,7 +116,15 @@ pub fn has_errors(&self) -> bool {
         self.diagnostic().handler().has_errors()
     }
     pub fn abort_if_errors(&self) {
-        self.diagnostic().handler().abort_if_errors()
+        self.diagnostic().handler().abort_if_errors();
+
+        let delayed_bug = self.delayed_span_bug.borrow();
+        match *delayed_bug {
+            Some((span, ref errmsg)) => {
+                self.diagnostic().span_bug(span, errmsg);
+            },
+            _ => {}
+        }
     }
     pub fn span_warn(&self, sp: Span, msg: &str) {
         if self.can_print_warnings {
@@ -171,6 +181,11 @@ pub fn opt_span_bug(&self, opt_sp: Option<Span>, msg: &str) -> ! {
             None => self.bug(msg),
         }
     }
+    /// Delay a span_bug() call until abort_if_errors()
+    pub fn delay_span_bug(&self, sp: Span, msg: &str) {
+        let mut delayed = self.delayed_span_bug.borrow_mut();
+        *delayed = Some((sp, msg.to_string()));
+    }
     pub fn span_bug(&self, sp: Span, msg: &str) -> ! {
         self.diagnostic().span_bug(sp, msg)
     }
@@ -402,6 +417,7 @@ pub fn build_session_(sopts: config::Options,
         plugin_llvm_passes: RefCell::new(Vec::new()),
         crate_types: RefCell::new(Vec::new()),
         crate_metadata: RefCell::new(Vec::new()),
+        delayed_span_bug: RefCell::new(None),
         features: RefCell::new(feature_gate::Features::new()),
         recursion_limit: Cell::new(64),
         can_print_warnings: can_print_warnings
index 12a6d5848572d7b35660664a3645adccc0cdf36c..3d56371dd52cafc56ae365b786a0b623e1504548 100644 (file)
@@ -830,6 +830,7 @@ fn repr(&self, tcx: &ctxt<'tcx>) -> String {
 impl<'tcx> Repr<'tcx> for ast::TraitItem {
     fn repr(&self, _tcx: &ctxt) -> String {
         let kind = match self.node {
+            ast::ConstTraitItem(..) => "ConstTraitItem",
             ast::MethodTraitItem(..) => "MethodTraitItem",
             ast::TypeTraitItem(..) => "TypeTraitItem",
         };
@@ -1054,9 +1055,39 @@ fn repr(&self, _: &ctxt) -> String {
     }
 }
 
+impl<'tcx> Repr<'tcx> for ty::ImplOrTraitItem<'tcx> {
+    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
+        format!("ImplOrTraitItem({})",
+                match *self {
+                    ty::ImplOrTraitItem::MethodTraitItem(ref i) => i.repr(tcx),
+                    ty::ImplOrTraitItem::ConstTraitItem(ref i) => i.repr(tcx),
+                    ty::ImplOrTraitItem::TypeTraitItem(ref i) => i.repr(tcx),
+                })
+    }
+}
+
+impl<'tcx> Repr<'tcx> for ty::AssociatedConst<'tcx> {
+    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
+        format!("AssociatedConst(name: {}, ty: {}, vis: {}, def_id: {})",
+                self.name.repr(tcx),
+                self.ty.repr(tcx),
+                self.vis.repr(tcx),
+                self.def_id.repr(tcx))
+    }
+}
+
+impl<'tcx> Repr<'tcx> for ty::AssociatedType {
+    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
+        format!("AssociatedType(name: {}, vis: {}, def_id: {})",
+                self.name.repr(tcx),
+                self.vis.repr(tcx),
+                self.def_id.repr(tcx))
+    }
+}
+
 impl<'tcx> Repr<'tcx> for ty::Method<'tcx> {
     fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("method(name: {}, generics: {}, predicates: {}, fty: {}, \
+        format!("Method(name: {}, generics: {}, predicates: {}, fty: {}, \
                  explicit_self: {}, vis: {}, def_id: {})",
                 self.name.repr(tcx),
                 self.generics.repr(tcx),
index 2ab4d7ff78a1d256edc6fad38d6e96b17e308412..37e3efb4d83fe112a39c11be151adffb76fdb93a 100644 (file)
@@ -41,7 +41,7 @@ fn realpath(pathname: *const libc::c_char, resolved: *mut libc::c_char)
 }
 
 #[cfg(all(not(windows), test))]
-mod test {
+mod tests {
     use tempdir::TempDir;
     use std::fs::{self, File};
     use super::realpath;
index 58073079d31dffcdaf725bc6d7056bfdaaa9de1a..1daeb1cb223e279670efd5d089a07ef87b19a1a3 100644 (file)
@@ -171,7 +171,7 @@ fn minimize_rpaths(rpaths: &[String]) -> Vec<String> {
 }
 
 #[cfg(all(unix, test))]
-mod test {
+mod tests {
     use super::{RPathConfig};
     use super::{minimize_rpaths, rpaths_to_flags, get_rpath_relative_to_output};
     use std::path::{Path, PathBuf};
index 2ceb34e68b7720ac7574818046f2d6a81657a4d1..dd6bc672a03d996ab8d1cf390eac171cef3696e5 100644 (file)
@@ -22,6 +22,7 @@ pub fn target() -> Target {
         target_pointer_width: "64".to_string(),
         arch: "aarch64".to_string(),
         target_os: "ios".to_string(),
+        target_env: "".to_string(),
         options: TargetOptions {
             features: "+neon,+fp-armv8,+cyclone".to_string(),
             eliminate_frame_pointer: false,
index 64b0e0cfd6baca44462cd6b733329580aaf1c277..fcc901fc81f576f7da57193785e0cc4f5444168f 100644 (file)
@@ -24,6 +24,7 @@ pub fn target() -> Target {
         target_pointer_width: "64".to_string(),
         arch: "aarch64".to_string(),
         target_os: "android".to_string(),
+        target_env: "".to_string(),
         options: base,
     }
 }
index a3ef6372f0648b9e1046b1ea1cd14584f9ab1749..18e67d066d03632f8c148a54c03326411364fc44 100644 (file)
@@ -19,6 +19,7 @@ pub fn target() -> Target {
         llvm_target: "aarch64-unknown-linux-gnu".to_string(),
         target_endian: "little".to_string(),
         target_pointer_width: "64".to_string(),
+        target_env: "gnu".to_string(),
         arch: "aarch64".to_string(),
         target_os: "linux".to_string(),
         options: base,
index fad9344143155628ee92b56fdda2ff0819dfd8af..57712d18cbae2fd7568cb59cc67bd2ef71c23697 100644 (file)
@@ -31,6 +31,7 @@ pub fn target() -> Target {
         target_pointer_width: "32".to_string(),
         arch: "arm".to_string(),
         target_os: "android".to_string(),
+        target_env: "gnu".to_string(),
         options: base,
     }
 }
index 32eccaf54b038816e01c02207fb35e558863f1e1..30015c4a7e6ff0ef1a34a6b04fd36ea956162ffd 100644 (file)
@@ -23,6 +23,7 @@ pub fn target() -> Target {
         target_pointer_width: "32".to_string(),
         arch: "arm".to_string(),
         target_os: "linux".to_string(),
+        target_env: "gnueabi".to_string(),
 
         options: TargetOptions {
             features: "+v6".to_string(),
index eff3601250f875c58e4aaee59261ee4d2ce99c0a..8f8c7114e6effa537c55bdeec16fa3b0ccb3a304 100644 (file)
@@ -23,6 +23,7 @@ pub fn target() -> Target {
         target_pointer_width: "32".to_string(),
         arch: "arm".to_string(),
         target_os: "linux".to_string(),
+        target_env: "gnueabihf".to_string(),
 
         options: TargetOptions {
             features: "+v6,+vfp2".to_string(),
index 4137642188691942df4c855a1d0ea29166582bba..3b55993659de24c132dbbb585b7fb7832b44c9c3 100644 (file)
@@ -19,6 +19,7 @@ pub fn target() -> Target {
         target_pointer_width: "32".to_string(),
         arch: "arm".to_string(),
         target_os: "ios".to_string(),
+        target_env: "".to_string(),
         options: TargetOptions {
             features: "+v7,+vfp3,+neon".to_string(),
             .. opts(Arch::Armv7)
index ef16aefdbd9dd9b8e3f9830703178e64f82a6ebf..5a67e3fe127d6f375bb7018a9ccf7b45da1ddce4 100644 (file)
@@ -19,6 +19,7 @@ pub fn target() -> Target {
         target_pointer_width: "32".to_string(),
         arch: "arm".to_string(),
         target_os: "ios".to_string(),
+        target_env: "".to_string(),
         options: TargetOptions {
             features: "+v7,+vfp4,+neon".to_string(),
             .. opts(Arch::Armv7s)
index afe63d006cf1a04c0600302a42987cc1fa159738..a9a073e2a8c64ae3db1c0394edc549f430b38329 100644 (file)
@@ -23,6 +23,7 @@ pub fn target() -> Target {
         target_pointer_width: "32".to_string(),
         arch: "x86".to_string(),
         target_os: "ios".to_string(),
+        target_env: "".to_string(),
         options: opts(Arch::I386)
     }
 }
index fcea900283d2851d1d785b6661d22e4556fc9bc4..47b329982d43e29383a77083d92c556c7e835a85 100644 (file)
@@ -26,6 +26,7 @@ pub fn target() -> Target {
         target_pointer_width: "32".to_string(),
         arch: "x86".to_string(),
         target_os: "macos".to_string(),
+        target_env: "".to_string(),
         options: base,
     }
 }
index 249f2d440e68155fd01960d9924930cadfe85a6d..9e2aa20085c3634f1dde00f97e1eb0def39a5ecf 100644 (file)
@@ -30,6 +30,7 @@ pub fn target() -> Target {
         target_pointer_width: "32".to_string(),
         arch: "x86".to_string(),
         target_os: "windows".to_string(),
+        target_env: "gnu".to_string(),
         options: options,
     }
 }
index 4450d8d67782d48fc899cdd684d38f447ccd7caf..ecabe71ad4c6c635ef279472ac60868a6cdd38c2 100644 (file)
@@ -22,6 +22,7 @@ pub fn target() -> Target {
         target_pointer_width: "32".to_string(),
         arch: "x86".to_string(),
         target_os: "dragonfly".to_string(),
+        target_env: "".to_string(),
         options: base,
     }
 }
index f21f6adfb4c0c2a03eb28a5e0aed816508b0e59a..21094ad905e90f5c281c8d451fa44fb676b97399 100644 (file)
@@ -22,6 +22,7 @@ pub fn target() -> Target {
         target_pointer_width: "32".to_string(),
         arch: "x86".to_string(),
         target_os: "linux".to_string(),
+        target_env: "gnu".to_string(),
         options: base,
     }
 }
index d267bc77e4975d52aca8dd8a8488aad6b1691aa0..823a4a81fa4c19f98f1cf04834c7640ad9695530 100644 (file)
@@ -19,12 +19,16 @@ pub fn opts() -> TargetOptions {
         morestack: true,
         linker_is_gnu: true,
         has_rpath: true,
-        pre_link_args: vec!(
-            // GNU-style linkers will use this to omit linking to libraries which
-            // don't actually fulfill any relocations, but only for libraries which
-            // follow this flag. Thus, use it before specifying libraries to link to.
+        pre_link_args: vec![
+            // We want to be able to strip as much executable code as possible
+            // from the linker command line, and this flag indicates to the
+            // linker that it can avoid linking in dynamic libraries that don't
+            // actually satisfy any symbols up to that point (as with many other
+            // resolutions the linker does). This option only applies to all
+            // following libraries so we're sure to pass it as one of the first
+            // arguments.
             "-Wl,--as-needed".to_string(),
-        ),
+        ],
         position_independent_executables: true,
         .. Default::default()
     }
index 8acc248e23410105c134612cf65f5822c6804a6d..4662ff1958ba87de61a7d1922324e047f7185f90 100644 (file)
@@ -22,6 +22,7 @@ pub fn target() -> Target {
         target_pointer_width: "32".to_string(),
         arch: "mips".to_string(),
         target_os: "linux".to_string(),
+        target_env: "gnu".to_string(),
         options: super::linux_base::opts()
     }
 }
index 604c62eb69f0f753fffe2e628f29ddbb076d55da..80e38c5ddea98e61cdc65bcdb8d94371b11f4373 100644 (file)
@@ -22,6 +22,7 @@ pub fn target() -> Target {
         target_pointer_width: "32".to_string(),
         arch: "mips".to_string(),
         target_os: "linux".to_string(),
+        target_env: "gnu".to_string(),
 
         options: super::linux_base::opts()
     }
index 07528df97f1334686123652efacf0c9525324fd0..3a79ae3e7c01b6e8116f47904f33b769ff8b917b 100644 (file)
 mod bitrig_base;
 mod openbsd_base;
 
-mod armv7_apple_ios;
-mod armv7s_apple_ios;
-mod i386_apple_ios;
-
-mod arm_linux_androideabi;
-mod arm_unknown_linux_gnueabi;
-mod arm_unknown_linux_gnueabihf;
-mod aarch64_apple_ios;
-mod aarch64_linux_android;
-mod aarch64_unknown_linux_gnu;
-mod i686_apple_darwin;
-mod i686_pc_windows_gnu;
-mod i686_unknown_dragonfly;
-mod i686_unknown_linux_gnu;
-mod mips_unknown_linux_gnu;
-mod mipsel_unknown_linux_gnu;
-mod powerpc_unknown_linux_gnu;
-mod x86_64_apple_darwin;
-mod x86_64_apple_ios;
-mod x86_64_pc_windows_gnu;
-mod x86_64_unknown_freebsd;
-mod x86_64_unknown_dragonfly;
-mod x86_64_unknown_bitrig;
-mod x86_64_unknown_linux_gnu;
-mod x86_64_unknown_openbsd;
-
 /// Everything `rustc` knows about how to compile for a specific target.
 ///
 /// Every field here must be specified, and has no default value.
@@ -100,6 +74,8 @@ pub struct Target {
     pub target_pointer_width: String,
     /// OS name to use for conditional compilation.
     pub target_os: String,
+    /// Environment name to use for conditional compilation.
+    pub target_env: String,
     /// Architecture to use for ABI considerations. Valid options: "x86", "x86_64", "arm",
     /// "aarch64", "mips", and "powerpc". "mips" includes "mipsel".
     pub arch: String,
@@ -115,14 +91,22 @@ pub struct Target {
 pub struct TargetOptions {
     /// Linker to invoke. Defaults to "cc".
     pub linker: String,
-    /// Linker arguments that are unconditionally passed *before* any user-defined libraries.
+    /// Linker arguments that are unconditionally passed *before* any
+    /// user-defined libraries.
     pub pre_link_args: Vec<String>,
-    /// Linker arguments that are unconditionally passed *after* any user-defined libraries.
+    /// Linker arguments that are unconditionally passed *after* any
+    /// user-defined libraries.
     pub post_link_args: Vec<String>,
-    /// Default CPU to pass to LLVM. Corresponds to `llc -mcpu=$cpu`. Defaults to "default".
+    /// Objects to link before and after all others, always found within the
+    /// sysroot folder.
+    pub pre_link_objects: Vec<String>,
+    pub post_link_objects: Vec<String>,
+    /// Default CPU to pass to LLVM. Corresponds to `llc -mcpu=$cpu`. Defaults
+    /// to "default".
     pub cpu: String,
-    /// Default target features to pass to LLVM. These features will *always* be passed, and cannot
-    /// be disabled even via `-C`. Corresponds to `llc -mattr=$features`.
+    /// Default target features to pass to LLVM. These features will *always* be
+    /// passed, and cannot be disabled even via `-C`. Corresponds to `llc
+    /// -mattr=$features`.
     pub features: String,
     /// Whether dynamic linking is available on this target. Defaults to false.
     pub dynamic_linking: bool,
@@ -207,6 +191,8 @@ fn default() -> TargetOptions {
             has_rpath: false,
             no_compiler_rt: false,
             position_independent_executables: false,
+            pre_link_objects: Vec::new(),
+            post_link_objects: Vec::new(),
         }
     }
 }
@@ -250,6 +236,8 @@ pub fn from_json(obj: Json) -> Target {
             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()),
             options: Default::default(),
         };
 
@@ -329,6 +317,7 @@ fn load_file(path: &Path) -> Result<Target, String> {
         macro_rules! load_specific {
             ( $($name:ident),+ ) => (
                 {
+                    $(mod $name;)*
                     let target = target.replace("-", "_");
                     if false { }
                     $(
@@ -358,6 +347,7 @@ macro_rules! load_specific {
             arm_unknown_linux_gnueabi,
             arm_unknown_linux_gnueabihf,
             aarch64_unknown_linux_gnu,
+            x86_64_unknown_linux_musl,
 
             arm_linux_androideabi,
             aarch64_linux_android,
index 5e0b7bcf3ef8bc04693ad23ba5a252dbfb95d036..3a2b4bd16065ef38e892a78415b4d0f4cc75b39a 100644 (file)
@@ -21,6 +21,7 @@ pub fn target() -> Target {
         target_pointer_width: "32".to_string(),
         arch: "powerpc".to_string(),
         target_os: "linux".to_string(),
+        target_env: "gnu".to_string(),
         options: base,
     }
 }
index 0b3b2bea62d777cc920f01c2b2776402367de433..89a67da2d8bbcf9b677553c31287036004fd85b2 100644 (file)
@@ -25,6 +25,7 @@ pub fn target() -> Target {
         target_pointer_width: "64".to_string(),
         arch: "x86_64".to_string(),
         target_os: "macos".to_string(),
+        target_env: "".to_string(),
         options: base,
     }
 }
index 9df2ccca50003059062e63524ca1933abb463b21..74491629ed8592faf1e53115f5dbfc7890756f17 100644 (file)
@@ -21,6 +21,7 @@ pub fn target() -> Target {
         target_pointer_width: "64".to_string(),
         arch: "x86_64".to_string(),
         target_os: "ios".to_string(),
+        target_env: "".to_string(),
         options: opts(Arch::X86_64)
     }
 }
index 6b3054656fe9f1fbe49f2536f7895350db7e2da3..bea7d16e9dfadd83897082db1e9218f3ea2e4305 100644 (file)
@@ -27,6 +27,7 @@ pub fn target() -> Target {
         target_pointer_width: "64".to_string(),
         arch: "x86_64".to_string(),
         target_os: "windows".to_string(),
+        target_env: "gnu".to_string(),
         options: base,
     }
 }
index 7b7877c0c6995855c365d86bdb54601d4a8de870..201c56b2e15c682b991738e9306332b331f467e4 100644 (file)
@@ -23,6 +23,7 @@ pub fn target() -> Target {
         target_pointer_width: "64".to_string(),
         arch: "x86_64".to_string(),
         target_os: "bitrig".to_string(),
+        target_env: "".to_string(),
         options: base,
     }
 }
index 676aaecc2fc7db4f16c92cff2c2ef88cc8355379..c590f0297b948a03648ac04b4c482d8ebb8c3935 100644 (file)
@@ -24,6 +24,7 @@ pub fn target() -> Target {
         target_pointer_width: "64".to_string(),
         arch: "x86_64".to_string(),
         target_os: "dragonfly".to_string(),
+        target_env: "".to_string(),
         options: base,
     }
 }
index 3275cb07b5abc3a7b7021d784e79d109d8c9a6e5..0d8ea90a2ab04921d0371cbe94f6244c273b1d15 100644 (file)
@@ -24,6 +24,7 @@ pub fn target() -> Target {
         target_pointer_width: "64".to_string(),
         arch: "x86_64".to_string(),
         target_os: "freebsd".to_string(),
+        target_env: "".to_string(),
         options: base,
     }
 }
index 49c4ad4aea99f60ef8894d188dc265881dd5cef8..ba945afc5649b38f70750eea70bda88479f72aff 100644 (file)
@@ -24,6 +24,7 @@ pub fn target() -> Target {
         target_pointer_width: "64".to_string(),
         arch: "x86_64".to_string(),
         target_os: "linux".to_string(),
+        target_env: "gnu".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
new file mode 100644 (file)
index 0000000..3debad2
--- /dev/null
@@ -0,0 +1,84 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use target::Target;
+
+pub fn target() -> Target {
+    let mut base = super::linux_base::opts();
+    base.cpu = "x86-64".to_string();
+    base.pre_link_args.push("-m64".to_string());
+
+    // Make sure that the linker/gcc really don't pull in anything, including
+    // default objects, libs, etc.
+    base.pre_link_args.push("-nostdlib".to_string());
+    base.pre_link_args.push("-static".to_string());
+
+    // At least when this was tested, the linker would not add the
+    // `GNU_EH_FRAME` program header to executables generated, which is required
+    // when unwinding to locate the unwinding information. I'm not sure why this
+    // argument is *not* necessary for normal builds, but it can't hurt!
+    base.pre_link_args.push("-Wl,--eh-frame-hdr".to_string());
+
+    // There's a whole bunch of circular dependencies when dealing with MUSL
+    // unfortunately. To put this in perspective libc is statically linked to
+    // liblibc and libunwind is statically linked to libstd:
+    //
+    // * libcore depends on `fmod` which is in libc (transitively in liblibc).
+    //   liblibc, however, depends on libcore.
+    // * compiler-rt has personality symbols that depend on libunwind, but
+    //   libunwind is in libstd which depends on compiler-rt.
+    //
+    // Recall that linkers discard libraries and object files as much as
+    // possible, and with all the static linking and archives flying around with
+    // MUSL the linker is super aggressively stripping out objects. For example
+    // the first case has fmod stripped from liblibc (it's in its own object
+    // file) so it's not there when libcore needs it. In the second example all
+    // the unused symbols from libunwind are stripped (each is in its own object
+    // file in libstd) before we end up linking compiler-rt which depends on
+    // those symbols.
+    //
+    // To deal with these circular dependencies we just force the compiler to
+    // link everything as a group, not stripping anything out until everything
+    // is processed. The linker will still perform a pass to strip out object
+    // files but it won't do so until all objects/archives have been processed.
+    base.pre_link_args.push("-Wl,-(".to_string());
+    base.post_link_args.push("-Wl,-)".to_string());
+
+    // When generating a statically linked executable there's generally some
+    // small setup needed which is listed in these files. These are provided by
+    // a musl toolchain and are linked by default by the `musl-gcc` script. Note
+    // that `gcc` also does this by default, it just uses some different files.
+    //
+    // Each target directory for musl has these object files included in it so
+    // they'll be included from there.
+    base.pre_link_objects.push("crt1.o".to_string());
+    base.pre_link_objects.push("crti.o".to_string());
+    base.post_link_objects.push("crtn.o".to_string());
+
+    // MUSL support doesn't currently include dynamic linking, so there's no
+    // need for dylibs or rpath business. Additionally `-pie` is incompatible
+    // with `-static`, so we can't pass `-pie`.
+    base.dynamic_linking = false;
+    base.has_rpath = false;
+    base.position_independent_executables = false;
+
+    Target {
+        data_layout: "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\
+                      f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\
+                      s0:64:64-f80:128:128-n8:16:32:64-S128".to_string(),
+        llvm_target: "x86_64-unknown-linux-musl".to_string(),
+        target_endian: "little".to_string(),
+        target_pointer_width: "64".to_string(),
+        arch: "x86_64".to_string(),
+        target_os: "linux".to_string(),
+        target_env: "musl".to_string(),
+        options: base,
+    }
+}
index d2667dcd1dd9e8f8bfac358b72f2d4a46f788698..7f64259adf9f8cf0c581a0e50d7a00a014b353a0 100644 (file)
@@ -23,6 +23,7 @@ pub fn target() -> Target {
         target_pointer_width: "64".to_string(),
         arch: "x86_64".to_string(),
         target_os: "openbsd".to_string(),
+        target_env: "".to_string(),
         options: base,
     }
 }
index 502321d07598cf2e058f49956a7fc529a3838048..27adf5bf21b63297a5491ba94efd3bea8f50867d 100644 (file)
 use rustc::middle::dataflow::KillFrom;
 use rustc::middle::expr_use_visitor as euv;
 use rustc::middle::mem_categorization as mc;
+use rustc::middle::free_region::FreeRegionMap;
 use rustc::middle::region;
 use rustc::middle::ty::{self, Ty};
 use rustc::util::ppaux::{note_and_explain_region, Repr, UserString};
+use std::mem;
 use std::rc::Rc;
 use std::string::String;
 use syntax::ast;
 impl<'a, 'tcx, 'v> Visitor<'v> for BorrowckCtxt<'a, 'tcx> {
     fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl,
                 b: &'v Block, s: Span, id: ast::NodeId) {
-        borrowck_fn(self, fk, fd, b, s, id);
+        match fk {
+            visit::FkItemFn(..) |
+            visit::FkMethod(..) => {
+                let new_free_region_map = self.tcx.free_region_map(id);
+                let old_free_region_map =
+                    mem::replace(&mut self.free_region_map, new_free_region_map);
+                borrowck_fn(self, fk, fd, b, s, id);
+                self.free_region_map = old_free_region_map;
+            }
+
+            visit::FkFnBlock => {
+                borrowck_fn(self, fk, fd, b, s, id);
+            }
+        }
     }
 
     fn visit_item(&mut self, item: &ast::Item) {
         borrowck_item(self, item);
     }
+
+    fn visit_trait_item(&mut self, ti: &ast::TraitItem) {
+        if let ast::ConstTraitItem(_, Some(ref expr)) = ti.node {
+            gather_loans::gather_loans_in_static_initializer(self, &*expr);
+        }
+        visit::walk_trait_item(self, ti);
+    }
+
+    fn visit_impl_item(&mut self, ii: &ast::ImplItem) {
+        if let ast::ConstImplItem(_, ref expr) = ii.node {
+            gather_loans::gather_loans_in_static_initializer(self, &*expr);
+        }
+        visit::walk_impl_item(self, ii);
+    }
 }
 
 pub fn check_crate(tcx: &ty::ctxt) {
     let mut bccx = BorrowckCtxt {
         tcx: tcx,
+        free_region_map: FreeRegionMap::new(),
         stats: BorrowStats {
             loaned_paths_same: 0,
             loaned_paths_imm: 0,
@@ -129,11 +159,13 @@ fn borrowck_fn(this: &mut BorrowckCtxt,
     let cfg = cfg::CFG::new(this.tcx, body);
     let AnalysisData { all_loans,
                        loans: loan_dfcx,
-                       move_data:flowed_moves } =
+                       move_data: flowed_moves } =
         build_borrowck_dataflow_data(this, fk, decl, &cfg, body, sp, id);
 
     move_data::fragments::instrument_move_fragments(&flowed_moves.move_data,
-                                                    this.tcx, sp, id);
+                                                    this.tcx,
+                                                    sp,
+                                                    id);
 
     check_loans::check_loans(this,
                              &loan_dfcx,
@@ -152,7 +184,9 @@ fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
                                           cfg: &cfg::CFG,
                                           body: &ast::Block,
                                           sp: Span,
-                                          id: ast::NodeId) -> AnalysisData<'a, 'tcx> {
+                                          id: ast::NodeId)
+                                          -> AnalysisData<'a, 'tcx>
+{
     // Check the body of fn items.
     let id_range = ast_util::compute_id_range_for_fn_body(fk, decl, body, sp, id);
     let (all_loans, move_data) =
@@ -203,10 +237,13 @@ pub fn from_fn_like(f: &'a FnLikeNode,
 /// the `BorrowckCtxt` itself , e.g. the flowgraph visualizer.
 pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>(
     tcx: &'a ty::ctxt<'tcx>,
-    input: FnPartsWithCFG<'a>) -> (BorrowckCtxt<'a, 'tcx>, AnalysisData<'a, 'tcx>) {
+    input: FnPartsWithCFG<'a>)
+    -> (BorrowckCtxt<'a, 'tcx>, AnalysisData<'a, 'tcx>)
+{
 
     let mut bccx = BorrowckCtxt {
         tcx: tcx,
+        free_region_map: FreeRegionMap::new(),
         stats: BorrowStats {
             loaned_paths_same: 0,
             loaned_paths_imm: 0,
@@ -234,6 +271,18 @@ pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>(
 pub struct BorrowckCtxt<'a, 'tcx: 'a> {
     tcx: &'a ty::ctxt<'tcx>,
 
+    // Hacky. As we visit various fns, we have to load up the
+    // free-region map for each one. This map is computed by during
+    // typeck for each fn item and stored -- closures just use the map
+    // from the fn item that encloses them. Since we walk the fns in
+    // order, we basically just overwrite this field as we enter a fn
+    // item and restore it afterwards in a stack-like fashion. Then
+    // the borrow checking code can assume that `free_region_map` is
+    // always the correct map for the current fn. Feels like it'd be
+    // better to just recompute this, rather than store it, but it's a
+    // bit of a pain to factor that code out at the moment.
+    free_region_map: FreeRegionMap,
+
     // Statistics:
     stats: BorrowStats
 }
@@ -518,8 +567,9 @@ pub enum MovedValueUseKind {
 
 impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
     pub fn is_subregion_of(&self, r_sub: ty::Region, r_sup: ty::Region)
-                           -> bool {
-        self.tcx.region_maps.is_subregion_of(r_sub, r_sup)
+                           -> bool
+    {
+        self.free_region_map.is_subregion_of(self.tcx, r_sub, r_sup)
     }
 
     pub fn report(&self, err: BckError<'tcx>) {
index 5741544fe5419638d262839ab3c512d8e4ef4a28..17fd0b81536258d5c229c229c34533bc1789558e 100644 (file)
@@ -36,7 +36,7 @@
 use snapshot_vec::{SnapshotVec, SnapshotVecDelegate};
 
 #[cfg(test)]
-mod test;
+mod tests;
 
 pub struct Graph<N,E> {
     nodes: SnapshotVec<Node<N>> ,
diff --git a/src/librustc_data_structures/graph/test.rs b/src/librustc_data_structures/graph/test.rs
deleted file mode 100644 (file)
index 33b2edd..0000000
+++ /dev/null
@@ -1,139 +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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use graph::*;
-use std::fmt::Debug;
-
-type TestNode = Node<&'static str>;
-type TestEdge = Edge<&'static str>;
-type TestGraph = Graph<&'static str, &'static str>;
-
-fn create_graph() -> TestGraph {
-    let mut graph = Graph::new();
-
-    // Create a simple graph
-    //
-    //    A -+> B --> C
-    //       |  |     ^
-    //       |  v     |
-    //       F  D --> E
-
-    let a = graph.add_node("A");
-    let b = graph.add_node("B");
-    let c = graph.add_node("C");
-    let d = graph.add_node("D");
-    let e = graph.add_node("E");
-    let f = graph.add_node("F");
-
-    graph.add_edge(a, b, "AB");
-    graph.add_edge(b, c, "BC");
-    graph.add_edge(b, d, "BD");
-    graph.add_edge(d, e, "DE");
-    graph.add_edge(e, c, "EC");
-    graph.add_edge(f, b, "FB");
-
-    return graph;
-}
-
-#[test]
-fn each_node() {
-    let graph = create_graph();
-    let expected = ["A", "B", "C", "D", "E", "F"];
-    graph.each_node(|idx, node| {
-        assert_eq!(&expected[idx.0], graph.node_data(idx));
-        assert_eq!(expected[idx.0], node.data);
-        true
-    });
-}
-
-#[test]
-fn each_edge() {
-    let graph = create_graph();
-    let expected = ["AB", "BC", "BD", "DE", "EC", "FB"];
-    graph.each_edge(|idx, edge| {
-        assert_eq!(&expected[idx.0], graph.edge_data(idx));
-        assert_eq!(expected[idx.0], edge.data);
-        true
-    });
-}
-
-fn test_adjacent_edges<N:PartialEq+Debug,E:PartialEq+Debug>(graph: &Graph<N,E>,
-                                                            start_index: NodeIndex,
-                                                            start_data: N,
-                                                            expected_incoming: &[(E,N)],
-                                                            expected_outgoing: &[(E,N)]) {
-    assert!(graph.node_data(start_index) == &start_data);
-
-    let mut counter = 0;
-    for (edge_index, edge) in graph.incoming_edges(start_index) {
-        assert!(graph.edge_data(edge_index) == &edge.data);
-        assert!(counter < expected_incoming.len());
-        debug!("counter={:?} expected={:?} edge_index={:?} edge={:?}",
-               counter, expected_incoming[counter], edge_index, edge);
-        match expected_incoming[counter] {
-            (ref e, ref n) => {
-                assert!(e == &edge.data);
-                assert!(n == graph.node_data(edge.source()));
-                assert!(start_index == edge.target);
-            }
-        }
-        counter += 1;
-    }
-    assert_eq!(counter, expected_incoming.len());
-
-    let mut counter = 0;
-    for (edge_index, edge) in graph.outgoing_edges(start_index) {
-        assert!(graph.edge_data(edge_index) == &edge.data);
-        assert!(counter < expected_outgoing.len());
-        debug!("counter={:?} expected={:?} edge_index={:?} edge={:?}",
-               counter, expected_outgoing[counter], edge_index, edge);
-        match expected_outgoing[counter] {
-            (ref e, ref n) => {
-                assert!(e == &edge.data);
-                assert!(start_index == edge.source);
-                assert!(n == graph.node_data(edge.target));
-            }
-        }
-        counter += 1;
-    }
-    assert_eq!(counter, expected_outgoing.len());
-}
-
-#[test]
-fn each_adjacent_from_a() {
-    let graph = create_graph();
-    test_adjacent_edges(&graph, NodeIndex(0), "A",
-                        &[],
-                        &[("AB", "B")]);
-}
-
-#[test]
-fn each_adjacent_from_b() {
-    let graph = create_graph();
-    test_adjacent_edges(&graph, NodeIndex(1), "B",
-                        &[("FB", "F"), ("AB", "A"),],
-                        &[("BD", "D"), ("BC", "C"),]);
-}
-
-#[test]
-fn each_adjacent_from_c() {
-    let graph = create_graph();
-    test_adjacent_edges(&graph, NodeIndex(2), "C",
-                        &[("EC", "E"), ("BC", "B")],
-                        &[]);
-}
-
-#[test]
-fn each_adjacent_from_d() {
-    let graph = create_graph();
-    test_adjacent_edges(&graph, NodeIndex(3), "D",
-                        &[("BD", "B")],
-                        &[("DE", "E")]);
-}
diff --git a/src/librustc_data_structures/graph/tests.rs b/src/librustc_data_structures/graph/tests.rs
new file mode 100644 (file)
index 0000000..33b2edd
--- /dev/null
@@ -0,0 +1,139 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use graph::*;
+use std::fmt::Debug;
+
+type TestNode = Node<&'static str>;
+type TestEdge = Edge<&'static str>;
+type TestGraph = Graph<&'static str, &'static str>;
+
+fn create_graph() -> TestGraph {
+    let mut graph = Graph::new();
+
+    // Create a simple graph
+    //
+    //    A -+> B --> C
+    //       |  |     ^
+    //       |  v     |
+    //       F  D --> E
+
+    let a = graph.add_node("A");
+    let b = graph.add_node("B");
+    let c = graph.add_node("C");
+    let d = graph.add_node("D");
+    let e = graph.add_node("E");
+    let f = graph.add_node("F");
+
+    graph.add_edge(a, b, "AB");
+    graph.add_edge(b, c, "BC");
+    graph.add_edge(b, d, "BD");
+    graph.add_edge(d, e, "DE");
+    graph.add_edge(e, c, "EC");
+    graph.add_edge(f, b, "FB");
+
+    return graph;
+}
+
+#[test]
+fn each_node() {
+    let graph = create_graph();
+    let expected = ["A", "B", "C", "D", "E", "F"];
+    graph.each_node(|idx, node| {
+        assert_eq!(&expected[idx.0], graph.node_data(idx));
+        assert_eq!(expected[idx.0], node.data);
+        true
+    });
+}
+
+#[test]
+fn each_edge() {
+    let graph = create_graph();
+    let expected = ["AB", "BC", "BD", "DE", "EC", "FB"];
+    graph.each_edge(|idx, edge| {
+        assert_eq!(&expected[idx.0], graph.edge_data(idx));
+        assert_eq!(expected[idx.0], edge.data);
+        true
+    });
+}
+
+fn test_adjacent_edges<N:PartialEq+Debug,E:PartialEq+Debug>(graph: &Graph<N,E>,
+                                                            start_index: NodeIndex,
+                                                            start_data: N,
+                                                            expected_incoming: &[(E,N)],
+                                                            expected_outgoing: &[(E,N)]) {
+    assert!(graph.node_data(start_index) == &start_data);
+
+    let mut counter = 0;
+    for (edge_index, edge) in graph.incoming_edges(start_index) {
+        assert!(graph.edge_data(edge_index) == &edge.data);
+        assert!(counter < expected_incoming.len());
+        debug!("counter={:?} expected={:?} edge_index={:?} edge={:?}",
+               counter, expected_incoming[counter], edge_index, edge);
+        match expected_incoming[counter] {
+            (ref e, ref n) => {
+                assert!(e == &edge.data);
+                assert!(n == graph.node_data(edge.source()));
+                assert!(start_index == edge.target);
+            }
+        }
+        counter += 1;
+    }
+    assert_eq!(counter, expected_incoming.len());
+
+    let mut counter = 0;
+    for (edge_index, edge) in graph.outgoing_edges(start_index) {
+        assert!(graph.edge_data(edge_index) == &edge.data);
+        assert!(counter < expected_outgoing.len());
+        debug!("counter={:?} expected={:?} edge_index={:?} edge={:?}",
+               counter, expected_outgoing[counter], edge_index, edge);
+        match expected_outgoing[counter] {
+            (ref e, ref n) => {
+                assert!(e == &edge.data);
+                assert!(start_index == edge.source);
+                assert!(n == graph.node_data(edge.target));
+            }
+        }
+        counter += 1;
+    }
+    assert_eq!(counter, expected_outgoing.len());
+}
+
+#[test]
+fn each_adjacent_from_a() {
+    let graph = create_graph();
+    test_adjacent_edges(&graph, NodeIndex(0), "A",
+                        &[],
+                        &[("AB", "B")]);
+}
+
+#[test]
+fn each_adjacent_from_b() {
+    let graph = create_graph();
+    test_adjacent_edges(&graph, NodeIndex(1), "B",
+                        &[("FB", "F"), ("AB", "A"),],
+                        &[("BD", "D"), ("BC", "C"),]);
+}
+
+#[test]
+fn each_adjacent_from_c() {
+    let graph = create_graph();
+    test_adjacent_edges(&graph, NodeIndex(2), "C",
+                        &[("EC", "E"), ("BC", "B")],
+                        &[]);
+}
+
+#[test]
+fn each_adjacent_from_d() {
+    let graph = create_graph();
+    test_adjacent_edges(&graph, NodeIndex(3), "D",
+                        &[("BD", "B")],
+                        &[("DE", "E")]);
+}
index 7036c010c6580898d87c3973654f454034e54ece..a899bbacc03016f8c624d68c8d18758f90b57c12 100644 (file)
@@ -14,7 +14,7 @@
 use snapshot_vec as sv;
 
 #[cfg(test)]
-mod test;
+mod tests;
 
 /// This trait is implemented by any type that can serve as a type
 /// variable. We call such variables *unification keys*. For example,
diff --git a/src/librustc_data_structures/unify/test.rs b/src/librustc_data_structures/unify/test.rs
deleted file mode 100644 (file)
index dbe3cfc..0000000
+++ /dev/null
@@ -1,195 +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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![allow(non_snake_case)]
-
-extern crate test;
-use self::test::Bencher;
-use std::collections::HashSet;
-use unify::{UnifyKey, UnificationTable};
-
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-struct UnitKey(u32);
-
-impl UnifyKey for UnitKey {
-    type Value = ();
-    fn index(&self) -> u32 { self.0 }
-    fn from_index(u: u32) -> UnitKey { UnitKey(u) }
-    fn tag(_: Option<UnitKey>) -> &'static str { "UnitKey" }
-}
-
-#[test]
-fn basic() {
-    let mut ut: UnificationTable<UnitKey> = UnificationTable::new();
-    let k1 = ut.new_key(());
-    let k2 = ut.new_key(());
-    assert_eq!(ut.unioned(k1, k2), false);
-    ut.union(k1, k2);
-    assert_eq!(ut.unioned(k1, k2), true);
-}
-
-#[test]
-fn big_array() {
-    let mut ut: UnificationTable<UnitKey> = UnificationTable::new();
-    let mut keys = Vec::new();
-    const MAX: usize = 1 << 15;
-
-    for _ in 0..MAX {
-        keys.push(ut.new_key(()));
-    }
-
-    for i in 1..MAX {
-        let l = keys[i-1];
-        let r = keys[i];
-        ut.union(l, r);
-    }
-
-    for i in 0..MAX {
-        assert!(ut.unioned(keys[0], keys[i]));
-    }
-}
-
-#[bench]
-fn big_array_bench(b: &mut Bencher) {
-    let mut ut: UnificationTable<UnitKey> = UnificationTable::new();
-    let mut keys = Vec::new();
-    const MAX: usize = 1 << 15;
-
-    for _ in 0..MAX {
-        keys.push(ut.new_key(()));
-    }
-
-
-    b.iter(|| {
-        for i in 1..MAX {
-            let l = keys[i-1];
-            let r = keys[i];
-            ut.union(l, r);
-        }
-
-        for i in 0..MAX {
-            assert!(ut.unioned(keys[0], keys[i]));
-        }
-    })
-}
-
-#[test]
-fn even_odd() {
-    let mut ut: UnificationTable<UnitKey> = UnificationTable::new();
-    let mut keys = Vec::new();
-    const MAX: usize = 1 << 10;
-
-    for i in 0..MAX {
-        let key = ut.new_key(());
-        keys.push(key);
-
-        if i >= 2 {
-            ut.union(key, keys[i-2]);
-        }
-    }
-
-    for i in 1..MAX {
-        assert!(!ut.unioned(keys[i-1], keys[i]));
-    }
-
-    for i in 2..MAX {
-        assert!(ut.unioned(keys[i-2], keys[i]));
-    }
-}
-
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-struct IntKey(u32);
-
-impl UnifyKey for IntKey {
-    type Value = Option<i32>;
-    fn index(&self) -> u32 { self.0 }
-    fn from_index(u: u32) -> IntKey { IntKey(u) }
-    fn tag(_: Option<IntKey>) -> &'static str { "IntKey" }
-}
-
-/// Test unifying a key whose value is `Some(_)`  with a key whose value is `None`.
-/// Afterwards both should be `Some(_)`.
-#[test]
-fn unify_key_Some_key_None() {
-    let mut ut: UnificationTable<IntKey> = UnificationTable::new();
-    let k1 = ut.new_key(Some(22));
-    let k2 = ut.new_key(None);
-    assert!(ut.unify_var_var(k1, k2).is_ok());
-    assert_eq!(ut.probe(k2), Some(22));
-    assert_eq!(ut.probe(k1), Some(22));
-}
-
-/// Test unifying a key whose value is `None`  with a key whose value is `Some(_)`.
-/// Afterwards both should be `Some(_)`.
-#[test]
-fn unify_key_None_key_Some() {
-    let mut ut: UnificationTable<IntKey> = UnificationTable::new();
-    let k1 = ut.new_key(Some(22));
-    let k2 = ut.new_key(None);
-    assert!(ut.unify_var_var(k2, k1).is_ok());
-    assert_eq!(ut.probe(k2), Some(22));
-    assert_eq!(ut.probe(k1), Some(22));
-}
-
-/// Test unifying a key whose value is `Some(x)` with a key whose value is `Some(y)`.
-/// This should yield an error.
-#[test]
-fn unify_key_Some_x_key_Some_y() {
-    let mut ut: UnificationTable<IntKey> = UnificationTable::new();
-    let k1 = ut.new_key(Some(22));
-    let k2 = ut.new_key(Some(23));
-    assert_eq!(ut.unify_var_var(k1, k2), Err((22, 23)));
-    assert_eq!(ut.unify_var_var(k2, k1), Err((23, 22)));
-    assert_eq!(ut.probe(k1), Some(22));
-    assert_eq!(ut.probe(k2), Some(23));
-}
-
-/// Test unifying a key whose value is `Some(x)` with a key whose value is `Some(x)`.
-/// This should be ok.
-#[test]
-fn unify_key_Some_x_key_Some_x() {
-    let mut ut: UnificationTable<IntKey> = UnificationTable::new();
-    let k1 = ut.new_key(Some(22));
-    let k2 = ut.new_key(Some(22));
-    assert!(ut.unify_var_var(k1, k2).is_ok());
-    assert_eq!(ut.probe(k1), Some(22));
-    assert_eq!(ut.probe(k2), Some(22));
-}
-
-/// Test unifying a key whose value is `None` with a value is `x`.
-/// Afterwards key should be `x`.
-#[test]
-fn unify_key_None_val() {
-    let mut ut: UnificationTable<IntKey> = UnificationTable::new();
-    let k1 = ut.new_key(None);
-    assert!(ut.unify_var_value(k1, 22).is_ok());
-    assert_eq!(ut.probe(k1), Some(22));
-}
-
-/// Test unifying a key whose value is `Some(x)` with the value `y`.
-/// This should yield an error.
-#[test]
-fn unify_key_Some_x_val_y() {
-    let mut ut: UnificationTable<IntKey> = UnificationTable::new();
-    let k1 = ut.new_key(Some(22));
-    assert_eq!(ut.unify_var_value(k1, 23), Err((22, 23)));
-    assert_eq!(ut.probe(k1), Some(22));
-}
-
-/// Test unifying a key whose value is `Some(x)` with the value `x`.
-/// This should be ok.
-#[test]
-fn unify_key_Some_x_val_x() {
-    let mut ut: UnificationTable<IntKey> = UnificationTable::new();
-    let k1 = ut.new_key(Some(22));
-    assert!(ut.unify_var_value(k1, 22).is_ok());
-    assert_eq!(ut.probe(k1), Some(22));
-}
-
diff --git a/src/librustc_data_structures/unify/tests.rs b/src/librustc_data_structures/unify/tests.rs
new file mode 100644 (file)
index 0000000..dbe3cfc
--- /dev/null
@@ -0,0 +1,195 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(non_snake_case)]
+
+extern crate test;
+use self::test::Bencher;
+use std::collections::HashSet;
+use unify::{UnifyKey, UnificationTable};
+
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+struct UnitKey(u32);
+
+impl UnifyKey for UnitKey {
+    type Value = ();
+    fn index(&self) -> u32 { self.0 }
+    fn from_index(u: u32) -> UnitKey { UnitKey(u) }
+    fn tag(_: Option<UnitKey>) -> &'static str { "UnitKey" }
+}
+
+#[test]
+fn basic() {
+    let mut ut: UnificationTable<UnitKey> = UnificationTable::new();
+    let k1 = ut.new_key(());
+    let k2 = ut.new_key(());
+    assert_eq!(ut.unioned(k1, k2), false);
+    ut.union(k1, k2);
+    assert_eq!(ut.unioned(k1, k2), true);
+}
+
+#[test]
+fn big_array() {
+    let mut ut: UnificationTable<UnitKey> = UnificationTable::new();
+    let mut keys = Vec::new();
+    const MAX: usize = 1 << 15;
+
+    for _ in 0..MAX {
+        keys.push(ut.new_key(()));
+    }
+
+    for i in 1..MAX {
+        let l = keys[i-1];
+        let r = keys[i];
+        ut.union(l, r);
+    }
+
+    for i in 0..MAX {
+        assert!(ut.unioned(keys[0], keys[i]));
+    }
+}
+
+#[bench]
+fn big_array_bench(b: &mut Bencher) {
+    let mut ut: UnificationTable<UnitKey> = UnificationTable::new();
+    let mut keys = Vec::new();
+    const MAX: usize = 1 << 15;
+
+    for _ in 0..MAX {
+        keys.push(ut.new_key(()));
+    }
+
+
+    b.iter(|| {
+        for i in 1..MAX {
+            let l = keys[i-1];
+            let r = keys[i];
+            ut.union(l, r);
+        }
+
+        for i in 0..MAX {
+            assert!(ut.unioned(keys[0], keys[i]));
+        }
+    })
+}
+
+#[test]
+fn even_odd() {
+    let mut ut: UnificationTable<UnitKey> = UnificationTable::new();
+    let mut keys = Vec::new();
+    const MAX: usize = 1 << 10;
+
+    for i in 0..MAX {
+        let key = ut.new_key(());
+        keys.push(key);
+
+        if i >= 2 {
+            ut.union(key, keys[i-2]);
+        }
+    }
+
+    for i in 1..MAX {
+        assert!(!ut.unioned(keys[i-1], keys[i]));
+    }
+
+    for i in 2..MAX {
+        assert!(ut.unioned(keys[i-2], keys[i]));
+    }
+}
+
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+struct IntKey(u32);
+
+impl UnifyKey for IntKey {
+    type Value = Option<i32>;
+    fn index(&self) -> u32 { self.0 }
+    fn from_index(u: u32) -> IntKey { IntKey(u) }
+    fn tag(_: Option<IntKey>) -> &'static str { "IntKey" }
+}
+
+/// Test unifying a key whose value is `Some(_)`  with a key whose value is `None`.
+/// Afterwards both should be `Some(_)`.
+#[test]
+fn unify_key_Some_key_None() {
+    let mut ut: UnificationTable<IntKey> = UnificationTable::new();
+    let k1 = ut.new_key(Some(22));
+    let k2 = ut.new_key(None);
+    assert!(ut.unify_var_var(k1, k2).is_ok());
+    assert_eq!(ut.probe(k2), Some(22));
+    assert_eq!(ut.probe(k1), Some(22));
+}
+
+/// Test unifying a key whose value is `None`  with a key whose value is `Some(_)`.
+/// Afterwards both should be `Some(_)`.
+#[test]
+fn unify_key_None_key_Some() {
+    let mut ut: UnificationTable<IntKey> = UnificationTable::new();
+    let k1 = ut.new_key(Some(22));
+    let k2 = ut.new_key(None);
+    assert!(ut.unify_var_var(k2, k1).is_ok());
+    assert_eq!(ut.probe(k2), Some(22));
+    assert_eq!(ut.probe(k1), Some(22));
+}
+
+/// Test unifying a key whose value is `Some(x)` with a key whose value is `Some(y)`.
+/// This should yield an error.
+#[test]
+fn unify_key_Some_x_key_Some_y() {
+    let mut ut: UnificationTable<IntKey> = UnificationTable::new();
+    let k1 = ut.new_key(Some(22));
+    let k2 = ut.new_key(Some(23));
+    assert_eq!(ut.unify_var_var(k1, k2), Err((22, 23)));
+    assert_eq!(ut.unify_var_var(k2, k1), Err((23, 22)));
+    assert_eq!(ut.probe(k1), Some(22));
+    assert_eq!(ut.probe(k2), Some(23));
+}
+
+/// Test unifying a key whose value is `Some(x)` with a key whose value is `Some(x)`.
+/// This should be ok.
+#[test]
+fn unify_key_Some_x_key_Some_x() {
+    let mut ut: UnificationTable<IntKey> = UnificationTable::new();
+    let k1 = ut.new_key(Some(22));
+    let k2 = ut.new_key(Some(22));
+    assert!(ut.unify_var_var(k1, k2).is_ok());
+    assert_eq!(ut.probe(k1), Some(22));
+    assert_eq!(ut.probe(k2), Some(22));
+}
+
+/// Test unifying a key whose value is `None` with a value is `x`.
+/// Afterwards key should be `x`.
+#[test]
+fn unify_key_None_val() {
+    let mut ut: UnificationTable<IntKey> = UnificationTable::new();
+    let k1 = ut.new_key(None);
+    assert!(ut.unify_var_value(k1, 22).is_ok());
+    assert_eq!(ut.probe(k1), Some(22));
+}
+
+/// Test unifying a key whose value is `Some(x)` with the value `y`.
+/// This should yield an error.
+#[test]
+fn unify_key_Some_x_val_y() {
+    let mut ut: UnificationTable<IntKey> = UnificationTable::new();
+    let k1 = ut.new_key(Some(22));
+    assert_eq!(ut.unify_var_value(k1, 23), Err((22, 23)));
+    assert_eq!(ut.probe(k1), Some(22));
+}
+
+/// Test unifying a key whose value is `Some(x)` with the value `x`.
+/// This should be ok.
+#[test]
+fn unify_key_Some_x_val_x() {
+    let mut ut: UnificationTable<IntKey> = UnificationTable::new();
+    let k1 = ut.new_key(Some(22));
+    assert!(ut.unify_var_value(k1, 22).is_ok());
+    assert_eq!(ut.probe(k1), Some(22));
+}
+
index 00c3450ebb935ac326ca6e904d05f49f8575c3f0..b8032bda8d070ede99791322e5f2ba00c49abc14 100644 (file)
@@ -35,6 +35,7 @@
 use syntax::fold::{self, Folder};
 use syntax::print::{pp, pprust};
 use syntax::ptr::P;
+use syntax::util::small_vector::SmallVector;
 
 use graphviz as dot;
 
@@ -475,6 +476,29 @@ fn fold_item_underscore(&mut self, i: ast::Item_) -> ast::Item_ {
         }
     }
 
+    fn fold_trait_item(&mut self, i: P<ast::TraitItem>) -> SmallVector<P<ast::TraitItem>> {
+        match i.node {
+            ast::ConstTraitItem(..) => {
+                self.within_static_or_const = true;
+                let ret = fold::noop_fold_trait_item(i, self);
+                self.within_static_or_const = false;
+                return ret;
+            }
+            _ => fold::noop_fold_trait_item(i, self),
+        }
+    }
+
+    fn fold_impl_item(&mut self, i: P<ast::ImplItem>) -> SmallVector<P<ast::ImplItem>> {
+        match i.node {
+            ast::ConstImplItem(..) => {
+                self.within_static_or_const = true;
+                let ret = fold::noop_fold_impl_item(i, self);
+                self.within_static_or_const = false;
+                return ret;
+            }
+            _ => fold::noop_fold_impl_item(i, self),
+        }
+    }
 
     fn fold_block(&mut self, b: P<ast::Block>) -> P<ast::Block> {
         fn expr_to_block(rules: ast::BlockCheckMode,
index 12b16e95a71a43601b7448d4a1abdf7541c650c8..a8cf75331799646679480a8a4499ff7b5cceb21a 100644 (file)
@@ -16,6 +16,7 @@
 use rustc_lint;
 use rustc_resolve as resolve;
 use rustc_typeck::middle::lang_items;
+use rustc_typeck::middle::free_region::FreeRegionMap;
 use rustc_typeck::middle::region::{self, CodeExtent, DestructionScopeData};
 use rustc_typeck::middle::resolve_lifetime;
 use rustc_typeck::middle::stability;
@@ -138,7 +139,8 @@ fn test_env<F>(source_string: &str,
                           stability::Index::new(krate));
     let infcx = infer::new_infer_ctxt(&tcx);
     body(Env { infcx: &infcx });
-    infcx.resolve_regions_and_report_errors(ast::CRATE_NODE_ID);
+    let free_regions = FreeRegionMap::new();
+    infcx.resolve_regions_and_report_errors(&free_regions, ast::CRATE_NODE_ID);
     assert_eq!(tcx.sess.err_count(), expected_err_count);
 }
 
index c12ac501c45a2a14fb510dcb90462a4b63610a65..1d5c5fb86cbd5988b783d19c69ac28f5b06ca8b0 100644 (file)
@@ -1068,6 +1068,26 @@ fn check_item(&mut self, cx: &Context, it: &ast::Item) {
         }
     }
 
+    fn check_trait_item(&mut self, cx: &Context, ti: &ast::TraitItem) {
+        match ti.node {
+            ast::ConstTraitItem(..) => {
+                NonUpperCaseGlobals::check_upper_case(cx, "associated constant",
+                                                      ti.ident, ti.span);
+            }
+            _ => {}
+        }
+    }
+
+    fn check_impl_item(&mut self, cx: &Context, ii: &ast::ImplItem) {
+        match ii.node {
+            ast::ConstImplItem(..) => {
+                NonUpperCaseGlobals::check_upper_case(cx, "associated constant",
+                                                      ii.ident, ii.span);
+            }
+            _ => {}
+        }
+    }
+
     fn check_pat(&mut self, cx: &Context, p: &ast::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())) {
@@ -1584,8 +1604,9 @@ fn check_trait_item(&mut self, cx: &Context, trait_item: &ast::TraitItem) {
         if self.private_traits.contains(&trait_item.id) { return }
 
         let desc = match trait_item.node {
+            ast::ConstTraitItem(..) => "an associated constant",
             ast::MethodTraitItem(..) => "a trait method",
-            ast::TypeTraitItem(..) => "an associated type"
+            ast::TypeTraitItem(..) => "an associated type",
         };
 
         self.check_missing_docs_attrs(cx, Some(trait_item.id),
@@ -1600,9 +1621,10 @@ fn check_impl_item(&mut self, cx: &Context, impl_item: &ast::ImplItem) {
         }
 
         let desc = match impl_item.node {
+            ast::ConstImplItem(..) => "an associated constant",
             ast::MethodImplItem(..) => "a method",
             ast::TypeImplItem(_) => "an associated type",
-            ast::MacImplItem(_) => "an impl item macro"
+            ast::MacImplItem(_) => "an impl item macro",
         };
         self.check_missing_docs_attrs(cx, Some(impl_item.id),
                                       &impl_item.attrs,
index 70c824a67a0efbd6d621c6e4533d390fe3221610..128e29ee76e7d6ec17acc19c8b9216cacef514b2 100644 (file)
@@ -119,6 +119,15 @@ fn visit_fn(&mut self, a: visit::FnKind<'v>, b: &'v ast::FnDecl,
         visit::walk_fn(self, a, b, c, d);
     }
 
+    fn visit_impl_item(&mut self, ii: &'v ast::ImplItem) {
+        // visit_fn handles methods, but associated consts have to be handled
+        // here.
+        if !self.parents.contains_key(&ii.id) {
+            self.parents.insert(ii.id, self.curparent);
+        }
+        visit::walk_impl_item(self, ii);
+    }
+
     fn visit_struct_def(&mut self, s: &ast::StructDef, _: ast::Ident,
                         _: &'v ast::Generics, n: ast::NodeId) {
         // Struct constructors are parented to their struct definitions because
@@ -272,6 +281,12 @@ fn visit_item(&mut self, item: &ast::Item) {
                 if public_ty || public_trait {
                     for impl_item in impl_items {
                         match impl_item.node {
+                            ast::ConstImplItem(..) => {
+                                if (public_ty && impl_item.vis == ast::Public)
+                                    || tr.is_some() {
+                                    self.exported_items.insert(impl_item.id);
+                                }
+                            }
                             ast::MethodImplItem(ref sig, _) => {
                                 let meth_public = match sig.explicit_self.node {
                                     ast::SelfStatic => public_ty,
@@ -399,6 +414,33 @@ fn def_privacy(&self, did: ast::DefId) -> PrivacyResult {
             debug!("privacy - is {:?} a public method", did);
 
             return match self.tcx.impl_or_trait_items.borrow().get(&did) {
+                Some(&ty::ConstTraitItem(ref ac)) => {
+                    debug!("privacy - it's a const: {:?}", *ac);
+                    match ac.container {
+                        ty::TraitContainer(id) => {
+                            debug!("privacy - recursing on trait {:?}", id);
+                            self.def_privacy(id)
+                        }
+                        ty::ImplContainer(id) => {
+                            match ty::impl_trait_ref(self.tcx, id) {
+                                Some(t) => {
+                                    debug!("privacy - impl of trait {:?}", id);
+                                    self.def_privacy(t.def_id)
+                                }
+                                None => {
+                                    debug!("privacy - found inherent \
+                                            associated constant {:?}",
+                                            ac.vis);
+                                    if ac.vis == ast::Public {
+                                        Allowable
+                                    } else {
+                                        ExternallyDenied
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
                 Some(&ty::MethodTraitItem(ref meth)) => {
                     debug!("privacy - well at least it's a method: {:?}",
                            *meth);
@@ -490,6 +532,7 @@ fn def_privacy(&self, did: ast::DefId) -> PrivacyResult {
                 //               where the method was defined?
                 Some(ast_map::NodeImplItem(ii)) => {
                     match ii.node {
+                        ast::ConstImplItem(..) |
                         ast::MethodImplItem(..) => {
                             let imp = self.tcx.map
                                           .get_parent_did(closest_private_id);
@@ -693,7 +736,11 @@ fn check_static_method(&mut self,
             ty::MethodTraitItem(method_type) => {
                 method_type.provided_source.unwrap_or(method_id)
             }
-            ty::TypeTraitItem(_) => method_id,
+            _ => {
+                self.tcx.sess
+                    .span_bug(span,
+                              "got non-method item in check_static_method")
+            }
         };
 
         let string = token::get_name(name);
@@ -787,6 +834,7 @@ fn check_path(&mut self, span: Span, path_id: ast::NodeId, last: ast::Name) {
             def::DefFn(..) => ck("function"),
             def::DefStatic(..) => ck("static"),
             def::DefConst(..) => ck("const"),
+            def::DefAssociatedConst(..) => ck("associated const"),
             def::DefVariant(..) => ck("variant"),
             def::DefTy(_, false) => ck("type"),
             def::DefTy(_, true) => ck("enum"),
@@ -1128,8 +1176,7 @@ fn check_inherited(tcx: &ty::ctxt, sp: Span, vis: ast::Visibility) {
                         ast::MethodImplItem(..) => {
                             check_inherited(tcx, impl_item.span, impl_item.vis);
                         }
-                        ast::TypeImplItem(_) |
-                        ast::MacImplItem(_) => {}
+                        _ => {}
                     }
                 }
             }
@@ -1307,6 +1354,7 @@ fn visit_item(&mut self, item: &ast::Item) {
                     impl_items.iter()
                               .any(|impl_item| {
                                   match impl_item.node {
+                                      ast::ConstImplItem(..) |
                                       ast::MethodImplItem(..) => {
                                           self.exported_items.contains(&impl_item.id)
                                       }
@@ -1330,6 +1378,7 @@ fn visit_item(&mut self, item: &ast::Item) {
                                 // don't erroneously report errors for private
                                 // types in private items.
                                 match impl_item.node {
+                                    ast::ConstImplItem(..) |
                                     ast::MethodImplItem(..)
                                         if self.item_is_public(&impl_item.id, impl_item.vis) =>
                                     {
@@ -1360,12 +1409,8 @@ fn visit_item(&mut self, item: &ast::Item) {
 
                             // Those in 3. are warned with this call.
                             for impl_item in impl_items {
-                                match impl_item.node {
-                                    ast::TypeImplItem(ref ty) => {
-                                        self.visit_ty(ty);
-                                    }
-                                    ast::MethodImplItem(..) |
-                                    ast::MacImplItem(_) => {},
+                                if let ast::TypeImplItem(ref ty) = impl_item.node {
+                                    self.visit_ty(ty);
                                 }
                             }
                         }
@@ -1376,15 +1421,20 @@ fn visit_item(&mut self, item: &ast::Item) {
                     let mut found_pub_static = false;
                     for impl_item in impl_items {
                         match impl_item.node {
+                            ast::ConstImplItem(..) => {
+                                if self.item_is_public(&impl_item.id, impl_item.vis) {
+                                    found_pub_static = true;
+                                    visit::walk_impl_item(self, impl_item);
+                                }
+                            }
                             ast::MethodImplItem(ref sig, _) => {
                                 if sig.explicit_self.node == ast::SelfStatic &&
-                                        self.item_is_public(&impl_item.id, impl_item.vis) {
+                                      self.item_is_public(&impl_item.id, impl_item.vis) {
                                     found_pub_static = true;
                                     visit::walk_impl_item(self, impl_item);
                                 }
                             }
-                            ast::TypeImplItem(_) |
-                            ast::MacImplItem(_) => {}
+                            _ => {}
                         }
                     }
                     if found_pub_static {
index 777154f3c9c3b41881f7b2c3849160402dc32853..0d25700d2b7f101f69f3ffb7adc7e671ae076b48 100644 (file)
@@ -530,6 +530,12 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, parent: &Rc<Module>) ->
                                         trait_item.span);
 
                     match trait_item.node {
+                        ast::ConstTraitItem(..) => {
+                            let def = DefAssociatedConst(local_def(trait_item.id),
+                                                         FromTrait(local_def(item.id)));
+                            // NB: not IMPORTABLE
+                            name_bindings.define_value(def, trait_item.span, PUBLIC);
+                        }
                         ast::MethodTraitItem(..) => {
                             let def = DefMethod(local_def(trait_item.id),
                                                 FromTrait(local_def(item.id)));
@@ -703,7 +709,8 @@ fn handle_external_def(&mut self,
                 csearch::get_tuple_struct_definition_if_ctor(&self.session.cstore, ctor_id)
                     .map_or(def, |_| DefStruct(ctor_id)), DUMMY_SP, modifiers);
           }
-          DefFn(..) | DefStatic(..) | DefConst(..) | DefMethod(..) => {
+          DefFn(..) | DefStatic(..) | DefConst(..) | DefAssociatedConst(..) |
+          DefMethod(..) => {
             debug!("(building reduced graph for external \
                     crate) building value (fn/static) {}", final_ident);
             // impl methods have already been defined with the correct importability modifier
index d300045c0ec01c1444f37cca16681a2ef82d1a5e..61eab4ce9b285e0128cfb57b6311bde190ff93be 100644 (file)
@@ -41,6 +41,7 @@
 use self::RibKind::*;
 use self::UseLexicalScopeFlag::*;
 use self::ModulePrefixResult::*;
+use self::AssocItemResolveResult::*;
 use self::NameSearchType::*;
 use self::BareIdentifierPatternResolution::*;
 use self::ParentLink::*;
@@ -60,7 +61,8 @@
 use rustc::util::nodemap::{NodeMap, NodeSet, DefIdSet, FnvHashMap};
 use rustc::util::lev_distance::lev_distance;
 
-use syntax::ast::{Arm, BindByRef, BindByValue, BindingMode, Block, Crate, CrateNum};
+use syntax::ast::{Arm, BindByRef, BindByValue, BindingMode, Block};
+use syntax::ast::{ConstImplItem, Crate, CrateNum};
 use syntax::ast::{DefId, Expr, ExprAgain, ExprBreak, ExprField};
 use syntax::ast::{ExprLoop, ExprWhile, ExprMethodCall};
 use syntax::ast::{ExprPath, ExprStruct, FnDecl};
@@ -69,7 +71,7 @@
 use syntax::ast::{ItemFn, ItemForeignMod, ItemImpl, ItemMac, ItemMod, ItemStatic, ItemDefaultImpl};
 use syntax::ast::{ItemStruct, ItemTrait, ItemTy, ItemUse};
 use syntax::ast::{Local, MethodImplItem, Name, NodeId};
-use syntax::ast::{Pat, PatEnum, PatIdent, PatLit};
+use syntax::ast::{Pat, PatEnum, PatIdent, PatLit, PatQPath};
 use syntax::ast::{PatRange, PatStruct, Path, PrimTy};
 use syntax::ast::{TraitRef, Ty, TyBool, TyChar, TyF32};
 use syntax::ast::{TyF64, TyFloat, TyIs, TyI8, TyI16, TyI32, TyI64, TyInt};
@@ -330,6 +332,15 @@ enum ModulePrefixResult {
     PrefixFound(Rc<Module>, usize)
 }
 
+#[derive(Copy, Clone)]
+enum AssocItemResolveResult {
+    /// Syntax such as `<T>::item`, which can't be resolved until type
+    /// checking.
+    TypecheckRequired,
+    /// We should have been able to resolve the associated item.
+    ResolveAttempt(Option<PathResolution>),
+}
+
 #[derive(Copy, Clone, PartialEq)]
 enum NameSearchType {
     /// We're doing a name search in order to resolve a `use` directive.
@@ -1830,21 +1841,36 @@ fn resolve_item(&mut self, item: &Item) {
                             //
                             // FIXME #4951: Do we need a node ID here?
 
-                            let type_parameters = match trait_item.node {
+                            match trait_item.node {
+                                ast::ConstTraitItem(_, ref default) => {
+                                    // Only impose the restrictions of
+                                    // ConstRibKind if there's an actual constant
+                                    // expression in a provided default.
+                                    if default.is_some() {
+                                        this.with_constant_rib(|this| {
+                                            visit::walk_trait_item(this, trait_item)
+                                        });
+                                    } else {
+                                        visit::walk_trait_item(this, trait_item)
+                                    }
+                                }
                                 ast::MethodTraitItem(ref sig, _) => {
-                                    HasTypeParameters(&sig.generics,
-                                                      FnSpace,
-                                                      MethodRibKind)
+                                    let type_parameters =
+                                        HasTypeParameters(&sig.generics,
+                                                          FnSpace,
+                                                          MethodRibKind);
+                                    this.with_type_parameter_rib(type_parameters, |this| {
+                                        visit::walk_trait_item(this, trait_item)
+                                    });
                                 }
                                 ast::TypeTraitItem(..) => {
                                     this.check_if_primitive_type_name(trait_item.ident.name,
                                                                       trait_item.span);
-                                    NoTypeParameters
+                                    this.with_type_parameter_rib(NoTypeParameters, |this| {
+                                        visit::walk_trait_item(this, trait_item)
+                                    });
                                 }
                             };
-                            this.with_type_parameter_rib(type_parameters, |this| {
-                                visit::walk_trait_item(this, trait_item)
-                            });
                         }
                     });
                 });
@@ -2094,6 +2120,15 @@ fn resolve_implementation(&mut self,
                     this.with_current_self_type(self_type, |this| {
                         for impl_item in impl_items {
                             match impl_item.node {
+                                ConstImplItem(..) => {
+                                    // If this is a trait impl, ensure the method
+                                    // exists in trait
+                                    this.check_trait_item(impl_item.ident.name,
+                                                          impl_item.span);
+                                    this.with_constant_rib(|this| {
+                                        visit::walk_impl_item(this, impl_item);
+                                    });
+                                }
                                 MethodImplItem(ref sig, _) => {
                                     // If this is a trait impl, ensure the method
                                     // exists in trait
@@ -2280,31 +2315,21 @@ fn resolve_block(&mut self, block: &Block) {
 
     fn resolve_type(&mut self, ty: &Ty) {
         match ty.node {
-            // `<T>::a::b::c` is resolved by typeck alone.
-            TyPath(Some(ast::QSelf { position: 0, .. }), _) => {}
-
             TyPath(ref maybe_qself, ref path) => {
-                let max_assoc_types = if let Some(ref qself) = *maybe_qself {
-                    // Make sure the trait is valid.
-                    let _ = self.resolve_trait_reference(ty.id, path, 1);
-                    path.segments.len() - qself.position
-                } else {
-                    path.segments.len()
-                };
-
-                let mut resolution = None;
-                for depth in 0..max_assoc_types {
-                    self.with_no_errors(|this| {
-                        resolution = this.resolve_path(ty.id, path, depth, TypeNS, true);
-                    });
-                    if resolution.is_some() {
-                        break;
-                    }
-                }
-                if let Some(DefMod(_)) = resolution.map(|r| r.base_def) {
-                    // A module is not a valid type.
-                    resolution = None;
-                }
+                let resolution =
+                    match self.resolve_possibly_assoc_item(ty.id,
+                                                           maybe_qself.as_ref(),
+                                                           path,
+                                                           TypeNS,
+                                                           true) {
+                        // `<T>::a::b::c` is resolved by typeck alone.
+                        TypecheckRequired => {
+                            // Resolve embedded types.
+                            visit::walk_ty(self, ty);
+                            return;
+                        }
+                        ResolveAttempt(resolution) => resolution,
+                    };
 
                 // This is a path in the type namespace. Walk through scopes
                 // looking for it.
@@ -2464,7 +2489,22 @@ struct or enum variant",
 
                 PatEnum(ref path, _) => {
                     // This must be an enum variant, struct or const.
-                    if let Some(path_res) = self.resolve_path(pat_id, path, 0, ValueNS, false) {
+                    let resolution =
+                        match self.resolve_possibly_assoc_item(pat_id, None,
+                                                               path, ValueNS,
+                                                               false) {
+                            // The below shouldn't happen because all
+                            // qualified paths should be in PatQPath.
+                            TypecheckRequired =>
+                                self.session.span_bug(
+                                    path.span,
+                                    "resolve_possibly_assoc_item claimed
+                                     that a path in PatEnum requires typecheck
+                                     to resolve, but qualified paths should be
+                                     PatQPath"),
+                            ResolveAttempt(resolution) => resolution,
+                        };
+                    if let Some(path_res) = resolution {
                         match path_res.base_def {
                             DefVariant(..) | DefStruct(..) | DefConst(..) => {
                                 self.record_def(pattern.id, path_res);
@@ -2475,19 +2515,70 @@ struct or enum variant",
                                                     referenced in a pattern, \
                                                     use a `const` instead");
                             }
+                            _ => {
+                                // If anything ends up here entirely resolved,
+                                // it's an error. If anything ends up here
+                                // partially resolved, that's OK, because it may
+                                // be a `T::CONST` that typeck will resolve to
+                                // an inherent impl.
+                                if path_res.depth == 0 {
+                                    self.resolve_error(
+                                        path.span,
+                                        &format!("`{}` is not an enum variant, struct or const",
+                                                 token::get_ident(
+                                                     path.segments.last().unwrap().identifier)));
+                                } else {
+                                    self.record_def(pattern.id, path_res);
+                                }
+                            }
+                        }
+                    } else {
+                        self.resolve_error(path.span,
+                            &format!("unresolved enum variant, struct or const `{}`",
+                                token::get_ident(path.segments.last().unwrap().identifier)));
+                    }
+                    visit::walk_path(self, path);
+                }
+
+                PatQPath(ref qself, ref path) => {
+                    // Associated constants only.
+                    let resolution =
+                        match self.resolve_possibly_assoc_item(pat_id, Some(qself),
+                                                               path, ValueNS,
+                                                               false) {
+                            TypecheckRequired => {
+                                // All `<T>::CONST` should end up here, and will
+                                // require use of the trait map to resolve
+                                // during typechecking.
+                                let const_name = path.segments.last().unwrap()
+                                                     .identifier.name;
+                                let traits = self.get_traits_containing_item(const_name);
+                                self.trait_map.insert(pattern.id, traits);
+                                visit::walk_pat(self, pattern);
+                                return true;
+                            }
+                            ResolveAttempt(resolution) => resolution,
+                        };
+                    if let Some(path_res) = resolution {
+                        match path_res.base_def {
+                            // All `<T as Trait>::CONST` should end up here, and
+                            // have the trait already selected.
+                            DefAssociatedConst(..) => {
+                                self.record_def(pattern.id, path_res);
+                            }
                             _ => {
                                 self.resolve_error(path.span,
-                                    &format!("`{}` is not an enum variant, struct or const",
+                                    &format!("`{}` is not an associated const",
                                         token::get_ident(
                                             path.segments.last().unwrap().identifier)));
                             }
                         }
                     } else {
                         self.resolve_error(path.span,
-                            &format!("unresolved enum variant, struct or const `{}`",
+                            &format!("unresolved associated const `{}`",
                                 token::get_ident(path.segments.last().unwrap().identifier)));
                     }
-                    visit::walk_path(self, path);
+                    visit::walk_pat(self, pattern);
                 }
 
                 PatStruct(ref path, _, _) => {
@@ -2542,7 +2633,7 @@ fn resolve_bare_identifier_pattern(&mut self, name: Name, span: Span)
                             def @ DefVariant(..) | def @ DefStruct(..) => {
                                 return FoundStructOrEnumVariant(def, LastMod(AllPublic));
                             }
-                            def @ DefConst(..) => {
+                            def @ DefConst(..) | def @ DefAssociatedConst(..) => {
                                 return FoundConst(def, LastMod(AllPublic));
                             }
                             DefStatic(..) => {
@@ -2579,6 +2670,47 @@ fn resolve_bare_identifier_pattern(&mut self, name: Name, span: Span)
         }
     }
 
+    /// Handles paths that may refer to associated items
+    fn resolve_possibly_assoc_item(&mut self,
+                                   id: NodeId,
+                                   maybe_qself: Option<&ast::QSelf>,
+                                   path: &Path,
+                                   namespace: Namespace,
+                                   check_ribs: bool)
+                                   -> AssocItemResolveResult
+    {
+        match maybe_qself {
+            Some(&ast::QSelf { position: 0, .. }) =>
+                return TypecheckRequired,
+            _ => {}
+        }
+        let max_assoc_types = if let Some(qself) = maybe_qself {
+            // Make sure the trait is valid.
+            let _ = self.resolve_trait_reference(id, path, 1);
+            path.segments.len() - qself.position
+        } else {
+            path.segments.len()
+        };
+
+        let mut resolution = self.with_no_errors(|this| {
+            this.resolve_path(id, path, 0, namespace, check_ribs)
+        });
+        for depth in 1..max_assoc_types {
+            if resolution.is_some() {
+                break;
+            }
+            self.with_no_errors(|this| {
+                resolution = this.resolve_path(id, path, depth,
+                                               TypeNS, true);
+            });
+        }
+        if let Some(DefMod(_)) = resolution.map(|r| r.base_def) {
+            // A module is not a valid type or value.
+            resolution = None;
+        }
+        ResolveAttempt(resolution)
+    }
+
     /// If `check_ribs` is true, checks the local definitions first; i.e.
     /// doesn't skip straight to the containing module.
     /// Skips `path_depth` trailing segments, which is also reflected in the
@@ -3093,38 +3225,23 @@ fn resolve_expr(&mut self, expr: &Expr) {
 
         // Next, resolve the node.
         match expr.node {
-            // `<T>::a::b::c` is resolved by typeck alone.
-            ExprPath(Some(ast::QSelf { position: 0, .. }), ref path) => {
-                let method_name = path.segments.last().unwrap().identifier.name;
-                let traits = self.search_for_traits_containing_method(method_name);
-                self.trait_map.insert(expr.id, traits);
-                visit::walk_expr(self, expr);
-            }
-
             ExprPath(ref maybe_qself, ref path) => {
-                let max_assoc_types = if let Some(ref qself) = *maybe_qself {
-                    // Make sure the trait is valid.
-                    let _ = self.resolve_trait_reference(expr.id, path, 1);
-                    path.segments.len() - qself.position
-                } else {
-                    path.segments.len()
-                };
-
-                let mut resolution = self.with_no_errors(|this| {
-                    this.resolve_path(expr.id, path, 0, ValueNS, true)
-                });
-                for depth in 1..max_assoc_types {
-                    if resolution.is_some() {
-                        break;
-                    }
-                    self.with_no_errors(|this| {
-                        resolution = this.resolve_path(expr.id, path, depth, TypeNS, true);
-                    });
-                }
-                if let Some(DefMod(_)) = resolution.map(|r| r.base_def) {
-                    // A module is not a valid type or value.
-                    resolution = None;
-                }
+                let resolution =
+                    match self.resolve_possibly_assoc_item(expr.id,
+                                                           maybe_qself.as_ref(),
+                                                           path,
+                                                           ValueNS,
+                                                           true) {
+                        // `<T>::a::b::c` is resolved by typeck alone.
+                        TypecheckRequired => {
+                            let method_name = path.segments.last().unwrap().identifier.name;
+                            let traits = self.get_traits_containing_item(method_name);
+                            self.trait_map.insert(expr.id, traits);
+                            visit::walk_expr(self, expr);
+                            return;
+                        }
+                        ResolveAttempt(resolution) => resolution,
+                    };
 
                 // This is a local path in the value namespace. Walk through
                 // scopes looking for it.
@@ -3155,7 +3272,7 @@ fn resolve_expr(&mut self, expr: &Expr) {
                         // so they can be completed during typeck.
                         if path_res.depth != 0 {
                             let method_name = path.segments.last().unwrap().identifier.name;
-                            let traits = self.search_for_traits_containing_method(method_name);
+                            let traits = self.get_traits_containing_item(method_name);
                             self.trait_map.insert(expr.id, traits);
                         }
 
@@ -3313,14 +3430,14 @@ fn record_candidate_traits_for_expr_if_necessary(&mut self, expr: &Expr) {
                 // 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.search_for_traits_containing_method(ident.node.name);
+                let traits = self.get_traits_containing_item(ident.node.name);
                 self.trait_map.insert(expr.id, traits);
             }
             ExprMethodCall(ident, _, _) => {
                 debug!("(recording candidate traits for expr) recording \
                         traits for {}",
                        expr.id);
-                let traits = self.search_for_traits_containing_method(ident.node.name);
+                let traits = self.get_traits_containing_item(ident.node.name);
                 self.trait_map.insert(expr.id, traits);
             }
             _ => {
@@ -3329,8 +3446,8 @@ fn record_candidate_traits_for_expr_if_necessary(&mut self, expr: &Expr) {
         }
     }
 
-    fn search_for_traits_containing_method(&mut self, name: Name) -> Vec<DefId> {
-        debug!("(searching for traits containing method) looking for '{}'",
+    fn get_traits_containing_item(&mut self, name: Name) -> Vec<DefId> {
+        debug!("(getting traits containing item) looking for '{}'",
                token::get_name(name));
 
         fn add_trait_info(found_traits: &mut Vec<DefId>,
index b53be98a06cc30198f16c20db0234319c5fde7af..c72072f06965096488b14541ee982668f32c3a7e 100644 (file)
@@ -794,13 +794,21 @@ fn link_natively(sess: &Session, trans: &CrateTranslation, dylib: bool,
     let pname = get_cc_prog(sess);
     let mut cmd = Command::new(&pname[..]);
 
+    let root = sess.target_filesearch(PathKind::Native).get_lib_path();
     cmd.args(&sess.target.target.options.pre_link_args);
+    for obj in &sess.target.target.options.pre_link_objects {
+        cmd.arg(root.join(obj));
+    }
+
     link_args(&mut cmd, sess, dylib, tmpdir.path(),
               trans, obj_filename, out_filename);
-    cmd.args(&sess.target.target.options.post_link_args);
     if !sess.target.target.options.no_compiler_rt {
         cmd.arg("-lcompiler-rt");
     }
+    for obj in &sess.target.target.options.post_link_objects {
+        cmd.arg(root.join(obj));
+    }
+    cmd.args(&sess.target.target.options.post_link_args);
 
     if sess.opts.debugging_opts.print_link_args {
         println!("{:?}", &cmd);
index 57dba30723f9cfeada05c0827494de10bf7160f7..39cfac42011aba8fe8c92d786ca9353c4aa2e15f 100644 (file)
@@ -242,6 +242,7 @@ fn lookup_def_kind(&self, ref_id: NodeId, span: Span) -> Option<recorder::Row> {
             def::DefTrait(_) => Some(recorder::TypeRef),
             def::DefStatic(_, _) |
             def::DefConst(_) |
+            def::DefAssociatedConst(..) |
             def::DefLocal(_) |
             def::DefVariant(_, _, _) |
             def::DefUpvar(..) => Some(recorder::VarRef),
@@ -359,14 +360,10 @@ fn process_method(&mut self, sig: &ast::MethodSig,
         // record the decl for this def (if it has one)
         let decl_id = ty::trait_item_of_item(&self.analysis.ty_cx,
                                              ast_util::local_def(id))
-            .and_then(|def_id| {
-                if match def_id {
-                    ty::MethodTraitItemId(def_id) => {
-                        def_id.node != 0 && def_id != ast_util::local_def(id)
-                    }
-                    ty::TypeTraitItemId(_) => false,
-                } {
-                    Some(def_id.def_id())
+            .and_then(|new_id| {
+                let def_id = new_id.def_id();
+                if def_id.node != 0 && def_id != ast_util::local_def(id) {
+                    Some(def_id)
                 } else {
                     None
                 }
@@ -542,25 +539,27 @@ fn process_static(&mut self,
     }
 
     fn process_const(&mut self,
-                      item: &ast::Item,
-                      typ: &ast::Ty,
-                      expr: &ast::Expr)
+                     id: ast::NodeId,
+                     ident: &ast::Ident,
+                     span: Span,
+                     typ: &ast::Ty,
+                     expr: &ast::Expr)
     {
-        let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(item.id));
+        let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(id));
 
-        let sub_span = self.span.sub_span_after_keyword(item.span,
+        let sub_span = self.span.sub_span_after_keyword(span,
                                                         keywords::Const);
-        self.fmt.static_str(item.span,
+        self.fmt.static_str(span,
                             sub_span,
-                            item.id,
-                            &get_ident(item.ident),
+                            id,
+                            &get_ident((*ident).clone()),
                             &qualname[..],
                             "",
                             &ty_to_string(&*typ),
                             self.cur_scope);
 
         // walk type and init value
-        self.visit_ty(&*typ);
+        self.visit_ty(typ);
         self.visit_expr(expr);
     }
 
@@ -800,6 +799,7 @@ fn process_path(&mut self,
             def::DefLocal(..) |
             def::DefStatic(..) |
             def::DefConst(..) |
+            def::DefAssociatedConst(..) |
             def::DefVariant(..) => self.fmt.ref_str(ref_kind.unwrap_or(recorder::VarRef),
                                                     span,
                                                     sub_span,
@@ -883,6 +883,7 @@ fn process_path(&mut self,
             def::DefLocal(_) |
             def::DefStatic(_,_) |
             def::DefConst(..) |
+            def::DefAssociatedConst(..) |
             def::DefStruct(_) |
             def::DefVariant(..) |
             def::DefFn(..) => self.write_sub_paths_truncated(path, false),
@@ -966,7 +967,10 @@ fn process_method_call(&mut self,
                     ty::MethodTraitItem(method) => {
                         method.provided_source.unwrap_or(def_id)
                     }
-                    ty::TypeTraitItem(_) => def_id,
+                    _ => self.sess
+                             .span_bug(ex.span,
+                                       "save::process_method_call: non-method \
+                                        DefId in MethodStatic or MethodStaticClosure"),
                 };
                 (Some(def_id), decl_id)
             }
@@ -1008,7 +1012,7 @@ fn process_pat(&mut self, p:&ast::Pat) {
 
                 let def = self.analysis.ty_cx.def_map.borrow().get(&p.id).unwrap().full_def();
                 let struct_def = match def {
-                    def::DefConst(..) => None,
+                    def::DefConst(..) | def::DefAssociatedConst(..) => None,
                     def::DefVariant(_, variant_id, _) => Some(variant_id),
                     _ => {
                         match ty::ty_to_def_id(ty::node_id_to_type(&self.analysis.ty_cx, p.id)) {
@@ -1040,7 +1044,8 @@ fn process_pat(&mut self, p:&ast::Pat) {
                     }
                 }
             }
-            ast::PatEnum(ref path, _) => {
+            ast::PatEnum(ref path, _) |
+            ast::PatQPath(_, ref path) => {
                 self.collected_paths.push((p.id, path.clone(), false, recorder::VarRef));
                 visit::walk_pat(self, p);
             }
@@ -1186,7 +1191,7 @@ fn visit_item(&mut self, item: &ast::Item) {
             ast::ItemStatic(ref typ, mt, ref expr) =>
                 self.process_static(item, &**typ, mt, &**expr),
             ast::ItemConst(ref typ, ref expr) =>
-                self.process_const(item, &**typ, &**expr),
+                self.process_const(item.id, &item.ident, item.span, &*typ, &*expr),
             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(_, _,
@@ -1236,16 +1241,25 @@ fn visit_generics(&mut self, generics: &ast::Generics) {
 
     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);
+            }
             ast::MethodTraitItem(ref sig, ref body) => {
                 self.process_method(sig, body.as_ref().map(|x| &**x),
                                     trait_item.id, trait_item.ident.name, trait_item.span);
             }
+            ast::ConstTraitItem(_, None) |
             ast::TypeTraitItem(..) => {}
         }
     }
 
     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);
+            }
             ast::MethodImplItem(ref sig, ref body) => {
                 self.process_method(sig, Some(body), impl_item.id,
                                     impl_item.ident.name, impl_item.span);
@@ -1432,8 +1446,9 @@ fn visit_arm(&mut self, arm: &ast::Arm) {
                     paths_to_process.push((id, p.clone(), Some(ref_kind)))
                 }
                 // FIXME(nrc) what are these doing here?
-                def::DefStatic(_, _) => {}
-                def::DefConst(..) => {}
+                def::DefStatic(_, _) |
+                def::DefConst(..) |
+                def::DefAssociatedConst(..) => {}
                 _ => error!("unexpected definition kind when processing collected paths: {:?}",
                             def)
             }
index 744ec5a616841eae4706f156b00f2ba5514725d6..060dde02c2d12269b38fb724153f363f24ac3759 100644 (file)
@@ -916,8 +916,8 @@ fn insert_lllocals<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
 
         let datum = Datum::new(llval, binding_info.ty, Lvalue);
         if let Some(cs) = cs {
-            bcx.fcx.schedule_drop_and_zero_mem(cs, llval, binding_info.ty);
             bcx.fcx.schedule_lifetime_end(cs, binding_info.llmatch);
+            bcx.fcx.schedule_drop_and_fill_mem(cs, llval, binding_info.ty);
         }
 
         debug!("binding {} to {}", binding_info.id, bcx.val_to_string(llval));
@@ -1809,7 +1809,8 @@ fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         ast::PatMac(..) => {
             bcx.sess().span_bug(pat.span, "unexpanded macro");
         }
-        ast::PatWild(_) | ast::PatLit(_) | ast::PatRange(_, _) => ()
+        ast::PatQPath(..) | ast::PatWild(_) | ast::PatLit(_) |
+        ast::PatRange(_, _) => ()
     }
     return bcx;
 }
index e2827eeae15d0bbb0cf17ae56fa57d6e4b8fc82f..cecf35001c4eb00097b85afead452b719da981d7 100644 (file)
@@ -414,6 +414,10 @@ fn find_discr_field_candidate<'tcx>(tcx: &ty::ctxt<'tcx>,
             assert_eq!(nonzero_fields.len(), 1);
             let nonzero_field = ty::lookup_field_type(tcx, did, nonzero_fields[0].id, substs);
             match nonzero_field.sty {
+                ty::ty_ptr(ty::mt { ty, .. }) if !type_is_sized(tcx, ty) => {
+                    path.push_all(&[0, FAT_PTR_ADDR]);
+                    Some(path)
+                },
                 ty::ty_ptr(..) | ty::ty_int(..) | ty::ty_uint(..) => {
                     path.push(0);
                     Some(path)
@@ -767,6 +771,7 @@ pub fn trans_switch<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             (_match::Switch, Some(trans_get_discr(bcx, r, scrutinee, None)))
         }
         Univariant(..) => {
+            // N.B.: Univariant means <= 1 enum variants (*not* == 1 variants).
             (_match::Single, None)
         }
     }
@@ -1058,7 +1063,7 @@ pub fn trans_drop_flag_ptr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, r: &Repr<'tcx
             ));
             bcx = fold_variants(bcx, r, val, |variant_cx, st, value| {
                 let ptr = struct_field_ptr(variant_cx, st, value, (st.fields.len() - 1), false);
-                datum::Datum::new(ptr, ptr_ty, datum::Rvalue::new(datum::ByRef))
+                datum::Datum::new(ptr, ptr_ty, datum::Lvalue)
                     .store_to(variant_cx, scratch.val)
             });
             let expr_datum = scratch.to_expr_datum();
index 59f3ff72602616f0dfe246234a55fd94f501b385..1e5b4d4d5ff333f26491585e5fb2cec52bc4d6bc 100644 (file)
@@ -471,8 +471,11 @@ fn iter_variant<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>,
 
           match adt::trans_switch(cx, &*repr, av) {
               (_match::Single, None) => {
-                  cx = iter_variant(cx, &*repr, av, &*(*variants)[0],
-                                    substs, &mut f);
+                  if n_variants != 0 {
+                      assert!(n_variants == 1);
+                      cx = iter_variant(cx, &*repr, av, &*(*variants)[0],
+                                        substs, &mut f);
+                  }
               }
               (_match::Switch, Some(lldiscrim_a)) => {
                   cx = f(cx, lldiscrim_a, cx.tcx().types.isize);
@@ -1078,25 +1081,17 @@ fn build_cfg(tcx: &ty::ctxt, id: ast::NodeId) -> (ast::NodeId, Option<cfg::CFG>)
         Some(ast_map::NodeTraitItem(trait_item)) => {
             match trait_item.node {
                 ast::MethodTraitItem(_, Some(ref body)) => body,
-                ast::MethodTraitItem(_, None) => {
-                    tcx.sess.bug("unexpected variant: required trait method \
-                                  in has_nested_returns")
-                }
-                ast::TypeTraitItem(..) => {
-                    tcx.sess.bug("unexpected variant: associated type trait item in \
-                                  has_nested_returns")
+                _ => {
+                    tcx.sess.bug("unexpected variant: trait item other than a \
+                                  provided method in has_nested_returns")
                 }
             }
         }
         Some(ast_map::NodeImplItem(impl_item)) => {
             match impl_item.node {
                 ast::MethodImplItem(_, ref body) => body,
-                ast::TypeImplItem(_) => {
-                    tcx.sess.bug("unexpected variant: associated type impl item in \
-                                  has_nested_returns")
-                }
-                ast::MacImplItem(_) => {
-                    tcx.sess.bug("unexpected variant: unexpanded macro impl item in \
+                _ => {
+                    tcx.sess.bug("unexpected variant: non-method impl item in \
                                   has_nested_returns")
                 }
             }
@@ -2363,13 +2358,14 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
         ast_map::NodeTraitItem(trait_item) => {
             debug!("get_item_val(): processing a NodeTraitItem");
             match trait_item.node {
-                ast::MethodTraitItem(_, None) | ast::TypeTraitItem(..) => {
-                    ccx.sess().span_bug(trait_item.span,
-                        "unexpected variant: required trait method in get_item_val()");
-                }
                 ast::MethodTraitItem(_, Some(_)) => {
                     register_method(ccx, id, &trait_item.attrs, trait_item.span)
                 }
+                _ => {
+                    ccx.sess().span_bug(trait_item.span,
+                        "unexpected variant: trait item other than a provided \
+                         method in get_item_val()");
+                }
             }
         }
 
@@ -2378,13 +2374,10 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
                 ast::MethodImplItem(..) => {
                     register_method(ccx, id, &impl_item.attrs, impl_item.span)
                 }
-                ast::TypeImplItem(_) => {
-                    ccx.sess().span_bug(impl_item.span,
-                        "unexpected variant: associated type in get_item_val()")
-                }
-                ast::MacImplItem(_) => {
+                _ => {
                     ccx.sess().span_bug(impl_item.span,
-                        "unexpected variant: unexpanded macro in get_item_val()")
+                        "unexpected variant: non-method impl item in \
+                         get_item_val()");
                 }
             }
         }
index 0e8c33cd93a5b36e36aa126413960af23eb55aec..0e4680723073f50881e8a0b0b0389ea221996d1a 100644 (file)
@@ -202,6 +202,7 @@ fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             }
             def::DefStatic(..) |
             def::DefConst(..) |
+            def::DefAssociatedConst(..) |
             def::DefLocal(..) |
             def::DefUpvar(..) => {
                 datum_callee(bcx, ref_expr)
@@ -465,9 +466,9 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>(
 
                     (true, source_id, new_substs)
                 }
-                ty::TypeTraitItem(_) => {
+                _ => {
                     tcx.sess.bug("trans_fn_ref_with_vtables() tried \
-                                  to translate an associated type?!")
+                                  to translate a non-method?!")
                 }
             }
         }
index 61af5bfaef8dee5db3da83e9ff959fad99ab1963..3ec73ff8eb9de129ffb1b8afe40b9b98556cc570 100644 (file)
@@ -393,19 +393,22 @@ fn schedule_drop_mem(&self,
             must_unwind: common::type_needs_unwind_cleanup(self.ccx, ty),
             val: val,
             ty: ty,
-            zero: false
+            fill_on_drop: false,
+            skip_dtor: false,
         };
 
-        debug!("schedule_drop_mem({:?}, val={}, ty={})",
+        debug!("schedule_drop_mem({:?}, val={}, ty={}) fill_on_drop={} skip_dtor={}",
                cleanup_scope,
                self.ccx.tn().val_to_string(val),
-               ty.repr(self.ccx.tcx()));
+               ty.repr(self.ccx.tcx()),
+               drop.fill_on_drop,
+               drop.skip_dtor);
 
         self.schedule_clean(cleanup_scope, drop as CleanupObj);
     }
 
-    /// Schedules a (deep) drop and zero-ing of `val`, which is a pointer to an instance of `ty`
-    fn schedule_drop_and_zero_mem(&self,
+    /// Schedules a (deep) drop and filling of `val`, which is a pointer to an instance of `ty`
+    fn schedule_drop_and_fill_mem(&self,
                                   cleanup_scope: ScopeId,
                                   val: ValueRef,
                                   ty: Ty<'tcx>) {
@@ -416,14 +419,48 @@ fn schedule_drop_and_zero_mem(&self,
             must_unwind: common::type_needs_unwind_cleanup(self.ccx, ty),
             val: val,
             ty: ty,
-            zero: true
+            fill_on_drop: true,
+            skip_dtor: false,
+        };
+
+        debug!("schedule_drop_and_fill_mem({:?}, val={}, ty={}, fill_on_drop={}, skip_dtor={})",
+               cleanup_scope,
+               self.ccx.tn().val_to_string(val),
+               ty.repr(self.ccx.tcx()),
+               drop.fill_on_drop,
+               drop.skip_dtor);
+
+        self.schedule_clean(cleanup_scope, drop as CleanupObj);
+    }
+
+    /// Issue #23611: Schedules a (deep) drop of the contents of
+    /// `val`, which is a pointer to an instance of struct/enum type
+    /// `ty`. The scheduled code handles extracting the discriminant
+    /// and dropping the contents associated with that variant
+    /// *without* executing any associated drop implementation.
+    fn schedule_drop_enum_contents(&self,
+                                   cleanup_scope: ScopeId,
+                                   val: ValueRef,
+                                   ty: Ty<'tcx>) {
+        // `if` below could be "!contents_needs_drop"; skipping drop
+        // is just an optimization, so sound to be conservative.
+        if !self.type_needs_drop(ty) { return; }
+
+        let drop = box DropValue {
+            is_immediate: false,
+            must_unwind: common::type_needs_unwind_cleanup(self.ccx, ty),
+            val: val,
+            ty: ty,
+            fill_on_drop: false,
+            skip_dtor: true,
         };
 
-        debug!("schedule_drop_and_zero_mem({:?}, val={}, ty={}, zero={})",
+        debug!("schedule_drop_enum_contents({:?}, val={}, ty={}) fill_on_drop={} skip_dtor={}",
                cleanup_scope,
                self.ccx.tn().val_to_string(val),
                ty.repr(self.ccx.tcx()),
-               true);
+               drop.fill_on_drop,
+               drop.skip_dtor);
 
         self.schedule_clean(cleanup_scope, drop as CleanupObj);
     }
@@ -440,13 +477,16 @@ fn schedule_drop_immediate(&self,
             must_unwind: common::type_needs_unwind_cleanup(self.ccx, ty),
             val: val,
             ty: ty,
-            zero: false
+            fill_on_drop: false,
+            skip_dtor: false,
         };
 
-        debug!("schedule_drop_immediate({:?}, val={}, ty={:?})",
+        debug!("schedule_drop_immediate({:?}, val={}, ty={:?}) fill_on_drop={} skip_dtor={}",
                cleanup_scope,
                self.ccx.tn().val_to_string(val),
-               ty.repr(self.ccx.tcx()));
+               ty.repr(self.ccx.tcx()),
+               drop.fill_on_drop,
+               drop.skip_dtor);
 
         self.schedule_clean(cleanup_scope, drop as CleanupObj);
     }
@@ -987,7 +1027,8 @@ pub struct DropValue<'tcx> {
     must_unwind: bool,
     val: ValueRef,
     ty: Ty<'tcx>,
-    zero: bool
+    fill_on_drop: bool,
+    skip_dtor: bool,
 }
 
 impl<'tcx> Cleanup<'tcx> for DropValue<'tcx> {
@@ -1007,13 +1048,18 @@ fn trans<'blk>(&self,
                    bcx: Block<'blk, 'tcx>,
                    debug_loc: DebugLoc)
                    -> Block<'blk, 'tcx> {
-        let _icx = base::push_ctxt("<DropValue as Cleanup>::trans");
+        let skip_dtor = self.skip_dtor;
+        let _icx = if skip_dtor {
+            base::push_ctxt("<DropValue as Cleanup>::trans skip_dtor=true")
+        } else {
+            base::push_ctxt("<DropValue as Cleanup>::trans skip_dtor=false")
+        };
         let bcx = if self.is_immediate {
-            glue::drop_ty_immediate(bcx, self.val, self.ty, debug_loc)
+            glue::drop_ty_immediate(bcx, self.val, self.ty, debug_loc, self.skip_dtor)
         } else {
-            glue::drop_ty(bcx, self.val, self.ty, debug_loc)
+            glue::drop_ty_core(bcx, self.val, self.ty, debug_loc, self.skip_dtor)
         };
-        if self.zero {
+        if self.fill_on_drop {
             base::drop_done_fill_mem(bcx, self.val, self.ty);
         }
         bcx
@@ -1190,10 +1236,14 @@ fn schedule_drop_mem(&self,
                          cleanup_scope: ScopeId,
                          val: ValueRef,
                          ty: Ty<'tcx>);
-    fn schedule_drop_and_zero_mem(&self,
+    fn schedule_drop_and_fill_mem(&self,
                                   cleanup_scope: ScopeId,
                                   val: ValueRef,
                                   ty: Ty<'tcx>);
+    fn schedule_drop_enum_contents(&self,
+                                   cleanup_scope: ScopeId,
+                                   val: ValueRef,
+                                   ty: Ty<'tcx>);
     fn schedule_drop_immediate(&self,
                                cleanup_scope: ScopeId,
                                val: ValueRef,
index 38136b03a214191122270774087afcbf2394333c..9932899ed8f0f64da56f4075ceeb3f6553418892 100644 (file)
@@ -173,13 +173,11 @@ pub fn get_const_expr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                             "cross crate constant could not be inlined");
     }
 
-    let item = ccx.tcx().map.expect_item(def_id.node);
-    if let ast::ItemConst(_, ref expr) = item.node {
-        &**expr
-    } else {
-        ccx.sess().span_bug(ref_expr.span,
-                            &format!("get_const_expr given non-constant item {}",
-                                     item.repr(ccx.tcx())));
+    match const_eval::lookup_const_by_id(ccx.tcx(), def_id, Some(ref_expr.id)) {
+        Some(ref expr) => expr,
+        None => {
+            ccx.sess().span_bug(ref_expr.span, "constant item not found")
+        }
     }
 }
 
@@ -201,7 +199,7 @@ pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         ast::ExprPath(..) => {
             let def = ccx.tcx().def_map.borrow().get(&expr.id).unwrap().full_def();
             match def {
-                def::DefConst(def_id) => {
+                def::DefConst(def_id) | def::DefAssociatedConst(def_id, _) => {
                     if !ccx.tcx().adjustments.borrow().contains_key(&expr.id) {
                         return get_const_val(ccx, def_id, expr);
                     }
@@ -774,7 +772,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                 def::DefFn(..) | def::DefMethod(..) => {
                     expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val
                 }
-                def::DefConst(def_id) => {
+                def::DefConst(def_id) | def::DefAssociatedConst(def_id, _) => {
                     const_deref_ptr(cx, get_const_val(cx, def_id, e))
                 }
                 def::DefVariant(enum_did, variant_did, _) => {
index b8c45d4751ef8894022e26b28a800420b7e17f92..1506e5b266981fc5bd11097bad1f2769cc02ffd2 100644 (file)
@@ -21,6 +21,7 @@
 use trans::common::{ExternMap,BuilderRef_res};
 use trans::debuginfo;
 use trans::declare;
+use trans::glue::DropGlueKind;
 use trans::monomorphize::MonoId;
 use trans::type_::{Type, TypeNames};
 use middle::subst::Substs;
@@ -73,7 +74,7 @@ pub struct SharedCrateContext<'tcx> {
     check_drop_flag_for_sanity: bool,
 
     available_monomorphizations: RefCell<FnvHashSet<String>>,
-    available_drop_glues: RefCell<FnvHashMap<Ty<'tcx>, String>>,
+    available_drop_glues: RefCell<FnvHashMap<DropGlueKind<'tcx>, String>>,
 }
 
 /// The local portion of a `CrateContext`.  There is one `LocalCrateContext`
@@ -89,7 +90,7 @@ pub struct LocalCrateContext<'tcx> {
     item_vals: RefCell<NodeMap<ValueRef>>,
     needs_unwind_cleanup_cache: RefCell<FnvHashMap<Ty<'tcx>, bool>>,
     fn_pointer_shims: RefCell<FnvHashMap<Ty<'tcx>, ValueRef>>,
-    drop_glues: RefCell<FnvHashMap<Ty<'tcx>, ValueRef>>,
+    drop_glues: RefCell<FnvHashMap<DropGlueKind<'tcx>, ValueRef>>,
     /// Track mapping of external ids to local items imported for inlining
     external: RefCell<DefIdMap<Option<ast::NodeId>>>,
     /// Backwards version of the `external` map (inlined items to where they
@@ -574,7 +575,7 @@ pub fn fn_pointer_shims(&self) -> &RefCell<FnvHashMap<Ty<'tcx>, ValueRef>> {
         &self.local.fn_pointer_shims
     }
 
-    pub fn drop_glues<'a>(&'a self) -> &'a RefCell<FnvHashMap<Ty<'tcx>, ValueRef>> {
+    pub fn drop_glues<'a>(&'a self) -> &'a RefCell<FnvHashMap<DropGlueKind<'tcx>, ValueRef>> {
         &self.local.drop_glues
     }
 
@@ -660,7 +661,7 @@ pub fn available_monomorphizations<'a>(&'a self) -> &'a RefCell<FnvHashSet<Strin
         &self.shared.available_monomorphizations
     }
 
-    pub fn available_drop_glues<'a>(&'a self) -> &'a RefCell<FnvHashMap<Ty<'tcx>, String>> {
+    pub fn available_drop_glues(&self) -> &RefCell<FnvHashMap<DropGlueKind<'tcx>, String>> {
         &self.shared.available_drop_glues
     }
 
index 7c769eca74aabe71669823c41cf0febe067acdc4..516ff443dacb94d87514417f7a6a8ff9ad198fd3 100644 (file)
@@ -1314,15 +1314,10 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                      impl_item.span,
                      true)
                 }
-                ast::TypeImplItem(_) => {
-                    cx.sess().span_bug(impl_item.span,
-                                       "create_function_debug_context() \
-                                        called on associated type?!")
-                }
-                ast::MacImplItem(_) => {
+                _ => {
                     cx.sess().span_bug(impl_item.span,
                                        "create_function_debug_context() \
-                                        called on unexpanded macro?!")
+                                        called on non-method impl item?!")
                 }
             }
         }
@@ -3442,6 +3437,10 @@ fn walk_pattern(cx: &CrateContext,
                 }
             }
 
+            ast::PatQPath(..) => {
+                scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
+            }
+
             ast::PatStruct(_, ref field_pats, _) => {
                 scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
 
index f974796e69cadb7462957d30a81cc67f107e010d..652f6ad366aaa09604301d0f2a9c7e282598d70f 100644 (file)
@@ -30,7 +30,6 @@
 use trans::cleanup;
 use trans::cleanup::CleanupMethods;
 use trans::common::*;
-use trans::datum;
 use trans::debuginfo::DebugLoc;
 use trans::declare;
 use trans::expr;
@@ -132,14 +131,26 @@ pub fn get_drop_glue_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 pub fn drop_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                            v: ValueRef,
                            t: Ty<'tcx>,
-                           debug_loc: DebugLoc)
-                           -> Block<'blk, 'tcx> {
+                           debug_loc: DebugLoc) -> Block<'blk, 'tcx> {
+    drop_ty_core(bcx, v, t, debug_loc, false)
+}
+
+pub fn drop_ty_core<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+                                v: ValueRef,
+                                t: Ty<'tcx>,
+                                debug_loc: DebugLoc,
+                                skip_dtor: bool) -> Block<'blk, 'tcx> {
     // NB: v is an *alias* of type t here, not a direct value.
-    debug!("drop_ty(t={})", t.repr(bcx.tcx()));
+    debug!("drop_ty_core(t={}, skip_dtor={})", t.repr(bcx.tcx()), skip_dtor);
     let _icx = push_ctxt("drop_ty");
     if bcx.fcx.type_needs_drop(t) {
         let ccx = bcx.ccx();
-        let glue = get_drop_glue(ccx, t);
+        let g = if skip_dtor {
+            DropGlueKind::TyContents(t)
+        } else {
+            DropGlueKind::Ty(t)
+        };
+        let glue = get_drop_glue_core(ccx, g);
         let glue_type = get_drop_glue_type(ccx, t);
         let ptr = if glue_type != t {
             PointerCast(bcx, v, type_of(ccx, glue_type).ptr_to())
@@ -155,22 +166,64 @@ pub fn drop_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 pub fn drop_ty_immediate<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                      v: ValueRef,
                                      t: Ty<'tcx>,
-                                     debug_loc: DebugLoc)
+                                     debug_loc: DebugLoc,
+                                     skip_dtor: bool)
                                      -> Block<'blk, 'tcx> {
     let _icx = push_ctxt("drop_ty_immediate");
     let vp = alloca(bcx, type_of(bcx.ccx(), t), "");
     store_ty(bcx, v, vp, t);
-    drop_ty(bcx, vp, t, debug_loc)
+    drop_ty_core(bcx, vp, t, debug_loc, skip_dtor)
 }
 
 pub fn get_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> ValueRef {
-    debug!("make drop glue for {}", ppaux::ty_to_string(ccx.tcx(), t));
-    let t = get_drop_glue_type(ccx, t);
-    debug!("drop glue type {}", ppaux::ty_to_string(ccx.tcx(), t));
-    match ccx.drop_glues().borrow().get(&t) {
+    get_drop_glue_core(ccx, DropGlueKind::Ty(t))
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+pub enum DropGlueKind<'tcx> {
+    /// The normal path; runs the dtor, and then recurs on the contents
+    Ty(Ty<'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.
+    TyContents(Ty<'tcx>),
+}
+
+impl<'tcx> DropGlueKind<'tcx> {
+    fn ty(&self) -> Ty<'tcx> {
+        match *self { DropGlueKind::Ty(t) | DropGlueKind::TyContents(t) => t }
+    }
+
+    fn map_ty<F>(&self, mut f: F) -> DropGlueKind<'tcx> where F: FnMut(Ty<'tcx>) -> Ty<'tcx>
+    {
+        match *self {
+            DropGlueKind::Ty(t) => DropGlueKind::Ty(f(t)),
+            DropGlueKind::TyContents(t) => DropGlueKind::TyContents(f(t)),
+        }
+    }
+
+    fn to_string<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> String {
+        let t_str = ppaux::ty_to_string(ccx.tcx(), self.ty());
+        match *self {
+            DropGlueKind::Ty(_) => format!("DropGlueKind::Ty({})", t_str),
+            DropGlueKind::TyContents(_) => format!("DropGlueKind::TyContents({})", t_str),
+        }
+    }
+}
+
+fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                                g: DropGlueKind<'tcx>) -> ValueRef {
+    debug!("make drop glue for {}", g.to_string(ccx));
+    let g = g.map_ty(|t| get_drop_glue_type(ccx, t));
+    debug!("drop glue type {}", g.to_string(ccx));
+    match ccx.drop_glues().borrow().get(&g) {
         Some(&glue) => return glue,
         _ => { }
     }
+    let t = g.ty();
 
     let llty = if type_is_sized(ccx.tcx(), t) {
         type_of(ccx, t).ptr_to()
@@ -182,9 +235,9 @@ pub fn get_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Val
 
     // To avoid infinite recursion, don't `make_drop_glue` until after we've
     // added the entry to the `drop_glues` cache.
-    if let Some(old_sym) = ccx.available_drop_glues().borrow().get(&t) {
+    if let Some(old_sym) = ccx.available_drop_glues().borrow().get(&g) {
         let llfn = declare::declare_cfn(ccx, &old_sym, llfnty, ty::mk_nil(ccx.tcx()));
-        ccx.drop_glues().borrow_mut().insert(t, llfn);
+        ccx.drop_glues().borrow_mut().insert(g, llfn);
         return llfn;
     };
 
@@ -192,7 +245,7 @@ pub fn get_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Val
     let llfn = declare::define_cfn(ccx, &fn_nm, llfnty, ty::mk_nil(ccx.tcx())).unwrap_or_else(||{
        ccx.sess().bug(&format!("symbol `{}` already defined", fn_nm));
     });
-    ccx.available_drop_glues().borrow_mut().insert(t, fn_nm);
+    ccx.available_drop_glues().borrow_mut().insert(g, fn_nm);
 
     let _s = StatRecorder::new(ccx, format!("drop {}", ty_to_short_str(ccx.tcx(), t)));
 
@@ -217,7 +270,7 @@ pub fn get_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Val
     // type, so we don't need to explicitly cast the function parameter.
 
     let llrawptr0 = get_param(llfn, fcx.arg_pos(0) as c_uint);
-    let bcx = make_drop_glue(bcx, llrawptr0, t);
+    let bcx = make_drop_glue(bcx, llrawptr0, g);
     finish_fn(&fcx, bcx, ty::FnConverging(ty::mk_nil(ccx.tcx())), DebugLoc::None);
 
     llfn
@@ -307,88 +360,36 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                  substs: &subst::Substs<'tcx>)
                                  -> Block<'blk, 'tcx>
 {
-    let repr = adt::represent_type(bcx.ccx(), t);
+    debug!("trans_struct_drop t: {}", bcx.ty_to_string(t));
 
     // Find and call the actual destructor
-    let dtor_addr = get_res_dtor(bcx.ccx(), dtor_did, t,
-                                 class_did, substs);
+    let dtor_addr = get_res_dtor(bcx.ccx(), dtor_did, t, class_did, substs);
 
-    // The first argument is the "self" argument for drop
+    // Class dtors have no explicit args, so the params should
+    // just consist of the environment (self).
     let params = unsafe {
         let ty = Type::from_ref(llvm::LLVMTypeOf(dtor_addr));
         ty.element_type().func_params()
     };
+    assert_eq!(params.len(), 1);
 
-    let fty = ty::lookup_item_type(bcx.tcx(), dtor_did).ty.subst(bcx.tcx(), substs);
-    let self_ty = match fty.sty {
-        ty::ty_bare_fn(_, ref f) => {
-            let sig = ty::erase_late_bound_regions(bcx.tcx(), &f.sig);
-            assert!(sig.inputs.len() == 1);
-            sig.inputs[0]
-        }
-        _ => bcx.sess().bug(&format!("Expected function type, found {}",
-                                    bcx.ty_to_string(fty)))
-    };
-
-    let (struct_data, info) = if type_is_sized(bcx.tcx(), t) {
-        (v0, None)
-    } else {
-        let data = GEPi(bcx, v0, &[0, abi::FAT_PTR_ADDR]);
-        let info = GEPi(bcx, v0, &[0, abi::FAT_PTR_EXTRA]);
-        (Load(bcx, data), Some(Load(bcx, info)))
-    };
-
-    adt::fold_variants(bcx, &*repr, struct_data, |variant_cx, st, value| {
-        // Be sure to put all of the fields into a scope so we can use an invoke
-        // instruction to call the user destructor but still call the field
-        // destructors if the user destructor panics.
-        let field_scope = variant_cx.fcx.push_custom_cleanup_scope();
-
-        // Class dtors have no explicit args, so the params should
-        // just consist of the environment (self).
-        assert_eq!(params.len(), 1);
-        let self_arg = if type_is_fat_ptr(bcx.tcx(), self_ty) {
-            // The dtor expects a fat pointer, so make one, even if we have to fake it.
-            let scratch = datum::rvalue_scratch_datum(bcx, t, "__fat_ptr_drop_self");
-            Store(bcx, value, GEPi(bcx, scratch.val, &[0, abi::FAT_PTR_ADDR]));
-            Store(bcx,
-                  // If we just had a thin pointer, make a fat pointer by sticking
-                  // null where we put the unsizing info. This works because t
-                  // is a sized type, so we will only unpack the fat pointer, never
-                  // use the fake info.
-                  info.unwrap_or(C_null(Type::i8p(bcx.ccx()))),
-                  GEPi(bcx, scratch.val, &[0, abi::FAT_PTR_EXTRA]));
-            PointerCast(variant_cx, scratch.val, params[0])
-        } else {
-            PointerCast(variant_cx, value, params[0])
-        };
-        let args = vec!(self_arg);
+    // Be sure to put the contents into a scope so we can use an invoke
+    // instruction to call the user destructor but still call the field
+    // destructors if the user destructor panics.
+    //
+    // FIXME (#14875) panic-in-drop semantics might be unsupported; we
+    // might well consider changing below to more direct code.
+    let contents_scope = bcx.fcx.push_custom_cleanup_scope();
 
-        // Add all the fields as a value which needs to be cleaned at the end of
-        // this scope. Iterate in reverse order so a Drop impl doesn't reverse
-        // the order in which fields get dropped.
-        for (i, &ty) in st.fields.iter().enumerate().rev() {
-            let llfld_a = adt::struct_field_ptr(variant_cx, &*st, value, i, false);
+    // Issue #23611: schedule cleanup of contents, re-inspecting the
+    // discriminant (if any) in case of variant swap in drop code.
+    bcx.fcx.schedule_drop_enum_contents(cleanup::CustomScope(contents_scope), v0, t);
 
-            let val = if type_is_sized(bcx.tcx(), ty) {
-                llfld_a
-            } else {
-                let scratch = datum::rvalue_scratch_datum(bcx, ty, "__fat_ptr_drop_field");
-                Store(bcx, llfld_a, GEPi(bcx, scratch.val, &[0, abi::FAT_PTR_ADDR]));
-                Store(bcx, info.unwrap(), GEPi(bcx, scratch.val, &[0, abi::FAT_PTR_EXTRA]));
-                scratch.val
-            };
-            variant_cx.fcx.schedule_drop_mem(cleanup::CustomScope(field_scope), val, ty);
-        }
-
-        let dtor_ty = ty::mk_ctor_fn(bcx.tcx(),
-                                     class_did,
-                                     &[get_drop_glue_type(bcx.ccx(), t)],
-                                     ty::mk_nil(bcx.tcx()));
-        let (_, variant_cx) = invoke(variant_cx, dtor_addr, &args[..], dtor_ty, DebugLoc::None);
+    let glue_type = get_drop_glue_type(bcx.ccx(), t);
+    let dtor_ty = ty::mk_ctor_fn(bcx.tcx(), class_did, &[glue_type], ty::mk_nil(bcx.tcx()));
+    let (_, bcx) = invoke(bcx, dtor_addr, &[v0], dtor_ty, DebugLoc::None);
 
-        variant_cx.fcx.pop_and_trans_custom_cleanup_scope(variant_cx, field_scope)
-    })
+    bcx.fcx.pop_and_trans_custom_cleanup_scope(bcx, contents_scope)
 }
 
 fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, info: ValueRef)
@@ -454,8 +455,10 @@ fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, info:
     }
 }
 
-fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: Ty<'tcx>)
+fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueKind<'tcx>)
                               -> Block<'blk, 'tcx> {
+    let t = g.ty();
+    let skip_dtor = match g { DropGlueKind::Ty(_) => false, DropGlueKind::TyContents(_) => true };
     // NB: v0 is an *alias* of type t here, not a direct value.
     let _icx = push_ctxt("make_drop_glue");
 
@@ -469,6 +472,10 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: Ty<'tcx>)
 
     match t.sty {
         ty::ty_uniq(content_ty) => {
+            // Support for ty_uniq is built-in and its drop glue is
+            // special. It may move to library and have Drop impl. As
+            // a safe-guard, assert ty_uniq not used with TyContents.
+            assert!(!skip_dtor);
             if !type_is_sized(bcx.tcx(), content_ty) {
                 let llval = GEPi(bcx, v0, &[0, abi::FAT_PTR_ADDR]);
                 let llbox = Load(bcx, llval);
@@ -505,8 +512,8 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: Ty<'tcx>)
         }
         ty::ty_struct(did, substs) | ty::ty_enum(did, substs) => {
             let tcx = bcx.tcx();
-            match ty::ty_dtor(tcx, did) {
-                ty::TraitDtor(dtor, true) => {
+            match (ty::ty_dtor(tcx, did), skip_dtor) {
+                (ty::TraitDtor(dtor, true), false) => {
                     // FIXME(16758) Since the struct is unsized, it is hard to
                     // find the drop flag (which is at the end of the struct).
                     // Lets just ignore the flag and pretend everything will be
@@ -523,16 +530,20 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: Ty<'tcx>)
                         trans_struct_drop(bcx, t, v0, dtor, did, substs)
                     }
                 }
-                ty::TraitDtor(dtor, false) => {
+                (ty::TraitDtor(dtor, false), false) => {
                     trans_struct_drop(bcx, t, v0, dtor, did, substs)
                 }
-                ty::NoDtor => {
+                (ty::NoDtor, _) | (_, true) => {
                     // No dtor? Just the default case
                     iter_structural_ty(bcx, v0, t, |bb, vv, tt| drop_ty(bb, vv, tt, DebugLoc::None))
                 }
             }
         }
         ty::ty_trait(..) => {
+            // No support in vtable for distinguishing destroying with
+            // versus without calling Drop::drop. Assert caller is
+            // okay with always calling the Drop impl, if any.
+            assert!(!skip_dtor);
             let data_ptr = GEPi(bcx, v0, &[0, abi::FAT_PTR_ADDR]);
             let vtable_ptr = Load(bcx, GEPi(bcx, v0, &[0, abi::FAT_PTR_EXTRA]));
             let dtor = Load(bcx, vtable_ptr);
index 2034c6223c13410d0d77b964d1043cda27309b86..3f44bc40f356b7f51362525272d4123adade4c39 100644 (file)
@@ -134,6 +134,14 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: ast::DefId)
 
             ccx.stats().n_inlines.set(ccx.stats().n_inlines.get() + 1);
 
+            // Associated consts already have to be evaluated in `typeck`, so
+            // the logic to do that already exists in `middle`. In order to
+            // reuse that code, it needs to be able to look up the traits for
+            // inlined items.
+            let ty_trait_item = ty::impl_or_trait_item(ccx.tcx(), fn_id).clone();
+            ccx.tcx().impl_or_trait_items.borrow_mut()
+                     .insert(local_def(trait_item.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
             // don't.
index e346fb0d93189a1b52ea245d54a6441b89df82c8..fda931fde6e6c8b14a03acf55092f3ea5cbfdea5 100644 (file)
@@ -74,8 +74,7 @@ pub fn trans_impl(ccx: &CrateContext,
                 ast::MethodImplItem(..) => {
                     visit::walk_impl_item(&mut v, impl_item);
                 }
-                ast::TypeImplItem(_) |
-                ast::MacImplItem(_) => {}
+                _ => {}
             }
         }
         return;
@@ -98,8 +97,7 @@ pub fn trans_impl(ccx: &CrateContext,
                 }
                 visit::walk_impl_item(&mut v, impl_item);
             }
-            ast::TypeImplItem(_) |
-            ast::MacImplItem(_) => {}
+            _ => {}
         }
     }
 }
@@ -336,9 +334,9 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             let impl_did = vtable_impl.impl_def_id;
             let mname = match ty::trait_item(ccx.tcx(), trait_id, n_method) {
                 ty::MethodTraitItem(method) => method.name,
-                ty::TypeTraitItem(_) => {
-                    bcx.tcx().sess.bug("can't monomorphize an associated \
-                                        type")
+                _ => {
+                    bcx.tcx().sess.bug("can't monomorphize a non-method trait \
+                                        item")
                 }
             };
             let mth_id = method_with_name(bcx.ccx(), impl_did, mname);
@@ -579,8 +577,8 @@ pub fn trans_object_shim<'a, 'tcx>(
     // Lookup the type of this method as declared in the trait and apply substitutions.
     let method_ty = match ty::trait_item(tcx, trait_id, method_offset_in_trait) {
         ty::MethodTraitItem(method) => method,
-        ty::TypeTraitItem(_) => {
-            tcx.sess.bug("can't create a method shim for an associated type")
+        _ => {
+            tcx.sess.bug("can't create a method shim for a non-method item")
         }
     };
     let fty = monomorphize::apply_param_substs(tcx, &object_substs, &method_ty.fty);
@@ -789,11 +787,11 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     trait_item_def_ids
         .iter()
 
-        // Filter out the associated types.
+        // Filter out non-method items.
         .filter_map(|item_def_id| {
             match *item_def_id {
                 ty::MethodTraitItemId(def_id) => Some(def_id),
-                ty::TypeTraitItemId(_) => None,
+                _ => None,
             }
         })
 
@@ -806,7 +804,7 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
             let trait_method_type = match ty::impl_or_trait_item(tcx, trait_method_def_id) {
                 ty::MethodTraitItem(m) => m,
-                ty::TypeTraitItem(_) => ccx.sess().bug("should be a method, not assoc type")
+                _ => ccx.sess().bug("should be a method, not other assoc item"),
             };
             let name = trait_method_type.name;
 
@@ -824,7 +822,7 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             let impl_method_def_id = method_with_name(ccx, impl_id, name);
             let impl_method_type = match ty::impl_or_trait_item(tcx, impl_method_def_id) {
                 ty::MethodTraitItem(m) => m,
-                ty::TypeTraitItem(_) => ccx.sess().bug("should be a method, not assoc type")
+                _ => ccx.sess().bug("should be a method, not other assoc item"),
             };
 
             debug!("emit_vtable_methods: impl_method_type={}",
index 1c8d020494fabfa0788d0c053d3ea0a37d38c3bb..03fdd0c45c16ae6aa37d19e01b8673ca26956ed5 100644 (file)
@@ -236,11 +236,9 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                     }
                     d
                 }
-                ast::TypeImplItem(_) => {
-                    ccx.sess().bug("can't monomorphize an associated type")
-                }
-                ast::MacImplItem(_) => {
-                    ccx.sess().bug("can't monomorphize an unexpanded macro")
+                _ => {
+                    ccx.sess().bug(&format!("can't monomorphize a {:?}",
+                                           map_node))
                 }
             }
         }
index 78797d086c677fb65492b919e00aeae89dadbd37..9dbf918ddb5c37a471744700910010bc46bd01f0 100644 (file)
@@ -51,6 +51,7 @@
 use middle::astconv_util::{prim_ty_to_ty, check_path_args, NO_TPS, NO_REGIONS};
 use middle::const_eval;
 use middle::def;
+use middle::implicator::object_region_bounds;
 use middle::resolve_lifetime as rl;
 use middle::privacy::{AllPublic, LastMod};
 use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs};
@@ -2087,39 +2088,6 @@ fn compute_object_lifetime_bound<'tcx>(
     return r;
 }
 
-/// Given an object type like `SomeTrait+Send`, computes the lifetime
-/// bounds that must hold on the elided self type. These are derived
-/// from the declarations of `SomeTrait`, `Send`, and friends -- if
-/// they declare `trait SomeTrait : 'static`, for example, then
-/// `'static` would appear in the list. The hard work is done by
-/// `ty::required_region_bounds`, see that for more information.
-pub fn object_region_bounds<'tcx>(
-    tcx: &ty::ctxt<'tcx>,
-    principal: &ty::PolyTraitRef<'tcx>,
-    others: ty::BuiltinBounds)
-    -> Vec<ty::Region>
-{
-    // Since we don't actually *know* the self type for an object,
-    // this "open(err)" serves as a kind of dummy standin -- basically
-    // a skolemized type.
-    let open_ty = ty::mk_infer(tcx, ty::FreshTy(0));
-
-    // Note that we preserve the overall binding levels here.
-    assert!(!open_ty.has_escaping_regions());
-    let substs = tcx.mk_substs(principal.0.substs.with_self_ty(open_ty));
-    let trait_refs = vec!(ty::Binder(Rc::new(ty::TraitRef::new(principal.0.def_id, substs))));
-
-    let param_bounds = ty::ParamBounds {
-        region_bounds: Vec::new(),
-        builtin_bounds: others,
-        trait_bounds: trait_refs,
-        projection_bounds: Vec::new(), // not relevant to computing region bounds
-    };
-
-    let predicates = ty::predicates(tcx, open_ty, &param_bounds);
-    ty::required_region_bounds(tcx, open_ty, predicates)
-}
-
 pub struct PartitionedBounds<'a> {
     pub builtin_bounds: ty::BuiltinBounds,
     pub trait_bounds: Vec<&'a ast::PolyTraitRef>,
index 0959f9d1b9154e4e2df4dcb30d1424e68b339938..1f4d6cc2fd471b4b8e04539edcb12438dedc6c36 100644 (file)
 use middle::const_eval;
 use middle::def;
 use middle::infer;
-use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding, pat_is_const};
+use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding};
+use middle::pat_util::pat_is_resolved_const;
+use middle::privacy::{AllPublic, LastMod};
 use middle::subst::Substs;
 use middle::ty::{self, Ty};
 use check::{check_expr, check_expr_has_type, check_expr_with_expectation};
 use check::{check_expr_coercable_to_type, demand, FnCtxt, Expectation};
-use check::{instantiate_path, structurally_resolved_type};
+use check::{instantiate_path, resolve_ty_and_def_ufcs, structurally_resolved_type};
 use require_same_types;
 use util::nodemap::FnvHashMap;
 use util::ppaux::Repr;
@@ -118,7 +120,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
             // subtyping doesn't matter here, as the value is some kind of scalar
             demand::eqtype(fcx, pat.span, expected, lhs_ty);
         }
-        ast::PatEnum(..) | ast::PatIdent(..) if pat_is_const(&tcx.def_map, pat) => {
+        ast::PatEnum(..) | ast::PatIdent(..) if pat_is_resolved_const(&tcx.def_map, pat) => {
             let const_did = tcx.def_map.borrow().get(&pat.id).unwrap().def_id();
             let const_scheme = ty::lookup_item_type(tcx, const_did);
             assert!(const_scheme.generics.is_empty());
@@ -181,6 +183,37 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
             let subpats = subpats.as_ref().map(|v| &v[..]);
             check_pat_enum(pcx, pat, path, subpats, expected);
         }
+        ast::PatQPath(ref qself, ref path) => {
+            let self_ty = fcx.to_ty(&qself.ty);
+            let path_res = if let Some(&d) = tcx.def_map.borrow().get(&pat.id) {
+                d
+            } else if qself.position == 0 {
+                def::PathResolution {
+                    // This is just a sentinel for finish_resolving_def_to_ty.
+                    base_def: def::DefMod(ast_util::local_def(ast::CRATE_NODE_ID)),
+                    last_private: LastMod(AllPublic),
+                    depth: path.segments.len()
+                }
+            } else {
+                tcx.sess.span_bug(pat.span,
+                                  &format!("unbound path {}", pat.repr(tcx)))
+            };
+            if let Some((opt_ty, segments, def)) =
+                    resolve_ty_and_def_ufcs(fcx, path_res, Some(self_ty),
+                                            path, pat.span, pat.id) {
+                if check_assoc_item_is_const(pcx, def, pat.span) {
+                    let scheme = ty::lookup_item_type(tcx, def.def_id());
+                    let predicates = ty::lookup_predicates(tcx, def.def_id());
+                    instantiate_path(fcx, segments,
+                                     scheme, &predicates,
+                                     opt_ty, def, pat.span, pat.id);
+                    let const_ty = fcx.node_ty(pat.id);
+                    demand::suptype(fcx, pat.span, expected, const_ty);
+                } else {
+                    fcx.write_error(pat.id)
+                }
+            }
+        }
         ast::PatStruct(ref path, ref fields, etc) => {
             check_pat_struct(pcx, pat, path, fields, etc, expected);
         }
@@ -331,6 +364,21 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
     // subtyping.
 }
 
+fn check_assoc_item_is_const(pcx: &pat_ctxt, def: def::Def, span: Span) -> bool {
+    match def {
+        def::DefAssociatedConst(..) => true,
+        def::DefMethod(..) => {
+            span_err!(pcx.fcx.ccx.tcx.sess, span, E0327,
+                      "associated items in match patterns must be constants");
+            false
+        }
+        _ => {
+            pcx.fcx.ccx.tcx.sess.span_bug(span, "non-associated item in
+                                                 check_assoc_item_is_const");
+        }
+    }
+}
+
 pub fn check_dereferencable<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
                                       span: Span, expected: Ty<'tcx>,
                                       inner: &ast::Pat) -> bool {
@@ -532,7 +580,24 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
     let fcx = pcx.fcx;
     let tcx = pcx.fcx.ccx.tcx;
 
-    let def = tcx.def_map.borrow().get(&pat.id).unwrap().full_def();
+    let path_res = *tcx.def_map.borrow().get(&pat.id).unwrap();
+
+    let (opt_ty, segments, def) = match resolve_ty_and_def_ufcs(fcx, path_res,
+                                                                None, path,
+                                                                pat.span, pat.id) {
+        Some(resolution) => resolution,
+        // Error handling done inside resolve_ty_and_def_ufcs, so if
+        // resolution fails just return.
+        None => {return;}
+    };
+
+    // Items that were partially resolved before should have been resolved to
+    // associated constants (i.e. not methods).
+    if path_res.depth != 0 && !check_assoc_item_is_const(pcx, def, pat.span) {
+        fcx.write_error(pat.id);
+        return;
+    }
+
     let enum_def = def.variant_def_ids()
         .map_or_else(|| def.def_id(), |(enum_def, _)| enum_def);
 
@@ -547,13 +612,23 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
     } else {
         ctor_scheme
     };
-    instantiate_path(pcx.fcx, &path.segments,
+    instantiate_path(pcx.fcx, segments,
                      path_scheme, &ctor_predicates,
-                     None, def, pat.span, pat.id);
+                     opt_ty, def, pat.span, pat.id);
+
+    // If we didn't have a fully resolved path to start with, we had an
+    // associated const, and we should quit now, since the rest of this
+    // function uses checks specific to structs and enums.
+    if path_res.depth != 0 {
+        let pat_ty = fcx.node_ty(pat.id);
+        demand::suptype(fcx, pat.span, expected, pat_ty);
+        return;
+    }
 
     let pat_ty = fcx.node_ty(pat.id);
     demand::eqtype(fcx, pat.span, expected, pat_ty);
 
+
     let real_path_ty = fcx.node_ty(pat.id);
     let (arg_tys, kind_name): (Vec<_>, &'static str) = match real_path_ty.sty {
         ty::ty_enum(enum_def_id, expected_substs)
index 532277d75b2e06af52afc2002fffe37f62957b58..b3267a5be495b4df92f5157913b5ff93bee04b76 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use middle::free_region::FreeRegionMap;
 use middle::infer;
 use middle::traits;
 use middle::ty::{self};
@@ -354,9 +355,19 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
         Ok(_) => {}
     }
 
-    // Finally, resolve all regions. This catches wily misuses of lifetime
-    // parameters.
-    infcx.resolve_regions_and_report_errors(impl_m_body_id);
+    // Finally, resolve all regions. This catches wily misuses of
+    // lifetime parameters. We have to build up a plausible lifetime
+    // environment based on what we find in the trait. We could also
+    // include the obligations derived from the method argument types,
+    // but I don't think it's necessary -- after all, those are still
+    // in effect when type-checking the body, and all the
+    // where-clauses in the header etc should be implied by the trait
+    // anyway, so it shouldn't be needed there either. Anyway, we can
+    // always add more relations later (it's backwards compat).
+    let mut free_regions = FreeRegionMap::new();
+    free_regions.relate_free_regions_from_predicates(tcx, &trait_param_env.caller_bounds);
+
+    infcx.resolve_regions_and_report_errors(&free_regions, impl_m_body_id);
 
     fn check_region_bounds_on_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
                                                 span: Span,
@@ -401,3 +412,85 @@ fn check_region_bounds_on_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
         return true;
     }
 }
+
+pub fn compare_const_impl<'tcx>(tcx: &ty::ctxt<'tcx>,
+                                impl_c: &ty::AssociatedConst<'tcx>,
+                                impl_c_span: Span,
+                                trait_c: &ty::AssociatedConst<'tcx>,
+                                impl_trait_ref: &ty::TraitRef<'tcx>) {
+    debug!("compare_const_impl(impl_trait_ref={})",
+           impl_trait_ref.repr(tcx));
+
+    let infcx = infer::new_infer_ctxt(tcx);
+    let mut fulfillment_cx = traits::FulfillmentContext::new();
+
+    // The below is for the most part highly similar to the procedure
+    // for methods above. It is simpler in many respects, especially
+    // because we shouldn't really have to deal with lifetimes or
+    // predicates. In fact some of this should probably be put into
+    // shared functions because of DRY violations...
+    let trait_to_impl_substs = &impl_trait_ref.substs;
+
+    // Create a parameter environment that represents the implementation's
+    // method.
+    let impl_param_env =
+        ty::ParameterEnvironment::for_item(tcx, impl_c.def_id.node);
+
+    // Create mapping from impl to skolemized.
+    let impl_to_skol_substs = &impl_param_env.free_substs;
+
+    // Create mapping from trait to skolemized.
+    let trait_to_skol_substs =
+        trait_to_impl_substs
+        .subst(tcx, impl_to_skol_substs)
+        .with_method(impl_to_skol_substs.types.get_slice(subst::FnSpace).to_vec(),
+                     impl_to_skol_substs.regions().get_slice(subst::FnSpace).to_vec());
+    debug!("compare_const_impl: trait_to_skol_substs={}",
+           trait_to_skol_substs.repr(tcx));
+
+    // Compute skolemized form of impl and trait const tys.
+    let impl_ty = impl_c.ty.subst(tcx, impl_to_skol_substs);
+    let trait_ty = trait_c.ty.subst(tcx, &trait_to_skol_substs);
+
+    let err = infcx.commit_if_ok(|_| {
+        let origin = infer::Misc(impl_c_span);
+
+        // There is no "body" here, so just pass dummy id.
+        let impl_ty =
+            assoc::normalize_associated_types_in(&infcx,
+                                                 &impl_param_env,
+                                                 &mut fulfillment_cx,
+                                                 impl_c_span,
+                                                 0,
+                                                 &impl_ty);
+        debug!("compare_const_impl: impl_ty={}",
+               impl_ty.repr(tcx));
+
+        let trait_ty =
+            assoc::normalize_associated_types_in(&infcx,
+                                                 &impl_param_env,
+                                                 &mut fulfillment_cx,
+                                                 impl_c_span,
+                                                 0,
+                                                 &trait_ty);
+        debug!("compare_const_impl: trait_ty={}",
+               trait_ty.repr(tcx));
+
+        infer::mk_subty(&infcx, false, origin, impl_ty, trait_ty)
+    });
+
+    match err {
+        Ok(()) => { }
+        Err(terr) => {
+            debug!("checking associated const for compatibility: impl ty {}, trait ty {}",
+                   impl_ty.repr(tcx),
+                   trait_ty.repr(tcx));
+            span_err!(tcx.sess, impl_c_span, E0326,
+                      "implemented const `{}` has an incompatible type for \
+                      trait: {}",
+                      token::get_name(trait_c.name),
+                      ty::type_err_to_str(tcx, &terr));
+            return;
+        }
+    }
+}
index 2f7e0073e1751ad0f99ee08fc7714ee5269749ff..008ba1c6bf83e3a3a9b30b1a3275eb8dee1a5bb5 100644 (file)
@@ -464,9 +464,9 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
                     ty::Predicate::Trait(ty::Binder(ref t_pred)) => {
                         let def_id = t_pred.trait_ref.def_id;
                         match rcx.tcx().lang_items.to_builtin_kind(def_id) {
+                            // Issue 24895: deliberately do not include `BoundCopy` here.
                             Some(ty::BoundSend) |
                             Some(ty::BoundSized) |
-                            Some(ty::BoundCopy) |
                             Some(ty::BoundSync) => false,
                             _ => true,
                         }
diff --git a/src/librustc_typeck/check/implicator.rs b/src/librustc_typeck/check/implicator.rs
deleted file mode 100644 (file)
index a4a18c7..0000000
+++ /dev/null
@@ -1,455 +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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// #![warn(deprecated_mode)]
-
-use astconv::object_region_bounds;
-use middle::infer::{InferCtxt, GenericKind};
-use middle::subst::Substs;
-use middle::traits;
-use middle::ty::{self, ToPolyTraitRef, Ty};
-use middle::ty_fold::{TypeFoldable, TypeFolder};
-
-use std::rc::Rc;
-use syntax::ast;
-use syntax::codemap::Span;
-
-use util::common::ErrorReported;
-use util::nodemap::FnvHashSet;
-use util::ppaux::Repr;
-
-// Helper functions related to manipulating region types.
-
-pub enum Implication<'tcx> {
-    RegionSubRegion(Option<Ty<'tcx>>, ty::Region, ty::Region),
-    RegionSubGeneric(Option<Ty<'tcx>>, ty::Region, GenericKind<'tcx>),
-    RegionSubClosure(Option<Ty<'tcx>>, ty::Region, ast::DefId, &'tcx Substs<'tcx>),
-    Predicate(ast::DefId, ty::Predicate<'tcx>),
-}
-
-struct Implicator<'a, 'tcx: 'a> {
-    infcx: &'a InferCtxt<'a,'tcx>,
-    closure_typer: &'a (ty::ClosureTyper<'tcx>+'a),
-    body_id: ast::NodeId,
-    stack: Vec<(ty::Region, Option<Ty<'tcx>>)>,
-    span: Span,
-    out: Vec<Implication<'tcx>>,
-    visited: FnvHashSet<Ty<'tcx>>,
-}
-
-/// This routine computes the well-formedness constraints that must hold for the type `ty` to
-/// appear in a context with lifetime `outer_region`
-pub fn implications<'a,'tcx>(
-    infcx: &'a InferCtxt<'a,'tcx>,
-    closure_typer: &ty::ClosureTyper<'tcx>,
-    body_id: ast::NodeId,
-    ty: Ty<'tcx>,
-    outer_region: ty::Region,
-    span: Span)
-    -> Vec<Implication<'tcx>>
-{
-    debug!("implications(body_id={}, ty={}, outer_region={})",
-           body_id,
-           ty.repr(closure_typer.tcx()),
-           outer_region.repr(closure_typer.tcx()));
-
-    let mut stack = Vec::new();
-    stack.push((outer_region, None));
-    let mut wf = Implicator { closure_typer: closure_typer,
-                              infcx: infcx,
-                              body_id: body_id,
-                              span: span,
-                              stack: stack,
-                              out: Vec::new(),
-                              visited: FnvHashSet() };
-    wf.accumulate_from_ty(ty);
-    debug!("implications: out={}", wf.out.repr(closure_typer.tcx()));
-    wf.out
-}
-
-impl<'a, 'tcx> Implicator<'a, 'tcx> {
-    fn tcx(&self) -> &'a ty::ctxt<'tcx> {
-        self.infcx.tcx
-    }
-
-    fn accumulate_from_ty(&mut self, ty: Ty<'tcx>) {
-        debug!("accumulate_from_ty(ty={})",
-               ty.repr(self.tcx()));
-
-        // When expanding out associated types, we can visit a cyclic
-        // set of types. Issue #23003.
-        if !self.visited.insert(ty) {
-            return;
-        }
-
-        match ty.sty {
-            ty::ty_bool |
-            ty::ty_char |
-            ty::ty_int(..) |
-            ty::ty_uint(..) |
-            ty::ty_float(..) |
-            ty::ty_bare_fn(..) |
-            ty::ty_err |
-            ty::ty_str => {
-                // No borrowed content reachable here.
-            }
-
-            ty::ty_closure(def_id, substs) => {
-                let &(r_a, opt_ty) = self.stack.last().unwrap();
-                self.out.push(Implication::RegionSubClosure(opt_ty, r_a, def_id, substs));
-            }
-
-            ty::ty_trait(ref t) => {
-                let required_region_bounds =
-                    object_region_bounds(self.tcx(), &t.principal, t.bounds.builtin_bounds);
-                self.accumulate_from_object_ty(ty, t.bounds.region_bound, required_region_bounds)
-            }
-
-            ty::ty_enum(def_id, substs) |
-            ty::ty_struct(def_id, substs) => {
-                let item_scheme = ty::lookup_item_type(self.tcx(), def_id);
-                self.accumulate_from_adt(ty, def_id, &item_scheme.generics, substs)
-            }
-
-            ty::ty_vec(t, _) |
-            ty::ty_ptr(ty::mt { ty: t, .. }) |
-            ty::ty_uniq(t) => {
-                self.accumulate_from_ty(t)
-            }
-
-            ty::ty_rptr(r_b, mt) => {
-                self.accumulate_from_rptr(ty, *r_b, mt.ty);
-            }
-
-            ty::ty_param(p) => {
-                self.push_param_constraint_from_top(p);
-            }
-
-            ty::ty_projection(ref data) => {
-                // `<T as TraitRef<..>>::Name`
-
-                self.push_projection_constraint_from_top(data);
-            }
-
-            ty::ty_tup(ref tuptys) => {
-                for &tupty in tuptys {
-                    self.accumulate_from_ty(tupty);
-                }
-            }
-
-            ty::ty_infer(_) => {
-                // This should not happen, BUT:
-                //
-                //   Currently we uncover region relationships on
-                //   entering the fn check. We should do this after
-                //   the fn check, then we can call this case a bug().
-            }
-        }
-    }
-
-    fn accumulate_from_rptr(&mut self,
-                            ty: Ty<'tcx>,
-                            r_b: ty::Region,
-                            ty_b: Ty<'tcx>) {
-        // We are walking down a type like this, and current
-        // position is indicated by caret:
-        //
-        //     &'a &'b ty_b
-        //         ^
-        //
-        // At this point, top of stack will be `'a`. We must
-        // require that `'a <= 'b`.
-
-        self.push_region_constraint_from_top(r_b);
-
-        // Now we push `'b` onto the stack, because it must
-        // constrain any borrowed content we find within `T`.
-
-        self.stack.push((r_b, Some(ty)));
-        self.accumulate_from_ty(ty_b);
-        self.stack.pop().unwrap();
-    }
-
-    /// Pushes a constraint that `r_b` must outlive the top region on the stack.
-    fn push_region_constraint_from_top(&mut self,
-                                       r_b: ty::Region) {
-
-        // Indicates that we have found borrowed content with a lifetime
-        // of at least `r_b`. This adds a constraint that `r_b` must
-        // outlive the region `r_a` on top of the stack.
-        //
-        // As an example, imagine walking a type like:
-        //
-        //     &'a &'b T
-        //         ^
-        //
-        // when we hit the inner pointer (indicated by caret), `'a` will
-        // be on top of stack and `'b` will be the lifetime of the content
-        // we just found. So we add constraint that `'a <= 'b`.
-
-        let &(r_a, opt_ty) = self.stack.last().unwrap();
-        self.push_sub_region_constraint(opt_ty, r_a, r_b);
-    }
-
-    /// Pushes a constraint that `r_a <= r_b`, due to `opt_ty`
-    fn push_sub_region_constraint(&mut self,
-                                  opt_ty: Option<Ty<'tcx>>,
-                                  r_a: ty::Region,
-                                  r_b: ty::Region) {
-        self.out.push(Implication::RegionSubRegion(opt_ty, r_a, r_b));
-    }
-
-    /// Pushes a constraint that `param_ty` must outlive the top region on the stack.
-    fn push_param_constraint_from_top(&mut self,
-                                      param_ty: ty::ParamTy) {
-        let &(region, opt_ty) = self.stack.last().unwrap();
-        self.push_param_constraint(region, opt_ty, param_ty);
-    }
-
-    /// Pushes a constraint that `projection_ty` must outlive the top region on the stack.
-    fn push_projection_constraint_from_top(&mut self,
-                                           projection_ty: &ty::ProjectionTy<'tcx>) {
-        let &(region, opt_ty) = self.stack.last().unwrap();
-        self.out.push(Implication::RegionSubGeneric(
-            opt_ty, region, GenericKind::Projection(projection_ty.clone())));
-    }
-
-    /// Pushes a constraint that `region <= param_ty`, due to `opt_ty`
-    fn push_param_constraint(&mut self,
-                             region: ty::Region,
-                             opt_ty: Option<Ty<'tcx>>,
-                             param_ty: ty::ParamTy) {
-        self.out.push(Implication::RegionSubGeneric(
-            opt_ty, region, GenericKind::Param(param_ty)));
-    }
-
-    fn accumulate_from_adt(&mut self,
-                           ty: Ty<'tcx>,
-                           def_id: ast::DefId,
-                           _generics: &ty::Generics<'tcx>,
-                           substs: &Substs<'tcx>)
-    {
-        let predicates =
-            ty::lookup_predicates(self.tcx(), def_id).instantiate(self.tcx(), substs);
-        let predicates = match self.fully_normalize(&predicates) {
-            Ok(predicates) => predicates,
-            Err(ErrorReported) => { return; }
-        };
-
-        for predicate in predicates.predicates.as_slice() {
-            match *predicate {
-                ty::Predicate::Trait(ref data) => {
-                    self.accumulate_from_assoc_types_transitive(data);
-                }
-                ty::Predicate::Equate(..) => { }
-                ty::Predicate::Projection(..) => { }
-                ty::Predicate::RegionOutlives(ref data) => {
-                    match ty::no_late_bound_regions(self.tcx(), data) {
-                        None => { }
-                        Some(ty::OutlivesPredicate(r_a, r_b)) => {
-                            self.push_sub_region_constraint(Some(ty), r_b, r_a);
-                        }
-                    }
-                }
-                ty::Predicate::TypeOutlives(ref data) => {
-                    match ty::no_late_bound_regions(self.tcx(), data) {
-                        None => { }
-                        Some(ty::OutlivesPredicate(ty_a, r_b)) => {
-                            self.stack.push((r_b, Some(ty)));
-                            self.accumulate_from_ty(ty_a);
-                            self.stack.pop().unwrap();
-                        }
-                    }
-                }
-            }
-        }
-
-        let obligations = predicates.predicates
-                                    .into_iter()
-                                    .map(|pred| Implication::Predicate(def_id, pred));
-        self.out.extend(obligations);
-
-        let variances = ty::item_variances(self.tcx(), def_id);
-
-        for (&region, &variance) in substs.regions().iter().zip(variances.regions.iter()) {
-            match variance {
-                ty::Contravariant | ty::Invariant => {
-                    // If any data with this lifetime is reachable
-                    // within, it must be at least contravariant.
-                    self.push_region_constraint_from_top(region)
-                }
-                ty::Covariant | ty::Bivariant => { }
-            }
-        }
-
-        for (&ty, &variance) in substs.types.iter().zip(variances.types.iter()) {
-            match variance {
-                ty::Covariant | ty::Invariant => {
-                    // If any data of this type is reachable within,
-                    // it must be at least covariant.
-                    self.accumulate_from_ty(ty);
-                }
-                ty::Contravariant | ty::Bivariant => { }
-            }
-        }
-    }
-
-    /// Given that there is a requirement that `Foo<X> : 'a`, where
-    /// `Foo` is declared like `struct Foo<T> where T : SomeTrait`,
-    /// this code finds all the associated types defined in
-    /// `SomeTrait` (and supertraits) and adds a requirement that `<X
-    /// as SomeTrait>::N : 'a` (where `N` is some associated type
-    /// defined in `SomeTrait`). This rule only applies to
-    /// trait-bounds that are not higher-ranked, because we cannot
-    /// project out of a HRTB. This rule helps code using associated
-    /// types to compile, see Issue #22246 for an example.
-    fn accumulate_from_assoc_types_transitive(&mut self,
-                                              data: &ty::PolyTraitPredicate<'tcx>)
-    {
-        debug!("accumulate_from_assoc_types_transitive({})",
-               data.repr(self.tcx()));
-
-        for poly_trait_ref in traits::supertraits(self.tcx(), data.to_poly_trait_ref()) {
-            match ty::no_late_bound_regions(self.tcx(), &poly_trait_ref) {
-                Some(trait_ref) => { self.accumulate_from_assoc_types(trait_ref); }
-                None => { }
-            }
-        }
-    }
-
-    fn accumulate_from_assoc_types(&mut self,
-                                   trait_ref: Rc<ty::TraitRef<'tcx>>)
-    {
-        debug!("accumulate_from_assoc_types({})",
-               trait_ref.repr(self.tcx()));
-
-        let trait_def_id = trait_ref.def_id;
-        let trait_def = ty::lookup_trait_def(self.tcx(), trait_def_id);
-        let assoc_type_projections: Vec<_> =
-            trait_def.associated_type_names
-                     .iter()
-                     .map(|&name| ty::mk_projection(self.tcx(), trait_ref.clone(), name))
-                     .collect();
-        debug!("accumulate_from_assoc_types: assoc_type_projections={}",
-               assoc_type_projections.repr(self.tcx()));
-        let tys = match self.fully_normalize(&assoc_type_projections) {
-            Ok(tys) => { tys }
-            Err(ErrorReported) => { return; }
-        };
-        for ty in tys {
-            self.accumulate_from_ty(ty);
-        }
-    }
-
-    fn accumulate_from_object_ty(&mut self,
-                                 ty: Ty<'tcx>,
-                                 region_bound: ty::Region,
-                                 required_region_bounds: Vec<ty::Region>)
-    {
-        // Imagine a type like this:
-        //
-        //     trait Foo { }
-        //     trait Bar<'c> : 'c { }
-        //
-        //     &'b (Foo+'c+Bar<'d>)
-        //         ^
-        //
-        // In this case, the following relationships must hold:
-        //
-        //     'b <= 'c
-        //     'd <= 'c
-        //
-        // The first conditions is due to the normal region pointer
-        // rules, which say that a reference cannot outlive its
-        // referent.
-        //
-        // The final condition may be a bit surprising. In particular,
-        // you may expect that it would have been `'c <= 'd`, since
-        // usually lifetimes of outer things are conservative
-        // approximations for inner things. However, it works somewhat
-        // differently with trait objects: here the idea is that if the
-        // user specifies a region bound (`'c`, in this case) it is the
-        // "master bound" that *implies* that bounds from other traits are
-        // all met. (Remember that *all bounds* in a type like
-        // `Foo+Bar+Zed` must be met, not just one, hence if we write
-        // `Foo<'x>+Bar<'y>`, we know that the type outlives *both* 'x and
-        // 'y.)
-        //
-        // Note: in fact we only permit builtin traits, not `Bar<'d>`, I
-        // am looking forward to the future here.
-
-        // The content of this object type must outlive
-        // `bounds.region_bound`:
-        let r_c = region_bound;
-        self.push_region_constraint_from_top(r_c);
-
-        // And then, in turn, to be well-formed, the
-        // `region_bound` that user specified must imply the
-        // region bounds required from all of the trait types:
-        for &r_d in &required_region_bounds {
-            // Each of these is an instance of the `'c <= 'b`
-            // constraint above
-            self.out.push(Implication::RegionSubRegion(Some(ty), r_d, r_c));
-        }
-    }
-
-    fn fully_normalize<T>(&self, value: &T) -> Result<T,ErrorReported>
-        where T : TypeFoldable<'tcx> + ty::HasProjectionTypes + Clone + Repr<'tcx>
-    {
-        let value =
-            traits::fully_normalize(self.infcx,
-                                    self.closure_typer,
-                                    traits::ObligationCause::misc(self.span, self.body_id),
-                                    value);
-        match value {
-            Ok(value) => Ok(value),
-            Err(errors) => {
-                // I don't like reporting these errors here, but I
-                // don't know where else to report them just now. And
-                // I don't really expect errors to arise here
-                // frequently. I guess the best option would be to
-                // propagate them out.
-                traits::report_fulfillment_errors(self.infcx, &errors);
-                Err(ErrorReported)
-            }
-        }
-    }
-}
-
-impl<'tcx> Repr<'tcx> for Implication<'tcx> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        match *self {
-            Implication::RegionSubRegion(_, ref r_a, ref r_b) => {
-                format!("RegionSubRegion({}, {})",
-                        r_a.repr(tcx),
-                        r_b.repr(tcx))
-            }
-
-            Implication::RegionSubGeneric(_, ref r, ref p) => {
-                format!("RegionSubGeneric({}, {})",
-                        r.repr(tcx),
-                        p.repr(tcx))
-            }
-
-            Implication::RegionSubClosure(_, ref a, ref b, ref c) => {
-                format!("RegionSubClosure({}, {}, {})",
-                        a.repr(tcx),
-                        b.repr(tcx),
-                        c.repr(tcx))
-            }
-
-            Implication::Predicate(ref def_id, ref p) => {
-                format!("Predicate({}, {})",
-                        def_id.repr(tcx),
-                        p.repr(tcx))
-            }
-        }
-    }
-}
index 7eb15a147963477a002de0e89c3443f51ea87ed3..cf1323e71bd0e94806d8ab03db4b9ff273af31db 100644 (file)
@@ -109,10 +109,11 @@ fn confirm(&mut self,
         self.add_obligations(&pick, &all_substs, &method_predicates);
 
         // Create the final `MethodCallee`.
+        let method_ty = pick.item.as_opt_method().unwrap();
         let fty = ty::mk_bare_fn(self.tcx(), None, self.tcx().mk_bare_fn(ty::BareFnTy {
             sig: ty::Binder(method_sig),
-            unsafety: pick.method_ty.fty.unsafety,
-            abi: pick.method_ty.fty.abi.clone(),
+            unsafety: method_ty.fty.unsafety,
+            abi: method_ty.fty.abi.clone(),
         }));
         let callee = MethodCallee {
             origin: method_origin,
@@ -204,7 +205,7 @@ fn fresh_receiver_substs(&mut self,
                         "impl {:?} is not an inherent impl", impl_def_id);
                 let impl_polytype = check::impl_self_ty(self.fcx, self.span, impl_def_id);
 
-                (impl_polytype.substs, MethodStatic(pick.method_ty.def_id))
+                (impl_polytype.substs, MethodStatic(pick.item.def_id()))
             }
 
             probe::ObjectPick(trait_def_id, method_num, vtable_index) => {
@@ -336,7 +337,8 @@ fn instantiate_method_substs(&mut self,
         // If they were not explicitly supplied, just construct fresh
         // variables.
         let num_supplied_types = supplied_method_types.len();
-        let num_method_types = pick.method_ty.generics.types.len(subst::FnSpace);
+        let num_method_types = pick.item.as_opt_method().unwrap()
+                                   .generics.types.len(subst::FnSpace);
         let method_types = {
             if num_supplied_types == 0 {
                 self.fcx.infcx().next_ty_vars(num_method_types)
@@ -360,7 +362,8 @@ fn instantiate_method_substs(&mut self,
         let method_regions =
             self.fcx.infcx().region_vars_for_defs(
                 self.span,
-                pick.method_ty.generics.regions.get_slice(subst::FnSpace));
+                pick.item.as_opt_method().unwrap()
+                    .generics.regions.get_slice(subst::FnSpace));
 
         (method_types, method_regions)
     }
@@ -397,7 +400,8 @@ fn instantiate_method_sig(&mut self,
         // Instantiate the bounds on the method with the
         // type/early-bound-regions substitutions performed. There can
         // be no late-bound regions appearing here.
-        let method_predicates = pick.method_ty.predicates.instantiate(self.tcx(), &all_substs);
+        let method_predicates = pick.item.as_opt_method().unwrap()
+                                    .predicates.instantiate(self.tcx(), &all_substs);
         let method_predicates = self.fcx.normalize_associated_types_in(self.span,
                                                                        &method_predicates);
 
@@ -410,7 +414,8 @@ fn instantiate_method_sig(&mut self,
         // NB: Instantiate late-bound regions first so that
         // `instantiate_type_scheme` can normalize associated types that
         // may reference those regions.
-        let method_sig = self.replace_late_bound_regions_with_fresh_var(&pick.method_ty.fty.sig);
+        let method_sig = self.replace_late_bound_regions_with_fresh_var(
+            &pick.item.as_opt_method().unwrap().fty.sig);
         debug!("late-bound lifetimes from method instantiated, method_sig={}",
                method_sig.repr(self.tcx()));
 
@@ -616,7 +621,7 @@ fn infcx(&self) -> &'a InferCtxt<'a, 'tcx> {
 
     fn enforce_illegal_method_limitations(&self, pick: &probe::Pick) {
         // Disallow calls to the method `drop` defined in the `Drop` trait.
-        match pick.method_ty.container {
+        match pick.item.container() {
             ty::TraitContainer(trait_def_id) => {
                 callee::check_legal_trait_for_method_call(self.fcx.ccx, self.span, trait_def_id)
             }
@@ -625,7 +630,7 @@ fn enforce_illegal_method_limitations(&self, pick: &probe::Pick) {
                 // potential calls to it will wind up in the other
                 // arm. But just to be sure, check that the method id
                 // does not appear in the list of destructors.
-                assert!(!self.tcx().destructors.borrow().contains(&pick.method_ty.def_id));
+                assert!(!self.tcx().destructors.borrow().contains(&pick.item.def_id()));
             }
         }
     }
index f1a4dbf7cd52881c7ceb1d88463f0161c51cccbc..c5d8e2758ba5c6a9c3538538862bc261c6646470 100644 (file)
@@ -58,7 +58,7 @@ pub enum CandidateSource {
     TraitSource(/* trait id */ ast::DefId),
 }
 
-type MethodIndex = usize; // just for doc purposes
+type ItemIndex = usize; // just for doc purposes
 
 /// Determines whether the type `self_ty` supports a method name `method_name` or not.
 pub fn exists<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
@@ -312,18 +312,25 @@ pub fn resolve_ufcs<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 {
     let mode = probe::Mode::Path;
     let pick = try!(probe::probe(fcx, span, mode, method_name, self_ty, expr_id));
-    let def_id = pick.method_ty.def_id;
+    let def_id = pick.item.def_id();
     let mut lp = LastMod(AllPublic);
     let provenance = match pick.kind {
         probe::InherentImplPick(impl_def_id) => {
-            if pick.method_ty.vis != ast::Public {
+            if pick.item.vis() != ast::Public {
                 lp = LastMod(DependsOn(def_id));
             }
             def::FromImpl(impl_def_id)
         }
-        _ => def::FromTrait(pick.method_ty.container.id())
+        _ => def::FromTrait(pick.item.container().id())
     };
-    Ok((def::DefMethod(def_id, provenance), lp))
+    let def_result = match pick.item {
+        ImplOrTraitItem::MethodTraitItem(..) => def::DefMethod(def_id, provenance),
+        ImplOrTraitItem::ConstTraitItem(..) => def::DefAssociatedConst(def_id, provenance),
+        ImplOrTraitItem::TypeTraitItem(..) => {
+            fcx.tcx().sess.span_bug(span, "resolve_ufcs: probe picked associated type");
+        }
+    };
+    Ok((def_result, lp))
 }
 
 
index 08e2f47c5a67583157ff010c4b7204247cedad51..7ff1355184b56ade0e49fc903c3b849dc06e7cdb 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use super::MethodError;
-use super::MethodIndex;
+use super::ItemIndex;
 use super::{CandidateSource,ImplSource,TraitSource};
 use super::suggest;
 
@@ -37,7 +37,7 @@ struct ProbeContext<'a, 'tcx:'a> {
     fcx: &'a FnCtxt<'a, 'tcx>,
     span: Span,
     mode: Mode,
-    method_name: ast::Name,
+    item_name: ast::Name,
     steps: Rc<Vec<CandidateStep<'tcx>>>,
     opt_simplified_steps: Option<Vec<fast_reject::SimplifiedType>>,
     inherent_candidates: Vec<Candidate<'tcx>>,
@@ -54,7 +54,7 @@ struct CandidateStep<'tcx> {
 
 struct Candidate<'tcx> {
     xform_self_ty: Ty<'tcx>,
-    method_ty: Rc<ty::Method<'tcx>>,
+    item: ty::ImplOrTraitItem<'tcx>,
     kind: CandidateKind<'tcx>,
 }
 
@@ -62,14 +62,14 @@ enum CandidateKind<'tcx> {
     InherentImplCandidate(/* Impl */ ast::DefId, subst::Substs<'tcx>),
     ObjectCandidate(/* Trait */ ast::DefId, /* method_num */ usize, /* vtable index */ usize),
     ExtensionImplCandidate(/* Impl */ ast::DefId, Rc<ty::TraitRef<'tcx>>,
-                           subst::Substs<'tcx>, MethodIndex),
-    ClosureCandidate(/* Trait */ ast::DefId, MethodIndex),
-    WhereClauseCandidate(ty::PolyTraitRef<'tcx>, MethodIndex),
-    ProjectionCandidate(ast::DefId, MethodIndex),
+                           subst::Substs<'tcx>, ItemIndex),
+    ClosureCandidate(/* Trait */ ast::DefId, ItemIndex),
+    WhereClauseCandidate(ty::PolyTraitRef<'tcx>, ItemIndex),
+    ProjectionCandidate(ast::DefId, ItemIndex),
 }
 
 pub struct Pick<'tcx> {
-    pub method_ty: Rc<ty::Method<'tcx>>,
+    pub item: ty::ImplOrTraitItem<'tcx>,
     pub kind: PickKind<'tcx>,
 
     // Indicates that the source expression should be autoderef'd N times
@@ -94,20 +94,20 @@ pub struct Pick<'tcx> {
 pub enum PickKind<'tcx> {
     InherentImplPick(/* Impl */ ast::DefId),
     ObjectPick(/* Trait */ ast::DefId, /* method_num */ usize, /* real_index */ usize),
-    ExtensionImplPick(/* Impl */ ast::DefId, MethodIndex),
-    TraitPick(/* Trait */ ast::DefId, MethodIndex),
-    WhereClausePick(/* Trait */ ty::PolyTraitRef<'tcx>, MethodIndex),
+    ExtensionImplPick(/* Impl */ ast::DefId, ItemIndex),
+    TraitPick(/* Trait */ ast::DefId, ItemIndex),
+    WhereClausePick(/* Trait */ ty::PolyTraitRef<'tcx>, ItemIndex),
 }
 
 pub type PickResult<'tcx> = Result<Pick<'tcx>, MethodError>;
 
-#[derive(PartialEq, Eq, Copy, Clone)]
+#[derive(PartialEq, Eq, Copy, Clone, Debug)]
 pub enum Mode {
     // An expression of the form `receiver.method_name(...)`.
     // Autoderefs are performed on `receiver`, lookup is done based on the
     // `self` argument  of the method, and static methods aren't considered.
     MethodCall,
-    // An expression of the form `Type::method` or `<T>::method`.
+    // An expression of the form `Type::item` or `<T>::item`.
     // No autoderefs are performed, lookup is done based on the type each
     // implementation is for, and static methods are included.
     Path
@@ -116,14 +116,14 @@ pub enum Mode {
 pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                        span: Span,
                        mode: Mode,
-                       method_name: ast::Name,
+                       item_name: ast::Name,
                        self_ty: Ty<'tcx>,
                        scope_expr_id: ast::NodeId)
                        -> PickResult<'tcx>
 {
-    debug!("probe(self_ty={}, method_name={}, scope_expr_id={})",
+    debug!("probe(self_ty={}, item_name={}, scope_expr_id={})",
            self_ty.repr(fcx.tcx()),
-           method_name,
+           item_name,
            scope_expr_id);
 
     // FIXME(#18741) -- right now, creating the steps involves evaluating the
@@ -171,7 +171,7 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         let mut probe_cx = ProbeContext::new(fcx,
                                              span,
                                              mode,
-                                             method_name,
+                                             item_name,
                                              steps,
                                              opt_simplified_steps);
         probe_cx.assemble_inherent_candidates();
@@ -221,7 +221,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
     fn new(fcx: &'a FnCtxt<'a,'tcx>,
            span: Span,
            mode: Mode,
-           method_name: ast::Name,
+           item_name: ast::Name,
            steps: Vec<CandidateStep<'tcx>>,
            opt_simplified_steps: Option<Vec<fast_reject::SimplifiedType>>)
            -> ProbeContext<'a,'tcx>
@@ -230,7 +230,7 @@ fn new(fcx: &'a FnCtxt<'a,'tcx>,
             fcx: fcx,
             span: span,
             mode: mode,
-            method_name: method_name,
+            item_name: item_name,
             inherent_candidates: Vec::new(),
             extension_candidates: Vec::new(),
             impl_dups: HashSet::new(),
@@ -387,12 +387,12 @@ fn assemble_inherent_impl_probe(&mut self, impl_def_id: ast::DefId) {
 
         debug!("assemble_inherent_impl_probe {:?}", impl_def_id);
 
-        let method = match impl_method(self.tcx(), impl_def_id, self.method_name) {
+        let item = match impl_item(self.tcx(), impl_def_id, self.item_name) {
             Some(m) => m,
             None => { return; } // No method with correct name on this impl
         };
 
-        if !self.has_applicable_self(&*method) {
+        if !self.has_applicable_self(&item) {
             // No receiver declared. Not a candidate.
             return self.record_static_candidate(ImplSource(impl_def_id));
         }
@@ -402,11 +402,11 @@ fn assemble_inherent_impl_probe(&mut self, impl_def_id: ast::DefId) {
 
         // Determine the receiver type that the method itself expects.
         let xform_self_ty =
-            self.xform_self_ty(&method, impl_ty, &impl_substs);
+            self.xform_self_ty(&item, impl_ty, &impl_substs);
 
         self.inherent_candidates.push(Candidate {
             xform_self_ty: xform_self_ty,
-            method_ty: method,
+            item: item,
             kind: InherentImplCandidate(impl_def_id, impl_substs)
         });
     }
@@ -427,23 +427,23 @@ fn assemble_inherent_candidates_from_object(&mut self,
         // itself. Hence, a `&self` method will wind up with an
         // argument type like `&Trait`.
         let trait_ref = data.principal_trait_ref_with_self_ty(self.tcx(), self_ty);
-        self.elaborate_bounds(&[trait_ref.clone()], |this, new_trait_ref, m, method_num| {
+        self.elaborate_bounds(&[trait_ref.clone()], |this, new_trait_ref, item, item_num| {
             let new_trait_ref = this.erase_late_bound_regions(&new_trait_ref);
 
             let vtable_index =
                 traits::get_vtable_index_of_object_method(tcx,
                                                           trait_ref.clone(),
                                                           new_trait_ref.def_id,
-                                                          method_num);
+                                                          item_num);
 
-            let xform_self_ty = this.xform_self_ty(&m,
+            let xform_self_ty = this.xform_self_ty(&item,
                                                    new_trait_ref.self_ty(),
                                                    new_trait_ref.substs);
 
             this.inherent_candidates.push(Candidate {
                 xform_self_ty: xform_self_ty,
-                method_ty: m,
-                kind: ObjectCandidate(new_trait_ref.def_id, method_num, vtable_index)
+                item: item,
+                kind: ObjectCandidate(new_trait_ref.def_id, item_num, vtable_index)
             });
         });
     }
@@ -476,27 +476,29 @@ fn assemble_inherent_candidates_from_param(&mut self,
             })
             .collect();
 
-        self.elaborate_bounds(&bounds, |this, poly_trait_ref, m, method_num| {
+        self.elaborate_bounds(&bounds, |this, poly_trait_ref, item, item_num| {
             let trait_ref =
                 this.erase_late_bound_regions(&poly_trait_ref);
 
             let xform_self_ty =
-                this.xform_self_ty(&m,
+                this.xform_self_ty(&item,
                                    trait_ref.self_ty(),
                                    trait_ref.substs);
 
-            debug!("found match: trait_ref={} substs={} m={}",
-                   trait_ref.repr(this.tcx()),
-                   trait_ref.substs.repr(this.tcx()),
-                   m.repr(this.tcx()));
-            assert_eq!(m.generics.types.get_slice(subst::TypeSpace).len(),
-                       trait_ref.substs.types.get_slice(subst::TypeSpace).len());
-            assert_eq!(m.generics.regions.get_slice(subst::TypeSpace).len(),
-                       trait_ref.substs.regions().get_slice(subst::TypeSpace).len());
-            assert_eq!(m.generics.types.get_slice(subst::SelfSpace).len(),
-                       trait_ref.substs.types.get_slice(subst::SelfSpace).len());
-            assert_eq!(m.generics.regions.get_slice(subst::SelfSpace).len(),
-                       trait_ref.substs.regions().get_slice(subst::SelfSpace).len());
+            if let Some(ref m) = item.as_opt_method() {
+                debug!("found match: trait_ref={} substs={} m={}",
+                       trait_ref.repr(this.tcx()),
+                       trait_ref.substs.repr(this.tcx()),
+                       m.repr(this.tcx()));
+                assert_eq!(m.generics.types.get_slice(subst::TypeSpace).len(),
+                           trait_ref.substs.types.get_slice(subst::TypeSpace).len());
+                assert_eq!(m.generics.regions.get_slice(subst::TypeSpace).len(),
+                           trait_ref.substs.regions().get_slice(subst::TypeSpace).len());
+                assert_eq!(m.generics.types.get_slice(subst::SelfSpace).len(),
+                           trait_ref.substs.types.get_slice(subst::SelfSpace).len());
+                assert_eq!(m.generics.regions.get_slice(subst::SelfSpace).len(),
+                           trait_ref.substs.regions().get_slice(subst::SelfSpace).len());
+            }
 
             // Because this trait derives from a where-clause, it
             // should not contain any inference variables or other
@@ -507,8 +509,8 @@ fn assemble_inherent_candidates_from_param(&mut self,
 
             this.inherent_candidates.push(Candidate {
                 xform_self_ty: xform_self_ty,
-                method_ty: m,
-                kind: WhereClauseCandidate(poly_trait_ref, method_num)
+                item: item,
+                kind: WhereClauseCandidate(poly_trait_ref, item_num)
             });
         });
     }
@@ -523,7 +525,7 @@ fn elaborate_bounds<F>(
         F: for<'b> FnMut(
             &mut ProbeContext<'b, 'tcx>,
             ty::PolyTraitRef<'tcx>,
-            Rc<ty::Method<'tcx>>,
+            ty::ImplOrTraitItem<'tcx>,
             usize,
         ),
     {
@@ -531,17 +533,17 @@ fn elaborate_bounds<F>(
 
         let tcx = self.tcx();
         for bound_trait_ref in traits::transitive_bounds(tcx, bounds) {
-            let (pos, method) = match trait_method(tcx,
-                                                   bound_trait_ref.def_id(),
-                                                   self.method_name) {
+            let (pos, item) = match trait_item(tcx,
+                                               bound_trait_ref.def_id(),
+                                               self.item_name) {
                 Some(v) => v,
                 None => { continue; }
             };
 
-            if !self.has_applicable_self(&*method) {
+            if !self.has_applicable_self(&item) {
                 self.record_static_candidate(TraitSource(bound_trait_ref.def_id()));
             } else {
-                mk_cand(self, bound_trait_ref, method, pos);
+                mk_cand(self, bound_trait_ref, item, pos);
             }
         }
     }
@@ -584,37 +586,34 @@ fn assemble_extension_candidates_for_trait(&mut self,
             ty::trait_items(self.tcx(), trait_def_id);
         let matching_index =
             trait_items.iter()
-                       .position(|item| item.name() == self.method_name);
+                       .position(|item| item.name() == self.item_name);
         let matching_index = match matching_index {
             Some(i) => i,
             None => { return Ok(()); }
         };
-        let method = match (&*trait_items)[matching_index].as_opt_method() {
-            Some(m) => m,
-            None => { return Ok(()); }
-        };
+        let ref item = (&*trait_items)[matching_index];
 
         // Check whether `trait_def_id` defines a method with suitable name:
-        if !self.has_applicable_self(&*method) {
+        if !self.has_applicable_self(item) {
             debug!("method has inapplicable self");
             self.record_static_candidate(TraitSource(trait_def_id));
             return Ok(());
         }
 
         self.assemble_extension_candidates_for_trait_impls(trait_def_id,
-                                                           method.clone(),
+                                                           item.clone(),
                                                            matching_index);
 
         try!(self.assemble_closure_candidates(trait_def_id,
-                                              method.clone(),
+                                              item.clone(),
                                               matching_index));
 
         self.assemble_projection_candidates(trait_def_id,
-                                            method.clone(),
+                                            item.clone(),
                                             matching_index);
 
         self.assemble_where_clause_candidates(trait_def_id,
-                                              method,
+                                              item.clone(),
                                               matching_index);
 
         Ok(())
@@ -622,8 +621,8 @@ fn assemble_extension_candidates_for_trait(&mut self,
 
     fn assemble_extension_candidates_for_trait_impls(&mut self,
                                                      trait_def_id: ast::DefId,
-                                                     method: Rc<ty::Method<'tcx>>,
-                                                     method_index: usize)
+                                                     item: ty::ImplOrTraitItem<'tcx>,
+                                                     item_index: usize)
     {
         ty::populate_implementations_for_trait_if_necessary(self.tcx(),
                                                             trait_def_id);
@@ -657,7 +656,7 @@ fn assemble_extension_candidates_for_trait_impls(&mut self,
 
             // Determine the receiver type that the method itself expects.
             let xform_self_ty =
-                self.xform_self_ty(&method,
+                self.xform_self_ty(&item,
                                    impl_trait_ref.self_ty(),
                                    impl_trait_ref.substs);
 
@@ -665,8 +664,8 @@ fn assemble_extension_candidates_for_trait_impls(&mut self,
 
             self.extension_candidates.push(Candidate {
                 xform_self_ty: xform_self_ty,
-                method_ty: method.clone(),
-                kind: ExtensionImplCandidate(impl_def_id, impl_trait_ref, impl_substs, method_index)
+                item: item.clone(),
+                kind: ExtensionImplCandidate(impl_def_id, impl_trait_ref, impl_substs, item_index)
             });
         }
     }
@@ -689,8 +688,8 @@ fn impl_can_possibly_match(&self, impl_def_id: ast::DefId) -> bool {
 
     fn assemble_closure_candidates(&mut self,
                                    trait_def_id: ast::DefId,
-                                   method_ty: Rc<ty::Method<'tcx>>,
-                                   method_index: usize)
+                                   item: ty::ImplOrTraitItem<'tcx>,
+                                   item_index: usize)
                                    -> Result<(),MethodError>
     {
         // Check if this is one of the Fn,FnMut,FnOnce traits.
@@ -736,13 +735,13 @@ fn assemble_closure_candidates(&mut self,
                                                              &trait_def.generics,
                                                              step.self_ty);
 
-            let xform_self_ty = self.xform_self_ty(&method_ty,
+            let xform_self_ty = self.xform_self_ty(&item,
                                                    step.self_ty,
                                                    &substs);
             self.inherent_candidates.push(Candidate {
                 xform_self_ty: xform_self_ty,
-                method_ty: method_ty.clone(),
-                kind: ClosureCandidate(trait_def_id, method_index)
+                item: item.clone(),
+                kind: ClosureCandidate(trait_def_id, item_index)
             });
         }
 
@@ -751,16 +750,16 @@ fn assemble_closure_candidates(&mut self,
 
     fn assemble_projection_candidates(&mut self,
                                       trait_def_id: ast::DefId,
-                                      method: Rc<ty::Method<'tcx>>,
-                                      method_index: usize)
+                                      item: ty::ImplOrTraitItem<'tcx>,
+                                      item_index: usize)
     {
         debug!("assemble_projection_candidates(\
                trait_def_id={}, \
-               method={}, \
-               method_index={})",
+               item={}, \
+               item_index={})",
                trait_def_id.repr(self.tcx()),
-               method.repr(self.tcx()),
-               method_index);
+               item.repr(self.tcx()),
+               item_index);
 
         for step in &*self.steps {
             debug!("assemble_projection_candidates: step={}",
@@ -792,7 +791,7 @@ fn assemble_projection_candidates(&mut self,
                        bound.repr(self.tcx()));
 
                 if self.infcx().can_equate(&step.self_ty, &bound.self_ty()).is_ok() {
-                    let xform_self_ty = self.xform_self_ty(&method,
+                    let xform_self_ty = self.xform_self_ty(&item,
                                                            bound.self_ty(),
                                                            bound.substs);
 
@@ -802,8 +801,8 @@ fn assemble_projection_candidates(&mut self,
 
                     self.extension_candidates.push(Candidate {
                         xform_self_ty: xform_self_ty,
-                        method_ty: method.clone(),
-                        kind: ProjectionCandidate(trait_def_id, method_index)
+                        item: item.clone(),
+                        kind: ProjectionCandidate(trait_def_id, item_index)
                     });
                 }
             }
@@ -812,8 +811,8 @@ fn assemble_projection_candidates(&mut self,
 
     fn assemble_where_clause_candidates(&mut self,
                                         trait_def_id: ast::DefId,
-                                        method_ty: Rc<ty::Method<'tcx>>,
-                                        method_index: usize)
+                                        item: ty::ImplOrTraitItem<'tcx>,
+                                        item_index: usize)
     {
         debug!("assemble_where_clause_candidates(trait_def_id={})",
                trait_def_id.repr(self.tcx()));
@@ -824,7 +823,7 @@ fn assemble_where_clause_candidates(&mut self,
                           .filter(|b| b.def_id() == trait_def_id)
         {
             let bound = self.erase_late_bound_regions(&poly_bound);
-            let xform_self_ty = self.xform_self_ty(&method_ty,
+            let xform_self_ty = self.xform_self_ty(&item,
                                                    bound.self_ty(),
                                                    bound.substs);
 
@@ -834,8 +833,8 @@ fn assemble_where_clause_candidates(&mut self,
 
             self.extension_candidates.push(Candidate {
                 xform_self_ty: xform_self_ty,
-                method_ty: method_ty.clone(),
-                kind: WhereClauseCandidate(poly_bound, method_index)
+                item: item.clone(),
+                kind: WhereClauseCandidate(poly_bound, item_index)
             });
         }
     }
@@ -860,7 +859,7 @@ fn pick(mut self) -> PickResult<'tcx> {
         try!(self.assemble_extension_candidates_for_all_traits());
 
         let out_of_scope_traits = match self.pick_core() {
-            Some(Ok(p)) => vec![p.method_ty.container.id()],
+            Some(Ok(p)) => vec![p.item.container().id()],
             Some(Err(MethodError::Ambiguity(v))) => v.into_iter().map(|source| {
                 match source {
                     TraitSource(id) => id,
@@ -1099,11 +1098,11 @@ fn collapse_candidates_to_trait_pick(&self,
         }
 
         // If so, just use this trait and call it a day.
-        let (trait_def_id, method_num) = trait_data;
-        let method_ty = probes[0].method_ty.clone();
+        let (trait_def_id, item_num) = trait_data;
+        let item = probes[0].item.clone();
         Some(Pick {
-            method_ty: method_ty,
-            kind: TraitPick(trait_def_id, method_num),
+            item: item,
+            kind: TraitPick(trait_def_id, item_num),
             autoderefs: 0,
             autoref: None,
             unsize: None
@@ -1117,28 +1116,25 @@ fn make_sub_ty(&self, sub: Ty<'tcx>, sup: Ty<'tcx>) -> infer::UnitResult<'tcx> {
         self.infcx().sub_types(false, infer::Misc(DUMMY_SP), sub, sup)
     }
 
-    fn has_applicable_self(&self, method: &ty::Method) -> bool {
+    fn has_applicable_self(&self, item: &ty::ImplOrTraitItem) -> bool {
         // "fast track" -- check for usage of sugar
-        match method.explicit_self {
-            ty::StaticExplicitSelfCategory => {
-                if self.mode == Mode::Path {
-                    return true;
-                }
-            }
-            ty::ByValueExplicitSelfCategory |
-            ty::ByReferenceExplicitSelfCategory(..) |
-            ty::ByBoxExplicitSelfCategory => {
-                return true;
-            }
+        match *item {
+            ty::ImplOrTraitItem::MethodTraitItem(ref method) =>
+                match method.explicit_self {
+                    ty::StaticExplicitSelfCategory => self.mode == Mode::Path,
+                    ty::ByValueExplicitSelfCategory |
+                    ty::ByReferenceExplicitSelfCategory(..) |
+                    ty::ByBoxExplicitSelfCategory => true,
+                },
+            ty::ImplOrTraitItem::ConstTraitItem(..) => self.mode == Mode::Path,
+            _ => false,
         }
-
         // FIXME -- check for types that deref to `Self`,
         // like `Rc<Self>` and so on.
         //
         // Note also that the current code will break if this type
         // includes any of the type parameters defined on the method
         // -- but this could be overcome.
-        return false;
     }
 
     fn record_static_candidate(&mut self, source: CandidateSource) {
@@ -1146,10 +1142,23 @@ fn record_static_candidate(&mut self, source: CandidateSource) {
     }
 
     fn xform_self_ty(&self,
-                     method: &Rc<ty::Method<'tcx>>,
+                     item: &ty::ImplOrTraitItem<'tcx>,
                      impl_ty: Ty<'tcx>,
                      substs: &subst::Substs<'tcx>)
                      -> Ty<'tcx>
+    {
+        match item.as_opt_method() {
+            Some(ref method) => self.xform_method_self_ty(method, impl_ty,
+                                                          substs),
+            None => impl_ty,
+        }
+    }
+
+    fn xform_method_self_ty(&self,
+                            method: &Rc<ty::Method<'tcx>>,
+                            impl_ty: Ty<'tcx>,
+                            substs: &subst::Substs<'tcx>)
+                            -> Ty<'tcx>
     {
         debug!("xform_self_ty(impl_ty={}, self_ty={}, substs={})",
                impl_ty.repr(self.tcx()),
@@ -1245,46 +1254,45 @@ fn erase_late_bound_regions<T>(&self, value: &ty::Binder<T>) -> T
     }
 }
 
-fn impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
-                     impl_def_id: ast::DefId,
-                     method_name: ast::Name)
-                     -> Option<Rc<ty::Method<'tcx>>>
+fn impl_item<'tcx>(tcx: &ty::ctxt<'tcx>,
+                   impl_def_id: ast::DefId,
+                   item_name: ast::Name)
+                   -> Option<ty::ImplOrTraitItem<'tcx>>
 {
     let impl_items = tcx.impl_items.borrow();
     let impl_items = impl_items.get(&impl_def_id).unwrap();
     impl_items
         .iter()
         .map(|&did| ty::impl_or_trait_item(tcx, did.def_id()))
-        .find(|m| m.name() == method_name)
-        .and_then(|item| item.as_opt_method())
+        .find(|item| item.name() == item_name)
 }
 
-/// Find method with name `method_name` defined in `trait_def_id` and return it, along with its
-/// index (or `None`, if no such method).
-fn trait_method<'tcx>(tcx: &ty::ctxt<'tcx>,
-                      trait_def_id: ast::DefId,
-                      method_name: ast::Name)
-                      -> Option<(usize, Rc<ty::Method<'tcx>>)>
+/// Find item with name `item_name` defined in `trait_def_id` and return it,
+/// along with its index (or `None`, if no such item).
+fn trait_item<'tcx>(tcx: &ty::ctxt<'tcx>,
+                    trait_def_id: ast::DefId,
+                    item_name: ast::Name)
+                    -> Option<(usize, ty::ImplOrTraitItem<'tcx>)>
 {
     let trait_items = ty::trait_items(tcx, trait_def_id);
     debug!("trait_method; items: {:?}", trait_items);
     trait_items
         .iter()
         .enumerate()
-        .find(|&(_, ref item)| item.name() == method_name)
-        .and_then(|(idx, item)| item.as_opt_method().map(|m| (idx, m)))
+        .find(|&(_, ref item)| item.name() == item_name)
+        .map(|(num, ref item)| (num, (*item).clone()))
 }
 
 impl<'tcx> Candidate<'tcx> {
     fn to_unadjusted_pick(&self) -> Pick<'tcx> {
         Pick {
-            method_ty: self.method_ty.clone(),
+            item: self.item.clone(),
             kind: match self.kind {
                 InherentImplCandidate(def_id, _) => {
                     InherentImplPick(def_id)
                 }
-                ObjectCandidate(def_id, method_num, real_index) => {
-                    ObjectPick(def_id, method_num, real_index)
+                ObjectCandidate(def_id, item_num, real_index) => {
+                    ObjectPick(def_id, item_num, real_index)
                 }
                 ExtensionImplCandidate(def_id, _, _, index) => {
                     ExtensionImplPick(def_id, index)
@@ -1323,25 +1331,25 @@ fn to_source(&self) -> CandidateSource {
         }
     }
 
-    fn to_trait_data(&self) -> Option<(ast::DefId,MethodIndex)> {
+    fn to_trait_data(&self) -> Option<(ast::DefId, ItemIndex)> {
         match self.kind {
             InherentImplCandidate(..) => {
                 None
             }
-            ObjectCandidate(trait_def_id, method_num, _) => {
-                Some((trait_def_id, method_num))
+            ObjectCandidate(trait_def_id, item_num, _) => {
+                Some((trait_def_id, item_num))
             }
-            ClosureCandidate(trait_def_id, method_num) => {
-                Some((trait_def_id, method_num))
+            ClosureCandidate(trait_def_id, item_num) => {
+                Some((trait_def_id, item_num))
             }
-            ExtensionImplCandidate(_, ref trait_ref, _, method_num) => {
-                Some((trait_ref.def_id, method_num))
+            ExtensionImplCandidate(_, ref trait_ref, _, item_num) => {
+                Some((trait_ref.def_id, item_num))
             }
-            WhereClauseCandidate(ref trait_ref, method_num) => {
-                Some((trait_ref.def_id(), method_num))
+            WhereClauseCandidate(ref trait_ref, item_num) => {
+                Some((trait_ref.def_id(), item_num))
             }
-            ProjectionCandidate(trait_def_id, method_num) => {
-                Some((trait_def_id, method_num))
+            ProjectionCandidate(trait_def_id, item_num) => {
+                Some((trait_def_id, item_num))
             }
         }
     }
@@ -1392,9 +1400,9 @@ fn repr(&self, _tcx: &ty::ctxt) -> String {
 
 impl<'tcx> Repr<'tcx> for Pick<'tcx> {
     fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        format!("Pick(method_ty={}, autoderefs={},
+        format!("Pick(item={}, autoderefs={},
                  autoref={}, unsize={}, kind={:?})",
-                self.method_ty.repr(tcx),
+                self.item.repr(tcx),
                 self.autoderefs,
                 self.autoref.repr(tcx),
                 self.unsize.repr(tcx),
index a4175fe8325b2c1d703372cc3938826aa1febdab..17658675ee2807bc1a660b4a57cb2cd82a883dac 100644 (file)
@@ -364,7 +364,7 @@ fn handle_external_def(traits: &mut AllTraitsVec,
 }
 
 pub struct AllTraits<'a> {
-    borrow: cell::Ref<'a Option<AllTraitsVec>>,
+    borrow: cell::Ref<'a, Option<AllTraitsVec>>,
     idx: usize
 }
 
index 348846b8ad401400e6b67a81bf247d215e5a7054..f9c78cd36e6ac1d93e3d3093337443363468201f 100644 (file)
@@ -78,7 +78,7 @@
 
 pub use self::LvaluePreference::*;
 pub use self::Expectation::*;
-pub use self::compare_method::compare_impl_method;
+pub use self::compare_method::{compare_impl_method, compare_const_impl};
 use self::TupleArgumentsFlag::*;
 
 use astconv::{self, ast_region_to_region, ast_ty_to_ty, AstConv, PathParamMode};
 pub mod _match;
 pub mod vtable;
 pub mod writeback;
-pub mod implicator;
 pub mod regionck;
 pub mod coercion;
 pub mod demand;
@@ -808,6 +807,9 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) {
 
         for impl_item in impl_items {
             match impl_item.node {
+                ast::ConstImplItem(_, ref expr) => {
+                    check_const(ccx, impl_item.span, &*expr, impl_item.id)
+                }
                 ast::MethodImplItem(ref sig, ref body) => {
                     check_method_body(ccx, &impl_pty.generics, sig, body,
                                       impl_item.id, impl_item.span);
@@ -823,14 +825,15 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) {
         let trait_def = ty::lookup_trait_def(ccx.tcx, local_def(it.id));
         for trait_item in trait_items {
             match trait_item.node {
-                ast::MethodTraitItem(_, None) => {
-                    // Nothing to do, since required methods don't have
-                    // bodies to check.
+                ast::ConstTraitItem(_, Some(ref expr)) => {
+                    check_const(ccx, trait_item.span, &*expr, trait_item.id)
                 }
                 ast::MethodTraitItem(ref sig, Some(ref body)) => {
                     check_method_body(ccx, &trait_def.generics, sig, body,
                                       trait_item.id, trait_item.span);
                 }
+                ast::ConstTraitItem(_, None) |
+                ast::MethodTraitItem(_, None) |
                 ast::TypeTraitItem(..) => {
                     // Nothing to do.
                 }
@@ -920,6 +923,48 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     // and compatible with trait signature
     for impl_item in impl_items {
         match impl_item.node {
+            ast::ConstImplItem(..) => {
+                let impl_const_def_id = local_def(impl_item.id);
+                let impl_const_ty = ty::impl_or_trait_item(ccx.tcx,
+                                                           impl_const_def_id);
+
+                // Find associated const definition.
+                let opt_associated_const =
+                    trait_items.iter()
+                               .find(|ac| ac.name() == impl_const_ty.name());
+                match opt_associated_const {
+                    Some(associated_const) => {
+                        match (associated_const, &impl_const_ty) {
+                            (&ty::ConstTraitItem(ref const_trait),
+                             &ty::ConstTraitItem(ref const_impl)) => {
+                                compare_const_impl(ccx.tcx,
+                                                   &const_impl,
+                                                   impl_item.span,
+                                                   &const_trait,
+                                                   &*impl_trait_ref);
+                            }
+                            _ => {
+                                span_err!(tcx.sess, impl_item.span, E0323,
+                                          "item `{}` is an associated const, \
+                                          which doesn't match its trait `{}`",
+                                          token::get_name(impl_const_ty.name()),
+                                          impl_trait_ref.repr(tcx))
+                            }
+                        }
+                    }
+                    None => {
+                        // This is `span_bug` as it should have already been
+                        // caught in resolve.
+                        tcx.sess.span_bug(
+                            impl_item.span,
+                            &format!(
+                                "associated const `{}` is not a member of \
+                                 trait `{}`",
+                                token::get_name(impl_const_ty.name()),
+                                impl_trait_ref.repr(tcx)));
+                    }
+                }
+            }
             ast::MethodImplItem(_, ref body) => {
                 let impl_method_def_id = local_def(impl_item.id);
                 let impl_item_ty = ty::impl_or_trait_item(ccx.tcx,
@@ -943,13 +988,11 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                                     &*impl_trait_ref);
                             }
                             _ => {
-                                // This is span_bug as it should have already been
-                                // caught in resolve.
-                                tcx.sess.span_bug(
-                                    impl_item.span,
-                                    &format!("item `{}` is of a different kind from its trait `{}`",
-                                             token::get_name(impl_item_ty.name()),
-                                             impl_trait_ref.repr(tcx)));
+                                span_err!(tcx.sess, impl_item.span, E0324,
+                                          "item `{}` is an associated method, \
+                                          which doesn't match its trait `{}`",
+                                          token::get_name(impl_item_ty.name()),
+                                          impl_trait_ref.repr(tcx))
                             }
                         }
                     }
@@ -979,13 +1022,11 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                         match (associated_type, &typedef_ty) {
                             (&ty::TypeTraitItem(_), &ty::TypeTraitItem(_)) => {}
                             _ => {
-                                // This is `span_bug` as it should have
-                                // already been caught in resolve.
-                                tcx.sess.span_bug(
-                                    impl_item.span,
-                                    &format!("item `{}` is of a different kind from its trait `{}`",
-                                             token::get_name(typedef_ty.name()),
-                                             impl_trait_ref.repr(tcx)));
+                                span_err!(tcx.sess, impl_item.span, E0325,
+                                          "item `{}` is an associated type, \
+                                          which doesn't match its trait `{}`",
+                                          token::get_name(typedef_ty.name()),
+                                          impl_trait_ref.repr(tcx))
                             }
                         }
                     }
@@ -1009,9 +1050,27 @@ trait `{}`",
 
     // Check for missing items from trait
     let provided_methods = ty::provided_trait_methods(tcx, impl_trait_ref.def_id);
+    let associated_consts = ty::associated_consts(tcx, impl_trait_ref.def_id);
     let mut missing_methods = Vec::new();
     for trait_item in &*trait_items {
         match *trait_item {
+            ty::ConstTraitItem(ref associated_const) => {
+                let is_implemented = impl_items.iter().any(|ii| {
+                    match ii.node {
+                        ast::ConstImplItem(..) => {
+                            ii.ident.name == associated_const.name
+                        }
+                        _ => false,
+                    }
+                });
+                let is_provided =
+                    associated_consts.iter().any(|ac| ac.default.is_some() &&
+                                                 ac.name == associated_const.name);
+                if !is_implemented && !is_provided {
+                    missing_methods.push(format!("`{}`",
+                                                 token::get_name(associated_const.name)));
+                }
+            }
             ty::MethodTraitItem(ref trait_method) => {
                 let is_implemented =
                     impl_items.iter().any(|ii| {
@@ -1019,8 +1078,7 @@ trait `{}`",
                             ast::MethodImplItem(..) => {
                                 ii.ident.name == trait_method.name
                             }
-                            ast::TypeImplItem(_) |
-                            ast::MacImplItem(_) => false,
+                            _ => false,
                         }
                     });
                 let is_provided =
@@ -1035,8 +1093,7 @@ trait `{}`",
                         ast::TypeImplItem(_) => {
                             ii.ident.name == associated_type.name
                         }
-                        ast::MethodImplItem(..) |
-                        ast::MacImplItem(_) => false,
+                        _ => false,
                     }
                 });
                 if !is_implemented {
@@ -3172,53 +3229,20 @@ fn check_struct_fields_on_error<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
                                 &format!("unbound path {}", expr.repr(tcx)))
           };
 
-          let def = path_res.base_def;
-          if path_res.depth == 0 {
+          if let Some((opt_ty, segments, def)) =
+                  resolve_ty_and_def_ufcs(fcx, path_res, opt_self_ty, path,
+                                          expr.span, expr.id) {
               let (scheme, predicates) = type_scheme_and_predicates_for_def(fcx,
                                                                             expr.span,
                                                                             def);
               instantiate_path(fcx,
-                               &path.segments,
+                               segments,
                                scheme,
                                &predicates,
-                               opt_self_ty,
+                               opt_ty,
                                def,
                                expr.span,
                                id);
-          } else {
-              let ty_segments = path.segments.init();
-              let base_ty_end = path.segments.len() - path_res.depth;
-              let ty = astconv::finish_resolving_def_to_ty(fcx,
-                                                           fcx,
-                                                           expr.span,
-                                                           PathParamMode::Optional,
-                                                           &def,
-                                                           opt_self_ty,
-                                                           &ty_segments[..base_ty_end],
-                                                           &ty_segments[base_ty_end..]);
-              let method_segment = path.segments.last().unwrap();
-              let method_name = method_segment.identifier.name;
-              match method::resolve_ufcs(fcx, expr.span, method_name, ty, id) {
-                  Ok((def, lp)) => {
-                      // Write back the new resolution.
-                      tcx.def_map.borrow_mut().insert(id, def::PathResolution {
-                          base_def: def,
-                          last_private: path_res.last_private.or(lp),
-                          depth: 0
-                      });
-
-                      let (scheme, predicates) =
-                          type_scheme_and_predicates_for_def(fcx, expr.span, def);
-                      instantiate_path(fcx, slice::ref_slice(method_segment),
-                                       scheme, &predicates,
-                                       Some(ty), def, expr.span, id);
-                  }
-                  Err(error) => {
-                      method::report_error(fcx, expr.span, ty,
-                                           method_name, None, error);
-                      fcx.write_error(id);
-                  }
-              }
           }
 
           // We always require that the type provided as the value for
@@ -3680,6 +3704,52 @@ fn check_struct_fields_on_error<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
     unifier();
 }
 
+pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, 'tcx>,
+                                             path_res: def::PathResolution,
+                                             opt_self_ty: Option<Ty<'tcx>>,
+                                             path: &'a ast::Path,
+                                             span: Span,
+                                             node_id: ast::NodeId)
+                                             -> Option<(Option<Ty<'tcx>>,
+                                                        &'a [ast::PathSegment],
+                                                        def::Def)>
+{
+    // If fully resolved already, we don't have to do anything.
+    if path_res.depth == 0 {
+        Some((opt_self_ty, &path.segments, path_res.base_def))
+    } else {
+        let mut def = path_res.base_def;
+        let ty_segments = path.segments.init();
+        let base_ty_end = path.segments.len() - path_res.depth;
+        let ty = astconv::finish_resolving_def_to_ty(fcx, fcx, span,
+                                                     PathParamMode::Optional,
+                                                     &mut def,
+                                                     opt_self_ty,
+                                                     &ty_segments[..base_ty_end],
+                                                     &ty_segments[base_ty_end..]);
+        let item_segment = path.segments.last().unwrap();
+        let item_name = item_segment.identifier.name;
+        match method::resolve_ufcs(fcx, span, item_name, ty, node_id) {
+            Ok((def, lp)) => {
+                // Write back the new resolution.
+                fcx.ccx.tcx.def_map.borrow_mut()
+                       .insert(node_id, def::PathResolution {
+                   base_def: def,
+                   last_private: path_res.last_private.or(lp),
+                   depth: 0
+                });
+                Some((Some(ty), slice::ref_slice(item_segment), def))
+            }
+            Err(error) => {
+                method::report_error(fcx, span, ty,
+                                     item_name, None, error);
+                fcx.write_error(node_id);
+                None
+            }
+        }
+    }
+}
+
 fn constrain_path_type_parameters(fcx: &FnCtxt,
                                   expr: &ast::Expr)
 {
@@ -4208,7 +4278,7 @@ fn type_scheme_and_predicates_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         }
         def::DefFn(id, _) | def::DefMethod(id, _) |
         def::DefStatic(id, _) | def::DefVariant(_, id, _) |
-        def::DefStruct(id) | def::DefConst(id) => {
+        def::DefStruct(id) | def::DefConst(id) | def::DefAssociatedConst(id, _) => {
             (ty::lookup_item_type(fcx.tcx(), id), ty::lookup_predicates(fcx.tcx(), id))
         }
         def::DefTrait(_) |
@@ -4250,7 +4320,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     // Luckily, we can (at least for now) deduce the intermediate steps
     // just from the end-point.
     //
-    // There are basically three cases to consider:
+    // There are basically four cases to consider:
     //
     // 1. Reference to a *type*, such as a struct or enum:
     //
@@ -4300,6 +4370,16 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     //    `SomeStruct::<A>`, contains parameters in TypeSpace, and the
     //    final segment, `foo::<B>` contains parameters in fn space.
     //
+    // 4. Reference to an *associated const*:
+    //
+    // impl<A> AnotherStruct<A> {
+    // const FOO: B = BAR;
+    // }
+    //
+    // The path in this case will look like
+    // `a::b::AnotherStruct::<A>::FOO`, so the penultimate segment
+    // only will have parameters in TypeSpace.
+    //
     // The first step then is to categorize the segments appropriately.
 
     assert!(!segments.is_empty());
@@ -4351,6 +4431,23 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             }
         }
 
+        def::DefAssociatedConst(_, provenance) => {
+            match provenance {
+                def::FromTrait(trait_did) => {
+                    callee::check_legal_trait_for_method_call(fcx.ccx, span, trait_did)
+                }
+                def::FromImpl(_) => {}
+            }
+
+            if segments.len() >= 2 {
+                segment_spaces = repeat(None).take(segments.len() - 2).collect();
+                segment_spaces.push(Some(subst::TypeSpace));
+                segment_spaces.push(None);
+            } else {
+                segment_spaces = vec![None];
+            }
+        }
+
         // Other cases. Various nonsense that really shouldn't show up
         // here. If they do, an error will have been reported
         // elsewhere. (I hope)
index 6dfc1e0ea6c2651598ba03f01462a3f74102bbf1..19cb570c82d13463a8f34a75fa57b4ab16788d6e 100644 (file)
@@ -85,8 +85,9 @@
 use astconv::AstConv;
 use check::dropck;
 use check::FnCtxt;
-use check::implicator;
 use check::vtable;
+use middle::free_region::FreeRegionMap;
+use middle::implicator;
 use middle::mem_categorization as mc;
 use middle::region::CodeExtent;
 use middle::subst::Substs;
@@ -124,6 +125,8 @@ pub fn regionck_expr(fcx: &FnCtxt, e: &ast::Expr) {
 
 pub fn regionck_item(fcx: &FnCtxt, item: &ast::Item) {
     let mut rcx = Rcx::new(fcx, RepeatingScope(item.id), item.id, Subject(item.id));
+    let tcx = fcx.tcx();
+    rcx.free_region_map.relate_free_regions_from_predicates(tcx, &fcx.inh.param_env.caller_bounds);
     rcx.visit_region_obligations(item.id);
     rcx.resolve_regions_and_report_errors();
 }
@@ -135,12 +138,21 @@ pub fn regionck_fn(fcx: &FnCtxt,
                    blk: &ast::Block) {
     debug!("regionck_fn(id={})", fn_id);
     let mut rcx = Rcx::new(fcx, RepeatingScope(blk.id), blk.id, Subject(fn_id));
+
     if fcx.err_count_since_creation() == 0 {
         // regionck assumes typeck succeeded
         rcx.visit_fn_body(fn_id, decl, blk, fn_span);
     }
 
+    let tcx = fcx.tcx();
+    rcx.free_region_map.relate_free_regions_from_predicates(tcx, &fcx.inh.param_env.caller_bounds);
+
     rcx.resolve_regions_and_report_errors();
+
+    // For the top-level fn, store the free-region-map. We don't store
+    // any map for closures; they just share the same map as the
+    // function that created them.
+    fcx.tcx().store_free_region_map(fn_id, rcx.free_region_map);
 }
 
 /// Checks that the types in `component_tys` are well-formed. This will add constraints into the
@@ -167,6 +179,8 @@ pub struct Rcx<'a, 'tcx: 'a> {
 
     region_bound_pairs: Vec<(ty::Region, GenericKind<'tcx>)>,
 
+    free_region_map: FreeRegionMap,
+
     // id of innermost fn body id
     body_id: ast::NodeId,
 
@@ -191,7 +205,8 @@ pub fn new(fcx: &'a FnCtxt<'a, 'tcx>,
               repeating_scope: initial_repeating_scope,
               body_id: initial_body_id,
               subject: subject,
-              region_bound_pairs: Vec::new()
+              region_bound_pairs: Vec::new(),
+              free_region_map: FreeRegionMap::new(),
         }
     }
 
@@ -277,13 +292,16 @@ fn visit_fn_body(&mut self,
             }
         };
 
-        let len = self.region_bound_pairs.len();
+        let old_region_bounds_pairs_len = self.region_bound_pairs.len();
+
         let old_body_id = self.set_body_id(body.id);
         self.relate_free_regions(&fn_sig[..], body.id, span);
         link_fn_args(self, CodeExtent::from_node_id(body.id), &fn_decl.inputs[..]);
         self.visit_block(body);
         self.visit_region_obligations(body.id);
-        self.region_bound_pairs.truncate(len);
+
+        self.region_bound_pairs.truncate(old_region_bounds_pairs_len);
+
         self.set_body_id(old_body_id);
     }
 
@@ -340,14 +358,16 @@ fn relate_free_regions(&mut self,
             let body_scope = ty::ReScope(body_scope);
             let implications = implicator::implications(self.fcx.infcx(), self.fcx, body_id,
                                                         ty, body_scope, span);
+
+            // Record any relations between free regions that we observe into the free-region-map.
+            self.free_region_map.relate_free_regions_from_implications(tcx, &implications);
+
+            // But also record other relationships, such as `T:'x`,
+            // that don't go into the free-region-map but which we use
+            // here.
             for implication in implications {
                 debug!("implication: {}", implication.repr(tcx));
                 match implication {
-                    implicator::Implication::RegionSubRegion(_,
-                                                             ty::ReFree(free_a),
-                                                             ty::ReFree(free_b)) => {
-                        tcx.region_maps.relate_free_regions(free_a, free_b);
-                    }
                     implicator::Implication::RegionSubRegion(_,
                                                              ty::ReFree(free_a),
                                                              ty::ReInfer(ty::ReVar(vid_b))) => {
@@ -388,7 +408,8 @@ fn resolve_regions_and_report_errors(&self) {
             }
         };
 
-        self.fcx.infcx().resolve_regions_and_report_errors(subject_node_id);
+        self.fcx.infcx().resolve_regions_and_report_errors(&self.free_region_map,
+                                                           subject_node_id);
     }
 }
 
@@ -541,11 +562,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
             }
             Err(..) => {
                 let tcx = rcx.fcx.tcx();
-                if tcx.sess.has_errors() {
-                    // cannot run dropck; okay b/c in error state anyway.
-                } else {
-                    tcx.sess.span_bug(expr.span, "cat_expr_unadjusted Errd");
-                }
+                tcx.sess.delay_span_bug(expr.span, "cat_expr_unadjusted Errd");
             }
         }
     }
@@ -562,11 +579,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
         }
         Err(..) => {
             let tcx = rcx.fcx.tcx();
-            if tcx.sess.has_errors() {
-                // cannot run dropck; okay b/c in error state anyway.
-            } else {
-                tcx.sess.span_bug(expr.span, "cat_expr Errd");
-            }
+            tcx.sess.delay_span_bug(expr.span, "cat_expr Errd");
         }
     }
 
index b0c994f7f6405500a582a480510210dcbfc923d4..fbfe73674e16088eb95388debd7338ffe97c53d9 100644 (file)
@@ -20,8 +20,9 @@
 use metadata::csearch;
 use middle::subst::{self, Subst};
 use middle::ty::RegionEscape;
-use middle::ty::{ImplContainer, ImplOrTraitItemId, MethodTraitItemId};
-use middle::ty::{ParameterEnvironment, TypeTraitItemId, lookup_item_type};
+use middle::ty::{ImplContainer, ImplOrTraitItemId, ConstTraitItemId};
+use middle::ty::{MethodTraitItemId, TypeTraitItemId};
+use middle::ty::{ParameterEnvironment, lookup_item_type};
 use middle::ty::{Ty, ty_bool, ty_char, ty_enum, ty_err};
 use middle::ty::{ty_param, TypeScheme, ty_ptr};
 use middle::ty::{ty_rptr, ty_struct, ty_trait, ty_tup};
@@ -278,6 +279,9 @@ fn create_impl_from_item(&self, item: &Item) -> Vec<ImplOrTraitItemId> {
                 let mut items: Vec<ImplOrTraitItemId> =
                         impl_items.iter().map(|impl_item| {
                     match impl_item.node {
+                        ast::ConstImplItem(..) => {
+                            ConstTraitItemId(local_def(impl_item.id))
+                        }
                         ast::MethodImplItem(..) => {
                             MethodTraitItemId(local_def(impl_item.id))
                         }
@@ -348,7 +352,7 @@ fn add_external_impl(&self,
                            .insert(item_def_id.def_id(), source);
                     }
                 }
-                ty::TypeTraitItem(_) => {}
+                _ => {}
             }
         }
 
index 5ed93703d977f25ced3824755210b2a0648739fd..6cb6df008c1cf7e505ae8c8616809a5dcf37dd8b 100644 (file)
@@ -68,6 +68,7 @@
 use middle::def;
 use constrained_type_params as ctp;
 use middle::lang_items::SizedTraitLangItem;
+use middle::free_region::FreeRegionMap;
 use middle::region;
 use middle::resolve_lifetime;
 use middle::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPerParamSpace};
@@ -196,7 +197,7 @@ fn method_ty(&self, method_id: ast::NodeId) -> Rc<ty::Method<'tcx>> {
         let def_id = local_def(method_id);
         match *self.tcx.impl_or_trait_items.borrow().get(&def_id).unwrap() {
             ty::MethodTraitItem(ref mty) => mty.clone(),
-            ty::TypeTraitItem(..) => {
+            _ => {
                 self.tcx.sess.bug(&format!("method with id {} has the wrong type", method_id));
             }
         }
@@ -691,11 +692,37 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     }
 }
 
+fn convert_associated_const<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+                                      container: ImplOrTraitItemContainer,
+                                      ident: ast::Ident,
+                                      id: ast::NodeId,
+                                      vis: ast::Visibility,
+                                      ty: ty::Ty<'tcx>,
+                                      default: Option<&ast::Expr>)
+{
+    ccx.tcx.predicates.borrow_mut().insert(local_def(id),
+                                           ty::GenericPredicates::empty());
+
+    write_ty_to_tcx(ccx.tcx, id, ty);
+    let default_id = default.map(|expr| local_def(expr.id));
+
+    let associated_const = Rc::new(ty::AssociatedConst {
+        name: ident.name,
+        vis: vis,
+        def_id: local_def(id),
+        container: container,
+        ty: ty,
+        default: default_id,
+    });
+    ccx.tcx.impl_or_trait_items.borrow_mut()
+       .insert(local_def(id), ty::ConstTraitItem(associated_const));
+}
+
 fn as_refsociated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                     container: ImplOrTraitItemContainer,
-                                     ident: ast::Ident,
-                                     id: ast::NodeId,
-                                     vis: ast::Visibility)
+                                 container: ImplOrTraitItemContainer,
+                                 ident: ast::Ident,
+                                 id: ast::NodeId,
+                                 vis: ast::Visibility)
 {
     let associated_type = Rc::new(ty::AssociatedType {
         name: ident.name,
@@ -828,45 +855,56 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) {
                 it.vis
             };
 
-            // Convert all the associated types.
+            // Convert all the associated consts.
             for impl_item in impl_items {
-                match impl_item.node {
-                    ast::TypeImplItem(ref ty) => {
-                        if opt_trait_ref.is_none() {
-                            span_err!(tcx.sess, impl_item.span, E0202,
-                                              "associated items are not allowed in inherent impls");
-                        }
-
-                        as_refsociated_type(ccx, ImplContainer(local_def(it.id)),
-                                                impl_item.ident, impl_item.id, impl_item.vis);
+                if let ast::ConstImplItem(ref ty, ref expr) = impl_item.node {
+                    let ty = ccx.icx(&ty_predicates)
+                                .to_ty(&ExplicitRscope, &*ty);
+                    tcx.tcache.borrow_mut().insert(local_def(impl_item.id),
+                                                   TypeScheme {
+                                                       generics: ty_generics.clone(),
+                                                       ty: ty,
+                                                   });
+                    convert_associated_const(ccx, ImplContainer(local_def(it.id)),
+                                             impl_item.ident, impl_item.id,
+                                             impl_item.vis.inherit_from(parent_visibility),
+                                             ty, Some(&*expr));
+                }
+            }
 
-                        let typ = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, ty);
-                        tcx.tcache.borrow_mut().insert(local_def(impl_item.id),
-                                                       TypeScheme {
-                                                           generics: ty::Generics::empty(),
-                                                           ty: typ,
-                                                       });
-                        tcx.predicates.borrow_mut().insert(local_def(impl_item.id),
-                                                           ty::GenericPredicates::empty());
-                        write_ty_to_tcx(tcx, impl_item.id, typ);
+            // Convert all the associated types.
+            for impl_item in impl_items {
+                if let ast::TypeImplItem(ref ty) = impl_item.node {
+                    if opt_trait_ref.is_none() {
+                        span_err!(tcx.sess, impl_item.span, E0202,
+                                  "associated items are not allowed in inherent impls");
                     }
-                    ast::MethodImplItem(..) |
-                    ast::MacImplItem(_) => {}
+
+                    as_refsociated_type(ccx, ImplContainer(local_def(it.id)),
+                                        impl_item.ident, impl_item.id, impl_item.vis);
+
+                    let typ = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, ty);
+                    tcx.tcache.borrow_mut().insert(local_def(impl_item.id),
+                                                   TypeScheme {
+                                                       generics: ty::Generics::empty(),
+                                                       ty: typ,
+                                                   });
+                    tcx.predicates.borrow_mut().insert(local_def(impl_item.id),
+                                                       ty::GenericPredicates::empty());
+                    write_ty_to_tcx(tcx, impl_item.id, typ);
                 }
             }
 
             let methods = impl_items.iter().filter_map(|ii| {
-                match ii.node {
-                    ast::MethodImplItem(ref sig, _) => {
-                        // if the method specifies a visibility, use that, otherwise
-                        // inherit the visibility from the impl (so `foo` in `pub impl
-                        // { fn foo(); }` is public, but private in `priv impl { fn
-                        // foo(); }`).
-                        let method_vis = ii.vis.inherit_from(parent_visibility);
-                        Some((sig, ii.id, ii.ident, method_vis, ii.span))
-                    }
-                    ast::TypeImplItem(_) |
-                    ast::MacImplItem(_) => None
+                if let ast::MethodImplItem(ref sig, _) = ii.node {
+                    // if the method specifies a visibility, use that, otherwise
+                    // inherit the visibility from the impl (so `foo` in `pub impl
+                    // { fn foo(); }` is public, but private in `priv impl { fn
+                    // foo(); }`).
+                    let method_vis = ii.vis.inherit_from(parent_visibility);
+                    Some((sig, ii.id, ii.ident, method_vis, ii.span))
+                } else {
+                    None
                 }
             });
             convert_methods(ccx,
@@ -877,18 +915,14 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) {
                             &ty_predicates);
 
             for impl_item in impl_items {
-                match impl_item.node {
-                    ast::MethodImplItem(ref sig, ref body) => {
-                        let body_id = body.id;
-                        check_method_self_type(ccx,
-                                               &BindingRscope::new(),
-                                               ccx.method_ty(impl_item.id),
-                                               selfty,
-                                               &sig.explicit_self,
-                                               body_id);
-                    }
-                    ast::TypeImplItem(_) |
-                    ast::MacImplItem(_) => {}
+                if let ast::MethodImplItem(ref sig, ref body) = impl_item.node {
+                    let body_id = body.id;
+                    check_method_self_type(ccx,
+                                           &BindingRscope::new(),
+                                           ccx.method_ty(impl_item.id),
+                                           selfty,
+                                           &sig.explicit_self,
+                                           body_id);
                 }
             }
 
@@ -919,18 +953,37 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) {
             // Convert all the associated types.
             for trait_item in trait_items {
                 match trait_item.node {
-                    ast::MethodTraitItem(..) => {}
+                    ast::ConstTraitItem(ref ty, ref default) => {
+                        let ty = ccx.icx(&trait_predicates)
+                                    .to_ty(&ExplicitRscope, ty);
+                        tcx.tcache.borrow_mut().insert(local_def(trait_item.id),
+                                                       TypeScheme {
+                                                           generics: trait_def.generics.clone(),
+                                                           ty: ty,
+                                                       });
+                        convert_associated_const(ccx, TraitContainer(local_def(it.id)),
+                                                 trait_item.ident, trait_item.id,
+                                                 ast::Public, ty, default.as_ref().map(|d| &**d));
+                    }
+                    _ => {}
+                }
+            };
+
+            // Convert all the associated types.
+            for trait_item in trait_items {
+                match trait_item.node {
                     ast::TypeTraitItem(..) => {
                         as_refsociated_type(ccx, TraitContainer(local_def(it.id)),
                                                 trait_item.ident, trait_item.id, ast::Public);
                     }
+                    _ => {}
                 }
             };
 
             let methods = trait_items.iter().filter_map(|ti| {
                 let sig = match ti.node {
                     ast::MethodTraitItem(ref sig, _) => sig,
-                    ast::TypeTraitItem(..) => return None,
+                    _ => return None,
                 };
                 Some((sig, ti.id, ti.ident, ast::Inherited, ti.span))
             });
@@ -947,6 +1000,9 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) {
             let trait_item_def_ids = Rc::new(trait_items.iter().map(|trait_item| {
                 let def_id = local_def(trait_item.id);
                 match trait_item.node {
+                    ast::ConstTraitItem(..) => {
+                        ty::ConstTraitItemId(def_id)
+                    }
                     ast::MethodTraitItem(..) => {
                         ty::MethodTraitItemId(def_id)
                     }
@@ -962,7 +1018,7 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) {
             for trait_item in trait_items {
                 let sig = match trait_item.node {
                     ast::MethodTraitItem(ref sig, _) => sig,
-                    ast::TypeTraitItem(..) => continue
+                    _ => continue
                 };
                 check_method_self_type(ccx,
                                        &BindingRscope::new(),
@@ -1185,8 +1241,8 @@ 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 {
-            ast::MethodTraitItem(..) => None,
             ast::TypeTraitItem(..) => Some(trait_item.ident.name),
+            _ => None,
         }
     }).collect();
 
@@ -1260,7 +1316,7 @@ fn trait_defines_associated_type_named(ccx: &CrateCtxt,
     trait_items.iter().any(|trait_item| {
         match trait_item.node {
             ast::TypeTraitItem(..) => trait_item.ident.name == assoc_name,
-            ast::MethodTraitItem(..) => false,
+            _ => false,
         }
     })
 }
@@ -1320,7 +1376,7 @@ fn predicates_for_associated_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         trait_items.iter().flat_map(|trait_item| {
             let bounds = match trait_item.node {
                 ast::TypeTraitItem(ref bounds, _) => bounds,
-                ast::MethodTraitItem(..) => {
+                _ => {
                     return vec!().into_iter();
                 }
             };
@@ -2158,7 +2214,16 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>(
                 format!("mismatched self type: expected `{}`",
                         ppaux::ty_to_string(tcx, required_type))
         }));
-        infcx.resolve_regions_and_report_errors(body_id);
+
+        // We could conceviably add more free-reion relations here,
+        // but since this code is just concerned with checking that
+        // the `&Self` types etc match up, it's not really necessary.
+        // It would just allow people to be more approximate in some
+        // cases. In any case, we can do it later as we feel the need;
+        // I'd like this function to go away eventually.
+        let free_regions = FreeRegionMap::new();
+
+        infcx.resolve_regions_and_report_errors(&free_regions, body_id);
     }
 
     fn liberate_early_bound_regions<'tcx,T>(
@@ -2227,7 +2292,8 @@ fn enforce_impl_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>,
         impl_items.iter()
                   .filter_map(|item| match item.node {
                       ast::TypeImplItem(..) => Some(ty::node_id_to_type(tcx, item.id)),
-                      ast::MethodImplItem(..) | ast::MacImplItem(..) => None,
+                      ast::ConstImplItem(..) | ast::MethodImplItem(..) |
+                      ast::MacImplItem(..) => None,
                   })
                   .flat_map(|ty| ctp::parameters_for_type(ty).into_iter())
                   .filter_map(|p| match p {
index b17702cfb8cb5c58d6b9bf907f3491affe892040..46cc4628e2eeb36022f7782bd7d89af67c72cee7 100644 (file)
     E0320, // recursive overflow during dropck
     E0321, // extended coherence rules for defaulted traits violated
     E0322, // cannot implement Sized explicitly
+    E0323, // implemented an associated const when another trait item expected
+    E0324, // implemented a method when another trait item expected
+    E0325, // implemented an associated type when another trait item expected
+    E0326, // associated const implemented with different type from trait
+    E0327, // referred to method instead of constant in match pattern
     E0366, // dropck forbid specialization to concrete type or region
     E0367, // dropck forbid specialization to predicate not in struct/enum
     E0368, // binary operation `<op>=` cannot be applied to types
index 4fc86cf181b8daf361d8756e527cbe25279b5e3f..0d59577a6d802ce1552cd45cf9267dad1c06f9f5 100644 (file)
 use rustc::middle::ty;
 use rustc::middle::subst;
 use rustc::middle::stability;
+use rustc::middle::const_eval;
 
 use core::DocContext;
 use doctree;
 use clean;
 
-use super::Clean;
+use super::{Clean, ToSource};
 
 /// Attempt to inline the definition of a local node id into this AST.
 ///
@@ -106,7 +107,7 @@ fn try_inline_def(cx: &DocContext, tcx: &ty::ctxt,
             record_extern_fqn(cx, did, clean::TypeStatic);
             clean::StaticItem(build_static(cx, tcx, did, mtbl))
         }
-        def::DefConst(did) => {
+        def::DefConst(did) | def::DefAssociatedConst(did, _) => {
             record_extern_fqn(cx, did, clean::TypeConst);
             clean::ConstantItem(build_const(cx, tcx, did))
         }
@@ -312,6 +313,27 @@ pub fn build_impl(cx: &DocContext,
         let did = did.def_id();
         let impl_item = ty::impl_or_trait_item(tcx, did);
         match impl_item {
+            ty::ConstTraitItem(ref assoc_const) => {
+                let did = assoc_const.def_id;
+                let type_scheme = ty::lookup_item_type(tcx, 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,
+                };
+                Some(clean::Item {
+                    name: Some(assoc_const.name.clean(cx)),
+                    inner: clean::AssociatedConstItem(
+                        type_scheme.ty.clean(cx),
+                        default,
+                    ),
+                    source: clean::Span::empty(),
+                    attrs: vec![],
+                    visibility: None,
+                    stability: stability::lookup(tcx, did).clean(cx),
+                    def_id: did
+                })
+            }
             ty::MethodTraitItem(method) => {
                 if method.vis != ast::Public && associated_trait.is_none() {
                     return None
@@ -443,7 +465,7 @@ fn build_const(cx: &DocContext, tcx: &ty::ctxt,
     use rustc::middle::const_eval;
     use syntax::print::pprust;
 
-    let expr = const_eval::lookup_const_by_id(tcx, did).unwrap_or_else(|| {
+    let expr = const_eval::lookup_const_by_id(tcx, did, None).unwrap_or_else(|| {
         panic!("expected lookup_const_by_id to succeed for {:?}", did);
     });
     debug!("converting constant expr {:?} to snippet", expr);
index 23c9edde77c33ea423a1f26fde6fd932c13ea3bf..1e6e9a7562a7c1be287fe5e69e42ff7f49dce460 100644 (file)
@@ -361,6 +361,7 @@ pub enum ItemEnum {
     ForeignStaticItem(Static),
     MacroItem(Macro),
     PrimitiveItem(PrimitiveType),
+    AssociatedConstItem(Type, Option<String>),
     AssociatedTypeItem(Vec<TyParamBound>, Option<Type>),
     DefaultImplItem(DefaultImpl),
 }
@@ -1235,6 +1236,11 @@ fn clean(&self, cx: &DocContext) -> PolyTrait {
 impl Clean<Item> for ast::TraitItem {
     fn clean(&self, cx: &DocContext) -> Item {
         let inner = match self.node {
+            ast::ConstTraitItem(ref ty, ref default) => {
+                AssociatedConstItem(ty.clean(cx),
+                                    default.as_ref().map(|expr|
+                                                         expr.span.to_src(cx)))
+            }
             ast::MethodTraitItem(ref sig, Some(_)) => {
                 MethodItem(sig.clean(cx))
             }
@@ -1260,6 +1266,12 @@ fn clean(&self, cx: &DocContext) -> Item {
 impl Clean<Item> for ast::ImplItem {
     fn clean(&self, cx: &DocContext) -> Item {
         let inner = match self.node {
+            ast::ConstImplItem(ref ty, ref expr) => {
+                ConstantItem(Constant{
+                    type_: ty.clean(cx),
+                    expr: expr.span.to_src(cx),
+                })
+            }
             ast::MethodImplItem(ref sig, _) => {
                 MethodItem(sig.clean(cx))
             }
@@ -1363,6 +1375,7 @@ fn clean(&self, cx: &DocContext) -> Item {
 impl<'tcx> Clean<Item> for ty::ImplOrTraitItem<'tcx> {
     fn clean(&self, cx: &DocContext) -> Item {
         match *self {
+            ty::ConstTraitItem(ref cti) => cti.clean(cx),
             ty::MethodTraitItem(ref mti) => mti.clean(cx),
             ty::TypeTraitItem(ref tti) => tti.clean(cx),
         }
@@ -2509,6 +2522,8 @@ fn name_from_pat(p: &ast::Pat) -> String {
         PatWild(PatWildMulti) => "..".to_string(),
         PatIdent(_, ref p, _) => token::get_ident(p.node).to_string(),
         PatEnum(ref p, _) => path_to_string(p),
+        PatQPath(..) => panic!("tried to get argument name from PatQPath, \
+                                which is not allowed in function arguments"),
         PatStruct(ref name, ref fields, etc) => {
             format!("{} {{ {}{} }}", path_to_string(name),
                 fields.iter().map(|&Spanned { node: ref fp, .. }|
@@ -2672,6 +2687,20 @@ fn clean(&self, _: &DocContext) -> Stability {
     }
 }
 
+impl<'tcx> Clean<Item> for ty::AssociatedConst<'tcx> {
+    fn clean(&self, cx: &DocContext) -> Item {
+        Item {
+            source: DUMMY_SP.clean(cx),
+            name: Some(self.name.clean(cx)),
+            attrs: Vec::new(),
+            inner: AssociatedConstItem(self.ty.clean(cx), None),
+            visibility: None,
+            def_id: self.def_id,
+            stability: None,
+        }
+    }
+}
+
 impl Clean<Item> for ty::AssociatedType {
     fn clean(&self, cx: &DocContext) -> Item {
         // When loading a cross-crate associated type, the bounds for this type
index d2385702a73d2c2c35fc85453890a3c56f7be2c5..afc93f41172e84498729ceece2adebcc6845022d 100644 (file)
@@ -39,6 +39,7 @@ pub enum ItemType {
     Primitive       = 15,
     AssociatedType  = 16,
     Constant        = 17,
+    AssociatedConst = 18,
 }
 
 impl ItemType {
@@ -63,6 +64,7 @@ pub fn from_item(item: &clean::Item) -> ItemType {
             clean::ForeignStaticItem(..)   => ItemType::Static, // no ForeignStatic
             clean::MacroItem(..)           => ItemType::Macro,
             clean::PrimitiveItem(..)       => ItemType::Primitive,
+            clean::AssociatedConstItem(..) => ItemType::AssociatedConst,
             clean::AssociatedTypeItem(..)  => ItemType::AssociatedType,
             clean::DefaultImplItem(..)     => ItemType::Impl,
         }
@@ -102,6 +104,7 @@ pub fn to_static_str(&self) -> &'static str {
             ItemType::Primitive       => "primitive",
             ItemType::AssociatedType  => "associatedtype",
             ItemType::Constant        => "constant",
+            ItemType::AssociatedConst => "associatedconstant",
         }
     }
 }
index 1993f03efd1fabbc8e7539be2ec4b93f57fe9e55..9a26a925847e41dbb045b32b809ce24f4009b537 100644 (file)
@@ -1460,7 +1460,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         try!(write!(fmt, "<span class='out-of-band'>"));
         try!(write!(fmt,
         r##"<span id='render-detail'>
-            <a id="toggle-all-docs" href="#" title="collapse all docs">[-]</a>
+            <a id="toggle-all-docs" href="#" title="collapse all docs">[&minus;]</a>
         </span>"##));
 
         // Write `src` tag
@@ -1629,6 +1629,7 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: usize, idx2: usize) -> Ordering
                 ItemType::Macro           => ("macros", "Macros"),
                 ItemType::Primitive       => ("primitives", "Primitive Types"),
                 ItemType::AssociatedType  => ("associated-types", "Associated Types"),
+                ItemType::AssociatedConst => ("associated-consts", "Associated Constants"),
             };
             try!(write!(w,
                         "<h2 id='{id}' class='section-header'>\
@@ -1799,7 +1800,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
         try!(write!(w, "{{\n"));
         for t in &types {
             try!(write!(w, "    "));
-            try!(render_method(w, t, MethodLink::Anchor));
+            try!(render_assoc_item(w, t, AssocItemLink::Anchor));
             try!(write!(w, ";\n"));
         }
         if !types.is_empty() && !required.is_empty() {
@@ -1807,7 +1808,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
         }
         for m in &required {
             try!(write!(w, "    "));
-            try!(render_method(w, m, MethodLink::Anchor));
+            try!(render_assoc_item(w, m, AssocItemLink::Anchor));
             try!(write!(w, ";\n"));
         }
         if !required.is_empty() && !provided.is_empty() {
@@ -1815,7 +1816,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
         }
         for m in &provided {
             try!(write!(w, "    "));
-            try!(render_method(w, m, MethodLink::Anchor));
+            try!(render_assoc_item(w, m, AssocItemLink::Anchor));
             try!(write!(w, " {{ ... }}\n"));
         }
         try!(write!(w, "}}"));
@@ -1831,7 +1832,7 @@ fn trait_item(w: &mut fmt::Formatter, m: &clean::Item)
                     ty = shortty(m),
                     name = *m.name.as_ref().unwrap(),
                     stab = m.stability_class()));
-        try!(render_method(w, m, MethodLink::Anchor));
+        try!(render_assoc_item(w, m, AssocItemLink::Anchor));
         try!(write!(w, "</code></h3>"));
         try!(document(w, m));
         Ok(())
@@ -1871,7 +1872,7 @@ fn trait_item(w: &mut fmt::Formatter, m: &clean::Item)
     }
 
     // If there are methods directly on this trait object, render them here.
-    try!(render_methods(w, it.def_id, MethodRender::All));
+    try!(render_assoc_items(w, it.def_id, AssocItemRender::All));
 
     let cache = cache();
     try!(write!(w, "
@@ -1903,6 +1904,17 @@ fn trait_item(w: &mut fmt::Formatter, m: &clean::Item)
     Ok(())
 }
 
+fn assoc_const(w: &mut fmt::Formatter, it: &clean::Item,
+               ty: &clean::Type, default: &Option<String>)
+               -> fmt::Result {
+    try!(write!(w, "const {}", it.name.as_ref().unwrap()));
+    try!(write!(w, ": {}", ty));
+    if let Some(ref default) = *default {
+        try!(write!(w, " = {}", default));
+    }
+    Ok(())
+}
+
 fn assoc_type(w: &mut fmt::Formatter, it: &clean::Item,
               bounds: &Vec<clean::TyParamBound>,
               default: &Option<clean::Type>)
@@ -1917,19 +1929,19 @@ fn assoc_type(w: &mut fmt::Formatter, it: &clean::Item,
     Ok(())
 }
 
-fn render_method(w: &mut fmt::Formatter, meth: &clean::Item,
-                 link: MethodLink) -> fmt::Result {
+fn render_assoc_item(w: &mut fmt::Formatter, meth: &clean::Item,
+                     link: AssocItemLink) -> fmt::Result {
     fn method(w: &mut fmt::Formatter, it: &clean::Item,
               unsafety: ast::Unsafety, abi: abi::Abi,
               g: &clean::Generics, selfty: &clean::SelfTy,
-              d: &clean::FnDecl, link: MethodLink) -> fmt::Result {
+              d: &clean::FnDecl, link: AssocItemLink) -> fmt::Result {
         use syntax::abi::Abi;
 
         let name = it.name.as_ref().unwrap();
         let anchor = format!("#{}.{}", shortty(it), name);
         let href = match link {
-            MethodLink::Anchor => anchor,
-            MethodLink::GotoSource(did) => {
+            AssocItemLink::Anchor => anchor,
+            AssocItemLink::GotoSource(did) => {
                 href(did).map(|p| format!("{}{}", p.0, anchor)).unwrap_or(anchor)
             }
         };
@@ -1958,10 +1970,13 @@ fn method(w: &mut fmt::Formatter, it: &clean::Item,
             method(w, meth, m.unsafety, m.abi, &m.generics, &m.self_, &m.decl,
                    link)
         }
+        clean::AssociatedConstItem(ref ty, ref default) => {
+            assoc_const(w, meth, ty, default)
+        }
         clean::AssociatedTypeItem(ref bounds, ref default) => {
             assoc_type(w, meth, bounds, default)
         }
-        _ => panic!("render_method called on non-method")
+        _ => panic!("render_assoc_item called on non-associated-item")
     }
 }
 
@@ -2001,7 +2016,7 @@ fn item_struct(w: &mut fmt::Formatter, it: &clean::Item,
             try!(write!(w, "</table>"));
         }
     }
-    render_methods(w, it.def_id, MethodRender::All)
+    render_assoc_items(w, it.def_id, AssocItemRender::All)
 }
 
 fn item_enum(w: &mut fmt::Formatter, it: &clean::Item,
@@ -2100,7 +2115,7 @@ fn item_enum(w: &mut fmt::Formatter, it: &clean::Item,
         try!(write!(w, "</table>"));
 
     }
-    try!(render_methods(w, it.def_id, MethodRender::All));
+    try!(render_assoc_items(w, it.def_id, AssocItemRender::All));
     Ok(())
 }
 
@@ -2184,19 +2199,19 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
 }
 
 #[derive(Copy, Clone)]
-enum MethodLink {
+enum AssocItemLink {
     Anchor,
     GotoSource(ast::DefId),
 }
 
-enum MethodRender<'a> {
+enum AssocItemRender<'a> {
     All,
     DerefFor { trait_: &'a clean::Type, type_: &'a clean::Type },
 }
 
-fn render_methods(w: &mut fmt::Formatter,
-                  it: ast::DefId,
-                  what: MethodRender) -> fmt::Result {
+fn render_assoc_items(w: &mut fmt::Formatter,
+                      it: ast::DefId,
+                      what: AssocItemRender) -> fmt::Result {
     let c = cache();
     let v = match c.impls.get(&it) {
         Some(v) => v,
@@ -2207,21 +2222,21 @@ fn render_methods(w: &mut fmt::Formatter,
     });
     if !non_trait.is_empty() {
         let render_header = match what {
-            MethodRender::All => {
+            AssocItemRender::All => {
                 try!(write!(w, "<h2 id='methods'>Methods</h2>"));
                 true
             }
-            MethodRender::DerefFor { trait_, type_ } => {
+            AssocItemRender::DerefFor { trait_, type_ } => {
                 try!(write!(w, "<h2 id='deref-methods'>Methods from \
                                     {}&lt;Target={}&gt;</h2>", trait_, type_));
                 false
             }
         };
         for i in &non_trait {
-            try!(render_impl(w, i, MethodLink::Anchor, render_header));
+            try!(render_impl(w, i, AssocItemLink::Anchor, render_header));
         }
     }
-    if let MethodRender::DerefFor { .. } = what {
+    if let AssocItemRender::DerefFor { .. } = what {
         return Ok(())
     }
     if !traits.is_empty() {
@@ -2243,7 +2258,7 @@ fn render_methods(w: &mut fmt::Formatter,
         });
         for i in &manual {
             let did = i.trait_did().unwrap();
-            try!(render_impl(w, i, MethodLink::GotoSource(did), true));
+            try!(render_impl(w, i, AssocItemLink::GotoSource(did), true));
         }
         if !derived.is_empty() {
             try!(write!(w, "<h3 id='derived_implementations'>\
@@ -2251,7 +2266,7 @@ fn render_methods(w: &mut fmt::Formatter,
             </h3>"));
             for i in &derived {
                 let did = i.trait_did().unwrap();
-                try!(render_impl(w, i, MethodLink::GotoSource(did), true));
+                try!(render_impl(w, i, AssocItemLink::GotoSource(did), true));
             }
         }
     }
@@ -2266,14 +2281,14 @@ fn render_deref_methods(w: &mut fmt::Formatter, impl_: &Impl) -> fmt::Result {
             _ => None,
         }
     }).next().unwrap();
-    let what = MethodRender::DerefFor { trait_: deref_type, type_: target };
+    let what = AssocItemRender::DerefFor { trait_: deref_type, type_: target };
     match *target {
-        clean::ResolvedPath { did, .. } => render_methods(w, did, what),
+        clean::ResolvedPath { did, .. } => render_assoc_items(w, did, what),
         _ => {
             if let Some(prim) = target.primitive_type() {
                 if let Some(c) = cache().primitive_locations.get(&prim) {
                     let did = ast::DefId { krate: *c, node: prim.to_node_id() };
-                    try!(render_methods(w, did, what));
+                    try!(render_assoc_items(w, did, what));
                 }
             }
             Ok(())
@@ -2281,7 +2296,7 @@ fn render_deref_methods(w: &mut fmt::Formatter, impl_: &Impl) -> fmt::Result {
     }
 }
 
-fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: MethodLink,
+fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: AssocItemLink,
                render_header: bool) -> fmt::Result {
     if render_header {
         try!(write!(w, "<h3 class='impl'><code>impl{} ",
@@ -2300,13 +2315,13 @@ fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: MethodLink,
     }
 
     fn doctraititem(w: &mut fmt::Formatter, item: &clean::Item,
-                    link: MethodLink) -> fmt::Result {
+                    link: AssocItemLink) -> fmt::Result {
         match item.inner {
             clean::MethodItem(..) | clean::TyMethodItem(..) => {
                 try!(write!(w, "<h4 id='method.{}' class='{}'><code>",
                             *item.name.as_ref().unwrap(),
                             shortty(item)));
-                try!(render_method(w, item, link));
+                try!(render_assoc_item(w, item, link));
                 try!(write!(w, "</code></h4>\n"));
             }
             clean::TypedefItem(ref tydef) => {
@@ -2317,6 +2332,14 @@ fn doctraititem(w: &mut fmt::Formatter, item: &clean::Item,
                 try!(write!(w, "type {} = {}", name, tydef.type_));
                 try!(write!(w, "</code></h4>\n"));
             }
+            clean::AssociatedConstItem(ref ty, ref default) => {
+                let name = item.name.as_ref().unwrap();
+                try!(write!(w, "<h4 id='assoc_const.{}' class='{}'><code>",
+                            *name,
+                            shortty(item)));
+                try!(assoc_const(w, item, ty, default));
+                try!(write!(w, "</code></h4>\n"));
+            }
             clean::AssociatedTypeItem(ref bounds, ref default) => {
                 let name = item.name.as_ref().unwrap();
                 try!(write!(w, "<h4 id='assoc_type.{}' class='{}'><code>",
@@ -2327,7 +2350,7 @@ fn doctraititem(w: &mut fmt::Formatter, item: &clean::Item,
             }
             _ => panic!("can't make docs for trait item with name {:?}", item.name)
         }
-        if let MethodLink::Anchor = link {
+        if let AssocItemLink::Anchor = link {
             document(w, item)
         } else {
             Ok(())
@@ -2339,10 +2362,10 @@ fn doctraititem(w: &mut fmt::Formatter, item: &clean::Item,
         try!(doctraititem(w, trait_item, link));
     }
 
-    fn render_default_methods(w: &mut fmt::Formatter,
-                              did: ast::DefId,
-                              t: &clean::Trait,
-                              i: &clean::Impl) -> fmt::Result {
+    fn render_default_items(w: &mut fmt::Formatter,
+                            did: ast::DefId,
+                            t: &clean::Trait,
+                            i: &clean::Impl) -> fmt::Result {
         for trait_item in &t.items {
             let n = trait_item.name.clone();
             match i.items.iter().find(|m| { m.name == n }) {
@@ -2350,7 +2373,7 @@ fn render_default_methods(w: &mut fmt::Formatter,
                 None => {}
             }
 
-            try!(doctraititem(w, trait_item, MethodLink::GotoSource(did)));
+            try!(doctraititem(w, trait_item, AssocItemLink::GotoSource(did)));
         }
         Ok(())
     }
@@ -2361,7 +2384,7 @@ fn render_default_methods(w: &mut fmt::Formatter,
     // for them work.
     if let Some(clean::ResolvedPath { did, .. }) = i.impl_.trait_ {
         if let Some(t) = cache().traits.get(&did) {
-            try!(render_default_methods(w, did, t, &i.impl_));
+            try!(render_default_items(w, did, t, &i.impl_));
         }
     }
     try!(write!(w, "</div>"));
@@ -2458,7 +2481,7 @@ fn item_primitive(w: &mut fmt::Formatter,
                   it: &clean::Item,
                   _p: &clean::PrimitiveType) -> fmt::Result {
     try!(document(w, it));
-    render_methods(w, it.def_id, MethodRender::All)
+    render_assoc_items(w, it.def_id, AssocItemRender::All)
 }
 
 fn get_basic_keywords() -> &'static str {
index c94dbc15103321f031d33a8ed0d587484d239530..b907e9e20b69867df2040215fb2b2ad68f8158cf 100644 (file)
@@ -392,7 +392,7 @@ a {
     text-decoration: underline;
 }
 
-.content span.trait, .content a.trait, .block a.current.trait { color: #ed9603; }
+.content span.trait, .content a.trait, .block a.current.trait { color: #8866ff; }
 .content span.mod, .content a.mod, block a.current.mod { color: #4d76ae; }
 .content span.enum, .content a.enum, .block a.current.enum { color: #5e9766; }
 .content span.struct, .content a.struct, .block a.current.struct { color: #e53700; }
index 56cea50a502399cae7e4279f07eff6d2852b3c3f..c2a59278a86dc79dbaff558c130461602299871f 100644 (file)
 
     $("#toggle-all-docs").on("click", function() {
         var toggle = $("#toggle-all-docs");
-        if (toggle.html() == "[-]") {
-            toggle.html("[+]");
+        if (toggle.html() == "[&minus;]") {
+            toggle.html("[&plus;]");
             toggle.attr("title", "expand all docs");
             $(".docblock").hide();
             $(".toggle-label").show();
             $(".toggle-wrapper").addClass("collapsed");
-            $(".collapse-toggle").children(".inner").html("+");
+            $(".collapse-toggle").children(".inner").html("&plus;");
         } else {
-            toggle.html("[-]");
+            toggle.html("[&minus;]");
             toggle.attr("title", "collapse all docs");
             $(".docblock").show();
             $(".toggle-label").hide();
             $(".toggle-wrapper").removeClass("collapsed");
-            $(".collapse-toggle").children(".inner").html("-");
+            $(".collapse-toggle").children(".inner").html("&minus;");
         }
     });
 
             if (relatedDoc.is(":visible")) {
                 relatedDoc.slideUp({duration:'fast', easing:'linear'});
                 toggle.parent(".toggle-wrapper").addClass("collapsed");
-                toggle.children(".inner").html("+");
+                toggle.children(".inner").html("&plus;");
                 toggle.children(".toggle-label").fadeIn();
             } else {
                 relatedDoc.slideDown({duration:'fast', easing:'linear'});
                 toggle.parent(".toggle-wrapper").removeClass("collapsed");
-                toggle.children(".inner").html("-");
+                toggle.children(".inner").html("&minus;");
                 toggle.children(".toggle-label").hide();
             }
         }
 
     $(function() {
         var toggle = $("<a/>", {'href': 'javascript:void(0)', 'class': 'collapse-toggle'})
-            .html("[<span class='inner'>-</span>]");
+            .html("[<span class='inner'>&minus;</span>]");
 
         $(".method").each(function() {
             if ($(this).next().is(".docblock") ||
index 78feb6c77c45451f8f2df38420c850651825923c..93aa74d7005f6d8989cbae865218d8d421165596 100644 (file)
@@ -198,7 +198,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use super::{TocBuilder, Toc, TocEntry};
 
     #[test]
index 53cfbb3efdda528aa39ca1a45b390ba0e7724542..74c16127f41ccac87c3bf3aba6d2acb37b644c7e 100644 (file)
@@ -184,7 +184,8 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
             // Primitives are never stripped
             clean::PrimitiveItem(..) => {}
 
-            // Associated types are never stripped
+            // Associated consts and types are never stripped
+            clean::AssociatedConstItem(..) |
             clean::AssociatedTypeItem(..) => {}
         }
 
index d0f990eaf782a5d0c25c17e74ba62e8fd7296334..8b90fce6fc4fc075709c354600e9d1daf4b18782 100644 (file)
@@ -117,7 +117,7 @@ pub unsafe fn symbol<T>(&self, symbol: &str) -> Result<*mut T, String> {
 }
 
 #[cfg(all(test, not(target_os = "ios")))]
-mod test {
+mod tests {
     use super::*;
     use prelude::v1::*;
     use libc;
@@ -125,7 +125,9 @@ mod test {
     use path::Path;
 
     #[test]
-    #[cfg_attr(any(windows, target_os = "android"), ignore)] // FIXME #8818, #10379
+    #[cfg_attr(any(windows,
+                   target_os = "android",  // FIXME #10379
+                   target_env = "musl"), ignore)]
     fn test_loading_cosine() {
         // The math library does not need to be loaded since it is already
         // statically linked in
index 42fad701533b2b04ad1a228016738c8958c3e629..a9dab8191fd9c90dfa43d3a562e1fc532e6fab84 100644 (file)
@@ -418,7 +418,7 @@ pub fn _print(args: fmt::Arguments) {
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use thread;
     use super::*;
 
index c82f9515e8d52813ba494a6b0a48b0b71bc27a65..d797e757a483ecf687d686327ed876a64c987223 100644 (file)
@@ -102,7 +102,7 @@ fn flush(&mut self) -> io::Result<()> { Ok(()) }
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use prelude::v1::*;
 
     use io::prelude::*;
index 11b057d0094ae1d0674b22db405f03307eb35a47..7366524fd7ea82f1729f67578920b5e0ac2adc41 100644 (file)
@@ -17,7 +17,7 @@
 use cell::RefCell;
 use rt::{backtrace, unwind};
 use sys::stdio::Stderr;
-use thread;
+use sys_common::thread_info;
 
 thread_local! {
     pub static LOCAL_STDERR: RefCell<Option<Box<Write + Send>>> = {
@@ -34,8 +34,8 @@ pub fn on_panic(obj: &(Any+Send), file: &'static str, line: u32) {
         }
     };
     let mut err = Stderr::new();
-    let thread = thread::current();
-    let name = thread.name().unwrap_or("<unnamed>");
+    let thread = thread_info::current_thread();
+    let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>");
     let prev = LOCAL_STDERR.with(|s| s.borrow_mut().take());
     match prev {
         Some(mut stderr) => {
index e8052041aeb300a669eee29af47b3a74287fed9a..2ceb60cc3aa9f7132b518f4708eb5f2fb7b982a9 100644 (file)
@@ -1241,6 +1241,16 @@ fn as_u8_slice(&self) -> &[u8] {
     ///
     /// Path::new("foo.txt");
     /// ```
+    ///
+    /// You can create `Path`s from `String`s, or even other `Path`s:
+    ///
+    /// ```
+    /// use std::path::Path;
+    ///
+    /// let s = String::from("bar.txt");
+    /// let p = Path::new(&s);
+    /// Path::new(&p);
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &Path {
         unsafe { mem::transmute(s.as_ref()) }
index 30d5ae5c6008beb7ba02865df4f745d18c4d6b36..a04bb6705b32167c9329bbce4c1b2d94f065d3d5 100644 (file)
@@ -346,7 +346,7 @@ fn drop(&mut self) {
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use prelude::v1::*;
 
     use sync::mpsc::channel;
index 2837bac445697348b4472a7034d27e92e193b059..d19bc5b617f8462e62f0ddc5f1c618ccd74d6d0a 100644 (file)
@@ -63,7 +63,7 @@ fn fill_bytes(&mut self, mut v: &mut [u8]) {
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use prelude::v1::*;
 
     use super::ReaderRng;
index ced84d7551eef349989e897afd1598264288d366..72cbe2b533bb7fc6b62cf366861085d55945e186 100644 (file)
@@ -38,7 +38,7 @@ pub fn log_enabled() -> bool {
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use prelude::v1::*;
     use sys_common;
     macro_rules! t { ($a:expr, $b:expr) => ({
index 4b754bd5f589f22ac3d957986a6fcc536769d9bf..8f75ae5ef5cc8441cd5b3e687a8465687e7928f1 100644 (file)
@@ -97,10 +97,15 @@ pub enum _Unwind_Context {}
         extern "C" fn(unwind_code: _Unwind_Reason_Code,
                       exception: *mut _Unwind_Exception);
 
-#[cfg(any(target_os = "linux", target_os = "freebsd"))]
+#[cfg(any(all(target_os = "linux", not(target_env = "musl")),
+          target_os = "freebsd"))]
 #[link(name = "gcc_s")]
 extern {}
 
+#[cfg(all(target_os = "linux", target_env = "musl", not(test)))]
+#[link(name = "unwind", kind = "static")]
+extern {}
+
 #[cfg(any(target_os = "android", target_os = "openbsd"))]
 #[link(name = "gcc")]
 extern {}
index 96c4bcec853dc28d8d687eae95b3b1e64f9f5a22..a7f3bc2bdc82c3a07d5d9441599f74afc9a0d819 100644 (file)
@@ -24,7 +24,7 @@
 //
 // On Linux, librt and libdl are indirect dependencies via std,
 // and binutils 2.22+ won't add them automatically
-#[cfg(target_os = "linux")]
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
 #[link(name = "dl")]
 #[link(name = "pthread")]
 extern {}
index 2cdde1aca9e682c7696d67ffad62c8f45adaa043..2d281eb4e249ca2be556107d114a100b9c6523f1 100644 (file)
@@ -155,7 +155,7 @@ pub fn spawn<F>(blk: F) -> Future<A>
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use prelude::v1::*;
     use sync::mpsc::channel;
     use sync::Future;
index b3cc133d229465bf1a3a1b0bdfe988c800c1f02c..74e85db1a06ff1eba3517292ea35281c167ee984 100644 (file)
@@ -1065,7 +1065,7 @@ fn cause(&self) -> Option<&error::Error> {
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use prelude::v1::*;
 
     use std::env;
index b8ad92841f2de65a8a7e8ef3df3a17886829fb6e..58f16a83ba9353d164ec01515f5fd52b6ba391d8 100644 (file)
@@ -346,7 +346,7 @@ fn next(&mut self) -> Option<*mut Handle<'static, ()>> {
 
 #[cfg(test)]
 #[allow(unused_imports)]
-mod test {
+mod tests {
     use prelude::v1::*;
 
     use thread;
index c75ac13080866ce2a0f3376a91cf830af7691ac0..4dd84364fa80ef0634832e194cf4242e04cd9272 100644 (file)
@@ -241,7 +241,7 @@ fn drop(&mut self) {
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use prelude::v1::*;
 
     use sync::Arc;
index 5e688717c4a28865cfcde04e427ebcd11c51b1e2..caf011c54f27a1c82b7b766f2a71c5d0bef5441c 100644 (file)
@@ -361,7 +361,7 @@ pub fn guard_poison<'a, T>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag {
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use prelude::v1::*;
 
     use sync::mpsc::channel;
index 948965f5efa9d157dca85f7e0121eba169546dc0..2ce974c1271aad77cb09b89ddb404caa829075d0 100644 (file)
@@ -121,7 +121,7 @@ pub fn call_once<F>(&'static self, f: F) where F: FnOnce() {
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use prelude::v1::*;
 
     use thread;
index 7d42d65d360f548db50943439b54c8908ffd6854..2b2c31d92edad45f151998aa7bc124fe26d3c644 100644 (file)
@@ -202,15 +202,19 @@ fn set_tcp_keepalive(&self, seconds: u32) -> io::Result<()> {
         setsockopt(&self.inner, libc::IPPROTO_TCP, libc::TCP_KEEPALIVE,
                    seconds as c_int)
     }
-    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
+    #[cfg(any(target_os = "freebsd",
+              target_os = "dragonfly",
+              target_os = "linux"))]
     fn set_tcp_keepalive(&self, seconds: u32) -> io::Result<()> {
         setsockopt(&self.inner, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE,
                    seconds as c_int)
     }
+
     #[cfg(not(any(target_os = "macos",
                   target_os = "ios",
                   target_os = "freebsd",
-                  target_os = "dragonfly")))]
+                  target_os = "dragonfly",
+                  target_os = "linux")))]
     fn set_tcp_keepalive(&self, _seconds: u32) -> io::Result<()> {
         Ok(())
     }
index b35063c0e234126757410e5d75e97b79f39ca385..00238500c3a85ae77b83230edd26fb3e8e89da5d 100644 (file)
@@ -151,7 +151,7 @@ fn drop(&mut self) {
 
 
 #[cfg(test)]
-mod test {
+mod tests {
     use prelude::v1::*;
     use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
     use cell::RefCell;
index 22cb59433713043dbaf2a3409072e147e13901c5..ae55bae37aa884e3870e7b43315f745e425a927d 100644 (file)
@@ -25,10 +25,9 @@ struct ThreadInfo {
 thread_local! { static THREAD_INFO: RefCell<Option<ThreadInfo>> = RefCell::new(None) }
 
 impl ThreadInfo {
-    fn with<R, F>(f: F) -> R where F: FnOnce(&mut ThreadInfo) -> R {
+    fn with<R, F>(f: F) -> Option<R> where F: FnOnce(&mut ThreadInfo) -> R {
         if THREAD_INFO.state() == LocalKeyState::Destroyed {
-            panic!("Use of std::thread::current() is not possible after \
-                    the thread's local data has been destroyed");
+            return None
         }
 
         THREAD_INFO.with(move |c| {
@@ -38,16 +37,16 @@ fn with<R, F>(f: F) -> R where F: FnOnce(&mut ThreadInfo) -> R {
                     thread: NewThread::new(None),
                 })
             }
-            f(c.borrow_mut().as_mut().unwrap())
+            Some(f(c.borrow_mut().as_mut().unwrap()))
         })
     }
 }
 
-pub fn current_thread() -> Thread {
+pub fn current_thread() -> Option<Thread> {
     ThreadInfo::with(|info| info.thread.clone())
 }
 
-pub fn stack_guard() -> usize {
+pub fn stack_guard() -> Option<usize> {
     ThreadInfo::with(|info| info.stack_guard)
 }
 
index 9504fe636978859d6b103d9317dd41cababe9a3b..66aaf26b09b72e1ff58b82002e463b7110732160 100644 (file)
@@ -249,6 +249,7 @@ fn mode(&mut self, mode: i32) -> &mut OpenOptions {
     /// # Ok(())
     /// # }
     /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()>
     {
         sys::fs2::symlink(src.as_ref(), dst.as_ref())
index 6887095c53a7d1cdc24a5a7cf7d1acfe5b9a8baf..2bc280d12743958fbe5a1ff36b9c96960a27b223 100644 (file)
@@ -81,7 +81,7 @@ unsafe fn term(signum: libc::c_int) -> ! {
         // We're calling into functions with stack checks
         stack::record_sp_limit(0);
 
-        let guard = thread_info::stack_guard();
+        let guard = thread_info::stack_guard().unwrap_or(0);
         let addr = (*info).si_addr as usize;
 
         if guard == 0 || addr < guard - PAGE_SIZE || addr >= guard {
index 281ac37e671152845bc3caaddf807f9e4a533133..cfab9d1c51a153d988b926bf16b158629c0856fe 100644 (file)
@@ -342,7 +342,10 @@ fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize {
     static mut __pthread_get_minstack: Option<F> = None;
 
     INIT.call_once(|| {
-        let lib = DynamicLibrary::open(None).unwrap();
+        let lib = match DynamicLibrary::open(None) {
+            Ok(l) => l,
+            Err(..) => return,
+        };
         unsafe {
             if let Ok(f) = lib.symbol("__pthread_get_minstack") {
                 __pthread_get_minstack = Some(mem::transmute::<*const (), F>(f));
index d2f51678d497fa737c463c0089b4729fe63b1a73..f59eb2c03013fd5eaa53c0e5050bf9b9969edf57 100644 (file)
@@ -82,7 +82,8 @@ pub struct SteadyTime {
     // OpenBSD provide it via libc
     #[cfg(not(any(target_os = "android",
                   target_os = "bitrig",
-                  target_os = "openbsd")))]
+                  target_os = "openbsd",
+                  target_env = "musl")))]
     #[link(name = "rt")]
     extern {}
 
index eac6496870eabcd2f79720e8c647a20df9b7ff6d..dd747d202a04b7195692ee03112419e4a95def47 100644 (file)
@@ -256,6 +256,7 @@ fn share_mode(&mut self, access: i32) -> &mut OpenOptions {
     /// # Ok(())
     /// # }
     /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q)
                                                         -> io::Result<()>
     {
@@ -278,6 +279,7 @@ pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q)
     /// # Ok(())
     /// # }
     /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>> (src: P, dst: Q)
                                                         -> io::Result<()>
     {
index 5ddcf3d1ea2991f9f62ce90b436b2d6a3510b005..2e5585d2f4389a8a51307594c6ecd49062d0a4e9 100644 (file)
@@ -367,6 +367,8 @@ fn zeroed_process_information() -> libc::types::os::arch::extra::PROCESS_INFORMA
 
 // Produces a wide string *without terminating null*
 fn make_command_line(prog: &OsStr, args: &[OsString]) -> Vec<u16> {
+    // Encode the command and arguments in a command line string such
+    // that the spawned process may recover them using CommandLineToArgvW.
     let mut cmd: Vec<u16> = Vec::new();
     append_arg(&mut cmd, prog);
     for arg in args {
@@ -387,30 +389,27 @@ fn append_arg(cmd: &mut Vec<u16>, arg: &OsStr) {
         }
 
         let mut iter = arg.encode_wide();
+        let mut backslashes: usize = 0;
         while let Some(x) = iter.next() {
-            if x == '"' as u16 {
-                // escape quotes
-                cmd.push('\\' as u16);
-                cmd.push('"' as u16);
-            } else if x == '\\' as u16 {
-                // is this a run of backslashes followed by a " ?
-                if iter.clone().skip_while(|y| *y == '\\' as u16).next() == Some('"' as u16) {
-                    // Double it ... NOTE: this behavior is being
-                    // preserved as it's been part of Rust for a long
-                    // time, but no one seems to know exactly why this
-                    // is the right thing to do.
-                    cmd.push('\\' as u16);
-                    cmd.push('\\' as u16);
-                } else {
-                    // Push it through unescaped
-                    cmd.push('\\' as u16);
-                }
+            if x == '\\' as u16 {
+                backslashes += 1;
             } else {
-                cmd.push(x)
+                if x == '"' as u16 {
+                    // Add n+1 backslashes to total 2n+1 before internal '"'.
+                    for _ in 0..(backslashes+1) {
+                        cmd.push('\\' as u16);
+                    }
+                }
+                backslashes = 0;
             }
+            cmd.push(x);
         }
 
         if quote {
+            // Add n backslashes to total 2n before ending '"'.
+            for _ in 0..backslashes {
+                cmd.push('\\' as u16);
+            }
             cmd.push('"' as u16);
         }
     }
@@ -486,6 +485,10 @@ fn test_wrapper(prog: &str, args: &[&str]) -> String {
             test_wrapper("echo", &["a b c"]),
             "echo \"a b c\""
         );
+        assert_eq!(
+            test_wrapper("echo", &["\" \\\" \\", "\\"]),
+            "echo \"\\\" \\\\\\\" \\\\\" \\"
+        );
         assert_eq!(
             test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[]),
             "\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}"
index 6d8f1cba7091f0b3dbf2f567e56c9c55e9aaa69b..bb2832b874657deb26f0b0dc983e2326e197a40b 100644 (file)
@@ -18,7 +18,6 @@
 
 // Sure wish we had macro hygiene, no?
 #[doc(hidden)]
-#[unstable(feature = "thread_local_internals")]
 pub mod __impl {
     pub use super::imp::Key as KeyInner;
     pub use super::imp::destroy_value;
@@ -78,12 +77,10 @@ pub struct LocalKey<T> {
     // This is trivially devirtualizable by LLVM because we never store anything
     // to this field and rustc can declare the `static` as constant as well.
     #[doc(hidden)]
-    #[unstable(feature = "thread_local_internals")]
     pub inner: fn() -> &'static __impl::KeyInner<UnsafeCell<Option<T>>>,
 
     // initialization routine to invoke to create a value
     #[doc(hidden)]
-    #[unstable(feature = "thread_local_internals")]
     pub init: fn() -> T,
 }
 
@@ -297,6 +294,7 @@ pub fn state(&'static self) -> LocalKeyState {
 }
 
 #[cfg(all(any(target_os = "macos", target_os = "linux"), not(target_arch = "aarch64")))]
+#[doc(hidden)]
 mod imp {
     use prelude::v1::*;
 
@@ -304,8 +302,6 @@ mod imp {
     use intrinsics;
     use ptr;
 
-    #[doc(hidden)]
-    #[unstable(feature = "thread_local_internals")]
     pub struct Key<T> {
         // Place the inner bits in an `UnsafeCell` to currently get around the
         // "only Sync statics" restriction. This allows any type to be placed in
@@ -313,20 +309,16 @@ pub struct Key<T> {
         //
         // Note that all access requires `T: 'static` so it can't be a type with
         // any borrowed pointers still.
-        #[unstable(feature = "thread_local_internals")]
         pub inner: UnsafeCell<T>,
 
         // Metadata to keep track of the state of the destructor. Remember that
         // these variables are thread-local, not global.
-        #[unstable(feature = "thread_local_internals")]
         pub dtor_registered: UnsafeCell<bool>, // should be Cell
-        #[unstable(feature = "thread_local_internals")]
         pub dtor_running: UnsafeCell<bool>, // should be Cell
     }
 
     unsafe impl<T> ::marker::Sync for Key<T> { }
 
-    #[doc(hidden)]
     impl<T> Key<T> {
         pub unsafe fn get(&'static self) -> Option<&'static T> {
             if intrinsics::needs_drop::<T>() && *self.dtor_running.get() {
@@ -364,6 +356,7 @@ unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
         use sys_common::thread_local as os;
 
         extern {
+            #[linkage = "extern_weak"]
             static __dso_handle: *mut u8;
             #[linkage = "extern_weak"]
             static __cxa_thread_atexit_impl: *const ();
@@ -422,8 +415,6 @@ fn _tlv_atexit(dtor: unsafe extern fn(*mut u8),
         _tlv_atexit(dtor, t);
     }
 
-    #[doc(hidden)]
-    #[unstable(feature = "thread_local_internals")]
     pub unsafe extern fn destroy_value<T>(ptr: *mut u8) {
         let ptr = ptr as *mut Key<T>;
         // Right before we run the user destructor be sure to flag the
@@ -435,6 +426,7 @@ fn _tlv_atexit(dtor: unsafe extern fn(*mut u8),
 }
 
 #[cfg(any(not(any(target_os = "macos", target_os = "linux")), target_arch = "aarch64"))]
+#[doc(hidden)]
 mod imp {
     use prelude::v1::*;
 
@@ -444,16 +436,12 @@ mod imp {
     use ptr;
     use sys_common::thread_local::StaticKey as OsStaticKey;
 
-    #[doc(hidden)]
-    #[unstable(feature = "thread_local_internals")]
     pub struct Key<T> {
         // Statically allocated initialization expression, using an `UnsafeCell`
         // for the same reasons as above.
-        #[unstable(feature = "thread_local_internals")]
         pub inner: UnsafeCell<T>,
 
         // OS-TLS key that we'll use to key off.
-        #[unstable(feature = "thread_local_internals")]
         pub os: OsStaticKey,
     }
 
@@ -464,7 +452,6 @@ struct Value<T: 'static> {
         value: T,
     }
 
-    #[doc(hidden)]
     impl<T> Key<T> {
         pub unsafe fn get(&'static self) -> Option<&'static T> {
             self.ptr().map(|p| &*p)
@@ -489,14 +476,12 @@ unsafe fn ptr(&'static self) -> Option<*mut T> {
                 key: self,
                 value: mem::transmute_copy(&self.inner),
             };
-            let ptr: *mut Value<T> = boxed::into_raw(ptr);
+            let ptr = boxed::into_raw(ptr);
             self.os.set(ptr as *mut u8);
             Some(&mut (*ptr).value as *mut T)
         }
     }
 
-    #[doc(hidden)]
-    #[unstable(feature = "thread_local_internals")]
     pub unsafe extern fn destroy_value<T: 'static>(ptr: *mut u8) {
         // The OS TLS ensures that this key contains a NULL value when this
         // destructor starts to run. We set it back to a sentinel value of 1 to
@@ -505,7 +490,7 @@ unsafe fn ptr(&'static self) -> Option<*mut T> {
         //
         // Note that to prevent an infinite loop we reset it back to null right
         // before we return from the destructor ourselves.
-        let ptr: Box<Value<T>> = Box::from_raw(ptr as *mut Value<T>);
+        let ptr = Box::from_raw(ptr as *mut Value<T>);
         let key = ptr.key;
         key.os.set(1 as *mut u8);
         drop(ptr);
index 28e4650478bb346ddf50d89be06e8f356f069753..ce531fb13812c30db599fef9a42b10e8f3a8aad0 100644 (file)
 //! ## Configuring threads
 //!
 //! A new thread can be configured before it is spawned via the `Builder` type,
-//! which currently allows you to set the name, stack size, and writers for
-//! `println!` and `panic!` for the child thread:
+//! which currently allows you to set the name and stack size for the child thread:
 //!
 //! ```rust
 //! # #![allow(unused_must_use)]
@@ -408,7 +407,9 @@ pub fn scoped<'a, T, F>(f: F) -> JoinGuard<'a, T> where
 /// Gets a handle to the thread that invokes it.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn current() -> Thread {
-    thread_info::current_thread()
+    thread_info::current_thread().expect("use of std::thread::current() is not \
+                                          possible after the thread's local \
+                                          data has been destroyed")
 }
 
 /// Cooperatively gives up a timeslice to the OS scheduler.
@@ -722,7 +723,7 @@ fn _assert_both<T: Send + Sync>() {}
 ////////////////////////////////////////////////////////////////////////////////
 
 #[cfg(test)]
-mod test {
+mod tests {
     use prelude::v1::*;
 
     use any::Any;
index 399810cb7f5010ae6d6a4042efadd15bbd347e1e..3b7bfb1043a35acc543fb9851df9422d8c45d1f3 100644 (file)
@@ -89,12 +89,6 @@ pub fn new(name: Name) -> Ident { Ident {name: name, ctxt: EMPTY_CTXT}}
     pub fn as_str<'a>(&'a self) -> &'a str {
         self.name.as_str()
     }
-
-    pub fn encode_with_hygiene(&self) -> String {
-        format!("\x00name_{},ctxt_{}\x00",
-                self.name.usize(),
-                self.ctxt)
-    }
 }
 
 impl fmt::Debug for Ident {
@@ -599,6 +593,12 @@ pub enum Pat_ {
     /// "None" means a * pattern where we don't bind the fields to names.
     PatEnum(Path, Option<Vec<P<Pat>>>),
 
+    /// An associated const named using the qualified path `<T>::CONST` or
+    /// `<T as Trait>::CONST`. Associated consts from inherent impls can be
+    /// refered to as simply `T::CONST`, in which case they will end up as
+    /// PatEnum, and the resolver will have to sort that out.
+    PatQPath(QSelf, Path),
+
     /// Destructuring of a struct, e.g. `Foo {x, y, ..}`
     /// The `bool` is `true` in the presence of a `..`
     PatStruct(Path, Vec<Spanned<FieldPat>>, bool),
@@ -1236,6 +1236,7 @@ pub struct TraitItem {
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum TraitItem_ {
+    ConstTraitItem(P<Ty>, Option<P<Expr>>),
     MethodTraitItem(MethodSig, Option<P<Block>>),
     TypeTraitItem(TyParamBounds, Option<P<Ty>>),
 }
@@ -1252,6 +1253,7 @@ pub struct ImplItem {
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum ImplItem_ {
+    ConstImplItem(P<Ty>, P<Expr>),
     MethodImplItem(MethodSig, P<Block>),
     TypeImplItem(P<Ty>),
     MacImplItem(Mac),
@@ -1869,7 +1871,7 @@ pub struct MacroDef {
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use serialize;
     use super::*;
 
index 1505d1e91b8206a9e44b8b4b5b938b16f35b6d06..36a7f3a93817c127b966e56ea6099ee55446e08e 100644 (file)
@@ -222,8 +222,7 @@ fn handle<A, I, M, C>(self, item_fn: I, method: M, closure: C) -> A where
                     ast::MethodImplItem(ref sig, ref body) => {
                         method(ii.id, ii.ident, sig, Some(ii.vis), body, ii.span)
                     }
-                    ast::TypeImplItem(_) |
-                    ast::MacImplItem(_) => {
+                    _ => {
                         panic!("impl method FnLikeNode that is not fn-like")
                     }
                 }
index 2a9a609ecd1e9dcbc89278eb04806f1c88dd77c0..795391d4009144cea3a2682086d5497b725a50a7 100644 (file)
@@ -940,6 +940,12 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
         }
         Some(NodeImplItem(ii)) => {
             match ii.node {
+                ConstImplItem(..) => {
+                    format!("assoc const {} in {}{}",
+                            token::get_ident(ii.ident),
+                            map.path_to_string(id),
+                            id_str)
+                }
                 MethodImplItem(..) => {
                     format!("method {} in {}{}",
                             token::get_ident(ii.ident),
@@ -959,9 +965,9 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
         }
         Some(NodeTraitItem(ti)) => {
             let kind = match ti.node {
+                ConstTraitItem(..) => "assoc constant",
                 MethodTraitItem(..) => "trait method",
                 TypeTraitItem(..) => "assoc type",
-//                 ConstTraitItem(..) => "assoc constant"
             };
 
             format!("{} {} in {}{}",
index 78f06ce5fd5d07f8025a4c5e1b688d0ce32afbcb..8471fef3487e62f53af6d48d68eaab0fa040d444 100644 (file)
@@ -579,7 +579,7 @@ fn walk_pat_<G>(pat: &Pat, it: &mut G) -> bool where G: FnMut(&Pat) -> bool {
             }
             PatMac(_) => panic!("attempted to analyze unexpanded pattern"),
             PatWild(_) | PatLit(_) | PatRange(_, _) | PatIdent(_, _, _) |
-            PatEnum(_, _) => {
+            PatEnum(_, _) | PatQPath(_, _) => {
                 true
             }
         }
@@ -632,7 +632,7 @@ pub fn lit_is_str(lit: &Lit) -> bool {
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use ast::*;
     use super::*;
 
index 34ad192845c58e2f94a6f5d150b81b6e3a893452..5e0cb647c8b41072ff2242d9c4dc9fcc7208f454 100644 (file)
@@ -949,7 +949,7 @@ pub struct MalformedCodemapPositions {
 //
 
 #[cfg(test)]
-mod test {
+mod tests {
     use super::*;
     use std::rc::Rc;
 
index d1db956adb3f5a13f28576ff6ac5ceab1802a800..4ea2d4e5c686c8b53115fcf1c2f2aa187c7adedd 100644 (file)
@@ -1553,7 +1553,7 @@ fn visit_mac(&mut self, mac: &ast::Mac) {
 
 
 #[cfg(test)]
-mod test {
+mod tests {
     use super::{pattern_bindings, expand_crate};
     use super::{PatIdentFinder, IdentRenamer, PatIdentRenamer, ExpansionConfig};
     use ast;
index 5776fa997407687b4902c0c9ba3309684061c846..e100b7705d8178ff813058b8a7aa8813f695f531 100644 (file)
@@ -30,16 +30,16 @@ pub mod rt {
     use ext::base::ExtCtxt;
     use parse::token;
     use parse;
-    use print::pprust;
     use ptr::P;
+    use std::rc::Rc;
 
-    use ast::{TokenTree, Generics, Expr};
+    use ast::{TokenTree, Expr};
 
     pub use parse::new_parser_from_tts;
-    pub use codemap::{BytePos, Span, dummy_spanned};
+    pub use codemap::{BytePos, Span, dummy_spanned, DUMMY_SP};
 
     pub trait ToTokens {
-        fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> ;
+        fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree>;
     }
 
     impl ToTokens for TokenTree {
@@ -70,277 +70,189 @@ fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
         }
     }
 
-    /* Should be (when bugs in default methods are fixed):
-
-    trait ToSource : ToTokens {
-        // Takes a thing and generates a string containing rust code for it.
-        pub fn to_source() -> String;
-
-        // If you can make source, you can definitely make tokens.
-        pub fn to_tokens(cx: &ExtCtxt) -> ~[TokenTree] {
-            cx.parse_tts(self.to_source())
+    impl ToTokens for ast::Ident {
+        fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+            vec![ast::TtToken(DUMMY_SP, token::Ident(*self, token::Plain))]
         }
     }
 
-    */
-
-    // FIXME: Move this trait to pprust and get rid of *_to_str?
-    pub trait ToSource {
-        // Takes a thing and generates a string containing rust code for it.
-        fn to_source(&self) -> String;
+    impl ToTokens for ast::Path {
+        fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+            vec![ast::TtToken(DUMMY_SP, token::Interpolated(token::NtPath(Box::new(self.clone()))))]
+        }
     }
 
-    // FIXME (Issue #16472): This should go away after ToToken impls
-    // are revised to go directly to token-trees.
-    trait ToSourceWithHygiene : ToSource {
-        // Takes a thing and generates a string containing rust code
-        // for it, encoding Idents as special byte sequences to
-        // maintain hygiene across serialization and deserialization.
-        fn to_source_with_hygiene(&self) -> String;
+    impl ToTokens for ast::Ty {
+        fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+            vec![ast::TtToken(self.span, token::Interpolated(token::NtTy(P(self.clone()))))]
+        }
     }
 
-    macro_rules! impl_to_source {
-        (P<$t:ty>, $pp:ident) => (
-            impl ToSource for P<$t> {
-                fn to_source(&self) -> String {
-                    pprust::$pp(&**self)
-                }
-            }
-            impl ToSourceWithHygiene for P<$t> {
-                fn to_source_with_hygiene(&self) -> String {
-                    pprust::with_hygiene::$pp(&**self)
-                }
-            }
-        );
-        ($t:ty, $pp:ident) => (
-            impl ToSource for $t {
-                fn to_source(&self) -> String {
-                    pprust::$pp(self)
-                }
-            }
-            impl ToSourceWithHygiene for $t {
-                fn to_source_with_hygiene(&self) -> String {
-                    pprust::with_hygiene::$pp(self)
-                }
-            }
-        );
+    impl ToTokens for ast::Block {
+        fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+            vec![ast::TtToken(self.span, token::Interpolated(token::NtBlock(P(self.clone()))))]
+        }
     }
 
-    fn slice_to_source<'a, T: ToSource>(sep: &'static str, xs: &'a [T]) -> String {
-        xs.iter()
-            .map(|i| i.to_source())
-            .collect::<Vec<String>>()
-            .connect(sep)
-            .to_string()
+    impl ToTokens for P<ast::Item> {
+        fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+            vec![ast::TtToken(self.span, token::Interpolated(token::NtItem(self.clone())))]
+        }
     }
 
-    fn slice_to_source_with_hygiene<'a, T: ToSourceWithHygiene>(
-        sep: &'static str, xs: &'a [T]) -> String {
-        xs.iter()
-            .map(|i| i.to_source_with_hygiene())
-            .collect::<Vec<String>>()
-            .connect(sep)
-            .to_string()
+    impl ToTokens for P<ast::ImplItem> {
+        fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+            vec![ast::TtToken(self.span, token::Interpolated(token::NtImplItem(self.clone())))]
+        }
     }
 
-    macro_rules! impl_to_source_slice {
-        ($t:ty, $sep:expr) => (
-            impl ToSource for [$t] {
-                fn to_source(&self) -> String {
-                    slice_to_source($sep, self)
-                }
-            }
-
-            impl ToSourceWithHygiene for [$t] {
-                fn to_source_with_hygiene(&self) -> String {
-                    slice_to_source_with_hygiene($sep, self)
-                }
-            }
-        )
+    impl ToTokens for P<ast::TraitItem> {
+        fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+            vec![ast::TtToken(self.span, token::Interpolated(token::NtTraitItem(self.clone())))]
+        }
     }
 
-    impl ToSource for ast::Ident {
-        fn to_source(&self) -> String {
-            token::get_ident(*self).to_string()
+    impl ToTokens for P<ast::Stmt> {
+        fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+            vec![ast::TtToken(self.span, token::Interpolated(token::NtStmt(self.clone())))]
         }
     }
 
-    impl ToSourceWithHygiene for ast::Ident {
-        fn to_source_with_hygiene(&self) -> String {
-            self.encode_with_hygiene()
+    impl ToTokens for P<ast::Expr> {
+        fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+            vec![ast::TtToken(self.span, token::Interpolated(token::NtExpr(self.clone())))]
         }
     }
 
-    impl_to_source! { ast::Path, path_to_string }
-    impl_to_source! { ast::Ty, ty_to_string }
-    impl_to_source! { ast::Block, block_to_string }
-    impl_to_source! { ast::Arg, arg_to_string }
-    impl_to_source! { Generics, generics_to_string }
-    impl_to_source! { ast::WhereClause, where_clause_to_string }
-    impl_to_source! { P<ast::Item>, item_to_string }
-    impl_to_source! { P<ast::ImplItem>, impl_item_to_string }
-    impl_to_source! { P<ast::TraitItem>, trait_item_to_string }
-    impl_to_source! { P<ast::Stmt>, stmt_to_string }
-    impl_to_source! { P<ast::Expr>, expr_to_string }
-    impl_to_source! { P<ast::Pat>, pat_to_string }
-    impl_to_source! { ast::Arm, arm_to_string }
-    impl_to_source_slice! { ast::Ty, ", " }
-    impl_to_source_slice! { P<ast::Item>, "\n\n" }
-
-    impl ToSource for ast::Attribute_ {
-        fn to_source(&self) -> String {
-            pprust::attribute_to_string(&dummy_spanned(self.clone()))
+    impl ToTokens for P<ast::Pat> {
+        fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+            vec![ast::TtToken(self.span, token::Interpolated(token::NtPat(self.clone())))]
         }
     }
-    impl ToSourceWithHygiene for ast::Attribute_ {
-        fn to_source_with_hygiene(&self) -> String {
-            self.to_source()
+
+    impl ToTokens for ast::Arm {
+        fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+            vec![ast::TtToken(DUMMY_SP, token::Interpolated(token::NtArm(self.clone())))]
         }
     }
 
-    impl ToSource for str {
-        fn to_source(&self) -> String {
-            let lit = dummy_spanned(ast::LitStr(
-                    token::intern_and_get_ident(self), ast::CookedStr));
-            pprust::lit_to_string(&lit)
-        }
+    macro_rules! impl_to_tokens_slice {
+        ($t: ty, $sep: expr) => {
+            impl ToTokens for [$t] {
+                fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
+                    let mut v = vec![];
+                    for (i, x) in self.iter().enumerate() {
+                        if i > 0 {
+                            v.push_all(&$sep);
+                        }
+                        v.extend(x.to_tokens(cx));
+                    }
+                    v
+                }
+            }
+        };
     }
-    impl ToSourceWithHygiene for str {
-        fn to_source_with_hygiene(&self) -> String {
-            self.to_source()
+
+    impl_to_tokens_slice! { ast::Ty, [ast::TtToken(DUMMY_SP, token::Comma)] }
+    impl_to_tokens_slice! { P<ast::Item>, [] }
+
+    impl ToTokens for P<ast::MetaItem> {
+        fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+            vec![ast::TtToken(DUMMY_SP, token::Interpolated(token::NtMeta(self.clone())))]
         }
     }
 
-    impl ToSource for () {
-        fn to_source(&self) -> String {
-            "()".to_string()
+    impl ToTokens for ast::Attribute {
+        fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
+            let mut r = vec![];
+            // FIXME: The spans could be better
+            r.push(ast::TtToken(self.span, token::Pound));
+            if self.node.style == ast::AttrInner {
+                r.push(ast::TtToken(self.span, token::Not));
+            }
+            r.push(ast::TtDelimited(self.span, Rc::new(ast::Delimited {
+                delim: token::Bracket,
+                open_span: self.span,
+                tts: self.node.value.to_tokens(cx),
+                close_span: self.span,
+            })));
+            r
         }
     }
-    impl ToSourceWithHygiene for () {
-        fn to_source_with_hygiene(&self) -> String {
-            self.to_source()
+
+    impl ToTokens for str {
+        fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
+            let lit = ast::LitStr(
+                token::intern_and_get_ident(self), ast::CookedStr);
+            dummy_spanned(lit).to_tokens(cx)
         }
     }
 
-    impl ToSource for bool {
-        fn to_source(&self) -> String {
-            let lit = dummy_spanned(ast::LitBool(*self));
-            pprust::lit_to_string(&lit)
+    impl ToTokens for () {
+        fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+            vec![ast::TtDelimited(DUMMY_SP, Rc::new(ast::Delimited {
+                delim: token::Paren,
+                open_span: DUMMY_SP,
+                tts: vec![],
+                close_span: DUMMY_SP,
+            }))]
         }
     }
-    impl ToSourceWithHygiene for bool {
-        fn to_source_with_hygiene(&self) -> String {
-            self.to_source()
+
+    impl ToTokens for ast::Lit {
+        fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
+            // FIXME: This is wrong
+            P(ast::Expr {
+                id: ast::DUMMY_NODE_ID,
+                node: ast::ExprLit(P(self.clone())),
+                span: DUMMY_SP,
+            }).to_tokens(cx)
         }
     }
 
-    impl ToSource for char {
-        fn to_source(&self) -> String {
-            let lit = dummy_spanned(ast::LitChar(*self));
-            pprust::lit_to_string(&lit)
+    impl ToTokens for bool {
+        fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
+            dummy_spanned(ast::LitBool(*self)).to_tokens(cx)
         }
     }
-    impl ToSourceWithHygiene for char {
-        fn to_source_with_hygiene(&self) -> String {
-            self.to_source()
+
+    impl ToTokens for char {
+        fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
+            dummy_spanned(ast::LitChar(*self)).to_tokens(cx)
         }
     }
 
-    macro_rules! impl_to_source_int {
+    macro_rules! impl_to_tokens_int {
         (signed, $t:ty, $tag:expr) => (
-            impl ToSource for $t {
-                fn to_source(&self) -> String {
+            impl ToTokens for $t {
+                fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
                     let lit = ast::LitInt(*self as u64, ast::SignedIntLit($tag,
                                                                           ast::Sign::new(*self)));
-                    pprust::lit_to_string(&dummy_spanned(lit))
-                }
-            }
-            impl ToSourceWithHygiene for $t {
-                fn to_source_with_hygiene(&self) -> String {
-                    self.to_source()
+                    dummy_spanned(lit).to_tokens(cx)
                 }
             }
         );
         (unsigned, $t:ty, $tag:expr) => (
-            impl ToSource for $t {
-                fn to_source(&self) -> String {
+            impl ToTokens for $t {
+                fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
                     let lit = ast::LitInt(*self as u64, ast::UnsignedIntLit($tag));
-                    pprust::lit_to_string(&dummy_spanned(lit))
-                }
-            }
-            impl ToSourceWithHygiene for $t {
-                fn to_source_with_hygiene(&self) -> String {
-                    self.to_source()
+                    dummy_spanned(lit).to_tokens(cx)
                 }
             }
         );
     }
 
-    impl_to_source_int! { signed, isize, ast::TyIs }
-    impl_to_source_int! { signed, i8,  ast::TyI8 }
-    impl_to_source_int! { signed, i16, ast::TyI16 }
-    impl_to_source_int! { signed, i32, ast::TyI32 }
-    impl_to_source_int! { signed, i64, ast::TyI64 }
-
-    impl_to_source_int! { unsigned, usize, ast::TyUs }
-    impl_to_source_int! { unsigned, u8,   ast::TyU8 }
-    impl_to_source_int! { unsigned, u16,  ast::TyU16 }
-    impl_to_source_int! { unsigned, u32,  ast::TyU32 }
-    impl_to_source_int! { unsigned, u64,  ast::TyU64 }
-
-    // Alas ... we write these out instead. All redundant.
-
-    macro_rules! impl_to_tokens {
-        ($t:ty) => (
-            impl ToTokens for $t {
-                fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
-                    cx.parse_tts_with_hygiene(self.to_source_with_hygiene())
-                }
-            }
-        )
-    }
+    impl_to_tokens_int! { signed, isize, ast::TyIs }
+    impl_to_tokens_int! { signed, i8,  ast::TyI8 }
+    impl_to_tokens_int! { signed, i16, ast::TyI16 }
+    impl_to_tokens_int! { signed, i32, ast::TyI32 }
+    impl_to_tokens_int! { signed, i64, ast::TyI64 }
 
-    macro_rules! impl_to_tokens_lifetime {
-        ($t:ty) => (
-            impl<'a> ToTokens for $t {
-                fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
-                    cx.parse_tts_with_hygiene(self.to_source_with_hygiene())
-                }
-            }
-        )
-    }
-
-    impl_to_tokens! { ast::Ident }
-    impl_to_tokens! { ast::Path }
-    impl_to_tokens! { P<ast::Item> }
-    impl_to_tokens! { P<ast::ImplItem> }
-    impl_to_tokens! { P<ast::TraitItem> }
-    impl_to_tokens! { P<ast::Pat> }
-    impl_to_tokens! { ast::Arm }
-    impl_to_tokens_lifetime! { &'a [P<ast::Item>] }
-    impl_to_tokens! { ast::Ty }
-    impl_to_tokens_lifetime! { &'a [ast::Ty] }
-    impl_to_tokens! { Generics }
-    impl_to_tokens! { ast::WhereClause }
-    impl_to_tokens! { P<ast::Stmt> }
-    impl_to_tokens! { P<ast::Expr> }
-    impl_to_tokens! { ast::Block }
-    impl_to_tokens! { ast::Arg }
-    impl_to_tokens! { ast::Attribute_ }
-    impl_to_tokens_lifetime! { &'a str }
-    impl_to_tokens! { () }
-    impl_to_tokens! { char }
-    impl_to_tokens! { bool }
-    impl_to_tokens! { isize }
-    impl_to_tokens! { i8 }
-    impl_to_tokens! { i16 }
-    impl_to_tokens! { i32 }
-    impl_to_tokens! { i64 }
-    impl_to_tokens! { usize }
-    impl_to_tokens! { u8 }
-    impl_to_tokens! { u16 }
-    impl_to_tokens! { u32 }
-    impl_to_tokens! { u64 }
+    impl_to_tokens_int! { unsigned, usize, ast::TyUs }
+    impl_to_tokens_int! { unsigned, u8,   ast::TyU8 }
+    impl_to_tokens_int! { unsigned, u16,  ast::TyU16 }
+    impl_to_tokens_int! { unsigned, u32,  ast::TyU32 }
+    impl_to_tokens_int! { unsigned, u64,  ast::TyU64 }
 
     pub trait ExtParseUtils {
         fn parse_item(&self, s: String) -> P<ast::Item>;
@@ -349,12 +261,6 @@ pub trait ExtParseUtils {
         fn parse_tts(&self, s: String) -> Vec<ast::TokenTree>;
     }
 
-    trait ExtParseUtilsWithHygiene {
-        // FIXME (Issue #16472): This should go away after ToToken impls
-        // are revised to go directly to token-trees.
-        fn parse_tts_with_hygiene(&self, s: String) -> Vec<ast::TokenTree>;
-    }
-
     impl<'a> ExtParseUtils for ExtCtxt<'a> {
 
         fn parse_item(&self, s: String) -> P<ast::Item> {
@@ -386,19 +292,6 @@ fn parse_tts(&self, s: String) -> Vec<ast::TokenTree> {
                                              self.parse_sess())
         }
     }
-
-    impl<'a> ExtParseUtilsWithHygiene for ExtCtxt<'a> {
-
-        fn parse_tts_with_hygiene(&self, s: String) -> Vec<ast::TokenTree> {
-            use parse::with_hygiene::parse_tts_from_source_str;
-            parse_tts_from_source_str("<quote expansion>".to_string(),
-                                      s,
-                                      self.cfg(),
-                                      self.parse_sess())
-        }
-
-    }
-
 }
 
 pub fn expand_quote_tokens<'cx>(cx: &'cx mut ExtCtxt,
index d0975c76e9351ad10d5cd9fba0be61d33d3f2ae3..60b1d4797d5212ff19c61eeb2fbd6394d845cbe8 100644 (file)
 
     // Allows use of unary negate on unsigned integers, e.g. -e for e: u8
     ("negate_unsigned", "1.0.0", Active),
+
+    // Allows the definition of associated constants in `trait` or `impl`
+    // blocks.
+    ("associated_consts", "1.0.0", Active),
 ];
 // (changing above list without updating src/doc/reference.md makes @cmr sad)
 
@@ -394,7 +398,7 @@ fn check_attribute(&self, attr: &ast::Attribute) {
                                are reserved for internal compiler diagnostics");
         } else if name.starts_with("derive_") {
             self.gate_feature("custom_derive", attr.span,
-                              "attributes of the form `#[derive_*]` are reserved
+                              "attributes of the form `#[derive_*]` are reserved \
                                for the compiler");
         } else {
             self.gate_feature("custom_attribute", attr.span,
@@ -620,7 +624,7 @@ fn visit_pat(&mut self, pattern: &ast::Pat) {
                                   pattern.span,
                                   "multiple-element slice matches anywhere \
                                    but at the end of a slice (e.g. \
-                                   `[0, ..xs, 0]` are experimental")
+                                   `[0, ..xs, 0]`) are experimental")
             }
             ast::PatVec(..) => {
                 self.gate_feature("slice_patterns",
@@ -659,6 +663,30 @@ fn visit_fn(&mut self,
         }
         visit::walk_fn(self, fn_kind, fn_decl, block, span);
     }
+
+    fn visit_trait_item(&mut self, ti: &'v ast::TraitItem) {
+        match ti.node {
+            ast::ConstTraitItem(..) => {
+                self.gate_feature("associated_consts",
+                                  ti.span,
+                                  "associated constants are experimental")
+            }
+            _ => {}
+        }
+        visit::walk_trait_item(self, ti);
+    }
+
+    fn visit_impl_item(&mut self, ii: &'v ast::ImplItem) {
+        match ii.node {
+            ast::ConstImplItem(..) => {
+                self.gate_feature("associated_consts",
+                                  ii.span,
+                                  "associated constants are experimental")
+            }
+            _ => {}
+        }
+        visit::walk_impl_item(self, ii);
+    }
 }
 
 fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler,
index 8ba36cefc65dd49bf80d897d6d8d0ae1399dadc6..adfda988b23b747a05c13329b097e2f4af80f8b7 100644 (file)
@@ -682,6 +682,13 @@ pub fn noop_fold_interpolated<T: Folder>(nt: token::Nonterminal, fld: &mut T)
         token::NtMeta(meta_item) => token::NtMeta(fld.fold_meta_item(meta_item)),
         token::NtPath(path) => token::NtPath(Box::new(fld.fold_path(*path))),
         token::NtTT(tt) => token::NtTT(P(fld.fold_tt(&*tt))),
+        token::NtArm(arm) => token::NtArm(fld.fold_arm(arm)),
+        token::NtImplItem(arm) =>
+            token::NtImplItem(fld.fold_impl_item(arm)
+                              .expect_one("expected fold to produce exactly one item")),
+        token::NtTraitItem(arm) =>
+            token::NtTraitItem(fld.fold_trait_item(arm)
+                               .expect_one("expected fold to produce exactly one item")),
     }
 }
 
@@ -973,6 +980,10 @@ pub fn noop_fold_trait_item<T: Folder>(i: P<TraitItem>, folder: &mut T)
         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)))
@@ -994,6 +1005,9 @@ pub fn noop_fold_impl_item<T: Folder>(i: P<ImplItem>, folder: &mut T)
         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))
@@ -1127,6 +1141,10 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
                 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| {
@@ -1343,7 +1361,7 @@ pub fn noop_fold_stmt<T: Folder>(Spanned {node, span}: Stmt, folder: &mut T)
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use std::io;
     use ast;
     use util::parser_testing::{string_to_crate, matches_codepattern};
index fb3a96f4c2887fdbd2b5c2875d239f50a37c9dc5..1577b50ad760caad882cbbcc98abc894293669e9 100644 (file)
@@ -383,7 +383,7 @@ pub fn gather_comments_and_literals(span_diagnostic: &diagnostic::SpanHandler,
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use super::*;
 
     #[test] fn test_block_doc_comment_1() {
index 8e37b983e21e0425e845223056e33dcecdd6b097..6b0674c9a41b420fe948a24a588b7bfbb4dbb3e2 100644 (file)
@@ -19,7 +19,6 @@
 
 use std::borrow::Cow;
 use std::char;
-use std::fmt;
 use std::mem::replace;
 use std::rc::Rc;
 
@@ -71,11 +70,6 @@ pub struct StringReader<'a> {
     pub peek_tok: token::Token,
     pub peek_span: Span,
 
-    // FIXME (Issue #16472): This field should go away after ToToken impls
-    // are revised to go directly to token-trees.
-    /// Is \x00<name>,<ctxt>\x00 is interpreted as encoded ast::Ident?
-    read_embedded_ident: bool,
-
     // cache a direct reference to the source text, so that we don't have to
     // retrieve it via `self.filemap.src.as_ref().unwrap()` all the time.
     source_text: Rc<String>
@@ -130,17 +124,6 @@ fn peek(&self) -> TokenAndSpan {
     }
 }
 
-// FIXME (Issue #16472): This function should go away after
-// ToToken impls are revised to go directly to token-trees.
-pub fn make_reader_with_embedded_idents<'b>(span_diagnostic: &'b SpanHandler,
-                                            filemap: Rc<codemap::FileMap>)
-                                            -> StringReader<'b> {
-    let mut sr = StringReader::new_raw(span_diagnostic, filemap);
-    sr.read_embedded_ident = true;
-    sr.advance_token();
-    sr
-}
-
 impl<'a> StringReader<'a> {
     /// For comments.rs, which hackily pokes into pos and curr
     pub fn new_raw<'b>(span_diagnostic: &'b SpanHandler,
@@ -162,7 +145,6 @@ pub fn new_raw<'b>(span_diagnostic: &'b SpanHandler,
             /* dummy values; not read */
             peek_tok: token::Eof,
             peek_span: codemap::DUMMY_SP,
-            read_embedded_ident: false,
             source_text: source_text
         };
         sr.bump();
@@ -578,81 +560,6 @@ fn scan_block_comment(&mut self) -> Option<TokenAndSpan> {
         })
     }
 
-    // FIXME (Issue #16472): The scan_embedded_hygienic_ident function
-    // should go away after we revise the syntax::ext::quote::ToToken
-    // impls to go directly to token-trees instead of thing -> string
-    // -> token-trees.  (The function is currently used to resolve
-    // Issues #15750 and #15962.)
-    //
-    // Since this function is only used for certain internal macros,
-    // and the functionality it provides is not exposed to end user
-    // programs, pnkfelix deliberately chose to write it in a way that
-    // favors rustc debugging effectiveness over runtime efficiency.
-
-    /// Scan through input of form \x00name_NNNNNN,ctxt_CCCCCCC\x00
-    /// whence: `NNNNNN` is a string of characters forming an integer
-    /// (the name) and `CCCCCCC` is a string of characters forming an
-    /// integer (the ctxt), separate by a comma and delimited by a
-    /// `\x00` marker.
-    #[inline(never)]
-    fn scan_embedded_hygienic_ident(&mut self) -> ast::Ident {
-        fn bump_expecting_char<'a,D:fmt::Debug>(r: &mut StringReader<'a>,
-                                                c: char,
-                                                described_c: D,
-                                                whence: &str) {
-            match r.curr {
-                Some(r_c) if r_c == c => r.bump(),
-                Some(r_c) => panic!("expected {:?}, hit {:?}, {}", described_c, r_c, whence),
-                None      => panic!("expected {:?}, hit EOF, {}", described_c, whence),
-            }
-        }
-
-        let whence = "while scanning embedded hygienic ident";
-
-        // skip over the leading `\x00`
-        bump_expecting_char(self, '\x00', "nul-byte", whence);
-
-        // skip over the "name_"
-        for c in "name_".chars() {
-            bump_expecting_char(self, c, c, whence);
-        }
-
-        let start_bpos = self.last_pos;
-        let base = 10;
-
-        // find the integer representing the name
-        self.scan_digits(base, base);
-        let encoded_name : u32 = self.with_str_from(start_bpos, |s| {
-            u32::from_str_radix(s, 10).unwrap_or_else(|_| {
-                panic!("expected digits representing a name, got {:?}, {}, range [{:?},{:?}]",
-                      s, whence, start_bpos, self.last_pos);
-            })
-        });
-
-        // skip over the `,`
-        bump_expecting_char(self, ',', "comma", whence);
-
-        // skip over the "ctxt_"
-        for c in "ctxt_".chars() {
-            bump_expecting_char(self, c, c, whence);
-        }
-
-        // find the integer representing the ctxt
-        let start_bpos = self.last_pos;
-        self.scan_digits(base, base);
-        let encoded_ctxt : ast::SyntaxContext = self.with_str_from(start_bpos, |s| {
-            u32::from_str_radix(s, 10).unwrap_or_else(|_| {
-                panic!("expected digits representing a ctxt, got {:?}, {}", s, whence);
-            })
-        });
-
-        // skip over the `\x00`
-        bump_expecting_char(self, '\x00', "nul-byte", whence);
-
-        ast::Ident { name: ast::Name(encoded_name),
-                     ctxt: encoded_ctxt, }
-    }
-
     /// Scan through any digits (base `scan_radix`) or underscores,
     /// and return how many digits there were.
     ///
@@ -1020,20 +927,6 @@ fn next_token_inner(&mut self) -> token::Token {
             return token::Literal(num, suffix)
         }
 
-        if self.read_embedded_ident {
-            match (c.unwrap(), self.nextch(), self.nextnextch()) {
-                ('\x00', Some('n'), Some('a')) => {
-                    let ast_ident = self.scan_embedded_hygienic_ident();
-                    return if self.curr_is(':') && self.nextch_is(':') {
-                        token::Ident(ast_ident, token::ModName)
-                    } else {
-                        token::Ident(ast_ident, token::Plain)
-                    };
-                }
-                _ => {}
-            }
-        }
-
         match c.expect("next_token_inner called at EOF") {
           // One-byte tokens.
           ';' => { self.bump(); return token::Semi; }
@@ -1501,7 +1394,7 @@ fn ident_continue(c: Option<char>) -> bool {
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use super::*;
 
     use codemap::{BytePos, CodeMap, Span, NO_EXPANSION};
index 1a1713a8ba632fb9fa3d3f99e539525a27266665..8c9ce5f78d482c4f9df632a17e2bc242a51f0f9e 100644 (file)
@@ -166,9 +166,6 @@ pub fn parse_stmt_from_source_str(name: String,
     maybe_aborted(p.parse_stmt(), p)
 }
 
-// Note: keep in sync with `with_hygiene::parse_tts_from_source_str`
-// until #16472 is resolved.
-//
 // Warning: This parses with quote_depth > 0, which is not the default.
 pub fn parse_tts_from_source_str(name: String,
                                  source: String,
@@ -186,8 +183,6 @@ pub fn parse_tts_from_source_str(name: String,
     maybe_aborted(panictry!(p.parse_all_token_trees()),p)
 }
 
-// Note: keep in sync with `with_hygiene::new_parser_from_source_str`
-// until #16472 is resolved.
 // Create a new parser from a source string
 pub fn new_parser_from_source_str<'a>(sess: &'a ParseSess,
                                       cfg: ast::CrateConfig,
@@ -220,8 +215,6 @@ pub fn new_sub_parser_from_file<'a>(sess: &'a ParseSess,
     p
 }
 
-// Note: keep this in sync with `with_hygiene::filemap_to_parser` until
-// #16472 is resolved.
 /// Given a filemap and config, return a parser
 pub fn filemap_to_parser<'a>(sess: &'a ParseSess,
                              filemap: Rc<FileMap>,
@@ -277,8 +270,6 @@ pub fn string_to_filemap(sess: &ParseSess, source: String, path: String)
     sess.span_diagnostic.cm.new_filemap(path, source)
 }
 
-// Note: keep this in sync with `with_hygiene::filemap_to_tts` (apart
-// from the StringReader constructor), until #16472 is resolved.
 /// Given a filemap, produce a sequence of token-trees
 pub fn filemap_to_tts(sess: &ParseSess, filemap: Rc<FileMap>)
     -> Vec<ast::TokenTree> {
@@ -300,69 +291,6 @@ pub fn tts_to_parser<'a>(sess: &'a ParseSess,
     p
 }
 
-// FIXME (Issue #16472): The `with_hygiene` mod should go away after
-// ToToken impls are revised to go directly to token-trees.
-pub mod with_hygiene {
-    use ast;
-    use codemap::FileMap;
-    use parse::parser::Parser;
-    use std::rc::Rc;
-    use super::ParseSess;
-    use super::{maybe_aborted, string_to_filemap, tts_to_parser};
-
-    // Note: keep this in sync with `super::parse_tts_from_source_str` until
-    // #16472 is resolved.
-    //
-    // Warning: This parses with quote_depth > 0, which is not the default.
-    pub fn parse_tts_from_source_str(name: String,
-                                     source: String,
-                                     cfg: ast::CrateConfig,
-                                     sess: &ParseSess) -> Vec<ast::TokenTree> {
-        let mut p = new_parser_from_source_str(
-            sess,
-            cfg,
-            name,
-            source
-        );
-        p.quote_depth += 1;
-        // right now this is re-creating the token trees from ... token trees.
-        maybe_aborted(panictry!(p.parse_all_token_trees()),p)
-    }
-
-    // Note: keep this in sync with `super::new_parser_from_source_str` until
-    // #16472 is resolved.
-    // Create a new parser from a source string
-    fn new_parser_from_source_str<'a>(sess: &'a ParseSess,
-                                      cfg: ast::CrateConfig,
-                                      name: String,
-                                      source: String) -> Parser<'a> {
-        filemap_to_parser(sess, string_to_filemap(sess, source, name), cfg)
-    }
-
-    // Note: keep this in sync with `super::filemap_to_parserr` until
-    // #16472 is resolved.
-    /// Given a filemap and config, return a parser
-    fn filemap_to_parser<'a>(sess: &'a ParseSess,
-                             filemap: Rc<FileMap>,
-                             cfg: ast::CrateConfig) -> Parser<'a> {
-        tts_to_parser(sess, filemap_to_tts(sess, filemap), cfg)
-    }
-
-    // Note: keep this in sync with `super::filemap_to_tts` until
-    // #16472 is resolved.
-    /// Given a filemap, produce a sequence of token-trees
-    fn filemap_to_tts(sess: &ParseSess, filemap: Rc<FileMap>)
-                      -> Vec<ast::TokenTree> {
-        // it appears to me that the cfg doesn't matter here... indeed,
-        // parsing tt's probably shouldn't require a parser at all.
-        use super::lexer::make_reader_with_embedded_idents as make_reader;
-        let cfg = Vec::new();
-        let srdr = make_reader(&sess.span_diagnostic, filemap);
-        let mut p1 = Parser::new(sess, cfg, Box::new(srdr));
-        panictry!(p1.parse_all_token_trees())
-    }
-}
-
 /// Abort if necessary
 pub fn maybe_aborted<T>(result: T, p: Parser) -> T {
     p.abort_if_errors();
@@ -761,7 +689,7 @@ pub fn integer_lit(s: &str, suffix: Option<&str>, sd: &SpanHandler, sp: Span) ->
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use super::*;
     use std::rc::Rc;
     use codemap::{Span, BytePos, Pos, Spanned, NO_EXPANSION};
index 68006a8979a6468c702fe7d0497a869d830c9e52..f76de1f04ce2ce2f5517ad2dd2bac5d349727f35 100644 (file)
@@ -17,8 +17,8 @@
 use ast::{Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue};
 use ast::{BiBitAnd, BiBitOr, BiBitXor, BiRem, BiLt, BiGt, Block};
 use ast::{BlockCheckMode, CaptureByRef, CaptureByValue, CaptureClause};
-use ast::{Crate, CrateConfig, Decl, DeclItem};
-use ast::{DeclLocal, DefaultBlock, DefaultReturn};
+use ast::{ConstImplItem, ConstTraitItem, Crate, CrateConfig};
+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};
@@ -40,8 +40,9 @@
 use ast::{MutImmutable, MutMutable, Mac_, MacInvocTT, MatchSource};
 use ast::{MutTy, BiMul, Mutability};
 use ast::{MethodImplItem, NamedField, UnNeg, NoReturn, UnNot};
-use ast::{Pat, PatBox, PatEnum, PatIdent, PatLit, PatMac, PatRange, PatRegion};
-use ast::{PatStruct, PatTup, PatVec, PatWild, PatWildMulti, PatWildSingle};
+use ast::{Pat, PatBox, PatEnum, PatIdent, PatLit, PatQPath, PatMac, PatRange};
+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};
@@ -109,6 +110,15 @@ pub enum PathParsingMode {
     LifetimeAndTypesWithColons,
 }
 
+/// How to parse a qualified path, whether to allow trailing parameters.
+#[derive(Copy, Clone, PartialEq)]
+pub enum QPathParsingMode {
+    /// No trailing parameters, e.g. `<T as Trait>::Item`
+    NoParameters,
+    /// Optional parameters, e.g. `<T as Trait>::item::<'a, U>`
+    MaybeParameters,
+}
+
 /// How to parse a bound, whether to allow bound modifiers such as `?`.
 #[derive(Copy, Clone, PartialEq)]
 pub enum BoundParsingMode {
@@ -902,7 +912,9 @@ pub fn parse_seq<T, F>(&mut self,
     pub fn bump(&mut self) -> PResult<()> {
         self.last_span = self.span;
         // Stash token for error recovery (sometimes; clone is not necessarily cheap).
-        self.last_token = if self.token.is_ident() || self.token.is_path() {
+        self.last_token = if self.token.is_ident() ||
+                          self.token.is_path() ||
+                          self.token == token::Comma {
             Some(Box::new(self.token.clone()))
         } else {
             None
@@ -1150,7 +1162,8 @@ pub fn parse_trait_items(&mut self) -> PResult<Vec<P<TraitItem>>> {
             &token::OpenDelim(token::Brace),
             &token::CloseDelim(token::Brace),
             seq_sep_none(),
-            |p| {
+            |p| -> PResult<P<TraitItem>> {
+            maybe_whole!(no_clone p, NtTraitItem);
             let mut attrs = p.parse_outer_attributes();
             let lo = p.span.lo;
 
@@ -1158,6 +1171,20 @@ pub fn parse_trait_items(&mut self) -> PResult<Vec<P<TraitItem>>> {
                 let TyParam {ident, bounds, default, ..} = try!(p.parse_ty_param());
                 try!(p.expect(&token::Semi));
                 (ident, TypeTraitItem(bounds, default))
+            } else if try!(p.eat_keyword(keywords::Const)) {
+                let ident = try!(p.parse_ident());
+                try!(p.expect(&token::Colon));
+                let ty = try!(p.parse_ty_sum());
+                let default = if p.check(&token::Eq) {
+                    try!(p.bump());
+                    let expr = try!(p.parse_expr_nopanic());
+                    try!(p.commit_expr_expecting(&expr, token::Semi));
+                    Some(expr)
+                } else {
+                    try!(p.expect(&token::Semi));
+                    None
+                };
+                (ident, ConstTraitItem(ty, default))
             } else {
                 let style = try!(p.parse_unsafety());
                 let abi = if try!(p.eat_keyword(keywords::Extern)) {
@@ -1331,36 +1358,9 @@ pub fn parse_ty_nopanic(&mut self) -> PResult<P<Ty>> {
             try!(self.expect(&token::CloseDelim(token::Paren)));
             TyTypeof(e)
         } else if try!(self.eat_lt()) {
-            // QUALIFIED PATH `<TYPE as TRAIT_REF>::item`
-            let self_type = try!(self.parse_ty_sum());
-
-            let mut path = if try!(self.eat_keyword(keywords::As) ){
-                try!(self.parse_path(LifetimeAndTypesWithoutColons))
-            } else {
-                ast::Path {
-                    span: self.span,
-                    global: false,
-                    segments: vec![]
-                }
-            };
-
-            let qself = QSelf {
-                ty: self_type,
-                position: path.segments.len()
-            };
 
-            try!(self.expect(&token::Gt));
-            try!(self.expect(&token::ModSep));
-
-            path.segments.push(ast::PathSegment {
-                identifier: try!(self.parse_ident()),
-                parameters: ast::PathParameters::none()
-            });
-
-            if path.segments.len() == 1 {
-                path.span.lo = self.last_span.lo;
-            }
-            path.span.hi = self.last_span.hi;
+            let (qself, path) =
+                 try!(self.parse_qualified_path(QPathParsingMode::NoParameters));
 
             TyPath(Some(qself), path)
         } else if self.check(&token::ModSep) ||
@@ -1577,6 +1577,61 @@ pub fn parse_literal_maybe_minus(&mut self) -> PResult<P<Expr>> {
         }
     }
 
+    // QUALIFIED PATH `<TYPE [as TRAIT_REF]>::IDENT[::<PARAMS>]`
+    // Assumes that the leading `<` has been parsed already.
+    pub fn parse_qualified_path(&mut self, mode: QPathParsingMode)
+                                -> PResult<(QSelf, ast::Path)> {
+        let self_type = try!(self.parse_ty_sum());
+        let mut path = if try!(self.eat_keyword(keywords::As)) {
+            try!(self.parse_path(LifetimeAndTypesWithoutColons))
+        } else {
+            ast::Path {
+                span: self.span,
+                global: false,
+                segments: vec![]
+            }
+        };
+
+        let qself = QSelf {
+            ty: self_type,
+            position: path.segments.len()
+        };
+
+        try!(self.expect(&token::Gt));
+        try!(self.expect(&token::ModSep));
+
+        let item_name = try!(self.parse_ident());
+        let parameters = match mode {
+            QPathParsingMode::NoParameters => ast::PathParameters::none(),
+            QPathParsingMode::MaybeParameters => {
+                if try!(self.eat(&token::ModSep)) {
+                    try!(self.expect_lt());
+                    // Consumed `item::<`, go look for types
+                    let (lifetimes, types, bindings) =
+                        try!(self.parse_generic_values_after_lt());
+                    ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
+                        lifetimes: lifetimes,
+                        types: OwnedSlice::from_vec(types),
+                        bindings: OwnedSlice::from_vec(bindings),
+                    })
+                } else {
+                    ast::PathParameters::none()
+                }
+            }
+        };
+        path.segments.push(ast::PathSegment {
+            identifier: item_name,
+            parameters: parameters
+        });
+
+        if path.segments.len() == 1 {
+            path.span.lo = self.last_span.lo;
+        }
+        path.span.hi = self.last_span.hi;
+
+        Ok((qself, path))
+    }
+
     /// Parses a path and optional type parameter bounds, depending on the
     /// mode. The `mode` parameter determines whether lifetimes, types, and/or
     /// bounds are permitted and whether `::` must precede type parameter
@@ -2040,49 +2095,10 @@ pub fn parse_bottom_expr(&mut self) -> PResult<P<Expr>> {
             }
             _ => {
                 if try!(self.eat_lt()){
-                    // QUALIFIED PATH `<TYPE as TRAIT_REF>::item::<'a, T>`
-                    let self_type = try!(self.parse_ty_sum());
-                    let mut path = if try!(self.eat_keyword(keywords::As) ){
-                        try!(self.parse_path(LifetimeAndTypesWithoutColons))
-                    } else {
-                        ast::Path {
-                            span: self.span,
-                            global: false,
-                            segments: vec![]
-                        }
-                    };
-                    let qself = QSelf {
-                        ty: self_type,
-                        position: path.segments.len()
-                    };
-                    try!(self.expect(&token::Gt));
-                    try!(self.expect(&token::ModSep));
 
-                    let item_name = try!(self.parse_ident());
-                    let parameters = if try!(self.eat(&token::ModSep) ){
-                        try!(self.expect_lt());
-                        // Consumed `item::<`, go look for types
-                        let (lifetimes, types, bindings) =
-                            try!(self.parse_generic_values_after_lt());
-                        ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
-                            lifetimes: lifetimes,
-                            types: OwnedSlice::from_vec(types),
-                            bindings: OwnedSlice::from_vec(bindings),
-                        })
-                    } else {
-                        ast::PathParameters::none()
-                    };
-                    path.segments.push(ast::PathSegment {
-                        identifier: item_name,
-                        parameters: parameters
-                    });
-
-                    if path.segments.len() == 1 {
-                        path.span.lo = self.last_span.lo;
-                    }
-                    path.span.hi = self.last_span.hi;
+                    let (qself, path) =
+                        try!(self.parse_qualified_path(QPathParsingMode::MaybeParameters));
 
-                    let hi = self.span.hi;
                     return Ok(self.mk_expr(lo, hi, ExprPath(Some(qself), path)));
                 }
                 if try!(self.eat_keyword(keywords::Move) ){
@@ -2941,6 +2957,8 @@ fn parse_match_expr(&mut self) -> PResult<P<Expr>> {
     }
 
     pub fn parse_arm_nopanic(&mut self) -> PResult<Arm> {
+        maybe_whole!(no_clone self, NtArm);
+
         let attrs = self.parse_outer_attributes();
         let pats = try!(self.parse_pats());
         let mut guard = None;
@@ -3153,16 +3171,25 @@ fn parse_pat_fields(&mut self) -> PResult<(Vec<codemap::Spanned<ast::FieldPat>>
     fn parse_pat_range_end(&mut self) -> PResult<P<Expr>> {
         if self.is_path_start() {
             let lo = self.span.lo;
-            let path = try!(self.parse_path(LifetimeAndTypesWithColons));
+            let (qself, path) = if try!(self.eat_lt()) {
+                // Parse a qualified path
+                let (qself, path) =
+                    try!(self.parse_qualified_path(QPathParsingMode::NoParameters));
+                (Some(qself), path)
+            } else {
+                // Parse an unqualified path
+                (None, try!(self.parse_path(LifetimeAndTypesWithColons)))
+            };
             let hi = self.last_span.hi;
-            Ok(self.mk_expr(lo, hi, ExprPath(None, path)))
+            Ok(self.mk_expr(lo, hi, ExprPath(qself, path)))
         } else {
             self.parse_literal_maybe_minus()
         }
     }
 
     fn is_path_start(&self) -> bool {
-        (self.token == token::ModSep || self.token.is_ident() || self.token.is_path())
+        (self.token == token::Lt || self.token == token::ModSep
+            || self.token.is_ident() || self.token.is_path())
             && !self.token.is_keyword(keywords::True) && !self.token.is_keyword(keywords::False)
     }
 
@@ -3238,25 +3265,44 @@ pub fn parse_pat_nopanic(&mut self) -> PResult<P<Pat>> {
                         pat = try!(self.parse_pat_ident(BindByValue(MutImmutable)));
                     }
                 } else {
-                    // Parse as a general path
-                    let path = try!(self.parse_path(LifetimeAndTypesWithColons));
+                    let (qself, path) = if try!(self.eat_lt()) {
+                        // Parse a qualified path
+                        let (qself, path) =
+                            try!(self.parse_qualified_path(QPathParsingMode::NoParameters));
+                        (Some(qself), path)
+                    } else {
+                        // Parse an unqualified path
+                        (None, try!(self.parse_path(LifetimeAndTypesWithColons)))
+                    };
                     match self.token {
                       token::DotDotDot => {
                         // Parse range
                         let hi = self.last_span.hi;
-                        let begin = self.mk_expr(lo, hi, ExprPath(None, path));
+                        let begin = self.mk_expr(lo, hi, ExprPath(qself, path));
                         try!(self.bump());
                         let end = try!(self.parse_pat_range_end());
                         pat = PatRange(begin, end);
                       }
                       token::OpenDelim(token::Brace) => {
-                        // Parse struct pattern
+                         if qself.is_some() {
+                            let span = self.span;
+                            self.span_err(span,
+                                          "unexpected `{` after qualified path");
+                            self.abort_if_errors();
+                        }
+                       // Parse struct pattern
                         try!(self.bump());
                         let (fields, etc) = try!(self.parse_pat_fields());
                         try!(self.bump());
                         pat = PatStruct(path, fields, etc);
                       }
                       token::OpenDelim(token::Paren) => {
+                        if qself.is_some() {
+                            let span = self.span;
+                            self.span_err(span,
+                                          "unexpected `(` after qualified path");
+                            self.abort_if_errors();
+                        }
                         // Parse tuple struct or enum pattern
                         if self.look_ahead(1, |t| *t == token::DotDot) {
                             // This is a "top constructor only" pat
@@ -3273,6 +3319,10 @@ pub fn parse_pat_nopanic(&mut self) -> PResult<P<Pat>> {
                             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![]));
@@ -3807,8 +3857,37 @@ pub fn parse_generics(&mut self) -> PResult<ast::Generics> {
     fn parse_generic_values_after_lt(&mut self) -> PResult<(Vec<ast::Lifetime>,
                                                             Vec<P<Ty>>,
                                                             Vec<P<TypeBinding>>)> {
+        let span_lo = self.span.lo;
         let lifetimes = try!(self.parse_lifetimes(token::Comma));
 
+        let missing_comma = !lifetimes.is_empty() &&
+                            !self.token.is_like_gt() &&
+                            self.last_token
+                                .as_ref().map_or(true,
+                                                 |x| &**x != &token::Comma);
+
+        if missing_comma {
+
+            let msg = format!("expected `,` or `>` after lifetime \
+                              name, found `{}`",
+                              self.this_token_to_string());
+            self.span_err(self.span, &msg);
+
+            let span_hi = self.span.hi;
+            let span_hi = if self.parse_ty_nopanic().is_ok() {
+                self.span.hi
+            } else {
+                span_hi
+            };
+
+            let msg = format!("did you mean a single argument type &'a Type, \
+                              or did you mean the comma-separated arguments \
+                              'a, Type?");
+            self.span_note(mk_sp(span_lo, span_hi), &msg);
+
+            self.abort_if_errors()
+        }
+
         // First parse types.
         let (types, returned) = try!(self.parse_seq_to_gt_or_return(
             Some(token::Comma),
@@ -4304,6 +4383,8 @@ fn parse_item_fn(&mut self, unsafety: Unsafety, abi: abi::Abi) -> PResult<ItemIn
 
     /// Parse an impl item.
     pub fn parse_impl_item(&mut self) -> PResult<P<ImplItem>> {
+        maybe_whole!(no_clone self, NtImplItem);
+
         let mut attrs = self.parse_outer_attributes();
         let lo = self.span.lo;
         let vis = try!(self.parse_visibility());
@@ -4313,6 +4394,14 @@ pub fn parse_impl_item(&mut self) -> PResult<P<ImplItem>> {
             let typ = try!(self.parse_ty_sum());
             try!(self.expect(&token::Semi));
             (name, TypeImplItem(typ))
+        } else if try!(self.eat_keyword(keywords::Const)) {
+            let name = try!(self.parse_ident());
+            try!(self.expect(&token::Colon));
+            let typ = try!(self.parse_ty_sum());
+            try!(self.expect(&token::Eq));
+            let expr = try!(self.parse_expr_nopanic());
+            try!(self.commit_expr_expecting(&expr, token::Semi));
+            (name, ConstImplItem(typ, expr))
         } else {
             let (name, inner_attrs, node) = try!(self.parse_impl_method(vis));
             attrs.extend(inner_attrs.into_iter());
index 2bb74944ce91abf0b085cd932ceb4439e985ae62..0106de913bb87de12ca60b7e925698199f110abc 100644 (file)
@@ -173,6 +173,14 @@ pub enum Token {
 }
 
 impl Token {
+    /// Returns `true` if the token starts with '>'.
+    pub fn is_like_gt(&self) -> bool {
+        match *self {
+            BinOp(Shr) | BinOpEq(Shr) | Gt | Ge => true,
+            _ => false,
+        }
+    }
+
     /// Returns `true` if the token can appear at the start of an expression.
     pub fn can_begin_expr(&self) -> bool {
         match *self {
@@ -373,6 +381,10 @@ pub enum Nonterminal {
     NtMeta(P<ast::MetaItem>),
     NtPath(Box<ast::Path>),
     NtTT(P<ast::TokenTree>), // needs P'ed to break a circularity
+    // These is not exposed to macros, but is used by quasiquote.
+    NtArm(ast::Arm),
+    NtImplItem(P<ast::ImplItem>),
+    NtTraitItem(P<ast::TraitItem>),
 }
 
 impl fmt::Debug for Nonterminal {
@@ -388,6 +400,9 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
             NtMeta(..) => f.pad("NtMeta(..)"),
             NtPath(..) => f.pad("NtPath(..)"),
             NtTT(..) => f.pad("NtTT(..)"),
+            NtArm(..) => f.pad("NtArm(..)"),
+            NtImplItem(..) => f.pad("NtImplItem(..)"),
+            NtTraitItem(..) => f.pad("NtTraitItem(..)"),
         }
     }
 }
@@ -746,7 +761,7 @@ pub fn fresh_mark() -> ast::Mrk {
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use super::*;
     use ast;
     use ext::mtwt;
index 5a57e09fcfff2a4fb5b9625da34a5db36e085271..87c164f7550f9a5e56b3a3f3918af47dc0ac43ec 100644 (file)
@@ -66,7 +66,6 @@ pub struct State<'a> {
     cur_cmnt_and_lit: CurrentCommentAndLiteral,
     boxes: Vec<pp::Breaks>,
     ann: &'a (PpAnn+'a),
-    encode_idents_with_hygiene: bool,
 }
 
 pub fn rust_printer<'a>(writer: Box<Write+'a>) -> State<'a> {
@@ -87,7 +86,6 @@ pub fn rust_printer_annotated<'a>(writer: Box<Write+'a>,
         },
         boxes: Vec::new(),
         ann: ann,
-        encode_idents_with_hygiene: false,
     }
 }
 
@@ -179,7 +177,6 @@ pub fn new(cm: &'a CodeMap,
             },
             boxes: Vec::new(),
             ann: ann,
-            encode_idents_with_hygiene: false,
         }
     }
 }
@@ -290,103 +287,99 @@ pub fn token_to_string(tok: &Token) -> String {
         token::SpecialVarNt(var)    => format!("${}", var.as_str()),
 
         token::Interpolated(ref nt) => match *nt {
-            token::NtExpr(ref e)  => expr_to_string(&**e),
-            token::NtMeta(ref e)  => meta_item_to_string(&**e),
-            token::NtTy(ref e)    => ty_to_string(&**e),
-            token::NtPath(ref e)  => path_to_string(&**e),
-            token::NtItem(..)     => "an interpolated item".to_string(),
-            token::NtBlock(..)    => "an interpolated block".to_string(),
-            token::NtStmt(..)     => "an interpolated statement".to_string(),
-            token::NtPat(..)      => "an interpolated pattern".to_string(),
-            token::NtIdent(..)    => "an interpolated identifier".to_string(),
-            token::NtTT(..)       => "an interpolated tt".to_string(),
+            token::NtExpr(ref e)   => expr_to_string(&**e),
+            token::NtMeta(ref e)   => meta_item_to_string(&**e),
+            token::NtTy(ref e)     => ty_to_string(&**e),
+            token::NtPath(ref e)   => path_to_string(&**e),
+            token::NtItem(..)      => "an interpolated item".to_string(),
+            token::NtBlock(..)     => "an interpolated block".to_string(),
+            token::NtStmt(..)      => "an interpolated statement".to_string(),
+            token::NtPat(..)       => "an interpolated pattern".to_string(),
+            token::NtIdent(..)     => "an interpolated identifier".to_string(),
+            token::NtTT(..)        => "an interpolated tt".to_string(),
+            token::NtArm(..)       => "an interpolated arm".to_string(),
+            token::NtImplItem(..)  => "an interpolated impl item".to_string(),
+            token::NtTraitItem(..) => "an interpolated trait item".to_string(),
         }
     }
 }
 
-// FIXME (Issue #16472): the thing_to_string_impls macro should go away
-// after we revise the syntax::ext::quote::ToToken impls to go directly
-// to token-trees instead of thing -> string -> token-trees.
-
-macro_rules! thing_to_string_impls {
-    ($to_string:ident) => {
-
 pub fn ty_to_string(ty: &ast::Ty) -> String {
-    $to_string(|s| s.print_type(ty))
+    to_string(|s| s.print_type(ty))
 }
 
 pub fn bounds_to_string(bounds: &[ast::TyParamBound]) -> String {
-    $to_string(|s| s.print_bounds("", bounds))
+    to_string(|s| s.print_bounds("", bounds))
 }
 
 pub fn pat_to_string(pat: &ast::Pat) -> String {
-    $to_string(|s| s.print_pat(pat))
+    to_string(|s| s.print_pat(pat))
 }
 
 pub fn arm_to_string(arm: &ast::Arm) -> String {
-    $to_string(|s| s.print_arm(arm))
+    to_string(|s| s.print_arm(arm))
 }
 
 pub fn expr_to_string(e: &ast::Expr) -> String {
-    $to_string(|s| s.print_expr(e))
+    to_string(|s| s.print_expr(e))
 }
 
 pub fn lifetime_to_string(e: &ast::Lifetime) -> String {
-    $to_string(|s| s.print_lifetime(e))
+    to_string(|s| s.print_lifetime(e))
 }
 
 pub fn tt_to_string(tt: &ast::TokenTree) -> String {
-    $to_string(|s| s.print_tt(tt))
+    to_string(|s| s.print_tt(tt))
 }
 
 pub fn tts_to_string(tts: &[ast::TokenTree]) -> String {
-    $to_string(|s| s.print_tts(tts))
+    to_string(|s| s.print_tts(tts))
 }
 
 pub fn stmt_to_string(stmt: &ast::Stmt) -> String {
-    $to_string(|s| s.print_stmt(stmt))
+    to_string(|s| s.print_stmt(stmt))
 }
 
 pub fn attr_to_string(attr: &ast::Attribute) -> String {
-    $to_string(|s| s.print_attribute(attr))
+    to_string(|s| s.print_attribute(attr))
 }
 
 pub fn item_to_string(i: &ast::Item) -> String {
-    $to_string(|s| s.print_item(i))
+    to_string(|s| s.print_item(i))
 }
 
 pub fn impl_item_to_string(i: &ast::ImplItem) -> String {
-    $to_string(|s| s.print_impl_item(i))
+    to_string(|s| s.print_impl_item(i))
 }
 
 pub fn trait_item_to_string(i: &ast::TraitItem) -> String {
-    $to_string(|s| s.print_trait_item(i))
+    to_string(|s| s.print_trait_item(i))
 }
 
 pub fn generics_to_string(generics: &ast::Generics) -> String {
-    $to_string(|s| s.print_generics(generics))
+    to_string(|s| s.print_generics(generics))
 }
 
 pub fn where_clause_to_string(i: &ast::WhereClause) -> String {
-    $to_string(|s| s.print_where_clause(i))
+    to_string(|s| s.print_where_clause(i))
 }
 
 pub fn fn_block_to_string(p: &ast::FnDecl) -> String {
-    $to_string(|s| s.print_fn_block_args(p))
+    to_string(|s| s.print_fn_block_args(p))
 }
 
 pub fn path_to_string(p: &ast::Path) -> String {
-    $to_string(|s| s.print_path(p, false, 0))
+    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))
+    to_string(|s| s.print_ident(*id))
 }
 
 pub fn fun_to_string(decl: &ast::FnDecl, unsafety: ast::Unsafety, name: ast::Ident,
                   opt_explicit_self: Option<&ast::ExplicitSelf_>,
                   generics: &ast::Generics) -> String {
-    $to_string(|s| {
+    to_string(|s| {
         try!(s.head(""));
         try!(s.print_fn(decl, unsafety, abi::Rust, Some(name),
                         generics, opt_explicit_self, ast::Inherited));
@@ -396,7 +389,7 @@ pub fn fun_to_string(decl: &ast::FnDecl, unsafety: ast::Unsafety, name: ast::Ide
 }
 
 pub fn block_to_string(blk: &ast::Block) -> String {
-    $to_string(|s| {
+    to_string(|s| {
         // containing cbox, will be closed by print-block at }
         try!(s.cbox(indent_unit));
         // head-ibox, will be closed by print-block after {
@@ -406,59 +399,31 @@ pub fn block_to_string(blk: &ast::Block) -> String {
 }
 
 pub fn meta_item_to_string(mi: &ast::MetaItem) -> String {
-    $to_string(|s| s.print_meta_item(mi))
+    to_string(|s| s.print_meta_item(mi))
 }
 
 pub fn attribute_to_string(attr: &ast::Attribute) -> String {
-    $to_string(|s| s.print_attribute(attr))
+    to_string(|s| s.print_attribute(attr))
 }
 
 pub fn lit_to_string(l: &ast::Lit) -> String {
-    $to_string(|s| s.print_literal(l))
+    to_string(|s| s.print_literal(l))
 }
 
 pub fn explicit_self_to_string(explicit_self: &ast::ExplicitSelf_) -> String {
-    $to_string(|s| s.print_explicit_self(explicit_self, ast::MutImmutable).map(|_| {}))
+    to_string(|s| s.print_explicit_self(explicit_self, ast::MutImmutable).map(|_| {}))
 }
 
 pub fn variant_to_string(var: &ast::Variant) -> String {
-    $to_string(|s| s.print_variant(var))
+    to_string(|s| s.print_variant(var))
 }
 
 pub fn arg_to_string(arg: &ast::Arg) -> String {
-    $to_string(|s| s.print_arg(arg))
+    to_string(|s| s.print_arg(arg))
 }
 
 pub fn mac_to_string(arg: &ast::Mac) -> String {
-    $to_string(|s| s.print_mac(arg, ::parse::token::Paren))
-}
-
-} }
-
-thing_to_string_impls! { to_string }
-
-// FIXME (Issue #16472): the whole `with_hygiene` mod should go away
-// after we revise the syntax::ext::quote::ToToken impls to go directly
-// to token-trees instea of thing -> string -> token-trees.
-
-pub mod with_hygiene {
-    use abi;
-    use ast;
-    use std::io;
-    use super::indent_unit;
-
-    // This function is the trick that all the rest of the routines
-    // hang on.
-    pub fn to_string_hyg<F>(f: F) -> String where
-        F: FnOnce(&mut super::State) -> io::Result<()>,
-    {
-        super::to_string(move |s| {
-            s.encode_idents_with_hygiene = true;
-            f(s)
-        })
-    }
-
-    thing_to_string_impls! { to_string_hyg }
+    to_string(|s| s.print_mac(arg, ::parse::token::Paren))
 }
 
 pub fn visibility_qualified(vis: ast::Visibility, s: &str) -> String {
@@ -796,6 +761,26 @@ pub fn print_foreign_item(&mut self,
         }
     }
 
+    fn print_associated_const(&mut self,
+                              ident: ast::Ident,
+                              ty: &ast::Ty,
+                              default: Option<&ast::Expr>,
+                              vis: ast::Visibility)
+                              -> io::Result<()>
+    {
+        try!(word(&mut self.s, &visibility_qualified(vis, "")));
+        try!(self.word_space("const"));
+        try!(self.print_ident(ident));
+        try!(self.word_space(":"));
+        try!(self.print_type(ty));
+        if let Some(expr) = default {
+            try!(space(&mut self.s));
+            try!(self.word_space("="));
+            try!(self.print_expr(expr));
+        }
+        word(&mut self.s, ";")
+    }
+
     fn print_associated_type(&mut self,
                              ident: ast::Ident,
                              bounds: Option<&ast::TyParamBounds>,
@@ -1269,6 +1254,11 @@ pub fn print_trait_item(&mut self, ti: &ast::TraitItem)
         try!(self.maybe_print_comment(ti.span.lo));
         try!(self.print_outer_attributes(&ti.attrs));
         match ti.node {
+            ast::ConstTraitItem(ref ty, ref default) => {
+                try!(self.print_associated_const(ti.ident, &ty,
+                                                 default.as_ref().map(|expr| &**expr),
+                                                 ast::Inherited));
+            }
             ast::MethodTraitItem(ref sig, ref body) => {
                 if body.is_some() {
                     try!(self.head(""));
@@ -1295,6 +1285,9 @@ pub fn print_impl_item(&mut self, ii: &ast::ImplItem) -> io::Result<()> {
         try!(self.maybe_print_comment(ii.span.lo));
         try!(self.print_outer_attributes(&ii.attrs));
         match ii.node {
+            ast::ConstImplItem(ref ty, ref expr) => {
+                try!(self.print_associated_const(ii.ident, &ty, Some(&expr), ii.vis));
+            }
             ast::MethodImplItem(ref sig, ref body) => {
                 try!(self.head(""));
                 try!(self.print_method_sig(ii.ident, sig, ii.vis));
@@ -2006,12 +1999,7 @@ pub fn print_decl(&mut self, decl: &ast::Decl) -> io::Result<()> {
     }
 
     pub fn print_ident(&mut self, ident: ast::Ident) -> io::Result<()> {
-        if self.encode_idents_with_hygiene {
-            let encoded = ident.encode_with_hygiene();
-            try!(word(&mut self.s, &encoded[..]))
-        } else {
-            try!(word(&mut self.s, &token::get_ident(ident)))
-        }
+        try!(word(&mut self.s, &token::get_ident(ident)));
         self.ann.post(self, NodeIdent(&ident))
     }
 
@@ -2192,6 +2180,9 @@ pub fn print_pat(&mut self, pat: &ast::Pat) -> io::Result<()> {
                     }
                 }
             }
+            ast::PatQPath(ref qself, ref path) => {
+                try!(self.print_qpath(path, qself, false));
+            }
             ast::PatStruct(ref path, ref fields, etc) => {
                 try!(self.print_path(path, true, 0));
                 try!(self.nbsp());
@@ -3008,7 +2999,7 @@ pub fn print_unsafety(&mut self, s: ast::Unsafety) -> io::Result<()> {
 fn repeat(s: &str, n: usize) -> String { iter::repeat(s).take(n).collect() }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use super::*;
 
     use ast;
index 6adeb30a94ec4d3c68f8a8af5bfe2d3f2e218edc..d016eb39239f68a64e0154ad5f491b671e5234b6 100644 (file)
@@ -142,7 +142,7 @@ pub fn is_whitespace(c: char) -> bool {
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use super::*;
 
     #[test] fn eqmodws() {
index 153f9d4a26df155dd4773cb2a22ecdc4a32ae985..5353d12b67813fe483dee91c92409ab2da067a5b 100644 (file)
@@ -204,7 +204,7 @@ fn move_map<F>(self, mut f: F) -> SmallVector<T> where F: FnMut(T) -> T {
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use super::*;
 
     #[test]
index 4c70fc9f81fb93ce267563a3253b1fe0614e51cc..6cf791b10be67612eaa75ad146d630fafb1a5602 100644 (file)
@@ -464,6 +464,10 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
                 }
             }
         }
+        PatQPath(ref qself, ref path) => {
+            visitor.visit_ty(&qself.ty);
+            visitor.visit_path(path, pattern.id)
+        }
         PatStruct(ref path, ref fields, _) => {
             visitor.visit_path(path, pattern.id);
             for field in fields {
@@ -619,6 +623,12 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai
         visitor.visit_attribute(attr);
     }
     match trait_item.node {
+        ConstTraitItem(ref ty, ref default) => {
+            visitor.visit_ty(ty);
+            if let Some(ref expr) = *default {
+                visitor.visit_expr(expr);
+            }
+        }
         MethodTraitItem(ref sig, None) => {
             visitor.visit_explicit_self(&sig.explicit_self);
             visitor.visit_generics(&sig.generics);
@@ -641,6 +651,10 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt
         visitor.visit_attribute(attr);
     }
     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(FkMethod(impl_item.ident, sig, Some(impl_item.vis)), &sig.decl,
                              body, impl_item.span, impl_item.id);
index c9ad08bb8523485ae9eb9478dfe97fd71fd8a493..2b8c24741ae7ccb0e2c6b94c61f2f628aed8dbad 100644 (file)
@@ -573,7 +573,7 @@ fn format(val: Param, op: FormatOp, flags: Flags) -> Result<Vec<u8> ,String> {
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use super::{expand,Param,Words,Variables,Number};
     use std::result::Result::Ok;
 
index 3de99088da47b3c653b9dcd6a8de63093b733df6..ef42d8c2506b38ecd8d2b9624f2ce8d84063ea1e 100644 (file)
@@ -345,7 +345,7 @@ pub fn msys_terminfo() -> Box<TermInfo> {
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
 
     use super::{boolnames, boolfnames, numnames, numfnames, stringnames, stringfnames};
 
index d5483593aa8888f3e487d145f7cd0e01b7b510de..26303d13b6cfcb61542d1d46ff45d29186a405a1 100644 (file)
@@ -52,7 +52,7 @@
   }
 
   for (var i = 0; i < toc.length; i++) {
-    if (toc[i].attributes['href'].value === href) {
+    if (toc[i].attributes['href'].value.split('/').pop() === href) {
       var nav = document.createElement('p');
       if (i > 0) {
         var prevNode = toc[i-1].cloneNode(true);
diff --git a/src/test/auxiliary/associated-const-cc-lib.rs b/src/test/auxiliary/associated-const-cc-lib.rs
new file mode 100644 (file)
index 0000000..1fd8fee
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(associated_consts)]
+
+#![crate_type="lib"]
+
+// These items are for testing that associated consts work cross-crate.
+pub trait Foo {
+    const BAR: usize;
+}
+
+pub struct FooNoDefault;
+
+impl Foo for FooNoDefault {
+    const BAR: usize = 0;
+}
+
+// These test that defaults and default resolution work cross-crate.
+pub trait FooDefault {
+    const BAR: usize = 1;
+}
+
+pub struct FooOverwriteDefault;
+
+impl FooDefault for FooOverwriteDefault {
+    const BAR: usize = 2;
+}
+
+pub struct FooUseDefault;
+
+impl FooDefault for FooUseDefault {}
+
+// Test inherent impls.
+pub struct InherentBar;
+
+impl InherentBar {
+    pub const BAR: usize = 3;
+}
index 5b7e52e9164e96744d8c34162eacf10d1b783cf7..54aac5195aee3bab71ec7c0c2bc9bc9121040f5b 100644 (file)
@@ -32,7 +32,6 @@ macro_rules! unexported_macro { () => (3) }
 #[plugin_registrar]
 pub fn plugin_registrar(reg: &mut Registry) {
     reg.register_macro("make_a_1", expand_make_a_1);
-    reg.register_macro("forged_ident", expand_forged_ident);
     reg.register_macro("identity", expand_identity);
     reg.register_syntax_extension(
         token::intern("into_foo"),
@@ -104,29 +103,4 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt,
     }
 }
 
-fn expand_forged_ident(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult+'static> {
-    use syntax::ext::quote::rt::*;
-
-    if !tts.is_empty() {
-        cx.span_fatal(sp, "forged_ident takes no arguments");
-    }
-
-    // Most of this is modelled after the expansion of the `quote_expr!`
-    // macro ...
-    let parse_sess = cx.parse_sess();
-    let cfg = cx.cfg();
-
-    // ... except this is where we inject a forged identifier,
-    // and deliberately do not call `cx.parse_tts_with_hygiene`
-    // (because we are testing that this will be *rejected*
-    //  by the default parser).
-
-    let expr = {
-        let tt = cx.parse_tts("\x00name_2,ctxt_0\x00".to_string());
-        let mut parser = new_parser_from_tts(parse_sess, cfg, tt);
-        parser.parse_expr()
-    };
-    MacEager::expr(expr)
-}
-
 pub fn foo() {}
index efbb5dfb5491ebe855be1249909590a2031c055a..81a6fb8ff6debbe064207a60c21b646d9973d258 100644 (file)
@@ -101,8 +101,8 @@ fn get(&self, x: f32, y: f32) -> f32 {
 
 fn main() {
     let symbols = [' ', '░', '▒', '▓', '█', '█'];
-    let mut pixels = [0f32; 256*256];
-    let n2d = Noise2DContext::new();
+    let mut pixels = Box::new([0f32; 256*256]);
+    let n2d = Box::new(Noise2DContext::new());
 
     for _ in 0..100 {
         for y in 0..256 {
index 7c9f33678a39c924fdabdd7849fe75a1bf865f49..55b2b1e2e324f600aa671bd9a98771b188ccefc4 100644 (file)
 use std::thread;
 
 struct Tables {
-    table8: [u8; 1 << 8],
-    table16: [u16; 1 << 16]
+    table8: Box<[u8; 1 << 8]>,
+    table16: Box<[u16; 1 << 16]>,
 }
 
 impl Tables {
     fn new() -> Tables {
-        let mut table8 = [0;1 << 8];
+        let mut table8 = Box::new([0;1 << 8]);
         for (i, v) in table8.iter_mut().enumerate() {
             *v = Tables::computed_cpl8(i as u8);
         }
-        let mut table16 = [0;1 << 16];
+        let mut table16 = Box::new([0;1 << 16]);
         for (i, v) in table16.iter_mut().enumerate() {
             *v = (table8[i & 255] as u16) << 8 |
                  table8[i >> 8]  as u16;
diff --git a/src/test/compile-fail-fulldeps/macro-crate-cannot-read-embedded-ident.rs b/src/test/compile-fail-fulldeps/macro-crate-cannot-read-embedded-ident.rs
deleted file mode 100644 (file)
index fd1deff..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// aux-build:macro_crate_test.rs
-// ignore-stage1
-// error-pattern: unknown start of token: \u{0}
-
-// Issue #15750 and #15962 : this test is checking that the standard
-// parser rejects embedded idents.  pnkfelix did not want to attempt
-// to make a test file that itself used the embedded ident input form,
-// since he worried that would be difficult to work with in many text
-// editors, so instead he made a macro that expands into the embedded
-// ident form.
-
-#![feature(plugin)]
-#![plugin(macro_crate_test)]
-
-fn main() {
-    let x = 0;
-    assert_eq!(3, forged_ident!());
-}
diff --git a/src/test/compile-fail-fulldeps/qquote.rs b/src/test/compile-fail-fulldeps/qquote.rs
new file mode 100644 (file)
index 0000000..cf68efe
--- /dev/null
@@ -0,0 +1,42 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-cross-compile
+
+#![feature(quote, rustc_private)]
+
+extern crate syntax;
+
+use syntax::ast;
+use syntax::codemap::{self, DUMMY_SP};
+use syntax::parse;
+use syntax::print::pprust;
+
+fn main() {
+    let ps = syntax::parse::new_parse_sess();
+    let mut cx = syntax::ext::base::ExtCtxt::new(
+        &ps, vec![],
+        syntax::ext::expand::ExpansionConfig::default("qquote".to_string()));
+    cx.bt_push(syntax::codemap::ExpnInfo {
+        call_site: DUMMY_SP,
+        callee: syntax::codemap::NameAndSpan {
+            name: "".to_string(),
+            format: syntax::codemap::MacroBang,
+            allow_internal_unstable: false,
+            span: None,
+        }
+    });
+    let cx = &mut cx;
+
+    assert_eq!(pprust::expr_to_string(&*quote_expr!(&cx, 23)), "23");
+
+    let expr = quote_expr!(&cx, 2 - $abcd + 7); //~ ERROR unresolved name `abcd`
+    assert_eq!(pprust::expr_to_string(&*expr), "2 - $abcd + 7");
+}
diff --git a/src/test/compile-fail/associated-const-dead-code.rs b/src/test/compile-fail/associated-const-dead-code.rs
new file mode 100644 (file)
index 0000000..1ed156d
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(associated_consts)]
+#![deny(dead_code)]
+
+struct MyFoo;
+
+impl MyFoo {
+    const BAR: u32 = 1;
+    //~^ ERROR associated const is never used: `BAR`
+}
+
+fn main() {
+    let _: MyFoo = MyFoo;
+}
diff --git a/src/test/compile-fail/associated-const-impl-wrong-type.rs b/src/test/compile-fail/associated-const-impl-wrong-type.rs
new file mode 100644 (file)
index 0000000..4f20d9e
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(associated_consts)]
+
+trait Foo {
+    const BAR: u32;
+}
+
+struct SignedBar;
+
+impl Foo for SignedBar {
+    const BAR: i32 = -1;
+    //~^ ERROR E0326
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/associated-const-private-impl.rs b/src/test/compile-fail/associated-const-private-impl.rs
new file mode 100644 (file)
index 0000000..be949db
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(associated_consts)]
+
+mod bar1 {
+    pub use self::bar2::Foo;
+    mod bar2 {
+        pub struct Foo;
+
+        impl Foo {
+            const ID: i32 = 1;
+        }
+    }
+}
+
+fn main() {
+    assert_eq!(1, bar1::Foo::ID);
+    //~^ERROR associated const `ID` is private
+}
diff --git a/src/test/compile-fail/associated-const-upper-case-lint.rs b/src/test/compile-fail/associated-const-upper-case-lint.rs
new file mode 100644 (file)
index 0000000..752691f
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(associated_consts)]
+#![deny(non_upper_case_globals)]
+#![allow(dead_code)]
+
+struct Foo;
+
+impl Foo {
+    const not_upper: bool = true;
+}
+//~^^ ERROR associated constant `not_upper` should have an upper case name such as `NOT_UPPER`
+
+fn main() {}
diff --git a/src/test/compile-fail/feature-gate-negate-unsigned.rs b/src/test/compile-fail/feature-gate-negate-unsigned.rs
new file mode 100644 (file)
index 0000000..7dc654f
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that negating unsigned integers is gated by `negate_unsigned` feature
+// gate
+
+const MAX: usize = -1;
+//~^ ERROR unary negation of unsigned integers may be removed in the future
+
+fn main() {}
diff --git a/src/test/compile-fail/feature-gate-on-unimplemented.rs b/src/test/compile-fail/feature-gate-on-unimplemented.rs
new file mode 100644 (file)
index 0000000..5d32bba
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that `#[rustc_on_unimplemented]` is gated by `on_unimplemented` feature
+// gate.
+
+#[rustc_on_unimplemented = "test error `{Self}` with `{Bar}`"]
+//~^ ERROR the `#[rustc_on_unimplemented]` attribute is an experimental feature
+trait Foo<Bar>
+{}
+
+fn main() {}
diff --git a/src/test/compile-fail/feature-gate-optin-builtin-traits.rs b/src/test/compile-fail/feature-gate-optin-builtin-traits.rs
new file mode 100644 (file)
index 0000000..59d7473
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that default and negative trait implementations are gated by
+// `optin_builtin_traits` feature gate
+
+struct DummyStruct;
+
+trait DummyTrait {
+    fn dummy(&self) {}
+}
+
+impl DummyTrait for .. {}
+//~^ ERROR default trait implementations are experimental and possibly buggy
+
+impl !DummyTrait for DummyStruct {}
+//~^ ERROR negative trait bounds are not yet fully implemented; use marker types for now
+
+fn main() {}
diff --git a/src/test/compile-fail/feature-gate-plugin.rs b/src/test/compile-fail/feature-gate-plugin.rs
new file mode 100644 (file)
index 0000000..3b5d762
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that `#![plugin(...)]` attribute is gated by `plugin` feature gate
+
+#![plugin(foo)]
+//~^ ERROR compiler plugins are experimental and possibly buggy
+
+fn main() {}
diff --git a/src/test/compile-fail/feature-gate-rustc-attrs.rs b/src/test/compile-fail/feature-gate-rustc-attrs.rs
new file mode 100644 (file)
index 0000000..dab44b6
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-tidy-linelength
+
+// Test that `#[rustc_*]` attributes are gated by `rustc_attrs` feature gate.
+
+#[rustc_variance] //~ ERROR the `#[rustc_variance]` attribute is an experimental feature
+#[rustc_error] //~ ERROR the `#[rustc_error]` attribute is an experimental feature
+#[rustc_move_fragments] //~ ERROR the `#[rustc_move_fragments]` attribute is an experimental feature
+#[rustc_foo]
+//~^ ERROR unless otherwise specified, attributes with the prefix `rustc_` are reserved for internal compiler diagnostics
+
+fn main() {}
diff --git a/src/test/compile-fail/feature-gate-rustc-diagnostic-macros.rs b/src/test/compile-fail/feature-gate-rustc-diagnostic-macros.rs
new file mode 100644 (file)
index 0000000..8286d83
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that diagnostic macros are gated by `rustc_diagnostic_macros` feature
+// gate
+
+__register_diagnostic!(E0001);
+//~^ ERROR macro undefined: '__register_diagnostic!'
+
+fn main() {
+    __diagnostic_used!(E0001);
+    //~^ ERROR macro undefined: '__diagnostic_used!'
+}
+
+__build_diagnostic_array!(DIAGNOSTICS);
+//~^ ERROR macro undefined: '__build_diagnostic_array!'
diff --git a/src/test/compile-fail/feature-gate-slice-patterns.rs b/src/test/compile-fail/feature-gate-slice-patterns.rs
new file mode 100644 (file)
index 0000000..625cb2d
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that slice pattern syntax is gated by `slice_patterns` feature gate
+
+fn main() {
+    let x = [1, 2, 3, 4, 5];
+    match x {
+        [1, 2, xs..] => {} //~ ERROR slice pattern syntax is experimental
+    }
+}
diff --git a/src/test/compile-fail/gated-associated_consts.rs b/src/test/compile-fail/gated-associated_consts.rs
new file mode 100644 (file)
index 0000000..21672b1
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait MyTrait {
+    const C: bool;
+    //~^ associated constants are experimental
+    //~| add #![feature(associated_consts)] to the crate attributes to enable
+}
+
+struct Foo;
+
+impl Foo {
+    const C: bool = true;
+    //~^ associated constants are experimental
+    //~| add #![feature(associated_consts)] to the crate attributes to enable
+}
diff --git a/src/test/compile-fail/gated-box-patterns.rs b/src/test/compile-fail/gated-box-patterns.rs
deleted file mode 100644 (file)
index d82d0de..0000000
+++ /dev/null
@@ -1,21 +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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Test that patterns including the box syntax are gated by `box_patterns` feature gate.
-
-fn main() {
-    let x = Box::new(1);
-
-    match x {
-        box 1 => (),
-        //~^ box pattern syntax is experimental
-        _     => ()
-    };
-}
diff --git a/src/test/compile-fail/gated-simd-ffi.rs b/src/test/compile-fail/gated-simd-ffi.rs
deleted file mode 100644 (file)
index 883e1be..0000000
+++ /dev/null
@@ -1,27 +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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Test that the use of smid types in the ffi is gated by `smid_ffi` feature gate.
-
-#![feature(simd)]
-
-#[repr(C)]
-#[derive(Copy, Clone)]
-#[simd]
-pub struct f32x4(f32, f32, f32, f32);
-
-#[allow(dead_code)]
-extern {
-    fn foo(x: f32x4);
-    //~^ ERROR use of SIMD type `f32x4` in FFI is highly experimental and may result in invalid code
-    //~| HELP add #![feature(simd_ffi)] to the crate attributes to enable
-}
-
-fn main() {}
diff --git a/src/test/compile-fail/impl-wrong-item-for-trait.rs b/src/test/compile-fail/impl-wrong-item-for-trait.rs
new file mode 100644 (file)
index 0000000..9b3e28c
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(associated_consts)]
+
+trait Foo {
+    fn bar(&self);
+    const MY_CONST: u32;
+}
+
+pub struct FooConstForMethod;
+
+impl Foo for FooConstForMethod {
+    //~^ ERROR E0046
+    const bar: u64 = 1;
+    //~^ ERROR E0323
+    const MY_CONST: u32 = 1;
+}
+
+pub struct FooMethodForConst;
+
+impl Foo for FooMethodForConst {
+    //~^ ERROR E0046
+    fn bar(&self) {}
+    fn MY_CONST() {}
+    //~^ ERROR E0324
+}
+
+pub struct FooTypeForMethod;
+
+impl Foo for FooTypeForMethod {
+    //~^ ERROR E0046
+    type bar = u64;
+    //~^ ERROR E0325
+    const MY_CONST: u32 = 1;
+}
+
+fn main () {}
diff --git a/src/test/compile-fail/issue-20616-1.rs b/src/test/compile-fail/issue-20616-1.rs
new file mode 100644 (file)
index 0000000..5b4f994
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// We need all these 9 issue-20616-N.rs files
+// becase we can only catch one parsing error at a time
+
+
+
+type Type_1_<'a, T> = &'a T;
+
+
+type Type_1<'a T> = &'a T; //~ error: expected `,` or `>` after lifetime name, found `T`
+
+
+//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
+
+
+//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
+
+
+//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
+
+
+type Type_5_<'a> = Type_1_<'a, ()>;
+
+
+//type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
+
+
+//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
+
+
+//type Type_7 = Box<(),,>; // error: expected type, found `,`
+
+
+//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
+
+
+//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
diff --git a/src/test/compile-fail/issue-20616-2.rs b/src/test/compile-fail/issue-20616-2.rs
new file mode 100644 (file)
index 0000000..65305ff
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// We need all these 9 issue-20616-N.rs files
+// becase we can only catch one parsing error at a time
+
+
+
+type Type_1_<'a, T> = &'a T;
+
+
+//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
+
+
+type Type_2 = Type_1_<'static ()>; //~ error: expected `,` or `>` after lifetime name, found `(`
+
+
+//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
+
+
+//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
+
+
+type Type_5_<'a> = Type_1_<'a, ()>;
+
+
+//type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
+
+
+//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
+
+
+//type Type_7 = Box<(),,>; // error: expected type, found `,`
+
+
+//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
+
+
+//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
diff --git a/src/test/compile-fail/issue-20616-3.rs b/src/test/compile-fail/issue-20616-3.rs
new file mode 100644 (file)
index 0000000..101f810
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// We need all these 9 issue-20616-N.rs files
+// becase we can only catch one parsing error at a time
+
+
+
+type Type_1_<'a, T> = &'a T;
+
+
+//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
+
+
+//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
+
+
+type Type_3<T> = Box<T,,>; //~ error: expected type, found `,`
+
+
+//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
+
+
+type Type_5_<'a> = Type_1_<'a, ()>;
+
+
+//type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
+
+
+//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
+
+
+//type Type_7 = Box<(),,>; // error: expected type, found `,`
+
+
+//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
+
+
+//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
diff --git a/src/test/compile-fail/issue-20616-4.rs b/src/test/compile-fail/issue-20616-4.rs
new file mode 100644 (file)
index 0000000..6450e9e
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// We need all these 9 issue-20616-N.rs files
+// becase we can only catch one parsing error at a time
+
+
+
+type Type_1_<'a, T> = &'a T;
+
+
+//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
+
+
+//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
+
+
+//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
+
+
+type Type_4<T> = Type_1_<'static,, T>; //~ error: expected type, found `,`
+
+
+type Type_5_<'a> = Type_1_<'a, ()>;
+
+
+//type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
+
+
+//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
+
+
+//type Type_7 = Box<(),,>; // error: expected type, found `,`
+
+
+//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
+
+
+//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
diff --git a/src/test/compile-fail/issue-20616-5.rs b/src/test/compile-fail/issue-20616-5.rs
new file mode 100644 (file)
index 0000000..d184042
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// We need all these 9 issue-20616-N.rs files
+// becase we can only catch one parsing error at a time
+
+
+
+type Type_1_<'a, T> = &'a T;
+
+
+//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
+
+
+//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
+
+
+//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
+
+
+//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
+
+
+type Type_5_<'a> = Type_1_<'a, ()>;
+
+
+type Type_5<'a> = Type_1_<'a, (),,>; //~ error: expected type, found `,`
+
+
+//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
+
+
+//type Type_7 = Box<(),,>; // error: expected type, found `,`
+
+
+//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
+
+
+//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
diff --git a/src/test/compile-fail/issue-20616-6.rs b/src/test/compile-fail/issue-20616-6.rs
new file mode 100644 (file)
index 0000000..b0b5bc6
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// We need all these 9 issue-20616-N.rs files
+// becase we can only catch one parsing error at a time
+
+
+
+type Type_1_<'a, T> = &'a T;
+
+
+//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
+
+
+//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
+
+
+//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
+
+
+//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
+
+
+type Type_5_<'a> = Type_1_<'a, ()>;
+
+
+//type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
+
+
+type Type_6 = Type_5_<'a,,>; //~ error: expected type, found `,`
+
+
+//type Type_7 = Box<(),,>; // error: expected type, found `,`
+
+
+//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
+
+
+//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
diff --git a/src/test/compile-fail/issue-20616-7.rs b/src/test/compile-fail/issue-20616-7.rs
new file mode 100644 (file)
index 0000000..0958f8b
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// We need all these 9 issue-20616-N.rs files
+// becase we can only catch one parsing error at a time
+
+
+
+type Type_1_<'a, T> = &'a T;
+
+
+//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
+
+
+//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
+
+
+//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
+
+
+//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
+
+
+type Type_5_<'a> = Type_1_<'a, ()>;
+
+
+//type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
+
+
+//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
+
+
+type Type_7 = Box<(),,>; //~ error: expected type, found `,`
+
+
+//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
+
+
+//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
diff --git a/src/test/compile-fail/issue-20616-8.rs b/src/test/compile-fail/issue-20616-8.rs
new file mode 100644 (file)
index 0000000..07ced7a
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// We need all these 9 issue-20616-N.rs files
+// becase we can only catch one parsing error at a time
+
+
+
+type Type_1_<'a, T> = &'a T;
+
+
+//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
+
+
+//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
+
+
+//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
+
+
+//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
+
+
+type Type_5_<'a> = Type_1_<'a, ()>;
+
+
+//type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
+
+
+//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
+
+
+//type Type_7 = Box<(),,>; // error: expected type, found `,`
+
+
+type Type_8<'a,,> = &'a (); //~ error: expected ident, found `,`
+
+
+//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
diff --git a/src/test/compile-fail/issue-20616-9.rs b/src/test/compile-fail/issue-20616-9.rs
new file mode 100644 (file)
index 0000000..7847dea
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// We need all these 9 issue-20616-N.rs files
+// becase we can only catch one parsing error at a time
+
+
+
+type Type_1_<'a, T> = &'a T;
+
+
+//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
+
+
+//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
+
+
+//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
+
+
+//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
+
+
+type Type_5_<'a> = Type_1_<'a, ()>;
+
+
+//type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
+
+
+//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
+
+
+//type Type_7 = Box<(),,>; // error: expected type, found `,`
+
+
+//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
+
+
+type Type_9<T,,> = Box<T>; //~ error: expected ident, found `,`
diff --git a/src/test/compile-fail/issue-22673.rs b/src/test/compile-fail/issue-22673.rs
new file mode 100644 (file)
index 0000000..6983d1f
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Expr : PartialEq<Self::Item> {
+    //~^ ERROR: unsupported cyclic reference between types/traits detected
+    type Item = Expr;
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/issue-22897.rs b/src/test/compile-fail/issue-22897.rs
new file mode 100644 (file)
index 0000000..c6bbf2d
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() { }
+
+// Before these errors would ICE as "cat_expr Errd" because the errors
+// were unknown when the bug was triggered.
+
+fn unconstrained_type() {
+    [];
+    //~^ ERROR cannot determine a type for this expression: unconstrained type
+}
diff --git a/src/test/compile-fail/issue-23041.rs b/src/test/compile-fail/issue-23041.rs
new file mode 100644 (file)
index 0000000..6889575
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::any::Any;
+fn main()
+{
+    fn bar(x:i32) ->i32 { 3*x };
+    let b:Box<Any> = Box::new(bar as fn(_)->_);
+    b.downcast_ref::<fn(_)->_>();
+    //~^ ERROR cannot determine a type for this expression: unconstrained type
+}
diff --git a/src/test/compile-fail/issue-23253.rs b/src/test/compile-fail/issue-23253.rs
new file mode 100644 (file)
index 0000000..e977cd1
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+enum Foo { Bar }
+
+fn main() {
+    Foo::Bar.a;
+    //~^ ERROR: attempted access of field `a` on type `Foo`, but no field with that name was found
+}
diff --git a/src/test/compile-fail/issue-23966.rs b/src/test/compile-fail/issue-23966.rs
new file mode 100644 (file)
index 0000000..18b5136
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    "".chars().fold(|_, _| (), ());
+    //~^ ERROR cannot determine a type for this expression: unconstrained type
+}
diff --git a/src/test/compile-fail/issue-24013.rs b/src/test/compile-fail/issue-24013.rs
new file mode 100644 (file)
index 0000000..0adad8a
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    use std::mem::{transmute, swap};
+    let a = 1;
+    let b = 2;
+    unsafe {swap::<&mut _>(transmute(&a), transmute(&b))};
+    //~^ ERROR cannot determine a type for this expression: unconstrained type
+}
diff --git a/src/test/compile-fail/issue-24895-copy-clone-dropck.rs b/src/test/compile-fail/issue-24895-copy-clone-dropck.rs
new file mode 100644 (file)
index 0000000..2883511
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that one cannot subvert Drop Check rule via a user-defined
+// Clone implementation.
+
+#![allow(unused_variables, unused_assignments)]
+
+struct D<T:Copy>(T, &'static str);
+
+#[derive(Copy)]
+struct S<'a>(&'a D<i32>, &'static str);
+impl<'a> Clone for S<'a> {
+    fn clone(&self) -> S<'a> {
+        println!("cloning `S(_, {})` and thus accessing: {}", self.1, (self.0).0);
+        S(self.0, self.1)
+    }
+}
+
+impl<T:Copy> Drop for D<T> {
+    fn drop(&mut self) {
+        println!("calling Drop for {}", self.1);
+        let _call = self.0.clone();
+    }
+}
+
+fn main() {
+    let (d2, d1);
+    d1 = D(34, "d1");
+    d2 = D(S(&d1, "inner"), "d2"); //~ ERROR `d1` does not live long enough
+}
diff --git a/src/test/compile-fail/method-path-in-pattern.rs b/src/test/compile-fail/method-path-in-pattern.rs
new file mode 100644 (file)
index 0000000..faf6d25
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Foo;
+
+impl Foo {
+    fn bar(&self) {}
+}
+
+trait MyTrait {
+    fn trait_bar() {}
+}
+
+impl MyTrait for Foo {}
+
+fn main() {
+    match 0u32 {
+        Foo::bar => {} //~ ERROR E0327
+    }
+    match 0u32 {
+        <Foo>::bar => {} //~ ERROR E0327
+    }
+    match 0u32 {
+        <Foo>::trait_bar => {} //~ ERROR E0327
+    }
+}
diff --git a/src/test/compile-fail/method-resolvable-path-in-pattern.rs b/src/test/compile-fail/method-resolvable-path-in-pattern.rs
new file mode 100644 (file)
index 0000000..0df824e
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Foo;
+
+trait MyTrait {
+    fn trait_bar() {}
+}
+
+impl MyTrait for Foo {}
+
+fn main() {
+    match 0u32 {
+        <Foo as MyTrait>::trait_bar => {}
+        //~^ ERROR `trait_bar` is not an associated const
+    }
+}
diff --git a/src/test/compile-fail/region-bound-extra-bound-in-impl.rs b/src/test/compile-fail/region-bound-extra-bound-in-impl.rs
new file mode 100644 (file)
index 0000000..5bcc6be
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Regression test for issue #22779. An extra where clause was
+// permitted on the impl that is not present on the trait.
+
+trait Tr<'a, T> {
+    fn renew<'b: 'a>(self) -> &'b mut [T];
+}
+
+impl<'a, T> Tr<'a, T> for &'a mut [T] {
+    fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b {
+        //~^ ERROR lifetime bound not satisfied
+        &mut self[..]
+    }
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/region-bound-extra-bound-in-inherent-impl.rs b/src/test/compile-fail/region-bound-extra-bound-in-inherent-impl.rs
new file mode 100644 (file)
index 0000000..c1df057
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test related to #22779. In this case, the impl is an inherent impl,
+// so it doesn't have to match any trait, so no error results.
+
+#![feature(rustc_attrs)]
+#![allow(dead_code)]
+
+struct MySlice<'a, T:'a>(&'a mut [T]);
+
+impl<'a, T> MySlice<'a, T> {
+    fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b {
+        &mut self.0[..]
+    }
+}
+
+#[rustc_error]
+fn main() { } //~ ERROR compilation successful
diff --git a/src/test/compile-fail/region-bound-same-bounds-in-trait-and-impl.rs b/src/test/compile-fail/region-bound-same-bounds-in-trait-and-impl.rs
new file mode 100644 (file)
index 0000000..3115e5a
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test related to #22779, but where the `'a:'b` relation
+// appears in the trait too. No error here.
+
+#![feature(rustc_attrs)]
+
+trait Tr<'a, T> {
+    fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b;
+}
+
+impl<'a, T> Tr<'a, T> for &'a mut [T] {
+    fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b {
+        &mut self[..]
+    }
+}
+
+#[rustc_error]
+fn main() { } //~ ERROR compilation successful
index 278ccd3c11936f3b931d0cd2ce64912ec55cc0c5..abffd33e3f83e857a192aa63a1264621be8f52a5 100644 (file)
@@ -50,7 +50,9 @@ fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
     fn okay_bound<'b,'c,'e:'b+'c>(self, b: Inv<'b>, c: Inv<'c>, e: Inv<'e>) {
     }
 
-    fn another_bound<'x: 't>(self, x: Inv<'x>, y: Inv<'t>) {}
+    fn another_bound<'x: 't>(self, x: Inv<'x>, y: Inv<'t>) {
+        //~^ ERROR lifetime bound not satisfied
+    }
 }
 
 fn main() { }
diff --git a/src/test/parse-fail/brace-after-qualified-path-in-match.rs b/src/test/parse-fail/brace-after-qualified-path-in-match.rs
new file mode 100644 (file)
index 0000000..66f462d
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn foo() {
+    match x {
+        <T as Trait>::Type{key: value} => (),
+        //~^ ERROR unexpected `{` after qualified path
+        _ => (),
+    }
+}
index 2c993b7654e677e7d7f5f6d3947ec3b5007214b2..be6bd516d6fe439388160260d61fc3c4f824d302 100644 (file)
@@ -16,6 +16,6 @@ impl Foo {
     fn foo() {}
 
     #[stable(feature = "rust1", since = "1.0.0")]
-} //~ ERROR expected one of `extern`, `fn`, `pub`, `type`, or `unsafe`, found `}`
+} //~ ERROR expected one of `const`, `extern`, `fn`, `pub`, `type`, or `unsafe`, found `}`
 
 fn main() {}
index 8462bd8fd016a14b50879dcddefc4a7e9326e943..d1d8d3acf91871bc581d3799380a47aca6d1126f 100644 (file)
@@ -14,6 +14,6 @@
 
 impl Foo {
     #[stable(feature = "rust1", since = "1.0.0")]
-} //~ ERROR expected one of `extern`, `fn`, `pub`, `type`, or `unsafe`, found `}`
+} //~ ERROR expected one of `const`, `extern`, `fn`, `pub`, `type`, or `unsafe`, found `}`
 
 fn main() {}
index 44d979ba9798b21cb2d9d85f77e19639edf44420..76a4687f544da3578a553d654818dd5783e9506e 100644 (file)
@@ -11,5 +11,5 @@
 // compile-flags: -Z parse-only
 
 trait MyTrait<T>: Iterator {
-    Item = T; //~ ERROR expected one of `extern`, `fn`, `type`, or `unsafe`, found `Item`
+    Item = T; //~ ERROR expected one of `const`, `extern`, `fn`, `type`, or `unsafe`, found `Item`
 }
diff --git a/src/test/parse-fail/paren-after-qualified-path-in-match.rs b/src/test/parse-fail/paren-after-qualified-path-in-match.rs
new file mode 100644 (file)
index 0000000..d06fd2b
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn foo() {
+    match x {
+        <T as Trait>::Type(2) => (),
+        //~^ ERROR unexpected `(` after qualified path
+        _ => (),
+    }
+}
diff --git a/src/test/parse-fail/qquote-1.rs b/src/test/parse-fail/qquote-1.rs
deleted file mode 100644 (file)
index e30308b..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-flags: -Z parse-only
-
-// ignore-test Can't use syntax crate here
-
-#![feature(quote)]
-
-extern crate syntax;
-
-use io::*;
-
-use syntax::diagnostic;
-use syntax::ast;
-use syntax::codemap;
-use syntax::parse;
-use syntax::print::*;
-
-
-trait fake_ext_ctxt {
-    fn cfg() -> ast::CrateConfig;
-    fn parse_sess() -> parse::parse_sess;
-    fn call_site() -> span;
-    fn ident_of(st: &str) -> ast::ident;
-}
-
-type fake_session = parse::parse_sess;
-
-impl fake_ext_ctxt for fake_session {
-    fn cfg() -> ast::CrateConfig { Vec::new() }
-    fn parse_sess() -> parse::parse_sess { self }
-    fn call_site() -> span {
-        codemap::span {
-            lo: codemap::BytePos(0),
-            hi: codemap::BytePos(0),
-            expn_id: NO_EXPANSION
-        }
-    }
-    fn ident_of(st: &str) -> ast::ident {
-        self.interner.intern(st)
-    }
-}
-
-fn mk_ctxt() -> fake_ext_ctxt {
-    parse::new_parse_sess(None) as fake_ext_ctxt
-}
-
-
-
-fn main() {
-    let cx = mk_ctxt();
-
-    let abc = quote_expr!(cx, 23);
-    check_pp(abc,  pprust::print_expr, "23");
-
-    let expr3 = quote_expr!(cx, 2 - $abcd + 7); //~ ERROR unresolved name: abcd
-    check_pp(expr3,  pprust::print_expr, "2 - 23 + 7");
-}
-
-fn check_pp<T>(expr: T, f: |pprust::ps, T|, expect: str) {
-    panic!();
-}
diff --git a/src/test/parse-fail/qquote-2.rs b/src/test/parse-fail/qquote-2.rs
deleted file mode 100644 (file)
index ac501d3..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-flags: -Z parse-only
-
-// ignore-test Can't use syntax crate here
-
-#![feature(quote)]
-
-extern crate syntax;
-
-use syntax::diagnostic;
-use syntax::ast;
-use syntax::codemap;
-use syntax::parse::parser;
-use syntax::print::*;
-
-trait fake_ext_ctxt {
-    fn cfg() -> ast::CrateConfig;
-    fn parse_sess() -> parse::parse_sess;
-    fn call_site() -> span;
-    fn ident_of(st: &str) -> ast::ident;
-}
-
-type fake_session = parse::parse_sess;
-
-impl fake_ext_ctxt for fake_session {
-    fn cfg() -> ast::CrateConfig { Vec::new() }
-    fn parse_sess() -> parse::parse_sess { self }
-    fn call_site() -> span {
-        codemap::span {
-            lo: codemap::BytePos(0),
-            hi: codemap::BytePos(0),
-            expn_id: codemap::NO_EXPANSION
-        }
-    }
-    fn ident_of(st: &str) -> ast::ident {
-        self.interner.intern(st)
-    }
-}
-
-fn mk_ctxt() -> fake_ext_ctxt {
-    parse::new_parse_sess(None) as fake_ext_ctxt
-}
-
-
-fn main() {
-    let cx = mk_ctxt();
-
-    let stmt = quote_stmt!(cx, let x isize = 20;); //~ ERROR expected end-of-string
-    check_pp(*stmt,  pprust::print_stmt, "");
-}
-
-fn check_pp<T>(expr: T, f: |pprust::ps, T|, expect: str) {
-    panic!();
-}
index be1e89dd71799ff5d66165477fed81197631ffbd..7b6caad86b6ccc0b6005dc41c869648a065650ec 100644 (file)
@@ -14,5 +14,5 @@
 
 impl S {
     static fn f() {}
-    //~^ ERROR expected one of `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `static`
 }
+//~^^ ERROR expected one of `const`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `static`
diff --git a/src/test/parse-fail/trait-pub-assoc-const.rs b/src/test/parse-fail/trait-pub-assoc-const.rs
new file mode 100644 (file)
index 0000000..adce0d7
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Foo {
+    pub const Foo: u32;
+     //~^ ERROR expected one of `const`, `extern`, `fn`, `type`, or `unsafe`, found `pub`
+}
+
+fn main() {}
index 02d76234d4e57d97d73d98ee1745b7f6cca84305..dab6c433aba4c187fac25a0323d0438332d4af96 100644 (file)
@@ -9,7 +9,8 @@
 // except according to those terms.
 
 trait Foo {
-    pub type Foo; //~ ERROR expected one of `extern`, `fn`, `type`, or `unsafe`, found `pub`
+    pub type Foo;
+    //~^ ERROR expected one of `const`, `extern`, `fn`, `type`, or `unsafe`, found `pub`
 }
 
 fn main() {}
index e76802d2ea0f7bdeb1d5976c8ac10d83368de6ba..7cb9363830c43ab28b3d9f3089ba3b86d583d0b4 100644 (file)
@@ -9,7 +9,8 @@
 // except according to those terms.
 
 trait Foo {
-    pub fn foo(); //~ ERROR expected one of `extern`, `fn`, `type`, or `unsafe`, found `pub`
+    pub fn foo();
+    //~^ ERROR expected one of `const`, `extern`, `fn`, `type`, or `unsafe`, found `pub`
 }
 
 fn main() {}
diff --git a/src/test/run-fail-fulldeps/qquote.rs b/src/test/run-fail-fulldeps/qquote.rs
new file mode 100644 (file)
index 0000000..6ae2239
--- /dev/null
@@ -0,0 +1,44 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-cross-compile
+
+// error-pattern:expected identifier, found keyword `let`
+
+#![feature(quote, rustc_private)]
+
+extern crate syntax;
+
+use syntax::ast;
+use syntax::codemap::{self, DUMMY_SP};
+use syntax::parse;
+use syntax::print::pprust;
+
+fn main() {
+    let ps = syntax::parse::new_parse_sess();
+    let mut cx = syntax::ext::base::ExtCtxt::new(
+        &ps, vec![],
+        syntax::ext::expand::ExpansionConfig::default("qquote".to_string()));
+    cx.bt_push(syntax::codemap::ExpnInfo {
+        call_site: DUMMY_SP,
+        callee: syntax::codemap::NameAndSpan {
+            name: "".to_string(),
+            format: syntax::codemap::MacroBang,
+            allow_internal_unstable: false,
+            span: None,
+        }
+    });
+    let cx = &mut cx;
+
+    assert_eq!(pprust::expr_to_string(&*quote_expr!(&cx, 23)), "23");
+
+    let expr = quote_expr!(&cx, let x isize = 20;);
+    assert_eq!(pprust::expr_to_string(&*expr), "let x isize = 20;");
+}
diff --git a/src/test/run-make/cannot-read-embedded-idents/Makefile b/src/test/run-make/cannot-read-embedded-idents/Makefile
deleted file mode 100644 (file)
index 0d047be..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
--include ../tools.mk
-
-# Issue #15750, #15962 : This test ensures that our special embedded
-# ident syntax hack is not treated as legitimate input by the lexer in
-# normal mode.
-#
-# It is modelled after the `unicode-input/` test, since we need to
-# create files with syntax that can trip up normal text editting tools
-# (namely text with embedded nul-bytes).
-
-# This test attempts to run rustc itself from the compiled binary; but
-# that means that you need to set the LD_LIBRARY_PATH for rustc itself
-# while running create_and_compile, and that won't work for stage1.
-
-# FIXME ignore windows
-ifndef IS_WINDOWS
-ifeq ($(RUST_BUILD_STAGE),1)
-DOTEST=
-else
-DOTEST=dotest
-endif
-endif
-
-all: $(DOTEST)
-
-dotest:
-       $(RUSTC) create_and_compile.rs
-       $(call RUN,create_and_compile)  "$(RUSTC)" "$(TMPDIR)"
diff --git a/src/test/run-make/cannot-read-embedded-idents/create_and_compile.rs b/src/test/run-make/cannot-read-embedded-idents/create_and_compile.rs
deleted file mode 100644 (file)
index fd69d27..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use std::env;
-use std::fs::File;
-use std::process::Command;
-use std::io::Write;
-use std::path::Path;
-
-// creates broken.rs, which has the Ident \x00name_0,ctxt_0\x00
-// embedded within it, and then attempts to compile broken.rs with the
-// provided `rustc`
-
-fn main() {
-    let args: Vec<String> = env::args().collect();
-    let rustc = &args[1];
-    let tmpdir = Path::new(&args[2]);
-
-    let main_file = tmpdir.join("broken.rs");
-    let _ = File::create(&main_file).unwrap()
-        .write_all(b"pub fn main() {
-                   let \x00name_0,ctxt_0\x00 = 3;
-                   println!(\"{}\", \x00name_0,ctxt_0\x00);
-        }").unwrap();
-
-    // rustc is passed to us with --out-dir and -L etc., so we
-    // can't exec it directly
-    let result = Command::new("sh")
-        .arg("-c")
-        .arg(&format!("{} {}", rustc, main_file.display()))
-        .output().unwrap();
-    let err = String::from_utf8_lossy(&result.stderr);
-
-    // positive test so that this test will be updated when the
-    // compiler changes.
-    assert!(err.contains("unknown start of token"))
-}
index 1541e809b6178d24a77c953d764e784c1dfcf023..fc9f241af7f10279671b309896ba0b64bd0ce085 100644 (file)
@@ -12,6 +12,7 @@
 // aux-build:issue-13560-2.rs
 // aux-build:issue-13560-3.rs
 // ignore-stage1
+// ignore-musl
 
 // Regression test for issue #13560, the test itself is all in the dependent
 // libraries. The fail which previously failed to compile is the one numbered 3.
index 710b3b07549f9e11b6216ad2312dddc2a782e6c4..ceface384847fe540c917a3c985776c129d88a2a 100644 (file)
@@ -9,87 +9,56 @@
 // except according to those terms.
 
 // ignore-cross-compile
-// ignore-pretty
-// ignore-test
 
-#![feature(quote)]
+#![feature(quote, rustc_private)]
 
 extern crate syntax;
 
-use std::io::*;
+use syntax::codemap::DUMMY_SP;
+use syntax::print::pprust::*;
 
-use syntax::diagnostic;
-use syntax::ast;
-use syntax::codemap;
-use syntax::codemap::span;
-use syntax::parse;
-use syntax::print::*;
-
-
-trait fake_ext_ctxt {
-    fn cfg() -> ast::CrateConfig;
-    fn parse_sess() -> parse::parse_sess;
-    fn call_site() -> span;
-    fn ident_of(st: &str) -> ast::ident;
-}
-
-type fake_session = parse::parse_sess;
-
-impl fake_ext_ctxt for fake_session {
-    fn cfg() -> ast::CrateConfig { Vec::new() }
-    fn parse_sess() -> parse::parse_sess { self }
-    fn call_site() -> span {
-        codemap::span {
-            lo: codemap::BytePos(0),
-            hi: codemap::BytePos(0),
-            expn_id: codemap::NO_EXPANSION
+fn main() {
+    let ps = syntax::parse::new_parse_sess();
+    let mut cx = syntax::ext::base::ExtCtxt::new(
+        &ps, vec![],
+        syntax::ext::expand::ExpansionConfig::default("qquote".to_string()));
+    cx.bt_push(syntax::codemap::ExpnInfo {
+        call_site: DUMMY_SP,
+        callee: syntax::codemap::NameAndSpan {
+            name: "".to_string(),
+            format: syntax::codemap::MacroBang,
+            allow_internal_unstable: false,
+            span: None,
         }
-    }
-    fn ident_of(st: &str) -> ast::ident {
-        self.interner.intern(st)
-    }
-}
-
-fn mk_ctxt() -> fake_ext_ctxt {
-    parse::new_parse_sess(None) as fake_ext_ctxt
-}
+    });
+    let cx = &mut cx;
 
-fn main() {
-    let cx = mk_ctxt();
+    macro_rules! check {
+        ($f: ident, $($e: expr),+; $expect: expr) => ({
+            $(assert_eq!($f(&$e), $expect);)+
+        });
+    }
 
     let abc = quote_expr!(cx, 23);
-    check_pp(ext_cx, abc,  pprust::print_expr, "23".to_string());
-
+    check!(expr_to_string, abc, *quote_expr!(cx, $abc); "23");
 
     let ty = quote_ty!(cx, isize);
-    check_pp(ext_cx, ty, pprust::print_type, "isize".to_string());
+    check!(ty_to_string, ty, *quote_ty!(cx, $ty); "isize");
 
-    let item = quote_item!(cx, static x : isize = 10;).get();
-    check_pp(ext_cx, item, pprust::print_item, "static x: isize = 10;".to_string());
+    let item = quote_item!(cx, static x: $ty = 10;).unwrap();
+    check!(item_to_string, item, quote_item!(cx, $item).unwrap(); "static x: isize = 10;");
 
-    let stmt = quote_stmt!(cx, let x = 20;);
-    check_pp(ext_cx, *stmt, pprust::print_stmt, "let x = 20;".to_string());
+    let twenty: u16 = 20;
+    let stmt = quote_stmt!(cx, let x = $twenty;).unwrap();
+    check!(stmt_to_string, stmt, *quote_stmt!(cx, $stmt).unwrap(); "let x = 20u16;");
 
     let pat = quote_pat!(cx, Some(_));
-    check_pp(ext_cx, pat, pprust::print_pat, "Some(_)".to_string());
+    check!(pat_to_string, pat, *quote_pat!(cx, $pat); "Some(_)");
 
-    let arm = quote_arm!(cx, (ref x, ref y) => (x, y));
-    check_pp(ext_cx, arm, pprust::print_stmt, "(ref x, ref y) = (x, y)".to_string());
+    let expr = quote_expr!(cx, (x, y));
+    let arm = quote_arm!(cx, (ref x, ref y) => $expr,);
+    check!(arm_to_string, arm, quote_arm!(cx, $arm); " (ref x, ref y) => (x, y),");
 
     let attr = quote_attr!(cx, #![cfg(foo = "bar")]);
-    check_pp(ext_cx, attr, pprust::print_attribute, "#![cfg(foo = "bar")]".to_string());
-}
-
-fn check_pp<T>(cx: fake_ext_ctxt,
-               expr: T, f: |pprust::ps, T|, expect: String) {
-    let s = io::with_str_writer(|wr| {
-        let pp = pprust::rust_printer(wr, cx.parse_sess().interner);
-        f(pp, expr);
-        pp::eof(pp.s);
-    });
-    stdout().write_line(s);
-    if expect != "".to_string() {
-        println!("expect: '%s', got: '%s'", expect, s);
-        assert_eq!(s, expect);
-    }
+    check!(attribute_to_string, attr, quote_attr!(cx, $attr); r#"#![cfg(foo = "bar")]"#);
 }
diff --git a/src/test/run-pass/associated-const-cross-crate-defaults.rs b/src/test/run-pass/associated-const-cross-crate-defaults.rs
new file mode 100644 (file)
index 0000000..92d2aae
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:associated-const-cc-lib.rs
+
+#![feature(associated_consts)]
+
+extern crate associated_const_cc_lib as foolib;
+
+pub struct LocalFooUseDefault;
+
+impl foolib::FooDefault for LocalFooUseDefault {}
+
+pub struct LocalFooOverwriteDefault;
+
+impl foolib::FooDefault for LocalFooOverwriteDefault {
+    const BAR: usize = 4;
+}
+
+fn main() {
+    assert_eq!(1, <foolib::FooUseDefault as foolib::FooDefault>::BAR);
+    assert_eq!(2, <foolib::FooOverwriteDefault as foolib::FooDefault>::BAR);
+    assert_eq!(1, <LocalFooUseDefault as foolib::FooDefault>::BAR);
+    assert_eq!(4, <LocalFooOverwriteDefault as foolib::FooDefault>::BAR);
+}
diff --git a/src/test/run-pass/associated-const-cross-crate.rs b/src/test/run-pass/associated-const-cross-crate.rs
new file mode 100644 (file)
index 0000000..73d5dc5
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:associated-const-cc-lib.rs
+
+#![feature(associated_consts)]
+
+extern crate associated_const_cc_lib as foolib;
+
+pub struct LocalFoo;
+
+impl foolib::Foo for LocalFoo {
+    const BAR: usize = 1;
+}
+
+fn main() {
+    assert_eq!(0, <foolib::FooNoDefault as foolib::Foo>::BAR);
+    assert_eq!(1, <LocalFoo as foolib::Foo>::BAR);
+    assert_eq!(3, foolib::InherentBar::BAR);
+}
diff --git a/src/test/run-pass/associated-const-in-global-const.rs b/src/test/run-pass/associated-const-in-global-const.rs
new file mode 100644 (file)
index 0000000..e3a1e29
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(associated_consts)]
+
+struct Foo;
+
+impl Foo {
+    const BAR: f32 = 1.5;
+}
+
+const FOOBAR: f32 = <Foo>::BAR;
+
+fn main() {
+    assert_eq!(1.5f32, FOOBAR);
+}
diff --git a/src/test/run-pass/associated-const-inherent-impl.rs b/src/test/run-pass/associated-const-inherent-impl.rs
new file mode 100644 (file)
index 0000000..5c9abf9
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(associated_consts)]
+
+struct Foo;
+
+impl Foo {
+    const ID: i32 = 1;
+}
+
+fn main() {
+    assert_eq!(1, Foo::ID);
+}
diff --git a/src/test/run-pass/associated-const-marks-live-code.rs b/src/test/run-pass/associated-const-marks-live-code.rs
new file mode 100644 (file)
index 0000000..ea91a95
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(associated_consts)]
+
+#![deny(dead_code)]
+
+const GLOBAL_BAR: u32 = 1;
+
+struct Foo;
+
+impl Foo {
+    const BAR: u32 = GLOBAL_BAR;
+}
+
+pub fn main() {
+    let _: u32 = Foo::BAR;
+}
diff --git a/src/test/run-pass/associated-const-match-patterns.rs b/src/test/run-pass/associated-const-match-patterns.rs
new file mode 100644 (file)
index 0000000..eeaacbf
--- /dev/null
@@ -0,0 +1,52 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(associated_consts)]
+
+struct Foo;
+
+enum Bar {
+    Var1,
+    Var2,
+}
+
+// Use inherent and trait impls to test UFCS syntax.
+impl Foo {
+    const MYBAR: Bar = Bar::Var2;
+}
+
+trait HasBar {
+    const THEBAR: Bar;
+}
+
+impl HasBar for Foo {
+    const THEBAR: Bar = Bar::Var1;
+}
+
+fn main() {
+    // Inherent impl
+    assert!(match Bar::Var2 {
+        Foo::MYBAR => true,
+        _ => false,
+    });
+    assert!(match Bar::Var2 {
+        <Foo>::MYBAR => true,
+        _ => false,
+    });
+    // Trait impl
+    assert!(match Bar::Var1 {
+        <Foo>::THEBAR => true,
+        _ => false,
+    });
+    assert!(match Bar::Var1 {
+        <Foo as HasBar>::THEBAR => true,
+        _ => false,
+    });
+}
diff --git a/src/test/run-pass/associated-const-overwrite-default.rs b/src/test/run-pass/associated-const-overwrite-default.rs
new file mode 100644 (file)
index 0000000..0846ad9
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(associated_consts)]
+
+trait Foo {
+    const ID: i32 = 2;
+}
+
+impl Foo for i32 {
+    const ID: i32 = 1;
+}
+
+fn main() {
+    assert_eq!(1, <i32 as Foo>::ID);
+}
diff --git a/src/test/run-pass/associated-const-public-impl.rs b/src/test/run-pass/associated-const-public-impl.rs
new file mode 100644 (file)
index 0000000..b1d0717
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(associated_consts)]
+
+mod bar1 {
+    pub use self::bar2::Foo;
+    mod bar2 {
+        pub struct Foo;
+
+        impl Foo {
+            pub const ID: i32 = 1;
+        }
+    }
+}
+
+fn main() {
+    assert_eq!(1, bar1::Foo::ID);
+}
diff --git a/src/test/run-pass/associated-const-resolution-order.rs b/src/test/run-pass/associated-const-resolution-order.rs
new file mode 100644 (file)
index 0000000..98b7164
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(associated_consts)]
+
+struct MyType;
+
+impl MyType {
+    const IMPL_IS_INHERENT: bool = true;
+}
+
+trait MyTrait {
+    const IMPL_IS_INHERENT: bool;
+    const IMPL_IS_ON_TRAIT: bool;
+}
+
+impl MyTrait for MyType {
+    const IMPL_IS_INHERENT: bool = false;
+    const IMPL_IS_ON_TRAIT: bool = true;
+}
+
+fn main() {
+    // Check that the inherent impl is used before the trait, but that the trait
+    // can still be accessed.
+    assert!(<MyType>::IMPL_IS_INHERENT);
+    assert!(!<MyType as MyTrait>::IMPL_IS_INHERENT);
+    assert!(<MyType>::IMPL_IS_ON_TRAIT);
+}
diff --git a/src/test/run-pass/associated-const-self-type.rs b/src/test/run-pass/associated-const-self-type.rs
new file mode 100644 (file)
index 0000000..d3add97
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(associated_consts)]
+
+trait MyInt {
+    const ONE: Self;
+}
+
+impl MyInt for i32 {
+    const ONE: i32 = 1;
+}
+
+fn main() {
+    assert_eq!(1, <i32>::ONE);
+}
diff --git a/src/test/run-pass/associated-const-ufcs-infer-trait.rs b/src/test/run-pass/associated-const-ufcs-infer-trait.rs
new file mode 100644 (file)
index 0000000..aa3e14a
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(associated_consts)]
+
+trait Foo {
+    const ID: i32;
+}
+
+impl Foo for i32 {
+    const ID: i32 = 1;
+}
+
+fn main() {
+    assert_eq!(1, <i32>::ID);
+}
diff --git a/src/test/run-pass/associated-const-use-default.rs b/src/test/run-pass/associated-const-use-default.rs
new file mode 100644 (file)
index 0000000..5813d86
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(associated_consts)]
+
+trait Foo {
+    const ID: i32 = 1;
+}
+
+impl Foo for i32 {}
+
+fn main() {
+    assert_eq!(1, <i32 as Foo>::ID);
+}
diff --git a/src/test/run-pass/associated-const-use-impl-of-same-trait.rs b/src/test/run-pass/associated-const-use-impl-of-same-trait.rs
new file mode 100644 (file)
index 0000000..6265847
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(associated_consts)]
+
+// The main purpose of this test is to ensure that different impls of the same
+// trait can refer to each other without setting off the static recursion check
+// (as long as there's no actual recursion).
+
+trait Foo {
+    const BAR: u32;
+}
+
+struct IsFoo1;
+
+impl Foo for IsFoo1 {
+    const BAR: u32 = 1;
+}
+
+struct IsFoo2;
+
+impl Foo for IsFoo2 {
+    const BAR: u32 = <IsFoo1 as Foo>::BAR;
+}
+
+fn main() {
+    assert_eq!(<IsFoo1>::BAR, <IsFoo2 as Foo>::BAR);
+}
diff --git a/src/test/run-pass/associated-const.rs b/src/test/run-pass/associated-const.rs
new file mode 100644 (file)
index 0000000..d906544
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(associated_consts)]
+
+trait Foo {
+    const ID: i32;
+}
+
+impl Foo for i32 {
+    const ID: i32 = 1;
+}
+
+fn main() {
+    assert_eq!(1, <i32 as Foo>::ID);
+}
index 79a530785452ac58c1bfa1d0f8694a452aae9594..66201ff901f309ce702e706b0e312be280919d48 100644 (file)
@@ -11,6 +11,7 @@
 // aux-build:issue-12133-rlib.rs
 // aux-build:issue-12133-dylib.rs
 // aux-build:issue-12133-dylib2.rs
+// ignore-musl
 
 // pretty-expanded FIXME #23616
 
index d074095dbdedd796e2c1d781c31250415100ae43..7f0a341f147154499f9ac1b28a9608e072121a29 100644 (file)
@@ -11,7 +11,7 @@
 // compile-flags:--test
 // ignore-pretty turns out the pretty-printer doesn't handle gensym'd things...
 
-mod test {
+mod tests {
     use super::*;
 
     #[test]
diff --git a/src/test/run-pass/issue-20616.rs b/src/test/run-pass/issue-20616.rs
new file mode 100644 (file)
index 0000000..e6b256f
--- /dev/null
@@ -0,0 +1,52 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+type MyType<'a, T> = &'a T;
+
+// combine lifetime bounds and type arguments in usual way
+type TypeA<'a> = MyType<'a, ()>;
+
+// ensure token `>>` works fine
+type TypeB = Box<TypeA<'static>>;
+type TypeB_ = Box<TypeA<'static,>>;
+
+// trailing comma when combine lifetime bounds and type arguments
+type TypeC<'a> = MyType<'a, (),>;
+
+// normal lifetime bounds
+type TypeD = TypeA<'static>;
+
+// trailing comma on lifetime bounds
+type TypeE = TypeA<'static,>;
+
+// normal type arugment
+type TypeF<T> = Box<T>;
+
+// type argument with trailing comma
+type TypeG<T> = Box<T,>;
+
+// trailing comma on liftime defs
+type TypeH<'a,> = &'a ();
+
+// trailing comma on type argument
+type TypeI<T,> = T;
+
+static STATIC: () = ();
+
+fn main() {
+
+    // ensure token `>=` works fine
+    let _: TypeA<'static>= &STATIC;
+    let _: TypeA<'static,>= &STATIC;
+
+    // ensure token `>>=` works fine
+    let _: Box<TypeA<'static>>= Box::new(&STATIC);
+    let _: Box<TypeA<'static,>>= Box::new(&STATIC);
+}
diff --git a/src/test/run-pass/issue-23433.rs b/src/test/run-pass/issue-23433.rs
new file mode 100644 (file)
index 0000000..82f8058
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Don't fail if we encounter a NonZero<*T> where T is an unsized type
+
+#![feature(unique)]
+
+use std::ptr::Unique;
+
+fn main() {
+    let mut a = [0u8; 5];
+    let b: Option<Unique<[u8]>> = unsafe { Some(Unique::new(&mut a)) };
+    match b {
+        Some(_) => println!("Got `Some`"),
+        None => panic!("Unexpected `None`"),
+    }
+}
diff --git a/src/test/run-pass/issue-23611-enum-swap-in-drop.rs b/src/test/run-pass/issue-23611-enum-swap-in-drop.rs
new file mode 100644 (file)
index 0000000..540cbd5
--- /dev/null
@@ -0,0 +1,265 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Issue 23611: this test is ensuring that, for an instance `X` of the
+// enum `E`, if you swap in a different variant during the execution
+// of the `<E as Drop>::drop`, then the appropriate substructure will
+// be torn down after the `<E as Drop>::drop` method returns.
+
+use std::cell::RefCell;
+use std::mem;
+
+use self::d::D;
+
+pub fn main() {
+    let log = RefCell::new(vec![]);
+    d::println(&format!("created empty log"));
+    test(&log);
+
+    // println!("log: {:?}", &log.borrow()[..]);
+    assert_eq!(
+        &log.borrow()[..],
+        [
+            //                                         created empty log
+            // +-- Make D(test_1, 10000000)
+            // | +-- Make D(g_b_5, 50000001)
+            // | |                                     in g_B(b2b0) from E::drop, b=b4b0
+            // | +-- Drop D(g_b_5, 50000001)
+            50000001,
+            // |
+            // | +-- Make D(drop_6, 60000002)
+            // | | +-- Make D(g_b_5, 50000003)
+            // | | |                                   in g_B(b2b0) from E::drop, b=b4b1
+            // | | +-- Drop D(g_b_5, 50000003)
+            50000003,
+            // | |
+            // | | +-- Make D(GaspB::drop_3, 30000004)
+            // | | | +-- Make D(g_b_5, 50000005)
+            // | | | |                                 in g_B(b4b2) from GaspB::drop
+            // | | | +-- Drop D(g_b_5, 50000005)
+            50000005,
+            // | | |
+            // | | +-- Drop D(GaspB::drop_3, 30000004)
+            30000004,
+            // | |
+            // +-- Drop D(test_1, 10000000)
+            10000000,
+            //   |
+            // +-- Make D(GaspA::drop_2, 20000006)
+            // | | +-- Make D(f_a_4, 40000007)
+            // | | |                                   in f_A(a3a0) from GaspA::drop
+            // | | +-- Drop D(f_a_4, 40000007)
+            40000007,
+            // | |
+            // +-- Drop D(GaspA::drop_2, 20000006)
+            20000006,
+            //   |
+            //   +-- Drop D(drop_6, 60000002)
+            60000002
+            //
+                ]);
+
+    // For reference purposes, the old (incorrect) behavior would produce the following
+    // output, which you can compare to the above:
+    //
+    //                                             created empty log
+    // +-- Make D(test_1, 10000000)
+    // | +-- Make D(g_b_5, 50000001)
+    // | |                                     in g_B(b2b0) from E::drop, b=b4b0
+    // | +-- Drop D(g_b_5, 50000001)
+    // |
+    // | +-- Make D(drop_6, 60000002)
+    // | | +-- Make D(g_b_5, 50000003)
+    // | | |                                   in g_B(b2b0) from E::drop, b=b4b1
+    // | | +-- Drop D(g_b_5, 50000003)
+    // | |
+    // | | +-- Make D(GaspB::drop_3, 30000004)
+    // | | | +-- Make D(g_b_5, 50000005)
+    // | | | |                                 in g_B(b4b2) from GaspB::drop
+    // | | | +-- Drop D(g_b_5, 50000005)
+    // | | |
+    // | | +-- Drop D(GaspB::drop_3, 30000004)
+    // | |
+    // +-- Drop D(test_1, 10000000)
+    //   |
+    // +-- Make D(GaspB::drop_3, 30000006)
+    // | | +-- Make D(f_a_4, 40000007)
+    // | | |                                   in f_A(a3a0) from GaspB::drop
+    // | | +-- Drop D(f_a_4, 40000007)
+    // | |
+    // +-- Drop D(GaspB::drop_3, 30000006)
+    //   |
+    //   +-- Drop D(drop_6, 60000002)
+
+    // Note that this calls f_A from GaspB::drop (and thus creates a D
+    // with a uid incorporating the origin of GaspB's drop that
+    // surrounds the f_A invocation), but the code as written only
+    // ever hands f_A off to instances of GaspA, and thus one should
+    // be able to prove the invariant that f_A is *only* invoked from
+    // from an instance of GaspA (either via the GaspA drop
+    // implementation or the E drop implementaton). Yet the old (bad)
+    // behavior allowed a call to f_A to leak in while we are tearing
+    // down a value of type GaspB.
+}
+
+fn test<'a>(log: d::Log<'a>) {
+    let _e = E::B(GaspB(g_b, 0xB4B0, log, D::new("test", 1, log)), true);
+}
+
+struct GaspA<'a>(for <'b> fn(u32, &'b str, d::Log<'a>), u32, d::Log<'a>, d::D<'a>);
+struct GaspB<'a>(for <'b> fn(u32, &'b str, d::Log<'a>), u32, d::Log<'a>, d::D<'a>);
+
+impl<'a> Drop for GaspA<'a> {
+    fn drop(&mut self) {
+        let _d = d::D::new("GaspA::drop", 2, self.2);
+        (self.0)(self.1, "GaspA::drop", self.2);
+    }
+}
+
+impl<'a> Drop for GaspB<'a> {
+    fn drop(&mut self) {
+        let _d = d::D::new("GaspB::drop", 3, self.2);
+        (self.0)(self.1, "GaspB::drop", self.2);
+    }
+}
+
+enum E<'a> {
+    A(GaspA<'a>, bool), B(GaspB<'a>, bool),
+}
+
+fn f_a(x: u32, ctxt: &str, log: d::Log) {
+    let _d = d::D::new("f_a", 4, log);
+    d::println(&format!("in f_A({:x}) from {}", x, ctxt));
+}
+fn g_b(y: u32, ctxt: &str, log: d::Log) {
+    let _d = d::D::new("g_b", 5, log);
+    d::println(&format!("in g_B({:x}) from {}", y, ctxt));
+}
+
+impl<'a> Drop for E<'a> {
+    fn drop(&mut self) {
+        let (do_drop, log) = match *self {
+            E::A(GaspA(ref f, ref mut val_a, log, ref _d_a), ref mut do_drop) => {
+                f(0xA1A0, &format!("E::drop, a={:x}", val_a), log);
+                *val_a += 1;
+                // swap in do_drop := false to avoid infinite dtor regress
+                (mem::replace(do_drop, false), log)
+            }
+            E::B(GaspB(ref g, ref mut val_b, log, ref _d_b), ref mut do_drop) => {
+                g(0xB2B0, &format!("E::drop, b={:x}", val_b), log);
+                *val_b += 1;
+                // swap in do_drop := false to avoid infinite dtor regress
+                (mem::replace(do_drop, false), log)
+            }
+        };
+
+        if do_drop {
+            mem::replace(self, E::A(GaspA(f_a, 0xA3A0, log, D::new("drop", 6, log)), true));
+        }
+    }
+}
+
+// This module provides simultaneous printouts of the dynamic extents
+// of all of the D values, in addition to logging the order that each
+// is dropped.
+//
+// This code is similar to a support code module embedded within
+// test/run-pass/issue-123338-ensure-param-drop-order.rs; however,
+// that (slightly simpler) code only identifies objects in the log via
+// (creation) time-stamps; this incorporates both timestamping and the
+// point of origin within the source code into the unique ID (uid).
+
+const PREF_INDENT: u32 = 20;
+
+pub mod d {
+    #![allow(unused_parens)]
+    use std::fmt;
+    use std::mem;
+    use std::cell::RefCell;
+
+    static mut counter: u16 = 0;
+    static mut trails: u64 = 0;
+
+    pub type Log<'a> = &'a RefCell<Vec<u32>>;
+
+    pub fn current_width() -> u32 {
+        unsafe { max_width() - trails.leading_zeros() }
+    }
+
+    pub fn max_width() -> u32 {
+        unsafe {
+            (mem::size_of_val(&trails)*8) as u32
+        }
+    }
+
+    pub fn indent_println(my_trails: u32, s: &str) {
+        let mut indent: String = String::new();
+        for i in 0..my_trails {
+            unsafe {
+                if trails & (1 << i) != 0 {
+                    indent = indent + "| ";
+                } else {
+                    indent = indent + "  ";
+                }
+            }
+        }
+        println!("{}{}", indent, s);
+    }
+
+    pub fn println(s: &str) {
+        indent_println(super::PREF_INDENT, s);
+    }
+
+    fn first_avail() -> u32 {
+        unsafe {
+            for i in 0..64 {
+                if trails & (1 << i) == 0 {
+                    return i;
+                }
+            }
+        }
+        panic!("exhausted trails");
+    }
+
+    pub struct D<'a> {
+        name: &'static str, i: u8, uid: u32, trail: u32, log: Log<'a>
+    }
+
+    impl<'a> fmt::Display for D<'a> {
+        fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
+            write!(w, "D({}_{}, {})", self.name, self.i, self.uid)
+        }
+    }
+
+    impl<'a> D<'a> {
+        pub fn new(name: &'static str, i: u8, log: Log<'a>) -> D<'a> {
+            unsafe {
+                let trail = first_avail();
+                let ctr = ((i as u32) * 10_000_000) + (counter as u32);
+                counter += 1;
+                trails |= (1 << trail);
+                let ret = D {
+                    name: name, i: i, log: log, uid: ctr, trail: trail
+                };
+                indent_println(trail, &format!("+-- Make {}", ret));
+                ret
+            }
+        }
+    }
+
+    impl<'a> Drop for D<'a> {
+        fn drop(&mut self) {
+            unsafe { trails &= !(1 << self.trail); };
+            self.log.borrow_mut().push(self.uid);
+            indent_println(self.trail, &format!("+-- Drop {}", self));
+            indent_println(::PREF_INDENT, "");
+        }
+    }
+}
diff --git a/src/test/run-pass/issue-24313.rs b/src/test/run-pass/issue-24313.rs
new file mode 100644 (file)
index 0000000..9acfb04
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::thread;
+use std::env;
+use std::process::Command;
+
+struct Handle(i32);
+
+impl Drop for Handle {
+    fn drop(&mut self) { panic!(); }
+}
+
+thread_local!(static HANDLE: Handle = Handle(0));
+
+fn main() {
+    let args = env::args().collect::<Vec<_>>();
+    if args.len() == 1 {
+        let out = Command::new(&args[0]).arg("test").output().unwrap();
+        let stderr = std::str::from_utf8(&out.stderr).unwrap();
+        assert!(stderr.contains("panicked at 'explicit panic'"),
+                "bad failure message:\n{}\n", stderr);
+    } else {
+        // TLS dtors are not always run on process exit
+        thread::spawn(|| {
+            HANDLE.with(|h| {
+                println!("{}", h.0);
+            });
+        }).join().unwrap();
+    }
+}
+
index 74da4273b6ab0fb9b773425793bed9e05ae5df70..98a7ce55540d163a46f53ec203cb1a31cef0ca40 100644 (file)
@@ -11,6 +11,7 @@
 // aux-build:linkage-visibility.rs
 // ignore-android: FIXME(#10379)
 // ignore-windows: std::dynamic_lib does not work on Windows well
+// ignore-musl
 
 #![feature(std_misc)]
 
index 0d0a5bee8a443f879ddc00df20d2bf80d1a153de..2c6e55b57b066a5be9c766243ec93ffff9d5b3a0 100644 (file)
@@ -8,11 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//ignore-android
-//ignore-freebsd
-//ignore-ios
-//ignore-dragonfly
-//ignore-bitrig
+// ignore-android
+// ignore-freebsd
+// ignore-ios
+// ignore-dragonfly
+// ignore-bitrig
+// ignore-musl
 
 #![feature(asm)]
 
index 973c61712c3ed719dc88f96aa79e218d84a3774f..f21b787dab72f052c2bee89a6d38d4fe10b7af41 100644 (file)
@@ -14,8 +14,8 @@
 
 // Test accessing external items from multiple compilation units.
 
+extern crate sepcomp_extern_lib;
 
-#[link(name = "sepcomp_extern_lib")]
 extern {
     #[allow(ctypes)]
     fn foo() -> usize;
index 447b4de450bf1097e046d90761b2c287bcd50d5b..d7877bff0cb91ae095c720f26e4ebde039eadb4f 100644 (file)
@@ -12,6 +12,7 @@
 
 #![allow(unused_mut)]
 #![feature(collections)]
+#![feature(collections_drain)]
 
 extern crate collections;
 
@@ -96,5 +97,6 @@ fn from_usize(v: usize) -> Foo {
 
     all_sync_send!(VecMap::<usize>::new(), iter, iter_mut, drain, into_iter, keys, values);
 
-    all_sync_send!(Vec::<usize>::new(), into_iter, drain);
+    all_sync_send!(Vec::<usize>::new(), into_iter);
+    is_sync_send!(Vec::<usize>::new(), drain(..));
 }