diff --git a/.travis.yml b/.travis.yml index 144329caa71a..a1bbb8a884fe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,33 +1,82 @@ -language: generic +language: rust sudo: required +dist: trusty services: - docker -# LLVM takes awhile to check out and otherwise we'll manage the submodules in -# our configure script, so disable auto submodule management. git: - submodules: false depth: 1 + submodules: false -before_install: - - docker build -t rust -f src/etc/Dockerfile src/etc +matrix: + include: + # Linux builders, all docker images + - env: IMAGE=arm-android + - env: IMAGE=cross + - env: IMAGE=i686-gnu + - env: IMAGE=i686-gnu-nopt + - env: IMAGE=x86_64-freebsd + - env: IMAGE=x86_64-gnu + - env: IMAGE=x86_64-gnu-cargotest + - env: IMAGE=x86_64-gnu-debug + - env: IMAGE=x86_64-gnu-nopt + - env: IMAGE=x86_64-gnu-rustbuild + - env: IMAGE=x86_64-gnu-llvm-3.7 ALLOW_PR=1 RUST_BACKTRACE=1 + - env: IMAGE=x86_64-musl + + # OSX builders + - env: > + RUST_CHECK_TARGET=check + RUST_CONFIGURE_ARGS=--target=x86_64-apple-darwin + SRC=. + os: osx + install: brew install ccache + - env: > + RUST_CHECK_TARGET=check + RUST_CONFIGURE_ARGS=--target=i686-apple-darwin + SRC=. + os: osx + install: brew install ccache + - env: > + RUST_CHECK_TARGET=check + RUST_CONFIGURE_ARGS=--target=x86_64-apple-darwin --enable-rustbuild + SRC=. + os: osx + install: brew install ccache + - env: > + RUST_CHECK_TARGET= + RUST_CONFIGURE_ARGS=--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios + SRC=. + os: osx + install: brew install ccache script: - - docker run -v `pwd`:/build rust - sh -c " - ./configure --enable-vendor --enable-rustbuild --llvm-root=/usr/lib/llvm-3.7 --enable-quiet-tests && - make tidy && - make check -j4 - " + - if [ -z "$ALLOW_PR" ] && [ "$TRAVIS_BRANCH" != "auto" ]; then + echo skipping, not a full build; + elif [ -z "$ENABLE_AUTO" ] then + echo skipping, not quite ready yet + elif [ "$TRAVIS_OS_NAME" = "osx" ]; then + git submodule update --init; + src/ci/run.sh; + else + git submodule update --init; + src/ci/docker/run.sh $IMAGE; + fi -# Real testing happens on http://buildbot.rust-lang.org/ -# -# See https://github.com/rust-lang/rust-buildbot -# CONTRIBUTING.md#pull-requests +# Save tagged docker images we created and load them if they're available +before_cache: + - docker history -q rust-ci | + grep -v missing | + xargs docker save | + gzip -9 > $HOME/docker/rust-ci.tar.gz +before_install: + - zcat $HOME/docker/rust-ci.tar.gz | docker load || true notifications: email: false -branches: - only: - - master +cache: + directories: + - $HOME/docker + - $HOME/.ccache + - $HOME/.cargo diff --git a/RELEASES.md b/RELEASES.md index 222ad3aa112a..e468a86e7acc 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,260 @@ +Version 1.13.0 (2016-11-10) +=========================== + +Language +-------- + +* [Stabilize the `?` operator][36995]. `?` is a simple way to propagate + errors, like the `try!` macro, described in [RFC 0243]. +* [Stabilize macros in type position][36014]. Described in [RFC 873]. +* [Stabilize attributes on statements][36995]. Described in [RFC 0016]. +* [Fix `#[derive]` for empty tuple structs/variants][35728] +* [Fix lifetime rules for 'if' conditions][36029] +* [Avoid loading and parsing unconfigured non-inline modules][36482] + +Compiler +-------- + +* [Add the `-C link-arg` argument][36574] +* [Remove the old AST-based backend from rustc_trans][35764] +* [Don't enable NEON by default on armv7 Linux][35814] +* [Fix debug line number info for macro expansions][35238] +* [Do not emit "class method" debuginfo for types that are not + DICompositeType][36008] +* [Warn about multiple conflicting #[repr] hints][34623] +* [When sizing DST, don't double-count nested struct prefixes][36351] +* [Default RUST_MIN_STACK to 16MiB for now][36505] +* [Improve rlib metadata format][36551]. Reduces rlib size significantly. +* [Reject macros with empty repetitions to avoid infinite loop][36721] +* [Expand macros without recursing to avoid stack overflows][36214] + +Diagnostics +----------- + +* [Replace macro backtraces with labeled local uses][35702] +* [Improve error message for missplaced doc comments][33922] +* [Buffer unix and lock windows to prevent message interleaving][35975] +* [Update lifetime errors to specifically note temporaries][36171] +* [Special case a few colors for Windows][36178] +* [Suggest `use self` when such an import resolves][36289] +* [Be more specific when type parameter shadows primitive type][36338] +* Many minor improvements + +Compile-time Optimizations +-------------------------- + +* [Compute and cache HIR hashes at beginning][35854] +* [Don't hash types in loan paths][36004] +* [Cache projections in trans][35761] +* [Optimize the parser's last token handling][36527] +* [Only instantiate #[inline] functions in codegen units referencing + them][36524]. This leads to big improvements in cases where crates export + define many inline functions without using them directly. +* [Lazily allocate TypedArena's first chunk][36592] +* [Don't allocate during default HashSet creation][36734] + +Stabilized APIs +--------------- + +* [`checked_abs`] +* [`wrapping_abs`] +* [`overflowing_abs`] +* [`RefCell::try_borrow`] +* [`RefCell::try_borrow_mut`] + +Libraries +--------- + +* [Add `assert_ne!` and `debug_assert_ne!`][35074] +* [Make `vec_deque::Drain`, `hash_map::Drain`, and `hash_set::Drain` + covariant][35354] +* [Implement `AsRef<[T]>` for `std::slice::Iter`][35559] +* [Implement `Debug` for `std::vec::IntoIter`][35707] +* [`CString`: avoid excessive growth just to 0-terminate][35871] +* [Implement `CoerceUnsized` for `{Cell, RefCell, UnsafeCell}`][35627] +* [Use arc4rand on FreeBSD][35884] +* [memrchr: Correct aligned offset computation][35969] +* [Improve Demangling of Rust Symbols][36059] +* [Use monotonic time in condition variables][35048] +* [Implement `Debug` for `std::path::{Components,Iter}`][36101] +* [Implement conversion traits for `char`][35755] +* [Fix illegal instruction caused by overflow in channel cloning][36104] +* [Zero first byte of CString on drop][36264] +* [Inherit overflow checks for sum and product][36372] +* [Add missing Eq implementations][36423] +* [Implement `Debug` for `DirEntry`][36631] +* [When `getaddrinfo` returns `EAI_SYSTEM` retrieve actual error from + `errno`][36754] +* [`SipHasher`] is deprecated. Use [`DefaultHasher`]. +* [Implement more traits for `std::io::ErrorKind`][35911] +* [Optimize BinaryHeap bounds checking][36072] +* [Work around pointer aliasing issue in `Vec::extend_from_slice`, + `extend_with_element`][36355] +* [Fix overflow checking in unsigned pow()][34942] + +Cargo +----- + +* This release includes security fixes to both curl and OpenSSL. +* [Fix transitive doctests when panic=abort][cargo/3021] +* [Add --all-features flag to cargo][cargo/3038] +* [Reject path-based dependencies in `cargo package`][cargo/3060] +* [Don't parse the home directory more than once][cargo/3078] +* [Don't try to generate Cargo.lock on empty workspaces][cargo/3092] +* [Update OpenSSL to 1.0.2j][cargo/3121] +* [Add license and license_file to cargo metadata output][cargo/3110] +* [Make crates-io registry URL optional in config; ignore all changes to + source.crates-io][cargo/3089] +* [Don't download dependencies from other platforms][cargo/3123] +* [Build transitive dev-dependencies when needed][cargo/3125] +* [Add support for per-target rustflags in .cargo/config][cargo/3157] +* [Avoid updating registry when adding existing deps][cargo/3144] +* [Warn about path overrides that won't work][cargo/3136] +* [Use workspaces during `cargo install`][cargo/3146] +* [Leak mspdbsrv.exe processes on Windows][cargo/3162] +* [Add --message-format flag][cargo/3000] +* [Pass target environment for rustdoc][cargo/3205] +* [Use `CommandExt::exec` for `cargo run` on Unix][cargo/2818] +* [Update curl and curl-sys][cargo/3241] +* [Call rustdoc test with the correct cfg flags of a package][cargo/3242] + +Tooling +------- + +* [rustdoc: Add the `--sysroot` argument][36586] +* [rustdoc: Fix a couple of issues with the search results][35655] +* [rustdoc: remove the `!` from macro URLs and titles][35234] +* [gdb: Fix pretty-printing special-cased Rust types][35585] +* [rustdoc: Filter more incorrect methods inherited through Deref][36266] + +Misc +---- + +* [Remove unmaintained style guide][35124] +* [Add s390x support][36369] +* [Initial work at Haiku OS support][36727] +* [Add mips-uclibc targets][35734] +* [Crate-ify compiler-rt into compiler-builtins][35021] +* [Add rustc version info (git hash + date) to dist tarball][36213] +* Many documentation improvements + +Compatibility Notes +------------------- + +* [`SipHasher`] is deprecated. Use [`DefaultHasher`]. +* [Deny (by default) transmuting from fn item types to pointer-sized + types][34923]. Continuing the long transition to zero-sized fn items, + per [RFC 401]. +* [Fix `#[derive]` for empty tuple structs/variants][35728]. + Part of [RFC 1506]. +* [Issue deprecation warnings for safe accesses to extern statics][36173] +* [Fix lifetime rules for 'if' conditions][36029]. +* [Inherit overflow checks for sum and product][36372]. +* [Forbid user-defined macros named "macro_rules"][36730]. + +[33922]: https://github.com/rust-lang/rust/pull/33922 +[34623]: https://github.com/rust-lang/rust/pull/34623 +[34923]: https://github.com/rust-lang/rust/pull/34923 +[34942]: https://github.com/rust-lang/rust/pull/34942 +[34982]: https://github.com/rust-lang/rust/pull/34982 +[35021]: https://github.com/rust-lang/rust/pull/35021 +[35048]: https://github.com/rust-lang/rust/pull/35048 +[35074]: https://github.com/rust-lang/rust/pull/35074 +[35124]: https://github.com/rust-lang/rust/pull/35124 +[35234]: https://github.com/rust-lang/rust/pull/35234 +[35238]: https://github.com/rust-lang/rust/pull/35238 +[35354]: https://github.com/rust-lang/rust/pull/35354 +[35559]: https://github.com/rust-lang/rust/pull/35559 +[35585]: https://github.com/rust-lang/rust/pull/35585 +[35627]: https://github.com/rust-lang/rust/pull/35627 +[35655]: https://github.com/rust-lang/rust/pull/35655 +[35702]: https://github.com/rust-lang/rust/pull/35702 +[35707]: https://github.com/rust-lang/rust/pull/35707 +[35728]: https://github.com/rust-lang/rust/pull/35728 +[35734]: https://github.com/rust-lang/rust/pull/35734 +[35755]: https://github.com/rust-lang/rust/pull/35755 +[35761]: https://github.com/rust-lang/rust/pull/35761 +[35764]: https://github.com/rust-lang/rust/pull/35764 +[35814]: https://github.com/rust-lang/rust/pull/35814 +[35854]: https://github.com/rust-lang/rust/pull/35854 +[35871]: https://github.com/rust-lang/rust/pull/35871 +[35884]: https://github.com/rust-lang/rust/pull/35884 +[35911]: https://github.com/rust-lang/rust/pull/35911 +[35969]: https://github.com/rust-lang/rust/pull/35969 +[35975]: https://github.com/rust-lang/rust/pull/35975 +[36004]: https://github.com/rust-lang/rust/pull/36004 +[36008]: https://github.com/rust-lang/rust/pull/36008 +[36014]: https://github.com/rust-lang/rust/pull/36014 +[36029]: https://github.com/rust-lang/rust/pull/36029 +[36059]: https://github.com/rust-lang/rust/pull/36059 +[36072]: https://github.com/rust-lang/rust/pull/36072 +[36101]: https://github.com/rust-lang/rust/pull/36101 +[36104]: https://github.com/rust-lang/rust/pull/36104 +[36171]: https://github.com/rust-lang/rust/pull/36171 +[36173]: https://github.com/rust-lang/rust/pull/36173 +[36178]: https://github.com/rust-lang/rust/pull/36178 +[36213]: https://github.com/rust-lang/rust/pull/36213 +[36214]: https://github.com/rust-lang/rust/pull/36214 +[36264]: https://github.com/rust-lang/rust/pull/36264 +[36266]: https://github.com/rust-lang/rust/pull/36266 +[36289]: https://github.com/rust-lang/rust/pull/36289 +[36338]: https://github.com/rust-lang/rust/pull/36338 +[36351]: https://github.com/rust-lang/rust/pull/36351 +[36355]: https://github.com/rust-lang/rust/pull/36355 +[36369]: https://github.com/rust-lang/rust/pull/36369 +[36372]: https://github.com/rust-lang/rust/pull/36372 +[36423]: https://github.com/rust-lang/rust/pull/36423 +[36482]: https://github.com/rust-lang/rust/pull/36482 +[36505]: https://github.com/rust-lang/rust/pull/36505 +[36524]: https://github.com/rust-lang/rust/pull/36524 +[36527]: https://github.com/rust-lang/rust/pull/36527 +[36551]: https://github.com/rust-lang/rust/pull/36551 +[36574]: https://github.com/rust-lang/rust/pull/36574 +[36586]: https://github.com/rust-lang/rust/pull/36586 +[36592]: https://github.com/rust-lang/rust/pull/36592 +[36631]: https://github.com/rust-lang/rust/pull/36631 +[36639]: https://github.com/rust-lang/rust/pull/36639 +[36721]: https://github.com/rust-lang/rust/pull/36721 +[36727]: https://github.com/rust-lang/rust/pull/36727 +[36730]: https://github.com/rust-lang/rust/pull/36730 +[36734]: https://github.com/rust-lang/rust/pull/36734 +[36754]: https://github.com/rust-lang/rust/pull/36754 +[36995]: https://github.com/rust-lang/rust/pull/36995 +[RFC 0016]: https://github.com/rust-lang/rfcs/blob/master/text/0016-more-attributes.md +[RFC 0243]: https://github.com/rust-lang/rfcs/blob/master/text/0243-trait-based-exception-handling.md +[RFC 1506]: https://github.com/rust-lang/rfcs/blob/master/text/1506-adt-kinds.md +[RFC 401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md +[RFC 873]: https://github.com/rust-lang/rfcs/blob/master/text/0873-type-macros.md +[cargo/2818]: https://github.com/rust-lang/cargo/pull/2818 +[cargo/3000]: https://github.com/rust-lang/cargo/pull/3000 +[cargo/3021]: https://github.com/rust-lang/cargo/pull/3021 +[cargo/3038]: https://github.com/rust-lang/cargo/pull/3038 +[cargo/3060]: https://github.com/rust-lang/cargo/pull/3060 +[cargo/3078]: https://github.com/rust-lang/cargo/pull/3078 +[cargo/3089]: https://github.com/rust-lang/cargo/pull/3089 +[cargo/3092]: https://github.com/rust-lang/cargo/pull/3092 +[cargo/3110]: https://github.com/rust-lang/cargo/pull/3110 +[cargo/3121]: https://github.com/rust-lang/cargo/pull/3121 +[cargo/3123]: https://github.com/rust-lang/cargo/pull/3123 +[cargo/3125]: https://github.com/rust-lang/cargo/pull/3125 +[cargo/3136]: https://github.com/rust-lang/cargo/pull/3136 +[cargo/3144]: https://github.com/rust-lang/cargo/pull/3144 +[cargo/3146]: https://github.com/rust-lang/cargo/pull/3146 +[cargo/3157]: https://github.com/rust-lang/cargo/pull/3157 +[cargo/3162]: https://github.com/rust-lang/cargo/pull/3162 +[cargo/3205]: https://github.com/rust-lang/cargo/pull/3205 +[cargo/3241]: https://github.com/rust-lang/cargo/pull/3241 +[cargo/3242]: https://github.com/rust-lang/cargo/pull/3242 +[rustup]: https://www.rustup.rs +[`checked_abs`]: https://doc.rust-lang.org/std/primitive.i32.html#method.checked_abs +[`wrapping_abs`]: https://doc.rust-lang.org/std/primitive.i32.html#method.wrapping_abs +[`overflowing_abs`]: https://doc.rust-lang.org/std/primitive.i32.html#method.overflowing_abs +[`RefCell::try_borrow`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.try_borrow +[`RefCell::try_borrow_mut`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.try_borrow_mut +[`SipHasher`]: https://doc.rust-lang.org/std/hash/struct.SipHasher.html +[`DefaultHasher`]: https://doc.rust-lang.org/std/collections/hash_map/struct.DefaultHasher.html + + Version 1.12.1 (2016-10-20) =========================== diff --git a/configure b/configure index 9c055e7217aa..133af075795c 100755 --- a/configure +++ b/configure @@ -624,6 +624,7 @@ opt ccache 0 "invoke gcc/clang via ccache to reuse object files between builds" opt local-rust 0 "use an installed rustc rather than downloading a snapshot" opt local-rebuild 0 "assume local-rust matches the current version, for rebuilds; implies local-rust, and is implied if local-rust already matches the current version" opt llvm-static-stdcpp 0 "statically link to libstdc++ for LLVM" +opt llvm-link-shared 0 "prefer shared linking to LLVM (llvm-config --link-shared)" opt rpath 1 "build rpaths into rustc itself" opt stage0-landing-pads 1 "enable landing pads during bootstrap with stage0" # This is used by the automation to produce single-target nightlies @@ -642,6 +643,7 @@ opt_nosave optimize-cxx 1 "build optimized C++ code" opt_nosave optimize-llvm 1 "build optimized LLVM" opt_nosave llvm-assertions 0 "build LLVM with assertions" opt_nosave debug-assertions 0 "build with debugging assertions" +opt_nosave llvm-release-debuginfo 0 "build LLVM with debugger metadata" opt_nosave debuginfo 0 "build with debugger metadata" opt_nosave debuginfo-lines 0 "build with line number debugger metadata" opt_nosave debug-jemalloc 0 "build jemalloc with --enable-debug --enable-fill" @@ -778,6 +780,7 @@ if [ -n "$CFG_DISABLE_OPTIMIZE_CXX" ]; then putvar CFG_DISABLE_OPTIMIZE_CXX; fi if [ -n "$CFG_DISABLE_OPTIMIZE_LLVM" ]; then putvar CFG_DISABLE_OPTIMIZE_LLVM; fi if [ -n "$CFG_ENABLE_LLVM_ASSERTIONS" ]; then putvar CFG_ENABLE_LLVM_ASSERTIONS; fi if [ -n "$CFG_ENABLE_DEBUG_ASSERTIONS" ]; then putvar CFG_ENABLE_DEBUG_ASSERTIONS; fi +if [ -n "$CFG_ENABLE_LLVM_RELEASE_DEBUGINFO" ]; then putvar CFG_ENABLE_LLVM_RELEASE_DEBUGINFO; fi if [ -n "$CFG_ENABLE_DEBUGINFO" ]; then putvar CFG_ENABLE_DEBUGINFO; fi if [ -n "$CFG_ENABLE_DEBUGINFO_LINES" ]; then putvar CFG_ENABLE_DEBUGINFO_LINES; fi if [ -n "$CFG_ENABLE_DEBUG_JEMALLOC" ]; then putvar CFG_ENABLE_DEBUG_JEMALLOC; fi @@ -852,6 +855,12 @@ probe_need CFG_CMAKE cmake # probe for it only in this case. if [ -n "$CFG_ANTLR4" ] then + CFG_ANTLR4_JAR="\"$(find /usr/ -name antlr-complete.jar 2>/dev/null | head -n 1)\"" + if [ "x" -eq "x$CFG_ANTLR4_JAR" ] + then + CFG_ANTLR4_JAR="\"$(find ~ -name antlr-complete.jar 2>/dev/null | head -n 1)\"" + fi + putvar CFG_ANTLR4_JAR $CFG_ANTLR4_JAR probe CFG_JAVAC javac fi @@ -1772,6 +1781,8 @@ do if [ -n "$CFG_DISABLE_OPTIMIZE_LLVM" ]; then CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_BUILD_TYPE=Debug" + elif [ -n "$CFG_ENABLE_LLVM_RELEASE_DEBUGINFO" ]; then + CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_BUILD_TYPE=RelWithDebInfo" else CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_BUILD_TYPE=Release" fi @@ -1782,7 +1793,7 @@ do CMAKE_ARGS="$CMAKE_ARGS -DLLVM_ENABLE_ASSERTIONS=ON" fi - CMAKE_ARGS="$CMAKE_ARGS -DLLVM_TARGETS_TO_BUILD='X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend'" + CMAKE_ARGS="$CMAKE_ARGS -DLLVM_TARGETS_TO_BUILD='X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430'" CMAKE_ARGS="$CMAKE_ARGS -G '$CFG_CMAKE_GENERATOR'" CMAKE_ARGS="$CMAKE_ARGS $CFG_LLVM_SRC_DIR" diff --git a/mk/cfg/armv5te-unknown-linux-gnueabi.mk b/mk/cfg/armv5te-unknown-linux-gnueabi.mk new file mode 100644 index 000000000000..98567a03c28a --- /dev/null +++ b/mk/cfg/armv5te-unknown-linux-gnueabi.mk @@ -0,0 +1,26 @@ +# armv5-unknown-linux-gnueabi configuration +CROSS_PREFIX_armv5te-unknown-linux-gnueabi=arm-linux-gnueabi- +CC_armv5te-unknown-linux-gnueabi=gcc +CXX_armv5te-unknown-linux-gnueabi=g++ +CPP_armv5te-unknown-linux-gnueabi=gcc -E +AR_armv5te-unknown-linux-gnueabi=ar +CFG_LIB_NAME_armv5te-unknown-linux-gnueabi=lib$(1).so +CFG_STATIC_LIB_NAME_armv5te-unknown-linux-gnueabi=lib$(1).a +CFG_LIB_GLOB_armv5te-unknown-linux-gnueabi=lib$(1)-*.so +CFG_LIB_DSYM_GLOB_armv5te-unknown-linux-gnueabi=lib$(1)-*.dylib.dSYM +CFG_JEMALLOC_CFLAGS_armv5te-unknown-linux-gnueabi := -D__arm__ -mfloat-abi=soft $(CFLAGS) -march=armv5te -marm +CFG_GCCISH_CFLAGS_armv5te-unknown-linux-gnueabi := -Wall -g -fPIC -D__arm__ -mfloat-abi=soft $(CFLAGS) -march=armv5te -marm +CFG_GCCISH_CXXFLAGS_armv5te-unknown-linux-gnueabi := -fno-rtti $(CXXFLAGS) +CFG_GCCISH_LINK_FLAGS_armv5te-unknown-linux-gnueabi := -shared -fPIC -g +CFG_GCCISH_DEF_FLAG_armv5te-unknown-linux-gnueabi := -Wl,--export-dynamic,--dynamic-list= +CFG_LLC_FLAGS_armv5te-unknown-linux-gnueabi := +CFG_INSTALL_NAME_ar,-unknown-linux-gnueabi = +CFG_EXE_SUFFIX_armv5te-unknown-linux-gnueabi := +CFG_WINDOWSY_armv5te-unknown-linux-gnueabi := +CFG_UNIXY_armv5te-unknown-linux-gnueabi := 1 +CFG_LDPATH_armv5te-unknown-linux-gnueabi := +CFG_RUN_armv5te-unknown-linux-gnueabi=$(2) +CFG_RUN_TARG_armv5te-unknown-linux-gnueabi=$(call CFG_RUN_armv5te-unknown-linux-gnueabi,,$(2)) +RUSTC_FLAGS_armv5te-unknown-linux-gnueabi := +RUSTC_CROSS_FLAGS_armv5te-unknown-linux-gnueabi := +CFG_GNU_TRIPLE_armv5te-unknown-linux-gnueabi := armv5te-unknown-linux-gnueabi diff --git a/mk/clean.mk b/mk/clean.mk index 3574f25d9b74..7013d9f03f83 100644 --- a/mk/clean.mk +++ b/mk/clean.mk @@ -35,7 +35,7 @@ clean-all: clean clean-llvm clean-llvm: $(CLEAN_LLVM_RULES) -clean: clean-misc $(CLEAN_STAGE_RULES) +clean: clean-misc clean-grammar $(CLEAN_STAGE_RULES) clean-misc: @$(call E, cleaning) @@ -47,6 +47,9 @@ clean-misc: $(Q)rm -Rf dist/* $(Q)rm -Rf doc +clean-grammar: + @$(call E, cleaning grammar verification) + $(Q)rm -Rf grammar define CLEAN_GENERIC clean-generic-$(2)-$(1): diff --git a/mk/crates.mk b/mk/crates.mk index 25192bfd27a4..7ae5846c54b9 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -100,7 +100,7 @@ DEPS_serialize := std log DEPS_term := std DEPS_test := std getopts term native:rust_test_helpers -DEPS_syntax := std term serialize log arena libc rustc_bitflags rustc_unicode rustc_errors syntax_pos +DEPS_syntax := std term serialize log arena libc rustc_bitflags rustc_unicode rustc_errors syntax_pos rustc_data_structures DEPS_syntax_ext := syntax syntax_pos rustc_errors fmt_macros proc_macro DEPS_syntax_pos := serialize DEPS_proc_macro_tokens := syntax syntax_pos log diff --git a/mk/grammar.mk b/mk/grammar.mk index 0d527bd06886..1bd042adb218 100644 --- a/mk/grammar.mk +++ b/mk/grammar.mk @@ -37,7 +37,7 @@ $(BG): $(BG)RustLexer.class: $(BG) $(SG)RustLexer.g4 $(Q)$(CFG_ANTLR4) -o $(BG) $(SG)RustLexer.g4 - $(Q)$(CFG_JAVAC) -d $(BG) $(BG)RustLexer.java + $(Q)$(CFG_JAVAC) -d $(BG) -classpath $(CFG_ANTLR4_JAR) $(BG)RustLexer.java check-build-lexer-verifier: $(BG)verify diff --git a/mk/llvm.mk b/mk/llvm.mk index 5a91f5fcaa48..76367e6f3a62 100644 --- a/mk/llvm.mk +++ b/mk/llvm.mk @@ -21,6 +21,8 @@ endif ifdef CFG_DISABLE_OPTIMIZE_LLVM LLVM_BUILD_CONFIG_MODE := Debug +else ifdef CFG_ENABLE_LLVM_RELEASE_DEBUGINFO +LLVM_BUILD_CONFIG_MODE := RelWithDebInfo else LLVM_BUILD_CONFIG_MODE := Release endif diff --git a/mk/main.mk b/mk/main.mk index 2fa8ccf3621e..9936c5b59be5 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -13,7 +13,7 @@ ###################################################################### # The version number -CFG_RELEASE_NUM=1.14.0 +CFG_RELEASE_NUM=1.15.0 # An optional number to put after the label, e.g. '.2' -> '-beta.2' # NB Make sure it starts with a dot to conform to semver pre-release @@ -285,7 +285,7 @@ endif # LLVM macros ###################################################################### -LLVM_OPTIONAL_COMPONENTS=x86 arm aarch64 mips powerpc pnacl systemz jsbackend +LLVM_OPTIONAL_COMPONENTS=x86 arm aarch64 mips powerpc pnacl systemz jsbackend msp430 LLVM_REQUIRED_COMPONENTS=ipo bitreader bitwriter linker asmparser mcjit \ interpreter instrumentation diff --git a/mk/tests.mk b/mk/tests.mk index f3d8f0387bbd..35ee7697a7a6 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -697,6 +697,8 @@ CTEST_DEPS_ui_$(1)-T-$(2)-H-$(3) = $$(UI_TESTS) CTEST_DEPS_mir-opt_$(1)-T-$(2)-H-$(3) = $$(MIR_OPT_TESTS) CTEST_DEPS_rustdocck_$(1)-T-$(2)-H-$(3) = $$(RUSTDOCCK_TESTS) \ $$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \ + $$(CSREQ$(1)_T_$(3)_H_$(3)) \ + $$(SREQ$(1)_T_$(3)_H_$(3)) \ $(S)src/etc/htmldocck.py endef diff --git a/src/Cargo.lock b/src/Cargo.lock index d3517175d4ce..ab1c1c453dd2 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -409,7 +409,6 @@ version = "0.0.0" dependencies = [ "build_helper 0.1.0", "gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_bitflags 0.0.0", ] [[package]] @@ -520,6 +519,7 @@ dependencies = [ "log 0.0.0", "rustc 0.0.0", "rustc_back 0.0.0", + "rustc_bitflags 0.0.0", "rustc_const_eval 0.0.0", "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", @@ -543,6 +543,7 @@ dependencies = [ "rustc_back 0.0.0", "rustc_const_eval 0.0.0", "rustc_const_math 0.0.0", + "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "rustc_platform_intrinsics 0.0.0", "syntax 0.0.0", @@ -621,6 +622,7 @@ version = "0.0.0" dependencies = [ "log 0.0.0", "rustc_bitflags 0.0.0", + "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "serialize 0.0.0", "syntax_pos 0.0.0", diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 08a8ca5a6313..a3fabbb3e809 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -226,13 +226,16 @@ class RustBuild(object): config = self.get_toml('cargo') if config: return config + config = self.get_mk('CFG_LOCAL_RUST_ROOT') + if config: + return config + '/bin/cargo' + self.exe_suffix() return os.path.join(self.bin_root(), "bin/cargo" + self.exe_suffix()) def rustc(self): config = self.get_toml('rustc') if config: return config - config = self.get_mk('CFG_LOCAL_RUST') + config = self.get_mk('CFG_LOCAL_RUST_ROOT') if config: return config + '/bin/rustc' + self.exe_suffix() return os.path.join(self.bin_root(), "bin/rustc" + self.exe_suffix()) diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index f27f9641036c..ac6be2a870b0 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -130,9 +130,7 @@ pub fn compiletest(build: &Build, build.test_helpers_out(target).display())); cmd.arg("--target-rustcflags").arg(targetflags.join(" ")); - // FIXME: CFG_PYTHON should probably be detected more robustly elsewhere - let python_default = "python"; - cmd.arg("--docck-python").arg(python_default); + cmd.arg("--docck-python").arg(build.python()); if build.config.build.ends_with("apple-darwin") { // Force /usr/bin/python on OSX for LLDB tests because we're loading the @@ -140,7 +138,7 @@ pub fn compiletest(build: &Build, // (namely not Homebrew-installed python) cmd.arg("--lldb-python").arg("/usr/bin/python"); } else { - cmd.arg("--lldb-python").arg(python_default); + cmd.arg("--lldb-python").arg(build.python()); } if let Some(ref gdb) = build.config.gdb { diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 5fc4f006729d..236989dbcfeb 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -212,6 +212,9 @@ pub fn rustc<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { cargo.env("LLVM_STATIC_STDCPP", compiler_file(build.cxx(target), "libstdc++.a")); } + if build.config.llvm_link_shared { + cargo.env("LLVM_LINK_SHARED", "1"); + } if let Some(ref s) = build.config.rustc_default_linker { cargo.env("CFG_DEFAULT_LINKER", s); } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 9a939fee43e8..60f65f623006 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -50,8 +50,10 @@ pub struct Config { // llvm codegen options pub llvm_assertions: bool, pub llvm_optimize: bool, + pub llvm_release_debuginfo: bool, pub llvm_version_check: bool, pub llvm_static_stdcpp: bool, + pub llvm_link_shared: bool, // rust codegen options pub rust_optimize: bool, @@ -89,6 +91,7 @@ pub struct Config { pub codegen_tests: bool, pub nodejs: Option, pub gdb: Option, + pub python: Option, } /// Per-target configuration stored in the global configuration structure. @@ -128,6 +131,8 @@ struct Build { submodules: Option, gdb: Option, vendor: Option, + nodejs: Option, + python: Option, } /// TOML representation of how the LLVM build is configured. @@ -137,6 +142,7 @@ struct Llvm { ninja: Option, assertions: Option, optimize: Option, + release_debuginfo: Option, version_check: Option, static_libstdcpp: Option, } @@ -232,7 +238,9 @@ impl Config { } config.rustc = build.rustc.map(PathBuf::from); config.cargo = build.cargo.map(PathBuf::from); + config.nodejs = build.nodejs.map(PathBuf::from); config.gdb = build.gdb.map(PathBuf::from); + config.python = build.python.map(PathBuf::from); set(&mut config.compiler_docs, build.compiler_docs); set(&mut config.docs, build.docs); set(&mut config.submodules, build.submodules); @@ -243,6 +251,7 @@ impl Config { set(&mut config.ninja, llvm.ninja); set(&mut config.llvm_assertions, llvm.assertions); set(&mut config.llvm_optimize, llvm.optimize); + set(&mut config.llvm_release_debuginfo, llvm.release_debuginfo); set(&mut config.llvm_version_check, llvm.version_check); set(&mut config.llvm_static_stdcpp, llvm.static_libstdcpp); } @@ -334,9 +343,11 @@ impl Config { ("COMPILER_DOCS", self.compiler_docs), ("DOCS", self.docs), ("LLVM_ASSERTIONS", self.llvm_assertions), + ("LLVM_RELEASE_DEBUGINFO", self.llvm_release_debuginfo), ("OPTIMIZE_LLVM", self.llvm_optimize), ("LLVM_VERSION_CHECK", self.llvm_version_check), ("LLVM_STATIC_STDCPP", self.llvm_static_stdcpp), + ("LLVM_LINK_SHARED", self.llvm_link_shared), ("OPTIMIZE", self.rust_optimize), ("DEBUG_ASSERTIONS", self.rust_debug_assertions), ("DEBUGINFO", self.rust_debuginfo), @@ -460,6 +471,10 @@ impl Config { self.rustc = Some(push_exe_path(path.clone(), &["bin", "rustc"])); self.cargo = Some(push_exe_path(path, &["bin", "cargo"])); } + "CFG_PYTHON" if value.len() > 0 => { + let path = parse_configure_path(value); + self.python = Some(path); + } _ => {} } } diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index 306708f9e4b6..b6774b3af20a 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -17,6 +17,9 @@ # Indicates whether the LLVM build is a Release or Debug build #optimize = true +# Indicates whether an LLVM Release build should include debug info +#release-debuginfo = false + # Indicates whether the LLVM assertions are enabled or not #assertions = false @@ -79,9 +82,19 @@ # Indicate whether submodules are managed and updated automatically. #submodules = true -# The path to (or name of) the GDB executable to use +# The path to (or name of) the GDB executable to use. This is only used for +# executing the debuginfo test suite. #gdb = "gdb" +# The node.js executable to use. Note that this is only used for the emscripten +# target when running tests, otherwise this can be omitted. +#nodejs = "node" + +# Python interpreter to use for various tasks throughout the build, notably +# rustdoc tests, the lldb python interpreter, and some dist bits and pieces. +# Note that Python 2 is currently required. +#python = "python2.7" + # Indicate whether the vendored sources are used for Rust dependencies or not #vendor = false diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 8676f5cc4a1e..d603455122eb 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -99,7 +99,7 @@ pub fn mingw(build: &Build, host: &str) { // (which is what we want). // // FIXME: this script should be rewritten into Rust - let mut cmd = Command::new("python"); + let mut cmd = Command::new(build.python()); cmd.arg(build.src.join("src/etc/make-win-dist.py")) .arg(tmpdir(build)) .arg(&image) @@ -159,7 +159,7 @@ pub fn rustc(build: &Build, stage: u32, host: &str) { // // FIXME: this script should be rewritten into Rust if host.contains("pc-windows-gnu") { - let mut cmd = Command::new("python"); + let mut cmd = Command::new(build.python()); cmd.arg(build.src.join("src/etc/make-win-dist.py")) .arg(&image) .arg(tmpdir(build)) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index e6b88ea58c9b..828e82d38321 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -774,6 +774,11 @@ impl Build { .or(self.config.musl_root.as_ref()) .map(|p| &**p) } + + /// Path to the python interpreter to use + fn python(&self) -> &Path { + self.config.python.as_ref().unwrap() + } } impl<'a> Compiler<'a> { diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index d4031077639c..1e73595ec998 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -57,6 +57,9 @@ else $(Q)$(BOOTSTRAP) dist --install $(BOOTSTRAP_ARGS) endif tidy: - $(Q)$(BOOTSTRAP) test src/tools/tidy $(BOOTSTRAP_ARGS) + $(Q)$(BOOTSTRAP) test src/tools/tidy $(BOOTSTRAP_ARGS) --stage 0 + +check-stage2-android: + $(Q)$(BOOTSTRAP) --step check-target --target arm-linux-androideabi .PHONY: dist diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 1b4e86fb30f2..96d1b695dd70 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -67,12 +67,20 @@ pub fn llvm(build: &Build, target: &str) { if build.config.ninja { cfg.generator("Ninja"); } + + let profile = match (build.config.llvm_optimize, build.config.llvm_release_debuginfo) { + (false, _) => "Debug", + (true, false) => "Release", + (true, true) => "RelWithDebInfo", + }; + cfg.target(target) .host(&build.config.build) .out_dir(&dst) - .profile(if build.config.llvm_optimize {"Release"} else {"Debug"}) + .profile(profile) .define("LLVM_ENABLE_ASSERTIONS", assertions) - .define("LLVM_TARGETS_TO_BUILD", "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend") + .define("LLVM_TARGETS_TO_BUILD", + "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430") .define("LLVM_INCLUDE_EXAMPLES", "OFF") .define("LLVM_INCLUDE_TESTS", "OFF") .define("LLVM_INCLUDE_DOCS", "OFF") diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index cc1b7136d475..47efa6952177 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -79,17 +79,28 @@ pub fn check(build: &mut Build) { break } - need_cmd("python".as_ref()); - - // Look for the nodejs command, needed for emscripten testing - if let Some(node) = have_cmd("node".as_ref()) { - build.config.nodejs = Some(node); - } else if let Some(node) = have_cmd("nodejs".as_ref()) { - build.config.nodejs = Some(node); + if build.config.python.is_none() { + build.config.python = have_cmd("python2.7".as_ref()); } + if build.config.python.is_none() { + build.config.python = have_cmd("python2".as_ref()); + } + if build.config.python.is_none() { + need_cmd("python".as_ref()); + build.config.python = Some("python".into()); + } + need_cmd(build.config.python.as_ref().unwrap().as_ref()); + if let Some(ref s) = build.config.nodejs { need_cmd(s.as_ref()); + } else { + // Look for the nodejs command, needed for emscripten testing + if let Some(node) = have_cmd("node".as_ref()) { + build.config.nodejs = Some(node); + } else if let Some(node) = have_cmd("nodejs".as_ref()) { + build.config.nodejs = Some(node); + } } if let Some(ref gdb) = build.config.gdb { diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 6f616434b10c..56be2ccb235a 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -424,6 +424,7 @@ pub fn build_rules(build: &Build) -> Rules { .host(true) .run(move |_| dist::rust_src(build)); rules.dist("dist-docs", "src/doc") + .default(true) .dep(|s| s.name("default:doc")) .run(move |s| dist::docs(build, s.stage, s.target)); rules.dist("install", "src") @@ -564,7 +565,8 @@ impl<'a> Rules<'a> { for dep in rule.deps.iter() { let dep = dep(&self.sbuild.name(rule.name)); if self.rules.contains_key(&dep.name) || dep.name.starts_with("default:") { - continue } + continue + } panic!("\ invalid rule dependency graph detected, was a rule added and maybe typo'd? @@ -685,8 +687,9 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd? "dist" => Kind::Dist, kind => panic!("unknown kind: `{}`", kind), }; + let host = self.build.config.host.iter().any(|h| h == dep.target); let rules = self.rules.values().filter(|r| r.default); - for rule in rules.filter(|r| r.kind == kind) { + for rule in rules.filter(|r| r.kind == kind && (!r.host || host)) { self.fill(dep.name(rule.name), order, added); } } else { diff --git a/src/ci/docker/arm-android/Dockerfile b/src/ci/docker/arm-android/Dockerfile new file mode 100644 index 000000000000..c5b70c227c40 --- /dev/null +++ b/src/ci/docker/arm-android/Dockerfile @@ -0,0 +1,46 @@ +FROM ubuntu:16.04 + +RUN dpkg --add-architecture i386 && \ + apt-get update && \ + apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + python-minimal \ + git \ + cmake \ + ccache \ + unzip \ + expect \ + openjdk-9-jre \ + sudo \ + libstdc++6:i386 + +WORKDIR /android/ +ENV PATH=$PATH:/android/ndk-arm-9/bin:/android/sdk/tools:/android/sdk/platform-tools + +COPY install-ndk.sh install-sdk.sh accept-licenses.sh /android/ +RUN sh /android/install-ndk.sh +RUN sh /android/install-sdk.sh + +COPY start-emulator.sh /android/ +ENTRYPOINT ["/android/start-emulator.sh"] + +ENV TARGETS=arm-linux-androideabi +ENV TARGETS=$TARGETS,i686-linux-android +ENV TARGETS=$TARGETS,aarch64-linux-android +ENV TARGETS=$TARGETS,armv7-linux-androideabi + +ENV RUST_CONFIGURE_ARGS \ + --target=$TARGETS \ + --arm-linux-androideabi-ndk=/android/ndk-arm-9 \ + --armv7-linux-androideabi-ndk=/android/ndk-arm-9 \ + --i686-linux-android-ndk=/android/ndk-x86-9 \ + --aarch64-linux-android-ndk=/android/ndk-aarch64 \ + --enable-rustbuild +ENV RUST_CHECK_TARGET check-stage2-android +RUN mkdir /tmp/obj +RUN chmod 777 /tmp/obj diff --git a/src/ci/docker/arm-android/accept-licenses.sh b/src/ci/docker/arm-android/accept-licenses.sh new file mode 100755 index 000000000000..8d8f60a5ec26 --- /dev/null +++ b/src/ci/docker/arm-android/accept-licenses.sh @@ -0,0 +1,15 @@ +#!/usr/bin/expect -f +# ignore-license + +set timeout 1800 +set cmd [lindex $argv 0] +set licenses [lindex $argv 1] + +spawn {*}$cmd +expect { + "Do you accept the license '*'*" { + exp_send "y\r" + exp_continue + } + eof +} diff --git a/src/ci/docker/arm-android/install-ndk.sh b/src/ci/docker/arm-android/install-ndk.sh new file mode 100644 index 000000000000..418ce69c5b1e --- /dev/null +++ b/src/ci/docker/arm-android/install-ndk.sh @@ -0,0 +1,45 @@ +#!/bin/sh +# Copyright 2016 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex + +cpgdb() { + cp android-ndk-r11c/prebuilt/linux-x86_64/bin/gdb /android/$1/bin/$2-gdb + cp android-ndk-r11c/prebuilt/linux-x86_64/bin/gdb-orig /android/$1/bin/gdb-orig + cp -r android-ndk-r11c/prebuilt/linux-x86_64/share /android/$1/share +} + +# Prep the Android NDK +# +# See https://github.com/servo/servo/wiki/Building-for-Android +curl -O https://dl.google.com/android/repository/android-ndk-r11c-linux-x86_64.zip +unzip -q android-ndk-r11c-linux-x86_64.zip +bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \ + --platform=android-9 \ + --toolchain=arm-linux-androideabi-4.9 \ + --install-dir=/android/ndk-arm-9 \ + --ndk-dir=/android/android-ndk-r11c \ + --arch=arm +cpgdb ndk-arm-9 arm-linux-androideabi +bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \ + --platform=android-21 \ + --toolchain=aarch64-linux-android-4.9 \ + --install-dir=/android/ndk-aarch64 \ + --ndk-dir=/android/android-ndk-r11c \ + --arch=arm64 +bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \ + --platform=android-9 \ + --toolchain=x86-4.9 \ + --install-dir=/android/ndk-x86-9 \ + --ndk-dir=/android/android-ndk-r11c \ + --arch=x86 + +rm -rf ./android-ndk-r11c-linux-x86_64.zip ./android-ndk-r11c diff --git a/src/ci/docker/arm-android/install-sdk.sh b/src/ci/docker/arm-android/install-sdk.sh new file mode 100644 index 000000000000..2db1d46ba227 --- /dev/null +++ b/src/ci/docker/arm-android/install-sdk.sh @@ -0,0 +1,33 @@ +#!/bin/sh +# Copyright 2016 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex + +# Prep the SDK and emulator +# +# Note that the update process requires that we accept a bunch of licenses, and +# we can't just pipe `yes` into it for some reason, so we take the same strategy +# located in https://github.com/appunite/docker by just wrapping it in a script +# which apparently magically accepts the licenses. + +mkdir sdk +curl https://dl.google.com/android/android-sdk_r24.4-linux.tgz | \ + tar xzf - -C sdk --strip-components=1 + +filter="platform-tools,android-18" +filter="$filter,sys-img-armeabi-v7a-android-18" + +./accept-licenses.sh "android - update sdk -a --no-ui --filter $filter" + +echo "no" | android create avd \ + --name arm-18 \ + --target android-18 \ + --abi armeabi-v7a diff --git a/src/ci/docker/arm-android/start-emulator.sh b/src/ci/docker/arm-android/start-emulator.sh new file mode 100755 index 000000000000..93f20b28b868 --- /dev/null +++ b/src/ci/docker/arm-android/start-emulator.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# Copyright 2016 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex +ANDROID_EMULATOR_FORCE_32BIT=true \ + emulator @arm-18 -no-window -partition-size 2047 & +exec "$@" diff --git a/src/ci/docker/cross/Dockerfile b/src/ci/docker/cross/Dockerfile new file mode 100644 index 000000000000..d8af878a9586 --- /dev/null +++ b/src/ci/docker/cross/Dockerfile @@ -0,0 +1,66 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + python-minimal \ + git \ + cmake \ + ccache \ + sudo \ + gcc-aarch64-linux-gnu libc6-dev-arm64-cross \ + gcc-arm-linux-gnueabi libc6-dev-armel-cross \ + gcc-arm-linux-gnueabihf libc6-dev-armhf-cross \ + gcc-mips-linux-gnu libc6-dev-mips-cross \ + gcc-mipsel-linux-gnu libc6-dev-mipsel-cross \ + gcc-mips64-linux-gnuabi64 libc6-dev-mips64-cross \ + gcc-mips64el-linux-gnuabi64 libc6-dev-mips64el-cross \ + gcc-powerpc-linux-gnu libc6-dev-powerpc-cross \ + gcc-powerpc64-linux-gnu libc6-dev-ppc64-cross \ + gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross \ + gcc-s390x-linux-gnu libc6-dev-s390x-cross + +ENV TARGETS=aarch64-unknown-linux-gnu +ENV TARGETS=$TARGETS,arm-unknown-linux-gnueabi +ENV TARGETS=$TARGETS,arm-unknown-linux-gnueabihf +ENV TARGETS=$TARGETS,armv7-unknown-linux-gnueabihf +ENV TARGETS=$TARGETS,asmjs-unknown-emscripten +ENV TARGETS=$TARGETS,mips-unknown-linux-gnu +ENV TARGETS=$TARGETS,mips64-unknown-linux-gnuabi64 +ENV TARGETS=$TARGETS,mips64el-unknown-linux-gnuabi64 +ENV TARGETS=$TARGETS,mipsel-unknown-linux-gnu +ENV TARGETS=$TARGETS,powerpc-unknown-linux-gnu +ENV TARGETS=$TARGETS,powerpc64-unknown-linux-gnu +ENV TARGETS=$TARGETS,powerpc64le-unknown-linux-gnu +ENV TARGETS=$TARGETS,s390x-unknown-linux-gnu +ENV TARGETS=$TARGETS,wasm32-unknown-emscripten + +#ENV TARGETS=$TARGETS,mips-unknown-linux-musl +#ENV TARGETS=$TARGETS,arm-unknown-linux-musleabi +#ENV TARGETS=$TARGETS,arm-unknown-linux-musleabihf +#ENV TARGETS=$TARGETS,armv7-unknown-linux-musleabihf +#ENV TARGETS=$TARGETS,x86_64-rumprun-netbsd + +ENV RUST_CONFIGURE_ARGS \ + --target=$TARGETS \ + --enable-rustbuild +ENV RUST_CHECK_TARGET "" + +ENV AR_s390x_unknown_linux_gnu=s390x-linux-gnu-ar \ + CC_s390x_unknown_linux_gnu=s390x-linux-gnu-gcc \ + AR_mips64_unknown_linux_gnuabi64=mips64-linux-gnuabi64-ar \ + CC_mips64_unknown_linux_gnuabi64=mips64-linux-gnuabi64-gcc \ + AR_mips64el_unknown_linux_gnuabi64=mips64el-linux-gnuabi64-ar \ + CC_mips64el_unknown_linux_gnuabi64=mips64el-linux-gnuabi64-gcc \ + AR_powerpc64_unknown_linux_gnu=powerpc64-linux-gnu-ar \ + CC_powerpc64_unknown_linux_gnu=powerpc64-linux-gnu-gcc + +# FIXME(rust-lang/rust#36150): powerpc unfortunately aborts right now +ENV NO_LLVM_ASSERTIONS=1 + +RUN mkdir /tmp/obj +RUN chmod 777 /tmp/obj diff --git a/src/ci/docker/i686-gnu-nopt/Dockerfile b/src/ci/docker/i686-gnu-nopt/Dockerfile new file mode 100644 index 000000000000..a9ef29daaf1a --- /dev/null +++ b/src/ci/docker/i686-gnu-nopt/Dockerfile @@ -0,0 +1,19 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++-multilib \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + ccache \ + sudo \ + gdb + +ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu --disable-optimize-tests +ENV RUST_CHECK_TARGET check +RUN mkdir /tmp/obj +RUN chmod 777 /tmp/obj diff --git a/src/ci/docker/i686-gnu/Dockerfile b/src/ci/docker/i686-gnu/Dockerfile new file mode 100644 index 000000000000..d0ddde95b447 --- /dev/null +++ b/src/ci/docker/i686-gnu/Dockerfile @@ -0,0 +1,19 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++-multilib \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + ccache \ + sudo \ + gdb + +ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu +ENV RUST_CHECK_TARGET check +RUN mkdir /tmp/obj +RUN chmod 777 /tmp/obj diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh new file mode 100755 index 000000000000..c5b1d00fb7cc --- /dev/null +++ b/src/ci/docker/run.sh @@ -0,0 +1,42 @@ +#!/bin/sh +# Copyright 2016 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -e + +script=`cd $(dirname $0) && pwd`/`basename $0` +image=$1 + +docker_dir="`dirname $script`" +ci_dir="`dirname $docker_dir`" +src_dir="`dirname $ci_dir`" +root_dir="`dirname $src_dir`" + +docker build \ + --rm \ + -t rust-ci \ + "`dirname "$script"`/$image" + +mkdir -p $HOME/.ccache +mkdir -p $HOME/.cargo + +exec docker run \ + --volume "$root_dir:/checkout:ro" \ + --workdir /tmp/obj \ + --env SRC=/checkout \ + --env CCACHE_DIR=/ccache \ + --volume "$HOME/.ccache:/ccache" \ + --env CARGO_HOME=/cargo \ + --env LOCAL_USER_ID=`id -u` \ + --volume "$HOME/.cargo:/cargo" \ + --interactive \ + --tty \ + rust-ci \ + /checkout/src/ci/run.sh diff --git a/src/ci/docker/x86_64-freebsd/Dockerfile b/src/ci/docker/x86_64-freebsd/Dockerfile new file mode 100644 index 000000000000..dc16c39961c4 --- /dev/null +++ b/src/ci/docker/x86_64-freebsd/Dockerfile @@ -0,0 +1,29 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + python-minimal \ + git \ + cmake \ + ccache \ + sudo \ + bzip2 \ + xz-utils \ + wget + +COPY build-toolchain.sh /tmp/ +RUN sh /tmp/build-toolchain.sh + +ENV \ + AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-ar \ + CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-gcc + +ENV RUST_CONFIGURE_ARGS --target=x86_64-unknown-freebsd --enable-rustbuild +ENV RUST_CHECK_TARGET "" +RUN mkdir /tmp/obj +RUN chmod 777 /tmp/obj diff --git a/src/ci/docker/x86_64-freebsd/build-toolchain.sh b/src/ci/docker/x86_64-freebsd/build-toolchain.sh new file mode 100644 index 000000000000..d4bc886d50ea --- /dev/null +++ b/src/ci/docker/x86_64-freebsd/build-toolchain.sh @@ -0,0 +1,96 @@ +#!/bin/bash +# Copyright 2016 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex + +ARCH=x86_64 +BINUTILS=2.25.1 +GCC=5.3.0 + +mkdir binutils +cd binutils + +# First up, build binutils +curl https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS.tar.bz2 | tar xjf - +mkdir binutils-build +cd binutils-build +../binutils-$BINUTILS/configure \ + --target=$ARCH-unknown-freebsd10 +make -j10 +make install +cd ../.. +rm -rf binutils + +# Next, download the FreeBSD libc and relevant header files + +mkdir freebsd +case "$ARCH" in + x86_64) + URL=ftp://ftp.freebsd.org/pub/FreeBSD/releases/amd64/10.2-RELEASE/base.txz + ;; + i686) + URL=ftp://ftp.freebsd.org/pub/FreeBSD/releases/i386/10.2-RELEASE/base.txz + ;; +esac +curl $URL | tar xJf - -C freebsd ./usr/include ./usr/lib ./lib + +dst=/usr/local/$ARCH-unknown-freebsd10 + +cp -r freebsd/usr/include $dst/ +cp freebsd/usr/lib/crt1.o $dst/lib +cp freebsd/usr/lib/Scrt1.o $dst/lib +cp freebsd/usr/lib/crti.o $dst/lib +cp freebsd/usr/lib/crtn.o $dst/lib +cp freebsd/usr/lib/libc.a $dst/lib +cp freebsd/usr/lib/libutil.a $dst/lib +cp freebsd/usr/lib/libutil_p.a $dst/lib +cp freebsd/usr/lib/libm.a $dst/lib +cp freebsd/usr/lib/librt.so.1 $dst/lib +cp freebsd/usr/lib/libexecinfo.so.1 $dst/lib +cp freebsd/lib/libc.so.7 $dst/lib +cp freebsd/lib/libm.so.5 $dst/lib +cp freebsd/lib/libutil.so.9 $dst/lib +cp freebsd/lib/libthr.so.3 $dst/lib/libpthread.so + +ln -s libc.so.7 $dst/lib/libc.so +ln -s libm.so.5 $dst/lib/libm.so +ln -s librt.so.1 $dst/lib/librt.so +ln -s libutil.so.9 $dst/lib/libutil.so +ln -s libexecinfo.so.1 $dst/lib/libexecinfo.so +rm -rf freebsd + +# Finally, download and build gcc to target FreeBSD +mkdir gcc +cd gcc +curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf - +cd gcc-$GCC +./contrib/download_prerequisites + +mkdir ../gcc-build +cd ../gcc-build +../gcc-$GCC/configure \ + --enable-languages=c \ + --target=$ARCH-unknown-freebsd10 \ + --disable-multilib \ + --disable-nls \ + --disable-libgomp \ + --disable-libquadmath \ + --disable-libssp \ + --disable-libvtv \ + --disable-libcilkrts \ + --disable-libada \ + --disable-libsanitizer \ + --disable-libquadmath-support \ + --disable-lto +make -j10 +make install +cd ../.. +rm -rf gcc diff --git a/src/ci/docker/x86_64-gnu-cargotest/Dockerfile b/src/ci/docker/x86_64-gnu-cargotest/Dockerfile new file mode 100644 index 000000000000..1db01f2b48d4 --- /dev/null +++ b/src/ci/docker/x86_64-gnu-cargotest/Dockerfile @@ -0,0 +1,20 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + python-minimal \ + git \ + cmake \ + ccache \ + libssl-dev \ + sudo + +ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --enable-rustbuild +ENV RUST_CHECK_TARGET check-cargotest +RUN mkdir /tmp/obj +RUN chmod 777 /tmp/obj diff --git a/src/ci/docker/x86_64-gnu-debug/Dockerfile b/src/ci/docker/x86_64-gnu-debug/Dockerfile new file mode 100644 index 000000000000..9e98215775e5 --- /dev/null +++ b/src/ci/docker/x86_64-gnu-debug/Dockerfile @@ -0,0 +1,22 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + ccache \ + sudo \ + gdb + +ENV RUST_CONFIGURE_ARGS \ + --build=x86_64-unknown-linux-gnu \ + --enable-debug \ + --enable-optimize +ENV RUST_CHECK_TARGET "" +RUN mkdir /tmp/obj +RUN chmod 777 /tmp/obj diff --git a/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile b/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile new file mode 100644 index 000000000000..ca06940ae5e2 --- /dev/null +++ b/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile @@ -0,0 +1,26 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + python2.7-minimal \ + git \ + cmake \ + ccache \ + sudo \ + gdb \ + llvm-3.7-tools \ + libedit-dev \ + zlib1g-dev + +ENV RUST_CONFIGURE_ARGS \ + --build=x86_64-unknown-linux-gnu \ + --enable-rustbuild \ + --llvm-root=/usr/lib/llvm-3.7 +ENV RUST_CHECK_TARGET check +RUN mkdir /tmp/obj +RUN chmod 777 /tmp/obj diff --git a/src/ci/docker/x86_64-gnu-nopt/Dockerfile b/src/ci/docker/x86_64-gnu-nopt/Dockerfile new file mode 100644 index 000000000000..73a3e2c726ce --- /dev/null +++ b/src/ci/docker/x86_64-gnu-nopt/Dockerfile @@ -0,0 +1,19 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + ccache \ + sudo \ + gdb + +ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --disable-optimize-tests +ENV RUST_CHECK_TARGET check +RUN mkdir /tmp/obj +RUN chmod 777 /tmp/obj diff --git a/src/ci/docker/x86_64-gnu-rustbuild/Dockerfile b/src/ci/docker/x86_64-gnu-rustbuild/Dockerfile new file mode 100644 index 000000000000..d4d0492e2a26 --- /dev/null +++ b/src/ci/docker/x86_64-gnu-rustbuild/Dockerfile @@ -0,0 +1,20 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + python-minimal \ + git \ + cmake \ + ccache \ + sudo \ + gdb + +ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --enable-rustbuild +ENV RUST_CHECK_TARGET check +RUN mkdir /tmp/obj +RUN chmod 777 /tmp/obj diff --git a/src/ci/docker/x86_64-gnu/Dockerfile b/src/ci/docker/x86_64-gnu/Dockerfile new file mode 100644 index 000000000000..f125693e7ae1 --- /dev/null +++ b/src/ci/docker/x86_64-gnu/Dockerfile @@ -0,0 +1,19 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + ccache \ + sudo \ + gdb + +ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu +ENV RUST_CHECK_TARGET check +RUN mkdir /tmp/obj +RUN chmod 777 /tmp/obj diff --git a/src/ci/docker/x86_64-musl/Dockerfile b/src/ci/docker/x86_64-musl/Dockerfile new file mode 100644 index 000000000000..1afaef2e0567 --- /dev/null +++ b/src/ci/docker/x86_64-musl/Dockerfile @@ -0,0 +1,27 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + ccache \ + xz-utils \ + sudo \ + gdb + +WORKDIR /build/ +COPY build-musl.sh /build/ +RUN sh /build/build-musl.sh && rm -rf /build + +ENV RUST_CONFIGURE_ARGS \ + --target=x86_64-unknown-linux-musl \ + --musl-root=/musl-x86_64 +ENV RUST_CHECK_TARGET check-stage2-T-x86_64-unknown-linux-musl-H-x86_64-unknown-linux-gnu + +RUN mkdir /tmp/obj +RUN chmod 777 /tmp/obj diff --git a/src/ci/docker/x86_64-musl/build-musl.sh b/src/ci/docker/x86_64-musl/build-musl.sh new file mode 100644 index 000000000000..2bfbd646b75c --- /dev/null +++ b/src/ci/docker/x86_64-musl/build-musl.sh @@ -0,0 +1,33 @@ +#!/bin/sh +# Copyright 2016 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex + +export CFLAGS="-fPIC" +MUSL=musl-1.1.14 +curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf - +cd $MUSL +./configure --prefix=/musl-x86_64 --disable-shared +make -j10 +make install +make clean +cd .. + +# To build MUSL we're going to need a libunwind lying around, so acquire that +# here and build it. +curl -L https://github.com/llvm-mirror/llvm/archive/release_37.tar.gz | tar xzf - +curl -L https://github.com/llvm-mirror/libunwind/archive/release_37.tar.gz | tar xzf - +mkdir libunwind-build +cd libunwind-build +cmake ../libunwind-release_37 -DLLVM_PATH=/build/llvm-release_37 \ + -DLIBUNWIND_ENABLE_SHARED=0 +make -j10 +cp lib/libunwind.a /musl-x86_64/lib diff --git a/src/ci/run.sh b/src/ci/run.sh new file mode 100755 index 000000000000..da238dddecac --- /dev/null +++ b/src/ci/run.sh @@ -0,0 +1,44 @@ +#!/bin/sh +# Copyright 2016 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -e + +if [ "$LOCAL_USER_ID" != "" ]; then + useradd --shell /bin/bash -u $LOCAL_USER_ID -o -c "" -m user + export HOME=/home/user + export LOCAL_USER_ID= + exec sudo -E -u user env PATH=$PATH "$0" +fi + +if [ "$NO_LLVM_ASSERTIONS" = "" ]; then + LLVM_ASSERTIONS=--enable-llvm-assertions +fi + +set -ex + +$SRC/configure \ + --disable-manage-submodules \ + --enable-debug-assertions \ + --enable-quiet-tests \ + --enable-ccache \ + --enable-vendor \ + $LLVM_ASSERTIONS \ + $RUST_CONFIGURE_ARGS + +if [ "$TRAVIS_OS_NAME" = "osx" ]; then + ncpus=$(sysctl -n hw.ncpu) +else + ncpus=$(nproc) +fi + +make -j $ncpus tidy +make -j $ncpus +exec make $RUST_CHECK_TARGET -j $ncpus diff --git a/src/compiler-rt b/src/compiler-rt index ecd2b1f6d689..3bc0272cab9f 160000 --- a/src/compiler-rt +++ b/src/compiler-rt @@ -1 +1 @@ -Subproject commit ecd2b1f6d689d5afbf5debe8afb3739337323852 +Subproject commit 3bc0272cab9fdcfc2ef4df9625ec3c9d5909db79 diff --git a/src/doc/book/associated-types.md b/src/doc/book/associated-types.md index 0998a88c4d24..f416e600415b 100644 --- a/src/doc/book/associated-types.md +++ b/src/doc/book/associated-types.md @@ -11,7 +11,7 @@ this: trait Graph { fn has_edge(&self, &N, &N) -> bool; fn edges(&self, &N) -> Vec; - // etc + // Etc. } ``` @@ -36,7 +36,7 @@ trait Graph { fn has_edge(&self, &Self::N, &Self::N) -> bool; fn edges(&self, &Self::N) -> Vec; - // etc + // Etc. } ``` diff --git a/src/doc/book/benchmark-tests.md b/src/doc/book/benchmark-tests.md index 797ec94774d7..e054736eb30b 100644 --- a/src/doc/book/benchmark-tests.md +++ b/src/doc/book/benchmark-tests.md @@ -110,7 +110,7 @@ computation entirely. This could be done for the example above by adjusting the # struct X; # impl X { fn iter(&self, _: F) where F: FnMut() -> T {} } let b = X; b.iter(|| { - // note lack of `;` (could also use an explicit `return`). + // Note lack of `;` (could also use an explicit `return`). (0..1000).fold(0, |old, new| old ^ new) }); ``` diff --git a/src/doc/book/box-syntax-and-patterns.md b/src/doc/book/box-syntax-and-patterns.md index 8d83b64d6831..cbf65dfa9ba8 100644 --- a/src/doc/book/box-syntax-and-patterns.md +++ b/src/doc/book/box-syntax-and-patterns.md @@ -38,7 +38,7 @@ so as to avoid copying a large data structure. For example: struct BigStruct { one: i32, two: i32, - // etc + // Etc. one_hundred: i32, } @@ -68,7 +68,7 @@ This is an antipattern in Rust. Instead, write this: struct BigStruct { one: i32, two: i32, - // etc + // Etc. one_hundred: i32, } diff --git a/src/doc/book/casting-between-types.md b/src/doc/book/casting-between-types.md index a101f397c379..296384ab6efd 100644 --- a/src/doc/book/casting-between-types.md +++ b/src/doc/book/casting-between-types.md @@ -106,7 +106,7 @@ from integers, and to cast between pointers to different types subject to some constraints. It is only unsafe to dereference the pointer: ```rust -let a = 300 as *const char; // a pointer to location 300 +let a = 300 as *const char; // `a` is a pointer to location 300. let b = a as u32; ``` @@ -135,14 +135,14 @@ cast four bytes into a `u32`: ```rust,ignore let a = [0u8, 0u8, 0u8, 0u8]; -let b = a as u32; // four u8s makes a u32 +let b = a as u32; // Four u8s makes a u32. ``` This errors with: ```text error: non-scalar cast: `[u8; 4]` as `u32` -let b = a as u32; // four u8s makes a u32 +let b = a as u32; // Four u8s makes a u32. ^~~~~~~~ ``` @@ -170,7 +170,7 @@ fn main() { let a = [0u8, 1u8, 0u8, 0u8]; let b = mem::transmute::<[u8; 4], u32>(a); println!("{}", b); // 256 - // or, more concisely: + // Or, more concisely: let c: u32 = mem::transmute(a); println!("{}", c); // 256 } diff --git a/src/doc/book/choosing-your-guarantees.md b/src/doc/book/choosing-your-guarantees.md index d88f619260ac..9dca3479d35e 100644 --- a/src/doc/book/choosing-your-guarantees.md +++ b/src/doc/book/choosing-your-guarantees.md @@ -25,7 +25,7 @@ the following: ```rust let x = Box::new(1); let y = x; -// x no longer accessible here +// `x` is no longer accessible here. ``` Here, the box was _moved_ into `y`. As `x` no longer owns it, the compiler will no longer allow the @@ -291,9 +291,9 @@ the inner data (mutably), and the lock will be released when the guard goes out ```rust,ignore { let guard = mutex.lock(); - // guard dereferences mutably to the inner type + // `guard` dereferences mutably to the inner type. *guard += 1; -} // lock released when destructor runs +} // Lock is released when destructor runs. ``` diff --git a/src/doc/book/closures.md b/src/doc/book/closures.md index fa9f66d43baa..a3c7333c6bec 100644 --- a/src/doc/book/closures.md +++ b/src/doc/book/closures.md @@ -116,7 +116,7 @@ let mut num = 5; { let plus_num = |x: i32| x + num; -} // plus_num goes out of scope, borrow of num ends +} // `plus_num` goes out of scope; borrow of `num` ends. let y = &mut num; ``` diff --git a/src/doc/book/comments.md b/src/doc/book/comments.md index e7eb48dc42c5..8fa397cd9a66 100644 --- a/src/doc/book/comments.md +++ b/src/doc/book/comments.md @@ -10,7 +10,7 @@ and *doc comments*. ```rust // Line comments are anything after ‘//’ and extend to the end of the line. -let x = 5; // this is also a line comment. +let x = 5; // This is also a line comment. // If you have a long explanation for something, you can put line comments next // to each other. Put a space between the // and your comment so that it’s diff --git a/src/doc/book/compiler-plugins.md b/src/doc/book/compiler-plugins.md index a9a81843ab19..ff29358df940 100644 --- a/src/doc/book/compiler-plugins.md +++ b/src/doc/book/compiler-plugins.md @@ -48,7 +48,7 @@ extern crate rustc_plugin; use syntax::parse::token; use syntax::tokenstream::TokenTree; use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager}; -use syntax::ext::build::AstBuilder; // trait for expr_usize +use syntax::ext::build::AstBuilder; // A trait for expr_usize. use syntax::ext::quote::rt::Span; use rustc_plugin::Registry; diff --git a/src/doc/book/concurrency.md b/src/doc/book/concurrency.md index 41d8345b7209..67d89d5484ca 100644 --- a/src/doc/book/concurrency.md +++ b/src/doc/book/concurrency.md @@ -213,10 +213,10 @@ fn main() { let mut data = Rc::new(vec![1, 2, 3]); for i in 0..3 { - // create a new owned reference + // Create a new owned reference: let data_ref = data.clone(); - // use it in a thread + // Use it in a thread: thread::spawn(move || { data_ref[0] += i; }); @@ -390,8 +390,8 @@ use std::sync::mpsc; fn main() { let data = Arc::new(Mutex::new(0)); - // `tx` is the "transmitter" or "sender" - // `rx` is the "receiver" + // `tx` is the "transmitter" or "sender". + // `rx` is the "receiver". let (tx, rx) = mpsc::channel(); for _ in 0..10 { diff --git a/src/doc/book/crates-and-modules.md b/src/doc/book/crates-and-modules.md index fcb7e0bc7eac..0e336635235b 100644 --- a/src/doc/book/crates-and-modules.md +++ b/src/doc/book/crates-and-modules.md @@ -126,7 +126,7 @@ Instead of declaring a module like this: ```rust,ignore mod english { - // contents of our module go here + // Contents of our module go here. } ``` diff --git a/src/doc/book/custom-allocators.md b/src/doc/book/custom-allocators.md index d69ef6cf7e83..1996305f09e7 100644 --- a/src/doc/book/custom-allocators.md +++ b/src/doc/book/custom-allocators.md @@ -41,7 +41,7 @@ which allocator is in use is done simply by linking to the desired allocator: extern crate alloc_system; fn main() { - let a = Box::new(4); // allocates from the system allocator + let a = Box::new(4); // Allocates from the system allocator. println!("{}", a); } ``` @@ -57,7 +57,7 @@ uses jemalloc by default one would write: extern crate alloc_jemalloc; pub fn foo() { - let a = Box::new(4); // allocates from jemalloc + let a = Box::new(4); // Allocates from jemalloc. println!("{}", a); } # fn main() {} @@ -72,11 +72,11 @@ crate which implements the allocator API (e.g. the same as `alloc_system` or annotated version of `alloc_system` ```rust,no_run -# // only needed for rustdoc --test down below +# // Only needed for rustdoc --test down below. # #![feature(lang_items)] // The compiler needs to be instructed that this crate is an allocator in order // to realize that when this is linked in another allocator like jemalloc should -// not be linked in +// not be linked in. #![feature(allocator)] #![allocator] @@ -85,7 +85,7 @@ annotated version of `alloc_system` // however, can use all of libcore. #![no_std] -// Let's give a unique name to our custom allocator +// Let's give a unique name to our custom allocator: #![crate_name = "my_allocator"] #![crate_type = "rlib"] @@ -126,7 +126,7 @@ pub extern fn __rust_reallocate(ptr: *mut u8, _old_size: usize, size: usize, #[no_mangle] pub extern fn __rust_reallocate_inplace(_ptr: *mut u8, old_size: usize, _size: usize, _align: usize) -> usize { - old_size // this api is not supported by libc + old_size // This api is not supported by libc. } #[no_mangle] @@ -134,7 +134,7 @@ pub extern fn __rust_usable_size(size: usize, _align: usize) -> usize { size } -# // only needed to get rustdoc to test this +# // Only needed to get rustdoc to test this: # fn main() {} # #[lang = "panic_fmt"] fn panic_fmt() {} # #[lang = "eh_personality"] fn eh_personality() {} @@ -149,7 +149,7 @@ After we compile this crate, it can be used as follows: extern crate my_allocator; fn main() { - let a = Box::new(8); // allocates memory via our custom allocator crate + let a = Box::new(8); // Allocates memory via our custom allocator crate. println!("{}", a); } ``` diff --git a/src/doc/book/deref-coercions.md b/src/doc/book/deref-coercions.md index cabe66f5b228..864cd282d937 100644 --- a/src/doc/book/deref-coercions.md +++ b/src/doc/book/deref-coercions.md @@ -33,13 +33,13 @@ automatically coerce to a `&T`. Here’s an example: ```rust fn foo(s: &str) { - // borrow a string for a second + // Borrow a string for a second. } -// String implements Deref +// String implements Deref. let owned = "Hello".to_string(); -// therefore, this works: +// Therefore, this works: foo(&owned); ``` @@ -55,14 +55,14 @@ type implements `Deref`, so this works: use std::rc::Rc; fn foo(s: &str) { - // borrow a string for a second + // Borrow a string for a second. } -// String implements Deref +// String implements Deref. let owned = "Hello".to_string(); let counted = Rc::new(owned); -// therefore, this works: +// Therefore, this works: foo(&counted); ``` @@ -76,10 +76,10 @@ Another very common implementation provided by the standard library is: ```rust fn foo(s: &[i32]) { - // borrow a slice for a second + // Borrow a slice for a second. } -// Vec implements Deref +// Vec implements Deref. let owned = vec![1, 2, 3]; foo(&owned); diff --git a/src/doc/book/documentation.md b/src/doc/book/documentation.md index 6292ba9aac40..f30a95b4e789 100644 --- a/src/doc/book/documentation.md +++ b/src/doc/book/documentation.md @@ -28,7 +28,7 @@ code. You can use documentation comments for this purpose: /// let five = Rc::new(5); /// ``` pub fn new(value: T) -> Rc { - // implementation goes here + // Implementation goes here. } ``` @@ -483,7 +483,7 @@ you have a module in `foo.rs`, you'll often open its code and see this: ```rust //! A module for using `foo`s. //! -//! The `foo` module contains a lot of useful functionality blah blah blah +//! The `foo` module contains a lot of useful functionality blah blah blah... ``` ### Crate documentation diff --git a/src/doc/book/drop.md b/src/doc/book/drop.md index 5513523e56b9..0b7ddcfbe885 100644 --- a/src/doc/book/drop.md +++ b/src/doc/book/drop.md @@ -18,9 +18,9 @@ impl Drop for HasDrop { fn main() { let x = HasDrop; - // do stuff + // Do stuff. -} // x goes out of scope here +} // `x` goes out of scope here. ``` When `x` goes out of scope at the end of `main()`, the code for `Drop` will diff --git a/src/doc/book/enums.md b/src/doc/book/enums.md index 5e05b4ebbdfa..790d6ff85469 100644 --- a/src/doc/book/enums.md +++ b/src/doc/book/enums.md @@ -51,7 +51,7 @@ possible variants: ```rust,ignore fn process_color_change(msg: Message) { - let Message::ChangeColor(r, g, b) = msg; // compile-time error + let Message::ChangeColor(r, g, b) = msg; // This causes a compile-time error. } ``` diff --git a/src/doc/book/error-handling.md b/src/doc/book/error-handling.md index a62e1b7dfa9c..0d9f49d66cbd 100644 --- a/src/doc/book/error-handling.md +++ b/src/doc/book/error-handling.md @@ -65,7 +65,7 @@ and in most cases, the entire program aborts.) Here's an example: ```rust,should_panic // Guess a number between 1 and 10. -// If it matches the number we had in mind, return true. Else, return false. +// If it matches the number we had in mind, return `true`. Else, return `false`. fn guess(n: i32) -> bool { if n < 1 || n > 10 { panic!("Invalid number: {}", n); @@ -350,7 +350,7 @@ fn file_path_ext_explicit(file_path: &str) -> Option<&str> { } fn file_name(file_path: &str) -> Option<&str> { - // implementation elided + // Implementation elided. unimplemented!() } ``` @@ -360,7 +360,7 @@ analysis, but its type doesn't quite fit... ```rust,ignore fn file_path_ext(file_path: &str) -> Option<&str> { - file_name(file_path).map(|x| extension(x)) //Compilation error + file_name(file_path).map(|x| extension(x)) // This causes a compilation error. } ``` @@ -1235,11 +1235,11 @@ use std::fs; use std::io; use std::num; -// We have to jump through some hoops to actually get error values. +// We have to jump through some hoops to actually get error values: let io_err: io::Error = io::Error::last_os_error(); let parse_err: num::ParseIntError = "not a number".parse::().unwrap_err(); -// OK, here are the conversions. +// OK, here are the conversions: let err1: Box = From::from(io_err); let err2: Box = From::from(parse_err); ``` @@ -1609,7 +1609,7 @@ fn main() { let data_path = &matches.free[0]; let city: &str = &matches.free[1]; - // Do stuff with information + // Do stuff with information. } ``` @@ -1747,7 +1747,7 @@ simply ignoring that row. use std::path::Path; struct Row { - // unchanged + // This struct remains unchanged. } struct PopulationCount { @@ -1769,7 +1769,7 @@ fn search>(file_path: P, city: &str) -> Vec { for row in rdr.decode::() { let row = row.unwrap(); match row.population { - None => { } // skip it + None => { } // Skip it. Some(count) => if row.city == city { found.push(PopulationCount { city: row.city, @@ -1825,7 +1825,7 @@ Let's try it: ```rust,ignore use std::error::Error; -// The rest of the code before this is unchanged +// The rest of the code before this is unchanged. fn search> (file_path: P, city: &str) @@ -1836,7 +1836,7 @@ fn search> for row in rdr.decode::() { let row = try!(row); match row.population { - None => { } // skip it + None => { } // Skip it. Some(count) => if row.city == city { found.push(PopulationCount { city: row.city, @@ -1957,7 +1957,7 @@ that it is generic on some type parameter `R` that satisfies ```rust,ignore use std::io; -// The rest of the code before this is unchanged +// The rest of the code before this is unchanged. fn search> (file_path: &Option

, city: &str) @@ -2070,7 +2070,7 @@ fn search> for row in rdr.decode::() { let row = try!(row); match row.population { - None => { } // skip it + None => { } // Skip it. Some(count) => if row.city == city { found.push(PopulationCount { city: row.city, diff --git a/src/doc/book/ffi.md b/src/doc/book/ffi.md index 8709c3f4b7b1..7510cd0b3b59 100644 --- a/src/doc/book/ffi.md +++ b/src/doc/book/ffi.md @@ -95,7 +95,7 @@ internal details. Wrapping the functions which expect buffers involves using the `slice::raw` module to manipulate Rust vectors as pointers to memory. Rust's vectors are guaranteed to be a contiguous block of memory. The -length is number of elements currently contained, and the capacity is the total size in elements of +length is the number of elements currently contained, and the capacity is the total size in elements of the allocated memory. The length is less than or equal to the capacity. ```rust @@ -277,7 +277,7 @@ extern { fn main() { unsafe { register_callback(callback); - trigger_callback(); // Triggers the callback + trigger_callback(); // Triggers the callback. } } ``` @@ -294,7 +294,7 @@ int32_t register_callback(rust_callback callback) { } void trigger_callback() { - cb(7); // Will call callback(7) in Rust + cb(7); // Will call callback(7) in Rust. } ``` @@ -320,13 +320,13 @@ Rust code: #[repr(C)] struct RustObject { a: i32, - // other members + // Other members... } extern "C" fn callback(target: *mut RustObject, a: i32) { println!("I'm called from C with value {0}", a); unsafe { - // Update the value in RustObject with the value received from the callback + // Update the value in RustObject with the value received from the callback: (*target).a = a; } } @@ -339,7 +339,7 @@ extern { } fn main() { - // Create the object that will be referenced in the callback + // Create the object that will be referenced in the callback: let mut rust_object = Box::new(RustObject { a: 5 }); unsafe { @@ -363,7 +363,7 @@ int32_t register_callback(void* callback_target, rust_callback callback) { } void trigger_callback() { - cb(cb_target, 7); // Will call callback(&rustObject, 7) in Rust + cb(cb_target, 7); // Will call callback(&rustObject, 7) in Rust. } ``` @@ -606,7 +606,7 @@ use libc::c_int; # #[cfg(hidden)] extern "C" { - /// Register the callback. + /// Registers the callback. fn register(cb: Option c_int>, c_int) -> c_int>); } # unsafe fn register(_: Option c_int>, diff --git a/src/doc/book/functions.md b/src/doc/book/functions.md index b040684d05f7..b453936fe00d 100644 --- a/src/doc/book/functions.md +++ b/src/doc/book/functions.md @@ -135,7 +135,7 @@ In Rust, however, using `let` to introduce a binding is _not_ an expression. The following will produce a compile-time error: ```rust,ignore -let x = (let y = 5); // expected identifier, found keyword `let` +let x = (let y = 5); // Expected identifier, found keyword `let`. ``` The compiler is telling us here that it was expecting to see the beginning of @@ -151,7 +151,7 @@ other returned value would be too surprising: ```rust let mut y = 5; -let x = (y = 6); // x has the value `()`, not `6` +let x = (y = 6); // `x` has the value `()`, not `6`. ``` The second kind of statement in Rust is the *expression statement*. Its @@ -183,7 +183,7 @@ But what about early returns? Rust does have a keyword for that, `return`: fn foo(x: i32) -> i32 { return x; - // we never run this code! + // We never run this code! x + 1 } ``` @@ -307,10 +307,10 @@ fn plus_one(i: i32) -> i32 { i + 1 } -// without type inference +// Without type inference: let f: fn(i32) -> i32 = plus_one; -// with type inference +// With type inference: let f = plus_one; ``` diff --git a/src/doc/book/generics.md b/src/doc/book/generics.md index 9ab601419cd7..eafad6a05fc3 100644 --- a/src/doc/book/generics.md +++ b/src/doc/book/generics.md @@ -78,7 +78,7 @@ We can write functions that take generic types with a similar syntax: ```rust fn takes_anything(x: T) { - // do something with x + // Do something with `x`. } ``` diff --git a/src/doc/book/guessing-game.md b/src/doc/book/guessing-game.md index e2a23979a819..c854b7c373d2 100644 --- a/src/doc/book/guessing-game.md +++ b/src/doc/book/guessing-game.md @@ -158,8 +158,8 @@ take a name on the left hand side of the assignment, it actually accepts a to use for now: ```rust -let foo = 5; // immutable. -let mut bar = 5; // mutable +let foo = 5; // `foo` is immutable. +let mut bar = 5; // `bar` is mutable. ``` [immutable]: mutability.html diff --git a/src/doc/book/inline-assembly.md b/src/doc/book/inline-assembly.md index 62e196a7ccdf..e531d5d7fc0f 100644 --- a/src/doc/book/inline-assembly.md +++ b/src/doc/book/inline-assembly.md @@ -34,7 +34,7 @@ fn foo() { } } -// other platforms +// Other platforms: #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] fn foo() { /* ... */ } @@ -130,7 +130,7 @@ stay valid. # #![feature(asm)] # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] # fn main() { unsafe { -// Put the value 0x200 in eax +// Put the value 0x200 in eax: asm!("mov $$0x200, %eax" : /* no outputs */ : /* no inputs */ : "eax"); # } } # #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] diff --git a/src/doc/book/lang-items.md b/src/doc/book/lang-items.md index de7dbab3f12e..6a08c1b6bb46 100644 --- a/src/doc/book/lang-items.md +++ b/src/doc/book/lang-items.md @@ -32,7 +32,7 @@ pub struct Box(*mut T); unsafe fn allocate(size: usize, _align: usize) -> *mut u8 { let p = libc::malloc(size as libc::size_t) as *mut u8; - // malloc failed + // Check if `malloc` failed: if p as usize == 0 { abort(); } @@ -46,8 +46,8 @@ unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) { } #[lang = "box_free"] -unsafe fn box_free(ptr: *mut T) { - deallocate(ptr as *mut u8, ::core::mem::size_of::(), ::core::mem::align_of::()); +unsafe fn box_free(ptr: *mut T) { + deallocate(ptr as *mut u8, ::core::mem::size_of_val(&*ptr), ::core::mem::align_of_val(&*ptr)); } #[start] diff --git a/src/doc/book/lifetimes.md b/src/doc/book/lifetimes.md index df1ee5a293c9..397263c69733 100644 --- a/src/doc/book/lifetimes.md +++ b/src/doc/book/lifetimes.md @@ -54,13 +54,13 @@ dangling pointer or ‘use after free’, when the resource is memory. A small example of such a situation would be: ```rust,compile_fail -let r; // Introduce reference: r +let r; // Introduce reference: `r`. { - let i = 1; // Introduce scoped value: i - r = &i; // Store reference of i in r -} // i goes out of scope and is dropped. + let i = 1; // Introduce scoped value: `i`. + r = &i; // Store reference of `i` in `r`. +} // `i` goes out of scope and is dropped. -println!("{}", r); // r still refers to i +println!("{}", r); // `r` still refers to `i`. ``` To fix this, we have to make sure that step four never happens after step @@ -81,9 +81,9 @@ let lang = "en"; let v; { - let p = format!("lang:{}=", lang); // -+ p goes into scope + let p = format!("lang:{}=", lang); // -+ `p` comes into scope. v = skip_prefix(line, p.as_str()); // | -} // -+ p goes out of scope +} // -+ `p` goes out of scope. println!("{}", v); ``` @@ -191,7 +191,7 @@ struct Foo<'a> { } fn main() { - let y = &5; // this is the same as `let _y = 5; let y = &_y;` + let y = &5; // This is the same as `let _y = 5; let y = &_y;`. let f = Foo { x: y }; println!("{}", f.x); @@ -233,7 +233,7 @@ impl<'a> Foo<'a> { } fn main() { - let y = &5; // this is the same as `let _y = 5; let y = &_y;` + let y = &5; // This is the same as `let _y = 5; let y = &_y;`. let f = Foo { x: y }; println!("x is: {}", f.x()); @@ -274,11 +274,11 @@ valid for. For example: ```rust fn main() { - let y = &5; // -+ y goes into scope + let y = &5; // -+ `y` comes into scope. // | - // stuff // | + // Stuff... // | // | -} // -+ y goes out of scope +} // -+ `y` goes out of scope. ``` Adding in our `Foo`: @@ -289,11 +289,12 @@ struct Foo<'a> { } fn main() { - let y = &5; // -+ y goes into scope - let f = Foo { x: y }; // -+ f goes into scope - // stuff // | + let y = &5; // -+ `y` comes into scope. + let f = Foo { x: y }; // -+ `f` comes into scope. // | -} // -+ f and y go out of scope + // Stuff... // | + // | +} // -+ `f` and `y` go out of scope. ``` Our `f` lives within the scope of `y`, so everything works. What if it didn’t? @@ -305,16 +306,16 @@ struct Foo<'a> { } fn main() { - let x; // -+ x goes into scope + let x; // -+ `x` comes into scope. // | { // | - let y = &5; // ---+ y goes into scope - let f = Foo { x: y }; // ---+ f goes into scope - x = &f.x; // | | error here - } // ---+ f and y go out of scope + let y = &5; // ---+ `y` comes into scope. + let f = Foo { x: y }; // ---+ `f` comes into scope. + x = &f.x; // | | This causes an error. + } // ---+ `f` and y go out of scope. // | println!("{}", x); // | -} // -+ x goes out of scope +} // -+ `x` goes out of scope. ``` Whew! As you can see here, the scopes of `f` and `y` are smaller than the scope diff --git a/src/doc/book/loops.md b/src/doc/book/loops.md index e4cb861d3b0f..688e8c552653 100644 --- a/src/doc/book/loops.md +++ b/src/doc/book/loops.md @@ -202,8 +202,8 @@ of the outer loops, you can use labels to specify which loop the `break` or ```rust 'outer: for x in 0..10 { 'inner: for y in 0..10 { - if x % 2 == 0 { continue 'outer; } // continues the loop over x - if y % 2 == 0 { continue 'inner; } // continues the loop over y + if x % 2 == 0 { continue 'outer; } // Continues the loop over `x`. + if y % 2 == 0 { continue 'inner; } // Continues the loop over `y`. println!("x: {}, y: {}", x, y); } } diff --git a/src/doc/book/macros.md b/src/doc/book/macros.md index 78fe07ec1be1..7f52b33948ee 100644 --- a/src/doc/book/macros.md +++ b/src/doc/book/macros.md @@ -533,33 +533,33 @@ An example: ```rust macro_rules! m1 { () => (()) } -// visible here: m1 +// Visible here: `m1`. mod foo { - // visible here: m1 + // Visible here: `m1`. #[macro_export] macro_rules! m2 { () => (()) } - // visible here: m1, m2 + // Visible here: `m1`, `m2`. } -// visible here: m1 +// Visible here: `m1`. macro_rules! m3 { () => (()) } -// visible here: m1, m3 +// Visible here: `m1`, `m3`. #[macro_use] mod bar { - // visible here: m1, m3 + // Visible here: `m1`, `m3`. macro_rules! m4 { () => (()) } - // visible here: m1, m3, m4 + // Visible here: `m1`, `m3`, `m4`. } -// visible here: m1, m3, m4 +// Visible here: `m1`, `m3`, `m4`. # fn main() { } ``` @@ -644,7 +644,7 @@ macro_rules! bct { (1, $p:tt, $($ps:tt),* ; $($ds:tt),*) => (bct!($($ps),*, 1, $p ; $($ds),*)); - // halt on empty data string + // Halt on empty data string: ( $($ps:tt),* ; ) => (()); } @@ -694,7 +694,7 @@ Like this: assert!(true); assert_eq!(5, 3 + 2); -// nope :( +// Nope :( assert!(5 < 3); assert_eq!(5, 3); diff --git a/src/doc/book/mutability.md b/src/doc/book/mutability.md index a0a49d55e105..18017cc4a5e5 100644 --- a/src/doc/book/mutability.md +++ b/src/doc/book/mutability.md @@ -6,7 +6,7 @@ status: ```rust,ignore let x = 5; -x = 6; // error! +x = 6; // Error! ``` We can introduce mutability with the `mut` keyword: @@ -14,7 +14,7 @@ We can introduce mutability with the `mut` keyword: ```rust let mut x = 5; -x = 6; // no problem! +x = 6; // No problem! ``` This is a mutable [variable binding][vb]. When a binding is mutable, it means @@ -136,7 +136,7 @@ some fields mutable and some immutable: ```rust,ignore struct Point { x: i32, - mut y: i32, // nope + mut y: i32, // Nope. } ``` @@ -154,7 +154,7 @@ a.x = 10; let b = Point { x: 5, y: 6}; -b.x = 10; // error: cannot assign to immutable field `b.x` +b.x = 10; // Error: cannot assign to immutable field `b.x`. ``` [struct]: structs.html diff --git a/src/doc/book/no-stdlib.md b/src/doc/book/no-stdlib.md index 2604ca8d4cab..a06de35c0ce6 100644 --- a/src/doc/book/no-stdlib.md +++ b/src/doc/book/no-stdlib.md @@ -41,10 +41,10 @@ in the same format as C: #![feature(start)] #![no_std] -// Pull in the system libc library for what crt0.o likely requires +// Pull in the system libc library for what crt0.o likely requires. extern crate libc; -// Entry point for this program +// Entry point for this program. #[start] fn start(_argc: isize, _argv: *const *const u8) -> isize { 0 @@ -84,10 +84,10 @@ compiler's name mangling too: #![no_std] #![no_main] -// Pull in the system libc library for what crt0.o likely requires +// Pull in the system libc library for what crt0.o likely requires. extern crate libc; -// Entry point for this program +// Entry point for this program. #[no_mangle] // ensure that this symbol is called `main` in the output pub extern fn main(_argc: i32, _argv: *const *const u8) -> i32 { 0 diff --git a/src/doc/book/operators-and-overloading.md b/src/doc/book/operators-and-overloading.md index 424e2cda6157..78ff871046ef 100644 --- a/src/doc/book/operators-and-overloading.md +++ b/src/doc/book/operators-and-overloading.md @@ -69,7 +69,7 @@ impl Add for Point { type Output = f64; fn add(self, rhs: i32) -> f64 { - // add an i32 to a Point and get an f64 + // Add an i32 to a Point and get an f64. # 1.0 } } diff --git a/src/doc/book/ownership.md b/src/doc/book/ownership.md index a711397b211d..11eda399adc9 100644 --- a/src/doc/book/ownership.md +++ b/src/doc/book/ownership.md @@ -107,7 +107,7 @@ try to use something after we’ve passed it as an argument: ```rust,ignore fn take(v: Vec) { - // what happens here isn’t important. + // What happens here isn’t important. } let v = vec![1, 2, 3]; @@ -264,9 +264,9 @@ Of course, if we had to hand ownership back with every function we wrote: ```rust fn foo(v: Vec) -> Vec { - // do stuff with v + // Do stuff with `v`. - // hand back ownership + // Hand back ownership. v } ``` @@ -275,9 +275,9 @@ This would get very tedious. It gets worse the more things we want to take owner ```rust fn foo(v1: Vec, v2: Vec) -> (Vec, Vec, i32) { - // do stuff with v1 and v2 + // Do stuff with `v1` and `v2`. - // hand back ownership, and the result of our function + // Hand back ownership, and the result of our function. (v1, v2, 42) } diff --git a/src/doc/book/patterns.md b/src/doc/book/patterns.md index 910b13754767..b50fa01b8e2b 100644 --- a/src/doc/book/patterns.md +++ b/src/doc/book/patterns.md @@ -163,7 +163,7 @@ ignore parts of a larger structure: ```rust fn coordinate() -> (i32, i32, i32) { - // generate and return some sort of triple tuple + // Generate and return some sort of triple tuple. # (1, 2, 3) } @@ -182,7 +182,7 @@ let tuple: (u32, String) = (5, String::from("five")); // Here, tuple is moved, because the String moved: let (x, _s) = tuple; -// The next line would give "error: use of partially moved value: `tuple`" +// The next line would give "error: use of partially moved value: `tuple`". // println!("Tuple is: {:?}", tuple); // However, diff --git a/src/doc/book/primitive-types.md b/src/doc/book/primitive-types.md index ea0bdf29fcc4..c4169d64ccc6 100644 --- a/src/doc/book/primitive-types.md +++ b/src/doc/book/primitive-types.md @@ -54,9 +54,9 @@ bigger numbers. If a number literal has nothing to cause its type to be inferred, it defaults: ```rust -let x = 42; // x has type i32 +let x = 42; // `x` has type `i32`. -let y = 1.0; // y has type f64 +let y = 1.0; // `y` has type `f64`. ``` Here’s a list of the different numeric types, with links to their documentation @@ -177,8 +177,8 @@ length of the slice: ```rust let a = [0, 1, 2, 3, 4]; -let complete = &a[..]; // A slice containing all of the elements in a -let middle = &a[1..4]; // A slice of a: only the elements 1, 2, and 3 +let complete = &a[..]; // A slice containing all of the elements in `a`. +let middle = &a[1..4]; // A slice of `a`: only the elements `1`, `2`, and `3`. ``` Slices have type `&[T]`. We’ll talk about that `T` when we cover @@ -264,8 +264,8 @@ You can disambiguate a single-element tuple from a value in parentheses with a comma: ```rust -(0,); // single-element tuple -(0); // zero in parentheses +(0,); // A single-element tuple. +(0); // A zero in parentheses. ``` ## Tuple Indexing diff --git a/src/doc/book/raw-pointers.md b/src/doc/book/raw-pointers.md index ae100aec3b51..2386475d15ea 100644 --- a/src/doc/book/raw-pointers.md +++ b/src/doc/book/raw-pointers.md @@ -101,11 +101,11 @@ programmer *must* guarantee this. The recommended method for the conversion is: ```rust -// explicit cast +// Explicit cast: let i: u32 = 1; let p_imm: *const u32 = &i as *const u32; -// implicit coercion +// Implicit coercion: let mut m: u32 = 2; let p_mut: *mut u32 = &mut m; diff --git a/src/doc/book/references-and-borrowing.md b/src/doc/book/references-and-borrowing.md index 1e2f061b0674..6c9c4fa7dd4b 100644 --- a/src/doc/book/references-and-borrowing.md +++ b/src/doc/book/references-and-borrowing.md @@ -46,9 +46,9 @@ like this: ```rust fn foo(v1: Vec, v2: Vec) -> (Vec, Vec, i32) { - // do stuff with v1 and v2 + // Do stuff with `v1` and `v2`. - // hand back ownership, and the result of our function + // Hand back ownership, and the result of our function. (v1, v2, 42) } @@ -63,9 +63,9 @@ the first step: ```rust fn foo(v1: &Vec, v2: &Vec) -> i32 { - // do stuff with v1 and v2 + // Do stuff with `v1` and `v2`. - // return the answer + // Return the answer. 42 } @@ -74,7 +74,7 @@ let v2 = vec![1, 2, 3]; let answer = foo(&v1, &v2); -// we can use v1 and v2 here! +// We can use `v1` and `v2` here! ``` A more concrete example: @@ -88,10 +88,10 @@ fn main() { // Borrow two vectors and sum them. // This kind of borrowing does not allow mutation through the borrowed reference. fn foo(v1: &Vec, v2: &Vec) -> i32 { - // do stuff with v1 and v2 + // Do stuff with `v1` and `v2`. let s1 = sum_vec(v1); let s2 = sum_vec(v2); - // return the answer + // Return the answer. s1 + s2 } @@ -248,12 +248,12 @@ scopes look like this: fn main() { let mut x = 5; - let y = &mut x; // -+ &mut borrow of x starts here + let y = &mut x; // -+ &mut borrow of `x` starts here. // | *y += 1; // | // | - println!("{}", x); // -+ - try to borrow x here -} // -+ &mut borrow of x ends here + println!("{}", x); // -+ - Try to borrow `x` here. +} // -+ &mut borrow of `x` ends here. ``` @@ -265,11 +265,11 @@ So when we add the curly braces: let mut x = 5; { - let y = &mut x; // -+ &mut borrow starts here + let y = &mut x; // -+ &mut borrow starts here. *y += 1; // | -} // -+ ... and ends here +} // -+ ... and ends here. -println!("{}", x); // <- try to borrow x here +println!("{}", x); // <- Try to borrow `x` here. ``` There’s no problem. Our mutable borrow goes out of scope before we create an diff --git a/src/doc/book/strings.md b/src/doc/book/strings.md index 135778c38b50..6af15d876836 100644 --- a/src/doc/book/strings.md +++ b/src/doc/book/strings.md @@ -83,10 +83,10 @@ converted using `&*`. ```rust,no_run use std::net::TcpStream; -TcpStream::connect("192.168.0.1:3000"); // &str parameter +TcpStream::connect("192.168.0.1:3000"); // Parameter is of type &str. let addr_string = "192.168.0.1:3000".to_string(); -TcpStream::connect(&*addr_string); // convert addr_string to &str +TcpStream::connect(&*addr_string); // Convert `addr_string` to &str. ``` Viewing a `String` as a `&str` is cheap, but converting the `&str` to a @@ -138,7 +138,7 @@ You can get something similar to an index like this: ```rust # let hachiko = "忠犬ハチ公"; -let dog = hachiko.chars().nth(1); // kinda like hachiko[1] +let dog = hachiko.chars().nth(1); // Kinda like `hachiko[1]`. ``` This emphasizes that we have to walk from the beginning of the list of `chars`. diff --git a/src/doc/book/structs.md b/src/doc/book/structs.md index d6960b10b080..cfd00cf997e0 100644 --- a/src/doc/book/structs.md +++ b/src/doc/book/structs.md @@ -82,9 +82,9 @@ fn main() { point.x = 5; - let point = point; // now immutable + let point = point; // `point` is now immutable. - point.y = 6; // this causes an error + point.y = 6; // This causes an error. } ``` @@ -234,10 +234,10 @@ rather than positions. You can define a `struct` with no members at all: ```rust -struct Electron {} // use empty braces... -struct Proton; // ...or just a semicolon +struct Electron {} // Use empty braces... +struct Proton; // ...or just a semicolon. -// whether you declared the struct with braces or not, do the same when creating one +// Whether you declared the struct with braces or not, do the same when creating one. let x = Electron {}; let y = Proton; ``` diff --git a/src/doc/book/testing.md b/src/doc/book/testing.md index 0e6cdb8f09dd..14a05102b9a0 100644 --- a/src/doc/book/testing.md +++ b/src/doc/book/testing.md @@ -23,7 +23,11 @@ $ cd adder Cargo will automatically generate a simple test when you make a new project. Here's the contents of `src/lib.rs`: -```rust +```rust,ignore +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# #[cfg(test)] mod tests { #[test] @@ -32,6 +36,18 @@ mod tests { } ``` +For now, let's remove the `mod` bit, and focus on just the function: + +```rust,ignore +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# +#[test] +fn it_works() { +} +``` + Note the `#[test]`. This attribute indicates that this is a test function. It currently has no body. That's good enough to pass! We can run the tests with `cargo test`: @@ -39,10 +55,11 @@ currently has no body. That's good enough to pass! We can run the tests with ```bash $ cargo test Compiling adder v0.1.0 (file:///home/you/projects/adder) - Running target/debug/deps/adder-91b3e234d4ed382a + Finished debug [unoptimized + debuginfo] target(s) in 0.15 secs + Running target/debug/deps/adder-941f01916ca4a642 running 1 test -test tests::it_works ... ok +test it_works ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured @@ -58,13 +75,15 @@ for the test we wrote, and another for documentation tests. We'll talk about those later. For now, see this line: ```text -test tests::it_works ... ok +test it_works ... ok ``` Note the `it_works`. This comes from the name of our function: ```rust +# fn main() { fn it_works() { +} # } ``` @@ -77,8 +96,11 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured So why does our do-nothing test pass? Any test which doesn't `panic!` passes, and any test that does `panic!` fails. Let's make our test fail: -```rust -# fn main() {} +```rust,ignore +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# #[test] fn it_works() { assert!(false); @@ -92,19 +114,21 @@ run our tests again: ```bash $ cargo test Compiling adder v0.1.0 (file:///home/you/projects/adder) - Running target/debug/deps/adder-91b3e234d4ed382a + Finished debug [unoptimized + debuginfo] target(s) in 0.17 secs + Running target/debug/deps/adder-941f01916ca4a642 running 1 test -test tests::it_works ... FAILED +test it_works ... FAILED failures: ----- test::it_works stdout ---- - thread 'tests::it_works' panicked at 'assertion failed: false', src/lib.rs:5 +---- it_works stdout ---- + thread 'it_works' panicked at 'assertion failed: false', src/lib.rs:5 +note: Run with `RUST_BACKTRACE=1` for a backtrace. failures: - tests::it_works + it_works test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured @@ -114,7 +138,7 @@ error: test failed Rust indicates that our test failed: ```text -test tests::it_works ... FAILED +test it_works ... FAILED ``` And that's reflected in the summary line: @@ -147,8 +171,11 @@ This is useful if you want to integrate `cargo test` into other tooling. We can invert our test's failure with another attribute: `should_panic`: -```rust -# fn main() {} +```rust,ignore +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# #[test] #[should_panic] fn it_works() { @@ -161,10 +188,11 @@ This test will now succeed if we `panic!` and fail if we complete. Let's try it: ```bash $ cargo test Compiling adder v0.1.0 (file:///home/you/projects/adder) - Running target/debug/deps/adder-91b3e234d4ed382a + Finished debug [unoptimized + debuginfo] target(s) in 0.17 secs + Running target/debug/deps/adder-941f01916ca4a642 running 1 test -test tests::it_works ... ok +test it_works ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured @@ -178,8 +206,11 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured Rust provides another macro, `assert_eq!`, that compares two arguments for equality: -```rust -# fn main() {} +```rust,ignore +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# #[test] #[should_panic] fn it_works() { @@ -193,10 +224,11 @@ passes: ```bash $ cargo test Compiling adder v0.1.0 (file:///home/you/projects/adder) - Running target/debug/deps/adder-91b3e234d4ed382a + Finished debug [unoptimized + debuginfo] target(s) in 0.21 secs + Running target/debug/deps/adder-941f01916ca4a642 running 1 test -test tests::it_works ... ok +test it_works ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured @@ -213,8 +245,11 @@ parameter can be added to the `should_panic` attribute. The test harness will make sure that the failure message contains the provided text. A safer version of the example above would be: -```rust -# fn main() {} +```rust,ignore +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# #[test] #[should_panic(expected = "assertion failed")] fn it_works() { @@ -225,7 +260,10 @@ fn it_works() { That's all there is to the basics! Let's write one 'real' test: ```rust,ignore -# fn main() {} +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# pub fn add_two(a: i32) -> i32 { a + 2 } @@ -244,8 +282,15 @@ some known arguments and compare it to the expected output. Sometimes a few specific tests can be very time-consuming to execute. These can be disabled by default by using the `ignore` attribute: -```rust -# fn main() {} +```rust,ignore +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# +pub fn add_two(a: i32) -> i32 { + a + 2 +} + #[test] fn it_works() { assert_eq!(4, add_two(2)); @@ -254,7 +299,7 @@ fn it_works() { #[test] #[ignore] fn expensive_test() { - // code that takes an hour to run + // Code that takes an hour to run... } ``` @@ -264,7 +309,8 @@ not: ```bash $ cargo test Compiling adder v0.1.0 (file:///home/you/projects/adder) - Running target/debug/deps/adder-91b3e234d4ed382a + Finished debug [unoptimized + debuginfo] target(s) in 0.20 secs + Running target/debug/deps/adder-941f01916ca4a642 running 2 tests test expensive_test ... ignored @@ -283,7 +329,8 @@ The expensive tests can be run explicitly using `cargo test -- --ignored`: ```bash $ cargo test -- --ignored - Running target/debug/deps/adder-91b3e234d4ed382a + Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs + Running target/debug/deps/adder-941f01916ca4a642 running 1 test test expensive_test ... ok @@ -310,7 +357,10 @@ was missing from our last example. Let's explain what this does. The idiomatic way of writing our example looks like this: ```rust,ignore -# fn main() {} +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# pub fn add_two(a: i32) -> i32 { a + 2 } @@ -339,7 +389,10 @@ a large module, and so this is a common use of globs. Let's change our `src/lib.rs` to make use of it: ```rust,ignore -# fn main() {} +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# pub fn add_two(a: i32) -> i32 { a + 2 } @@ -389,9 +442,14 @@ To write an integration test, let's make a `tests` directory and put a `tests/integration_test.rs` file inside with this as its contents: ```rust,ignore +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# +# // Sadly, this code will not work in play.rust-lang.org, because we have no +# // crate adder to import. You'll need to try this part on your own machine. extern crate adder; -# fn main() {} #[test] fn it_works() { assert_eq!(4, adder::add_two(2)); @@ -452,7 +510,10 @@ running examples in your documentation (**note:** this only works in library crates, not binary crates). Here's a fleshed-out `src/lib.rs` with examples: ```rust,ignore -# fn main() {} +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# //! The `adder` crate provides functions that add numbers to other numbers. //! //! # Examples @@ -525,3 +586,45 @@ you add more examples. We haven’t covered all of the details with writing documentation tests. For more, please see the [Documentation chapter](documentation.html). + +# Testing and concurrency + +One thing that is important to note when writing tests are run concurrently +using threads. For this reason you should take care that your tests are written +in such a way as to not depend on each-other, or on any shared state. "Shared +state" can also include the environment, such as the current working directory, +or environment variables. + +If this is an issue it is possible to control this concurrency, either by +setting the environment variable `RUST_TEST_THREADS`, or by passing the argument +`--test-threads` to the tests: + +```bash +$ RUST_TEST_THREADS=1 cargo test # Run tests with no concurrency +... +$ cargo test -- --test-threads=1 # Same as above +... +``` + +# Test output + +By default Rust's test library captures and discards output to standard +out/error, e.g. output from `println!()`. This too can be controlled using the +environment or a switch: + + +```bash +$ RUST_TEST_NOCAPTURE=1 cargo test # Preserve stdout/stderr +... +$ cargo test -- --nocapture # Same as above +... +``` + +However a better method avoiding capture is to use logging rather than raw +output. Rust has a [standard logging API][log], which provides a frontend to +multiple logging implementations. This can be used in conjunction with the +default [env_logger] to output any debugging information in a manner that can be +controlled at runtime. + +[log]: https://crates.io/crates/log +[env_logger]: https://crates.io/crates/env_logger diff --git a/src/doc/book/trait-objects.md b/src/doc/book/trait-objects.md index b1aee579aabc..a0396a75fa26 100644 --- a/src/doc/book/trait-objects.md +++ b/src/doc/book/trait-objects.md @@ -221,8 +221,8 @@ struct FooVtable { // u8: fn call_method_on_u8(x: *const ()) -> String { - // the compiler guarantees that this function is only called - // with `x` pointing to a u8 + // The compiler guarantees that this function is only called + // with `x` pointing to a u8. let byte: &u8 = unsafe { &*(x as *const u8) }; byte.method() @@ -233,7 +233,7 @@ static Foo_for_u8_vtable: FooVtable = FooVtable { size: 1, align: 1, - // cast to a function pointer + // Cast to a function pointer: method: call_method_on_u8 as fn(*const ()) -> String, }; @@ -241,8 +241,8 @@ static Foo_for_u8_vtable: FooVtable = FooVtable { // String: fn call_method_on_String(x: *const ()) -> String { - // the compiler guarantees that this function is only called - // with `x` pointing to a String + // The compiler guarantees that this function is only called + // with `x` pointing to a String. let string: &String = unsafe { &*(x as *const String) }; string.method() @@ -250,7 +250,7 @@ fn call_method_on_String(x: *const ()) -> String { static Foo_for_String_vtable: FooVtable = FooVtable { destructor: /* compiler magic */, - // values for a 64-bit computer, halve them for 32-bit ones + // Values for a 64-bit computer, halve them for 32-bit ones. size: 24, align: 8, @@ -278,17 +278,17 @@ let x: u8 = 1; // let b: &Foo = &a; let b = TraitObject { - // store the data + // Store the data: data: &a, - // store the methods + // Store the methods: vtable: &Foo_for_String_vtable }; // let y: &Foo = x; let y = TraitObject { - // store the data + // Store the data: data: &x, - // store the methods + // Store the methods: vtable: &Foo_for_u8_vtable }; diff --git a/src/doc/book/traits.md b/src/doc/book/traits.md index b0d954adf677..4747869b65c7 100644 --- a/src/doc/book/traits.md +++ b/src/doc/book/traits.md @@ -243,28 +243,22 @@ to know more about [operator traits][operators-and-overloading]. # Rules for implementing traits So far, we’ve only added trait implementations to structs, but you can -implement a trait for any type. So technically, we _could_ implement `HasArea` -for `i32`: +implement a trait for any type such as `f32`: ```rust -trait HasArea { - fn area(&self) -> f64; +trait ApproxEqual { + fn approx_equal(&self, other: &Self) -> bool; } - -impl HasArea for i32 { - fn area(&self) -> f64 { - println!("this is silly"); - - *self as f64 +impl ApproxEqual for f32 { + fn approx_equal(&self, other: &Self) -> bool { + // Appropriate for `self` and `other` being close to 1.0. + (self - other).abs() <= ::std::f32::EPSILON } } -5.area(); +println!("{}", 1.0.approx_equal(&1.00000001)); ``` -It is considered poor style to implement methods on such primitive types, even -though it is possible. - This may seem like the Wild West, but there are two restrictions around implementing traits that prevent this from getting out of hand. The first is that if the trait isn’t defined in your scope, it doesn’t apply. Here’s an @@ -276,9 +270,9 @@ won’t have its methods: ```rust,ignore let mut f = std::fs::File::create("foo.txt").expect("Couldn’t create foo.txt"); -let buf = b"whatever"; // byte string literal. buf: &[u8; 8] +let buf = b"whatever"; // buf: &[u8; 8], a byte string literal. let result = f.write(buf); -# result.unwrap(); // ignore the error +# result.unwrap(); // Ignore the error. ``` Here’s the error: @@ -297,7 +291,7 @@ use std::io::Write; let mut f = std::fs::File::create("foo.txt").expect("Couldn’t create foo.txt"); let buf = b"whatever"; let result = f.write(buf); -# result.unwrap(); // ignore the error +# result.unwrap(); // Ignore the error. ``` This will compile without error. @@ -419,14 +413,14 @@ impl ConvertTo for i32 { fn convert(&self) -> i64 { *self as i64 } } -// can be called with T == i32 +// Can be called with T == i32. fn normal>(x: &T) -> i64 { x.convert() } -// can be called with T == i64 +// Can be called with T == i64. fn inverse(x: i32) -> T - // this is using ConvertTo as if it were "ConvertTo" + // This is using ConvertTo as if it were "ConvertTo". where i32: ConvertTo { x.convert() } @@ -476,15 +470,15 @@ impl Foo for OverrideDefault { fn is_invalid(&self) -> bool { println!("Called OverrideDefault.is_invalid!"); - true // overrides the expected value of is_invalid() + true // Overrides the expected value of `is_invalid()`. } } let default = UseDefault; -assert!(!default.is_invalid()); // prints "Called UseDefault.is_valid." +assert!(!default.is_invalid()); // Prints "Called UseDefault.is_valid." let over = OverrideDefault; -assert!(over.is_invalid()); // prints "Called OverrideDefault.is_invalid!" +assert!(over.is_invalid()); // Prints "Called OverrideDefault.is_invalid!" ``` # Inheritance diff --git a/src/doc/book/unsafe.md b/src/doc/book/unsafe.md index 9cab586b82c4..a272afa70bb1 100644 --- a/src/doc/book/unsafe.md +++ b/src/doc/book/unsafe.md @@ -12,7 +12,7 @@ four contexts. The first one is to mark a function as unsafe: ```rust unsafe fn danger_will_robinson() { - // scary stuff + // Scary stuff... } ``` @@ -23,7 +23,7 @@ The second use of `unsafe` is an unsafe block: ```rust unsafe { - // scary stuff + // Scary stuff... } ``` diff --git a/src/doc/book/variable-bindings.md b/src/doc/book/variable-bindings.md index 03f17371de68..54316649c715 100644 --- a/src/doc/book/variable-bindings.md +++ b/src/doc/book/variable-bindings.md @@ -194,7 +194,7 @@ fn main() { let y: i32 = 3; println!("The value of x is {} and value of y is {}", x, y); } - println!("The value of x is {} and value of y is {}", x, y); // This won't work + println!("The value of x is {} and value of y is {}", x, y); // This won't work. } ``` @@ -207,7 +207,7 @@ Instead we get this error: $ cargo build Compiling hello v0.1.0 (file:///home/you/projects/hello_world) main.rs:7:62: 7:63 error: unresolved name `y`. Did you mean `x`? [E0425] -main.rs:7 println!("The value of x is {} and value of y is {}", x, y); // This won't work +main.rs:7 println!("The value of x is {} and value of y is {}", x, y); // This won't work. ^ note: in expansion of format_args! :2:25: 2:56 note: expansion site @@ -229,13 +229,13 @@ scope will override the previous binding. ```rust let x: i32 = 8; { - println!("{}", x); // Prints "8" + println!("{}", x); // Prints "8". let x = 12; - println!("{}", x); // Prints "12" + println!("{}", x); // Prints "12". } -println!("{}", x); // Prints "8" +println!("{}", x); // Prints "8". let x = 42; -println!("{}", x); // Prints "42" +println!("{}", x); // Prints "42". ``` Shadowing and mutable bindings may appear as two sides of the same coin, but @@ -249,8 +249,8 @@ by any means. ```rust let mut x: i32 = 1; x = 7; -let x = x; // x is now immutable and is bound to 7 +let x = x; // `x` is now immutable and is bound to `7`. let y = 4; -let y = "I can also be bound to text!"; // y is now of a different type +let y = "I can also be bound to text!"; // `y` is now of a different type. ``` diff --git a/src/doc/book/vectors.md b/src/doc/book/vectors.md index cb6781cdf28f..b948a54f44a5 100644 --- a/src/doc/book/vectors.md +++ b/src/doc/book/vectors.md @@ -17,7 +17,7 @@ situation, this is just convention.) There’s an alternate form of `vec!` for repeating an initial value: ```rust -let v = vec![0; 10]; // ten zeroes +let v = vec![0; 10]; // A vector of ten zeroes. ``` Vectors store their contents as contiguous arrays of `T` on the heap. This means @@ -46,10 +46,10 @@ let v = vec![1, 2, 3, 4, 5]; let i: usize = 0; let j: i32 = 0; -// works +// Works: v[i]; -// doesn’t +// Doesn’t: v[j]; ``` diff --git a/src/grammar/README.md b/src/grammar/README.md index 6e0cf17a8804..cd2dd38de36a 100644 --- a/src/grammar/README.md +++ b/src/grammar/README.md @@ -1,14 +1,18 @@ -Reference grammar. +# Reference grammar. Uses [antlr4](http://www.antlr.org/) and a custom Rust tool to compare -ASTs/token streams generated. You can use the `check-lexer` make target to +ASTs/token streams generated. You can use the `make check-lexer` target to run all of the available tests. -To use manually: +The build of the rust part is included with `make tidy` and can be run with `make check-build-lexer-verifier`. + +# Manual build + +To use manually, assuming antlr4 ist installed at `/usr/share/java/antlr-complete.jar`: ``` antlr4 RustLexer.g4 -javac *.java +javac -classpath /usr/share/java/antlr-complete.jar *.java rustc -O verify.rs for file in ../*/**.rs; do echo $file; @@ -18,3 +22,12 @@ done Note That the `../*/**.rs` glob will match every `*.rs` file in the above directory and all of its recursive children. This is a zsh extension. + + +## Cleanup + +To cleanup you can use a command like this: + +```bash +rm -f verify *.class *.java *.tokens +``` diff --git a/src/grammar/check.sh b/src/grammar/check.sh index 560b6b72471e..70a8f6fca2e5 100755 --- a/src/grammar/check.sh +++ b/src/grammar/check.sh @@ -20,11 +20,11 @@ skipped=0 check() { grep --silent "// ignore-lexer-test" "$1"; - # if it's *not* found... + # if it is *not* found... if [ $? -eq 1 ]; then - cd $2 # This `cd` is so java will pick up RustLexer.class. I couldn't + cd $2 # This `cd` is so java will pick up RustLexer.class. I could not # figure out how to wrangle the CLASSPATH, just adding build/grammar - # didn't seem to have any effect. + # did not seem to have any effect. if $3 RustLexer tokens -tokens < $1 | $4 $1 $5; then echo "pass: $1" passed=`expr $passed + 1` diff --git a/src/grammar/verify.rs b/src/grammar/verify.rs index 884db3418924..48be58f731cd 100644 --- a/src/grammar/verify.rs +++ b/src/grammar/verify.rs @@ -11,6 +11,7 @@ #![feature(plugin, rustc_private)] extern crate syntax; +extern crate syntax_pos; extern crate rustc; #[macro_use] @@ -290,9 +291,10 @@ fn main() { let options = config::basic_options(); let session = session::build_session(options, &DepGraph::new(false), None, - syntax::diagnostics::registry::Registry::new(&[]), + syntax::errors::registry::Registry::new(&[]), Rc::new(DummyCrateStore)); - let filemap = session.parse_sess.codemap().new_filemap(String::from(""), code); + let filemap = session.parse_sess.codemap() + .new_filemap("".to_string(), None, code); let mut lexer = lexer::StringReader::new(session.diagnostic(), filemap); let cm = session.codemap(); diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index bfed8a8e83a5..12809171b743 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -17,7 +17,7 @@ use core::{isize, usize}; #[cfg(not(test))] -use core::intrinsics::{min_align_of, size_of}; +use core::intrinsics::{min_align_of_val, size_of_val}; #[allow(improper_ctypes)] extern "C" { @@ -152,11 +152,12 @@ unsafe fn exchange_free(ptr: *mut u8, old_size: usize, align: usize) { #[cfg(not(test))] #[lang = "box_free"] #[inline] -unsafe fn box_free(ptr: *mut T) { - let size = size_of::(); +unsafe fn box_free(ptr: *mut T) { + let size = size_of_val(&*ptr); + let align = min_align_of_val(&*ptr); // We do not allocate for Box when T is ZST, so deallocation is also not necessary. if size != 0 { - deallocate(ptr as *mut u8, size, min_align_of::()); + deallocate(ptr as *mut u8, size, align); } } diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 71c49ee616cb..24f8e3a2d918 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1499,26 +1499,7 @@ impl ops::DerefMut for Vec { impl FromIterator for Vec { #[inline] fn from_iter>(iter: I) -> Vec { - // Unroll the first iteration, as the vector is going to be - // expanded on this iteration in every case when the iterable is not - // empty, but the loop in extend_desugared() is not going to see the - // vector being full in the few subsequent loop iterations. - // So we get better branch prediction. - let mut iterator = iter.into_iter(); - let mut vector = match iterator.next() { - None => return Vec::new(), - Some(element) => { - let (lower, _) = iterator.size_hint(); - let mut vector = Vec::with_capacity(lower.saturating_add(1)); - unsafe { - ptr::write(vector.get_unchecked_mut(0), element); - vector.set_len(1); - } - vector - } - }; - vector.extend_desugared(iterator); - vector + >::from_iter(iter.into_iter()) } } @@ -1586,36 +1567,64 @@ impl<'a, T> IntoIterator for &'a mut Vec { impl Extend for Vec { #[inline] fn extend>(&mut self, iter: I) { - self.extend_desugared(iter.into_iter()) + self.spec_extend(iter.into_iter()) } } -trait IsTrustedLen : Iterator { - fn trusted_len(&self) -> Option { None } +// Specialization trait used for Vec::from_iter and Vec::extend +trait SpecExtend { + fn from_iter(iter: I) -> Self; + fn spec_extend(&mut self, iter: I); } -impl IsTrustedLen for I where I: Iterator { } -impl IsTrustedLen for I where I: TrustedLen +impl SpecExtend for Vec + where I: Iterator, { - fn trusted_len(&self) -> Option { - let (low, high) = self.size_hint(); + default fn from_iter(mut iterator: I) -> Self { + // Unroll the first iteration, as the vector is going to be + // expanded on this iteration in every case when the iterable is not + // empty, but the loop in extend_desugared() is not going to see the + // vector being full in the few subsequent loop iterations. + // So we get better branch prediction. + let mut vector = match iterator.next() { + None => return Vec::new(), + Some(element) => { + let (lower, _) = iterator.size_hint(); + let mut vector = Vec::with_capacity(lower.saturating_add(1)); + unsafe { + ptr::write(vector.get_unchecked_mut(0), element); + vector.set_len(1); + } + vector + } + }; + vector.spec_extend(iterator); + vector + } + + default fn spec_extend(&mut self, iter: I) { + self.extend_desugared(iter) + } +} + +impl SpecExtend for Vec + where I: TrustedLen, +{ + fn from_iter(iterator: I) -> Self { + let mut vector = Vec::new(); + vector.spec_extend(iterator); + vector + } + + fn spec_extend(&mut self, iterator: I) { + // This is the case for a TrustedLen iterator. + let (low, high) = iterator.size_hint(); if let Some(high_value) = high { debug_assert_eq!(low, high_value, "TrustedLen iterator's size hint is not exact: {:?}", (low, high)); } - high - } -} - -impl Vec { - fn extend_desugared>(&mut self, mut iterator: I) { - // This function should be the moral equivalent of: - // - // for item in iterator { - // self.push(item); - // } - if let Some(additional) = iterator.trusted_len() { + if let Some(additional) = high { self.reserve(additional); unsafe { let mut ptr = self.as_mut_ptr().offset(self.len() as isize); @@ -1628,17 +1637,30 @@ impl Vec { } } } else { - while let Some(element) = iterator.next() { - let len = self.len(); - if len == self.capacity() { - let (lower, _) = iterator.size_hint(); - self.reserve(lower.saturating_add(1)); - } - unsafe { - ptr::write(self.get_unchecked_mut(len), element); - // NB can't overflow since we would have had to alloc the address space - self.set_len(len + 1); - } + self.extend_desugared(iterator) + } + } +} + +impl Vec { + fn extend_desugared>(&mut self, mut iterator: I) { + // This is the case for a general iterator. + // + // This function should be the moral equivalent of: + // + // for item in iterator { + // self.push(item); + // } + while let Some(element) = iterator.next() { + let len = self.len(); + if len == self.capacity() { + let (lower, _) = iterator.size_hint(); + self.reserve(lower.saturating_add(1)); + } + unsafe { + ptr::write(self.get_unchecked_mut(len), element); + // NB can't overflow since we would have had to alloc the address space + self.set_len(len + 1); } } } diff --git a/src/libcompiler_builtins/Cargo.toml b/src/libcompiler_builtins/Cargo.toml index a52873fc326b..9e91e390a572 100644 --- a/src/libcompiler_builtins/Cargo.toml +++ b/src/libcompiler_builtins/Cargo.toml @@ -7,6 +7,7 @@ version = "0.0.0" [lib] name = "compiler_builtins" path = "lib.rs" +test = false [dependencies] core = { path = "../libcore" } diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index e844a158484a..3726eee9a93c 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -51,76 +51,472 @@ extern "rust-intrinsic" { // NB: These intrinsics take raw pointers because they mutate aliased // memory, which is not valid for either `&` or `&mut`. + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange` method by passing + /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) + /// as both the `success` and `failure` parameters. For example, + /// [`AtomicBool::compare_exchange`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). pub fn atomic_cxchg(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange` method by passing + /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) + /// as both the `success` and `failure` parameters. For example, + /// [`AtomicBool::compare_exchange`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). pub fn atomic_cxchg_acq(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange` method by passing + /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html) + /// as the `success` and + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as the `failure` parameters. For example, + /// [`AtomicBool::compare_exchange`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). pub fn atomic_cxchg_rel(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange` method by passing + /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html) + /// as the `success` and + /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) + /// as the `failure` parameters. For example, + /// [`AtomicBool::compare_exchange`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). pub fn atomic_cxchg_acqrel(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange` method by passing + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as both the `success` and `failure` parameters. For example, + /// [`AtomicBool::compare_exchange`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). pub fn atomic_cxchg_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange` method by passing + /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) + /// as the `success` and + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as the `failure` parameters. For example, + /// [`AtomicBool::compare_exchange`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). pub fn atomic_cxchg_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange` method by passing + /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) + /// as the `success` and + /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) + /// as the `failure` parameters. For example, + /// [`AtomicBool::compare_exchange`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). pub fn atomic_cxchg_failacq(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange` method by passing + /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) + /// as the `success` and + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as the `failure` parameters. For example, + /// [`AtomicBool::compare_exchange`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). pub fn atomic_cxchg_acq_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange` method by passing + /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html) + /// as the `success` and + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as the `failure` parameters. For example, + /// [`AtomicBool::compare_exchange`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). pub fn atomic_cxchg_acqrel_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing + /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) + /// as both the `success` and `failure` parameters. For example, + /// [`AtomicBool::compare_exchange_weak`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). pub fn atomic_cxchgweak(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing + /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) + /// as both the `success` and `failure` parameters. For example, + /// [`AtomicBool::compare_exchange_weak`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). pub fn atomic_cxchgweak_acq(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing + /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html) + /// as the `success` and + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as the `failure` parameters. For example, + /// [`AtomicBool::compare_exchange_weak`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). pub fn atomic_cxchgweak_rel(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing + /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html) + /// as the `success` and + /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) + /// as the `failure` parameters. For example, + /// [`AtomicBool::compare_exchange_weak`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). pub fn atomic_cxchgweak_acqrel(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as both the `success` and `failure` parameters. For example, + /// [`AtomicBool::compare_exchange_weak`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). pub fn atomic_cxchgweak_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing + /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) + /// as the `success` and + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as the `failure` parameters. For example, + /// [`AtomicBool::compare_exchange_weak`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). pub fn atomic_cxchgweak_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing + /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) + /// as the `success` and + /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) + /// as the `failure` parameters. For example, + /// [`AtomicBool::compare_exchange_weak`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). pub fn atomic_cxchgweak_failacq(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing + /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) + /// as the `success` and + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as the `failure` parameters. For example, + /// [`AtomicBool::compare_exchange_weak`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). pub fn atomic_cxchgweak_acq_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing + /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html) + /// as the `success` and + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as the `failure` parameters. For example, + /// [`AtomicBool::compare_exchange_weak`] + /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). pub fn atomic_cxchgweak_acqrel_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); + /// Loads the current value of the pointer. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `load` method by passing + /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::load`](../../std/sync/atomic/struct.AtomicBool.html#method.load). pub fn atomic_load(src: *const T) -> T; + /// Loads the current value of the pointer. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `load` method by passing + /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::load`](../../std/sync/atomic/struct.AtomicBool.html#method.load). pub fn atomic_load_acq(src: *const T) -> T; + /// Loads the current value of the pointer. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `load` method by passing + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::load`](../../std/sync/atomic/struct.AtomicBool.html#method.load). pub fn atomic_load_relaxed(src: *const T) -> T; pub fn atomic_load_unordered(src: *const T) -> T; + /// Stores the value at the specified memory location. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `store` method by passing + /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::store`](../../std/sync/atomic/struct.AtomicBool.html#method.store). pub fn atomic_store(dst: *mut T, val: T); + /// Stores the value at the specified memory location. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `store` method by passing + /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::store`](../../std/sync/atomic/struct.AtomicBool.html#method.store). pub fn atomic_store_rel(dst: *mut T, val: T); + /// Stores the value at the specified memory location. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `store` method by passing + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::store`](../../std/sync/atomic/struct.AtomicBool.html#method.store). pub fn atomic_store_relaxed(dst: *mut T, val: T); pub fn atomic_store_unordered(dst: *mut T, val: T); + /// Stores the value at the specified memory location, returning the old value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `swap` method by passing + /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::swap`](../../std/sync/atomic/struct.AtomicBool.html#method.swap). pub fn atomic_xchg(dst: *mut T, src: T) -> T; + /// Stores the value at the specified memory location, returning the old value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `swap` method by passing + /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::swap`](../../std/sync/atomic/struct.AtomicBool.html#method.swap). pub fn atomic_xchg_acq(dst: *mut T, src: T) -> T; + /// Stores the value at the specified memory location, returning the old value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `swap` method by passing + /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::swap`](../../std/sync/atomic/struct.AtomicBool.html#method.swap). pub fn atomic_xchg_rel(dst: *mut T, src: T) -> T; + /// Stores the value at the specified memory location, returning the old value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `swap` method by passing + /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::swap`](../../std/sync/atomic/struct.AtomicBool.html#method.swap). pub fn atomic_xchg_acqrel(dst: *mut T, src: T) -> T; + /// Stores the value at the specified memory location, returning the old value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `swap` method by passing + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::swap`](../../std/sync/atomic/struct.AtomicBool.html#method.swap). pub fn atomic_xchg_relaxed(dst: *mut T, src: T) -> T; + /// Add to the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_add` method by passing + /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicIsize::fetch_add`](../../std/sync/atomic/struct.AtomicIsize.html#method.fetch_add). pub fn atomic_xadd(dst: *mut T, src: T) -> T; + /// Add to the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_add` method by passing + /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicIsize::fetch_add`](../../std/sync/atomic/struct.AtomicIsize.html#method.fetch_add). pub fn atomic_xadd_acq(dst: *mut T, src: T) -> T; + /// Add to the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_add` method by passing + /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicIsize::fetch_add`](../../std/sync/atomic/struct.AtomicIsize.html#method.fetch_add). pub fn atomic_xadd_rel(dst: *mut T, src: T) -> T; + /// Add to the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_add` method by passing + /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicIsize::fetch_add`](../../std/sync/atomic/struct.AtomicIsize.html#method.fetch_add). pub fn atomic_xadd_acqrel(dst: *mut T, src: T) -> T; + /// Add to the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_add` method by passing + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicIsize::fetch_add`](../../std/sync/atomic/struct.AtomicIsize.html#method.fetch_add). pub fn atomic_xadd_relaxed(dst: *mut T, src: T) -> T; + /// Subtract from the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_sub` method by passing + /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicIsize::fetch_sub`](../../std/sync/atomic/struct.AtomicIsize.html#method.fetch_sub). pub fn atomic_xsub(dst: *mut T, src: T) -> T; + /// Subtract from the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_sub` method by passing + /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicIsize::fetch_sub`](../../std/sync/atomic/struct.AtomicIsize.html#method.fetch_sub). pub fn atomic_xsub_acq(dst: *mut T, src: T) -> T; + /// Subtract from the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_sub` method by passing + /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicIsize::fetch_sub`](../../std/sync/atomic/struct.AtomicIsize.html#method.fetch_sub). pub fn atomic_xsub_rel(dst: *mut T, src: T) -> T; + /// Subtract from the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_sub` method by passing + /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicIsize::fetch_sub`](../../std/sync/atomic/struct.AtomicIsize.html#method.fetch_sub). pub fn atomic_xsub_acqrel(dst: *mut T, src: T) -> T; + /// Subtract from the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_sub` method by passing + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicIsize::fetch_sub`](../../std/sync/atomic/struct.AtomicIsize.html#method.fetch_sub). pub fn atomic_xsub_relaxed(dst: *mut T, src: T) -> T; + /// Bitwise and with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_and` method by passing + /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_and`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_and). pub fn atomic_and(dst: *mut T, src: T) -> T; + /// Bitwise and with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_and` method by passing + /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_and`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_and). pub fn atomic_and_acq(dst: *mut T, src: T) -> T; + /// Bitwise and with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_and` method by passing + /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_and`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_and). pub fn atomic_and_rel(dst: *mut T, src: T) -> T; + /// Bitwise and with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_and` method by passing + /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_and`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_and). pub fn atomic_and_acqrel(dst: *mut T, src: T) -> T; + /// Bitwise and with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_and` method by passing + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_and`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_and). pub fn atomic_and_relaxed(dst: *mut T, src: T) -> T; + /// Bitwise nand with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic::AtomicBool` type via the `fetch_nand` method by passing + /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_nand`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_nand). pub fn atomic_nand(dst: *mut T, src: T) -> T; + /// Bitwise nand with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic::AtomicBool` type via the `fetch_nand` method by passing + /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_nand`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_nand). pub fn atomic_nand_acq(dst: *mut T, src: T) -> T; + /// Bitwise nand with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic::AtomicBool` type via the `fetch_nand` method by passing + /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_nand`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_nand). pub fn atomic_nand_rel(dst: *mut T, src: T) -> T; + /// Bitwise nand with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic::AtomicBool` type via the `fetch_nand` method by passing + /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_nand`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_nand). pub fn atomic_nand_acqrel(dst: *mut T, src: T) -> T; + /// Bitwise nand with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic::AtomicBool` type via the `fetch_nand` method by passing + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_nand`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_nand). pub fn atomic_nand_relaxed(dst: *mut T, src: T) -> T; + /// Bitwise or with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_or` method by passing + /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_or`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_or). pub fn atomic_or(dst: *mut T, src: T) -> T; + /// Bitwise or with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_or` method by passing + /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_or`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_or). pub fn atomic_or_acq(dst: *mut T, src: T) -> T; + /// Bitwise or with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_or` method by passing + /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_or`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_or). pub fn atomic_or_rel(dst: *mut T, src: T) -> T; + /// Bitwise or with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_or` method by passing + /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_or`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_or). pub fn atomic_or_acqrel(dst: *mut T, src: T) -> T; + /// Bitwise or with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_or` method by passing + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_or`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_or). pub fn atomic_or_relaxed(dst: *mut T, src: T) -> T; + /// Bitwise xor with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_xor` method by passing + /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_xor`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_xor). pub fn atomic_xor(dst: *mut T, src: T) -> T; + /// Bitwise xor with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_xor` method by passing + /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_xor`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_xor). pub fn atomic_xor_acq(dst: *mut T, src: T) -> T; + /// Bitwise xor with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_xor` method by passing + /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_xor`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_xor). pub fn atomic_xor_rel(dst: *mut T, src: T) -> T; + /// Bitwise xor with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_xor` method by passing + /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_xor`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_xor). pub fn atomic_xor_acqrel(dst: *mut T, src: T) -> T; + /// Bitwise xor with the current value, returning the previous value. + /// The stabilized version of this intrinsic is available on the + /// `std::sync::atomic` types via the `fetch_xor` method by passing + /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) + /// as the `order`. For example, + /// [`AtomicBool::fetch_xor`](../../std/sync/atomic/struct.AtomicBool.html#method.fetch_xor). pub fn atomic_xor_relaxed(dst: *mut T, src: T) -> T; pub fn atomic_max(dst: *mut T, src: T) -> T; @@ -631,8 +1027,12 @@ extern "rust-intrinsic" { pub fn volatile_set_memory(dst: *mut T, val: u8, count: usize); /// Perform a volatile load from the `src` pointer. + /// The stabilized version of this intrinsic is + /// [`std::ptr::read_volatile`](../../std/ptr/fn.read_volatile.html). pub fn volatile_load(src: *const T) -> T; /// Perform a volatile store to the `dst` pointer. + /// The stabilized version of this intrinsic is + /// [`std::ptr::write_volatile`](../../std/ptr/fn.write_volatile.html). pub fn volatile_store(dst: *mut T, val: T); /// Returns the square root of an `f32` @@ -766,12 +1166,21 @@ extern "rust-intrinsic" { pub fn bswap(x: T) -> T; /// Performs checked integer addition. + /// The stabilized versions of this intrinsic are available on the integer + /// primitives via the `overflowing_add` method. For example, + /// [`std::u32::overflowing_add`](../../std/primitive.u32.html#method.overflowing_add) pub fn add_with_overflow(x: T, y: T) -> (T, bool); /// Performs checked integer subtraction + /// The stabilized versions of this intrinsic are available on the integer + /// primitives via the `overflowing_sub` method. For example, + /// [`std::u32::overflowing_sub`](../../std/primitive.u32.html#method.overflowing_sub) pub fn sub_with_overflow(x: T, y: T) -> (T, bool); /// Performs checked integer multiplication + /// The stabilized versions of this intrinsic are available on the integer + /// primitives via the `overflowing_mul` method. For example, + /// [`std::u32::overflowing_mul`](../../std/primitive.u32.html#method.overflowing_mul) pub fn mul_with_overflow(x: T, y: T) -> (T, bool); /// Performs an unchecked division, resulting in undefined behavior @@ -782,10 +1191,19 @@ extern "rust-intrinsic" { pub fn unchecked_rem(x: T, y: T) -> T; /// Returns (a + b) mod 2^N, where N is the width of T in bits. + /// The stabilized versions of this intrinsic are available on the integer + /// primitives via the `wrapping_add` method. For example, + /// [`std::u32::wrapping_add`](../../std/primitive.u32.html#method.wrapping_add) pub fn overflowing_add(a: T, b: T) -> T; /// Returns (a - b) mod 2^N, where N is the width of T in bits. + /// The stabilized versions of this intrinsic are available on the integer + /// primitives via the `wrapping_sub` method. For example, + /// [`std::u32::wrapping_sub`](../../std/primitive.u32.html#method.wrapping_sub) pub fn overflowing_sub(a: T, b: T) -> T; /// Returns (a * b) mod 2^N, where N is the width of T in bits. + /// The stabilized versions of this intrinsic are available on the integer + /// primitives via the `wrapping_mul` method. For example, + /// [`std::u32::wrapping_mul`](../../std/primitive.u32.html#method.wrapping_mul) pub fn overflowing_mul(a: T, b: T) -> T; /// Returns the value of the discriminant for the variant in 'v', diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 9d402971d18d..e94582cda7c3 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -666,13 +666,17 @@ float_sum_product! { f32 f64 } /// An iterator that always continues to yield `None` when exhausted. /// /// Calling next on a fused iterator that has returned `None` once is guaranteed -/// to return `None` again. This trait is should be implemented by all iterators +/// to return [`None`] again. This trait is should be implemented by all iterators /// that behave this way because it allows for some significant optimizations. /// /// Note: In general, you should not use `FusedIterator` in generic bounds if -/// you need a fused iterator. Instead, you should just call `Iterator::fused()` -/// on the iterator. If the iterator is already fused, the additional `Fuse` +/// you need a fused iterator. Instead, you should just call [`Iterator::fuse()`] +/// on the iterator. If the iterator is already fused, the additional [`Fuse`] /// wrapper will be a no-op with no performance penalty. +/// +/// [`None`]: ../../std/option/enum.Option.html#variant.None +/// [`Iterator::fuse()`]: ../../std/iter/trait.Iterator.html#method.fuse +/// [`Fuse`]: ../../std/iter/struct.Fuse.html #[unstable(feature = "fused", issue = "35602")] pub trait FusedIterator: Iterator {} @@ -682,16 +686,20 @@ impl<'a, I: FusedIterator + ?Sized> FusedIterator for &'a mut I {} /// An iterator that reports an accurate length using size_hint. /// /// The iterator reports a size hint where it is either exact -/// (lower bound is equal to upper bound), or the upper bound is `None`. -/// The upper bound must only be `None` if the actual iterator length is -/// larger than `usize::MAX`. +/// (lower bound is equal to upper bound), or the upper bound is [`None`]. +/// The upper bound must only be [`None`] if the actual iterator length is +/// larger than [`usize::MAX`]. /// /// The iterator must produce exactly the number of elements it reported. /// /// # Safety /// /// This trait must only be implemented when the contract is upheld. -/// Consumers of this trait must inspect `.size_hint()`’s upper bound. +/// Consumers of this trait must inspect [`.size_hint()`]’s upper bound. +/// +/// [`None`]: ../../std/option/enum.Option.html#variant.None +/// [`usize::MAX`]: ../../std/usize/constant.MAX.html +/// [`.size_hint()`]: ../../std/iter/trait.Iterator.html#method.size_hint #[unstable(feature = "trusted_len", issue = "37572")] pub unsafe trait TrustedLen : Iterator {} diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 3cf32d1a5591..b3f5363f5b15 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -550,8 +550,7 @@ macro_rules! unimplemented { /// into libsyntax itself. /// /// For more information, see documentation for `std`'s macros. -#[cfg(dox)] -pub mod builtin { +mod builtin { /// The core macro for formatted string creation & output. /// /// For more information, see the documentation for [`std::format_args!`]. @@ -559,6 +558,7 @@ pub mod builtin { /// [`std::format_args!`]: ../std/macro.format_args.html #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] + #[cfg(dox)] macro_rules! format_args { ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }) } @@ -570,6 +570,7 @@ pub mod builtin { /// [`std::env!`]: ../std/macro.env.html #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] + #[cfg(dox)] macro_rules! env { ($name:expr) => ({ /* compiler built-in */ }) } /// Optionally inspect an environment variable at compile time. @@ -579,6 +580,7 @@ pub mod builtin { /// [`std::option_env!`]: ../std/macro.option_env.html #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] + #[cfg(dox)] macro_rules! option_env { ($name:expr) => ({ /* compiler built-in */ }) } /// Concatenate identifiers into one identifier. @@ -588,6 +590,7 @@ pub mod builtin { /// [`std::concat_idents!`]: ../std/macro.concat_idents.html #[unstable(feature = "concat_idents_macro", issue = "29599")] #[macro_export] + #[cfg(dox)] macro_rules! concat_idents { ($($e:ident),*) => ({ /* compiler built-in */ }) } @@ -599,6 +602,7 @@ pub mod builtin { /// [`std::concat!`]: ../std/macro.concat.html #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] + #[cfg(dox)] macro_rules! concat { ($($e:expr),*) => ({ /* compiler built-in */ }) } /// A macro which expands to the line number on which it was invoked. @@ -608,6 +612,7 @@ pub mod builtin { /// [`std::line!`]: ../std/macro.line.html #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] + #[cfg(dox)] macro_rules! line { () => ({ /* compiler built-in */ }) } /// A macro which expands to the column number on which it was invoked. @@ -617,6 +622,7 @@ pub mod builtin { /// [`std::column!`]: ../std/macro.column.html #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] + #[cfg(dox)] macro_rules! column { () => ({ /* compiler built-in */ }) } /// A macro which expands to the file name from which it was invoked. @@ -626,6 +632,7 @@ pub mod builtin { /// [`std::file!`]: ../std/macro.file.html #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] + #[cfg(dox)] macro_rules! file { () => ({ /* compiler built-in */ }) } /// A macro which stringifies its argument. @@ -635,6 +642,7 @@ pub mod builtin { /// [`std::stringify!`]: ../std/macro.stringify.html #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] + #[cfg(dox)] macro_rules! stringify { ($t:tt) => ({ /* compiler built-in */ }) } /// Includes a utf8-encoded file as a string. @@ -644,6 +652,7 @@ pub mod builtin { /// [`std::include_str!`]: ../std/macro.include_str.html #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] + #[cfg(dox)] macro_rules! include_str { ($file:expr) => ({ /* compiler built-in */ }) } /// Includes a file as a reference to a byte array. @@ -653,6 +662,7 @@ pub mod builtin { /// [`std::include_bytes!`]: ../std/macro.include_bytes.html #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] + #[cfg(dox)] macro_rules! include_bytes { ($file:expr) => ({ /* compiler built-in */ }) } /// Expands to a string that represents the current module path. @@ -662,6 +672,7 @@ pub mod builtin { /// [`std::module_path!`]: ../std/macro.module_path.html #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] + #[cfg(dox)] macro_rules! module_path { () => ({ /* compiler built-in */ }) } /// Boolean evaluation of configuration flags. @@ -671,6 +682,7 @@ pub mod builtin { /// [`std::cfg!`]: ../std/macro.cfg.html #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] + #[cfg(dox)] macro_rules! cfg { ($($cfg:tt)*) => ({ /* compiler built-in */ }) } /// Parse a file as an expression or an item according to the context. @@ -680,5 +692,6 @@ pub mod builtin { /// [`std::include!`]: ../std/macro.include.html #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] + #[cfg(dox)] macro_rules! include { ($file:expr) => ({ /* compiler built-in */ }) } } diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index bdb0dd8e7d1a..9af10966eda4 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -26,15 +26,15 @@ use hash::Hasher; /// appropriate. /// /// An example of a non-`Send` type is the reference-counting pointer -/// [`rc::Rc`][rc]. If two threads attempt to clone `Rc`s that point to the same +/// [`rc::Rc`][`Rc`]. If two threads attempt to clone [`Rc`]s that point to the same /// reference-counted value, they might try to update the reference count at the -/// same time, which is [undefined behavior][ub] because `Rc` doesn't use atomic +/// same time, which is [undefined behavior][ub] because [`Rc`] doesn't use atomic /// operations. Its cousin [`sync::Arc`][arc] does use atomic operations (incurring /// some overhead) and thus is `Send`. /// /// See [the Nomicon](../../nomicon/send-and-sync.html) for more details. /// -/// [rc]: ../../std/rc/struct.Rc.html +/// [`Rc`]: ../../std/rc/struct.Rc.html /// [arc]: ../../std/sync/struct.Arc.html /// [ub]: ../../reference.html#behavior-considered-undefined #[stable(feature = "rust1", since = "1.0.0")] @@ -183,20 +183,17 @@ pub trait Unsize { /// Copies happen implicitly, for example as part of an assignment `y = x`. The behavior of /// `Copy` is not overloadable; it is always a simple bit-wise copy. /// -/// Cloning is an explicit action, `x.clone()`. The implementation of [`Clone`][clone] can +/// Cloning is an explicit action, `x.clone()`. The implementation of [`Clone`] can /// provide any type-specific behavior necessary to duplicate values safely. For example, -/// the implementation of `Clone` for [`String`][string] needs to copy the pointed-to string -/// buffer in the heap. A simple bitwise copy of `String` values would merely copy the -/// pointer, leading to a double free down the line. For this reason, `String` is `Clone` +/// the implementation of [`Clone`] for [`String`] needs to copy the pointed-to string +/// buffer in the heap. A simple bitwise copy of [`String`] values would merely copy the +/// pointer, leading to a double free down the line. For this reason, [`String`] is [`Clone`] /// but not `Copy`. /// -/// `Clone` is a supertrait of `Copy`, so everything which is `Copy` must also implement -/// `Clone`. If a type is `Copy` then its `Clone` implementation need only return `*self` +/// [`Clone`] is a supertrait of `Copy`, so everything which is `Copy` must also implement +/// [`Clone`]. If a type is `Copy` then its [`Clone`] implementation need only return `*self` /// (see the example above). /// -/// [clone]: ../clone/trait.Clone.html -/// [string]: ../../std/string/struct.String.html -/// /// ## When can my type be `Copy`? /// /// A type can implement `Copy` if all of its components implement `Copy`. For example, this @@ -210,7 +207,7 @@ pub trait Unsize { /// } /// ``` /// -/// A struct can be `Copy`, and `i32` is `Copy`, therefore `Point` is eligible to be `Copy`. +/// A struct can be `Copy`, and [`i32`] is `Copy`, therefore `Point` is eligible to be `Copy`. /// By contrast, consider /// /// ``` @@ -231,8 +228,8 @@ pub trait Unsize { /// ## When *can't* my type be `Copy`? /// /// Some types can't be copied safely. For example, copying `&mut T` would create an aliased -/// mutable reference. Copying [`String`] would duplicate responsibility for managing the `String`'s -/// buffer, leading to a double free. +/// mutable reference. Copying [`String`] would duplicate responsibility for managing the +/// [`String`]'s buffer, leading to a double free. /// /// Generalizing the latter case, any type implementing [`Drop`] can't be `Copy`, because it's /// managing some resource besides its own [`size_of::()`] bytes. @@ -255,6 +252,9 @@ pub trait Unsize { /// [`String`]: ../../std/string/struct.String.html /// [`Drop`]: ../../std/ops/trait.Drop.html /// [`size_of::()`]: ../../std/mem/fn.size_of.html +/// [`Clone`]: ../clone/trait.Clone.html +/// [`String`]: ../../std/string/struct.String.html +/// [`i32`]: ../../std/primitive.i32.html #[stable(feature = "rust1", since = "1.0.0")] #[lang = "copy"] pub trait Copy : Clone { @@ -290,20 +290,20 @@ pub trait Copy : Clone { /// mutability" in a non-thread-safe form, such as [`cell::Cell`][cell] /// and [`cell::RefCell`][refcell]. These types allow for mutation of /// their contents even through an immutable, shared reference. For -/// example the `set` method on `Cell` takes `&self`, so it requires -/// only a shared reference `&Cell`. The method performs no -/// synchronization, thus `Cell` cannot be `Sync`. +/// example the `set` method on [`Cell`][cell] takes `&self`, so it requires +/// only a shared reference [`&Cell`][cell]. The method performs no +/// synchronization, thus [`Cell`][cell] cannot be `Sync`. /// /// Another example of a non-`Sync` type is the reference-counting -/// pointer [`rc::Rc`][rc]. Given any reference `&Rc`, you can clone -/// a new `Rc`, modifying the reference counts in a non-atomic way. +/// pointer [`rc::Rc`][rc]. Given any reference [`&Rc`][rc], you can clone +/// a new [`Rc`][rc], modifying the reference counts in a non-atomic way. /// /// For cases when one does need thread-safe interior mutability, /// Rust provides [atomic data types], as well as explicit locking via /// [`sync::Mutex`][mutex] and [`sync::RWLock`][rwlock]. These types /// ensure that any mutation cannot cause data races, hence the types /// are `Sync`. Likewise, [`sync::Arc`][arc] provides a thread-safe -/// analogue of `Rc`. +/// analogue of [`Rc`][rc]. /// /// Any types with interior mutability must also use the /// [`cell::UnsafeCell`][unsafecell] wrapper around the value(s) which diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index e0aa25724c1f..209107ef92ce 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -337,7 +337,7 @@ pub unsafe fn zeroed() -> T { /// Bypasses Rust's normal memory-initialization checks by pretending to /// produce a value of type `T`, while doing nothing at all. /// -/// **This is incredibly dangerous, and should not be done lightly. Deeply +/// **This is incredibly dangerous and should not be done lightly. Deeply /// consider initializing your memory with a default value instead.** /// /// This is useful for [FFI] functions and initializing arrays sometimes, @@ -352,24 +352,18 @@ pub unsafe fn zeroed() -> T { /// a boolean, your program may take one, both, or neither of the branches. /// /// Writing to the uninitialized value is similarly dangerous. Rust believes the -/// value is initialized, and will therefore try to [`Drop`][drop] the uninitialized +/// value is initialized, and will therefore try to [`Drop`] the uninitialized /// value and its fields if you try to overwrite it in a normal manner. The only way /// to safely initialize an uninitialized value is with [`ptr::write`][write], /// [`ptr::copy`][copy], or [`ptr::copy_nonoverlapping`][copy_no]. /// -/// If the value does implement `Drop`, it must be initialized before +/// If the value does implement [`Drop`], it must be initialized before /// it goes out of scope (and therefore would be dropped). Note that this /// includes a `panic` occurring and unwinding the stack suddenly. /// -/// [ub]: ../../reference.html#behavior-considered-undefined -/// [write]: ../ptr/fn.write.html -/// [copy]: ../intrinsics/fn.copy.html -/// [copy_no]: ../intrinsics/fn.copy_nonoverlapping.html -/// [drop]: ../ops/trait.Drop.html -/// /// # Examples /// -/// Here's how to safely initialize an array of `Vec`s. +/// Here's how to safely initialize an array of [`Vec`]s. /// /// ``` /// use std::mem; @@ -410,8 +404,8 @@ pub unsafe fn zeroed() -> T { /// ``` /// /// This example emphasizes exactly how delicate and dangerous using `mem::uninitialized` -/// can be. Note that the `vec!` macro *does* let you initialize every element with a -/// value that is only `Clone`, so the following is semantically equivalent and +/// can be. Note that the [`vec!`] macro *does* let you initialize every element with a +/// value that is only [`Clone`], so the following is semantically equivalent and /// vastly less dangerous, as long as you can live with an extra heap /// allocation: /// @@ -419,6 +413,15 @@ pub unsafe fn zeroed() -> T { /// let data: Vec> = vec![Vec::new(); 1000]; /// println!("{:?}", &data[0]); /// ``` +/// +/// [`Vec`]: ../../std/vec/struct.Vec.html +/// [`vec!`]: ../../std/macro.vec.html +/// [`Clone`]: ../../std/clone/trait.Clone.html +/// [ub]: ../../reference.html#behavior-considered-undefined +/// [write]: ../ptr/fn.write.html +/// [copy]: ../intrinsics/fn.copy.html +/// [copy_no]: ../intrinsics/fn.copy_nonoverlapping.html +/// [`Drop`]: ../ops/trait.Drop.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn uninitialized() -> T { @@ -492,7 +495,7 @@ pub fn swap(x: &mut T, y: &mut T) { /// } /// ``` /// -/// Note that `T` does not necessarily implement `Clone`, so it can't even clone and reset +/// Note that `T` does not necessarily implement [`Clone`], so it can't even clone and reset /// `self.buf`. But `replace` can be used to disassociate the original value of `self.buf` from /// `self`, allowing it to be returned: /// @@ -507,6 +510,8 @@ pub fn swap(x: &mut T, y: &mut T) { /// } /// } /// ``` +/// +/// [`Clone`]: ../../std/clone/trait.Clone.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn replace(dest: &mut T, mut src: T) -> T { @@ -571,8 +576,8 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// v.push(4); // no problems /// ``` /// -/// Since `RefCell` enforces the borrow rules at runtime, `drop` can -/// release a `RefCell` borrow: +/// Since [`RefCell`] enforces the borrow rules at runtime, `drop` can +/// release a [`RefCell`] borrow: /// /// ``` /// use std::cell::RefCell; @@ -588,7 +593,7 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// println!("{}", *borrow); /// ``` /// -/// Integers and other types implementing `Copy` are unaffected by `drop`. +/// Integers and other types implementing [`Copy`] are unaffected by `drop`. /// /// ``` /// #[derive(Copy, Clone)] @@ -602,6 +607,8 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// println!("x: {}, y: {}", x, y.0); // still available /// ``` /// +/// [`RefCell`]: ../../std/cell/struct.RefCell.html +/// [`Copy`]: ../../std/marker/trait.Copy.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn drop(_x: T) { } diff --git a/src/libcore/tuple.rs b/src/libcore/tuple.rs index c3608b60a31a..55d55079ddc1 100644 --- a/src/libcore/tuple.rs +++ b/src/libcore/tuple.rs @@ -13,11 +13,6 @@ use cmp::*; use cmp::Ordering::*; -// FIXME(#19630) Remove this work-around -macro_rules! e { - ($e:expr) => { $e } -} - // macro for implementing n-ary tuple functions and operations macro_rules! tuple_impls { ($( @@ -29,7 +24,7 @@ macro_rules! tuple_impls { #[stable(feature = "rust1", since = "1.0.0")] impl<$($T:Clone),+> Clone for ($($T,)+) { fn clone(&self) -> ($($T,)+) { - ($(e!(self.$idx.clone()),)+) + ($(self.$idx.clone(),)+) } } @@ -37,11 +32,11 @@ macro_rules! tuple_impls { impl<$($T:PartialEq),+> PartialEq for ($($T,)+) { #[inline] fn eq(&self, other: &($($T,)+)) -> bool { - e!($(self.$idx == other.$idx)&&+) + $(self.$idx == other.$idx)&&+ } #[inline] fn ne(&self, other: &($($T,)+)) -> bool { - e!($(self.$idx != other.$idx)||+) + $(self.$idx != other.$idx)||+ } } diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index e7d401f0929f..b179a16e55e5 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -139,7 +139,7 @@ pub struct Parser<'a> { input: &'a str, cur: iter::Peekable>, /// Error messages accumulated during parsing - pub errors: Vec, + pub errors: Vec<(string::String, Option)>, /// Current position of implicit positional argument pointer curarg: usize, } @@ -165,7 +165,9 @@ impl<'a> Iterator for Parser<'a> { if self.consume('}') { Some(String(self.string(pos + 1))) } else { - self.err("unmatched `}` found"); + self.err_with_note("unmatched `}` found", + "if you intended to print `}`, \ + you can escape it using `}}`"); None } } @@ -192,7 +194,14 @@ impl<'a> Parser<'a> { /// String, but I think it does when this eventually uses conditions so it /// might as well start using it now. fn err(&mut self, msg: &str) { - self.errors.push(msg.to_owned()); + self.errors.push((msg.to_owned(), None)); + } + + /// Notifies of an error. The message doesn't actually need to be of type + /// String, but I think it does when this eventually uses conditions so it + /// might as well start using it now. + fn err_with_note(&mut self, msg: &str, note: &str) { + self.errors.push((msg.to_owned(), Some(note.to_owned()))); } /// Optionally consumes the specified character. If the character is not at @@ -222,7 +231,13 @@ impl<'a> Parser<'a> { self.err(&format!("expected `{:?}`, found `{:?}`", c, maybe)); } } else { - self.err(&format!("expected `{:?}` but string was terminated", c)); + let msg = &format!("expected `{:?}` but string was terminated", c); + if c == '}' { + self.err_with_note(msg, + "if you intended to print `{`, you can escape it using `{{`"); + } else { + self.err(msg); + } } } diff --git a/src/liblibc b/src/liblibc index 7d9b71f0971f..6e8c1b490ccb 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit 7d9b71f0971f8fa196d864d7071f216a59036d6e +Subproject commit 6e8c1b490ccbe5e84d248bab883515bc85394b5f diff --git a/src/librustc/dep_graph/dep_tracking_map.rs b/src/librustc/dep_graph/dep_tracking_map.rs index 50a478fcc2fd..50dfe9d22f12 100644 --- a/src/librustc/dep_graph/dep_tracking_map.rs +++ b/src/librustc/dep_graph/dep_tracking_map.rs @@ -112,15 +112,15 @@ impl MemoizationMap for RefCell> { /// switched to `Map(key)`. Therefore, if `op` makes use of any /// HIR nodes or shared state accessed through its closure /// environment, it must explicitly register a read of that - /// state. As an example, see `type_scheme_of_item` in `collect`, + /// state. As an example, see `type_of_item` in `collect`, /// which looks something like this: /// /// ``` - /// fn type_scheme_of_item(..., item: &hir::Item) -> ty::TypeScheme<'tcx> { + /// fn type_of_item(..., item: &hir::Item) -> Ty<'tcx> { /// let item_def_id = ccx.tcx.map.local_def_id(it.id); - /// ccx.tcx.tcache.memoized(item_def_id, || { + /// ccx.tcx.item_types.memoized(item_def_id, || { /// ccx.tcx.dep_graph.read(DepNode::Hir(item_def_id)); // (*) - /// compute_type_scheme_of_item(ccx, item) + /// compute_type_of_item(ccx, item) /// }); /// } /// ``` diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index 9c00e95c17e0..e365cea6d0e5 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -25,5 +25,5 @@ pub use self::dep_node::WorkProductId; pub use self::graph::DepGraph; pub use self::graph::WorkProduct; pub use self::query::DepGraphQuery; -pub use self::visit::visit_all_items_in_krate; +pub use self::visit::visit_all_item_likes_in_krate; pub use self::raii::DepTask; diff --git a/src/librustc/dep_graph/visit.rs b/src/librustc/dep_graph/visit.rs index d085c24036ce..600732fc6f70 100644 --- a/src/librustc/dep_graph/visit.rs +++ b/src/librustc/dep_graph/visit.rs @@ -10,22 +10,21 @@ use hir; use hir::def_id::DefId; -use hir::intravisit::Visitor; +use hir::itemlikevisit::ItemLikeVisitor; use ty::TyCtxt; use super::dep_node::DepNode; - /// Visit all the items in the krate in some order. When visiting a /// particular item, first create a dep-node by calling `dep_node_fn` /// and push that onto the dep-graph stack of tasks, and also create a /// read edge from the corresponding AST node. This is used in /// compiler passes to automatically record the item that they are /// working on. -pub fn visit_all_items_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - mut dep_node_fn: F, - visitor: &mut V) - where F: FnMut(DefId) -> DepNode, V: Visitor<'tcx> +pub fn visit_all_item_likes_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + mut dep_node_fn: F, + visitor: &mut V) + where F: FnMut(DefId) -> DepNode, V: ItemLikeVisitor<'tcx> { struct TrackingVisitor<'visit, 'tcx: 'visit, F: 'visit, V: 'visit> { tcx: TyCtxt<'visit, 'tcx, 'tcx>, @@ -33,8 +32,8 @@ pub fn visit_all_items_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, visitor: &'visit mut V } - impl<'visit, 'tcx, F, V> Visitor<'tcx> for TrackingVisitor<'visit, 'tcx, F, V> - where F: FnMut(DefId) -> DepNode, V: Visitor<'tcx> + impl<'visit, 'tcx, F, V> ItemLikeVisitor<'tcx> for TrackingVisitor<'visit, 'tcx, F, V> + where F: FnMut(DefId) -> DepNode, V: ItemLikeVisitor<'tcx> { fn visit_item(&mut self, i: &'tcx hir::Item) { let item_def_id = self.tcx.map.local_def_id(i.id); @@ -46,6 +45,17 @@ pub fn visit_all_items_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, self.visitor.visit_item(i); debug!("Ended task {:?}", task_id); } + + fn visit_impl_item(&mut self, i: &'tcx hir::ImplItem) { + let impl_item_def_id = self.tcx.map.local_def_id(i.id); + let task_id = (self.dep_node_fn)(impl_item_def_id); + let _task = self.tcx.dep_graph.in_task(task_id.clone()); + debug!("Started task {:?}", task_id); + assert!(!self.tcx.map.is_inlined_def_id(impl_item_def_id)); + self.tcx.dep_graph.read(DepNode::Hir(impl_item_def_id)); + self.visitor.visit_impl_item(i); + debug!("Ended task {:?}", task_id); + } } let krate = tcx.dep_graph.with_ignore(|| tcx.map.krate()); @@ -54,5 +64,5 @@ pub fn visit_all_items_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, dep_node_fn: &mut dep_node_fn, visitor: visitor }; - krate.visit_all_items(&mut tracking_visitor) + krate.visit_all_item_likes(&mut tracking_visitor) } diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index 044e36e5c9cd..feefc43f4013 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -106,7 +106,7 @@ pub type DefMap = NodeMap; // within. pub type ExportMap = NodeMap>; -#[derive(Copy, Clone, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)] pub struct Export { pub name: ast::Name, // The name of the target. pub def: Def, // The definition of the target. diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 9932e5fe6862..4cfa889ec561 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -8,7 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! HIR walker. Each overridden visit method has full control over what +//! HIR walker for walking the contents of nodes. +//! +//! **For an overview of the visitor strategy, see the docs on the +//! `super::itemlikevisit::ItemLikeVisitor` trait.** +//! +//! If you have decided to use this visitor, here are some general +//! notes on how to do it: +//! +//! Each overridden visit method has full control over what //! happens with its node, it can do its own traversal of the node's children, //! call `intravisit::walk_*` to apply the default traversal algorithm, or prevent //! deeper traversal by doing nothing. @@ -30,6 +38,8 @@ use syntax::ast::{NodeId, CRATE_NODE_ID, Name, Attribute}; use syntax::codemap::Spanned; use syntax_pos::Span; use hir::*; +use hir::map::Map; +use super::itemlikevisit::DeepVisitor; use std::cmp; use std::u32; @@ -76,22 +86,70 @@ pub trait Visitor<'v> : Sized { /////////////////////////////////////////////////////////////////////////// // Nested items. - /// Invoked when a nested item is encountered. By default, does - /// nothing. If you want a deep walk, you need to override to - /// fetch the item contents. But most of the time, it is easier - /// (and better) to invoke `Crate::visit_all_items`, which visits - /// all items in the crate in some order (but doesn't respect - /// nesting). - #[allow(unused_variables)] - fn visit_nested_item(&mut self, id: ItemId) { + /// The default versions of the `visit_nested_XXX` routines invoke + /// this method to get a map to use; if they get back `None`, they + /// just skip nested things. Otherwise, they will lookup the + /// nested item-like things in the map and visit it. So the best + /// way to implement a nested visitor is to override this method + /// to return a `Map`; one advantage of this is that if we add + /// more types of nested things in the future, they will + /// automatically work. + /// + /// **If for some reason you want the nested behavior, but don't + /// have a `Map` are your disposal:** then you should override the + /// `visit_nested_XXX` methods, and override this method to + /// `panic!()`. This way, if a new `visit_nested_XXX` variant is + /// added in the future, we will see the panic in your code and + /// fix it appropriately. + fn nested_visit_map(&mut self) -> Option<&Map<'v>> { + None } - /// Visit the top-level item and (optionally) nested items. See + /// Invoked when a nested item is encountered. By default does + /// nothing unless you override `nested_visit_map` to return + /// `Some(_)`, in which case it will walk the item. **You probably + /// don't want to override this method** -- instead, override + /// `nested_visit_map` or use the "shallow" or "deep" visit + /// patterns described on `itemlikevisit::ItemLikeVisitor`. The only + /// reason to override this method is if you want a nested pattern + /// but cannot supply a `Map`; see `nested_visit_map` for advice. + #[allow(unused_variables)] + fn visit_nested_item(&mut self, id: ItemId) { + let opt_item = self.nested_visit_map() + .map(|map| map.expect_item(id.id)); + if let Some(item) = opt_item { + self.visit_item(item); + } + } + + /// Like `visit_nested_item()`, but for impl items. See + /// `visit_nested_item()` for advice on when to override this + /// method. + #[allow(unused_variables)] + fn visit_nested_impl_item(&mut self, id: ImplItemId) { + let opt_item = self.nested_visit_map() + .map(|map| map.impl_item(id)); + if let Some(item) = opt_item { + self.visit_impl_item(item); + } + } + + /// Visit the top-level item and (optionally) nested items / impl items. See /// `visit_nested_item` for details. fn visit_item(&mut self, i: &'v Item) { walk_item(self, i) } + /// When invoking `visit_all_item_likes()`, you need to supply an + /// item-like visitor. This method converts a "intra-visit" + /// visitor into an item-like visitor that walks the entire tree. + /// If you use this, you probably don't want to process the + /// contents of nested item-like things, since the outer loop will + /// visit them as well. + fn as_deep_visitor<'s>(&'s mut self) -> DeepVisitor<'s, Self> { + DeepVisitor::new(self) + } + /////////////////////////////////////////////////////////////////////////// fn visit_id(&mut self, _node_id: NodeId) { @@ -147,6 +205,9 @@ pub trait Visitor<'v> : Sized { fn visit_impl_item(&mut self, ii: &'v ImplItem) { walk_impl_item(self, ii) } + fn visit_impl_item_ref(&mut self, ii: &'v ImplItemRef) { + walk_impl_item_ref(self, ii) + } fn visit_trait_ref(&mut self, t: &'v TraitRef) { walk_trait_ref(self, t) } @@ -206,6 +267,12 @@ pub trait Visitor<'v> : Sized { fn visit_vis(&mut self, vis: &'v Visibility) { walk_vis(self, vis) } + fn visit_associated_item_kind(&mut self, kind: &'v AssociatedItemKind) { + walk_associated_item_kind(self, kind); + } + fn visit_defaultness(&mut self, defaultness: &'v Defaultness) { + walk_defaultness(self, defaultness); + } } pub fn walk_opt_name<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_name: Option) { @@ -341,12 +408,14 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { visitor.visit_id(item.id); visitor.visit_trait_ref(trait_ref) } - ItemImpl(.., ref type_parameters, ref opt_trait_reference, ref typ, ref impl_items) => { + ItemImpl(.., ref type_parameters, ref opt_trait_reference, ref typ, ref impl_item_refs) => { visitor.visit_id(item.id); visitor.visit_generics(type_parameters); walk_list!(visitor, visit_trait_ref, opt_trait_reference); visitor.visit_ty(typ); - walk_list!(visitor, visit_impl_item, impl_items); + for impl_item_ref in impl_item_refs { + visitor.visit_impl_item_ref(impl_item_ref); + } } ItemStruct(ref struct_definition, ref generics) | ItemUnion(ref struct_definition, ref generics) => { @@ -677,10 +746,14 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai } pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplItem) { - visitor.visit_vis(&impl_item.vis); - visitor.visit_name(impl_item.span, impl_item.name); - walk_list!(visitor, visit_attribute, &impl_item.attrs); - match impl_item.node { + // NB: Deliberately force a compilation error if/when new fields are added. + let ImplItem { id: _, name, ref vis, ref defaultness, ref attrs, ref node, span } = *impl_item; + + visitor.visit_name(span, name); + visitor.visit_vis(vis); + visitor.visit_defaultness(defaultness); + walk_list!(visitor, visit_attribute, attrs); + match *node { ImplItemKind::Const(ref ty, ref expr) => { visitor.visit_id(impl_item.id); visitor.visit_ty(ty); @@ -703,6 +776,17 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt } } +pub fn walk_impl_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, impl_item_ref: &'v ImplItemRef) { + // NB: Deliberately force a compilation error if/when new fields are added. + let ImplItemRef { id, name, ref kind, span, ref vis, ref defaultness } = *impl_item_ref; + visitor.visit_nested_impl_item(id); + visitor.visit_name(span, name); + visitor.visit_associated_item_kind(kind); + visitor.visit_vis(vis); + visitor.visit_defaultness(defaultness); +} + + pub fn walk_struct_def<'v, V: Visitor<'v>>(visitor: &mut V, struct_definition: &'v VariantData) { visitor.visit_id(struct_definition.id()); walk_list!(visitor, visit_struct_field, struct_definition.fields()); @@ -872,6 +956,18 @@ pub fn walk_vis<'v, V: Visitor<'v>>(visitor: &mut V, vis: &'v Visibility) { } } +pub fn walk_associated_item_kind<'v, V: Visitor<'v>>(_: &mut V, _: &'v AssociatedItemKind) { + // No visitable content here: this fn exists so you can call it if + // the right thing to do, should content be added in the future, + // would be to walk it. +} + +pub fn walk_defaultness<'v, V: Visitor<'v>>(_: &mut V, _: &'v Defaultness) { + // No visitable content here: this fn exists so you can call it if + // the right thing to do, should content be added in the future, + // would be to walk it. +} + #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, PartialEq, Eq)] pub struct IdRange { pub min: NodeId, diff --git a/src/librustc/hir/itemlikevisit.rs b/src/librustc/hir/itemlikevisit.rs new file mode 100644 index 000000000000..1e373441e9e8 --- /dev/null +++ b/src/librustc/hir/itemlikevisit.rs @@ -0,0 +1,84 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use super::{Item, ImplItem}; +use super::intravisit::Visitor; + +/// The "item-like visitor" visitor defines only the top-level methods +/// that can be invoked by `Crate::visit_all_item_likes()`. Whether +/// this trait is the right one to implement will depend on the +/// overall pattern you need. Here are the three available patterns, +/// in roughly the order of desirability: +/// +/// 1. **Shallow visit**: Get a simple callback for every item (or item-like thing) in the HIR. +/// - Example: find all items with a `#[foo]` attribute on them. +/// - How: Implement `ItemLikeVisitor` and call `tcx.visit_all_item_likes_in_krate()`. +/// - Pro: Efficient; just walks the lists of item-like things, not the nodes themselves. +/// - Pro: Integrates well into dependency tracking. +/// - Con: Don't get information about nesting +/// - Con: Don't have methods for specific bits of HIR, like "on +/// every expr, do this". +/// 2. **Deep visit**: Want to scan for specific kinds of HIR nodes within +/// an item, but don't care about how item-like things are nested +/// within one another. +/// - Example: Examine each expression to look for its type and do some check or other. +/// - How: Implement `intravisit::Visitor` and use +/// `tcx.visit_all_item_likes_in_krate(visitor.as_deep_visitor())`. Within +/// your `intravisit::Visitor` impl, implement methods like +/// `visit_expr()`; don't forget to invoke +/// `intravisit::walk_visit_expr()` to keep walking the subparts. +/// - Pro: Visitor methods for any kind of HIR node, not just item-like things. +/// - Pro: Integrates well into dependency tracking. +/// - Con: Don't get information about nesting between items +/// 3. **Nested visit**: Want to visit the whole HIR and you care about the nesting between +/// item-like things. +/// - Example: Lifetime resolution, which wants to bring lifetimes declared on the +/// impl into scope while visiting the impl-items, and then back out again. +/// - How: Implement `intravisit::Visitor` and override the `visit_nested_foo()` foo methods +/// as needed. Walk your crate with `intravisit::walk_crate()` invoked on `tcx.map.krate()`. +/// - Pro: Visitor methods for any kind of HIR node, not just item-like things. +/// - Pro: Preserves nesting information +/// - Con: Does not integrate well into dependency tracking. +/// +/// Note: the methods of `ItemLikeVisitor` intentionally have no +/// defaults, so that as we expand the list of item-like things, we +/// revisit the various visitors to see if they need to change. This +/// is harder to do with `intravisit::Visitor`, so when you add a new +/// `visit_nested_foo()` method, it is recommended that you search for +/// existing `fn visit_nested` methods to see where changes are +/// needed. +pub trait ItemLikeVisitor<'hir> { + fn visit_item(&mut self, item: &'hir Item); + fn visit_impl_item(&mut self, impl_item: &'hir ImplItem); +} + +pub struct DeepVisitor<'v, V: 'v> { + visitor: &'v mut V, +} + +impl<'v, 'hir, V> DeepVisitor<'v, V> + where V: Visitor<'hir> + 'v +{ + pub fn new(base: &'v mut V) -> Self { + DeepVisitor { visitor: base } + } +} + +impl<'v, 'hir, V> ItemLikeVisitor<'hir> for DeepVisitor<'v, V> + where V: Visitor<'hir> +{ + fn visit_item(&mut self, item: &'hir Item) { + self.visitor.visit_item(item); + } + + fn visit_impl_item(&mut self, impl_item: &'hir ImplItem) { + self.visitor.visit_impl_item(impl_item); + } +} diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index b985298e47cc..05c4ae521803 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -105,6 +105,7 @@ impl<'a> LoweringContext<'a> { fn lower_crate(&mut self, c: &Crate) -> hir::Crate { struct ItemLowerer<'lcx, 'interner: 'lcx> { items: BTreeMap, + impl_items: BTreeMap, lctx: &'lcx mut LoweringContext<'interner>, } @@ -113,12 +114,20 @@ impl<'a> LoweringContext<'a> { self.items.insert(item.id, self.lctx.lower_item(item)); visit::walk_item(self, item); } + + fn visit_impl_item(&mut self, item: &ImplItem) { + let id = self.lctx.lower_impl_item_ref(item).id; + self.impl_items.insert(id, self.lctx.lower_impl_item(item)); + visit::walk_impl_item(self, item); + } } - let items = { - let mut item_lowerer = ItemLowerer { items: BTreeMap::new(), lctx: self }; + let (items, impl_items) = { + let mut item_lowerer = ItemLowerer { items: BTreeMap::new(), + impl_items: BTreeMap::new(), + lctx: self }; visit::walk_crate(&mut item_lowerer, c); - item_lowerer.items + (item_lowerer.items, item_lowerer.impl_items) }; hir::Crate { @@ -127,6 +136,7 @@ impl<'a> LoweringContext<'a> { span: c.span, exported_macros: c.exported_macros.iter().map(|m| self.lower_macro_def(m)).collect(), items: items, + impl_items: impl_items, } } @@ -631,7 +641,7 @@ impl<'a> LoweringContext<'a> { } ItemKind::Impl(unsafety, polarity, ref generics, ref ifce, ref ty, ref impl_items) => { let new_impl_items = impl_items.iter() - .map(|item| self.lower_impl_item(item)) + .map(|item| self.lower_impl_item_ref(item)) .collect(); let ifce = ifce.as_ref().map(|trait_ref| self.lower_trait_ref(trait_ref)); hir::ItemImpl(self.lower_unsafety(unsafety), @@ -689,7 +699,7 @@ impl<'a> LoweringContext<'a> { name: i.ident.name, attrs: this.lower_attrs(&i.attrs), vis: this.lower_visibility(&i.vis), - defaultness: this.lower_defaultness(i.defaultness), + defaultness: this.lower_defaultness(i.defaultness, true /* [1] */), node: match i.node { ImplItemKind::Const(ref ty, ref expr) => { hir::ImplItemKind::Const(this.lower_ty(ty), this.lower_expr(expr)) @@ -705,6 +715,28 @@ impl<'a> LoweringContext<'a> { span: i.span, } }) + + // [1] since `default impl` is not yet implemented, this is always true in impls + } + + fn lower_impl_item_ref(&mut self, i: &ImplItem) -> hir::ImplItemRef { + hir::ImplItemRef { + id: hir::ImplItemId { node_id: i.id }, + name: i.ident.name, + span: i.span, + vis: self.lower_visibility(&i.vis), + defaultness: self.lower_defaultness(i.defaultness, true /* [1] */), + kind: match i.node { + ImplItemKind::Const(..) => hir::AssociatedItemKind::Const, + ImplItemKind::Type(..) => hir::AssociatedItemKind::Type, + ImplItemKind::Method(ref sig, _) => hir::AssociatedItemKind::Method { + has_self: sig.decl.get_self().is_some(), + }, + ImplItemKind::Macro(..) => unimplemented!(), + }, + } + + // [1] since `default impl` is not yet implemented, this is always true in impls } fn lower_mod(&mut self, m: &Mod) -> hir::Mod { @@ -1620,10 +1652,13 @@ impl<'a> LoweringContext<'a> { } } - fn lower_defaultness(&mut self, d: Defaultness) -> hir::Defaultness { + fn lower_defaultness(&mut self, d: Defaultness, has_value: bool) -> hir::Defaultness { match d { - Defaultness::Default => hir::Defaultness::Default, - Defaultness::Final => hir::Defaultness::Final, + Defaultness::Default => hir::Defaultness::Default { has_value: has_value }, + Defaultness::Final => { + assert!(has_value); + hir::Defaultness::Final + } } } diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index 04fcf7e84508..51a378a08336 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -92,6 +92,11 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { /// Because we want to track parent items and so forth, enable /// deep walking so that we walk nested items in the context of /// their outer items. + + fn nested_visit_map(&mut self) -> Option<&map::Map<'ast>> { + panic!("visit_nested_xxx must be manually implemented in this visitor") + } + fn visit_nested_item(&mut self, item: ItemId) { debug!("visit_nested_item: {:?}", item); if !self.ignore_nested_items { @@ -99,6 +104,10 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { } } + fn visit_nested_impl_item(&mut self, item_id: ImplItemId) { + self.visit_impl_item(self.krate.impl_item(item_id)) + } + fn visit_item(&mut self, i: &'ast Item) { debug!("visit_item: {:?}", i); diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 39114ec4238e..06cfc8aee8c9 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -254,9 +254,14 @@ impl<'ast> Map<'ast> { return DepNode::Hir(def_id); } + EntryImplItem(..) => { + let def_id = self.local_def_id(id); + assert!(!self.is_inlined_def_id(def_id)); + return DepNode::Hir(def_id); + } + EntryForeignItem(p, _) | EntryTraitItem(p, _) | - EntryImplItem(p, _) | EntryVariant(p, _) | EntryExpr(p, _) | EntryStmt(p, _) | @@ -378,6 +383,14 @@ impl<'ast> Map<'ast> { self.forest.krate() } + pub fn impl_item(&self, id: ImplItemId) -> &'ast ImplItem { + self.read(id.node_id); + + // NB: intentionally bypass `self.forest.krate()` so that we + // do not trigger a read of the whole krate here + self.forest.krate.impl_item(id) + } + /// Get the attributes on the krate. This is preferable to /// invoking `krate.attrs` because it registers a tighter /// dep-graph access. diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 6b5b8101a146..9f5ff6914b0c 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -68,6 +68,7 @@ pub mod check_attr; pub mod def; pub mod def_id; pub mod intravisit; +pub mod itemlikevisit; pub mod lowering; pub mod map; pub mod pat_util; @@ -423,6 +424,8 @@ pub struct Crate { // detected, which in turn can make compile-fail tests yield // slightly different results. pub items: BTreeMap, + + pub impl_items: BTreeMap, } impl Crate { @@ -430,6 +433,10 @@ impl Crate { &self.items[&id] } + pub fn impl_item(&self, id: ImplItemId) -> &ImplItem { + &self.impl_items[&id] + } + /// Visits all items in the crate in some determinstic (but /// unspecified) order. If you just need to process every item, /// but don't care about nesting, this method is the best choice. @@ -438,12 +445,16 @@ impl Crate { /// follows lexical scoping rules -- then you want a different /// approach. You should override `visit_nested_item` in your /// visitor and then call `intravisit::walk_crate` instead. - pub fn visit_all_items<'hir, V>(&'hir self, visitor: &mut V) - where V: intravisit::Visitor<'hir> + pub fn visit_all_item_likes<'hir, V>(&'hir self, visitor: &mut V) + where V: itemlikevisit::ItemLikeVisitor<'hir> { for (_, item) in &self.items { visitor.visit_item(item); } + + for (_, impl_item) in &self.impl_items { + visitor.visit_impl_item(impl_item); + } } } @@ -1041,6 +1052,14 @@ pub enum TraitItem_ { TypeTraitItem(TyParamBounds, Option>), } +// The bodies for items are stored "out of line", in a separate +// hashmap in the `Crate`. Here we just record the node-id of the item +// so it can fetched later. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct ImplItemId { + pub node_id: NodeId, +} + /// Represents anything within an `impl` block #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct ImplItem { @@ -1240,17 +1259,27 @@ pub enum Constness { #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum Defaultness { - Default, + Default { has_value: bool }, Final, } impl Defaultness { + pub fn has_value(&self) -> bool { + match *self { + Defaultness::Default { has_value, .. } => has_value, + Defaultness::Final => true, + } + } + pub fn is_final(&self) -> bool { *self == Defaultness::Final } pub fn is_default(&self) -> bool { - *self == Defaultness::Default + match *self { + Defaultness::Default { .. } => true, + _ => false, + } } } @@ -1527,7 +1556,7 @@ pub enum Item_ { Generics, Option, // (optional) trait this impl implements P, // self - HirVec), + HirVec), } impl Item_ { @@ -1551,6 +1580,29 @@ impl Item_ { } } +/// A reference from an impl to one of its associated items. This +/// contains the item's id, naturally, but also the item's name and +/// some other high-level details (like whether it is an associated +/// type or method, and whether it is public). This allows other +/// passes to find the impl they want without loading the id (which +/// means fewer edges in the incremental compilation graph). +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct ImplItemRef { + pub id: ImplItemId, + pub name: Name, + pub kind: AssociatedItemKind, + pub span: Span, + pub vis: Visibility, + pub defaultness: Defaultness, +} + +#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum AssociatedItemKind { + Const, + Method { has_self: bool }, + Type, +} + #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct ForeignItem { pub name: Name, diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 2c4ffb853c1f..807bbec3b588 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -809,7 +809,7 @@ impl<'a> State<'a> { self.bopen()?; self.print_inner_attributes(&item.attrs)?; for impl_item in impl_items { - self.print_impl_item(impl_item)?; + self.print_impl_item_ref(impl_item)?; } self.bclose(item.span)?; } @@ -1020,14 +1020,25 @@ impl<'a> State<'a> { self.ann.post(self, NodeSubItem(ti.id)) } + pub fn print_impl_item_ref(&mut self, item_ref: &hir::ImplItemRef) -> io::Result<()> { + if let Some(krate) = self.krate { + // skip nested items if krate context was not provided + let item = &krate.impl_item(item_ref.id); + self.print_impl_item(item) + } else { + Ok(()) + } + } + pub fn print_impl_item(&mut self, ii: &hir::ImplItem) -> io::Result<()> { self.ann.pre(self, NodeSubItem(ii.id))?; self.hardbreak_if_not_bol()?; self.maybe_print_comment(ii.span.lo)?; self.print_outer_attributes(&ii.attrs)?; - if let hir::Defaultness::Default = ii.defaultness { - self.word_nbsp("default")?; + match ii.defaultness { + hir::Defaultness::Default { .. } => self.word_nbsp("default")?, + hir::Defaultness::Final => (), } match ii.node { diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index fda08eba0213..5d33d6e6d2e7 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -184,7 +184,7 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { { // We use SmallVector here instead of Vec because this code is hot and // it's rare that the stack length exceeds 1. - let mut stack = SmallVector::zero(); + let mut stack = SmallVector::new(); stack.push((a_ty, dir, b_vid)); loop { // For each turn of the loop, we extract a tuple @@ -274,7 +274,7 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { { let mut generalize = Generalizer { infcx: self.infcx, - span: self.trace.origin.span(), + span: self.trace.cause.span, for_vid: for_vid, make_region_vars: make_region_vars, cycle_detected: false diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 47c0bc5fd60c..58caac4034e3 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -80,8 +80,9 @@ use hir::print as pprust; use lint; use hir::def::Def; use hir::def_id::DefId; -use infer::{self, TypeOrigin}; +use infer; use middle::region; +use traits::{ObligationCause, ObligationCauseCode}; use ty::{self, TyCtxt, TypeFoldable}; use ty::{Region, ReFree}; use ty::error::TypeError; @@ -524,10 +525,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { fn note_error_origin(&self, err: &mut DiagnosticBuilder<'tcx>, - origin: &TypeOrigin) + cause: &ObligationCause<'tcx>) { - match origin { - &TypeOrigin::MatchExpressionArm(_, arm_span, source) => match source { + match cause.code { + ObligationCauseCode::MatchExpressionArm { arm_span, source } => match source { hir::MatchSource::IfLetDesugar {..} => { err.span_note(arm_span, "`if let` arm with an incompatible type"); } @@ -541,7 +542,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn note_type_err(&self, diag: &mut DiagnosticBuilder<'tcx>, - origin: TypeOrigin, + cause: &ObligationCause<'tcx>, secondary_span: Option<(Span, String)>, values: Option>, terr: &TypeError<'tcx>) @@ -558,7 +559,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } }; - let span = origin.span(); + let span = cause.span; if let Some((expected, found)) = expected_found { let is_simple_error = if let &TypeError::Sorts(ref values) = terr { @@ -588,7 +589,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { diag.span_label(sp, &msg); } - self.note_error_origin(diag, &origin); + self.note_error_origin(diag, &cause); self.check_and_note_conflicting_crates(diag, terr, span); self.tcx.note_and_explain_type_err(diag, terr, span); } @@ -598,17 +599,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { terr: &TypeError<'tcx>) -> DiagnosticBuilder<'tcx> { - let span = trace.origin.span(); - let failure_str = trace.origin.as_failure_str(); - let mut diag = match trace.origin { - TypeOrigin::IfExpressionWithNoElse(_) => { + let span = trace.cause.span; + let failure_str = trace.cause.as_failure_str(); + let mut diag = match trace.cause.code { + ObligationCauseCode::IfExpressionWithNoElse => { struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str) }, _ => { struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str) }, }; - self.note_type_err(&mut diag, trace.origin, None, Some(trace.values), terr); + self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr); diag } @@ -1052,21 +1053,28 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { match item.node { hir::ItemFn(ref fn_decl, unsafety, constness, _, ref gen, _) => { Some((fn_decl, gen, unsafety, constness, item.name, item.span)) - }, - _ => None + } + _ => None, } } ast_map::NodeImplItem(item) => { - match item.node { - hir::ImplItemKind::Method(ref sig, _) => { - Some((&sig.decl, - &sig.generics, - sig.unsafety, - sig.constness, - item.name, - item.span)) + let id = self.tcx.map.get_parent(item.id); + if let Some(ast_map::NodeItem(parent_scope)) = self.tcx.map.find(id) { + if let hir::ItemImpl(_, _, _, None, _, _) = parent_scope.node { + // this impl scope implements a trait, do not recomend + // using explicit lifetimes (#37363) + return; } - _ => None, + } + if let hir::ImplItemKind::Method(ref sig, _) = item.node { + Some((&sig.decl, + &sig.generics, + sig.unsafety, + sig.constness, + item.name, + item.span)) + } else { + None } }, ast_map::NodeTraitItem(item) => { @@ -1079,12 +1087,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { item.name, item.span)) } - _ => None + _ => None, } } - _ => None + _ => None, }, - None => None + None => None, }; let (fn_decl, generics, unsafety, constness, name, span) = node_inner.expect("expect item fn"); @@ -1436,7 +1444,7 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> { match self.tcx.expect_def(cur_ty.id) { Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) | Def::Union(did) => { - let generics = self.tcx.lookup_generics(did); + let generics = self.tcx.item_generics(did); let expected = generics.regions.len() as u32; @@ -1688,18 +1696,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { if let Some((expected, found)) = self.values_str(&trace.values) { // FIXME: do we want a "the" here? err.span_note( - trace.origin.span(), + trace.cause.span, &format!("...so that {} (expected {}, found {})", - trace.origin.as_requirement_str(), expected, found)); + trace.cause.as_requirement_str(), expected, found)); } else { // FIXME: this really should be handled at some earlier stage. Our // handling of region checking when type errors are present is // *terrible*. err.span_note( - trace.origin.span(), + trace.cause.span, &format!("...so that {}", - trace.origin.as_requirement_str())); + trace.cause.as_requirement_str())); } } infer::Reborrow(span) => { @@ -1954,3 +1962,45 @@ fn name_to_dummy_lifetime(name: ast::Name) -> hir::Lifetime { span: syntax_pos::DUMMY_SP, name: name } } + +impl<'tcx> ObligationCause<'tcx> { + fn as_failure_str(&self) -> &'static str { + use traits::ObligationCauseCode::*; + match self.code { + CompareImplMethodObligation { .. } => "method not compatible with trait", + MatchExpressionArm { source, .. } => match source { + hir::MatchSource::IfLetDesugar{..} => "`if let` arms have incompatible types", + _ => "match arms have incompatible types", + }, + IfExpression => "if and else have incompatible types", + IfExpressionWithNoElse => "if may be missing an else clause", + EquatePredicate => "equality predicate not satisfied", + MainFunctionType => "main function has wrong type", + StartFunctionType => "start function has wrong type", + IntrinsicType => "intrinsic has wrong type", + MethodReceiver => "mismatched method receiver", + _ => "mismatched types", + } + } + + fn as_requirement_str(&self) -> &'static str { + use traits::ObligationCauseCode::*; + match self.code { + CompareImplMethodObligation { .. } => "method type is compatible with trait", + ExprAssignable => "expression is assignable", + MatchExpressionArm { source, .. } => match source { + hir::MatchSource::IfLetDesugar{..} => "`if let` arms have compatible types", + _ => "match arms have compatible types", + }, + IfExpression => "if and else have compatible types", + IfExpressionWithNoElse => "if missing an else returns ()", + EquatePredicate => "equality where clause is satisfied", + MainFunctionType => "`main` function has the correct type", + StartFunctionType => "`start` function has the correct type", + IntrinsicType => "intrinsic has the correct type", + MethodReceiver => "method receiver has the correct type", + _ => "types are compatible", + } + } +} + diff --git a/src/librustc/infer/fudge.rs b/src/librustc/infer/fudge.rs new file mode 100644 index 000000000000..806b94486615 --- /dev/null +++ b/src/librustc/infer/fudge.rs @@ -0,0 +1,137 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use ty::{self, TyCtxt}; +use ty::fold::{TypeFoldable, TypeFolder}; + +use super::InferCtxt; +use super::RegionVariableOrigin; + +impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { + /// This rather funky routine is used while processing expected + /// types. What happens here is that we want to propagate a + /// coercion through the return type of a fn to its + /// argument. Consider the type of `Option::Some`, which is + /// basically `for fn(T) -> Option`. So if we have an + /// expression `Some(&[1, 2, 3])`, and that has the expected type + /// `Option<&[u32]>`, we would like to type check `&[1, 2, 3]` + /// with the expectation of `&[u32]`. This will cause us to coerce + /// from `&[u32; 3]` to `&[u32]` and make the users life more + /// pleasant. + /// + /// The way we do this is using `fudge_regions_if_ok`. What the + /// routine actually does is to start a snapshot and execute the + /// closure `f`. In our example above, what this closure will do + /// is to unify the expectation (`Option<&[u32]>`) with the actual + /// return type (`Option`, where `?T` represents the variable + /// instantiated for `T`). This will cause `?T` to be unified + /// with `&?a [u32]`, where `?a` is a fresh lifetime variable. The + /// input type (`?T`) is then returned by `f()`. + /// + /// At this point, `fudge_regions_if_ok` will normalize all type + /// variables, converting `?T` to `&?a [u32]` and end the + /// snapshot. The problem is that we can't just return this type + /// out, because it references the region variable `?a`, and that + /// region variable was popped when we popped the snapshot. + /// + /// So what we do is to keep a list (`region_vars`, in the code below) + /// of region variables created during the snapshot (here, `?a`). We + /// fold the return value and replace any such regions with a *new* + /// region variable (e.g., `?b`) and return the result (`&?b [u32]`). + /// This can then be used as the expectation for the fn argument. + /// + /// The important point here is that, for soundness purposes, the + /// regions in question are not particularly important. We will + /// use the expected types to guide coercions, but we will still + /// type-check the resulting types from those coercions against + /// the actual types (`?T`, `Option(&self, + origin: &RegionVariableOrigin, + f: F) -> Result where + F: FnOnce() -> Result, + T: TypeFoldable<'tcx>, + { + let (region_vars, value) = self.probe(|snapshot| { + let vars_at_start = self.type_variables.borrow().num_vars(); + + match f() { + Ok(value) => { + let value = self.resolve_type_vars_if_possible(&value); + + // At this point, `value` could in principle refer + // to regions that have been created during the + // snapshot (we assert below that `f()` does not + // create any new type variables, so there + // shouldn't be any of those). Once we exit + // `probe()`, those are going to be popped, so we + // will have to eliminate any references to them. + + assert_eq!(self.type_variables.borrow().num_vars(), vars_at_start, + "type variables were created during fudge_regions_if_ok"); + let region_vars = + self.region_vars.vars_created_since_snapshot( + &snapshot.region_vars_snapshot); + + Ok((region_vars, value)) + } + Err(e) => Err(e), + } + })?; + + // At this point, we need to replace any of the now-popped + // region variables that appear in `value` with a fresh region + // variable. We can't do this during the probe because they + // would just get popped then too. =) + + // Micro-optimization: if no variables have been created, then + // `value` can't refer to any of them. =) So we can just return it. + if region_vars.is_empty() { + return Ok(value); + } + + let mut fudger = RegionFudger { + infcx: self, + region_vars: ®ion_vars, + origin: origin + }; + + Ok(value.fold_with(&mut fudger)) + } +} + +pub struct RegionFudger<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { + infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + region_vars: &'a Vec, + origin: &'a RegionVariableOrigin, +} + +impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFudger<'a, 'gcx, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { + self.infcx.tcx + } + + fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region { + match *r { + ty::ReVar(v) if self.region_vars.contains(&v) => { + self.infcx.next_region_var(self.origin.clone()) + } + _ => { + r + } + } + } +} diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index 737ce8bdf681..08e522f5fd6e 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -58,7 +58,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { // Start a snapshot so we can examine "all bindings that were // created as part of this type comparison". return self.infcx.commit_if_ok(|snapshot| { - let span = self.trace.origin.span(); + let span = self.trace.cause.span; // First, we instantiate each bound region in the subtype with a fresh // region variable. @@ -230,7 +230,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { // created as part of this type comparison". return self.infcx.commit_if_ok(|snapshot| { // Instantiate each bound region with a fresh region variable. - let span = self.trace.origin.span(); + let span = self.trace.cause.span; let (a_with_fresh, a_map) = self.infcx.replace_late_bound_regions_with_fresh_var( span, HigherRankedType, a); @@ -247,7 +247,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { // Generalize the regions appearing in result0 if possible let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot); - let span = self.trace.origin.span(); + let span = self.trace.cause.span; let result1 = fold_regions_in( self.tcx(), @@ -325,10 +325,10 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { // Instantiate each bound region with a fresh region variable. let (a_with_fresh, a_map) = self.infcx.replace_late_bound_regions_with_fresh_var( - self.trace.origin.span(), HigherRankedType, a); + self.trace.cause.span, HigherRankedType, a); let (b_with_fresh, b_map) = self.infcx.replace_late_bound_regions_with_fresh_var( - self.trace.origin.span(), HigherRankedType, b); + self.trace.cause.span, HigherRankedType, b); let a_vars = var_ids(self, &a_map); let b_vars = var_ids(self, &b_map); @@ -341,7 +341,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { // Generalize the regions appearing in result0 if possible let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot); - let span = self.trace.origin.span(); + let span = self.trace.cause.span; let result1 = fold_regions_in( self.tcx(), @@ -463,7 +463,7 @@ fn var_ids<'a, 'gcx, 'tcx>(fields: &CombineFields<'a, 'gcx, 'tcx>, ty::ReVar(r) => { r } _ => { span_bug!( - fields.trace.origin.span(), + fields.trace.cause.span, "found non-region-vid: {:?}", r); } diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index ebafd206e26e..6ae104d79122 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -32,7 +32,7 @@ use ty::{self, Ty, TyCtxt}; use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use ty::relate::{Relate, RelateResult, TypeRelation}; -use traits::{self, PredicateObligations, Reveal}; +use traits::{self, ObligationCause, PredicateObligations, Reveal}; use rustc_data_structures::unify::{self, UnificationTable}; use std::cell::{Cell, RefCell, Ref, RefMut}; use std::fmt; @@ -50,6 +50,7 @@ mod bivariate; mod combine; mod equate; pub mod error_reporting; +mod fudge; mod glb; mod higher_ranked; pub mod lattice; @@ -172,90 +173,6 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// region that each late-bound region was replaced with. pub type SkolemizationMap<'tcx> = FxHashMap; -/// Why did we require that the two types be related? -/// -/// See `error_reporting.rs` for more details -#[derive(Clone, Copy, Debug)] -pub enum TypeOrigin { - // Not yet categorized in a better way - Misc(Span), - - // Checking that method of impl is compatible with trait - MethodCompatCheck(Span), - - // Checking that this expression can be assigned where it needs to be - // FIXME(eddyb) #11161 is the original Expr required? - ExprAssignable(Span), - - // Relating trait type parameters to those found in impl etc - RelateOutputImplTypes(Span), - - // Computing common supertype in the arms of a match expression - MatchExpressionArm(Span, Span, hir::MatchSource), - - // Computing common supertype in an if expression - IfExpression(Span), - - // Computing common supertype of an if expression with no else counter-part - IfExpressionWithNoElse(Span), - - // `where a == b` - EquatePredicate(Span), - - // `main` has wrong type - MainFunctionType(Span), - - // `start` has wrong type - StartFunctionType(Span), - - // intrinsic has wrong type - IntrinsicType(Span), - - // method receiver - MethodReceiver(Span), -} - -impl TypeOrigin { - fn as_failure_str(&self) -> &'static str { - match self { - &TypeOrigin::Misc(_) | - &TypeOrigin::RelateOutputImplTypes(_) | - &TypeOrigin::ExprAssignable(_) => "mismatched types", - &TypeOrigin::MethodCompatCheck(_) => "method not compatible with trait", - &TypeOrigin::MatchExpressionArm(.., source) => match source { - hir::MatchSource::IfLetDesugar{..} => "`if let` arms have incompatible types", - _ => "match arms have incompatible types", - }, - &TypeOrigin::IfExpression(_) => "if and else have incompatible types", - &TypeOrigin::IfExpressionWithNoElse(_) => "if may be missing an else clause", - &TypeOrigin::EquatePredicate(_) => "equality predicate not satisfied", - &TypeOrigin::MainFunctionType(_) => "main function has wrong type", - &TypeOrigin::StartFunctionType(_) => "start function has wrong type", - &TypeOrigin::IntrinsicType(_) => "intrinsic has wrong type", - &TypeOrigin::MethodReceiver(_) => "mismatched method receiver", - } - } - - fn as_requirement_str(&self) -> &'static str { - match self { - &TypeOrigin::Misc(_) => "types are compatible", - &TypeOrigin::MethodCompatCheck(_) => "method type is compatible with trait", - &TypeOrigin::ExprAssignable(_) => "expression is assignable", - &TypeOrigin::RelateOutputImplTypes(_) => { - "trait type parameters matches those specified on the impl" - } - &TypeOrigin::MatchExpressionArm(..) => "match arms have compatible types", - &TypeOrigin::IfExpression(_) => "if and else have compatible types", - &TypeOrigin::IfExpressionWithNoElse(_) => "if missing an else returns ()", - &TypeOrigin::EquatePredicate(_) => "equality where clause is satisfied", - &TypeOrigin::MainFunctionType(_) => "`main` function has the correct type", - &TypeOrigin::StartFunctionType(_) => "`start` function has the correct type", - &TypeOrigin::IntrinsicType(_) => "intrinsic has the correct type", - &TypeOrigin::MethodReceiver(_) => "method receiver has the correct type", - } - } -} - /// See `error_reporting.rs` for more details #[derive(Clone, Debug)] pub enum ValuePairs<'tcx> { @@ -270,7 +187,7 @@ pub enum ValuePairs<'tcx> { /// See `error_reporting.rs` for more details. #[derive(Clone)] pub struct TypeTrace<'tcx> { - origin: TypeOrigin, + cause: ObligationCause<'tcx>, values: ValuePairs<'tcx>, } @@ -986,49 +903,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { r } - /// Execute `f` and commit only the region bindings if successful. - /// The function f must be very careful not to leak any non-region - /// variables that get created. - pub fn commit_regions_if_ok(&self, f: F) -> Result where - F: FnOnce() -> Result - { - debug!("commit_regions_if_ok()"); - let CombinedSnapshot { projection_cache_snapshot, - type_snapshot, - int_snapshot, - float_snapshot, - region_vars_snapshot, - obligations_in_snapshot } = self.start_snapshot(); - - let r = self.commit_if_ok(|_| f()); - - debug!("commit_regions_if_ok: rolling back everything but regions"); - - assert!(!self.obligations_in_snapshot.get()); - self.obligations_in_snapshot.set(obligations_in_snapshot); - - // Roll back any non-region bindings - they should be resolved - // inside `f`, with, e.g. `resolve_type_vars_if_possible`. - self.projection_cache - .borrow_mut() - .rollback_to(projection_cache_snapshot); - self.type_variables - .borrow_mut() - .rollback_to(type_snapshot); - self.int_unification_table - .borrow_mut() - .rollback_to(int_snapshot); - self.float_unification_table - .borrow_mut() - .rollback_to(float_snapshot); - - // Commit region vars that may escape through resolved types. - self.region_vars - .commit(region_vars_snapshot); - - r - } - /// Execute `f` then unroll any bindings it creates pub fn probe(&self, f: F) -> R where F: FnOnce(&CombinedSnapshot) -> R, @@ -1049,14 +923,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn sub_types(&self, a_is_expected: bool, - origin: TypeOrigin, + cause: &ObligationCause<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, ()> { debug!("sub_types({:?} <: {:?})", a, b); self.commit_if_ok(|_| { - let trace = TypeTrace::types(origin, a_is_expected, a, b); + let trace = TypeTrace::types(cause, a_is_expected, a, b); self.sub(a_is_expected, trace, &a, &b).map(|ok| ok.unit()) }) } @@ -1067,7 +941,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { -> UnitResult<'tcx> { self.probe(|_| { - let origin = TypeOrigin::Misc(syntax_pos::DUMMY_SP); + let origin = &ObligationCause::dummy(); let trace = TypeTrace::types(origin, true, a, b); self.sub(true, trace, &a, &b).map(|InferOk { obligations, .. }| { // FIXME(#32730) propagate obligations @@ -1078,20 +952,20 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn eq_types(&self, a_is_expected: bool, - origin: TypeOrigin, + cause: &ObligationCause<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, ()> { self.commit_if_ok(|_| { - let trace = TypeTrace::types(origin, a_is_expected, a, b); + let trace = TypeTrace::types(cause, a_is_expected, a, b); self.equate(a_is_expected, trace, &a, &b).map(|ok| ok.unit()) }) } pub fn eq_trait_refs(&self, a_is_expected: bool, - origin: TypeOrigin, + cause: &ObligationCause<'tcx>, a: ty::TraitRef<'tcx>, b: ty::TraitRef<'tcx>) -> InferResult<'tcx, ()> @@ -1099,7 +973,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { debug!("eq_trait_refs({:?} = {:?})", a, b); self.commit_if_ok(|_| { let trace = TypeTrace { - origin: origin, + cause: cause.clone(), values: TraitRefs(ExpectedFound::new(a_is_expected, a, b)) }; self.equate(a_is_expected, trace, &a, &b).map(|ok| ok.unit()) @@ -1108,22 +982,22 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn eq_impl_headers(&self, a_is_expected: bool, - origin: TypeOrigin, + cause: &ObligationCause<'tcx>, a: &ty::ImplHeader<'tcx>, b: &ty::ImplHeader<'tcx>) -> InferResult<'tcx, ()> { debug!("eq_impl_header({:?} = {:?})", a, b); match (a.trait_ref, b.trait_ref) { - (Some(a_ref), Some(b_ref)) => self.eq_trait_refs(a_is_expected, origin, a_ref, b_ref), - (None, None) => self.eq_types(a_is_expected, origin, a.self_ty, b.self_ty), + (Some(a_ref), Some(b_ref)) => self.eq_trait_refs(a_is_expected, cause, a_ref, b_ref), + (None, None) => self.eq_types(a_is_expected, cause, a.self_ty, b.self_ty), _ => bug!("mk_eq_impl_headers given mismatched impl kinds"), } } pub fn sub_poly_trait_refs(&self, a_is_expected: bool, - origin: TypeOrigin, + cause: ObligationCause<'tcx>, a: ty::PolyTraitRef<'tcx>, b: ty::PolyTraitRef<'tcx>) -> InferResult<'tcx, ()> @@ -1131,7 +1005,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { debug!("sub_poly_trait_refs({:?} <: {:?})", a, b); self.commit_if_ok(|_| { let trace = TypeTrace { - origin: origin, + cause: cause, values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a, b)) }; self.sub(a_is_expected, trace, &a, &b).map(|ok| ok.unit()) @@ -1147,16 +1021,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } pub fn equality_predicate(&self, - span: Span, + cause: &ObligationCause<'tcx>, predicate: &ty::PolyEquatePredicate<'tcx>) -> InferResult<'tcx, ()> { self.commit_if_ok(|snapshot| { let (ty::EquatePredicate(a, b), skol_map) = self.skolemize_late_bound_regions(predicate, snapshot); - let origin = TypeOrigin::EquatePredicate(span); - let eqty_ok = self.eq_types(false, origin, a, b)?; - self.leak_check(false, span, &skol_map, snapshot)?; + let cause_span = cause.span; + let eqty_ok = self.eq_types(false, cause, a, b)?; + self.leak_check(false, cause_span, &skol_map, snapshot)?; self.pop_skolemized(skol_map, snapshot); Ok(eqty_ok.unit()) }) @@ -1193,10 +1067,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tcx.mk_var(self.next_ty_var_id(true)) } - pub fn next_ty_vars(&self, n: usize) -> Vec> { - (0..n).map(|_i| self.next_ty_var()).collect() - } - pub fn next_int_var_id(&self) -> IntVid { self.int_unification_table .borrow_mut() @@ -1490,26 +1360,21 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } pub fn report_mismatched_types(&self, - origin: TypeOrigin, + cause: &ObligationCause<'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>, err: TypeError<'tcx>) { - let trace = TypeTrace { - origin: origin, - values: Types(ExpectedFound { - expected: expected, - found: actual - }) - }; + let trace = TypeTrace::types(cause, true, expected, actual); self.report_and_explain_type_error(trace, &err).emit(); } pub fn report_conflicting_default_types(&self, span: Span, + body_id: ast::NodeId, expected: type_variable::Default<'tcx>, actual: type_variable::Default<'tcx>) { let trace = TypeTrace { - origin: TypeOrigin::Misc(span), + cause: ObligationCause::misc(span, body_id), values: Types(ExpectedFound { expected: expected.ty, found: actual.ty @@ -1554,15 +1419,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// See `higher_ranked_match` in `higher_ranked/mod.rs` for more /// details. pub fn match_poly_projection_predicate(&self, - origin: TypeOrigin, + cause: ObligationCause<'tcx>, match_a: ty::PolyProjectionPredicate<'tcx>, match_b: ty::TraitRef<'tcx>) -> InferResult<'tcx, HrMatchResult>> { - let span = origin.span(); + let span = cause.span; let match_trait_ref = match_a.skip_binder().projection_ty.trait_ref; let trace = TypeTrace { - origin: origin, + cause: cause, values: TraitRefs(ExpectedFound::new(true, match_trait_ref, match_b)) }; @@ -1700,7 +1565,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { { if let InferTables::Local(tables) = self.tables { if let Some(ty) = tables.borrow().closure_tys.get(&def_id) { - return ty.subst(self.tcx, substs.func_substs); + return ty.subst(self.tcx, substs.substs); } } @@ -1711,23 +1576,23 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> TypeTrace<'tcx> { pub fn span(&self) -> Span { - self.origin.span() + self.cause.span } - pub fn types(origin: TypeOrigin, + pub fn types(cause: &ObligationCause<'tcx>, a_is_expected: bool, a: Ty<'tcx>, b: Ty<'tcx>) -> TypeTrace<'tcx> { TypeTrace { - origin: origin, + cause: cause.clone(), values: Types(ExpectedFound::new(a_is_expected, a, b)) } } pub fn dummy(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> TypeTrace<'tcx> { TypeTrace { - origin: TypeOrigin::Misc(syntax_pos::DUMMY_SP), + cause: ObligationCause::dummy(), values: Types(ExpectedFound { expected: tcx.types.err, found: tcx.types.err, @@ -1738,26 +1603,7 @@ impl<'a, 'gcx, 'tcx> TypeTrace<'tcx> { impl<'tcx> fmt::Debug for TypeTrace<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "TypeTrace({:?})", self.origin) - } -} - -impl TypeOrigin { - pub fn span(&self) -> Span { - match *self { - TypeOrigin::MethodCompatCheck(span) => span, - TypeOrigin::ExprAssignable(span) => span, - TypeOrigin::Misc(span) => span, - TypeOrigin::RelateOutputImplTypes(span) => span, - TypeOrigin::MatchExpressionArm(match_span, ..) => match_span, - TypeOrigin::IfExpression(span) => span, - TypeOrigin::IfExpressionWithNoElse(span) => span, - TypeOrigin::EquatePredicate(span) => span, - TypeOrigin::MainFunctionType(span) => span, - TypeOrigin::StartFunctionType(span) => span, - TypeOrigin::IntrinsicType(span) => span, - TypeOrigin::MethodReceiver(span) => span, - } + write!(f, "TypeTrace({:?})", self.cause) } } @@ -1834,16 +1680,6 @@ impl RegionVariableOrigin { } } -impl<'tcx> TypeFoldable<'tcx> for TypeOrigin { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _folder: &mut F) -> Self { - self.clone() - } - - fn super_visit_with>(&self, _visitor: &mut V) -> bool { - false - } -} - impl<'tcx> TypeFoldable<'tcx> for ValuePairs<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { match *self { @@ -1871,12 +1707,12 @@ impl<'tcx> TypeFoldable<'tcx> for ValuePairs<'tcx> { impl<'tcx> TypeFoldable<'tcx> for TypeTrace<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { TypeTrace { - origin: self.origin.fold_with(folder), + cause: self.cause.fold_with(folder), values: self.values.fold_with(folder) } } fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.origin.visit_with(visitor) || self.values.visit_with(visitor) + self.cause.visit_with(visitor) || self.values.visit_with(visitor) } } diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs index 159de2faced5..dae30ea97c80 100644 --- a/src/librustc/infer/sub.rs +++ b/src/librustc/infer/sub.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::combine::CombineFields; use super::SubregionOrigin; +use super::combine::CombineFields; use super::type_variable::{SubtypeOf, SupertypeOf}; use ty::{self, Ty, TyCtxt}; @@ -111,11 +111,13 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> -> RelateResult<'tcx, &'tcx ty::Region> { debug!("{}.regions({:?}, {:?}) self.cause={:?}", self.tag(), a, b, self.fields.cause); + // FIXME -- we have more fine-grained information available // from the "cause" field, we could perhaps give more tailored // error messages. let origin = SubregionOrigin::Subtype(self.fields.trace.clone()); self.fields.infcx.region_vars.make_subregion(origin, a, b); + Ok(a) } diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 3856ea420b0f..804765ec8811 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -184,6 +184,10 @@ impl<'tcx> TypeVariableTable<'tcx> { v } + pub fn num_vars(&self) -> usize { + self.values.len() + } + pub fn root_var(&mut self, vid: ty::TyVid) -> ty::TyVid { self.eq_relations.find(vid) } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index fa49e5c72895..8c0d70c6d602 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -40,6 +40,7 @@ #![feature(rustc_private)] #![feature(slice_patterns)] #![feature(staged_api)] +#![feature(unboxed_closures)] #![cfg_attr(stage0, feature(question_mark))] #![cfg_attr(test, feature(test))] diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index f44f82860077..a490b58964a7 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -106,7 +106,7 @@ pub trait IntoEarlyLint { fn into_early_lint(self, id: LintId) -> EarlyLint; } -impl<'a> IntoEarlyLint for (Span, &'a str) { +impl<'a, S: Into> IntoEarlyLint for (S, &'a str) { fn into_early_lint(self, id: LintId) -> EarlyLint { let (span, msg) = self; let mut diagnostic = Diagnostic::new(errors::Level::Warning, msg); @@ -530,7 +530,10 @@ pub trait LintContext: Sized { }) } - fn lookup_and_emit(&self, lint: &'static Lint, span: Option, msg: &str) { + fn lookup_and_emit>(&self, + lint: &'static Lint, + span: Option, + msg: &str) { let (level, src) = match self.level_src(lint) { None => return, Some(pair) => pair, @@ -553,7 +556,7 @@ pub trait LintContext: Sized { } /// Emit a lint at the appropriate level, for a particular span. - fn span_lint(&self, lint: &'static Lint, span: Span, msg: &str) { + fn span_lint>(&self, lint: &'static Lint, span: S, msg: &str) { self.lookup_and_emit(lint, Some(span), msg); } @@ -601,7 +604,7 @@ pub trait LintContext: Sized { /// Emit a lint at the appropriate level, with no associated span. fn lint(&self, lint: &'static Lint, msg: &str) { - self.lookup_and_emit(lint, None, msg); + self.lookup_and_emit(lint, None as Option, msg); } /// Merge the lints specified by any lint attributes into the @@ -789,16 +792,15 @@ impl<'a> LintContext for EarlyContext<'a> { } } -impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { +impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { /// Because lints are scoped lexically, we want to walk nested /// items in the context of the outer item, so enable /// deep-walking. - fn visit_nested_item(&mut self, item: hir::ItemId) { - let tcx = self.tcx; - self.visit_item(tcx.map.expect_item(item.id)) + fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> { + Some(&self.tcx.map) } - fn visit_item(&mut self, it: &hir::Item) { + fn visit_item(&mut self, it: &'tcx hir::Item) { self.with_lint_attrs(&it.attrs, |cx| { run_lints!(cx, check_item, late_passes, it); cx.visit_ids(|v| v.visit_item(it)); @@ -807,7 +809,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { }) } - fn visit_foreign_item(&mut self, it: &hir::ForeignItem) { + fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem) { self.with_lint_attrs(&it.attrs, |cx| { run_lints!(cx, check_foreign_item, late_passes, it); hir_visit::walk_foreign_item(cx, it); @@ -815,19 +817,19 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { }) } - fn visit_pat(&mut self, p: &hir::Pat) { + fn visit_pat(&mut self, p: &'tcx hir::Pat) { run_lints!(self, check_pat, late_passes, p); hir_visit::walk_pat(self, p); } - fn visit_expr(&mut self, e: &hir::Expr) { + fn visit_expr(&mut self, e: &'tcx hir::Expr) { self.with_lint_attrs(&e.attrs, |cx| { run_lints!(cx, check_expr, late_passes, e); hir_visit::walk_expr(cx, e); }) } - fn visit_stmt(&mut self, s: &hir::Stmt) { + fn visit_stmt(&mut self, s: &'tcx hir::Stmt) { // statement attributes are actually just attributes on one of // - item // - local @@ -837,17 +839,17 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { hir_visit::walk_stmt(self, s); } - fn visit_fn(&mut self, fk: hir_visit::FnKind<'v>, decl: &'v hir::FnDecl, - body: &'v hir::Expr, span: Span, id: ast::NodeId) { + fn visit_fn(&mut self, fk: hir_visit::FnKind<'tcx>, decl: &'tcx hir::FnDecl, + body: &'tcx hir::Expr, span: Span, id: ast::NodeId) { run_lints!(self, check_fn, late_passes, fk, decl, body, span, id); hir_visit::walk_fn(self, fk, decl, body, span, id); run_lints!(self, check_fn_post, late_passes, fk, decl, body, span, id); } fn visit_variant_data(&mut self, - s: &hir::VariantData, + s: &'tcx hir::VariantData, name: ast::Name, - g: &hir::Generics, + g: &'tcx hir::Generics, item_id: ast::NodeId, _: Span) { run_lints!(self, check_struct_def, late_passes, s, name, g, item_id); @@ -855,14 +857,17 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { run_lints!(self, check_struct_def_post, late_passes, s, name, g, item_id); } - fn visit_struct_field(&mut self, s: &hir::StructField) { + fn visit_struct_field(&mut self, s: &'tcx hir::StructField) { self.with_lint_attrs(&s.attrs, |cx| { run_lints!(cx, check_struct_field, late_passes, s); hir_visit::walk_struct_field(cx, s); }) } - fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics, item_id: ast::NodeId) { + fn visit_variant(&mut self, + v: &'tcx hir::Variant, + g: &'tcx hir::Generics, + item_id: ast::NodeId) { self.with_lint_attrs(&v.node.attrs, |cx| { run_lints!(cx, check_variant, late_passes, v, g); hir_visit::walk_variant(cx, v, g, item_id); @@ -870,7 +875,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { }) } - fn visit_ty(&mut self, t: &hir::Ty) { + fn visit_ty(&mut self, t: &'tcx hir::Ty) { run_lints!(self, check_ty, late_passes, t); hir_visit::walk_ty(self, t); } @@ -879,45 +884,45 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { run_lints!(self, check_name, late_passes, sp, name); } - fn visit_mod(&mut self, m: &hir::Mod, s: Span, n: ast::NodeId) { + fn visit_mod(&mut self, m: &'tcx hir::Mod, s: Span, n: ast::NodeId) { run_lints!(self, check_mod, late_passes, m, s, n); hir_visit::walk_mod(self, m, n); run_lints!(self, check_mod_post, late_passes, m, s, n); } - fn visit_local(&mut self, l: &hir::Local) { + fn visit_local(&mut self, l: &'tcx hir::Local) { self.with_lint_attrs(&l.attrs, |cx| { run_lints!(cx, check_local, late_passes, l); hir_visit::walk_local(cx, l); }) } - fn visit_block(&mut self, b: &hir::Block) { + fn visit_block(&mut self, b: &'tcx hir::Block) { run_lints!(self, check_block, late_passes, b); hir_visit::walk_block(self, b); run_lints!(self, check_block_post, late_passes, b); } - fn visit_arm(&mut self, a: &hir::Arm) { + fn visit_arm(&mut self, a: &'tcx hir::Arm) { run_lints!(self, check_arm, late_passes, a); hir_visit::walk_arm(self, a); } - fn visit_decl(&mut self, d: &hir::Decl) { + fn visit_decl(&mut self, d: &'tcx hir::Decl) { run_lints!(self, check_decl, late_passes, d); hir_visit::walk_decl(self, d); } - fn visit_expr_post(&mut self, e: &hir::Expr) { + fn visit_expr_post(&mut self, e: &'tcx hir::Expr) { run_lints!(self, check_expr_post, late_passes, e); } - fn visit_generics(&mut self, g: &hir::Generics) { + fn visit_generics(&mut self, g: &'tcx hir::Generics) { run_lints!(self, check_generics, late_passes, g); hir_visit::walk_generics(self, g); } - fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) { + fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { self.with_lint_attrs(&trait_item.attrs, |cx| { run_lints!(cx, check_trait_item, late_passes, trait_item); cx.visit_ids(|v| hir_visit::walk_trait_item(v, trait_item)); @@ -926,7 +931,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { }); } - fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) { + fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { self.with_lint_attrs(&impl_item.attrs, |cx| { run_lints!(cx, check_impl_item, late_passes, impl_item); cx.visit_ids(|v| hir_visit::walk_impl_item(v, impl_item)); @@ -935,20 +940,20 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { }); } - fn visit_lifetime(&mut self, lt: &hir::Lifetime) { + fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) { run_lints!(self, check_lifetime, late_passes, lt); } - fn visit_lifetime_def(&mut self, lt: &hir::LifetimeDef) { + fn visit_lifetime_def(&mut self, lt: &'tcx hir::LifetimeDef) { run_lints!(self, check_lifetime_def, late_passes, lt); } - fn visit_path(&mut self, p: &hir::Path, id: ast::NodeId) { + fn visit_path(&mut self, p: &'tcx hir::Path, id: ast::NodeId) { run_lints!(self, check_path, late_passes, p, id); hir_visit::walk_path(self, p); } - fn visit_path_list_item(&mut self, prefix: &hir::Path, item: &hir::PathListItem) { + fn visit_path_list_item(&mut self, prefix: &'tcx hir::Path, item: &'tcx hir::PathListItem) { run_lints!(self, check_path_list_item, late_passes, item); hir_visit::walk_path_list_item(self, prefix, item); } @@ -1113,7 +1118,6 @@ struct IdVisitor<'a, 'b: 'a, 'tcx: 'a+'b> { // Output any lints that were previously added to the session. impl<'a, 'b, 'tcx, 'v> hir_visit::Visitor<'v> for IdVisitor<'a, 'b, 'tcx> { - fn visit_id(&mut self, id: ast::NodeId) { if let Some(lints) = self.cx.sess().lints.borrow_mut().remove(&id) { debug!("LateContext::visit_id: id={:?} lints={:?}", id, lints); diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 3583ccdb97ba..f61978271e7f 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -89,6 +89,13 @@ pub enum NativeLibraryKind { NativeUnknown, // default way to specify a dynamic library } +#[derive(Clone, Hash, RustcEncodable, RustcDecodable)] +pub struct NativeLibrary { + pub kind: NativeLibraryKind, + pub name: String, + pub cfg: Option>, +} + /// The data we save and restore about an inlined item or method. This is not /// part of the AST that we parse from a file, but it becomes part of the tree /// that we trans. @@ -204,7 +211,7 @@ pub trait CrateStore<'tcx> { fn crate_hash(&self, cnum: CrateNum) -> Svh; fn crate_disambiguator(&self, cnum: CrateNum) -> InternedString; fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option; - fn native_libraries(&self, cnum: CrateNum) -> Vec<(NativeLibraryKind, String)>; + fn native_libraries(&self, cnum: CrateNum) -> Vec; fn reachable_ids(&self, cnum: CrateNum) -> Vec; fn is_no_builtins(&self, cnum: CrateNum) -> bool; @@ -231,7 +238,7 @@ pub trait CrateStore<'tcx> { // This is basically a 1-based range of ints, which is a little // silly - I may fix that. fn crates(&self) -> Vec; - fn used_libraries(&self) -> Vec<(String, NativeLibraryKind)>; + fn used_libraries(&self) -> Vec; fn used_link_args(&self) -> Vec; // utility functions @@ -377,7 +384,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { -> InternedString { bug!("crate_disambiguator") } fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option { bug!("plugin_registrar_fn") } - fn native_libraries(&self, cnum: CrateNum) -> Vec<(NativeLibraryKind, String)> + fn native_libraries(&self, cnum: CrateNum) -> Vec { bug!("native_libraries") } fn reachable_ids(&self, cnum: CrateNum) -> Vec { bug!("reachable_ids") } fn is_no_builtins(&self, cnum: CrateNum) -> bool { bug!("is_no_builtins") } @@ -412,7 +419,9 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { // This is basically a 1-based range of ints, which is a little // silly - I may fix that. fn crates(&self) -> Vec { vec![] } - fn used_libraries(&self) -> Vec<(String, NativeLibraryKind)> { vec![] } + fn used_libraries(&self) -> Vec { + vec![] + } fn used_link_args(&self) -> Vec { vec![] } // utility functions diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 23fc5911259d..991398813752 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -16,6 +16,7 @@ use dep_graph::DepNode; use hir::map as ast_map; use hir::{self, pat_util, PatKind}; use hir::intravisit::{self, Visitor}; +use hir::itemlikevisit::ItemLikeVisitor; use middle::privacy; use ty::{self, TyCtxt}; @@ -329,11 +330,12 @@ fn has_allow_dead_code_or_lang_attr(attrs: &[ast::Attribute]) -> bool { // or // 2) We are not sure to be live or not // * Implementation of a trait method -struct LifeSeeder { - worklist: Vec +struct LifeSeeder<'k> { + worklist: Vec, + krate: &'k hir::Crate, } -impl<'v> Visitor<'v> for LifeSeeder { +impl<'v, 'k> ItemLikeVisitor<'v> for LifeSeeder<'k> { fn visit_item(&mut self, item: &hir::Item) { let allow_dead_code = has_allow_dead_code_or_lang_attr(&item.attrs); if allow_dead_code { @@ -357,17 +359,22 @@ impl<'v> Visitor<'v> for LifeSeeder { } } } - hir::ItemImpl(.., ref opt_trait, _, ref impl_items) => { - for impl_item in impl_items { + hir::ItemImpl(.., ref opt_trait, _, ref impl_item_refs) => { + for impl_item_ref in impl_item_refs { + let impl_item = self.krate.impl_item(impl_item_ref.id); if opt_trait.is_some() || has_allow_dead_code_or_lang_attr(&impl_item.attrs) { - self.worklist.push(impl_item.id); + self.worklist.push(impl_item_ref.id.node_id); } } } _ => () } } + + fn visit_impl_item(&mut self, _item: &hir::ImplItem) { + // ignore: we are handling this in `visit_item` above + } } fn create_and_seed_worklist<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -386,9 +393,10 @@ fn create_and_seed_worklist<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Seed implemented trait items let mut life_seeder = LifeSeeder { - worklist: worklist + worklist: worklist, + krate: krate, }; - krate.visit_all_items(&mut life_seeder); + krate.visit_all_item_likes(&mut life_seeder); return life_seeder.worklist; } @@ -433,7 +441,7 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { } fn should_warn_about_field(&mut self, field: &hir::StructField) -> bool { - let field_type = self.tcx.tables().node_id_to_type(field.id); + let field_type = self.tcx.item_type(self.tcx.map.local_def_id(field.id)); let is_marker_field = match field_type.ty_to_def_id() { Some(def_id) => self.tcx.lang_items.items().iter().any(|item| *item == Some(def_id)), _ => false @@ -503,17 +511,16 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { } } -impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> { +impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> { /// Walk nested items in place so that we don't report dead-code /// on inner functions when the outer function is already getting /// an error. We could do this also by checking the parents, but /// this is how the code is setup and it seems harmless enough. - fn visit_nested_item(&mut self, item: hir::ItemId) { - let tcx = self.tcx; - self.visit_item(tcx.map.expect_item(item.id)) + fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> { + Some(&self.tcx.map) } - fn visit_item(&mut self, item: &hir::Item) { + fn visit_item(&mut self, item: &'tcx hir::Item) { if self.should_warn_about_item(item) { self.warn_dead_code( item.id, @@ -527,7 +534,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> { } } - fn visit_variant(&mut self, variant: &hir::Variant, g: &hir::Generics, id: ast::NodeId) { + fn visit_variant(&mut self, + variant: &'tcx hir::Variant, + g: &'tcx hir::Generics, + id: ast::NodeId) { if self.should_warn_about_variant(&variant.node) { self.warn_dead_code(variant.node.data.id(), variant.span, variant.node.name, "variant"); @@ -536,14 +546,14 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> { } } - fn visit_foreign_item(&mut self, fi: &hir::ForeignItem) { + fn visit_foreign_item(&mut self, fi: &'tcx hir::ForeignItem) { if !self.symbol_is_live(fi.id, None) { self.warn_dead_code(fi.id, fi.span, fi.name, fi.node.descriptive_variant()); } intravisit::walk_foreign_item(self, fi); } - fn visit_struct_field(&mut self, field: &hir::StructField) { + fn visit_struct_field(&mut self, field: &'tcx hir::StructField) { if self.should_warn_about_field(&field) { self.warn_dead_code(field.id, field.span, field.name, "field"); @@ -552,7 +562,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> { intravisit::walk_struct_field(self, field); } - fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) { + fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { match impl_item.node { hir::ImplItemKind::Const(_, ref expr) => { if !self.symbol_is_live(impl_item.id, None) { @@ -573,7 +583,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> { } // Overwrite so that we don't warn the trait item itself. - fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) { + fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { match trait_item.node { hir::ConstTraitItem(_, Some(ref body))| hir::MethodTraitItem(_, Some(ref body)) => { diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index 5634e2012c97..25fe407271bc 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -235,5 +235,5 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { unsafe_context: UnsafeContext::new(SafeContext), }; - tcx.map.krate().visit_all_items(&mut visitor); + tcx.map.krate().visit_all_item_likes(&mut visitor.as_deep_visitor()); } diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs index 11bde922f47f..9dd54457a349 100644 --- a/src/librustc/middle/entry.rs +++ b/src/librustc/middle/entry.rs @@ -17,8 +17,8 @@ use syntax::ast::NodeId; use syntax::attr; use syntax::entry::EntryPointType; use syntax_pos::Span; -use hir::{Item, ItemFn}; -use hir::intravisit::Visitor; +use hir::{Item, ItemFn, ImplItem}; +use hir::itemlikevisit::ItemLikeVisitor; struct EntryContext<'a, 'tcx: 'a> { session: &'a Session, @@ -39,13 +39,17 @@ struct EntryContext<'a, 'tcx: 'a> { non_main_fns: Vec<(NodeId, Span)> , } -impl<'a, 'tcx> Visitor<'tcx> for EntryContext<'a, 'tcx> { +impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> { fn visit_item(&mut self, item: &'tcx Item) { let def_id = self.map.local_def_id(item.id); let def_key = self.map.def_key(def_id); let at_root = def_key.parent == Some(CRATE_DEF_INDEX); find_item(item, self, at_root); } + + fn visit_impl_item(&mut self, _impl_item: &'tcx ImplItem) { + // entry fn is never an impl item + } } pub fn find_entry_point(session: &Session, ast_map: &ast_map::Map) { @@ -74,7 +78,7 @@ pub fn find_entry_point(session: &Session, ast_map: &ast_map::Map) { non_main_fns: Vec::new(), }; - ast_map.krate().visit_all_items(&mut ctxt); + ast_map.krate().visit_all_item_likes(&mut ctxt); configure_main(&mut ctxt); } diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index 7dbf9aa74144..cf08b59312d5 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -26,7 +26,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let mut visitor = ItemVisitor { tcx: tcx }; - tcx.visit_all_items_in_krate(DepNode::IntrinsicCheck, &mut visitor); + tcx.visit_all_item_likes_in_krate(DepNode::IntrinsicCheck, &mut visitor.as_deep_visitor()); } struct ItemVisitor<'a, 'tcx: 'a> { @@ -51,7 +51,7 @@ struct ExprVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> { fn def_id_is_transmute(&self, def_id: DefId) -> bool { - let intrinsic = match self.infcx.tcx.lookup_item_type(def_id).ty.sty { + let intrinsic = match self.infcx.tcx.item_type(def_id).sty { ty::TyFnDef(.., ref bfty) => bfty.abi == RustIntrinsic, _ => return false }; diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 3e7de79246b6..9b4b1396669a 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -31,7 +31,7 @@ use util::nodemap::FxHashMap; use syntax::ast; use syntax::parse::token::InternedString; -use hir::intravisit::Visitor; +use hir::itemlikevisit::ItemLikeVisitor; use hir; // The actual lang items defined come at the end of this file in one handy table. @@ -149,7 +149,7 @@ struct LanguageItemCollector<'a, 'tcx: 'a> { item_refs: FxHashMap<&'static str, usize>, } -impl<'a, 'v, 'tcx> Visitor<'v> for LanguageItemCollector<'a, 'tcx> { +impl<'a, 'v, 'tcx> ItemLikeVisitor<'v> for LanguageItemCollector<'a, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { if let Some(value) = extract(&item.attrs) { let item_index = self.item_refs.get(&value[..]).cloned(); @@ -164,6 +164,10 @@ impl<'a, 'v, 'tcx> Visitor<'v> for LanguageItemCollector<'a, 'tcx> { } } } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + // at present, lang items are always items, not impl items + } } impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> { @@ -219,7 +223,7 @@ impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> { } pub fn collect_local_language_items(&mut self, krate: &hir::Crate) { - krate.visit_all_items(self); + krate.visit_all_item_likes(self); } pub fn collect_external_language_items(&mut self) { diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index a654d65bc679..d381188d56b5 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -112,7 +112,7 @@ use self::VarKind::*; use dep_graph::DepNode; use hir::def::*; use hir::pat_util; -use ty::{self, Ty, TyCtxt, ParameterEnvironment}; +use ty::{self, TyCtxt, ParameterEnvironment}; use traits::{self, Reveal}; use ty::subst::Subst; use lint; @@ -196,7 +196,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for IrMaps<'a, 'tcx> { pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let _task = tcx.dep_graph.in_task(DepNode::Liveness); - tcx.map.krate().visit_all_items(&mut IrMaps::new(tcx)); + tcx.map.krate().visit_all_item_likes(&mut IrMaps::new(tcx).as_deep_visitor()); tcx.sess.abort_if_errors(); } @@ -1440,28 +1440,30 @@ fn check_expr(this: &mut Liveness, expr: &Expr) { } impl<'a, 'tcx> Liveness<'a, 'tcx> { - fn fn_ret(&self, id: NodeId) -> ty::Binder> { - let fn_ty = self.ir.tcx.tables().node_id_to_type(id); - match fn_ty.sty { - ty::TyClosure(closure_def_id, substs) => - self.ir.tcx.closure_type(closure_def_id, substs).sig.output(), - _ => fn_ty.fn_ret() - } - } - fn check_ret(&self, id: NodeId, sp: Span, - _fk: FnKind, + fk: FnKind, entry_ln: LiveNode, body: &hir::Expr) { + let fn_ty = if let FnKind::Closure(_) = fk { + self.ir.tcx.tables().node_id_to_type(id) + } else { + self.ir.tcx.item_type(self.ir.tcx.map.local_def_id(id)) + }; + let fn_ret = match fn_ty.sty { + ty::TyClosure(closure_def_id, substs) => + self.ir.tcx.closure_type(closure_def_id, substs).sig.output(), + _ => fn_ty.fn_ret() + }; + // within the fn body, late-bound regions are liberated // and must outlive the *call-site* of the function. let fn_ret = self.ir.tcx.liberate_late_bound_regions( self.ir.tcx.region_maps.call_site_extent(id, body.id), - &self.fn_ret(id)); + &fn_ret); if !fn_ret.is_never() && self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() { let param_env = ParameterEnvironment::for_item(self.ir.tcx, id); diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index e3ed13e1e401..fedf8c2ec747 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -945,9 +945,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { let ref_ty = self.overloaded_method_return_ty(method_ty); base_cmt = self.cat_rvalue_node(elt.id(), elt.span(), ref_ty); - // FIXME(#20649) -- why are we using the `self_ty` as the element type...? - let self_ty = method_ty.fn_sig().input(0); - (self.tcx().no_late_bound_regions(&self_ty).unwrap(), + (ref_ty.builtin_deref(false, ty::NoPreference).unwrap().ty, ElementKind::OtherElement) } None => { diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 7868e700f270..ac614494355a 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -29,6 +29,7 @@ use syntax::ast; use syntax::attr; use hir; use hir::intravisit::Visitor; +use hir::itemlikevisit::ItemLikeVisitor; use hir::intravisit; // Returns true if the given set of generics implies that the item it's @@ -324,17 +325,21 @@ struct CollectPrivateImplItemsVisitor<'a> { worklist: &'a mut Vec, } -impl<'a, 'v> Visitor<'v> for CollectPrivateImplItemsVisitor<'a> { +impl<'a, 'v> ItemLikeVisitor<'v> for CollectPrivateImplItemsVisitor<'a> { fn visit_item(&mut self, item: &hir::Item) { // We need only trait impls here, not inherent impls, and only non-exported ones - if let hir::ItemImpl(.., Some(_), _, ref impl_items) = item.node { + if let hir::ItemImpl(.., Some(_), _, ref impl_item_refs) = item.node { if !self.access_levels.is_reachable(item.id) { - for impl_item in impl_items { - self.worklist.push(impl_item.id); + for impl_item_ref in impl_item_refs { + self.worklist.push(impl_item_ref.id.node_id); } } } } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + // processed in visit_item above + } } pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -364,7 +369,7 @@ pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, access_levels: access_levels, worklist: &mut reachable_context.worklist, }; - tcx.map.krate().visit_all_items(&mut collect_private_impl_items); + tcx.map.krate().visit_all_item_likes(&mut collect_private_impl_items); } // Step 2: Mark all symbols that the symbols on the worklist touch. diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 34a6a547d944..5f9a6b283c6a 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -1235,7 +1235,7 @@ pub fn resolve_crate(sess: &Session, map: &ast_map::Map) -> RegionMaps { }, terminating_scopes: NodeSet() }; - krate.visit_all_items(&mut visitor); + krate.visit_all_item_likes(&mut visitor.as_deep_visitor()); } return maps; } diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 292d9592ceb0..f682dfbf1be9 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -119,7 +119,7 @@ pub fn krate(sess: &Session, late_bound: NodeMap(), }; sess.track_errors(|| { - krate.visit_all_items(&mut LifetimeContext { + intravisit::walk_crate(&mut LifetimeContext { sess: sess, hir_map: hir_map, map: &mut map, @@ -127,14 +127,21 @@ pub fn krate(sess: &Session, def_map: def_map, trait_ref_hack: false, labels_in_fn: vec![], - }); + }, krate); })?; Ok(map) } -impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { - fn visit_item(&mut self, item: &hir::Item) { - assert!(self.labels_in_fn.is_empty()); +impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { + // Override the nested functions -- lifetimes follow lexical scope, + // so it's convenient to walk the tree in lexical order. + fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> { + Some(&self.hir_map) + } + + fn visit_item(&mut self, item: &'tcx hir::Item) { + // Save labels for nested items. + let saved_labels_in_fn = replace(&mut self.labels_in_fn, vec![]); // Items always introduce a new root scope self.with(RootScope, |_, this| { @@ -175,10 +182,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { }); // Done traversing the item; remove any labels it created - self.labels_in_fn.truncate(0); + self.labels_in_fn = saved_labels_in_fn; } - fn visit_foreign_item(&mut self, item: &hir::ForeignItem) { + fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) { // Items save/restore the set of labels. This way inner items // can freely reuse names, be they loop labels or lifetimes. let saved = replace(&mut self.labels_in_fn, vec![]); @@ -201,8 +208,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { replace(&mut self.labels_in_fn, saved); } - fn visit_fn(&mut self, fk: FnKind<'v>, decl: &'v hir::FnDecl, - b: &'v hir::Expr, s: Span, fn_id: ast::NodeId) { + fn visit_fn(&mut self, fk: FnKind<'tcx>, decl: &'tcx hir::FnDecl, + b: &'tcx hir::Expr, s: Span, fn_id: ast::NodeId) { match fk { FnKind::ItemFn(_, generics, ..) => { self.visit_early_late(fn_id,decl, generics, |this| { @@ -227,7 +234,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { } } - fn visit_ty(&mut self, ty: &hir::Ty) { + fn visit_ty(&mut self, ty: &'tcx hir::Ty) { match ty.node { hir::TyBareFn(ref c) => { self.with(LateScope(&c.lifetimes, self.scope), |old_scope, this| { @@ -257,7 +264,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { } } - fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) { + fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { // We reset the labels on every trait item, so that different // methods in an impl can reuse label names. let saved = replace(&mut self.labels_in_fn, vec![]); @@ -274,7 +281,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { replace(&mut self.labels_in_fn, saved); } - fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) { + fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) { if lifetime_ref.name == keywords::StaticLifetime.name() { self.insert_lifetime(lifetime_ref, DefStaticRegion); return; @@ -282,7 +289,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { self.resolve_lifetime_ref(lifetime_ref); } - fn visit_generics(&mut self, generics: &hir::Generics) { + fn visit_generics(&mut self, generics: &'tcx hir::Generics) { for ty_param in generics.ty_params.iter() { walk_list!(self, visit_ty_param_bound, &ty_param.bounds); if let Some(ref ty) = ty_param.default { @@ -331,8 +338,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { } fn visit_poly_trait_ref(&mut self, - trait_ref: &hir::PolyTraitRef, - _modifier: &hir::TraitBoundModifier) { + trait_ref: &'tcx hir::PolyTraitRef, + _modifier: &'tcx hir::TraitBoundModifier) { debug!("visit_poly_trait_ref trait_ref={:?}", trait_ref); if !self.trait_ref_hack || !trait_ref.bound_lifetimes.is_empty() { @@ -490,13 +497,12 @@ fn extract_labels(ctxt: &mut LifetimeContext, b: &hir::Expr) { } impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { - fn add_scope_and_walk_fn<'b>(&mut self, - fk: FnKind, - fd: &hir::FnDecl, - fb: &'b hir::Expr, - _span: Span, - fn_id: ast::NodeId) { - + fn add_scope_and_walk_fn(&mut self, + fk: FnKind<'tcx>, + fd: &'tcx hir::FnDecl, + fb: &'tcx hir::Expr, + _span: Span, + fn_id: ast::NodeId) { match fk { FnKind::ItemFn(_, generics, ..) => { intravisit::walk_fn_decl(self, fd); @@ -519,8 +525,15 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { |_old_scope, this| this.visit_expr(fb)) } + // FIXME(#37666) this works around a limitation in the region inferencer + fn hack(&mut self, f: F) where + F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>), + { + f(self) + } + fn with(&mut self, wrap_scope: ScopeChain, f: F) where - F: FnOnce(Scope, &mut LifetimeContext), + F: for<'b> FnOnce(Scope, &mut LifetimeContext<'b, 'tcx>), { let LifetimeContext {sess, hir_map, ref mut map, ..} = *self; let mut this = LifetimeContext { @@ -557,10 +570,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { /// ordering is not important there. fn visit_early_late(&mut self, fn_id: ast::NodeId, - decl: &hir::FnDecl, - generics: &hir::Generics, + decl: &'tcx hir::FnDecl, + generics: &'tcx hir::Generics, walk: F) where - F: FnOnce(&mut LifetimeContext), + F: for<'b, 'c> FnOnce(&'b mut LifetimeContext<'c, 'tcx>), { let fn_def_id = self.hir_map.local_def_id(fn_id); insert_late_bound_lifetimes(self.map, @@ -590,11 +603,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } } - let this = self; - this.with(EarlyScope(&early, start as u32, this.scope), move |old_scope, this| { + self.with(EarlyScope(&early, start as u32, self.scope), move |old_scope, this| { this.with(LateScope(&late, this.scope), move |_, this| { this.check_lifetime_defs(old_scope, &generics.lifetimes); - walk(this); + this.hack(walk); // FIXME(#37666) workaround in place of `walk(this)` }); }); } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index d79833998d6c..7e4efc7ddca0 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -120,7 +120,7 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> { // stability. The stability is recorded in the index and used as the parent. fn annotate(&mut self, id: NodeId, attrs: &[Attribute], item_sp: Span, kind: AnnotationKind, visit_children: F) - where F: FnOnce(&mut Annotator) + where F: FnOnce(&mut Self) { if self.index.staged_api[&LOCAL_CRATE] && self.tcx.sess.features.borrow().staged_api { debug!("annotate(id = {:?}, attrs = {:?})", id, attrs); @@ -234,16 +234,15 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> { } } -impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> { +impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { /// Because stability levels are scoped lexically, we want to walk /// nested items in the context of the outer item, so enable /// deep-walking. - fn visit_nested_item(&mut self, item: hir::ItemId) { - let tcx = self.tcx; - self.visit_item(tcx.map.expect_item(item.id)) + fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> { + Some(&self.tcx.map) } - fn visit_item(&mut self, i: &Item) { + fn visit_item(&mut self, i: &'tcx Item) { let orig_in_trait_impl = self.in_trait_impl; let mut kind = AnnotationKind::Required; match i.node { @@ -272,13 +271,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> { self.in_trait_impl = orig_in_trait_impl; } - fn visit_trait_item(&mut self, ti: &hir::TraitItem) { + fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) { self.annotate(ti.id, &ti.attrs, ti.span, AnnotationKind::Required, |v| { intravisit::walk_trait_item(v, ti); }); } - fn visit_impl_item(&mut self, ii: &hir::ImplItem) { + fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) { let kind = if self.in_trait_impl { AnnotationKind::Prohibited } else { @@ -289,25 +288,25 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> { }); } - fn visit_variant(&mut self, var: &Variant, g: &'v Generics, item_id: NodeId) { + fn visit_variant(&mut self, var: &'tcx Variant, g: &'tcx Generics, item_id: NodeId) { self.annotate(var.node.data.id(), &var.node.attrs, var.span, AnnotationKind::Required, |v| { intravisit::walk_variant(v, var, g, item_id); }) } - fn visit_struct_field(&mut self, s: &StructField) { + fn visit_struct_field(&mut self, s: &'tcx StructField) { self.annotate(s.id, &s.attrs, s.span, AnnotationKind::Required, |v| { intravisit::walk_struct_field(v, s); }); } - fn visit_foreign_item(&mut self, i: &hir::ForeignItem) { + fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem) { self.annotate(i.id, &i.attrs, i.span, AnnotationKind::Required, |v| { intravisit::walk_foreign_item(v, i); }); } - fn visit_macro_def(&mut self, md: &'v hir::MacroDef) { + fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef) { if md.imported_from.is_none() { self.annotate(md.id, &md.attrs, md.span, AnnotationKind::Required, |_| {}); } @@ -444,16 +443,15 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { } } -impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> { +impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { /// Because stability levels are scoped lexically, we want to walk /// nested items in the context of the outer item, so enable /// deep-walking. - fn visit_nested_item(&mut self, item: hir::ItemId) { - let tcx = self.tcx; - self.visit_item(tcx.map.expect_item(item.id)) + fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> { + Some(&self.tcx.map) } - fn visit_item(&mut self, item: &hir::Item) { + fn visit_item(&mut self, item: &'tcx hir::Item) { // When compiling with --test we don't enforce stability on the // compiler-generated test module, demarcated with `DUMMY_SP` plus the // name `__test` @@ -464,31 +462,31 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> { intravisit::walk_item(self, item); } - fn visit_expr(&mut self, ex: &hir::Expr) { + fn visit_expr(&mut self, ex: &'tcx hir::Expr) { check_expr(self.tcx, ex, &mut |id, sp, stab, depr| self.check(id, sp, stab, depr)); intravisit::walk_expr(self, ex); } - fn visit_path(&mut self, path: &hir::Path, id: ast::NodeId) { + fn visit_path(&mut self, path: &'tcx hir::Path, id: ast::NodeId) { check_path(self.tcx, path, id, &mut |id, sp, stab, depr| self.check(id, sp, stab, depr)); intravisit::walk_path(self, path) } - fn visit_path_list_item(&mut self, prefix: &hir::Path, item: &hir::PathListItem) { + fn visit_path_list_item(&mut self, prefix: &'tcx hir::Path, item: &'tcx hir::PathListItem) { check_path_list_item(self.tcx, item, &mut |id, sp, stab, depr| self.check(id, sp, stab, depr)); intravisit::walk_path_list_item(self, prefix, item) } - fn visit_pat(&mut self, pat: &hir::Pat) { + fn visit_pat(&mut self, pat: &'tcx hir::Pat) { check_pat(self.tcx, pat, &mut |id, sp, stab, depr| self.check(id, sp, stab, depr)); intravisit::walk_pat(self, pat) } - fn visit_block(&mut self, b: &hir::Block) { + fn visit_block(&mut self, b: &'tcx hir::Block) { let old_skip_count = self.in_skip_block; match b.rules { hir::BlockCheckMode::PushUnstableBlock => { @@ -527,9 +525,10 @@ pub fn check_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // For implementations of traits, check the stability of each item // individually as it's possible to have a stable trait with unstable // items. - hir::ItemImpl(.., Some(ref t), _, ref impl_items) => { + hir::ItemImpl(.., Some(ref t), _, ref impl_item_refs) => { let trait_did = tcx.expect_def(t.ref_id).def_id(); - for impl_item in impl_items { + for impl_item_ref in impl_item_refs { + let impl_item = tcx.map.impl_item(impl_item_ref.id); let item = tcx.associated_items(trait_did) .find(|item| item.name == impl_item.name).unwrap(); if warn_about_defns { diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs index 2c08e17f8f1a..12d32bf31b13 100644 --- a/src/librustc/middle/weak_lang_items.rs +++ b/src/librustc/middle/weak_lang_items.rs @@ -50,7 +50,7 @@ pub fn check_crate(krate: &hir::Crate, { let mut cx = Context { sess: sess, items: items }; - krate.visit_all_items(&mut cx); + krate.visit_all_item_likes(&mut cx.as_deep_visitor()); } verify(sess, items); } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 9d82006ac9f9..b3cec6ec8ff3 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -923,7 +923,7 @@ impl<'tcx> Debug for Lvalue<'tcx> { ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => write!(fmt, "{:?}[-{:?} of {:?}]", data.base, offset, min_length), ProjectionElem::Subslice { from, to } if to == 0 => - write!(fmt, "{:?}[{:?}:", data.base, from), + write!(fmt, "{:?}[{:?}:]", data.base, from), ProjectionElem::Subslice { from, to } if from == 0 => write!(fmt, "{:?}[:-{:?}]", data.base, to), ProjectionElem::Subslice { from, to } => diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index f9afbaf104a6..73ea84e94aec 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -125,7 +125,7 @@ impl<'tcx> Lvalue<'tcx> { Lvalue::Local(index) => LvalueTy::Ty { ty: mir.local_decls[index].ty }, Lvalue::Static(def_id) => - LvalueTy::Ty { ty: tcx.lookup_item_type(def_id).ty }, + LvalueTy::Ty { ty: tcx.item_type(def_id) }, Lvalue::Projection(ref proj) => proj.base.ty(mir, tcx).projection_ty(tcx, &proj.elem), } @@ -188,7 +188,7 @@ impl<'tcx> Rvalue<'tcx> { )) } AggregateKind::Adt(def, _, substs, _) => { - Some(tcx.lookup_item_type(def.did).ty.subst(tcx, substs)) + Some(tcx.item_type(def.did).subst(tcx, substs)) } AggregateKind::Closure(did, substs) => { Some(tcx.mk_closure_from_closure_substs(did, substs)) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 724b32d2cd71..9becbd99eb33 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -258,14 +258,15 @@ impl Session { pub fn unimpl(&self, msg: &str) -> ! { self.diagnostic().unimpl(msg) } - pub fn add_lint(&self, - lint: &'static lint::Lint, - id: ast::NodeId, - sp: Span, - msg: String) + pub fn add_lint>(&self, + lint: &'static lint::Lint, + id: ast::NodeId, + sp: S, + msg: String) { self.add_lint_diagnostic(lint, id, (sp, &msg[..])) } + pub fn add_lint_diagnostic(&self, lint: &'static lint::Lint, id: ast::NodeId, diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 1ccd048cedca..2e06e83f8489 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -14,8 +14,8 @@ use super::{SelectionContext, Obligation, ObligationCause}; use hir::def_id::{DefId, LOCAL_CRATE}; use ty::{self, Ty, TyCtxt}; -use infer::{InferCtxt, InferOk, TypeOrigin}; -use syntax_pos::DUMMY_SP; + +use infer::{InferCtxt, InferOk}; #[derive(Copy, Clone)] struct InferIsLocal(bool); @@ -55,8 +55,10 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, debug!("overlap: b_impl_header={:?}", b_impl_header); // Do `a` and `b` unify? If not, no overlap. - match selcx.infcx().eq_impl_headers(true, TypeOrigin::Misc(DUMMY_SP), &a_impl_header, - &b_impl_header) { + match selcx.infcx().eq_impl_headers(true, + &ObligationCause::dummy(), + &a_impl_header, + &b_impl_header) { Ok(InferOk { obligations, .. }) => { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()); diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 7e70fdb92e68..e0a397ad28fb 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -26,7 +26,7 @@ use super::{ use fmt_macros::{Parser, Piece, Position}; use hir::def_id::DefId; -use infer::{self, InferCtxt, TypeOrigin}; +use infer::{self, InferCtxt}; use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL; use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; use ty::error::ExpectedFound; @@ -100,7 +100,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } self.probe(|_| { - let origin = TypeOrigin::Misc(obligation.cause.span); let err_buf; let mut err = &error.err; let mut values = None; @@ -121,9 +120,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { obligation.cause.clone(), 0 ); - let origin = TypeOrigin::Misc(obligation.cause.span); if let Err(error) = self.eq_types( - false, origin, + false, &obligation.cause, data.ty, normalized.value ) { values = Some(infer::ValuePairs::Types(ExpectedFound { @@ -136,10 +134,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } let mut diag = struct_span_err!( - self.tcx.sess, origin.span(), E0271, + self.tcx.sess, obligation.cause.span, E0271, "type mismatch resolving `{}`", predicate ); - self.note_type_err(&mut diag, origin, None, values, err); + self.note_type_err(&mut diag, &obligation.cause, None, values, err); self.note_obligation_cause(&mut diag, obligation); diag.emit(); }); @@ -529,7 +527,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::Predicate::Equate(ref predicate) => { let predicate = self.resolve_type_vars_if_possible(predicate); - let err = self.equality_predicate(span, + let err = self.equality_predicate(&obligation.cause, &predicate).err().unwrap(); struct_span_err!(self.tcx.sess, span, E0278, "the requirement `{}` is not satisfied (`{}`)", @@ -851,7 +849,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { { let tcx = self.tcx; match *cause_code { - ObligationCauseCode::MiscObligation => { } + ObligationCauseCode::ExprAssignable | + ObligationCauseCode::MatchExpressionArm { .. } | + ObligationCauseCode::IfExpression | + ObligationCauseCode::IfExpressionWithNoElse | + ObligationCauseCode::EquatePredicate | + ObligationCauseCode::MainFunctionType | + ObligationCauseCode::StartFunctionType | + ObligationCauseCode::IntrinsicType | + ObligationCauseCode::MethodReceiver | + ObligationCauseCode::MiscObligation => { + } ObligationCauseCode::SliceOrArrayElem => { err.note("slice and array elements must have `Sized` type"); } diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 6de93adce3f8..f406580286da 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -154,9 +154,13 @@ impl<'a, 'gcx, 'tcx> DeferredObligation<'tcx> { pub fn try_select(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option>> { if let ty::TyAnon(def_id, substs) = self.predicate.skip_binder().self_ty().sty { + let ty = if def_id.is_local() { + tcx.item_types.borrow().get(&def_id).cloned() + } else { + Some(tcx.item_type(def_id)) + }; // We can resolve the `impl Trait` to its concrete type. - if let Some(ty_scheme) = tcx.opt_lookup_item_type(def_id) { - let concrete_ty = ty_scheme.ty.subst(tcx, substs); + if let Some(concrete_ty) = ty.subst(tcx, substs) { let predicate = ty::TraitRef { def_id: self.predicate.def_id(), substs: tcx.mk_substs_trait(concrete_ty, &[]) @@ -515,11 +519,9 @@ fn process_predicate<'a, 'gcx, 'tcx>( } ty::Predicate::Equate(ref binder) => { - match selcx.infcx().equality_predicate(obligation.cause.span, binder) { - Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - Ok(Some(Vec::new())) + match selcx.infcx().equality_predicate(&obligation.cause, binder) { + Ok(InferOk { obligations, value: () }) => { + Ok(Some(obligations)) }, Err(_) => Err(CodeSelectionError(Unimplemented)), } diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 36405df6325a..a5fdaed97125 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -15,6 +15,7 @@ pub use self::FulfillmentErrorCode::*; pub use self::Vtable::*; pub use self::ObligationCauseCode::*; +use hir; use hir::def_id::DefId; use middle::free_region::FreeRegionMap; use ty::subst::Substs; @@ -148,6 +149,35 @@ pub enum ObligationCauseCode<'tcx> { trait_item_def_id: DefId, lint_id: Option, }, + + // Checking that this expression can be assigned where it needs to be + // FIXME(eddyb) #11161 is the original Expr required? + ExprAssignable, + + // Computing common supertype in the arms of a match expression + MatchExpressionArm { arm_span: Span, + source: hir::MatchSource }, + + // Computing common supertype in an if expression + IfExpression, + + // Computing common supertype of an if expression with no else counter-part + IfExpressionWithNoElse, + + // `where a == b` + EquatePredicate, + + // `main` has wrong type + MainFunctionType, + + // `start` has wrong type + StartFunctionType, + + // intrinsic has wrong type + IntrinsicType, + + // method receiver + MethodReceiver, } #[derive(Clone, Debug, PartialEq, Eq)] @@ -603,7 +633,7 @@ pub fn get_vtable_methods<'a, 'tcx>( // do not hold for this particular set of type parameters. // Note that this method could then never be called, so we // do not want to try and trans it, in that case (see #23435). - let predicates = tcx.lookup_predicates(def_id).instantiate_own(tcx, substs); + let predicates = tcx.item_predicates(def_id).instantiate_own(tcx, substs); if !normalize_and_test_predicates(tcx, predicates.predicates) { debug!("get_vtable_methods: predicates do not hold"); return None; diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index c783bd561bb1..0681be129b67 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -129,7 +129,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let trait_def = self.lookup_trait_def(trait_def_id); let trait_ref = trait_def.trait_ref.clone(); let trait_ref = trait_ref.to_poly_trait_ref(); - let predicates = self.lookup_super_predicates(trait_def_id); + let predicates = self.item_super_predicates(trait_def_id); predicates .predicates .into_iter() @@ -166,7 +166,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // Search for a predicate like `Self : Sized` amongst the trait bounds. let free_substs = self.construct_free_substs(def_id, self.region_maps.node_extent(ast::DUMMY_NODE_ID)); - let predicates = self.lookup_predicates(def_id); + let predicates = self.item_predicates(def_id); let predicates = predicates.instantiate(self, free_substs).predicates; elaborate_predicates(self, predicates) .any(|predicate| { @@ -238,7 +238,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // The `Self` type is erased, so it should not appear in list of // arguments or return type apart from the receiver. - let ref sig = self.lookup_item_type(method.def_id).ty.fn_sig(); + let ref sig = self.item_type(method.def_id).fn_sig(); for &input_ty in &sig.0.inputs[1..] { if self.contains_illegal_self_type_reference(trait_def_id, input_ty) { return Some(MethodViolationCode::ReferencesSelf); @@ -249,7 +249,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } // We can't monomorphize things like `fn foo(...)`. - if !self.lookup_generics(method.def_id).types.is_empty() { + if !self.item_generics(method.def_id).types.is_empty() { return Some(MethodViolationCode::Generic); } diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index b1ab61b09757..a2d45fa27149 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -24,7 +24,7 @@ use super::VtableImplData; use super::util; use hir::def_id::DefId; -use infer::{InferOk, TypeOrigin}; +use infer::InferOk; use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap}; use syntax::parse::token; use syntax::ast; @@ -209,11 +209,8 @@ fn project_and_unify_type<'cx, 'gcx, 'tcx>( obligations); let infcx = selcx.infcx(); - let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span); - match infcx.eq_types(true, origin, normalized_ty, obligation.predicate.ty) { - Ok(InferOk { obligations: inferred_obligations, .. }) => { - // FIXME(#32730) once obligations are generated in inference, drop this assertion - assert!(inferred_obligations.is_empty()); + match infcx.eq_types(true, &obligation.cause, normalized_ty, obligation.predicate.ty) { + Ok(InferOk { obligations: inferred_obligations, value: () }) => { obligations.extend(inferred_obligations); Ok(Some(obligations)) }, @@ -311,7 +308,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, ty::TyAnon(def_id, substs) if !substs.has_escaping_regions() => { // (*) // Only normalize `impl Trait` after type-checking, usually in trans. if self.selcx.projection_mode() == Reveal::All { - let generic_ty = self.tcx().lookup_item_type(def_id).ty; + let generic_ty = self.tcx().item_type(def_id); let concrete_ty = generic_ty.subst(self.tcx(), substs); self.fold_ty(concrete_ty) } else { @@ -809,7 +806,7 @@ fn assemble_candidates_from_trait_def<'cx, 'gcx, 'tcx>( }; // If so, extract what we know from the trait and try to come up with a good answer. - let trait_predicates = selcx.tcx().lookup_predicates(def_id); + let trait_predicates = selcx.tcx().item_predicates(def_id); let bounds = trait_predicates.instantiate(selcx.tcx(), substs); let bounds = elaborate_predicates(selcx.tcx(), bounds.predicates); assemble_candidates_from_predicates(selcx, @@ -840,18 +837,18 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>( let same_name = data.item_name() == obligation.predicate.item_name; let is_match = same_name && infcx.probe(|_| { - let origin = TypeOrigin::Misc(obligation.cause.span); let data_poly_trait_ref = data.to_poly_trait_ref(); let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); infcx.sub_poly_trait_refs(false, - origin, + obligation.cause.clone(), data_poly_trait_ref, obligation_poly_trait_ref) - // FIXME(#32730) once obligations are propagated from unification in - // inference, drop this assertion - .map(|InferOk { obligations, .. }| assert!(obligations.is_empty())) + .map(|InferOk { obligations: _, value: () }| { + // FIXME(#32730) -- do we need to take obligations + // into account in any way? At the moment, no. + }) .is_ok() }); @@ -943,7 +940,7 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( // an error when we confirm the candidate // (which will ultimately lead to `normalize_to_error` // being invoked). - node_item.item.has_value + node_item.item.defaultness.has_value() } else { node_item.item.defaultness.is_default() }; @@ -1007,8 +1004,9 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( // types, which appear not to unify -- so the // overlap check succeeds, when it should // fail. - bug!("Tried to project an inherited associated type during \ - coherence checking, which is currently not supported."); + span_bug!(obligation.cause.span, + "Tried to project an inherited associated type during \ + coherence checking, which is currently not supported."); }; candidate_set.vec.extend(new_candidate); } @@ -1153,12 +1151,11 @@ fn confirm_object_candidate<'cx, 'gcx, 'tcx>( // select those with a relevant trait-ref let mut env_predicates = env_predicates.filter(|data| { - let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span); let data_poly_trait_ref = data.to_poly_trait_ref(); let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); selcx.infcx().probe(|_| { selcx.infcx().sub_poly_trait_refs(false, - origin, + obligation.cause.clone(), data_poly_trait_ref, obligation_poly_trait_ref).is_ok() }) @@ -1187,12 +1184,10 @@ fn confirm_fn_pointer_candidate<'cx, 'gcx, 'tcx>( fn_pointer_vtable: VtableFnPointerData<'tcx, PredicateObligation<'tcx>>) -> Progress<'tcx> { - // FIXME(#32730) drop this assertion once obligations are propagated from inference (fn pointer - // vtable nested obligations ONLY come from unification in inference) - assert!(fn_pointer_vtable.nested.is_empty()); let fn_type = selcx.infcx().shallow_resolve(fn_pointer_vtable.fn_ty); let sig = fn_type.fn_sig(); confirm_callable_candidate(selcx, obligation, sig, util::TupleArgumentsFlag::Yes) + .with_addl_obligations(fn_pointer_vtable.nested) } fn confirm_closure_candidate<'cx, 'gcx, 'tcx>( @@ -1265,12 +1260,10 @@ fn confirm_param_env_candidate<'cx, 'gcx, 'tcx>( -> Progress<'tcx> { let infcx = selcx.infcx(); - let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span); + let cause = obligation.cause.clone(); let trait_ref = obligation.predicate.trait_ref; - match infcx.match_poly_projection_predicate(origin, poly_projection, trait_ref) { + match infcx.match_poly_projection_predicate(cause, poly_projection, trait_ref) { Ok(InferOk { value: ty_match, obligations }) => { - // FIXME(#32730) once obligations are generated in inference, drop this assertion - assert!(obligations.is_empty()); Progress { ty: ty_match.value, obligations: obligations, @@ -1303,7 +1296,7 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>( match assoc_ty { Some(node_item) => { - let ty = if !node_item.item.has_value { + let ty = if !node_item.item.defaultness.has_value() { // This means that the impl is missing a definition for the // associated type. This error will be reported by the type // checker method `check_impl_items_against_trait`, so here we @@ -1313,7 +1306,7 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>( obligation.predicate.trait_ref); tcx.types.err } else { - tcx.lookup_item_type(node_item.item.def_id).ty + tcx.item_type(node_item.item.def_id) }; let substs = translate_substs(selcx.infcx(), impl_def_id, substs, node_item.node); Progress { diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 5e3f78b1208d..c25e7ee344f6 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -35,7 +35,7 @@ use super::util; use hir::def_id::DefId; use infer; -use infer::{InferCtxt, InferOk, TypeFreshener, TypeOrigin}; +use infer::{InferCtxt, InferOk, TypeFreshener}; use ty::subst::{Kind, Subst, Substs}; use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; use traits; @@ -418,9 +418,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { None => Ok(None), Some(candidate) => { let mut candidate = self.confirm_candidate(obligation, candidate)?; - // FIXME(#32730) remove this assertion once inferred obligations are propagated - // from inference - assert!(self.inferred_obligations.len() == 0); let inferred_obligations = (*self.inferred_obligations).into_iter().cloned(); candidate.nested_obligations_mut().extend(inferred_obligations); Ok(Some(candidate)) @@ -521,7 +518,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::Predicate::Equate(ref p) => { // does this code ever run? - match self.infcx.equality_predicate(obligation.cause.span, p) { + match self.infcx.equality_predicate(&obligation.cause, p) { Ok(InferOk { obligations, .. }) => { self.inferred_obligations.extend(obligations); EvaluatedToOk @@ -1200,7 +1197,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { def_id={:?}, substs={:?}", def_id, substs); - let item_predicates = self.tcx().lookup_predicates(def_id); + let item_predicates = self.tcx().item_predicates(def_id); let bounds = item_predicates.instantiate(self.tcx(), substs); debug!("match_projection_obligation_against_definition_bounds: \ bounds={:?}", @@ -1247,9 +1244,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { -> bool { assert!(!skol_trait_ref.has_escaping_regions()); - let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span); + let cause = obligation.cause.clone(); match self.infcx.sub_poly_trait_refs(false, - origin, + cause, trait_bound.clone(), ty::Binder(skol_trait_ref.clone())) { Ok(InferOk { obligations, .. }) => { @@ -1912,16 +1909,16 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { tys.to_vec() } - ty::TyClosure(_, ref substs) => { + ty::TyClosure(def_id, ref substs) => { // FIXME(#27086). We are invariant w/r/t our - // substs.func_substs, but we don't see them as + // func_substs, but we don't see them as // constituent types; this seems RIGHT but also like // something that a normal type couldn't simulate. Is // this just a gap with the way that PhantomData and // OIBIT interact? That is, there is no way to say // "make me invariant with respect to this TYPE, but // do not act as though I can reach it" - substs.upvar_tys.to_vec() + substs.upvar_tys(def_id, self.tcx()).collect() } // for `PhantomData`, we pass `T` @@ -2439,16 +2436,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { /// selection of the impl. Therefore, if there is a mismatch, we /// report an error to the user. fn confirm_poly_trait_refs(&mut self, - obligation_cause: ObligationCause, + obligation_cause: ObligationCause<'tcx>, obligation_trait_ref: ty::PolyTraitRef<'tcx>, expected_trait_ref: ty::PolyTraitRef<'tcx>) -> Result<(), SelectionError<'tcx>> { - let origin = TypeOrigin::RelateOutputImplTypes(obligation_cause.span); - let obligation_trait_ref = obligation_trait_ref.clone(); self.infcx.sub_poly_trait_refs(false, - origin, + obligation_cause.clone(), expected_trait_ref.clone(), obligation_trait_ref.clone()) .map(|InferOk { obligations, .. }| self.inferred_obligations.extend(obligations)) @@ -2482,9 +2477,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { builtin_bounds: data_b.builtin_bounds, projection_bounds: data_a.projection_bounds.clone(), }); - let origin = TypeOrigin::Misc(obligation.cause.span); let InferOk { obligations, .. } = - self.infcx.sub_types(false, origin, new_trait, target) + self.infcx.sub_types(false, &obligation.cause, new_trait, target) .map_err(|_| Unimplemented)?; self.inferred_obligations.extend(obligations); @@ -2553,9 +2547,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // [T; n] -> [T]. (&ty::TyArray(a, _), &ty::TySlice(b)) => { - let origin = TypeOrigin::Misc(obligation.cause.span); let InferOk { obligations, .. } = - self.infcx.sub_types(false, origin, a, b) + self.infcx.sub_types(false, &obligation.cause, a, b) .map_err(|_| Unimplemented)?; self.inferred_obligations.extend(obligations); } @@ -2617,9 +2610,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } }); let new_struct = tcx.mk_adt(def, tcx.mk_substs(params)); - let origin = TypeOrigin::Misc(obligation.cause.span); let InferOk { obligations, .. } = - self.infcx.sub_types(false, origin, new_struct, target) + self.infcx.sub_types(false, &obligation.cause, new_struct, target) .map_err(|_| Unimplemented)?; self.inferred_obligations.extend(obligations); @@ -2705,10 +2697,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { impl_trait_ref, skol_obligation_trait_ref); - let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span); let InferOk { obligations, .. } = self.infcx.eq_trait_refs(false, - origin, + &obligation.cause, impl_trait_ref.value.clone(), skol_obligation_trait_ref) .map_err(|e| { @@ -2780,9 +2771,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation, poly_trait_ref); - let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span); self.infcx.sub_poly_trait_refs(false, - origin, + obligation.cause.clone(), poly_trait_ref, obligation.predicate.to_poly_trait_ref()) .map(|InferOk { obligations, .. }| self.inferred_obligations.extend(obligations)) @@ -2884,7 +2874,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // obligation will normalize to `<$0 as Iterator>::Item = $1` and // `$1: Copy`, so we must ensure the obligations are emitted in // that order. - let predicates = tcx.lookup_predicates(def_id); + let predicates = tcx.item_predicates(def_id); assert_eq!(predicates.parent, None); let predicates = predicates.predicates.iter().flat_map(|predicate| { let predicate = normalize_with_depth(self, cause.clone(), recursion_depth, diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 91c40a5cc851..870494363c85 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -22,7 +22,7 @@ use super::util::impl_trait_ref_and_oblig; use rustc_data_structures::fx::FxHashMap; use hir::def_id::DefId; -use infer::{InferCtxt, InferOk, TypeOrigin}; +use infer::{InferCtxt, InferOk}; use middle::region; use ty::subst::{Subst, Substs}; use traits::{self, Reveal, ObligationCause}; @@ -223,8 +223,10 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, target_substs); // do the impls unify? If not, no specialization. - match infcx.eq_trait_refs(true, TypeOrigin::Misc(DUMMY_SP), source_trait_ref, - target_trait_ref) { + match infcx.eq_trait_refs(true, + &ObligationCause::dummy(), + source_trait_ref, + target_trait_ref) { Ok(InferOk { obligations, .. }) => { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()) diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index d33e8b5675f5..d03ba5b0a31f 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -213,6 +213,34 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { lint_id: lint_id, }) } + super::ExprAssignable => { + Some(super::ExprAssignable) + } + super::MatchExpressionArm { arm_span, source } => { + Some(super::MatchExpressionArm { arm_span: arm_span, + source: source }) + } + super::IfExpression => { + Some(super::IfExpression) + } + super::IfExpressionWithNoElse => { + Some(super::IfExpressionWithNoElse) + } + super::EquatePredicate => { + Some(super::EquatePredicate) + } + super::MainFunctionType => { + Some(super::MainFunctionType) + } + super::StartFunctionType => { + Some(super::StartFunctionType) + } + super::IntrinsicType => { + Some(super::IntrinsicType) + } + super::MethodReceiver => { + Some(super::MethodReceiver) + } } } } @@ -461,6 +489,15 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Normalized<'tcx, T> { impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { match *self { + super::ExprAssignable | + super::MatchExpressionArm { arm_span: _, source: _ } | + super::IfExpression | + super::IfExpressionWithNoElse | + super::EquatePredicate | + super::MainFunctionType | + super::StartFunctionType | + super::IntrinsicType | + super::MethodReceiver | super::MiscObligation | super::SliceOrArrayElem | super::TupleElem | @@ -497,6 +534,15 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> { fn super_visit_with>(&self, visitor: &mut V) -> bool { match *self { + super::ExprAssignable | + super::MatchExpressionArm { arm_span: _, source: _ } | + super::IfExpression | + super::IfExpressionWithNoElse | + super::EquatePredicate | + super::MainFunctionType | + super::StartFunctionType | + super::IntrinsicType | + super::MethodReceiver | super::MiscObligation | super::SliceOrArrayElem | super::TupleElem | diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 9346bbd30f9c..b94597d47592 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -128,7 +128,7 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> { match *predicate { ty::Predicate::Trait(ref data) => { // Predicates declared on the trait. - let predicates = tcx.lookup_super_predicates(data.def_id()); + let predicates = tcx.item_super_predicates(data.def_id()); let mut predicates: Vec<_> = predicates.predicates @@ -295,7 +295,7 @@ impl<'cx, 'gcx, 'tcx> Iterator for SupertraitDefIds<'cx, 'gcx, 'tcx> { None => { return None; } }; - let predicates = self.tcx.lookup_super_predicates(def_id); + let predicates = self.tcx.item_super_predicates(def_id); let visited = &mut self.visited; self.stack.extend( predicates.predicates @@ -362,7 +362,7 @@ pub fn impl_trait_ref_and_oblig<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, let Normalized { value: impl_trait_ref, obligations: normalization_obligations1 } = super::normalize(selcx, ObligationCause::dummy(), &impl_trait_ref); - let predicates = selcx.tcx().lookup_predicates(impl_def_id); + let predicates = selcx.tcx().item_predicates(impl_def_id); let predicates = predicates.instantiate(selcx.tcx(), impl_substs); let Normalized { value: predicates, obligations: normalization_obligations2 } = super::normalize(selcx, ObligationCause::dummy(), &predicates); diff --git a/src/librustc/ty/contents.rs b/src/librustc/ty/contents.rs index 7ed4de38be97..9f80c2487fb2 100644 --- a/src/librustc/ty/contents.rs +++ b/src/librustc/ty/contents.rs @@ -98,10 +98,11 @@ impl TypeContents { TC::OwnsOwned | (*self & TC::OwnsAll) } - pub fn union(v: &[T], mut f: F) -> TypeContents where - F: FnMut(&T) -> TypeContents, + pub fn union(v: I, mut f: F) -> TypeContents where + I: IntoIterator, + F: FnMut(T) -> TypeContents, { - v.iter().fold(TC::None, |tc, ty| tc | f(ty)) + v.into_iter().fold(TC::None, |tc, ty| tc | f(ty)) } pub fn has_dtor(&self) -> bool { @@ -215,8 +216,10 @@ impl<'a, 'tcx> ty::TyS<'tcx> { } ty::TyStr => TC::None, - ty::TyClosure(_, ref substs) => { - TypeContents::union(&substs.upvar_tys, |ty| tc_ty(tcx, &ty, cache)) + ty::TyClosure(def_id, ref substs) => { + TypeContents::union( + substs.upvar_tys(def_id, tcx), + |ty| tc_ty(tcx, &ty, cache)) } ty::TyTuple(ref tys) => { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 60a48ba580a0..45450456e8a6 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -444,7 +444,7 @@ pub struct GlobalCtxt<'tcx> { pub maybe_unused_trait_imports: NodeSet, // Records the type of every item. - pub tcache: RefCell>>, + pub item_types: RefCell>>, // Internal cache for metadata decoding. No need to track deps on this. pub rcache: RefCell>>, @@ -665,10 +665,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.ty_param_defs.borrow().get(&node_id).unwrap().clone() } - pub fn node_type_insert(self, id: NodeId, ty: Ty<'gcx>) { - self.tables.borrow_mut().node_types.insert(id, ty); - } - pub fn alloc_generics(self, generics: ty::Generics<'gcx>) -> &'gcx ty::Generics<'gcx> { self.global_interners.arenas.generics.alloc(generics) @@ -815,7 +811,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { mir_map: RefCell::new(DepTrackingMap::new(dep_graph.clone())), freevars: RefCell::new(freevars), maybe_unused_trait_imports: maybe_unused_trait_imports, - tcache: RefCell::new(DepTrackingMap::new(dep_graph.clone())), + item_types: RefCell::new(DepTrackingMap::new(dep_graph.clone())), rcache: RefCell::new(FxHashMap()), tc_cache: RefCell::new(FxHashMap()), associated_items: RefCell::new(DepTrackingMap::new(dep_graph.clone())), @@ -1450,12 +1446,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn mk_closure(self, closure_id: DefId, - substs: &'tcx Substs<'tcx>, - tys: &[Ty<'tcx>]) + substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { self.mk_closure_from_closure_substs(closure_id, ClosureSubsts { - func_substs: substs, - upvar_tys: self.intern_type_list(tys) + substs: substs }) } @@ -1578,4 +1572,3 @@ impl InternIteratorElement for Result { Ok(f(&iter.collect::, _>>()?)) } } - diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 649d78f9d9e2..2c09b89beb23 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -88,8 +88,7 @@ impl FlagComputation { &ty::TyClosure(_, ref substs) => { self.add_flags(TypeFlags::HAS_TY_CLOSURE); self.add_flags(TypeFlags::HAS_LOCAL_NAMES); - self.add_substs(&substs.func_substs); - self.add_tys(&substs.upvar_tys); + self.add_substs(&substs.substs); } &ty::TyInfer(infer) => { diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index fdf5185eb69e..8222583d9a7d 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -218,7 +218,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // users may find it useful. Currently, we omit the parent if // the impl is either in the same module as the self-type or // as the trait. - let self_ty = self.lookup_item_type(impl_def_id).ty; + let self_ty = self.item_type(impl_def_id); let in_self_mod = match characteristic_def_id_of_type(self_ty) { None => false, Some(ty_def_id) => self.parent_def_id(ty_def_id) == Some(parent_def_id), diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 5ce43d905ec7..5ee1c3678d67 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -631,7 +631,9 @@ impl<'a, 'gcx, 'tcx> Struct { // Perhaps one of the upvars of this closure is non-zero // Let's recurse and find out! - (_, &ty::TyClosure(_, ty::ClosureSubsts { upvar_tys: tys, .. })) | + (_, &ty::TyClosure(def_id, ref substs)) => { + Struct::non_zero_field_path(infcx, substs.upvar_tys(def_id, tcx)) + } // Can we use one of the fields in this tuple? (_, &ty::TyTuple(tys)) => { Struct::non_zero_field_path(infcx, tys.iter().cloned()) @@ -961,7 +963,13 @@ impl<'a, 'gcx, 'tcx> Layout { } // Tuples and closures. - ty::TyClosure(_, ty::ClosureSubsts { upvar_tys: tys, .. }) | + ty::TyClosure(def_id, ref substs) => { + let mut st = Struct::new(dl, false); + let tys = substs.upvar_tys(def_id, tcx); + st.extend(dl, tys.map(|ty| ty.layout(infcx)), ty)?; + Univariant { variant: st, non_zero: false } + } + ty::TyTuple(tys) => { let mut st = Struct::new(dl, false); st.extend(dl, tys.iter().map(|ty| ty.layout(infcx)), ty)?; diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 43abb61e7fcd..bf0445858794 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -33,7 +33,7 @@ macro_rules! dep_map_ty { } dep_map_ty! { AssociatedItems: AssociatedItems(DefId) -> ty::AssociatedItem } -dep_map_ty! { Tcache: ItemSignature(DefId) -> Ty<'tcx> } +dep_map_ty! { Types: ItemSignature(DefId) -> Ty<'tcx> } dep_map_ty! { Generics: ItemSignature(DefId) -> &'tcx ty::Generics<'tcx> } dep_map_ty! { Predicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx> } dep_map_ty! { SuperPredicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx> } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 1d260fd65fef..f5c23401a4e6 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -50,7 +50,7 @@ use syntax_pos::{DUMMY_SP, Span}; use rustc_const_math::ConstInt; use hir; -use hir::intravisit::Visitor; +use hir::itemlikevisit::ItemLikeVisitor; pub use self::sty::{Binder, DebruijnIndex}; pub use self::sty::{BuiltinBound, BuiltinBounds}; @@ -169,9 +169,9 @@ impl<'a, 'gcx, 'tcx> ImplHeader<'tcx> { let header = ImplHeader { impl_def_id: impl_def_id, - self_ty: tcx.lookup_item_type(impl_def_id).ty, + self_ty: tcx.item_type(impl_def_id), trait_ref: tcx.impl_trait_ref(impl_def_id), - predicates: tcx.lookup_predicates(impl_def_id).predicates + predicates: tcx.item_predicates(impl_def_id).predicates }.subst(tcx, impl_substs); let traits::Normalized { value: mut header, obligations } = @@ -189,7 +189,6 @@ pub struct AssociatedItem { pub kind: AssociatedKind, pub vis: Visibility, pub defaultness: hir::Defaultness, - pub has_value: bool, pub container: AssociatedItemContainer, /// Whether this is a method with an explicit self @@ -708,7 +707,7 @@ impl<'a, 'gcx, 'tcx> GenericPredicates<'tcx> { instantiated: &mut InstantiatedPredicates<'tcx>, substs: &Substs<'tcx>) { if let Some(def_id) = self.parent { - tcx.lookup_predicates(def_id).instantiate_into(tcx, instantiated, substs); + tcx.item_predicates(def_id).instantiate_into(tcx, instantiated, substs); } instantiated.predicates.extend(self.predicates.iter().map(|p| p.subst(tcx, substs))) } @@ -1301,31 +1300,6 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { } } -/// A "type scheme", in ML terminology, is a type combined with some -/// set of generic types that the type is, well, generic over. In Rust -/// terms, it is the "type" of a fn item or struct -- this type will -/// include various generic parameters that must be substituted when -/// the item/struct is referenced. That is called converting the type -/// scheme to a monotype. -/// -/// - `generics`: the set of type parameters and their bounds -/// - `ty`: the base types, which may reference the parameters defined -/// in `generics` -/// -/// Note that TypeSchemes are also sometimes called "polytypes" (and -/// in fact this struct used to carry that name, so you may find some -/// stray references in a comment or something). We try to reserve the -/// "poly" prefix to refer to higher-ranked things, as in -/// `PolyTraitRef`. -/// -/// Note that each item also comes with predicates, see -/// `lookup_predicates`. -#[derive(Clone, Debug)] -pub struct TypeScheme<'tcx> { - pub generics: &'tcx Generics<'tcx>, - pub ty: Ty<'tcx>, -} - bitflags! { flags AdtFlags: u32 { const NO_ADT_FLAGS = 0, @@ -1359,8 +1333,6 @@ pub struct VariantDefData<'tcx, 'container: 'tcx> { } pub struct FieldDefData<'tcx, 'container: 'tcx> { - /// The field's DefId. NOTE: the fields of tuple-like enum variants - /// are not real items, and don't have entries in tcache etc. pub did: DefId, pub name: Name, pub vis: Visibility, @@ -1541,14 +1513,9 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> { &self.variants[0] } - #[inline] - pub fn type_scheme(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> TypeScheme<'gcx> { - tcx.lookup_item_type(self.did) - } - #[inline] pub fn predicates(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> GenericPredicates<'gcx> { - tcx.lookup_predicates(self.did) + tcx.item_predicates(self.did) } /// Returns an iterator over all fields contained @@ -1784,7 +1751,7 @@ impl<'a, 'tcx> AdtDefData<'tcx, 'tcx> { def_id: sized_trait, substs: tcx.mk_substs_trait(ty, &[]) }).to_predicate(); - let predicates = tcx.lookup_predicates(self.did).predicates; + let predicates = tcx.item_predicates(self.did).predicates; if predicates.into_iter().any(|p| p == sized_predicate) { vec![] } else { @@ -1963,7 +1930,7 @@ impl LvaluePreference { } /// Helper for looking things up in the various maps that are populated during -/// typeck::collect (e.g., `tcx.associated_items`, `tcx.tcache`, etc). All of +/// typeck::collect (e.g., `tcx.associated_items`, `tcx.types`, etc). All of /// these share the pattern that if the id is local, it should have been loaded /// into the map by the `typeck::collect` phase. If the def-id is external, /// then we have to go consult the crate loading code (and cache the result for @@ -2104,7 +2071,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn provided_trait_methods(self, id: DefId) -> Vec { self.associated_items(id) - .filter(|item| item.kind == AssociatedKind::Method && item.has_value) + .filter(|item| item.kind == AssociatedKind::Method && item.defaultness.has_value()) .collect() } @@ -2145,69 +2112,109 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { .expect("missing AssociatedItem in metadata"); } + // When the user asks for a given associated item, we + // always go ahead and convert all the associated items in + // the container. Note that we are also careful only to + // ever register a read on the *container* of the assoc + // item, not the assoc item itself. This prevents changes + // in the details of an item (for example, the type to + // which an associated type is bound) from contaminating + // those tasks that just need to scan the names of items + // and so forth. + let id = self.map.as_local_node_id(def_id).unwrap(); let parent_id = self.map.get_parent(id); let parent_def_id = self.map.local_def_id(parent_id); - match self.map.get(id) { - ast_map::NodeTraitItem(trait_item) => { - let (kind, has_self, has_value) = match trait_item.node { - hir::MethodTraitItem(ref sig, ref body) => { - (AssociatedKind::Method, sig.decl.get_self().is_some(), - body.is_some()) - } - hir::ConstTraitItem(_, ref value) => { - (AssociatedKind::Const, false, value.is_some()) - } - hir::TypeTraitItem(_, ref ty) => { - (AssociatedKind::Type, false, ty.is_some()) - } - }; - - AssociatedItem { - name: trait_item.name, - kind: kind, - vis: Visibility::from_hir(&hir::Inherited, id, self), - defaultness: hir::Defaultness::Default, - has_value: has_value, - def_id: def_id, - container: TraitContainer(parent_def_id), - method_has_self_argument: has_self + let parent_item = self.map.expect_item(parent_id); + match parent_item.node { + hir::ItemImpl(.., ref impl_trait_ref, _, ref impl_item_refs) => { + for impl_item_ref in impl_item_refs { + let assoc_item = + self.associated_item_from_impl_item_ref(parent_def_id, + impl_trait_ref.is_some(), + impl_item_ref); + self.associated_items.borrow_mut().insert(assoc_item.def_id, assoc_item); } } - ast_map::NodeImplItem(impl_item) => { - let (kind, has_self) = match impl_item.node { - hir::ImplItemKind::Method(ref sig, _) => { - (AssociatedKind::Method, sig.decl.get_self().is_some()) - } - hir::ImplItemKind::Const(..) => (AssociatedKind::Const, false), - hir::ImplItemKind::Type(..) => (AssociatedKind::Type, false) - }; - // Trait impl items are always public. - let public = hir::Public; - let parent_item = self.map.expect_item(parent_id); - let vis = if let hir::ItemImpl(.., Some(_), _, _) = parent_item.node { - &public - } else { - &impl_item.vis - }; - - AssociatedItem { - name: impl_item.name, - kind: kind, - vis: Visibility::from_hir(vis, id, self), - defaultness: impl_item.defaultness, - has_value: true, - def_id: def_id, - container: ImplContainer(parent_def_id), - method_has_self_argument: has_self + hir::ItemTrait(.., ref trait_items) => { + for trait_item in trait_items { + let assoc_item = + self.associated_item_from_trait_item_ref(parent_def_id, trait_item); + self.associated_items.borrow_mut().insert(assoc_item.def_id, assoc_item); } } - item => bug!("associated_item: {:?} not an associated item", item) + + ref r => { + panic!("unexpected container of associated items: {:?}", r) + } } + + // memoize wants us to return something, so return + // the one we generated for this def-id + *self.associated_items.borrow().get(&def_id).unwrap() }) } + fn associated_item_from_trait_item_ref(self, + parent_def_id: DefId, + trait_item: &hir::TraitItem) + -> AssociatedItem { + let def_id = self.map.local_def_id(trait_item.id); + + let (kind, has_self, has_value) = match trait_item.node { + hir::MethodTraitItem(ref sig, ref body) => { + (AssociatedKind::Method, sig.decl.get_self().is_some(), + body.is_some()) + } + hir::ConstTraitItem(_, ref value) => { + (AssociatedKind::Const, false, value.is_some()) + } + hir::TypeTraitItem(_, ref ty) => { + (AssociatedKind::Type, false, ty.is_some()) + } + }; + + AssociatedItem { + name: trait_item.name, + kind: kind, + vis: Visibility::from_hir(&hir::Inherited, trait_item.id, self), + defaultness: hir::Defaultness::Default { has_value: has_value }, + def_id: def_id, + container: TraitContainer(parent_def_id), + method_has_self_argument: has_self + } + } + + fn associated_item_from_impl_item_ref(self, + parent_def_id: DefId, + from_trait_impl: bool, + impl_item_ref: &hir::ImplItemRef) + -> AssociatedItem { + let def_id = self.map.local_def_id(impl_item_ref.id.node_id); + let (kind, has_self) = match impl_item_ref.kind { + hir::AssociatedItemKind::Const => (ty::AssociatedKind::Const, false), + hir::AssociatedItemKind::Method { has_self } => { + (ty::AssociatedKind::Method, has_self) + } + hir::AssociatedItemKind::Type => (ty::AssociatedKind::Type, false), + }; + + // Trait impl items are always public. + let public = hir::Public; + let vis = if from_trait_impl { &public } else { &impl_item_ref.vis }; + + ty::AssociatedItem { + name: impl_item_ref.name, + kind: kind, + vis: ty::Visibility::from_hir(vis, impl_item_ref.id.node_id, self), + defaultness: impl_item_ref.defaultness, + def_id: def_id, + container: ImplContainer(parent_def_id), + method_has_self_argument: has_self + } + } + pub fn associated_item_def_ids(self, def_id: DefId) -> Rc> { self.associated_item_def_ids.memoize(def_id, || { if !def_id.is_local() { @@ -2216,19 +2223,22 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let id = self.map.as_local_node_id(def_id).unwrap(); let item = self.map.expect_item(id); - match item.node { + let vec: Vec<_> = match item.node { hir::ItemTrait(.., ref trait_items) => { - Rc::new(trait_items.iter().map(|trait_item| { - self.map.local_def_id(trait_item.id) - }).collect()) + trait_items.iter() + .map(|trait_item| trait_item.id) + .map(|id| self.map.local_def_id(id)) + .collect() } - hir::ItemImpl(.., ref impl_items) => { - Rc::new(impl_items.iter().map(|impl_item| { - self.map.local_def_id(impl_item.id) - }).collect()) + hir::ItemImpl(.., ref impl_item_refs) => { + impl_item_refs.iter() + .map(|impl_item_ref| impl_item_ref.id) + .map(|id| self.map.local_def_id(id.node_id)) + .collect() } _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait") - } + }; + Rc::new(vec) }) } @@ -2351,38 +2361,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - // Register a given item type - pub fn register_item_type(self, did: DefId, scheme: TypeScheme<'gcx>) { - self.tcache.borrow_mut().insert(did, scheme.ty); - self.generics.borrow_mut().insert(did, scheme.generics); - } - // If the given item is in an external crate, looks up its type and adds it to // the type cache. Returns the type parameters and type. - pub fn lookup_item_type(self, did: DefId) -> TypeScheme<'gcx> { - let ty = lookup_locally_or_in_crate_store( - "tcache", did, &self.tcache, - || self.sess.cstore.item_type(self.global_tcx(), did)); - - TypeScheme { - ty: ty, - generics: self.lookup_generics(did) - } - } - - pub fn opt_lookup_item_type(self, did: DefId) -> Option> { - if did.krate != LOCAL_CRATE { - return Some(self.lookup_item_type(did)); - } - - if let Some(ty) = self.tcache.borrow().get(&did).cloned() { - Some(TypeScheme { - ty: ty, - generics: self.lookup_generics(did) - }) - } else { - None - } + pub fn item_type(self, did: DefId) -> Ty<'gcx> { + lookup_locally_or_in_crate_store( + "item_types", did, &self.item_types, + || self.sess.cstore.item_type(self.global_tcx(), did)) } /// Given the did of a trait, returns its canonical trait ref. @@ -2411,21 +2395,21 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } /// Given the did of an item, returns its generics. - pub fn lookup_generics(self, did: DefId) -> &'gcx Generics<'gcx> { + pub fn item_generics(self, did: DefId) -> &'gcx Generics<'gcx> { lookup_locally_or_in_crate_store( "generics", did, &self.generics, || self.alloc_generics(self.sess.cstore.item_generics(self.global_tcx(), did))) } /// Given the did of an item, returns its full set of predicates. - pub fn lookup_predicates(self, did: DefId) -> GenericPredicates<'gcx> { + pub fn item_predicates(self, did: DefId) -> GenericPredicates<'gcx> { lookup_locally_or_in_crate_store( "predicates", did, &self.predicates, || self.sess.cstore.item_predicates(self.global_tcx(), did)) } /// Given the did of a trait, returns its superpredicates. - pub fn lookup_super_predicates(self, did: DefId) -> GenericPredicates<'gcx> { + pub fn item_super_predicates(self, did: DefId) -> GenericPredicates<'gcx> { lookup_locally_or_in_crate_store( "super_predicates", did, &self.super_predicates, || self.sess.cstore.item_super_predicates(self.global_tcx(), did)) @@ -2602,12 +2586,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // tables by typeck; else, it will be retreived from // the external crate metadata. if let Some(ty) = self.tables.borrow().closure_tys.get(&def_id) { - return ty.subst(self, substs.func_substs); + return ty.subst(self, substs.substs); } let ty = self.sess.cstore.closure_ty(self.global_tcx(), def_id); self.tables.borrow_mut().closure_tys.insert(def_id, ty.clone()); - ty.subst(self, substs.func_substs) + ty.subst(self, substs.substs) } /// Given the def_id of an impl, return the def_id of the trait it implements. @@ -2718,7 +2702,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // let tcx = self.global_tcx(); - let generic_predicates = tcx.lookup_predicates(def_id); + let generic_predicates = tcx.item_predicates(def_id); let bounds = generic_predicates.instantiate(tcx, free_substs); let bounds = tcx.liberate_late_bound_regions(free_id_outlive, &ty::Binder(bounds)); let predicates = bounds.predicates; @@ -2753,12 +2737,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_region(ty::ReScope(self.region_maps.node_extent(id))) } - pub fn visit_all_items_in_krate(self, - dep_node_fn: F, - visitor: &mut V) - where F: FnMut(DefId) -> DepNode, V: Visitor<'gcx> + pub fn visit_all_item_likes_in_krate(self, + dep_node_fn: F, + visitor: &mut V) + where F: FnMut(DefId) -> DepNode, V: ItemLikeVisitor<'gcx> { - dep_graph::visit_all_items_in_krate(self.global_tcx(), dep_node_fn, visitor); + dep_graph::visit_all_item_likes_in_krate(self.global_tcx(), dep_node_fn, visitor); } /// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err` diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs index 51feab9d40c9..e3d13f593954 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -72,7 +72,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // in the `subtys` iterator (e.g., when encountering a // projection). match ty.sty { - ty::TyClosure(_, ref substs) => { + ty::TyClosure(def_id, ref substs) => { // FIXME(#27086). We do not accumulate from substs, since they // don't represent reachable data. This means that, in // practice, some of the lifetime parameters might not @@ -110,7 +110,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // what func/type parameters are used and unused, // taking into consideration UFCS and so forth. - for &upvar_ty in substs.upvar_tys { + for upvar_ty in substs.upvar_tys(def_id, *self) { self.compute_components(upvar_ty, out); } } diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index cb90e6392cf0..2a01bad33c52 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -534,13 +534,8 @@ impl<'tcx> Relate<'tcx> for ty::ClosureSubsts<'tcx> { -> RelateResult<'tcx, ty::ClosureSubsts<'tcx>> where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a { - let substs = relate_substs(relation, None, a.func_substs, b.func_substs)?; - assert_eq!(a.upvar_tys.len(), b.upvar_tys.len()); - Ok(ty::ClosureSubsts { - func_substs: substs, - upvar_tys: relation.tcx().mk_type_list( - a.upvar_tys.iter().zip(b.upvar_tys).map(|(a, b)| relation.relate(a, b)))? - }) + let substs = relate_substs(relation, None, a.substs, b.substs)?; + Ok(ty::ClosureSubsts { substs: substs }) } } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 9ca911837b51..e73be23a42c7 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -198,11 +198,8 @@ impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::Binder { impl<'a, 'tcx> Lift<'tcx> for ty::ClosureSubsts<'a> { type Lifted = ty::ClosureSubsts<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { - tcx.lift(&(self.func_substs, self.upvar_tys)).map(|(substs, upvar_tys)| { - ty::ClosureSubsts { - func_substs: substs, - upvar_tys: upvar_tys - } + tcx.lift(&self.substs).map(|substs| { + ty::ClosureSubsts { substs: substs } }) } } @@ -482,7 +479,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::TyAnon(did, substs) => ty::TyAnon(did, substs.fold_with(folder)), ty::TyBool | ty::TyChar | ty::TyStr | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyError | ty::TyInfer(_) | - ty::TyParam(..) | ty::TyNever => self.sty.clone(), + ty::TyParam(..) | ty::TyNever => return self }; folder.tcx().mk_ty(sty) } @@ -654,13 +651,12 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Region { impl<'tcx> TypeFoldable<'tcx> for ty::ClosureSubsts<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { ty::ClosureSubsts { - func_substs: self.func_substs.fold_with(folder), - upvar_tys: self.upvar_tys.fold_with(folder), + substs: self.substs.fold_with(folder), } } fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.func_substs.visit_with(visitor) || self.upvar_tys.visit_with(visitor) + self.substs.visit_with(visitor) } } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 92dfb883ef30..56466d596829 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -11,6 +11,7 @@ //! This module contains TypeVariants and its major components use hir::def_id::DefId; + use middle::region; use ty::subst::Substs; use ty::{self, AdtDef, ToPredicate, TypeFlags, Ty, TyCtxt, TypeFoldable}; @@ -164,7 +165,7 @@ pub enum TypeVariants<'tcx> { /// Anonymized (`impl Trait`) type found in a return type. /// The DefId comes from the `impl Trait` ast::Ty node, and the /// substitutions are for the generics of the function in question. - /// After typeck, the concrete type can be found in the `tcache` map. + /// After typeck, the concrete type can be found in the `types` map. TyAnon(DefId, &'tcx Substs<'tcx>), /// A type parameter; for example, `T` in `fn f(x: T) {} @@ -254,15 +255,23 @@ pub enum TypeVariants<'tcx> { /// handle). Plus it fixes an ICE. :P #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct ClosureSubsts<'tcx> { - /// Lifetime and type parameters from the enclosing function. + /// Lifetime and type parameters from the enclosing function, + /// concatenated with the types of the upvars. + /// /// These are separated out because trans wants to pass them around /// when monomorphizing. - pub func_substs: &'tcx Substs<'tcx>, + pub substs: &'tcx Substs<'tcx>, +} - /// The types of the upvars. The list parallels the freevars and - /// `upvar_borrows` lists. These are kept distinct so that we can - /// easily index into them. - pub upvar_tys: &'tcx Slice> +impl<'a, 'gcx, 'acx, 'tcx> ClosureSubsts<'tcx> { + #[inline] + pub fn upvar_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'acx>) -> + impl Iterator> + 'tcx + { + let generics = tcx.item_generics(def_id); + self.substs[self.substs.len()-generics.own_count()..].iter().map( + |t| t.as_type().expect("unexpected region in upvars")) + } } #[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] @@ -556,7 +565,7 @@ pub struct DebruijnIndex { /// /// These are regions that are stored behind a binder and must be substituted /// with some concrete region before being used. There are 2 kind of -/// bound regions: early-bound, which are bound in a TypeScheme/TraitDef, +/// bound regions: early-bound, which are bound in an item's Generics, /// and are substituted by a Substs, and late-bound, which are part of /// higher-ranked types (e.g. `for<'a> fn(&'a ())`) and are substituted by /// the likes of `liberate_late_bound_regions`. The distinction exists @@ -1234,7 +1243,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { substs.regions().collect() } TyClosure(_, ref substs) => { - substs.func_substs.regions().collect() + substs.substs.regions().collect() } TyProjection(ref data) => { data.trait_ref.substs.regions().collect() diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index a4ceecd8c9d7..41fcb09fb2dc 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -177,12 +177,28 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { -> &'tcx Substs<'tcx> where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region, FT: FnMut(&ty::TypeParameterDef<'tcx>, &[Kind<'tcx>]) -> Ty<'tcx> { - let defs = tcx.lookup_generics(def_id); + let defs = tcx.item_generics(def_id); let mut substs = Vec::with_capacity(defs.count()); Substs::fill_item(&mut substs, tcx, defs, &mut mk_region, &mut mk_type); tcx.intern_substs(&substs) } + pub fn extend_to(&self, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + def_id: DefId, + mut mk_region: FR, + mut mk_type: FT) + -> &'tcx Substs<'tcx> + where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region, + FT: FnMut(&ty::TypeParameterDef<'tcx>, &[Kind<'tcx>]) -> Ty<'tcx> + { + let defs = tcx.item_generics(def_id); + let mut result = Vec::with_capacity(defs.count()); + result.extend(self[..].iter().cloned()); + Substs::fill_single(&mut result, defs, &mut mk_region, &mut mk_type); + tcx.intern_substs(&result) + } + fn fill_item(substs: &mut Vec>, tcx: TyCtxt<'a, 'gcx, 'tcx>, defs: &ty::Generics<'tcx>, @@ -192,10 +208,18 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { FT: FnMut(&ty::TypeParameterDef<'tcx>, &[Kind<'tcx>]) -> Ty<'tcx> { if let Some(def_id) = defs.parent { - let parent_defs = tcx.lookup_generics(def_id); + let parent_defs = tcx.item_generics(def_id); Substs::fill_item(substs, tcx, parent_defs, mk_region, mk_type); } + Substs::fill_single(substs, defs, mk_region, mk_type) + } + fn fill_single(substs: &mut Vec>, + defs: &ty::Generics<'tcx>, + mk_region: &mut FR, + mk_type: &mut FT) + where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region, + FT: FnMut(&ty::TypeParameterDef<'tcx>, &[Kind<'tcx>]) -> Ty<'tcx> { // Handle Self first, before all regions. let mut types = defs.types.iter(); if defs.parent.is_none() && defs.has_self { @@ -271,9 +295,14 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { source_ancestor: DefId, target_substs: &Substs<'tcx>) -> &'tcx Substs<'tcx> { - let defs = tcx.lookup_generics(source_ancestor); + let defs = tcx.item_generics(source_ancestor); tcx.mk_substs(target_substs.iter().chain(&self[defs.own_count()..]).cloned()) } + + pub fn truncate_to(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, generics: &ty::Generics<'tcx>) + -> &'tcx Substs<'tcx> { + tcx.mk_substs(self.iter().take(generics.count()).cloned()) + } } impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> { @@ -519,7 +548,7 @@ impl<'a, 'gcx, 'tcx> ty::TraitRef<'tcx> { trait_id: DefId, substs: &Substs<'tcx>) -> ty::TraitRef<'tcx> { - let defs = tcx.lookup_generics(trait_id); + let defs = tcx.item_generics(trait_id); ty::TraitRef { def_id: trait_id, diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs index fc3202994838..fd81065e61d4 100644 --- a/src/librustc/ty/trait_def.rs +++ b/src/librustc/ty/trait_def.rs @@ -18,7 +18,7 @@ use std::cell::{Cell, RefCell}; use hir; use util::nodemap::FxHashMap; -/// As `TypeScheme` but for a trait ref. +/// A trait's definition with type information. pub struct TraitDef<'tcx> { pub unsafety: hir::Unsafety, diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index b1aeaeb48d14..7d3e380a3b59 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -11,6 +11,7 @@ //! misc. type-system utilities too small to deserve their own file use hir::def_id::DefId; +use hir::map::DefPathData; use infer::InferCtxt; use hir::map as ast_map; use hir::pat_util; @@ -390,6 +391,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // (e.g. calling `foo.0.clone()` of `Foo`). return !self.has_attr(dtor_method, "unsafe_destructor_blind_to_params"); } + + pub fn closure_base_def_id(&self, def_id: DefId) -> DefId { + let mut def_id = def_id; + while self.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr { + def_id = self.parent_def_id(def_id).unwrap_or_else(|| { + bug!("closure {:?} has no parent", def_id); + }); + } + def_id + } } /// When hashing a type this ends up affecting properties like symbol names. We diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index bebdebf127a5..a6ecfd2fb706 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -97,8 +97,7 @@ fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { stack.extend(substs.types().rev()); } ty::TyClosure(_, ref substs) => { - stack.extend(substs.func_substs.types().rev()); - stack.extend(substs.upvar_tys.iter().cloned().rev()); + stack.extend(substs.substs.types().rev()); } ty::TyTuple(ts) => { stack.extend(ts.iter().cloned().rev()); diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 155fa4989ea3..74c6d7d334c3 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -446,7 +446,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { -> Vec> { let predicates = - self.infcx.tcx.lookup_predicates(def_id) + self.infcx.tcx.item_predicates(def_id) .instantiate(self.infcx.tcx, substs); let cause = self.cause(traits::ItemObligation(def_id)); predicates.predicates diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 01b44ced8e08..a63c7ba6a25c 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -105,7 +105,7 @@ pub fn parameterized(f: &mut fmt::Formatter, } } } - let mut generics = tcx.lookup_generics(item_def_id); + let mut generics = tcx.item_generics(item_def_id); let mut path_def_id = did; verbose = tcx.sess.verbose(); has_self = generics.has_self; @@ -115,7 +115,7 @@ pub fn parameterized(f: &mut fmt::Formatter, // Methods. assert!(is_value_path); child_types = generics.types.len(); - generics = tcx.lookup_generics(def_id); + generics = tcx.item_generics(def_id); num_regions = generics.regions.len(); num_types = generics.types.len(); @@ -865,7 +865,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { TyAdt(def, substs) => { ty::tls::with(|tcx| { if def.did.is_local() && - !tcx.tcache.borrow().contains_key(&def.did) { + !tcx.item_types.borrow().contains_key(&def.did) { write!(f, "{}<..>", tcx.item_path_str(def.did)) } else { parameterized(f, substs, def.did, &[]) @@ -878,7 +878,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { ty::tls::with(|tcx| { // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, // by looking up the projections associated with the def_id. - let item_predicates = tcx.lookup_predicates(def_id); + let item_predicates = tcx.item_predicates(def_id); let substs = tcx.lift(&substs).unwrap_or_else(|| { tcx.intern_substs(&[]) }); @@ -907,13 +907,14 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { } TyStr => write!(f, "str"), TyClosure(did, substs) => ty::tls::with(|tcx| { + let upvar_tys = substs.upvar_tys(did, tcx); write!(f, "[closure")?; if let Some(node_id) = tcx.map.as_local_node_id(did) { write!(f, "@{:?}", tcx.map.span(node_id))?; let mut sep = " "; tcx.with_freevars(node_id, |freevars| { - for (freevar, upvar_ty) in freevars.iter().zip(substs.upvar_tys) { + for (freevar, upvar_ty) in freevars.iter().zip(upvar_tys) { let def_id = freevar.def.def_id(); let node_id = tcx.map.as_local_node_id(def_id).unwrap(); write!(f, @@ -930,7 +931,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { // visible in trans bug reports, I imagine. write!(f, "@{:?}", did)?; let mut sep = " "; - for (index, upvar_ty) in substs.upvar_tys.iter().enumerate() { + for (index, upvar_ty) in upvar_tys.enumerate() { write!(f, "{}{}:{}", sep, index, upvar_ty)?; sep = ", "; } diff --git a/src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs b/src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs new file mode 100644 index 000000000000..37216e20762d --- /dev/null +++ b/src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs @@ -0,0 +1,34 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use target::{Target, TargetOptions, TargetResult}; + +pub fn target() -> TargetResult { + let base = super::linux_base::opts(); + Ok(Target { + llvm_target: "armv5te-unknown-linux-gnueabi".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), + arch: "arm".to_string(), + target_os: "linux".to_string(), + target_env: "gnu".to_string(), + target_vendor: "unknown".to_string(), + + options: TargetOptions { + features: "+soft-float".to_string(), + // No atomic instructions on ARMv5 + max_atomic_width: Some(0), + abi_blacklist: super::arm_base::abi_blacklist(), + .. base + } + }) +} + diff --git a/src/librustc_back/target/linux_musl_base.rs b/src/librustc_back/target/linux_musl_base.rs index d55907aeedfb..18cca425a32c 100644 --- a/src/librustc_back/target/linux_musl_base.rs +++ b/src/librustc_back/target/linux_musl_base.rs @@ -16,7 +16,6 @@ pub fn opts() -> TargetOptions { // 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 @@ -67,5 +66,8 @@ pub fn opts() -> TargetOptions { base.has_rpath = false; base.position_independent_executables = false; + // These targets statically link libc by default + base.crt_static_default = true; + base } diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 4d9315a1a3bd..f195ccb3f429 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -145,6 +145,7 @@ supported_targets! { ("arm-unknown-linux-gnueabihf", arm_unknown_linux_gnueabihf), ("arm-unknown-linux-musleabi", arm_unknown_linux_musleabi), ("arm-unknown-linux-musleabihf", arm_unknown_linux_musleabihf), + ("armv5te-unknown-linux-gnueabi", armv5te_unknown_linux_gnueabi), ("armv7-unknown-linux-gnueabihf", armv7_unknown_linux_gnueabihf), ("armv7-unknown-linux-musleabihf", armv7_unknown_linux_musleabihf), ("aarch64-unknown-linux-gnu", aarch64_unknown_linux_gnu), @@ -358,6 +359,11 @@ pub struct TargetOptions { // will 'just work'. pub obj_is_bitcode: bool, + // LLVM can't produce object files for this target. Instead, we'll make LLVM + // emit assembly and then use `gcc` to turn that assembly into an object + // file + pub no_integrated_as: bool, + /// Don't use this field; instead use the `.max_atomic_width()` method. pub max_atomic_width: Option, @@ -367,6 +373,9 @@ pub struct TargetOptions { /// A blacklist of ABIs unsupported by the current target. Note that generic /// ABIs are considered to be supported on all platforms and cannot be blacklisted. pub abi_blacklist: Vec, + + /// Whether or not the CRT is statically linked by default. + pub crt_static_default: bool, } impl Default for TargetOptions { @@ -415,9 +424,11 @@ impl Default for TargetOptions { allow_asm: true, has_elf_tls: false, obj_is_bitcode: false, + no_integrated_as: false, max_atomic_width: None, panic_strategy: PanicStrategy::Unwind, abi_blacklist: vec![], + crt_static_default: false, } } } @@ -575,8 +586,10 @@ impl Target { key!(exe_allocation_crate); key!(has_elf_tls, bool); key!(obj_is_bitcode, bool); + key!(no_integrated_as, bool); key!(max_atomic_width, Option); try!(key!(panic_strategy, PanicStrategy)); + key!(crt_static_default, bool); if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) { for name in array.iter().filter_map(|abi| abi.as_string()) { @@ -734,8 +747,10 @@ impl ToJson for Target { target_option_val!(exe_allocation_crate); target_option_val!(has_elf_tls); target_option_val!(obj_is_bitcode); + target_option_val!(no_integrated_as); target_option_val!(max_atomic_width); target_option_val!(panic_strategy); + target_option_val!(crt_static_default); if default.abi_blacklist != self.options.abi_blacklist { d.insert("abi-blacklist".to_string(), self.options.abi_blacklist.iter() diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs b/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs index 28f58723862c..8461f6d061a5 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs @@ -88,7 +88,7 @@ pub trait MirWithFlowState<'tcx> { } impl<'a, 'tcx: 'a, BD> MirWithFlowState<'tcx> for MirBorrowckCtxtPreDataflow<'a, 'tcx, BD> - where 'a, 'tcx: 'a, BD: BitDenotation> + where 'tcx: 'a, BD: BitDenotation> { type BD = BD; fn node_id(&self) -> NodeId { self.node_id } diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index be85069db313..cdb19d164bf2 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -709,9 +709,11 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { ty::TyAdt(def, substs) => { self.open_drop_for_adt(c, def, substs) } - ty::TyTuple(tys) | ty::TyClosure(_, ty::ClosureSubsts { - upvar_tys: tys, .. - }) => { + ty::TyClosure(def_id, substs) => { + let tys : Vec<_> = substs.upvar_tys(def_id, self.tcx).collect(); + self.open_drop_for_tuple(c, &tys) + } + ty::TyTuple(tys) => { self.open_drop_for_tuple(c, tys) } ty::TyBox(ty) => { @@ -858,7 +860,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let free_func = tcx.lang_items.require(lang_items::BoxFreeFnLangItem) .unwrap_or_else(|e| tcx.sess.fatal(&e)); let substs = tcx.mk_substs(iter::once(Kind::from(ty))); - let fty = tcx.lookup_item_type(free_func).ty.subst(tcx, substs); + let fty = tcx.item_type(free_func).subst(tcx, substs); self.patch.new_block(BasicBlockData { statements: statements, diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index fb842f70a54a..5e54e333bb90 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -110,7 +110,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { } }; - tcx.visit_all_items_in_krate(DepNode::BorrowCheck, &mut bccx); + tcx.visit_all_item_likes_in_krate(DepNode::BorrowCheck, &mut bccx.as_deep_visitor()); if tcx.sess.borrowck_stats() { println!("--- borrowck stats ---"); @@ -993,27 +993,34 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { if let Categorization::Local(local_id) = err.cmt.cat { let span = self.tcx.map.span(local_id); if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) { - if snippet.starts_with("ref ") { - db.span_label(span, - &format!("use `{}` here to make mutable", - snippet.replace("ref ", "ref mut "))); - } else if snippet != "self" { - db.span_label(span, - &format!("use `mut {}` here to make mutable", snippet)); + if snippet.starts_with("ref mut ") || snippet.starts_with("&mut ") { + db.span_label(error_span, &format!("cannot reborrow mutably")); + db.span_label(error_span, &format!("try removing `&mut` here")); + } else { + if snippet.starts_with("ref ") { + db.span_label(span, + &format!("use `{}` here to make mutable", + snippet.replace("ref ", "ref mut "))); + } else if snippet != "self" { + db.span_label(span, + &format!("use `mut {}` here to make mutable", snippet)); + } + db.span_label(error_span, &format!("cannot borrow mutably")); } + } else { + db.span_label(error_span, &format!("cannot borrow mutably")); } - db.span_label(error_span, &format!("cannot borrow mutably")); } } } } err_out_of_scope(super_scope, sub_scope, cause) => { - let (value_kind, value_msg, is_temporary) = match err.cmt.cat { + let (value_kind, value_msg) = match err.cmt.cat { mc::Categorization::Rvalue(_) => - ("temporary value", "temporary value created here", true), + ("temporary value", "temporary value created here"), _ => - ("borrowed value", "does not live long enough", false) + ("borrowed value", "borrow occurs here") }; let is_closure = match cause { @@ -1026,14 +1033,14 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { Some(primary) => { db.span = MultiSpan::from_span(s); db.span_label(primary, &format!("capture occurs here")); - db.span_label(s, &value_msg); + db.span_label(s, &"does not live long enough"); true } None => false } } _ => { - db.span_label(error_span, &value_msg); + db.span_label(error_span, &"does not live long enough"); false } }; @@ -1043,11 +1050,11 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { match (sub_span, super_span) { (Some(s1), Some(s2)) if s1 == s2 => { - if !is_temporary && !is_closure { + if !is_closure { db.span = MultiSpan::from_span(s1); - db.span_label(error_span, &format!("borrow occurs here")); + db.span_label(error_span, &value_msg); let msg = match opt_loan_path(&err.cmt) { - None => "borrowed value".to_string(), + None => value_kind.to_string(), Some(lp) => { format!("`{}`", self.loan_path_to_string(&lp)) } @@ -1060,17 +1067,16 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { db.note("values in a scope are dropped in the opposite order \ they are created"); } - (Some(s1), Some(s2)) if !is_temporary && !is_closure => { + (Some(s1), Some(s2)) if !is_closure => { db.span = MultiSpan::from_span(s2); - db.span_label(error_span, &format!("borrow occurs here")); + db.span_label(error_span, &value_msg); let msg = match opt_loan_path(&err.cmt) { - None => "borrowed value".to_string(), + None => value_kind.to_string(), Some(lp) => { format!("`{}`", self.loan_path_to_string(&lp)) } }; - db.span_label(s2, - &format!("{} dropped here while still borrowed", msg)); + db.span_label(s2, &format!("{} dropped here while still borrowed", msg)); db.span_label(s1, &format!("{} needs to live until here", value_kind)); } _ => { diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index e0e8a2159192..f63a27e0d756 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -78,7 +78,8 @@ impl<'a, 'v, 'tcx> Visitor<'v> for OuterVisitor<'a, 'tcx> { } pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - tcx.visit_all_items_in_krate(DepNode::MatchCheck, &mut OuterVisitor { tcx: tcx }); + tcx.visit_all_item_likes_in_krate(DepNode::MatchCheck, + &mut OuterVisitor { tcx: tcx }.as_deep_visitor()); tcx.sess.abort_if_errors(); } diff --git a/src/librustc_const_eval/diagnostics.rs b/src/librustc_const_eval/diagnostics.rs index db72057636a8..83b0d9dec6d9 100644 --- a/src/librustc_const_eval/diagnostics.rs +++ b/src/librustc_const_eval/diagnostics.rs @@ -40,7 +40,9 @@ Ensure the ordering of the match arm is correct and remove any superfluous arms. "##, -/*E0002: r##" +E0002: r##" +## Note: this error code is no longer emitted by the compiler. + This error indicates that an empty match expression is invalid because the type it is matching on is non-empty (there exist values of this type). In safe code it is impossible to create an instance of an empty type, so empty match @@ -68,10 +70,11 @@ fn foo(x: Option) { } } ``` -"##,*/ +"##, +E0003: r##" +## Note: this error code is no longer emitted by the compiler. -/*E0003: r##" Not-a-Number (NaN) values cannot be compared for equality and hence can never match the input to a match expression. So, the following will not compile: @@ -98,7 +101,6 @@ match number { } ``` "##, -*/ E0004: r##" This error indicates that the compiler cannot guarantee a matching pattern for diff --git a/src/librustc_data_structures/accumulate_vec.rs b/src/librustc_data_structures/accumulate_vec.rs index 3894db40277a..937cb3f60074 100644 --- a/src/librustc_data_structures/accumulate_vec.rs +++ b/src/librustc_data_structures/accumulate_vec.rs @@ -11,22 +11,68 @@ //! A vector type intended to be used for collecting from iterators onto the stack. //! //! Space for up to N elements is provided on the stack. If more elements are collected, Vec is -//! used to store the values on the heap. This type does not support re-allocating onto the heap, -//! and there is no way to push more elements onto the existing storage. +//! used to store the values on the heap. //! //! The N above is determined by Array's implementor, by way of an associatated constant. -use std::ops::Deref; -use std::iter::{IntoIterator, FromIterator}; +use std::ops::{Deref, DerefMut}; +use std::iter::{self, IntoIterator, FromIterator}; +use std::slice; +use std::vec; -use array_vec::{Array, ArrayVec}; +use rustc_serialize::{Encodable, Encoder, Decodable, Decoder}; -#[derive(Debug)] +use array_vec::{self, Array, ArrayVec}; + +#[derive(PartialEq, Eq, Hash, Debug)] pub enum AccumulateVec { Array(ArrayVec), Heap(Vec) } +impl Clone for AccumulateVec + where A: Array, + A::Element: Clone { + fn clone(&self) -> Self { + match *self { + AccumulateVec::Array(ref arr) => AccumulateVec::Array(arr.clone()), + AccumulateVec::Heap(ref vec) => AccumulateVec::Heap(vec.clone()), + } + } +} + +impl AccumulateVec { + pub fn new() -> AccumulateVec { + AccumulateVec::Array(ArrayVec::new()) + } + + pub fn one(el: A::Element) -> Self { + iter::once(el).collect() + } + + pub fn many>(iter: I) -> Self { + iter.into_iter().collect() + } + + pub fn len(&self) -> usize { + match *self { + AccumulateVec::Array(ref arr) => arr.len(), + AccumulateVec::Heap(ref vec) => vec.len(), + } + } + + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + pub fn pop(&mut self) -> Option { + match *self { + AccumulateVec::Array(ref mut arr) => arr.pop(), + AccumulateVec::Heap(ref mut vec) => vec.pop(), + } + } +} + impl Deref for AccumulateVec { type Target = [A::Element]; fn deref(&self) -> &Self::Target { @@ -37,6 +83,15 @@ impl Deref for AccumulateVec { } } +impl DerefMut for AccumulateVec { + fn deref_mut(&mut self) -> &mut [A::Element] { + match *self { + AccumulateVec::Array(ref mut v) => &mut v[..], + AccumulateVec::Heap(ref mut v) => &mut v[..], + } + } +} + impl FromIterator for AccumulateVec { fn from_iter(iter: I) -> AccumulateVec where I: IntoIterator { let iter = iter.into_iter(); @@ -50,3 +105,94 @@ impl FromIterator for AccumulateVec { } } +pub struct IntoIter { + repr: IntoIterRepr, +} + +enum IntoIterRepr { + Array(array_vec::Iter), + Heap(vec::IntoIter), +} + +impl Iterator for IntoIter { + type Item = A::Element; + + fn next(&mut self) -> Option { + match self.repr { + IntoIterRepr::Array(ref mut arr) => arr.next(), + IntoIterRepr::Heap(ref mut iter) => iter.next(), + } + } + + fn size_hint(&self) -> (usize, Option) { + match self.repr { + IntoIterRepr::Array(ref iter) => iter.size_hint(), + IntoIterRepr::Heap(ref iter) => iter.size_hint(), + } + } +} + +impl IntoIterator for AccumulateVec { + type Item = A::Element; + type IntoIter = IntoIter; + fn into_iter(self) -> Self::IntoIter { + IntoIter { + repr: match self { + AccumulateVec::Array(arr) => IntoIterRepr::Array(arr.into_iter()), + AccumulateVec::Heap(vec) => IntoIterRepr::Heap(vec.into_iter()), + } + } + } +} + +impl<'a, A: Array> IntoIterator for &'a AccumulateVec { + type Item = &'a A::Element; + type IntoIter = slice::Iter<'a, A::Element>; + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl<'a, A: Array> IntoIterator for &'a mut AccumulateVec { + type Item = &'a mut A::Element; + type IntoIter = slice::IterMut<'a, A::Element>; + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } +} + +impl From> for AccumulateVec { + fn from(v: Vec) -> AccumulateVec { + AccumulateVec::many(v) + } +} + +impl Default for AccumulateVec { + fn default() -> AccumulateVec { + AccumulateVec::new() + } +} + +impl Encodable for AccumulateVec + where A: Array, + A::Element: Encodable { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_seq(self.len(), |s| { + for (i, e) in self.iter().enumerate() { + try!(s.emit_seq_elt(i, |s| e.encode(s))); + } + Ok(()) + }) + } +} + +impl Decodable for AccumulateVec + where A: Array, + A::Element: Decodable { + fn decode(d: &mut D) -> Result, D::Error> { + d.read_seq(|d, len| { + Ok(try!((0..len).map(|i| d.read_seq_elt(i, |d| Decodable::decode(d))).collect())) + }) + } +} + diff --git a/src/librustc_data_structures/array_vec.rs b/src/librustc_data_structures/array_vec.rs index f87426cee59e..631cf2cfcf6d 100644 --- a/src/librustc_data_structures/array_vec.rs +++ b/src/librustc_data_structures/array_vec.rs @@ -9,15 +9,15 @@ // except according to those terms. //! A stack-allocated vector, allowing storage of N elements on the stack. -//! -//! Currently, only the N = 8 case is supported (due to Array only being impl-ed for [T; 8]). use std::marker::Unsize; use std::iter::Extend; -use std::ptr::drop_in_place; -use std::ops::{Deref, DerefMut}; +use std::ptr::{self, drop_in_place}; +use std::ops::{Deref, DerefMut, Range}; +use std::hash::{Hash, Hasher}; use std::slice; use std::fmt; +use std::mem; pub unsafe trait Array { type Element; @@ -25,6 +25,12 @@ pub unsafe trait Array { const LEN: usize; } +unsafe impl Array for [T; 1] { + type Element = T; + type PartialStorage = [ManuallyDrop; 1]; + const LEN: usize = 1; +} + unsafe impl Array for [T; 8] { type Element = T; type PartialStorage = [ManuallyDrop; 8]; @@ -36,6 +42,32 @@ pub struct ArrayVec { values: A::PartialStorage } +impl Hash for ArrayVec + where A: Array, + A::Element: Hash { + fn hash(&self, state: &mut H) where H: Hasher { + (&self[..]).hash(state); + } +} + +impl PartialEq for ArrayVec { + fn eq(&self, other: &Self) -> bool { + self == other + } +} + +impl Eq for ArrayVec {} + +impl Clone for ArrayVec + where A: Array, + A::Element: Clone { + fn clone(&self) -> Self { + let mut v = ArrayVec::new(); + v.extend(self.iter().cloned()); + v + } +} + impl ArrayVec { pub fn new() -> Self { ArrayVec { @@ -43,6 +75,41 @@ impl ArrayVec { values: Default::default(), } } + + pub fn len(&self) -> usize { + self.count + } + + pub unsafe fn set_len(&mut self, len: usize) { + self.count = len; + } + + /// Panics when the stack vector is full. + pub fn push(&mut self, el: A::Element) { + let arr = &mut self.values as &mut [ManuallyDrop<_>]; + arr[self.count] = ManuallyDrop { value: el }; + self.count += 1; + } + + pub fn pop(&mut self) -> Option { + if self.count > 0 { + let arr = &mut self.values as &mut [ManuallyDrop<_>]; + self.count -= 1; + unsafe { + let value = ptr::read(&arr[self.count]); + Some(value.value) + } + } else { + None + } + } +} + +impl Default for ArrayVec + where A: Array { + fn default() -> Self { + ArrayVec::new() + } } impl fmt::Debug for ArrayVec @@ -81,15 +148,69 @@ impl Drop for ArrayVec { impl Extend for ArrayVec { fn extend(&mut self, iter: I) where I: IntoIterator { for el in iter { - unsafe { - let arr = &mut self.values as &mut [ManuallyDrop<_>]; - arr[self.count].value = el; - } - self.count += 1; + self.push(el); } } } +pub struct Iter { + indices: Range, + store: A::PartialStorage, +} + +impl Drop for Iter { + fn drop(&mut self) { + for _ in self {} + } +} + +impl Iterator for Iter { + type Item = A::Element; + + fn next(&mut self) -> Option { + let arr = &self.store as &[ManuallyDrop<_>]; + unsafe { + self.indices.next().map(|i| ptr::read(&arr[i]).value) + } + } + + fn size_hint(&self) -> (usize, Option) { + self.indices.size_hint() + } +} + +impl IntoIterator for ArrayVec { + type Item = A::Element; + type IntoIter = Iter; + fn into_iter(self) -> Self::IntoIter { + let store = unsafe { + ptr::read(&self.values) + }; + let indices = 0..self.count; + mem::forget(self); + Iter { + indices: indices, + store: store, + } + } +} + +impl<'a, A: Array> IntoIterator for &'a ArrayVec { + type Item = &'a A::Element; + type IntoIter = slice::Iter<'a, A::Element>; + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl<'a, A: Array> IntoIterator for &'a mut ArrayVec { + type Item = &'a mut A::Element; + type IntoIter = slice::IterMut<'a, A::Element>; + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } +} + // FIXME: This should use repr(transparent) from rust-lang/rfcs#1758. #[allow(unions_with_drop_fields)] pub union ManuallyDrop { @@ -98,9 +219,17 @@ pub union ManuallyDrop { empty: (), } -impl Default for ManuallyDrop { - fn default() -> Self { - ManuallyDrop { empty: () } +impl ManuallyDrop { + fn new() -> ManuallyDrop { + ManuallyDrop { + empty: () + } + } +} + +impl Default for ManuallyDrop { + fn default() -> Self { + ManuallyDrop::new() } } diff --git a/src/librustc_data_structures/base_n.rs b/src/librustc_data_structures/base_n.rs new file mode 100644 index 000000000000..bf3e682f86f6 --- /dev/null +++ b/src/librustc_data_structures/base_n.rs @@ -0,0 +1,64 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// Convert unsigned integers into a string representation with some base. +/// Bases up to and including 36 can be used for case-insensitive things. + +use std::str; + +pub const MAX_BASE: u64 = 64; +const BASE_64: &'static [u8; MAX_BASE as usize] = + b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@$"; + +#[inline] +pub fn push_str(mut n: u64, base: u64, output: &mut String) { + debug_assert!(base >= 2 && base <= MAX_BASE); + let mut s = [0u8; 64]; + let mut index = 0; + + loop { + s[index] = BASE_64[(n % base) as usize]; + index += 1; + n /= base; + + if n == 0 { + break; + } + } + &mut s[0..index].reverse(); + output.push_str(str::from_utf8(&s[0..index]).unwrap()); +} + +#[inline] +pub fn encode(n: u64, base: u64) -> String { + let mut s = String::with_capacity(13); + push_str(n, base, &mut s); + s +} + +#[test] +fn test_encode() { + fn test(n: u64, base: u64) { + assert_eq!(Ok(n), u64::from_str_radix(&encode(n, base)[..], base as u32)); + } + + for base in 2..37 { + test(0, base); + test(1, base); + test(35, base); + test(36, base); + test(37, base); + test(u64::max_value(), base); + + for i in 0 .. 1_000 { + test(i * 983, base); + } + } +} diff --git a/src/librustc_data_structures/graph/mod.rs b/src/librustc_data_structures/graph/mod.rs index fdb629ca5a57..f94ed6b72094 100644 --- a/src/librustc_data_structures/graph/mod.rs +++ b/src/librustc_data_structures/graph/mod.rs @@ -231,18 +231,30 @@ impl Graph { // # Iterating over nodes, edges + pub fn enumerated_nodes(&self) -> EnumeratedNodes { + EnumeratedNodes { + iter: self.nodes.iter().enumerate() + } + } + + pub fn enumerated_edges(&self) -> EnumeratedEdges { + EnumeratedEdges { + iter: self.edges.iter().enumerate() + } + } + pub fn each_node<'a, F>(&'a self, mut f: F) -> bool where F: FnMut(NodeIndex, &'a Node) -> bool { //! Iterates over all edges defined in the graph. - self.nodes.iter().enumerate().all(|(i, node)| f(NodeIndex(i), node)) + self.enumerated_nodes().all(|(node_idx, node)| f(node_idx, node)) } pub fn each_edge<'a, F>(&'a self, mut f: F) -> bool where F: FnMut(EdgeIndex, &'a Edge) -> bool { //! Iterates over all edges defined in the graph - self.edges.iter().enumerate().all(|(i, edge)| f(EdgeIndex(i), edge)) + self.enumerated_edges().all(|(edge_idx, edge)| f(edge_idx, edge)) } pub fn outgoing_edges(&self, source: NodeIndex) -> AdjacentEdges { @@ -270,14 +282,11 @@ impl Graph { self.incoming_edges(target).sources() } - // # Fixed-point iteration - // - // A common use for graphs in our compiler is to perform - // fixed-point iteration. In this case, each edge represents a - // constraint, and the nodes themselves are associated with - // variables or other bitsets. This method facilitates such a - // computation. - + /// A common use for graphs in our compiler is to perform + /// fixed-point iteration. In this case, each edge represents a + /// constraint, and the nodes themselves are associated with + /// variables or other bitsets. This method facilitates such a + /// computation. pub fn iterate_until_fixed_point<'a, F>(&'a self, mut op: F) where F: FnMut(usize, EdgeIndex, &'a Edge) -> bool { @@ -286,8 +295,8 @@ impl Graph { while changed { changed = false; iteration += 1; - for (i, edge) in self.edges.iter().enumerate() { - changed |= op(iteration, EdgeIndex(i), edge); + for (edge_index, edge) in self.enumerated_edges() { + changed |= op(iteration, edge_index, edge); } } } @@ -298,10 +307,67 @@ impl Graph { -> DepthFirstTraversal<'a, N, E> { DepthFirstTraversal::with_start_node(self, start, direction) } + + /// Whether or not a node can be reached from itself. + pub fn is_node_cyclic(&self, starting_node_index: NodeIndex) -> bool { + // This is similar to depth traversal below, but we + // can't use that, because depth traversal doesn't show + // the starting node a second time. + let mut visited = BitVector::new(self.len_nodes()); + let mut stack = vec![starting_node_index]; + + while let Some(current_node_index) = stack.pop() { + visited.insert(current_node_index.0); + + // Directionality doesn't change the answer, + // so just use outgoing edges. + for (_, edge) in self.outgoing_edges(current_node_index) { + let target_node_index = edge.target(); + + if target_node_index == starting_node_index { + return true; + } + + if !visited.contains(target_node_index.0) { + stack.push(target_node_index); + } + } + } + + false + } } // # Iterators +pub struct EnumeratedNodes<'g, N> + where N: 'g, +{ + iter: ::std::iter::Enumerate<::std::slice::Iter<'g, Node>> +} + +impl<'g, N: Debug> Iterator for EnumeratedNodes<'g, N> { + type Item = (NodeIndex, &'g Node); + + fn next(&mut self) -> Option<(NodeIndex, &'g Node)> { + self.iter.next().map(|(idx, n)| (NodeIndex(idx), n)) + } +} + +pub struct EnumeratedEdges<'g, E> + where E: 'g, +{ + iter: ::std::iter::Enumerate<::std::slice::Iter<'g, Edge>> +} + +impl<'g, E: Debug> Iterator for EnumeratedEdges<'g, E> { + type Item = (EdgeIndex, &'g Edge); + + fn next(&mut self) -> Option<(EdgeIndex, &'g Edge)> { + self.iter.next().map(|(idx, e)| (EdgeIndex(idx), e)) + } +} + pub struct AdjacentEdges<'g, N, E> where N: 'g, E: 'g @@ -336,7 +402,7 @@ impl<'g, N: Debug, E: Debug> Iterator for AdjacentEdges<'g, N, E> { } } -pub struct AdjacentTargets<'g, N: 'g, E: 'g> +pub struct AdjacentTargets<'g, N, E> where N: 'g, E: 'g { @@ -351,7 +417,7 @@ impl<'g, N: Debug, E: Debug> Iterator for AdjacentTargets<'g, N, E> { } } -pub struct AdjacentSources<'g, N: 'g, E: 'g> +pub struct AdjacentSources<'g, N, E> where N: 'g, E: 'g { @@ -366,7 +432,10 @@ impl<'g, N: Debug, E: Debug> Iterator for AdjacentSources<'g, N, E> { } } -pub struct DepthFirstTraversal<'g, N: 'g, E: 'g> { +pub struct DepthFirstTraversal<'g, N, E> + where N: 'g, + E: 'g +{ graph: &'g Graph, stack: Vec, visited: BitVector, diff --git a/src/librustc_data_structures/graph/tests.rs b/src/librustc_data_structures/graph/tests.rs index be7f48d27e04..a87410e6e1c8 100644 --- a/src/librustc_data_structures/graph/tests.rs +++ b/src/librustc_data_structures/graph/tests.rs @@ -20,10 +20,13 @@ fn create_graph() -> TestGraph { // Create a simple graph // - // A -+> B --> C - // | | ^ - // | v | - // F D --> E + // F + // | + // V + // A --> B --> C + // | ^ + // v | + // D --> E let a = graph.add_node("A"); let b = graph.add_node("B"); @@ -42,6 +45,29 @@ fn create_graph() -> TestGraph { return graph; } +fn create_graph_with_cycle() -> TestGraph { + let mut graph = Graph::new(); + + // Create a graph with a cycle. + // + // A --> B <-- + + // | | + // v | + // C --> D + + let a = graph.add_node("A"); + let b = graph.add_node("B"); + let c = graph.add_node("C"); + let d = graph.add_node("D"); + + graph.add_edge(a, b, "AB"); + graph.add_edge(b, c, "BC"); + graph.add_edge(c, d, "CD"); + graph.add_edge(d, b, "DB"); + + return graph; +} + #[test] fn each_node() { let graph = create_graph(); @@ -139,3 +165,15 @@ fn each_adjacent_from_d() { let graph = create_graph(); test_adjacent_edges(&graph, NodeIndex(3), "D", &[("BD", "B")], &[("DE", "E")]); } + +#[test] +fn is_node_cyclic_a() { + let graph = create_graph_with_cycle(); + assert!(!graph.is_node_cyclic(NodeIndex(0))); +} + +#[test] +fn is_node_cyclic_b() { + let graph = create_graph_with_cycle(); + assert!(graph.is_node_cyclic(NodeIndex(1))); +} diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index fdcbec6bac11..de13b9bf4be1 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -46,6 +46,8 @@ extern crate libc; pub mod array_vec; pub mod accumulate_vec; +pub mod small_vec; +pub mod base_n; pub mod bitslice; pub mod blake2b; pub mod bitvec; diff --git a/src/librustc_data_structures/small_vec.rs b/src/librustc_data_structures/small_vec.rs new file mode 100644 index 000000000000..565a3c443a34 --- /dev/null +++ b/src/librustc_data_structures/small_vec.rs @@ -0,0 +1,203 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A vector type intended to be used for collecting from iterators onto the stack. +//! +//! Space for up to N elements is provided on the stack. If more elements are collected, Vec is +//! used to store the values on the heap. SmallVec is similar to AccumulateVec, but adds +//! the ability to push elements. +//! +//! The N above is determined by Array's implementor, by way of an associatated constant. + +use std::ops::{Deref, DerefMut}; +use std::iter::{IntoIterator, FromIterator}; +use std::fmt::{self, Debug}; +use std::mem; +use std::ptr; + +use rustc_serialize::{Encodable, Encoder, Decodable, Decoder}; + +use accumulate_vec::{IntoIter, AccumulateVec}; +use array_vec::Array; + +pub struct SmallVec(AccumulateVec); + +impl Clone for SmallVec + where A: Array, + A::Element: Clone { + fn clone(&self) -> Self { + SmallVec(self.0.clone()) + } +} + +impl Debug for SmallVec + where A: Array + Debug, + A::Element: Debug { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("SmallVec").field(&self.0).finish() + } +} + +impl SmallVec { + pub fn new() -> Self { + SmallVec(AccumulateVec::new()) + } + + pub fn with_capacity(cap: usize) -> Self { + let mut vec = SmallVec::new(); + vec.reserve(cap); + vec + } + + pub fn one(el: A::Element) -> Self { + SmallVec(AccumulateVec::one(el)) + } + + pub fn many>(els: I) -> Self { + SmallVec(AccumulateVec::many(els)) + } + + pub fn expect_one(self, err: &'static str) -> A::Element { + assert!(self.len() == 1, err); + match self.0 { + AccumulateVec::Array(arr) => arr.into_iter().next().unwrap(), + AccumulateVec::Heap(vec) => vec.into_iter().next().unwrap(), + } + } + + /// Will reallocate onto the heap if needed. + pub fn push(&mut self, el: A::Element) { + self.reserve(1); + match self.0 { + AccumulateVec::Array(ref mut array) => array.push(el), + AccumulateVec::Heap(ref mut vec) => vec.push(el), + } + } + + pub fn reserve(&mut self, n: usize) { + match self.0 { + AccumulateVec::Array(_) => { + if self.len() + n > A::LEN { + let len = self.len(); + let array = mem::replace(&mut self.0, + AccumulateVec::Heap(Vec::with_capacity(len + n))); + if let AccumulateVec::Array(array) = array { + match self.0 { + AccumulateVec::Heap(ref mut vec) => vec.extend(array), + _ => unreachable!() + } + } + } + } + AccumulateVec::Heap(ref mut vec) => vec.reserve(n) + } + } + + pub unsafe fn set_len(&mut self, len: usize) { + match self.0 { + AccumulateVec::Array(ref mut arr) => arr.set_len(len), + AccumulateVec::Heap(ref mut vec) => vec.set_len(len), + } + } + + pub fn insert(&mut self, index: usize, element: A::Element) { + let len = self.len(); + + // Reserve space for shifting elements to the right + self.reserve(1); + + assert!(index <= len); + + unsafe { + // infallible + // The spot to put the new value + { + let p = self.as_mut_ptr().offset(index as isize); + // Shift everything over to make space. (Duplicating the + // `index`th element into two consecutive places.) + ptr::copy(p, p.offset(1), len - index); + // Write it in, overwriting the first copy of the `index`th + // element. + ptr::write(p, element); + } + self.set_len(len + 1); + } + } +} + +impl Deref for SmallVec { + type Target = AccumulateVec; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for SmallVec { + fn deref_mut(&mut self) -> &mut AccumulateVec { + &mut self.0 + } +} + +impl FromIterator for SmallVec { + fn from_iter(iter: I) -> Self where I: IntoIterator { + SmallVec(iter.into_iter().collect()) + } +} + +impl Extend for SmallVec { + fn extend>(&mut self, iter: I) { + let iter = iter.into_iter(); + self.reserve(iter.size_hint().0); + for el in iter { + self.push(el); + } + } +} + +impl IntoIterator for SmallVec { + type Item = A::Element; + type IntoIter = IntoIter; + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + +impl Default for SmallVec { + fn default() -> SmallVec { + SmallVec::new() + } +} + +impl Encodable for SmallVec + where A: Array, + A::Element: Encodable { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_seq(self.len(), |s| { + for (i, e) in self.iter().enumerate() { + try!(s.emit_seq_elt(i, |s| e.encode(s))); + } + Ok(()) + }) + } +} + +impl Decodable for SmallVec + where A: Array, + A::Element: Decodable { + fn decode(d: &mut D) -> Result, D::Error> { + d.read_seq(|d, len| { + let mut vec = SmallVec::with_capacity(len); + for i in 0..len { + vec.push(try!(d.read_seq_elt(i, |d| Decodable::decode(d)))); + } + Ok(vec) + }) + } +} diff --git a/src/librustc_driver/derive_registrar.rs b/src/librustc_driver/derive_registrar.rs index ea7621e16e7b..4db620b2bec3 100644 --- a/src/librustc_driver/derive_registrar.rs +++ b/src/librustc_driver/derive_registrar.rs @@ -9,7 +9,7 @@ // except according to those terms. use rustc::dep_graph::DepNode; -use rustc::hir::intravisit::Visitor; +use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::map::Map; use rustc::hir; use syntax::ast; @@ -20,7 +20,7 @@ pub fn find(hir_map: &Map) -> Option { let krate = hir_map.krate(); let mut finder = Finder { registrar: None }; - krate.visit_all_items(&mut finder); + krate.visit_all_item_likes(&mut finder); finder.registrar } @@ -28,10 +28,14 @@ struct Finder { registrar: Option, } -impl<'v> Visitor<'v> for Finder { +impl<'v> ItemLikeVisitor<'v> for Finder { fn visit_item(&mut self, item: &hir::Item) { if attr::contains_name(&item.attrs, "rustc_derive_registrar") { self.registrar = Some(item.id); } } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + } } + diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index d83918495676..6a3a1bbb55ca 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -709,10 +709,12 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, let crate_types = sess.crate_types.borrow(); let num_crate_types = crate_types.len(); let is_proc_macro_crate = crate_types.contains(&config::CrateTypeProcMacro); + let is_test_crate = sess.opts.test; syntax_ext::proc_macro_registrar::modify(&sess.parse_sess, &mut resolver, krate, is_proc_macro_crate, + is_test_crate, num_crate_types, sess.diagnostic(), &sess.features.borrow()) @@ -755,8 +757,6 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, || ast_validation::check_crate(sess, &krate)); time(sess.time_passes(), "name resolution", || -> CompileResult { - resolver.resolve_imports(); - // Since import resolution will eventually happen in expansion, // don't perform `after_expand` until after import resolution. after_expand(&krate)?; @@ -1056,7 +1056,11 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub fn phase_5_run_llvm_passes(sess: &Session, trans: &trans::CrateTranslation, outputs: &OutputFilenames) -> CompileResult { - if sess.opts.cg.no_integrated_as { + if sess.opts.cg.no_integrated_as || + (sess.target.target.options.no_integrated_as && + (outputs.outputs.contains_key(&OutputType::Object) || + outputs.outputs.contains_key(&OutputType::Exe))) + { let output_types = OutputTypes::new(&[(OutputType::Assembly, None)]); time(sess.time_passes(), "LLVM passes", @@ -1064,6 +1068,17 @@ pub fn phase_5_run_llvm_passes(sess: &Session, write::run_assembler(sess, outputs); + // HACK the linker expects the object file to be named foo.0.o but + // `run_assembler` produces an object named just foo.o. Rename it if we + // are going to build an executable + if sess.opts.output_types.contains_key(&OutputType::Exe) { + let f = outputs.path(OutputType::Object); + fs::copy(&f, + f.with_file_name(format!("{}.0.o", + f.file_stem().unwrap().to_string_lossy()))).unwrap(); + fs::remove_file(f).unwrap(); + } + // Remove assembly source, unless --save-temps was specified if !sess.opts.cg.save_temps { fs::remove_file(&outputs.temp_path(OutputType::Assembly, None)).unwrap(); diff --git a/src/librustc_driver/target_features.rs b/src/librustc_driver/target_features.rs index ba51947a3330..57a9edc5c586 100644 --- a/src/librustc_driver/target_features.rs +++ b/src/librustc_driver/target_features.rs @@ -12,6 +12,7 @@ use syntax::{ast, attr}; use llvm::LLVMRustHasFeature; use rustc::session::Session; use rustc_trans::back::write::create_target_machine; +use syntax::feature_gate::UnstableFeatures; use syntax::parse::token::InternedString; use syntax::parse::token::intern_and_get_ident as intern; use libc::c_char; @@ -47,4 +48,32 @@ pub fn add_configuration(cfg: &mut ast::CrateConfig, sess: &Session) { cfg.push(attr::mk_name_value_item_str(tf.clone(), intern(&feat[..feat.len() - 1]))) } } + + let requested_features = sess.opts.cg.target_feature.split(','); + let unstable_options = sess.opts.debugging_opts.unstable_options; + let is_nightly = UnstableFeatures::from_environment().is_nightly_build(); + let found_negative = requested_features.clone().any(|r| r == "-crt-static"); + let found_positive = requested_features.clone().any(|r| r == "+crt-static"); + + // If the target we're compiling for requests a static crt by default, + // then see if the `-crt-static` feature was passed to disable that. + // Otherwise if we don't have a static crt by default then see if the + // `+crt-static` feature was passed. + let crt_static = if sess.target.target.options.crt_static_default { + !found_negative + } else { + found_positive + }; + + // If we switched from the default then that's only allowed on nightly, so + // gate that here. + if (found_positive || found_negative) && (!is_nightly || !unstable_options) { + sess.fatal("specifying the `crt-static` target feature is only allowed \ + on the nightly channel with `-Z unstable-options` passed \ + as well"); + } + + if crt_static { + cfg.push(attr::mk_name_value_item_str(tf.clone(), intern("crt-static"))); + } } diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 8dc21550148c..782c74c8c78c 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -21,9 +21,9 @@ use rustc::middle::region::CodeExtentData; use rustc::middle::resolve_lifetime; use rustc::middle::stability; use rustc::ty::subst::{Kind, Subst}; -use rustc::traits::Reveal; +use rustc::traits::{ObligationCause, Reveal}; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc::infer::{self, InferOk, InferResult, TypeOrigin}; +use rustc::infer::{self, InferOk, InferResult}; use rustc_metadata::cstore::CStore; use rustc::hir::map as hir_map; use rustc::session::{self, config}; @@ -36,7 +36,6 @@ use errors::emitter::Emitter; use errors::{Level, DiagnosticBuilder}; use syntax::parse::token; use syntax::feature_gate::UnstableFeatures; -use syntax_pos::DUMMY_SP; use rustc::hir; @@ -245,7 +244,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { } pub fn make_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool { - match self.infcx.sub_types(true, TypeOrigin::Misc(DUMMY_SP), a, b) { + match self.infcx.sub_types(true, &ObligationCause::dummy(), a, b) { Ok(_) => true, Err(ref e) => panic!("Encountered error: {}", e), } diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index 37477da755c9..998cbae2cce1 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -51,7 +51,7 @@ use rustc::ty::TyCtxt; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::graph::{Direction, INCOMING, OUTGOING, NodeIndex}; use rustc::hir; -use rustc::hir::intravisit::Visitor; +use rustc::hir::itemlikevisit::ItemLikeVisitor; use graphviz::IntoCow; use std::env; use std::fs::File; @@ -81,7 +81,7 @@ pub fn assert_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { if_this_changed: vec![], then_this_would_need: vec![] }; visitor.process_attrs(ast::CRATE_NODE_ID, &tcx.map.krate().attrs); - tcx.map.krate().visit_all_items(&mut visitor); + tcx.map.krate().visit_all_item_likes(&mut visitor); (visitor.if_this_changed, visitor.then_this_would_need) }; @@ -167,10 +167,14 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for IfThisChanged<'a, 'tcx> { +impl<'a, 'tcx> ItemLikeVisitor<'tcx> for IfThisChanged<'a, 'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item) { self.process_attrs(item.id, &item.attrs); } + + fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { + self.process_attrs(impl_item.id, &impl_item.attrs); + } } fn check_paths<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index 58a215299741..f98e698a1c9d 100644 --- a/src/librustc_incremental/calculate_svh/mod.rs +++ b/src/librustc_incremental/calculate_svh/mod.rs @@ -34,6 +34,7 @@ use rustc::dep_graph::DepNode; use rustc::hir; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use rustc::hir::intravisit as visit; +use rustc::hir::intravisit::Visitor; use rustc::ty::TyCtxt; use rustc_data_structures::fx::FxHashMap; use rustc::util::common::record_time; @@ -45,6 +46,7 @@ use self::caching_codemap_view::CachingCodemapView; use self::hasher::IchHasher; use ich::Fingerprint; + mod def_path_hash; mod svh_visitor; mod caching_codemap_view; @@ -87,7 +89,12 @@ impl<'a> ::std::ops::Index<&'a DepNode> for IncrementalHashesMap { type Output = Fingerprint; fn index(&self, index: &'a DepNode) -> &Fingerprint { - &self.hashes[index] + match self.hashes.get(index) { + Some(fingerprint) => fingerprint, + None => { + bug!("Could not find ICH for {:?}", index); + } + } } } @@ -107,7 +114,12 @@ pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) record_time(&tcx.sess.perf_stats.incr_comp_hashes_time, || { visitor.calculate_def_id(DefId::local(CRATE_DEF_INDEX), |v| visit::walk_crate(v, krate)); - krate.visit_all_items(&mut visitor); + krate.visit_all_item_likes(&mut visitor.as_deep_visitor()); + + for macro_def in krate.exported_macros.iter() { + visitor.calculate_node_id(macro_def.id, + |v| v.visit_macro_def(macro_def)); + } }); tcx.sess.perf_stats.incr_comp_hashes_count.set(visitor.hashes.len() as u64); @@ -199,12 +211,17 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { } -impl<'a, 'tcx> visit::Visitor<'tcx> for HashItemsVisitor<'a, 'tcx> { +impl<'a, 'tcx> Visitor<'tcx> for HashItemsVisitor<'a, 'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item) { self.calculate_node_id(item.id, |v| v.visit_item(item)); visit::walk_item(self, item); } + fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { + self.calculate_node_id(impl_item.id, |v| v.visit_impl_item(impl_item)); + visit::walk_impl_item(self, impl_item); + } + fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) { self.calculate_node_id(item.id, |v| v.visit_foreign_item(item)); visit::walk_foreign_item(self, item); diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 0b0dd596784e..a1ece48462b1 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -8,11 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME (#14132): Even this SVH computation still has implementation -// artifacts: namely, the order of item declaration will affect the -// hash computation, but for many kinds of items the order of -// declaration should be irrelevant to the ABI. - use self::SawExprComponent::*; use self::SawAbiComponent::*; use self::SawItemComponent::*; @@ -24,6 +19,7 @@ use syntax::ast::{self, Name, NodeId}; use syntax::attr; use syntax::parse::token; use syntax_pos::{Span, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos}; +use syntax::tokenstream; use rustc::hir; use rustc::hir::*; use rustc::hir::def::{Def, PathResolution}; @@ -199,6 +195,8 @@ enum SawAbiComponent<'a> { SawExpr(SawExprComponent<'a>), SawStmt, SawVis, + SawAssociatedItemKind(hir::AssociatedItemKind), + SawDefaultness(hir::Defaultness), SawWherePredicate, SawTyParamBound, SawPolyTraitRef, @@ -499,10 +497,6 @@ macro_rules! hash_span { } impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx> { - fn visit_nested_item(&mut self, _: ItemId) { - // Each item is hashed independently; ignore nested items. - } - fn visit_variant_data(&mut self, s: &'tcx VariantData, name: Name, @@ -697,6 +691,18 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has visit::walk_vis(self, v) } + fn visit_associated_item_kind(&mut self, kind: &'tcx AssociatedItemKind) { + debug!("visit_associated_item_kind: st={:?}", self.st); + SawAssociatedItemKind(*kind).hash(self.st); + visit::walk_associated_item_kind(self, kind); + } + + fn visit_defaultness(&mut self, defaultness: &'tcx Defaultness) { + debug!("visit_associated_item_kind: st={:?}", self.st); + SawDefaultness(*defaultness).hash(self.st); + visit::walk_defaultness(self, defaultness); + } + fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate) { debug!("visit_where_predicate: st={:?}", self.st); SawWherePredicate.hash(self.st); @@ -759,9 +765,10 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has debug!("visit_macro_def: st={:?}", self.st); SawMacroDef.hash(self.st); hash_attrs!(self, ¯o_def.attrs); + for tt in ¯o_def.body { + self.hash_token_tree(tt); + } visit::walk_macro_def(self, macro_def) - // FIXME(mw): We should hash the body of the macro too but we don't - // have a stable way of doing so yet. } } @@ -931,4 +938,139 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { self.overflow_checks_enabled = true; } } + + fn hash_token_tree(&mut self, tt: &tokenstream::TokenTree) { + self.hash_discriminant(tt); + match *tt { + tokenstream::TokenTree::Token(span, ref token) => { + hash_span!(self, span); + self.hash_token(token, span); + } + tokenstream::TokenTree::Delimited(span, ref delimited) => { + hash_span!(self, span); + let tokenstream::Delimited { + ref delim, + open_span, + ref tts, + close_span, + } = **delimited; + + delim.hash(self.st); + hash_span!(self, open_span); + tts.len().hash(self.st); + for sub_tt in tts { + self.hash_token_tree(sub_tt); + } + hash_span!(self, close_span); + } + tokenstream::TokenTree::Sequence(span, ref sequence_repetition) => { + hash_span!(self, span); + let tokenstream::SequenceRepetition { + ref tts, + ref separator, + op, + num_captures, + } = **sequence_repetition; + + tts.len().hash(self.st); + for sub_tt in tts { + self.hash_token_tree(sub_tt); + } + self.hash_discriminant(separator); + if let Some(ref separator) = *separator { + self.hash_token(separator, span); + } + op.hash(self.st); + num_captures.hash(self.st); + } + } + } + + fn hash_token(&mut self, + token: &token::Token, + error_reporting_span: Span) { + self.hash_discriminant(token); + match *token { + token::Token::Eq | + token::Token::Lt | + token::Token::Le | + token::Token::EqEq | + token::Token::Ne | + token::Token::Ge | + token::Token::Gt | + token::Token::AndAnd | + token::Token::OrOr | + token::Token::Not | + token::Token::Tilde | + token::Token::At | + token::Token::Dot | + token::Token::DotDot | + token::Token::DotDotDot | + token::Token::Comma | + token::Token::Semi | + token::Token::Colon | + token::Token::ModSep | + token::Token::RArrow | + token::Token::LArrow | + token::Token::FatArrow | + token::Token::Pound | + token::Token::Dollar | + token::Token::Question | + token::Token::Underscore | + token::Token::Whitespace | + token::Token::Comment | + token::Token::Eof => {} + + token::Token::BinOp(bin_op_token) | + token::Token::BinOpEq(bin_op_token) => bin_op_token.hash(self.st), + + token::Token::OpenDelim(delim_token) | + token::Token::CloseDelim(delim_token) => delim_token.hash(self.st), + + token::Token::Literal(ref lit, ref opt_name) => { + self.hash_discriminant(lit); + match *lit { + token::Lit::Byte(val) | + token::Lit::Char(val) | + token::Lit::Integer(val) | + token::Lit::Float(val) | + token::Lit::Str_(val) | + token::Lit::ByteStr(val) => val.as_str().hash(self.st), + token::Lit::StrRaw(val, n) | + token::Lit::ByteStrRaw(val, n) => { + val.as_str().hash(self.st); + n.hash(self.st); + } + }; + opt_name.map(ast::Name::as_str).hash(self.st); + } + + token::Token::Ident(ident) | + token::Token::Lifetime(ident) | + token::Token::SubstNt(ident) => ident.name.as_str().hash(self.st), + token::Token::MatchNt(ident1, ident2) => { + ident1.name.as_str().hash(self.st); + ident2.name.as_str().hash(self.st); + } + + token::Token::Interpolated(ref non_terminal) => { + // FIXME(mw): This could be implemented properly. It's just a + // lot of work, since we would need to hash the AST + // in a stable way, in addition to the HIR. + // Since this is hardly used anywhere, just emit a + // warning for now. + if self.tcx.sess.opts.debugging_opts.incremental.is_some() { + let msg = format!("Quasi-quoting might make incremental \ + compilation very inefficient: {:?}", + non_terminal); + self.tcx.sess.span_warn(error_reporting_span, &msg[..]); + } + + non_terminal.hash(self.st); + } + + token::Token::DocComment(val) | + token::Token::Shebang(val) => val.as_str().hash(self.st), + } + } } diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index 69b9be12de46..0cd1c88fb877 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -45,7 +45,7 @@ use super::load::DirtyNodes; use rustc::dep_graph::{DepGraphQuery, DepNode}; use rustc::hir; use rustc::hir::def_id::DefId; -use rustc::hir::intravisit::Visitor; +use rustc::hir::itemlikevisit::ItemLikeVisitor; use syntax::ast::{self, Attribute, NestedMetaItem}; use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use syntax::parse::token::InternedString; @@ -74,7 +74,7 @@ pub fn check_dirty_clean_annotations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let query = tcx.dep_graph.query(); debug!("query-nodes: {:?}", query.nodes()); let krate = tcx.map.krate(); - krate.visit_all_items(&mut DirtyCleanVisitor { + krate.visit_all_item_likes(&mut DirtyCleanVisitor { tcx: tcx, query: &query, dirty_inputs: dirty_inputs, @@ -169,7 +169,7 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for DirtyCleanVisitor<'a, 'tcx> { +impl<'a, 'tcx> ItemLikeVisitor<'tcx> for DirtyCleanVisitor<'a, 'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item) { let def_id = self.tcx.map.local_def_id(item.id); for attr in self.tcx.get_attrs(def_id).iter() { @@ -184,6 +184,9 @@ impl<'a, 'tcx> Visitor<'tcx> for DirtyCleanVisitor<'a, 'tcx> { } } } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + } } pub fn check_dirty_clean_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -195,7 +198,7 @@ pub fn check_dirty_clean_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.dep_graph.with_ignore(||{ let krate = tcx.map.krate(); - krate.visit_all_items(&mut DirtyCleanMetadataVisitor { + krate.visit_all_item_likes(&mut DirtyCleanMetadataVisitor { tcx: tcx, prev_metadata_hashes: prev_metadata_hashes, current_metadata_hashes: current_metadata_hashes, @@ -209,7 +212,7 @@ pub struct DirtyCleanMetadataVisitor<'a, 'tcx:'a, 'm> { current_metadata_hashes: &'m FxHashMap, } -impl<'a, 'tcx, 'm> Visitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx, 'm> { +impl<'a, 'tcx, 'm> ItemLikeVisitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx, 'm> { fn visit_item(&mut self, item: &'tcx hir::Item) { let def_id = self.tcx.map.local_def_id(item.id); @@ -225,6 +228,9 @@ impl<'a, 'tcx, 'm> Visitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx, 'm> { } } } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + } } impl<'a, 'tcx, 'm> DirtyCleanMetadataVisitor<'a, 'tcx, 'm> { diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs index ca9c11920232..2572a9c1d78f 100644 --- a/src/librustc_incremental/persist/fs.rs +++ b/src/librustc_incremental/persist/fs.rs @@ -119,7 +119,7 @@ use rustc::hir::svh::Svh; use rustc::session::Session; use rustc::ty::TyCtxt; use rustc::util::fs as fs_util; -use rustc_data_structures::flock; +use rustc_data_structures::{flock, base_n}; use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use std::ffi::OsString; @@ -135,6 +135,12 @@ const DEP_GRAPH_FILENAME: &'static str = "dep-graph.bin"; const WORK_PRODUCTS_FILENAME: &'static str = "work-products.bin"; const METADATA_HASHES_FILENAME: &'static str = "metadata.bin"; +// We encode integers using the following base, so they are shorter than decimal +// or hexadecimal numbers (we want short file and directory names). Since these +// numbers will be used in file names, we choose an encoding that is not +// case-sensitive (as opposed to base64, for example). +const INT_ENCODE_BASE: u64 = 36; + pub fn dep_graph_path(sess: &Session) -> PathBuf { in_incr_comp_dir_sess(sess, DEP_GRAPH_FILENAME) } @@ -195,6 +201,19 @@ pub fn prepare_session_directory(tcx: TyCtxt) -> Result { debug!("crate-dir: {}", crate_dir.display()); try!(create_dir(tcx.sess, &crate_dir, "crate")); + // Hack: canonicalize the path *after creating the directory* + // because, on windows, long paths can cause problems; + // canonicalization inserts this weird prefix that makes windows + // tolerate long paths. + let crate_dir = match crate_dir.canonicalize() { + Ok(v) => v, + Err(err) => { + tcx.sess.err(&format!("incremental compilation: error canonicalizing path `{}`: {}", + crate_dir.display(), err)); + return Err(()); + } + }; + let mut source_directories_already_tried = FxHashSet(); loop { @@ -327,7 +346,7 @@ pub fn finalize_session_directory(sess: &Session, svh: Svh) { let mut new_sub_dir_name = String::from(&old_sub_dir_name[.. dash_indices[2] + 1]); // Append the svh - new_sub_dir_name.push_str(&encode_base_36(svh.as_u64())); + base_n::push_str(svh.as_u64(), INT_ENCODE_BASE, &mut new_sub_dir_name); // Create the full path let new_path = incr_comp_session_dir.parent().unwrap().join(new_sub_dir_name); @@ -433,7 +452,8 @@ fn generate_session_dir_path(crate_dir: &Path) -> PathBuf { let directory_name = format!("s-{}-{}-working", timestamp, - encode_base_36(random_number as u64)); + base_n::encode(random_number as u64, + INT_ENCODE_BASE)); debug!("generate_session_dir_path: directory_name = {}", directory_name); let directory_path = crate_dir.join(directory_name); debug!("generate_session_dir_path: directory_path = {}", directory_path.display()); @@ -562,27 +582,11 @@ fn extract_timestamp_from_session_dir(directory_name: &str) string_to_timestamp(&directory_name[dash_indices[0]+1 .. dash_indices[1]]) } -const BASE_36: &'static [u8] = b"0123456789abcdefghijklmnopqrstuvwxyz"; - -fn encode_base_36(mut n: u64) -> String { - let mut s = Vec::with_capacity(13); - loop { - s.push(BASE_36[(n % 36) as usize]); - n /= 36; - - if n == 0 { - break; - } - } - s.reverse(); - String::from_utf8(s).unwrap() -} - fn timestamp_to_string(timestamp: SystemTime) -> String { let duration = timestamp.duration_since(UNIX_EPOCH).unwrap(); let micros = duration.as_secs() * 1_000_000 + (duration.subsec_nanos() as u64) / 1000; - encode_base_36(micros) + base_n::encode(micros, INT_ENCODE_BASE) } fn string_to_timestamp(s: &str) -> Result { @@ -629,7 +633,7 @@ pub fn find_metadata_hashes_for(tcx: TyCtxt, cnum: CrateNum) -> Option }; let target_svh = tcx.sess.cstore.crate_hash(cnum); - let target_svh = encode_base_36(target_svh.as_u64()); + let target_svh = base_n::encode(target_svh.as_u64(), INT_ENCODE_BASE); let sub_dir = find_metadata_hashes_iter(&target_svh, dir_entries.filter_map(|e| { e.ok().map(|e| e.file_name().to_string_lossy().into_owned()) @@ -677,7 +681,9 @@ fn crate_path(sess: &Session, let mut hasher = DefaultHasher::new(); crate_disambiguator.hash(&mut hasher); - let crate_name = format!("{}-{}", crate_name, encode_base_36(hasher.finish())); + let crate_name = format!("{}-{}", + crate_name, + base_n::encode(hasher.finish(), INT_ENCODE_BASE)); incr_dir.join(crate_name) } @@ -1049,21 +1055,3 @@ fn test_find_metadata_hashes_iter() None ); } - -#[test] -fn test_encode_base_36() { - fn test(n: u64) { - assert_eq!(Ok(n), u64::from_str_radix(&encode_base_36(n)[..], 36)); - } - - test(0); - test(1); - test(35); - test(36); - test(37); - test(u64::max_value()); - - for i in 0 .. 1_000 { - test(i * 983); - } -} diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index c19b3c40f65c..51ffb1ebc8e9 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -118,9 +118,10 @@ impl LateLintPass for BoxPointers { hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemUnion(..) => { - self.check_heap_type(cx, it.span, cx.tcx.tables().node_id_to_type(it.id)) + let def_id = cx.tcx.map.local_def_id(it.id); + self.check_heap_type(cx, it.span, cx.tcx.item_type(def_id)) } - _ => (), + _ => () } // If it's a struct, we also have to check the fields' types @@ -128,9 +129,9 @@ impl LateLintPass for BoxPointers { hir::ItemStruct(ref struct_def, _) | hir::ItemUnion(ref struct_def, _) => { for struct_field in struct_def.fields() { - self.check_heap_type(cx, - struct_field.span, - cx.tcx.tables().node_id_to_type(struct_field.id)); + let def_id = cx.tcx.map.local_def_id(struct_field.id); + self.check_heap_type(cx, struct_field.span, + cx.tcx.item_type(def_id)); } } _ => (), @@ -386,7 +387,7 @@ impl LateLintPass for MissingDoc { "a trait" } hir::ItemTy(..) => "a type alias", - hir::ItemImpl(.., Some(ref trait_ref), _, ref impl_items) => { + hir::ItemImpl(.., Some(ref trait_ref), _, ref impl_item_refs) => { // If the trait is private, add the impl items to private_traits so they don't get // reported for missing docs. let real_trait = cx.tcx.expect_def(trait_ref.ref_id).def_id(); @@ -394,8 +395,8 @@ impl LateLintPass for MissingDoc { match cx.tcx.map.find(node_id) { Some(hir_map::NodeItem(item)) => { if item.vis == hir::Visibility::Inherited { - for itm in impl_items { - self.private_traits.insert(itm.id); + for impl_item_ref in impl_item_refs { + self.private_traits.insert(impl_item_ref.id.node_id); } } } @@ -585,11 +586,9 @@ impl LateLintPass for MissingDebugImplementations { let debug_def = cx.tcx.lookup_trait_def(debug); let mut impls = NodeSet(); debug_def.for_each_impl(cx.tcx, |d| { - if let Some(n) = cx.tcx.map.as_local_node_id(d) { - if let Some(ty_def) = cx.tcx.tables().node_id_to_type(n).ty_to_def_id() { - if let Some(node_id) = cx.tcx.map.as_local_node_id(ty_def) { - impls.insert(node_id); - } + if let Some(ty_def) = cx.tcx.item_type(d).ty_to_def_id() { + if let Some(node_id) = cx.tcx.map.as_local_node_id(ty_def) { + impls.insert(node_id); } } }); @@ -1225,7 +1224,7 @@ impl LateLintPass for MutableTransmutes { } fn def_id_is_transmute(cx: &LateContext, def_id: DefId) -> bool { - match cx.tcx.lookup_item_type(def_id).ty.sty { + match cx.tcx.item_type(def_id).sty { ty::TyFnDef(.., ref bfty) if bfty.abi == RustIntrinsic => (), _ => return false, } @@ -1282,7 +1281,7 @@ impl LateLintPass for UnionsWithDropFields { if let hir::ItemUnion(ref vdata, _) = item.node { let param_env = &ty::ParameterEnvironment::for_item(ctx.tcx, item.id); for field in vdata.fields() { - let field_ty = ctx.tcx.tables().node_id_to_type(field.id); + let field_ty = ctx.tcx.item_type(ctx.tcx.map.local_def_id(field.id)); if ctx.tcx.type_needs_drop_given_env(field_ty, param_env) { ctx.span_lint(UNIONS_WITH_DROP_FIELDS, field.span, diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 48471282672a..4155d3e67a26 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -675,8 +675,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { fn check_foreign_fn(&mut self, id: ast::NodeId, decl: &hir::FnDecl) { let def_id = self.cx.tcx.map.local_def_id(id); - let scheme = self.cx.tcx.lookup_item_type(def_id); - let sig = scheme.ty.fn_sig(); + let sig = self.cx.tcx.item_type(def_id).fn_sig(); let sig = self.cx.tcx.erase_late_bound_regions(&sig); for (&input_ty, input_hir) in sig.inputs.iter().zip(&decl.inputs) { @@ -693,8 +692,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { fn check_foreign_static(&mut self, id: ast::NodeId, span: Span) { let def_id = self.cx.tcx.map.local_def_id(id); - let scheme = self.cx.tcx.lookup_item_type(def_id); - self.check_type_for_ffi_and_report_errors(span, scheme.ty); + let ty = self.cx.tcx.item_type(def_id); + self.check_type_for_ffi_and_report_errors(span, ty); } } @@ -740,11 +739,12 @@ impl LateLintPass for VariantSizeDifferences { if let hir::ItemEnum(ref enum_definition, ref gens) = it.node { if gens.ty_params.is_empty() { // sizes only make sense for non-generic types - let t = cx.tcx.tables().node_id_to_type(it.id); + let t = cx.tcx.item_type(cx.tcx.map.local_def_id(it.id)); let layout = cx.tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| { let ty = cx.tcx.erase_regions(&t); - ty.layout(&infcx) - .unwrap_or_else(|e| bug!("failed to get layout for `{}`: {}", t, e)) + ty.layout(&infcx).unwrap_or_else(|e| { + bug!("failed to get layout for `{}`: {}", t, e) + }) }); if let Layout::General { ref variants, ref size, discr, .. } = *layout { diff --git a/src/librustc_llvm/Cargo.toml b/src/librustc_llvm/Cargo.toml index f97daa22ff66..88f8c0553adc 100644 --- a/src/librustc_llvm/Cargo.toml +++ b/src/librustc_llvm/Cargo.toml @@ -12,9 +12,6 @@ crate-type = ["dylib"] [features] static-libstdcpp = [] -[dependencies] -rustc_bitflags = { path = "../librustc_bitflags" } - [build-dependencies] build_helper = { path = "../build_helper" } gcc = "0.3.27" diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index 8656bb8bf003..50bc3e7b6243 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -17,6 +17,35 @@ use std::path::{PathBuf, Path}; use build_helper::output; +fn detect_llvm_link(llvm_config: &Path) -> (&'static str, Option<&'static str>) { + let mut version_cmd = Command::new(llvm_config); + version_cmd.arg("--version"); + let version_output = output(&mut version_cmd); + let mut parts = version_output.split('.').take(2) + .filter_map(|s| s.parse::().ok()); + if let (Some(major), Some(minor)) = (parts.next(), parts.next()) { + if major > 3 || (major == 3 && minor >= 9) { + // Force the link mode we want, preferring static by default, but + // possibly overridden by `configure --enable-llvm-link-shared`. + if env::var_os("LLVM_LINK_SHARED").is_some() { + return ("dylib", Some("--link-shared")); + } else { + return ("static", Some("--link-static")); + } + } else if major == 3 && minor == 8 { + // Find out LLVM's default linking mode. + let mut mode_cmd = Command::new(llvm_config); + mode_cmd.arg("--shared-mode"); + if output(&mut mode_cmd).trim() == "shared" { + return ("dylib", None); + } else { + return ("static", None); + } + } + } + ("static", None) +} + fn main() { println!("cargo:rustc-cfg=cargobuild"); @@ -66,7 +95,7 @@ fn main() { let is_crossed = target != host; let optional_components = - ["x86", "arm", "aarch64", "mips", "powerpc", "pnacl", "systemz", "jsbackend"]; + ["x86", "arm", "aarch64", "mips", "powerpc", "pnacl", "systemz", "jsbackend", "msp430"]; // FIXME: surely we don't need all these components, right? Stuff like mcjit // or interpreter the compiler itself never uses. @@ -116,6 +145,9 @@ fn main() { cfg.flag("-DLLVM_RUSTLLVM"); } + println!("cargo:rerun-if-changed=../rustllvm/PassWrapper.cpp"); + println!("cargo:rerun-if-changed=../rustllvm/RustWrapper.cpp"); + println!("cargo:rerun-if-changed=../rustllvm/ArchiveWrapper.cpp"); cfg.file("../rustllvm/PassWrapper.cpp") .file("../rustllvm/RustWrapper.cpp") .file("../rustllvm/ArchiveWrapper.cpp") @@ -123,22 +155,16 @@ fn main() { .cpp_link_stdlib(None) // we handle this below .compile("librustllvm.a"); + let (llvm_kind, llvm_link_arg) = detect_llvm_link(&llvm_config); + // Link in all LLVM libraries, if we're uwring the "wrong" llvm-config then // we don't pick up system libs because unfortunately they're for the host // of llvm-config, not the target that we're attempting to link. let mut cmd = Command::new(&llvm_config); cmd.arg("--libs"); - // Force static linking with "--link-static" if available. - let mut version_cmd = Command::new(&llvm_config); - version_cmd.arg("--version"); - let version_output = output(&mut version_cmd); - let mut parts = version_output.split('.'); - if let (Some(major), Some(minor)) = (parts.next().and_then(|s| s.parse::().ok()), - parts.next().and_then(|s| s.parse::().ok())) { - if major > 3 || (major == 3 && minor >= 9) { - cmd.arg("--link-static"); - } + if let Some(link_arg) = llvm_link_arg { + cmd.arg(link_arg); } if !is_crossed { @@ -174,7 +200,7 @@ fn main() { } let kind = if name.starts_with("LLVM") { - "static" + llvm_kind } else { "dylib" }; diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 78a9d67ed770..ebd75be7bba0 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -41,6 +41,7 @@ pub enum CallConv { ColdCallConv = 9, X86StdcallCallConv = 64, X86FastcallCallConv = 65, + ArmAapcsCallConv = 67, X86_64_SysV = 78, X86_64_Win64 = 79, X86_VectorCall = 80, @@ -82,59 +83,31 @@ pub enum DLLStorageClass { DllExport = 2, // Function to be accessible from DLL. } -bitflags! { - #[derive(Default, Debug)] - flags Attribute : u64 { - const ZExt = 1 << 0, - const SExt = 1 << 1, - const NoReturn = 1 << 2, - const InReg = 1 << 3, - const StructRet = 1 << 4, - const NoUnwind = 1 << 5, - const NoAlias = 1 << 6, - const ByVal = 1 << 7, - const Nest = 1 << 8, - const ReadNone = 1 << 9, - const ReadOnly = 1 << 10, - const NoInline = 1 << 11, - const AlwaysInline = 1 << 12, - const OptimizeForSize = 1 << 13, - const StackProtect = 1 << 14, - const StackProtectReq = 1 << 15, - const NoCapture = 1 << 21, - const NoRedZone = 1 << 22, - const NoImplicitFloat = 1 << 23, - const Naked = 1 << 24, - const InlineHint = 1 << 25, - const ReturnsTwice = 1 << 29, - const UWTable = 1 << 30, - const NonLazyBind = 1 << 31, - - // Some of these are missing from the LLVM C API, the rest are - // present, but commented out, and preceded by the following warning: - // FIXME: These attributes are currently not included in the C API as - // a temporary measure until the API/ABI impact to the C API is understood - // and the path forward agreed upon. - const SanitizeAddress = 1 << 32, - const MinSize = 1 << 33, - const NoDuplicate = 1 << 34, - const StackProtectStrong = 1 << 35, - const SanitizeThread = 1 << 36, - const SanitizeMemory = 1 << 37, - const NoBuiltin = 1 << 38, - const Returned = 1 << 39, - const Cold = 1 << 40, - const Builtin = 1 << 41, - const OptimizeNone = 1 << 42, - const InAlloca = 1 << 43, - const NonNull = 1 << 44, - const JumpTable = 1 << 45, - const Convergent = 1 << 46, - const SafeStack = 1 << 47, - const NoRecurse = 1 << 48, - const InaccessibleMemOnly = 1 << 49, - const InaccessibleMemOrArgMemOnly = 1 << 50, - } +/// Matches LLVMRustAttribute in rustllvm.h +/// Semantically a subset of the C++ enum llvm::Attribute::AttrKind, +/// though it is not ABI compatible (since it's a C++ enum) +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub enum Attribute { + AlwaysInline = 0, + ByVal = 1, + Cold = 2, + InlineHint = 3, + MinSize = 4, + Naked = 5, + NoAlias = 6, + NoCapture = 7, + NoInline = 8, + NonNull = 9, + NoRedZone = 10, + NoReturn = 11, + NoUnwind = 12, + OptimizeForSize = 13, + ReadOnly = 14, + SExt = 15, + StructRet = 16, + UWTable = 17, + ZExt = 18, } /// LLVMIntPredicate @@ -422,10 +395,21 @@ pub type RustArchiveMemberRef = *mut RustArchiveMember_opaque; #[allow(missing_copy_implementations)] pub enum OperandBundleDef_opaque {} pub type OperandBundleDefRef = *mut OperandBundleDef_opaque; +#[allow(missing_copy_implementations)] +pub enum Attribute_opaque {} +pub type AttributeRef = *mut Attribute_opaque; pub type DiagnosticHandler = unsafe extern "C" fn(DiagnosticInfoRef, *mut c_void); pub type InlineAsmDiagHandler = unsafe extern "C" fn(SMDiagnosticRef, *const c_void, c_uint); +/// LLVMVisibility +#[repr(C)] +pub enum Visibility { + Default, + Hidden, + Protected, +} + pub mod debuginfo { pub use self::DIDescriptorFlags::*; use super::MetadataRef; @@ -521,6 +505,9 @@ extern "C" { /// See llvm::LLVMType::getContext. pub fn LLVMGetTypeContext(Ty: TypeRef) -> ContextRef; + /// See llvm::Value::getContext + pub fn LLVMRustGetValueContext(V: ValueRef) -> ContextRef; + // Operations on integer types pub fn LLVMInt1TypeInContext(C: ContextRef) -> TypeRef; pub fn LLVMInt8TypeInContext(C: ContextRef) -> TypeRef; @@ -746,8 +733,8 @@ extern "C" { pub fn LLVMRustSetLinkage(Global: ValueRef, RustLinkage: Linkage); pub fn LLVMGetSection(Global: ValueRef) -> *const c_char; pub fn LLVMSetSection(Global: ValueRef, Section: *const c_char); - pub fn LLVMGetVisibility(Global: ValueRef) -> c_uint; - pub fn LLVMSetVisibility(Global: ValueRef, Viz: c_uint); + pub fn LLVMGetVisibility(Global: ValueRef) -> Visibility; + pub fn LLVMSetVisibility(Global: ValueRef, Viz: Visibility); pub fn LLVMGetAlignment(Global: ValueRef) -> c_uint; pub fn LLVMSetAlignment(Global: ValueRef, Bytes: c_uint); pub fn LLVMSetDLLStorageClass(V: ValueRef, C: DLLStorageClass); @@ -783,6 +770,8 @@ extern "C" { Name: *const c_char) -> ValueRef; + pub fn LLVMRustCreateAttribute(C: ContextRef, kind: Attribute, val: u64) -> AttributeRef; + // Operations on functions pub fn LLVMAddFunction(M: ModuleRef, Name: *const c_char, FunctionTy: TypeRef) -> ValueRef; pub fn LLVMGetNamedFunction(M: ModuleRef, Name: *const c_char) -> ValueRef; @@ -801,16 +790,12 @@ extern "C" { pub fn LLVMGetGC(Fn: ValueRef) -> *const c_char; pub fn LLVMSetGC(Fn: ValueRef, Name: *const c_char); pub fn LLVMRustAddDereferenceableAttr(Fn: ValueRef, index: c_uint, bytes: u64); - pub fn LLVMRustAddFunctionAttribute(Fn: ValueRef, index: c_uint, PA: u64); - pub fn LLVMRustAddFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char); + pub fn LLVMRustAddFunctionAttribute(Fn: ValueRef, index: c_uint, attr: AttributeRef); pub fn LLVMRustAddFunctionAttrStringValue(Fn: ValueRef, index: c_uint, Name: *const c_char, Value: *const c_char); - pub fn LLVMRustRemoveFunctionAttributes(Fn: ValueRef, index: c_uint, attr: u64); - pub fn LLVMRustRemoveFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char); - pub fn LLVMGetFunctionAttr(Fn: ValueRef) -> c_uint; - pub fn LLVMRemoveFunctionAttr(Fn: ValueRef, val: c_uint); + pub fn LLVMRustRemoveFunctionAttributes(Fn: ValueRef, index: c_uint, attr: AttributeRef); // Operations on parameters pub fn LLVMCountParams(Fn: ValueRef) -> c_uint; @@ -821,9 +806,8 @@ extern "C" { pub fn LLVMGetLastParam(Fn: ValueRef) -> ValueRef; pub fn LLVMGetNextParam(Arg: ValueRef) -> ValueRef; pub fn LLVMGetPreviousParam(Arg: ValueRef) -> ValueRef; - pub fn LLVMAddAttribute(Arg: ValueRef, PA: c_uint); - pub fn LLVMRemoveAttribute(Arg: ValueRef, PA: c_uint); - pub fn LLVMGetAttribute(Arg: ValueRef) -> c_uint; + pub fn LLVMAddAttribute(Arg: ValueRef, attr: AttributeRef); + pub fn LLVMRemoveAttribute(Arg: ValueRef, attr: AttributeRef); pub fn LLVMSetParamAlignment(Arg: ValueRef, align: c_uint); // Operations on basic blocks @@ -867,7 +851,7 @@ extern "C" { pub fn LLVMAddInstrAttribute(Instr: ValueRef, index: c_uint, IA: c_uint); pub fn LLVMRemoveInstrAttribute(Instr: ValueRef, index: c_uint, IA: c_uint); pub fn LLVMSetInstrParamAlignment(Instr: ValueRef, index: c_uint, align: c_uint); - pub fn LLVMRustAddCallSiteAttribute(Instr: ValueRef, index: c_uint, Val: u64); + pub fn LLVMRustAddCallSiteAttribute(Instr: ValueRef, index: c_uint, attr: AttributeRef); pub fn LLVMRustAddDereferenceableCallSiteAttr(Instr: ValueRef, index: c_uint, bytes: u64); // Operations on call instructions (only) diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 07b87072c435..c81d3b48aa96 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -29,12 +29,8 @@ #![feature(staged_api)] #![feature(linked_from)] #![feature(concat_idents)] -#![cfg_attr(not(stage0), feature(rustc_private))] extern crate libc; -#[macro_use] -#[no_link] -extern crate rustc_bitflags; pub use self::IntPredicate::*; pub use self::RealPredicate::*; @@ -68,54 +64,6 @@ impl LLVMRustResult { } } -#[derive(Copy, Clone, Default, Debug)] -pub struct Attributes { - regular: Attribute, - dereferenceable_bytes: u64, -} - -impl Attributes { - pub fn set(&mut self, attr: Attribute) -> &mut Self { - self.regular = self.regular | attr; - self - } - - pub fn unset(&mut self, attr: Attribute) -> &mut Self { - self.regular = self.regular - attr; - self - } - - pub fn set_dereferenceable(&mut self, bytes: u64) -> &mut Self { - self.dereferenceable_bytes = bytes; - self - } - - pub fn unset_dereferenceable(&mut self) -> &mut Self { - self.dereferenceable_bytes = 0; - self - } - - pub fn apply_llfn(&self, idx: AttributePlace, llfn: ValueRef) { - unsafe { - self.regular.apply_llfn(idx, llfn); - if self.dereferenceable_bytes != 0 { - LLVMRustAddDereferenceableAttr(llfn, idx.as_uint(), self.dereferenceable_bytes); - } - } - } - - pub fn apply_callsite(&self, idx: AttributePlace, callsite: ValueRef) { - unsafe { - self.regular.apply_callsite(idx, callsite); - if self.dereferenceable_bytes != 0 { - LLVMRustAddDereferenceableCallSiteAttr(callsite, - idx.as_uint(), - self.dereferenceable_bytes); - } - } - } -} - pub fn AddFunctionAttrStringValue(llfn: ValueRef, idx: AttributePlace, attr: &'static str, @@ -140,7 +88,7 @@ impl AttributePlace { AttributePlace::Argument(0) } - fn as_uint(self) -> c_uint { + pub fn as_uint(self) -> c_uint { match self { AttributePlace::Function => !0, AttributePlace::Argument(i) => i, @@ -228,16 +176,20 @@ pub fn set_thread_local(global: ValueRef, is_thread_local: bool) { } impl Attribute { + fn as_object(&self, value: ValueRef) -> AttributeRef { + unsafe { LLVMRustCreateAttribute(LLVMRustGetValueContext(value), *self, 0) } + } + pub fn apply_llfn(&self, idx: AttributePlace, llfn: ValueRef) { - unsafe { LLVMRustAddFunctionAttribute(llfn, idx.as_uint(), self.bits()) } + unsafe { LLVMRustAddFunctionAttribute(llfn, idx.as_uint(), self.as_object(llfn)) } } pub fn apply_callsite(&self, idx: AttributePlace, callsite: ValueRef) { - unsafe { LLVMRustAddCallSiteAttribute(callsite, idx.as_uint(), self.bits()) } + unsafe { LLVMRustAddCallSiteAttribute(callsite, idx.as_uint(), self.as_object(callsite)) } } pub fn unapply_llfn(&self, idx: AttributePlace, llfn: ValueRef) { - unsafe { LLVMRustRemoveFunctionAttributes(llfn, idx.as_uint(), self.bits()) } + unsafe { LLVMRustRemoveFunctionAttributes(llfn, idx.as_uint(), self.as_object(llfn)) } } pub fn toggle_llfn(&self, idx: AttributePlace, llfn: ValueRef, set: bool) { @@ -413,6 +365,11 @@ pub fn initialize_available_targets() { LLVMInitializeJSBackendTargetInfo, LLVMInitializeJSBackendTarget, LLVMInitializeJSBackendTargetMC); + init_target!(llvm_component = "msp430", + LLVMInitializeMSP430TargetInfo, + LLVMInitializeMSP430Target, + LLVMInitializeMSP430TargetMC, + LLVMInitializeMSP430AsmPrinter); } pub fn last_error() -> Option { diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index e009955b92ee..e2fa535bb44a 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -133,7 +133,10 @@ pub fn decode_inlined_item<'a, 'tcx>(cdata: &CrateMetadata, &InlinedItem::ImplItem(_, ref ii) => ii.id, }; let inlined_did = tcx.map.local_def_id(item_node_id); - tcx.register_item_type(inlined_did, tcx.lookup_item_type(orig_did)); + let ty = tcx.item_type(orig_did); + let generics = tcx.item_generics(orig_did); + tcx.item_types.borrow_mut().insert(inlined_did, ty); + tcx.generics.borrow_mut().insert(inlined_did, generics); for (id, entry) in ast.side_tables.decode((cdata, tcx, id_ranges)) { match entry { @@ -141,7 +144,7 @@ pub fn decode_inlined_item<'a, 'tcx>(cdata: &CrateMetadata, tcx.def_map.borrow_mut().insert(id, def::PathResolution::new(def)); } TableEntry::NodeType(ty) => { - tcx.node_type_insert(id, ty); + tcx.tables.borrow_mut().node_types.insert(id, ty); } TableEntry::ItemSubsts(item_substs) => { tcx.tables.borrow_mut().item_substs.insert(id, item_substs); diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 75944122f5c1..5384535024e5 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -23,6 +23,7 @@ use rustc::session::search_paths::PathKind; use rustc::middle; use rustc::middle::cstore::{CrateStore, validate_crate_name, ExternCrate}; use rustc::util::nodemap::{FxHashMap, FxHashSet}; +use rustc::middle::cstore::NativeLibrary; use rustc::hir::map::Definitions; use std::cell::{RefCell, Cell}; @@ -35,6 +36,7 @@ use syntax::ast; use syntax::abi::Abi; use syntax::attr; use syntax::ext::base::SyntaxExtension; +use syntax::feature_gate::{self, GateIssue}; use syntax::parse::token::{InternedString, intern}; use syntax_pos::{Span, DUMMY_SP}; use log; @@ -77,9 +79,8 @@ struct ExternCrateInfo { fn register_native_lib(sess: &Session, cstore: &CStore, span: Option, - name: String, - kind: cstore::NativeLibraryKind) { - if name.is_empty() { + lib: NativeLibrary) { + if lib.name.is_empty() { match span { Some(span) => { struct_span_err!(sess, span, E0454, @@ -94,17 +95,21 @@ fn register_native_lib(sess: &Session, return } let is_osx = sess.target.target.options.is_like_osx; - if kind == cstore::NativeFramework && !is_osx { + if lib.kind == cstore::NativeFramework && !is_osx { let msg = "native frameworks are only available on OSX targets"; match span { - Some(span) => { - span_err!(sess, span, E0455, - "{}", msg) - } + Some(span) => span_err!(sess, span, E0455, "{}", msg), None => sess.err(msg), } } - cstore.add_used_library(name, kind); + if lib.cfg.is_some() && !sess.features.borrow().link_cfg { + feature_gate::emit_feature_err(&sess.parse_sess, + "link_cfg", + span.unwrap(), + GateIssue::Language, + "is feature gated"); + } + cstore.add_used_library(lib); } // Extra info about a crate loaded for plugins or exported macros. @@ -313,11 +318,11 @@ impl<'a> CrateLoader<'a> { name: &str, hash: Option<&Svh>, span: Span, - kind: PathKind, + path_kind: PathKind, mut dep_kind: DepKind) -> (CrateNum, Rc) { info!("resolving crate `extern crate {} as {}`", name, ident); - let result = if let Some(cnum) = self.existing_match(name, hash, kind) { + let result = if let Some(cnum) = self.existing_match(name, hash, path_kind) { LoadResult::Previous(cnum) } else { info!("falling back to a load"); @@ -327,7 +332,7 @@ impl<'a> CrateLoader<'a> { ident: ident, crate_name: name, hash: hash.map(|a| &*a), - filesearch: self.sess.target_filesearch(kind), + filesearch: self.sess.target_filesearch(path_kind), target: &self.sess.target.target, triple: &self.sess.opts.target_triple, root: root, @@ -345,7 +350,7 @@ impl<'a> CrateLoader<'a> { let mut proc_macro_locator = locator::Context { target: &self.sess.host, triple: config::host_triple(), - filesearch: self.sess.host_filesearch(PathKind::Crate), + filesearch: self.sess.host_filesearch(path_kind), rejected_via_hash: vec![], rejected_via_triple: vec![], rejected_via_kind: vec![], @@ -635,9 +640,9 @@ impl<'a> CrateLoader<'a> { fn register_statically_included_foreign_items(&mut self) { let libs = self.cstore.get_used_libraries(); - for (lib, list) in self.foreign_item_map.iter() { - let is_static = libs.borrow().iter().any(|&(ref name, kind)| { - lib == name && kind == cstore::NativeStatic + for (foreign_lib, list) in self.foreign_item_map.iter() { + let is_static = libs.borrow().iter().any(|lib| { + *foreign_lib == lib.name && lib.kind == cstore::NativeStatic }); if is_static { for id in list { @@ -898,7 +903,18 @@ impl<'a> CrateLoader<'a> { InternedString::new("foo") } }; - register_native_lib(self.sess, self.cstore, Some(m.span), n.to_string(), kind); + let cfg = items.iter().find(|k| { + k.check_name("cfg") + }).and_then(|a| a.meta_item_list()); + let cfg = cfg.map(|list| { + list[0].meta_item().unwrap().clone() + }); + let lib = NativeLibrary { + name: n.to_string(), + kind: kind, + cfg: cfg, + }; + register_native_lib(self.sess, self.cstore, Some(m.span), lib); } // Finally, process the #[linked_from = "..."] attribute @@ -924,7 +940,12 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { } for &(ref name, kind) in &self.sess.opts.libs { - register_native_lib(self.sess, self.cstore, None, name.clone(), kind); + let lib = NativeLibrary { + name: name.clone(), + kind: kind, + cfg: None, + }; + register_native_lib(self.sess, self.cstore, None, lib); } self.register_statically_included_foreign_items(); } diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 8c95e4aec0a0..37853b7473a6 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -31,7 +31,7 @@ use syntax::{ast, attr}; use syntax::ext::base::SyntaxExtension; use syntax_pos; -pub use rustc::middle::cstore::{NativeLibraryKind, LinkagePreference}; +pub use rustc::middle::cstore::{NativeLibrary, LinkagePreference}; pub use rustc::middle::cstore::{NativeStatic, NativeFramework, NativeUnknown}; pub use rustc::middle::cstore::{CrateSource, LinkMeta}; @@ -97,7 +97,7 @@ pub struct CStore { metas: RefCell>>, /// Map from NodeId's of local extern crate statements to crate numbers extern_mod_crate_map: RefCell>, - used_libraries: RefCell>, + used_libraries: RefCell>, used_link_args: RefCell>, statically_included_foreign_items: RefCell, pub inlined_item_cache: RefCell>>, @@ -212,12 +212,12 @@ impl CStore { libs } - pub fn add_used_library(&self, lib: String, kind: NativeLibraryKind) { - assert!(!lib.is_empty()); - self.used_libraries.borrow_mut().push((lib, kind)); + pub fn add_used_library(&self, lib: NativeLibrary) { + assert!(!lib.name.is_empty()); + self.used_libraries.borrow_mut().push(lib); } - pub fn get_used_libraries<'a>(&'a self) -> &'a RefCell> { + pub fn get_used_libraries(&self) -> &RefCell> { &self.used_libraries } diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 83de8acdb605..2018d829597d 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -14,7 +14,7 @@ use locator; use schema; use rustc::middle::cstore::{InlinedItem, CrateStore, CrateSource, DepKind, ExternCrate}; -use rustc::middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference, LoadedMacro}; +use rustc::middle::cstore::{NativeLibrary, LinkMeta, LinkagePreference, LoadedMacro}; use rustc::hir::def::{self, Def}; use rustc::middle::lang_items; use rustc::session::Session; @@ -295,7 +295,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { }) } - fn native_libraries(&self, cnum: CrateNum) -> Vec<(NativeLibraryKind, String)> + fn native_libraries(&self, cnum: CrateNum) -> Vec { self.get_crate_data(cnum).get_native_libraries() } @@ -356,7 +356,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn load_macro(&self, id: DefId, sess: &Session) -> LoadedMacro { let data = self.get_crate_data(id.krate); if let Some(ref proc_macros) = data.proc_macros { - return LoadedMacro::ProcMacro(proc_macros[id.index.as_usize()].1.clone()); + return LoadedMacro::ProcMacro(proc_macros[id.index.as_usize() - 1].1.clone()); } let (name, def) = data.get_macro(id.index); @@ -524,7 +524,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { result } - fn used_libraries(&self) -> Vec<(String, NativeLibraryKind)> + fn used_libraries(&self) -> Vec { self.get_used_libraries().borrow().clone() } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 78cde4c2fcb7..3af9d291ae55 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -11,7 +11,7 @@ // Decoding metadata from a single crate's metadata use astencode::decode_inlined_item; -use cstore::{self, CrateMetadata, MetadataBlob, NativeLibraryKind}; +use cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary}; use index::Index; use schema::*; @@ -23,7 +23,7 @@ use rustc::hir::intravisit::IdRange; use rustc::middle::cstore::{DepKind, InlinedItem, LinkagePreference}; use rustc::hir::def::{self, Def, CtorKind}; -use rustc::hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE}; +use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc::middle::lang_items; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::Substs; @@ -513,7 +513,14 @@ impl<'a, 'tcx> CrateMetadata { } pub fn get_def(&self, index: DefIndex) -> Option { - self.entry(index).kind.to_def(self.local_def_id(index)) + if self.proc_macros.is_some() { + Some(match index { + CRATE_DEF_INDEX => Def::Mod(self.local_def_id(index)), + _ => Def::Macro(self.local_def_id(index)), + }) + } else { + self.entry(index).kind.to_def(self.local_def_id(index)) + } } pub fn get_trait_def(&self, @@ -527,7 +534,7 @@ impl<'a, 'tcx> CrateMetadata { ty::TraitDef::new(data.unsafety, data.paren_sugar, - tcx.lookup_generics(self.local_def_id(item_id)), + tcx.item_generics(self.local_def_id(item_id)), data.trait_ref.decode((self, tcx)), self.def_path(item_id).unwrap().deterministic_hash(tcx)) } @@ -643,15 +650,24 @@ impl<'a, 'tcx> CrateMetadata { } pub fn get_stability(&self, id: DefIndex) -> Option { - self.entry(id).stability.map(|stab| stab.decode(self)) + match self.proc_macros { + Some(_) if id != CRATE_DEF_INDEX => None, + _ => self.entry(id).stability.map(|stab| stab.decode(self)), + } } pub fn get_deprecation(&self, id: DefIndex) -> Option { - self.entry(id).deprecation.map(|depr| depr.decode(self)) + match self.proc_macros { + Some(_) if id != CRATE_DEF_INDEX => None, + _ => self.entry(id).deprecation.map(|depr| depr.decode(self)), + } } pub fn get_visibility(&self, id: DefIndex) -> ty::Visibility { - self.entry(id).visibility + match self.proc_macros { + Some(_) => ty::Visibility::Public, + _ => self.entry(id).visibility, + } } fn get_impl_data(&self, id: DefIndex) -> ImplData<'tcx> { @@ -692,11 +708,11 @@ impl<'a, 'tcx> CrateMetadata { where F: FnMut(def::Export) { if let Some(ref proc_macros) = self.proc_macros { - for (id, &(name, _)) in proc_macros.iter().enumerate() { - callback(def::Export { - name: name, - def: Def::Macro(DefId { krate: self.cnum, index: DefIndex::new(id), }), - }) + if id == CRATE_DEF_INDEX { + for (id, &(name, _)) in proc_macros.iter().enumerate() { + let def = Def::Macro(DefId { krate: self.cnum, index: DefIndex::new(id + 1) }); + callback(def::Export { name: name, def: def }); + } } return } @@ -834,7 +850,6 @@ impl<'a, 'tcx> CrateMetadata { kind: ty::AssociatedKind::Const, vis: item.visibility, defaultness: container.defaultness(), - has_value: container.has_value(), def_id: self.local_def_id(id), container: container.with_def_id(parent), method_has_self_argument: false @@ -848,7 +863,6 @@ impl<'a, 'tcx> CrateMetadata { kind: ty::AssociatedKind::Method, vis: item.visibility, defaultness: data.container.defaultness(), - has_value: data.container.has_value(), def_id: self.local_def_id(id), container: data.container.with_def_id(parent), method_has_self_argument: data.has_self @@ -861,7 +875,6 @@ impl<'a, 'tcx> CrateMetadata { kind: ty::AssociatedKind::Type, vis: item.visibility, defaultness: container.defaultness(), - has_value: container.has_value(), def_id: self.local_def_id(id), container: container.with_def_id(parent), method_has_self_argument: false @@ -894,6 +907,9 @@ impl<'a, 'tcx> CrateMetadata { } pub fn get_item_attrs(&self, node_id: DefIndex) -> Vec { + if self.proc_macros.is_some() && node_id != CRATE_DEF_INDEX { + return Vec::new(); + } // The attributes for a tuple struct are attached to the definition, not the ctor; // we assume that someone passing in a tuple struct ctor is actually wanting to // look at the definition @@ -980,7 +996,7 @@ impl<'a, 'tcx> CrateMetadata { } - pub fn get_native_libraries(&self) -> Vec<(NativeLibraryKind, String)> { + pub fn get_native_libraries(&self) -> Vec { self.root.native_libraries.decode(self).collect() } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index ac1f2afcb2ad..3ab542442a1f 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -13,7 +13,7 @@ use index::Index; use schema::*; use rustc::middle::cstore::{InlinedItemRef, LinkMeta}; -use rustc::middle::cstore::{LinkagePreference, NativeLibraryKind}; +use rustc::middle::cstore::{LinkagePreference, NativeLibrary}; use rustc::hir::def; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId}; use rustc::middle::dependency_format::Linkage; @@ -38,6 +38,7 @@ use syntax; use syntax_pos; use rustc::hir::{self, PatKind}; +use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::intravisit::Visitor; use rustc::hir::intravisit; @@ -246,7 +247,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_item_type(&mut self, def_id: DefId) -> Lazy> { let tcx = self.tcx; - self.lazy(&tcx.lookup_item_type(def_id).ty) + self.lazy(&tcx.item_type(def_id)) } /// Encode data for the given variant of the given ADT. The @@ -444,12 +445,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_generics(&mut self, def_id: DefId) -> Lazy> { let tcx = self.tcx; - self.lazy(tcx.lookup_generics(def_id)) + self.lazy(tcx.item_generics(def_id)) } fn encode_predicates(&mut self, def_id: DefId) -> Lazy> { let tcx = self.tcx; - self.lazy(&tcx.lookup_predicates(def_id)) + self.lazy(&tcx.item_predicates(def_id)) } fn encode_info_for_trait_item(&mut self, def_id: DefId) -> Entry<'tcx> { @@ -459,10 +460,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let ast_item = tcx.map.expect_trait_item(node_id); let trait_item = tcx.associated_item(def_id); - let container = if trait_item.has_value { - AssociatedContainer::TraitWithDefault - } else { - AssociatedContainer::TraitRequired + let container = match trait_item.defaultness { + hir::Defaultness::Default { has_value: true } => + AssociatedContainer::TraitWithDefault, + hir::Defaultness::Default { has_value: false } => + AssociatedContainer::TraitRequired, + hir::Defaultness::Final => + span_bug!(ast_item.span, "traits cannot have final items"), }; let kind = match trait_item.kind { @@ -500,7 +504,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { Some(self.encode_item_type(def_id)) } ty::AssociatedKind::Type => { - if trait_item.has_value { + if trait_item.defaultness.has_value() { Some(self.encode_item_type(def_id)) } else { None @@ -529,8 +533,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let impl_def_id = impl_item.container.id(); let container = match impl_item.defaultness { - hir::Defaultness::Default => AssociatedContainer::ImplDefault, + hir::Defaultness::Default { has_value: true } => AssociatedContainer::ImplDefault, hir::Defaultness::Final => AssociatedContainer::ImplFinal, + hir::Defaultness::Default { has_value: false } => + span_bug!(ast_item.span, "impl items always have values (currently)"), }; let kind = match impl_item.kind { @@ -556,7 +562,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let (ast, mir) = if impl_item.kind == ty::AssociatedKind::Const { (true, true) } else if let hir::ImplItemKind::Method(ref sig, _) = ast_item.node { - let generics = self.tcx.lookup_generics(def_id); + let generics = self.tcx.item_generics(def_id); let types = generics.parent_types as usize + generics.types.len(); let needs_inline = types > 0 || attr::requests_inline(&ast_item.attrs); let is_const_fn = sig.constness == hir::Constness::Const; @@ -717,7 +723,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { paren_sugar: trait_def.paren_sugar, has_default_impl: tcx.trait_has_default_impl(def_id), trait_ref: self.lazy(&trait_def.trait_ref), - super_predicates: self.lazy(&tcx.lookup_super_predicates(def_id)), + super_predicates: self.lazy(&tcx.item_super_predicates(def_id)), }; EntryKind::Trait(self.lazy(&data)) @@ -1056,10 +1062,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { stability: None, deprecation: None, - ty: None, + ty: Some(self.encode_item_type(def_id)), inherent_impls: LazySeq::empty(), variances: LazySeq::empty(), - generics: None, + generics: Some(self.encode_generics(def_id)), predicates: None, ast: None, @@ -1074,7 +1080,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { EncodeContext::encode_info_for_mod, FromId(CRATE_NODE_ID, (&krate.module, &krate.attrs, &hir::Public))); let mut visitor = EncodeVisitor { index: index }; - krate.visit_all_items(&mut visitor); + krate.visit_all_item_likes(&mut visitor.as_deep_visitor()); for macro_def in &krate.exported_macros { visitor.visit_macro_def(macro_def); } @@ -1134,14 +1140,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy_seq_ref(&tcx.lang_items.missing)) } - fn encode_native_libraries(&mut self) -> LazySeq<(NativeLibraryKind, String)> { + fn encode_native_libraries(&mut self) -> LazySeq { let used_libraries = self.tcx.sess.cstore.used_libraries(); - self.lazy_seq(used_libraries.into_iter().filter_map(|(lib, kind)| { - match kind { - cstore::NativeStatic => None, // these libraries are not propagated - cstore::NativeFramework | cstore::NativeUnknown => Some((kind, lib)), - } - })) + self.lazy_seq(used_libraries) } fn encode_codemap(&mut self) -> LazySeq { @@ -1164,7 +1165,7 @@ struct ImplVisitor<'a, 'tcx: 'a> { impls: FxHashMap>, } -impl<'a, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'tcx> { +impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ImplVisitor<'a, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { if let hir::ItemImpl(..) = item.node { let impl_id = self.tcx.map.local_def_id(item.id); @@ -1176,6 +1177,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'tcx> { } } } + + fn visit_impl_item(&mut self, _impl_item: &'v hir::ImplItem) { + // handled in `visit_item` above + } } impl<'a, 'tcx> EncodeContext<'a, 'tcx> { @@ -1185,7 +1190,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { tcx: self.tcx, impls: FxHashMap(), }; - self.tcx.map.krate().visit_all_items(&mut visitor); + self.tcx.map.krate().visit_all_item_likes(&mut visitor); let all_impls: Vec<_> = visitor.impls .into_iter() diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs index b6b347fff5f2..b677a63edc06 100644 --- a/src/librustc_metadata/locator.rs +++ b/src/librustc_metadata/locator.rs @@ -217,7 +217,7 @@ use creader::Library; use schema::{METADATA_HEADER, rustc_version}; use rustc::hir::svh::Svh; -use rustc::session::Session; +use rustc::session::{config, Session}; use rustc::session::filesearch::{FileSearch, FileMatches, FileDoesntMatch}; use rustc::session::search_paths::PathKind; use rustc::util::common; @@ -355,6 +355,11 @@ impl<'a> Context<'a> { "can't find crate for `{}`{}", self.ident, add); + + if (self.ident == "std" || self.ident == "core") + && self.triple != config::host_triple() { + err.note(&format!("the `{}` target may not be installed", self.triple)); + } err.span_label(self.span, &format!("can't find crate")); err }; diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index d7a5f7ad7154..32c8c5e2ee87 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -14,7 +14,7 @@ use index; use rustc::hir; use rustc::hir::def::{self, CtorKind}; use rustc::hir::def_id::{DefIndex, DefId}; -use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibraryKind}; +use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibrary}; use rustc::middle::lang_items; use rustc::mir; use rustc::ty::{self, Ty}; @@ -175,7 +175,7 @@ pub struct CrateRoot { pub dylib_dependency_formats: LazySeq>, pub lang_items: LazySeq<(DefIndex, usize)>, pub lang_items_missing: LazySeq, - pub native_libraries: LazySeq<(NativeLibraryKind, String)>, + pub native_libraries: LazySeq, pub codemap: LazySeq, pub impls: LazySeq, pub reachable_ids: LazySeq, @@ -310,21 +310,16 @@ impl AssociatedContainer { } } - pub fn has_value(&self) -> bool { - match *self { - AssociatedContainer::TraitRequired => false, - - AssociatedContainer::TraitWithDefault | - AssociatedContainer::ImplDefault | - AssociatedContainer::ImplFinal => true, - } - } - pub fn defaultness(&self) -> hir::Defaultness { match *self { - AssociatedContainer::TraitRequired | + AssociatedContainer::TraitRequired => hir::Defaultness::Default { + has_value: false, + }, + AssociatedContainer::TraitWithDefault | - AssociatedContainer::ImplDefault => hir::Defaultness::Default, + AssociatedContainer::ImplDefault => hir::Defaultness::Default { + has_value: true, + }, AssociatedContainer::ImplFinal => hir::Defaultness::Final, } diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index b53f8c4da86f..2c7b47c76699 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -54,7 +54,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let tcx = this.hir.tcx(); // Enter the remainder scope, i.e. the bindings' destruction scope. - this.push_scope(remainder_scope, block); + this.push_scope(remainder_scope); let_extent_stack.push(remainder_scope); // Declare the bindings, which may create a visibility scope. diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs index 9f612175e5da..71e97e4bfe0d 100644 --- a/src/librustc_mir/build/cfg.rs +++ b/src/librustc_mir/build/cfg.rs @@ -40,11 +40,6 @@ impl<'tcx> CFG<'tcx> { self.block_data_mut(block).statements.push(statement); } - pub fn current_location(&mut self, block: BasicBlock) -> Location { - let index = self.block_data(block).statements.len(); - Location { block: block, statement_index: index } - } - pub fn push_assign(&mut self, block: BasicBlock, source_info: SourceInfo, diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 902798ec9800..458a952543e4 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -36,13 +36,6 @@ pub struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// see the `scope` module for more details scopes: Vec>, - /// for each scope, a span of blocks that defines it; - /// we track these for use in region and borrow checking, - /// but these are liable to get out of date once optimization - /// begins. They are also hopefully temporary, and will be - /// no longer needed when we adopt graph-based regions. - scope_auxiliary: IndexVec, - /// the current set of loops; see the `scope` module for more /// details loop_scopes: Vec, @@ -82,30 +75,6 @@ impl Idx for ScopeId { } } -/// For each scope, we track the extent (from the HIR) and a -/// single-entry-multiple-exit subgraph that contains all the -/// statements/terminators within it. -/// -/// This information is separated out from the main `ScopeData` -/// because it is short-lived. First, the extent contains node-ids, -/// so it cannot be saved and re-loaded. Second, any optimization will mess up -/// the dominator/postdominator information. -/// -/// The intention is basically to use this information to do -/// regionck/borrowck and then throw it away once we are done. -pub struct ScopeAuxiliary { - /// extent of this scope from the MIR. - pub extent: CodeExtent, - - /// "entry point": dominator of all nodes in the scope - pub dom: Location, - - /// "exit points": mutual postdominators of all nodes in the scope - pub postdoms: Vec, -} - -pub type ScopeAuxiliaryVec = IndexVec; - /////////////////////////////////////////////////////////////////////////// /// The `BlockAnd` "monad" packages up the new basic block along with a /// produced value (sometimes just unit, of course). The `unpack!` @@ -155,9 +124,10 @@ macro_rules! unpack { pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, fn_id: ast::NodeId, arguments: A, + abi: Abi, return_ty: Ty<'gcx>, ast_body: &'gcx hir::Expr) - -> (Mir<'tcx>, ScopeAuxiliaryVec) + -> Mir<'tcx> where A: Iterator, Option<&'gcx hir::Pat>)> { let arguments: Vec<_> = arguments.collect(); @@ -191,12 +161,9 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, assert_eq!(block, builder.return_block()); let mut spread_arg = None; - match tcx.tables().node_id_to_type(fn_id).sty { - ty::TyFnDef(_, _, f) if f.abi == Abi::RustCall => { - // RustCall pseudo-ABI untuples the last argument. - spread_arg = Some(Local::new(arguments.len())); - } - _ => {} + if abi == Abi::RustCall { + // RustCall pseudo-ABI untuples the last argument. + spread_arg = Some(Local::new(arguments.len())); } // Gather the upvars of a closure, if any. @@ -223,15 +190,15 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, }).collect() }); - let (mut mir, aux) = builder.finish(upvar_decls, return_ty); + let mut mir = builder.finish(upvar_decls, return_ty); mir.spread_arg = spread_arg; - (mir, aux) + mir } pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>, item_id: ast::NodeId, ast_expr: &'tcx hir::Expr) - -> (Mir<'tcx>, ScopeAuxiliaryVec) { + -> Mir<'tcx> { let tcx = hir.tcx(); let ty = tcx.tables().expr_ty_adjusted(ast_expr); let span = tcx.map.span(item_id); @@ -271,7 +238,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { scopes: vec![], visibility_scopes: IndexVec::new(), visibility_scope: ARGUMENT_VISIBILITY_SCOPE, - scope_auxiliary: IndexVec::new(), loop_scopes: vec![], local_decls: IndexVec::from_elem_n(LocalDecl::new_return_pointer(return_ty), 1), var_indices: NodeMap(), @@ -290,22 +256,22 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn finish(self, upvar_decls: Vec, return_ty: Ty<'tcx>) - -> (Mir<'tcx>, ScopeAuxiliaryVec) { + -> Mir<'tcx> { for (index, block) in self.cfg.basic_blocks.iter().enumerate() { if block.terminator.is_none() { span_bug!(self.fn_span, "no terminator on block {:?}", index); } } - (Mir::new(self.cfg.basic_blocks, - self.visibility_scopes, - IndexVec::new(), - return_ty, - self.local_decls, - self.arg_count, - upvar_decls, - self.fn_span - ), self.scope_auxiliary) + Mir::new(self.cfg.basic_blocks, + self.visibility_scopes, + IndexVec::new(), + return_ty, + self.local_decls, + self.arg_count, + upvar_decls, + self.fn_span + ) } fn args_and_body(&mut self, diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index b5343975a9cd..4d9b6c0e05a4 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -86,7 +86,7 @@ should go to. */ -use build::{BlockAnd, BlockAndExtension, Builder, CFG, ScopeAuxiliary, ScopeId}; +use build::{BlockAnd, BlockAndExtension, Builder, CFG}; use rustc::middle::region::{CodeExtent, CodeExtentData}; use rustc::middle::lang_items; use rustc::ty::subst::{Kind, Subst}; @@ -97,14 +97,10 @@ use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::fx::FxHashMap; pub struct Scope<'tcx> { - /// the scope-id within the scope_auxiliary - id: ScopeId, - /// The visibility scope this scope was created in. visibility_scope: VisibilityScope, - /// the extent of this scope within source code; also stored in - /// `ScopeAuxiliary`, but kept here for convenience + /// the extent of this scope within source code. extent: CodeExtent, /// Whether there's anything to do for the cleanup path, that is, @@ -276,7 +272,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>) -> BlockAnd { debug!("in_scope(extent={:?}, block={:?})", extent, block); - self.push_scope(extent, block); + self.push_scope(extent); let rv = unpack!(block = f(self)); unpack!(block = self.pop_scope(extent, block)); debug!("in_scope: exiting extent={:?} block={:?}", extent, block); @@ -287,12 +283,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// scope and call `pop_scope` afterwards. Note that these two /// calls must be paired; using `in_scope` as a convenience /// wrapper maybe preferable. - pub fn push_scope(&mut self, extent: CodeExtent, entry: BasicBlock) { + pub fn push_scope(&mut self, extent: CodeExtent) { debug!("push_scope({:?})", extent); - let id = ScopeId::new(self.scope_auxiliary.len()); let vis_scope = self.visibility_scope; self.scopes.push(Scope { - id: id, visibility_scope: vis_scope, extent: extent, needs_cleanup: false, @@ -300,11 +294,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { free: None, cached_exits: FxHashMap() }); - self.scope_auxiliary.push(ScopeAuxiliary { - extent: extent, - dom: self.cfg.current_location(entry), - postdoms: vec![] - }); } /// Pops a scope, which should have extent `extent`, adding any @@ -325,9 +314,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { &self.scopes, block, self.arg_count)); - self.scope_auxiliary[scope.id] - .postdoms - .push(self.cfg.current_location(block)); block.unit() } @@ -375,9 +361,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.cfg.terminate(block, scope.source_info(span), free); block = next; } - self.scope_auxiliary[scope.id] - .postdoms - .push(self.cfg.current_location(block)); } } let scope = &self.scopes[len - scope_count]; @@ -806,7 +789,7 @@ fn build_free<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, TerminatorKind::Call { func: Operand::Constant(Constant { span: data.span, - ty: tcx.lookup_item_type(free_func).ty.subst(tcx, substs), + ty: tcx.item_type(free_func).subst(tcx, substs), literal: Literal::Item { def_id: free_func, substs: substs diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index ba0d3b49a6c1..24c1ca574a01 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -521,8 +521,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }; let upvars = cx.tcx.with_freevars(expr.id, |freevars| { freevars.iter() - .enumerate() - .map(|(i, fv)| capture_freevar(cx, expr, fv, substs.upvar_tys[i])) + .zip(substs.upvar_tys(def_id, cx.tcx)) + .map(|(fv, ty)| capture_freevar(cx, expr, fv, ty)) .collect() }); ExprKind::Closure { diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index ecc2d8fe050a..038300068fce 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -149,8 +149,8 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { let substs = self.tcx.mk_substs_trait(self_ty, params); for item in self.tcx.associated_items(trait_def_id) { if item.kind == ty::AssociatedKind::Method && item.name == method_name { - let method_ty = self.tcx.lookup_item_type(item.def_id); - let method_ty = method_ty.ty.subst(self.tcx, substs); + let method_ty = self.tcx.item_type(item.def_id); + let method_ty = method_ty.subst(self.tcx, substs); return (method_ty, Literal::Item { def_id: item.def_id, substs: substs, diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index af2f9adfc9a8..992c0e9b5fc8 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -31,15 +31,16 @@ use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::Substs; use rustc::hir; use rustc::hir::intravisit::{self, FnKind, Visitor}; +use syntax::abi::Abi; use syntax::ast; use syntax_pos::Span; use std::mem; pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - tcx.visit_all_items_in_krate(DepNode::Mir, &mut BuildMir { + tcx.visit_all_item_likes_in_krate(DepNode::Mir, &mut BuildMir { tcx: tcx - }); + }.as_deep_visitor()); } /// A pass to lift all the types and substitutions in a Mir @@ -102,11 +103,11 @@ impl<'a, 'gcx, 'tcx> BuildMir<'a, 'gcx> { impl<'a, 'gcx, 'tcx> CxBuilder<'a, 'gcx, 'tcx> { fn build(&'tcx mut self, f: F) - where F: for<'b> FnOnce(Cx<'b, 'gcx, 'tcx>) -> (Mir<'tcx>, build::ScopeAuxiliaryVec) + where F: for<'b> FnOnce(Cx<'b, 'gcx, 'tcx>) -> Mir<'tcx> { let (src, def_id) = (self.src, self.def_id); self.infcx.enter(|infcx| { - let (mut mir, scope_auxiliary) = f(Cx::new(&infcx, src)); + let mut mir = f(Cx::new(&infcx, src)); // Convert the Mir to global types. let tcx = infcx.tcx.global_tcx(); @@ -119,7 +120,7 @@ impl<'a, 'gcx, 'tcx> CxBuilder<'a, 'gcx, 'tcx> { mem::transmute::>(mir) }; - pretty::dump_mir(tcx, "mir_map", &0, src, &mir, Some(&scope_auxiliary)); + pretty::dump_mir(tcx, "mir_map", &0, src, &mir); let mir = tcx.alloc_mir(mir); assert!(tcx.mir_map.borrow_mut().insert(def_id, mir).is_none()); @@ -221,10 +222,11 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> { } }; - let implicit_argument = if let FnKind::Closure(..) = fk { - Some((closure_self_ty(self.tcx, id, body.id), None)) + let (abi, implicit_argument) = if let FnKind::Closure(..) = fk { + (Abi::Rust, Some((closure_self_ty(self.tcx, id, body.id), None))) } else { - None + let def_id = self.tcx.map.local_def_id(id); + (self.tcx.item_type(def_id).fn_abi(), None) }; let explicit_arguments = @@ -237,7 +239,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> { let arguments = implicit_argument.into_iter().chain(explicit_arguments); self.cx(MirSource::Fn(id)).build(|cx| { - build::construct_fn(cx, id, arguments, fn_sig.output, body) + build::construct_fn(cx, id, arguments, abi, fn_sig.output, body) }); intravisit::walk_fn(self, fk, decl, body, span, id); diff --git a/src/librustc_mir/pretty.rs b/src/librustc_mir/pretty.rs index d6f514cfb913..e7188d536980 100644 --- a/src/librustc_mir/pretty.rs +++ b/src/librustc_mir/pretty.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use build::{ScopeAuxiliaryVec, ScopeId}; use rustc::hir; use rustc::hir::def_id::DefId; use rustc::mir::*; @@ -43,8 +42,7 @@ pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pass_name: &str, disambiguator: &Display, src: MirSource, - mir: &Mir<'tcx>, - auxiliary: Option<&ScopeAuxiliaryVec>) { + mir: &Mir<'tcx>) { let filters = match tcx.sess.opts.debugging_opts.dump_mir { None => return, Some(ref filters) => filters, @@ -81,7 +79,7 @@ pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, writeln!(file, "// pass_name = {}", pass_name)?; writeln!(file, "// disambiguator = {}", disambiguator)?; writeln!(file, "")?; - write_mir_fn(tcx, src, mir, &mut file, auxiliary)?; + write_mir_fn(tcx, src, mir, &mut file)?; Ok(()) }); } @@ -106,52 +104,24 @@ pub fn write_mir_pretty<'a, 'b, 'tcx, I>(tcx: TyCtxt<'b, 'tcx, 'tcx>, let id = tcx.map.as_local_node_id(def_id).unwrap(); let src = MirSource::from_node(tcx, id); - write_mir_fn(tcx, src, mir, w, None)?; + write_mir_fn(tcx, src, mir, w)?; for (i, mir) in mir.promoted.iter_enumerated() { writeln!(w, "")?; - write_mir_fn(tcx, MirSource::Promoted(id, i), mir, w, None)?; + write_mir_fn(tcx, MirSource::Promoted(id, i), mir, w)?; } } Ok(()) } -enum Annotation { - EnterScope(ScopeId), - ExitScope(ScopeId), -} - -fn scope_entry_exit_annotations(auxiliary: Option<&ScopeAuxiliaryVec>) - -> FxHashMap> -{ - // compute scope/entry exit annotations - let mut annotations = FxHashMap(); - if let Some(auxiliary) = auxiliary { - for (scope_id, auxiliary) in auxiliary.iter_enumerated() { - annotations.entry(auxiliary.dom) - .or_insert(vec![]) - .push(Annotation::EnterScope(scope_id)); - - for &loc in &auxiliary.postdoms { - annotations.entry(loc) - .or_insert(vec![]) - .push(Annotation::ExitScope(scope_id)); - } - } - } - return annotations; -} - pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource, mir: &Mir<'tcx>, - w: &mut Write, - auxiliary: Option<&ScopeAuxiliaryVec>) + w: &mut Write) -> io::Result<()> { - let annotations = scope_entry_exit_annotations(auxiliary); write_mir_intro(tcx, src, mir, w)?; for block in mir.basic_blocks().indices() { - write_basic_block(tcx, block, mir, w, &annotations)?; + write_basic_block(tcx, block, mir, w)?; if block.index() + 1 != mir.basic_blocks().len() { writeln!(w, "")?; } @@ -165,8 +135,7 @@ pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn write_basic_block(tcx: TyCtxt, block: BasicBlock, mir: &Mir, - w: &mut Write, - annotations: &FxHashMap>) + w: &mut Write) -> io::Result<()> { let data = &mir[block]; @@ -176,19 +145,6 @@ fn write_basic_block(tcx: TyCtxt, // List of statements in the middle. let mut current_location = Location { block: block, statement_index: 0 }; for statement in &data.statements { - if let Some(ref annotations) = annotations.get(¤t_location) { - for annotation in annotations.iter() { - match *annotation { - Annotation::EnterScope(id) => - writeln!(w, "{0}{0}// Enter Scope({1})", - INDENT, id.index())?, - Annotation::ExitScope(id) => - writeln!(w, "{0}{0}// Exit Scope({1})", - INDENT, id.index())?, - } - } - } - let indented_mir = format!("{0}{0}{1:?};", INDENT, statement); writeln!(w, "{0:1$} // {2}", indented_mir, diff --git a/src/librustc_mir/transform/dump_mir.rs b/src/librustc_mir/transform/dump_mir.rs index b8fd9fb12ab0..035f33de91aa 100644 --- a/src/librustc_mir/transform/dump_mir.rs +++ b/src/librustc_mir/transform/dump_mir.rs @@ -64,8 +64,7 @@ impl<'tcx> MirPassHook<'tcx> for DumpMir { is_after: is_after }, src, - mir, - None + mir ); } } diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index b33a7060e375..4ff2beb3fdb7 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -277,8 +277,12 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { .and_then(|impl_node_id| self.tcx.map.find(impl_node_id)) .map(|node| { if let hir_map::NodeItem(item) = node { - if let hir::ItemImpl(_, _, _, _, _, ref methods) = item.node { - span = methods.first().map(|method| method.span); + if let hir::ItemImpl(.., ref impl_item_refs) = item.node { + span = impl_item_refs.first() + .map(|iiref| { + self.tcx.map.impl_item(iiref.id) + .span + }); } } }); diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 9d3afe541cca..0ceed274b6da 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -127,7 +127,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { match *lvalue { Lvalue::Local(index) => LvalueTy::Ty { ty: self.mir.local_decls[index].ty }, Lvalue::Static(def_id) => - LvalueTy::Ty { ty: self.tcx().lookup_item_type(def_id).ty }, + LvalueTy::Ty { ty: self.tcx().item_type(def_id) }, Lvalue::Projection(ref proj) => { let base_ty = self.sanitize_lvalue(&proj.base, location); if let LvalueTy::Ty { ty } = base_ty { @@ -274,9 +274,15 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { ty::TyAdt(adt_def, substs) if adt_def.is_univariant() => { (&adt_def.variants[0], substs) } - ty::TyTuple(tys) | ty::TyClosure(_, ty::ClosureSubsts { - upvar_tys: tys, .. - }) => { + ty::TyClosure(def_id, substs) => { + return match substs.upvar_tys(def_id, tcx).nth(field.index()) { + Some(ty) => Ok(ty), + None => Err(FieldAccessError::OutOfRange { + field_count: substs.upvar_tys(def_id, tcx).count() + }) + } + } + ty::TyTuple(tys) => { return match tys.get(field.index()) { Some(&ty) => Ok(ty), None => Err(FieldAccessError::OutOfRange { @@ -300,32 +306,43 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { pub struct TypeChecker<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, fulfillment_cx: traits::FulfillmentContext<'tcx>, - last_span: Span + last_span: Span, + body_id: ast::NodeId, } impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { - fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>) -> Self { + fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, body_id: ast::NodeId) -> Self { TypeChecker { infcx: infcx, fulfillment_cx: traits::FulfillmentContext::new(), - last_span: DUMMY_SP + last_span: DUMMY_SP, + body_id: body_id, } } - fn sub_types(&self, span: Span, sup: Ty<'tcx>, sub: Ty<'tcx>) - -> infer::UnitResult<'tcx> - { - self.infcx.sub_types(false, infer::TypeOrigin::Misc(span), sup, sub) - // FIXME(#32730) propagate obligations - .map(|InferOk { obligations, .. }| assert!(obligations.is_empty())) + fn misc(&self, span: Span) -> traits::ObligationCause<'tcx> { + traits::ObligationCause::misc(span, self.body_id) } - fn eq_types(&self, span: Span, a: Ty<'tcx>, b: Ty<'tcx>) + pub fn register_infer_ok_obligations(&mut self, infer_ok: InferOk<'tcx, T>) -> T { + for obligation in infer_ok.obligations { + self.fulfillment_cx.register_predicate_obligation(self.infcx, obligation); + } + infer_ok.value + } + + fn sub_types(&mut self, sup: Ty<'tcx>, sub: Ty<'tcx>) + -> infer::UnitResult<'tcx> + { + self.infcx.sub_types(false, &self.misc(self.last_span), sup, sub) + .map(|ok| self.register_infer_ok_obligations(ok)) + } + + fn eq_types(&mut self, span: Span, a: Ty<'tcx>, b: Ty<'tcx>) -> infer::UnitResult<'tcx> { - self.infcx.eq_types(false, infer::TypeOrigin::Misc(span), a, b) - // FIXME(#32730) propagate obligations - .map(|InferOk { obligations, .. }| assert!(obligations.is_empty())) + self.infcx.eq_types(false, &self.misc(span), a, b) + .map(|ok| self.register_infer_ok_obligations(ok)) } fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { @@ -340,7 +357,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let lv_ty = lv.ty(mir, tcx).to_ty(tcx); let rv_ty = rv.ty(mir, tcx); if let Some(rv_ty) = rv_ty { - if let Err(terr) = self.sub_types(self.last_span, rv_ty, lv_ty) { + if let Err(terr) = self.sub_types(rv_ty, lv_ty) { span_mirbug!(self, stmt, "bad assignment ({:?} = {:?}): {:?}", lv_ty, rv_ty, terr); } @@ -401,7 +418,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } => { let lv_ty = location.ty(mir, tcx).to_ty(tcx); let rv_ty = value.ty(mir, tcx); - if let Err(terr) = self.sub_types(self.last_span, rv_ty, lv_ty) { + if let Err(terr) = self.sub_types(rv_ty, lv_ty) { span_mirbug!(self, term, "bad DropAndReplace ({:?} = {:?}): {:?}", lv_ty, rv_ty, terr); } @@ -418,7 +435,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } TerminatorKind::SwitchInt { ref discr, switch_ty, .. } => { let discr_ty = discr.ty(mir, tcx).to_ty(tcx); - if let Err(terr) = self.sub_types(self.last_span, discr_ty, switch_ty) { + if let Err(terr) = self.sub_types(discr_ty, switch_ty) { span_mirbug!(self, term, "bad SwitchInt ({:?} on {:?}): {:?}", switch_ty, discr_ty, terr); } @@ -480,7 +497,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } - fn check_call_dest(&self, + fn check_call_dest(&mut self, mir: &Mir<'tcx>, term: &Terminator<'tcx>, sig: &ty::FnSig<'tcx>, @@ -489,7 +506,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { match *destination { Some((ref dest, _)) => { let dest_ty = dest.ty(mir, tcx).to_ty(tcx); - if let Err(terr) = self.sub_types(self.last_span, sig.output, dest_ty) { + if let Err(terr) = self.sub_types(sig.output, dest_ty) { span_mirbug!(self, term, "call dest mismatch ({:?} <- {:?}): {:?}", dest_ty, sig.output, terr); @@ -504,7 +521,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } - fn check_call_inputs(&self, + fn check_call_inputs(&mut self, mir: &Mir<'tcx>, term: &Terminator<'tcx>, sig: &ty::FnSig<'tcx>, @@ -517,7 +534,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } for (n, (fn_arg, op_arg)) in sig.inputs.iter().zip(args).enumerate() { let op_arg_ty = op_arg.ty(mir, self.tcx()); - if let Err(terr) = self.sub_types(self.last_span, op_arg_ty, fn_arg) { + if let Err(terr) = self.sub_types(op_arg_ty, fn_arg) { span_mirbug!(self, term, "bad arg #{:?} ({:?} <- {:?}): {:?}", n, fn_arg, op_arg_ty, terr); } @@ -535,7 +552,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } - fn check_box_free_inputs(&self, + fn check_box_free_inputs(&mut self, mir: &Mir<'tcx>, term: &Terminator<'tcx>, sig: &ty::FnSig<'tcx>, @@ -572,7 +589,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } }; - if let Err(terr) = self.sub_types(self.last_span, arg_ty, pointee_ty) { + if let Err(terr) = self.sub_types(arg_ty, pointee_ty) { span_mirbug!(self, term, "bad box_free arg ({:?} <- {:?}): {:?}", pointee_ty, arg_ty, terr); } @@ -709,7 +726,7 @@ impl<'tcx> MirPass<'tcx> for TypeckMir { } let param_env = ty::ParameterEnvironment::for_item(tcx, src.item_id()); tcx.infer_ctxt(None, Some(param_env), Reveal::NotSpecializable).enter(|infcx| { - let mut checker = TypeChecker::new(&infcx); + let mut checker = TypeChecker::new(&infcx, src.item_id()); { let mut verifier = TypeVerifier::new(&mut checker, mir); verifier.visit_mir(mir); diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 02a0b3ab28d6..5df8accd8cef 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -644,13 +644,13 @@ fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Exp } pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - tcx.visit_all_items_in_krate(DepNode::CheckConst, - &mut CheckCrateVisitor { - tcx: tcx, - mode: Mode::Var, - qualif: ConstQualif::NOT_CONST, - rvalue_borrows: NodeMap(), - }); + tcx.visit_all_item_likes_in_krate(DepNode::CheckConst, + &mut CheckCrateVisitor { + tcx: tcx, + mode: Mode::Var, + qualif: ConstQualif::NOT_CONST, + rvalue_borrows: NodeMap(), + }.as_deep_visitor()); tcx.sess.abort_if_errors(); } diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs index 417987d9664e..3bdaf276b40c 100644 --- a/src/librustc_passes/hir_stats.rs +++ b/src/librustc_passes/hir_stats.rs @@ -106,12 +106,20 @@ impl<'k> StatCollector<'k> { } impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { + fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'v>> { + panic!("visit_nested_xxx must be manually implemented in this visitor") + } fn visit_nested_item(&mut self, id: hir::ItemId) { let nested_item = self.krate.unwrap().item(id.id); self.visit_item(nested_item) } + fn visit_nested_impl_item(&mut self, impl_item_id: hir::ImplItemId) { + let nested_impl_item = self.krate.unwrap().impl_item(impl_item_id); + self.visit_impl_item(nested_impl_item) + } + fn visit_item(&mut self, i: &'v hir::Item) { self.record("Item", Id::Node(i.id), i); hir_visit::walk_item(self, i) diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs index e58cd8938193..724100e02237 100644 --- a/src/librustc_passes/loops.rs +++ b/src/librustc_passes/loops.rs @@ -33,10 +33,10 @@ struct CheckLoopVisitor<'a> { pub fn check_crate(sess: &Session, map: &Map) { let _task = map.dep_graph.in_task(DepNode::CheckLoops); let krate = map.krate(); - krate.visit_all_items(&mut CheckLoopVisitor { + krate.visit_all_item_likes(&mut CheckLoopVisitor { sess: sess, cx: Normal, - }); + }.as_deep_visitor()); } impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> { @@ -44,6 +44,10 @@ impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> { self.with_context(Normal, |v| intravisit::walk_item(v, i)); } + fn visit_impl_item(&mut self, i: &hir::ImplItem) { + self.with_context(Normal, |v| intravisit::walk_impl_item(v, i)); + } + fn visit_expr(&mut self, e: &hir::Expr) { match e.node { hir::ExprWhile(ref e, ref b, _) => { diff --git a/src/librustc_passes/rvalues.rs b/src/librustc_passes/rvalues.rs index d55ce4c35638..7386be2528c9 100644 --- a/src/librustc_passes/rvalues.rs +++ b/src/librustc_passes/rvalues.rs @@ -18,20 +18,20 @@ use rustc::ty::{self, TyCtxt, ParameterEnvironment}; use rustc::traits::Reveal; use rustc::hir; -use rustc::hir::intravisit; +use rustc::hir::intravisit::{self, Visitor}; use syntax::ast; use syntax_pos::Span; pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let mut rvcx = RvalueContext { tcx: tcx }; - tcx.visit_all_items_in_krate(DepNode::RvalueCheck, &mut rvcx); + tcx.visit_all_item_likes_in_krate(DepNode::RvalueCheck, &mut rvcx.as_deep_visitor()); } struct RvalueContext<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, } -impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for RvalueContext<'a, 'tcx> { +impl<'a, 'tcx, 'v> Visitor<'v> for RvalueContext<'a, 'tcx> { fn visit_fn(&mut self, fk: intravisit::FnKind<'v>, fd: &'v hir::FnDecl, diff --git a/src/librustc_passes/static_recursion.rs b/src/librustc_passes/static_recursion.rs index 0e0f8a845673..5f76f865c4ac 100644 --- a/src/librustc_passes/static_recursion.rs +++ b/src/librustc_passes/static_recursion.rs @@ -100,7 +100,8 @@ pub fn check_crate<'ast>(sess: &Session, discriminant_map: RefCell::new(NodeMap()), }; sess.track_errors(|| { - ast_map.krate().visit_all_items(&mut visitor); + // FIXME(#37712) could use ItemLikeVisitor if trait items were item-like + ast_map.krate().visit_all_item_likes(&mut visitor.as_deep_visitor()); }) } diff --git a/src/librustc_plugin/build.rs b/src/librustc_plugin/build.rs index ff3038c3d117..75046f6aeb87 100644 --- a/src/librustc_plugin/build.rs +++ b/src/librustc_plugin/build.rs @@ -16,14 +16,14 @@ use errors; use syntax_pos::Span; use rustc::dep_graph::DepNode; use rustc::hir::map::Map; -use rustc::hir::intravisit::Visitor; +use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir; struct RegistrarFinder { registrars: Vec<(ast::NodeId, Span)> , } -impl<'v> Visitor<'v> for RegistrarFinder { +impl<'v> ItemLikeVisitor<'v> for RegistrarFinder { fn visit_item(&mut self, item: &hir::Item) { if let hir::ItemFn(..) = item.node { if attr::contains_name(&item.attrs, @@ -32,6 +32,9 @@ impl<'v> Visitor<'v> for RegistrarFinder { } } } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + } } /// Find the function marked with `#[plugin_registrar]`, if any. @@ -42,7 +45,7 @@ pub fn find_plugin_registrar(diagnostic: &errors::Handler, let krate = hir_map.krate(); let mut finder = RegistrarFinder { registrars: Vec::new() }; - krate.visit_all_items(&mut finder); + krate.visit_all_item_likes(&mut finder); match finder.registrars.len() { 0 => None, diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index dc7399e22890..b116408269e4 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -31,6 +31,7 @@ use rustc::hir::{self, PatKind}; use rustc::hir::def::{self, Def, CtorKind}; use rustc::hir::def_id::DefId; use rustc::hir::intravisit::{self, Visitor}; +use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::pat_util::EnumerateAndAdjustIterator; use rustc::lint; use rustc::middle::privacy::{AccessLevel, AccessLevels}; @@ -115,15 +116,14 @@ impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> { } } -impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { +impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { /// We want to visit items in the context of their containing /// module and so forth, so supply a crate for doing a deep walk. - fn visit_nested_item(&mut self, item: hir::ItemId) { - let tcx = self.tcx; - self.visit_item(tcx.map.expect_item(item.id)) + fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> { + Some(&self.tcx.map) } - fn visit_item(&mut self, item: &hir::Item) { + fn visit_item(&mut self, item: &'tcx hir::Item) { let inherited_item_level = match item.node { // Impls inherit level from their types and traits hir::ItemImpl(.., None, ref ty, _) => { @@ -158,15 +158,17 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { } } } - hir::ItemImpl(.., None, _, ref impl_items) => { - for impl_item in impl_items { + hir::ItemImpl(.., None, _, ref impl_item_refs) => { + for impl_item_ref in impl_item_refs { + let impl_item = self.tcx.map.impl_item(impl_item_ref.id); if impl_item.vis == hir::Public { self.update(impl_item.id, item_level); } } } - hir::ItemImpl(.., Some(_), _, ref impl_items) => { - for impl_item in impl_items { + hir::ItemImpl(.., Some(_), _, ref impl_item_refs) => { + for impl_item_ref in impl_item_refs { + let impl_item = self.tcx.map.impl_item(impl_item_ref.id); self.update(impl_item.id, item_level); } } @@ -249,11 +251,12 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { // The interface is empty hir::ItemDefaultImpl(..) => {} // Visit everything except for private impl items - hir::ItemImpl(.., ref generics, None, _, ref impl_items) => { + hir::ItemImpl(.., ref generics, None, _, ref impl_item_refs) => { if item_level.is_some() { self.reach().visit_generics(generics); - for impl_item in impl_items { - if self.get(impl_item.id).is_some() { + for impl_item_ref in impl_item_refs { + if self.get(impl_item_ref.id.node_id).is_some() { + let impl_item = self.tcx.map.impl_item(impl_item_ref.id); self.reach().visit_impl_item(impl_item); } } @@ -269,7 +272,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { self.prev_level = orig_level; } - fn visit_block(&mut self, b: &'v hir::Block) { + fn visit_block(&mut self, b: &'tcx hir::Block) { let orig_level = replace(&mut self.prev_level, None); // Blocks can have public items, for example impls, but they always @@ -280,7 +283,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { self.prev_level = orig_level; } - fn visit_mod(&mut self, m: &hir::Mod, _sp: Span, id: ast::NodeId) { + fn visit_mod(&mut self, m: &'tcx hir::Mod, _sp: Span, id: ast::NodeId) { // This code is here instead of in visit_item so that the // crate module gets processed as well. if self.prev_level.is_some() { @@ -296,14 +299,14 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { intravisit::walk_mod(self, m, id); } - fn visit_macro_def(&mut self, md: &'v hir::MacroDef) { + fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef) { self.update(md.id, Some(AccessLevel::Public)); } } impl<'b, 'a, 'tcx: 'a> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> { // Make the type hidden under a type alias reachable - fn reach_aliased_type(&mut self, item: &hir::Item, path: &hir::Path) { + fn reach_aliased_type(&mut self, item: &'tcx hir::Item, path: &'tcx hir::Path) { if let hir::ItemTy(ref ty, ref generics) = item.node { // See `fn is_public_type_alias` for details self.visit_ty(ty); @@ -317,8 +320,14 @@ impl<'b, 'a, 'tcx: 'a> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> { } } -impl<'b, 'a, 'tcx: 'a, 'v> Visitor<'v> for ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> { - fn visit_ty(&mut self, ty: &hir::Ty) { +impl<'b, 'a, 'tcx: 'a> Visitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> { + fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) { + // when we visit an impl, its methods and items are part of its "interface" + let impl_item = self.ev.tcx.map.impl_item(item_id); + self.visit_impl_item(impl_item) + } + + fn visit_ty(&mut self, ty: &'tcx hir::Ty) { if let hir::TyPath(_, ref path) = ty.node { let def = self.ev.tcx.expect_def(ty.id); match def { @@ -350,7 +359,7 @@ impl<'b, 'a, 'tcx: 'a, 'v> Visitor<'v> for ReachEverythingInTheInterfaceVisitor< intravisit::walk_ty(self, ty); } - fn visit_trait_ref(&mut self, trait_ref: &hir::TraitRef) { + fn visit_trait_ref(&mut self, trait_ref: &'tcx hir::TraitRef) { let def_id = self.ev.tcx.expect_def(trait_ref.ref_id).def_id(); if let Some(node_id) = self.ev.tcx.map.as_local_node_id(def_id) { let item = self.ev.tcx.map.expect_item(node_id); @@ -412,21 +421,20 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { } } -impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { +impl<'a, 'tcx> Visitor<'tcx> for PrivacyVisitor<'a, 'tcx> { /// We want to visit items in the context of their containing /// module and so forth, so supply a crate for doing a deep walk. - fn visit_nested_item(&mut self, item: hir::ItemId) { - let tcx = self.tcx; - self.visit_item(tcx.map.expect_item(item.id)) + fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> { + Some(&self.tcx.map) } - fn visit_item(&mut self, item: &hir::Item) { + fn visit_item(&mut self, item: &'tcx hir::Item) { let orig_curitem = replace(&mut self.curitem, item.id); intravisit::walk_item(self, item); self.curitem = orig_curitem; } - fn visit_expr(&mut self, expr: &hir::Expr) { + fn visit_expr(&mut self, expr: &'tcx hir::Expr) { match expr.node { hir::ExprMethodCall(..) => { let method_call = ty::MethodCall::expr(expr.id); @@ -486,7 +494,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { intravisit::walk_expr(self, expr); } - fn visit_pat(&mut self, pattern: &hir::Pat) { + fn visit_pat(&mut self, pattern: &'tcx hir::Pat) { // Foreign functions do not have their patterns mapped in the def_map, // and there's nothing really relevant there anyway, so don't bother // checking privacy. If you can name the type then you can pass it to an @@ -522,7 +530,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { intravisit::walk_pat(self, pattern); } - fn visit_foreign_item(&mut self, fi: &hir::ForeignItem) { + fn visit_foreign_item(&mut self, fi: &'tcx hir::ForeignItem) { self.in_foreign = true; intravisit::walk_foreign_item(self, fi); self.in_foreign = false; @@ -616,15 +624,14 @@ impl<'a, 'b, 'tcx, 'v> Visitor<'v> for ObsoleteCheckTypeForPrivatenessVisitor<'a fn visit_expr(&mut self, _: &hir::Expr) {} } -impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { +impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { /// We want to visit items in the context of their containing /// module and so forth, so supply a crate for doing a deep walk. - fn visit_nested_item(&mut self, item: hir::ItemId) { - let tcx = self.tcx; - self.visit_item(tcx.map.expect_item(item.id)) + fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> { + Some(&self.tcx.map) } - fn visit_item(&mut self, item: &hir::Item) { + fn visit_item(&mut self, item: &'tcx hir::Item) { match item.node { // contents of a private mod can be reexported, so we need // to check internals. @@ -649,7 +656,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> // (i.e. we could just return here to not check them at // all, or some worse estimation of whether an impl is // publicly visible). - hir::ItemImpl(.., ref g, ref trait_ref, ref self_, ref impl_items) => { + hir::ItemImpl(.., ref g, ref trait_ref, ref self_, ref impl_item_refs) => { // `impl [... for] Private` is never visible. let self_contains_private; // impl [... for] Public<...>, but not `impl [... for] @@ -694,16 +701,17 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> // are private (because `T` won't be visible externally). let trait_or_some_public_method = trait_ref.is_some() || - impl_items.iter() - .any(|impl_item| { - match impl_item.node { - hir::ImplItemKind::Const(..) | - hir::ImplItemKind::Method(..) => { - self.access_levels.is_reachable(impl_item.id) - } - hir::ImplItemKind::Type(_) => false, - } - }); + impl_item_refs.iter() + .any(|impl_item_ref| { + let impl_item = self.tcx.map.impl_item(impl_item_ref.id); + match impl_item.node { + hir::ImplItemKind::Const(..) | + hir::ImplItemKind::Method(..) => { + self.access_levels.is_reachable(impl_item.id) + } + hir::ImplItemKind::Type(_) => false, + } + }); if !self_contains_private && not_private_trait && @@ -713,12 +721,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> match *trait_ref { None => { - for impl_item in impl_items { + for impl_item_ref in impl_item_refs { // This is where we choose whether to walk down // further into the impl to check its items. We // should only walk into public items so that we // don't erroneously report errors for private // types in private items. + let impl_item = self.tcx.map.impl_item(impl_item_ref.id); match impl_item.node { hir::ImplItemKind::Const(..) | hir::ImplItemKind::Method(..) @@ -750,7 +759,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> intravisit::walk_path(self, &tr.path); // Those in 3. are warned with this call. - for impl_item in impl_items { + for impl_item_ref in impl_item_refs { + let impl_item = self.tcx.map.impl_item(impl_item_ref.id); if let hir::ImplItemKind::Type(ref ty) = impl_item.node { self.visit_ty(ty); } @@ -761,7 +771,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> // impl Public { ... }. Any public static // methods will be visible as `Public::foo`. let mut found_pub_static = false; - for impl_item in impl_items { + for impl_item_ref in impl_item_refs { + let impl_item = self.tcx.map.impl_item(impl_item_ref.id); match impl_item.node { hir::ImplItemKind::Const(..) => { if self.item_is_public(&impl_item.id, &impl_item.vis) { @@ -805,7 +816,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> intravisit::walk_item(self, item); } - fn visit_generics(&mut self, generics: &hir::Generics) { + fn visit_generics(&mut self, generics: &'tcx hir::Generics) { for ty_param in generics.ty_params.iter() { for bound in ty_param.bounds.iter() { self.check_ty_param_bound(bound) @@ -826,13 +837,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> } } - fn visit_foreign_item(&mut self, item: &hir::ForeignItem) { + fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) { if self.access_levels.is_reachable(item.id) { intravisit::walk_foreign_item(self, item) } } - fn visit_ty(&mut self, t: &hir::Ty) { + fn visit_ty(&mut self, t: &'tcx hir::Ty) { if let hir::TyPath(..) = t.node { if self.path_is_private_type(t.id) { self.old_error_set.insert(t.id); @@ -841,7 +852,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> intravisit::walk_ty(self, t) } - fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics, item_id: ast::NodeId) { + fn visit_variant(&mut self, + v: &'tcx hir::Variant, + g: &'tcx hir::Generics, + item_id: ast::NodeId) { if self.access_levels.is_reachable(v.node.data.id()) { self.in_variant = true; intravisit::walk_variant(self, v, g, item_id); @@ -849,7 +863,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> } } - fn visit_struct_field(&mut self, s: &hir::StructField) { + fn visit_struct_field(&mut self, s: &'tcx hir::StructField) { if s.vis == hir::Public || self.in_variant { intravisit::walk_struct_field(self, s); } @@ -859,8 +873,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> // expression/block context can't possibly contain exported things. // (Making them no-ops stops us from traversing the whole AST without // having to be super careful about our `walk_...` calls above.) - fn visit_block(&mut self, _: &hir::Block) {} - fn visit_expr(&mut self, _: &hir::Expr) {} + fn visit_block(&mut self, _: &'tcx hir::Block) {} + fn visit_expr(&mut self, _: &'tcx hir::Expr) {} } /////////////////////////////////////////////////////////////////////////////// @@ -1039,7 +1053,7 @@ impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> { } } -impl<'a, 'tcx, 'v> Visitor<'v> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> { +impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { let min = |vis1: ty::Visibility, vis2| { if vis1.is_at_least(vis2, &self.tcx.map) { vis2 } else { vis1 } @@ -1085,12 +1099,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivateItemsInPublicInterfacesVisitor<'a, 'tc hir::ItemDefaultImpl(..) => {} // An inherent impl is public when its type is public // Subitems of inherent impls have their own publicity - hir::ItemImpl(.., ref generics, None, ref ty, ref impl_items) => { + hir::ItemImpl(.., ref generics, None, ref ty, ref impl_item_refs) => { let ty_vis = self.ty_visibility(ty); check.required_visibility = ty_vis; check.visit_generics(generics); - for impl_item in impl_items { + for impl_item_ref in impl_item_refs { + let impl_item = self.tcx.map.impl_item(impl_item_ref.id); let impl_item_vis = ty::Visibility::from_hir(&impl_item.vis, item.id, self.tcx); check.required_visibility = min(impl_item_vis, ty_vis); @@ -1099,16 +1114,21 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivateItemsInPublicInterfacesVisitor<'a, 'tc } // A trait impl is public when both its type and its trait are public // Subitems of trait impls have inherited publicity - hir::ItemImpl(.., ref generics, Some(ref trait_ref), ref ty, ref impl_items) => { + hir::ItemImpl(.., ref generics, Some(ref trait_ref), ref ty, ref impl_item_refs) => { let vis = min(self.ty_visibility(ty), self.trait_ref_visibility(trait_ref)); check.required_visibility = vis; check.visit_generics(generics); - for impl_item in impl_items { + for impl_item_ref in impl_item_refs { + let impl_item = self.tcx.map.impl_item(impl_item_ref.id); check.visit_impl_item(impl_item); } } } } + + fn visit_impl_item(&mut self, _impl_item: &'v hir::ImplItem) { + // handled in `visit_item` above + } } pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -1161,7 +1181,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx: tcx, old_error_set: &visitor.old_error_set, }; - krate.visit_all_items(&mut visitor); + krate.visit_all_item_likes(&mut visitor); } visitor.access_levels diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 99e7a9042c0c..627c72ff8c92 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -15,7 +15,7 @@ use macros::{InvocationData, LegacyScope}; use resolve_imports::ImportDirective; -use resolve_imports::ImportDirectiveSubclass::{self, GlobImport}; +use resolve_imports::ImportDirectiveSubclass::{self, GlobImport, SingleImport}; use {Resolver, Module, ModuleS, ModuleKind, NameBinding, NameBindingKind, ToNameBinding}; use Namespace::{self, TypeNS, ValueNS, MacroNS}; use ResolveResult::Success; @@ -37,6 +37,7 @@ use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind}; use syntax::ast::{Mutability, StmtKind, TraitItem, TraitItemKind}; use syntax::ast::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple}; use syntax::ext::base::SyntaxExtension; +use syntax::ext::base::Determinacy::Undetermined; use syntax::ext::expand::mark_tts; use syntax::ext::hygiene::Mark; use syntax::ext::tt::macro_rules; @@ -45,15 +46,25 @@ use syntax::visit::{self, Visitor}; use syntax_pos::{Span, DUMMY_SP}; -impl<'a> ToNameBinding<'a> for (Module<'a>, Span, ty::Visibility) { +impl<'a> ToNameBinding<'a> for (Module<'a>, ty::Visibility, Span, Mark) { fn to_name_binding(self) -> NameBinding<'a> { - NameBinding { kind: NameBindingKind::Module(self.0), span: self.1, vis: self.2 } + NameBinding { + kind: NameBindingKind::Module(self.0), + vis: self.1, + span: self.2, + expansion: self.3, + } } } -impl<'a> ToNameBinding<'a> for (Def, Span, ty::Visibility) { +impl<'a> ToNameBinding<'a> for (Def, ty::Visibility, Span, Mark) { fn to_name_binding(self) -> NameBinding<'a> { - NameBinding { kind: NameBindingKind::Def(self.0), span: self.1, vis: self.2 } + NameBinding { + kind: NameBindingKind::Def(self.0), + vis: self.1, + span: self.2, + expansion: self.3, + } } } @@ -147,9 +158,14 @@ impl<'b> Resolver<'b> { .emit(); } - let subclass = ImportDirectiveSubclass::single(binding.name, source.name); - let span = view_path.span; - self.add_import_directive(module_path, subclass, span, item.id, vis); + let subclass = SingleImport { + target: binding.name, + source: source.name, + result: self.per_ns(|_, _| Cell::new(Err(Undetermined))), + }; + self.add_import_directive( + module_path, subclass, view_path.span, item.id, vis, expansion, + ); } ViewPathList(_, ref source_items) => { // Make sure there's at most one `mod` import in the list. @@ -195,9 +211,15 @@ impl<'b> Resolver<'b> { (module_path.to_vec(), name, rename) } }; - let subclass = ImportDirectiveSubclass::single(rename, name); - let (span, id) = (source_item.span, source_item.node.id); - self.add_import_directive(module_path, subclass, span, id, vis); + let subclass = SingleImport { + target: rename, + source: name, + result: self.per_ns(|_, _| Cell::new(Err(Undetermined))), + }; + let id = source_item.node.id; + self.add_import_directive( + module_path, subclass, source_item.span, id, vis, expansion, + ); } } ViewPathGlob(_) => { @@ -205,8 +227,9 @@ impl<'b> Resolver<'b> { is_prelude: is_prelude, max_vis: Cell::new(ty::Visibility::PrivateExternal), }; - let span = view_path.span; - self.add_import_directive(module_path, subclass, span, item.id, vis); + self.add_import_directive( + module_path, subclass, view_path.span, item.id, vis, expansion, + ); } } } @@ -217,7 +240,7 @@ impl<'b> Resolver<'b> { // n.b. we don't need to look at the path option here, because cstore already did let crate_id = self.session.cstore.extern_mod_stmt_cnum(item.id).unwrap(); let module = self.get_extern_crate_root(crate_id); - let binding = (module, sp, ty::Visibility::Public).to_name_binding(); + let binding = (module, ty::Visibility::Public, sp, expansion).to_name_binding(); let binding = self.arenas.alloc_name_binding(binding); let directive = self.arenas.alloc_import_directive(ImportDirective { id: item.id, @@ -227,6 +250,7 @@ impl<'b> Resolver<'b> { span: item.span, module_path: Vec::new(), vis: Cell::new(vis), + expansion: expansion, }); let imported_binding = self.import(binding, directive); self.define(parent, name, TypeNS, imported_binding); @@ -245,7 +269,7 @@ impl<'b> Resolver<'b> { normal_ancestor_id: Some(item.id), ..ModuleS::new(Some(parent), ModuleKind::Def(def, name)) }); - self.define(parent, name, TypeNS, (module, sp, vis)); + self.define(parent, name, TypeNS, (module, vis, sp, expansion)); self.module_map.insert(item.id, module); // Descend into the module. @@ -258,30 +282,30 @@ impl<'b> Resolver<'b> { ItemKind::Static(_, m, _) => { let mutbl = m == Mutability::Mutable; let def = Def::Static(self.definitions.local_def_id(item.id), mutbl); - self.define(parent, name, ValueNS, (def, sp, vis)); + self.define(parent, name, ValueNS, (def, vis, sp, expansion)); } ItemKind::Const(..) => { let def = Def::Const(self.definitions.local_def_id(item.id)); - self.define(parent, name, ValueNS, (def, sp, vis)); + self.define(parent, name, ValueNS, (def, vis, sp, expansion)); } ItemKind::Fn(..) => { let def = Def::Fn(self.definitions.local_def_id(item.id)); - self.define(parent, name, ValueNS, (def, sp, vis)); + self.define(parent, name, ValueNS, (def, vis, sp, expansion)); } // These items live in the type namespace. ItemKind::Ty(..) => { let def = Def::TyAlias(self.definitions.local_def_id(item.id)); - self.define(parent, name, TypeNS, (def, sp, vis)); + self.define(parent, name, TypeNS, (def, vis, sp, expansion)); } ItemKind::Enum(ref enum_definition, _) => { let def = Def::Enum(self.definitions.local_def_id(item.id)); let module = self.new_module(parent, ModuleKind::Def(def, name), true); - self.define(parent, name, TypeNS, (module, sp, vis)); + self.define(parent, name, TypeNS, (module, vis, sp, expansion)); for variant in &(*enum_definition).variants { - self.build_reduced_graph_for_variant(variant, module, vis); + self.build_reduced_graph_for_variant(variant, module, vis, expansion); } } @@ -289,14 +313,14 @@ impl<'b> Resolver<'b> { ItemKind::Struct(ref struct_def, _) => { // Define a name in the type namespace. let def = Def::Struct(self.definitions.local_def_id(item.id)); - self.define(parent, name, TypeNS, (def, sp, vis)); + self.define(parent, name, TypeNS, (def, vis, sp, expansion)); // If this is a tuple or unit struct, define a name // in the value namespace as well. if !struct_def.is_struct() { let ctor_def = Def::StructCtor(self.definitions.local_def_id(struct_def.id()), CtorKind::from_ast(struct_def)); - self.define(parent, name, ValueNS, (ctor_def, sp, vis)); + self.define(parent, name, ValueNS, (ctor_def, vis, sp, expansion)); } // Record field names for error reporting. @@ -310,7 +334,7 @@ impl<'b> Resolver<'b> { ItemKind::Union(ref vdata, _) => { let def = Def::Union(self.definitions.local_def_id(item.id)); - self.define(parent, name, TypeNS, (def, sp, vis)); + self.define(parent, name, TypeNS, (def, vis, sp, expansion)); // Record field names for error reporting. let field_names = vdata.fields().iter().filter_map(|field| { @@ -329,7 +353,7 @@ impl<'b> Resolver<'b> { // Add all the items within to a new module. let module = self.new_module(parent, ModuleKind::Def(Def::Trait(def_id), name), true); - self.define(parent, name, TypeNS, (module, sp, vis)); + self.define(parent, name, TypeNS, (module, vis, sp, expansion)); self.current_module = module; } ItemKind::Mac(_) => panic!("unexpanded macro in resolve!"), @@ -341,37 +365,38 @@ impl<'b> Resolver<'b> { fn build_reduced_graph_for_variant(&mut self, variant: &Variant, parent: Module<'b>, - vis: ty::Visibility) { + vis: ty::Visibility, + expansion: Mark) { let name = variant.node.name.name; let def_id = self.definitions.local_def_id(variant.node.data.id()); // Define a name in the type namespace. let def = Def::Variant(def_id); - self.define(parent, name, TypeNS, (def, variant.span, vis)); + self.define(parent, name, TypeNS, (def, vis, variant.span, expansion)); // Define a constructor name in the value namespace. // Braced variants, unlike structs, generate unusable names in // value namespace, they are reserved for possible future use. let ctor_kind = CtorKind::from_ast(&variant.node.data); let ctor_def = Def::VariantCtor(def_id, ctor_kind); - self.define(parent, name, ValueNS, (ctor_def, variant.span, vis)); + self.define(parent, name, ValueNS, (ctor_def, vis, variant.span, expansion)); } /// Constructs the reduced graph for one foreign item. - fn build_reduced_graph_for_foreign_item(&mut self, foreign_item: &ForeignItem) { + fn build_reduced_graph_for_foreign_item(&mut self, item: &ForeignItem, expansion: Mark) { let parent = self.current_module; - let name = foreign_item.ident.name; + let name = item.ident.name; - let def = match foreign_item.node { + let def = match item.node { ForeignItemKind::Fn(..) => { - Def::Fn(self.definitions.local_def_id(foreign_item.id)) + Def::Fn(self.definitions.local_def_id(item.id)) } ForeignItemKind::Static(_, m) => { - Def::Static(self.definitions.local_def_id(foreign_item.id), m) + Def::Static(self.definitions.local_def_id(item.id), m) } }; - let vis = self.resolve_visibility(&foreign_item.vis); - self.define(parent, name, ValueNS, (def, foreign_item.span, vis)); + let vis = self.resolve_visibility(&item.vis); + self.define(parent, name, ValueNS, (def, vis, item.span, expansion)); } fn build_reduced_graph_for_block(&mut self, block: &Block) { @@ -390,8 +415,7 @@ impl<'b> Resolver<'b> { } /// Builds the reduced graph for a single item in an external crate. - fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'b>, - child: Export) { + fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'b>, child: Export) { let name = child.name; let def = child.def; let def_id = def.def_id(); @@ -404,24 +428,24 @@ impl<'b> Resolver<'b> { match def { Def::Mod(..) | Def::Enum(..) => { let module = self.new_module(parent, ModuleKind::Def(def, name), false); - self.define(parent, name, TypeNS, (module, DUMMY_SP, vis)); + self.define(parent, name, TypeNS, (module, vis, DUMMY_SP, Mark::root())); } Def::Variant(..) => { - self.define(parent, name, TypeNS, (def, DUMMY_SP, vis)); + self.define(parent, name, TypeNS, (def, vis, DUMMY_SP, Mark::root())); } Def::VariantCtor(..) => { - self.define(parent, name, ValueNS, (def, DUMMY_SP, vis)); + self.define(parent, name, ValueNS, (def, vis, DUMMY_SP, Mark::root())); } Def::Fn(..) | Def::Static(..) | Def::Const(..) | Def::AssociatedConst(..) | Def::Method(..) => { - self.define(parent, name, ValueNS, (def, DUMMY_SP, vis)); + self.define(parent, name, ValueNS, (def, vis, DUMMY_SP, Mark::root())); } Def::Trait(..) => { let module = self.new_module(parent, ModuleKind::Def(def, name), false); - self.define(parent, name, TypeNS, (module, DUMMY_SP, vis)); + self.define(parent, name, TypeNS, (module, vis, DUMMY_SP, Mark::root())); // If this is a trait, add all the trait item names to the trait info. let trait_item_def_ids = self.session.cstore.associated_item_def_ids(def_id); @@ -433,27 +457,27 @@ impl<'b> Resolver<'b> { } } Def::TyAlias(..) | Def::AssociatedTy(..) => { - self.define(parent, name, TypeNS, (def, DUMMY_SP, vis)); + self.define(parent, name, TypeNS, (def, vis, DUMMY_SP, Mark::root())); } Def::Struct(..) => { - self.define(parent, name, TypeNS, (def, DUMMY_SP, vis)); + self.define(parent, name, TypeNS, (def, vis, DUMMY_SP, Mark::root())); // Record field names for error reporting. let field_names = self.session.cstore.struct_field_names(def_id); self.insert_field_names(def_id, field_names); } Def::StructCtor(..) => { - self.define(parent, name, ValueNS, (def, DUMMY_SP, vis)); + self.define(parent, name, ValueNS, (def, vis, DUMMY_SP, Mark::root())); } Def::Union(..) => { - self.define(parent, name, TypeNS, (def, DUMMY_SP, vis)); + self.define(parent, name, TypeNS, (def, vis, DUMMY_SP, Mark::root())); // Record field names for error reporting. let field_names = self.session.cstore.struct_field_names(def_id); self.insert_field_names(def_id, field_names); } Def::Macro(..) => { - self.define(parent, name, MacroNS, (def, DUMMY_SP, vis)); + self.define(parent, name, MacroNS, (def, vis, DUMMY_SP, Mark::root())); } Def::Local(..) | Def::PrimTy(..) | @@ -479,9 +503,11 @@ impl<'b> Resolver<'b> { }) } - pub fn get_macro(&mut self, def: Def) -> Rc { - let def_id = match def { - Def::Macro(def_id) => def_id, + pub fn get_macro(&mut self, binding: &'b NameBinding<'b>) -> Rc { + let def_id = match binding.kind { + NameBindingKind::Def(Def::Macro(def_id)) => def_id, + NameBindingKind::Import { binding, .. } => return self.get_macro(binding), + NameBindingKind::Ambiguity { b1, .. } => return self.get_macro(b1), _ => panic!("Expected Def::Macro(..)"), }; if let Some(ext) = self.macro_map.get(&def_id) { @@ -518,10 +544,14 @@ impl<'b> Resolver<'b> { module.populated.set(true) } - fn legacy_import_macro(&mut self, name: Name, def: Def, span: Span, allow_shadowing: bool) { - self.used_crates.insert(def.def_id().krate); + fn legacy_import_macro(&mut self, + name: Name, + binding: &'b NameBinding<'b>, + span: Span, + allow_shadowing: bool) { + self.used_crates.insert(binding.def().def_id().krate); self.macro_names.insert(name); - if self.builtin_macros.insert(name, def.def_id()).is_some() && !allow_shadowing { + if self.builtin_macros.insert(name, binding).is_some() && !allow_shadowing { let msg = format!("`{}` is already in scope", name); let note = "macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)"; @@ -548,13 +578,13 @@ impl<'b> Resolver<'b> { if let Some(span) = legacy_imports.import_all { module.for_each_child(|name, ns, binding| if ns == MacroNS { - self.legacy_import_macro(name, binding.def(), span, allow_shadowing); + self.legacy_import_macro(name, binding, span, allow_shadowing); }); } else { for (name, span) in legacy_imports.imports { - let result = self.resolve_name_in_module(module, name, MacroNS, false, None); + let result = self.resolve_name_in_module(module, name, MacroNS, false, false, None); if let Success(binding) = result { - self.legacy_import_macro(name, binding.def(), span, allow_shadowing); + self.legacy_import_macro(name, binding, span, allow_shadowing); } else { span_err!(self.session, span, E0469, "imported macro not found"); } @@ -562,7 +592,7 @@ impl<'b> Resolver<'b> { } for (name, span) in legacy_imports.reexports { self.used_crates.insert(module.def_id().unwrap().krate); - let result = self.resolve_name_in_module(module, name, MacroNS, false, None); + let result = self.resolve_name_in_module(module, name, MacroNS, false, false, None); if let Success(binding) = result { self.macro_exports.push(Export { name: name, def: binding.def() }); } else { @@ -638,7 +668,9 @@ pub struct BuildReducedGraphVisitor<'a, 'b: 'a> { impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { fn visit_invoc(&mut self, id: ast::NodeId) -> &'b InvocationData<'b> { - let invocation = self.resolver.invocations[&Mark::from_placeholder_id(id)]; + let mark = Mark::from_placeholder_id(id); + self.resolver.current_module.unresolved_invocations.borrow_mut().insert(mark); + let invocation = self.resolver.invocations[&mark]; invocation.module.set(self.resolver.current_module); invocation.legacy_scope.set(self.legacy_scope); invocation @@ -691,7 +723,7 @@ impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> { } fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) { - self.resolver.build_reduced_graph_for_foreign_item(foreign_item); + self.resolver.build_reduced_graph_for_foreign_item(foreign_item, self.expansion); visit::walk_foreign_item(self, foreign_item); } @@ -728,7 +760,7 @@ impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> { self.resolver.trait_item_map.insert((item.ident.name, def_id), is_static_method); let vis = ty::Visibility::Public; - self.resolver.define(parent, item.ident.name, ns, (def, item.span, vis)); + self.resolver.define(parent, item.ident.name, ns, (def, vis, item.span, self.expansion)); self.resolver.current_module = parent.parent.unwrap(); // nearest normal ancestor visit::walk_trait_item(self, item); diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs index e1ea40809da0..492c5e695bbb 100644 --- a/src/librustc_resolve/check_unused.rs +++ b/src/librustc_resolve/check_unused.rs @@ -22,16 +22,18 @@ use std::ops::{Deref, DerefMut}; use Resolver; -use Namespace::{TypeNS, ValueNS}; use rustc::lint; +use rustc::util::nodemap::NodeMap; use syntax::ast::{self, ViewPathGlob, ViewPathList, ViewPathSimple}; use syntax::visit::{self, Visitor}; -use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::{Span, MultiSpan, DUMMY_SP}; struct UnusedImportCheckVisitor<'a, 'b: 'a> { resolver: &'a mut Resolver<'b>, + /// All the (so far) unused imports, grouped path list + unused_imports: NodeMap>, } // Deref and DerefMut impls allow treating UnusedImportCheckVisitor as Resolver. @@ -52,23 +54,22 @@ impl<'a, 'b> DerefMut for UnusedImportCheckVisitor<'a, 'b> { impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> { // We have information about whether `use` (import) directives are actually // used now. If an import is not used at all, we signal a lint error. - fn check_import(&mut self, id: ast::NodeId, span: Span) { - if !self.used_imports.contains(&(id, TypeNS)) && - !self.used_imports.contains(&(id, ValueNS)) { + fn check_import(&mut self, item_id: ast::NodeId, id: ast::NodeId, span: Span) { + let mut used = false; + self.per_ns(|this, ns| used |= this.used_imports.contains(&(id, ns))); + if !used { if self.maybe_unused_trait_imports.contains(&id) { // Check later. return; } - let msg = if let Ok(snippet) = self.session.codemap().span_to_snippet(span) { - format!("unused import: `{}`", snippet) - } else { - "unused import".to_string() - }; - self.session.add_lint(lint::builtin::UNUSED_IMPORTS, id, span, msg); + self.unused_imports.entry(item_id).or_insert_with(NodeMap).insert(id, span); } else { // This trait import is definitely used, in a way other than // method resolution. self.maybe_unused_trait_imports.remove(&id); + if let Some(i) = self.unused_imports.get_mut(&item_id) { + i.remove(&id); + } } } } @@ -98,16 +99,16 @@ impl<'a, 'b> Visitor for UnusedImportCheckVisitor<'a, 'b> { ast::ItemKind::Use(ref p) => { match p.node { ViewPathSimple(..) => { - self.check_import(item.id, p.span) + self.check_import(item.id, item.id, p.span) } ViewPathList(_, ref list) => { for i in list { - self.check_import(i.node.id, i.span); + self.check_import(item.id, i.node.id, i.span); } } ViewPathGlob(_) => { - self.check_import(item.id, p.span) + self.check_import(item.id, item.id, p.span); } } } @@ -117,6 +118,35 @@ impl<'a, 'b> Visitor for UnusedImportCheckVisitor<'a, 'b> { } pub fn check_crate(resolver: &mut Resolver, krate: &ast::Crate) { - let mut visitor = UnusedImportCheckVisitor { resolver: resolver }; + let mut visitor = UnusedImportCheckVisitor { + resolver: resolver, + unused_imports: NodeMap(), + }; visit::walk_crate(&mut visitor, krate); + + for (id, spans) in &visitor.unused_imports { + let len = spans.len(); + let mut spans = spans.values().map(|s| *s).collect::>(); + spans.sort(); + let ms = MultiSpan::from_spans(spans.clone()); + let mut span_snippets = spans.iter() + .filter_map(|s| { + match visitor.session.codemap().span_to_snippet(*s) { + Ok(s) => Some(format!("`{}`", s)), + _ => None, + } + }).collect::>(); + span_snippets.sort(); + let msg = format!("unused import{}{}", + if len > 1 { "s" } else { "" }, + if span_snippets.len() > 0 { + format!(": {}", span_snippets.join(", ")) + } else { + String::new() + }); + visitor.session.add_lint(lint::builtin::UNUSED_IMPORTS, + *id, + ms, + msg); + } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index fe90cd34687c..a3a60e4f6d75 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -76,7 +76,7 @@ use std::fmt; use std::mem::replace; use std::rc::Rc; -use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution}; +use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution, ImportResolver}; use macros::{InvocationData, LegacyBinding, LegacyScope}; // NB: This module needs to be declared first so diagnostics are @@ -536,6 +536,34 @@ pub enum Namespace { MacroNS, } +#[derive(Clone, Default, Debug)] +pub struct PerNS { + value_ns: T, + type_ns: T, + macro_ns: Option, +} + +impl ::std::ops::Index for PerNS { + type Output = T; + fn index(&self, ns: Namespace) -> &T { + match ns { + ValueNS => &self.value_ns, + TypeNS => &self.type_ns, + MacroNS => self.macro_ns.as_ref().unwrap(), + } + } +} + +impl ::std::ops::IndexMut for PerNS { + fn index_mut(&mut self, ns: Namespace) -> &mut T { + match ns { + ValueNS => &mut self.value_ns, + TypeNS => &mut self.type_ns, + MacroNS => self.macro_ns.as_mut().unwrap(), + } + } +} + impl<'a> Visitor for Resolver<'a> { fn visit_item(&mut self, item: &Item) { self.resolve_item(item); @@ -612,7 +640,7 @@ impl<'a> Visitor for Resolver<'a> { }; // Create a value rib for the function. - self.value_ribs.push(Rib::new(rib_kind)); + self.ribs[ValueNS].push(Rib::new(rib_kind)); // Create a label rib for the function. self.label_ribs.push(Rib::new(rib_kind)); @@ -642,13 +670,13 @@ impl<'a> Visitor for Resolver<'a> { debug!("(resolving function) leaving function"); self.label_ribs.pop(); - self.value_ribs.pop(); + self.ribs[ValueNS].pop(); } } pub type ErrorMessage = Option<(Span, String)>; -#[derive(Clone, PartialEq, Eq)] +#[derive(Clone, PartialEq, Eq, Debug)] pub enum ResolveResult { Failed(ErrorMessage), // Failed to resolve the name, optional helpful error message. Indeterminate, // Couldn't determine due to unresolved globs. @@ -656,14 +684,6 @@ pub enum ResolveResult { } impl ResolveResult { - fn and_then ResolveResult>(self, f: F) -> ResolveResult { - match self { - Failed(msg) => Failed(msg), - Indeterminate => Indeterminate, - Success(t) => f(t), - } - } - fn success(self) -> Option { match self { Success(t) => Some(t), @@ -798,6 +818,10 @@ pub struct ModuleS<'a> { normal_ancestor_id: Option, resolutions: RefCell>>>, + legacy_macro_resolutions: RefCell>, + + // Macro invocations that can expand into items in this module. + unresolved_invocations: RefCell>, no_implicit_prelude: bool, @@ -822,6 +846,8 @@ impl<'a> ModuleS<'a> { kind: kind, normal_ancestor_id: None, resolutions: RefCell::new(FxHashMap()), + legacy_macro_resolutions: RefCell::new(Vec::new()), + unresolved_invocations: RefCell::new(FxHashSet()), no_implicit_prelude: false, glob_importers: RefCell::new(Vec::new()), globs: RefCell::new((Vec::new())), @@ -877,6 +903,7 @@ impl<'a> fmt::Debug for ModuleS<'a> { #[derive(Clone, Debug)] pub struct NameBinding<'a> { kind: NameBindingKind<'a>, + expansion: Mark, span: Span, vis: ty::Visibility, } @@ -911,6 +938,7 @@ struct PrivacyError<'a>(Span, Name, &'a NameBinding<'a>); struct AmbiguityError<'a> { span: Span, name: Name, + lexical: bool, b1: &'a NameBinding<'a>, b2: &'a NameBinding<'a>, } @@ -969,7 +997,7 @@ impl<'a> NameBinding<'a> { fn is_glob_import(&self) -> bool { match self.kind { NameBindingKind::Import { directive, .. } => directive.is_glob(), - NameBindingKind::Ambiguity { .. } => true, + NameBindingKind::Ambiguity { b1, .. } => b1.is_glob_import(), _ => false, } } @@ -1044,12 +1072,9 @@ pub struct Resolver<'a> { // The module that represents the current item scope. current_module: Module<'a>, - // The current set of local scopes, for values. + // The current set of local scopes for types and values. // FIXME #4948: Reuse ribs to avoid allocation. - value_ribs: Vec>, - - // The current set of local scopes, for types. - type_ribs: Vec>, + ribs: PerNS>>, // The current set of local scopes, for labels. label_ribs: Vec>, @@ -1107,17 +1132,21 @@ pub struct Resolver<'a> { arenas: &'a ResolverArenas<'a>, dummy_binding: &'a NameBinding<'a>, new_import_semantics: bool, // true if `#![feature(item_like_imports)]` + use_extern_macros: bool, // true if `#![feature(use_extern_macros)]` pub exported_macros: Vec, crate_loader: &'a mut CrateLoader, macro_names: FxHashSet, - builtin_macros: FxHashMap, + builtin_macros: FxHashMap>, lexical_macro_resolutions: Vec<(Name, LegacyScope<'a>)>, macro_map: FxHashMap>, macro_exports: Vec, // Maps the `Mark` of an expansion to its containing module or block. invocations: FxHashMap>, + + // Avoid duplicated errors for "name already defined". + name_already_seen: FxHashMap, } pub struct ResolverArenas<'a> { @@ -1265,8 +1294,11 @@ impl<'a> Resolver<'a> { indeterminate_imports: Vec::new(), current_module: graph_root, - value_ribs: vec![Rib::new(ModuleRibKind(graph_root))], - type_ribs: vec![Rib::new(ModuleRibKind(graph_root))], + ribs: PerNS { + value_ns: vec![Rib::new(ModuleRibKind(graph_root))], + type_ns: vec![Rib::new(ModuleRibKind(graph_root))], + macro_ns: None, + }, label_ribs: Vec::new(), current_trait_ref: None, @@ -1297,10 +1329,12 @@ impl<'a> Resolver<'a> { arenas: arenas, dummy_binding: arenas.alloc_name_binding(NameBinding { kind: NameBindingKind::Def(Def::Err), + expansion: Mark::root(), span: DUMMY_SP, vis: ty::Visibility::Public, }), new_import_semantics: session.features.borrow().item_like_imports, + use_extern_macros: session.features.borrow().use_extern_macros, exported_macros: Vec::new(), crate_loader: crate_loader, @@ -1310,6 +1344,7 @@ impl<'a> Resolver<'a> { macro_map: FxHashMap(), macro_exports: Vec::new(), invocations: invocations, + name_already_seen: FxHashMap(), } } @@ -1325,8 +1360,20 @@ impl<'a> Resolver<'a> { } } + fn per_ns T>(&mut self, mut f: F) -> PerNS { + PerNS { + type_ns: f(self, TypeNS), + value_ns: f(self, ValueNS), + macro_ns: match self.use_extern_macros { + true => Some(f(self, MacroNS)), + false => None, + }, + } + } + /// Entry point to crate resolution. pub fn resolve_crate(&mut self, krate: &Crate) { + ImportResolver { resolver: self }.finalize_imports(); self.current_module = self.graph_root; visit::walk_crate(self, krate); @@ -1343,14 +1390,6 @@ impl<'a> Resolver<'a> { }) } - fn get_ribs<'b>(&'b mut self, ns: Namespace) -> &'b mut Vec> { - match ns { - ValueNS => &mut self.value_ribs, - TypeNS => &mut self.type_ribs, - MacroNS => panic!("The macro namespace has no ribs"), - } - } - fn record_use(&mut self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>, span: Span) -> bool /* true if an error was reported */ { // track extern crates for unused_extern_crate lint @@ -1367,8 +1406,9 @@ impl<'a> Resolver<'a> { } NameBindingKind::Import { .. } => false, NameBindingKind::Ambiguity { b1, b2 } => { - let ambiguity_error = AmbiguityError { span: span, name: name, b1: b1, b2: b2 }; - self.ambiguity_errors.push(ambiguity_error); + self.ambiguity_errors.push(AmbiguityError { + span: span, name: name, lexical: false, b1: b1, b2: b2, + }); true } _ => false @@ -1402,7 +1442,7 @@ impl<'a> Resolver<'a> { -> ResolveResult> { fn search_parent_externals<'a>(this: &mut Resolver<'a>, needle: Name, module: Module<'a>) -> Option> { - match this.resolve_name_in_module(module, needle, TypeNS, false, None) { + match this.resolve_name_in_module(module, needle, TypeNS, false, false, None) { Success(binding) if binding.is_extern_crate() => Some(module), _ => if let (&ModuleKind::Def(..), Some(parent)) = (&module.kind, module.parent) { search_parent_externals(this, needle, parent) @@ -1420,7 +1460,7 @@ impl<'a> Resolver<'a> { // modules as we go. while index < module_path_len { let name = module_path[index].name; - match self.resolve_name_in_module(search_module, name, TypeNS, false, span) { + match self.resolve_name_in_module(search_module, name, TypeNS, false, false, span) { Failed(_) => { let segment_name = name.as_str(); let module_name = module_to_string(search_module); @@ -1566,8 +1606,8 @@ impl<'a> Resolver<'a> { } // Walk backwards up the ribs in scope. - for i in (0 .. self.get_ribs(ns).len()).rev() { - if let Some(def) = self.get_ribs(ns)[i].bindings.get(&ident).cloned() { + for i in (0 .. self.ribs[ns].len()).rev() { + if let Some(def) = self.ribs[ns][i].bindings.get(&ident).cloned() { // The ident resolves to a type parameter or local variable. return Some(LexicalScopeBinding::LocalDef(LocalDef { ribs: Some((ns, i)), @@ -1575,9 +1615,9 @@ impl<'a> Resolver<'a> { })); } - if let ModuleRibKind(module) = self.get_ribs(ns)[i].kind { + if let ModuleRibKind(module) = self.ribs[ns][i].kind { let name = ident.name; - let item = self.resolve_name_in_module(module, name, ns, true, record_used); + let item = self.resolve_name_in_module(module, name, ns, true, false, record_used); if let Success(binding) = item { // The ident resolves to an item. return Some(LexicalScopeBinding::Item(binding)); @@ -1586,14 +1626,14 @@ impl<'a> Resolver<'a> { if let ModuleKind::Block(..) = module.kind { // We can see through blocks } else if !module.no_implicit_prelude { return self.prelude.and_then(|prelude| { - self.resolve_name_in_module(prelude, name, ns, false, None).success() + self.resolve_name_in_module(prelude, name, ns, false, false, None).success() }).map(LexicalScopeBinding::Item) } else { return None; } } - if let MacroDefinition(mac) = self.get_ribs(ns)[i].kind { + if let MacroDefinition(mac) = self.ribs[ns][i].kind { // If an invocation of this macro created `ident`, give up on `ident` // and switch to `ident`'s source from the macro definition. let (source_ctxt, source_macro) = ident.ctxt.source(); @@ -1678,14 +1718,15 @@ impl<'a> Resolver<'a> { if let Some(module) = module { // Move down in the graph. let orig_module = replace(&mut self.current_module, module); - self.value_ribs.push(Rib::new(ModuleRibKind(module))); - self.type_ribs.push(Rib::new(ModuleRibKind(module))); + self.ribs[ValueNS].push(Rib::new(ModuleRibKind(module))); + self.ribs[TypeNS].push(Rib::new(ModuleRibKind(module))); + self.finalize_current_module_macro_resolutions(); f(self); self.current_module = orig_module; - self.value_ribs.pop(); - self.type_ribs.pop(); + self.ribs[ValueNS].pop(); + self.ribs[TypeNS].pop(); } else { f(self); } @@ -1860,7 +1901,7 @@ impl<'a> Resolver<'a> { function_type_rib.bindings.insert(Ident::with_empty_ctxt(name), def); self.record_def(type_parameter.id, PathResolution::new(def)); } - self.type_ribs.push(function_type_rib); + self.ribs[TypeNS].push(function_type_rib); } NoTypeParameters => { @@ -1871,7 +1912,7 @@ impl<'a> Resolver<'a> { f(self); if let HasTypeParameters(..) = type_parameters { - self.type_ribs.pop(); + self.ribs[TypeNS].pop(); } } @@ -1886,11 +1927,11 @@ impl<'a> Resolver<'a> { fn with_constant_rib(&mut self, f: F) where F: FnOnce(&mut Resolver) { - self.value_ribs.push(Rib::new(ConstantItemRibKind)); - self.type_ribs.push(Rib::new(ConstantItemRibKind)); + self.ribs[ValueNS].push(Rib::new(ConstantItemRibKind)); + self.ribs[TypeNS].push(Rib::new(ConstantItemRibKind)); f(self); - self.type_ribs.pop(); - self.value_ribs.pop(); + self.ribs[TypeNS].pop(); + self.ribs[ValueNS].pop(); } fn resolve_trait_reference(&mut self, @@ -2000,9 +2041,9 @@ impl<'a> Resolver<'a> { // plain insert (no renaming, types are not currently hygienic....) self_type_rib.bindings.insert(keywords::SelfType.ident(), self_def); - self.type_ribs.push(self_type_rib); + self.ribs[TypeNS].push(self_type_rib); f(self); - self.type_ribs.pop(); + self.ribs[TypeNS].pop(); } fn resolve_implementation(&mut self, @@ -2156,7 +2197,7 @@ impl<'a> Resolver<'a> { } fn resolve_arm(&mut self, arm: &Arm) { - self.value_ribs.push(Rib::new(NormalRibKind)); + self.ribs[ValueNS].push(Rib::new(NormalRibKind)); let mut bindings_list = FxHashMap(); for pattern in &arm.pats { @@ -2170,7 +2211,7 @@ impl<'a> Resolver<'a> { walk_list!(self, visit_expr, &arm.guard); self.visit_expr(&arm.body); - self.value_ribs.pop(); + self.ribs[ValueNS].pop(); } fn resolve_block(&mut self, block: &Block) { @@ -2182,11 +2223,12 @@ impl<'a> Resolver<'a> { let mut num_macro_definition_ribs = 0; if let Some(anonymous_module) = anonymous_module { debug!("(resolving block) found anonymous module, moving down"); - self.value_ribs.push(Rib::new(ModuleRibKind(anonymous_module))); - self.type_ribs.push(Rib::new(ModuleRibKind(anonymous_module))); + self.ribs[ValueNS].push(Rib::new(ModuleRibKind(anonymous_module))); + self.ribs[TypeNS].push(Rib::new(ModuleRibKind(anonymous_module))); self.current_module = anonymous_module; + self.finalize_current_module_macro_resolutions(); } else { - self.value_ribs.push(Rib::new(NormalRibKind)); + self.ribs[ValueNS].push(Rib::new(NormalRibKind)); } // Descend into the block. @@ -2194,7 +2236,7 @@ impl<'a> Resolver<'a> { if let Some(marks) = self.macros_at_scope.remove(&stmt.id) { num_macro_definition_ribs += marks.len() as u32; for mark in marks { - self.value_ribs.push(Rib::new(MacroDefinition(mark))); + self.ribs[ValueNS].push(Rib::new(MacroDefinition(mark))); self.label_ribs.push(Rib::new(MacroDefinition(mark))); } } @@ -2205,12 +2247,12 @@ impl<'a> Resolver<'a> { // Move back up. self.current_module = orig_module; for _ in 0 .. num_macro_definition_ribs { - self.value_ribs.pop(); + self.ribs[ValueNS].pop(); self.label_ribs.pop(); } - self.value_ribs.pop(); + self.ribs[ValueNS].pop(); if let Some(_) = anonymous_module { - self.type_ribs.pop(); + self.ribs[TypeNS].pop(); } debug!("(resolving block) leaving block"); } @@ -2329,7 +2371,7 @@ impl<'a> Resolver<'a> { Some(..) if pat_src == PatternSource::Match => { // `Variant1(a) | Variant2(a)`, ok // Reuse definition from the first `a`. - def = self.value_ribs.last_mut().unwrap().bindings[&ident.node]; + def = self.ribs[ValueNS].last_mut().unwrap().bindings[&ident.node]; } Some(..) => { span_bug!(ident.span, "two bindings with the same name from \ @@ -2339,7 +2381,7 @@ impl<'a> Resolver<'a> { // A completely fresh binding, add to the lists if it's valid. if ident.node.name != keywords::Invalid.name() { bindings.insert(ident.node, outer_pat_id); - self.value_ribs.last_mut().unwrap().bindings.insert(ident.node, def); + self.ribs[ValueNS].last_mut().unwrap().bindings.insert(ident.node, def); } } } @@ -2623,9 +2665,8 @@ impl<'a> Resolver<'a> { // Resolve a local definition, potentially adjusting for closures. fn adjust_local_def(&mut self, local_def: LocalDef, span: Span) -> Option { let ribs = match local_def.ribs { - Some((TypeNS, i)) => &self.type_ribs[i + 1..], - Some((ValueNS, i)) => &self.value_ribs[i + 1..], - _ => &[] as &[_], + Some((ns, i)) => &self.ribs[ns][i + 1..], + None => &[] as &[_], }; let mut def = local_def.def; match def { @@ -2719,8 +2760,7 @@ impl<'a> Resolver<'a> { let module_path = segments.split_last().unwrap().1.iter().map(|ps| ps.identifier).collect::>(); - let containing_module; - match self.resolve_module_path(&module_path, UseLexicalScope, Some(span)) { + let module = match self.resolve_module_path(&module_path, UseLexicalScope, Some(span)) { Failed(err) => { if let Some((span, msg)) = err { resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); @@ -2728,14 +2768,11 @@ impl<'a> Resolver<'a> { return Err(true); } Indeterminate => return Err(false), - Success(resulting_module) => { - containing_module = resulting_module; - } - } + Success(module) => module, + }; let name = segments.last().unwrap().identifier.name; - let result = - self.resolve_name_in_module(containing_module, name, namespace, false, Some(span)); + let result = self.resolve_name_in_module(module, name, namespace, false, false, Some(span)); result.success().ok_or(false) } @@ -2747,10 +2784,9 @@ impl<'a> Resolver<'a> { where T: Named, { let module_path = segments.split_last().unwrap().1.iter().map(T::ident).collect::>(); - let root_module = self.graph_root; + let root = self.graph_root; - let containing_module; - match self.resolve_module_path_from_root(root_module, &module_path, 0, Some(span)) { + let module = match self.resolve_module_path_from_root(root, &module_path, 0, Some(span)) { Failed(err) => { if let Some((span, msg)) = err { resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); @@ -2760,14 +2796,11 @@ impl<'a> Resolver<'a> { Indeterminate => return Err(false), - Success(resulting_module) => { - containing_module = resulting_module; - } - } + Success(module) => module, + }; let name = segments.last().unwrap().ident().name; - let result = - self.resolve_name_in_module(containing_module, name, namespace, false, Some(span)); + let result = self.resolve_name_in_module(module, name, namespace, false, false, Some(span)); result.success().ok_or(false) } @@ -2787,8 +2820,8 @@ impl<'a> Resolver<'a> { where F: FnOnce(&mut Resolver<'a>) -> T, { self.with_empty_ribs(|this| { - this.value_ribs.push(Rib::new(ModuleRibKind(module))); - this.type_ribs.push(Rib::new(ModuleRibKind(module))); + this.ribs[ValueNS].push(Rib::new(ModuleRibKind(module))); + this.ribs[TypeNS].push(Rib::new(ModuleRibKind(module))); f(this) }) } @@ -2796,13 +2829,11 @@ impl<'a> Resolver<'a> { fn with_empty_ribs(&mut self, f: F) -> T where F: FnOnce(&mut Resolver<'a>) -> T, { - let value_ribs = replace(&mut self.value_ribs, Vec::new()); - let type_ribs = replace(&mut self.type_ribs, Vec::new()); + let ribs = replace(&mut self.ribs, PerNS::>::default()); let label_ribs = replace(&mut self.label_ribs, Vec::new()); let result = f(self); - self.value_ribs = value_ribs; - self.type_ribs = type_ribs; + self.ribs = ribs; self.label_ribs = label_ribs; result } @@ -2854,7 +2885,7 @@ impl<'a> Resolver<'a> { return SuggestionType::Macro(format!("{}!", macro_name)); } - let names = self.value_ribs + let names = self.ribs[ValueNS] .iter() .rev() .flat_map(|rib| rib.bindings.keys().map(|ident| &ident.name)); @@ -2957,7 +2988,7 @@ impl<'a> Resolver<'a> { } else { let mut method_scope = false; let mut is_static = false; - self.value_ribs.iter().rev().all(|rib| { + self.ribs[ValueNS].iter().rev().all(|rib| { method_scope = match rib.kind { MethodRibKind(is_static_) => { is_static = is_static_; @@ -3068,10 +3099,10 @@ impl<'a> Resolver<'a> { ExprKind::IfLet(ref pattern, ref subexpression, ref if_block, ref optional_else) => { self.visit_expr(subexpression); - self.value_ribs.push(Rib::new(NormalRibKind)); + self.ribs[ValueNS].push(Rib::new(NormalRibKind)); self.resolve_pattern(pattern, PatternSource::IfLet, &mut FxHashMap()); self.visit_block(if_block); - self.value_ribs.pop(); + self.ribs[ValueNS].pop(); optional_else.as_ref().map(|expr| self.visit_expr(expr)); } @@ -3085,22 +3116,22 @@ impl<'a> Resolver<'a> { ExprKind::WhileLet(ref pattern, ref subexpression, ref block, label) => { self.visit_expr(subexpression); - self.value_ribs.push(Rib::new(NormalRibKind)); + self.ribs[ValueNS].push(Rib::new(NormalRibKind)); self.resolve_pattern(pattern, PatternSource::WhileLet, &mut FxHashMap()); self.resolve_labeled_block(label, expr.id, block); - self.value_ribs.pop(); + self.ribs[ValueNS].pop(); } ExprKind::ForLoop(ref pattern, ref subexpression, ref block, label) => { self.visit_expr(subexpression); - self.value_ribs.push(Rib::new(NormalRibKind)); + self.ribs[ValueNS].push(Rib::new(NormalRibKind)); self.resolve_pattern(pattern, PatternSource::For, &mut FxHashMap()); self.resolve_labeled_block(label, expr.id, block); - self.value_ribs.pop(); + self.ribs[ValueNS].pop(); } ExprKind::Field(ref subexpression, _) => { @@ -3350,14 +3381,18 @@ impl<'a> Resolver<'a> { self.report_shadowing_errors(); let mut reported_spans = FxHashSet(); - for &AmbiguityError { span, name, b1, b2 } in &self.ambiguity_errors { + for &AmbiguityError { span, name, b1, b2, lexical } in &self.ambiguity_errors { if !reported_spans.insert(span) { continue } let msg1 = format!("`{}` could resolve to the name imported here", name); let msg2 = format!("`{}` could also resolve to the name imported here", name); self.session.struct_span_err(span, &format!("`{}` is ambiguous", name)) .span_note(b1.span, &msg1) .span_note(b2.span, &msg2) - .note(&format!("Consider adding an explicit import of `{}` to disambiguate", name)) + .note(&if lexical || !b1.is_glob_import() { + "macro-expanded macro imports do not shadow".to_owned() + } else { + format!("consider adding an explicit import of `{}` to disambiguate", name) + }) .emit(); } @@ -3380,12 +3415,12 @@ impl<'a> Resolver<'a> { fn report_shadowing_errors(&mut self) { for (name, scope) in replace(&mut self.lexical_macro_resolutions, Vec::new()) { - self.resolve_macro_name(scope, name); + self.resolve_legacy_scope(scope, name, true); } let mut reported_errors = FxHashSet(); for binding in replace(&mut self.disallowed_shadowing, Vec::new()) { - if self.resolve_macro_name(binding.parent, binding.name).is_some() && + if self.resolve_legacy_scope(binding.parent, binding.name, false).is_some() && reported_errors.insert((binding.name, binding.span)) { let msg = format!("`{}` is already in scope", binding.name); self.session.struct_span_err(binding.span, &msg) @@ -3396,7 +3431,7 @@ impl<'a> Resolver<'a> { } } - fn report_conflict(&self, + fn report_conflict(&mut self, parent: Module, name: Name, ns: Namespace, @@ -3420,6 +3455,13 @@ impl<'a> Resolver<'a> { }; let span = binding.span; + + if let Some(s) = self.name_already_seen.get(&name) { + if s == &span { + return; + } + } + let msg = { let kind = match (ns, old_binding.module()) { (ValueNS, _) => "a value", @@ -3472,6 +3514,7 @@ impl<'a> Resolver<'a> { err.span_label(old_binding.span, &format!("previous {} of `{}` here", noun, name)); } err.emit(); + self.name_already_seen.insert(name, span); } } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index f30c129c48fd..524d491a464e 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -8,14 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use {Module, ModuleKind, Resolver}; +use {Module, ModuleKind, NameBinding, NameBindingKind, Resolver, AmbiguityError}; +use Namespace::{self, MacroNS}; +use ResolveResult::{Success, Indeterminate, Failed}; use build_reduced_graph::BuildReducedGraphVisitor; +use resolve_imports::ImportResolver; use rustc::hir::def_id::{DefId, BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, DefIndex}; use rustc::hir::def::{Def, Export}; use rustc::hir::map::{self, DefCollector}; +use rustc::ty; use std::cell::Cell; use std::rc::Rc; -use syntax::ast; +use syntax::ast::{self, Name}; use syntax::errors::DiagnosticBuilder; use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator}; use syntax::ext::base::{NormalTT, SyntaxExtension}; @@ -27,7 +31,7 @@ use syntax::parse::token::intern; use syntax::ptr::P; use syntax::util::lev_distance::find_best_match_for_name; use syntax::visit::Visitor; -use syntax_pos::Span; +use syntax_pos::{Span, DUMMY_SP}; #[derive(Clone)] pub struct InvocationData<'a> { @@ -83,6 +87,11 @@ pub struct LegacyBinding<'a> { pub span: Span, } +pub enum MacroBinding<'a> { + Legacy(&'a LegacyBinding<'a>), + Modern(&'a NameBinding<'a>), +} + impl<'a> base::Resolver for Resolver<'a> { fn next_node_id(&mut self) -> ast::NodeId { self.session.next_node_id() @@ -131,12 +140,14 @@ impl<'a> base::Resolver for Resolver<'a> { self.collect_def_ids(invocation, expansion); self.current_module = invocation.module.get(); + self.current_module.unresolved_invocations.borrow_mut().remove(&mark); let mut visitor = BuildReducedGraphVisitor { resolver: self, legacy_scope: LegacyScope::Invocation(invocation), expansion: mark, }; expansion.visit_with(&mut visitor); + self.current_module.unresolved_invocations.borrow_mut().remove(&mark); invocation.expansion.set(visitor.legacy_scope); } @@ -177,18 +188,28 @@ impl<'a> base::Resolver for Resolver<'a> { index: DefIndex::new(self.macro_map.len()), }; self.macro_map.insert(def_id, ext); - self.builtin_macros.insert(ident.name, def_id); + let binding = self.arenas.alloc_name_binding(NameBinding { + kind: NameBindingKind::Def(Def::Macro(def_id)), + span: DUMMY_SP, + vis: ty::Visibility::PrivateExternal, + expansion: Mark::root(), + }); + self.builtin_macros.insert(ident.name, binding); } fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec) { self.macros_at_scope.insert(id, macros); } + fn resolve_imports(&mut self) { + ImportResolver { resolver: self }.resolve_imports() + } + fn find_attr_invoc(&mut self, attrs: &mut Vec) -> Option { for i in 0..attrs.len() { let name = intern(&attrs[i].name()); - match self.builtin_macros.get(&name) { - Some(&def_id) => match *self.get_macro(Def::Macro(def_id)) { + match self.builtin_macros.get(&name).cloned() { + Some(binding) => match *self.get_macro(binding) { MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => { return Some(attrs.remove(i)) } @@ -212,25 +233,81 @@ impl<'a> base::Resolver for Resolver<'a> { if let LegacyScope::Expansion(parent) = invocation.legacy_scope.get() { invocation.legacy_scope.set(LegacyScope::simplify_expansion(parent)); } - self.resolve_macro_name(invocation.legacy_scope.get(), name).ok_or_else(|| { - if force { - let msg = format!("macro undefined: '{}!'", name); - let mut err = self.session.struct_span_err(path.span, &msg); - self.suggest_macro_name(&name.as_str(), &mut err); - err.emit(); - Determinacy::Determined - } else { - Determinacy::Undetermined - } - }) + + self.current_module = invocation.module.get(); + let result = match self.resolve_legacy_scope(invocation.legacy_scope.get(), name, false) { + Some(MacroBinding::Legacy(binding)) => Ok(binding.ext.clone()), + Some(MacroBinding::Modern(binding)) => Ok(self.get_macro(binding)), + None => match self.resolve_in_item_lexical_scope(name, MacroNS, None) { + Some(binding) => Ok(self.get_macro(binding)), + None => return Err(if force { + let msg = format!("macro undefined: '{}!'", name); + let mut err = self.session.struct_span_err(path.span, &msg); + self.suggest_macro_name(&name.as_str(), &mut err); + err.emit(); + Determinacy::Determined + } else { + Determinacy::Undetermined + }), + }, + }; + + if self.use_extern_macros { + self.current_module.legacy_macro_resolutions.borrow_mut() + .push((scope, name, path.span)); + } + result } } impl<'a> Resolver<'a> { - pub fn resolve_macro_name(&mut self, mut scope: LegacyScope<'a>, name: ast::Name) - -> Option> { + // Resolve the name in the module's lexical scope, excluding non-items. + fn resolve_in_item_lexical_scope(&mut self, + name: Name, + ns: Namespace, + record_used: Option) + -> Option<&'a NameBinding<'a>> { + let mut module = self.current_module; + let mut potential_expanded_shadower = None; + loop { + // Since expanded macros may not shadow the lexical scope (enforced below), + // we can ignore unresolved invocations (indicated by the penultimate argument). + match self.resolve_name_in_module(module, name, ns, true, true, record_used) { + Success(binding) => { + let span = match record_used { + Some(span) => span, + None => return Some(binding), + }; + if let Some(shadower) = potential_expanded_shadower { + self.ambiguity_errors.push(AmbiguityError { + span: span, name: name, b1: shadower, b2: binding, lexical: true, + }); + return Some(shadower); + } else if binding.expansion == Mark::root() { + return Some(binding); + } else { + potential_expanded_shadower = Some(binding); + } + }, + Indeterminate => return None, + Failed(..) => {} + } + + match module.kind { + ModuleKind::Block(..) => module = module.parent.unwrap(), + ModuleKind::Def(..) => return potential_expanded_shadower, + } + } + } + + pub fn resolve_legacy_scope(&mut self, + mut scope: LegacyScope<'a>, + name: Name, + record_used: bool) + -> Option> { let mut possible_time_travel = None; let mut relative_depth: u32 = 0; + let mut binding = None; loop { scope = match scope { LegacyScope::Empty => break, @@ -249,25 +326,59 @@ impl<'a> Resolver<'a> { relative_depth = relative_depth.saturating_sub(1); invocation.legacy_scope.get() } - LegacyScope::Binding(binding) => { - if binding.name == name { - if let Some(scope) = possible_time_travel { - // Check for disallowed shadowing later - self.lexical_macro_resolutions.push((name, scope)); - } else if relative_depth > 0 { - self.disallowed_shadowing.push(binding); + LegacyScope::Binding(potential_binding) => { + if potential_binding.name == name { + if (!self.use_extern_macros || record_used) && relative_depth > 0 { + self.disallowed_shadowing.push(potential_binding); } - return Some(binding.ext.clone()); + binding = Some(potential_binding); + break } - binding.parent + potential_binding.parent } }; } - if let Some(scope) = possible_time_travel { - self.lexical_macro_resolutions.push((name, scope)); + let binding = match binding { + Some(binding) => MacroBinding::Legacy(binding), + None => match self.builtin_macros.get(&name).cloned() { + Some(binding) => MacroBinding::Modern(binding), + None => return None, + }, + }; + + if !self.use_extern_macros { + if let Some(scope) = possible_time_travel { + // Check for disallowed shadowing later + self.lexical_macro_resolutions.push((name, scope)); + } + } + + Some(binding) + } + + pub fn finalize_current_module_macro_resolutions(&mut self) { + let module = self.current_module; + for &(mark, name, span) in module.legacy_macro_resolutions.borrow().iter() { + let legacy_scope = self.invocations[&mark].legacy_scope.get(); + let legacy_resolution = self.resolve_legacy_scope(legacy_scope, name, true); + let resolution = self.resolve_in_item_lexical_scope(name, MacroNS, Some(span)); + let (legacy_resolution, resolution) = match (legacy_resolution, resolution) { + (Some(legacy_resolution), Some(resolution)) => (legacy_resolution, resolution), + _ => continue, + }; + let (legacy_span, participle) = match legacy_resolution { + MacroBinding::Modern(binding) if binding.def() == resolution.def() => continue, + MacroBinding::Modern(binding) => (binding.span, "imported"), + MacroBinding::Legacy(binding) => (binding.span, "defined"), + }; + let msg1 = format!("`{}` could resolve to the macro {} here", name, participle); + let msg2 = format!("`{}` could also resolve to the macro imported here", name); + self.session.struct_span_err(span, &format!("`{}` is ambiguous", name)) + .span_note(legacy_span, &msg1) + .span_note(resolution.span, &msg2) + .emit(); } - self.builtin_macros.get(&name).cloned().map(|def_id| self.get_macro(Def::Macro(def_id))) } fn suggest_macro_name(&mut self, name: &str, err: &mut DiagnosticBuilder<'a>) { diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 5d66caec31b3..d0ce1acaadf6 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -10,8 +10,8 @@ use self::ImportDirectiveSubclass::*; -use Module; -use Namespace::{self, TypeNS, ValueNS}; +use {Module, PerNS}; +use Namespace::{self, TypeNS, MacroNS}; use {NameBinding, NameBindingKind, PrivacyError, ToNameBinding}; use ResolveResult; use ResolveResult::*; @@ -26,26 +26,20 @@ use rustc::hir::def::*; use syntax::ast::{Ident, NodeId, Name}; use syntax::ext::base::Determinacy::{self, Determined, Undetermined}; +use syntax::ext::hygiene::Mark; use syntax::util::lev_distance::find_best_match_for_name; use syntax_pos::Span; use std::cell::{Cell, RefCell}; use std::mem; -impl<'a> Resolver<'a> { - pub fn resolve_imports(&mut self) { - ImportResolver { resolver: self }.resolve_imports(); - } -} - /// Contains data for specific types of import directives. #[derive(Clone, Debug)] pub enum ImportDirectiveSubclass<'a> { SingleImport { target: Name, source: Name, - value_result: Cell, Determinacy>>, - type_result: Cell, Determinacy>>, + result: PerNS, Determinacy>>>, }, GlobImport { is_prelude: bool, @@ -55,17 +49,6 @@ pub enum ImportDirectiveSubclass<'a> { ExternCrate, } -impl<'a> ImportDirectiveSubclass<'a> { - pub fn single(target: Name, source: Name) -> Self { - SingleImport { - target: target, - source: source, - type_result: Cell::new(Err(Undetermined)), - value_result: Cell::new(Err(Undetermined)), - } - } -} - /// One import directive. #[derive(Debug,Clone)] pub struct ImportDirective<'a> { @@ -76,6 +59,7 @@ pub struct ImportDirective<'a> { pub subclass: ImportDirectiveSubclass<'a>, pub span: Span, pub vis: Cell, + pub expansion: Mark, } impl<'a> ImportDirective<'a> { @@ -158,6 +142,7 @@ impl<'a> Resolver<'a> { name: Name, ns: Namespace, allow_private_imports: bool, + ignore_unresolved_invocations: bool, record_used: Option) -> ResolveResult<&'a NameBinding<'a>> { self.populate_module_if_necessary(module); @@ -191,23 +176,55 @@ impl<'a> Resolver<'a> { return resolution.binding.map(Success).unwrap_or(Failed(None)); } - // If the resolution doesn't depend on glob definability, check privacy and return. - if let Some(result) = self.try_result(&resolution, ns) { - return result.and_then(|binding| { - if self.is_accessible(binding.vis) && !is_disallowed_private_import(binding) || - binding.is_extern_crate() { // c.f. issue #37020 - Success(binding) - } else { - Failed(None) + let check_usable = |this: &mut Self, binding: &'a NameBinding<'a>| { + let usable = + this.is_accessible(binding.vis) && !is_disallowed_private_import(binding) || + binding.is_extern_crate(); // c.f. issue #37020 + if usable { Success(binding) } else { Failed(None) } + }; + + // Items and single imports are not shadowable. + if let Some(binding) = resolution.binding { + if !binding.is_glob_import() { + return check_usable(self, binding); + } + } + + // Check if a single import can still define the name. + match resolution.single_imports { + SingleImports::AtLeastOne => return Indeterminate, + SingleImports::MaybeOne(directive) if self.is_accessible(directive.vis.get()) => { + let module = match directive.imported_module.get() { + Some(module) => module, + None => return Indeterminate, + }; + let name = match directive.subclass { + SingleImport { source, .. } => source, + _ => unreachable!(), + }; + match self.resolve_name_in_module(module, name, ns, true, false, None) { + Failed(_) => {} + _ => return Indeterminate, } - }); + } + SingleImports::MaybeOne(_) | SingleImports::None => {}, + } + + let no_unresolved_invocations = + ignore_unresolved_invocations || module.unresolved_invocations.borrow().is_empty(); + match resolution.binding { + // In `MacroNS`, expanded bindings do not shadow (enforced in `try_define`). + Some(binding) if no_unresolved_invocations || ns == MacroNS => + return check_usable(self, binding), + None if no_unresolved_invocations => {} + _ => return Indeterminate, } // Check if the globs are determined for directive in module.globs.borrow().iter() { if self.is_accessible(directive.vis.get()) { if let Some(module) = directive.imported_module.get() { - let result = self.resolve_name_in_module(module, name, ns, true, None); + let result = self.resolve_name_in_module(module, name, ns, true, false, None); if let Indeterminate = result { return Indeterminate; } @@ -220,46 +237,14 @@ impl<'a> Resolver<'a> { Failed(None) } - // Returns Some(the resolution of the name), or None if the resolution depends - // on whether more globs can define the name. - fn try_result(&mut self, resolution: &NameResolution<'a>, ns: Namespace) - -> Option>> { - match resolution.binding { - Some(binding) if !binding.is_glob_import() => - return Some(Success(binding)), // Items and single imports are not shadowable. - _ => {} - }; - - // Check if a single import can still define the name. - match resolution.single_imports { - SingleImports::AtLeastOne => return Some(Indeterminate), - SingleImports::MaybeOne(directive) if self.is_accessible(directive.vis.get()) => { - let module = match directive.imported_module.get() { - Some(module) => module, - None => return Some(Indeterminate), - }; - let name = match directive.subclass { - SingleImport { source, .. } => source, - _ => unreachable!(), - }; - match self.resolve_name_in_module(module, name, ns, true, None) { - Failed(_) => {} - _ => return Some(Indeterminate), - } - } - SingleImports::MaybeOne(_) | SingleImports::None => {}, - } - - resolution.binding.map(Success) - } - // Add an import directive to the current module. pub fn add_import_directive(&mut self, module_path: Vec, subclass: ImportDirectiveSubclass<'a>, span: Span, id: NodeId, - vis: ty::Visibility) { + vis: ty::Visibility, + expansion: Mark) { let current_module = self.current_module; let directive = self.arenas.alloc_import_directive(ImportDirective { parent: current_module, @@ -269,15 +254,16 @@ impl<'a> Resolver<'a> { span: span, id: id, vis: Cell::new(vis), + expansion: expansion, }); self.indeterminate_imports.push(directive); match directive.subclass { SingleImport { target, .. } => { - for &ns in &[ValueNS, TypeNS] { - let mut resolution = self.resolution(current_module, target, ns).borrow_mut(); + self.per_ns(|this, ns| { + let mut resolution = this.resolution(current_module, target, ns).borrow_mut(); resolution.single_imports.add_directive(directive); - } + }); } // We don't add prelude imports to the globs since they only affect lexical scopes, // which are not relevant to import resolution. @@ -312,6 +298,7 @@ impl<'a> Resolver<'a> { }, span: directive.span, vis: vis, + expansion: directive.expansion, } } @@ -324,28 +311,26 @@ impl<'a> Resolver<'a> { self.update_resolution(module, name, ns, |this, resolution| { if let Some(old_binding) = resolution.binding { if binding.is_glob_import() { - if !this.new_import_semantics || !old_binding.is_glob_import() { + if !this.new_import_semantics { resolution.duplicate_globs.push(binding); + } else if !old_binding.is_glob_import() && + !(ns == MacroNS && old_binding.expansion != Mark::root()) { } else if binding.def() != old_binding.def() { - resolution.binding = Some(this.arenas.alloc_name_binding(NameBinding { - kind: NameBindingKind::Ambiguity { - b1: old_binding, - b2: binding, - }, - vis: if old_binding.vis.is_at_least(binding.vis, this) { - old_binding.vis - } else { - binding.vis - }, - span: old_binding.span, - })); + resolution.binding = Some(this.ambiguity(old_binding, binding)); } else if !old_binding.vis.is_at_least(binding.vis, this) { // We are glob-importing the same item but with greater visibility. resolution.binding = Some(binding); } } else if old_binding.is_glob_import() { - resolution.duplicate_globs.push(old_binding); - resolution.binding = Some(binding); + if !this.new_import_semantics { + resolution.duplicate_globs.push(old_binding); + resolution.binding = Some(binding); + } else if ns == MacroNS && binding.expansion != Mark::root() && + binding.def() != old_binding.def() { + resolution.binding = Some(this.ambiguity(binding, old_binding)); + } else { + resolution.binding = Some(binding); + } } else { return Err(old_binding); } @@ -357,6 +342,16 @@ impl<'a> Resolver<'a> { }) } + pub fn ambiguity(&mut self, b1: &'a NameBinding<'a>, b2: &'a NameBinding<'a>) + -> &'a NameBinding<'a> { + self.arenas.alloc_name_binding(NameBinding { + kind: NameBindingKind::Ambiguity { b1: b1, b2: b2 }, + vis: if b1.vis.is_at_least(b2.vis, self) { b1.vis } else { b2.vis }, + span: b1.span, + expansion: Mark::root(), + }) + } + // Use `f` to mutate the resolution of the name in the module. // If the resolution becomes a success, define it in the module's glob importers. fn update_resolution(&mut self, module: Module<'a>, name: Name, ns: Namespace, f: F) -> T @@ -393,10 +388,22 @@ impl<'a> Resolver<'a> { t } + + // Define a "dummy" resolution containing a Def::Err as a placeholder for a + // failed resolution + fn import_dummy_binding(&mut self, directive: &'a ImportDirective<'a>) { + if let SingleImport { target, .. } = directive.subclass { + let dummy_binding = self.dummy_binding; + let dummy_binding = self.import(dummy_binding, directive); + self.per_ns(|this, ns| { + let _ = this.try_define(directive.parent, target, ns, dummy_binding.clone()); + }); + } + } } -struct ImportResolver<'a, 'b: 'a> { - resolver: &'a mut Resolver<'b>, +pub struct ImportResolver<'a, 'b: 'a> { + pub resolver: &'a mut Resolver<'b>, } impl<'a, 'b: 'a> ::std::ops::Deref for ImportResolver<'a, 'b> { @@ -429,28 +436,21 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { /// Resolves all imports for the crate. This method performs the fixed- /// point iteration. - fn resolve_imports(&mut self) { - let mut i = 0; + pub fn resolve_imports(&mut self) { let mut prev_num_indeterminates = self.indeterminate_imports.len() + 1; - while self.indeterminate_imports.len() < prev_num_indeterminates { prev_num_indeterminates = self.indeterminate_imports.len(); - debug!("(resolving imports) iteration {}, {} imports left", i, prev_num_indeterminates); - - let mut imports = Vec::new(); - ::std::mem::swap(&mut imports, &mut self.indeterminate_imports); - - for import in imports { + for import in mem::replace(&mut self.indeterminate_imports, Vec::new()) { match self.resolve_import(&import) { Failed(_) => self.determined_imports.push(import), Indeterminate => self.indeterminate_imports.push(import), Success(()) => self.determined_imports.push(import), } } - - i += 1; } + } + pub fn finalize_imports(&mut self) { for module in self.arenas.local_modules().iter() { self.finalize_resolutions_in(module); } @@ -484,17 +484,6 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } } - // Define a "dummy" resolution containing a Def::Err as a placeholder for a - // failed resolution - fn import_dummy_binding(&mut self, directive: &'b ImportDirective<'b>) { - if let SingleImport { target, .. } = directive.subclass { - let dummy_binding = self.dummy_binding; - let dummy_binding = self.import(dummy_binding, directive); - let _ = self.try_define(directive.parent, target, ValueNS, dummy_binding.clone()); - let _ = self.try_define(directive.parent, target, TypeNS, dummy_binding); - } - } - /// Attempts to resolve the given import. The return value indicates /// failure if we're certain the name does not exist, indeterminate if we /// don't know whether the name exists at the moment due to other @@ -526,9 +515,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { }; directive.imported_module.set(Some(module)); - let (source, target, value_result, type_result) = match directive.subclass { - SingleImport { source, target, ref value_result, ref type_result } => - (source, target, value_result, type_result), + let (source, target, result) = match directive.subclass { + SingleImport { source, target, ref result } => (source, target, result), GlobImport { .. } => { self.resolve_glob_import(directive); return Success(()); @@ -537,46 +525,45 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { }; let mut indeterminate = false; - for &(ns, result) in &[(ValueNS, value_result), (TypeNS, type_result)] { - if let Err(Undetermined) = result.get() { - result.set({ - match self.resolve_name_in_module(module, source, ns, false, None) { + self.per_ns(|this, ns| { + if let Err(Undetermined) = result[ns].get() { + result[ns].set({ + match this.resolve_name_in_module(module, source, ns, false, false, None) { Success(binding) => Ok(binding), Indeterminate => Err(Undetermined), Failed(_) => Err(Determined), } }); } else { - continue + return }; - match result.get() { + match result[ns].get() { Err(Undetermined) => indeterminate = true, Err(Determined) => { - self.update_resolution(directive.parent, target, ns, |_, resolution| { + this.update_resolution(directive.parent, target, ns, |_, resolution| { resolution.single_imports.directive_failed() }); } Ok(binding) if !binding.is_importable() => { let msg = format!("`{}` is not directly importable", target); - struct_span_err!(self.session, directive.span, E0253, "{}", &msg) + struct_span_err!(this.session, directive.span, E0253, "{}", &msg) .span_label(directive.span, &format!("cannot be imported directly")) .emit(); // Do not import this illegal binding. Import a dummy binding and pretend // everything is fine - self.import_dummy_binding(directive); - return Success(()); + this.import_dummy_binding(directive); } Ok(binding) => { - let imported_binding = self.import(binding, directive); - let conflict = self.try_define(directive.parent, target, ns, imported_binding); + let imported_binding = this.import(binding, directive); + let conflict = this.try_define(directive.parent, target, ns, imported_binding); if let Err(old_binding) = conflict { - let binding = &self.import(binding, directive); - self.report_conflict(directive.parent, target, ns, binding, old_binding); + let binding = &this.import(binding, directive); + this.report_conflict(directive.parent, target, ns, binding, old_binding); } } } - } + }); if indeterminate { Indeterminate } else { Success(()) } } @@ -604,9 +591,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { }, }; - let (name, value_result, type_result) = match directive.subclass { - SingleImport { source, ref value_result, ref type_result, .. } => - (source, value_result.get(), type_result.get()), + let (name, result) = match directive.subclass { + SingleImport { source, ref result, .. } => (source, result), GlobImport { .. } if module.def_id() == directive.parent.def_id() => { // Importing a module into itself is not allowed. let msg = "Cannot glob-import a module into itself.".into(); @@ -624,21 +610,27 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { _ => unreachable!(), }; - for &(ns, result) in &[(ValueNS, value_result), (TypeNS, type_result)] { - if let Ok(binding) = result { - if self.record_use(name, ns, binding, directive.span) { - self.resolution(module, name, ns).borrow_mut().binding = - Some(self.dummy_binding); + let mut all_ns_err = true; + self.per_ns(|this, ns| { + if let Ok(binding) = result[ns].get() { + all_ns_err = false; + if this.record_use(name, ns, binding, directive.span) { + this.resolution(module, name, ns).borrow_mut().binding = + Some(this.dummy_binding); } } - } + }); - if value_result.is_err() && type_result.is_err() { - let (value_result, type_result); - value_result = self.resolve_name_in_module(module, name, ValueNS, false, Some(span)); - type_result = self.resolve_name_in_module(module, name, TypeNS, false, Some(span)); + if all_ns_err { + let mut all_ns_failed = true; + self.per_ns(|this, ns| { + match this.resolve_name_in_module(module, name, ns, false, false, Some(span)) { + Success(_) => all_ns_failed = false, + _ => {} + } + }); - return if let (Failed(_), Failed(_)) = (value_result, type_result) { + return if all_ns_failed { let resolutions = module.resolutions.borrow(); let names = resolutions.iter().filter_map(|(&(ref n, _), resolution)| { if *n == name { return None; } // Never suggest the same name @@ -666,64 +658,49 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } } - let session = self.session; - let reexport_error = || { - let msg = format!("`{}` is private, and cannot be reexported", name); - let note_msg = - format!("consider marking `{}` as `pub` in the imported module", name); - struct_span_err!(session, directive.span, E0364, "{}", &msg) - .span_note(directive.span, ¬e_msg) - .emit(); - }; - - let extern_crate_lint = || { - let msg = format!("extern crate `{}` is private, and cannot be reexported \ - (error E0364), consider declaring with `pub`", - name); - session.add_lint(PRIVATE_IN_PUBLIC, directive.id, directive.span, msg); - }; - - match (value_result, type_result) { - // All namespaces must be re-exported with extra visibility for an error to occur. - (Ok(value_binding), Ok(type_binding)) => { + let mut reexport_error = None; + let mut any_successful_reexport = false; + self.per_ns(|this, ns| { + if let Ok(binding) = result[ns].get() { let vis = directive.vis.get(); - if !value_binding.pseudo_vis().is_at_least(vis, self) && - !type_binding.pseudo_vis().is_at_least(vis, self) { - reexport_error(); - } else if type_binding.is_extern_crate() && - !type_binding.vis.is_at_least(vis, self) { - extern_crate_lint(); - } - } - - (Ok(binding), _) if !binding.pseudo_vis().is_at_least(directive.vis.get(), self) => { - reexport_error(); - } - - (_, Ok(binding)) if !binding.pseudo_vis().is_at_least(directive.vis.get(), self) => { - if binding.is_extern_crate() { - extern_crate_lint(); + if !binding.pseudo_vis().is_at_least(vis, this) { + reexport_error = Some((ns, binding)); } else { - struct_span_err!(self.session, directive.span, E0365, - "`{}` is private, and cannot be reexported", name) - .span_label(directive.span, &format!("reexport of private `{}`", name)) - .note(&format!("consider declaring type or module `{}` with `pub`", name)) - .emit(); + any_successful_reexport = true; } } + }); - _ => {} + // All namespaces must be re-exported with extra visibility for an error to occur. + if !any_successful_reexport { + let (ns, binding) = reexport_error.unwrap(); + if ns == TypeNS && binding.is_extern_crate() { + let msg = format!("extern crate `{}` is private, and cannot be reexported \ + (error E0364), consider declaring with `pub`", + name); + self.session.add_lint(PRIVATE_IN_PUBLIC, directive.id, directive.span, msg); + } else if ns == TypeNS { + struct_span_err!(self.session, directive.span, E0365, + "`{}` is private, and cannot be reexported", name) + .span_label(directive.span, &format!("reexport of private `{}`", name)) + .note(&format!("consider declaring type or module `{}` with `pub`", name)) + .emit(); + } else { + let msg = format!("`{}` is private, and cannot be reexported", name); + let note_msg = + format!("consider marking `{}` as `pub` in the imported module", name); + struct_span_err!(self.session, directive.span, E0364, "{}", &msg) + .span_note(directive.span, ¬e_msg) + .emit(); + } } // Record what this import resolves to for later uses in documentation, // this may resolve to either a value or a type, but for documentation // purposes it's good enough to just favor one over the other. - let def = match type_result.ok().map(NameBinding::def) { - Some(def) => def, - None => value_result.ok().map(NameBinding::def).unwrap(), - }; - let path_resolution = PathResolution::new(def); - self.def_map.insert(directive.id, path_resolution); + self.per_ns(|this, ns| if let Some(binding) = result[ns].get().ok() { + this.def_map.entry(directive.id).or_insert(PathResolution::new(binding.def())); + }); debug!("(resolving single import) successfully resolved import"); return Success(()); diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index ab5bbea07a30..778f01841416 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -286,7 +286,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { scope: NodeId) -> Option { if let Some(ident) = field.ident { let qualname = format!("::{}::{}", self.tcx.node_path_str(scope), ident); - let typ = self.tcx.tables().node_types.get(&field.id).unwrap().to_string(); + let def_id = self.tcx.map.local_def_id(field.id); + let typ = self.tcx.item_type(def_id).to_string(); let sub_span = self.span_utils.sub_span_before_token(field.span, token::Colon); filter!(self.span_utils, sub_span, field.span, None); Some(VariableData { @@ -535,7 +536,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let def_id = if decl_id.is_local() { let ti = self.tcx.associated_item(decl_id); self.tcx.associated_items(ti.container.id()) - .find(|item| item.name == ti.name && item.has_value) + .find(|item| item.name == ti.name && item.defaultness.has_value()) .map(|item| item.def_id) } else { None diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs index 031b9a6a5aa5..9ec764b82f86 100644 --- a/src/librustc_save_analysis/span_utils.rs +++ b/src/librustc_save_analysis/span_utils.rs @@ -177,25 +177,44 @@ impl<'a> SpanUtils<'a> { } // Return the span for the last ident before a `<` and outside any - // brackets, or the last span. + // angle brackets, or the last span. pub fn sub_span_for_type_name(&self, span: Span) -> Option { let mut toks = self.retokenise_span(span); let mut prev = toks.real_token(); let mut result = None; + + // We keep track of the following two counts - the depth of nesting of + // angle brackets, and the depth of nesting of square brackets. For the + // angle bracket count, we only count tokens which occur outside of any + // square brackets (i.e. bracket_count == 0). The intutition here is + // that we want to count angle brackets in the type, but not any which + // could be in expression context (because these could mean 'less than', + // etc.). + let mut angle_count = 0; let mut bracket_count = 0; loop { let next = toks.real_token(); - if (next.tok == token::Lt || next.tok == token::Colon) && bracket_count == 0 && + if (next.tok == token::Lt || next.tok == token::Colon) && + angle_count == 0 && + bracket_count == 0 && prev.tok.is_ident() { result = Some(prev.sp); } + if bracket_count == 0 { + angle_count += match prev.tok { + token::Lt => 1, + token::Gt => -1, + token::BinOp(token::Shl) => 2, + token::BinOp(token::Shr) => -2, + _ => 0, + }; + } + bracket_count += match prev.tok { - token::Lt => 1, - token::Gt => -1, - token::BinOp(token::Shl) => 2, - token::BinOp(token::Shr) => -2, + token::OpenDelim(token::Bracket) => 1, + token::CloseDelim(token::Bracket) => -1, _ => 0, }; @@ -204,7 +223,7 @@ impl<'a> SpanUtils<'a> { } prev = next; } - if bracket_count != 0 { + if angle_count != 0 || bracket_count != 0 { let loc = self.sess.codemap().lookup_char_pos(span.lo); span_bug!(span, "Mis-counted brackets when breaking path? Parsing '{}' \ @@ -213,7 +232,7 @@ impl<'a> SpanUtils<'a> { loc.file.name, loc.line); } - if result.is_none() && prev.tok.is_ident() && bracket_count == 0 { + if result.is_none() && prev.tok.is_ident() && angle_count == 0 { return self.make_sub_span(span, Some(prev.sp)); } self.make_sub_span(span, result) @@ -222,19 +241,20 @@ impl<'a> SpanUtils<'a> { // Reparse span and return an owned vector of sub spans of the first limit // identifier tokens in the given nesting level. // example with Foo, Bar> - // Nesting = 0: all idents outside of brackets: [Foo] - // Nesting = 1: idents within one level of brackets: [Bar, Bar] + // Nesting = 0: all idents outside of angle brackets: [Foo] + // Nesting = 1: idents within one level of angle brackets: [Bar, Bar] pub fn spans_with_brackets(&self, span: Span, nesting: isize, limit: isize) -> Vec { let mut result: Vec = vec![]; let mut toks = self.retokenise_span(span); // We keep track of how many brackets we're nested in + let mut angle_count: isize = 0; let mut bracket_count: isize = 0; let mut found_ufcs_sep = false; loop { let ts = toks.real_token(); if ts.tok == token::Eof { - if bracket_count != 0 { + if angle_count != 0 || bracket_count != 0 { if generated_code(span) { return vec![]; } @@ -252,6 +272,14 @@ impl<'a> SpanUtils<'a> { return result; } bracket_count += match ts.tok { + token::OpenDelim(token::Bracket) => 1, + token::CloseDelim(token::Bracket) => -1, + _ => 0, + }; + if bracket_count > 0 { + continue; + } + angle_count += match ts.tok { token::Lt => 1, token::Gt => -1, token::BinOp(token::Shl) => 2, @@ -269,11 +297,11 @@ impl<'a> SpanUtils<'a> { // path, trying to pull out the non-nested idents (e.g., avoiding 'a // in `>::C`). So we end up with a span for `B>::C` from // the start of the first ident to the end of the path. - if !found_ufcs_sep && bracket_count == -1 { + if !found_ufcs_sep && angle_count == -1 { found_ufcs_sep = true; - bracket_count += 1; + angle_count += 1; } - if ts.tok.is_ident() && bracket_count == nesting { + if ts.tok.is_ident() && angle_count == nesting { result.push(self.make_sub_span(span, Some(ts.sp)).unwrap()); } } diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml index 38f9e7ab0c51..796a80d08094 100644 --- a/src/librustc_trans/Cargo.toml +++ b/src/librustc_trans/Cargo.toml @@ -16,6 +16,7 @@ graphviz = { path = "../libgraphviz" } log = { path = "../liblog" } rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } +rustc_bitflags = { path = "../librustc_bitflags" } rustc_const_eval = { path = "../librustc_const_eval" } rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 0a5b013c79ac..07f53466b497 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use llvm::{self, ValueRef, Integer, Pointer, Float, Double, Struct, Array, Vector}; +use llvm::{self, ValueRef, Integer, Pointer, Float, Double, Struct, Array, Vector, AttributePlace}; use base; use build::AllocaFcx; use common::{type_is_fat_ptr, BlockAndBuilder, C_uint}; @@ -24,6 +24,7 @@ use cabi_s390x; use cabi_mips; use cabi_mips64; use cabi_asmjs; +use cabi_msp430; use machine::{llalign_of_min, llsize_of, llsize_of_alloc}; use type_::Type; use type_of; @@ -49,6 +50,93 @@ enum ArgKind { Ignore, } +// Hack to disable non_upper_case_globals only for the bitflags! and not for the rest +// of this module +pub use self::attr_impl::ArgAttribute; + +#[allow(non_upper_case_globals)] +mod attr_impl { + // The subset of llvm::Attribute needed for arguments, packed into a bitfield. + bitflags! { + #[derive(Default, Debug)] + flags ArgAttribute : u8 { + const ByVal = 1 << 0, + const NoAlias = 1 << 1, + const NoCapture = 1 << 2, + const NonNull = 1 << 3, + const ReadOnly = 1 << 4, + const SExt = 1 << 5, + const StructRet = 1 << 6, + const ZExt = 1 << 7, + } + } +} + +macro_rules! for_each_kind { + ($flags: ident, $f: ident, $($kind: ident),+) => ({ + $(if $flags.contains(ArgAttribute::$kind) { $f(llvm::Attribute::$kind) })+ + }) +} + +impl ArgAttribute { + fn for_each_kind(&self, mut f: F) where F: FnMut(llvm::Attribute) { + for_each_kind!(self, f, + ByVal, NoAlias, NoCapture, NonNull, ReadOnly, SExt, StructRet, ZExt) + } +} + +/// A compact representation of LLVM attributes (at least those relevant for this module) +/// that can be manipulated without interacting with LLVM's Attribute machinery. +#[derive(Copy, Clone, Debug, Default)] +pub struct ArgAttributes { + regular: ArgAttribute, + dereferenceable_bytes: u64, +} + +impl ArgAttributes { + pub fn set(&mut self, attr: ArgAttribute) -> &mut Self { + self.regular = self.regular | attr; + self + } + + pub fn unset(&mut self, attr: ArgAttribute) -> &mut Self { + self.regular = self.regular - attr; + self + } + + pub fn set_dereferenceable(&mut self, bytes: u64) -> &mut Self { + self.dereferenceable_bytes = bytes; + self + } + + pub fn unset_dereferenceable(&mut self) -> &mut Self { + self.dereferenceable_bytes = 0; + self + } + + pub fn apply_llfn(&self, idx: AttributePlace, llfn: ValueRef) { + unsafe { + self.regular.for_each_kind(|attr| attr.apply_llfn(idx, llfn)); + if self.dereferenceable_bytes != 0 { + llvm::LLVMRustAddDereferenceableAttr(llfn, + idx.as_uint(), + self.dereferenceable_bytes); + } + } + } + + pub fn apply_callsite(&self, idx: AttributePlace, callsite: ValueRef) { + unsafe { + self.regular.for_each_kind(|attr| attr.apply_callsite(idx, callsite)); + if self.dereferenceable_bytes != 0 { + llvm::LLVMRustAddDereferenceableCallSiteAttr(callsite, + idx.as_uint(), + self.dereferenceable_bytes); + } + } + } +} + /// Information about how a specific C type /// should be passed to or returned from a function /// @@ -80,7 +168,7 @@ pub struct ArgType { /// Dummy argument, which is emitted before the real argument pub pad: Option, /// LLVM attributes of argument - pub attrs: llvm::Attributes + pub attrs: ArgAttributes } impl ArgType { @@ -92,7 +180,7 @@ impl ArgType { signedness: None, cast: None, pad: None, - attrs: llvm::Attributes::default() + attrs: ArgAttributes::default() } } @@ -100,15 +188,15 @@ impl ArgType { assert_eq!(self.kind, ArgKind::Direct); // Wipe old attributes, likely not valid through indirection. - self.attrs = llvm::Attributes::default(); + self.attrs = ArgAttributes::default(); let llarg_sz = llsize_of_alloc(ccx, self.ty); // For non-immediate arguments the callee gets its own copy of // the value on the stack, so there are no aliases. It's also // program-invisible so can't possibly capture - self.attrs.set(llvm::Attribute::NoAlias) - .set(llvm::Attribute::NoCapture) + self.attrs.set(ArgAttribute::NoAlias) + .set(ArgAttribute::NoCapture) .set_dereferenceable(llarg_sz); self.kind = ArgKind::Indirect; @@ -124,9 +212,9 @@ impl ArgType { if let Some(signed) = self.signedness { if self.ty.int_width() < bits { self.attrs.set(if signed { - llvm::Attribute::SExt + ArgAttribute::SExt } else { - llvm::Attribute::ZExt + ArgAttribute::ZExt }); } } @@ -273,10 +361,10 @@ impl FnType { C => llvm::CCallConv, Win64 => llvm::X86_64_Win64, SysV64 => llvm::X86_64_SysV, + Aapcs => llvm::ArmAapcsCallConv, // These API constants ought to be more specific... Cdecl => llvm::CCallConv, - Aapcs => llvm::CCallConv, }; let mut inputs = &sig.inputs[..]; @@ -314,7 +402,7 @@ impl FnType { if ty.is_bool() { let llty = Type::i1(ccx); let mut arg = ArgType::new(llty, llty); - arg.attrs.set(llvm::Attribute::ZExt); + arg.attrs.set(ArgAttribute::ZExt); arg } else { let mut arg = ArgType::new(type_of::type_of(ccx, ty), @@ -349,7 +437,7 @@ impl FnType { if let ty::TyBox(_) = ret_ty.sty { // `Box` pointer return values never alias because ownership // is transferred - ret.attrs.set(llvm::Attribute::NoAlias); + ret.attrs.set(ArgAttribute::NoAlias); } // We can also mark the return value as `dereferenceable` in certain cases @@ -371,7 +459,7 @@ impl FnType { let rust_ptr_attrs = |ty: Ty<'tcx>, arg: &mut ArgType| match ty.sty { // `Box` pointer parameters never alias because ownership is transferred ty::TyBox(inner) => { - arg.attrs.set(llvm::Attribute::NoAlias); + arg.attrs.set(ArgAttribute::NoAlias); Some(inner) } @@ -386,18 +474,18 @@ impl FnType { let interior_unsafe = mt.ty.type_contents(ccx.tcx()).interior_unsafe(); if mt.mutbl != hir::MutMutable && !interior_unsafe { - arg.attrs.set(llvm::Attribute::NoAlias); + arg.attrs.set(ArgAttribute::NoAlias); } if mt.mutbl == hir::MutImmutable && !interior_unsafe { - arg.attrs.set(llvm::Attribute::ReadOnly); + arg.attrs.set(ArgAttribute::ReadOnly); } // When a reference in an argument has no named lifetime, it's // impossible for that reference to escape this function // (returned or stored beyond the call by a closure). if let ReLateBound(_, BrAnon(_)) = *b { - arg.attrs.set(llvm::Attribute::NoCapture); + arg.attrs.set(ArgAttribute::NoCapture); } Some(mt.ty) @@ -417,9 +505,9 @@ impl FnType { let mut info = ArgType::new(original_tys[1], sizing_tys[1]); if let Some(inner) = rust_ptr_attrs(ty, &mut data) { - data.attrs.set(llvm::Attribute::NonNull); + data.attrs.set(ArgAttribute::NonNull); if ccx.tcx().struct_tail(inner).is_trait() { - info.attrs.set(llvm::Attribute::NonNull); + info.attrs.set(ArgAttribute::NonNull); } } args.push(data); @@ -490,7 +578,7 @@ impl FnType { fixup(arg); } if self.ret.is_indirect() { - self.ret.attrs.set(llvm::Attribute::StructRet); + self.ret.attrs.set(ArgAttribute::StructRet); } return; } @@ -520,11 +608,12 @@ impl FnType { "s390x" => cabi_s390x::compute_abi_info(ccx, self), "asmjs" => cabi_asmjs::compute_abi_info(ccx, self), "wasm32" => cabi_asmjs::compute_abi_info(ccx, self), + "msp430" => cabi_msp430::compute_abi_info(ccx, self), a => ccx.sess().fatal(&format!("unrecognized arch \"{}\" in target specification", a)) } if self.ret.is_indirect() { - self.ret.attrs.set(llvm::Attribute::StructRet); + self.ret.attrs.set(ArgAttribute::StructRet); } } diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index 4d3361c1873f..c3340281d073 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -108,9 +108,9 @@ fn compute_fields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, }).collect::>() }, ty::TyTuple(fields) => fields.to_vec(), - ty::TyClosure(_, substs) => { + ty::TyClosure(def_id, substs) => { if variant_index > 0 { bug!("{} is a closure, which only has one variant", t);} - substs.upvar_tys.to_vec() + substs.upvar_tys(def_id, cx.tcx()).collect() }, _ => bug!("{} is not a type that can have fields.", t) } @@ -245,8 +245,6 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // So we start with the discriminant, pad it up to the alignment with // more of its own type, then use alignment-sized ints to get the rest // of the size. - // - // FIXME #10604: this breaks when vector types are present. let size = size.bytes(); let align = align.abi(); let discr_ty = Type::from_integer(cx, discr); diff --git a/src/librustc_trans/attributes.rs b/src/librustc_trans/attributes.rs index 62eac35e0abd..f1e90419a49e 100644 --- a/src/librustc_trans/attributes.rs +++ b/src/librustc_trans/attributes.rs @@ -24,10 +24,9 @@ pub fn inline(val: ValueRef, inline: InlineAttr) { Always => Attribute::AlwaysInline.apply_llfn(Function, val), Never => Attribute::NoInline.apply_llfn(Function, val), None => { - let attr = Attribute::InlineHint | - Attribute::AlwaysInline | - Attribute::NoInline; - attr.unapply_llfn(Function, val) + Attribute::InlineHint.unapply_llfn(Function, val); + Attribute::AlwaysInline.unapply_llfn(Function, val); + Attribute::NoInline.unapply_llfn(Function, val); }, }; } diff --git a/src/librustc_trans/back/archive.rs b/src/librustc_trans/back/archive.rs index e063209799f1..df8dd7750ae0 100644 --- a/src/librustc_trans/back/archive.rs +++ b/src/librustc_trans/back/archive.rs @@ -145,8 +145,11 @@ impl<'a> ArchiveBuilder<'a> { /// /// This ignores adding the bytecode from the rlib, and if LTO is enabled /// then the object file also isn't added. - pub fn add_rlib(&mut self, rlib: &Path, name: &str, lto: bool) - -> io::Result<()> { + pub fn add_rlib(&mut self, + rlib: &Path, + name: &str, + lto: bool, + skip_objects: bool) -> io::Result<()> { // Ignoring obj file starting with the crate name // as simple comparison is not enough - there // might be also an extra name suffix @@ -159,9 +162,23 @@ impl<'a> ArchiveBuilder<'a> { self.config.sess.cstore.metadata_filename().to_owned(); self.add_archive(rlib, move |fname: &str| { - let skip_obj = lto && fname.starts_with(&obj_start) - && fname.ends_with(".o"); - skip_obj || fname.ends_with(bc_ext) || fname == metadata_filename + if fname.ends_with(bc_ext) || fname == metadata_filename { + return true + } + + // Don't include Rust objects if LTO is enabled + if lto && fname.starts_with(&obj_start) && fname.ends_with(".o") { + return true + } + + // Otherwise if this is *not* a rust object and we're skipping + // objects then skip this file + if skip_objects && (!fname.starts_with(&obj_start) || !fname.ends_with(".o")) { + return true + } + + // ok, don't skip this + return false }) } diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index ad8e0c1ee59f..95d63311ee6e 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -19,7 +19,7 @@ use session::config::{OutputFilenames, Input, OutputType}; use session::filesearch; use session::search_paths::PathKind; use session::Session; -use middle::cstore::{self, LinkMeta}; +use middle::cstore::{self, LinkMeta, NativeLibrary}; use middle::cstore::{LinkagePreference, NativeLibraryKind}; use middle::dependency_format::Linkage; use CrateTranslation; @@ -43,6 +43,7 @@ use std::process::Command; use std::str; use flate; use syntax::ast; +use syntax::attr; use syntax_pos::Span; // RLIB LLVM-BYTECODE OBJECT LAYOUT @@ -406,12 +407,29 @@ fn link_rlib<'a>(sess: &'a Session, ab.add_file(obj); } - for (l, kind) in sess.cstore.used_libraries() { - match kind { - NativeLibraryKind::NativeStatic => ab.add_native_library(&l), + // Note that in this loop we are ignoring the value of `lib.cfg`. That is, + // we may not be configured to actually include a static library if we're + // adding it here. That's because later when we consume this rlib we'll + // decide whether we actually needed the static library or not. + // + // To do this "correctly" we'd need to keep track of which libraries added + // which object files to the archive. We don't do that here, however. The + // #[link(cfg(..))] feature is unstable, though, and only intended to get + // liblibc working. In that sense the check below just indicates that if + // there are any libraries we want to omit object files for at link time we + // just exclude all custom object files. + // + // Eventually if we want to stabilize or flesh out the #[link(cfg(..))] + // feature then we'll need to figure out how to record what objects were + // loaded from the libraries found here and then encode that into the + // metadata of the rlib we're generating somehow. + for lib in sess.cstore.used_libraries() { + match lib.kind { + NativeLibraryKind::NativeStatic => {} NativeLibraryKind::NativeFramework | - NativeLibraryKind::NativeUnknown => {} + NativeLibraryKind::NativeUnknown => continue, } + ab.add_native_library(&lib.name); } // After adding all files to the archive, we need to update the @@ -578,10 +596,28 @@ fn link_staticlib(sess: &Session, objects: &[PathBuf], out_filename: &Path, each_linked_rlib(sess, &mut |cnum, path| { let name = sess.cstore.crate_name(cnum); - ab.add_rlib(path, &name, sess.lto()).unwrap(); - let native_libs = sess.cstore.native_libraries(cnum); - all_native_libs.extend(native_libs); + + // Here when we include the rlib into our staticlib we need to make a + // decision whether to include the extra object files along the way. + // These extra object files come from statically included native + // libraries, but they may be cfg'd away with #[link(cfg(..))]. + // + // This unstable feature, though, only needs liblibc to work. The only + // use case there is where musl is statically included in liblibc.rlib, + // so if we don't want the included version we just need to skip it. As + // a result the logic here is that if *any* linked library is cfg'd away + // we just skip all object files. + // + // Clearly this is not sufficient for a general purpose feature, and + // we'd want to read from the library's metadata to determine which + // object files come from where and selectively skip them. + let skip_object_files = native_libs.iter().any(|lib| { + lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib) + }); + ab.add_rlib(path, &name, sess.lto(), skip_object_files).unwrap(); + + all_native_libs.extend(sess.cstore.native_libraries(cnum)); }); ab.update_symbols(); @@ -594,13 +630,14 @@ fn link_staticlib(sess: &Session, objects: &[PathBuf], out_filename: &Path, platforms, and so may need to be preserved"); } - for &(kind, ref lib) in &all_native_libs { - let name = match kind { - NativeLibraryKind::NativeStatic => "static library", + for lib in all_native_libs.iter().filter(|l| relevant_lib(sess, l)) { + let name = match lib.kind { NativeLibraryKind::NativeUnknown => "library", NativeLibraryKind::NativeFramework => "framework", + // These are included, no need to print them + NativeLibraryKind::NativeStatic => continue, }; - sess.note_without_error(&format!("{}: {}", name, *lib)); + sess.note_without_error(&format!("{}: {}", name, lib.name)); } } @@ -876,14 +913,12 @@ fn add_local_native_libraries(cmd: &mut Linker, sess: &Session) { } }); - let libs = sess.cstore.used_libraries(); - - let staticlibs = libs.iter().filter_map(|&(ref l, kind)| { - if kind == NativeLibraryKind::NativeStatic {Some(l)} else {None} - }); - let others = libs.iter().filter(|&&(_, kind)| { - kind != NativeLibraryKind::NativeStatic + let pair = sess.cstore.used_libraries().into_iter().filter(|l| { + relevant_lib(sess, l) + }).partition(|lib| { + lib.kind == NativeLibraryKind::NativeStatic }); + let (staticlibs, others): (Vec<_>, Vec<_>) = pair; // Some platforms take hints about whether a library is static or dynamic. // For those that support this, we ensure we pass the option if the library @@ -899,15 +934,15 @@ fn add_local_native_libraries(cmd: &mut Linker, sess: &Session) { // don't otherwise explicitly reference them. This can occur for // libraries which are just providing bindings, libraries with generic // functions, etc. - cmd.link_whole_staticlib(l, &search_path); + cmd.link_whole_staticlib(&l.name, &search_path); } cmd.hint_dynamic(); - for &(ref l, kind) in others { - match kind { - NativeLibraryKind::NativeUnknown => cmd.link_dylib(l), - NativeLibraryKind::NativeFramework => cmd.link_framework(l), + for lib in others { + match lib.kind { + NativeLibraryKind::NativeUnknown => cmd.link_dylib(&lib.name), + NativeLibraryKind::NativeFramework => cmd.link_framework(&lib.name), NativeLibraryKind::NativeStatic => bug!(), } } @@ -1017,7 +1052,16 @@ fn add_upstream_rust_crates(cmd: &mut Linker, cnum: CrateNum) { let src = sess.cstore.used_crate_source(cnum); let cratepath = &src.rlib.unwrap().0; - if !sess.lto() && crate_type != config::CrateTypeDylib { + + // See the comment above in `link_staticlib` and `link_rlib` for why if + // there's a static library that's not relevant we skip all object + // files. + let native_libs = sess.cstore.native_libraries(cnum); + let skip_native = native_libs.iter().any(|lib| { + lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib) + }); + + if !sess.lto() && crate_type != config::CrateTypeDylib && !skip_native { cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath)); return } @@ -1029,33 +1073,42 @@ fn add_upstream_rust_crates(cmd: &mut Linker, time(sess.time_passes(), &format!("altering {}.rlib", name), || { let cfg = archive_config(sess, &dst, Some(cratepath)); let mut archive = ArchiveBuilder::new(cfg); - archive.remove_file(sess.cstore.metadata_filename()); archive.update_symbols(); let mut any_objects = false; for f in archive.src_files() { - if f.ends_with("bytecode.deflate") { + if f.ends_with("bytecode.deflate") || + f == sess.cstore.metadata_filename() { archive.remove_file(&f); continue } + let canonical = f.replace("-", "_"); let canonical_name = name.replace("-", "_"); + let is_rust_object = + canonical.starts_with(&canonical_name) && { + let num = &f[name.len()..f.len() - 2]; + num.len() > 0 && num[1..].parse::().is_ok() + }; + + // If we've been requested to skip all native object files + // (those not generated by the rust compiler) then we can skip + // this file. See above for why we may want to do this. + let skip_because_cfg_say_so = skip_native && !is_rust_object; + // If we're performing LTO and this is a rust-generated object // file, then we don't need the object file as it's part of the // LTO module. Note that `#![no_builtins]` is excluded from LTO, // though, so we let that object file slide. - if sess.lto() && - !sess.cstore.is_no_builtins(cnum) && - canonical.starts_with(&canonical_name) && - canonical.ends_with(".o") { - let num = &f[name.len()..f.len() - 2]; - if num.len() > 0 && num[1..].parse::().is_ok() { - archive.remove_file(&f); - continue - } + let skip_because_lto = sess.lto() && is_rust_object && + !sess.cstore.is_no_builtins(cnum); + + if skip_because_cfg_say_so || skip_because_lto { + archive.remove_file(&f); + } else { + any_objects = true; } - any_objects = true; } if !any_objects { @@ -1127,15 +1180,26 @@ fn add_upstream_native_libraries(cmd: &mut Linker, sess: &Session) { // the paths. let crates = sess.cstore.used_crates(LinkagePreference::RequireStatic); for (cnum, _) in crates { - let libs = sess.cstore.native_libraries(cnum); - for &(kind, ref lib) in &libs { - match kind { - NativeLibraryKind::NativeUnknown => cmd.link_dylib(lib), - NativeLibraryKind::NativeFramework => cmd.link_framework(lib), - NativeLibraryKind::NativeStatic => { - bug!("statics shouldn't be propagated"); - } + for lib in sess.cstore.native_libraries(cnum) { + if !relevant_lib(sess, &lib) { + continue + } + match lib.kind { + NativeLibraryKind::NativeUnknown => cmd.link_dylib(&lib.name), + NativeLibraryKind::NativeFramework => cmd.link_framework(&lib.name), + + // ignore statically included native libraries here as we've + // already included them when we included the rust library + // previously + NativeLibraryKind::NativeStatic => {} } } } } + +fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool { + match lib.cfg { + Some(ref cfg) => attr::cfg_matches(cfg, &sess.parse_sess, None), + None => true, + } +} diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index bf2a5d76c10d..0ad663f05b48 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -231,7 +231,7 @@ impl<'a, 'tcx> Instance<'tcx> { match key.disambiguated_data.data { DefPathData::TypeNs(_) | DefPathData::ValueNs(_) => { - instance_ty = scx.tcx().lookup_item_type(ty_def_id); + instance_ty = scx.tcx().item_type(ty_def_id); break; } _ => { @@ -248,7 +248,7 @@ impl<'a, 'tcx> Instance<'tcx> { // Erase regions because they may not be deterministic when hashed // and should not matter anyhow. - let instance_ty = scx.tcx().erase_regions(&instance_ty.ty); + let instance_ty = scx.tcx().erase_regions(&instance_ty); let hash = get_symbol_hash(scx, &def_path, instance_ty, Some(substs)); diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 9012914deeb0..01eea08c50bc 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -147,7 +147,16 @@ impl Emitter for SharedEmitter { // arise as some of intrinsics are converted into function calls // and nobody provides implementations those functions fn target_feature(sess: &Session) -> String { - format!("{},{}", sess.target.target.options.features, sess.opts.cg.target_feature) + let rustc_features = [ + "crt-static", + ]; + let requested_features = sess.opts.cg.target_feature.split(','); + let llvm_features = requested_features.filter(|f| { + !rustc_features.iter().any(|s| f.contains(s)) + }); + format!("{},{}", + sess.target.target.options.features, + llvm_features.collect::>().join(",")) } fn get_llvm_opt_level(optimize: config::OptLevel) -> llvm::CodeGenOptLevel { diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index d50669272f72..0c0b7fbf4afe 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -74,7 +74,7 @@ use monomorphize::{self, Instance}; use partitioning::{self, PartitioningStrategy, CodegenUnit}; use symbol_map::SymbolMap; use symbol_names_test; -use trans_item::TransItem; +use trans_item::{TransItem, DefPathBasedNames}; use type_::Type; use type_of; use value::Value; @@ -1003,34 +1003,49 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> { } } -/// Builds an LLVM function out of a source function. -/// -/// If the function closes over its environment a closure will be returned. -pub fn trans_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - llfndecl: ValueRef, - instance: Instance<'tcx>, - sig: &ty::FnSig<'tcx>, - abi: Abi) { - ccx.stats().n_closures.set(ccx.stats().n_closures.get() + 1); - - let _icx = push_ctxt("trans_closure"); - if !ccx.sess().no_landing_pads() { - attributes::emit_uwtable(llfndecl, true); - } +pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance<'tcx>) { + let _s = if ccx.sess().trans_stats() { + let mut instance_name = String::new(); + DefPathBasedNames::new(ccx.tcx(), true, true) + .push_def_path(instance.def, &mut instance_name); + Some(StatRecorder::new(ccx, instance_name)) + } else { + None + }; // this is an info! to allow collecting monomorphization statistics // and to allow finding the last function before LLVM aborts from // release builds. - info!("trans_closure(..., {})", instance); + info!("trans_instance({})", instance); - let fn_ty = FnType::new(ccx, abi, sig, &[]); + let _icx = push_ctxt("trans_instance"); + + let fn_ty = ccx.tcx().item_type(instance.def); + let fn_ty = ccx.tcx().erase_regions(&fn_ty); + let fn_ty = monomorphize::apply_param_substs(ccx.shared(), instance.substs, &fn_ty); + + let ty::BareFnTy { abi, ref sig, .. } = *common::ty_fn_ty(ccx, fn_ty); + let sig = ccx.tcx().erase_late_bound_regions_and_normalize(sig); + + let lldecl = match ccx.instances().borrow().get(&instance) { + Some(&val) => val, + None => bug!("Instance `{:?}` not already declared", instance) + }; + + ccx.stats().n_closures.set(ccx.stats().n_closures.get() + 1); + + if !ccx.sess().no_landing_pads() { + attributes::emit_uwtable(lldecl, true); + } + + let fn_ty = FnType::new(ccx, abi, &sig, &[]); let (arena, fcx): (TypedArena<_>, FunctionContext); arena = TypedArena::new(); fcx = FunctionContext::new(ccx, - llfndecl, + lldecl, fn_ty, - Some((instance, sig, abi)), + Some((instance, &sig, abi)), &arena); if fcx.mir.is_none() { @@ -1040,26 +1055,6 @@ pub fn trans_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, mir::trans_mir(&fcx); } -pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance<'tcx>) { - let _s = StatRecorder::new(ccx, ccx.tcx().item_path_str(instance.def)); - debug!("trans_instance(instance={:?})", instance); - let _icx = push_ctxt("trans_instance"); - - let fn_ty = ccx.tcx().lookup_item_type(instance.def).ty; - let fn_ty = ccx.tcx().erase_regions(&fn_ty); - let fn_ty = monomorphize::apply_param_substs(ccx.shared(), instance.substs, &fn_ty); - - let sig = ccx.tcx().erase_late_bound_regions_and_normalize(fn_ty.fn_sig()); - let abi = fn_ty.fn_abi(); - - let lldecl = match ccx.instances().borrow().get(&instance) { - Some(&val) => val, - None => bug!("Instance `{:?}` not already declared", instance) - }; - - trans_closure(ccx, lldecl, instance, &sig, abi); -} - pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId, substs: &'tcx Substs<'tcx>, @@ -1068,7 +1063,7 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, attributes::inline(llfndecl, attributes::InlineAttr::Hint); attributes::set_frame_pointer_elimination(ccx, llfndecl); - let ctor_ty = ccx.tcx().lookup_item_type(def_id).ty; + let ctor_ty = ccx.tcx().item_type(def_id); let ctor_ty = monomorphize::apply_param_substs(ccx.shared(), substs, &ctor_ty); let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&ctor_ty.fn_sig()); @@ -1514,7 +1509,7 @@ pub fn filter_reachable_ids(tcx: TyCtxt, reachable: NodeSet) -> NodeSet { hir_map::NodeImplItem(&hir::ImplItem { node: hir::ImplItemKind::Method(..), .. }) => { let def_id = tcx.map.local_def_id(id); - let generics = tcx.lookup_generics(def_id); + let generics = tcx.item_generics(def_id); let attributes = tcx.get_attrs(def_id); (generics.parent_types == 0 && generics.types.is_empty()) && // Functions marked with #[inline] are only ever translated @@ -1719,7 +1714,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let applicable = match sess.cstore.describe_def(def_id) { Some(Def::Static(..)) => true, Some(Def::Fn(_)) => { - shared_ccx.tcx().lookup_generics(def_id).types.is_empty() + shared_ccx.tcx().item_generics(def_id).types.is_empty() } _ => false }; diff --git a/src/librustc_trans/cabi_asmjs.rs b/src/librustc_trans/cabi_asmjs.rs index 3cbc378ab021..f410627400c3 100644 --- a/src/librustc_trans/cabi_asmjs.rs +++ b/src/librustc_trans/cabi_asmjs.rs @@ -10,8 +10,8 @@ #![allow(non_upper_case_globals)] -use llvm::{Struct, Array, Attribute}; -use abi::{FnType, ArgType}; +use llvm::{Struct, Array}; +use abi::{FnType, ArgType, ArgAttribute}; use context::CrateContext; // Data layout: e-p:32:32-i64:64-v128:32:128-n32-S128 @@ -39,7 +39,7 @@ fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) { if arg.ty.is_aggregate() { arg.make_indirect(ccx); - arg.attrs.set(Attribute::ByVal); + arg.attrs.set(ArgAttribute::ByVal); } } diff --git a/src/librustc_trans/cabi_msp430.rs b/src/librustc_trans/cabi_msp430.rs new file mode 100644 index 000000000000..aa90bb7ab753 --- /dev/null +++ b/src/librustc_trans/cabi_msp430.rs @@ -0,0 +1,59 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Reference: MSP430 Embedded Application Binary Interface +// http://www.ti.com/lit/an/slaa534/slaa534.pdf + +#![allow(non_upper_case_globals)] + +use llvm::Struct; + +use abi::{self, ArgType, FnType}; +use context::CrateContext; +use type_::Type; + +fn ty_size(ty: Type) -> usize { + abi::ty_size(ty, 2) +} + +// 3.5 Structures or Unions Passed and Returned by Reference +// +// "Structures (including classes) and unions larger than 32 bits are passed and +// returned by reference. To pass a structure or union by reference, the caller +// places its address in the appropriate location: either in a register or on +// the stack, according to its position in the argument list. (..)" +fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { + if ret.ty.kind() == Struct && ty_size(ret.ty) > 32 { + ret.make_indirect(ccx); + } else { + ret.extend_integer_width_to(16); + } +} + +fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) { + if arg.ty.kind() == Struct && ty_size(arg.ty) > 32 { + arg.make_indirect(ccx); + } else { + arg.extend_integer_width_to(16); + } +} + +pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { + if !fty.ret.is_ignore() { + classify_ret_ty(ccx, &mut fty.ret); + } + + for arg in &mut fty.args { + if arg.is_ignore() { + continue; + } + classify_arg_ty(ccx, arg); + } +} diff --git a/src/librustc_trans/cabi_x86.rs b/src/librustc_trans/cabi_x86.rs index b52231fa6b43..5377b49a2b44 100644 --- a/src/librustc_trans/cabi_x86.rs +++ b/src/librustc_trans/cabi_x86.rs @@ -9,7 +9,7 @@ // except according to those terms. use llvm::*; -use abi::FnType; +use abi::{ArgAttribute, FnType}; use type_::Type; use super::common::*; use super::machine::*; @@ -45,7 +45,7 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { if arg.is_ignore() { continue; } if arg.ty.kind() == Struct { arg.make_indirect(ccx); - arg.attrs.set(Attribute::ByVal); + arg.attrs.set(ArgAttribute::ByVal); } else { arg.extend_integer_width_to(32); } diff --git a/src/librustc_trans/cabi_x86_64.rs b/src/librustc_trans/cabi_x86_64.rs index 33990148c8b7..7f2fdbf000b6 100644 --- a/src/librustc_trans/cabi_x86_64.rs +++ b/src/librustc_trans/cabi_x86_64.rs @@ -15,8 +15,8 @@ use self::RegClass::*; use llvm::{Integer, Pointer, Float, Double}; -use llvm::{Struct, Array, Attribute, Vector}; -use abi::{self, ArgType, FnType}; +use llvm::{Struct, Array, Vector}; +use abi::{self, ArgType, ArgAttribute, FnType}; use context::CrateContext; use type_::Type; @@ -334,7 +334,7 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { fn x86_64_ty(ccx: &CrateContext, arg: &mut ArgType, is_mem_cls: F, - ind_attr: Option) + ind_attr: Option) where F: FnOnce(&[RegClass]) -> bool { if !arg.ty.is_reg_ty() { @@ -384,7 +384,7 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { sse_regs -= needed_sse; } in_mem - }, Some(Attribute::ByVal)); + }, Some(ArgAttribute::ByVal)); // An integer, pointer, double or float parameter // thus the above closure passed to `x86_64_ty` won't diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index ffb13a833a58..df56e27128c7 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -26,11 +26,11 @@ use attributes; use base; use base::*; use build::*; -use closure; use common::{self, Block, Result, CrateContext, FunctionContext, SharedCrateContext}; use consts; use debuginfo::DebugLoc; use declare; +use value::Value; use meth; use monomorphize::{self, Instance}; use trans_item::TransItem; @@ -147,11 +147,12 @@ impl<'tcx> Callee<'tcx> { // after passing through fulfill_obligation let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap(); let instance = Instance::new(def_id, substs); - let llfn = closure::trans_closure_method(ccx, - vtable_closure.closure_def_id, - vtable_closure.substs, - instance, - trait_closure_kind); + let llfn = trans_closure_method( + ccx, + vtable_closure.closure_def_id, + vtable_closure.substs, + instance, + trait_closure_kind); let method_ty = def_ty(ccx.shared(), def_id, substs); Callee::ptr(llfn, method_ty) @@ -246,10 +247,174 @@ fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>, def_id: DefId, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { - let ty = shared.tcx().lookup_item_type(def_id).ty; + let ty = shared.tcx().item_type(def_id); monomorphize::apply_param_substs(shared, substs, &ty) } + +fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, + def_id: DefId, + substs: ty::ClosureSubsts<'tcx>, + method_instance: Instance<'tcx>, + trait_closure_kind: ty::ClosureKind) + -> ValueRef +{ + // If this is a closure, redirect to it. + let (llfn, _) = get_fn(ccx, def_id, substs.substs); + + // If the closure is a Fn closure, but a FnOnce is needed (etc), + // then adapt the self type + let llfn_closure_kind = ccx.tcx().closure_kind(def_id); + + let _icx = push_ctxt("trans_closure_adapter_shim"); + + debug!("trans_closure_adapter_shim(llfn_closure_kind={:?}, \ + trait_closure_kind={:?}, llfn={:?})", + llfn_closure_kind, trait_closure_kind, Value(llfn)); + + match (llfn_closure_kind, trait_closure_kind) { + (ty::ClosureKind::Fn, ty::ClosureKind::Fn) | + (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) | + (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => { + // No adapter needed. + llfn + } + (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => { + // The closure fn `llfn` is a `fn(&self, ...)`. We want a + // `fn(&mut self, ...)`. In fact, at trans time, these are + // basically the same thing, so we can just return llfn. + llfn + } + (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | + (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { + // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut + // self, ...)`. We want a `fn(self, ...)`. We can produce + // this by doing something like: + // + // fn call_once(self, ...) { call_mut(&self, ...) } + // fn call_once(mut self, ...) { call_mut(&mut self, ...) } + // + // These are both the same at trans time. + trans_fn_once_adapter_shim(ccx, def_id, substs, method_instance, llfn) + } + _ => { + bug!("trans_closure_adapter_shim: cannot convert {:?} to {:?}", + llfn_closure_kind, + trait_closure_kind); + } + } +} + +fn trans_fn_once_adapter_shim<'a, 'tcx>( + ccx: &'a CrateContext<'a, 'tcx>, + def_id: DefId, + substs: ty::ClosureSubsts<'tcx>, + method_instance: Instance<'tcx>, + llreffn: ValueRef) + -> ValueRef +{ + if let Some(&llfn) = ccx.instances().borrow().get(&method_instance) { + return llfn; + } + + debug!("trans_fn_once_adapter_shim(def_id={:?}, substs={:?}, llreffn={:?})", + def_id, substs, Value(llreffn)); + + let tcx = ccx.tcx(); + + // Find a version of the closure type. Substitute static for the + // region since it doesn't really matter. + let closure_ty = tcx.mk_closure_from_closure_substs(def_id, substs); + let ref_closure_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReErased), closure_ty); + + // Make a version with the type of by-ref closure. + let ty::ClosureTy { unsafety, abi, mut sig } = tcx.closure_type(def_id, substs); + sig.0.inputs.insert(0, ref_closure_ty); // sig has no self type as of yet + let llref_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { + unsafety: unsafety, + abi: abi, + sig: sig.clone() + })); + debug!("trans_fn_once_adapter_shim: llref_fn_ty={:?}", + llref_fn_ty); + + + // Make a version of the closure type with the same arguments, but + // with argument #0 being by value. + assert_eq!(abi, Abi::RustCall); + sig.0.inputs[0] = closure_ty; + + let sig = tcx.erase_late_bound_regions_and_normalize(&sig); + let fn_ty = FnType::new(ccx, abi, &sig, &[]); + + let llonce_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { + unsafety: unsafety, + abi: abi, + sig: ty::Binder(sig) + })); + + // Create the by-value helper. + let function_name = method_instance.symbol_name(ccx.shared()); + let lloncefn = declare::define_internal_fn(ccx, &function_name, llonce_fn_ty); + attributes::set_frame_pointer_elimination(ccx, lloncefn); + + let (block_arena, fcx): (TypedArena<_>, FunctionContext); + block_arena = TypedArena::new(); + fcx = FunctionContext::new(ccx, lloncefn, fn_ty, None, &block_arena); + let mut bcx = fcx.init(false); + + + // the first argument (`self`) will be the (by value) closure env. + + let mut llargs = get_params(fcx.llfn); + let mut self_idx = fcx.fn_ty.ret.is_indirect() as usize; + let env_arg = &fcx.fn_ty.args[0]; + let llenv = if env_arg.is_indirect() { + llargs[self_idx] + } else { + let scratch = alloc_ty(bcx, closure_ty, "self"); + let mut llarg_idx = self_idx; + env_arg.store_fn_arg(&bcx.build(), &mut llarg_idx, scratch); + scratch + }; + + debug!("trans_fn_once_adapter_shim: env={:?}", Value(llenv)); + // Adjust llargs such that llargs[self_idx..] has the call arguments. + // For zero-sized closures that means sneaking in a new argument. + if env_arg.is_ignore() { + if self_idx > 0 { + self_idx -= 1; + llargs[self_idx] = llenv; + } else { + llargs.insert(0, llenv); + } + } else { + llargs[self_idx] = llenv; + } + + let dest = fcx.llretslotptr.get(); + + let callee = Callee { + data: Fn(llreffn), + ty: llref_fn_ty + }; + + // Call the by-ref closure body with `self` in a cleanup scope, + // to drop `self` when the body returns, or in case it unwinds. + let self_scope = fcx.push_custom_cleanup_scope(); + fcx.schedule_drop_mem(self_scope, llenv, closure_ty); + + bcx = callee.call(bcx, DebugLoc::None, &llargs[self_idx..], dest).bcx; + + fcx.pop_and_trans_custom_cleanup_scope(bcx, self_scope); + + fcx.finish(bcx, DebugLoc::None); + + ccx.instances().borrow_mut().insert(method_instance, lloncefn); + + lloncefn +} + /// Translates an adapter that implements the `Fn` trait for a fn /// pointer. This is basically the equivalent of something like: /// @@ -400,7 +565,7 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let substs = tcx.normalize_associated_type(&substs); let instance = Instance::new(def_id, substs); - let item_ty = ccx.tcx().lookup_item_type(def_id).ty; + let item_ty = ccx.tcx().item_type(def_id); let fn_ty = monomorphize::apply_param_substs(ccx.shared(), substs, &item_ty); if let Some(&llfn) = ccx.instances().borrow().get(&instance) { @@ -435,13 +600,8 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // reference. It also occurs when testing libcore and in some // other weird situations. Annoying. - let fn_ptr_ty = match fn_ty.sty { - ty::TyFnDef(.., fty) => { - // Create a fn pointer with the substituted signature. - tcx.mk_fn_ptr(fty) - } - _ => bug!("expected fn item type, found {}", fn_ty) - }; + // Create a fn pointer with the substituted signature. + let fn_ptr_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(common::ty_fn_ty(ccx, fn_ty).into_owned())); let llptrty = type_of::type_of(ccx, fn_ptr_ty); let llfn = if let Some(llfn) = declare::get_declared_value(ccx, &sym) { diff --git a/src/librustc_trans/closure.rs b/src/librustc_trans/closure.rs deleted file mode 100644 index a1d645fb993b..000000000000 --- a/src/librustc_trans/closure.rs +++ /dev/null @@ -1,319 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use arena::TypedArena; -use llvm::{self, ValueRef, get_params}; -use rustc::hir::def_id::DefId; -use abi::{Abi, FnType}; -use attributes; -use base::*; -use callee::{self, Callee}; -use common::*; -use debuginfo::{DebugLoc}; -use declare; -use monomorphize::{Instance}; -use value::Value; -use rustc::ty::{self, Ty, TyCtxt}; - -use rustc::hir; - -fn get_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - closure_id: DefId, - fn_ty: Ty<'tcx>) - -> Ty<'tcx> { - match tcx.closure_kind(closure_id) { - ty::ClosureKind::Fn => { - tcx.mk_imm_ref(tcx.mk_region(ty::ReErased), fn_ty) - } - ty::ClosureKind::FnMut => { - tcx.mk_mut_ref(tcx.mk_region(ty::ReErased), fn_ty) - } - ty::ClosureKind::FnOnce => fn_ty, - } -} - -/// Returns the LLVM function declaration for a closure, creating it if -/// necessary. If the ID does not correspond to a closure ID, returns None. -fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - closure_id: DefId, - substs: ty::ClosureSubsts<'tcx>) - -> ValueRef { - // Normalize type so differences in regions and typedefs don't cause - // duplicate declarations - let tcx = ccx.tcx(); - let substs = tcx.erase_regions(&substs); - let instance = Instance::new(closure_id, substs.func_substs); - - if let Some(&llfn) = ccx.instances().borrow().get(&instance) { - debug!("get_or_create_closure_declaration(): found closure {:?}: {:?}", - instance, Value(llfn)); - return llfn; - } - - let symbol = instance.symbol_name(ccx.shared()); - - // Compute the rust-call form of the closure call method. - let sig = &tcx.closure_type(closure_id, substs).sig; - let sig = tcx.erase_late_bound_regions_and_normalize(sig); - let closure_type = tcx.mk_closure_from_closure_substs(closure_id, substs); - let function_type = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { - unsafety: hir::Unsafety::Normal, - abi: Abi::RustCall, - sig: ty::Binder(ty::FnSig { - inputs: Some(get_self_type(tcx, closure_id, closure_type)) - .into_iter().chain(sig.inputs).collect(), - output: sig.output, - variadic: false - }) - })); - let llfn = declare::declare_fn(ccx, &symbol, function_type); - - attributes::set_frame_pointer_elimination(ccx, llfn); - - debug!("get_or_create_declaration_if_closure(): inserting new \ - closure {:?}: {:?}", - instance, Value(llfn)); - - // NOTE: We do *not* store llfn in the ccx.instances() map here, - // that is only done, when the closures body is translated. - - llfn -} - -pub fn trans_closure_body_via_mir<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - closure_def_id: DefId, - closure_substs: ty::ClosureSubsts<'tcx>) { - // (*) Note that in the case of inlined functions, the `closure_def_id` will be the - // defid of the closure in its original crate, whereas `id` will be the id of the local - // inlined copy. - debug!("trans_closure_body_via_mir(closure_def_id={:?}, closure_substs={:?})", - closure_def_id, closure_substs); - - let tcx = ccx.tcx(); - let _icx = push_ctxt("closure::trans_closure_expr"); - - let param_substs = closure_substs.func_substs; - let instance = Instance::new(closure_def_id, param_substs); - - // If we have not done so yet, translate this closure's body - if !ccx.instances().borrow().contains_key(&instance) { - let llfn = get_or_create_closure_declaration(ccx, closure_def_id, closure_substs); - - unsafe { - if ccx.sess().target.target.options.allows_weak_linkage { - llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::WeakODRLinkage); - llvm::SetUniqueComdat(ccx.llmod(), llfn); - } else { - llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::InternalLinkage); - } - } - - // set an inline hint for all closures - attributes::inline(llfn, attributes::InlineAttr::Hint); - - // Get the type of this closure. Use the current `param_substs` as - // the closure substitutions. This makes sense because the closure - // takes the same set of type arguments as the enclosing fn, and - // this function (`trans_closure`) is invoked at the point - // of the closure expression. - - let sig = &tcx.closure_type(closure_def_id, closure_substs).sig; - let sig = tcx.erase_late_bound_regions_and_normalize(sig); - - let closure_type = tcx.mk_closure_from_closure_substs(closure_def_id, - closure_substs); - let sig = ty::FnSig { - inputs: Some(get_self_type(tcx, closure_def_id, closure_type)) - .into_iter().chain(sig.inputs).collect(), - output: sig.output, - variadic: false - }; - - trans_closure(ccx, - llfn, - Instance::new(closure_def_id, param_substs), - &sig, - Abi::RustCall); - - ccx.instances().borrow_mut().insert(instance, llfn); - } -} - -pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, - closure_def_id: DefId, - substs: ty::ClosureSubsts<'tcx>, - method_instance: Instance<'tcx>, - trait_closure_kind: ty::ClosureKind) - -> ValueRef -{ - // If this is a closure, redirect to it. - let llfn = get_or_create_closure_declaration(ccx, closure_def_id, substs); - - // If weak linkage is not allowed, we have to make sure that a local, - // private copy of the closure is available in this codegen unit - if !ccx.sess().target.target.options.allows_weak_linkage && - !ccx.sess().opts.single_codegen_unit() { - - trans_closure_body_via_mir(ccx, closure_def_id, substs); - } - - // If the closure is a Fn closure, but a FnOnce is needed (etc), - // then adapt the self type - let llfn_closure_kind = ccx.tcx().closure_kind(closure_def_id); - - let _icx = push_ctxt("trans_closure_adapter_shim"); - - debug!("trans_closure_adapter_shim(llfn_closure_kind={:?}, \ - trait_closure_kind={:?}, llfn={:?})", - llfn_closure_kind, trait_closure_kind, Value(llfn)); - - match (llfn_closure_kind, trait_closure_kind) { - (ty::ClosureKind::Fn, ty::ClosureKind::Fn) | - (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) | - (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => { - // No adapter needed. - llfn - } - (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => { - // The closure fn `llfn` is a `fn(&self, ...)`. We want a - // `fn(&mut self, ...)`. In fact, at trans time, these are - // basically the same thing, so we can just return llfn. - llfn - } - (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | - (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { - // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut - // self, ...)`. We want a `fn(self, ...)`. We can produce - // this by doing something like: - // - // fn call_once(self, ...) { call_mut(&self, ...) } - // fn call_once(mut self, ...) { call_mut(&mut self, ...) } - // - // These are both the same at trans time. - trans_fn_once_adapter_shim(ccx, closure_def_id, substs, method_instance, llfn) - } - _ => { - bug!("trans_closure_adapter_shim: cannot convert {:?} to {:?}", - llfn_closure_kind, - trait_closure_kind); - } - } -} - -fn trans_fn_once_adapter_shim<'a, 'tcx>( - ccx: &'a CrateContext<'a, 'tcx>, - closure_def_id: DefId, - substs: ty::ClosureSubsts<'tcx>, - method_instance: Instance<'tcx>, - llreffn: ValueRef) - -> ValueRef -{ - if let Some(&llfn) = ccx.instances().borrow().get(&method_instance) { - return llfn; - } - - debug!("trans_fn_once_adapter_shim(closure_def_id={:?}, substs={:?}, llreffn={:?})", - closure_def_id, substs, Value(llreffn)); - - let tcx = ccx.tcx(); - - // Find a version of the closure type. Substitute static for the - // region since it doesn't really matter. - let closure_ty = tcx.mk_closure_from_closure_substs(closure_def_id, substs); - let ref_closure_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReErased), closure_ty); - - // Make a version with the type of by-ref closure. - let ty::ClosureTy { unsafety, abi, mut sig } = - tcx.closure_type(closure_def_id, substs); - sig.0.inputs.insert(0, ref_closure_ty); // sig has no self type as of yet - let llref_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { - unsafety: unsafety, - abi: abi, - sig: sig.clone() - })); - debug!("trans_fn_once_adapter_shim: llref_fn_ty={:?}", - llref_fn_ty); - - - // Make a version of the closure type with the same arguments, but - // with argument #0 being by value. - assert_eq!(abi, Abi::RustCall); - sig.0.inputs[0] = closure_ty; - - let sig = tcx.erase_late_bound_regions_and_normalize(&sig); - let fn_ty = FnType::new(ccx, abi, &sig, &[]); - - let llonce_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { - unsafety: unsafety, - abi: abi, - sig: ty::Binder(sig) - })); - - // Create the by-value helper. - let function_name = method_instance.symbol_name(ccx.shared()); - let lloncefn = declare::define_internal_fn(ccx, &function_name, llonce_fn_ty); - attributes::set_frame_pointer_elimination(ccx, lloncefn); - - let (block_arena, fcx): (TypedArena<_>, FunctionContext); - block_arena = TypedArena::new(); - fcx = FunctionContext::new(ccx, lloncefn, fn_ty, None, &block_arena); - let mut bcx = fcx.init(false); - - - // the first argument (`self`) will be the (by value) closure env. - - let mut llargs = get_params(fcx.llfn); - let mut self_idx = fcx.fn_ty.ret.is_indirect() as usize; - let env_arg = &fcx.fn_ty.args[0]; - let llenv = if env_arg.is_indirect() { - llargs[self_idx] - } else { - let scratch = alloc_ty(bcx, closure_ty, "self"); - let mut llarg_idx = self_idx; - env_arg.store_fn_arg(&bcx.build(), &mut llarg_idx, scratch); - scratch - }; - - debug!("trans_fn_once_adapter_shim: env={:?}", Value(llenv)); - // Adjust llargs such that llargs[self_idx..] has the call arguments. - // For zero-sized closures that means sneaking in a new argument. - if env_arg.is_ignore() { - if self_idx > 0 { - self_idx -= 1; - llargs[self_idx] = llenv; - } else { - llargs.insert(0, llenv); - } - } else { - llargs[self_idx] = llenv; - } - - let dest = fcx.llretslotptr.get(); - - let callee = Callee { - data: callee::Fn(llreffn), - ty: llref_fn_ty - }; - - // Call the by-ref closure body with `self` in a cleanup scope, - // to drop `self` when the body returns, or in case it unwinds. - let self_scope = fcx.push_custom_cleanup_scope(); - fcx.schedule_drop_mem(self_scope, llenv, closure_ty); - - bcx = callee.call(bcx, DebugLoc::None, &llargs[self_idx..], dest).bcx; - - fcx.pop_and_trans_custom_cleanup_scope(bcx, self_scope); - - fcx.finish(bcx, DebugLoc::None); - - ccx.instances().borrow_mut().insert(method_instance, lloncefn); - - lloncefn -} diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 2c0ba36f3b41..5902b0b1ce07 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -189,7 +189,7 @@ //! regardless of whether it is actually needed or not. use rustc::hir; -use rustc::hir::intravisit as hir_visit; +use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::map as hir_map; use rustc::hir::def_id::DefId; @@ -213,7 +213,7 @@ use glue::{self, DropGlueKind}; use monomorphize::{self, Instance}; use util::nodemap::{FxHashSet, FxHashMap, DefIdMap}; -use trans_item::{TransItem, type_to_string, def_id_to_string}; +use trans_item::{TransItem, DefPathBasedNames}; #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)] pub enum TransItemCollectionMode { @@ -306,10 +306,9 @@ fn collect_roots<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, scx: scx, mode: mode, output: &mut roots, - enclosing_item: None, }; - scx.tcx().map.krate().visit_all_items(&mut visitor); + scx.tcx().map.krate().visit_all_item_likes(&mut visitor); } roots @@ -337,7 +336,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>, } TransItem::Static(node_id) => { let def_id = scx.tcx().map.local_def_id(node_id); - let ty = scx.tcx().lookup_item_type(def_id).ty; + let ty = scx.tcx().item_type(def_id); let ty = glue::get_drop_glue_type(scx.tcx(), ty); neighbors.push(TransItem::DropGlue(DropGlueKind::Ty(ty))); @@ -446,24 +445,6 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { debug!("visiting rvalue {:?}", *rvalue); match *rvalue { - mir::Rvalue::Aggregate(mir::AggregateKind::Closure(def_id, - ref substs), _) => { - let mir = self.scx.tcx().item_mir(def_id); - - let concrete_substs = monomorphize::apply_param_substs(self.scx, - self.param_substs, - &substs.func_substs); - let concrete_substs = self.scx.tcx().erase_regions(&concrete_substs); - - let visitor = MirNeighborCollector { - scx: self.scx, - mir: &mir, - output: self.output, - param_substs: concrete_substs - }; - - visit_mir_and_promoted(visitor, &mir); - } // When doing an cast from a regular pointer to a fat pointer, we // have to instantiate all methods of the trait being cast to, so we // can build the appropriate vtable. @@ -618,7 +599,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { fn can_result_in_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool { - match tcx.lookup_item_type(def_id).ty.sty { + match tcx.item_type(def_id).sty { ty::TyFnDef(def_id, _, f) => { // Some constructors also have type TyFnDef but they are // always instantiated inline and don't result in @@ -797,8 +778,8 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, } } } - ty::TyClosure(_, substs) => { - for upvar_ty in substs.upvar_tys { + ty::TyClosure(def_id, substs) => { + for upvar_ty in substs.upvar_tys(def_id, scx.tcx()) { let upvar_ty = glue::get_drop_glue_type(scx.tcx(), upvar_ty); if glue::type_needs_drop(scx.tcx(), upvar_ty) { output.push(TransItem::DropGlue(DropGlueKind::Ty(upvar_ty))); @@ -888,10 +869,12 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, traits::VtableImpl(impl_data) => { Some(traits::find_method(tcx, trait_method.name, rcvr_substs, &impl_data)) } - // If we have a closure or a function pointer, we will also encounter - // the concrete closure/function somewhere else (during closure or fn - // pointer construction). That's where we track those things. - traits::VtableClosure(..) | + traits::VtableClosure(closure_data) => { + Some((closure_data.closure_def_id, closure_data.substs.substs)) + } + // Trait object and function pointer shims are always + // instantiated in-place, and as they are just an ABI-adjusting + // indirect call they do not have any dependencies. traits::VtableFnPointer(..) | traits::VtableObject(..) => { None @@ -1046,14 +1029,10 @@ struct RootCollector<'b, 'a: 'b, 'tcx: 'a + 'b> { scx: &'b SharedCrateContext<'a, 'tcx>, mode: TransItemCollectionMode, output: &'b mut Vec>, - enclosing_item: Option<&'tcx hir::Item>, } -impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> { +impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { fn visit_item(&mut self, item: &'v hir::Item) { - let old_enclosing_item = self.enclosing_item; - self.enclosing_item = Some(item); - match item.node { hir::ItemExternCrate(..) | hir::ItemUse(..) | @@ -1077,13 +1056,12 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> { hir::ItemStruct(_, ref generics) | hir::ItemUnion(_, ref generics) => { if !generics.is_parameterized() { - let ty = self.scx.tcx().tables().node_types[&item.id]; - if self.mode == TransItemCollectionMode::Eager { + let def_id = self.scx.tcx().map.local_def_id(item.id); debug!("RootCollector: ADT drop-glue for {}", - def_id_to_string(self.scx.tcx(), - self.scx.tcx().map.local_def_id(item.id))); + def_id_to_string(self.scx.tcx(), def_id)); + let ty = self.scx.tcx().item_type(def_id); let ty = glue::get_drop_glue_type(self.scx.tcx(), ty); self.output.push(TransItem::DropGlue(DropGlueKind::Ty(ty))); } @@ -1111,9 +1089,6 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> { } } } - - hir_visit::walk_item(self, item); - self.enclosing_item = old_enclosing_item; } fn visit_impl_item(&mut self, ii: &'v hir::ImplItem) { @@ -1148,8 +1123,6 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> { } _ => { /* Nothing to do here */ } } - - hir_visit::walk_impl_item(self, ii) } } @@ -1162,7 +1135,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, ' _, ref generics, .., - ref items) => { + ref impl_item_refs) => { if generics.is_type_parameterized() { return } @@ -1174,15 +1147,16 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, ' if let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) { let callee_substs = tcx.erase_regions(&trait_ref.substs); - let overridden_methods: FxHashSet<_> = items.iter() - .map(|item| item.name) - .collect(); + let overridden_methods: FxHashSet<_> = + impl_item_refs.iter() + .map(|iiref| iiref.name) + .collect(); for method in tcx.provided_trait_methods(trait_ref.def_id) { if overridden_methods.contains(&method.name) { continue; } - if !tcx.lookup_generics(method.def_id).types.is_empty() { + if !tcx.item_generics(method.def_id).types.is_empty() { continue; } @@ -1201,7 +1175,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, ' callee_substs, &impl_data); - let predicates = tcx.lookup_predicates(def_id).predicates + let predicates = tcx.item_predicates(def_id).predicates .subst(tcx, substs); if !traits::normalize_and_test_predicates(tcx, predicates) { continue; @@ -1251,3 +1225,21 @@ fn visit_mir_and_promoted<'tcx, V: MirVisitor<'tcx>>(mut visitor: V, mir: &mir:: visitor.visit_mir(promoted); } } + +fn def_id_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> String { + let mut output = String::new(); + let printer = DefPathBasedNames::new(tcx, false, false); + printer.push_def_path(def_id, &mut output); + output +} + +fn type_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + ty: ty::Ty<'tcx>) + -> String { + let mut output = String::new(); + let printer = DefPathBasedNames::new(tcx, false, false); + printer.push_type_name(ty, &mut output); + output +} diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 464b261b08e0..df70a6e81166 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -18,6 +18,7 @@ use llvm::{ValueRef, BasicBlockRef, BuilderRef, ContextRef, TypeKind}; use llvm::{True, False, Bool, OperandBundleDef}; use rustc::hir::def::Def; use rustc::hir::def_id::DefId; +use rustc::hir::map::DefPathData; use rustc::infer::TransNormalize; use rustc::mir::Mir; use rustc::util::common::MemoizationMap; @@ -44,6 +45,8 @@ use rustc::hir; use arena::TypedArena; use libc::{c_uint, c_char}; +use std::borrow::Cow; +use std::iter; use std::ops::Deref; use std::ffi::CString; use std::cell::{Cell, RefCell, Ref}; @@ -109,7 +112,16 @@ pub fn type_pair_fields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) Some([monomorphize::field_ty(ccx.tcx(), substs, &fields[0]), monomorphize::field_ty(ccx.tcx(), substs, &fields[1])]) } - ty::TyClosure(_, ty::ClosureSubsts { upvar_tys: tys, .. }) | + ty::TyClosure(def_id, substs) => { + let mut tys = substs.upvar_tys(def_id, ccx.tcx()); + tys.next().and_then(|first_ty| tys.next().and_then(|second_ty| { + if tys.next().is_some() { + None + } else { + Some([first_ty, second_ty]) + } + })) + } ty::TyTuple(tys) => { if tys.len() != 2 { return None; @@ -815,7 +827,7 @@ pub fn C_cstr(cx: &CrateContext, s: InternedString, null_terminated: bool) -> Va pub fn C_str_slice(cx: &CrateContext, s: InternedString) -> ValueRef { let len = s.len(); let cs = consts::ptrcast(C_cstr(cx, s, false), Type::i8p(cx)); - C_named_struct(cx.tn().find_type("str_slice").unwrap(), &[cs, C_uint(cx, len)]) + C_named_struct(cx.str_slice_type(), &[cs, C_uint(cx, len)]) } pub fn C_struct(cx: &CrateContext, elts: &[ValueRef], packed: bool) -> ValueRef { @@ -1060,3 +1072,36 @@ pub fn shift_mask_val<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, _ => bug!("shift_mask_val: expected Integer or Vector, found {:?}", kind), } } + +pub fn ty_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + ty: Ty<'tcx>) + -> Cow<'tcx, ty::BareFnTy<'tcx>> +{ + match ty.sty { + ty::TyFnDef(_, _, fty) => Cow::Borrowed(fty), + // Shims currently have type TyFnPtr. Not sure this should remain. + ty::TyFnPtr(fty) => Cow::Borrowed(fty), + ty::TyClosure(def_id, substs) => { + let tcx = ccx.tcx(); + let ty::ClosureTy { unsafety, abi, sig } = tcx.closure_type(def_id, substs); + + let env_region = ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrEnv); + let env_ty = match tcx.closure_kind(def_id) { + ty::ClosureKind::Fn => tcx.mk_imm_ref(tcx.mk_region(env_region), ty), + ty::ClosureKind::FnMut => tcx.mk_mut_ref(tcx.mk_region(env_region), ty), + ty::ClosureKind::FnOnce => ty, + }; + + let sig = sig.map_bound(|sig| ty::FnSig { + inputs: iter::once(env_ty).chain(sig.inputs).collect(), + ..sig + }); + Cow::Owned(ty::BareFnTy { unsafety: unsafety, abi: abi, sig: sig }) + } + _ => bug!("unexpected type {:?} to ty_fn_sig", ty) + } +} + +pub fn is_closure(tcx: TyCtxt, def_id: DefId) -> bool { + tcx.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr +} diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 0dc10aa7759e..670a84565faf 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -84,7 +84,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef { return g; } - let ty = ccx.tcx().lookup_item_type(def_id).ty; + let ty = ccx.tcx().item_type(def_id); let g = if let Some(id) = ccx.tcx().map.as_local_node_id(def_id) { let llty = type_of::type_of(ccx, ty); @@ -226,7 +226,7 @@ pub fn trans_static(ccx: &CrateContext, v }; - let ty = ccx.tcx().lookup_item_type(def_id).ty; + let ty = ccx.tcx().item_type(def_id); let llty = type_of::type_of(ccx, ty); let g = if val_llty == llty { g diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 264d4940c17f..7657fc7d1c8b 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -25,7 +25,8 @@ use monomorphize::Instance; use partitioning::CodegenUnit; use trans_item::TransItem; -use type_::{Type, TypeNames}; +use type_::Type; +use rustc_data_structures::base_n; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TyCtxt}; use session::config::NoDebugInfo; @@ -87,7 +88,6 @@ pub struct LocalCrateContext<'tcx> { llmod: ModuleRef, llcx: ContextRef, previous_work_product: Option, - tn: TypeNames, // FIXME: This seems to be largely unused. codegen_unit: CodegenUnit<'tcx>, needs_unwind_cleanup_cache: RefCell, bool>>, fn_pointer_shims: RefCell, ValueRef>>, @@ -137,6 +137,7 @@ pub struct LocalCrateContext<'tcx> { type_hashcodes: RefCell, String>>, int_type: Type, opaque_vec_type: Type, + str_slice_type: Type, builder: BuilderRef_res, /// Holds the LLVM values for closure IDs. @@ -611,7 +612,6 @@ impl<'tcx> LocalCrateContext<'tcx> { llcx: llcx, previous_work_product: previous_work_product, codegen_unit: codegen_unit, - tn: TypeNames::new(), needs_unwind_cleanup_cache: RefCell::new(FxHashMap()), fn_pointer_shims: RefCell::new(FxHashMap()), drop_glues: RefCell::new(FxHashMap()), @@ -631,6 +631,7 @@ impl<'tcx> LocalCrateContext<'tcx> { type_hashcodes: RefCell::new(FxHashMap()), int_type: Type::from_ref(ptr::null_mut()), opaque_vec_type: Type::from_ref(ptr::null_mut()), + str_slice_type: Type::from_ref(ptr::null_mut()), builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)), closure_vals: RefCell::new(FxHashMap()), dbg_cx: dbg_cx, @@ -662,7 +663,7 @@ impl<'tcx> LocalCrateContext<'tcx> { local_ccx.int_type = int_type; local_ccx.opaque_vec_type = opaque_vec_type; - local_ccx.tn.associate_type("str_slice", &str_slice_ty); + local_ccx.str_slice_type = str_slice_ty; if shared.tcx.sess.count_llvm_insns() { base::init_insn_ctxt() @@ -700,22 +701,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local_ccxs[self.index] } - /// Get a (possibly) different `CrateContext` from the same - /// `SharedCrateContext`. - pub fn rotate(&'b self) -> CrateContext<'b, 'tcx> { - let (_, index) = - self.local_ccxs - .iter() - .zip(0..self.local_ccxs.len()) - .min_by_key(|&(local_ccx, _idx)| local_ccx.n_llvm_insns.get()) - .unwrap(); - CrateContext { - shared: self.shared, - index: index, - local_ccxs: &self.local_ccxs[..], - } - } - /// Either iterate over only `self`, or iterate over all `CrateContext`s in /// the `SharedCrateContext`. The iterator produces `(ccx, is_origin)` /// pairs, where `is_origin` is `true` if `ccx` is `self` and `false` @@ -778,10 +763,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { unsafe { llvm::LLVMRustGetModuleDataLayout(self.llmod()) } } - pub fn tn<'a>(&'a self) -> &'a TypeNames { - &self.local().tn - } - pub fn export_map<'a>(&'a self) -> &'a ExportMap { &self.shared.export_map } @@ -885,6 +866,10 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { self.local().opaque_vec_type } + pub fn str_slice_type(&self) -> Type { + self.local().str_slice_type + } + pub fn closure_vals<'a>(&'a self) -> &'a RefCell, ValueRef>> { &self.local().closure_vals } @@ -975,7 +960,11 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { self.local().local_gen_sym_counter.set(idx + 1); // Include a '.' character, so there can be no accidental conflicts with // user defined names - format!("{}.{}", prefix, idx) + let mut name = String::with_capacity(prefix.len() + 6); + name.push_str(prefix); + name.push_str("."); + base_n::push_str(idx as u64, base_n::MAX_BASE, &mut name); + name } } diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index e81461b66217..5b9ef78ddc22 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -574,10 +574,11 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, MetadataCreationResult::new(pointer_type_metadata(cx, t, fn_metadata), false) } - ty::TyClosure(_, ref substs) => { + ty::TyClosure(def_id, substs) => { + let upvar_tys : Vec<_> = substs.upvar_tys(def_id, cx.tcx()).collect(); prepare_tuple_metadata(cx, t, - &substs.upvar_tys, + &upvar_tys, unique_type_id, usage_site_span).finalize(cx) } @@ -1765,7 +1766,7 @@ pub fn create_global_var_metadata(cx: &CrateContext, }; let is_local_to_unit = is_node_local_to_unit(cx, node_id); - let variable_type = tcx.erase_regions(&tcx.tables().node_id_to_type(node_id)); + let variable_type = tcx.erase_regions(&tcx.item_type(node_def_id)); let type_metadata = type_metadata(cx, variable_type, span); let var_name = tcx.item_name(node_def_id).to_string(); let linkage_name = mangled_name_of_item(cx, node_def_id, ""); diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 62fb40cc389c..482275d298bc 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -25,7 +25,6 @@ use llvm::{ModuleRef, ContextRef, ValueRef}; use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilderRef, DISubprogram, DIArray, FlagPrototyped}; use rustc::hir::def_id::DefId; -use rustc::hir::map::DefPathData; use rustc::ty::subst::Substs; use abi::Abi; @@ -248,21 +247,19 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, }; // Find the enclosing function, in case this is a closure. - let mut fn_def_id = instance.def; - let mut def_key = cx.tcx().def_key(fn_def_id); + let def_key = cx.tcx().def_key(instance.def); let mut name = def_key.disambiguated_data.data.to_string(); let name_len = name.len(); - while def_key.disambiguated_data.data == DefPathData::ClosureExpr { - fn_def_id.index = def_key.parent.expect("closure without a parent?"); - def_key = cx.tcx().def_key(fn_def_id); - } + + let fn_def_id = cx.tcx().closure_base_def_id(instance.def); // Get_template_parameters() will append a `<...>` clause to the function // name if necessary. - let generics = cx.tcx().lookup_generics(fn_def_id); + let generics = cx.tcx().item_generics(fn_def_id); + let substs = instance.substs.truncate_to(cx.tcx(), generics); let template_parameters = get_template_parameters(cx, &generics, - instance.substs, + substs, file_metadata, &mut name); @@ -397,7 +394,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, generics: &ty::Generics<'tcx>) -> Vec { let mut names = generics.parent.map_or(vec![], |def_id| { - get_type_parameter_names(cx, cx.tcx().lookup_generics(def_id)) + get_type_parameter_names(cx, cx.tcx().item_generics(def_id)) }); names.extend(generics.types.iter().map(|param| param.name)); names @@ -412,7 +409,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let self_type = cx.tcx().impl_of_method(instance.def).and_then(|impl_def_id| { // If the method does *not* belong to a trait, proceed if cx.tcx().trait_id_of_impl(impl_def_id).is_none() { - let impl_self_ty = cx.tcx().lookup_item_type(impl_def_id).ty; + let impl_self_ty = cx.tcx().item_type(impl_def_id); let impl_self_ty = cx.tcx().erase_regions(&impl_self_ty); let impl_self_ty = monomorphize::apply_param_substs(cx.shared(), instance.substs, diff --git a/src/librustc_trans/declare.rs b/src/librustc_trans/declare.rs index 1ec5ca4a563a..7d6a672077a0 100644 --- a/src/librustc_trans/declare.rs +++ b/src/librustc_trans/declare.rs @@ -19,14 +19,17 @@ //! interested in defining the ValueRef they return. //! * Use define_* family of methods when you might be defining the ValueRef. //! * When in doubt, define. + use llvm::{self, ValueRef}; use llvm::AttributePlace::Function; use rustc::ty; use abi::{Abi, FnType}; use attributes; use context::CrateContext; +use common; use type_::Type; use value::Value; +use syntax::attr; use std::ffi::CString; @@ -69,6 +72,16 @@ fn declare_raw_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, ty: llvm::Attribute::NoRedZone.apply_llfn(Function, llfn); } + // If we're compiling the compiler-builtins crate, e.g. the equivalent of + // compiler-rt, then we want to implicitly compile everything with hidden + // visibility as we're going to link this object all over the place but + // don't want the symbols to get exported. + if attr::contains_name(ccx.tcx().map.krate_attrs(), "compiler_builtins") { + unsafe { + llvm::LLVMSetVisibility(llfn, llvm::Visibility::Hidden); + } + } + match ccx.tcx().sess.opts.cg.opt_level.as_ref().map(String::as_ref) { Some("s") => { llvm::Attribute::OptimizeForSize.apply_llfn(Function, llfn); @@ -103,8 +116,8 @@ pub fn declare_cfn(ccx: &CrateContext, name: &str, fn_type: Type) -> ValueRef { pub fn declare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, fn_type: ty::Ty<'tcx>) -> ValueRef { debug!("declare_rust_fn(name={:?}, fn_type={:?})", name, fn_type); - let abi = fn_type.fn_abi(); - let sig = ccx.tcx().erase_late_bound_regions_and_normalize(fn_type.fn_sig()); + let ty::BareFnTy { abi, ref sig, .. } = *common::ty_fn_ty(ccx, fn_type); + let sig = ccx.tcx().erase_late_bound_regions_and_normalize(sig); debug!("declare_rust_fn (after region erasure) sig={:?}", sig); let fty = FnType::new(ccx, abi, &sig, &[]); diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 648dd9f3e3ae..d6d4d33923f1 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -531,8 +531,8 @@ fn drop_structural_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, let mut cx = cx; match t.sty { - ty::TyClosure(_, ref substs) => { - for (i, upvar_ty) in substs.upvar_tys.iter().enumerate() { + ty::TyClosure(def_id, substs) => { + for (i, upvar_ty) in substs.upvar_tys(def_id, cx.tcx()).enumerate() { let llupvar = adt::trans_field_ptr(cx, t, value, Disr(0), i); cx = drop_ty(cx, llupvar, upvar_ty, DebugLoc::None); } diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 8ef7f04d4ee1..d0cb302e1ab1 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -23,6 +23,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![cfg_attr(not(stage0), deny(warnings))] +#![feature(associated_consts)] #![feature(box_patterns)] #![feature(box_syntax)] #![feature(cell_extras)] @@ -55,6 +56,9 @@ extern crate rustc_platform_intrinsics as intrinsics; extern crate serialize; extern crate rustc_const_math; extern crate rustc_const_eval; +#[macro_use] +#[no_link] +extern crate rustc_bitflags; #[macro_use] extern crate log; #[macro_use] extern crate syntax; @@ -101,6 +105,7 @@ mod cabi_arm; mod cabi_asmjs; mod cabi_mips; mod cabi_mips64; +mod cabi_msp430; mod cabi_powerpc; mod cabi_powerpc64; mod cabi_s390x; @@ -109,7 +114,6 @@ mod cabi_x86_64; mod cabi_x86_win64; mod callee; mod cleanup; -mod closure; mod collector; mod common; mod consts; diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index b8d346b11c13..bca81fa36458 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -553,14 +553,6 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } failure?; - // FIXME Shouldn't need to manually trigger closure instantiations. - if let mir::AggregateKind::Closure(def_id, substs) = *kind { - use closure; - closure::trans_closure_body_via_mir(self.ccx, - def_id, - self.monomorphize(&substs)); - } - match *kind { mir::AggregateKind::Array => { self.const_array(dest_ty, &fields) diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index d2adf88c9168..12b17c26cbc4 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -470,8 +470,8 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>, } else { (arg_ty, false) }; - let upvar_tys = if let ty::TyClosure(_, ref substs) = closure_ty.sty { - &substs.upvar_tys[..] + let upvar_tys = if let ty::TyClosure(def_id, substs) = closure_ty.sty { + substs.upvar_tys(def_id, tcx) } else { bug!("upvar_decls with non-closure arg0 type `{}`", closure_ty); }; diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index f25877b1de12..15cbbc720d6d 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -133,15 +133,6 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } }, _ => { - // FIXME Shouldn't need to manually trigger closure instantiations. - if let mir::AggregateKind::Closure(def_id, substs) = *kind { - use closure; - - closure::trans_closure_body_via_mir(bcx.ccx(), - def_id, - bcx.monomorphize(&substs)); - } - for (i, operand) in operands.iter().enumerate() { let op = self.trans_operand(&bcx, operand); // Do not generate stores and GEPis for zero-sized fields. @@ -729,11 +720,13 @@ fn get_overflow_intrinsic(oop: OverflowOp, bcx: &BlockAndBuilder, ty: Ty) -> Val let new_sty = match ty.sty { TyInt(Is) => match &tcx.sess.target.target.target_pointer_width[..] { + "16" => TyInt(I16), "32" => TyInt(I32), "64" => TyInt(I64), _ => panic!("unsupported target word size") }, TyUint(Us) => match &tcx.sess.target.target.target_pointer_width[..] { + "16" => TyUint(U16), "32" => TyUint(U32), "64" => TyUint(U64), _ => panic!("unsupported target word size") diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index c9c12fb6d453..09a1cbd319ac 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -495,7 +495,7 @@ fn characteristic_def_id_of_trans_item<'a, 'tcx>(scx: &SharedCrateContext<'a, 't if let Some(impl_def_id) = tcx.impl_of_method(instance.def) { // This is a method within an inherent impl, find out what the // self-type is: - let impl_self_ty = tcx.lookup_item_type(impl_def_id).ty; + let impl_self_ty = tcx.item_type(impl_def_id); let impl_self_ty = tcx.erase_regions(&impl_self_ty); let impl_self_ty = monomorphize::apply_param_substs(scx, instance.substs, diff --git a/src/librustc_trans/symbol_names_test.rs b/src/librustc_trans/symbol_names_test.rs index 25c30151ad45..aa23a1817227 100644 --- a/src/librustc_trans/symbol_names_test.rs +++ b/src/librustc_trans/symbol_names_test.rs @@ -35,7 +35,8 @@ pub fn report_symbol_names(scx: &SharedCrateContext) { let _ignore = tcx.dep_graph.in_ignore(); let mut visitor = SymbolNamesTest { scx: scx }; - tcx.map.krate().visit_all_items(&mut visitor); + // FIXME(#37712) could use ItemLikeVisitor if trait items were item-like + tcx.map.krate().visit_all_item_likes(&mut visitor.as_deep_visitor()); } struct SymbolNamesTest<'a, 'tcx:'a> { diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 8930387c046e..7fa59127704d 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -18,6 +18,7 @@ use attributes; use base; use consts; use context::{CrateContext, SharedCrateContext}; +use common; use declare; use glue::DropGlueKind; use llvm; @@ -34,6 +35,7 @@ use type_of; use glue; use abi::{Abi, FnType}; use back::symbol_names; +use std::fmt::Write; #[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)] pub enum TransItem<'tcx> { @@ -131,7 +133,7 @@ impl<'a, 'tcx> TransItem<'tcx> { linkage: llvm::Linkage, symbol_name: &str) { let def_id = ccx.tcx().map.local_def_id(node_id); - let ty = ccx.tcx().lookup_item_type(def_id).ty; + let ty = ccx.tcx().item_type(def_id); let llty = type_of::type_of(ccx, ty); let g = declare::define_global(ccx, symbol_name, llty).unwrap_or_else(|| { @@ -153,7 +155,7 @@ impl<'a, 'tcx> TransItem<'tcx> { assert!(!instance.substs.needs_infer() && !instance.substs.has_param_types()); - let item_ty = ccx.tcx().lookup_item_type(instance.def).ty; + let item_ty = ccx.tcx().item_type(instance.def); let item_ty = ccx.tcx().erase_regions(&item_ty); let mono_ty = monomorphize::apply_param_substs(ccx.shared(), instance.substs, &item_ty); @@ -166,6 +168,11 @@ impl<'a, 'tcx> TransItem<'tcx> { llvm::SetUniqueComdat(ccx.llmod(), lldecl); } + if let ty::TyClosure(..) = mono_ty.sty { + // set an inline hint for all closures + attributes::inline(lldecl, attributes::InlineAttr::Hint); + } + attributes::from_fn_attrs(ccx, &attrs, lldecl); ccx.instances().borrow_mut().insert(instance, lldecl); @@ -239,6 +246,7 @@ impl<'a, 'tcx> TransItem<'tcx> { TransItem::Fn(ref instance) => { !instance.def.is_local() || instance.substs.types().next().is_some() || + common::is_closure(tcx, instance.def) || attr::requests_inline(&tcx.get_attrs(instance.def)[..]) } TransItem::DropGlue(..) => true, @@ -302,7 +310,8 @@ impl<'a, 'tcx> TransItem<'tcx> { DropGlueKind::Ty(_) => s.push_str("drop-glue "), DropGlueKind::TyContents(_) => s.push_str("drop-glue-contents "), }; - push_unique_type_name(tcx, dg.ty(), &mut s); + let printer = DefPathBasedNames::new(tcx, false, false); + printer.push_type_name(dg.ty(), &mut s); s } TransItem::Fn(instance) => { @@ -321,7 +330,8 @@ impl<'a, 'tcx> TransItem<'tcx> { -> String { let mut result = String::with_capacity(32); result.push_str(prefix); - push_instance_as_string(tcx, instance, &mut result); + let printer = DefPathBasedNames::new(tcx, false, false); + printer.push_instance_as_string(instance, &mut result); result } } @@ -362,207 +372,219 @@ impl<'a, 'tcx> TransItem<'tcx> { /// Same as `unique_type_name()` but with the result pushed onto the given /// `output` parameter. -pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - t: Ty<'tcx>, - output: &mut String) { - match t.sty { - ty::TyBool => output.push_str("bool"), - ty::TyChar => output.push_str("char"), - ty::TyStr => output.push_str("str"), - ty::TyNever => output.push_str("!"), - ty::TyInt(ast::IntTy::Is) => output.push_str("isize"), - ty::TyInt(ast::IntTy::I8) => output.push_str("i8"), - ty::TyInt(ast::IntTy::I16) => output.push_str("i16"), - ty::TyInt(ast::IntTy::I32) => output.push_str("i32"), - ty::TyInt(ast::IntTy::I64) => output.push_str("i64"), - ty::TyUint(ast::UintTy::Us) => output.push_str("usize"), - ty::TyUint(ast::UintTy::U8) => output.push_str("u8"), - ty::TyUint(ast::UintTy::U16) => output.push_str("u16"), - ty::TyUint(ast::UintTy::U32) => output.push_str("u32"), - ty::TyUint(ast::UintTy::U64) => output.push_str("u64"), - ty::TyFloat(ast::FloatTy::F32) => output.push_str("f32"), - ty::TyFloat(ast::FloatTy::F64) => output.push_str("f64"), - ty::TyAdt(adt_def, substs) => { - push_item_name(tcx, adt_def.did, output); - push_type_params(tcx, substs, &[], output); - }, - ty::TyTuple(component_types) => { - output.push('('); - for &component_type in component_types { - push_unique_type_name(tcx, component_type, output); - output.push_str(", "); - } - if !component_types.is_empty() { - output.pop(); - output.pop(); - } - output.push(')'); - }, - ty::TyBox(inner_type) => { - output.push_str("Box<"); - push_unique_type_name(tcx, inner_type, output); - output.push('>'); - }, - ty::TyRawPtr(ty::TypeAndMut { ty: inner_type, mutbl } ) => { - output.push('*'); - match mutbl { - hir::MutImmutable => output.push_str("const "), - hir::MutMutable => output.push_str("mut "), - } +pub struct DefPathBasedNames<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + omit_disambiguators: bool, + omit_local_crate_name: bool, +} - push_unique_type_name(tcx, inner_type, output); - }, - ty::TyRef(_, ty::TypeAndMut { ty: inner_type, mutbl }) => { - output.push('&'); - if mutbl == hir::MutMutable { - output.push_str("mut "); - } +impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { + pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, + omit_disambiguators: bool, + omit_local_crate_name: bool) + -> Self { + DefPathBasedNames { + tcx: tcx, + omit_disambiguators: omit_disambiguators, + omit_local_crate_name: omit_local_crate_name, + } + } - push_unique_type_name(tcx, inner_type, output); - }, - ty::TyArray(inner_type, len) => { - output.push('['); - push_unique_type_name(tcx, inner_type, output); - output.push_str(&format!("; {}", len)); - output.push(']'); - }, - ty::TySlice(inner_type) => { - output.push('['); - push_unique_type_name(tcx, inner_type, output); - output.push(']'); - }, - ty::TyTrait(ref trait_data) => { - push_item_name(tcx, trait_data.principal.def_id(), output); - push_type_params(tcx, - trait_data.principal.skip_binder().substs, - &trait_data.projection_bounds, - output); - }, - ty::TyFnDef(.., &ty::BareFnTy{ unsafety, abi, ref sig } ) | - ty::TyFnPtr(&ty::BareFnTy{ unsafety, abi, ref sig } ) => { - if unsafety == hir::Unsafety::Unsafe { - output.push_str("unsafe "); - } - - if abi != ::abi::Abi::Rust { - output.push_str("extern \""); - output.push_str(abi.name()); - output.push_str("\" "); - } - - output.push_str("fn("); - - let sig = tcx.erase_late_bound_regions_and_normalize(sig); - if !sig.inputs.is_empty() { - for ¶meter_type in &sig.inputs { - push_unique_type_name(tcx, parameter_type, output); + pub fn push_type_name(&self, t: Ty<'tcx>, output: &mut String) { + match t.sty { + ty::TyBool => output.push_str("bool"), + ty::TyChar => output.push_str("char"), + ty::TyStr => output.push_str("str"), + ty::TyNever => output.push_str("!"), + ty::TyInt(ast::IntTy::Is) => output.push_str("isize"), + ty::TyInt(ast::IntTy::I8) => output.push_str("i8"), + ty::TyInt(ast::IntTy::I16) => output.push_str("i16"), + ty::TyInt(ast::IntTy::I32) => output.push_str("i32"), + ty::TyInt(ast::IntTy::I64) => output.push_str("i64"), + ty::TyUint(ast::UintTy::Us) => output.push_str("usize"), + ty::TyUint(ast::UintTy::U8) => output.push_str("u8"), + ty::TyUint(ast::UintTy::U16) => output.push_str("u16"), + ty::TyUint(ast::UintTy::U32) => output.push_str("u32"), + ty::TyUint(ast::UintTy::U64) => output.push_str("u64"), + ty::TyFloat(ast::FloatTy::F32) => output.push_str("f32"), + ty::TyFloat(ast::FloatTy::F64) => output.push_str("f64"), + ty::TyAdt(adt_def, substs) => { + self.push_def_path(adt_def.did, output); + self.push_type_params(substs, &[], output); + }, + ty::TyTuple(component_types) => { + output.push('('); + for &component_type in component_types { + self.push_type_name(component_type, output); output.push_str(", "); } - output.pop(); - output.pop(); - } - - if sig.variadic { - if !sig.inputs.is_empty() { - output.push_str(", ..."); - } else { - output.push_str("..."); + if !component_types.is_empty() { + output.pop(); + output.pop(); + } + output.push(')'); + }, + ty::TyBox(inner_type) => { + output.push_str("Box<"); + self.push_type_name(inner_type, output); + output.push('>'); + }, + ty::TyRawPtr(ty::TypeAndMut { ty: inner_type, mutbl } ) => { + output.push('*'); + match mutbl { + hir::MutImmutable => output.push_str("const "), + hir::MutMutable => output.push_str("mut "), } - } - output.push(')'); + self.push_type_name(inner_type, output); + }, + ty::TyRef(_, ty::TypeAndMut { ty: inner_type, mutbl }) => { + output.push('&'); + if mutbl == hir::MutMutable { + output.push_str("mut "); + } - if !sig.output.is_nil() { - output.push_str(" -> "); - push_unique_type_name(tcx, sig.output, output); + self.push_type_name(inner_type, output); + }, + ty::TyArray(inner_type, len) => { + output.push('['); + self.push_type_name(inner_type, output); + write!(output, "; {}", len).unwrap(); + output.push(']'); + }, + ty::TySlice(inner_type) => { + output.push('['); + self.push_type_name(inner_type, output); + output.push(']'); + }, + ty::TyTrait(ref trait_data) => { + self.push_def_path(trait_data.principal.def_id(), output); + self.push_type_params(trait_data.principal.skip_binder().substs, + &trait_data.projection_bounds, + output); + }, + ty::TyFnDef(.., &ty::BareFnTy{ unsafety, abi, ref sig } ) | + ty::TyFnPtr(&ty::BareFnTy{ unsafety, abi, ref sig } ) => { + if unsafety == hir::Unsafety::Unsafe { + output.push_str("unsafe "); + } + + if abi != ::abi::Abi::Rust { + output.push_str("extern \""); + output.push_str(abi.name()); + output.push_str("\" "); + } + + output.push_str("fn("); + + let ty::FnSig { + inputs: sig_inputs, + output: sig_output, + variadic: sig_variadic + } = self.tcx.erase_late_bound_regions_and_normalize(sig); + + if !sig_inputs.is_empty() { + for ¶meter_type in &sig_inputs { + self.push_type_name(parameter_type, output); + output.push_str(", "); + } + output.pop(); + output.pop(); + } + + if sig_variadic { + if !sig_inputs.is_empty() { + output.push_str(", ..."); + } else { + output.push_str("..."); + } + } + + output.push(')'); + + if !sig_output.is_nil() { + output.push_str(" -> "); + self.push_type_name(sig_output, output); + } + }, + ty::TyClosure(def_id, ref closure_substs) => { + self.push_def_path(def_id, output); + let generics = self.tcx.item_generics(self.tcx.closure_base_def_id(def_id)); + let substs = closure_substs.substs.truncate_to(self.tcx, generics); + self.push_type_params(substs, &[], output); + } + ty::TyError | + ty::TyInfer(_) | + ty::TyProjection(..) | + ty::TyParam(_) | + ty::TyAnon(..) => { + bug!("DefPathBasedNames: Trying to create type name for \ + unexpected type: {:?}", t); } - }, - ty::TyClosure(def_id, ref closure_substs) => { - push_item_name(tcx, def_id, output); - output.push_str("{"); - output.push_str(&format!("{}:{}", def_id.krate, def_id.index.as_usize())); - output.push_str("}"); - push_type_params(tcx, closure_substs.func_substs, &[], output); - } - ty::TyError | - ty::TyInfer(_) | - ty::TyProjection(..) | - ty::TyParam(_) | - ty::TyAnon(..) => { - bug!("debuginfo: Trying to create type name for \ - unexpected type: {:?}", t); } } -} -fn push_item_name(tcx: TyCtxt, - def_id: DefId, - output: &mut String) { - let def_path = tcx.def_path(def_id); + pub fn push_def_path(&self, + def_id: DefId, + output: &mut String) { + let def_path = self.tcx.def_path(def_id); - // some_crate:: - output.push_str(&tcx.crate_name(def_path.krate)); - output.push_str("::"); + // some_crate:: + if !(self.omit_local_crate_name && def_id.is_local()) { + output.push_str(&self.tcx.crate_name(def_path.krate)); + output.push_str("::"); + } - // foo::bar::ItemName:: - for part in tcx.def_path(def_id).data { - output.push_str(&format!("{}[{}]::", - part.data.as_interned_str(), - part.disambiguator)); + // foo::bar::ItemName:: + for part in self.tcx.def_path(def_id).data { + if self.omit_disambiguators { + write!(output, "{}::", part.data.as_interned_str()).unwrap(); + } else { + write!(output, "{}[{}]::", + part.data.as_interned_str(), + part.disambiguator).unwrap(); + } + } + + // remove final "::" + output.pop(); + output.pop(); } - // remove final "::" - output.pop(); - output.pop(); -} + pub fn push_type_params(&self, + substs: &Substs<'tcx>, + projections: &[ty::PolyExistentialProjection<'tcx>], + output: &mut String) { + if substs.types().next().is_none() && projections.is_empty() { + return; + } -fn push_type_params<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - substs: &Substs<'tcx>, - projections: &[ty::PolyExistentialProjection<'tcx>], - output: &mut String) { - if substs.types().next().is_none() && projections.is_empty() { - return; + output.push('<'); + + for type_parameter in substs.types() { + self.push_type_name(type_parameter, output); + output.push_str(", "); + } + + for projection in projections { + let projection = projection.skip_binder(); + let name = &projection.item_name.as_str(); + output.push_str(name); + output.push_str("="); + self.push_type_name(projection.ty, output); + output.push_str(", "); + } + + output.pop(); + output.pop(); + + output.push('>'); } - output.push('<'); - - for type_parameter in substs.types() { - push_unique_type_name(tcx, type_parameter, output); - output.push_str(", "); + pub fn push_instance_as_string(&self, + instance: Instance<'tcx>, + output: &mut String) { + self.push_def_path(instance.def, output); + self.push_type_params(instance.substs, &[], output); } - - for projection in projections { - let projection = projection.skip_binder(); - let name = &projection.item_name.as_str(); - output.push_str(name); - output.push_str("="); - push_unique_type_name(tcx, projection.ty, output); - output.push_str(", "); - } - - output.pop(); - output.pop(); - - output.push('>'); -} - -fn push_instance_as_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - instance: Instance<'tcx>, - output: &mut String) { - push_item_name(tcx, instance.def, output); - push_type_params(tcx, instance.substs, &[], output); -} - -pub fn def_id_to_string(tcx: TyCtxt, def_id: DefId) -> String { - let mut output = String::new(); - push_item_name(tcx, def_id, &mut output); - output -} - -pub fn type_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - ty: Ty<'tcx>) - -> String { - let mut output = String::new(); - push_unique_type_name(tcx, ty, &mut output); - output } diff --git a/src/librustc_trans/type_.rs b/src/librustc_trans/type_.rs index 2a6f79d3ed57..2b2776acab86 100644 --- a/src/librustc_trans/type_.rs +++ b/src/librustc_trans/type_.rs @@ -15,7 +15,6 @@ use llvm::{TypeRef, Bool, False, True, TypeKind}; use llvm::{Float, Double, X86_FP80, PPC_FP128, FP128}; use context::CrateContext; -use util::nodemap::FxHashMap; use syntax::ast; use rustc::ty::layout; @@ -24,7 +23,6 @@ use std::ffi::CString; use std::fmt; use std::mem; use std::ptr; -use std::cell::RefCell; use libc::c_uint; @@ -321,26 +319,3 @@ impl Type { } } } - -/* Memory-managed object interface to type handles. */ - -pub struct TypeNames { - named_types: RefCell>, -} - -impl TypeNames { - pub fn new() -> TypeNames { - TypeNames { - named_types: RefCell::new(FxHashMap()) - } - } - - pub fn associate_type(&self, s: &str, t: &Type) { - assert!(self.named_types.borrow_mut().insert(s.to_string(), - t.to_ref()).is_none()); - } - - pub fn find_type(&self, s: &str) -> Option { - self.named_types.borrow().get(s).map(|x| Type::from_ref(*x)) - } -} diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index 132b0a910b9c..16d4f97200cb 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -10,14 +10,12 @@ #![allow(non_camel_case_types)] -use rustc::hir::def_id::DefId; use abi::FnType; use adt; use common::*; use machine; use rustc::ty::{self, Ty, TypeFoldable}; -use rustc::ty::subst::Substs; - +use trans_item::DefPathBasedNames; use type_::Type; use syntax::ast; @@ -238,7 +236,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> if let ty::TyStr = ty.sty { // This means we get a nicer name in the output (str is always // unsized). - cx.tn().find_type("str_slice").unwrap() + cx.str_slice_type() } else { let ptr_ty = in_memory_type_of(cx, ty).ptr_to(); let info_ty = unsized_info_ty(cx, ty); @@ -282,12 +280,12 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> let n = t.simd_size(cx.tcx()) as u64; Type::vector(&llet, n) } - ty::TyAdt(def, substs) => { + ty::TyAdt(..) => { // Only create the named struct, but don't fill it in. We // fill it in *after* placing it into the type cache. This // avoids creating more than one copy of the enum when one // of the enum's variants refers to the enum itself. - let name = llvm_type_name(cx, def.did, substs); + let name = llvm_type_name(cx, t); adt::incomplete_type_of(cx, t, &name[..]) } @@ -319,21 +317,9 @@ pub fn align_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) layout.align(&cx.tcx().data_layout).abi() as machine::llalign } -fn llvm_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, - did: DefId, - substs: &Substs<'tcx>) - -> String { - let base = cx.tcx().item_path_str(did); - let strings: Vec = substs.types().map(|t| t.to_string()).collect(); - let tstr = if strings.is_empty() { - base - } else { - format!("{}<{}>", base, strings.join(", ")) - }; - - if did.is_local() { - tstr - } else { - format!("{}.{}", did.krate, tstr) - } +fn llvm_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> String { + let mut name = String::with_capacity(32); + let printer = DefPathBasedNames::new(cx.tcx(), true, true); + printer.push_type_name(ty, &mut name); + name } diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml index 720423371a83..f08d26373e50 100644 --- a/src/librustc_typeck/Cargo.toml +++ b/src/librustc_typeck/Cargo.toml @@ -18,6 +18,7 @@ rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_const_eval = { path = "../librustc_const_eval" } rustc_const_math = { path = "../librustc_const_math" } +rustc_data_structures = { path = "../librustc_data_structures" } rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" } syntax_pos = { path = "../libsyntax_pos" } rustc_errors = { path = "../librustc_errors" } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 513b4860d5e8..9bde6b0c4d99 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -16,12 +16,12 @@ //! somewhat differently during the collect and check phases, //! particularly with respect to looking up the types of top-level //! items. In the collect phase, the crate context is used as the -//! `AstConv` instance; in this phase, the `get_item_type_scheme()` -//! function triggers a recursive call to `type_scheme_of_item()` +//! `AstConv` instance; in this phase, the `get_item_type()` +//! function triggers a recursive call to `type_of_item()` //! (note that `ast_ty_to_ty()` will detect recursive types and report //! an error). In the check phase, when the FnCtxt is used as the -//! `AstConv`, `get_item_type_scheme()` just looks up the item type in -//! `tcx.tcache` (using `ty::lookup_item_type`). +//! `AstConv`, `get_item_type()` just looks up the item type in +//! `tcx.types` (using `TyCtxt::item_type`). //! //! The `RegionScope` trait controls what happens when the user does //! not specify a region in some location where a region is required @@ -85,11 +85,8 @@ pub trait AstConv<'gcx, 'tcx> { fn get_generics(&self, span: Span, id: DefId) -> Result<&'tcx ty::Generics<'tcx>, ErrorReported>; - /// Identify the type scheme for an item with a type, like a type - /// alias, fn, or struct. This allows you to figure out the set of - /// type parameters defined on the item. - fn get_item_type_scheme(&self, span: Span, id: DefId) - -> Result, ErrorReported>; + /// Identify the type for an item, like a type alias, fn, or struct. + fn get_item_type(&self, span: Span, id: DefId) -> Result, ErrorReported>; /// Returns the `TraitDef` for a given trait. This allows you to /// figure out the set of type parameters defined on the trait. @@ -938,8 +935,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { -> Ty<'tcx> { let tcx = self.tcx(); - let decl_ty = match self.get_item_type_scheme(span, did) { - Ok(type_scheme) => type_scheme.ty, + let decl_ty = match self.get_item_type(span, did) { + Ok(ty) => ty, Err(ErrorReported) => { return tcx.types.err; } @@ -1521,8 +1518,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // Self in impl (we know the concrete type). tcx.prohibit_type_params(base_segments); - let impl_id = tcx.map.as_local_node_id(def_id).unwrap(); - let ty = tcx.tables().node_id_to_type(impl_id); + let ty = tcx.item_type(def_id); if let Some(free_substs) = self.get_free_substs() { ty.subst(tcx, free_substs) } else { @@ -2152,27 +2148,32 @@ fn check_type_argument_count(tcx: TyCtxt, span: Span, supplied: usize, "expected" }; let arguments_plural = if required == 1 { "" } else { "s" }; - struct_span_err!(tcx.sess, span, E0243, "wrong number of type arguments") - .span_label( - span, - &format!("{} {} type argument{}, found {}", - expected, required, arguments_plural, supplied) - ) + + struct_span_err!(tcx.sess, span, E0243, + "wrong number of type arguments: {} {}, found {}", + expected, required, supplied) + .span_label(span, + &format!("{} {} type argument{}", + expected, + required, + arguments_plural)) .emit(); } else if supplied > accepted { - let expected = if required == 0 { - "expected no".to_string() - } else if required < accepted { + let expected = if required < accepted { format!("expected at most {}", accepted) } else { format!("expected {}", accepted) }; let arguments_plural = if accepted == 1 { "" } else { "s" }; - struct_span_err!(tcx.sess, span, E0244, "wrong number of type arguments") + struct_span_err!(tcx.sess, span, E0244, + "wrong number of type arguments: {}, found {}", + expected, supplied) .span_label( span, - &format!("{} type argument{}, found {}", expected, arguments_plural, supplied) + &format!("{} type argument{}", + if accepted == 0 { "expected no" } else { &expected }, + arguments_plural) ) .emit(); } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index ca630624cdb3..556d1f84fccd 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -11,7 +11,8 @@ use rustc::hir::{self, PatKind}; use rustc::hir::def::{Def, CtorKind}; use rustc::hir::pat_util::EnumerateAndAdjustIterator; -use rustc::infer::{self, InferOk, TypeOrigin}; +use rustc::infer; +use rustc::traits::ObligationCauseCode; use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference}; use check::{FnCtxt, Expectation, Diverges}; use util::nodemap::FxHashMap; @@ -450,17 +451,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => false }; - let origin = if is_if_let_fallback { - TypeOrigin::IfExpressionWithNoElse(expr.span) + let cause = if is_if_let_fallback { + self.cause(expr.span, ObligationCauseCode::IfExpressionWithNoElse) } else { - TypeOrigin::MatchExpressionArm(expr.span, arm.body.span, match_src) + self.cause(expr.span, ObligationCauseCode::MatchExpressionArm { + arm_span: arm.body.span, + source: match_src + }) }; let result = if is_if_let_fallback { - self.eq_types(true, origin, arm_ty, result_ty) - .map(|InferOk { obligations, .. }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); + self.eq_types(true, &cause, arm_ty, result_ty) + .map(|infer_ok| { + self.register_infer_ok_obligations(infer_ok); arm_ty }) } else if i == 0 { @@ -468,7 +471,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.try_coerce(&arm.body, arm_ty, coerce_first) } else { let prev_arms = || arms[..i].iter().map(|arm| &*arm.body); - self.try_find_coercion_lub(origin, prev_arms, result_ty, &arm.body, arm_ty) + self.try_find_coercion_lub(&cause, prev_arms, result_ty, &arm.body, arm_ty) }; result_ty = match result { @@ -479,7 +482,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } else { (result_ty, arm_ty) }; - self.report_mismatched_types(origin, expected, found, e); + self.report_mismatched_types(&cause, expected, found, e); self.tcx.types.err } }; diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index c456b9358b3e..4edf0011cb39 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -105,7 +105,6 @@ enum CastError { NeedViaPtr, NeedViaThinPtr, NeedViaInt, - NeedViaUsize, NonScalar, } @@ -139,26 +138,39 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { fn report_cast_error(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, e: CastError) { match e { - CastError::NeedViaPtr | CastError::NeedViaThinPtr | - CastError::NeedViaInt | - CastError::NeedViaUsize => { + CastError::NeedViaPtr => { + let mut err = fcx.type_error_struct(self.span, + |actual| { + format!("casting `{}` as `{}` is invalid", + actual, + fcx.ty_to_string(self.cast_ty)) + }, + self.expr_ty); + if self.cast_ty.is_uint() { + err.help(&format!("cast through {} first", + match e { + CastError::NeedViaPtr => "a raw pointer", + CastError::NeedViaThinPtr => "a thin pointer", + _ => bug!(), + })); + } + err.emit(); + } + CastError::NeedViaInt => { fcx.type_error_struct(self.span, - |actual| { - format!("casting `{}` as `{}` is invalid", - actual, - fcx.ty_to_string(self.cast_ty)) - }, - self.expr_ty) - .help(&format!("cast through {} first", - match e { - CastError::NeedViaPtr => "a raw pointer", - CastError::NeedViaThinPtr => "a thin pointer", - CastError::NeedViaInt => "an integer", - CastError::NeedViaUsize => "a usize", - _ => bug!(), - })) - .emit(); + |actual| { + format!("casting `{}` as `{}` is invalid", + actual, + fcx.ty_to_string(self.cast_ty)) + }, + self.expr_ty) + .help(&format!("cast through {} first", + match e { + CastError::NeedViaInt => "an integer", + _ => bug!(), + })) + .emit(); } CastError::CastToBool => { struct_span_err!(fcx.tcx.sess, self.span, E0054, "cannot cast as `bool`") @@ -366,21 +378,23 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { (Int(Bool), Float) | (Int(CEnum), Float) | (Int(Char), Float) => Err(CastError::NeedViaInt), + (Int(Bool), Ptr(_)) | (Int(CEnum), Ptr(_)) | - (Int(Char), Ptr(_)) => Err(CastError::NeedViaUsize), + (Int(Char), Ptr(_)) | + (Ptr(_), Float) | + (FnPtr, Float) | + (Float, Ptr(_)) => Err(CastError::IllegalCast), // ptr -> * (Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast (Ptr(m_expr), Int(_)) => self.check_ptr_addr_cast(fcx, m_expr), // ptr-addr-cast - (Ptr(_), Float) | (FnPtr, Float) => Err(CastError::NeedViaUsize), (FnPtr, Int(_)) => Ok(CastKind::FnPtrAddrCast), (RPtr(_), Int(_)) | (RPtr(_), Float) => Err(CastError::NeedViaPtr), // * -> ptr (Int(_), Ptr(mt)) => self.check_addr_ptr_cast(fcx, mt), // addr-ptr-cast (FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt), - (Float, Ptr(_)) => Err(CastError::NeedViaUsize), (RPtr(rmt), Ptr(mt)) => self.check_ref_cast(fcx, rmt, mt), // array-ptr-cast // prim -> prim @@ -391,7 +405,6 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { (Int(_), Int(_)) | (Int(_), Float) | (Float, Int(_)) | (Float, Float) => { Ok(CastKind::NumericCast) } - } } diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index af834f3f84d4..75287d4064ae 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -47,12 +47,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { body: &'gcx hir::Expr, expected_sig: Option>) -> Ty<'tcx> { - let expr_def_id = self.tcx.map.local_def_id(expr.id); - debug!("check_closure opt_kind={:?} expected_sig={:?}", opt_kind, expected_sig); + let expr_def_id = self.tcx.map.local_def_id(expr.id); let mut fn_ty = AstConv::ty_of_closure(self, hir::Unsafety::Normal, decl, @@ -62,16 +61,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Create type variables (for now) to represent the transformed // types of upvars. These will be unified during the upvar // inference phase (`upvar.rs`). - let num_upvars = self.tcx.with_freevars(expr.id, |fv| fv.len()); - let upvar_tys = self.next_ty_vars(num_upvars); - - debug!("check_closure: expr.id={:?} upvar_tys={:?}", - expr.id, - upvar_tys); - let closure_type = self.tcx.mk_closure(expr_def_id, - self.parameter_environment.free_substs, - &upvar_tys); + self.parameter_environment.free_substs.extend_to(self.tcx, expr_def_id, + |_, _| span_bug!(expr.span, "closure has region param"), + |_, _| self.infcx.next_ty_var() + ) + ); + + debug!("check_closure: expr.id={:?} closure_type={:?}", expr.id, closure_type); let fn_sig = self.tcx .liberate_late_bound_regions(self.tcx.region_maps.call_site_extent(expr.id, body.id), diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 16493412d690..718c273785ae 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -63,8 +63,8 @@ use check::FnCtxt; use rustc::hir; -use rustc::infer::{Coercion, InferOk, TypeOrigin, TypeTrace}; -use rustc::traits::{self, ObligationCause}; +use rustc::infer::{Coercion, InferOk, TypeTrace}; +use rustc::traits::{self, ObligationCause, ObligationCauseCode}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; use rustc::ty::{self, LvaluePreference, TypeAndMut, Ty}; use rustc::ty::fold::TypeFoldable; @@ -78,7 +78,7 @@ use std::ops::Deref; struct Coerce<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - origin: TypeOrigin, + cause: ObligationCause<'tcx>, use_lub: bool, unsizing_obligations: RefCell>>, } @@ -104,10 +104,10 @@ fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability, } impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { - fn new(fcx: &'f FnCtxt<'f, 'gcx, 'tcx>, origin: TypeOrigin) -> Self { + fn new(fcx: &'f FnCtxt<'f, 'gcx, 'tcx>, cause: ObligationCause<'tcx>) -> Self { Coerce { fcx: fcx, - origin: origin, + cause: cause, use_lub: false, unsizing_obligations: RefCell::new(vec![]), } @@ -115,19 +115,14 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { self.commit_if_ok(|_| { - let trace = TypeTrace::types(self.origin, false, a, b); + let trace = TypeTrace::types(&self.cause, false, a, b); if self.use_lub { self.lub(false, trace, &a, &b) - .map(|InferOk { value, obligations }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - value - }) + .map(|ok| self.register_infer_ok_obligations(ok)) } else { self.sub(false, trace, &a, &b) .map(|InferOk { value, obligations }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); + self.fcx.register_predicates(obligations); value }) } @@ -238,7 +233,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { _ => return self.unify_and_identity(a, b), }; - let span = self.origin.span(); + let span = self.cause.span; let mut first_error = None; let mut r_borrow_var = None; @@ -430,7 +425,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { (&ty::TyRef(_, mt_a), &ty::TyRef(_, mt_b)) => { coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?; - let coercion = Coercion(self.origin.span()); + let coercion = Coercion(self.cause.span); let r_borrow = self.next_region_var(coercion); (mt_a.ty, Some(AutoBorrow::Ref(r_borrow, mt_b.mutbl))) } @@ -449,7 +444,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let mut leftover_predicates = vec![]; // Create an obligation for `Source: CoerceUnsized`. - let cause = ObligationCause::misc(self.origin.span(), self.body_id); + let cause = ObligationCause::misc(self.cause.span, self.body_id); queue.push_back(self.tcx .predicate_for_trait_def(cause, coerce_unsized_did, 0, source, &[target])); @@ -635,7 +630,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let source = self.resolve_type_vars_with_obligations(expr_ty); debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target); - let mut coerce = Coerce::new(self, TypeOrigin::ExprAssignable(expr.span)); + let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable); + let mut coerce = Coerce::new(self, cause); self.commit_if_ok(|_| { let adjustment = apply(&mut coerce, &|| Some(expr), source, target)?; if !adjustment.is_identity() { @@ -655,7 +651,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// tries to unify the types, potentially inserting coercions on any of the /// provided expressions and returns their LUB (aka "common supertype"). pub fn try_find_coercion_lub<'b, E, I>(&self, - origin: TypeOrigin, + cause: &ObligationCause<'tcx>, exprs: E, prev_ty: Ty<'tcx>, new: &'b hir::Expr, @@ -669,7 +665,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let new_ty = self.resolve_type_vars_with_obligations(new_ty); debug!("coercion::try_find_lub({:?}, {:?})", prev_ty, new_ty); - let trace = TypeTrace::types(origin, true, prev_ty, new_ty); + let trace = TypeTrace::types(cause, true, prev_ty, new_ty); // Special-case that coercion alone cannot handle: // Two function item types of differing IDs or Substs. @@ -677,21 +673,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { (&ty::TyFnDef(a_def_id, a_substs, a_fty), &ty::TyFnDef(b_def_id, b_substs, b_fty)) => { // The signature must always match. let fty = self.lub(true, trace.clone(), &a_fty, &b_fty) - .map(|InferOk { value, obligations }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - value - })?; + .map(|ok| self.register_infer_ok_obligations(ok))?; if a_def_id == b_def_id { // Same function, maybe the parameters match. let substs = self.commit_if_ok(|_| { self.lub(true, trace.clone(), &a_substs, &b_substs) - .map(|InferOk { value, obligations }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - value - }) + .map(|ok| self.register_infer_ok_obligations(ok)) }); if let Ok(substs) = substs { @@ -715,7 +703,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => {} } - let mut coerce = Coerce::new(self, origin); + let mut coerce = Coerce::new(self, cause.clone()); coerce.use_lub = true; // First try to coerce the new expression to the type of the previous ones, @@ -760,11 +748,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if !noop { return self.commit_if_ok(|_| { self.lub(true, trace.clone(), &prev_ty, &new_ty) - .map(|InferOk { value, obligations }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - value - }) + .map(|ok| self.register_infer_ok_obligations(ok)) }); } } @@ -777,11 +761,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } else { self.commit_if_ok(|_| { self.lub(true, trace, &prev_ty, &new_ty) - .map(|InferOk { value, obligations }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - value - }) + .map(|ok| self.register_infer_ok_obligations(ok)) }) } } diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index ffde940b3f48..2602ff05badd 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -9,10 +9,10 @@ // except according to those terms. use rustc::hir; -use rustc::infer::{self, InferOk, TypeOrigin}; +use rustc::infer::{self, InferOk}; use rustc::middle::free_region::FreeRegionMap; use rustc::ty; -use rustc::traits::{self, Reveal}; +use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal}; use rustc::ty::error::{ExpectedFound, TypeError}; use rustc::ty::subst::{Subst, Substs}; use rustc::hir::{ImplItemKind, TraitItem_, Ty_}; @@ -95,6 +95,17 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let trait_to_impl_substs = impl_trait_ref.substs; + let cause = ObligationCause { + span: impl_m_span, + body_id: impl_m_body_id, + code: ObligationCauseCode::CompareImplMethodObligation { + item_name: impl_m.name, + impl_item_def_id: impl_m.def_id, + trait_item_def_id: trait_m.def_id, + lint_id: if !old_broken_mode { Some(impl_m_body_id) } else { None }, + }, + }; + // This code is best explained by example. Consider a trait: // // trait Trait<'t,T> { @@ -174,10 +185,10 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, debug!("compare_impl_method: trait_to_skol_substs={:?}", trait_to_skol_substs); - let impl_m_generics = tcx.lookup_generics(impl_m.def_id); - let trait_m_generics = tcx.lookup_generics(trait_m.def_id); - let impl_m_predicates = tcx.lookup_predicates(impl_m.def_id); - let trait_m_predicates = tcx.lookup_predicates(trait_m.def_id); + let impl_m_generics = tcx.item_generics(impl_m.def_id); + let trait_m_generics = tcx.item_generics(trait_m.def_id); + let impl_m_predicates = tcx.item_predicates(impl_m.def_id); + let trait_m_predicates = tcx.item_predicates(trait_m.def_id); // Check region bounds. check_region_bounds_on_impl_method(ccx, @@ -193,7 +204,7 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // environment. We can't just use `impl_env.caller_bounds`, // however, because we want to replace all late-bound regions with // region variables. - let impl_predicates = tcx.lookup_predicates(impl_m_predicates.parent.unwrap()); + let impl_predicates = tcx.item_predicates(impl_m_predicates.parent.unwrap()); let mut hybrid_preds = impl_predicates.instantiate(tcx, impl_to_skol_substs); debug!("compare_impl_method: impl_bounds={:?}", hybrid_preds); @@ -235,20 +246,9 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let traits::Normalized { value: predicate, .. } = traits::normalize(&mut selcx, normalize_cause.clone(), &predicate); - let cause = traits::ObligationCause { - span: impl_m_span, - body_id: impl_m_body_id, - code: traits::ObligationCauseCode::CompareImplMethodObligation { - item_name: impl_m.name, - impl_item_def_id: impl_m.def_id, - trait_item_def_id: trait_m.def_id, - lint_id: if !old_broken_mode { Some(impl_m_body_id) } else { None }, - }, - }; - fulfillment_cx.borrow_mut().register_predicate_obligation( &infcx, - traits::Obligation::new(cause, predicate)); + traits::Obligation::new(cause.clone(), predicate)); } // We now need to check that the signature of the impl method is @@ -266,10 +266,9 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // Compute skolemized form of impl and trait method tys. let tcx = infcx.tcx; - let origin = TypeOrigin::MethodCompatCheck(impl_m_span); let m_fty = |method: &ty::AssociatedItem| { - match tcx.lookup_item_type(method.def_id).ty.sty { + match tcx.item_type(method.def_id).sty { ty::TyFnDef(_, _, f) => f, _ => bug!() } @@ -315,7 +314,7 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, debug!("compare_impl_method: trait_fty={:?}", trait_fty); - let sub_result = infcx.sub_types(false, origin, impl_fty, trait_fty) + let sub_result = infcx.sub_types(false, &cause, impl_fty, trait_fty) .map(|InferOk { obligations, .. }| { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()); @@ -328,22 +327,25 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let (impl_err_span, trait_err_span) = extract_spans_for_error_reporting(&infcx, &terr, - origin, + &cause, impl_m, impl_sig, trait_m, trait_sig); - let origin = TypeOrigin::MethodCompatCheck(impl_err_span); + let cause = ObligationCause { + span: impl_err_span, + ..cause.clone() + }; let mut diag = struct_span_err!(tcx.sess, - origin.span(), + cause.span, E0053, "method `{}` has an incompatible type for trait", trait_m.name); infcx.note_type_err(&mut diag, - origin, + &cause, trait_err_span.map(|sp| (sp, format!("type in trait"))), Some(infer::ValuePairs::Types(ExpectedFound { expected: trait_fty, @@ -429,7 +431,7 @@ fn check_region_bounds_on_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>, terr: &TypeError, - origin: TypeOrigin, + cause: &ObligationCause<'tcx>, impl_m: &ty::AssociatedItem, impl_sig: ty::FnSig<'tcx>, trait_m: &ty::AssociatedItem, @@ -478,9 +480,9 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a } } }) - .unwrap_or((origin.span(), tcx.map.span_if_local(trait_m.def_id))) + .unwrap_or((cause.span, tcx.map.span_if_local(trait_m.def_id))) } else { - (origin.span(), tcx.map.span_if_local(trait_m.def_id)) + (cause.span, tcx.map.span_if_local(trait_m.def_id)) } } TypeError::Sorts(ExpectedFound { .. }) => { @@ -499,25 +501,25 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a .zip(impl_m_iter) .zip(trait_m_iter) .filter_map(|(((impl_arg_ty, trait_arg_ty), impl_arg), trait_arg)| { - match infcx.sub_types(true, origin, trait_arg_ty, impl_arg_ty) { + match infcx.sub_types(true, &cause, trait_arg_ty, impl_arg_ty) { Ok(_) => None, Err(_) => Some((impl_arg.ty.span, Some(trait_arg.ty.span))), } }) .next() .unwrap_or_else(|| { - if infcx.sub_types(false, origin, impl_sig.output, trait_sig.output) + if infcx.sub_types(false, &cause, impl_sig.output, trait_sig.output) .is_err() { (impl_m_output.span(), Some(trait_m_output.span())) } else { - (origin.span(), tcx.map.span_if_local(trait_m.def_id)) + (cause.span, tcx.map.span_if_local(trait_m.def_id)) } }) } else { - (origin.span(), tcx.map.span_if_local(trait_m.def_id)) + (cause.span, tcx.map.span_if_local(trait_m.def_id)) } } - _ => (origin.span(), tcx.map.span_if_local(trait_m.def_id)), + _ => (cause.span, tcx.map.span_if_local(trait_m.def_id)), } } @@ -542,7 +544,7 @@ fn compare_self_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ty::ImplContainer(_) => impl_trait_ref.self_ty(), ty::TraitContainer(_) => tcx.mk_self_type() }; - let method_ty = tcx.lookup_item_type(method.def_id).ty; + let method_ty = tcx.item_type(method.def_id); let self_arg_ty = *method_ty.fn_sig().input(0).skip_binder(); match ExplicitSelf::determine(untransformed_self_ty, self_arg_ty) { ExplicitSelf::ByValue => "self".to_string(), @@ -601,8 +603,8 @@ fn compare_number_of_generics<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, trait_item_span: Option) -> Result<(), ErrorReported> { let tcx = ccx.tcx; - let impl_m_generics = tcx.lookup_generics(impl_m.def_id); - let trait_m_generics = tcx.lookup_generics(trait_m.def_id); + let impl_m_generics = tcx.item_generics(impl_m.def_id); + let trait_m_generics = tcx.item_generics(trait_m.def_id); let num_impl_m_type_params = impl_m_generics.types.len(); let num_trait_m_type_params = trait_m_generics.types.len(); if num_impl_m_type_params != num_trait_m_type_params { @@ -672,7 +674,7 @@ fn compare_number_of_method_arguments<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, -> Result<(), ErrorReported> { let tcx = ccx.tcx; let m_fty = |method: &ty::AssociatedItem| { - match tcx.lookup_item_type(method.def_id).ty.sty { + match tcx.item_type(method.def_id).sty { ty::TyFnDef(_, _, f) => f, _ => bug!() } @@ -785,9 +787,9 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, trait_to_skol_substs); // Compute skolemized form of impl and trait const tys. - let impl_ty = tcx.lookup_item_type(impl_c.def_id).ty.subst(tcx, impl_to_skol_substs); - let trait_ty = tcx.lookup_item_type(trait_c.def_id).ty.subst(tcx, trait_to_skol_substs); - let mut origin = TypeOrigin::Misc(impl_c_span); + let impl_ty = tcx.item_type(impl_c.def_id).subst(tcx, impl_to_skol_substs); + let trait_ty = tcx.item_type(trait_c.def_id).subst(tcx, trait_to_skol_substs); + let mut cause = ObligationCause::misc(impl_c_span, impl_c_node_id); let err = infcx.commit_if_ok(|_| { // There is no "body" here, so just pass dummy id. @@ -807,11 +809,12 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, debug!("compare_const_impl: trait_ty={:?}", trait_ty); - infcx.sub_types(false, origin, impl_ty, trait_ty) - .map(|InferOk { obligations, .. }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()) - }) + infcx.sub_types(false, &cause, impl_ty, trait_ty) + .map(|InferOk { obligations, value: () }| { + for obligation in obligations { + fulfillment_cx.register_predicate_obligation(&infcx, obligation); + } + }) }); if let Err(terr) = err { @@ -821,12 +824,12 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // Locate the Span containing just the type of the offending impl match tcx.map.expect_impl_item(impl_c_node_id).node { - ImplItemKind::Const(ref ty, _) => origin = TypeOrigin::Misc(ty.span), + ImplItemKind::Const(ref ty, _) => cause.span = ty.span, _ => bug!("{:?} is not a impl const", impl_c), } let mut diag = struct_span_err!(tcx.sess, - origin.span(), + cause.span, E0326, "implemented const `{}` has an incompatible type for \ trait", @@ -840,7 +843,7 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, }; infcx.note_type_err(&mut diag, - origin, + &cause, Some((trait_c_span, format!("type in trait"))), Some(infer::ValuePairs::Types(ExpectedFound { expected: trait_ty, diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index d622bc7f751d..ef1c08bdab54 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -11,7 +11,8 @@ use check::FnCtxt; use rustc::ty::Ty; -use rustc::infer::{InferOk, TypeOrigin}; +use rustc::infer::{InferOk}; +use rustc::traits::ObligationCause; use syntax_pos::Span; use rustc::hir; @@ -20,34 +21,32 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Requires that the two types unify, and prints an error message if // they don't. pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { - let origin = TypeOrigin::Misc(sp); - match self.sub_types(false, origin, actual, expected) { - Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); + let cause = self.misc(sp); + match self.sub_types(false, &cause, actual, expected) { + Ok(InferOk { obligations, value: () }) => { + self.register_predicates(obligations); }, Err(e) => { - self.report_mismatched_types(origin, expected, actual, e); + self.report_mismatched_types(&cause, expected, actual, e); } } } pub fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { - self.demand_eqtype_with_origin(TypeOrigin::Misc(sp), expected, actual); + self.demand_eqtype_with_origin(&self.misc(sp), expected, actual); } pub fn demand_eqtype_with_origin(&self, - origin: TypeOrigin, + cause: &ObligationCause<'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>) { - match self.eq_types(false, origin, actual, expected) { - Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); + match self.eq_types(false, cause, actual, expected) { + Ok(InferOk { obligations, value: () }) => { + self.register_predicates(obligations); }, Err(e) => { - self.report_mismatched_types(origin, expected, actual, e); + self.report_mismatched_types(cause, expected, actual, e); } } } @@ -56,9 +55,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn demand_coerce(&self, expr: &hir::Expr, checked_ty: Ty<'tcx>, expected: Ty<'tcx>) { let expected = self.resolve_type_vars_with_obligations(expected); if let Err(e) = self.try_coerce(expr, checked_ty, expected) { - let origin = TypeOrigin::Misc(expr.span); + let cause = self.misc(expr.span); let expr_ty = self.resolve_type_vars_with_obligations(checked_ty); - self.report_mismatched_types(origin, expected, expr_ty, e); + self.report_mismatched_types(&cause, expected, expr_ty, e); } } } diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index a06b3e70881a..8868d1e54f4b 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -17,7 +17,7 @@ use rustc::infer::{self, InferOk}; use middle::region; use rustc::ty::subst::{Subst, Substs}; use rustc::ty::{self, AdtKind, Ty, TyCtxt}; -use rustc::traits::{self, Reveal}; +use rustc::traits::{self, ObligationCause, Reveal}; use util::nodemap::FxHashSet; use syntax::ast; @@ -41,8 +41,8 @@ use syntax_pos::{self, Span}; /// cannot do `struct S; impl Drop for S { ... }`). /// pub fn check_drop_impl(ccx: &CrateCtxt, drop_impl_did: DefId) -> Result<(), ()> { - let dtor_self_type = ccx.tcx.lookup_item_type(drop_impl_did).ty; - let dtor_predicates = ccx.tcx.lookup_predicates(drop_impl_did); + let dtor_self_type = ccx.tcx.item_type(drop_impl_did); + let dtor_predicates = ccx.tcx.item_predicates(drop_impl_did); match dtor_self_type.sty { ty::TyAdt(adt_def, self_to_impl_substs) => { ensure_drop_params_and_item_params_correspond(ccx, @@ -85,7 +85,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>( let tcx = infcx.tcx; let mut fulfillment_cx = traits::FulfillmentContext::new(); - let named_type = tcx.lookup_item_type(self_type_did).ty; + let named_type = tcx.item_type(self_type_did); let named_type = named_type.subst(tcx, &infcx.parameter_environment.free_substs); let drop_impl_span = tcx.map.def_id_span(drop_impl_did, syntax_pos::DUMMY_SP); @@ -93,8 +93,8 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>( infcx.fresh_substs_for_item(drop_impl_span, drop_impl_did); let fresh_impl_self_ty = drop_impl_ty.subst(tcx, fresh_impl_substs); - match infcx.eq_types(true, infer::TypeOrigin::Misc(drop_impl_span), - named_type, fresh_impl_self_ty) { + let cause = &ObligationCause::misc(drop_impl_span, drop_impl_node_id); + match infcx.eq_types(true, cause, named_type, fresh_impl_self_ty) { Ok(InferOk { obligations, .. }) => { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()); @@ -177,7 +177,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>( // We can assume the predicates attached to struct/enum definition // hold. - let generic_assumptions = tcx.lookup_predicates(self_type_did); + let generic_assumptions = tcx.item_predicates(self_type_did); let assumptions_in_impl_context = generic_assumptions.instantiate(tcx, &self_to_impl_substs); let assumptions_in_impl_context = assumptions_in_impl_context.predicates; @@ -482,8 +482,14 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>( Ok(()) } - ty::TyTuple(tys) | - ty::TyClosure(_, ty::ClosureSubsts { upvar_tys: tys, .. }) => { + ty::TyClosure(def_id, substs) => { + for ty in substs.upvar_tys(def_id, tcx) { + iterate_over_potentially_unsafe_regions_in_type(cx, context, ty, depth+1)? + } + Ok(()) + } + + ty::TyTuple(tys) => { for ty in tys { iterate_over_potentially_unsafe_regions_in_type(cx, context, ty, depth+1)? } @@ -570,30 +576,30 @@ fn has_dtor_of_interest<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, // Constructs new Ty just like the type defined by `adt_def` coupled // with `substs`, except each type and lifetime parameter marked as -// `#[may_dangle]` in the Drop impl (identified by `impl_id`) is +// `#[may_dangle]` in the Drop impl (identified by `impl_def_id`) is // respectively mapped to `()` or `'static`. // // For example: If the `adt_def` maps to: // // enum Foo<'a, X, Y> { ... } // -// and the `impl_id` maps to: +// and the `impl_def_id` maps to: // // impl<#[may_dangle] 'a, X, #[may_dangle] Y> Drop for Foo<'a, X, Y> { ... } // // then revises input: `Foo<'r,i64,&'r i64>` to: `Foo<'static,i64,()>` fn revise_self_ty<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, adt_def: ty::AdtDef<'tcx>, - impl_id: DefId, + impl_def_id: DefId, substs: &Substs<'tcx>) -> Ty<'tcx> { // Get generics for `impl Drop` to query for `#[may_dangle]` attr. - let impl_bindings = tcx.lookup_generics(impl_id); + let impl_bindings = tcx.item_generics(impl_def_id); // Get Substs attached to Self on `impl Drop`; process in parallel // with `substs`, replacing dangling entries as appropriate. let self_substs = { - let impl_self_ty: Ty<'tcx> = tcx.lookup_item_type(impl_id).ty; + let impl_self_ty: Ty<'tcx> = tcx.item_type(impl_def_id); if let ty::TyAdt(self_adt_def, self_substs) = impl_self_ty.sty { assert_eq!(adt_def, self_adt_def); self_substs @@ -648,5 +654,5 @@ fn revise_self_ty<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, t }); - return tcx.mk_adt(adt_def, &substs); + tcx.mk_adt(adt_def, &substs) } diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 95d2b2211f5b..77106b8b0c3a 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -12,7 +12,7 @@ //! intrinsics that the compiler exposes. use intrinsics; -use rustc::infer::TypeOrigin; +use rustc::traits::{ObligationCause, ObligationCauseCode}; use rustc::ty::subst::Substs; use rustc::ty::FnSig; use rustc::ty::{self, Ty}; @@ -34,7 +34,6 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, output: Ty<'tcx>) { let tcx = ccx.tcx; let def_id = tcx.map.local_def_id(it.id); - let i_ty = tcx.lookup_item_type(def_id); let substs = Substs::for_item(tcx, def_id, |_, _| tcx.mk_region(ty::ReErased), @@ -49,7 +48,7 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, variadic: false, }), })); - let i_n_tps = i_ty.generics.types.len(); + let i_n_tps = tcx.item_generics(def_id).types.len(); if i_n_tps != n_tps { let span = match it.node { hir::ForeignItemFn(_, ref generics) => generics.span, @@ -64,8 +63,10 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, .emit(); } else { require_same_types(ccx, - TypeOrigin::IntrinsicType(it.span), - i_ty.ty, + &ObligationCause::new(it.span, + it.id, + ObligationCauseCode::IntrinsicType), + tcx.item_type(def_id), fty); } } @@ -330,8 +331,8 @@ pub fn check_platform_intrinsic_type(ccx: &CrateCtxt, }; let tcx = ccx.tcx; - let i_ty = tcx.lookup_item_type(tcx.map.local_def_id(it.id)); - let i_n_tps = i_ty.generics.types.len(); + let def_id = tcx.map.local_def_id(it.id); + let i_n_tps = tcx.item_generics(def_id).types.len(); let name = it.name.as_str(); let (n_tps, inputs, output) = match &*name { @@ -374,7 +375,8 @@ pub fn check_platform_intrinsic_type(ccx: &CrateCtxt, let mut structural_to_nomimal = FxHashMap(); - let sig = tcx.no_late_bound_regions(i_ty.ty.fn_sig()).unwrap(); + let sig = tcx.item_type(def_id).fn_sig(); + let sig = tcx.no_late_bound_regions(sig).unwrap(); if intr.inputs.len() != sig.inputs.len() { span_err!(tcx.sess, it.span, E0444, "platform-specific intrinsic has invalid number of \ diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 3894a7a2097e..54e93978b798 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -17,7 +17,7 @@ use rustc::traits; use rustc::ty::{self, LvaluePreference, NoPreference, PreferMutLvalue, Ty}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; use rustc::ty::fold::TypeFoldable; -use rustc::infer::{self, InferOk, TypeOrigin}; +use rustc::infer::{self, InferOk}; use syntax_pos::Span; use rustc::hir; @@ -276,7 +276,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // If they were not explicitly supplied, just construct fresh // variables. let num_supplied_types = supplied_method_types.len(); - let method_generics = self.tcx.lookup_generics(pick.item.def_id); + let method_generics = self.tcx.item_generics(pick.item.def_id); let num_method_types = method_generics.types.len(); if num_supplied_types > 0 && num_supplied_types != num_method_types { @@ -330,10 +330,9 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { } fn unify_receivers(&mut self, self_ty: Ty<'tcx>, method_self_ty: Ty<'tcx>) { - match self.sub_types(false, TypeOrigin::Misc(self.span), self_ty, method_self_ty) { - Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); + match self.sub_types(false, &self.misc(self.span), self_ty, method_self_ty) { + Ok(InferOk { obligations, value: () }) => { + self.register_predicates(obligations); } Err(_) => { span_bug!(self.span, @@ -359,14 +358,14 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // type/early-bound-regions substitutions performed. There can // be no late-bound regions appearing here. let def_id = pick.item.def_id; - let method_predicates = self.tcx.lookup_predicates(def_id) + let method_predicates = self.tcx.item_predicates(def_id) .instantiate(self.tcx, all_substs); let method_predicates = self.normalize_associated_types_in(self.span, &method_predicates); debug!("method_predicates after subst = {:?}", method_predicates); - let fty = match self.tcx.lookup_item_type(def_id).ty.sty { + let fty = match self.tcx.item_type(def_id).sty { ty::TyFnDef(_, _, f) => f, _ => bug!() }; diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 579a54fb5318..66a532fd76ac 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -230,7 +230,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let tcx = self.tcx; let method_item = self.associated_item(trait_def_id, m_name).unwrap(); let def_id = method_item.def_id; - let generics = tcx.lookup_generics(def_id); + let generics = tcx.item_generics(def_id); assert_eq!(generics.types.len(), 0); assert_eq!(generics.regions.len(), 0); @@ -242,7 +242,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // NB: Instantiate late-bound regions first so that // `instantiate_type_scheme` can normalize associated types that // may reference those regions. - let original_method_ty = tcx.lookup_item_type(def_id).ty; + let original_method_ty = tcx.item_type(def_id); let fty = match original_method_ty.sty { ty::TyFnDef(_, _, f) => f, _ => bug!() diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 7068b2dea726..545d4e788524 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -16,13 +16,13 @@ use super::suggest; use check::FnCtxt; use hir::def_id::DefId; use hir::def::Def; +use rustc::infer::InferOk; use rustc::ty::subst::{Subst, Substs}; -use rustc::traits; +use rustc::traits::{self, ObligationCause}; use rustc::ty::{self, Ty, ToPolyTraitRef, TraitRef, TypeFoldable}; -use rustc::infer::{InferOk, TypeOrigin}; use rustc::util::nodemap::FxHashSet; use syntax::ast; -use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::Span; use rustc::hir; use std::mem; use std::ops::Deref; @@ -672,9 +672,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } }; - let impl_type = self.tcx.lookup_item_type(impl_def_id); + let impl_type = self.tcx.item_type(impl_def_id); let impl_simplified_type = - match ty::fast_reject::simplify_type(self.tcx, impl_type.ty, false) { + match ty::fast_reject::simplify_type(self.tcx, impl_type, false) { Some(simplified_type) => simplified_type, None => { return true; @@ -771,7 +771,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { def_id, substs); - let trait_predicates = self.tcx.lookup_predicates(def_id); + let trait_predicates = self.tcx.item_predicates(def_id); let bounds = trait_predicates.instantiate(self.tcx, substs); let predicates = bounds.predicates; debug!("assemble_projection_candidates: predicates={:?}", @@ -1032,10 +1032,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { self.probe(|_| { // First check that the self type can be related. match self.sub_types(false, - TypeOrigin::Misc(DUMMY_SP), + &ObligationCause::dummy(), self_ty, probe.xform_self_ty) { - Ok(InferOk { obligations, .. }) => { + Ok(InferOk { obligations, value: () }) => { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()) } @@ -1070,7 +1070,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let cause = traits::ObligationCause::misc(self.span, self.body_id); // Check whether the impl imposes obligations we have to worry about. - let impl_bounds = self.tcx.lookup_predicates(impl_def_id); + let impl_bounds = self.tcx.item_predicates(impl_def_id); let impl_bounds = impl_bounds.instantiate(self.tcx, substs); let traits::Normalized { value: impl_bounds, obligations: norm_obligations } = traits::normalize(selcx, cause.clone(), &impl_bounds); @@ -1171,7 +1171,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { impl_ty: Ty<'tcx>, substs: &Substs<'tcx>) -> Ty<'tcx> { - let self_ty = self.tcx.lookup_item_type(method).ty.fn_sig().input(0); + let self_ty = self.tcx.item_type(method).fn_sig().input(0); debug!("xform_self_ty(impl_ty={:?}, self_ty={:?}, substs={:?})", impl_ty, self_ty, @@ -1184,7 +1184,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // are given do not include type/lifetime parameters for the // method yet. So create fresh variables here for those too, // if there are any. - let generics = self.tcx.lookup_generics(method); + let generics = self.tcx.item_generics(method); assert_eq!(substs.types().count(), generics.parent_types as usize); assert_eq!(substs.regions().count(), generics.parent_regions as usize); @@ -1218,7 +1218,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { /// Get the type of an impl and generate substitutions with placeholders. fn impl_ty_and_substs(&self, impl_def_id: DefId) -> (Ty<'tcx>, &'tcx Substs<'tcx>) { - let impl_ty = self.tcx.lookup_item_type(impl_def_id).ty; + let impl_ty = self.tcx.item_type(impl_def_id); let substs = Substs::for_item(self.tcx, impl_def_id, diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 0cb8cf2a5888..4ae15740cf2a 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -308,7 +308,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let limit = if candidates.len() == 5 { 5 } else { 4 }; for (i, trait_did) in candidates.iter().take(limit).enumerate() { - err.help(&format!("candidate #{}: `use {}`", + err.help(&format!("candidate #{}: `use {};`", i + 1, self.tcx.item_path_str(*trait_did))); } @@ -439,7 +439,7 @@ impl Ord for TraitInfo { /// Retrieve all traits in this crate and any dependent crates. pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> { if ccx.all_traits.borrow().is_none() { - use rustc::hir::intravisit; + use rustc::hir::itemlikevisit; let mut traits = vec![]; @@ -450,7 +450,7 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> { map: &'a hir_map::Map<'tcx>, traits: &'a mut AllTraitsVec, } - impl<'v, 'a, 'tcx> intravisit::Visitor<'v> for Visitor<'a, 'tcx> { + impl<'v, 'a, 'tcx> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a, 'tcx> { fn visit_item(&mut self, i: &'v hir::Item) { match i.node { hir::ItemTrait(..) => { @@ -460,8 +460,11 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> { _ => {} } } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + } } - ccx.tcx.map.krate().visit_all_items(&mut Visitor { + ccx.tcx.map.krate().visit_all_item_likes(&mut Visitor { map: &ccx.tcx.map, traits: &mut traits, }); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 08242cff112c..f08178e49fb2 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -86,9 +86,10 @@ use fmt_macros::{Parser, Piece, Position}; use hir::def::{Def, CtorKind, PathResolution}; use hir::def_id::{DefId, LOCAL_CRATE}; use hir::pat_util; -use rustc::infer::{self, InferCtxt, InferOk, TypeOrigin, TypeTrace, type_variable}; +use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin, + TypeTrace, type_variable}; use rustc::ty::subst::{Kind, Subst, Substs}; -use rustc::traits::{self, Reveal}; +use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal}; use rustc::ty::{ParamTy, ParameterEnvironment}; use rustc::ty::{LvaluePreference, NoPreference, PreferMutLvalue}; use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, Visibility}; @@ -120,6 +121,7 @@ use syntax::util::lev_distance::find_best_match_for_name; use syntax_pos::{self, BytePos, Span}; use rustc::hir::intravisit::{self, Visitor}; +use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::{self, PatKind}; use rustc::hir::print as pprust; use rustc_back::slice; @@ -524,30 +526,35 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> { +impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> { fn visit_item(&mut self, i: &'tcx hir::Item) { check_item_body(self.ccx, i); } + + fn visit_impl_item(&mut self, _item: &'tcx hir::ImplItem) { + // done as part of `visit_item` above + } } pub fn check_wf_new(ccx: &CrateCtxt) -> CompileResult { ccx.tcx.sess.track_errors(|| { let mut visit = wfcheck::CheckTypeWellFormedVisitor::new(ccx); - ccx.tcx.visit_all_items_in_krate(DepNode::WfCheck, &mut visit); + ccx.tcx.visit_all_item_likes_in_krate(DepNode::WfCheck, &mut visit.as_deep_visitor()); }) } pub fn check_item_types(ccx: &CrateCtxt) -> CompileResult { ccx.tcx.sess.track_errors(|| { let mut visit = CheckItemTypesVisitor { ccx: ccx }; - ccx.tcx.visit_all_items_in_krate(DepNode::TypeckItemType, &mut visit); + ccx.tcx.visit_all_item_likes_in_krate(DepNode::TypeckItemType, + &mut visit.as_deep_visitor()); }) } pub fn check_item_bodies(ccx: &CrateCtxt) -> CompileResult { ccx.tcx.sess.track_errors(|| { let mut visit = CheckItemBodiesVisitor { ccx: ccx }; - ccx.tcx.visit_all_items_in_krate(DepNode::TypeckItemBody, &mut visit); + ccx.tcx.visit_all_item_likes_in_krate(DepNode::TypeckItemBody, &mut visit); // Process deferred obligations, now that all functions // bodies have been fully inferred. @@ -597,7 +604,7 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, body: &'tcx hir::Expr, fn_id: ast::NodeId, span: Span) { - let raw_fty = ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(fn_id)).ty; + let raw_fty = ccx.tcx.item_type(ccx.tcx.map.local_def_id(fn_id)); let fn_ty = match raw_fty.sty { ty::TyFnDef(.., f) => f, _ => span_bug!(body.span, "check_bare_fn: function type expected") @@ -780,15 +787,16 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, } fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) { - check_representable(ccx.tcx, span, id); + let def_id = ccx.tcx.map.local_def_id(id); + check_representable(ccx.tcx, span, def_id); - if ccx.tcx.lookup_simd(ccx.tcx.map.local_def_id(id)) { - check_simd(ccx.tcx, span, id); + if ccx.tcx.lookup_simd(def_id) { + check_simd(ccx.tcx, span, def_id); } } fn check_union(ccx: &CrateCtxt, id: ast::NodeId, span: Span) { - check_representable(ccx.tcx, span, id); + check_representable(ccx.tcx, span, ccx.tcx.map.local_def_id(id)); } pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { @@ -807,7 +815,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { it.id); } hir::ItemFn(..) => {} // entirely within check_item_body - hir::ItemImpl(.., ref impl_items) => { + hir::ItemImpl(.., ref impl_item_refs) => { debug!("ItemImpl {} with id {}", it.name, it.id); let impl_def_id = ccx.tcx.map.local_def_id(it.id); if let Some(impl_trait_ref) = ccx.tcx.impl_trait_ref(impl_def_id) { @@ -815,7 +823,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { it.span, impl_def_id, impl_trait_ref, - impl_items); + impl_item_refs); let trait_def_id = impl_trait_ref.def_id; check_on_unimplemented(ccx, trait_def_id, it); } @@ -831,7 +839,8 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { check_union(ccx, it.id, it.span); } hir::ItemTy(_, ref generics) => { - let pty_ty = ccx.tcx.tables().node_id_to_type(it.id); + let def_id = ccx.tcx.map.local_def_id(it.id); + let pty_ty = ccx.tcx.item_type(def_id); check_bounds_are_used(ccx, generics, pty_ty); } hir::ItemForeignMod(ref m) => { @@ -847,8 +856,8 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { } } else { for item in &m.items { - let pty = ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(item.id)); - if !pty.generics.types.is_empty() { + let generics = ccx.tcx.item_generics(ccx.tcx.map.local_def_id(item.id)); + if !generics.types.is_empty() { let mut err = struct_span_err!(ccx.tcx.sess, item.span, E0044, "foreign items may not have type parameters"); span_help!(&mut err, item.span, @@ -876,10 +885,11 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { hir::ItemFn(ref decl, .., ref body) => { check_bare_fn(ccx, &decl, &body, it.id, it.span); } - hir::ItemImpl(.., ref impl_items) => { + hir::ItemImpl(.., ref impl_item_refs) => { debug!("ItemImpl {} with id {}", it.name, it.id); - for impl_item in impl_items { + for impl_item_ref in impl_item_refs { + let impl_item = ccx.tcx.map.impl_item(impl_item_ref.id); match impl_item.node { hir::ImplItemKind::Const(_, ref expr) => { check_const(ccx, &expr, impl_item.id) @@ -917,7 +927,7 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { fn check_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, def_id: DefId, item: &hir::Item) { - let generics = ccx.tcx.lookup_generics(def_id); + let generics = ccx.tcx.item_generics(def_id); if let Some(ref attr) = item.attrs.iter().find(|a| { a.check_name("rustc_on_unimplemented") }) { @@ -1016,7 +1026,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_span: Span, impl_id: DefId, impl_trait_ref: ty::TraitRef<'tcx>, - impl_items: &[hir::ImplItem]) { + impl_item_refs: &[hir::ImplItemRef]) { // If the trait reference itself is erroneous (so the compilation is going // to fail), skip checking the items here -- the `impl_item` table in `tcx` // isn't populated for such impls. @@ -1027,9 +1037,11 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let trait_def = tcx.lookup_trait_def(impl_trait_ref.def_id); let mut overridden_associated_type = None; + let impl_items = || impl_item_refs.iter().map(|iiref| ccx.tcx.map.impl_item(iiref.id)); + // Check existing impl methods to see if they are both present in trait // and compatible with trait signature - for impl_item in impl_items { + for impl_item in impl_items() { let ty_impl_item = tcx.associated_item(tcx.map.local_def_id(impl_item.id)); let ty_trait_item = tcx.associated_items(impl_trait_ref.def_id) .find(|ac| ac.name == ty_impl_item.name); @@ -1098,7 +1110,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } hir::ImplItemKind::Type(_) => { if ty_trait_item.kind == ty::AssociatedKind::Type { - if ty_trait_item.has_value { + if ty_trait_item.defaultness.has_value() { overridden_associated_type = Some(impl_item); } } else { @@ -1132,7 +1144,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, .unwrap_or(false); if !is_implemented { - if !trait_item.has_value { + if !trait_item.defaultness.has_value() { missing_items.push(trait_item); } else if associated_type_overridden { invalidated_items.push(trait_item.name); @@ -1143,12 +1155,11 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let signature = |item: &ty::AssociatedItem| { match item.kind { ty::AssociatedKind::Method => { - format!("{}", tcx.lookup_item_type(item.def_id).ty.fn_sig().0) + format!("{}", tcx.item_type(item.def_id).fn_sig().0) } ty::AssociatedKind::Type => format!("type {};", item.name.to_string()), ty::AssociatedKind::Const => { - format!("const {}: {:?};", item.name.to_string(), - tcx.lookup_item_type(item.def_id).ty) + format!("const {}: {:?};", item.name.to_string(), tcx.item_type(item.def_id)) } } }; @@ -1218,7 +1229,7 @@ fn check_const_with_type<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, fn check_const<'a, 'tcx>(ccx: &CrateCtxt<'a,'tcx>, expr: &'tcx hir::Expr, id: ast::NodeId) { - let decl_ty = ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(id)).ty; + let decl_ty = ccx.tcx.item_type(ccx.tcx.map.local_def_id(id)); check_const_with_type(ccx, expr, decl_ty, id); } @@ -1227,9 +1238,9 @@ fn check_const<'a, 'tcx>(ccx: &CrateCtxt<'a,'tcx>, /// pointer, which would mean their size is unbounded. fn check_representable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, - item_id: ast::NodeId) + item_def_id: DefId) -> bool { - let rty = tcx.tables().node_id_to_type(item_id); + let rty = tcx.item_type(item_def_id); // Check that it is possible to represent this type. This call identifies // (1) types that contain themselves and (2) types that contain a different @@ -1238,7 +1249,6 @@ fn check_representable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // caught by case 1. match rty.is_representable(tcx, sp) { Representability::SelfRecursive => { - let item_def_id = tcx.map.local_def_id(item_id); tcx.recursive_type_with_infinite_size_error(item_def_id).emit(); return false } @@ -1247,8 +1257,8 @@ fn check_representable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, return true } -pub fn check_simd<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, id: ast::NodeId) { - let t = tcx.tables().node_id_to_type(id); +pub fn check_simd<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: DefId) { + let t = tcx.item_type(def_id); match t.sty { ty::TyAdt(def, substs) if def.is_struct() => { let fields = &def.struct_variant().fields; @@ -1328,7 +1338,7 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, disr_vals.push(current_disr_val); } - check_representable(ccx.tcx, sp, id); + check_representable(ccx.tcx, sp, def_id); } impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { @@ -1341,13 +1351,12 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { fn get_generics(&self, _: Span, id: DefId) -> Result<&'tcx ty::Generics<'tcx>, ErrorReported> { - Ok(self.tcx().lookup_generics(id)) + Ok(self.tcx().item_generics(id)) } - fn get_item_type_scheme(&self, _: Span, id: DefId) - -> Result, ErrorReported> + fn get_item_type(&self, _: Span, id: DefId) -> Result, ErrorReported> { - Ok(self.tcx().lookup_item_type(id)) + Ok(self.tcx().item_type(id)) } fn get_trait_def(&self, _: Span, id: DefId) @@ -1521,6 +1530,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } + pub fn cause(&self, + span: Span, + code: ObligationCauseCode<'tcx>) + -> ObligationCause<'tcx> { + ObligationCause::new(span, self.body_id, code) + } + + pub fn misc(&self, span: Span) -> ObligationCause<'tcx> { + self.cause(span, ObligationCauseCode::MiscObligation) + } + /// Resolves type variables in `ty` if possible. Unlike the infcx /// version (resolve_type_vars_if_possible), this version will /// also select obligations if it seems useful, in an effort @@ -1662,7 +1682,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// generic type scheme. fn instantiate_bounds(&self, span: Span, def_id: DefId, substs: &Substs<'tcx>) -> ty::InstantiatedPredicates<'tcx> { - let bounds = self.tcx.lookup_predicates(def_id); + let bounds = self.tcx.item_predicates(def_id); let result = bounds.instantiate(self.tcx, substs); let result = self.normalize_associated_types_in(span, &result.predicates); debug!("instantiate_bounds(bounds={:?}, substs={:?}) = {:?}", @@ -1687,7 +1707,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let ty_var = self.next_ty_var(); self.anon_types.borrow_mut().insert(def_id, ty_var); - let item_predicates = self.tcx.lookup_predicates(def_id); + let item_predicates = self.tcx.item_predicates(def_id); let bounds = item_predicates.instantiate(self.tcx, substs); let span = self.tcx.map.def_id_span(def_id, codemap::DUMMY_SP); @@ -1786,6 +1806,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .register_predicate_obligation(self, obligation); } + pub fn register_predicates(&self, + obligations: Vec>) + { + for obligation in obligations { + self.register_predicate(obligation); + } + } + + pub fn register_infer_ok_obligations(&self, infer_ok: InferOk<'tcx, T>) -> T { + self.register_predicates(infer_ok.obligations); + infer_ok.value + } + pub fn to_ty(&self, ast_t: &hir::Ty) -> Ty<'tcx> { let t = AstConv::ast_ty_to_ty(self, self, ast_t); self.register_wf_obligation(t, ast_t.span, traits::MiscObligation); @@ -2096,15 +2129,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(default) = default_map.get(ty) { let default = default.clone(); match self.eq_types(false, - TypeOrigin::Misc(default.origin_span), - ty, default.ty) { - Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()) - }, - Err(_) => { - conflicts.push((*ty, default)); - } + &self.misc(default.origin_span), + ty, + default.ty) { + Ok(ok) => self.register_infer_ok_obligations(ok), + Err(_) => conflicts.push((*ty, default)), } } } @@ -2146,6 +2175,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.report_conflicting_default_types( first_default.origin_span, + self.body_id, first_default, second_default) } @@ -2194,10 +2224,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(default) = default_map.get(ty) { let default = default.clone(); match self.eq_types(false, - TypeOrigin::Misc(default.origin_span), - ty, default.ty) { - // FIXME(#32730) propagate obligations - Ok(InferOk { obligations, .. }) => assert!(obligations.is_empty()), + &self.misc(default.origin_span), + ty, + default.ty) { + Ok(ok) => self.register_infer_ok_obligations(ok), Err(_) => { result = Some(default); } @@ -2742,11 +2772,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { span: Span, // (potential) receiver for this impl did: DefId) -> TypeAndSubsts<'tcx> { - let ity = self.tcx.lookup_item_type(did); + let ity = self.tcx.item_type(did); debug!("impl_self_ty: ity={:?}", ity); let substs = self.fresh_substs_for_item(span, did); - let substd_ty = self.instantiate_type_scheme(span, &substs, &ity.ty); + let substd_ty = self.instantiate_type_scheme(span, &substs, &ity); TypeAndSubsts { substs: substs, ty: substd_ty } } @@ -2760,18 +2790,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { formal_args: &[Ty<'tcx>]) -> Vec> { let expected_args = expected_ret.only_has_type(self).and_then(|ret_ty| { - self.commit_regions_if_ok(|| { + self.fudge_regions_if_ok(&RegionVariableOrigin::Coercion(call_span), || { // Attempt to apply a subtyping relationship between the formal // return type (likely containing type variables if the function // is polymorphic) and the expected return type. // No argument expectations are produced if unification fails. - let origin = TypeOrigin::Misc(call_span); - let ures = self.sub_types(false, origin, formal_ret, ret_ty); + let origin = self.misc(call_span); + let ures = self.sub_types(false, &origin, formal_ret, ret_ty); // FIXME(#15760) can't use try! here, FromError doesn't default // to identity so the resulting type is not constrained. match ures { - // FIXME(#32730) propagate obligations - Ok(InferOk { obligations, .. }) => assert!(obligations.is_empty()), + Ok(ok) => self.register_infer_ok_obligations(ok), Err(e) => return Err(e), } @@ -2852,16 +2881,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.diverges.set(Diverges::Maybe); let unit = self.tcx.mk_nil(); - let (origin, expected, found, result) = + let (cause, expected_ty, found_ty, result); if let Some(else_expr) = opt_else_expr { let else_ty = self.check_expr_with_expectation(else_expr, expected); let else_diverges = self.diverges.get(); + cause = self.cause(sp, ObligationCauseCode::IfExpression); // Only try to coerce-unify if we have a then expression // to assign coercions to, otherwise it's () or diverging. - let origin = TypeOrigin::IfExpression(sp); - let result = if let Some(ref then) = then_blk.expr { - let res = self.try_find_coercion_lub(origin, || Some(&**then), + expected_ty = then_ty; + found_ty = else_ty; + result = if let Some(ref then) = then_blk.expr { + let res = self.try_find_coercion_lub(&cause, || Some(&**then), then_ty, else_expr, else_ty); // In case we did perform an adjustment, we have to update @@ -2876,33 +2907,27 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { res } else { self.commit_if_ok(|_| { - let trace = TypeTrace::types(origin, true, then_ty, else_ty); + let trace = TypeTrace::types(&cause, true, then_ty, else_ty); self.lub(true, trace, &then_ty, &else_ty) - .map(|InferOk { value, obligations }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - value - }) + .map(|ok| self.register_infer_ok_obligations(ok)) }) }; // We won't diverge unless both branches do (or the condition does). self.diverges.set(cond_diverges | then_diverges & else_diverges); - - (origin, then_ty, else_ty, result) } else { // If the condition is false we can't diverge. self.diverges.set(cond_diverges); - let origin = TypeOrigin::IfExpressionWithNoElse(sp); - (origin, unit, then_ty, - self.eq_types(true, origin, unit, then_ty) - .map(|InferOk { obligations, .. }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - unit - })) - }; + cause = self.cause(sp, ObligationCauseCode::IfExpressionWithNoElse); + expected_ty = unit; + found_ty = then_ty; + result = self.eq_types(true, &cause, unit, then_ty) + .map(|ok| { + self.register_infer_ok_obligations(ok); + unit + }); + } match result { Ok(ty) => { @@ -2913,7 +2938,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } Err(e) => { - self.report_mismatched_types(origin, expected, found, e); + self.report_mismatched_types(&cause, expected_ty, found_ty, e); self.tcx.types.err } } @@ -3564,17 +3589,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(ref e) = *expr_opt { self.check_expr_coercable_to_type(&e, self.ret_ty); } else { - let eq_result = self.eq_types(false, - TypeOrigin::Misc(expr.span), - self.ret_ty, - tcx.mk_nil()) - // FIXME(#32730) propagate obligations - .map(|InferOk { obligations, .. }| assert!(obligations.is_empty())); - if eq_result.is_err() { - struct_span_err!(tcx.sess, expr.span, E0069, - "`return;` in a function whose return type is not `()`") - .span_label(expr.span, &format!("return type is not ()")) - .emit(); + match self.eq_types(false, + &self.misc(expr.span), + self.ret_ty, + tcx.mk_nil()) + { + Ok(ok) => self.register_infer_ok_obligations(ok), + Err(_) => { + struct_span_err!(tcx.sess, expr.span, E0069, + "`return;` in a function whose return type is not `()`") + .span_label(expr.span, &format!("return type is not ()")) + .emit(); + } } } tcx.types.never @@ -3695,20 +3721,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { for (i, e) in args.iter().enumerate() { let e_ty = self.check_expr_with_hint(e, coerce_to); - let origin = TypeOrigin::Misc(e.span); + let cause = self.misc(e.span); // Special-case the first element, as it has no "previous expressions". let result = if i == 0 { self.try_coerce(e, e_ty, coerce_to) } else { let prev_elems = || args[..i].iter().map(|e| &**e); - self.try_find_coercion_lub(origin, prev_elems, unified, e, e_ty) + self.try_find_coercion_lub(&cause, prev_elems, unified, e, e_ty) }; match result { Ok(ty) => unified = ty, Err(e) => { - self.report_mismatched_types(origin, unified, e_ty, e); + self.report_mismatched_types(&cause, unified, e_ty, e); } } } @@ -4064,9 +4090,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // We're not diverging and there's an expected type, which, // in case it's not `()`, could result in an error higher-up. // We have a chance to error here early and be more helpful. - let origin = TypeOrigin::Misc(blk.span); - let trace = TypeTrace::types(origin, false, ty, ety); - match self.sub_types(false, origin, ty, ety) { + let cause = self.misc(blk.span); + let trace = TypeTrace::types(&cause, false, ty, ety); + match self.sub_types(false, &cause, ty, ety) { Ok(InferOk { obligations, .. }) => { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()); @@ -4184,11 +4210,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Def::VariantCtor(def_id, ..) => { // Everything but the final segment should have no // parameters at all. - let mut generics = self.tcx.lookup_generics(def_id); + let mut generics = self.tcx.item_generics(def_id); if let Some(def_id) = generics.parent { // Variant and struct constructors use the // generics of their parent type definition. - generics = self.tcx.lookup_generics(def_id); + generics = self.tcx.item_generics(def_id); } type_segment = Some((segments.last().unwrap(), generics)); } @@ -4198,7 +4224,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Def::Const(def_id) | Def::Static(def_id, _) => { fn_segment = Some((segments.last().unwrap(), - self.tcx.lookup_generics(def_id))); + self.tcx.item_generics(def_id))); } // Case 3. Reference to a method or associated const. @@ -4212,9 +4238,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty::ImplContainer(_) => {} } - let generics = self.tcx.lookup_generics(def_id); + let generics = self.tcx.item_generics(def_id); if segments.len() >= 2 { - let parent_generics = self.tcx.lookup_generics(generics.parent.unwrap()); + let parent_generics = self.tcx.item_generics(generics.parent.unwrap()); type_segment = Some((&segments[segments.len() - 2], parent_generics)); } else { // `::assoc` will end up here, and so can `T::assoc`. @@ -4344,9 +4370,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // The things we are substituting into the type should not contain // escaping late-bound regions, and nor should the base type scheme. - let scheme = self.tcx.lookup_item_type(def.def_id()); + let ty = self.tcx.item_type(def.def_id()); assert!(!substs.has_escaping_regions()); - assert!(!scheme.ty.has_escaping_regions()); + assert!(!ty.has_escaping_regions()); // Add all the obligations that are required, substituting and // normalized appropriately. @@ -4357,21 +4383,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Substitute the values for the type parameters into the type of // the referenced item. - let ty_substituted = self.instantiate_type_scheme(span, &substs, &scheme.ty); + let ty_substituted = self.instantiate_type_scheme(span, &substs, &ty); if let Some((ty::ImplContainer(impl_def_id), self_ty)) = ufcs_associated { // In the case of `Foo::method` and `>::method`, if `method` // is inherent, there is no `Self` parameter, instead, the impl needs // type parameters, which we can infer by unifying the provided `Self` // with the substituted impl type. - let impl_scheme = self.tcx.lookup_item_type(impl_def_id); + let ty = self.tcx.item_type(impl_def_id); - let impl_ty = self.instantiate_type_scheme(span, &substs, &impl_scheme.ty); - match self.sub_types(false, TypeOrigin::Misc(span), self_ty, impl_ty) { - Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - } + let impl_ty = self.instantiate_type_scheme(span, &substs, &ty); + match self.sub_types(false, &self.misc(span), self_ty, impl_ty) { + Ok(ok) => self.register_infer_ok_obligations(ok), Err(_) => { span_bug!(span, "instantiate_value_path: (UFCS) {:?} was a subtype of {:?} but now is not?", diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index d4e5e9a5bb35..a280001d5e99 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -91,7 +91,7 @@ use middle::region::{self, CodeExtent}; use rustc::ty::subst::Substs; use rustc::traits; use rustc::ty::{self, Ty, MethodCall, TypeFoldable}; -use rustc::infer::{self, GenericKind, InferOk, SubregionOrigin, TypeOrigin, VerifyBound}; +use rustc::infer::{self, GenericKind, SubregionOrigin, VerifyBound}; use hir::pat_util; use rustc::ty::adjustment; use rustc::ty::wf::ImpliedBound; @@ -1149,7 +1149,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { autoderefs: usize, autoref: &adjustment::AutoBorrow<'tcx>) { - debug!("link_autoref(autoref={:?})", autoref); + debug!("link_autoref(autoderefs={}, autoref={:?})", autoderefs, autoref); let mc = mc::MemCategorizationContext::new(self); let expr_cmt = ignore_err!(mc.cat_expr_autoderefd(expr, autoderefs)); debug!("expr_cmt={:?}", expr_cmt); @@ -1729,7 +1729,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // ``` // // we can thus deduce that `>::SomeType : 'a`. - let trait_predicates = self.tcx.lookup_predicates(projection_ty.trait_ref.def_id); + let trait_predicates = self.tcx.item_predicates(projection_ty.trait_ref.def_id); assert_eq!(trait_predicates.parent, None); let predicates = trait_predicates.predicates.as_slice().to_vec(); traits::elaborate_predicates(self.tcx, predicates) @@ -1762,10 +1762,10 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { outlives); // check whether this predicate applies to our current projection - match self.eq_types(false, TypeOrigin::Misc(span), ty, outlives.0) { - Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); + let cause = self.fcx.misc(span); + match self.eq_types(false, &cause, ty, outlives.0) { + Ok(ok) => { + self.register_infer_ok_obligations(ok); Ok(outlives.1) } Err(_) => { Err(()) } diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 2fea86cb2120..1ea47107c3b1 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -183,8 +183,8 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { // inference algorithm will reject it). // Extract the type variables UV0...UVn. - let closure_substs = match self.fcx.node_ty(id).sty { - ty::TyClosure(_, ref substs) => substs, + let (def_id, closure_substs) = match self.fcx.node_ty(id).sty { + ty::TyClosure(def_id, substs) => (def_id, substs), ref t => { span_bug!( span, @@ -197,7 +197,9 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { let final_upvar_tys = self.final_upvar_tys(id); debug!("analyze_closure: id={:?} closure_substs={:?} final_upvar_tys={:?}", id, closure_substs, final_upvar_tys); - for (&upvar_ty, final_upvar_ty) in closure_substs.upvar_tys.iter().zip(final_upvar_tys) { + for (upvar_ty, final_upvar_ty) in + closure_substs.upvar_tys(def_id, self.fcx.tcx).zip(final_upvar_tys) + { self.fcx.demand_eqtype(span, final_upvar_ty, upvar_ty); } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 4136f543ccca..1ad81660f836 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -15,8 +15,7 @@ use CrateCtxt; use hir::def_id::DefId; use middle::region::{CodeExtent}; -use rustc::infer::TypeOrigin; -use rustc::traits; +use rustc::traits::{self, ObligationCauseCode}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::util::nodemap::{FxHashSet, FxHashMap}; @@ -29,7 +28,7 @@ use rustc::hir; pub struct CheckTypeWellFormedVisitor<'ccx, 'tcx:'ccx> { ccx: &'ccx CrateCtxt<'ccx, 'tcx>, - code: traits::ObligationCauseCode<'tcx>, + code: ObligationCauseCode<'tcx>, } /// Helper type of a temporary returned by .for_item(...). @@ -37,7 +36,7 @@ pub struct CheckTypeWellFormedVisitor<'ccx, 'tcx:'ccx> { /// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(FnCtxt<'b, 'gcx, 'tcx>). struct CheckWfFcxBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { inherited: super::InheritedBuilder<'a, 'gcx, 'tcx>, - code: traits::ObligationCauseCode<'gcx>, + code: ObligationCauseCode<'gcx>, id: ast::NodeId, span: Span } @@ -67,7 +66,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { -> CheckTypeWellFormedVisitor<'ccx, 'gcx> { CheckTypeWellFormedVisitor { ccx: ccx, - code: traits::ObligationCauseCode::MiscObligation + code: ObligationCauseCode::MiscObligation } } @@ -179,18 +178,18 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { let (mut implied_bounds, self_ty) = match item.container { ty::TraitContainer(_) => (vec![], fcx.tcx.mk_self_type()), ty::ImplContainer(def_id) => (fcx.impl_implied_bounds(def_id, span), - fcx.tcx.lookup_item_type(def_id).ty) + fcx.tcx.item_type(def_id)) }; match item.kind { ty::AssociatedKind::Const => { - let ty = fcx.tcx.lookup_item_type(item.def_id).ty; + let ty = fcx.tcx.item_type(item.def_id); let ty = fcx.instantiate_type_scheme(span, free_substs, &ty); fcx.register_wf_obligation(ty, span, code.clone()); } ty::AssociatedKind::Method => { reject_shadowing_type_parameters(fcx.tcx, span, item.def_id); - let method_ty = fcx.tcx.lookup_item_type(item.def_id).ty; + let method_ty = fcx.tcx.item_type(item.def_id); let method_ty = fcx.instantiate_type_scheme(span, free_substs, &method_ty); let predicates = fcx.instantiate_bounds(span, item.def_id, free_substs); let fty = match method_ty.sty { @@ -204,8 +203,8 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { free_id_outlive, self_ty); } ty::AssociatedKind::Type => { - if item.has_value { - let ty = fcx.tcx.lookup_item_type(item.def_id).ty; + if item.defaultness.has_value() { + let ty = fcx.tcx.item_type(item.def_id); let ty = fcx.instantiate_type_scheme(span, free_substs, &ty); fcx.register_wf_obligation(ty, span, code.clone()); } @@ -276,7 +275,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { // // 3) that the trait definition does not have any type parameters - let predicates = self.tcx().lookup_predicates(trait_def_id); + let predicates = self.tcx().item_predicates(trait_def_id); // We must exclude the Self : Trait predicate contained by all // traits. @@ -353,8 +352,8 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { self.for_item(item).with_fcx(|fcx, this| { let free_substs = &fcx.parameter_environment.free_substs; let def_id = fcx.tcx.map.local_def_id(item.id); - let type_scheme = fcx.tcx.lookup_item_type(def_id); - let item_ty = fcx.instantiate_type_scheme(item.span, free_substs, &type_scheme.ty); + let ty = fcx.tcx.item_type(def_id); + let item_ty = fcx.instantiate_type_scheme(item.span, free_substs, &ty); let bare_fn_ty = match item_ty.sty { ty::TyFnDef(.., ref bare_fn_ty) => bare_fn_ty, _ => { @@ -378,11 +377,11 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { debug!("check_item_type: {:?}", item); self.for_item(item).with_fcx(|fcx, this| { - let type_scheme = fcx.tcx.lookup_item_type(fcx.tcx.map.local_def_id(item.id)); + let ty = fcx.tcx.item_type(fcx.tcx.map.local_def_id(item.id)); let item_ty = fcx.instantiate_type_scheme(item.span, &fcx.parameter_environment .free_substs, - &type_scheme.ty); + &ty); fcx.register_wf_obligation(item_ty, item.span, this.code.clone()); @@ -417,7 +416,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { } } None => { - let self_ty = fcx.tcx.tables().node_id_to_type(item.id); + let self_ty = fcx.tcx.item_type(item_def_id); let self_ty = fcx.instantiate_type_scheme(item.span, free_substs, &self_ty); fcx.register_wf_obligation(self_ty, ast_self_ty.span, this.code.clone()); } @@ -426,7 +425,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { let predicates = fcx.instantiate_bounds(item.span, item_def_id, free_substs); this.check_where_clauses(fcx, item.span, &predicates); - fcx.impl_implied_bounds(fcx.tcx.map.local_def_id(item.id), item.span) + fcx.impl_implied_bounds(item_def_id, item.span) }); } @@ -492,7 +491,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { let span = method_sig.decl.inputs[0].pat.span; let free_substs = &fcx.parameter_environment.free_substs; - let method_ty = fcx.tcx.lookup_item_type(method.def_id).ty; + let method_ty = fcx.tcx.item_type(method.def_id); let fty = fcx.instantiate_type_scheme(span, free_substs, &method_ty); let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &fty.fn_sig()); @@ -515,21 +514,21 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { debug!("check_method_receiver: receiver ty = {:?}", rcvr_ty); - let origin = TypeOrigin::MethodReceiver(span); - fcx.demand_eqtype_with_origin(origin, rcvr_ty, self_arg_ty); + let cause = fcx.cause(span, ObligationCauseCode::MethodReceiver); + fcx.demand_eqtype_with_origin(&cause, rcvr_ty, self_arg_ty); } fn check_variances_for_type_defn(&self, item: &hir::Item, ast_generics: &hir::Generics) { - let ty = self.tcx().tables().node_id_to_type(item.id); + let item_def_id = self.tcx().map.local_def_id(item.id); + let ty = self.tcx().item_type(item_def_id); if self.tcx().has_error_field(ty) { return; } - let item_def_id = self.tcx().map.local_def_id(item.id); - let ty_predicates = self.tcx().lookup_predicates(item_def_id); + let ty_predicates = self.tcx().item_predicates(item_def_id); assert_eq!(ty_predicates.parent, None); let variances = self.tcx().item_variances(item_def_id); @@ -583,8 +582,8 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { } fn reject_shadowing_type_parameters(tcx: TyCtxt, span: Span, def_id: DefId) { - let generics = tcx.lookup_generics(def_id); - let parent = tcx.lookup_generics(generics.parent.unwrap()); + let generics = tcx.item_generics(def_id); + let parent = tcx.item_generics(generics.parent.unwrap()); let impl_params: FxHashMap<_, _> = parent.types .iter() .map(|tp| (tp.name, tp.def_id)) @@ -654,7 +653,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let fields = struct_def.fields().iter() .map(|field| { - let field_ty = self.tcx.tables().node_id_to_type(field.id); + let field_ty = self.tcx.item_type(self.tcx.map.local_def_id(field.id)); let field_ty = self.instantiate_type_scheme(field.span, &self.parameter_environment .free_substs, @@ -683,7 +682,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { None => { // Inherent impl: take implied bounds from the self type. - let self_ty = self.tcx.lookup_item_type(impl_def_id).ty; + let self_ty = self.tcx.item_type(impl_def_id); let self_ty = self.instantiate_type_scheme(span, free_substs, &self_ty); vec![self_ty] } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 9f3214a0d813..979ce82ff4ec 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -20,8 +20,6 @@ use rustc::ty::adjustment; use rustc::ty::fold::{TypeFolder,TypeFoldable}; use rustc::infer::{InferCtxt, FixupError}; use rustc::util::nodemap::DefIdMap; -use write_substs_to_tcx; -use write_ty_to_tcx; use std::cell::Cell; @@ -67,7 +65,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { wbcx.visit_closures(); wbcx.visit_liberated_fn_sigs(); wbcx.visit_fru_field_types(); - wbcx.visit_anon_types(item_id); + wbcx.visit_anon_types(); wbcx.visit_deferred_obligations(item_id); } } @@ -133,6 +131,12 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { self.fcx.tcx } + fn write_ty_to_tcx(&self, node_id: ast::NodeId, ty: Ty<'gcx>) { + debug!("write_ty_to_tcx({}, {:?})", node_id, ty); + assert!(!ty.needs_infer()); + self.tcx().tables.borrow_mut().node_types.insert(node_id, ty); + } + // Hacky hack: During type-checking, we treat *all* operators // as potentially overloaded. But then, during writeback, if // we observe that something like `a+b` is (known to be) @@ -241,7 +245,7 @@ impl<'cx, 'gcx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'gcx, 'tcx> { let var_ty = self.fcx.local_ty(l.span, l.id); let var_ty = self.resolve(&var_ty, ResolvingLocal(l.span)); - write_ty_to_tcx(self.fcx.ccx, l.id, var_ty); + self.write_ty_to_tcx(l.id, var_ty); intravisit::walk_local(self, l); } @@ -249,7 +253,7 @@ impl<'cx, 'gcx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'gcx, 'tcx> { match t.node { hir::TyArray(ref ty, ref count_expr) => { self.visit_ty(&ty); - write_ty_to_tcx(self.fcx.ccx, count_expr.id, self.tcx().types.usize); + self.write_ty_to_tcx(count_expr.id, self.tcx().types.usize); } hir::TyBareFn(ref function_declaration) => { intravisit::walk_fn_decl_nopat(self, &function_declaration.decl); @@ -302,13 +306,11 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } } - fn visit_anon_types(&self, item_id: ast::NodeId) { + fn visit_anon_types(&self) { if self.fcx.writeback_errors.get() { return } - let item_def_id = self.fcx.tcx.map.local_def_id(item_id); - let gcx = self.tcx().global_tcx(); for (&def_id, &concrete_ty) in self.fcx.anon_types.borrow().iter() { let reason = ResolvingAnonTy(def_id); @@ -349,10 +351,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } }); - gcx.register_item_type(def_id, ty::TypeScheme { - ty: outside_ty, - generics: gcx.lookup_generics(item_def_id) - }); + gcx.item_types.borrow_mut().insert(def_id, outside_ty); } } @@ -363,13 +362,17 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { // Resolve the type of the node with id `id` let n_ty = self.fcx.node_ty(id); let n_ty = self.resolve(&n_ty, reason); - write_ty_to_tcx(self.fcx.ccx, id, n_ty); + self.write_ty_to_tcx(id, n_ty); debug!("Node {} has type {:?}", id, n_ty); // Resolve any substitutions self.fcx.opt_node_ty_substs(id, |item_substs| { - write_substs_to_tcx(self.fcx.ccx, id, - self.resolve(item_substs, reason)); + let item_substs = self.resolve(item_substs, reason); + if !item_substs.is_noop() { + debug!("write_substs_to_tcx({}, {:?})", id, item_substs); + assert!(!item_substs.substs.needs_infer()); + self.tcx().tables.borrow_mut().item_substs.insert(id, item_substs); + } }); } diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index 7e41a672bf32..b4a10c52270e 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -16,7 +16,7 @@ use syntax::ast; use syntax_pos::{Span, DUMMY_SP}; use rustc::hir; -use rustc::hir::intravisit::Visitor; +use rustc::hir::itemlikevisit::ItemLikeVisitor; struct UnusedTraitImportVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -40,7 +40,7 @@ impl<'a, 'tcx> UnusedTraitImportVisitor<'a, 'tcx> { } } -impl<'a, 'tcx, 'v> Visitor<'v> for UnusedTraitImportVisitor<'a, 'tcx> { +impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for UnusedTraitImportVisitor<'a, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { if item.vis == hir::Public || item.span == DUMMY_SP { return; @@ -58,10 +58,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for UnusedTraitImportVisitor<'a, 'tcx> { } } } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + } } pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let _task = tcx.dep_graph.in_task(DepNode::UnusedTraitCheck); let mut visitor = UnusedTraitImportVisitor { tcx: tcx }; - tcx.map.krate().visit_all_items(&mut visitor); + tcx.map.krate().visit_all_item_likes(&mut visitor); } diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 90541539c1e2..2663739e36b2 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -19,7 +19,7 @@ use hir::def_id::DefId; use middle::lang_items::UnsizeTraitLangItem; use rustc::ty::subst::Subst; use rustc::ty::{self, TyCtxt, TypeFoldable}; -use rustc::traits::{self, Reveal}; +use rustc::traits::{self, ObligationCause, Reveal}; use rustc::ty::ParameterEnvironment; use rustc::ty::{Ty, TyBool, TyChar, TyError}; use rustc::ty::{TyParam, TyRawPtr}; @@ -30,11 +30,11 @@ use rustc::ty::{TyProjection, TyAnon}; use rustc::ty::util::CopyImplementationError; use middle::free_region::FreeRegionMap; use CrateCtxt; -use rustc::infer::{self, InferCtxt, TypeOrigin}; +use rustc::infer::{self, InferCtxt}; use syntax_pos::Span; use rustc::dep_graph::DepNode; use rustc::hir::map as hir_map; -use rustc::hir::intravisit; +use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::{Item, ItemImpl}; use rustc::hir; @@ -51,12 +51,15 @@ struct CoherenceCheckVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { cc: &'a CoherenceChecker<'a, 'gcx, 'tcx>, } -impl<'a, 'gcx, 'tcx, 'v> intravisit::Visitor<'v> for CoherenceCheckVisitor<'a, 'gcx, 'tcx> { +impl<'a, 'gcx, 'tcx, 'v> ItemLikeVisitor<'v> for CoherenceCheckVisitor<'a, 'gcx, 'tcx> { fn visit_item(&mut self, item: &Item) { if let ItemImpl(..) = item.node { self.cc.check_implementation(item) } } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + } } impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { @@ -87,8 +90,9 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { // Check implementations and traits. This populates the tables // containing the inherent methods and extension methods. It also // builds up the trait inheritance table. - self.crate_context.tcx.visit_all_items_in_krate(DepNode::CoherenceCheckImpl, - &mut CoherenceCheckVisitor { cc: self }); + self.crate_context.tcx.visit_all_item_likes_in_krate( + DepNode::CoherenceCheckImpl, + &mut CoherenceCheckVisitor { cc: self }); // Populate the table of destructors. It might seem a bit strange to // do this here, but it's actually the most convenient place, since @@ -106,7 +110,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { fn check_implementation(&self, item: &Item) { let tcx = self.crate_context.tcx; let impl_did = tcx.map.local_def_id(item.id); - let self_type = tcx.lookup_item_type(impl_did); + let self_type = tcx.item_type(impl_did); // If there are no traits, then this implementation must have a // base type. @@ -129,14 +133,14 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { } else { // Skip inherent impls where the self type is an error // type. This occurs with e.g. resolve failures (#30589). - if self_type.ty.references_error() { + if self_type.references_error() { return; } // Add the implementation to the mapping from implementation to base // type def ID, if there is a base type for this implementation and // the implementation does not have any associated traits. - if let Some(base_def_id) = self.get_base_type_def_id(item.span, self_type.ty) { + if let Some(base_def_id) = self.get_base_type_def_id(item.span, self_type) { self.add_inherent_impl(base_def_id, impl_did); } } @@ -175,8 +179,8 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { } let method_def_id = items[0]; - let self_type = tcx.lookup_item_type(impl_did); - match self_type.ty.sty { + let self_type = tcx.item_type(impl_did); + match self_type.sty { ty::TyAdt(type_def, _) => { type_def.set_destructor(method_def_id); } @@ -232,13 +236,13 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { return; }; - let self_type = tcx.lookup_item_type(impl_did); + let self_type = tcx.item_type(impl_did); debug!("check_implementations_of_copy: self_type={:?} (bound)", self_type); let span = tcx.map.span(impl_node_id); let param_env = ParameterEnvironment::for_item(tcx, impl_node_id); - let self_type = self_type.ty.subst(tcx, ¶m_env.free_substs); + let self_type = self_type.subst(tcx, ¶m_env.free_substs); assert!(!self_type.has_escaping_regions()); debug!("check_implementations_of_copy: self_type={:?} (free)", @@ -326,7 +330,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { return; }; - let source = tcx.lookup_item_type(impl_did).ty; + let source = tcx.item_type(impl_did); let trait_ref = self.crate_context.tcx.impl_trait_ref(impl_did).unwrap(); let target = trait_ref.substs.type_at(1); debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (bound)", @@ -344,12 +348,12 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { target); tcx.infer_ctxt(None, Some(param_env), Reveal::ExactMatch).enter(|infcx| { - let origin = TypeOrigin::Misc(span); + let cause = ObligationCause::misc(span, impl_node_id); let check_mutbl = |mt_a: ty::TypeAndMut<'gcx>, mt_b: ty::TypeAndMut<'gcx>, mk_ptr: &Fn(Ty<'gcx>) -> Ty<'gcx>| { if (mt_a.mutbl, mt_b.mutbl) == (hir::MutImmutable, hir::MutMutable) { - infcx.report_mismatched_types(origin, + infcx.report_mismatched_types(&cause, mk_ptr(mt_b.ty), target, ty::error::TypeError::Mutability); @@ -397,7 +401,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { } // Ignore fields that aren't significantly changed - if let Ok(ok) = infcx.sub_types(false, origin, b, a) { + if let Ok(ok) = infcx.sub_types(false, &cause, b, a) { if ok.obligations.is_empty() { return None; } diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index bff794364c09..a507077bef77 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -17,12 +17,12 @@ use rustc::ty::{self, TyCtxt}; use syntax::ast; use syntax_pos::Span; use rustc::dep_graph::DepNode; -use rustc::hir::intravisit; +use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir; pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let mut orphan = OrphanChecker { tcx: tcx }; - tcx.visit_all_items_in_krate(DepNode::CoherenceOrphanCheck, &mut orphan); + tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOrphanCheck, &mut orphan); } struct OrphanChecker<'cx, 'tcx: 'cx> { @@ -81,7 +81,7 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { // defined in this crate. debug!("coherence2::orphan check: inherent impl {}", self.tcx.map.node_to_string(item.id)); - let self_ty = self.tcx.lookup_item_type(def_id).ty; + let self_ty = self.tcx.item_type(def_id); match self_ty.sty { ty::TyAdt(def, _) => { self.check_def_id(item, def.did); @@ -380,8 +380,12 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { } } -impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for OrphanChecker<'cx, 'tcx> { +impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { self.check_item(item); } + + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + } } diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index b5aba512a66b..e5be7f63067a 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -14,11 +14,11 @@ use hir::def_id::DefId; use rustc::traits::{self, Reveal}; -use rustc::ty::{self, TyCtxt}; +use rustc::ty::{self, TyCtxt, TypeFoldable}; use syntax::ast; use rustc::dep_graph::DepNode; use rustc::hir; -use rustc::hir::intravisit; +use rustc::hir::itemlikevisit::ItemLikeVisitor; use util::nodemap::DefIdMap; use lint; @@ -30,7 +30,7 @@ pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { // this secondary walk specifically checks for some other cases, // like defaulted traits, for which additional overlap rules exist - tcx.visit_all_items_in_krate(DepNode::CoherenceOverlapCheckSpecial, &mut overlap); + tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOverlapCheckSpecial, &mut overlap); } struct OverlapChecker<'cx, 'tcx: 'cx> { @@ -97,7 +97,7 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> { } } -impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> { +impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OverlapChecker<'cx, 'tcx> { fn visit_item(&mut self, item: &'v hir::Item) { match item.node { hir::ItemEnum(..) | @@ -134,6 +134,12 @@ impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> { let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap(); let trait_def_id = trait_ref.def_id; + if trait_ref.references_error() { + debug!("coherence: skipping impl {:?} with error {:?}", + impl_def_id, trait_ref); + return + } + let _task = self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapCheck(trait_def_id)); @@ -199,4 +205,7 @@ impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> { _ => {} } } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + } } diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs index cca6c8843067..6d5de8f25065 100644 --- a/src/librustc_typeck/coherence/unsafety.rs +++ b/src/librustc_typeck/coherence/unsafety.rs @@ -12,12 +12,12 @@ //! crate or pertains to a type defined in this crate. use rustc::ty::TyCtxt; -use rustc::hir::intravisit; +use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::{self, Unsafety}; pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let mut orphan = UnsafetyChecker { tcx: tcx }; - tcx.map.krate().visit_all_items(&mut orphan); + let mut unsafety = UnsafetyChecker { tcx: tcx }; + tcx.map.krate().visit_all_item_likes(&mut unsafety); } struct UnsafetyChecker<'cx, 'tcx: 'cx> { @@ -94,7 +94,7 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> { } } -impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> { +impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for UnsafetyChecker<'cx, 'tcx> { fn visit_item(&mut self, item: &'v hir::Item) { match item.node { hir::ItemDefaultImpl(unsafety, _) => { @@ -106,4 +106,7 @@ impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> { _ => {} } } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index d92a98485103..535b6bcdcba1 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -13,7 +13,7 @@ # Collect phase The collect phase of type check has the job of visiting all items, -determining their type, and writing that type into the `tcx.tcache` +determining their type, and writing that type into the `tcx.types` table. Despite its name, this table does not really operate as a *cache*, at least not for the types of items defined within the current crate: we assume that after the collect phase, the types of @@ -22,8 +22,7 @@ all local items will be present in the table. Unlike most of the types that are present in Rust, the types computed for each item are in fact type schemes. This means that they are generic types that may have type parameters. TypeSchemes are -represented by an instance of `ty::TypeScheme`. This combines the -core type along with a list of the bounds for each parameter. Type +represented by a pair of `Generics` and `Ty`. Type parameters themselves are represented as `ty_param()` instances. The phasing of type conversion is somewhat complicated. There is no @@ -51,8 +50,8 @@ There are some shortcomings in this design: - Before walking the set of supertraits for a given trait, you must call `ensure_super_predicates` on that trait def-id. Otherwise, - `lookup_super_predicates` will result in ICEs. -- Because the type scheme includes defaults, cycles through type + `item_super_predicates` will result in ICEs. +- Because the item generics include defaults, cycles through type parameter defaults are illegal even if those defaults are never employed. This is not necessarily a bug. @@ -67,24 +66,24 @@ use rustc_const_eval::EvalHint::UncheckedExprHint; use rustc_const_eval::{eval_const_expr_partial, report_const_eval_err}; use rustc::ty::subst::Substs; use rustc::ty::{ToPredicate, ImplContainer, AssociatedItemContainer, TraitContainer}; -use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt, TypeScheme}; +use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt}; use rustc::ty::util::IntTypeExt; use rscope::*; use rustc::dep_graph::DepNode; use util::common::{ErrorReported, MemoizationMap}; use util::nodemap::{NodeMap, FxHashMap, FxHashSet}; -use {CrateCtxt, write_ty_to_tcx}; +use CrateCtxt; use rustc_const_math::ConstInt; use std::cell::RefCell; -use std::collections::hash_map::Entry::{Occupied, Vacant}; use syntax::{abi, ast, attr}; -use syntax::parse::token::keywords; +use syntax::parse::token::{self, keywords}; use syntax_pos::Span; -use rustc::hir::{self, intravisit, map as hir_map, print as pprust}; +use rustc::hir::{self, map as hir_map, print as pprust}; +use rustc::hir::intravisit::{self, Visitor}; use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def_id::DefId; @@ -93,7 +92,7 @@ use rustc::hir::def_id::DefId; pub fn collect_item_types(ccx: &CrateCtxt) { let mut visitor = CollectItemTypesVisitor { ccx: ccx }; - ccx.tcx.visit_all_items_in_krate(DepNode::CollectItem, &mut visitor); + ccx.tcx.visit_all_item_likes_in_krate(DepNode::CollectItem, &mut visitor.as_deep_visitor()); } /////////////////////////////////////////////////////////////////////////// @@ -129,9 +128,30 @@ struct CollectItemTypesVisitor<'a, 'tcx: 'a> { ccx: &'a CrateCtxt<'a, 'tcx> } -impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> { +impl<'a, 'tcx, 'v> Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { convert_item(self.ccx, item); + intravisit::walk_item(self, item); + } + + fn visit_expr(&mut self, expr: &hir::Expr) { + if let hir::ExprClosure(..) = expr.node { + convert_closure(self.ccx, expr.id); + } + intravisit::walk_expr(self, expr); + } + + fn visit_ty(&mut self, ty: &hir::Ty) { + if let hir::TyImplTrait(..) = ty.node { + let def_id = self.ccx.tcx.map.local_def_id(ty.id); + generics_of_def_id(self.ccx, def_id); + } + intravisit::walk_ty(self, ty); + } + + fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) { + convert_impl_item(self.ccx, impl_item); + intravisit::walk_impl_item(self, impl_item); } } @@ -308,11 +328,9 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> { }) } - fn get_item_type_scheme(&self, span: Span, id: DefId) - -> Result, ErrorReported> - { + fn get_item_type(&self, span: Span, id: DefId) -> Result, ErrorReported> { self.ccx.cycle_check(span, AstConvRequest::GetItemTypeScheme(id), || { - Ok(type_scheme_of_def_id(self.ccx, id)) + Ok(type_of_def_id(self.ccx, id)) }) } @@ -447,7 +465,7 @@ impl<'tcx> GetTypeParameterBounds<'tcx> for ty::GenericPredicates<'tcx> { let def = astconv.tcx().type_parameter_def(node_id); let mut results = self.parent.map_or(vec![], |def_id| { - let parent = astconv.tcx().lookup_predicates(def_id); + let parent = astconv.tcx().item_predicates(def_id); parent.get_type_parameter_bounds(astconv, span, node_id) }); @@ -546,16 +564,45 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, { let tt = ccx.icx(struct_predicates).to_ty(&ExplicitRscope, &field.ty); ty_f.fulfill_ty(tt); - write_ty_to_tcx(ccx, field.id, tt); - /* add the field to the tcache */ - ccx.tcx.register_item_type(ccx.tcx.map.local_def_id(field.id), - ty::TypeScheme { - generics: struct_generics, - ty: tt - }); - ccx.tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(field.id), - struct_predicates.clone()); + let def_id = ccx.tcx.map.local_def_id(field.id); + ccx.tcx.item_types.borrow_mut().insert(def_id, tt); + ccx.tcx.generics.borrow_mut().insert(def_id, struct_generics); + ccx.tcx.predicates.borrow_mut().insert(def_id, struct_predicates.clone()); +} + +fn convert_closure<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + node_id: ast::NodeId) +{ + let tcx = ccx.tcx; + let def_id = tcx.map.local_def_id(node_id); + let base_def_id = tcx.closure_base_def_id(def_id); + let base_generics = generics_of_def_id(ccx, base_def_id); + + // provide junk type parameter defs - the only place that + // cares about anything but the length is instantiation, + // and we don't do that for closures. + let upvar_decls : Vec<_> = tcx.with_freevars(node_id, |fv| { + fv.iter().enumerate().map(|(i, _)| ty::TypeParameterDef { + index: (base_generics.count() as u32) + (i as u32), + name: token::intern(""), + def_id: def_id, + default_def_id: base_def_id, + default: None, + object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault, + pure_wrt_drop: false, + }).collect() + }); + tcx.generics.borrow_mut().insert(def_id, tcx.alloc_generics(ty::Generics { + parent: Some(base_def_id), + parent_regions: base_generics.parent_regions + (base_generics.regions.len() as u32), + parent_types: base_generics.parent_types + (base_generics.types.len() as u32), + regions: vec![], + types: upvar_decls, + has_self: base_generics.has_self, + })); + + type_of_def_id(ccx, def_id); } fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, @@ -580,8 +627,7 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let substs = mk_item_substs(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)), ccx.tcx.map.span(id), def_id); let fty = ccx.tcx.mk_fn_def(def_id, substs, fty); - ccx.tcx.tcache.borrow_mut().insert(def_id, fty); - write_ty_to_tcx(ccx, id, fty); + ccx.tcx.item_types.borrow_mut().insert(def_id, fty); ccx.tcx.predicates.borrow_mut().insert(def_id, ty_generic_predicates); } @@ -596,9 +642,7 @@ fn convert_associated_const<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, }; let def_id = ccx.tcx.map.local_def_id(id); ccx.tcx.predicates.borrow_mut().insert(def_id, predicates); - ccx.tcx.tcache.borrow_mut().insert(def_id, ty); - - write_ty_to_tcx(ccx, id, ty); + ccx.tcx.item_types.borrow_mut().insert(def_id, ty); } fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, @@ -614,8 +658,7 @@ fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ccx.tcx.predicates.borrow_mut().insert(def_id, predicates); if let Some(ty) = ty { - ccx.tcx.tcache.borrow_mut().insert(def_id, ty); - write_ty_to_tcx(ccx, id, ty); + ccx.tcx.item_types.borrow_mut().insert(def_id, ty); } } @@ -662,11 +705,13 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { } hir::ItemEnum(ref enum_definition, _) => { let def_id = ccx.tcx.map.local_def_id(it.id); - let scheme = type_scheme_of_def_id(ccx, def_id); + let ty = type_of_def_id(ccx, def_id); + let generics = generics_of_def_id(ccx, def_id); let predicates = predicates_of_item(ccx, it); convert_enum_variant_types(ccx, tcx.lookup_adt_def_master(ccx.tcx.map.local_def_id(it.id)), - scheme, + ty, + generics, predicates, &enum_definition.variants); }, @@ -686,22 +731,19 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { ref generics, ref opt_trait_ref, ref selfty, - ref impl_items) => { + _) => { // Create generics from the generics specified in the impl head. debug!("convert: ast_generics={:?}", generics); let def_id = ccx.tcx.map.local_def_id(it.id); - let ty_generics = generics_of_def_id(ccx, def_id); + generics_of_def_id(ccx, def_id); let mut ty_predicates = ty_generic_predicates(ccx, generics, None, vec![], false); debug!("convert: impl_bounds={:?}", ty_predicates); let selfty = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, &selfty); - write_ty_to_tcx(ccx, it.id, selfty); + tcx.item_types.borrow_mut().insert(def_id, selfty); - tcx.register_item_type(def_id, - TypeScheme { generics: ty_generics, - ty: selfty }); let trait_ref = opt_trait_ref.as_ref().map(|ast_trait_ref| { AstConv::instantiate_mono_trait_ref(&ccx.icx(&ty_predicates), &ExplicitRscope, @@ -710,77 +752,16 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { }); tcx.impl_trait_refs.borrow_mut().insert(def_id, trait_ref); - enforce_impl_params_are_constrained(ccx, generics, &mut ty_predicates, def_id); + // Subtle: before we store the predicates into the tcx, we + // sort them so that predicates like `T: Foo` come + // before uses of `U`. This avoids false ambiguity errors + // in trait checking. See `setup_constraining_predicates` + // for details. + ctp::setup_constraining_predicates(&mut ty_predicates.predicates, + trait_ref, + &mut ctp::parameters_for_impl(selfty, trait_ref)); + tcx.predicates.borrow_mut().insert(def_id, ty_predicates.clone()); - - - // Convert all the associated consts. - // Also, check if there are any duplicate associated items - let mut seen_type_items = FxHashMap(); - let mut seen_value_items = FxHashMap(); - - for impl_item in impl_items { - let seen_items = match impl_item.node { - hir::ImplItemKind::Type(_) => &mut seen_type_items, - _ => &mut seen_value_items, - }; - match seen_items.entry(impl_item.name) { - Occupied(entry) => { - let mut err = struct_span_err!(tcx.sess, impl_item.span, E0201, - "duplicate definitions with name `{}`:", - impl_item.name); - err.span_label(*entry.get(), - &format!("previous definition of `{}` here", - impl_item.name)); - err.span_label(impl_item.span, &format!("duplicate definition")); - err.emit(); - } - Vacant(entry) => { - entry.insert(impl_item.span); - } - } - - if let hir::ImplItemKind::Const(ref ty, _) = impl_item.node { - let const_def_id = ccx.tcx.map.local_def_id(impl_item.id); - let ty_generics = generics_of_def_id(ccx, const_def_id); - let ty = ccx.icx(&ty_predicates) - .to_ty(&ExplicitRscope, &ty); - tcx.register_item_type(const_def_id, - TypeScheme { - generics: ty_generics, - ty: ty, - }); - convert_associated_const(ccx, ImplContainer(def_id), - impl_item.id, ty); - } - } - - // Convert all the associated types. - for impl_item in impl_items { - if let hir::ImplItemKind::Type(ref ty) = impl_item.node { - let type_def_id = ccx.tcx.map.local_def_id(impl_item.id); - generics_of_def_id(ccx, type_def_id); - - if opt_trait_ref.is_none() { - span_err!(tcx.sess, impl_item.span, E0202, - "associated types are not allowed in inherent impls"); - } - - let typ = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, ty); - - convert_associated_type(ccx, ImplContainer(def_id), impl_item.id, Some(typ)); - } - } - - for impl_item in impl_items { - if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node { - convert_method(ccx, ImplContainer(def_id), - impl_item.id, sig, selfty, - &ty_predicates); - } - } - - enforce_impl_lifetimes_are_constrained(ccx, generics, def_id, impl_items); }, hir::ItemTrait(.., ref trait_items) => { let trait_def = trait_def_of_item(ccx, it); @@ -788,7 +769,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { let _: Result<(), ErrorReported> = // any error is already reported, can ignore ccx.ensure_super_predicates(it.span, def_id); convert_trait_predicates(ccx, it); - let trait_predicates = tcx.lookup_predicates(def_id); + let trait_predicates = tcx.item_predicates(def_id); debug!("convert: trait_bounds={:?}", trait_predicates); @@ -799,14 +780,10 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { for trait_item in trait_items { if let hir::ConstTraitItem(ref ty, _) = trait_item.node { let const_def_id = ccx.tcx.map.local_def_id(trait_item.id); - let ty_generics = generics_of_def_id(ccx, const_def_id); + generics_of_def_id(ccx, const_def_id); let ty = ccx.icx(&trait_predicates) .to_ty(&ExplicitRscope, ty); - tcx.register_item_type(const_def_id, - TypeScheme { - generics: ty_generics, - ty: ty, - }); + tcx.item_types.borrow_mut().insert(const_def_id, ty); convert_associated_const(ccx, container, trait_item.id, ty) } } @@ -840,43 +817,89 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { hir::ItemStruct(ref struct_def, _) | hir::ItemUnion(ref struct_def, _) => { let def_id = ccx.tcx.map.local_def_id(it.id); - let scheme = type_scheme_of_def_id(ccx, def_id); + let ty = type_of_def_id(ccx, def_id); + let generics = generics_of_def_id(ccx, def_id); let predicates = predicates_of_item(ccx, it); let variant = tcx.lookup_adt_def_master(def_id).struct_variant(); for (f, ty_f) in struct_def.fields().iter().zip(variant.fields.iter()) { - convert_field(ccx, &scheme.generics, &predicates, f, ty_f) + convert_field(ccx, generics, &predicates, f, ty_f) } if !struct_def.is_struct() { - convert_variant_ctor(ccx, struct_def.id(), variant, scheme, predicates); + convert_variant_ctor(ccx, struct_def.id(), variant, ty, predicates); } }, hir::ItemTy(_, ref generics) => { ensure_no_ty_param_bounds(ccx, it.span, generics, "type"); let def_id = ccx.tcx.map.local_def_id(it.id); - type_scheme_of_def_id(ccx, def_id); + type_of_def_id(ccx, def_id); + generics_of_def_id(ccx, def_id); predicates_of_item(ccx, it); }, _ => { let def_id = ccx.tcx.map.local_def_id(it.id); - type_scheme_of_def_id(ccx, def_id); + type_of_def_id(ccx, def_id); + generics_of_def_id(ccx, def_id); predicates_of_item(ccx, it); }, } } +fn convert_impl_item(ccx: &CrateCtxt, impl_item: &hir::ImplItem) { + let tcx = ccx.tcx; + + // we can lookup details about the impl because items are visited + // before impl-items + let impl_def_id = tcx.map.get_parent_did(impl_item.id); + let impl_predicates = tcx.item_predicates(impl_def_id); + let impl_trait_ref = tcx.impl_trait_ref(impl_def_id); + let impl_self_ty = tcx.item_type(impl_def_id); + + match impl_item.node { + hir::ImplItemKind::Const(ref ty, _) => { + let const_def_id = ccx.tcx.map.local_def_id(impl_item.id); + generics_of_def_id(ccx, const_def_id); + let ty = ccx.icx(&impl_predicates) + .to_ty(&ExplicitRscope, &ty); + tcx.item_types.borrow_mut().insert(const_def_id, ty); + convert_associated_const(ccx, ImplContainer(impl_def_id), + impl_item.id, ty); + } + + hir::ImplItemKind::Type(ref ty) => { + let type_def_id = ccx.tcx.map.local_def_id(impl_item.id); + generics_of_def_id(ccx, type_def_id); + + if impl_trait_ref.is_none() { + span_err!(tcx.sess, impl_item.span, E0202, + "associated types are not allowed in inherent impls"); + } + + let typ = ccx.icx(&impl_predicates).to_ty(&ExplicitRscope, ty); + + convert_associated_type(ccx, ImplContainer(impl_def_id), impl_item.id, Some(typ)); + } + + hir::ImplItemKind::Method(ref sig, _) => { + convert_method(ccx, ImplContainer(impl_def_id), + impl_item.id, sig, impl_self_ty, + &impl_predicates); + } + } +} + fn convert_variant_ctor<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ctor_id: ast::NodeId, variant: ty::VariantDef<'tcx>, - scheme: ty::TypeScheme<'tcx>, + ty: Ty<'tcx>, predicates: ty::GenericPredicates<'tcx>) { let tcx = ccx.tcx; let def_id = tcx.map.local_def_id(ctor_id); generics_of_def_id(ccx, def_id); let ctor_ty = match variant.ctor_kind { - CtorKind::Fictive | CtorKind::Const => scheme.ty, + CtorKind::Fictive | CtorKind::Const => ty, CtorKind::Fn => { let inputs: Vec<_> = variant.fields @@ -890,26 +913,26 @@ fn convert_variant_ctor<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, abi: abi::Abi::Rust, sig: ty::Binder(ty::FnSig { inputs: inputs, - output: scheme.ty, + output: ty, variadic: false }) })) } }; - write_ty_to_tcx(ccx, ctor_id, ctor_ty); - tcx.tcache.borrow_mut().insert(def_id, ctor_ty); + tcx.item_types.borrow_mut().insert(def_id, ctor_ty); tcx.predicates.borrow_mut().insert(tcx.map.local_def_id(ctor_id), predicates); } fn convert_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, def: ty::AdtDefMaster<'tcx>, - scheme: ty::TypeScheme<'tcx>, + ty: Ty<'tcx>, + generics: &'tcx ty::Generics<'tcx>, predicates: ty::GenericPredicates<'tcx>, variants: &[hir::Variant]) { // fill the field types for (variant, ty_variant) in variants.iter().zip(def.variants.iter()) { for (f, ty_f) in variant.node.data.fields().iter().zip(ty_variant.fields.iter()) { - convert_field(ccx, &scheme.generics, &predicates, f, ty_f) + convert_field(ccx, generics, &predicates, f, ty_f) } // Convert the ctor, if any. This also registers the variant as @@ -918,7 +941,7 @@ fn convert_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ccx, variant.node.data.id(), ty_variant, - scheme.clone(), + ty, predicates.clone() ); } @@ -1216,7 +1239,7 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item) } }; - let super_predicates = ccx.tcx.lookup_super_predicates(def_id); + let super_predicates = ccx.tcx.item_super_predicates(def_id); // `ty_generic_predicates` below will consider the bounds on the type // parameters (including `Self`) and the explicit where-clauses, @@ -1283,7 +1306,7 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let node_id = if let Some(id) = tcx.map.as_local_node_id(def_id) { id } else { - return tcx.lookup_generics(def_id); + return tcx.item_generics(def_id); }; tcx.generics.memoize(def_id, || { use rustc::hir::map::*; @@ -1298,6 +1321,18 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let parent_id = tcx.map.get_parent(node_id); Some(tcx.map.local_def_id(parent_id)) } + NodeTy(&hir::Ty { node: hir::TyImplTrait(..), .. }) => { + let mut parent_id = node_id; + loop { + match tcx.map.get(parent_id) { + NodeItem(_) | NodeImplItem(_) | NodeTraitItem(_) => break, + _ => { + parent_id = tcx.map.get_parent_node(parent_id); + } + } + } + Some(tcx.map.local_def_id(parent_id)) + } _ => None }; @@ -1377,13 +1412,11 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let mut own_start = has_self as u32; let (parent_regions, parent_types) = parent_def_id.map_or((0, 0), |def_id| { let generics = generics_of_def_id(ccx, def_id); - assert_eq!(generics.parent, None); - assert_eq!(generics.parent_regions, 0); - assert_eq!(generics.parent_types, 0); assert_eq!(has_self, false); parent_has_self = generics.has_self; own_start = generics.count() as u32; - (generics.regions.len() as u32, generics.types.len() as u32) + (generics.parent_regions + generics.regions.len() as u32, + generics.parent_types + generics.types.len() as u32) }); let early_lifetimes = early_bound_lifetimes_from_generics(ccx, ast_generics); @@ -1436,12 +1469,15 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let node_id = if let Some(id) = ccx.tcx.map.as_local_node_id(def_id) { id } else { - return ccx.tcx.lookup_item_type(def_id).ty; + return ccx.tcx.item_type(def_id); }; - ccx.tcx.tcache.memoize(def_id, || { + ccx.tcx.item_types.memoize(def_id, || { use rustc::hir::map::*; use rustc::hir::*; + // Alway bring in generics, as computing the type needs them. + generics_of_def_id(ccx, def_id); + let ty = match ccx.tcx.map.get(node_id) { NodeItem(item) => { match item.node { @@ -1500,29 +1536,22 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } } + NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) => { + ccx.tcx.mk_closure(def_id, Substs::for_item( + ccx.tcx, def_id, + |def, _| ccx.tcx.mk_region(def.to_early_bound_region()), + |def, _| ccx.tcx.mk_param_from_def(def) + )) + } x => { bug!("unexpected sort of node in type_of_def_id(): {:?}", x); } }; - write_ty_to_tcx(ccx, node_id, ty); ty }) } -fn type_scheme_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a,'tcx>, - def_id: DefId) - -> ty::TypeScheme<'tcx> { - if def_id.is_local() { - ty::TypeScheme { - generics: generics_of_def_id(ccx, def_id), - ty: type_of_def_id(ccx, def_id) - } - } else { - ccx.tcx.lookup_item_type(def_id) - } -} - fn predicates_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item) -> ty::GenericPredicates<'tcx> { @@ -1554,7 +1583,8 @@ fn convert_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // moral failing, but at the moment it seems like the only // convenient way to extract the ABI. - ndm let def_id = ccx.tcx.map.local_def_id(it.id); - type_scheme_of_def_id(ccx, def_id); + type_of_def_id(ccx, def_id); + generics_of_def_id(ccx, def_id); let no_generics = hir::Generics::empty(); let generics = match it.node { @@ -1648,7 +1678,7 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, let ref base_predicates = match parent { Some(def_id) => { assert_eq!(super_predicates, vec![]); - tcx.lookup_predicates(def_id) + tcx.item_predicates(def_id) } None => { ty::GenericPredicates { @@ -2028,110 +2058,3 @@ pub fn mk_item_substs<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, |def, _| tcx.mk_region(def.to_early_bound_region()), |def, _| tcx.mk_param_from_def(def)) } - -/// Checks that all the type parameters on an impl -fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - generics: &hir::Generics, - impl_predicates: &mut ty::GenericPredicates<'tcx>, - impl_def_id: DefId) -{ - let impl_scheme = ccx.tcx.lookup_item_type(impl_def_id); - let impl_trait_ref = ccx.tcx.impl_trait_ref(impl_def_id); - - // The trait reference is an input, so find all type parameters - // reachable from there, to start (if this is an inherent impl, - // then just examine the self type). - let mut input_parameters: FxHashSet<_> = - ctp::parameters_for(&impl_scheme.ty, false).into_iter().collect(); - if let Some(ref trait_ref) = impl_trait_ref { - input_parameters.extend(ctp::parameters_for(trait_ref, false)); - } - - ctp::setup_constraining_predicates(&mut impl_predicates.predicates, - impl_trait_ref, - &mut input_parameters); - - let ty_generics = generics_of_def_id(ccx, impl_def_id); - for (ty_param, param) in ty_generics.types.iter().zip(&generics.ty_params) { - let param_ty = ty::ParamTy::for_def(ty_param); - if !input_parameters.contains(&ctp::Parameter::from(param_ty)) { - report_unused_parameter(ccx, param.span, "type", ¶m_ty.to_string()); - } - } -} - -fn enforce_impl_lifetimes_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - ast_generics: &hir::Generics, - impl_def_id: DefId, - impl_items: &[hir::ImplItem]) -{ - // Every lifetime used in an associated type must be constrained. - let impl_scheme = ccx.tcx.lookup_item_type(impl_def_id); - let impl_predicates = ccx.tcx.lookup_predicates(impl_def_id); - let impl_trait_ref = ccx.tcx.impl_trait_ref(impl_def_id); - - let mut input_parameters: FxHashSet<_> = - ctp::parameters_for(&impl_scheme.ty, false).into_iter().collect(); - if let Some(ref trait_ref) = impl_trait_ref { - input_parameters.extend(ctp::parameters_for(trait_ref, false)); - } - ctp::identify_constrained_type_params( - &impl_predicates.predicates.as_slice(), impl_trait_ref, &mut input_parameters); - - let lifetimes_in_associated_types: FxHashSet<_> = impl_items.iter() - .map(|item| ccx.tcx.map.local_def_id(item.id)) - .filter(|&def_id| { - let item = ccx.tcx.associated_item(def_id); - item.kind == ty::AssociatedKind::Type && item.has_value - }) - .flat_map(|def_id| { - ctp::parameters_for(&ccx.tcx.lookup_item_type(def_id).ty, true) - }).collect(); - - for (ty_lifetime, lifetime) in impl_scheme.generics.regions.iter() - .zip(&ast_generics.lifetimes) - { - let param = ctp::Parameter::from(ty_lifetime.to_early_bound_region_data()); - - if - lifetimes_in_associated_types.contains(¶m) && // (*) - !input_parameters.contains(¶m) - { - report_unused_parameter(ccx, lifetime.lifetime.span, - "lifetime", &lifetime.lifetime.name.to_string()); - } - } - - // (*) This is a horrible concession to reality. I think it'd be - // better to just ban unconstrianed lifetimes outright, but in - // practice people do non-hygenic macros like: - // - // ``` - // macro_rules! __impl_slice_eq1 { - // ($Lhs: ty, $Rhs: ty, $Bound: ident) => { - // impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq { - // .... - // } - // } - // } - // ``` - // - // In a concession to backwards compatbility, we continue to - // permit those, so long as the lifetimes aren't used in - // associated types. I believe this is sound, because lifetimes - // used elsewhere are not projected back out. -} - -fn report_unused_parameter(ccx: &CrateCtxt, - span: Span, - kind: &str, - name: &str) -{ - struct_span_err!( - ccx.tcx.sess, span, E0207, - "the {} parameter `{}` is not constrained by the \ - impl trait, self type, or predicates", - kind, name) - .span_label(span, &format!("unconstrained {} parameter", kind)) - .emit(); -} diff --git a/src/librustc_typeck/constrained_type_params.rs b/src/librustc_typeck/constrained_type_params.rs index 7918537a6c08..22be4491273e 100644 --- a/src/librustc_typeck/constrained_type_params.rs +++ b/src/librustc_typeck/constrained_type_params.rs @@ -23,6 +23,18 @@ impl From for Parameter { fn from(param: ty::EarlyBoundRegion) -> Self { Parameter(param.index) } } +/// Return the set of parameters constrained by the impl header. +pub fn parameters_for_impl<'tcx>(impl_self_ty: Ty<'tcx>, + impl_trait_ref: Option>) + -> FxHashSet +{ + let vec = match impl_trait_ref { + Some(tr) => parameters_for(&tr, false), + None => parameters_for(&impl_self_ty, false), + }; + vec.into_iter().collect() +} + /// If `include_projections` is false, returns the list of parameters that are /// constrained by `t` - i.e. the value of each parameter in the list is /// uniquely determined by `t` (see RFC 447). If it is true, return the list diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index be012d8976f6..f5432c6e0fcd 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1355,7 +1355,7 @@ extern "rust-intrinsic" { } ``` -Please check that you provided the right number of lifetime parameters +Please check that you provided the right number of type parameters and verify with the function declaration in the Rust source code. Example: diff --git a/src/librustc_typeck/impl_wf_check.rs b/src/librustc_typeck/impl_wf_check.rs new file mode 100644 index 000000000000..9f5b73d9b307 --- /dev/null +++ b/src/librustc_typeck/impl_wf_check.rs @@ -0,0 +1,203 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This pass enforces various "well-formedness constraints" on impls. +//! Logically, it is part of wfcheck -- but we do it early so that we +//! can stop compilation afterwards, since part of the trait matching +//! infrastructure gets very grumpy if these conditions don't hold. In +//! particular, if there are type parameters that are not part of the +//! impl, then coherence will report strange inference ambiguity +//! errors; if impls have duplicate items, we get misleading +//! specialization errors. These things can (and probably should) be +//! fixed, but for the moment it's easier to do these checks early. + +use constrained_type_params as ctp; +use rustc::dep_graph::DepNode; +use rustc::hir; +use rustc::hir::itemlikevisit::ItemLikeVisitor; +use rustc::hir::def_id::DefId; +use rustc::ty; +use rustc::util::nodemap::{FxHashMap, FxHashSet}; +use std::collections::hash_map::Entry::{Occupied, Vacant}; + +use syntax_pos::Span; + +use CrateCtxt; + +/// Checks that all the type/lifetime parameters on an impl also +/// appear in the trait ref or self-type (or are constrained by a +/// where-clause). These rules are needed to ensure that, given a +/// trait ref like `>`, we can derive the values of all +/// parameters on the impl (which is needed to make specialization +/// possible). +/// +/// However, in the case of lifetimes, we only enforce these rules if +/// the lifetime parameter is used in an associated type. This is a +/// concession to backwards compatibility; see comment at the end of +/// the fn for details. +/// +/// Example: +/// +/// ``` +/// impl Trait for Bar { ... } +/// ^ T does not appear in `Foo` or `Bar`, error! +/// +/// impl Trait> for Bar { ... } +/// ^ T appears in `Foo`, ok. +/// +/// impl Trait for Bar where Bar: Iterator { ... } +/// ^ T is bound to `::Item`, ok. +/// +/// impl<'a> Trait for Bar { } +/// ^ 'a is unused, but for back-compat we allow it +/// +/// impl<'a> Trait for Bar { type X = &'a i32; } +/// ^ 'a is unused and appears in assoc type, error +/// ``` +pub fn impl_wf_check<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>) { + // We will tag this as part of the WF check -- logically, it is, + // but it's one that we must perform earlier than the rest of + // WfCheck. + ccx.tcx.visit_all_item_likes_in_krate(DepNode::WfCheck, &mut ImplWfCheck { ccx: ccx }); +} + +struct ImplWfCheck<'a, 'tcx: 'a> { + ccx: &'a CrateCtxt<'a, 'tcx>, +} + +impl<'a, 'tcx> ItemLikeVisitor<'tcx> for ImplWfCheck<'a, 'tcx> { + fn visit_item(&mut self, item: &'tcx hir::Item) { + match item.node { + hir::ItemImpl(.., ref generics, _, _, ref impl_item_refs) => { + let impl_def_id = self.ccx.tcx.map.local_def_id(item.id); + enforce_impl_params_are_constrained(self.ccx, + generics, + impl_def_id, + impl_item_refs); + enforce_impl_items_are_distinct(self.ccx, impl_item_refs); + } + _ => { } + } + } + + fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem) { } +} + +fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + impl_hir_generics: &hir::Generics, + impl_def_id: DefId, + impl_item_refs: &[hir::ImplItemRef]) +{ + // Every lifetime used in an associated type must be constrained. + let impl_self_ty = ccx.tcx.item_type(impl_def_id); + let impl_generics = ccx.tcx.item_generics(impl_def_id); + let impl_predicates = ccx.tcx.item_predicates(impl_def_id); + let impl_trait_ref = ccx.tcx.impl_trait_ref(impl_def_id); + + let mut input_parameters = ctp::parameters_for_impl(impl_self_ty, impl_trait_ref); + ctp::identify_constrained_type_params( + &impl_predicates.predicates.as_slice(), impl_trait_ref, &mut input_parameters); + + // Disallow ANY unconstrained type parameters. + for (ty_param, param) in impl_generics.types.iter().zip(&impl_hir_generics.ty_params) { + let param_ty = ty::ParamTy::for_def(ty_param); + if !input_parameters.contains(&ctp::Parameter::from(param_ty)) { + report_unused_parameter(ccx, param.span, "type", ¶m_ty.to_string()); + } + } + + // Disallow unconstrained lifetimes, but only if they appear in assoc types. + let lifetimes_in_associated_types: FxHashSet<_> = impl_item_refs.iter() + .map(|item_ref| ccx.tcx.map.local_def_id(item_ref.id.node_id)) + .filter(|&def_id| { + let item = ccx.tcx.associated_item(def_id); + item.kind == ty::AssociatedKind::Type && item.defaultness.has_value() + }) + .flat_map(|def_id| { + ctp::parameters_for(&ccx.tcx.item_type(def_id), true) + }).collect(); + for (ty_lifetime, lifetime) in impl_generics.regions.iter() + .zip(&impl_hir_generics.lifetimes) + { + let param = ctp::Parameter::from(ty_lifetime.to_early_bound_region_data()); + + if + lifetimes_in_associated_types.contains(¶m) && // (*) + !input_parameters.contains(¶m) + { + report_unused_parameter(ccx, lifetime.lifetime.span, + "lifetime", &lifetime.lifetime.name.to_string()); + } + } + + // (*) This is a horrible concession to reality. I think it'd be + // better to just ban unconstrianed lifetimes outright, but in + // practice people do non-hygenic macros like: + // + // ``` + // macro_rules! __impl_slice_eq1 { + // ($Lhs: ty, $Rhs: ty, $Bound: ident) => { + // impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq { + // .... + // } + // } + // } + // ``` + // + // In a concession to backwards compatbility, we continue to + // permit those, so long as the lifetimes aren't used in + // associated types. I believe this is sound, because lifetimes + // used elsewhere are not projected back out. +} + +fn report_unused_parameter(ccx: &CrateCtxt, + span: Span, + kind: &str, + name: &str) +{ + struct_span_err!( + ccx.tcx.sess, span, E0207, + "the {} parameter `{}` is not constrained by the \ + impl trait, self type, or predicates", + kind, name) + .span_label(span, &format!("unconstrained {} parameter", kind)) + .emit(); +} + +/// Enforce that we do not have two items in an impl with the same name. +fn enforce_impl_items_are_distinct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + impl_item_refs: &[hir::ImplItemRef]) +{ + let tcx = ccx.tcx; + let mut seen_type_items = FxHashMap(); + let mut seen_value_items = FxHashMap(); + for impl_item_ref in impl_item_refs { + let impl_item = tcx.map.impl_item(impl_item_ref.id); + let seen_items = match impl_item.node { + hir::ImplItemKind::Type(_) => &mut seen_type_items, + _ => &mut seen_value_items, + }; + match seen_items.entry(impl_item.name) { + Occupied(entry) => { + let mut err = struct_span_err!(tcx.sess, impl_item.span, E0201, + "duplicate definitions with name `{}`:", + impl_item.name); + err.span_label(*entry.get(), + &format!("previous definition of `{}` here", + impl_item.name)); + err.span_label(impl_item.span, &format!("duplicate definition")); + err.emit(); + } + Vacant(entry) => { + entry.insert(impl_item.span); + } + } + } +} diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index d7573c7a7bd2..a1ee69791169 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -44,7 +44,7 @@ independently: into the `ty` representation - collect: computes the types of each top-level item and enters them into - the `cx.tcache` table for later use + the `tcx.types` table for later use - coherence: enforces coherence rules, builds some tables @@ -95,6 +95,7 @@ extern crate rustc_platform_intrinsics as intrinsics; extern crate rustc_back; extern crate rustc_const_math; extern crate rustc_const_eval; +extern crate rustc_data_structures; extern crate rustc_errors as errors; pub use rustc::dep_graph; @@ -106,10 +107,10 @@ pub use rustc::util; use dep_graph::DepNode; use hir::map as hir_map; -use rustc::infer::{InferOk, TypeOrigin}; +use rustc::infer::InferOk; use rustc::ty::subst::Substs; -use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc::traits::{self, Reveal}; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal}; use session::{config, CompileResult}; use util::common::time; @@ -130,6 +131,7 @@ mod rscope; mod astconv; pub mod collect; mod constrained_type_params; +mod impl_wf_check; pub mod coherence; pub mod variance; @@ -159,27 +161,6 @@ pub struct CrateCtxt<'a, 'tcx: 'a> { pub deferred_obligations: RefCell>>>, } -// Functions that write types into the node type table -fn write_ty_to_tcx<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, node_id: ast::NodeId, ty: Ty<'tcx>) { - debug!("write_ty_to_tcx({}, {:?})", node_id, ty); - assert!(!ty.needs_infer()); - ccx.tcx.node_type_insert(node_id, ty); -} - -fn write_substs_to_tcx<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - node_id: ast::NodeId, - item_substs: ty::ItemSubsts<'tcx>) { - if !item_substs.is_noop() { - debug!("write_substs_to_tcx({}, {:?})", - node_id, - item_substs); - - assert!(!item_substs.substs.needs_infer()); - - ccx.tcx.tables.borrow_mut().item_substs.insert(node_id, item_substs); - } -} - fn require_c_abi_if_variadic(tcx: TyCtxt, decl: &hir::FnDecl, abi: Abi, @@ -193,19 +174,19 @@ fn require_c_abi_if_variadic(tcx: TyCtxt, } fn require_same_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - origin: TypeOrigin, + cause: &ObligationCause<'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>) -> bool { ccx.tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| { - match infcx.eq_types(false, origin.clone(), expected, actual) { + match infcx.eq_types(false, &cause, expected, actual) { Ok(InferOk { obligations, .. }) => { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()); true } Err(err) => { - infcx.report_mismatched_types(origin, expected, actual, err); + infcx.report_mismatched_types(cause, expected, actual, err); false } } @@ -216,7 +197,8 @@ fn check_main_fn_ty(ccx: &CrateCtxt, main_id: ast::NodeId, main_span: Span) { let tcx = ccx.tcx; - let main_t = tcx.tables().node_id_to_type(main_id); + let main_def_id = tcx.map.local_def_id(main_id); + let main_t = tcx.item_type(main_def_id); match main_t.sty { ty::TyFnDef(..) => { match tcx.map.find(main_id) { @@ -237,7 +219,6 @@ fn check_main_fn_ty(ccx: &CrateCtxt, } _ => () } - let main_def_id = tcx.map.local_def_id(main_id); let substs = tcx.intern_substs(&[]); let se_ty = tcx.mk_fn_def(main_def_id, substs, tcx.mk_bare_fn(ty::BareFnTy { @@ -252,7 +233,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt, require_same_types( ccx, - TypeOrigin::MainFunctionType(main_span), + &ObligationCause::new(main_span, main_id, ObligationCauseCode::MainFunctionType), se_ty, main_t); } @@ -268,7 +249,8 @@ fn check_start_fn_ty(ccx: &CrateCtxt, start_id: ast::NodeId, start_span: Span) { let tcx = ccx.tcx; - let start_t = tcx.tables().node_id_to_type(start_id); + let start_def_id = ccx.tcx.map.local_def_id(start_id); + let start_t = tcx.item_type(start_def_id); match start_t.sty { ty::TyFnDef(..) => { match tcx.map.find(start_id) { @@ -289,7 +271,6 @@ fn check_start_fn_ty(ccx: &CrateCtxt, _ => () } - let start_def_id = ccx.tcx.map.local_def_id(start_id); let substs = tcx.intern_substs(&[]); let se_ty = tcx.mk_fn_def(start_def_id, substs, tcx.mk_bare_fn(ty::BareFnTy { @@ -307,7 +288,7 @@ fn check_start_fn_ty(ccx: &CrateCtxt, require_same_types( ccx, - TypeOrigin::StartFunctionType(start_span), + &ObligationCause::new(start_span, start_id, ObligationCauseCode::StartFunctionType), se_ty, start_t); } @@ -354,6 +335,11 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) time(time_passes, "variance inference", || variance::infer_variance(tcx)); + tcx.sess.track_errors(|| { + time(time_passes, "impl wf inference", || + impl_wf_check::impl_wf_check(&ccx)); + })?; + tcx.sess.track_errors(|| { time(time_passes, "coherence checking", || coherence::check_coherence(&ccx)); diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index c9e93a1a46d6..8a0c1c68322d 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -22,7 +22,7 @@ use rustc::ty::maps::ItemVariances; use rustc::hir::map as hir_map; use syntax::ast; use rustc::hir; -use rustc::hir::intravisit::Visitor; +use rustc::hir::itemlikevisit::ItemLikeVisitor; use super::terms::*; use super::terms::VarianceTerm::*; @@ -65,13 +65,13 @@ pub fn add_constraints_from_crate<'a, 'tcx>(terms_cx: TermsContext<'a, 'tcx>) }; // See README.md for a discussion on dep-graph management. - tcx.visit_all_items_in_krate(|def_id| ItemVariances::to_dep_node(&def_id), - &mut constraint_cx); + tcx.visit_all_item_likes_in_krate(|def_id| ItemVariances::to_dep_node(&def_id), + &mut constraint_cx); constraint_cx } -impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> { +impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { let tcx = self.terms_cx.tcx; let did = tcx.map.local_def_id(item.id); @@ -82,16 +82,16 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> { hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemUnion(..) => { - let scheme = tcx.lookup_item_type(did); + let generics = tcx.item_generics(did); // Not entirely obvious: constraints on structs/enums do not // affect the variance of their type parameters. See discussion // in comment at top of module. // - // self.add_constraints_from_generics(&scheme.generics); + // self.add_constraints_from_generics(generics); for field in tcx.lookup_adt_def(did).all_fields() { - self.add_constraints_from_ty(&scheme.generics, + self.add_constraints_from_ty(generics, field.unsubst_ty(), self.covariant); } @@ -115,6 +115,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> { hir::ItemDefaultImpl(..) => {} } } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + } } /// Is `param_id` a lifetime according to `map`? @@ -336,7 +339,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } ty::TyAdt(def, substs) => { - let item_type = self.tcx().lookup_item_type(def.did); + let adt_generics = self.tcx().item_generics(def.did); // This edge is actually implied by the call to // `lookup_trait_def`, but I'm trying to be future-proof. See @@ -345,8 +348,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.add_constraints_from_substs(generics, def.did, - &item_type.generics.types, - &item_type.generics.regions, + &adt_generics.types, + &adt_generics.regions, substs, variance); } diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs index f6732f36e355..0a3238480d90 100644 --- a/src/librustc_typeck/variance/terms.rs +++ b/src/librustc_typeck/variance/terms.rs @@ -27,7 +27,7 @@ use std::fmt; use std::rc::Rc; use syntax::ast; use rustc::hir; -use rustc::hir::intravisit::Visitor; +use rustc::hir::itemlikevisit::ItemLikeVisitor; use util::nodemap::NodeMap; use self::VarianceTerm::*; @@ -109,7 +109,7 @@ pub fn determine_parameters_to_be_inferred<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx> }; // See README.md for a discussion on dep-graph management. - tcx.visit_all_items_in_krate(|def_id| ItemVariances::to_dep_node(&def_id), &mut terms_cx); + tcx.visit_all_item_likes_in_krate(|def_id| ItemVariances::to_dep_node(&def_id), &mut terms_cx); terms_cx } @@ -227,7 +227,7 @@ impl<'a, 'tcx> TermsContext<'a, 'tcx> { } } -impl<'a, 'tcx, 'v> Visitor<'v> for TermsContext<'a, 'tcx> { +impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { debug!("add_inferreds for item {}", self.tcx.map.node_to_string(item.id)); @@ -257,4 +257,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for TermsContext<'a, 'tcx> { hir::ItemTy(..) => {} } } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + } } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index a2955169cbb8..185f897c1baa 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -164,7 +164,7 @@ pub fn build_external_trait<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tc did: DefId) -> clean::Trait { let def = tcx.lookup_trait_def(did); let trait_items = tcx.associated_items(did).map(|item| item.clean(cx)).collect(); - let predicates = tcx.lookup_predicates(did); + let predicates = tcx.item_predicates(did); let generics = (def.generics, &predicates).clean(cx); let generics = filter_non_trait_generics(did, generics); let (generics, supertrait_bounds) = separate_supertrait_bounds(generics); @@ -178,8 +178,8 @@ pub fn build_external_trait<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tc fn build_external_function<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> clean::Function { - let t = tcx.lookup_item_type(did); - let (decl, style, abi) = match t.ty.sty { + let ty = tcx.item_type(did); + let (decl, style, abi) = match ty.sty { ty::TyFnDef(.., ref f) => ((did, &f.sig).clean(cx), f.unsafety, f.abi), _ => panic!("bad function"), }; @@ -190,10 +190,10 @@ fn build_external_function<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx hir::Constness::NotConst }; - let predicates = tcx.lookup_predicates(did); + let predicates = tcx.item_predicates(did); clean::Function { decl: decl, - generics: (t.generics, &predicates).clean(cx), + generics: (tcx.item_generics(did), &predicates).clean(cx), unsafety: style, constness: constness, abi: abi, @@ -202,11 +202,10 @@ fn build_external_function<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx fn build_enum<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> clean::Enum { - let t = tcx.lookup_item_type(did); - let predicates = tcx.lookup_predicates(did); + let predicates = tcx.item_predicates(did); clean::Enum { - generics: (t.generics, &predicates).clean(cx), + generics: (tcx.item_generics(did), &predicates).clean(cx), variants_stripped: false, variants: tcx.lookup_adt_def(did).variants.clean(cx), } @@ -214,8 +213,7 @@ fn build_enum<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, fn build_struct<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> clean::Struct { - let t = tcx.lookup_item_type(did); - let predicates = tcx.lookup_predicates(did); + let predicates = tcx.item_predicates(did); let variant = tcx.lookup_adt_def(did).struct_variant(); clean::Struct { @@ -224,7 +222,7 @@ fn build_struct<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, CtorKind::Fn => doctree::Tuple, CtorKind::Const => doctree::Unit, }, - generics: (t.generics, &predicates).clean(cx), + generics: (tcx.item_generics(did), &predicates).clean(cx), fields: variant.fields.clean(cx), fields_stripped: false, } @@ -232,13 +230,12 @@ fn build_struct<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, fn build_union<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> clean::Union { - let t = tcx.lookup_item_type(did); - let predicates = tcx.lookup_predicates(did); + let predicates = tcx.item_predicates(did); let variant = tcx.lookup_adt_def(did).struct_variant(); clean::Union { struct_type: doctree::Plain, - generics: (t.generics, &predicates).clean(cx), + generics: (tcx.item_generics(did), &predicates).clean(cx), fields: variant.fields.clean(cx), fields_stripped: false, } @@ -246,12 +243,11 @@ fn build_union<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, fn build_type_alias<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> clean::Typedef { - let t = tcx.lookup_item_type(did); - let predicates = tcx.lookup_predicates(did); + let predicates = tcx.item_predicates(did); clean::Typedef { - type_: t.ty.clean(cx), - generics: (t.generics, &predicates).clean(cx), + type_: tcx.item_type(did).clean(cx), + generics: (tcx.item_generics(did), &predicates).clean(cx), } } @@ -354,8 +350,7 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, }); } - let ty = tcx.lookup_item_type(did); - let for_ = ty.ty.clean(cx); + let for_ = tcx.item_type(did).clean(cx); // Only inline impl if the implementing type is // reachable in rustdoc generated documentation @@ -365,12 +360,11 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, } } - let predicates = tcx.lookup_predicates(did); + let predicates = tcx.item_predicates(did); let trait_items = tcx.associated_items(did).filter_map(|item| { match item.kind { ty::AssociatedKind::Const => { - let type_scheme = tcx.lookup_item_type(item.def_id); - let default = if item.has_value { + let default = if item.defaultness.has_value() { Some(pprust::expr_to_string( lookup_const_by_id(tcx, item.def_id, None).unwrap().0)) } else { @@ -379,7 +373,7 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, Some(clean::Item { name: Some(item.name.clean(cx)), inner: clean::AssociatedConstItem( - type_scheme.ty.clean(cx), + tcx.item_type(item.def_id).clean(cx), default, ), source: clean::Span::empty(), @@ -413,13 +407,13 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, abi: abi }) } - _ => panic!("not a tymethod"), + ref r => panic!("not a tymethod: {:?}", r), }; Some(cleaned) } ty::AssociatedKind::Type => { let typedef = clean::Typedef { - type_: tcx.lookup_item_type(item.def_id).ty.clean(cx), + type_: tcx.item_type(item.def_id).clean(cx), generics: clean::Generics { lifetimes: vec![], type_params: vec![], @@ -463,7 +457,7 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, provided_trait_methods: provided, trait_: trait_, for_: for_, - generics: (ty.generics, &predicates).clean(cx), + generics: (tcx.item_generics(did), &predicates).clean(cx), items: trait_items, polarity: Some(polarity.clean(cx)), }), @@ -514,7 +508,7 @@ fn build_const<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("got snippet {}", sn); clean::Constant { - type_: ty.map(|t| t.clean(cx)).unwrap_or_else(|| tcx.lookup_item_type(did).ty.clean(cx)), + type_: ty.map(|t| t.clean(cx)).unwrap_or_else(|| tcx.item_type(did).clean(cx)), expr: sn } } @@ -523,7 +517,7 @@ fn build_static<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId, mutable: bool) -> clean::Static { clean::Static { - type_: tcx.lookup_item_type(did).ty.clean(cx), + type_: tcx.item_type(did).clean(cx), mutability: if mutable {clean::Mutable} else {clean::Immutable}, expr: "\n\n\n".to_string(), // trigger the "[definition]" links } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 9e29d191946b..a141d0e4788d 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1342,13 +1342,13 @@ impl<'tcx> Clean for ty::AssociatedItem { fn clean(&self, cx: &DocContext) -> Item { let inner = match self.kind { ty::AssociatedKind::Const => { - let ty = cx.tcx().lookup_item_type(self.def_id).ty; + let ty = cx.tcx().item_type(self.def_id); AssociatedConstItem(ty.clean(cx), None) } ty::AssociatedKind::Method => { - let generics = (cx.tcx().lookup_generics(self.def_id), - &cx.tcx().lookup_predicates(self.def_id)).clean(cx); - let fty = match cx.tcx().lookup_item_type(self.def_id).ty.sty { + let generics = (cx.tcx().item_generics(self.def_id), + &cx.tcx().item_predicates(self.def_id)).clean(cx); + let fty = match cx.tcx().item_type(self.def_id).sty { ty::TyFnDef(_, _, f) => f, _ => unreachable!() }; @@ -1357,7 +1357,7 @@ impl<'tcx> Clean for ty::AssociatedItem { if self.method_has_self_argument { let self_ty = match self.container { ty::ImplContainer(def_id) => { - cx.tcx().lookup_item_type(def_id).ty + cx.tcx().item_type(def_id) } ty::TraitContainer(_) => cx.tcx().mk_self_type() }; @@ -1373,9 +1373,10 @@ impl<'tcx> Clean for ty::AssociatedItem { } } } + let provided = match self.container { ty::ImplContainer(_) => false, - ty::TraitContainer(_) => self.has_value + ty::TraitContainer(_) => self.defaultness.has_value() }; if provided { MethodItem(Method { @@ -1405,7 +1406,7 @@ impl<'tcx> Clean for ty::AssociatedItem { // all of the generics from there and then look for bounds that are // applied to this associated type in question. let def = cx.tcx().lookup_trait_def(did); - let predicates = cx.tcx().lookup_predicates(did); + let predicates = cx.tcx().item_predicates(did); let generics = (def.generics, &predicates).clean(cx); generics.where_predicates.iter().filter_map(|pred| { let (name, self_type, trait_, bounds) = match *pred { @@ -1440,8 +1441,8 @@ impl<'tcx> Clean for ty::AssociatedItem { None => bounds.push(TyParamBound::maybe_sized(cx)), } - let ty = if self.has_value { - Some(cx.tcx().lookup_item_type(self.def_id).ty) + let ty = if self.defaultness.has_value() { + Some(cx.tcx().item_type(self.def_id)) } else { None }; @@ -1901,7 +1902,7 @@ impl<'tcx> Clean for ty::Ty<'tcx> { ty::TyAnon(def_id, substs) => { // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, // by looking up the projections associated with the def_id. - let item_predicates = cx.tcx().lookup_predicates(def_id); + let item_predicates = cx.tcx().item_predicates(def_id); let substs = cx.tcx().lift(&substs).unwrap(); let bounds = item_predicates.instantiate(cx.tcx(), substs); ImplTrait(bounds.predicates.into_iter().filter_map(|predicate| { @@ -2890,7 +2891,8 @@ pub struct Stability { pub feature: String, pub since: String, pub deprecated_since: String, - pub reason: String, + pub deprecated_reason: String, + pub unstable_reason: String, pub issue: Option } @@ -2913,12 +2915,13 @@ impl Clean for attr::Stability { Some(attr::RustcDeprecation {ref since, ..}) => since.to_string(), _=> "".to_string(), }, - reason: { - match (&self.rustc_depr, &self.level) { - (&Some(ref depr), _) => depr.reason.to_string(), - (&None, &attr::Unstable {reason: Some(ref reason), ..}) => reason.to_string(), - _ => "".to_string(), - } + deprecated_reason: match self.rustc_depr { + Some(ref depr) => depr.reason.to_string(), + _ => "".to_string(), + }, + unstable_reason: match self.level { + attr::Unstable { reason: Some(ref reason), .. } => reason.to_string(), + _ => "".to_string(), }, issue: match self.level { attr::Unstable {issue, ..} => Some(issue), diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 15e042f8c080..19e084905aa9 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -153,7 +153,7 @@ fn trait_is_same_or_supertrait(cx: &DocContext, child: DefId, if child == trait_ { return true } - let predicates = cx.tcx().lookup_super_predicates(child).predicates; + let predicates = cx.tcx().item_super_predicates(child).predicates; predicates.iter().filter_map(|pred| { if let ty::Predicate::Trait(ref pred) = *pred { if pred.0.trait_ref.self_ty().is_self() { diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 625acce27bd6..eef530081abe 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -42,7 +42,7 @@ pub struct UnsafetySpace(pub hir::Unsafety); #[derive(Copy, Clone)] pub struct ConstnessSpace(pub hir::Constness); /// Wrapper struct for properly emitting a method declaration. -pub struct Method<'a>(pub &'a clean::FnDecl, pub &'a str); +pub struct Method<'a>(pub &'a clean::FnDecl, pub usize); /// Similar to VisSpace, but used for mutability #[derive(Copy, Clone)] pub struct MutableSpace(pub clean::Mutability); @@ -50,7 +50,7 @@ pub struct MutableSpace(pub clean::Mutability); #[derive(Copy, Clone)] pub struct RawMutableSpace(pub clean::Mutability); /// Wrapper struct for emitting a where clause from Generics. -pub struct WhereClause<'a>(pub &'a clean::Generics); +pub struct WhereClause<'a>(pub &'a clean::Generics, pub usize); /// Wrapper struct for emitting type parameter bounds. pub struct TyParamBounds<'a>(pub &'a [clean::TyParamBound]); /// Wrapper struct for emitting a comma-separated list of items @@ -157,52 +157,71 @@ impl fmt::Display for clean::Generics { impl<'a> fmt::Display for WhereClause<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let &WhereClause(gens) = self; + let &WhereClause(gens, pad) = self; if gens.where_predicates.is_empty() { return Ok(()); } + let mut clause = String::new(); if f.alternate() { - f.write_str(" ")?; + clause.push_str(" where "); } else { - f.write_str(" where ")?; + clause.push_str(" where "); } for (i, pred) in gens.where_predicates.iter().enumerate() { if i > 0 { - f.write_str(", ")?; + if f.alternate() { + clause.push_str(", "); + } else { + clause.push_str(",
"); + } } match pred { &clean::WherePredicate::BoundPredicate { ref ty, ref bounds } => { let bounds = bounds; if f.alternate() { - write!(f, "{:#}: {:#}", ty, TyParamBounds(bounds))?; + clause.push_str(&format!("{:#}: {:#}", ty, TyParamBounds(bounds))); } else { - write!(f, "{}: {}", ty, TyParamBounds(bounds))?; + clause.push_str(&format!("{}: {}", ty, TyParamBounds(bounds))); } } &clean::WherePredicate::RegionPredicate { ref lifetime, ref bounds } => { - write!(f, "{}: ", lifetime)?; + clause.push_str(&format!("{}: ", lifetime)); for (i, lifetime) in bounds.iter().enumerate() { if i > 0 { - f.write_str(" + ")?; + clause.push_str(" + "); } - write!(f, "{}", lifetime)?; + clause.push_str(&format!("{}", lifetime)); } } &clean::WherePredicate::EqPredicate { ref lhs, ref rhs } => { if f.alternate() { - write!(f, "{:#} == {:#}", lhs, rhs)?; + clause.push_str(&format!("{:#} == {:#}", lhs, rhs)); } else { - write!(f, "{} == {}", lhs, rhs)?; + clause.push_str(&format!("{} == {}", lhs, rhs)); } } } } if !f.alternate() { - f.write_str("
")?; + clause.push_str("
"); + let plain = format!("{:#}", self); + if plain.len() > 80 { + //break it onto its own line regardless, but make sure method impls and trait + //blocks keep their fixed padding (2 and 9, respectively) + let padding = if pad > 10 { + clause = clause.replace("class='where'", "class='where fmt-newline'"); + repeat(" ").take(8).collect::() + } else { + repeat(" ").take(pad + 6).collect::() + }; + clause = clause.replace("
", &format!("
{}", padding)); + } else { + clause = clause.replace("
", " "); + } } - Ok(()) + write!(f, "{}", clause) } } @@ -718,30 +737,43 @@ impl fmt::Display for clean::Type { } fn fmt_impl(i: &clean::Impl, f: &mut fmt::Formatter, link_trait: bool) -> fmt::Result { + let mut plain = String::new(); + if f.alternate() { write!(f, "impl{:#} ", i.generics)?; } else { write!(f, "impl{} ", i.generics)?; } + plain.push_str(&format!("impl{:#} ", i.generics)); + if let Some(ref ty) = i.trait_ { - write!(f, "{}", - if i.polarity == Some(clean::ImplPolarity::Negative) { "!" } else { "" })?; + if i.polarity == Some(clean::ImplPolarity::Negative) { + write!(f, "!")?; + plain.push_str("!"); + } + if link_trait { fmt::Display::fmt(ty, f)?; + plain.push_str(&format!("{:#}", ty)); } else { match *ty { clean::ResolvedPath{ typarams: None, ref path, is_generic: false, .. } => { let last = path.segments.last().unwrap(); fmt::Display::fmt(&last.name, f)?; fmt::Display::fmt(&last.params, f)?; + plain.push_str(&format!("{:#}{:#}", last.name, last.params)); } _ => unreachable!(), } } write!(f, " for ")?; + plain.push_str(" for "); } + fmt::Display::fmt(&i.for_, f)?; - fmt::Display::fmt(&WhereClause(&i.generics), f)?; + plain.push_str(&format!("{:#}", i.for_)); + + fmt::Display::fmt(&WhereClause(&i.generics, plain.len() + 1), f)?; Ok(()) } @@ -870,24 +902,30 @@ impl<'a> fmt::Display for Method<'a> { let mut output: String; let plain: String; + let pad = repeat(" ").take(indent).collect::(); if arrow.is_empty() { output = format!("({})", args); - plain = format!("{}({})", indent.replace(" ", " "), args_plain); + plain = format!("{}({})", pad, args_plain); } else { output = format!("({args})
{arrow}", args = args, arrow = arrow); - plain = format!("{indent}({args}){arrow}", - indent = indent.replace(" ", " "), + plain = format!("{pad}({args}){arrow}", + pad = pad, args = args_plain, arrow = arrow_plain); } if plain.len() > 80 { - let pad = format!("
{}", indent); + let pad = repeat(" ").take(indent).collect::(); + let pad = format!("
{}", pad); output = output.replace("
", &pad); } else { output = output.replace("
", ""); } - write!(f, "{}", output) + if f.alternate() { + write!(f, "{}", output.replace("
", "\n")) + } else { + write!(f, "{}", output) + } } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 2db771d77111..44dadc4367b5 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -257,8 +257,6 @@ pub struct Cache { parent_stack: Vec, parent_is_trait_impl: bool, search_index: Vec, - seen_modules: FxHashSet, - seen_mod: bool, stripped_mod: bool, deref_trait_did: Option, deref_mut_trait_did: Option, @@ -469,10 +467,8 @@ pub fn run(mut krate: clean::Crate, clean::NameValue(ref x, ref s) if "html_playground_url" == *x => { markdown::PLAYGROUND.with(|slot| { - if slot.borrow().is_none() { - let name = krate.name.clone(); - *slot.borrow_mut() = Some((Some(name), s.clone())); - } + let name = krate.name.clone(); + *slot.borrow_mut() = Some((Some(name), s.clone())); }); } clean::NameValue(ref x, ref s) @@ -520,8 +516,6 @@ pub fn run(mut krate: clean::Crate, parent_is_trait_impl: false, extern_locations: FxHashMap(), primitive_locations: FxHashMap(), - seen_modules: FxHashSet(), - seen_mod: false, stripped_mod: false, access_levels: krate.access_levels.clone(), orphan_impl_items: Vec::new(), @@ -878,12 +872,12 @@ fn extern_location(e: &clean::ExternalCrate, dst: &Path) -> ExternalLocation { impl<'a> DocFolder for SourceCollector<'a> { fn fold_item(&mut self, item: clean::Item) -> Option { // If we're including source files, and we haven't seen this file yet, - // then we need to render it out to the filesystem + // then we need to render it out to the filesystem. if self.scx.include_sources // skip all invalid spans && item.source.filename != "" - // macros from other libraries get special filenames which we can - // safely ignore + // Macros from other libraries get special filenames which we can + // safely ignore. && !(item.source.filename.starts_with("<") && item.source.filename.ends_with("macros>")) { @@ -977,41 +971,30 @@ impl DocFolder for Cache { _ => self.stripped_mod, }; - // Inlining can cause us to visit the same item multiple times. - // (i.e. relevant for gathering impls and implementors) - let orig_seen_mod = if item.is_mod() { - let seen_this = self.seen_mod || !self.seen_modules.insert(item.def_id); - mem::replace(&mut self.seen_mod, seen_this) - } else { - self.seen_mod - }; - // Register any generics to their corresponding string. This is used - // when pretty-printing types + // when pretty-printing types. if let Some(generics) = item.inner.generics() { self.generics(generics); } - if !self.seen_mod { - // Propagate a trait methods' documentation to all implementors of the - // trait - if let clean::TraitItem(ref t) = item.inner { - self.traits.insert(item.def_id, t.clone()); - } + // Propagate a trait method's documentation to all implementors of the + // trait. + if let clean::TraitItem(ref t) = item.inner { + self.traits.entry(item.def_id).or_insert_with(|| t.clone()); + } - // Collect all the implementors of traits. - if let clean::ImplItem(ref i) = item.inner { - if let Some(did) = i.trait_.def_id() { - self.implementors.entry(did).or_insert(vec![]).push(Implementor { - def_id: item.def_id, - stability: item.stability.clone(), - impl_: i.clone(), - }); - } + // Collect all the implementors of traits. + if let clean::ImplItem(ref i) = item.inner { + if let Some(did) = i.trait_.def_id() { + self.implementors.entry(did).or_insert(vec![]).push(Implementor { + def_id: item.def_id, + stability: item.stability.clone(), + impl_: i.clone(), + }); } } - // Index this method for searching later on + // Index this method for searching later on. if let Some(ref s) = item.name { let (parent, is_inherent_impl_item) = match item.inner { clean::StrippedItem(..) => ((None, None), false), @@ -1112,8 +1095,8 @@ impl DocFolder for Cache { (self.stack.clone(), item.type_())); } } - // link variants to their parent enum because pages aren't emitted - // for each variant + // Link variants to their parent enum because pages aren't emitted + // for each variant. clean::VariantItem(..) if !self.stripped_mod => { let mut stack = self.stack.clone(); stack.pop(); @@ -1159,8 +1142,8 @@ impl DocFolder for Cache { _ => false }; - // Once we've recursively found all the generics, then hoard off all the - // implementations elsewhere + // Once we've recursively found all the generics, hoard off all the + // implementations elsewhere. let ret = self.fold_item_recur(item).and_then(|item| { if let clean::Item { inner: clean::ImplItem(_), .. } = item { // Figure out the id of this impl. This may map to a @@ -1186,12 +1169,10 @@ impl DocFolder for Cache { } else { unreachable!() }; - if !self.seen_mod { - if let Some(did) = did { - self.impls.entry(did).or_insert(vec![]).push(Impl { - impl_item: item, - }); - } + if let Some(did) = did { + self.impls.entry(did).or_insert(vec![]).push(Impl { + impl_item: item, + }); } None } else { @@ -1201,7 +1182,6 @@ impl DocFolder for Cache { if pushed { self.stack.pop().unwrap(); } if parent_pushed { self.parent_stack.pop().unwrap(); } - self.seen_mod = orig_seen_mod; self.stripped_mod = orig_stripped_mod; self.parent_is_trait_impl = orig_parent_is_trait_impl; ret @@ -1224,7 +1204,7 @@ impl Context { } /// Recurse in the directory structure and change the "root path" to make - /// sure it always points to the top (relatively) + /// sure it always points to the top (relatively). fn recurse(&mut self, s: String, f: F) -> T where F: FnOnce(&mut Context) -> T, { @@ -1255,11 +1235,11 @@ impl Context { fn krate(self, mut krate: clean::Crate) -> Result<(), Error> { let mut item = match krate.module.take() { Some(i) => i, - None => return Ok(()) + None => return Ok(()), }; item.name = Some(krate.name); - // render the crate documentation + // Render the crate documentation let mut work = vec![(self, item)]; while let Some((mut cx, item)) = work.pop() { @@ -1878,8 +1858,8 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec Vec{}", text)) }; @@ -1909,7 +1889,12 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec{}", text)) }; } else if let Some(depr) = item.deprecation.as_ref() { @@ -1972,14 +1957,13 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, UnstableFeatures::Allow => f.constness, _ => hir::Constness::NotConst }; - let prefix = format!("{}{}{}{:#}fn {}{:#}", + let indent = format!("{}{}{}{:#}fn {}{:#}", VisSpace(&it.visibility), ConstnessSpace(vis_constness), UnsafetySpace(f.unsafety), AbiSpace(f.abi), it.name.as_ref().unwrap(), - f.generics); - let indent = repeat(" ").take(prefix.len()).collect::(); + f.generics).len(); write!(w, "

{vis}{constness}{unsafety}{abi}fn \
                {name}{generics}{decl}{where_clause}
", vis = VisSpace(&it.visibility), @@ -1988,22 +1972,29 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, abi = AbiSpace(f.abi), name = it.name.as_ref().unwrap(), generics = f.generics, - where_clause = WhereClause(&f.generics), - decl = Method(&f.decl, &indent))?; + where_clause = WhereClause(&f.generics, 2), + decl = Method(&f.decl, indent))?; document(w, cx, it) } fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, t: &clean::Trait) -> fmt::Result { let mut bounds = String::new(); + let mut bounds_plain = String::new(); if !t.bounds.is_empty() { if !bounds.is_empty() { bounds.push(' '); + bounds_plain.push(' '); } bounds.push_str(": "); + bounds_plain.push_str(": "); for (i, p) in t.bounds.iter().enumerate() { - if i > 0 { bounds.push_str(" + "); } + if i > 0 { + bounds.push_str(" + "); + bounds_plain.push_str(" + "); + } bounds.push_str(&format!("{}", *p)); + bounds_plain.push_str(&format!("{:#}", *p)); } } @@ -2014,7 +2005,8 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, it.name.as_ref().unwrap(), t.generics, bounds, - WhereClause(&t.generics))?; + // Where clauses in traits are indented nine spaces, per rustdoc.css + WhereClause(&t.generics, 9))?; let types = t.items.iter().filter(|m| m.is_associated_type()).collect::>(); let consts = t.items.iter().filter(|m| m.is_associated_const()).collect::>(); @@ -2028,7 +2020,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, write!(w, "{{\n")?; for t in &types { write!(w, " ")?; - render_assoc_item(w, t, AssocItemLink::Anchor(None))?; + render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait)?; write!(w, ";\n")?; } if !types.is_empty() && !consts.is_empty() { @@ -2036,7 +2028,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, } for t in &consts { write!(w, " ")?; - render_assoc_item(w, t, AssocItemLink::Anchor(None))?; + render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait)?; write!(w, ";\n")?; } if !consts.is_empty() && !required.is_empty() { @@ -2044,7 +2036,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, } for m in &required { write!(w, " ")?; - render_assoc_item(w, m, AssocItemLink::Anchor(None))?; + render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait)?; write!(w, ";\n")?; } if !required.is_empty() && !provided.is_empty() { @@ -2052,7 +2044,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, } for m in &provided { write!(w, " ")?; - render_assoc_item(w, m, AssocItemLink::Anchor(None))?; + render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait)?; write!(w, " {{ ... }}\n")?; } write!(w, "}}")?; @@ -2073,7 +2065,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, id = id, stab = m.stability_class(), ns_id = ns_id)?; - render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)))?; + render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl)?; write!(w, "")?; render_stability_since(w, m, t)?; write!(w, "")?; @@ -2227,7 +2219,8 @@ fn render_stability_since(w: &mut fmt::Formatter, fn render_assoc_item(w: &mut fmt::Formatter, item: &clean::Item, - link: AssocItemLink) -> fmt::Result { + link: AssocItemLink, + parent: ItemType) -> fmt::Result { fn method(w: &mut fmt::Formatter, meth: &clean::Item, unsafety: hir::Unsafety, @@ -2235,7 +2228,8 @@ fn render_assoc_item(w: &mut fmt::Formatter, abi: abi::Abi, g: &clean::Generics, d: &clean::FnDecl, - link: AssocItemLink) + link: AssocItemLink, + parent: ItemType) -> fmt::Result { let name = meth.name.as_ref().unwrap(); let anchor = format!("#{}.{}", meth.type_(), name); @@ -2265,7 +2259,16 @@ fn render_assoc_item(w: &mut fmt::Formatter, AbiSpace(abi), name, *g); - let indent = repeat(" ").take(prefix.len()).collect::(); + let mut indent = prefix.len(); + let where_indent = if parent == ItemType::Trait { + indent += 4; + 8 + } else if parent == ItemType::Impl { + 2 + } else { + let prefix = prefix + &format!("{:#}", Method(d, indent)); + prefix.lines().last().unwrap().len() + 1 + }; write!(w, "{}{}{}fn {name}\ {generics}{decl}{where_clause}", ConstnessSpace(vis_constness), @@ -2274,19 +2277,18 @@ fn render_assoc_item(w: &mut fmt::Formatter, href = href, name = name, generics = *g, - decl = Method(d, &indent), - where_clause = WhereClause(g)) + decl = Method(d, indent), + where_clause = WhereClause(g, where_indent)) } match item.inner { clean::StrippedItem(..) => Ok(()), clean::TyMethodItem(ref m) => { method(w, item, m.unsafety, hir::Constness::NotConst, - m.abi, &m.generics, &m.decl, link) + m.abi, &m.generics, &m.decl, link, parent) } clean::MethodItem(ref m) => { method(w, item, m.unsafety, m.constness, - m.abi, &m.generics, &m.decl, - link) + m.abi, &m.generics, &m.decl, link, parent) } clean::AssociatedConstItem(ref ty, ref default) => { assoc_const(w, item, ty, default.as_ref(), link) @@ -2383,11 +2385,15 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, e: &clean::Enum) -> fmt::Result { write!(w, "
")?;
     render_attributes(w, it)?;
+    let padding = format!("{}enum {}{:#} ",
+                          VisSpace(&it.visibility),
+                          it.name.as_ref().unwrap(),
+                          e.generics).len();
     write!(w, "{}enum {}{}{}",
            VisSpace(&it.visibility),
            it.name.as_ref().unwrap(),
            e.generics,
-           WhereClause(&e.generics))?;
+           WhereClause(&e.generics, padding))?;
     if e.variants.is_empty() && !e.variants_stripped {
         write!(w, " {{}}")?;
     } else {
@@ -2467,8 +2473,13 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
             if let clean::VariantItem(Variant {
                 kind: VariantKind::Struct(ref s)
             }) = variant.inner {
-                write!(w, "

Fields

\n - ")?; + let variant_id = derive_id(format!("{}.{}.fields", + ItemType::Variant, + variant.name.as_ref().unwrap())); + write!(w, "", + id = variant_id)?; + write!(w, "

Fields of {name}

\n +
", name = variant.name.as_ref().unwrap())?; for field in &s.fields { use clean::StructFieldItem; if let StructFieldItem(ref ty) = field.inner { @@ -2492,7 +2503,7 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, write!(w, "")?; } } - write!(w, "
")?; + write!(w, "")?; } render_stability_since(w, variant, it)?; } @@ -2559,17 +2570,23 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item, fields: &[clean::Item], tab: &str, structhead: bool) -> fmt::Result { + let mut plain = String::new(); write!(w, "{}{}{}", VisSpace(&it.visibility), if structhead {"struct "} else {""}, it.name.as_ref().unwrap())?; + plain.push_str(&format!("{}{}{}", + VisSpace(&it.visibility), + if structhead {"struct "} else {""}, + it.name.as_ref().unwrap())); if let Some(g) = g { + plain.push_str(&format!("{:#}", g)); write!(w, "{}", g)? } match ty { doctree::Plain => { if let Some(g) = g { - write!(w, "{}", WhereClause(g))? + write!(w, "{}", WhereClause(g, plain.len() + 1))? } let mut has_visible_fields = false; write!(w, " {{")?; @@ -2598,30 +2615,35 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item, } doctree::Tuple => { write!(w, "(")?; + plain.push_str("("); for (i, field) in fields.iter().enumerate() { if i > 0 { write!(w, ", ")?; + plain.push_str(", "); } match field.inner { clean::StrippedItem(box clean::StructFieldItem(..)) => { + plain.push_str("_"); write!(w, "_")? } clean::StructFieldItem(ref ty) => { + plain.push_str(&format!("{}{:#}", VisSpace(&field.visibility), *ty)); write!(w, "{}{}", VisSpace(&field.visibility), *ty)? } _ => unreachable!() } } write!(w, ")")?; + plain.push_str(")"); if let Some(g) = g { - write!(w, "{}", WhereClause(g))? + write!(w, "{}", WhereClause(g, plain.len() + 1))? } write!(w, ";")?; } doctree::Unit => { // Needed for PhantomData. if let Some(g) = g { - write!(w, "{}", WhereClause(g))? + write!(w, "{}", WhereClause(g, plain.len() + 1))? } write!(w, ";")?; } @@ -2634,13 +2656,19 @@ fn render_union(w: &mut fmt::Formatter, it: &clean::Item, fields: &[clean::Item], tab: &str, structhead: bool) -> fmt::Result { + let mut plain = String::new(); write!(w, "{}{}{}", VisSpace(&it.visibility), if structhead {"union "} else {""}, it.name.as_ref().unwrap())?; + plain.push_str(&format!("{}{}{}", + VisSpace(&it.visibility), + if structhead {"union "} else {""}, + it.name.as_ref().unwrap())); if let Some(g) = g { write!(w, "{}", g)?; - write!(w, "{}", WhereClause(g))?; + plain.push_str(&format!("{:#}", g)); + write!(w, "{}", WhereClause(g, plain.len() + 1))?; } write!(w, " {{\n{}", tab)?; @@ -2831,7 +2859,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi write!(w, "

", id, item_type)?; write!(w, "

\n")?; @@ -2941,10 +2969,11 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi fn item_typedef(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, t: &clean::Typedef) -> fmt::Result { + let indent = format!("type {}{:#} ", it.name.as_ref().unwrap(), t.generics).len(); write!(w, "
type {}{}{where_clause} = {type_};
", it.name.as_ref().unwrap(), t.generics, - where_clause = WhereClause(&t.generics), + where_clause = WhereClause(&t.generics, indent), type_ = t.type_)?; document(w, cx, it) @@ -2956,7 +2985,7 @@ impl<'a> fmt::Display for Sidebar<'a> { let it = self.item; let parentlen = cx.current.len() - if it.is_mod() {1} else {0}; - // the sidebar is designed to display sibling functions, modules and + // The sidebar is designed to display sibling functions, modules and // other miscellaneous information. since there are lots of sibling // items (and that causes quadratic growth in large modules), // we refactor common parts into a shared JavaScript file per module. @@ -2975,7 +3004,7 @@ impl<'a> fmt::Display for Sidebar<'a> { } write!(fmt, "

")?; - // sidebar refers to the enclosing module, not this module + // Sidebar refers to the enclosing module, not this module. let relpath = if it.is_mod() { "../" } else { "" }; write!(fmt, "", diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 474d2bbe7fcb..5ffab949d019 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -1013,6 +1013,22 @@ .html(' Expand description')); var wrapper = $("
").append(mainToggle); $("#main > .docblock").before(wrapper); + + $(".docblock.autohide").each(function() { + var wrap = $(this).prev(); + if (wrap.is(".toggle-wrapper")) { + var toggle = wrap.children().first(); + if ($(this).children().first().is("h3")) { + toggle.children(".toggle-label") + .text(" Show " + $(this).children().first().text()); + } + $(this).hide(); + wrap.addClass("collapsed"); + toggle.children(".inner").text(labelForToggleButton(true)); + toggle.children(".toggle-label").show(); + } + }); + var mainToggle = $(toggle).append( $('', {'class': 'toggle-label'}) diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 46b34b5a638b..7ee184c089ca 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -339,6 +339,10 @@ h4 > code, h3 > code, .invisible > code { border-bottom: 1px solid; } +.fields + table { + margin-bottom: 1em; +} + .content .item-list { list-style-type: none; padding: 0; @@ -361,9 +365,17 @@ h4 > code, h3 > code, .invisible > code { position: relative; } /* Shift "where ..." part of method or fn definition down a line */ -.content .method .where, .content .fn .where { display: block; } +.content .method .where, +.content .fn .where, +.content .where.fmt-newline { + display: block; +} /* Bit of whitespace to indent it */ -.content .method .where::before, .content .fn .where::before { content: ' '; } +.content .method .where::before, +.content .fn .where::before, +.content .where.fmt-newline::before { + content: ' '; +} .content .methods > div { margin-left: 40px; } @@ -663,6 +675,10 @@ span.since { margin-top: 5px; } +.sub-variant, .sub-variant > h3 { + margin-top: 0 !important; +} + .enum > .toggle-wrapper + .docblock, .struct > .toggle-wrapper + .docblock { margin-left: 30px; margin-bottom: 20px; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index ee395e0616b8..3af7c20c1336 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -162,6 +162,10 @@ pub fn opts() -> Vec { unstable(optmulti("Z", "", "internal and debugging options (only on nightly build)", "FLAG")), stable(optopt("", "sysroot", "Override the system root", "PATH")), + stable(optopt("", "playground-url", + "URL to send code snippets to, may be reset by --markdown-playground-url \ + or `#![doc(html_playground_url=...)]`", + "URL")), ] } @@ -230,6 +234,10 @@ pub fn main_args(args: &[String]) -> isize { } }; + if let Some(playground) = matches.opt_str("playground-url") { + html::markdown::PLAYGROUND.with(|s| { *s.borrow_mut() = Some((None, playground)); }); + } + let test_args = matches.opt_strs("test-args"); let test_args: Vec = test_args.iter() .flat_map(|s| s.split_whitespace()) diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index d0407162793e..939fd6ccfc88 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -44,7 +44,9 @@ pub struct RustdocVisitor<'a, 'tcx: 'a> { pub attrs: hir::HirVec, pub cx: &'a core::DocContext<'a, 'tcx>, view_item_stack: FxHashSet, - inlining_from_glob: bool, + inlining: bool, + /// Is the current module and all of its parents public? + inside_public_path: bool, } impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { @@ -57,7 +59,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { attrs: hir::HirVec::new(), cx: cx, view_item_stack: stack, - inlining_from_glob: false, + inlining: false, + inside_public_path: true, } } @@ -189,10 +192,14 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { om.stab = self.stability(id); om.depr = self.deprecation(id); om.id = id; + // Keep track of if there were any private modules in the path. + let orig_inside_public_path = self.inside_public_path; + self.inside_public_path &= vis == hir::Public; for i in &m.item_ids { let item = self.cx.map.expect_item(i.id); self.visit_item(item, None, &mut om); } + self.inside_public_path = orig_inside_public_path; if let Some(exports) = self.cx.export_map.get(&id) { for export in exports { if let Def::Macro(def_id) = export.def { @@ -336,8 +343,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let ret = match tcx.map.get(def_node_id) { hir_map::NodeItem(it) => { + let prev = mem::replace(&mut self.inlining, true); if glob { - let prev = mem::replace(&mut self.inlining_from_glob, true); match it.node { hir::ItemMod(ref m) => { for i in &m.item_ids { @@ -348,10 +355,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { hir::ItemEnum(..) => {} _ => { panic!("glob not mapped to a module or enum"); } } - self.inlining_from_glob = prev; } else { self.visit_item(it, renamed, om); } + self.inlining = prev; true } _ => false, @@ -365,6 +372,19 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { debug!("Visiting item {:?}", item); let name = renamed.unwrap_or(item.name); match item.node { + hir::ItemForeignMod(ref fm) => { + // If inlining we only want to include public functions. + om.foreigns.push(if self.inlining { + hir::ForeignMod { + abi: fm.abi, + items: fm.items.iter().filter(|i| i.vis == hir::Public).cloned().collect(), + } + } else { + fm.clone() + }); + } + // If we're inlining, skip private items. + _ if self.inlining && item.vis != hir::Public => {} hir::ItemExternCrate(ref p) => { let cstore = &self.cx.sess().cstore; om.extern_crates.push(ExternCrate { @@ -379,7 +399,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } hir::ItemUse(ref vpath) => { let node = vpath.node.clone(); - let node = if item.vis == hir::Public { + // If there was a private module in the current path then don't bother inlining + // anything as it will probably be stripped anyway. + let node = if item.vis == hir::Public && self.inside_public_path { let please_inline = item.attrs.iter().any(|item| { match item.meta_item_list() { Some(list) if item.check_name("doc") => { @@ -479,43 +501,44 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { }; om.traits.push(t); }, - hir::ItemImpl(unsafety, polarity, ref gen, ref tr, ref ty, ref items) => { - let i = Impl { - unsafety: unsafety, - polarity: polarity, - generics: gen.clone(), - trait_: tr.clone(), - for_: ty.clone(), - items: items.clone(), - attrs: item.attrs.clone(), - id: item.id, - whence: item.span, - vis: item.vis.clone(), - stab: self.stability(item.id), - depr: self.deprecation(item.id), - }; - // Don't duplicate impls when inlining glob imports, we'll pick - // them up regardless of where they're located. - if !self.inlining_from_glob { + + hir::ItemImpl(unsafety, polarity, ref gen, ref tr, ref ty, ref item_ids) => { + // Don't duplicate impls when inlining, we'll pick them up + // regardless of where they're located. + if !self.inlining { + let items = item_ids.iter() + .map(|ii| self.cx.map.impl_item(ii.id).clone()) + .collect(); + let i = Impl { + unsafety: unsafety, + polarity: polarity, + generics: gen.clone(), + trait_: tr.clone(), + for_: ty.clone(), + items: items, + attrs: item.attrs.clone(), + id: item.id, + whence: item.span, + vis: item.vis.clone(), + stab: self.stability(item.id), + depr: self.deprecation(item.id), + }; om.impls.push(i); } }, hir::ItemDefaultImpl(unsafety, ref trait_ref) => { - let i = DefaultImpl { - unsafety: unsafety, - trait_: trait_ref.clone(), - id: item.id, - attrs: item.attrs.clone(), - whence: item.span, - }; - // see comment above about ItemImpl - if !self.inlining_from_glob { + // See comment above about ItemImpl. + if !self.inlining { + let i = DefaultImpl { + unsafety: unsafety, + trait_: trait_ref.clone(), + id: item.id, + attrs: item.attrs.clone(), + whence: item.span, + }; om.def_traits.push(i); } } - hir::ItemForeignMod(ref fm) => { - om.foreigns.push(fm.clone()); - } } } diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 44dd4e9874ac..cd7a50d07e26 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -187,7 +187,10 @@ impl BufRead for BufReader { fn fill_buf(&mut self) -> io::Result<&[u8]> { // If we've reached the end of our internal buffer then we need to fetch // some more data from the underlying reader. - if self.pos == self.cap { + // Branch using `>=` instead of the more correct `==` + // to tell the compiler that the pos..cap slice is always valid. + if self.pos >= self.cap { + debug_assert!(self.pos == self.cap); self.cap = self.inner.read(&mut self.buf)?; self.pos = 0; } diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 49080680fac6..7b7be6e2eeeb 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -154,6 +154,14 @@ impl Ipv4Addr { /// Creates a new IPv4 address from four eight-bit octets. /// /// The result will represent the IP address `a`.`b`.`c`.`d`. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::new(127, 0, 0, 1); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { Ipv4Addr { @@ -167,6 +175,15 @@ impl Ipv4Addr { } /// Returns the four eight-bit integers that make up this address. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::new(127, 0, 0, 1); + /// assert_eq!(addr.octets(), [127, 0, 0, 1]); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn octets(&self) -> [u8; 4] { let bits = ntoh(self.inner.s_addr); @@ -176,8 +193,18 @@ impl Ipv4Addr { /// Returns true for the special 'unspecified' address (0.0.0.0). /// /// This property is defined in _UNIX Network Programming, Second Edition_, - /// W. Richard Stevens, p. 891; see also [ip7] - /// [ip7][http://man7.org/linux/man-pages/man7/ip.7.html] + /// W. Richard Stevens, p. 891; see also [ip7]. + /// + /// [ip7]: http://man7.org/linux/man-pages/man7/ip.7.html + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_unspecified(), true); + /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_unspecified(), false); + /// ``` #[stable(feature = "ip_shared", since = "1.12.0")] pub fn is_unspecified(&self) -> bool { self.inner.s_addr == 0 @@ -186,7 +213,17 @@ impl Ipv4Addr { /// Returns true if this is a loopback address (127.0.0.0/8). /// /// This property is defined by [RFC 1122]. + /// /// [RFC 1122]: https://tools.ietf.org/html/rfc1122 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_loopback(), true); + /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_loopback(), false); + /// ``` #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_loopback(&self) -> bool { self.octets()[0] == 127 @@ -195,11 +232,26 @@ impl Ipv4Addr { /// Returns true if this is a private address. /// /// The private address ranges are defined in [RFC 1918] and include: - /// [RFC 1918]: https://tools.ietf.org/html/rfc1918 /// /// - 10.0.0.0/8 /// - 172.16.0.0/12 /// - 192.168.0.0/16 + /// + /// [RFC 1918]: https://tools.ietf.org/html/rfc1918 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(10, 0, 0, 1).is_private(), true); + /// assert_eq!(Ipv4Addr::new(10, 10, 10, 10).is_private(), true); + /// assert_eq!(Ipv4Addr::new(172, 16, 10, 10).is_private(), true); + /// assert_eq!(Ipv4Addr::new(172, 29, 45, 14).is_private(), true); + /// assert_eq!(Ipv4Addr::new(172, 32, 0, 2).is_private(), false); + /// assert_eq!(Ipv4Addr::new(192, 168, 0, 2).is_private(), true); + /// assert_eq!(Ipv4Addr::new(192, 169, 0, 2).is_private(), false); + /// ``` #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_private(&self) -> bool { match (self.octets()[0], self.octets()[1]) { @@ -213,7 +265,18 @@ impl Ipv4Addr { /// Returns true if the address is link-local (169.254.0.0/16). /// /// This property is defined by [RFC 3927]. + /// /// [RFC 3927]: https://tools.ietf.org/html/rfc3927 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(169, 254, 0, 0).is_link_local(), true); + /// assert_eq!(Ipv4Addr::new(169, 254, 10, 65).is_link_local(), true); + /// assert_eq!(Ipv4Addr::new(16, 89, 10, 65).is_link_local(), false); + /// ``` #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_link_local(&self) -> bool { self.octets()[0] == 169 && self.octets()[1] == 254 @@ -221,7 +284,6 @@ impl Ipv4Addr { /// Returns true if the address appears to be globally routable. /// See [iana-ipv4-special-registry][ipv4-sr]. - /// [ipv4-sr]: http://goo.gl/RaZ7lg /// /// The following return false: /// @@ -231,6 +293,24 @@ impl Ipv4Addr { /// - the broadcast address (255.255.255.255/32) /// - test addresses used for documentation (192.0.2.0/24, 198.51.100.0/24 and 203.0.113.0/24) /// - the unspecified address (0.0.0.0) + /// + /// [ipv4-sr]: http://goo.gl/RaZ7lg + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv4Addr; + /// + /// fn main() { + /// assert_eq!(Ipv4Addr::new(10, 254, 0, 0).is_global(), false); + /// assert_eq!(Ipv4Addr::new(192, 168, 10, 65).is_global(), false); + /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_global(), false); + /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_global(), false); + /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true); + /// } + /// ``` pub fn is_global(&self) -> bool { !self.is_private() && !self.is_loopback() && !self.is_link_local() && !self.is_broadcast() && !self.is_documentation() && !self.is_unspecified() @@ -240,7 +320,18 @@ impl Ipv4Addr { /// /// Multicast addresses have a most significant octet between 224 and 239, /// and is defined by [RFC 5771]. + /// /// [RFC 5771]: https://tools.ietf.org/html/rfc5771 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(224, 254, 0, 0).is_multicast(), true); + /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_multicast(), true); + /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_multicast(), false); + /// ``` #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_multicast(&self) -> bool { self.octets()[0] >= 224 && self.octets()[0] <= 239 @@ -249,7 +340,17 @@ impl Ipv4Addr { /// Returns true if this is a broadcast address (255.255.255.255). /// /// A broadcast address has all octets set to 255 as defined in [RFC 919]. + /// /// [RFC 919]: https://tools.ietf.org/html/rfc919 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_broadcast(), true); + /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_broadcast(), false); + /// ``` #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_broadcast(&self) -> bool { self.octets()[0] == 255 && self.octets()[1] == 255 && @@ -259,11 +360,23 @@ impl Ipv4Addr { /// Returns true if this address is in a range designated for documentation. /// /// This is defined in [RFC 5737]: - /// [RFC 5737]: https://tools.ietf.org/html/rfc5737 /// /// - 192.0.2.0/24 (TEST-NET-1) /// - 198.51.100.0/24 (TEST-NET-2) /// - 203.0.113.0/24 (TEST-NET-3) + /// + /// [RFC 5737]: https://tools.ietf.org/html/rfc5737 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_documentation(), true); + /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_documentation(), true); + /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_documentation(), true); + /// assert_eq!(Ipv4Addr::new(193, 34, 17, 19).is_documentation(), false); + /// ``` #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_documentation(&self) -> bool { match(self.octets()[0], self.octets()[1], self.octets()[2], self.octets()[3]) { @@ -277,6 +390,15 @@ impl Ipv4Addr { /// Converts this address to an IPv4-compatible IPv6 address. /// /// a.b.c.d becomes ::a.b.c.d + /// + /// # Examples + /// + /// ``` + /// use std::net::{Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_compatible(), + /// Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 767)); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn to_ipv6_compatible(&self) -> Ipv6Addr { Ipv6Addr::new(0, 0, 0, 0, 0, 0, @@ -287,6 +409,15 @@ impl Ipv4Addr { /// Converts this address to an IPv4-mapped IPv6 address. /// /// a.b.c.d becomes ::ffff:a.b.c.d + /// + /// # Examples + /// + /// ``` + /// use std::net::{Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped(), + /// Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 49152, 767)); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn to_ipv6_mapped(&self) -> Ipv6Addr { Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, @@ -425,6 +556,7 @@ impl Ipv6Addr { /// Returns true for the special 'unspecified' address (::). /// /// This property is defined in [RFC 4291]. + /// /// [RFC 4291]: https://tools.ietf.org/html/rfc4291 #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_unspecified(&self) -> bool { @@ -434,6 +566,7 @@ impl Ipv6Addr { /// Returns true if this is a loopback address (::1). /// /// This property is defined in [RFC 4291]. + /// /// [RFC 4291]: https://tools.ietf.org/html/rfc4291 #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_loopback(&self) -> bool { @@ -458,6 +591,7 @@ impl Ipv6Addr { /// Returns true if this is a unique local address (fc00::/7). /// /// This property is defined in [RFC 4193]. + /// /// [RFC 4193]: https://tools.ietf.org/html/rfc4193 pub fn is_unique_local(&self) -> bool { (self.segments()[0] & 0xfe00) == 0xfc00 @@ -466,6 +600,7 @@ impl Ipv6Addr { /// Returns true if the address is unicast and link-local (fe80::/10). /// /// This property is defined in [RFC 4291]. + /// /// [RFC 4291]: https://tools.ietf.org/html/rfc4291 pub fn is_unicast_link_local(&self) -> bool { (self.segments()[0] & 0xffc0) == 0xfe80 @@ -481,6 +616,7 @@ impl Ipv6Addr { /// (2001:db8::/32). /// /// This property is defined in [RFC 3849]. + /// /// [RFC 3849]: https://tools.ietf.org/html/rfc3849 pub fn is_documentation(&self) -> bool { (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) @@ -524,6 +660,7 @@ impl Ipv6Addr { /// Returns true if this is a multicast address (ff00::/8). /// /// This property is defined by [RFC 4291]. + /// /// [RFC 4291]: https://tools.ietf.org/html/rfc4291 #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_multicast(&self) -> bool { diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 0e7c5b06713f..159aa997b272 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -67,11 +67,12 @@ pub struct TcpListener(net_imp::TcpListener); /// An infinite iterator over the connections from a `TcpListener`. /// -/// This iterator will infinitely yield `Some` of the accepted connections. It +/// This iterator will infinitely yield [`Some`] of the accepted connections. It /// is equivalent to calling `accept` in a loop. /// /// This `struct` is created by the [`incoming`] method on [`TcpListener`]. /// +/// [`Some`]: ../../std/option/enum.Option.html#variant.Some /// [`incoming`]: struct.TcpListener.html#method.incoming /// [`TcpListener`]: struct.TcpListener.html #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 3e414a28a301..8bf9bbb13208 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -25,11 +25,18 @@ //! //! ```rust //! use std::path::Path; +//! use std::ffi::OsStr; //! //! let path = Path::new("/tmp/foo/bar.txt"); -//! let file = path.file_name(); +//! +//! let parent = path.parent(); +//! assert_eq!(parent, Some(Path::new("/tmp/foo"))); +//! +//! let file_stem = path.file_stem(); +//! assert_eq!(file_stem, Some(OsStr::new("bar"))); +//! //! let extension = path.extension(); -//! let parent_dir = path.parent(); +//! assert_eq!(extension, Some(OsStr::new("txt"))); //! ``` //! //! To build or modify paths, use `PathBuf`: @@ -990,17 +997,24 @@ impl PathBuf { /// /// # Examples /// + /// Pushing a relative path extends the existing path: + /// /// ``` /// use std::path::PathBuf; /// - /// let mut path = PathBuf::new(); - /// path.push("/tmp"); + /// let mut path = PathBuf::from("/tmp"); /// path.push("file.bk"); /// assert_eq!(path, PathBuf::from("/tmp/file.bk")); + /// ``` /// - /// // Pushing an absolute path replaces the current path - /// path.push("/etc/passwd"); - /// assert_eq!(path, PathBuf::from("/etc/passwd")); + /// Pushing an absolute path replaces the existing path: + /// + /// ``` + /// use std::path::PathBuf; + /// + /// let mut path = PathBuf::from("/tmp"); + /// path.push("/etc"); + /// assert_eq!(path, PathBuf::from("/etc")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn push>(&mut self, path: P) { @@ -1319,13 +1333,19 @@ impl AsRef for PathBuf { /// /// ``` /// use std::path::Path; +/// use std::ffi::OsStr; /// /// let path = Path::new("/tmp/foo/bar.txt"); -/// let file = path.file_name(); -/// let extension = path.extension(); -/// let parent_dir = path.parent(); -/// ``` /// +/// let parent = path.parent(); +/// assert_eq!(parent, Some(Path::new("/tmp/foo"))); +/// +/// let file_stem = path.file_stem(); +/// assert_eq!(file_stem, Some(OsStr::new("bar"))); +/// +/// let extension = path.extension(); +/// assert_eq!(extension, Some(OsStr::new("txt"))); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Path { inner: OsStr, diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index fce640e7c7a2..2773629c7d7d 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -1267,6 +1267,38 @@ impl error::Error for TryRecvError { } } +#[stable(feature = "mpsc_recv_timeout_error", since = "1.14.0")] +impl fmt::Display for RecvTimeoutError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + RecvTimeoutError::Timeout => { + "timed out waiting on channel".fmt(f) + } + RecvTimeoutError::Disconnected => { + "channel is empty and sending half is closed".fmt(f) + } + } + } +} + +#[stable(feature = "mpsc_recv_timeout_error", since = "1.14.0")] +impl error::Error for RecvTimeoutError { + fn description(&self) -> &str { + match *self { + RecvTimeoutError::Timeout => { + "timed out waiting on channel" + } + RecvTimeoutError::Disconnected => { + "channel is empty and sending half is closed" + } + } + } + + fn cause(&self) -> Option<&error::Error> { + None + } +} + #[cfg(all(test, not(target_os = "emscripten")))] mod tests { use env; diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index 10a0c567e142..41d675b6f88f 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -39,7 +39,7 @@ const MILLIS_PER_SEC: u64 = 1_000; /// let ten_millis = Duration::from_millis(10); /// ``` #[stable(feature = "duration", since = "1.3.0")] -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)] pub struct Duration { secs: u64, nanos: u32, // Always 0 <= nanos < NANOS_PER_SEC diff --git a/src/libsyntax/Cargo.toml b/src/libsyntax/Cargo.toml index 8b61e1b0d3a3..0b38f5450b63 100644 --- a/src/libsyntax/Cargo.toml +++ b/src/libsyntax/Cargo.toml @@ -14,3 +14,4 @@ log = { path = "../liblog" } rustc_bitflags = { path = "../librustc_bitflags" } syntax_pos = { path = "../libsyntax_pos" } rustc_errors = { path = "../librustc_errors" } +rustc_data_structures = { path = "../librustc_data_structures" } diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 57a936bf9b0c..2977e340a3c0 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -789,9 +789,6 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, // Merge the deprecation info into the stability info if let Some(rustc_depr) = rustc_depr { if let Some(ref mut stab) = stab { - if let Unstable {reason: ref mut reason @ None, ..} = stab.level { - *reason = Some(rustc_depr.reason.clone()) - } stab.rustc_depr = Some(rustc_depr); } else { span_err!(diagnostic, item_sp, E0549, diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 946257a16d5a..02429f02738f 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -277,7 +277,7 @@ impl<'a> fold::Folder for StripUnconfigured<'a> { fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector { match self.configure_stmt(stmt) { Some(stmt) => fold::noop_fold_stmt(stmt, self), - None => return SmallVector::zero(), + None => return SmallVector::new(), } } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 63eee7df9e85..7f66b060052e 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -440,7 +440,7 @@ impl MacResult for DummyResult { if self.expr_only { None } else { - Some(SmallVector::zero()) + Some(SmallVector::new()) } } @@ -448,7 +448,7 @@ impl MacResult for DummyResult { if self.expr_only { None } else { - Some(SmallVector::zero()) + Some(SmallVector::new()) } } @@ -456,7 +456,7 @@ impl MacResult for DummyResult { if self.expr_only { None } else { - Some(SmallVector::zero()) + Some(SmallVector::new()) } } @@ -524,6 +524,7 @@ pub trait Resolver { fn add_ext(&mut self, ident: ast::Ident, ext: Rc); fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec); + fn resolve_imports(&mut self); fn find_attr_invoc(&mut self, attrs: &mut Vec) -> Option; fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, force: bool) -> Result, Determinacy>; @@ -547,6 +548,7 @@ impl Resolver for DummyResolver { fn add_ext(&mut self, _ident: ast::Ident, _ext: Rc) {} fn add_expansions_at_stmt(&mut self, _id: ast::NodeId, _macros: Vec) {} + fn resolve_imports(&mut self) {} fn find_attr_invoc(&mut self, _attrs: &mut Vec) -> Option { None } fn resolve_macro(&mut self, _scope: Mark, _path: &ast::Path, _force: bool) -> Result, Determinacy> { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index e3b23e239f91..8e0c3ce8448d 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -89,7 +89,7 @@ macro_rules! expansions { Expansion::OptExpr(Some(ref expr)) => visitor.visit_expr(expr), Expansion::OptExpr(None) => {} $($( Expansion::$kind(ref ast) => visitor.$visit(ast), )*)* - $($( Expansion::$kind(ref ast) => for ast in ast.as_slice() { + $($( Expansion::$kind(ref ast) => for ast in &ast[..] { visitor.$visit_elt(ast); }, )*)* } @@ -222,6 +222,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.cx.current_expansion.depth = 0; let (expansion, mut invocations) = self.collect_invocations(expansion); + self.resolve_imports(); invocations.reverse(); let mut expansions = Vec::new(); @@ -230,9 +231,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> { loop { let invoc = if let Some(invoc) = invocations.pop() { invoc - } else if undetermined_invocations.is_empty() { - break } else { + self.resolve_imports(); + if undetermined_invocations.is_empty() { break } invocations = mem::replace(&mut undetermined_invocations, Vec::new()); force = !mem::replace(&mut progress, false); continue @@ -292,6 +293,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> { expansion.fold_with(&mut placeholder_expander) } + fn resolve_imports(&mut self) { + if self.monotonic { + let err_count = self.cx.parse_sess.span_diagnostic.err_count(); + self.cx.resolver.resolve_imports(); + self.cx.resolve_err_count += self.cx.parse_sess.span_diagnostic.err_count() - err_count; + } + } + fn collect_invocations(&mut self, expansion: Expansion) -> (Expansion, Vec) { let result = { let mut collector = InvocationCollector { @@ -511,29 +520,31 @@ impl<'a> Parser<'a> { -> PResult<'a, Expansion> { Ok(match kind { ExpansionKind::Items => { - let mut items = SmallVector::zero(); + let mut items = SmallVector::new(); while let Some(item) = self.parse_item()? { items.push(item); } Expansion::Items(items) } ExpansionKind::TraitItems => { - let mut items = SmallVector::zero(); + let mut items = SmallVector::new(); while self.token != token::Eof { items.push(self.parse_trait_item()?); } Expansion::TraitItems(items) } ExpansionKind::ImplItems => { - let mut items = SmallVector::zero(); + let mut items = SmallVector::new(); while self.token != token::Eof { items.push(self.parse_impl_item()?); } Expansion::ImplItems(items) } ExpansionKind::Stmts => { - let mut stmts = SmallVector::zero(); - while self.token != token::Eof { + let mut stmts = SmallVector::new(); + while self.token != token::Eof && + // won't make progress on a `}` + self.token != token::CloseDelim(token::Brace) { if let Some(stmt) = self.parse_full_stmt(macro_legacy_warnings)? { stmts.push(stmt); } @@ -571,7 +582,7 @@ macro_rules! fully_configure { ($this:ident, $node:ident, $noop_fold:ident) => { match $noop_fold($node, &mut $this.cfg).pop() { Some(node) => node, - None => return SmallVector::zero(), + None => return SmallVector::new(), } } } @@ -687,7 +698,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector { let stmt = match self.cfg.configure_stmt(stmt) { Some(stmt) => stmt, - None => return SmallVector::zero(), + None => return SmallVector::new(), }; let (mac, style, attrs) = if let StmtKind::Mac(mac) = stmt.node { diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index ec48cae3f765..bda84cdaf39e 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -104,7 +104,7 @@ pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[tokenstream::T } fn make_items(mut self: Box>) -> Option>> { - let mut ret = SmallVector::zero(); + let mut ret = SmallVector::new(); while self.p.token != token::Eof { match panictry!(self.p.parse_item()) { Some(item) => ret.push(item), diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 1066646aa8e8..39ffab4dc17a 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -130,7 +130,7 @@ struct MatcherTtFrame { } #[derive(Clone)] -pub struct MatcherPos { +struct MatcherPos { stack: Vec, top_elts: TokenTreeOrTokenTreeVec, sep: Option, @@ -143,6 +143,8 @@ pub struct MatcherPos { sp_lo: BytePos, } +pub type NamedParseResult = ParseResult>>; + pub fn count_names(ms: &[TokenTree]) -> usize { ms.iter().fold(0, |count, elt| { count + match *elt { @@ -160,14 +162,13 @@ pub fn count_names(ms: &[TokenTree]) -> usize { }) } -pub fn initial_matcher_pos(ms: Vec, sep: Option, lo: BytePos) - -> Box { +fn initial_matcher_pos(ms: Vec, lo: BytePos) -> Box { let match_idx_hi = count_names(&ms[..]); - let matches: Vec<_> = (0..match_idx_hi).map(|_| Vec::new()).collect(); + let matches = create_matches(match_idx_hi); Box::new(MatcherPos { stack: vec![], top_elts: TtSeq(ms), - sep: sep, + sep: None, idx: 0, up: None, matches: matches, @@ -200,27 +201,25 @@ pub enum NamedMatch { MatchedNonterminal(Rc) } -pub fn nameize(p_s: &ParseSess, ms: &[TokenTree], res: &[Rc]) - -> ParseResult>> { - fn n_rec(p_s: &ParseSess, m: &TokenTree, res: &[Rc], - ret_val: &mut HashMap>, idx: &mut usize) +fn nameize>>(ms: &[TokenTree], mut res: I) -> NamedParseResult { + fn n_rec>>(m: &TokenTree, mut res: &mut I, + ret_val: &mut HashMap>) -> Result<(), (syntax_pos::Span, String)> { match *m { TokenTree::Sequence(_, ref seq) => { for next_m in &seq.tts { - n_rec(p_s, next_m, res, ret_val, idx)? + n_rec(next_m, res.by_ref(), ret_val)? } } TokenTree::Delimited(_, ref delim) => { for next_m in &delim.tts { - n_rec(p_s, next_m, res, ret_val, idx)?; + n_rec(next_m, res.by_ref(), ret_val)?; } } TokenTree::Token(sp, MatchNt(bind_name, _)) => { match ret_val.entry(bind_name) { Vacant(spot) => { - spot.insert(res[*idx].clone()); - *idx += 1; + spot.insert(res.next().unwrap()); } Occupied(..) => { return Err((sp, format!("duplicated bind name: {}", bind_name))) @@ -237,9 +236,8 @@ pub fn nameize(p_s: &ParseSess, ms: &[TokenTree], res: &[Rc]) } let mut ret_val = HashMap::new(); - let mut idx = 0; for m in ms { - match n_rec(p_s, m, res, &mut ret_val, &mut idx) { + match n_rec(m, res.by_ref(), &mut ret_val) { Ok(_) => {}, Err((sp, msg)) => return Error(sp, msg), } @@ -265,11 +263,8 @@ pub fn parse_failure_msg(tok: Token) -> String { } } -pub type NamedParseResult = ParseResult>>; - -/// Perform a token equality check, ignoring syntax context (that is, an -/// unhygienic comparison) -pub fn token_name_eq(t1 : &Token, t2 : &Token) -> bool { +/// Perform a token equality check, ignoring syntax context (that is, an unhygienic comparison) +fn token_name_eq(t1 : &Token, t2 : &Token) -> bool { match (t1,t2) { (&token::Ident(id1),&token::Ident(id2)) | (&token::Lifetime(id1),&token::Lifetime(id2)) => @@ -278,234 +273,228 @@ pub fn token_name_eq(t1 : &Token, t2 : &Token) -> bool { } } -pub fn parse(sess: &ParseSess, rdr: TtReader, ms: &[TokenTree]) -> NamedParseResult { - let mut parser = Parser::new_with_doc_flag(sess, Box::new(rdr), true); - let mut cur_eis = SmallVector::one(initial_matcher_pos(ms.to_owned(), None, parser.span.lo)); +fn create_matches(len: usize) -> Vec>> { + (0..len).into_iter().map(|_| Vec::new()).collect() +} - loop { - let mut bb_eis = Vec::new(); // black-box parsed by parser.rs - let mut next_eis = Vec::new(); // or proceed normally - let mut eof_eis = Vec::new(); - - let (sp, tok) = (parser.span, parser.token.clone()); - - /* we append new items to this while we go */ - loop { - let mut ei = match cur_eis.pop() { - None => break, /* for each Earley Item */ - Some(ei) => ei, - }; - - // When unzipped trees end, remove them - while ei.idx >= ei.top_elts.len() { - match ei.stack.pop() { - Some(MatcherTtFrame { elts, idx }) => { - ei.top_elts = elts; - ei.idx = idx + 1; - } - None => break +fn inner_parse_loop(cur_eis: &mut SmallVector>, + next_eis: &mut Vec>, + eof_eis: &mut SmallVector>, + bb_eis: &mut SmallVector>, + token: &Token, span: &syntax_pos::Span) -> ParseResult<()> { + while let Some(mut ei) = cur_eis.pop() { + // When unzipped trees end, remove them + while ei.idx >= ei.top_elts.len() { + match ei.stack.pop() { + Some(MatcherTtFrame { elts, idx }) => { + ei.top_elts = elts; + ei.idx = idx + 1; } + None => break } + } - let idx = ei.idx; - let len = ei.top_elts.len(); + let idx = ei.idx; + let len = ei.top_elts.len(); - /* at end of sequence */ - if idx >= len { - // can't move out of `match`es, so: - if ei.up.is_some() { - // hack: a matcher sequence is repeating iff it has a - // parent (the top level is just a container) + // at end of sequence + if idx >= len { + // We are repeating iff there is a parent + if ei.up.is_some() { + // Disregarding the separator, add the "up" case to the tokens that should be + // examined. + // (remove this condition to make trailing seps ok) + if idx == len { + let mut new_pos = ei.up.clone().unwrap(); + // update matches (the MBE "parse tree") by appending + // each tree as a subtree. - // disregard separator, try to go up - // (remove this condition to make trailing seps ok) - if idx == len { - // pop from the matcher position + // I bet this is a perf problem: we're preemptively + // doing a lot of array work that will get thrown away + // most of the time. - let mut new_pos = ei.up.clone().unwrap(); - - // update matches (the MBE "parse tree") by appending - // each tree as a subtree. - - // I bet this is a perf problem: we're preemptively - // doing a lot of array work that will get thrown away - // most of the time. - - // Only touch the binders we have actually bound - for idx in ei.match_lo..ei.match_hi { - let sub = (ei.matches[idx]).clone(); - (&mut new_pos.matches[idx]) - .push(Rc::new(MatchedSeq(sub, mk_sp(ei.sp_lo, - sp.hi)))); - } - - new_pos.match_cur = ei.match_hi; - new_pos.idx += 1; - cur_eis.push(new_pos); + // Only touch the binders we have actually bound + for idx in ei.match_lo..ei.match_hi { + let sub = ei.matches[idx].clone(); + new_pos.matches[idx] + .push(Rc::new(MatchedSeq(sub, mk_sp(ei.sp_lo, + span.hi)))); } - // can we go around again? + new_pos.match_cur = ei.match_hi; + new_pos.idx += 1; + cur_eis.push(new_pos); + } - // the *_t vars are workarounds for the lack of unary move - match ei.sep { - Some(ref t) if idx == len => { // we need a separator - // i'm conflicted about whether this should be hygienic.... - // though in this case, if the separators are never legal - // idents, it shouldn't matter. - if token_name_eq(&tok, t) { //pass the separator - let mut ei_t = ei.clone(); - // ei_t.match_cur = ei_t.match_lo; - ei_t.idx += 1; - next_eis.push(ei_t); - } - } - _ => { // we don't need a separator - let mut ei_t = ei; - ei_t.match_cur = ei_t.match_lo; - ei_t.idx = 0; - cur_eis.push(ei_t); - } + // Check if we need a separator + if idx == len && ei.sep.is_some() { + // We have a separator, and it is the current token. + if ei.sep.as_ref().map(|ref sep| token_name_eq(&token, sep)).unwrap_or(false) { + ei.idx += 1; + next_eis.push(ei); } - } else { - eof_eis.push(ei); + } else { // we don't need a separator + ei.match_cur = ei.match_lo; + ei.idx = 0; + cur_eis.push(ei); } } else { - match ei.top_elts.get_tt(idx) { - /* need to descend into sequence */ - TokenTree::Sequence(sp, seq) => { - if seq.op == tokenstream::KleeneOp::ZeroOrMore { - let mut new_ei = ei.clone(); - new_ei.match_cur += seq.num_captures; - new_ei.idx += 1; - //we specifically matched zero repeats. - for idx in ei.match_cur..ei.match_cur + seq.num_captures { - (&mut new_ei.matches[idx]).push(Rc::new(MatchedSeq(vec![], sp))); - } + // We aren't repeating, so we must be potentially at the end of the input. + eof_eis.push(ei); + } + } else { + match ei.top_elts.get_tt(idx) { + /* need to descend into sequence */ + TokenTree::Sequence(sp, seq) => { + if seq.op == tokenstream::KleeneOp::ZeroOrMore { + // Examine the case where there are 0 matches of this sequence + let mut new_ei = ei.clone(); + new_ei.match_cur += seq.num_captures; + new_ei.idx += 1; + for idx in ei.match_cur..ei.match_cur + seq.num_captures { + new_ei.matches[idx].push(Rc::new(MatchedSeq(vec![], sp))); + } + cur_eis.push(new_ei); + } - cur_eis.push(new_ei); - } - - let matches: Vec<_> = (0..ei.matches.len()) - .map(|_| Vec::new()).collect(); - let ei_t = ei; - cur_eis.push(Box::new(MatcherPos { - stack: vec![], - sep: seq.separator.clone(), - idx: 0, - matches: matches, - match_lo: ei_t.match_cur, - match_cur: ei_t.match_cur, - match_hi: ei_t.match_cur + seq.num_captures, - up: Some(ei_t), - sp_lo: sp.lo, - top_elts: Tt(TokenTree::Sequence(sp, seq)), - })); + // Examine the case where there is at least one match of this sequence + let matches = create_matches(ei.matches.len()); + cur_eis.push(Box::new(MatcherPos { + stack: vec![], + sep: seq.separator.clone(), + idx: 0, + matches: matches, + match_lo: ei.match_cur, + match_cur: ei.match_cur, + match_hi: ei.match_cur + seq.num_captures, + up: Some(ei), + sp_lo: sp.lo, + top_elts: Tt(TokenTree::Sequence(sp, seq)), + })); + } + TokenTree::Token(_, MatchNt(..)) => { + // Built-in nonterminals never start with these tokens, + // so we can eliminate them from consideration. + match *token { + token::CloseDelim(_) => {}, + _ => bb_eis.push(ei), } - TokenTree::Token(_, MatchNt(..)) => { - // Built-in nonterminals never start with these tokens, - // so we can eliminate them from consideration. - match tok { - token::CloseDelim(_) => {}, - _ => bb_eis.push(ei), - } - } - TokenTree::Token(sp, SubstNt(..)) => { - return Error(sp, "missing fragment specifier".to_string()) - } - seq @ TokenTree::Delimited(..) | seq @ TokenTree::Token(_, DocComment(..)) => { - let lower_elts = mem::replace(&mut ei.top_elts, Tt(seq)); - let idx = ei.idx; - ei.stack.push(MatcherTtFrame { - elts: lower_elts, - idx: idx, - }); - ei.idx = 0; - cur_eis.push(ei); - } - TokenTree::Token(_, ref t) => { - if token_name_eq(t,&tok) { - let mut ei_t = ei.clone(); - ei_t.idx += 1; - next_eis.push(ei_t); - } + } + TokenTree::Token(sp, SubstNt(..)) => { + return Error(sp, "missing fragment specifier".to_string()) + } + seq @ TokenTree::Delimited(..) | seq @ TokenTree::Token(_, DocComment(..)) => { + let lower_elts = mem::replace(&mut ei.top_elts, Tt(seq)); + let idx = ei.idx; + ei.stack.push(MatcherTtFrame { + elts: lower_elts, + idx: idx, + }); + ei.idx = 0; + cur_eis.push(ei); + } + TokenTree::Token(_, ref t) => { + if token_name_eq(t, &token) { + ei.idx += 1; + next_eis.push(ei); } } } } + } + + Success(()) +} + +pub fn parse(sess: &ParseSess, rdr: TtReader, ms: &[TokenTree]) -> NamedParseResult { + let mut parser = Parser::new_with_doc_flag(sess, Box::new(rdr), true); + let mut cur_eis = SmallVector::one(initial_matcher_pos(ms.to_owned(), parser.span.lo)); + let mut next_eis = Vec::new(); // or proceed normally + + loop { + let mut bb_eis = SmallVector::new(); // black-box parsed by parser.rs + let mut eof_eis = SmallVector::new(); + assert!(next_eis.is_empty()); + + match inner_parse_loop(&mut cur_eis, &mut next_eis, &mut eof_eis, &mut bb_eis, + &parser.token, &parser.span) { + Success(_) => {}, + Failure(sp, tok) => return Failure(sp, tok), + Error(sp, msg) => return Error(sp, msg), + } + + // inner parse loop handled all cur_eis, so it's empty + assert!(cur_eis.is_empty()); /* error messages here could be improved with links to orig. rules */ - if token_name_eq(&tok, &token::Eof) { + if token_name_eq(&parser.token, &token::Eof) { if eof_eis.len() == 1 { - let mut v = Vec::new(); - for dv in &mut (&mut eof_eis[0]).matches { - v.push(dv.pop().unwrap()); - } - return nameize(sess, ms, &v[..]); + return nameize(ms, eof_eis[0].matches.iter_mut().map(|mut dv| dv.pop().unwrap())); } else if eof_eis.len() > 1 { - return Error(sp, "ambiguity: multiple successful parses".to_string()); + return Error(parser.span, "ambiguity: multiple successful parses".to_string()); } else { - return Failure(sp, token::Eof); + return Failure(parser.span, token::Eof); } - } else { - if (!bb_eis.is_empty() && !next_eis.is_empty()) - || bb_eis.len() > 1 { - let nts = bb_eis.iter().map(|ei| match ei.top_elts.get_tt(ei.idx) { - TokenTree::Token(_, MatchNt(bind, name)) => { - format!("{} ('{}')", name, bind) - } - _ => panic!() - }).collect::>().join(" or "); + } else if (!bb_eis.is_empty() && !next_eis.is_empty()) || bb_eis.len() > 1 { + let nts = bb_eis.iter().map(|ei| match ei.top_elts.get_tt(ei.idx) { + TokenTree::Token(_, MatchNt(bind, name)) => { + format!("{} ('{}')", name, bind) + } + _ => panic!() + }).collect::>().join(" or "); - return Error(sp, format!( - "local ambiguity: multiple parsing options: {}", - match next_eis.len() { - 0 => format!("built-in NTs {}.", nts), - 1 => format!("built-in NTs {} or 1 other option.", nts), - n => format!("built-in NTs {} or {} other options.", nts, n), - } - )) - } else if bb_eis.is_empty() && next_eis.is_empty() { - return Failure(sp, tok); - } else if !next_eis.is_empty() { - /* Now process the next token */ - while !next_eis.is_empty() { - cur_eis.push(next_eis.pop().unwrap()); + return Error(parser.span, format!( + "local ambiguity: multiple parsing options: {}", + match next_eis.len() { + 0 => format!("built-in NTs {}.", nts), + 1 => format!("built-in NTs {} or 1 other option.", nts), + n => format!("built-in NTs {} or {} other options.", nts, n), } - parser.bump(); - } else /* bb_eis.len() == 1 */ { - let mut ei = bb_eis.pop().unwrap(); - if let TokenTree::Token(span, MatchNt(_, ident)) = ei.top_elts.get_tt(ei.idx) { - let match_cur = ei.match_cur; - (&mut ei.matches[match_cur]).push(Rc::new(MatchedNonterminal( - Rc::new(parse_nt(&mut parser, span, &ident.name.as_str()))))); - ei.idx += 1; - ei.match_cur += 1; - } else { - unreachable!() - } - cur_eis.push(ei); + )); + } else if bb_eis.is_empty() && next_eis.is_empty() { + return Failure(parser.span, parser.token); + } else if !next_eis.is_empty() { + /* Now process the next token */ + cur_eis.extend(next_eis.drain(..)); + parser.bump(); + } else /* bb_eis.len() == 1 */ { + let mut ei = bb_eis.pop().unwrap(); + if let TokenTree::Token(span, MatchNt(_, ident)) = ei.top_elts.get_tt(ei.idx) { + let match_cur = ei.match_cur; + ei.matches[match_cur].push(Rc::new(MatchedNonterminal( + Rc::new(parse_nt(&mut parser, span, &ident.name.as_str()))))); + ei.idx += 1; + ei.match_cur += 1; + } else { + unreachable!() } + cur_eis.push(ei); } assert!(!cur_eis.is_empty()); } } -pub fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal { +fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal { match name { "tt" => { p.quote_depth += 1; //but in theory, non-quoted tts might be useful let mut tt = panictry!(p.parse_token_tree()); p.quote_depth -= 1; - loop { - let nt = match tt { - TokenTree::Token(_, token::Interpolated(ref nt)) => nt.clone(), - _ => break, - }; - match *nt { - token::NtTT(ref sub_tt) => tt = sub_tt.clone(), - _ => break, + while let TokenTree::Token(sp, token::Interpolated(nt)) = tt { + if let token::NtTT(..) = *nt { + match Rc::try_unwrap(nt) { + Ok(token::NtTT(sub_tt)) => tt = sub_tt, + Ok(_) => unreachable!(), + Err(nt_rc) => match *nt_rc { + token::NtTT(ref sub_tt) => tt = sub_tt.clone(), + _ => unreachable!(), + }, + } + } else { + tt = TokenTree::Token(sp, token::Interpolated(nt.clone())); + break } } return token::NtTT(tt); diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 9116b392f178..ea66fdc31cf0 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -311,6 +311,11 @@ declare_features! ( // Allows using `Self` and associated types in struct expressions and patterns. (active, more_struct_aliases, "1.14.0", Some(37544)), + + // Allows #[link(..., cfg(..))] + (active, link_cfg, "1.14.0", Some(37406)), + + (active, use_extern_macros, "1.15.0", Some(35896)), ); declare_features! ( diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index feed400897c0..34280812421a 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -45,6 +45,7 @@ extern crate libc; extern crate rustc_unicode; pub extern crate rustc_errors as errors; extern crate syntax_pos; +extern crate rustc_data_structures; extern crate serialize as rustc_serialize; // used by deriving diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 7d15334ff9f4..2e38ca82d5db 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1902,12 +1902,12 @@ impl<'a> Parser<'a> { if let Some(recv) = followed_by_ty_params { assert!(recv.is_empty()); *recv = attrs; - } else { + debug!("parse_lifetime_defs ret {:?}", res); + return Ok(res); + } else if !attrs.is_empty() { let msg = "trailing attribute after lifetime parameters"; return Err(self.fatal(msg)); } - debug!("parse_lifetime_defs ret {:?}", res); - return Ok(res); } } @@ -4409,7 +4409,7 @@ impl<'a> Parser<'a> { let bounded_lifetime = self.parse_lifetime()?; - self.eat(&token::Colon); + self.expect(&token::Colon)?; let bounds = self.parse_lifetimes(token::BinOp(token::Plus))?; diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 618878c1f798..59a7e75d1255 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -132,7 +132,7 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> { path: self.cx.path.clone(), bench: is_bench_fn(&self.cx, &i), ignore: is_ignored(&i), - should_panic: should_panic(&i) + should_panic: should_panic(&i, &self.cx) }; self.cx.testfns.push(test); self.tests.push(i.ident); @@ -395,14 +395,44 @@ fn is_ignored(i: &ast::Item) -> bool { i.attrs.iter().any(|attr| attr.check_name("ignore")) } -fn should_panic(i: &ast::Item) -> ShouldPanic { +fn should_panic(i: &ast::Item, cx: &TestCtxt) -> ShouldPanic { match i.attrs.iter().find(|attr| attr.check_name("should_panic")) { Some(attr) => { - let msg = attr.meta_item_list() - .and_then(|list| list.iter().find(|mi| mi.check_name("expected"))) - .and_then(|li| li.meta_item()) - .and_then(|mi| mi.value_str()); - ShouldPanic::Yes(msg) + let sd = cx.span_diagnostic; + if attr.is_value_str() { + sd.struct_span_warn( + attr.span(), + "attribute must be of the form: \ + `#[should_panic]` or \ + `#[should_panic(expected = \"error message\")]`" + ).note("Errors in this attribute were erroneously allowed \ + and will become a hard error in a future release.") + .emit(); + return ShouldPanic::Yes(None); + } + match attr.meta_item_list() { + // Handle #[should_panic] + None => ShouldPanic::Yes(None), + // Handle #[should_panic(expected = "foo")] + Some(list) => { + let msg = list.iter() + .find(|mi| mi.check_name("expected")) + .and_then(|mi| mi.meta_item()) + .and_then(|mi| mi.value_str()); + if list.len() != 1 || msg.is_none() { + sd.struct_span_warn( + attr.span(), + "argument must be of the form: \ + `expected = \"error message\"`" + ).note("Errors in this attribute were erroneously \ + allowed and will become a hard error in a \ + future release.").emit(); + ShouldPanic::Yes(None) + } else { + ShouldPanic::Yes(msg) + } + }, + } } None => ShouldPanic::No, } diff --git a/src/libsyntax/util/move_map.rs b/src/libsyntax/util/move_map.rs index e1078b719bf0..fe05e2958b3a 100644 --- a/src/libsyntax/util/move_map.rs +++ b/src/libsyntax/util/move_map.rs @@ -10,6 +10,8 @@ use std::ptr; +use util::small_vector::SmallVector; + pub trait MoveMap: Sized { fn move_map(self, mut f: F) -> Self where F: FnMut(T) -> T { self.move_flat_map(|e| Some(f(e))) @@ -75,3 +77,50 @@ impl MoveMap for ::ptr::P<[T]> { ::ptr::P::from_vec(self.into_vec().move_flat_map(f)) } } + +impl MoveMap for SmallVector { + fn move_flat_map(mut self, mut f: F) -> Self + where F: FnMut(T) -> I, + I: IntoIterator + { + let mut read_i = 0; + let mut write_i = 0; + unsafe { + let mut old_len = self.len(); + self.set_len(0); // make sure we just leak elements in case of panic + + while read_i < old_len { + // move the read_i'th item out of the vector and map it + // to an iterator + let e = ptr::read(self.get_unchecked(read_i)); + let mut iter = f(e).into_iter(); + read_i += 1; + + while let Some(e) = iter.next() { + if write_i < read_i { + ptr::write(self.get_unchecked_mut(write_i), e); + write_i += 1; + } else { + // If this is reached we ran out of space + // in the middle of the vector. + // However, the vector is in a valid state here, + // so we just do a somewhat inefficient insert. + self.set_len(old_len); + self.insert(write_i, e); + + old_len = self.len(); + self.set_len(0); + + read_i += 1; + write_i += 1; + } + } + } + + // write_i tracks the number of actually written new items. + self.set_len(write_i); + } + + self + } +} diff --git a/src/libsyntax/util/small_vector.rs b/src/libsyntax/util/small_vector.rs index 9be7dbd68174..31e675836fc7 100644 --- a/src/libsyntax/util/small_vector.rs +++ b/src/libsyntax/util/small_vector.rs @@ -8,253 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use self::SmallVectorRepr::*; -use self::IntoIterRepr::*; +use rustc_data_structures::small_vec::SmallVec; -use core::ops; -use std::iter::{IntoIterator, FromIterator}; -use std::mem; -use std::slice; -use std::vec; - -use util::move_map::MoveMap; - -/// A vector type optimized for cases where the size is almost always 0 or 1 -#[derive(Clone)] -pub struct SmallVector { - repr: SmallVectorRepr, -} - -#[derive(Clone)] -enum SmallVectorRepr { - Zero, - One(T), - Many(Vec), -} - -impl Default for SmallVector { - fn default() -> Self { - SmallVector { repr: Zero } - } -} - -impl Into> for SmallVector { - fn into(self) -> Vec { - match self.repr { - Zero => Vec::new(), - One(t) => vec![t], - Many(vec) => vec, - } - } -} - -impl FromIterator for SmallVector { - fn from_iter>(iter: I) -> SmallVector { - let mut v = SmallVector::zero(); - v.extend(iter); - v - } -} - -impl Extend for SmallVector { - fn extend>(&mut self, iter: I) { - for val in iter { - self.push(val); - } - } -} - -impl SmallVector { - pub fn zero() -> SmallVector { - SmallVector { repr: Zero } - } - - pub fn one(v: T) -> SmallVector { - SmallVector { repr: One(v) } - } - - pub fn many(vs: Vec) -> SmallVector { - SmallVector { repr: Many(vs) } - } - - pub fn as_slice(&self) -> &[T] { - self - } - - pub fn as_mut_slice(&mut self) -> &mut [T] { - self - } - - pub fn pop(&mut self) -> Option { - match self.repr { - Zero => None, - One(..) => { - let one = mem::replace(&mut self.repr, Zero); - match one { - One(v1) => Some(v1), - _ => unreachable!() - } - } - Many(ref mut vs) => vs.pop(), - } - } - - pub fn push(&mut self, v: T) { - match self.repr { - Zero => self.repr = One(v), - One(..) => { - let one = mem::replace(&mut self.repr, Zero); - match one { - One(v1) => mem::replace(&mut self.repr, Many(vec![v1, v])), - _ => unreachable!() - }; - } - Many(ref mut vs) => vs.push(v) - } - } - - pub fn push_all(&mut self, other: SmallVector) { - for v in other.into_iter() { - self.push(v); - } - } - - pub fn get(&self, idx: usize) -> &T { - match self.repr { - One(ref v) if idx == 0 => v, - Many(ref vs) => &vs[idx], - _ => panic!("out of bounds access") - } - } - - pub fn expect_one(self, err: &'static str) -> T { - match self.repr { - One(v) => v, - Many(v) => { - if v.len() == 1 { - v.into_iter().next().unwrap() - } else { - panic!(err) - } - } - _ => panic!(err) - } - } - - pub fn len(&self) -> usize { - match self.repr { - Zero => 0, - One(..) => 1, - Many(ref vals) => vals.len() - } - } - - pub fn is_empty(&self) -> bool { self.len() == 0 } - - pub fn map U>(self, mut f: F) -> SmallVector { - let repr = match self.repr { - Zero => Zero, - One(t) => One(f(t)), - Many(vec) => Many(vec.into_iter().map(f).collect()), - }; - SmallVector { repr: repr } - } -} - -impl ops::Deref for SmallVector { - type Target = [T]; - - fn deref(&self) -> &[T] { - match self.repr { - Zero => { - let result: &[T] = &[]; - result - } - One(ref v) => { - unsafe { slice::from_raw_parts(v, 1) } - } - Many(ref vs) => vs - } - } -} - -impl ops::DerefMut for SmallVector { - fn deref_mut(&mut self) -> &mut [T] { - match self.repr { - Zero => { - let result: &mut [T] = &mut []; - result - } - One(ref mut v) => { - unsafe { slice::from_raw_parts_mut(v, 1) } - } - Many(ref mut vs) => vs - } - } -} - -impl IntoIterator for SmallVector { - type Item = T; - type IntoIter = IntoIter; - fn into_iter(self) -> Self::IntoIter { - let repr = match self.repr { - Zero => ZeroIterator, - One(v) => OneIterator(v), - Many(vs) => ManyIterator(vs.into_iter()) - }; - IntoIter { repr: repr } - } -} - -pub struct IntoIter { - repr: IntoIterRepr, -} - -enum IntoIterRepr { - ZeroIterator, - OneIterator(T), - ManyIterator(vec::IntoIter), -} - -impl Iterator for IntoIter { - type Item = T; - - fn next(&mut self) -> Option { - match self.repr { - ZeroIterator => None, - OneIterator(..) => { - let mut replacement = ZeroIterator; - mem::swap(&mut self.repr, &mut replacement); - match replacement { - OneIterator(v) => Some(v), - _ => unreachable!() - } - } - ManyIterator(ref mut inner) => inner.next() - } - } - - fn size_hint(&self) -> (usize, Option) { - match self.repr { - ZeroIterator => (0, Some(0)), - OneIterator(..) => (1, Some(1)), - ManyIterator(ref inner) => inner.size_hint() - } - } -} - -impl MoveMap for SmallVector { - fn move_flat_map(self, mut f: F) -> Self - where F: FnMut(T) -> I, - I: IntoIterator - { - match self.repr { - Zero => Self::zero(), - One(v) => f(v).into_iter().collect(), - Many(vs) => SmallVector { repr: Many(vs.move_flat_map(f)) }, - } - } -} +pub type SmallVector = SmallVec<[T; 1]>; #[cfg(test)] mod tests { @@ -262,7 +18,7 @@ mod tests { #[test] fn test_len() { - let v: SmallVector = SmallVector::zero(); + let v: SmallVector = SmallVector::new(); assert_eq!(0, v.len()); assert_eq!(1, SmallVector::one(1).len()); @@ -271,30 +27,30 @@ mod tests { #[test] fn test_push_get() { - let mut v = SmallVector::zero(); + let mut v = SmallVector::new(); v.push(1); assert_eq!(1, v.len()); - assert_eq!(&1, v.get(0)); + assert_eq!(1, v[0]); v.push(2); assert_eq!(2, v.len()); - assert_eq!(&2, v.get(1)); + assert_eq!(2, v[1]); v.push(3); assert_eq!(3, v.len()); - assert_eq!(&3, v.get(2)); + assert_eq!(3, v[2]); } #[test] fn test_from_iter() { let v: SmallVector = (vec![1, 2, 3]).into_iter().collect(); assert_eq!(3, v.len()); - assert_eq!(&1, v.get(0)); - assert_eq!(&2, v.get(1)); - assert_eq!(&3, v.get(2)); + assert_eq!(1, v[0]); + assert_eq!(2, v[1]); + assert_eq!(3, v[2]); } #[test] fn test_move_iter() { - let v = SmallVector::zero(); + let v = SmallVector::new(); let v: Vec = v.into_iter().collect(); assert_eq!(v, Vec::new()); @@ -308,7 +64,7 @@ mod tests { #[test] #[should_panic] fn test_expect_one_zero() { - let _: isize = SmallVector::zero().expect_one(""); + let _: isize = SmallVector::new().expect_one(""); } #[test] diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index de78f859f0f6..6eba8baf5b82 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -22,7 +22,7 @@ use syntax::ptr::P; use syntax_pos::{Span, DUMMY_SP}; use syntax::tokenstream; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::collections::hash_map::Entry; #[derive(PartialEq)] @@ -756,8 +756,12 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, } if !parser.errors.is_empty() { - cx.ecx.span_err(cx.fmtsp, - &format!("invalid format string: {}", parser.errors.remove(0))); + let (err, note) = parser.errors.remove(0); + let mut e = cx.ecx.struct_span_err(cx.fmtsp, &format!("invalid format string: {}", err)); + if let Some(note) = note { + e.note(¬e); + } + e.emit(); return DummyResult::raw_expr(sp); } if !cx.literal.is_empty() { @@ -767,6 +771,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, // Make sure that all arguments were used and all arguments have types. let num_pos_args = cx.args.len() - cx.names.len(); + let mut errs = vec![]; for (i, ty) in cx.arg_types.iter().enumerate() { if ty.len() == 0 { if cx.count_positions.contains_key(&i) { @@ -779,9 +784,80 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, // positional argument "argument never used" }; - cx.ecx.span_err(cx.args[i].span, msg); + errs.push((cx.args[i].span, msg)); } } + if errs.len() > 0 { + let args_used = cx.arg_types.len() - errs.len(); + let args_unused = errs.len(); + + let mut diag = { + if errs.len() == 1 { + let (sp, msg) = errs.into_iter().next().unwrap(); + cx.ecx.struct_span_err(sp, msg) + } else { + let mut diag = cx.ecx.struct_span_err(cx.fmtsp, + "multiple unused formatting arguments"); + for (sp, msg) in errs { + diag.span_note(sp, msg); + } + diag + } + }; + + // Decide if we want to look for foreign formatting directives. + if args_used < args_unused { + use super::format_foreign as foreign; + let fmt_str = &fmt.node.0[..]; + + // The set of foreign substitutions we've explained. This prevents spamming the user + // with `%d should be written as {}` over and over again. + let mut explained = HashSet::new(); + + // Used to ensure we only report translations for *one* kind of foreign format. + let mut found_foreign = false; + + macro_rules! check_foreign { + ($kind:ident) => {{ + let mut show_doc_note = false; + + for sub in foreign::$kind::iter_subs(fmt_str) { + let trn = match sub.translate() { + Some(trn) => trn, + + // If it has no translation, don't call it out specifically. + None => continue, + }; + + let sub = String::from(sub.as_str()); + if explained.contains(&sub) { + continue; + } + explained.insert(sub.clone()); + + if !found_foreign { + found_foreign = true; + show_doc_note = true; + } + + diag.help(&format!("`{}` should be written as `{}`", sub, trn)); + } + + if show_doc_note { + diag.note(concat!(stringify!($kind), " formatting not supported; see \ + the documentation for `std::fmt`")); + } + }}; + } + + check_foreign!(printf); + if !found_foreign { + check_foreign!(shell); + } + } + + diag.emit(); + } cx.into_expr() } diff --git a/src/libsyntax_ext/format_foreign.rs b/src/libsyntax_ext/format_foreign.rs new file mode 100644 index 000000000000..3c802e8334da --- /dev/null +++ b/src/libsyntax_ext/format_foreign.rs @@ -0,0 +1,1013 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +macro_rules! try_opt { + ($e:expr) => { + match $e { + Some(v) => v, + None => return None, + } + }; +} + +pub mod printf { + use super::strcursor::StrCursor as Cur; + + /// Represents a single `printf`-style substitution. + #[derive(Clone, Eq, PartialEq, Debug)] + pub enum Substitution<'a> { + /// A formatted output substitution. + Format(Format<'a>), + /// A literal `%%` escape. + Escape, + } + + impl<'a> Substitution<'a> { + pub fn as_str(&self) -> &str { + match *self { + Substitution::Format(ref fmt) => fmt.span, + Substitution::Escape => "%%", + } + } + + /// Translate this substitution into an equivalent Rust formatting directive. + /// + /// This ignores cases where the substitution does not have an exact equivalent, or where + /// the substitution would be unnecessary. + pub fn translate(&self) -> Option { + match *self { + Substitution::Format(ref fmt) => fmt.translate(), + Substitution::Escape => None, + } + } + } + + #[derive(Clone, Eq, PartialEq, Debug)] + /// A single `printf`-style formatting directive. + pub struct Format<'a> { + /// The entire original formatting directive. + pub span: &'a str, + /// The (1-based) parameter to be converted. + pub parameter: Option, + /// Formatting flags. + pub flags: &'a str, + /// Minimum width of the output. + pub width: Option, + /// Precision of the conversion. + pub precision: Option, + /// Length modifier for the conversion. + pub length: Option<&'a str>, + /// Type of parameter being converted. + pub type_: &'a str, + } + + impl<'a> Format<'a> { + /// Translate this directive into an equivalent Rust formatting directive. + /// + /// Returns `None` in cases where the `printf` directive does not have an exact Rust + /// equivalent, rather than guessing. + pub fn translate(&self) -> Option { + use std::fmt::Write; + + let (c_alt, c_zero, c_left, c_plus) = { + let mut c_alt = false; + let mut c_zero = false; + let mut c_left = false; + let mut c_plus = false; + for c in self.flags.chars() { + match c { + '#' => c_alt = true, + '0' => c_zero = true, + '-' => c_left = true, + '+' => c_plus = true, + _ => return None + } + } + (c_alt, c_zero, c_left, c_plus) + }; + + // Has a special form in Rust for numbers. + let fill = if c_zero { Some("0") } else { None }; + + let align = if c_left { Some("<") } else { None }; + + // Rust doesn't have an equivalent to the `' '` flag. + let sign = if c_plus { Some("+") } else { None }; + + // Not *quite* the same, depending on the type... + let alt = c_alt; + + let width = match self.width { + Some(Num::Next) => { + // NOTE: Rust doesn't support this. + return None; + } + w @ Some(Num::Arg(_)) => w, + w @ Some(Num::Num(_)) => w, + None => None, + }; + + let precision = self.precision; + + // NOTE: although length *can* have an effect, we can't duplicate the effect in Rust, so + // we just ignore it. + + let (type_, use_zero_fill, is_int) = match self.type_ { + "d" | "i" | "u" => (None, true, true), + "f" | "F" => (None, false, false), + "s" | "c" => (None, false, false), + "e" | "E" => (Some(self.type_), true, false), + "x" | "X" | "o" => (Some(self.type_), true, true), + "p" => (Some(self.type_), false, true), + "g" => (Some("e"), true, false), + "G" => (Some("E"), true, false), + _ => return None, + }; + + let (fill, width, precision) = match (is_int, width, precision) { + (true, Some(_), Some(_)) => { + // Rust can't duplicate this insanity. + return None; + }, + (true, None, Some(p)) => (Some("0"), Some(p), None), + (true, w, None) => (fill, w, None), + (false, w, p) => (fill, w, p), + }; + + let align = match (self.type_, width.is_some(), align.is_some()) { + ("s", true, false) => Some(">"), + _ => align, + }; + + let (fill, zero_fill) = match (fill, use_zero_fill) { + (Some("0"), true) => (None, true), + (fill, _) => (fill, false), + }; + + let alt = match type_ { + Some("x") | Some("X") => alt, + _ => false, + }; + + let has_options = fill.is_some() + || align.is_some() + || sign.is_some() + || alt + || zero_fill + || width.is_some() + || precision.is_some() + || type_.is_some() + ; + + // Initialise with a rough guess. + let cap = self.span.len() + if has_options { 2 } else { 0 }; + let mut s = String::with_capacity(cap); + + s.push_str("{"); + + if let Some(arg) = self.parameter { + try_opt!(write!(s, "{}", try_opt!(arg.checked_sub(1))).ok()); + } + + if has_options { + s.push_str(":"); + + let align = if let Some(fill) = fill { + s.push_str(fill); + align.or(Some(">")) + } else { + align + }; + + if let Some(align) = align { + s.push_str(align); + } + + if let Some(sign) = sign { + s.push_str(sign); + } + + if alt { + s.push_str("#"); + } + + if zero_fill { + s.push_str("0"); + } + + if let Some(width) = width { + try_opt!(width.translate(&mut s).ok()); + } + + if let Some(precision) = precision { + s.push_str("."); + try_opt!(precision.translate(&mut s).ok()); + } + + if let Some(type_) = type_ { + s.push_str(type_); + } + } + + s.push_str("}"); + Some(s) + } + } + + /// A general number used in a `printf` formatting directive. + #[derive(Copy, Clone, Eq, PartialEq, Debug)] + pub enum Num { + // The range of these values is technically bounded by `NL_ARGMAX`... but, at least for GNU + // libc, it apparently has no real fixed limit. A `u16` is used here on the basis that it + // is *vanishingly* unlikely that *anyone* is going to try formatting something wider, or + // with more precision, than 32 thousand positions which is so wide it couldn't possibly fit + // on a screen. + + /// A specific, fixed value. + Num(u16), + /// The value is derived from a positional argument. + Arg(u16), + /// The value is derived from the "next" unconverted argument. + Next, + } + + impl Num { + fn from_str(s: &str, arg: Option<&str>) -> Self { + if let Some(arg) = arg { + Num::Arg(arg.parse().expect(&format!("invalid format arg `{:?}`", arg))) + } else if s == "*" { + Num::Next + } else { + Num::Num(s.parse().expect(&format!("invalid format num `{:?}`", s))) + } + } + + fn translate(&self, s: &mut String) -> ::std::fmt::Result { + use std::fmt::Write; + match *self { + Num::Num(n) => write!(s, "{}", n), + Num::Arg(n) => { + let n = try!(n.checked_sub(1).ok_or(::std::fmt::Error)); + write!(s, "{}$", n) + }, + Num::Next => write!(s, "*"), + } + } + } + + /// Returns an iterator over all substitutions in a given string. + pub fn iter_subs(s: &str) -> Substitutions { + Substitutions { + s: s, + } + } + + /// Iterator over substitutions in a string. + pub struct Substitutions<'a> { + s: &'a str, + } + + impl<'a> Iterator for Substitutions<'a> { + type Item = Substitution<'a>; + fn next(&mut self) -> Option { + match parse_next_substitution(self.s) { + Some((sub, tail)) => { + self.s = tail; + Some(sub) + }, + None => None, + } + } + } + + enum State { + Start, + Flags, + Width, + WidthArg, + Prec, + PrecInner, + Length, + Type, + } + + /// Parse the next substitution from the input string. + pub fn parse_next_substitution(s: &str) -> Option<(Substitution, &str)> { + use self::State::*; + + let at = { + let start = try_opt!(s.find('%')); + match s[start+1..].chars().next() { + Some('%') => return Some((Substitution::Escape, &s[start+2..])), + Some(_) => {/* fall-through */}, + None => return None, + } + + Cur::new_at_start(&s[start..]) + }; + + // This is meant to be a translation of the following regex: + // + // ```regex + // (?x) + // ^ % + // (?: (?P \d+) \$ )? + // (?P [-+ 0\#']* ) + // (?P \d+ | \* (?: (?P \d+) \$ )? )? + // (?: \. (?P \d+ | \* (?: (?P \d+) \$ )? ) )? + // (?P + // # Standard + // hh | h | ll | l | L | z | j | t + // + // # Other + // | I32 | I64 | I | q + // )? + // (?P . ) + // ``` + + // Used to establish the full span at the end. + let start = at; + // The current position within the string. + let mut at = try_opt!(at.at_next_cp()); + // `c` is the next codepoint, `next` is a cursor after it. + let (mut c, mut next) = try_opt!(at.next_cp()); + + // Update `at`, `c`, and `next`, exiting if we're out of input. + macro_rules! move_to { + ($cur:expr) => { + { + at = $cur; + let (c_, next_) = try_opt!(at.next_cp()); + c = c_; + next = next_; + } + }; + } + + // Constructs a result when parsing fails. + // + // Note: `move` used to capture copies of the cursors as they are *now*. + let fallback = move || { + return Some(( + Substitution::Format(Format { + span: start.slice_between(next).unwrap(), + parameter: None, + flags: "", + width: None, + precision: None, + length: None, + type_: at.slice_between(next).unwrap(), + }), + next.slice_after() + )); + }; + + // Next parsing state. + let mut state = Start; + + // Sadly, Rust isn't *quite* smart enough to know these *must* be initialised by the end. + let mut parameter: Option = None; + let mut flags: &str = ""; + let mut width: Option = None; + let mut precision: Option = None; + let mut length: Option<&str> = None; + let mut type_: &str = ""; + let end: Cur; + + if let Start = state { + match c { + '1'...'9' => { + let end = at_next_cp_while(next, is_digit); + match end.next_cp() { + // Yes, this *is* the parameter. + Some(('$', end2)) => { + state = Flags; + parameter = Some(at.slice_between(end).unwrap().parse().unwrap()); + move_to!(end2); + }, + // Wait, no, actually, it's the width. + Some(_) => { + state = Prec; + parameter = None; + flags = ""; + width = Some(Num::from_str(at.slice_between(end).unwrap(), None)); + move_to!(end); + }, + // It's invalid, is what it is. + None => return fallback(), + } + }, + _ => { + state = Flags; + parameter = None; + move_to!(at); + } + } + } + + if let Flags = state { + let end = at_next_cp_while(at, is_flag); + state = Width; + flags = at.slice_between(end).unwrap(); + move_to!(end); + } + + if let Width = state { + match c { + '*' => { + state = WidthArg; + move_to!(next); + }, + '1' ... '9' => { + let end = at_next_cp_while(next, is_digit); + state = Prec; + width = Some(Num::from_str(at.slice_between(end).unwrap(), None)); + move_to!(end); + }, + _ => { + state = Prec; + width = None; + move_to!(at); + } + } + } + + if let WidthArg = state { + let end = at_next_cp_while(at, is_digit); + match end.next_cp() { + Some(('$', end2)) => { + state = Prec; + width = Some(Num::from_str("", Some(at.slice_between(end).unwrap()))); + move_to!(end2); + }, + _ => { + state = Prec; + width = Some(Num::Next); + move_to!(end); + } + } + } + + if let Prec = state { + match c { + '.' => { + state = PrecInner; + move_to!(next); + }, + _ => { + state = Length; + precision = None; + move_to!(at); + } + } + } + + if let PrecInner = state { + match c { + '*' => { + let end = at_next_cp_while(next, is_digit); + match end.next_cp() { + Some(('$', end2)) => { + state = Length; + precision = Some(Num::from_str("*", next.slice_between(end))); + move_to!(end2); + }, + _ => { + state = Length; + precision = Some(Num::Next); + move_to!(end); + } + } + }, + '0' ... '9' => { + let end = at_next_cp_while(next, is_digit); + state = Length; + precision = Some(Num::from_str(at.slice_between(end).unwrap(), None)); + move_to!(end); + }, + _ => return fallback(), + } + } + + if let Length = state { + let c1_next1 = next.next_cp(); + match (c, c1_next1) { + ('h', Some(('h', next1))) + | ('l', Some(('l', next1))) + => { + state = Type; + length = Some(at.slice_between(next1).unwrap()); + move_to!(next1); + }, + + ('h', _) | ('l', _) | ('L', _) + | ('z', _) | ('j', _) | ('t', _) + | ('q', _) + => { + state = Type; + length = Some(at.slice_between(next).unwrap()); + move_to!(next); + }, + + ('I', _) => { + let end = next.at_next_cp() + .and_then(|end| end.at_next_cp()) + .map(|end| (next.slice_between(end).unwrap(), end)); + let end = match end { + Some(("32", end)) => end, + Some(("64", end)) => end, + _ => next + }; + state = Type; + length = Some(at.slice_between(end).unwrap()); + move_to!(end); + }, + + _ => { + state = Type; + length = None; + move_to!(at); + } + } + } + + if let Type = state { + drop(c); + type_ = at.slice_between(next).unwrap(); + + // Don't use `move_to!` here, as we *can* be at the end of the input. + at = next; + } + + drop(c); + drop(next); + + end = at; + + let f = Format { + span: start.slice_between(end).unwrap(), + parameter: parameter, + flags: flags, + width: width, + precision: precision, + length: length, + type_: type_, + }; + Some((Substitution::Format(f), end.slice_after())) + } + + fn at_next_cp_while(mut cur: Cur, mut pred: F) -> Cur + where F: FnMut(char) -> bool { + loop { + match cur.next_cp() { + Some((c, next)) => if pred(c) { + cur = next; + } else { + return cur; + }, + None => return cur, + } + } + } + + fn is_digit(c: char) -> bool { + match c { + '0' ... '9' => true, + _ => false + } + } + + fn is_flag(c: char) -> bool { + match c { + '0' | '-' | '+' | ' ' | '#' | '\'' => true, + _ => false + } + } + + #[cfg(test)] + mod tests { + use super::{ + Format as F, + Num as N, + Substitution as S, + iter_subs, + parse_next_substitution as pns, + }; + + macro_rules! assert_eq_pnsat { + ($lhs:expr, $rhs:expr) => { + assert_eq!( + pns($lhs).and_then(|(s, _)| s.translate()), + $rhs.map(>::from) + ) + }; + } + + #[test] + fn test_escape() { + assert_eq!(pns("has no escapes"), None); + assert_eq!(pns("has no escapes, either %"), None); + assert_eq!(pns("*so* has a %% escape"), Some((S::Escape," escape"))); + assert_eq!(pns("%% leading escape"), Some((S::Escape, " leading escape"))); + assert_eq!(pns("trailing escape %%"), Some((S::Escape, ""))); + } + + #[test] + fn test_parse() { + macro_rules! assert_pns_eq_sub { + ($in_:expr, { + $param:expr, $flags:expr, + $width:expr, $prec:expr, $len:expr, $type_:expr, + }) => { + assert_eq!( + pns(concat!($in_, "!")), + Some(( + S::Format(F { + span: $in_, + parameter: $param, + flags: $flags, + width: $width, + precision: $prec, + length: $len, + type_: $type_, + }), + "!" + )) + ) + }; + } + + assert_pns_eq_sub!("%!", + { None, "", None, None, None, "!", }); + assert_pns_eq_sub!("%c", + { None, "", None, None, None, "c", }); + assert_pns_eq_sub!("%s", + { None, "", None, None, None, "s", }); + assert_pns_eq_sub!("%06d", + { None, "0", Some(N::Num(6)), None, None, "d", }); + assert_pns_eq_sub!("%4.2f", + { None, "", Some(N::Num(4)), Some(N::Num(2)), None, "f", }); + assert_pns_eq_sub!("%#x", + { None, "#", None, None, None, "x", }); + assert_pns_eq_sub!("%-10s", + { None, "-", Some(N::Num(10)), None, None, "s", }); + assert_pns_eq_sub!("%*s", + { None, "", Some(N::Next), None, None, "s", }); + assert_pns_eq_sub!("%-10.*s", + { None, "-", Some(N::Num(10)), Some(N::Next), None, "s", }); + assert_pns_eq_sub!("%-*.*s", + { None, "-", Some(N::Next), Some(N::Next), None, "s", }); + assert_pns_eq_sub!("%.6i", + { None, "", None, Some(N::Num(6)), None, "i", }); + assert_pns_eq_sub!("%+i", + { None, "+", None, None, None, "i", }); + assert_pns_eq_sub!("%08X", + { None, "0", Some(N::Num(8)), None, None, "X", }); + assert_pns_eq_sub!("%lu", + { None, "", None, None, Some("l"), "u", }); + assert_pns_eq_sub!("%Iu", + { None, "", None, None, Some("I"), "u", }); + assert_pns_eq_sub!("%I32u", + { None, "", None, None, Some("I32"), "u", }); + assert_pns_eq_sub!("%I64u", + { None, "", None, None, Some("I64"), "u", }); + assert_pns_eq_sub!("%'d", + { None, "'", None, None, None, "d", }); + assert_pns_eq_sub!("%10s", + { None, "", Some(N::Num(10)), None, None, "s", }); + assert_pns_eq_sub!("%-10.10s", + { None, "-", Some(N::Num(10)), Some(N::Num(10)), None, "s", }); + assert_pns_eq_sub!("%1$d", + { Some(1), "", None, None, None, "d", }); + assert_pns_eq_sub!("%2$.*3$d", + { Some(2), "", None, Some(N::Arg(3)), None, "d", }); + assert_pns_eq_sub!("%1$*2$.*3$d", + { Some(1), "", Some(N::Arg(2)), Some(N::Arg(3)), None, "d", }); + assert_pns_eq_sub!("%-8ld", + { None, "-", Some(N::Num(8)), None, Some("l"), "d", }); + } + + #[test] + fn test_iter() { + let s = "The %d'th word %% is: `%.*s` %!\n"; + let subs: Vec<_> = iter_subs(s).map(|sub| sub.translate()).collect(); + assert_eq!( + subs.iter().map(|ms| ms.as_ref().map(|s| &s[..])).collect::>(), + vec![Some("{}"), None, Some("{:.*}"), None] + ); + } + + /// Check that the translations are what we expect. + #[test] + fn test_trans() { + assert_eq_pnsat!("%c", Some("{}")); + assert_eq_pnsat!("%d", Some("{}")); + assert_eq_pnsat!("%u", Some("{}")); + assert_eq_pnsat!("%x", Some("{:x}")); + assert_eq_pnsat!("%X", Some("{:X}")); + assert_eq_pnsat!("%e", Some("{:e}")); + assert_eq_pnsat!("%E", Some("{:E}")); + assert_eq_pnsat!("%f", Some("{}")); + assert_eq_pnsat!("%g", Some("{:e}")); + assert_eq_pnsat!("%G", Some("{:E}")); + assert_eq_pnsat!("%s", Some("{}")); + assert_eq_pnsat!("%p", Some("{:p}")); + + assert_eq_pnsat!("%06d", Some("{:06}")); + assert_eq_pnsat!("%4.2f", Some("{:4.2}")); + assert_eq_pnsat!("%#x", Some("{:#x}")); + assert_eq_pnsat!("%-10s", Some("{:<10}")); + assert_eq_pnsat!("%*s", None); + assert_eq_pnsat!("%-10.*s", Some("{:<10.*}")); + assert_eq_pnsat!("%-*.*s", None); + assert_eq_pnsat!("%.6i", Some("{:06}")); + assert_eq_pnsat!("%+i", Some("{:+}")); + assert_eq_pnsat!("%08X", Some("{:08X}")); + assert_eq_pnsat!("%lu", Some("{}")); + assert_eq_pnsat!("%Iu", Some("{}")); + assert_eq_pnsat!("%I32u", Some("{}")); + assert_eq_pnsat!("%I64u", Some("{}")); + assert_eq_pnsat!("%'d", None); + assert_eq_pnsat!("%10s", Some("{:>10}")); + assert_eq_pnsat!("%-10.10s", Some("{:<10.10}")); + assert_eq_pnsat!("%1$d", Some("{0}")); + assert_eq_pnsat!("%2$.*3$d", Some("{1:02$}")); + assert_eq_pnsat!("%1$*2$.*3$s", Some("{0:>1$.2$}")); + assert_eq_pnsat!("%-8ld", Some("{:<8}")); + } + } +} + +pub mod shell { + use super::strcursor::StrCursor as Cur; + + #[derive(Clone, Eq, PartialEq, Debug)] + pub enum Substitution<'a> { + Ordinal(u8), + Name(&'a str), + Escape, + } + + impl<'a> Substitution<'a> { + pub fn as_str(&self) -> String { + match *self { + Substitution::Ordinal(n) => format!("${}", n), + Substitution::Name(n) => format!("${}", n), + Substitution::Escape => "$$".into(), + } + } + + pub fn translate(&self) -> Option { + match *self { + Substitution::Ordinal(n) => Some(format!("{{{}}}", n)), + Substitution::Name(n) => Some(format!("{{{}}}", n)), + Substitution::Escape => None, + } + } + } + + /// Returns an iterator over all substitutions in a given string. + pub fn iter_subs(s: &str) -> Substitutions { + Substitutions { + s: s, + } + } + + /// Iterator over substitutions in a string. + pub struct Substitutions<'a> { + s: &'a str, + } + + impl<'a> Iterator for Substitutions<'a> { + type Item = Substitution<'a>; + fn next(&mut self) -> Option { + match parse_next_substitution(self.s) { + Some((sub, tail)) => { + self.s = tail; + Some(sub) + }, + None => None, + } + } + } + + /// Parse the next substitution from the input string. + pub fn parse_next_substitution(s: &str) -> Option<(Substitution, &str)> { + let at = { + let start = try_opt!(s.find('$')); + match s[start+1..].chars().next() { + Some('$') => return Some((Substitution::Escape, &s[start+2..])), + Some(c @ '0' ... '9') => { + let n = (c as u8) - b'0'; + return Some((Substitution::Ordinal(n), &s[start+2..])); + }, + Some(_) => {/* fall-through */}, + None => return None, + } + + Cur::new_at_start(&s[start..]) + }; + + let at = try_opt!(at.at_next_cp()); + match at.next_cp() { + Some((c, inner)) => { + if !is_ident_head(c) { + None + } else { + let end = at_next_cp_while(inner, is_ident_tail); + Some((Substitution::Name(at.slice_between(end).unwrap()), end.slice_after())) + } + }, + _ => None + } + } + + fn at_next_cp_while(mut cur: Cur, mut pred: F) -> Cur + where F: FnMut(char) -> bool { + loop { + match cur.next_cp() { + Some((c, next)) => if pred(c) { + cur = next; + } else { + return cur; + }, + None => return cur, + } + } + } + + fn is_ident_head(c: char) -> bool { + match c { + 'a' ... 'z' | 'A' ... 'Z' | '_' => true, + _ => false + } + } + + fn is_ident_tail(c: char) -> bool { + match c { + '0' ... '9' => true, + c => is_ident_head(c) + } + } + + #[cfg(test)] + mod tests { + use super::{ + Substitution as S, + parse_next_substitution as pns, + }; + + macro_rules! assert_eq_pnsat { + ($lhs:expr, $rhs:expr) => { + assert_eq!( + pns($lhs).and_then(|(f, _)| f.translate()), + $rhs.map(>::from) + ) + }; + } + + #[test] + fn test_escape() { + assert_eq!(pns("has no escapes"), None); + assert_eq!(pns("has no escapes, either $"), None); + assert_eq!(pns("*so* has a $$ escape"), Some((S::Escape, " escape"))); + assert_eq!(pns("$$ leading escape"), Some((S::Escape, " leading escape"))); + assert_eq!(pns("trailing escape $$"), Some((S::Escape, ""))); + } + + #[test] + fn test_parse() { + macro_rules! assert_pns_eq_sub { + ($in_:expr, $kind:ident($arg:expr)) => { + assert_eq!(pns(concat!($in_, "!")), Some((S::$kind($arg.into()), "!"))) + }; + } + + assert_pns_eq_sub!("$0", Ordinal(0)); + assert_pns_eq_sub!("$1", Ordinal(1)); + assert_pns_eq_sub!("$9", Ordinal(9)); + assert_pns_eq_sub!("$N", Name("N")); + assert_pns_eq_sub!("$NAME", Name("NAME")); + } + + #[test] + fn test_iter() { + use super::iter_subs; + let s = "The $0'th word $$ is: `$WORD` $!\n"; + let subs: Vec<_> = iter_subs(s).map(|sub| sub.translate()).collect(); + assert_eq!( + subs.iter().map(|ms| ms.as_ref().map(|s| &s[..])).collect::>(), + vec![Some("{0}"), None, Some("{WORD}")] + ); + } + + #[test] + fn test_trans() { + assert_eq_pnsat!("$0", Some("{0}")); + assert_eq_pnsat!("$9", Some("{9}")); + assert_eq_pnsat!("$1", Some("{1}")); + assert_eq_pnsat!("$10", Some("{1}")); + assert_eq_pnsat!("$stuff", Some("{stuff}")); + assert_eq_pnsat!("$NAME", Some("{NAME}")); + assert_eq_pnsat!("$PREFIX/bin", Some("{PREFIX}")); + } + + } +} + +mod strcursor { + use std; + + pub struct StrCursor<'a> { + s: &'a str, + at: usize, + } + + impl<'a> StrCursor<'a> { + pub fn new_at_start(s: &'a str) -> StrCursor<'a> { + StrCursor { + s: s, + at: 0, + } + } + + pub fn at_next_cp(mut self) -> Option> { + match self.try_seek_right_cp() { + true => Some(self), + false => None + } + } + + pub fn next_cp(mut self) -> Option<(char, StrCursor<'a>)> { + let cp = match self.cp_after() { + Some(cp) => cp, + None => return None, + }; + self.seek_right(cp.len_utf8()); + Some((cp, self)) + } + + fn slice_before(&self) -> &'a str { + &self.s[0..self.at] + } + + pub fn slice_after(&self) -> &'a str { + &self.s[self.at..] + } + + pub fn slice_between(&self, until: StrCursor<'a>) -> Option<&'a str> { + if !str_eq_literal(self.s, until.s) { + None + } else { + use std::cmp::{max, min}; + let beg = min(self.at, until.at); + let end = max(self.at, until.at); + Some(&self.s[beg..end]) + } + } + + fn cp_after(&self) -> Option { + self.slice_after().chars().next() + } + + fn try_seek_right_cp(&mut self) -> bool { + match self.slice_after().chars().next() { + Some(c) => { + self.at += c.len_utf8(); + true + }, + None => false, + } + } + + fn seek_right(&mut self, bytes: usize) { + self.at += bytes; + } + } + + impl<'a> Copy for StrCursor<'a> {} + + impl<'a> Clone for StrCursor<'a> { + fn clone(&self) -> StrCursor<'a> { + *self + } + } + + impl<'a> std::fmt::Debug for StrCursor<'a> { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + write!(fmt, "StrCursor({:?} | {:?})", self.slice_before(), self.slice_after()) + } + } + + fn str_eq_literal(a: &str, b: &str) -> bool { + a.as_bytes().as_ptr() == b.as_bytes().as_ptr() + && a.len() == b.len() + } +} diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index e1542c9e466a..1ebac19b4f02 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -40,6 +40,7 @@ mod concat; mod concat_idents; mod env; mod format; +mod format_foreign; mod log_syntax; mod trace_macros; diff --git a/src/libsyntax_ext/proc_macro_registrar.rs b/src/libsyntax_ext/proc_macro_registrar.rs index d6d31200a994..36fd6408b4f3 100644 --- a/src/libsyntax_ext/proc_macro_registrar.rs +++ b/src/libsyntax_ext/proc_macro_registrar.rs @@ -38,12 +38,14 @@ struct CollectCustomDerives<'a> { in_root: bool, handler: &'a errors::Handler, is_proc_macro_crate: bool, + is_test_crate: bool, } pub fn modify(sess: &ParseSess, resolver: &mut ::syntax::ext::base::Resolver, mut krate: ast::Crate, is_proc_macro_crate: bool, + is_test_crate: bool, num_crate_types: usize, handler: &errors::Handler, features: &Features) -> ast::Crate { @@ -55,6 +57,7 @@ pub fn modify(sess: &ParseSess, in_root: true, handler: handler, is_proc_macro_crate: is_proc_macro_crate, + is_test_crate: is_test_crate, }; visit::walk_crate(&mut collect, &krate); @@ -137,6 +140,12 @@ impl<'a> Visitor for CollectCustomDerives<'a> { attributes found"); } + if self.is_test_crate { + self.handler.span_err(attr.span(), + "`--test` cannot be used with proc-macro crates"); + return; + } + if !self.is_proc_macro_crate { self.handler.span_err(attr.span(), "the `#[proc_macro_derive]` attribute is \ diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index d99850332c36..d6e45aa0b9f0 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -52,7 +52,7 @@ pub type FileName = String; /// able to use many of the functions on spans in codemap and you cannot assume /// that the length of the span = hi - lo; there may be space in the BytePos /// range between files. -#[derive(Clone, Copy, Hash, PartialEq, Eq)] +#[derive(Clone, Copy, Hash, PartialEq, Eq, Ord, PartialOrd)] pub struct Span { pub lo: BytePos, pub hi: BytePos, @@ -67,7 +67,7 @@ pub struct Span { /// the error, and would be rendered with `^^^`. /// - they can have a *label*. In this case, the label is written next /// to the mark in the snippet when we render. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct MultiSpan { primary_spans: Vec, span_labels: Vec<(Span, String)>, @@ -254,7 +254,7 @@ impl From for MultiSpan { } } -#[derive(PartialEq, Eq, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Copy)] +#[derive(PartialEq, Eq, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Copy, Ord, PartialOrd)] pub struct ExpnId(pub u32); pub const NO_EXPANSION: ExpnId = ExpnId(!0); diff --git a/src/libterm/terminfo/searcher.rs b/src/libterm/terminfo/searcher.rs index 4b1df7d170db..011d06b1c0f2 100644 --- a/src/libterm/terminfo/searcher.rs +++ b/src/libterm/terminfo/searcher.rs @@ -26,38 +26,34 @@ pub fn get_dbpath_for_term(term: &str) -> Option { }; // Find search directory - match env::var_os("TERMINFO") { - Some(dir) => dirs_to_search.push(PathBuf::from(dir)), - None => { - if let Some(mut homedir) = env::home_dir() { - // ncurses compatibility; - homedir.push(".terminfo"); - dirs_to_search.push(homedir) - } - match env::var("TERMINFO_DIRS") { - Ok(dirs) => { - for i in dirs.split(':') { - if i == "" { - dirs_to_search.push(PathBuf::from("/usr/share/terminfo")); - } else { - dirs_to_search.push(PathBuf::from(i)); - } - } - } - // Found nothing in TERMINFO_DIRS, use the default paths: - // According to /etc/terminfo/README, after looking at - // ~/.terminfo, ncurses will search /etc/terminfo, then - // /lib/terminfo, and eventually /usr/share/terminfo. - // On Haiku the database can be found at /boot/system/data/terminfo - Err(..) => { - dirs_to_search.push(PathBuf::from("/etc/terminfo")); - dirs_to_search.push(PathBuf::from("/lib/terminfo")); - dirs_to_search.push(PathBuf::from("/usr/share/terminfo")); - dirs_to_search.push(PathBuf::from("/boot/system/data/terminfo")); - } + if let Some(dir) = env::var_os("TERMINFO") { + dirs_to_search.push(PathBuf::from(dir)); + } + + if let Ok(dirs) = env::var("TERMINFO_DIRS") { + for i in dirs.split(':') { + if i == "" { + dirs_to_search.push(PathBuf::from("/usr/share/terminfo")); + } else { + dirs_to_search.push(PathBuf::from(i)); } } - }; + } else { + // Found nothing in TERMINFO_DIRS, use the default paths: + // According to /etc/terminfo/README, after looking at + // ~/.terminfo, ncurses will search /etc/terminfo, then + // /lib/terminfo, and eventually /usr/share/terminfo. + // On Haiku the database can be found at /boot/system/data/terminfo + if let Some(mut homedir) = env::home_dir() { + homedir.push(".terminfo"); + dirs_to_search.push(homedir) + } + + dirs_to_search.push(PathBuf::from("/etc/terminfo")); + dirs_to_search.push(PathBuf::from("/lib/terminfo")); + dirs_to_search.push(PathBuf::from("/usr/share/terminfo")); + dirs_to_search.push(PathBuf::from("/boot/system/data/terminfo")); + } // Look for the terminal in all of the search directories for mut p in dirs_to_search { diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 95ae6eb2efe8..8749a64e5fdb 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -75,9 +75,9 @@ const TEST_WARN_TIMEOUT_S: u64 = 60; // to be used by rustc to compile tests in libtest pub mod test { pub use {Bencher, TestName, TestResult, TestDesc, TestDescAndFn, TestOpts, TrFailed, - TrIgnored, TrOk, Metric, MetricMap, StaticTestFn, StaticTestName, DynTestName, - DynTestFn, run_test, test_main, test_main_static, filter_tests, parse_opts, - StaticBenchFn, ShouldPanic}; + TrFailedMsg, TrIgnored, TrOk, Metric, MetricMap, StaticTestFn, StaticTestName, + DynTestName, DynTestFn, run_test, test_main, test_main_static, filter_tests, + parse_opts, StaticBenchFn, ShouldPanic}; } pub mod stats; @@ -473,6 +473,7 @@ pub struct BenchSamples { pub enum TestResult { TrOk, TrFailed, + TrFailedMsg(String), TrIgnored, TrMetrics(MetricMap), TrBench(BenchSamples), @@ -611,7 +612,7 @@ impl ConsoleTestState { pub fn write_result(&mut self, result: &TestResult) -> io::Result<()> { match *result { TrOk => self.write_ok(), - TrFailed => self.write_failed(), + TrFailed | TrFailedMsg(_) => self.write_failed(), TrIgnored => self.write_ignored(), TrMetrics(ref mm) => { self.write_metric()?; @@ -638,6 +639,7 @@ impl ConsoleTestState { match *result { TrOk => "ok".to_owned(), TrFailed => "failed".to_owned(), + TrFailedMsg(ref msg) => format!("failed: {}", msg), TrIgnored => "ignored".to_owned(), TrMetrics(ref mm) => mm.fmt_metrics(), TrBench(ref bs) => fmt_bench_samples(bs), @@ -773,6 +775,14 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec) -> io::Resu st.failed += 1; st.failures.push((test, stdout)); } + TrFailedMsg(msg) => { + st.failed += 1; + let mut stdout = stdout; + stdout.extend_from_slice( + format!("note: {}", msg).as_bytes() + ); + st.failures.push((test, stdout)); + } } Ok(()) } @@ -1270,12 +1280,16 @@ fn calc_result(desc: &TestDesc, task_result: Result<(), Box>) -> Tes match (&desc.should_panic, task_result) { (&ShouldPanic::No, Ok(())) | (&ShouldPanic::Yes, Err(_)) => TrOk, - (&ShouldPanic::YesWithMessage(msg), Err(ref err)) + (&ShouldPanic::YesWithMessage(msg), Err(ref err)) => if err.downcast_ref::() - .map(|e| &**e) - .or_else(|| err.downcast_ref::<&'static str>().map(|e| *e)) - .map(|e| e.contains(msg)) - .unwrap_or(false) => TrOk, + .map(|e| &**e) + .or_else(|| err.downcast_ref::<&'static str>().map(|e| *e)) + .map(|e| e.contains(msg)) + .unwrap_or(false) { + TrOk + } else { + TrFailedMsg(format!("Panic did not include expected string '{}'", msg)) + }, _ => TrFailed, } } @@ -1482,8 +1496,9 @@ pub mod bench { #[cfg(test)] mod tests { - use test::{TrFailed, TrIgnored, TrOk, filter_tests, parse_opts, TestDesc, TestDescAndFn, - TestOpts, run_test, MetricMap, StaticTestName, DynTestName, DynTestFn, ShouldPanic}; + use test::{TrFailed, TrFailedMsg, TrIgnored, TrOk, filter_tests, parse_opts, TestDesc, + TestDescAndFn, TestOpts, run_test, MetricMap, StaticTestName, DynTestName, + DynTestFn, ShouldPanic}; use std::sync::mpsc::channel; #[test] @@ -1565,18 +1580,20 @@ mod tests { fn f() { panic!("an error message"); } + let expected = "foobar"; + let failed_msg = "Panic did not include expected string"; let desc = TestDescAndFn { desc: TestDesc { name: StaticTestName("whatever"), ignore: false, - should_panic: ShouldPanic::YesWithMessage("foobar"), + should_panic: ShouldPanic::YesWithMessage(expected), }, testfn: DynTestFn(Box::new(move |()| f())), }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, desc, tx); let (_, res, _) = rx.recv().unwrap(); - assert!(res == TrFailed); + assert!(res == TrFailedMsg(format!("{} '{}'", failed_msg, expected))); } #[test] diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 60093e9bd37a..a5ba1d219c36 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -137,13 +137,20 @@ LLVMRustAddPass(LLVMPassManagerRef PM, LLVMPassRef rust_pass) { #define SUBTARGET_SYSTEMZ #endif +#ifdef LLVM_COMPONENT_MSP430 +#define SUBTARGET_MSP430 SUBTARGET(MSP430) +#else +#define SUBTARGET_MSP430 +#endif + #define GEN_SUBTARGETS \ SUBTARGET_X86 \ SUBTARGET_ARM \ SUBTARGET_AARCH64 \ SUBTARGET_MIPS \ SUBTARGET_PPC \ - SUBTARGET_SYSTEMZ + SUBTARGET_SYSTEMZ \ + SUBTARGET_MSP430 #define SUBTARGET(x) namespace llvm { \ extern const SubtargetFeatureKV x##FeatureKV[]; \ diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 369388caa049..7f0c7e2e5c9f 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -109,37 +109,84 @@ extern "C" LLVMTypeRef LLVMRustMetadataTypeInContext(LLVMContextRef C) { return wrap(Type::getMetadataTy(*unwrap(C))); } -extern "C" void LLVMRustAddCallSiteAttribute(LLVMValueRef Instr, unsigned index, uint64_t Val) { +static Attribute::AttrKind +from_rust(LLVMRustAttribute kind) { + switch (kind) { + case AlwaysInline: + return Attribute::AlwaysInline; + case ByVal: + return Attribute::ByVal; + case Cold: + return Attribute::Cold; + case InlineHint: + return Attribute::InlineHint; + case MinSize: + return Attribute::MinSize; + case Naked: + return Attribute::Naked; + case NoAlias: + return Attribute::NoAlias; + case NoCapture: + return Attribute::NoCapture; + case NoInline: + return Attribute::NoInline; + case NonNull: + return Attribute::NonNull; + case NoRedZone: + return Attribute::NoRedZone; + case NoReturn: + return Attribute::NoReturn; + case NoUnwind: + return Attribute::NoUnwind; + case OptimizeForSize: + return Attribute::OptimizeForSize; + case ReadOnly: + return Attribute::ReadOnly; + case SExt: + return Attribute::SExt; + case StructRet: + return Attribute::StructRet; + case UWTable: + return Attribute::UWTable; + case ZExt: + return Attribute::ZExt; + default: + llvm_unreachable("bad AttributeKind"); + } +} + +extern "C" LLVMAttributeRef LLVMRustCreateAttribute(LLVMContextRef C, LLVMRustAttribute Kind, uint64_t Val) { + return wrap(Attribute::get(*unwrap(C), from_rust(Kind), Val)); +} + +extern "C" void LLVMRustAddCallSiteAttribute(LLVMValueRef Instr, unsigned index, LLVMAttributeRef attr) { CallSite Call = CallSite(unwrap(Instr)); - AttrBuilder B; - B.addRawValue(Val); + AttrBuilder B(unwrap(attr)); Call.setAttributes( Call.getAttributes().addAttributes(Call->getContext(), index, AttributeSet::get(Call->getContext(), index, B))); } - extern "C" void LLVMRustAddDereferenceableCallSiteAttr(LLVMValueRef Instr, - unsigned idx, - uint64_t b) + unsigned index, + uint64_t bytes) { CallSite Call = CallSite(unwrap(Instr)); AttrBuilder B; - B.addDereferenceableAttr(b); + B.addDereferenceableAttr(bytes); Call.setAttributes( - Call.getAttributes().addAttributes(Call->getContext(), idx, + Call.getAttributes().addAttributes(Call->getContext(), index, AttributeSet::get(Call->getContext(), - idx, B))); + index, B))); } extern "C" void LLVMRustAddFunctionAttribute(LLVMValueRef Fn, unsigned index, - uint64_t Val) + LLVMAttributeRef attr) { Function *A = unwrap(Fn); - AttrBuilder B; - B.addRawValue(Val); + AttrBuilder B(unwrap(attr)); A->addAttributes(index, AttributeSet::get(A->getContext(), index, B)); } @@ -153,16 +200,6 @@ extern "C" void LLVMRustAddDereferenceableAttr(LLVMValueRef Fn, A->addAttributes(index, AttributeSet::get(A->getContext(), index, B)); } -extern "C" void LLVMRustAddFunctionAttrString(LLVMValueRef Fn, - unsigned index, - const char *Name) -{ - Function *F = unwrap(Fn); - AttrBuilder B; - B.addAttribute(Name); - F->addAttributes(index, AttributeSet::get(F->getContext(), index, B)); -} - extern "C" void LLVMRustAddFunctionAttrStringValue(LLVMValueRef Fn, unsigned index, const char *Name, @@ -175,31 +212,15 @@ extern "C" void LLVMRustAddFunctionAttrStringValue(LLVMValueRef Fn, extern "C" void LLVMRustRemoveFunctionAttributes(LLVMValueRef Fn, unsigned index, - uint64_t Val) + LLVMAttributeRef attr) { - Function *A = unwrap(Fn); - const AttributeSet PAL = A->getAttributes(); - AttrBuilder B(Val); + Function *F = unwrap(Fn); + const AttributeSet PAL = F->getAttributes(); + AttrBuilder B(unwrap(attr)); const AttributeSet PALnew = - PAL.removeAttributes(A->getContext(), index, - AttributeSet::get(A->getContext(), index, B)); - A->setAttributes(PALnew); -} - -extern "C" void LLVMRustRemoveFunctionAttrString(LLVMValueRef fn, - unsigned index, - const char *Name) -{ - Function *f = unwrap(fn); - LLVMContext &C = f->getContext(); - AttrBuilder B; - B.addAttribute(Name); - AttributeSet to_remove = AttributeSet::get(C, index, B); - - AttributeSet attrs = f->getAttributes(); - f->setAttributes(attrs.removeAttributes(f->getContext(), - index, - to_remove)); + PAL.removeAttributes(F->getContext(), index, + AttributeSet::get(F->getContext(), index, B)); + F->setAttributes(PALnew); } // enable fpmath flag UnsafeAlgebra @@ -1293,3 +1314,7 @@ extern "C" LLVMRustLinkage LLVMRustGetLinkage(LLVMValueRef V) { extern "C" void LLVMRustSetLinkage(LLVMValueRef V, LLVMRustLinkage RustLinkage) { LLVMSetLinkage(V, from_rust(RustLinkage)); } + +extern "C" LLVMContextRef LLVMRustGetValueContext(LLVMValueRef V) { + return wrap(&unwrap(V)->getContext()); +} diff --git a/src/rustllvm/rustllvm.h b/src/rustllvm/rustllvm.h index ffe94d1e22f2..346153d578c4 100644 --- a/src/rustllvm/rustllvm.h +++ b/src/rustllvm/rustllvm.h @@ -72,6 +72,28 @@ enum class LLVMRustResult { Failure }; +enum LLVMRustAttribute { + AlwaysInline = 0, + ByVal = 1, + Cold = 2, + InlineHint = 3, + MinSize = 4, + Naked = 5, + NoAlias = 6, + NoCapture = 7, + NoInline = 8, + NonNull = 9, + NoRedZone = 10, + NoReturn = 11, + NoUnwind = 12, + OptimizeForSize = 13, + ReadOnly = 14, + SExt = 15, + StructRet = 16, + UWTable = 17, + ZExt = 18, +}; + typedef struct OpaqueRustString *RustStringRef; typedef struct LLVMOpaqueTwine *LLVMTwineRef; typedef struct LLVMOpaqueDebugLoc *LLVMDebugLocRef; diff --git a/src/test/codegen/lifetime_start_end.rs b/src/test/codegen/lifetime_start_end.rs index 81f6cf309da5..e3b35cf35525 100644 --- a/src/test/codegen/lifetime_start_end.rs +++ b/src/test/codegen/lifetime_start_end.rs @@ -27,16 +27,16 @@ pub fn test() { let b = &Some(a); &b; // keep variable in an alloca -// CHECK: [[S_b:%[0-9]+]] = bitcast %"2.std::option::Option"** %b to i8* +// CHECK: [[S_b:%[0-9]+]] = bitcast %"core::option::Option"** %b to i8* // CHECK: call void @llvm.lifetime.start(i{{[0-9 ]+}}, i8* [[S_b]]) -// CHECK: [[S__5:%[0-9]+]] = bitcast %"2.std::option::Option"* %_5 to i8* +// CHECK: [[S__5:%[0-9]+]] = bitcast %"core::option::Option"* %_5 to i8* // CHECK: call void @llvm.lifetime.start(i{{[0-9 ]+}}, i8* [[S__5]]) -// CHECK: [[E__5:%[0-9]+]] = bitcast %"2.std::option::Option"* %_5 to i8* +// CHECK: [[E__5:%[0-9]+]] = bitcast %"core::option::Option"* %_5 to i8* // CHECK: call void @llvm.lifetime.end(i{{[0-9 ]+}}, i8* [[E__5]]) -// CHECK: [[E_b:%[0-9]+]] = bitcast %"2.std::option::Option"** %b to i8* +// CHECK: [[E_b:%[0-9]+]] = bitcast %"core::option::Option"** %b to i8* // CHECK: call void @llvm.lifetime.end(i{{[0-9 ]+}}, i8* [[E_b]]) } diff --git a/src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-a-b.rs b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-a-b.rs new file mode 100644 index 000000000000..8a92ca74f376 --- /dev/null +++ b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-a-b.rs @@ -0,0 +1,28 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// force-host +// no-prefer-dynamic + +#![feature(proc_macro, proc_macro_lib)] +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro_derive(A)] +pub fn derive_a(_: TokenStream) -> TokenStream { + "".parse().unwrap() +} + +#[proc_macro_derive(B)] +pub fn derive_b(_: TokenStream) -> TokenStream { + "".parse().unwrap() +} diff --git a/src/test/compile-fail-fulldeps/proc-macro/error-on-test.rs b/src/test/compile-fail-fulldeps/proc-macro/error-on-test.rs new file mode 100644 index 000000000000..1fd48f075deb --- /dev/null +++ b/src/test/compile-fail-fulldeps/proc-macro/error-on-test.rs @@ -0,0 +1,22 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: --test + +#![crate_type = "proc-macro"] +#![feature(proc_macro)] + +extern crate proc_macro; + +#[proc_macro_derive(A)] +//~^ ERROR: `--test` cannot be used with proc-macro crates +pub fn foo1(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + "".parse().unwrap() +} diff --git a/src/test/compile-fail-fulldeps/proc-macro/issue-37788.rs b/src/test/compile-fail-fulldeps/proc-macro/issue-37788.rs new file mode 100644 index 000000000000..6d1030026dba --- /dev/null +++ b/src/test/compile-fail-fulldeps/proc-macro/issue-37788.rs @@ -0,0 +1,21 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:derive-a-b.rs + +#![feature(proc_macro)] + +#[macro_use] +extern crate derive_a_b; + +fn main() { + // Test that constructing the `visible_parent_map` (in `cstore_impl.rs`) does not ICE. + std::cell::Cell::new(0) //~ ERROR mismatched types +} diff --git a/src/test/compile-fail/E0243.rs b/src/test/compile-fail/E0243.rs index 4434723e12f8..d20435a37ff5 100644 --- a/src/test/compile-fail/E0243.rs +++ b/src/test/compile-fail/E0243.rs @@ -10,8 +10,8 @@ struct Foo { x: T } struct Bar { x: Foo } - //~^ ERROR E0243 - //~| NOTE expected 1 type argument, found 0 + //~^ ERROR wrong number of type arguments: expected 1, found 0 [E0243] + //~| NOTE expected 1 type argument fn main() { } diff --git a/src/test/compile-fail/E0244.rs b/src/test/compile-fail/E0244.rs index 5678a7fd450d..02d4b337894b 100644 --- a/src/test/compile-fail/E0244.rs +++ b/src/test/compile-fail/E0244.rs @@ -10,8 +10,8 @@ struct Foo { x: bool } struct Bar { x: Foo } - //~^ ERROR E0244 - //~| NOTE expected no type arguments, found 2 + //~^ ERROR wrong number of type arguments: expected 0, found 2 [E0244] + //~| NOTE expected no type arguments fn main() { diff --git a/src/test/compile-fail/E0428.rs b/src/test/compile-fail/E0428.rs index 63b4efb73f0c..f8502140c440 100644 --- a/src/test/compile-fail/E0428.rs +++ b/src/test/compile-fail/E0428.rs @@ -9,11 +9,8 @@ // except according to those terms. struct Bar; //~ previous definition of `Bar` here - //~| previous definition of `Bar` here struct Bar; //~ ERROR E0428 //~| NOTE already defined - //~| ERROR E0428 - //~| NOTE already defined fn main () { } diff --git a/src/test/compile-fail/blind-item-block-item-shadow.rs b/src/test/compile-fail/blind-item-block-item-shadow.rs index 03af0d51ec29..2d53aee39e95 100644 --- a/src/test/compile-fail/blind-item-block-item-shadow.rs +++ b/src/test/compile-fail/blind-item-block-item-shadow.rs @@ -15,6 +15,5 @@ fn main() { struct Bar; use foo::Bar; //~^ ERROR a type named `Bar` has already been defined in this block - //~^^ ERROR a value named `Bar` has already been defined in this block } } diff --git a/src/test/compile-fail/cast-rfc0401.rs b/src/test/compile-fail/cast-rfc0401.rs index 0c373057c76e..1dbad9e30e3a 100644 --- a/src/test/compile-fail/cast-rfc0401.rs +++ b/src/test/compile-fail/cast-rfc0401.rs @@ -48,16 +48,13 @@ fn main() let _ = v as f32; //~^ ERROR casting - //~^^ HELP through a usize first let _ = main as f64; //~^ ERROR casting - //~^^ HELP through a usize first let _ = &v as usize; //~^ ERROR casting //~^^ HELP through a raw pointer first let _ = f as *const u8; //~^ ERROR casting - //~^^ HELP through a usize first let _ = 3_i32 as bool; //~^ ERROR cannot cast as `bool` [E0054] //~| unsupported cast @@ -80,13 +77,10 @@ fn main() let _ = false as *const u8; //~^ ERROR casting - //~^^ HELP through a usize first let _ = E::A as *const u8; //~^ ERROR casting - //~^^ HELP through a usize first let _ = 'a' as *const u8; //~^ ERROR casting - //~^^ HELP through a usize first let _ = 42usize as *const [u8]; //~ ERROR casting let _ = v as *const [u8]; //~ ERROR cannot cast diff --git a/src/test/compile-fail/coherence-error-suppression.rs b/src/test/compile-fail/coherence-error-suppression.rs new file mode 100644 index 000000000000..b33f27fbc8a0 --- /dev/null +++ b/src/test/compile-fail/coherence-error-suppression.rs @@ -0,0 +1,25 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// check that error types in coherence do not cause error cascades. + +trait Foo {} + +impl Foo for i8 {} +impl Foo for i16 {} +impl Foo for i32 {} +impl Foo for i64 {} +impl Foo for DoesNotExist {} //~ ERROR `DoesNotExist` is undefined +impl Foo for u8 {} +impl Foo for u16 {} +impl Foo for u32 {} +impl Foo for u64 {} + +fn main() {} diff --git a/src/test/compile-fail/crt-static-gated.rs b/src/test/compile-fail/crt-static-gated.rs new file mode 100644 index 000000000000..6c7c60b653a2 --- /dev/null +++ b/src/test/compile-fail/crt-static-gated.rs @@ -0,0 +1,14 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-C target-feature=+crt-static +// error-pattern: specifying the `crt-static` target feature is only allowed + +fn main() {} diff --git a/src/test/compile-fail/dep-graph-type-alias.rs b/src/test/compile-fail/dep-graph-type-alias.rs index 80cc9e71c7ab..2e33f11c04b4 100644 --- a/src/test/compile-fail/dep-graph-type-alias.rs +++ b/src/test/compile-fail/dep-graph-type-alias.rs @@ -42,8 +42,9 @@ trait Trait { struct SomeType; -#[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK +#[rustc_then_this_would_need(ItemSignature)] //~ ERROR no path impl SomeType { + #[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK fn method(&self, _: TypeAlias) {} } diff --git a/src/test/compile-fail/double-type-import.rs b/src/test/compile-fail/double-type-import.rs index 923f95e69d12..760612c05ce4 100644 --- a/src/test/compile-fail/double-type-import.rs +++ b/src/test/compile-fail/double-type-import.rs @@ -11,8 +11,7 @@ mod foo { pub use self::bar::X; use self::bar::X; - //~^ ERROR a value named `X` has already been imported in this module - //~| ERROR a type named `X` has already been imported in this module + //~^ ERROR a type named `X` has already been imported in this module mod bar { pub struct X; diff --git a/src/test/compile-fail/fat-ptr-cast.rs b/src/test/compile-fail/fat-ptr-cast.rs index b2fd11d4b39e..c62987a5b900 100644 --- a/src/test/compile-fail/fat-ptr-cast.rs +++ b/src/test/compile-fail/fat-ptr-cast.rs @@ -19,6 +19,9 @@ fn main() { a as usize; //~ ERROR casting //~^ HELP cast through a raw pointer first + a as isize; //~ ERROR casting + a as i16; //~ ERROR casting `&[i32]` as `i16` is invalid + a as u32; //~ ERROR casting `&[i32]` as `u32` is invalid b as usize; //~ ERROR non-scalar cast p as usize; //~^ ERROR casting diff --git a/src/test/compile-fail/generic-type-less-params-with-defaults.rs b/src/test/compile-fail/generic-type-less-params-with-defaults.rs index 9b1f3e51647c..9b19e09eeae7 100644 --- a/src/test/compile-fail/generic-type-less-params-with-defaults.rs +++ b/src/test/compile-fail/generic-type-less-params-with-defaults.rs @@ -17,6 +17,6 @@ struct Vec( fn main() { let _: Vec; - //~^ ERROR E0243 - //~| NOTE expected at least 1 type argument, found 0 + //~^ ERROR wrong number of type arguments: expected at least 1, found 0 [E0243] + //~| NOTE expected at least 1 type argument } diff --git a/src/test/compile-fail/generic-type-more-params-with-defaults.rs b/src/test/compile-fail/generic-type-more-params-with-defaults.rs index 8f733ddfce18..b5764ef89ab5 100644 --- a/src/test/compile-fail/generic-type-more-params-with-defaults.rs +++ b/src/test/compile-fail/generic-type-more-params-with-defaults.rs @@ -17,6 +17,6 @@ struct Vec( fn main() { let _: Vec; - //~^ ERROR E0244 - //~| NOTE expected at most 2 type arguments, found 3 + //~^ ERROR wrong number of type arguments: expected at most 2, found 3 [E0244] + //~| NOTE expected at most 2 type arguments } diff --git a/src/test/compile-fail/ifmt-bad-arg.rs b/src/test/compile-fail/ifmt-bad-arg.rs index 59c61a42e077..a23b4b077410 100644 --- a/src/test/compile-fail/ifmt-bad-arg.rs +++ b/src/test/compile-fail/ifmt-bad-arg.rs @@ -17,6 +17,7 @@ fn main() { //~^ ERROR: argument never used format!("{foo}"); //~ ERROR: no argument named `foo` + format!("", 1, 2); //~ ERROR: multiple unused formatting arguments format!("{}", 1, 2); //~ ERROR: argument never used format!("{1}", 1, 2); //~ ERROR: argument never used format!("{}", 1, foo=2); //~ ERROR: named argument never used @@ -53,4 +54,6 @@ fn main() { format!("foo } bar"); //~ ERROR: unmatched `}` found format!("foo }"); //~ ERROR: unmatched `}` found + + format!("foo %s baz", "bar"); //~ ERROR: argument never used } diff --git a/src/test/compile-fail/imports/auxiliary/two_macros.rs b/src/test/compile-fail/imports/auxiliary/two_macros.rs new file mode 100644 index 000000000000..2ac8e3ef983d --- /dev/null +++ b/src/test/compile-fail/imports/auxiliary/two_macros.rs @@ -0,0 +1,15 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[macro_export] +macro_rules! m { ($($t:tt)*) => { $($t)* } } + +#[macro_export] +macro_rules! n { ($($t:tt)*) => { $($t)* } } diff --git a/src/test/compile-fail/imports/duplicate.rs b/src/test/compile-fail/imports/duplicate.rs index fb61bb8e489b..faf85a523e8f 100644 --- a/src/test/compile-fail/imports/duplicate.rs +++ b/src/test/compile-fail/imports/duplicate.rs @@ -46,9 +46,9 @@ mod g { fn main() { e::foo(); f::foo(); //~ ERROR `foo` is ambiguous - //~| NOTE Consider adding an explicit import of `foo` to disambiguate + //~| NOTE consider adding an explicit import of `foo` to disambiguate g::foo(); //~ ERROR `foo` is ambiguous - //~| NOTE Consider adding an explicit import of `foo` to disambiguate + //~| NOTE consider adding an explicit import of `foo` to disambiguate } mod ambiguous_module_errors { diff --git a/src/test/compile-fail/imports/macros.rs b/src/test/compile-fail/imports/macros.rs new file mode 100644 index 000000000000..c11d2aab7c62 --- /dev/null +++ b/src/test/compile-fail/imports/macros.rs @@ -0,0 +1,55 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:two_macros.rs + +#![feature(item_like_imports, use_extern_macros)] + +extern crate two_macros; // two identity macros `m` and `n` + +mod foo { + pub use two_macros::n as m; +} + +mod m1 { + m!(use two_macros::*;); + use foo::m; // This shadows the glob import +} + +mod m2 { + use two_macros::*; //~ NOTE could also resolve + m! { //~ ERROR ambiguous + //~| NOTE macro-expanded macro imports do not shadow + use foo::m; //~ NOTE could resolve to the name imported here + //~^^^ NOTE in this expansion + } +} + +mod m3 { + use two_macros::m; //~ NOTE could also resolve + fn f() { + use two_macros::n as m; // This shadows the above import + m!(); + } + + fn g() { + m! { //~ ERROR ambiguous + //~| NOTE macro-expanded macro imports do not shadow + use two_macros::n as m; //~ NOTE could resolve to the name imported here + //~^^^ NOTE in this expansion + } + } +} + +mod m4 { + macro_rules! m { () => {} } //~ NOTE could resolve to the macro defined here + use two_macros::m; //~ NOTE could also resolve to the macro imported here + m!(); //~ ERROR ambiguous +} diff --git a/src/test/compile-fail/incr_comp_with_macro_export.rs b/src/test/compile-fail/incr_comp_with_macro_export.rs new file mode 100644 index 000000000000..eafef1723036 --- /dev/null +++ b/src/test/compile-fail/incr_comp_with_macro_export.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Zincremental=tmp/cfail-tests/incr_comp_with_macro_export +// must-compile-successfully + + +// This test case makes sure that we can compile with incremental compilation +// enabled when there are macros exported from this crate. (See #37756) + +#![crate_type="rlib"] + +#[macro_export] +macro_rules! some_macro { + ($e:expr) => ($e + 1) +} diff --git a/src/test/compile-fail/issue-14092.rs b/src/test/compile-fail/issue-14092.rs index df8707ab823e..85dd88e614fd 100644 --- a/src/test/compile-fail/issue-14092.rs +++ b/src/test/compile-fail/issue-14092.rs @@ -9,7 +9,7 @@ // except according to those terms. fn fn1(0: Box) {} - //~^ ERROR E0243 - //~| NOTE expected 1 type argument, found 0 + //~^ ERROR wrong number of type arguments: expected 1, found 0 [E0243] + //~| NOTE expected 1 type argument fn main() {} diff --git a/src/test/compile-fail/issue-17444.rs b/src/test/compile-fail/issue-17444.rs index c1d5827eb90c..dafcff238387 100644 --- a/src/test/compile-fail/issue-17444.rs +++ b/src/test/compile-fail/issue-17444.rs @@ -15,5 +15,4 @@ enum Test { fn main() { let _x = Test::Foo as *const isize; //~^ ERROR casting `Test` as `*const isize` is invalid - //~^^ HELP cast through a usize first } diff --git a/src/test/compile-fail/issue-21554.rs b/src/test/compile-fail/issue-21554.rs index 741707a47b60..1b87862a056d 100644 --- a/src/test/compile-fail/issue-21554.rs +++ b/src/test/compile-fail/issue-21554.rs @@ -13,5 +13,4 @@ struct Inches(i32); fn main() { Inches as f32; //~^ ERROR casting - //~^^ cast through a usize first } diff --git a/src/test/compile-fail/issue-23024.rs b/src/test/compile-fail/issue-23024.rs index e266f004317e..5d9b49f486c6 100644 --- a/src/test/compile-fail/issue-23024.rs +++ b/src/test/compile-fail/issue-23024.rs @@ -18,6 +18,6 @@ fn main() vfnfer.push(box h); println!("{:?}",(vfnfer[0] as Fn)(3)); //~^ ERROR the precise format of `Fn`-family traits' - //~| ERROR E0243 + //~| ERROR wrong number of type arguments: expected 1, found 0 [E0243] //~| ERROR the value of the associated type `Output` (from the trait `std::ops::FnOnce`) } diff --git a/src/test/compile-fail/issue-3214.rs b/src/test/compile-fail/issue-3214.rs index d3b932fbc53e..010cfb54c1ae 100644 --- a/src/test/compile-fail/issue-3214.rs +++ b/src/test/compile-fail/issue-3214.rs @@ -15,7 +15,6 @@ fn foo() { impl Drop for foo { //~^ ERROR wrong number of type arguments - //~^^ ERROR the type parameter `T` is not constrained fn drop(&mut self) {} } } diff --git a/src/test/compile-fail/issue-37131.rs b/src/test/compile-fail/issue-37131.rs new file mode 100644 index 000000000000..88c6eb7f515c --- /dev/null +++ b/src/test/compile-fail/issue-37131.rs @@ -0,0 +1,18 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Tests that compiling for a target which is not installed will result in a helpful +// error message. + +// compile-flags: --target=s390x-unknown-linux-gnu +// ignore s390x + +// error-pattern:target may not be installed +fn main() { } diff --git a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs index 6da87fca3f35..4323929e2e37 100644 --- a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs +++ b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs @@ -49,8 +49,6 @@ struct Baz<'x> { impl<'a> Baz<'a> { fn baz2<'b>(&self, x: &isize) -> (&'b isize, &'b isize) { - //~^ HELP consider using an explicit lifetime parameter as shown: fn baz2<'b>(&self, x: &' - // FIXME #35038: The above suggestion is different on Linux and Mac. (self.bar, x) //~ ERROR E0312 //~^ ERROR E0312 } diff --git a/src/test/compile-fail/link-cfg-gated.rs b/src/test/compile-fail/link-cfg-gated.rs new file mode 100644 index 000000000000..27918a27caf5 --- /dev/null +++ b/src/test/compile-fail/link-cfg-gated.rs @@ -0,0 +1,15 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[link(name = "foo", cfg(foo))] +//~^ ERROR: is feature gated +extern {} + +fn main() {} diff --git a/src/test/compile-fail/lint-unused-imports.rs b/src/test/compile-fail/lint-unused-imports.rs index 3f91c3e1e5c7..5b1c04946a40 100644 --- a/src/test/compile-fail/lint-unused-imports.rs +++ b/src/test/compile-fail/lint-unused-imports.rs @@ -17,8 +17,9 @@ use std::mem::*; // shouldn't get errors for not using // everything imported // Should get errors for both 'Some' and 'None' -use std::option::Option::{Some, None}; //~ ERROR unused import: `Some` - //~^ ERROR unused import: `None` +use std::option::Option::{Some, None}; +//~^ ERROR unused imports: `None`, `Some` +//~| ERROR unused imports: `None`, `Some` use test::A; //~ ERROR unused import: `test::A` // Be sure that if we just bring some methods into scope that they're also diff --git a/src/test/compile-fail/no-method-suggested-traits.rs b/src/test/compile-fail/no-method-suggested-traits.rs index 9ccc7cc75ad5..ea8796d38f93 100644 --- a/src/test/compile-fail/no-method-suggested-traits.rs +++ b/src/test/compile-fail/no-method-suggested-traits.rs @@ -34,31 +34,31 @@ fn main() { 1u32.method(); //~^ HELP following traits are implemented but not in scope, perhaps add a `use` for one of them //~^^ ERROR no method named - //~^^^ HELP `use foo::Bar` - //~^^^^ HELP `use no_method_suggested_traits::foo::PubPub` + //~^^^ HELP `use foo::Bar;` + //~^^^^ HELP `use no_method_suggested_traits::foo::PubPub;` std::rc::Rc::new(&mut Box::new(&1u32)).method(); //~^ HELP following traits are implemented but not in scope, perhaps add a `use` for one of them //~^^ ERROR no method named - //~^^^ HELP `use foo::Bar` - //~^^^^ HELP `use no_method_suggested_traits::foo::PubPub` + //~^^^ HELP `use foo::Bar;` + //~^^^^ HELP `use no_method_suggested_traits::foo::PubPub;` 'a'.method(); //~^ ERROR no method named //~^^ HELP the following trait is implemented but not in scope, perhaps add a `use` for it: - //~^^^ HELP `use foo::Bar` + //~^^^ HELP `use foo::Bar;` std::rc::Rc::new(&mut Box::new(&'a')).method(); //~^ ERROR no method named //~^^ HELP the following trait is implemented but not in scope, perhaps add a `use` for it: - //~^^^ HELP `use foo::Bar` + //~^^^ HELP `use foo::Bar;` 1i32.method(); //~^ ERROR no method named //~^^ HELP the following trait is implemented but not in scope, perhaps add a `use` for it: - //~^^^ HELP `use no_method_suggested_traits::foo::PubPub` + //~^^^ HELP `use no_method_suggested_traits::foo::PubPub;` std::rc::Rc::new(&mut Box::new(&1i32)).method(); //~^ ERROR no method named //~^^ HELP the following trait is implemented but not in scope, perhaps add a `use` for it: - //~^^^ HELP `use no_method_suggested_traits::foo::PubPub` + //~^^^ HELP `use no_method_suggested_traits::foo::PubPub;` Foo.method(); //~^ ERROR no method named diff --git a/src/test/compile-fail/typeck-builtin-bound-type-parameters.rs b/src/test/compile-fail/typeck-builtin-bound-type-parameters.rs index 41242a44f58b..0d98e044ab04 100644 --- a/src/test/compile-fail/typeck-builtin-bound-type-parameters.rs +++ b/src/test/compile-fail/typeck-builtin-bound-type-parameters.rs @@ -9,16 +9,16 @@ // except according to those terms. fn foo1, U>(x: T) {} -//~^ ERROR E0244 -//~| NOTE expected no type arguments, found 1 +//~^ ERROR wrong number of type arguments: expected 0, found 1 [E0244] +//~| NOTE expected no type arguments trait Trait: Copy {} -//~^ ERROR E0244 -//~| NOTE expected no type arguments, found 1 +//~^ ERROR wrong number of type arguments: expected 0, found 1 [E0244] +//~| NOTE expected no type arguments struct MyStruct1>; -//~^ ERROR E0244 -//~| NOTE expected no type arguments, found 1 +//~^ ERROR wrong number of type arguments: expected 0, found 1 [E0244] +//~| NOTE expected no type arguments struct MyStruct2<'a, T: Copy<'a>>; //~^ ERROR: wrong number of lifetime parameters: expected 0, found 1 @@ -26,8 +26,8 @@ struct MyStruct2<'a, T: Copy<'a>>; fn foo2<'a, T:Copy<'a, U>, U>(x: T) {} -//~^ ERROR E0244 -//~| NOTE expected no type arguments, found 1 +//~^ ERROR wrong number of type arguments: expected 0, found 1 [E0244] +//~| NOTE expected no type arguments //~| ERROR: wrong number of lifetime parameters: expected 0, found 1 //~| NOTE unexpected lifetime parameter diff --git a/src/test/compile-fail/typeck-cast-pointer-to-float.rs b/src/test/compile-fail/typeck-cast-pointer-to-float.rs index 2277b1bad776..3f8b8f49cb30 100644 --- a/src/test/compile-fail/typeck-cast-pointer-to-float.rs +++ b/src/test/compile-fail/typeck-cast-pointer-to-float.rs @@ -12,5 +12,4 @@ fn main() { let x : i16 = 22; ((&x) as *const i16) as f32; //~^ ERROR casting `*const i16` as `f32` is invalid - //~^^ HELP cast through a usize first } diff --git a/src/test/compile-fail/typeck_type_placeholder_lifetime_1.rs b/src/test/compile-fail/typeck_type_placeholder_lifetime_1.rs index f40445a030e0..ad57752b6f75 100644 --- a/src/test/compile-fail/typeck_type_placeholder_lifetime_1.rs +++ b/src/test/compile-fail/typeck_type_placeholder_lifetime_1.rs @@ -17,6 +17,6 @@ struct Foo<'a, T:'a> { pub fn main() { let c: Foo<_, _> = Foo { r: &5 }; - //~^ ERROR E0244 - //~| NOTE expected 1 type argument, found 2 + //~^ ERROR wrong number of type arguments: expected 1, found 2 [E0244] + //~| NOTE expected 1 type argument } diff --git a/src/test/compile-fail/typeck_type_placeholder_lifetime_2.rs b/src/test/compile-fail/typeck_type_placeholder_lifetime_2.rs index 47898690fcce..f1ecad0056e9 100644 --- a/src/test/compile-fail/typeck_type_placeholder_lifetime_2.rs +++ b/src/test/compile-fail/typeck_type_placeholder_lifetime_2.rs @@ -17,6 +17,6 @@ struct Foo<'a, T:'a> { pub fn main() { let c: Foo<_, usize> = Foo { r: &5 }; - //~^ ERROR E0244 - //~| NOTE expected 1 type argument, found 2 + //~^ ERROR wrong number of type arguments: expected 1, found 2 [E0244] + //~| NOTE expected 1 type argument } diff --git a/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs b/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs index 50f4f3b98b33..95d78c075017 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs @@ -13,8 +13,8 @@ trait Trait {} fn f isize>(x: F) {} -//~^ ERROR E0244 -//~| NOTE expected no type arguments, found 1 +//~^ ERROR wrong number of type arguments: expected 0, found 1 [E0244] +//~| NOTE expected no type arguments //~| ERROR E0220 //~| NOTE associated type `Output` not found diff --git a/src/test/compile-fail/variant-namespacing.rs b/src/test/compile-fail/variant-namespacing.rs index a8bb94b78fcc..3d8e2daaa15b 100644 --- a/src/test/compile-fail/variant-namespacing.rs +++ b/src/test/compile-fail/variant-namespacing.rs @@ -33,17 +33,11 @@ const XUnit: u8 = 0; extern crate variant_namespacing; pub use variant_namespacing::XE::*; //~^ ERROR `XStruct` has already been defined -//~| ERROR `XStruct` has already been defined //~| ERROR `XTuple` has already been defined -//~| ERROR `XTuple` has already been defined -//~| ERROR `XUnit` has already been defined //~| ERROR `XUnit` has already been defined pub use E::*; //~^ ERROR `Struct` has already been defined -//~| ERROR `Struct` has already been defined //~| ERROR `Tuple` has already been defined -//~| ERROR `Tuple` has already been defined -//~| ERROR `Unit` has already been defined //~| ERROR `Unit` has already been defined fn main() {} diff --git a/src/test/debuginfo/vec-slices.rs b/src/test/debuginfo/vec-slices.rs index 5553f8427e90..d321df8431b8 100644 --- a/src/test/debuginfo/vec-slices.rs +++ b/src/test/debuginfo/vec-slices.rs @@ -21,21 +21,21 @@ // gdb-command:print singleton.length // gdb-check:$2 = 1 -// gdbg-command:print *((int64_t[1]*)(singleton.data_ptr)) +// gdbg-command:print *((i64[1]*)(singleton.data_ptr)) // gdbr-command:print *(singleton.data_ptr as &[i64; 1]) // gdbg-check:$3 = {1} // gdbr-check:$3 = [1] // gdb-command:print multiple.length // gdb-check:$4 = 4 -// gdbg-command:print *((int64_t[4]*)(multiple.data_ptr)) +// gdbg-command:print *((i64[4]*)(multiple.data_ptr)) // gdbr-command:print *(multiple.data_ptr as &[i64; 4]) // gdbg-check:$5 = {2, 3, 4, 5} // gdbr-check:$5 = [2, 3, 4, 5] // gdb-command:print slice_of_slice.length // gdb-check:$6 = 2 -// gdbg-command:print *((int64_t[2]*)(slice_of_slice.data_ptr)) +// gdbg-command:print *((i64[2]*)(slice_of_slice.data_ptr)) // gdbr-command:print *(slice_of_slice.data_ptr as &[i64; 2]) // gdbg-check:$7 = {3, 4} // gdbr-check:$7 = [3, 4] @@ -61,14 +61,14 @@ // gdbg-command:print 'vec_slices::MUT_VECT_SLICE'.length // gdbr-command:print MUT_VECT_SLICE.length // gdb-check:$14 = 2 -// gdbg-command:print *((int64_t[2]*)('vec_slices::MUT_VECT_SLICE'.data_ptr)) +// gdbg-command:print *((i64[2]*)('vec_slices::MUT_VECT_SLICE'.data_ptr)) // gdbr-command:print *(MUT_VECT_SLICE.data_ptr as &[i64; 2]) // gdbg-check:$15 = {64, 65} // gdbr-check:$15 = [64, 65] //gdb-command:print mut_slice.length //gdb-check:$16 = 5 -//gdbg-command:print *((int64_t[5]*)(mut_slice.data_ptr)) +//gdbg-command:print *((i64[5]*)(mut_slice.data_ptr)) //gdbr-command:print *(mut_slice.data_ptr as &[i64; 5]) //gdbg-check:$17 = {1, 2, 3, 4, 5} //gdbr-check:$17 = [1, 2, 3, 4, 5] diff --git a/src/test/incremental/change_private_fn_cc/struct_point.rs b/src/test/incremental/change_private_fn_cc/struct_point.rs index d6d2b5436ff3..ded87dd27f41 100644 --- a/src/test/incremental/change_private_fn_cc/struct_point.rs +++ b/src/test/incremental/change_private_fn_cc/struct_point.rs @@ -23,10 +23,7 @@ #![rustc_partition_reused(module="struct_point-fn_calls_methods_in_another_impl", cfg="rpass2")] #![rustc_partition_reused(module="struct_point-fn_read_field", cfg="rpass2")] #![rustc_partition_reused(module="struct_point-fn_write_field", cfg="rpass2")] - -// FIXME(#37335) -- should be reused, but an errant Krate edge causes -// it to get translated (at least I *think* this is that same problem) -#![rustc_partition_translated(module="struct_point-fn_make_struct", cfg="rpass2")] +#![rustc_partition_reused(module="struct_point-fn_make_struct", cfg="rpass2")] extern crate point; diff --git a/src/test/incremental/change_private_impl_method/struct_point.rs b/src/test/incremental/change_private_impl_method/struct_point.rs index 8fa34bde1705..46e5a88eef94 100644 --- a/src/test/incremental/change_private_impl_method/struct_point.rs +++ b/src/test/incremental/change_private_impl_method/struct_point.rs @@ -20,9 +20,8 @@ #![rustc_partition_translated(module="struct_point-point", cfg="rpass2")] -// FIXME(#37121) -- the following two modules *should* be reused but are not -#![rustc_partition_translated(module="struct_point-fn_calls_methods_in_same_impl", cfg="rpass2")] -#![rustc_partition_translated(module="struct_point-fn_calls_methods_in_another_impl", cfg="rpass2")] +#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_same_impl", cfg="rpass2")] +#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_another_impl", cfg="rpass2")] #![rustc_partition_reused(module="struct_point-fn_make_struct", cfg="rpass2")] #![rustc_partition_reused(module="struct_point-fn_read_field", cfg="rpass2")] #![rustc_partition_reused(module="struct_point-fn_write_field", cfg="rpass2")] @@ -60,8 +59,7 @@ mod point { mod fn_calls_methods_in_same_impl { use point::Point; - // FIXME(#37121) -- we should not need to typeck this again - #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] pub fn check() { let x = Point { x: 2.0, y: 2.0 }; x.distance_from_origin(); @@ -72,8 +70,7 @@ mod fn_calls_methods_in_same_impl { mod fn_calls_methods_in_another_impl { use point::Point; - // FIXME(#37121) -- we should not need to typeck this again - #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] pub fn check() { let mut x = Point { x: 2.0, y: 2.0 }; x.translate(3.0, 3.0); diff --git a/src/test/incremental/change_private_impl_method_cc/struct_point.rs b/src/test/incremental/change_private_impl_method_cc/struct_point.rs index d8e5fbadad8b..bb7f7025c590 100644 --- a/src/test/incremental/change_private_impl_method_cc/struct_point.rs +++ b/src/test/incremental/change_private_impl_method_cc/struct_point.rs @@ -19,12 +19,13 @@ #![feature(stmt_expr_attributes)] #![allow(dead_code)] -// FIXME(#37333) -- the following modules *should* be reused but are not +#![rustc_partition_reused(module="struct_point-fn_read_field", cfg="rpass2")] +#![rustc_partition_reused(module="struct_point-fn_write_field", cfg="rpass2")] +#![rustc_partition_reused(module="struct_point-fn_make_struct", cfg="rpass2")] + +// FIXME(#37720) these two should be reused, but data gets entangled across crates #![rustc_partition_translated(module="struct_point-fn_calls_methods_in_same_impl", cfg="rpass2")] #![rustc_partition_translated(module="struct_point-fn_calls_methods_in_another_impl", cfg="rpass2")] -#![rustc_partition_translated(module="struct_point-fn_make_struct", cfg="rpass2")] -#![rustc_partition_translated(module="struct_point-fn_read_field", cfg="rpass2")] -#![rustc_partition_translated(module="struct_point-fn_write_field", cfg="rpass2")] extern crate point; @@ -32,7 +33,7 @@ extern crate point; mod fn_calls_methods_in_same_impl { use point::Point; - // FIXME(#37333) -- we should not need to typeck this again + // FIXME(#37720) data gets entangled across crates #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] pub fn check() { let x = Point { x: 2.0, y: 2.0 }; @@ -44,9 +45,9 @@ mod fn_calls_methods_in_same_impl { mod fn_calls_methods_in_another_impl { use point::Point; - // FIXME(#37333) -- we should not need to typeck this again + // FIXME(#37720) data gets entangled across crates #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] - pub fn check() { + pub fn dirty() { let mut x = Point { x: 2.0, y: 2.0 }; x.translate(3.0, 3.0); } @@ -56,8 +57,7 @@ mod fn_calls_methods_in_another_impl { mod fn_make_struct { use point::Point; - // FIXME(#37333) -- we should not need to typeck this again - #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] pub fn make_origin() -> Point { Point { x: 2.0, y: 2.0 } } @@ -67,8 +67,7 @@ mod fn_make_struct { mod fn_read_field { use point::Point; - // FIXME(#37333) -- we should not need to typeck this again - #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] pub fn get_x(p: Point) -> f32 { p.x } @@ -78,8 +77,7 @@ mod fn_read_field { mod fn_write_field { use point::Point; - // FIXME(#37333) -- we should not need to typeck this again - #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] pub fn inc_x(p: &mut Point) { p.x += 1.0; } diff --git a/src/test/incremental/hashes/call_expressions.rs b/src/test/incremental/hashes/call_expressions.rs new file mode 100644 index 000000000000..d2030d935546 --- /dev/null +++ b/src/test/incremental/hashes/call_expressions.rs @@ -0,0 +1,203 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +// This test case tests the incremental compilation hash (ICH) implementation +// for function and method call expressions. + +// The general pattern followed here is: Change one thing between rev1 and rev2 +// and make sure that the hash has changed, then change nothing between rev2 and +// rev3 and make sure that the hash has not changed. + +// must-compile-successfully +// revisions: cfail1 cfail2 cfail3 +// compile-flags: -Z query-dep-graph + + +#![allow(warnings)] +#![feature(rustc_attrs)] +#![crate_type="rlib"] + +fn callee1(_x: u32, _y: i64) {} +fn callee2(_x: u32, _y: i64) {} + + +// Change Callee (Function) ---------------------------------------------------- +#[cfg(cfail1)] +pub fn change_callee_function() { + callee1(1, 2) +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_callee_function() { + callee2(1, 2) +} + + + +// Change Argument (Function) -------------------------------------------------- +#[cfg(cfail1)] +pub fn change_argument_function() { + callee1(1, 2) +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_argument_function() { + callee1(1, 3) +} + + + +// Change Callee Indirectly (Function) ----------------------------------------- +mod change_callee_indirectly_function { + #[cfg(cfail1)] + use super::callee1 as callee; + #[cfg(not(cfail1))] + use super::callee2 as callee; + + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + pub fn change_callee_indirectly_function() { + callee(1, 2) + } +} + + +struct Struct; +impl Struct { + fn method1(&self, _x: char, _y: bool) {} + fn method2(&self, _x: char, _y: bool) {} +} + +// Change Callee (Method) ------------------------------------------------------ +#[cfg(cfail1)] +pub fn change_callee_method() { + let s = Struct; + s.method1('x', true); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_callee_method() { + let s = Struct; + s.method2('x', true); +} + + + +// Change Argument (Method) ---------------------------------------------------- +#[cfg(cfail1)] +pub fn change_argument_method() { + let s = Struct; + s.method1('x', true); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_argument_method() { + let s = Struct; + s.method1('y', true); +} + + + +// Change Callee (Method, UFCS) ------------------------------------------------ +#[cfg(cfail1)] +pub fn change_ufcs_callee_method() { + let s = Struct; + Struct::method1(&s, 'x', true); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_ufcs_callee_method() { + let s = Struct; + Struct::method2(&s, 'x', true); +} + + + +// Change Argument (Method, UFCS) ---------------------------------------------- +#[cfg(cfail1)] +pub fn change_argument_method_ufcs() { + let s = Struct; + Struct::method1(&s, 'x', true); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_argument_method_ufcs() { + let s = Struct; + Struct::method1(&s, 'x', false); +} + + + +// Change To UFCS -------------------------------------------------------------- +#[cfg(cfail1)] +pub fn change_to_ufcs() { + let s = Struct; + s.method1('x', true); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_to_ufcs() { + let s = Struct; + Struct::method1(&s, 'x', true); +} + + +struct Struct2; +impl Struct2 { + fn method1(&self, _x: char, _y: bool) {} +} + +// Change UFCS Callee Indirectly ----------------------------------------------- +mod change_ufcs_callee_indirectly { + #[cfg(cfail1)] + use super::Struct as Struct; + #[cfg(not(cfail1))] + use super::Struct2 as Struct; + + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + pub fn change_ufcs_callee_indirectly() { + let s = Struct; + Struct::method1(&s, 'q', false) + } +} diff --git a/src/test/incremental/hashes/if_expressions.rs b/src/test/incremental/hashes/if_expressions.rs new file mode 100644 index 000000000000..ba6289f754ed --- /dev/null +++ b/src/test/incremental/hashes/if_expressions.rs @@ -0,0 +1,232 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +// This test case tests the incremental compilation hash (ICH) implementation +// for if expressions. + +// The general pattern followed here is: Change one thing between rev1 and rev2 +// and make sure that the hash has changed, then change nothing between rev2 and +// rev3 and make sure that the hash has not changed. + +// must-compile-successfully +// revisions: cfail1 cfail2 cfail3 +// compile-flags: -Z query-dep-graph + + +#![allow(warnings)] +#![feature(rustc_attrs)] +#![crate_type="rlib"] + +// Change condition (if) ------------------------------------------------------- +#[cfg(cfail1)] +pub fn change_condition(x: bool) -> u32 { + if x { + return 1 + } + + return 0 +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_condition(x: bool) -> u32 { + if !x { + return 1 + } + + return 0 +} + +// Change then branch (if) ----------------------------------------------------- +#[cfg(cfail1)] +pub fn change_then_branch(x: bool) -> u32 { + if x { + return 1 + } + + return 0 +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_then_branch(x: bool) -> u32 { + if x { + return 2 + } + + return 0 +} + + + +// Change else branch (if) ----------------------------------------------------- +#[cfg(cfail1)] +pub fn change_else_branch(x: bool) -> u32 { + if x { + 1 + } else { + 2 + } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_else_branch(x: bool) -> u32 { + if x { + 1 + } else { + 3 + } +} + + + +// Add else branch (if) -------------------------------------------------------- +#[cfg(cfail1)] +pub fn add_else_branch(x: bool) -> u32 { + let mut ret = 1; + + if x { + ret += 1; + } + + ret +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn add_else_branch(x: bool) -> u32 { + let mut ret = 1; + + if x { + ret += 1; + } else { + } + + ret +} + + + +// Change condition (if let) --------------------------------------------------- +#[cfg(cfail1)] +pub fn change_condition_if_let(x: Option) -> u32 { + if let Some(_x) = x { + return 1 + } + + 0 +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_condition_if_let(x: Option) -> u32 { + if let Some(_) = x { + return 1 + } + + 0 +} + + + +// Change then branch (if let) ------------------------------------------------- +#[cfg(cfail1)] +pub fn change_then_branch_if_let(x: Option) -> u32 { + if let Some(x) = x { + return x + } + + 0 +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_then_branch_if_let(x: Option) -> u32 { + if let Some(x) = x { + return x + 1 + } + + 0 +} + + + +// Change else branch (if let) ------------------------------------------------- +#[cfg(cfail1)] +pub fn change_else_branch_if_let(x: Option) -> u32 { + if let Some(x) = x { + x + } else { + 1 + } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_else_branch_if_let(x: Option) -> u32 { + if let Some(x) = x { + x + } else { + 2 + } +} + + + +// Add else branch (if let) ---------------------------------------------------- +#[cfg(cfail1)] +pub fn add_else_branch_if_let(x: Option) -> u32 { + let mut ret = 1; + + if let Some(x) = x { + ret += x; + } + + ret +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn add_else_branch_if_let(x: Option) -> u32 { + let mut ret = 1; + + if let Some(x) = x { + ret += x; + } else { + } + + ret +} diff --git a/src/test/incremental/hashes/inherent_impls.rs b/src/test/incremental/hashes/inherent_impls.rs new file mode 100644 index 000000000000..f7a390e87450 --- /dev/null +++ b/src/test/incremental/hashes/inherent_impls.rs @@ -0,0 +1,128 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +// This test case tests the incremental compilation hash (ICH) implementation +// for let expressions. + +// The general pattern followed here is: Change one thing between rev1 and rev2 +// and make sure that the hash has changed, then change nothing between rev2 and +// rev3 and make sure that the hash has not changed. + +// must-compile-successfully +// revisions: cfail1 cfail2 cfail3 +// compile-flags: -Z query-dep-graph + + +#![allow(warnings)] +#![feature(rustc_attrs)] +#![crate_type="rlib"] + +struct Foo; + +// Change Method Name ----------------------------------------------------------- +#[cfg(cfail1)] +impl Foo { + pub fn method_name() { } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl Foo { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + pub fn method_name2() { } +} + +// Change Method Body ----------------------------------------------------------- +// +// This should affect the method itself, but not the impl. +#[cfg(cfail1)] +impl Foo { + pub fn method_body() { } +} + +#[cfg(not(cfail1))] +#[rustc_clean(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl Foo { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + pub fn method_body() { + println!("Hello, world!"); + } +} + +// Change Method Privacy ----------------------------------------------------------- +#[cfg(cfail1)] +impl Foo { + pub fn method_privacy() { } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl Foo { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + fn method_privacy() { } +} + +// Change Method Selfness ----------------------------------------------------------- +#[cfg(cfail1)] +impl Foo { + pub fn method_selfness() { } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl Foo { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + pub fn method_selfness(&self) { } +} + +// Change Method Selfmutness ----------------------------------------------------------- +#[cfg(cfail1)] +impl Foo { + pub fn method_selfmutness(&self) { } +} + +#[cfg(not(cfail1))] +#[rustc_clean(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl Foo { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + pub fn method_selfmutness(&mut self) { } +} + diff --git a/src/test/incremental/hashes/trait_impls.rs b/src/test/incremental/hashes/trait_impls.rs new file mode 100644 index 000000000000..500aaf52324b --- /dev/null +++ b/src/test/incremental/hashes/trait_impls.rs @@ -0,0 +1,404 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +// This test case tests the incremental compilation hash (ICH) implementation +// for let expressions. + +// The general pattern followed here is: Change one thing between rev1 and rev2 +// and make sure that the hash has changed, then change nothing between rev2 and +// rev3 and make sure that the hash has not changed. + +// must-compile-successfully +// revisions: cfail1 cfail2 cfail3 +// compile-flags: -Z query-dep-graph + + +#![allow(warnings)] +#![feature(rustc_attrs)] +#![feature(specialization)] +#![crate_type="rlib"] + +struct Foo; + +// Change Method Name ----------------------------------------------------------- + +#[cfg(cfail1)] +pub trait ChangeMethodNameTrait { + fn method_name(); +} + +#[cfg(cfail1)] +impl ChangeMethodNameTrait for Foo { + fn method_name() { } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub trait ChangeMethodNameTrait { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + fn method_name2(); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl ChangeMethodNameTrait for Foo { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + fn method_name2() { } +} + +// Change Method Body ----------------------------------------------------------- +// +// This should affect the method itself, but not the trait. + +pub trait ChangeMethodBodyTrait { + fn method_name(); +} + +#[cfg(cfail1)] +impl ChangeMethodBodyTrait for Foo { + fn method_name() { } +} + +#[cfg(not(cfail1))] +#[rustc_clean(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl ChangeMethodBodyTrait for Foo { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + fn method_name() { + () + } +} + +// Change Method Selfness ----------------------------------------------------------- + +#[cfg(cfail1)] +pub trait ChangeMethodSelfnessTrait { + fn method_name(); +} + +#[cfg(cfail1)] +impl ChangeMethodSelfnessTrait for Foo { + fn method_name() { } +} + +#[cfg(not(cfail1))] +pub trait ChangeMethodSelfnessTrait { + fn method_name(&self); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl ChangeMethodSelfnessTrait for Foo { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + fn method_name(&self) { + () + } +} + +// Change Method Selfness ----------------------------------------------------------- + +#[cfg(cfail1)] +pub trait RemoveMethodSelfnessTrait { + fn method_name(&self); +} + +#[cfg(cfail1)] +impl RemoveMethodSelfnessTrait for Foo { + fn method_name(&self) { } +} + +#[cfg(not(cfail1))] +pub trait RemoveMethodSelfnessTrait { + fn method_name(); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl RemoveMethodSelfnessTrait for Foo { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + fn method_name() { + () + } +} + +// Change Method Selfmutness ----------------------------------------------------------- + +#[cfg(cfail1)] +pub trait ChangeMethodSelfmutnessTrait { + fn method_name(&self); +} + +#[cfg(cfail1)] +impl ChangeMethodSelfmutnessTrait for Foo { + fn method_name(&self) { } +} + +#[cfg(not(cfail1))] +pub trait ChangeMethodSelfmutnessTrait { + fn method_name(&mut self); +} + +#[cfg(not(cfail1))] +#[rustc_clean(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl ChangeMethodSelfmutnessTrait for Foo { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + fn method_name(&mut self) { + () + } +} + +// Change item kind ----------------------------------------------------------- + +#[cfg(cfail1)] +pub trait ChangeItemKindTrait { + fn name(); +} + +#[cfg(cfail1)] +impl ChangeItemKindTrait for Foo { + fn name() { } +} + +#[cfg(not(cfail1))] +pub trait ChangeItemKindTrait { + type name; +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl ChangeItemKindTrait for Foo { + type name = (); +} + +// Remove item ----------------------------------------------------------- + +#[cfg(cfail1)] +pub trait RemoveItemTrait { + type TypeName; + fn method_name(); +} + +#[cfg(cfail1)] +impl RemoveItemTrait for Foo { + type TypeName = (); + fn method_name() { } +} + +#[cfg(not(cfail1))] +pub trait RemoveItemTrait { + type TypeName; +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl RemoveItemTrait for Foo { + type TypeName = (); +} + +// Add item ----------------------------------------------------------- + +#[cfg(cfail1)] +pub trait AddItemTrait { + type TypeName; +} + +#[cfg(cfail1)] +impl AddItemTrait for Foo { + type TypeName = (); +} + +#[cfg(not(cfail1))] +pub trait AddItemTrait { + type TypeName; + fn method_name(); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl AddItemTrait for Foo { + type TypeName = (); + fn method_name() { } +} + +// Change has-value ----------------------------------------------------------- + +#[cfg(cfail1)] +pub trait ChangeHasValueTrait { + fn method_name(); +} + +#[cfg(cfail1)] +impl ChangeHasValueTrait for Foo { + fn method_name() { } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub trait ChangeHasValueTrait { + fn method_name() { } +} + +#[cfg(not(cfail1))] +#[rustc_clean(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl ChangeHasValueTrait for Foo { + fn method_name() { } +} + +// Add default + +pub trait AddDefaultTrait { + fn method_name(); +} + +#[cfg(cfail1)] +impl AddDefaultTrait for Foo { + fn method_name() { } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl AddDefaultTrait for Foo { + default fn method_name() { } +} + +// Remove default + +pub trait RemoveDefaultTrait { + fn method_name(); +} + +#[cfg(cfail1)] +impl RemoveDefaultTrait for Foo { + default fn method_name() { } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl RemoveDefaultTrait for Foo { + fn method_name() { } +} + +// Add arguments + +#[cfg(cfail1)] +pub trait AddArgumentTrait { + fn method_name(&self); +} + +#[cfg(cfail1)] +impl AddArgumentTrait for Foo { + fn method_name(&self) { } +} + +#[cfg(not(cfail1))] +pub trait AddArgumentTrait { + fn method_name(&self, x: u32); +} + +#[cfg(not(cfail1))] +#[rustc_clean(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl AddArgumentTrait for Foo { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + fn method_name(&self, _x: u32) { } +} + +// Change argument type + +#[cfg(cfail1)] +pub trait ChangeArgumentTypeTrait { + fn method_name(&self, x: u32); +} + +#[cfg(cfail1)] +impl ChangeArgumentTypeTrait for Foo { + fn method_name(&self, _x: u32) { } +} + +#[cfg(not(cfail1))] +pub trait ChangeArgumentTypeTrait { + fn method_name(&self, x: char); +} + +#[cfg(not(cfail1))] +#[rustc_clean(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +impl ChangeArgumentTypeTrait for Foo { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + fn method_name(&self, _x: char) { } +} + diff --git a/src/test/incremental/hashes/type_defs.rs b/src/test/incremental/hashes/type_defs.rs new file mode 100644 index 000000000000..35fb583cd4ed --- /dev/null +++ b/src/test/incremental/hashes/type_defs.rs @@ -0,0 +1,249 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +// This test case tests the incremental compilation hash (ICH) implementation +// for `type` definitions. + +// The general pattern followed here is: Change one thing between rev1 and rev2 +// and make sure that the hash has changed, then change nothing between rev2 and +// rev3 and make sure that the hash has not changed. + +// We also test the ICH for `type` definitions exported in metadata. Same as +// above, we want to make sure that the change between rev1 and rev2 also +// results in a change of the ICH for the enum's metadata, and that it stays +// the same between rev2 and rev3. + +// must-compile-successfully +// revisions: cfail1 cfail2 cfail3 +// compile-flags: -Z query-dep-graph + +#![allow(warnings)] +#![feature(rustc_attrs)] +#![crate_type="rlib"] + + +// Change type (primitive) ----------------------------------------------------- +#[cfg(cfail1)] +type ChangePrimitiveType = i32; + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail3")] +type ChangePrimitiveType = i64; + + + +// Change mutability ----------------------------------------------------------- +#[cfg(cfail1)] +type ChangeMutability = &'static i32; + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail3")] +type ChangeMutability = &'static mut i32; + + + +// Change mutability ----------------------------------------------------------- +#[cfg(cfail1)] +type ChangeLifetime<'a> = (&'static i32, &'a i32); + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail3")] +type ChangeLifetime<'a> = (&'a i32, &'a i32); + + + +// Change type (struct) ----------------------------------------------------------- +struct Struct1; +struct Struct2; + +#[cfg(cfail1)] +type ChangeTypeStruct = Struct1; + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail3")] +type ChangeTypeStruct = Struct2; + + + +// Change type (tuple) --------------------------------------------------------- +#[cfg(cfail1)] +type ChangeTypeTuple = (u32, u64); + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail3")] +type ChangeTypeTuple = (u32, i64); + + + +// Change type (enum) ---------------------------------------------------------- +enum Enum1 { + Var1, + Var2, +} +enum Enum2 { + Var1, + Var2, +} + +#[cfg(cfail1)] +type ChangeTypeEnum = Enum1; + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail3")] +type ChangeTypeEnum = Enum2; + + + +// Add tuple field ------------------------------------------------------------- +#[cfg(cfail1)] +type AddTupleField = (i32, i64); + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail3")] +type AddTupleField = (i32, i64, i16); + + + +// Change nested tuple field --------------------------------------------------- +#[cfg(cfail1)] +type ChangeNestedTupleField = (i32, (i64, i16)); + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail3")] +type ChangeNestedTupleField = (i32, (i64, i8)); + + + +// Add type param -------------------------------------------------------------- +#[cfg(cfail1)] +type AddTypeParam = (T1, T1); + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail3")] +type AddTypeParam = (T1, T2); + + + +// Add type param bound -------------------------------------------------------- +#[cfg(cfail1)] +type AddTypeParamBound = (T1, u32); + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail3")] +type AddTypeParamBound = (T1, u32); + + + +// Add type param bound in where clause ---------------------------------------- +#[cfg(cfail1)] +type AddTypeParamBoundWhereClause where T1: Clone = (T1, u32); + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail3")] +type AddTypeParamBoundWhereClause where T1: Clone+Copy = (T1, u32); + + + +// Add lifetime param ---------------------------------------------------------- +#[cfg(cfail1)] +type AddLifetimeParam<'a> = (&'a u32, &'a u32); + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail3")] +type AddLifetimeParam<'a, 'b> = (&'a u32, &'b u32); + + + +// Add lifetime param bound ---------------------------------------------------- +#[cfg(cfail1)] +type AddLifetimeParamBound<'a, 'b> = (&'a u32, &'b u32); + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail3")] +type AddLifetimeParamBound<'a, 'b: 'a> = (&'a u32, &'b u32); + + + +// Add lifetime param bound in where clause ------------------------------------ +#[cfg(cfail1)] +type AddLifetimeParamBoundWhereClause<'a, 'b, 'c> +where 'b: 'a + = (&'a u32, &'b u32, &'c u32); + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail3")] +type AddLifetimeParamBoundWhereClause<'a, 'b, 'c> +where 'b: 'a, + 'c: 'a + = (&'a u32, &'b u32, &'c u32); + + + +// Change Trait Bound Indirectly ----------------------------------------------- +trait ReferencedTrait1 {} +trait ReferencedTrait2 {} + +mod change_trait_bound_indirectly { + #[cfg(cfail1)] + use super::ReferencedTrait1 as Trait; + #[cfg(not(cfail1))] + use super::ReferencedTrait2 as Trait; + + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + type ChangeTraitBoundIndirectly = (T, u32); +} + + + +// Change Trait Bound Indirectly In Where Clause ------------------------------- +mod change_trait_bound_indirectly_in_where_clause { + #[cfg(cfail1)] + use super::ReferencedTrait1 as Trait; + #[cfg(not(cfail1))] + use super::ReferencedTrait2 as Trait; + + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + type ChangeTraitBoundIndirectly where T : Trait = (T, u32); +} diff --git a/src/test/parse-fail/issue-37234.rs b/src/test/parse-fail/issue-37234.rs new file mode 100644 index 000000000000..651e11d9d21b --- /dev/null +++ b/src/test/parse-fail/issue-37234.rs @@ -0,0 +1,19 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +macro_rules! failed { + () => {{ + let x = 5 ""; //~ ERROR found `""` + }} //~ ERROR macro expansion ignores token `}` +} + +fn main() { + failed!(); +} diff --git a/src/test/parse-fail/where-clauses-no-bounds-or-predicates.rs b/src/test/parse-fail/where-clauses-no-bounds-or-predicates.rs index 45165b76c4af..78d974540873 100644 --- a/src/test/parse-fail/where-clauses-no-bounds-or-predicates.rs +++ b/src/test/parse-fail/where-clauses-no-bounds-or-predicates.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -20,5 +20,8 @@ fn equal2(_: &T, _: &T) -> bool where T: { true } +fn foo<'a>() where 'a {} +//~^ ERROR expected `:`, found `{` + fn main() { } diff --git a/src/test/run-fail/test-should-panic-bad-message.rs b/src/test/run-fail/test-should-panic-bad-message.rs new file mode 100644 index 000000000000..7186672b4049 --- /dev/null +++ b/src/test/run-fail/test-should-panic-bad-message.rs @@ -0,0 +1,19 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: --test + +// error-pattern:panicked at 'bar' +// check-stdout +#[test] +#[should_panic(expected = "foo")] +pub fn test_bar() { + panic!("bar") +} diff --git a/src/test/run-fail/test-should-panic-no-message.rs b/src/test/run-fail/test-should-panic-no-message.rs new file mode 100644 index 000000000000..50dc2aed8e9d --- /dev/null +++ b/src/test/run-fail/test-should-panic-no-message.rs @@ -0,0 +1,19 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: --test + +// error-pattern:panicked at 'explicit panic' +// check-stdout +#[test] +#[should_panic(expected = "foo")] +pub fn test_explicit() { + panic!() +} diff --git a/src/test/run-make/issue-37839/Makefile b/src/test/run-make/issue-37839/Makefile new file mode 100644 index 000000000000..f17ce537fb81 --- /dev/null +++ b/src/test/run-make/issue-37839/Makefile @@ -0,0 +1,6 @@ +-include ../tools.mk + +all: + $(RUSTC) a.rs && $(RUSTC) b.rs + $(BARE_RUSTC) c.rs -L dependency=$(TMPDIR) --extern b=$(TMPDIR)/libb.rlib \ + --out-dir=$(TMPDIR) diff --git a/src/test/run-make/issue-37839/a.rs b/src/test/run-make/issue-37839/a.rs new file mode 100644 index 000000000000..3dff45388c75 --- /dev/null +++ b/src/test/run-make/issue-37839/a.rs @@ -0,0 +1,13 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(proc_macro)] +#![allow(unused)] +#![crate_type = "proc-macro"] diff --git a/src/test/run-make/issue-37839/b.rs b/src/test/run-make/issue-37839/b.rs new file mode 100644 index 000000000000..82f48f6d8d66 --- /dev/null +++ b/src/test/run-make/issue-37839/b.rs @@ -0,0 +1,12 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "lib"] +#[macro_use] extern crate a; diff --git a/src/test/run-make/issue-37839/c.rs b/src/test/run-make/issue-37839/c.rs new file mode 100644 index 000000000000..85bece514279 --- /dev/null +++ b/src/test/run-make/issue-37839/c.rs @@ -0,0 +1,12 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "lib"] +extern crate b; diff --git a/src/test/run-make/link-cfg/Makefile b/src/test/run-make/link-cfg/Makefile new file mode 100644 index 000000000000..4abc0caa6986 --- /dev/null +++ b/src/test/run-make/link-cfg/Makefile @@ -0,0 +1,22 @@ +-include ../tools.mk + +all: $(call DYLIB,return1) $(call DYLIB,return2) $(call NATIVE_STATICLIB,return3) + ls $(TMPDIR) + $(RUSTC) --print cfg --target x86_64-unknown-linux-musl | grep crt-static + + $(RUSTC) no-deps.rs --cfg foo + $(call RUN,no-deps) + $(RUSTC) no-deps.rs --cfg bar + $(call RUN,no-deps) + + $(RUSTC) dep.rs + $(RUSTC) with-deps.rs --cfg foo + $(call RUN,with-deps) + $(RUSTC) with-deps.rs --cfg bar + $(call RUN,with-deps) + + $(RUSTC) dep-with-staticlib.rs + $(RUSTC) with-staticlib-deps.rs --cfg foo + $(call RUN,with-staticlib-deps) + $(RUSTC) with-staticlib-deps.rs --cfg bar + $(call RUN,with-staticlib-deps) diff --git a/src/test/run-make/link-cfg/dep-with-staticlib.rs b/src/test/run-make/link-cfg/dep-with-staticlib.rs new file mode 100644 index 000000000000..ecc2365ddb06 --- /dev/null +++ b/src/test/run-make/link-cfg/dep-with-staticlib.rs @@ -0,0 +1,18 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(link_cfg)] +#![crate_type = "rlib"] + +#[link(name = "return1", cfg(foo))] +#[link(name = "return3", kind = "static", cfg(bar))] +extern { + pub fn my_function() -> i32; +} diff --git a/src/test/run-make/link-cfg/dep.rs b/src/test/run-make/link-cfg/dep.rs new file mode 100644 index 000000000000..7da879c2bfa2 --- /dev/null +++ b/src/test/run-make/link-cfg/dep.rs @@ -0,0 +1,18 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(link_cfg)] +#![crate_type = "rlib"] + +#[link(name = "return1", cfg(foo))] +#[link(name = "return2", cfg(bar))] +extern { + pub fn my_function() -> i32; +} diff --git a/src/test/run-make/link-cfg/no-deps.rs b/src/test/run-make/link-cfg/no-deps.rs new file mode 100644 index 000000000000..6b1141067440 --- /dev/null +++ b/src/test/run-make/link-cfg/no-deps.rs @@ -0,0 +1,30 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(link_cfg)] + +#[link(name = "return1", cfg(foo))] +#[link(name = "return2", cfg(bar))] +extern { + fn my_function() -> i32; +} + +fn main() { + unsafe { + let v = my_function(); + if cfg!(foo) { + assert_eq!(v, 1); + } else if cfg!(bar) { + assert_eq!(v, 2); + } else { + panic!("unknown"); + } + } +} diff --git a/src/test/run-make/link-cfg/return1.c b/src/test/run-make/link-cfg/return1.c new file mode 100644 index 000000000000..a2a3d051dd14 --- /dev/null +++ b/src/test/run-make/link-cfg/return1.c @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#ifdef _WIN32 +__declspec(dllexport) +#endif +int my_function() { + return 1; +} diff --git a/src/test/run-make/link-cfg/return2.c b/src/test/run-make/link-cfg/return2.c new file mode 100644 index 000000000000..d6ddcccf2fb7 --- /dev/null +++ b/src/test/run-make/link-cfg/return2.c @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#ifdef _WIN32 +__declspec(dllexport) +#endif +int my_function() { + return 2; +} diff --git a/src/test/run-make/link-cfg/return3.c b/src/test/run-make/link-cfg/return3.c new file mode 100644 index 000000000000..6a3b695f2081 --- /dev/null +++ b/src/test/run-make/link-cfg/return3.c @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#ifdef _WIN32 +__declspec(dllexport) +#endif +int my_function() { + return 3; +} diff --git a/src/test/run-make/link-cfg/with-deps.rs b/src/test/run-make/link-cfg/with-deps.rs new file mode 100644 index 000000000000..799555c500a1 --- /dev/null +++ b/src/test/run-make/link-cfg/with-deps.rs @@ -0,0 +1,24 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate dep; + +fn main() { + unsafe { + let v = dep::my_function(); + if cfg!(foo) { + assert_eq!(v, 1); + } else if cfg!(bar) { + assert_eq!(v, 2); + } else { + panic!("unknown"); + } + } +} diff --git a/src/test/run-make/link-cfg/with-staticlib-deps.rs b/src/test/run-make/link-cfg/with-staticlib-deps.rs new file mode 100644 index 000000000000..33a9c7720e26 --- /dev/null +++ b/src/test/run-make/link-cfg/with-staticlib-deps.rs @@ -0,0 +1,24 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate dep_with_staticlib; + +fn main() { + unsafe { + let v = dep_with_staticlib::my_function(); + if cfg!(foo) { + assert_eq!(v, 1); + } else if cfg!(bar) { + assert_eq!(v, 3); + } else { + panic!("unknown"); + } + } +} diff --git a/src/test/run-make/missing-items/Makefile b/src/test/run-make/missing-items/Makefile deleted file mode 100644 index bcc9cdf2d652..000000000000 --- a/src/test/run-make/missing-items/Makefile +++ /dev/null @@ -1,10 +0,0 @@ --include ../tools.mk - -all: - $(RUSTC) m1.rs -C prefer-dynamic - $(RUSTC) m2.rs 2>&1 | grep "error\[E0046\]: not all trait items implemented, missing: .*" - $(RUSTC) m2.rs 2>&1 | grep " --> m2.rs:18:1" - $(RUSTC) m2.rs 2>&1 | grep " | ^ missing .CONSTANT., .Type., .method. in implementation" - $(RUSTC) m2.rs 2>&1 | grep " = note: .CONSTANT. from trait: .const CONSTANT: u32;." - $(RUSTC) m2.rs 2>&1 | grep " = note: .Type. from trait: .type Type;." - $(RUSTC) m2.rs 2>&1 | grep " = note: .method. from trait: .fn(&Self, std::string::String) -> ::Type." diff --git a/src/test/run-make/save-analysis/foo.rs b/src/test/run-make/save-analysis/foo.rs index e9ed897bf302..e8b69729af67 100644 --- a/src/test/run-make/save-analysis/foo.rs +++ b/src/test/run-make/save-analysis/foo.rs @@ -57,6 +57,12 @@ fn test_alias(i: Option<::Item>) { let y = x.1; } +// Issue #37700 +const LUT_BITS: usize = 3; +pub struct HuffmanTable { + ac_lut: Option<[(i16, u8); 1 << LUT_BITS]>, +} + struct TupStruct(isize, isize, Box); fn test_tup_struct(x: TupStruct) -> isize { diff --git a/src/test/run-pass/auxiliary/link-cfg-works-transitive-dylib.rs b/src/test/run-pass/auxiliary/link-cfg-works-transitive-dylib.rs new file mode 100644 index 000000000000..d41fd490f58e --- /dev/null +++ b/src/test/run-pass/auxiliary/link-cfg-works-transitive-dylib.rs @@ -0,0 +1,14 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(link_cfg)] + +#[link(name = "foo", cfg(foo))] +extern {} diff --git a/src/test/run-pass/auxiliary/link-cfg-works-transitive-rlib.rs b/src/test/run-pass/auxiliary/link-cfg-works-transitive-rlib.rs new file mode 100644 index 000000000000..9f096c351fbe --- /dev/null +++ b/src/test/run-pass/auxiliary/link-cfg-works-transitive-rlib.rs @@ -0,0 +1,17 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// no-prefer-dynamic + +#![feature(link_cfg)] +#![crate_type = "rlib"] + +#[link(name = "foo", cfg(foo))] +extern {} diff --git a/src/test/run-pass/crt-static-off-works.rs b/src/test/run-pass/crt-static-off-works.rs new file mode 100644 index 000000000000..c94c877c12c6 --- /dev/null +++ b/src/test/run-pass/crt-static-off-works.rs @@ -0,0 +1,17 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-C target-feature=-crt-static -Z unstable-options +// ignore-musl - requires changing the linker which is hard + +#![feature(cfg_target_feature)] + +#[cfg(not(target_feature = "crt-static"))] +fn main() {} diff --git a/src/test/run-pass/crt-static-on-works.rs b/src/test/run-pass/crt-static-on-works.rs new file mode 100644 index 000000000000..ae8e5f629704 --- /dev/null +++ b/src/test/run-pass/crt-static-on-works.rs @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-C target-feature=+crt-static -Z unstable-options + +#![feature(cfg_target_feature)] + +#[cfg(target_feature = "crt-static")] +fn main() {} diff --git a/src/test/run-pass/issue-37655.rs b/src/test/run-pass/issue-37655.rs new file mode 100644 index 000000000000..d229bcacc501 --- /dev/null +++ b/src/test/run-pass/issue-37655.rs @@ -0,0 +1,46 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Regression test for #37655. The problem was a false edge created by +// coercion that wound up requiring that `'a` (in `split()`) outlive +// `'b`, which shouldn't be necessary. + +#![allow(warnings)] + +trait SliceExt { + type Item; + + fn get_me(&self, index: I) -> &I::Output + where I: SliceIndex; +} + +impl SliceExt for [T] { + type Item = T; + + fn get_me(&self, index: I) -> &I::Output + where I: SliceIndex + { + panic!() + } +} + +pub trait SliceIndex { + type Output: ?Sized; +} + +impl SliceIndex for usize { + type Output = T; +} + +fn foo<'a, 'b>(split: &'b [&'a [u8]]) -> &'a [u8] { + split.get_me(0) +} + +fn main() { } diff --git a/src/test/run-pass/issue-37733.rs b/src/test/run-pass/issue-37733.rs new file mode 100644 index 000000000000..358b93254de9 --- /dev/null +++ b/src/test/run-pass/issue-37733.rs @@ -0,0 +1,15 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +type A = for<> fn(); + +type B = for<'a,> fn(); + +pub fn main() {} diff --git a/src/test/run-pass/link-cfg-works.rs b/src/test/run-pass/link-cfg-works.rs new file mode 100644 index 000000000000..7db948c7daa9 --- /dev/null +++ b/src/test/run-pass/link-cfg-works.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:link-cfg-works-transitive-rlib.rs +// aux-build:link-cfg-works-transitive-dylib.rs + +#![feature(link_cfg)] + +extern crate link_cfg_works_transitive_rlib; +extern crate link_cfg_works_transitive_dylib; + +#[link(name = "foo", cfg(foo))] +extern {} + +fn main() {} + diff --git a/src/test/run-pass/path-lookahead.rs b/src/test/run-pass/path-lookahead.rs new file mode 100644 index 000000000000..017259af190f --- /dev/null +++ b/src/test/run-pass/path-lookahead.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Parser test for #37765 + +fn with_parens(arg: T) -> String { //~WARN dead_code + return (::to_string(&arg)); //~WARN unused_parens +} + +fn no_parens(arg: T) -> String { //~WARN dead_code + return ::to_string(&arg); +} + +fn main() { + +} diff --git a/src/test/run-pass/test-should-panic-attr.rs b/src/test/run-pass/test-should-panic-attr.rs new file mode 100644 index 000000000000..2d068872a4d3 --- /dev/null +++ b/src/test/run-pass/test-should-panic-attr.rs @@ -0,0 +1,46 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: --test + +#[test] +#[should_panic = "foo"] +//~^ WARN: attribute must be of the form: +fn test1() { + panic!(); +} + +#[test] +#[should_panic(expected)] +//~^ WARN: argument must be of the form: +fn test2() { + panic!(); +} + +#[test] +#[should_panic(expect)] +//~^ WARN: argument must be of the form: +fn test3() { + panic!(); +} + +#[test] +#[should_panic(expected(foo, bar))] +//~^ WARN: argument must be of the form: +fn test4() { + panic!(); +} + +#[test] +#[should_panic(expected = "foo", bar)] +//~^ WARN: argument must be of the form: +fn test5() { + panic!(); +} diff --git a/src/test/rustdoc/inline_local/glob-extern-no-defaults.rs b/src/test/rustdoc/inline_local/glob-extern-no-defaults.rs new file mode 100644 index 000000000000..fd2fdd7b8d32 --- /dev/null +++ b/src/test/rustdoc/inline_local/glob-extern-no-defaults.rs @@ -0,0 +1,35 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: --no-defaults + +#![crate_name = "foo"] + +mod mod1 { + extern { + pub fn public_fn(); + fn private_fn(); + } +} + +pub use mod1::*; + +// @has foo/index.html +// @has - "mod1" +// @has - "public_fn" +// @!has - "private_fn" +// @has foo/fn.public_fn.html +// @!has foo/fn.private_fn.html + +// @has foo/mod1/index.html +// @has - "public_fn" +// @has - "private_fn" +// @has foo/mod1/fn.public_fn.html +// @has foo/mod1/fn.private_fn.html diff --git a/src/test/rustdoc/inline_local/glob-extern.rs b/src/test/rustdoc/inline_local/glob-extern.rs new file mode 100644 index 000000000000..cf899d7728c9 --- /dev/null +++ b/src/test/rustdoc/inline_local/glob-extern.rs @@ -0,0 +1,31 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_name = "foo"] + +mod mod1 { + extern { + pub fn public_fn(); + fn private_fn(); + } +} + +pub use mod1::*; + +// @has foo/index.html +// @!has - "mod1" +// @has - "public_fn" +// @!has - "private_fn" +// @has foo/fn.public_fn.html +// @!has foo/fn.private_fn.html + +// @!has foo/mod1/index.html +// @has foo/mod1/fn.public_fn.html +// @!has foo/mod1/fn.private_fn.html diff --git a/src/test/rustdoc/inline_local/glob-private-no-defaults.rs b/src/test/rustdoc/inline_local/glob-private-no-defaults.rs new file mode 100644 index 000000000000..420b60f2aca9 --- /dev/null +++ b/src/test/rustdoc/inline_local/glob-private-no-defaults.rs @@ -0,0 +1,58 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: --no-defaults + +#![crate_name = "foo"] + +mod mod1 { + mod mod2 { + pub struct Mod2Public; + struct Mod2Private; + } + pub use self::mod2::*; + + pub struct Mod1Public; + struct Mod1Private; +} +pub use mod1::*; + +// @has foo/index.html +// @has - "mod1" +// @has - "Mod1Public" +// @!has - "Mod1Private" +// @!has - "mod2" +// @has - "Mod2Public" +// @!has - "Mod2Private" +// @has foo/struct.Mod1Public.html +// @!has foo/struct.Mod1Private.html +// @has foo/struct.Mod2Public.html +// @!has foo/struct.Mod2Private.html + +// @has foo/mod1/index.html +// @has - "mod2" +// @has - "Mod1Public" +// @has - "Mod1Private" +// @!has - "Mod2Public" +// @!has - "Mod2Private" +// @has foo/mod1/struct.Mod1Public.html +// @has foo/mod1/struct.Mod1Private.html +// @!has foo/mod1/struct.Mod2Public.html +// @!has foo/mod1/struct.Mod2Private.html + +// @has foo/mod1/mod2/index.html +// @has - "Mod2Public" +// @has - "Mod2Private" +// @has foo/mod1/mod2/struct.Mod2Public.html +// @has foo/mod1/mod2/struct.Mod2Private.html + +// @!has foo/mod2/index.html +// @!has foo/mod2/struct.Mod2Public.html +// @!has foo/mod2/struct.Mod2Private.html diff --git a/src/test/rustdoc/inline_local/glob-private.rs b/src/test/rustdoc/inline_local/glob-private.rs new file mode 100644 index 000000000000..b5e256dfdce9 --- /dev/null +++ b/src/test/rustdoc/inline_local/glob-private.rs @@ -0,0 +1,49 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_name = "foo"] + +mod mod1 { + mod mod2 { + pub struct Mod2Public; + struct Mod2Private; + } + pub use self::mod2::*; + + pub struct Mod1Public; + struct Mod1Private; +} +pub use mod1::*; + +// @has foo/index.html +// @!has - "mod1" +// @has - "Mod1Public" +// @!has - "Mod1Private" +// @!has - "mod2" +// @has - "Mod2Public" +// @!has - "Mod2Private" +// @has foo/struct.Mod1Public.html +// @!has foo/struct.Mod1Private.html +// @has foo/struct.Mod2Public.html +// @!has foo/struct.Mod2Private.html + +// @!has foo/mod1/index.html +// @has foo/mod1/struct.Mod1Public.html +// @!has foo/mod1/struct.Mod1Private.html +// @!has foo/mod1/struct.Mod2Public.html +// @!has foo/mod1/struct.Mod2Private.html + +// @!has foo/mod1/mod2/index.html +// @has foo/mod1/mod2/struct.Mod2Public.html +// @!has foo/mod1/mod2/struct.Mod2Private.html + +// @!has foo/mod2/index.html +// @!has foo/mod2/struct.Mod2Public.html +// @!has foo/mod2/struct.Mod2Private.html diff --git a/src/test/rustdoc/issue-32374.rs b/src/test/rustdoc/issue-32374.rs index 262a1ffce747..dea73317e5e3 100644 --- a/src/test/rustdoc/issue-32374.rs +++ b/src/test/rustdoc/issue-32374.rs @@ -20,6 +20,16 @@ // 'Deprecated since 1.0.0: text' // @has - 'test' // @has - '#32374' +// @matches issue_32374/struct.T.html '//*[@class="stab unstable"]' \ +// 'Unstable \(test #32374\)$' #[rustc_deprecated(since = "1.0.0", reason = "text")] #[unstable(feature = "test", issue = "32374")] pub struct T; + +// @has issue_32374/struct.U.html '//*[@class="stab deprecated"]' \ +// 'Deprecated since 1.0.0: deprecated' +// @has issue_32374/struct.U.html '//*[@class="stab unstable"]' \ +// 'Unstable (test #32374): unstable' +#[rustc_deprecated(since = "1.0.0", reason = "deprecated")] +#[unstable(feature = "test", issue = "32374", reason = "unstable")] +pub struct U; diff --git a/src/test/rustdoc/line-breaks.rs b/src/test/rustdoc/line-breaks.rs index cc608a244757..a1eabb515a5c 100644 --- a/src/test/rustdoc/line-breaks.rs +++ b/src/test/rustdoc/line-breaks.rs @@ -10,6 +10,9 @@ #![crate_name = "foo"] +use std::ops::Add; +use std::fmt::Display; + //@count foo/fn.function_with_a_really_long_name.html //pre/br 2 pub fn function_with_a_really_long_name(parameter_one: i32, parameter_two: i32) @@ -19,3 +22,19 @@ pub fn function_with_a_really_long_name(parameter_one: i32, //@count foo/fn.short_name.html //pre/br 0 pub fn short_name(param: i32) -> i32 { param + 1 } + +//@count foo/fn.where_clause.html //pre/br 4 +pub fn where_clause(param_one: T, + param_two: U) + where T: Add + Display + Copy, + U: Add + Display + Copy, + T::Output: Display + Add + Copy, + >::Output: Display, + U::Output: Display + Copy +{ + let x = param_one + param_two; + println!("{} + {} = {}", param_one, param_two, x); + let y = param_two + param_one; + println!("{} + {} = {}", param_two, param_one, y); + println!("{} + {} = {}", x, y, x + y); +} diff --git a/src/test/compile-fail/issue-31424.rs b/src/test/ui/did_you_mean/issue-31424.rs similarity index 79% rename from src/test/compile-fail/issue-31424.rs rename to src/test/ui/did_you_mean/issue-31424.rs index 262efab22a29..374d06bb71d2 100644 --- a/src/test/compile-fail/issue-31424.rs +++ b/src/test/ui/did_you_mean/issue-31424.rs @@ -15,15 +15,12 @@ struct Struct; impl Struct { fn foo(&mut self) { (&mut self).bar(); - //~^ ERROR cannot borrow immutable argument `self` as mutable - // ... and no SUGGESTION that suggests `&mut mut self` } // In this case we could keep the suggestion, but to distinguish the // two cases is pretty hard. It's an obscure case anyway. fn bar(self: &mut Self) { (&mut self).bar(); - //~^ ERROR cannot borrow immutable argument `self` as mutable } } diff --git a/src/test/ui/did_you_mean/issue-31424.stderr b/src/test/ui/did_you_mean/issue-31424.stderr new file mode 100644 index 000000000000..4873acf551eb --- /dev/null +++ b/src/test/ui/did_you_mean/issue-31424.stderr @@ -0,0 +1,17 @@ +error: cannot borrow immutable argument `self` as mutable + --> $DIR/issue-31424.rs:17:15 + | +17 | (&mut self).bar(); + | ^^^^ + | | + | try removing `&mut` here + | cannot reborrow mutably + +error: cannot borrow immutable argument `self` as mutable + --> $DIR/issue-31424.rs:23:15 + | +23 | (&mut self).bar(); + | ^^^^ cannot borrow mutably + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/did_you_mean/issue-34126.rs b/src/test/ui/did_you_mean/issue-34126.rs new file mode 100644 index 000000000000..9523e6bbf383 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-34126.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Z { } + +impl Z { + fn run(&self, z: &mut Z) { } + fn start(&mut self) { + self.run(&mut self); + } +} + +fn main() { + let mut z = Z {}; + z.start(); +} diff --git a/src/test/ui/did_you_mean/issue-34126.stderr b/src/test/ui/did_you_mean/issue-34126.stderr new file mode 100644 index 000000000000..8011298c80cd --- /dev/null +++ b/src/test/ui/did_you_mean/issue-34126.stderr @@ -0,0 +1,11 @@ +error: cannot borrow immutable argument `self` as mutable + --> $DIR/issue-34126.rs:16:23 + | +16 | self.run(&mut self); + | ^^^^ + | | + | try removing `&mut` here + | cannot reborrow mutably + +error: aborting due to previous error + diff --git a/src/test/ui/did_you_mean/issue-34337.rs b/src/test/ui/did_you_mean/issue-34337.rs new file mode 100644 index 000000000000..42853a5d83db --- /dev/null +++ b/src/test/ui/did_you_mean/issue-34337.rs @@ -0,0 +1,17 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn get(key: &mut String) { } + +fn main() { + let mut v: Vec = Vec::new(); + let ref mut key = v[0]; + get(&mut key); +} diff --git a/src/test/ui/did_you_mean/issue-34337.stderr b/src/test/ui/did_you_mean/issue-34337.stderr new file mode 100644 index 000000000000..d658912835b9 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-34337.stderr @@ -0,0 +1,11 @@ +error: cannot borrow immutable local variable `key` as mutable + --> $DIR/issue-34337.rs:16:14 + | +16 | get(&mut key); + | ^^^ + | | + | try removing `&mut` here + | cannot reborrow mutably + +error: aborting due to previous error + diff --git a/src/test/ui/did_you_mean/issue-37139.rs b/src/test/ui/did_you_mean/issue-37139.rs new file mode 100644 index 000000000000..65181768053c --- /dev/null +++ b/src/test/ui/did_you_mean/issue-37139.rs @@ -0,0 +1,25 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum TestEnum { + Item(i32), +} + +fn test(_: &mut i32) { +} + +fn main() { + let mut x = TestEnum::Item(10); + match x { + TestEnum::Item(ref mut x) => { + test(&mut x); + } + } +} diff --git a/src/test/ui/did_you_mean/issue-37139.stderr b/src/test/ui/did_you_mean/issue-37139.stderr new file mode 100644 index 000000000000..b1a8231fdb6c --- /dev/null +++ b/src/test/ui/did_you_mean/issue-37139.stderr @@ -0,0 +1,11 @@ +error: cannot borrow immutable local variable `x` as mutable + --> $DIR/issue-37139.rs:22:23 + | +22 | test(&mut x); + | ^ + | | + | try removing `&mut` here + | cannot reborrow mutably + +error: aborting due to previous error + diff --git a/src/test/ui/fmt/format-string-error.rs b/src/test/ui/fmt/format-string-error.rs new file mode 100644 index 000000000000..ec715b3f0ba6 --- /dev/null +++ b/src/test/ui/fmt/format-string-error.rs @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + println!("{"); + println!("{{}}"); + println!("}"); +} + diff --git a/src/test/ui/fmt/format-string-error.stderr b/src/test/ui/fmt/format-string-error.stderr new file mode 100644 index 000000000000..58b392f0b8d6 --- /dev/null +++ b/src/test/ui/fmt/format-string-error.stderr @@ -0,0 +1,20 @@ +error: invalid format string: expected `'}'` but string was terminated + --> $DIR/format-string-error.rs:12:5 + | +12 | println!("{"); + | ^^^^^^^^^^^^^^ + | + = note: if you intended to print `{`, you can escape it using `{{` + = note: this error originates in a macro outside of the current crate + +error: invalid format string: unmatched `}` found + --> $DIR/format-string-error.rs:14:5 + | +14 | println!("}"); + | ^^^^^^^^^^^^^^ + | + = note: if you intended to print `}`, you can escape it using `}}` + = note: this error originates in a macro outside of the current crate + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/lifetimes/borrowck-let-suggestion.stderr b/src/test/ui/lifetimes/borrowck-let-suggestion.stderr index 91600340019c..d85483f43c9e 100644 --- a/src/test/ui/lifetimes/borrowck-let-suggestion.stderr +++ b/src/test/ui/lifetimes/borrowck-let-suggestion.stderr @@ -1,8 +1,8 @@ error: borrowed value does not live long enough - --> $DIR/borrowck-let-suggestion.rs:12:13 + --> $DIR/borrowck-let-suggestion.rs:12:23 | 12 | let x = [1].iter(); - | ^^^ - temporary value only lives until here + | --- ^ temporary value dropped here while still borrowed | | | temporary value created here 13 | } diff --git a/src/test/ui/lifetimes/consider-using-explicit-lifetime.rs b/src/test/ui/lifetimes/consider-using-explicit-lifetime.rs new file mode 100644 index 000000000000..603f55af465f --- /dev/null +++ b/src/test/ui/lifetimes/consider-using-explicit-lifetime.rs @@ -0,0 +1,28 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::str::FromStr; + +pub struct Foo<'a> { + field: &'a str, +} + +impl<'a> Foo<'a> { + fn bar(path: &str) -> Result { + Ok(Foo { field: path }) + } +} + +impl<'a> FromStr for Foo<'a> { + type Err = (); + fn from_str(path: &str) -> Result { + Ok(Foo { field: path }) + } +} diff --git a/src/test/ui/lifetimes/consider-using-explicit-lifetime.stderr b/src/test/ui/lifetimes/consider-using-explicit-lifetime.stderr new file mode 100644 index 000000000000..353e251369a1 --- /dev/null +++ b/src/test/ui/lifetimes/consider-using-explicit-lifetime.stderr @@ -0,0 +1,22 @@ +error: main function not found + +error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements + --> $DIR/consider-using-explicit-lifetime.rs:19:12 + | +19 | Ok(Foo { field: path }) + | ^^^ + +error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements + --> $DIR/consider-using-explicit-lifetime.rs:26:12 + | +26 | Ok(Foo { field: path }) + | ^^^ + | +help: consider using an explicit lifetime parameter as shown: fn from_str(path: &'a str) -> Result + --> $DIR/consider-using-explicit-lifetime.rs:25:5 + | +25 | fn from_str(path: &str) -> Result { + | ^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/macros/format-foreign.rs b/src/test/ui/macros/format-foreign.rs new file mode 100644 index 000000000000..cca45ca9ecdd --- /dev/null +++ b/src/test/ui/macros/format-foreign.rs @@ -0,0 +1,20 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + println!("%.*3$s %s!\n", "Hello,", "World", 4); + println!("%1$*2$.*3$f", 123.456); + + // This should *not* produce hints, on the basis that there's equally as + // many "correct" format specifiers. It's *probably* just an actual typo. + println!("{} %f", "one", 2.0); + + println!("Hi there, $NAME.", NAME="Tim"); +} diff --git a/src/test/ui/macros/format-foreign.stderr b/src/test/ui/macros/format-foreign.stderr new file mode 100644 index 000000000000..0283052a89f5 --- /dev/null +++ b/src/test/ui/macros/format-foreign.stderr @@ -0,0 +1,52 @@ +error: multiple unused formatting arguments + --> $DIR/format-foreign.rs:12:5 + | +12 | println!("%.*3$s %s!/n", "Hello,", "World", 4); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: argument never used + --> $DIR/format-foreign.rs:12:30 + | +12 | println!("%.*3$s %s!/n", "Hello,", "World", 4); + | ^^^^^^^^ +note: argument never used + --> $DIR/format-foreign.rs:12:40 + | +12 | println!("%.*3$s %s!/n", "Hello,", "World", 4); + | ^^^^^^^ +note: argument never used + --> $DIR/format-foreign.rs:12:49 + | +12 | println!("%.*3$s %s!/n", "Hello,", "World", 4); + | ^ + = help: `%.*3$s` should be written as `{:.2$}` + = help: `%s` should be written as `{}` + = note: printf formatting not supported; see the documentation for `std::fmt` + = note: this error originates in a macro outside of the current crate + +error: argument never used + --> $DIR/format-foreign.rs:13:29 + | +13 | println!("%1$*2$.*3$f", 123.456); + | ^^^^^^^ + | + = help: `%1$*2$.*3$f` should be written as `{0:1$.2$}` + = note: printf formatting not supported; see the documentation for `std::fmt` + +error: argument never used + --> $DIR/format-foreign.rs:17:30 + | +17 | println!("{} %f", "one", 2.0); + | ^^^ + +error: named argument never used + --> $DIR/format-foreign.rs:19:39 + | +19 | println!("Hi there, $NAME.", NAME="Tim"); + | ^^^^^ + | + = help: `$NAME` should be written as `{NAME}` + = note: shell formatting not supported; see the documentation for `std::fmt` + +error: aborting due to 4 previous errors + diff --git a/src/test/run-make/missing-items/m1.rs b/src/test/ui/missing-items/auxiliary/m1.rs similarity index 82% rename from src/test/run-make/missing-items/m1.rs rename to src/test/ui/missing-items/auxiliary/m1.rs index 060c7a9571b7..f8389692267e 100644 --- a/src/test/run-make/missing-items/m1.rs +++ b/src/test/ui/missing-items/auxiliary/m1.rs @@ -9,9 +9,9 @@ // except according to those terms. #![feature(associated_consts)] -#![crate_type = "dylib"] + pub trait X { - const CONSTANT: u32; - type Type; - fn method(&self, s: String) -> Self::Type; + const CONSTANT: u32; + type Type; + fn method(&self, s: String) -> Self::Type; } diff --git a/src/test/run-make/missing-items/m2.rs b/src/test/ui/missing-items/m2.rs similarity index 95% rename from src/test/run-make/missing-items/m2.rs rename to src/test/ui/missing-items/m2.rs index 7055673acc9a..fc09039640b9 100644 --- a/src/test/run-make/missing-items/m2.rs +++ b/src/test/ui/missing-items/m2.rs @@ -8,8 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// aux-build:m1.rs + #![feature(associated_consts)] -#![crate_type = "dylib"] + extern crate m1; struct X { diff --git a/src/test/ui/missing-items/m2.stderr b/src/test/ui/missing-items/m2.stderr new file mode 100644 index 000000000000..caeb9ff415cd --- /dev/null +++ b/src/test/ui/missing-items/m2.stderr @@ -0,0 +1,14 @@ +error: main function not found + +error[E0046]: not all trait items implemented, missing: `CONSTANT`, `Type`, `method` + --> $DIR/m2.rs:20:1 + | +20 | impl m1::X for X { + | ^ missing `CONSTANT`, `Type`, `method` in implementation + | + = note: `CONSTANT` from trait: `const CONSTANT: u32;` + = note: `Type` from trait: `type Type;` + = note: `method` from trait: `fn(&Self, std::string::String) -> ::Type` + +error: aborting due to previous error + diff --git a/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr b/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr index 0bba986e437b..5bb656878b3f 100644 --- a/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr +++ b/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr @@ -10,10 +10,10 @@ error: `young[..]` does not live long enough = note: values in a scope are dropped in the opposite order they are created error: borrowed value does not live long enough - --> $DIR/borrowck-let-suggestion-suffixes.rs:24:14 + --> $DIR/borrowck-let-suggestion-suffixes.rs:24:18 | 24 | v3.push(&'x'); // statement 6 - | ^^^ - temporary value only lives until here + | --- ^ temporary value dropped here while still borrowed | | | temporary value created here ... @@ -23,10 +23,10 @@ error: borrowed value does not live long enough = note: consider using a `let` binding to increase its lifetime error: borrowed value does not live long enough - --> $DIR/borrowck-let-suggestion-suffixes.rs:34:18 + --> $DIR/borrowck-let-suggestion-suffixes.rs:34:22 | 34 | v4.push(&'y'); - | ^^^ - temporary value only lives until here + | --- ^ temporary value dropped here while still borrowed | | | temporary value created here ... @@ -36,10 +36,10 @@ error: borrowed value does not live long enough = note: consider using a `let` binding to increase its lifetime error: borrowed value does not live long enough - --> $DIR/borrowck-let-suggestion-suffixes.rs:45:14 + --> $DIR/borrowck-let-suggestion-suffixes.rs:45:18 | 45 | v5.push(&'z'); - | ^^^ - temporary value only lives until here + | --- ^ temporary value dropped here while still borrowed | | | temporary value created here ... diff --git a/src/test/compile-fail/issue-15480.rs b/src/test/ui/span/issue-15480.rs similarity index 91% rename from src/test/compile-fail/issue-15480.rs rename to src/test/ui/span/issue-15480.rs index 30f58f909a08..ea5f4d3fe60e 100644 --- a/src/test/compile-fail/issue-15480.rs +++ b/src/test/ui/span/issue-15480.rs @@ -11,7 +11,6 @@ fn main() { let v = vec![ &3 -//~^ ERROR borrowed value does not live long enough ]; for &&x in &v { diff --git a/src/test/ui/span/issue-15480.stderr b/src/test/ui/span/issue-15480.stderr new file mode 100644 index 000000000000..85f6c41c3664 --- /dev/null +++ b/src/test/ui/span/issue-15480.stderr @@ -0,0 +1,15 @@ +error: borrowed value does not live long enough + --> $DIR/issue-15480.rs:14:6 + | +13 | &3 + | - temporary value created here +14 | ]; + | ^ temporary value dropped here while still borrowed +... +19 | } + | - temporary value needs to live until here + | + = note: consider using a `let` binding to increase its lifetime + +error: aborting due to previous error + diff --git a/src/test/ui/span/multispan-import-lint.rs b/src/test/ui/span/multispan-import-lint.rs new file mode 100644 index 000000000000..43b6cd8f85f8 --- /dev/null +++ b/src/test/ui/span/multispan-import-lint.rs @@ -0,0 +1,15 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::cmp::{Eq, Ord, min, PartialEq, PartialOrd}; + +fn main() { + let _ = min(1, 2); +} diff --git a/src/test/ui/span/multispan-import-lint.stderr b/src/test/ui/span/multispan-import-lint.stderr new file mode 100644 index 000000000000..b581584eee7e --- /dev/null +++ b/src/test/ui/span/multispan-import-lint.stderr @@ -0,0 +1,6 @@ +warning: unused imports: `Eq`, `Ord`, `PartialEq`, `PartialOrd`, #[warn(unused_imports)] on by default + --> $DIR/multispan-import-lint.rs:11:16 + | +11 | use std::cmp::{Eq, Ord, min, PartialEq, PartialOrd}; + | ^^ ^^^ ^^^^^^^^^ ^^^^^^^^^^ + diff --git a/src/test/compile-fail/regions-close-over-borrowed-ref-in-obj.rs b/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.rs similarity index 88% rename from src/test/compile-fail/regions-close-over-borrowed-ref-in-obj.rs rename to src/test/ui/span/regions-close-over-borrowed-ref-in-obj.rs index 25b8137d29ca..a524562f2d95 100644 --- a/src/test/compile-fail/regions-close-over-borrowed-ref-in-obj.rs +++ b/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.rs @@ -17,7 +17,7 @@ impl<'a> Foo for &'a isize { } fn main() { let blah; { - let ss: &isize = &1; //~ ERROR borrowed value does not live long enough + let ss: &isize = &1; blah = box ss as Box; } } diff --git a/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.stderr b/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.stderr new file mode 100644 index 000000000000..205734c25e0e --- /dev/null +++ b/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.stderr @@ -0,0 +1,13 @@ +error: borrowed value does not live long enough + --> $DIR/regions-close-over-borrowed-ref-in-obj.rs:22:5 + | +20 | let ss: &isize = &1; + | - temporary value created here +21 | blah = box ss as Box; +22 | } + | ^ temporary value dropped here while still borrowed +23 | } + | - temporary value needs to live until here + +error: aborting due to previous error + diff --git a/src/test/compile-fail/slice-borrow.rs b/src/test/ui/span/slice-borrow.rs similarity index 86% rename from src/test/compile-fail/slice-borrow.rs rename to src/test/ui/span/slice-borrow.rs index 0062f66ae220..4ca0ccaa731d 100644 --- a/src/test/compile-fail/slice-borrow.rs +++ b/src/test/ui/span/slice-borrow.rs @@ -13,7 +13,7 @@ fn main() { let y; { - let x: &[isize] = &[1, 2, 3, 4, 5]; //~ ERROR borrowed value does not live long enough + let x: &[isize] = &[1, 2, 3, 4, 5]; y = &x[1..]; } } diff --git a/src/test/ui/span/slice-borrow.stderr b/src/test/ui/span/slice-borrow.stderr new file mode 100644 index 000000000000..efe81fd00bf4 --- /dev/null +++ b/src/test/ui/span/slice-borrow.stderr @@ -0,0 +1,13 @@ +error: borrowed value does not live long enough + --> $DIR/slice-borrow.rs:18:5 + | +16 | let x: &[isize] = &[1, 2, 3, 4, 5]; + | --------------- temporary value created here +17 | y = &x[1..]; +18 | } + | ^ temporary value dropped here while still borrowed +19 | } + | - temporary value needs to live until here + +error: aborting due to previous error + diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 8cb2e3b1c2de..3cc14541fcdf 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1334,8 +1334,18 @@ actual:\n\ // FIXME (#9639): This needs to handle non-utf8 paths let mut args = vec![input_file.to_str().unwrap().to_owned(), "-L".to_owned(), - self.config.build_base.to_str().unwrap().to_owned(), - format!("--target={}", target)]; + self.config.build_base.to_str().unwrap().to_owned()]; + + // Optionally prevent default --target if specified in test compile-flags. + let custom_target = self.props.compile_flags + .iter() + .fold(false, |acc, ref x| acc || x.starts_with("--target")); + + if !custom_target { + args.extend(vec![ + format!("--target={}", target), + ]); + } if let Some(revision) = self.revision { args.extend(vec![ @@ -1456,8 +1466,11 @@ actual:\n\ // If this is emscripten, then run tests under nodejs if self.config.target.contains("emscripten") { - let nodejs = self.config.nodejs.clone().unwrap_or("nodejs".to_string()); - args.push(nodejs); + if let Some(ref p) = self.config.nodejs { + args.push(p.clone()); + } else { + self.fatal("no NodeJS binary found (--nodejs)"); + } } let exe_file = self.make_exe_name();