diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000000000..686c48abb30cd --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,110 @@ +environment: + matrix: + # 32/64 bit MSVC + - MSYS_BITS: 64 + TARGET: x86_64-pc-windows-msvc + CHECK: check + CONFIGURE_ARGS: --enable-llvm-assertions --enable-debug-assertions + - MSYS_BITS: 32 + TARGET: i686-pc-windows-msvc + CHECK: check + CONFIGURE_ARGS: --enable-llvm-assertions --enable-debug-assertions + + # MSVC rustbuild + - MSYS_BITS: 64 + CONFIGURE_ARGS: --enable-rustbuild --enable-llvm-assertions --enable-debug-assertions + TARGET: x86_64-pc-windows-msvc + CHECK: check + + # MSVC cargotest + - MSYS_BITS: 64 + CONFIGURE_ARGS: --enable-rustbuild --enable-llvm-assertions --enable-debug-assertions + TARGET: x86_64-pc-windows-msvc + CHECK: check-cargotest + + # 32/64-bit MinGW builds. + # + # The MinGW builds unfortunately have to both download a custom toolchain and + # avoid the one installed by AppVeyor by default. Interestingly, though, for + # different reasons! + # + # For 32-bit the installed gcc toolchain on AppVeyor uses the pthread + # threading model. This is unfortunately not what we want, and if we compile + # with it then there's lots of link errors in the standard library (undefined + # references to pthread symbols). + # + # For 64-bit the installed gcc toolchain is currently 5.3.0 which + # unfortunately segfaults on Windows with --enable-llvm-assertions (segfaults + # in LLVM). See rust-lang/rust#28445 for more information, but to work around + # this we go back in time to 4.9.2 specifically. + # + # Finally, note that the downloads below are all in the `rust-lang-ci` S3 + # bucket, but they cleraly didn't originate there! The downloads originally + # came from the mingw-w64 SourceForge download site. Unfortunately + # SourceForge is notoriously flaky, so we mirror it on our own infrastructure. + # + # And as a final point of note, the 32-bit MinGW build using the makefiles do + # *not* use debug assertions and llvm assertions. This is because they take + # too long on appveyor and this is tested by rustbuild below. + - MSYS_BITS: 32 + TARGET: i686-pc-windows-gnu + CHECK: check + MINGW_URL: https://s3.amazonaws.com/rust-lang-ci + MINGW_ARCHIVE: i686-4.9.2-release-win32-dwarf-rt_v4-rev4.7z + MINGW_DIR: mingw32 + + - MSYS_BITS: 32 + CONFIGURE_ARGS: --enable-rustbuild --enable-llvm-assertions --enable-debug-assertions + TARGET: i686-pc-windows-gnu + CHECK: check + MINGW_URL: https://s3.amazonaws.com/rust-lang-ci + MINGW_ARCHIVE: i686-4.9.2-release-win32-dwarf-rt_v4-rev4.7z + MINGW_DIR: mingw32 + + - MSYS_BITS: 64 + CONFIGURE_ARGS: --enable-llvm-assertions --enable-debug-assertions + TARGET: x86_64-pc-windows-gnu + CHECK: check + MINGW_URL: https://s3.amazonaws.com/rust-lang-ci + MINGW_ARCHIVE: x86_64-4.9.2-release-win32-seh-rt_v4-rev4.7z + MINGW_DIR: mingw64 + +clone_depth: 1 +build: false + +install: + # If we need to download a custom MinGW, do so here and set the path + # appropriately. + # + # Note that this *also* means that we're not using what is typically + # /mingw32/bin/python2.7.exe, which is a "correct" python interpreter where + # /usr/bin/python2.7.exe is not. To ensure we use the right interpreter we + # move `C:\Python27` ahead in PATH and then also make sure the `python2.7.exe` + # file exists in there (which it doesn't by default). + - if defined MINGW_URL appveyor DownloadFile %MINGW_URL%/%MINGW_ARCHIVE% + - if defined MINGW_URL 7z x -y %MINGW_ARCHIVE% > nul + - if defined MINGW_URL set PATH=C:\Python27;%CD%\%MINGW_DIR%\bin;C:\msys64\usr\bin;%PATH% + - if defined MINGW_URL copy C:\Python27\python.exe C:\Python27\python2.7.exe + + # Otherwise pull in the MinGW installed on appveyor + - if NOT defined MINGW_URL set PATH=C:\msys64\mingw%MSYS_BITS%\bin;C:\msys64\usr\bin;%PATH% + +test_script: + - sh ./configure + %CONFIGURE_ARGS% + --build=%TARGET% + - bash -c "make -j$(nproc)" + - bash -c "make %CHECK% -j$(nproc)" + +cache: + - build/%TARGET%/llvm -> src/rustllvm/llvm-auto-clean-trigger + - "%TARGET%/llvm -> src/rustllvm/llvm-auto-clean-trigger" + +branches: + only: + - auto + +# init: +# - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) +# on_finish: +# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) diff --git a/mk/llvm.mk b/mk/llvm.mk index d6f812049e03c..5a91f5fcaa483 100644 --- a/mk/llvm.mk +++ b/mk/llvm.mk @@ -36,22 +36,27 @@ endif # If CFG_LLVM_ROOT is defined then we don't build LLVM ourselves ifeq ($(CFG_LLVM_ROOT),) -LLVM_STAMP_$(1) = $$(CFG_LLVM_BUILD_DIR_$(1))/llvm-auto-clean-stamp +LLVM_STAMP_$(1) = $(S)src/rustllvm/llvm-auto-clean-trigger LLVM_DONE_$(1) = $$(CFG_LLVM_BUILD_DIR_$(1))/llvm-finished-building $$(LLVM_CONFIG_$(1)): $$(LLVM_DONE_$(1)) -$$(LLVM_DONE_$(1)): $$(LLVM_DEPS_TARGET_$(1)) $$(LLVM_STAMP_$(1)) - @$$(call E, cmake: llvm) ifneq ($$(CFG_NINJA),) - $$(Q)$$(CFG_NINJA) -C $$(CFG_LLVM_BUILD_DIR_$(1)) +BUILD_LLVM_$(1) := $$(CFG_NINJA) -C $$(CFG_LLVM_BUILD_DIR_$(1)) else ifeq ($$(findstring msvc,$(1)),msvc) - $$(Q)$$(CFG_CMAKE) --build $$(CFG_LLVM_BUILD_DIR_$(1)) \ - --config $$(LLVM_BUILD_CONFIG_MODE) +BUILD_LLVM_$(1) := $$(CFG_CMAKE) --build $$(CFG_LLVM_BUILD_DIR_$(1)) \ + --config $$(LLVM_BUILD_CONFIG_MODE) else - $$(Q)$$(MAKE) -C $$(CFG_LLVM_BUILD_DIR_$(1)) +BUILD_LLVM_$(1) := $$(MAKE) -C $$(CFG_LLVM_BUILD_DIR_$(1)) endif - $$(Q)touch $$@ + +$$(LLVM_DONE_$(1)): $$(LLVM_DEPS_TARGET_$(1)) $$(LLVM_STAMP_$(1)) + @$$(call E, cmake: llvm) + $$(Q)if ! cmp $$(LLVM_STAMP_$(1)) $$(LLVM_DONE_$(1)); then \ + $$(MAKE) clean-llvm$(1); \ + $$(BUILD_LLVM_$(1)); \ + fi + $$(Q)cp $$(LLVM_STAMP_$(1)) $$@ ifneq ($$(CFG_NINJA),) clean-llvm$(1): @@ -75,17 +80,6 @@ endif $$(LLVM_AR_$(1)): $$(LLVM_CONFIG_$(1)) -# This is used to independently force an LLVM clean rebuild -# when we changed something not otherwise captured by builtin -# dependencies. In these cases, commit a change that touches -# the stamp in the source dir. -$$(LLVM_STAMP_$(1)): $$(S)src/rustllvm/llvm-auto-clean-trigger - @$$(call E, make: cleaning llvm) - $$(Q)touch $$@.start_time - $$(Q)$$(MAKE) clean-llvm$(1) - @$$(call E, make: done cleaning llvm) - touch -r $$@.start_time $$@ && rm $$@.start_time - ifeq ($$(CFG_ENABLE_LLVM_STATIC_STDCPP),1) LLVM_STDCPP_RUSTFLAGS_$(1) = -L "$$(dir $$(shell $$(CC_$(1)) $$(CFG_GCCISH_CFLAGS_$(1)) \ -print-file-name=lib$(CFG_STDCPP_NAME).a))" diff --git a/mk/main.mk b/mk/main.mk index e68a8f3005561..d4efee90361b7 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -53,17 +53,6 @@ endif # versions in the same place CFG_FILENAME_EXTRA=$(shell printf '%s' $(CFG_RELEASE)$(CFG_EXTRA_FILENAME) | $(CFG_HASH_COMMAND)) -# A magic value that allows the compiler to use unstable features during the -# bootstrap even when doing so would normally be an error because of feature -# staging or because the build turns on warnings-as-errors and unstable features -# default to warnings. The build has to match this key in an env var. -# -# This value is keyed off the release to ensure that all compilers for one -# particular release have the same bootstrap key. Note that this is -# intentionally not "secure" by any definition, this is largely just a deterrent -# from users enabling unstable features on the stable compiler. -CFG_BOOTSTRAP_KEY=$(CFG_FILENAME_EXTRA) - # If local-rust is the same as the current version, then force a local-rebuild ifdef CFG_ENABLE_LOCAL_RUST ifeq ($(CFG_RELEASE),\ @@ -73,14 +62,6 @@ ifeq ($(CFG_RELEASE),\ endif endif -# The stage0 compiler needs to use the previous key recorded in src/stage0.txt, -# except for local-rebuild when it just uses the same current key. -ifdef CFG_ENABLE_LOCAL_REBUILD -CFG_BOOTSTRAP_KEY_STAGE0=$(CFG_BOOTSTRAP_KEY) -else -CFG_BOOTSTRAP_KEY_STAGE0=$(shell sed -ne 's/^rustc_key: //p' $(S)src/stage0.txt) -endif - # The name of the package to use for creating tarballs, installers etc. CFG_PACKAGE_NAME=rustc-$(CFG_PACKAGE_VERS) @@ -387,13 +368,16 @@ CFG_INFO := $(info cfg: disabling unstable features (CFG_DISABLE_UNSTABLE_FEATUR # Turn on feature-staging export CFG_DISABLE_UNSTABLE_FEATURES # Subvert unstable feature lints to do the self-build -export RUSTC_BOOTSTRAP_KEY:=$(CFG_BOOTSTRAP_KEY) +export RUSTC_BOOTSTRAP endif -export CFG_BOOTSTRAP_KEY ifdef CFG_MUSL_ROOT export CFG_MUSL_ROOT endif +# FIXME: Transitionary measure to bootstrap using the old bootstrap logic. +# Remove this once the bootstrap compiler uses the new login in Issue #36548. +export RUSTC_BOOTSTRAP_KEY=62b3e239 + ###################################################################### # Per-stage targets and runner ###################################################################### diff --git a/mk/target.mk b/mk/target.mk index 2a08b7b046534..1b139909ab458 100644 --- a/mk/target.mk +++ b/mk/target.mk @@ -42,23 +42,6 @@ $(foreach host,$(CFG_HOST), \ $(foreach crate,$(CRATES), \ $(eval $(call RUST_CRATE_FULLDEPS,$(stage),$(target),$(host),$(crate))))))) -# $(1) stage -# $(2) target -# $(3) host -define DEFINE_BOOTSTRAP_KEY -BOOTSTRAP_KEY$(1)_T_$(2)_H_$(3) := $$(CFG_BOOTSTRAP_KEY) -ifeq ($(1),0) -ifeq ($(3),$$(CFG_BUILD)) -BOOTSTRAP_KEY$(1)_T_$(2)_H_$(3) := $$(CFG_BOOTSTRAP_KEY_STAGE0) -endif -endif -endef - -$(foreach host,$(CFG_TARGET), \ - $(foreach target,$(CFG_TARGET), \ - $(foreach stage,$(STAGES), \ - $(eval $(call DEFINE_BOOTSTRAP_KEY,$(stage),$(target),$(host)))))) - # RUST_TARGET_STAGE_N template: This defines how target artifacts are built # for all stage/target architecture combinations. This is one giant rule which # works as follows: @@ -83,8 +66,6 @@ $(foreach host,$(CFG_TARGET), \ define RUST_TARGET_STAGE_N $$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$(4): CFG_COMPILER_HOST_TRIPLE = $(2) -$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$(4): \ - export RUSTC_BOOTSTRAP_KEY := $$(BOOTSTRAP_KEY$(1)_T_$(2)_H_$(3)) $$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$(4): \ $$(CRATEFILE_$(4)) \ $$(CRATE_FULLDEPS_$(1)_T_$(2)_H_$(3)_$(4)) \ @@ -132,8 +113,6 @@ endef # $(4) - name of the tool being built define TARGET_TOOL -$$(TBIN$(1)_T_$(2)_H_$(3))/$(4)$$(X_$(2)): \ - export RUSTC_BOOTSTRAP_KEY := $$(BOOTSTRAP_KEY$(1)_T_$(2)_H_$(3)) $$(TBIN$(1)_T_$(2)_H_$(3))/$(4)$$(X_$(2)): \ $$(TOOL_SOURCE_$(4)) \ $$(TOOL_INPUTS_$(4)) \ diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index b8d0eb3ff996a..af76a49fed045 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -214,7 +214,7 @@ pub fn compiletest(build: &Build, } } } - build.add_bootstrap_key(compiler, &mut cmd); + build.add_bootstrap_key(&mut cmd); cmd.arg("--adb-path").arg("adb"); cmd.arg("--adb-test-dir").arg(ADB_TEST_DIR); diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 418c3a48ed348..ff8e4757bd1f1 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -119,7 +119,7 @@ fn build_startup_objects(build: &Build, target: &str, into: &Path) { for file in t!(fs::read_dir(build.src.join("src/rtstartup"))) { let file = t!(file); let mut cmd = Command::new(&compiler_path); - build.add_bootstrap_key(&compiler, &mut cmd); + build.add_bootstrap_key(&mut cmd); build.run(cmd.arg("--target").arg(target) .arg("--emit=obj") .arg("--out-dir").arg(into) @@ -185,7 +185,6 @@ pub fn rustc<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { cargo.env("CFG_RELEASE", &build.release) .env("CFG_RELEASE_CHANNEL", &build.config.channel) .env("CFG_VERSION", &build.version) - .env("CFG_BOOTSTRAP_KEY", &build.bootstrap_key) .env("CFG_PREFIX", build.config.prefix.clone().unwrap_or(String::new())) .env("CFG_LIBDIR_RELATIVE", "lib"); diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 6158e94875e95..e4577bfcdfc94 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -120,6 +120,7 @@ struct Build { rustc: Option, compiler_docs: Option, docs: Option, + submodules: Option, } /// TOML representation of how the LLVM build is configured. @@ -225,6 +226,7 @@ impl Config { config.cargo = build.cargo.map(PathBuf::from); set(&mut config.compiler_docs, build.compiler_docs); set(&mut config.docs, build.docs); + set(&mut config.submodules, build.submodules); if let Some(ref llvm) = toml.llvm { set(&mut config.ccache, llvm.ccache); diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index f054b29d0b140..39c976edc13d1 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -76,6 +76,9 @@ # library and facade crates. #compiler-docs = false +# Indicate whether submodules are managed and updated automatically. +#submodules = true + # ============================================================================= # Options for compiling Rust code itself # ============================================================================= diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 30983869c2e3b..a63c23b46212d 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -662,7 +662,7 @@ impl Build { .env("RUSTDOC_REAL", self.rustdoc(compiler)) .env("RUSTC_FLAGS", self.rustc_flags(target).join(" ")); - self.add_bootstrap_key(compiler, &mut cargo); + self.add_bootstrap_key(&mut cargo); // Specify some various options for build scripts used throughout // the build. @@ -871,16 +871,11 @@ impl Build { } /// Adds the compiler's bootstrap key to the environment of `cmd`. - fn add_bootstrap_key(&self, compiler: &Compiler, cmd: &mut Command) { - // In stage0 we're using a previously released stable compiler, so we - // use the stage0 bootstrap key. Otherwise we use our own build's - // bootstrap key. - let bootstrap_key = if compiler.is_snapshot(self) && !self.local_rebuild { - &self.bootstrap_key_stage0 - } else { - &self.bootstrap_key - }; - cmd.env("RUSTC_BOOTSTRAP_KEY", bootstrap_key); + fn add_bootstrap_key(&self, cmd: &mut Command) { + cmd.env("RUSTC_BOOTSTRAP", ""); + // FIXME: Transitionary measure to bootstrap using the old bootstrap logic. + // Remove this once the bootstrap compiler uses the new login in Issue #36548. + cmd.env("RUSTC_BOOTSTRAP_KEY", "62b3e239"); } /// Returns the compiler's libdir where it stores the dynamic libraries that diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 63fc59e43286e..1b4e86fb30f25 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -18,9 +18,10 @@ //! LLVM and compiler-rt are essentially just wired up to everything else to //! ensure that they're always in place if needed. +use std::fs::{self, File}; +use std::io::{Read, Write}; use std::path::Path; use std::process::Command; -use std::fs::{self, File}; use build_helper::output; use cmake; @@ -43,11 +44,17 @@ pub fn llvm(build: &Build, target: &str) { // artifacts are missing) then we keep going, otherwise we bail out. let dst = build.llvm_out(target); let stamp = build.src.join("src/rustllvm/llvm-auto-clean-trigger"); + let mut stamp_contents = String::new(); + t!(t!(File::open(&stamp)).read_to_string(&mut stamp_contents)); let done_stamp = dst.join("llvm-finished-building"); - build.clear_if_dirty(&dst, &stamp); - if fs::metadata(&done_stamp).is_ok() { - return + if done_stamp.exists() { + let mut done_contents = String::new(); + t!(t!(File::open(&done_stamp)).read_to_string(&mut done_contents)); + if done_contents == stamp_contents { + return + } } + drop(fs::remove_dir_all(&dst)); println!("Building LLVM for {}", target); @@ -73,7 +80,9 @@ pub fn llvm(build: &Build, target: &str) { .define("WITH_POLLY", "OFF") .define("LLVM_ENABLE_TERMINFO", "OFF") .define("LLVM_ENABLE_LIBEDIT", "OFF") - .define("LLVM_PARALLEL_COMPILE_JOBS", build.jobs().to_string()); + .define("LLVM_PARALLEL_COMPILE_JOBS", build.jobs().to_string()) + .define("LLVM_TARGET_ARCH", target.split('-').next().unwrap()) + .define("LLVM_DEFAULT_TARGET_TRIPLE", target); if target.starts_with("i686") { cfg.define("LLVM_BUILD_32_BITS", "ON"); @@ -86,9 +95,7 @@ pub fn llvm(build: &Build, target: &str) { // actually exists most of the time in normal installs of LLVM. let host = build.llvm_out(&build.config.build).join("bin/llvm-tblgen"); cfg.define("CMAKE_CROSSCOMPILING", "True") - .define("LLVM_TARGET_ARCH", target.split('-').next().unwrap()) - .define("LLVM_TABLEGEN", &host) - .define("LLVM_DEFAULT_TARGET_TRIPLE", target); + .define("LLVM_TABLEGEN", &host); } // MSVC handles compiler business itself @@ -114,7 +121,7 @@ pub fn llvm(build: &Build, target: &str) { // tools and libs on all platforms. cfg.build(); - t!(File::create(&done_stamp)); + t!(t!(File::create(&done_stamp)).write_all(stamp_contents.as_bytes())); } fn check_llvm_version(build: &Build, llvm_config: &Path) { diff --git a/src/libcore/any.rs b/src/libcore/any.rs index f7edcb998a927..eb0636e8576be 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -351,12 +351,10 @@ impl TypeId { /// # Examples /// /// ``` - /// #![feature(get_type_id)] - /// /// use std::any::{Any, TypeId}; /// - /// fn is_string(s: &Any) -> bool { - /// TypeId::of::() == s.get_type_id() + /// fn is_string(_s: &T) -> bool { + /// TypeId::of::() == TypeId::of::() /// } /// /// fn main() { diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 035418570a019..9eeb2608071c2 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -420,6 +420,18 @@ impl<'a, I, T: 'a> FusedIterator for Cloned where I: FusedIterator, T: Clone {} +#[doc(hidden)] +unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Cloned + where I: TrustedRandomAccess, T: Clone +{ + unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item { + self.it.get_unchecked(i).clone() + } + + #[inline] + fn may_have_side_effect() -> bool { true } +} + /// An iterator that repeats endlessly. /// /// This `struct` is created by the [`cycle()`] method on [`Iterator`]. See its @@ -773,6 +785,13 @@ impl ZipImpl for Zip unsafe { Some((self.a.get_unchecked(i), self.b.get_unchecked(i))) } + } else if A::may_have_side_effect() && self.index < self.a.len() { + // match the base implementation's potential side effects + unsafe { + self.a.get_unchecked(self.index); + } + self.index += 1; + None } else { None } @@ -789,6 +808,23 @@ impl ZipImpl for Zip where A: DoubleEndedIterator + ExactSizeIterator, B: DoubleEndedIterator + ExactSizeIterator { + // Adjust a, b to equal length + if A::may_have_side_effect() { + let sz = self.a.len(); + if sz > self.len { + for _ in 0..sz - cmp::max(self.len, self.index) { + self.a.next_back(); + } + } + } + if B::may_have_side_effect() { + let sz = self.b.len(); + if sz > self.len { + for _ in 0..sz - self.len { + self.b.next_back(); + } + } + } if self.index < self.len { self.len -= 1; let i = self.len; @@ -814,6 +850,9 @@ unsafe impl TrustedRandomAccess for Zip (self.a.get_unchecked(i), self.b.get_unchecked(i)) } + fn may_have_side_effect() -> bool { + A::may_have_side_effect() || B::may_have_side_effect() + } } #[unstable(feature = "fused", issue = "35602")] @@ -920,6 +959,18 @@ impl ExactSizeIterator for Map impl FusedIterator for Map where F: FnMut(I::Item) -> B {} +#[doc(hidden)] +unsafe impl TrustedRandomAccess for Map + where I: TrustedRandomAccess, + F: FnMut(I::Item) -> B, +{ + unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item { + (self.f)(self.iter.get_unchecked(i)) + } + #[inline] + fn may_have_side_effect() -> bool { true } +} + /// An iterator that filters the elements of `iter` with `predicate`. /// /// This `struct` is created by the [`filter()`] method on [`Iterator`]. See its @@ -1135,6 +1186,10 @@ unsafe impl TrustedRandomAccess for Enumerate unsafe fn get_unchecked(&mut self, i: usize) -> (usize, I::Item) { (self.count + i, self.iter.get_unchecked(i)) } + + fn may_have_side_effect() -> bool { + I::may_have_side_effect() + } } #[unstable(feature = "fused", issue = "35602")] @@ -1764,6 +1819,10 @@ unsafe impl TrustedRandomAccess for Fuse unsafe fn get_unchecked(&mut self, i: usize) -> I::Item { self.iter.get_unchecked(i) } + + fn may_have_side_effect() -> bool { + I::may_have_side_effect() + } } #[unstable(feature = "fused", issue = "35602")] diff --git a/src/libcore/iter_private.rs b/src/libcore/iter_private.rs index 83eeef31ab054..bc1aaa09f3dbd 100644 --- a/src/libcore/iter_private.rs +++ b/src/libcore/iter_private.rs @@ -14,6 +14,7 @@ /// # Safety /// /// The iterator's .len() and size_hint() must be exact. +/// `.len()` must be cheap to call. /// /// .get_unchecked() must return distinct mutable references for distinct /// indices (if applicable), and must return a valid reference if index is in @@ -21,5 +22,7 @@ #[doc(hidden)] pub unsafe trait TrustedRandomAccess : ExactSizeIterator { unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item; + /// Return `true` if getting an iterator element may have + /// side effects. Remember to take inner iterators into account. + fn may_have_side_effect() -> bool; } - diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index d1df56905df24..31be404ba905a 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -1968,6 +1968,7 @@ unsafe impl<'a, T> TrustedRandomAccess for Iter<'a, T> { unsafe fn get_unchecked(&mut self, i: usize) -> &'a T { &*self.ptr.offset(i as isize) } + fn may_have_side_effect() -> bool { false } } #[doc(hidden)] @@ -1975,4 +1976,5 @@ unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> { unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut T { &mut *self.ptr.offset(i as isize) } + fn may_have_side_effect() -> bool { false } } diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index c4fe68dfa438c..657f7e7992fee 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -277,7 +277,9 @@ impl AtomicBool { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn store(&self, val: bool, order: Ordering) { - unsafe { atomic_store(self.v.get(), val as u8, order); } + unsafe { + atomic_store(self.v.get(), val as u8, order); + } } /// Stores a value into the bool, returning the old value. @@ -366,9 +368,11 @@ impl AtomicBool { current: bool, new: bool, success: Ordering, - failure: Ordering) -> Result { - match unsafe { atomic_compare_exchange(self.v.get(), current as u8, new as u8, - success, failure) } { + failure: Ordering) + -> Result { + match unsafe { + atomic_compare_exchange(self.v.get(), current as u8, new as u8, success, failure) + } { Ok(x) => Ok(x != 0), Err(x) => Err(x != 0), } @@ -409,9 +413,11 @@ impl AtomicBool { current: bool, new: bool, success: Ordering, - failure: Ordering) -> Result { - match unsafe { atomic_compare_exchange_weak(self.v.get(), current as u8, new as u8, - success, failure) } { + failure: Ordering) + -> Result { + match unsafe { + atomic_compare_exchange_weak(self.v.get(), current as u8, new as u8, success, failure) + } { Ok(x) => Ok(x != 0), Err(x) => Err(x != 0), } @@ -632,9 +638,7 @@ impl AtomicPtr { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn load(&self, order: Ordering) -> *mut T { - unsafe { - atomic_load(self.p.get() as *mut usize, order) as *mut T - } + unsafe { atomic_load(self.p.get() as *mut usize, order) as *mut T } } /// Stores a value into the pointer. @@ -660,7 +664,9 @@ impl AtomicPtr { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn store(&self, ptr: *mut T, order: Ordering) { - unsafe { atomic_store(self.p.get() as *mut usize, ptr as usize, order); } + unsafe { + atomic_store(self.p.get() as *mut usize, ptr as usize, order); + } } /// Stores a value into the pointer, returning the old value. @@ -745,7 +751,8 @@ impl AtomicPtr { current: *mut T, new: *mut T, success: Ordering, - failure: Ordering) -> Result<*mut T, *mut T> { + failure: Ordering) + -> Result<*mut T, *mut T> { unsafe { let res = atomic_compare_exchange(self.p.get() as *mut usize, current as usize, @@ -794,7 +801,8 @@ impl AtomicPtr { current: *mut T, new: *mut T, success: Ordering, - failure: Ordering) -> Result<*mut T, *mut T> { + failure: Ordering) + -> Result<*mut T, *mut T> { unsafe { let res = atomic_compare_exchange_weak(self.p.get() as *mut usize, current as usize, @@ -1266,9 +1274,9 @@ fn strongest_failure_ordering(order: Ordering) -> Ordering { match order { Release => Relaxed, Relaxed => Relaxed, - SeqCst => SeqCst, + SeqCst => SeqCst, Acquire => Acquire, - AcqRel => Acquire, + AcqRel => Acquire, } } @@ -1277,9 +1285,9 @@ unsafe fn atomic_store(dst: *mut T, val: T, order: Ordering) { match order { Release => intrinsics::atomic_store_rel(dst, val), Relaxed => intrinsics::atomic_store_relaxed(dst, val), - SeqCst => intrinsics::atomic_store(dst, val), + SeqCst => intrinsics::atomic_store(dst, val), Acquire => panic!("there is no such thing as an acquire store"), - AcqRel => panic!("there is no such thing as an acquire/release store"), + AcqRel => panic!("there is no such thing as an acquire/release store"), } } @@ -1288,9 +1296,9 @@ unsafe fn atomic_load(dst: *const T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_load_acq(dst), Relaxed => intrinsics::atomic_load_relaxed(dst), - SeqCst => intrinsics::atomic_load(dst), + SeqCst => intrinsics::atomic_load(dst), Release => panic!("there is no such thing as a release load"), - AcqRel => panic!("there is no such thing as an acquire/release load"), + AcqRel => panic!("there is no such thing as an acquire/release load"), } } @@ -1299,9 +1307,9 @@ unsafe fn atomic_swap(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_xchg_acq(dst, val), Release => intrinsics::atomic_xchg_rel(dst, val), - AcqRel => intrinsics::atomic_xchg_acqrel(dst, val), + AcqRel => intrinsics::atomic_xchg_acqrel(dst, val), Relaxed => intrinsics::atomic_xchg_relaxed(dst, val), - SeqCst => intrinsics::atomic_xchg(dst, val) + SeqCst => intrinsics::atomic_xchg(dst, val), } } @@ -1311,9 +1319,9 @@ unsafe fn atomic_add(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_xadd_acq(dst, val), Release => intrinsics::atomic_xadd_rel(dst, val), - AcqRel => intrinsics::atomic_xadd_acqrel(dst, val), + AcqRel => intrinsics::atomic_xadd_acqrel(dst, val), Relaxed => intrinsics::atomic_xadd_relaxed(dst, val), - SeqCst => intrinsics::atomic_xadd(dst, val) + SeqCst => intrinsics::atomic_xadd(dst, val), } } @@ -1323,9 +1331,9 @@ unsafe fn atomic_sub(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_xsub_acq(dst, val), Release => intrinsics::atomic_xsub_rel(dst, val), - AcqRel => intrinsics::atomic_xsub_acqrel(dst, val), + AcqRel => intrinsics::atomic_xsub_acqrel(dst, val), Relaxed => intrinsics::atomic_xsub_relaxed(dst, val), - SeqCst => intrinsics::atomic_xsub(dst, val) + SeqCst => intrinsics::atomic_xsub(dst, val), } } @@ -1334,26 +1342,23 @@ unsafe fn atomic_compare_exchange(dst: *mut T, old: T, new: T, success: Ordering, - failure: Ordering) -> Result { + failure: Ordering) + -> Result { let (val, ok) = match (success, failure) { (Acquire, Acquire) => intrinsics::atomic_cxchg_acq(dst, old, new), (Release, Relaxed) => intrinsics::atomic_cxchg_rel(dst, old, new), - (AcqRel, Acquire) => intrinsics::atomic_cxchg_acqrel(dst, old, new), + (AcqRel, Acquire) => intrinsics::atomic_cxchg_acqrel(dst, old, new), (Relaxed, Relaxed) => intrinsics::atomic_cxchg_relaxed(dst, old, new), - (SeqCst, SeqCst) => intrinsics::atomic_cxchg(dst, old, new), + (SeqCst, SeqCst) => intrinsics::atomic_cxchg(dst, old, new), (Acquire, Relaxed) => intrinsics::atomic_cxchg_acq_failrelaxed(dst, old, new), - (AcqRel, Relaxed) => intrinsics::atomic_cxchg_acqrel_failrelaxed(dst, old, new), - (SeqCst, Relaxed) => intrinsics::atomic_cxchg_failrelaxed(dst, old, new), - (SeqCst, Acquire) => intrinsics::atomic_cxchg_failacq(dst, old, new), + (AcqRel, Relaxed) => intrinsics::atomic_cxchg_acqrel_failrelaxed(dst, old, new), + (SeqCst, Relaxed) => intrinsics::atomic_cxchg_failrelaxed(dst, old, new), + (SeqCst, Acquire) => intrinsics::atomic_cxchg_failacq(dst, old, new), (_, AcqRel) => panic!("there is no such thing as an acquire/release failure ordering"), (_, Release) => panic!("there is no such thing as a release failure ordering"), _ => panic!("a failure ordering can't be stronger than a success ordering"), }; - if ok { - Ok(val) - } else { - Err(val) - } + if ok { Ok(val) } else { Err(val) } } #[inline] @@ -1361,26 +1366,23 @@ unsafe fn atomic_compare_exchange_weak(dst: *mut T, old: T, new: T, success: Ordering, - failure: Ordering) -> Result { + failure: Ordering) + -> Result { let (val, ok) = match (success, failure) { (Acquire, Acquire) => intrinsics::atomic_cxchgweak_acq(dst, old, new), (Release, Relaxed) => intrinsics::atomic_cxchgweak_rel(dst, old, new), - (AcqRel, Acquire) => intrinsics::atomic_cxchgweak_acqrel(dst, old, new), + (AcqRel, Acquire) => intrinsics::atomic_cxchgweak_acqrel(dst, old, new), (Relaxed, Relaxed) => intrinsics::atomic_cxchgweak_relaxed(dst, old, new), - (SeqCst, SeqCst) => intrinsics::atomic_cxchgweak(dst, old, new), + (SeqCst, SeqCst) => intrinsics::atomic_cxchgweak(dst, old, new), (Acquire, Relaxed) => intrinsics::atomic_cxchgweak_acq_failrelaxed(dst, old, new), - (AcqRel, Relaxed) => intrinsics::atomic_cxchgweak_acqrel_failrelaxed(dst, old, new), - (SeqCst, Relaxed) => intrinsics::atomic_cxchgweak_failrelaxed(dst, old, new), - (SeqCst, Acquire) => intrinsics::atomic_cxchgweak_failacq(dst, old, new), + (AcqRel, Relaxed) => intrinsics::atomic_cxchgweak_acqrel_failrelaxed(dst, old, new), + (SeqCst, Relaxed) => intrinsics::atomic_cxchgweak_failrelaxed(dst, old, new), + (SeqCst, Acquire) => intrinsics::atomic_cxchgweak_failacq(dst, old, new), (_, AcqRel) => panic!("there is no such thing as an acquire/release failure ordering"), (_, Release) => panic!("there is no such thing as a release failure ordering"), _ => panic!("a failure ordering can't be stronger than a success ordering"), }; - if ok { - Ok(val) - } else { - Err(val) - } + if ok { Ok(val) } else { Err(val) } } #[inline] @@ -1388,9 +1390,9 @@ unsafe fn atomic_and(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_and_acq(dst, val), Release => intrinsics::atomic_and_rel(dst, val), - AcqRel => intrinsics::atomic_and_acqrel(dst, val), + AcqRel => intrinsics::atomic_and_acqrel(dst, val), Relaxed => intrinsics::atomic_and_relaxed(dst, val), - SeqCst => intrinsics::atomic_and(dst, val) + SeqCst => intrinsics::atomic_and(dst, val), } } @@ -1399,9 +1401,9 @@ unsafe fn atomic_or(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_or_acq(dst, val), Release => intrinsics::atomic_or_rel(dst, val), - AcqRel => intrinsics::atomic_or_acqrel(dst, val), + AcqRel => intrinsics::atomic_or_acqrel(dst, val), Relaxed => intrinsics::atomic_or_relaxed(dst, val), - SeqCst => intrinsics::atomic_or(dst, val) + SeqCst => intrinsics::atomic_or(dst, val), } } @@ -1410,9 +1412,9 @@ unsafe fn atomic_xor(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_xor_acq(dst, val), Release => intrinsics::atomic_xor_rel(dst, val), - AcqRel => intrinsics::atomic_xor_acqrel(dst, val), + AcqRel => intrinsics::atomic_xor_acqrel(dst, val), Relaxed => intrinsics::atomic_xor_relaxed(dst, val), - SeqCst => intrinsics::atomic_xor(dst, val) + SeqCst => intrinsics::atomic_xor(dst, val), } } @@ -1443,9 +1445,9 @@ pub fn fence(order: Ordering) { match order { Acquire => intrinsics::atomic_fence_acq(), Release => intrinsics::atomic_fence_rel(), - AcqRel => intrinsics::atomic_fence_acqrel(), - SeqCst => intrinsics::atomic_fence(), - Relaxed => panic!("there is no such thing as a relaxed fence") + AcqRel => intrinsics::atomic_fence_acqrel(), + SeqCst => intrinsics::atomic_fence(), + Relaxed => panic!("there is no such thing as a relaxed fence"), } } } diff --git a/src/libpanic_unwind/dwarf/eh.rs b/src/libpanic_unwind/dwarf/eh.rs index 2284a9bbb73e1..e7994f4e0ef0a 100644 --- a/src/libpanic_unwind/dwarf/eh.rs +++ b/src/libpanic_unwind/dwarf/eh.rs @@ -116,7 +116,7 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext) -> EHAction { // The "IP" is an index into the call-site table, with two exceptions: // -1 means 'no-action', and 0 means 'terminate'. match ip as isize { - -1 => return EHAction::None, + -1 => return EHAction::None, 0 => return EHAction::Terminate, _ => (), } @@ -182,12 +182,8 @@ unsafe fn read_encoded_pointer(reader: &mut DwarfReader, assert!(context.func_start != 0); context.func_start } - DW_EH_PE_textrel => { - (*context.get_text_start)() - } - DW_EH_PE_datarel => { - (*context.get_data_start)() - } + DW_EH_PE_textrel => (*context.get_text_start)(), + DW_EH_PE_datarel => (*context.get_data_start)(), _ => panic!(), }; diff --git a/src/libpanic_unwind/emcc.rs b/src/libpanic_unwind/emcc.rs index b3ab1117674ca..0e48e37c92358 100644 --- a/src/libpanic_unwind/emcc.rs +++ b/src/libpanic_unwind/emcc.rs @@ -57,13 +57,10 @@ unsafe extern "C" fn rust_eh_personality(version: c_int, exception_object: *mut uw::_Unwind_Exception, context: *mut uw::_Unwind_Context) -> uw::_Unwind_Reason_Code { - __gxx_personality_v0(version, actions, - exception_class, - exception_object, - context) + __gxx_personality_v0(version, actions, exception_class, exception_object, context) } -extern { +extern "C" { fn __cxa_allocate_exception(thrown_size: libc::size_t) -> *mut libc::c_void; fn __cxa_free_exception(thrown_exception: *mut libc::c_void); fn __cxa_throw(thrown_exception: *mut libc::c_void, diff --git a/src/libpanic_unwind/gcc.rs b/src/libpanic_unwind/gcc.rs index b0e05ff205866..f0f19be3366bd 100644 --- a/src/libpanic_unwind/gcc.rs +++ b/src/libpanic_unwind/gcc.rs @@ -156,14 +156,16 @@ unsafe extern "C" fn rust_eh_personality(version: c_int, let eh_action = find_eh_action(context); if actions as i32 & uw::_UA_SEARCH_PHASE as i32 != 0 { match eh_action { - EHAction::None | EHAction::Cleanup(_) => return uw::_URC_CONTINUE_UNWIND, + EHAction::None | + EHAction::Cleanup(_) => return uw::_URC_CONTINUE_UNWIND, EHAction::Catch(_) => return uw::_URC_HANDLER_FOUND, EHAction::Terminate => return uw::_URC_FATAL_PHASE1_ERROR, } } else { match eh_action { EHAction::None => return uw::_URC_CONTINUE_UNWIND, - EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => { + EHAction::Cleanup(lpad) | + EHAction::Catch(lpad) => { uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0, exception_object as uintptr_t); uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, 0); uw::_Unwind_SetIP(context, lpad); @@ -182,7 +184,7 @@ unsafe extern "C" fn rust_eh_personality(version: c_int, unsafe extern "C" fn rust_eh_personality(state: uw::_Unwind_State, exception_object: *mut uw::_Unwind_Exception, context: *mut uw::_Unwind_Context) - -> uw::_Unwind_Reason_Code { + -> uw::_Unwind_Reason_Code { let state = state as c_int; let action = state & uw::_US_ACTION_MASK as c_int; let search_phase = if action == uw::_US_VIRTUAL_UNWIND_FRAME as c_int { @@ -191,7 +193,7 @@ unsafe extern "C" fn rust_eh_personality(state: uw::_Unwind_State, // we want to continue unwinding the stack, otherwise all our backtraces // would end at __rust_try if state & uw::_US_FORCE_UNWIND as c_int != 0 { - return continue_unwind(exception_object, context) + return continue_unwind(exception_object, context); } true } else if action == uw::_US_UNWIND_FRAME_STARTING as c_int { @@ -207,7 +209,9 @@ unsafe extern "C" fn rust_eh_personality(state: uw::_Unwind_State, // To preserve signatures of functions like _Unwind_GetLanguageSpecificData(), which // take only the context pointer, GCC personality routines stash a pointer to exception_object // in the context, using location reserved for ARM's "scratch register" (r12). - uw::_Unwind_SetGR(context, uw::UNWIND_POINTER_REG, exception_object as uw::_Unwind_Ptr); + uw::_Unwind_SetGR(context, + uw::UNWIND_POINTER_REG, + exception_object as uw::_Unwind_Ptr); // ...A more principled approach would be to provide the full definition of ARM's // _Unwind_Context in our libunwind bindings and fetch the required data from there directly, // bypassing DWARF compatibility functions. @@ -223,7 +227,8 @@ unsafe extern "C" fn rust_eh_personality(state: uw::_Unwind_State, } else { match eh_action { EHAction::None => return continue_unwind(exception_object, context), - EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => { + EHAction::Cleanup(lpad) | + EHAction::Catch(lpad) => { uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0, exception_object as uintptr_t); uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, 0); uw::_Unwind_SetIP(context, lpad); @@ -247,8 +252,8 @@ unsafe extern "C" fn rust_eh_personality(state: uw::_Unwind_State, // defined in libgcc extern "C" { fn __gnu_unwind_frame(exception_object: *mut uw::_Unwind_Exception, - context: *mut uw::_Unwind_Context) - -> uw::_Unwind_Reason_Code; + context: *mut uw::_Unwind_Context) + -> uw::_Unwind_Reason_Code; } } diff --git a/src/libpanic_unwind/seh64_gnu.rs b/src/libpanic_unwind/seh64_gnu.rs index e6d3920b29cb0..d4906b556b31a 100644 --- a/src/libpanic_unwind/seh64_gnu.rs +++ b/src/libpanic_unwind/seh64_gnu.rs @@ -129,7 +129,8 @@ unsafe fn find_landing_pad(dc: &c::DISPATCHER_CONTEXT) -> Option { }; match find_eh_action(dc.HandlerData, &eh_ctx) { EHAction::None => None, - EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => Some(lpad), + EHAction::Cleanup(lpad) | + EHAction::Catch(lpad) => Some(lpad), EHAction::Terminate => intrinsics::abort(), } } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 137c6b58dc998..80340f9a9255b 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -401,6 +401,7 @@ impl<'a> LoweringContext<'a> { bounds: self.lower_bounds(&tp.bounds), default: tp.default.as_ref().map(|x| self.lower_ty(x)), span: tp.span, + pure_wrt_drop: tp.attrs.iter().any(|attr| attr.check_name("may_dangle")), } } @@ -420,6 +421,7 @@ impl<'a> LoweringContext<'a> { hir::LifetimeDef { lifetime: self.lower_lifetime(&l.lifetime), bounds: self.lower_lifetimes(&l.bounds), + pure_wrt_drop: l.attrs.iter().any(|attr| attr.check_name("may_dangle")), } } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index f64b0e9c7342c..6e81c3e700ed2 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -95,6 +95,7 @@ impl fmt::Debug for Lifetime { pub struct LifetimeDef { pub lifetime: Lifetime, pub bounds: HirVec, + pub pure_wrt_drop: bool, } /// A "Path" is essentially Rust's notion of a name; for instance: @@ -290,6 +291,7 @@ pub struct TyParam { pub bounds: TyParamBounds, pub default: Option>, pub span: Span, + pub pure_wrt_drop: bool, } /// Represents lifetimes and type parameters attached to a declaration @@ -328,6 +330,36 @@ impl Generics { } } +pub enum UnsafeGeneric { + Region(LifetimeDef, &'static str), + Type(TyParam, &'static str), +} + +impl UnsafeGeneric { + pub fn attr_name(&self) -> &'static str { + match *self { + UnsafeGeneric::Region(_, s) => s, + UnsafeGeneric::Type(_, s) => s, + } + } +} + +impl Generics { + pub fn carries_unsafe_attr(&self) -> Option { + for r in &self.lifetimes { + if r.pure_wrt_drop { + return Some(UnsafeGeneric::Region(r.clone(), "may_dangle")); + } + } + for t in &self.ty_params { + if t.pure_wrt_drop { + return Some(UnsafeGeneric::Type(t.clone(), "may_dangle")); + } + } + return None; + } +} + /// A `where` clause in a definition #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct WhereClause { diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 373ea4aac57b0..be6594320244d 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -1231,16 +1231,17 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> { lifetime: hir::Lifetime, region_names: &HashSet) -> hir::HirVec { - ty_params.iter().map(|ty_param| { - let bounds = self.rebuild_ty_param_bounds(ty_param.bounds.clone(), + ty_params.into_iter().map(|ty_param| { + let bounds = self.rebuild_ty_param_bounds(ty_param.bounds, lifetime, region_names); hir::TyParam { name: ty_param.name, id: ty_param.id, bounds: bounds, - default: ty_param.default.clone(), + default: ty_param.default, span: ty_param.span, + pure_wrt_drop: ty_param.pure_wrt_drop, } }).collect() } @@ -1299,8 +1300,11 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> { -> hir::Generics { let mut lifetimes = Vec::new(); for lt in add { - lifetimes.push(hir::LifetimeDef { lifetime: *lt, - bounds: hir::HirVec::new() }); + lifetimes.push(hir::LifetimeDef { + lifetime: *lt, + bounds: hir::HirVec::new(), + pure_wrt_drop: false, + }); } for lt in &generics.lifetimes { if keep.contains(<.lifetime.name) || diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index dfd6256c35773..b54862ae0ade6 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -35,7 +35,6 @@ use session::Session; use session::search_paths::PathKind; use util::nodemap::{NodeSet, DefIdMap}; use std::path::PathBuf; -use std::rc::Rc; use syntax::ast; use syntax::attr; use syntax::ext::base::MultiItemModifier; @@ -425,7 +424,7 @@ pub struct LoadedMacro { pub enum LoadedMacroKind { Def(ast::MacroDef), - CustomDerive(String, Rc), + CustomDerive(String, Box), } pub trait CrateLoader { diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index ec6843eb75d1f..5ce43d905ec71 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -597,7 +597,8 @@ impl<'a, 'gcx, 'tcx> Struct { -> Result, LayoutError<'gcx>> { let tcx = infcx.tcx.global_tcx(); match (ty.layout(infcx)?, &ty.sty) { - (&Scalar { non_zero: true, .. }, _) => Ok(Some(vec![])), + (&Scalar { non_zero: true, .. }, _) | + (&CEnum { non_zero: true, .. }, _) => Ok(Some(vec![])), (&FatPointer { non_zero: true, .. }, _) => { Ok(Some(vec![FAT_PTR_ADDR as u32])) } @@ -769,6 +770,7 @@ pub enum Layout { CEnum { discr: Integer, signed: bool, + non_zero: bool, // Inclusive discriminant range. // If min > max, it represents min...u64::MAX followed by 0...max. // FIXME(eddyb) always use the shortest range, e.g. by finding @@ -1002,9 +1004,10 @@ impl<'a, 'gcx, 'tcx> Layout { if def.is_enum() && def.variants.iter().all(|v| v.fields.is_empty()) { // All bodies empty -> intlike - let (mut min, mut max) = (i64::MAX, i64::MIN); + let (mut min, mut max, mut non_zero) = (i64::MAX, i64::MIN, true); for v in &def.variants { let x = v.disr_val.to_u64_unchecked() as i64; + if x == 0 { non_zero = false; } if x < min { min = x; } if x > max { max = x; } } @@ -1013,6 +1016,7 @@ impl<'a, 'gcx, 'tcx> Layout { return success(CEnum { discr: discr, signed: signed, + non_zero: non_zero, min: min as u64, max: max as u64 }); @@ -1069,19 +1073,17 @@ impl<'a, 'gcx, 'tcx> Layout { // FIXME(eddyb) should take advantage of a newtype. if path == &[0] && variants[discr].len() == 1 { - match *variants[discr][0].layout(infcx)? { - Scalar { value, .. } => { - return success(RawNullablePointer { - nndiscr: discr as u64, - value: value - }); - } - _ => { - bug!("Layout::compute: `{}`'s non-zero \ - `{}` field not scalar?!", - ty, variants[discr][0]) - } - } + let value = match *variants[discr][0].layout(infcx)? { + Scalar { value, .. } => value, + CEnum { discr, .. } => Int(discr), + _ => bug!("Layout::compute: `{}`'s non-zero \ + `{}` field not scalar?!", + ty, variants[discr][0]) + }; + return success(RawNullablePointer { + nndiscr: discr as u64, + value: value, + }); } path.push(0); // For GEP through a pointer. diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index d1fa2128842ba..03d0e1e41be2e 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -680,6 +680,11 @@ pub struct TypeParameterDef<'tcx> { pub default_def_id: DefId, // for use in error reporing about defaults pub default: Option>, pub object_lifetime_default: ObjectLifetimeDefault<'tcx>, + + /// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute + /// on generic parameter `T`, asserts data behind the parameter + /// `T` won't be accessed during the parent type's `Drop` impl. + pub pure_wrt_drop: bool, } #[derive(Clone, RustcEncodable, RustcDecodable)] @@ -688,6 +693,11 @@ pub struct RegionParameterDef<'tcx> { pub def_id: DefId, pub index: u32, pub bounds: Vec<&'tcx ty::Region>, + + /// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute + /// on generic parameter `'a`, asserts data of lifetime `'a` + /// won't be accessed during the parent type's `Drop` impl. + pub pure_wrt_drop: bool, } impl<'tcx> RegionParameterDef<'tcx> { @@ -732,6 +742,14 @@ impl<'tcx> Generics<'tcx> { pub fn count(&self) -> usize { self.parent_count() + self.own_count() } + + pub fn region_param(&self, param: &EarlyBoundRegion) -> &RegionParameterDef<'tcx> { + &self.regions[param.index as usize - self.has_self as usize] + } + + pub fn type_param(&self, param: &ParamTy) -> &TypeParameterDef<'tcx> { + &self.types[param.idx as usize - self.has_self as usize - self.regions.len()] + } } /// Bounds on generics. diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 5948e02620eca..49683c634692c 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -716,6 +716,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> { default: self.default.fold_with(folder), default_def_id: self.default_def_id, object_lifetime_default: self.object_lifetime_default.fold_with(folder), + pure_wrt_drop: self.pure_wrt_drop, } } @@ -754,6 +755,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::RegionParameterDef<'tcx> { def_id: self.def_id, index: self.index, bounds: self.bounds.fold_with(folder), + pure_wrt_drop: self.pure_wrt_drop, } } diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 7d7bbd931225f..e82da3c395831 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -304,8 +304,15 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - let params = self.iter().map(|k| k.fold_with(folder)).collect(); - folder.tcx().mk_substs(params) + let params: Vec<_> = self.iter().map(|k| k.fold_with(folder)).collect(); + + // If folding doesn't change the substs, it's faster to avoid + // calling `mk_substs` and instead reuse the existing substs. + if params[..] == self[..] { + self + } else { + folder.tcx().mk_substs(params) + } } fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { diff --git a/src/librustc_data_structures/blake2b.rs b/src/librustc_data_structures/blake2b.rs new file mode 100644 index 0000000000000..996df2e7fcfca --- /dev/null +++ b/src/librustc_data_structures/blake2b.rs @@ -0,0 +1,286 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +// An implementation of the Blake2b cryptographic hash function. +// The implementation closely follows: https://tools.ietf.org/html/rfc7693 +// +// "BLAKE2 is a cryptographic hash function faster than MD5, SHA-1, SHA-2, and +// SHA-3, yet is at least as secure as the latest standard SHA-3." +// according to their own website :) +// +// Indeed this implementation is two to three times as fast as our SHA-256 +// implementation. If you have the luxury of being able to use crates from +// crates.io, you can go there and find still faster implementations. + +pub struct Blake2bCtx { + b: [u8; 128], + h: [u64; 8], + t: [u64; 2], + c: usize, + outlen: usize, +} + +impl ::std::fmt::Debug for Blake2bCtx { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + write!(fmt, "{:?}", self.h) + } +} + +#[inline(always)] +fn b2b_g(v: &mut [u64; 16], + a: usize, + b: usize, + c: usize, + d: usize, + x: u64, + y: u64) +{ + v[a] = v[a].wrapping_add(v[b]).wrapping_add(x); + v[d] = (v[d] ^ v[a]).rotate_right(32); + v[c] = v[c].wrapping_add(v[d]); + v[b] = (v[b] ^ v[c]).rotate_right(24); + v[a] = v[a].wrapping_add(v[b]).wrapping_add(y); + v[d] = (v[d] ^ v[a]).rotate_right(16); + v[c] = v[c].wrapping_add(v[d]); + v[b] = (v[b] ^ v[c]).rotate_right(63); +} + +// Initialization vector +const BLAKE2B_IV: [u64; 8] = [ + 0x6A09E667F3BCC908, 0xBB67AE8584CAA73B, + 0x3C6EF372FE94F82B, 0xA54FF53A5F1D36F1, + 0x510E527FADE682D1, 0x9B05688C2B3E6C1F, + 0x1F83D9ABFB41BD6B, 0x5BE0CD19137E2179 +]; + +fn blake2b_compress(ctx: &mut Blake2bCtx, last: bool) { + + const SIGMA: [[usize; 16]; 12] = [ + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ], + [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 ], + [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 ], + [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 ], + [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 ], + [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 ], + [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 ], + [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 ], + [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 ], + [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 ], + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ], + [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 ] + ]; + + let mut v: [u64; 16] = [ + ctx.h[0], + ctx.h[1], + ctx.h[2], + ctx.h[3], + ctx.h[4], + ctx.h[5], + ctx.h[6], + ctx.h[7], + + BLAKE2B_IV[0], + BLAKE2B_IV[1], + BLAKE2B_IV[2], + BLAKE2B_IV[3], + BLAKE2B_IV[4], + BLAKE2B_IV[5], + BLAKE2B_IV[6], + BLAKE2B_IV[7], + ]; + + v[12] ^= ctx.t[0]; // low 64 bits of offset + v[13] ^= ctx.t[1]; // high 64 bits + if last { + v[14] = !v[14]; + } + + { + // Re-interpret the input buffer in the state as u64s + let m: &mut [u64; 16] = unsafe { + let b: &mut [u8; 128] = &mut ctx.b; + ::std::mem::transmute(b) + }; + + // It's OK to modify the buffer in place since this is the last time + // this data will be accessed before it's overwritten + if cfg!(target_endian = "big") { + for word in &mut m[..] { + *word = word.to_be(); + } + } + + for i in 0 .. 12 { + b2b_g(&mut v, 0, 4, 8, 12, m[SIGMA[i][ 0]], m[SIGMA[i][ 1]]); + b2b_g(&mut v, 1, 5, 9, 13, m[SIGMA[i][ 2]], m[SIGMA[i][ 3]]); + b2b_g(&mut v, 2, 6, 10, 14, m[SIGMA[i][ 4]], m[SIGMA[i][ 5]]); + b2b_g(&mut v, 3, 7, 11, 15, m[SIGMA[i][ 6]], m[SIGMA[i][ 7]]); + b2b_g(&mut v, 0, 5, 10, 15, m[SIGMA[i][ 8]], m[SIGMA[i][ 9]]); + b2b_g(&mut v, 1, 6, 11, 12, m[SIGMA[i][10]], m[SIGMA[i][11]]); + b2b_g(&mut v, 2, 7, 8, 13, m[SIGMA[i][12]], m[SIGMA[i][13]]); + b2b_g(&mut v, 3, 4, 9, 14, m[SIGMA[i][14]], m[SIGMA[i][15]]); + } + } + + for i in 0 .. 8 { + ctx.h[i] ^= v[i] ^ v[i + 8]; + } +} + +pub fn blake2b_new(outlen: usize, key: &[u8]) -> Blake2bCtx { + assert!(outlen > 0 && outlen <= 64 && key.len() <= 64); + + let mut ctx = Blake2bCtx { + b: [0; 128], + h: BLAKE2B_IV, + t: [0; 2], + c: 0, + outlen: outlen, + }; + + ctx.h[0] ^= 0x01010000 ^ ((key.len() << 8) as u64) ^ (outlen as u64); + + if key.len() > 0 { + blake2b_update(&mut ctx, key); + ctx.c = ctx.b.len(); + } + + ctx +} + +pub fn blake2b_update(ctx: &mut Blake2bCtx, mut data: &[u8]) +{ + let mut bytes_to_copy = data.len(); + let mut space_in_buffer = ctx.b.len() - ctx.c; + + while bytes_to_copy > space_in_buffer { + checked_mem_copy(data, &mut ctx.b[ctx.c .. ], space_in_buffer); + + ctx.t[0] = ctx.t[0].wrapping_add(ctx.b.len() as u64); + if ctx.t[0] < (ctx.b.len() as u64) { + ctx.t[1] += 1; + } + blake2b_compress(ctx, false); + ctx.c = 0; + + data = &data[space_in_buffer .. ]; + bytes_to_copy -= space_in_buffer; + space_in_buffer = ctx.b.len(); + } + + if bytes_to_copy > 0 { + checked_mem_copy(data, &mut ctx.b[ctx.c .. ], bytes_to_copy); + ctx.c += bytes_to_copy; + } +} + +pub fn blake2b_final(mut ctx: Blake2bCtx, out: &mut [u8]) +{ + ctx.t[0] = ctx.t[0].wrapping_add(ctx.c as u64); + if ctx.t[0] < ctx.c as u64 { + ctx.t[1] += 1; + } + + while ctx.c < 128 { + ctx.b[ctx.c] = 0; + ctx.c += 1; + } + + blake2b_compress(&mut ctx, true); + + if cfg!(target_endian = "big") { + // Make sure that the data is in memory in little endian format, as is + // demanded by BLAKE2 + for word in &mut ctx.h { + *word = word.to_le(); + } + } + + checked_mem_copy(&ctx.h, out, ctx.outlen); +} + +#[inline(always)] +fn checked_mem_copy(from: &[T1], to: &mut [T2], byte_count: usize) { + let from_size = from.len() * ::std::mem::size_of::(); + let to_size = to.len() * ::std::mem::size_of::(); + assert!(from_size >= byte_count); + assert!(to_size >= byte_count); + let from_byte_ptr = from.as_ptr() as * const u8; + let to_byte_ptr = to.as_mut_ptr() as * mut u8; + unsafe { + ::std::ptr::copy_nonoverlapping(from_byte_ptr, to_byte_ptr, byte_count); + } +} + +pub fn blake2b(out: &mut [u8], key: &[u8], data: &[u8]) +{ + let mut ctx = blake2b_new(out.len(), key); + blake2b_update(&mut ctx, data); + blake2b_final(ctx, out); +} + +#[cfg(test)] +fn selftest_seq(out: &mut [u8], seed: u32) +{ + let mut a: u32 = 0xDEAD4BADu32.wrapping_mul(seed); + let mut b: u32 = 1; + + for i in 0 .. out.len() { + let t: u32 = a.wrapping_add(b); + a = b; + b = t; + out[i] = ((t >> 24) & 0xFF) as u8; + } +} + +#[test] +fn blake2b_selftest() +{ + // grand hash of hash results + const BLAKE2B_RES: [u8; 32] = [ + 0xC2, 0x3A, 0x78, 0x00, 0xD9, 0x81, 0x23, 0xBD, + 0x10, 0xF5, 0x06, 0xC6, 0x1E, 0x29, 0xDA, 0x56, + 0x03, 0xD7, 0x63, 0xB8, 0xBB, 0xAD, 0x2E, 0x73, + 0x7F, 0x5E, 0x76, 0x5A, 0x7B, 0xCC, 0xD4, 0x75 + ]; + + // parameter sets + const B2B_MD_LEN: [usize; 4] = [20, 32, 48, 64]; + const B2B_IN_LEN: [usize; 6] = [0, 3, 128, 129, 255, 1024]; + + let mut data = [0u8; 1024]; + let mut md = [0u8; 64]; + let mut key = [0u8; 64]; + + let mut ctx = blake2b_new(32, &[]); + + for i in 0 .. 4 { + let outlen = B2B_MD_LEN[i]; + for j in 0 .. 6 { + let inlen = B2B_IN_LEN[j]; + + selftest_seq(&mut data[.. inlen], inlen as u32); // unkeyed hash + blake2b(&mut md[.. outlen], &[], &data[.. inlen]); + blake2b_update(&mut ctx, &md[.. outlen]); // hash the hash + + selftest_seq(&mut key[0 .. outlen], outlen as u32); // keyed hash + blake2b(&mut md[.. outlen], &key[.. outlen], &data[.. inlen]); + blake2b_update(&mut ctx, &md[.. outlen]); // hash the hash + } + } + + // compute and compare the hash of hashes + blake2b_final(ctx, &mut md[..]); + for i in 0 .. 32 { + assert_eq!(md[i], BLAKE2B_RES[i]); + } +} diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index c8f4d766153cf..26b9f48ad04dd 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -42,6 +42,7 @@ extern crate serialize as rustc_serialize; // used by deriving extern crate libc; pub mod bitslice; +pub mod blake2b; pub mod bitvec; pub mod graph; pub mod ivar; diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index c079146edbf42..5e590cb445f79 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -333,6 +333,7 @@ impl ObligationForest { } } Err(err) => { + stalled = false; let backtrace = self.error_at(index); errors.push(Error { error: err, @@ -342,6 +343,16 @@ impl ObligationForest { } } + if stalled { + // There's no need to perform marking, cycle processing and compression when nothing + // changed. + return Outcome { + completed: vec![], + errors: errors, + stalled: stalled, + }; + } + self.mark_as_waiting(); self.process_cycles(processor); diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 1d7ff45b3b8a0..a307e9b696def 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -51,8 +51,8 @@ impl ColorConfig { fn use_color(&self) -> bool { match *self { ColorConfig::Always => true, - ColorConfig::Never => false, - ColorConfig::Auto => stderr_isatty(), + ColorConfig::Never => false, + ColorConfig::Auto => stderr_isatty(), } } } @@ -83,22 +83,22 @@ macro_rules! println_maybe_styled { } impl EmitterWriter { - pub fn stderr(color_config: ColorConfig, - code_map: Option>) - -> EmitterWriter { + pub fn stderr(color_config: ColorConfig, code_map: Option>) -> EmitterWriter { if color_config.use_color() { let dst = Destination::from_stderr(); - EmitterWriter { dst: dst, - cm: code_map} + EmitterWriter { + dst: dst, + cm: code_map, + } } else { - EmitterWriter { dst: Raw(Box::new(io::stderr())), - cm: code_map} + EmitterWriter { + dst: Raw(Box::new(io::stderr())), + cm: code_map, + } } } - pub fn new(dst: Box, - code_map: Option>) - -> EmitterWriter { + pub fn new(dst: Box, code_map: Option>) -> EmitterWriter { EmitterWriter { dst: Raw(dst), cm: code_map, @@ -107,9 +107,9 @@ impl EmitterWriter { fn preprocess_annotations(&self, msp: &MultiSpan) -> Vec { fn add_annotation_to_file(file_vec: &mut Vec, - file: Rc, - line_index: usize, - ann: Annotation) { + file: Rc, + line_index: usize, + ann: Annotation) { for slot in file_vec.iter_mut() { // Look through each of our files for the one we're adding to @@ -168,15 +168,15 @@ impl EmitterWriter { } add_annotation_to_file(&mut output, - lo.file, - lo.line, - Annotation { - start_col: lo.col.0, - end_col: hi.col.0, - is_primary: span_label.is_primary, - is_minimized: is_minimized, - label: span_label.label.clone(), - }); + lo.file, + lo.line, + Annotation { + start_col: lo.col.0, + end_col: hi.col.0, + is_primary: span_label.is_primary, + is_minimized: is_minimized, + label: span_label.label.clone(), + }); } } output @@ -237,9 +237,7 @@ impl EmitterWriter { '^', Style::UnderlinePrimary); if !annotation.is_minimized { - buffer.set_style(line_offset, - width_offset + p, - Style::UnderlinePrimary); + buffer.set_style(line_offset, width_offset + p, Style::UnderlinePrimary); } } else { buffer.putc(line_offset + 1, @@ -247,9 +245,7 @@ impl EmitterWriter { '-', Style::UnderlineSecondary); if !annotation.is_minimized { - buffer.set_style(line_offset, - width_offset + p, - Style::UnderlineSecondary); + buffer.set_style(line_offset, width_offset + p, Style::UnderlineSecondary); } } } @@ -429,8 +425,7 @@ impl EmitterWriter { } // Check to make sure we're not in any <*macros> if !cm.span_to_filename(def_site).contains("macros>") && - !trace.macro_decl_name.starts_with("#[") - { + !trace.macro_decl_name.starts_with("#[") { new_labels.push((trace.call_site, "in this macro invocation".to_string())); break; @@ -475,10 +470,10 @@ impl EmitterWriter { if spans_updated { children.push(SubDiagnostic { level: Level::Note, - message:"this error originates in a macro outside of the current \ - crate".to_string(), + message: "this error originates in a macro outside of the current crate" + .to_string(), span: MultiSpan::new(), - render_span: None + render_span: None, }); } } @@ -502,8 +497,7 @@ impl EmitterWriter { buffer.append(0, &level.to_string(), Style::HeaderMsg); buffer.append(0, ": ", Style::NoStyle); buffer.append(0, msg, Style::NoStyle); - } - else { + } else { buffer.append(0, &level.to_string(), Style::Level(level.clone())); match code { &Some(ref code) => { @@ -522,23 +516,21 @@ impl EmitterWriter { let mut annotated_files = self.preprocess_annotations(msp); // Make sure our primary file comes first - let primary_lo = - if let (Some(ref cm), Some(ref primary_span)) = (self.cm.as_ref(), - msp.primary_span().as_ref()) { - if primary_span != &&DUMMY_SP && primary_span != &&COMMAND_LINE_SP { - cm.lookup_char_pos(primary_span.lo) - } - else { - emit_to_destination(&buffer.render(), level, &mut self.dst)?; - return Ok(()); - } + let primary_lo = if let (Some(ref cm), Some(ref primary_span)) = + (self.cm.as_ref(), msp.primary_span().as_ref()) { + if primary_span != &&DUMMY_SP && primary_span != &&COMMAND_LINE_SP { + cm.lookup_char_pos(primary_span.lo) } else { - // If we don't have span information, emit and exit emit_to_destination(&buffer.render(), level, &mut self.dst)?; return Ok(()); - }; + } + } else { + // If we don't have span information, emit and exit + emit_to_destination(&buffer.render(), level, &mut self.dst)?; + return Ok(()); + }; if let Ok(pos) = - annotated_files.binary_search_by(|x| x.file.name.cmp(&primary_lo.file.name)) { + annotated_files.binary_search_by(|x| x.file.name.cmp(&primary_lo.file.name)) { annotated_files.swap(0, pos); } @@ -554,8 +546,8 @@ impl EmitterWriter { buffer.prepend(buffer_msg_line_offset, "--> ", Style::LineNumber); let loc = primary_lo.clone(); buffer.append(buffer_msg_line_offset, - &format!("{}:{}:{}", loc.file.name, loc.line, loc.col.0 + 1), - Style::LineAndColumn); + &format!("{}:{}:{}", loc.file.name, loc.line, loc.col.0 + 1), + Style::LineAndColumn); for _ in 0..max_line_num_len { buffer.prepend(buffer_msg_line_offset, " ", Style::NoStyle); } @@ -569,8 +561,8 @@ impl EmitterWriter { // Then, the secondary file indicator buffer.prepend(buffer_msg_line_offset + 1, "::: ", Style::LineNumber); buffer.append(buffer_msg_line_offset + 1, - &annotated_file.file.name, - Style::LineAndColumn); + &annotated_file.file.name, + Style::LineAndColumn); for _ in 0..max_line_num_len { buffer.prepend(buffer_msg_line_offset + 1, " ", Style::NoStyle); } @@ -591,7 +583,7 @@ impl EmitterWriter { // this annotated line and the next one if line_idx < (annotated_file.lines.len() - 1) { let line_idx_delta = annotated_file.lines[line_idx + 1].line_index - - annotated_file.lines[line_idx].line_index; + annotated_file.lines[line_idx].line_index; if line_idx_delta > 2 { let last_buffer_line_num = buffer.num_lines(); buffer.puts(last_buffer_line_num, 0, "...", Style::LineNumber); @@ -672,12 +664,7 @@ impl EmitterWriter { let max_line_num = self.get_max_line_num(span, children); let max_line_num_len = max_line_num.to_string().len(); - match self.emit_message_default(span, - message, - code, - level, - max_line_num_len, - false) { + match self.emit_message_default(span, message, code, level, max_line_num_len, false) { Ok(()) => { if !children.is_empty() { let mut buffer = StyledBuffer::new(); @@ -723,13 +710,15 @@ impl EmitterWriter { } } } - Err(e) => panic!("failed to emit error: {}", e) + Err(e) => panic!("failed to emit error: {}", e), } match write!(&mut self.dst, "\n") { Err(e) => panic!("failed to emit error: {}", e), - _ => match self.dst.flush() { - Err(e) => panic!("failed to emit error: {}", e), - _ => () + _ => { + match self.dst.flush() { + Err(e) => panic!("failed to emit error: {}", e), + _ => (), + } } } } @@ -753,8 +742,9 @@ fn overlaps(a1: &Annotation, a2: &Annotation) -> bool { } fn emit_to_destination(rendered_buffer: &Vec>, - lvl: &Level, - dst: &mut Destination) -> io::Result<()> { + lvl: &Level, + dst: &mut Destination) + -> io::Result<()> { use lock; // In order to prevent error message interleaving, where multiple error lines get intermixed @@ -795,8 +785,7 @@ fn stderr_isatty() -> bool { const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD; extern "system" { fn GetStdHandle(which: DWORD) -> HANDLE; - fn GetConsoleMode(hConsoleHandle: HANDLE, - lpMode: *mut DWORD) -> BOOL; + fn GetConsoleMode(hConsoleHandle: HANDLE, lpMode: *mut DWORD) -> BOOL; } unsafe { let handle = GetStdHandle(STD_ERROR_HANDLE); @@ -824,9 +813,7 @@ impl BufferedWriter { // note: we use _new because the conditional compilation at its use site may make this // this function unused on some platforms fn _new() -> BufferedWriter { - BufferedWriter { - buffer: vec![] - } + BufferedWriter { buffer: vec![] } } } @@ -853,35 +840,34 @@ impl Destination { /// When not on Windows, prefer the buffered terminal so that we can buffer an entire error /// to be emitted at one time. fn from_stderr() -> Destination { - let stderr: Option> = + let stderr: Option> = term::TerminfoTerminal::new(BufferedWriter::_new()) .map(|t| Box::new(t) as Box); match stderr { Some(t) => BufferedTerminal(t), - None => Raw(Box::new(io::stderr())), + None => Raw(Box::new(io::stderr())), } } #[cfg(windows)] /// Return a normal, unbuffered terminal when on Windows. fn from_stderr() -> Destination { - let stderr: Option> = - term::TerminfoTerminal::new(io::stderr()) - .map(|t| Box::new(t) as Box) - .or_else(|| term::WinConsole::new(io::stderr()).ok() - .map(|t| Box::new(t) as Box)); + let stderr: Option> = term::TerminfoTerminal::new(io::stderr()) + .map(|t| Box::new(t) as Box) + .or_else(|| { + term::WinConsole::new(io::stderr()) + .ok() + .map(|t| Box::new(t) as Box) + }); match stderr { Some(t) => Terminal(t), - None => Raw(Box::new(io::stderr())), + None => Raw(Box::new(io::stderr())), } } - fn apply_style(&mut self, - lvl: Level, - style: Style) - -> io::Result<()> { + fn apply_style(&mut self, lvl: Level, style: Style) -> io::Result<()> { match style { Style::FileNameStyle | Style::LineAndColumn => {} Style::LineNumber => { @@ -931,18 +917,26 @@ impl Destination { fn start_attr(&mut self, attr: term::Attr) -> io::Result<()> { match *self { - Terminal(ref mut t) => { t.attr(attr)?; } - BufferedTerminal(ref mut t) => { t.attr(attr)?; } - Raw(_) => { } + Terminal(ref mut t) => { + t.attr(attr)?; + } + BufferedTerminal(ref mut t) => { + t.attr(attr)?; + } + Raw(_) => {} } Ok(()) } fn reset_attrs(&mut self) -> io::Result<()> { match *self { - Terminal(ref mut t) => { t.reset()?; } - BufferedTerminal(ref mut t) => { t.reset()?; } - Raw(_) => { } + Terminal(ref mut t) => { + t.reset()?; + } + BufferedTerminal(ref mut t) => { + t.reset()?; + } + Raw(_) => {} } Ok(()) } diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index af8ac81b4fbb1..25b314256b092 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -28,8 +28,10 @@ extern crate serialize; extern crate term; -#[macro_use] extern crate log; -#[macro_use] extern crate libc; +#[macro_use] +extern crate log; +#[macro_use] +extern crate libc; extern crate rustc_unicode; extern crate serialize as rustc_serialize; // used by deriving extern crate syntax_pos; @@ -52,8 +54,8 @@ pub mod registry; pub mod styled_buffer; mod lock; -use syntax_pos::{BytePos, Loc, FileLinesResult, FileName, MultiSpan, Span, NO_EXPANSION }; -use syntax_pos::{MacroBacktrace}; +use syntax_pos::{BytePos, Loc, FileLinesResult, FileName, MultiSpan, Span, NO_EXPANSION}; +use syntax_pos::MacroBacktrace; #[derive(Clone)] pub enum RenderSpan { @@ -89,9 +91,11 @@ impl CodeSuggestion { pub fn splice_lines(&self, cm: &CodeMapper) -> String { use syntax_pos::{CharPos, Loc, Pos}; - fn push_trailing(buf: &mut String, line_opt: Option<&str>, - lo: &Loc, hi_opt: Option<&Loc>) { - let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi|hi.col.to_usize())); + fn push_trailing(buf: &mut String, + line_opt: Option<&str>, + lo: &Loc, + hi_opt: Option<&Loc>) { + let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize())); if let Some(line) = line_opt { if line.len() > lo { buf.push_str(match hi_opt { @@ -119,7 +123,11 @@ impl CodeSuggestion { // Find the bounding span. let lo = primary_spans.iter().map(|sp| sp.lo).min().unwrap(); let hi = primary_spans.iter().map(|sp| sp.hi).min().unwrap(); - let bounding_span = Span { lo: lo, hi: hi, expn_id: NO_EXPANSION }; + let bounding_span = Span { + lo: lo, + hi: hi, + expn_id: NO_EXPANSION, + }; let lines = cm.span_to_lines(bounding_span).unwrap(); assert!(!lines.lines.is_empty()); @@ -153,7 +161,7 @@ impl CodeSuggestion { } } if let Some(cur_line) = fm.get_line(cur_lo.line - 1) { - buf.push_str(&cur_line[.. cur_lo.col.to_usize()]); + buf.push_str(&cur_line[..cur_lo.col.to_usize()]); } } buf.push_str(substitute); @@ -263,8 +271,7 @@ impl<'a> DiagnosticBuilder<'a> { /// all, and you just supplied a `Span` to create the diagnostic, /// then the snippet will just include that `Span`, which is /// called the primary span. - pub fn span_label(&mut self, span: Span, label: &fmt::Display) - -> &mut DiagnosticBuilder<'a> { + pub fn span_label(&mut self, span: Span, label: &fmt::Display) -> &mut DiagnosticBuilder<'a> { self.span.push_span_label(span, format!("{}", label)); self } @@ -273,8 +280,7 @@ impl<'a> DiagnosticBuilder<'a> { label: &fmt::Display, expected: &fmt::Display, found: &fmt::Display) - -> &mut DiagnosticBuilder<'a> - { + -> &mut DiagnosticBuilder<'a> { self.note_expected_found_extra(label, expected, found, &"", &"") } @@ -284,8 +290,7 @@ impl<'a> DiagnosticBuilder<'a> { found: &fmt::Display, expected_extra: &fmt::Display, found_extra: &fmt::Display) - -> &mut DiagnosticBuilder<'a> - { + -> &mut DiagnosticBuilder<'a> { // For now, just attach these as notes self.note(&format!("expected {} `{}`{}", label, expected, expected_extra)); self.note(&format!(" found {} `{}`{}", label, found, found_extra)); @@ -314,7 +319,7 @@ impl<'a> DiagnosticBuilder<'a> { self.sub(Level::Warning, msg, sp.into(), None); self } - pub fn help(&mut self , msg: &str) -> &mut DiagnosticBuilder<'a> { + pub fn help(&mut self, msg: &str) -> &mut DiagnosticBuilder<'a> { self.sub(Level::Help, msg, MultiSpan::new(), None); self } @@ -333,10 +338,13 @@ impl<'a> DiagnosticBuilder<'a> { msg: &str, suggestion: String) -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Help, msg, MultiSpan::new(), Some(Suggestion(CodeSuggestion { - msp: sp.into(), - substitutes: vec![suggestion], - }))); + self.sub(Level::Help, + msg, + MultiSpan::new(), + Some(Suggestion(CodeSuggestion { + msp: sp.into(), + substitutes: vec![suggestion], + }))); self } @@ -360,18 +368,17 @@ impl<'a> DiagnosticBuilder<'a> { /// Convenience function for internal use, clients should use one of the /// struct_* methods on Handler. - fn new(handler: &'a Handler, - level: Level, - message: &str) -> DiagnosticBuilder<'a> { + fn new(handler: &'a Handler, level: Level, message: &str) -> DiagnosticBuilder<'a> { DiagnosticBuilder::new_with_code(handler, level, None, message) } /// Convenience function for internal use, clients should use one of the /// struct_* methods on Handler. fn new_with_code(handler: &'a Handler, - level: Level, - code: Option, - message: &str) -> DiagnosticBuilder<'a> { + level: Level, + code: Option, + message: &str) + -> DiagnosticBuilder<'a> { DiagnosticBuilder { handler: handler, level: level, @@ -410,9 +417,8 @@ impl<'a> fmt::Debug for DiagnosticBuilder<'a> { impl<'a> Drop for DiagnosticBuilder<'a> { fn drop(&mut self) { if !panicking() && !self.cancelled() { - let mut db = DiagnosticBuilder::new(self.handler, - Bug, - "Error constructed but not emitted"); + let mut db = + DiagnosticBuilder::new(self.handler, Bug, "Error constructed but not emitted"); db.emit(); panic!(); } @@ -443,7 +449,8 @@ impl Handler { pub fn with_emitter(can_emit_warnings: bool, treat_err_as_bug: bool, - e: Box) -> Handler { + e: Box) + -> Handler { Handler { err_count: Cell::new(0), emitter: RefCell::new(e), @@ -544,10 +551,10 @@ impl Handler { pub fn cancel(&self, err: &mut DiagnosticBuilder) { if err.level == Level::Error || err.level == Level::Fatal { - self.err_count.set( - self.err_count.get().checked_sub(1) - .expect("cancelled an error but err_count is 0") - ); + self.err_count.set(self.err_count + .get() + .checked_sub(1) + .expect("cancelled an error but err_count is 0")); } err.cancel(); } @@ -558,14 +565,16 @@ impl Handler { } } - pub fn span_fatal>(&self, sp: S, msg: &str) - -> FatalError { + pub fn span_fatal>(&self, sp: S, msg: &str) -> FatalError { self.emit(&sp.into(), msg, Fatal); self.bump_err_count(); self.panic_if_treat_err_as_bug(); return FatalError; } - pub fn span_fatal_with_code>(&self, sp: S, msg: &str, code: &str) + pub fn span_fatal_with_code>(&self, + sp: S, + msg: &str, + code: &str) -> FatalError { self.emit_with_code(&sp.into(), msg, code, Fatal); self.bump_err_count(); @@ -619,9 +628,7 @@ impl Handler { if self.treat_err_as_bug { self.bug(msg); } - let mut db = DiagnosticBuilder::new(self, - Fatal, - msg); + let mut db = DiagnosticBuilder::new(self, Fatal, msg); db.emit(); self.bump_err_count(); FatalError @@ -630,28 +637,20 @@ impl Handler { if self.treat_err_as_bug { self.bug(msg); } - let mut db = DiagnosticBuilder::new(self, - Error, - msg); + let mut db = DiagnosticBuilder::new(self, Error, msg); db.emit(); self.bump_err_count(); } pub fn warn(&self, msg: &str) { - let mut db = DiagnosticBuilder::new(self, - Warning, - msg); + let mut db = DiagnosticBuilder::new(self, Warning, msg); db.emit(); } pub fn note_without_error(&self, msg: &str) { - let mut db = DiagnosticBuilder::new(self, - Note, - msg); + let mut db = DiagnosticBuilder::new(self, Note, msg); db.emit(); } pub fn bug(&self, msg: &str) -> ! { - let mut db = DiagnosticBuilder::new(self, - Bug, - msg); + let mut db = DiagnosticBuilder::new(self, Bug, msg); db.emit(); panic!(ExplicitBug); } @@ -678,44 +677,41 @@ impl Handler { match *delayed_bug { Some((ref span, ref errmsg)) => { self.span_bug(span.clone(), errmsg); - }, + } _ => {} } return; } 1 => s = "aborting due to previous error".to_string(), - _ => { - s = format!("aborting due to {} previous errors", - self.err_count.get()); + _ => { + s = format!("aborting due to {} previous errors", self.err_count.get()); } } panic!(self.fatal(&s)); } - pub fn emit(&self, - msp: &MultiSpan, - msg: &str, - lvl: Level) { - if lvl == Warning && !self.can_emit_warnings { return } + pub fn emit(&self, msp: &MultiSpan, msg: &str, lvl: Level) { + if lvl == Warning && !self.can_emit_warnings { + return; + } let mut db = DiagnosticBuilder::new(self, lvl, msg); db.set_span(msp.clone()); db.emit(); - if !self.continue_after_error.get() { self.abort_if_errors(); } - } - pub fn emit_with_code(&self, - msp: &MultiSpan, - msg: &str, - code: &str, - lvl: Level) { - if lvl == Warning && !self.can_emit_warnings { return } - let mut db = DiagnosticBuilder::new_with_code(self, - lvl, - Some(code.to_owned()), - msg); + if !self.continue_after_error.get() { + self.abort_if_errors(); + } + } + pub fn emit_with_code(&self, msp: &MultiSpan, msg: &str, code: &str, lvl: Level) { + if lvl == Warning && !self.can_emit_warnings { + return; + } + let mut db = DiagnosticBuilder::new_with_code(self, lvl, Some(code.to_owned()), msg); db.set_span(msp.clone()); db.emit(); - if !self.continue_after_error.get() { self.abort_if_errors(); } + if !self.continue_after_error.get() { + self.abort_if_errors(); + } } } @@ -750,7 +746,7 @@ impl Level { } else { term::color::YELLOW } - }, + } Note => term::color::BRIGHT_GREEN, Help => term::color::BRIGHT_CYAN, Cancelled => unreachable!(), @@ -769,8 +765,8 @@ impl Level { } } -pub fn expect(diag: &Handler, opt: Option, msg: M) -> T where - M: FnOnce() -> String, +pub fn expect(diag: &Handler, opt: Option, msg: M) -> T + where M: FnOnce() -> String { match opt { Some(t) => t, diff --git a/src/librustc_errors/lock.rs b/src/librustc_errors/lock.rs index 0a9e0c4bbefb3..4c298228c37c7 100644 --- a/src/librustc_errors/lock.rs +++ b/src/librustc_errors/lock.rs @@ -40,9 +40,9 @@ pub fn acquire_global_lock(name: &str) -> Box { extern "system" { fn CreateMutexA(lpMutexAttributes: LPSECURITY_ATTRIBUTES, bInitialOwner: BOOL, - lpName: LPCSTR) -> HANDLE; - fn WaitForSingleObject(hHandle: HANDLE, - dwMilliseconds: DWORD) -> DWORD; + lpName: LPCSTR) + -> HANDLE; + fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD; fn ReleaseMutex(hMutex: HANDLE) -> BOOL; fn CloseHandle(hObject: HANDLE) -> BOOL; } @@ -76,7 +76,8 @@ pub fn acquire_global_lock(name: &str) -> Box { // open up a handle to one if it already exists. let mutex = CreateMutexA(0 as *mut _, 0, cname.as_ptr() as *const u8); if mutex.is_null() { - panic!("failed to create global mutex named `{}`: {}", name, + panic!("failed to create global mutex named `{}`: {}", + name, io::Error::last_os_error()); } let mutex = Handle(mutex); @@ -96,8 +97,10 @@ pub fn acquire_global_lock(name: &str) -> Box { WAIT_OBJECT_0 | WAIT_ABANDONED => {} code => { panic!("WaitForSingleObject failed on global mutex named \ - `{}`: {} (ret={:x})", name, - io::Error::last_os_error(), code); + `{}`: {} (ret={:x})", + name, + io::Error::last_os_error(), + code); } } diff --git a/src/librustc_errors/registry.rs b/src/librustc_errors/registry.rs index a6cfd1a5a9ac3..83737681471e2 100644 --- a/src/librustc_errors/registry.rs +++ b/src/librustc_errors/registry.rs @@ -12,7 +12,7 @@ use std::collections::HashMap; #[derive(Clone)] pub struct Registry { - descriptions: HashMap<&'static str, &'static str> + descriptions: HashMap<&'static str, &'static str>, } impl Registry { diff --git a/src/librustc_errors/snippet.rs b/src/librustc_errors/snippet.rs index 5ade8cd9bad82..abfb71c861b25 100644 --- a/src/librustc_errors/snippet.rs +++ b/src/librustc_errors/snippet.rs @@ -13,12 +13,12 @@ use syntax_pos::{Span, FileMap}; use CodeMapper; use std::rc::Rc; -use {Level}; +use Level; #[derive(Clone)] pub struct SnippetData { codemap: Rc, - files: Vec + files: Vec, } #[derive(Clone)] @@ -84,4 +84,4 @@ pub enum Style { NoStyle, ErrorCode, Level(Level), -} \ No newline at end of file +} diff --git a/src/librustc_errors/styled_buffer.rs b/src/librustc_errors/styled_buffer.rs index 9768b68619e79..dfc7c64de0197 100644 --- a/src/librustc_errors/styled_buffer.rs +++ b/src/librustc_errors/styled_buffer.rs @@ -28,10 +28,9 @@ impl StyledBuffer { pub fn copy_tabs(&mut self, row: usize) { if row < self.text.len() { - for i in row+1..self.text.len() { + for i in row + 1..self.text.len() { for j in 0..self.text[i].len() { - if self.text[row].len() > j && - self.text[row][j] == '\t' && + if self.text[row].len() > j && self.text[row][j] == '\t' && self.text[i][j] == ' ' { self.text[i][j] = '\t'; } @@ -44,7 +43,7 @@ impl StyledBuffer { let mut output: Vec> = vec![]; let mut styled_vec: Vec = vec![]; - //before we render, do a little patch-up work to support tabs + // before we render, do a little patch-up work to support tabs self.copy_tabs(3); for (row, row_style) in self.text.iter().zip(&self.styles) { diff --git a/src/librustc_incremental/calculate_svh/hasher.rs b/src/librustc_incremental/calculate_svh/hasher.rs index 28db39d667c4c..d92a8d375e0d3 100644 --- a/src/librustc_incremental/calculate_svh/hasher.rs +++ b/src/librustc_incremental/calculate_svh/hasher.rs @@ -9,20 +9,20 @@ // except according to those terms. use std::hash::Hasher; -use std::collections::hash_map::DefaultHasher; +use std::mem; +use rustc_data_structures::blake2b; +use ich::Fingerprint; #[derive(Debug)] pub struct IchHasher { - // FIXME: this should use SHA1, not DefaultHasher. DefaultHasher is not - // built to avoid collisions. - state: DefaultHasher, + state: blake2b::Blake2bCtx, bytes_hashed: u64, } impl IchHasher { pub fn new() -> IchHasher { IchHasher { - state: DefaultHasher::new(), + state: blake2b::blake2b_new(mem::size_of::(), &[]), bytes_hashed: 0 } } @@ -30,17 +30,43 @@ impl IchHasher { pub fn bytes_hashed(&self) -> u64 { self.bytes_hashed } + + pub fn finish(self) -> Fingerprint { + let mut fingerprint = Fingerprint::zero(); + blake2b::blake2b_final(self.state, &mut fingerprint.0); + fingerprint + } } impl Hasher for IchHasher { - #[inline] fn finish(&self) -> u64 { - self.state.finish() + bug!("Use other finish() implementation to get the full 128-bit hash."); } #[inline] fn write(&mut self, bytes: &[u8]) { - self.state.write(bytes); + blake2b::blake2b_update(&mut self.state, bytes); self.bytes_hashed += bytes.len() as u64; } + + #[inline] + fn write_u16(&mut self, i: u16) { + self.write(&unsafe { mem::transmute::<_, [u8; 2]>(i.to_le()) }) + } + + #[inline] + fn write_u32(&mut self, i: u32) { + self.write(&unsafe { mem::transmute::<_, [u8; 4]>(i.to_le()) }) + } + + #[inline] + fn write_u64(&mut self, i: u64) { + self.write(&unsafe { mem::transmute::<_, [u8; 8]>(i.to_le()) }) + } + + #[inline] + fn write_usize(&mut self, i: usize) { + // always hash as u64, so we don't depend on the size of `usize` + self.write_u64(i as u64); + } } diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index 12627e02debd0..3b0b37bb01ce3 100644 --- a/src/librustc_incremental/calculate_svh/mod.rs +++ b/src/librustc_incremental/calculate_svh/mod.rs @@ -29,7 +29,7 @@ use syntax::ast; use std::cell::RefCell; -use std::hash::{Hash, Hasher}; +use std::hash::Hash; use rustc::dep_graph::DepNode; use rustc::hir; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; @@ -43,21 +43,22 @@ use self::def_path_hash::DefPathHashes; use self::svh_visitor::StrictVersionHashVisitor; use self::caching_codemap_view::CachingCodemapView; use self::hasher::IchHasher; +use ich::Fingerprint; mod def_path_hash; mod svh_visitor; mod caching_codemap_view; -mod hasher; +pub mod hasher; pub struct IncrementalHashesMap { - hashes: FnvHashMap, u64>, + hashes: FnvHashMap, Fingerprint>, // These are the metadata hashes for the current crate as they were stored // during the last compilation session. They are only loaded if // -Z query-dep-graph was specified and are needed for auto-tests using // the #[rustc_metadata_dirty] and #[rustc_metadata_clean] attributes to // check whether some metadata hash has changed in between two revisions. - pub prev_metadata_hashes: RefCell>, + pub prev_metadata_hashes: RefCell>, } impl IncrementalHashesMap { @@ -68,11 +69,12 @@ impl IncrementalHashesMap { } } - pub fn insert(&mut self, k: DepNode, v: u64) -> Option { + pub fn insert(&mut self, k: DepNode, v: Fingerprint) -> Option { self.hashes.insert(k, v) } - pub fn iter<'a>(&'a self) -> ::std::collections::hash_map::Iter<'a, DepNode, u64> { + pub fn iter<'a>(&'a self) + -> ::std::collections::hash_map::Iter<'a, DepNode, Fingerprint> { self.hashes.iter() } @@ -82,9 +84,9 @@ impl IncrementalHashesMap { } impl<'a> ::std::ops::Index<&'a DepNode> for IncrementalHashesMap { - type Output = u64; + type Output = Fingerprint; - fn index(&self, index: &'a DepNode) -> &u64 { + fn index(&self, index: &'a DepNode) -> &Fingerprint { &self.hashes[index] } } @@ -141,12 +143,13 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { &mut self.def_path_hashes, &mut self.codemap, self.hash_spans)); + let bytes_hashed = state.bytes_hashed(); let item_hash = state.finish(); self.hashes.insert(DepNode::Hir(def_id), item_hash); debug!("calculate_item_hash: def_id={:?} hash={:?}", def_id, item_hash); let bytes_hashed = self.tcx.sess.perf_stats.incr_comp_bytes_hashed.get() + - state.bytes_hashed(); + bytes_hashed; self.tcx.sess.perf_stats.incr_comp_bytes_hashed.set(bytes_hashed); } diff --git a/src/librustc_incremental/ich/fingerprint.rs b/src/librustc_incremental/ich/fingerprint.rs new file mode 100644 index 0000000000000..005ac3896ce4c --- /dev/null +++ b/src/librustc_incremental/ich/fingerprint.rs @@ -0,0 +1,81 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc_serialize::{Encodable, Decodable, Encoder, Decoder}; + +const FINGERPRINT_LENGTH: usize = 16; + +#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Clone, Copy)] +pub struct Fingerprint(pub [u8; FINGERPRINT_LENGTH]); + +impl Fingerprint { + #[inline] + pub fn zero() -> Fingerprint { + Fingerprint([0; FINGERPRINT_LENGTH]) + } + + pub fn from_smaller_hash(hash: u64) -> Fingerprint { + let mut result = Fingerprint::zero(); + result.0[0] = (hash >> 0) as u8; + result.0[1] = (hash >> 8) as u8; + result.0[2] = (hash >> 16) as u8; + result.0[3] = (hash >> 24) as u8; + result.0[4] = (hash >> 32) as u8; + result.0[5] = (hash >> 40) as u8; + result.0[6] = (hash >> 48) as u8; + result.0[7] = (hash >> 56) as u8; + result + } + + pub fn to_smaller_hash(&self) -> u64 { + ((self.0[0] as u64) << 0) | + ((self.0[1] as u64) << 8) | + ((self.0[2] as u64) << 16) | + ((self.0[3] as u64) << 24) | + ((self.0[4] as u64) << 32) | + ((self.0[5] as u64) << 40) | + ((self.0[6] as u64) << 48) | + ((self.0[7] as u64) << 56) + } +} + +impl Encodable for Fingerprint { + #[inline] + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + for &byte in &self.0[..] { + s.emit_u8(byte)?; + } + Ok(()) + } +} + +impl Decodable for Fingerprint { + #[inline] + fn decode(d: &mut D) -> Result { + let mut result = Fingerprint([0u8; FINGERPRINT_LENGTH]); + for byte in &mut result.0[..] { + *byte = d.read_u8()?; + } + Ok(result) + } +} + +impl ::std::fmt::Display for Fingerprint { + fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + for i in 0 .. self.0.len() { + if i > 0 { + write!(formatter, "::")?; + } + + write!(formatter, "{}", self.0[i])?; + } + Ok(()) + } +} diff --git a/src/librustc_incremental/ich/mod.rs b/src/librustc_incremental/ich/mod.rs new file mode 100644 index 0000000000000..8edd04322d7f6 --- /dev/null +++ b/src/librustc_incremental/ich/mod.rs @@ -0,0 +1,13 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub use self::fingerprint::Fingerprint; + +mod fingerprint; diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 67104e912f90e..577e50699bffd 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -45,6 +45,7 @@ const ATTR_THEN_THIS_WOULD_NEED: &'static str = "rustc_then_this_would_need"; mod assert_dep_graph; mod calculate_svh; mod persist; +pub mod ich; pub use assert_dep_graph::assert_dep_graph; pub use calculate_svh::compute_incremental_hashes_map; diff --git a/src/librustc_incremental/persist/data.rs b/src/librustc_incremental/persist/data.rs index 57e7a0bc21a4e..734ffe6a94412 100644 --- a/src/librustc_incremental/persist/data.rs +++ b/src/librustc_incremental/persist/data.rs @@ -14,6 +14,7 @@ use rustc::dep_graph::{DepNode, WorkProduct, WorkProductId}; use rustc::hir::def_id::DefIndex; use std::sync::Arc; use rustc_data_structures::fnv::FnvHashMap; +use ich::Fingerprint; use super::directory::DefPathIndex; @@ -60,7 +61,7 @@ pub struct SerializedHash { /// the hash as of previous compilation, computed by code in /// `hash` module - pub hash: u64, + pub hash: Fingerprint, } #[derive(Debug, RustcEncodable, RustcDecodable)] @@ -116,5 +117,5 @@ pub struct SerializedMetadataHash { pub def_index: DefIndex, /// the hash itself, computed by `calculate_item_hash` - pub hash: u64, + pub hash: Fingerprint, } diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index 95452021d8784..0418148ffc7df 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -51,6 +51,7 @@ use rustc_data_structures::fnv::{FnvHashSet, FnvHashMap}; use syntax::parse::token::InternedString; use syntax_pos::Span; use rustc::ty::TyCtxt; +use ich::Fingerprint; use {ATTR_DIRTY, ATTR_CLEAN, ATTR_DIRTY_METADATA, ATTR_CLEAN_METADATA}; @@ -186,8 +187,8 @@ impl<'a, 'tcx> Visitor<'tcx> for DirtyCleanVisitor<'a, 'tcx> { } pub fn check_dirty_clean_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - prev_metadata_hashes: &FnvHashMap, - current_metadata_hashes: &FnvHashMap) { + prev_metadata_hashes: &FnvHashMap, + current_metadata_hashes: &FnvHashMap) { if !tcx.sess.opts.debugging_opts.query_dep_graph { return; } @@ -204,8 +205,8 @@ pub fn check_dirty_clean_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub struct DirtyCleanMetadataVisitor<'a, 'tcx:'a, 'm> { tcx: TyCtxt<'a, 'tcx, 'tcx>, - prev_metadata_hashes: &'m FnvHashMap, - current_metadata_hashes: &'m FnvHashMap, + prev_metadata_hashes: &'m FnvHashMap, + current_metadata_hashes: &'m FnvHashMap, } impl<'a, 'tcx, 'm> Visitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx, 'm> { diff --git a/src/librustc_incremental/persist/hash.rs b/src/librustc_incremental/persist/hash.rs index ca173db15fcac..e365cbbd3a9a1 100644 --- a/src/librustc_incremental/persist/hash.rs +++ b/src/librustc_incremental/persist/hash.rs @@ -18,6 +18,7 @@ use rustc_serialize::Decodable; use rustc_serialize::opaque::Decoder; use IncrementalHashesMap; +use ich::Fingerprint; use super::data::*; use super::fs::*; use super::file_format; @@ -25,7 +26,7 @@ use super::file_format; pub struct HashContext<'a, 'tcx: 'a> { pub tcx: TyCtxt<'a, 'tcx, 'tcx>, incremental_hashes_map: &'a IncrementalHashesMap, - item_metadata_hashes: FnvHashMap, + item_metadata_hashes: FnvHashMap, crate_hashes: FnvHashMap, } @@ -50,7 +51,7 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> { } } - pub fn hash(&mut self, dep_node: &DepNode) -> Option { + pub fn hash(&mut self, dep_node: &DepNode) -> Option { match *dep_node { DepNode::Krate => { Some(self.incremental_hashes_map[dep_node]) @@ -89,7 +90,7 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> { } } - fn metadata_hash(&mut self, def_id: DefId) -> u64 { + fn metadata_hash(&mut self, def_id: DefId) -> Fingerprint { debug!("metadata_hash(def_id={:?})", def_id); assert!(!def_id.is_local()); @@ -102,14 +103,15 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> { // check whether we did not find detailed metadata for this // krate; in that case, we just use the krate's overall hash - if let Some(&hash) = self.crate_hashes.get(&def_id.krate) { - debug!("metadata_hash: def_id={:?} crate_hash={:?}", def_id, hash); + if let Some(&svh) = self.crate_hashes.get(&def_id.krate) { + debug!("metadata_hash: def_id={:?} crate_hash={:?}", def_id, svh); // micro-"optimization": avoid a cache miss if we ask // for metadata from this particular def-id again. - self.item_metadata_hashes.insert(def_id, hash.as_u64()); + let fingerprint = svh_to_fingerprint(svh); + self.item_metadata_hashes.insert(def_id, fingerprint); - return hash.as_u64(); + return fingerprint; } // otherwise, load the data and repeat. @@ -206,3 +208,7 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> { Ok(()) } } + +fn svh_to_fingerprint(svh: Svh) -> Fingerprint { + Fingerprint::from_smaller_hash(svh.as_u64()) +} diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index db8d3125e510b..1f43e79ace3ae 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -22,6 +22,7 @@ use std::fs; use std::path::{Path}; use IncrementalHashesMap; +use ich::Fingerprint; use super::data::*; use super::directory::*; use super::dirty_clean; @@ -315,7 +316,7 @@ fn delete_dirty_work_product(tcx: TyCtxt, fn load_prev_metadata_hashes(tcx: TyCtxt, retraced: &RetracedDefIdDirectory, - output: &mut FnvHashMap) { + output: &mut FnvHashMap) { if !tcx.sess.opts.debugging_opts.query_dep_graph { return } diff --git a/src/librustc_incremental/persist/preds.rs b/src/librustc_incremental/persist/preds.rs index af13484e4288d..fe1d627253f28 100644 --- a/src/librustc_incremental/persist/preds.rs +++ b/src/librustc_incremental/persist/preds.rs @@ -14,6 +14,7 @@ use rustc_data_structures::fnv::FnvHashMap; use rustc_data_structures::graph::{DepthFirstTraversal, INCOMING, NodeIndex}; use super::hash::*; +use ich::Fingerprint; /// A data-structure that makes it easy to enumerate the hashable /// predecessors of any given dep-node. @@ -26,7 +27,7 @@ pub struct Predecessors<'query> { // - Keys: some hashable node // - Values: the hash thereof - pub hashes: FnvHashMap<&'query DepNode, u64>, + pub hashes: FnvHashMap<&'query DepNode, Fingerprint>, } impl<'q> Predecessors<'q> { diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index bc542b71ac670..bc156b0e8913b 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -16,13 +16,13 @@ use rustc::ty::TyCtxt; use rustc_data_structures::fnv::FnvHashMap; use rustc_serialize::Encodable as RustcEncodable; use rustc_serialize::opaque::Encoder; -use std::hash::{Hash, Hasher}; +use std::hash::Hash; use std::io::{self, Cursor, Write}; use std::fs::{self, File}; use std::path::PathBuf; -use std::collections::hash_map::DefaultHasher; use IncrementalHashesMap; +use ich::Fingerprint; use super::data::*; use super::directory::*; use super::hash::*; @@ -30,6 +30,7 @@ use super::preds::*; use super::fs::*; use super::dirty_clean; use super::file_format; +use calculate_svh::hasher::IchHasher; pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, incremental_hashes_map: &IncrementalHashesMap, @@ -185,7 +186,7 @@ pub fn encode_metadata_hashes(tcx: TyCtxt, svh: Svh, preds: &Predecessors, builder: &mut DefIdDirectoryBuilder, - current_metadata_hashes: &mut FnvHashMap, + current_metadata_hashes: &mut FnvHashMap, encoder: &mut Encoder) -> io::Result<()> { // For each `MetaData(X)` node where `X` is local, accumulate a @@ -233,7 +234,7 @@ pub fn encode_metadata_hashes(tcx: TyCtxt, // is the det. hash of the def-path. This is convenient // because we can sort this to get a stable ordering across // compilations, even if the def-ids themselves have changed. - let mut hashes: Vec<(DepNode, u64)> = sources.iter() + let mut hashes: Vec<(DepNode, Fingerprint)> = sources.iter() .map(|dep_node| { let hash_dep_node = dep_node.map_def(|&def_id| Some(def_id_hash(def_id))).unwrap(); let hash = preds.hashes[dep_node]; @@ -242,7 +243,7 @@ pub fn encode_metadata_hashes(tcx: TyCtxt, .collect(); hashes.sort(); - let mut state = DefaultHasher::new(); + let mut state = IchHasher::new(); hashes.hash(&mut state); let hash = state.finish(); diff --git a/src/librustc_metadata/macro_import.rs b/src/librustc_metadata/macro_import.rs index 7cd03b2d5b941..3b1b2a4cd27e4 100644 --- a/src/librustc_metadata/macro_import.rs +++ b/src/librustc_metadata/macro_import.rs @@ -11,7 +11,6 @@ //! Used by `rustc` when loading a crate with exported macros. use std::collections::HashSet; -use std::rc::Rc; use std::env; use std::mem; @@ -212,7 +211,7 @@ impl<'a> CrateLoader<'a> { fn register_custom_derive(&mut self, trait_name: &str, expand: fn(TokenStream) -> TokenStream) { - let derive = Rc::new(CustomDerive::new(expand)); + let derive = Box::new(CustomDerive::new(expand)); self.0.push(LoadedMacro { kind: LoadedMacroKind::CustomDerive(trait_name.to_string(), derive), import_site: self.1, diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 5600669d45fb9..e0abe8da82b9c 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -36,7 +36,7 @@ use syntax::parse::token; 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::{MultiItemModifier, Resolver as SyntaxResolver}; +use syntax::ext::base::{SyntaxExtension, Resolver as SyntaxResolver}; use syntax::ext::hygiene::Mark; use syntax::feature_gate::{self, emit_feature_err}; use syntax::ext::tt::macro_rules; @@ -195,22 +195,25 @@ impl<'b> Resolver<'b> { // We need to error on `#[macro_use] extern crate` when it isn't at the // crate root, because `$crate` won't work properly. let is_crate_root = self.current_module.parent.is_none(); + let import_macro = |this: &mut Self, name, ext, span| { + let shadowing = this.builtin_macros.insert(name, Rc::new(ext)).is_some(); + if shadowing && expansion != Mark::root() { + let msg = format!("`{}` is already in scope", name); + this.session.struct_span_err(span, &msg) + .note("macro-expanded `#[macro_use]`s may not shadow \ + existing macros (see RFC 1560)") + .emit(); + } + }; + + let mut custom_derive_crate = false; for loaded_macro in self.crate_loader.load_macros(item, is_crate_root) { match loaded_macro.kind { LoadedMacroKind::Def(mut def) => { - let name = def.ident.name; if def.use_locally { - let ext = - Rc::new(macro_rules::compile(&self.session.parse_sess, &def)); - if self.builtin_macros.insert(name, ext).is_some() && - expansion != Mark::root() { - let msg = format!("`{}` is already in scope", name); - self.session.struct_span_err(loaded_macro.import_site, &msg) - .note("macro-expanded `#[macro_use]`s may not shadow \ - existing macros (see RFC 1560)") - .emit(); - } - self.macro_names.insert(name); + self.macro_names.insert(def.ident.name); + let ext = macro_rules::compile(&self.session.parse_sess, &def); + import_macro(self, def.ident.name, ext, loaded_macro.import_site); } if def.export { def.id = self.next_node_id(); @@ -218,10 +221,19 @@ impl<'b> Resolver<'b> { } } LoadedMacroKind::CustomDerive(name, ext) => { - self.insert_custom_derive(&name, ext, item.span); + custom_derive_crate = true; + let ext = SyntaxExtension::CustomDerive(ext); + import_macro(self, token::intern(&name), ext, loaded_macro.import_site); } } } + + if custom_derive_crate && !self.session.features.borrow().proc_macro { + let issue = feature_gate::GateIssue::Language; + let msg = "loading custom derive macro crates is experimentally supported"; + emit_feature_err(&self.session.parse_sess, "proc_macro", item.span, issue, msg); + } + self.crate_loader.process_item(item, &self.definitions); // n.b. we don't need to look at the path option here, because cstore already did @@ -238,6 +250,12 @@ impl<'b> Resolver<'b> { self.define(parent, name, TypeNS, (module, sp, vis)); self.populate_module_if_necessary(module); + } else if custom_derive_crate { + // Define an empty module + let def = Def::Mod(self.definitions.local_def_id(item.id)); + let module = ModuleS::new(Some(parent), ModuleKind::Def(def, name)); + let module = self.arenas.alloc_module(module); + self.define(parent, name, TypeNS, (module, sp, vis)); } } @@ -504,17 +522,6 @@ impl<'b> Resolver<'b> { false } - - fn insert_custom_derive(&mut self, name: &str, ext: Rc, sp: Span) { - if !self.session.features.borrow().proc_macro { - let sess = &self.session.parse_sess; - let msg = "loading custom derive macro crates is experimentally supported"; - emit_feature_err(sess, "proc_macro", sp, feature_gate::GateIssue::Language, msg); - } - if self.derive_modes.insert(token::intern(name), ext).is_some() { - self.session.span_err(sp, &format!("cannot shadow existing derive mode `{}`", name)); - } - } } pub struct BuildReducedGraphVisitor<'a, 'b: 'a> { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 83e66fdd3bc40..298f41b971d06 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -53,7 +53,6 @@ use rustc::ty; use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap}; use rustc::util::nodemap::{NodeMap, NodeSet, FnvHashMap, FnvHashSet}; -use syntax::ext::base::MultiItemModifier; use syntax::ext::hygiene::Mark; use syntax::ast::{self, FloatTy}; use syntax::ast::{CRATE_NODE_ID, Name, NodeId, IntTy, UintTy}; @@ -1082,7 +1081,6 @@ pub struct Resolver<'a> { new_import_semantics: bool, // true if `#![feature(item_like_imports)]` pub exported_macros: Vec, - pub derive_modes: FnvHashMap>, crate_loader: &'a mut CrateLoader, macro_names: FnvHashSet, builtin_macros: FnvHashMap>, @@ -1273,7 +1271,6 @@ impl<'a> Resolver<'a> { new_import_semantics: session.features.borrow().item_like_imports, exported_macros: Vec::new(), - derive_modes: FnvHashMap(), crate_loader: crate_loader, macro_names: FnvHashSet(), builtin_macros: FnvHashMap(), diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 86ab077191eef..cf5ea236b3ec7 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -17,9 +17,9 @@ use std::cell::Cell; use std::rc::Rc; use syntax::ast; use syntax::errors::DiagnosticBuilder; -use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator, MultiItemModifier}; +use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator}; use syntax::ext::base::{NormalTT, SyntaxExtension}; -use syntax::ext::expand::{Expansion, Invocation, InvocationKind}; +use syntax::ext::expand::Expansion; use syntax::ext::hygiene::Mark; use syntax::ext::tt::macro_rules; use syntax::parse::token::intern; @@ -162,21 +162,13 @@ impl<'a> base::Resolver for Resolver<'a> { None } - fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation, force: bool) + fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, force: bool) -> Result, Determinacy> { - let (name, span) = match invoc.kind { - InvocationKind::Bang { ref mac, .. } => { - let path = &mac.node.path; - if path.segments.len() > 1 || path.global || - !path.segments[0].parameters.is_empty() { - self.session.span_err(path.span, - "expected macro name without module separators"); - return Err(Determinacy::Determined); - } - (path.segments[0].identifier.name, path.span) - } - InvocationKind::Attr { ref attr, .. } => (intern(&*attr.name()), attr.span), - }; + if path.segments.len() > 1 || path.global || !path.segments[0].parameters.is_empty() { + self.session.span_err(path.span, "expected macro name without module separators"); + return Err(Determinacy::Determined); + } + let name = path.segments[0].identifier.name; let invocation = self.invocations[&scope]; if let LegacyScope::Expansion(parent) = invocation.legacy_scope.get() { @@ -184,8 +176,8 @@ impl<'a> base::Resolver for Resolver<'a> { } self.resolve_macro_name(invocation.legacy_scope.get(), name, true).ok_or_else(|| { if force { - let mut err = - self.session.struct_span_err(span, &format!("macro undefined: '{}!'", name)); + 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 @@ -194,10 +186,6 @@ impl<'a> base::Resolver for Resolver<'a> { } }) } - - fn resolve_derive_mode(&mut self, ident: ast::Ident) -> Option> { - self.derive_modes.get(&ident.name).cloned() - } } impl<'a> Resolver<'a> { diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 5a8c5cb4b82c6..e46bdbb5ccf4a 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -130,7 +130,7 @@ pub fn build_link_meta(incremental_hashes_map: &IncrementalHashesMap, -> LinkMeta { let r = LinkMeta { crate_name: name.to_owned(), - crate_hash: Svh::new(incremental_hashes_map[&DepNode::Krate]), + crate_hash: Svh::new(incremental_hashes_map[&DepNode::Krate].to_smaller_hash()), }; info!("{:?}", r); return r; diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 3caf8c9e4c3b8..02aa7c069f9b3 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1250,12 +1250,27 @@ fn write_metadata(cx: &SharedCrateContext, reachable_ids: &NodeSet) -> Vec { use flate; - let any_library = cx.sess() - .crate_types - .borrow() - .iter() - .any(|ty| *ty != config::CrateTypeExecutable); - if !any_library { + #[derive(PartialEq, Eq, PartialOrd, Ord)] + enum MetadataKind { + None, + Uncompressed, + Compressed + } + + let kind = cx.sess().crate_types.borrow().iter().map(|ty| { + match *ty { + config::CrateTypeExecutable | + config::CrateTypeStaticlib | + config::CrateTypeCdylib => MetadataKind::None, + + config::CrateTypeRlib => MetadataKind::Uncompressed, + + config::CrateTypeDylib | + config::CrateTypeProcMacro => MetadataKind::Compressed, + } + }).max().unwrap(); + + if kind == MetadataKind::None { return Vec::new(); } @@ -1265,6 +1280,11 @@ fn write_metadata(cx: &SharedCrateContext, cx.link_meta(), reachable_ids, cx.mir_map()); + if kind == MetadataKind::Uncompressed { + return metadata; + } + + assert!(kind == MetadataKind::Compressed); let mut compressed = cstore.metadata_encoding_version().to_vec(); compressed.extend_from_slice(&flate::deflate_bytes(&metadata)); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index d58b8f083e248..c9ce320988c47 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -2218,10 +2218,12 @@ fn check_type_argument_count(tcx: TyCtxt, span: Span, supplied: usize, } else { "expected" }; + let arguments_plural = if required == 1 { "" } else { "s" }; struct_span_err!(tcx.sess, span, E0243, "wrong number of type arguments") .span_label( span, - &format!("{} {} type arguments, found {}", expected, required, supplied) + &format!("{} {} type argument{}, found {}", + expected, required, arguments_plural, supplied) ) .emit(); } else if supplied > accepted { @@ -2232,11 +2234,12 @@ fn check_type_argument_count(tcx: TyCtxt, span: Span, supplied: usize, } else { format!("expected {}", accepted) }; + let arguments_plural = if accepted == 1 { "" } else { "s" }; struct_span_err!(tcx.sess, span, E0244, "wrong number of type arguments") .span_label( span, - &format!("{} type arguments, found {}", expected, supplied) + &format!("{} type argument{}, found {}", expected, arguments_plural, supplied) ) .emit(); } diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index cc958fb3b2343..5e2b49bac1b2f 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -71,7 +71,8 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>( ccx: &CrateCtxt<'a, 'tcx>, drop_impl_did: DefId, drop_impl_ty: Ty<'tcx>, - self_type_did: DefId) -> Result<(), ()> + self_type_did: DefId) + -> Result<(), ()> { let tcx = ccx.tcx; let drop_impl_node_id = tcx.map.as_local_node_id(drop_impl_did).unwrap(); @@ -123,7 +124,9 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>( drop_impl_did: DefId, dtor_predicates: &ty::GenericPredicates<'tcx>, self_type_did: DefId, - self_to_impl_substs: &Substs<'tcx>) -> Result<(), ()> { + self_to_impl_substs: &Substs<'tcx>) + -> Result<(), ()> +{ // Here is an example, analogous to that from // `compare_impl_method`. @@ -350,7 +353,8 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>( cx: &mut DropckContext<'a, 'b, 'gcx, 'tcx>, context: TypeContext, ty: Ty<'tcx>, - depth: usize) -> Result<(), Error<'tcx>> + depth: usize) + -> Result<(), Error<'tcx>> { let tcx = cx.rcx.tcx; // Issue #22443: Watch out for overflow. While we are careful to @@ -402,16 +406,27 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>( // unbounded type parameter `T`, we must resume the recursive // analysis on `T` (since it would be ignored by // type_must_outlive). - if has_dtor_of_interest(tcx, ty) { - debug!("iterate_over_potentially_unsafe_regions_in_type \ - {}ty: {} - is a dtorck type!", - (0..depth).map(|_| ' ').collect::(), - ty); - - cx.rcx.type_must_outlive(infer::SubregionOrigin::SafeDestructor(cx.span), - ty, tcx.mk_region(ty::ReScope(cx.parent_scope))); - - return Ok(()); + let dropck_kind = has_dtor_of_interest(tcx, ty); + debug!("iterate_over_potentially_unsafe_regions_in_type \ + ty: {:?} dropck_kind: {:?}", ty, dropck_kind); + match dropck_kind { + DropckKind::NoBorrowedDataAccessedInMyDtor => { + // The maximally blind attribute. + } + DropckKind::BorrowedDataMustStrictlyOutliveSelf => { + cx.rcx.type_must_outlive(infer::SubregionOrigin::SafeDestructor(cx.span), + ty, tcx.mk_region(ty::ReScope(cx.parent_scope))); + return Ok(()); + } + DropckKind::RevisedSelf(revised_ty) => { + cx.rcx.type_must_outlive(infer::SubregionOrigin::SafeDestructor(cx.span), + revised_ty, tcx.mk_region(ty::ReScope(cx.parent_scope))); + // Do not return early from this case; we want + // to recursively process the internal structure of Self + // (because even though the Drop for Self has been asserted + // safe, the types instantiated for the generics of Self + // may themselves carry dropck constraints.) + } } debug!("iterate_over_potentially_unsafe_regions_in_type \ @@ -492,16 +507,140 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>( } } +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +enum DropckKind<'tcx> { + /// The "safe" kind; i.e. conservatively assume any borrow + /// accessed by dtor, and therefore such data must strictly + /// outlive self. + /// + /// Equivalent to RevisedTy with no change to the self type. + BorrowedDataMustStrictlyOutliveSelf, + + /// The nearly completely-unsafe kind. + /// + /// Equivalent to RevisedSelf with *all* parameters remapped to () + /// (maybe...?) + NoBorrowedDataAccessedInMyDtor, + + /// Assume all borrowed data access by dtor occurs as if Self has the + /// type carried by this variant. In practice this means that some + /// of the type parameters are remapped to `()` (and some lifetime + /// parameters remapped to `'static`), because the developer has asserted + /// that the destructor will not access their contents. + RevisedSelf(Ty<'tcx>), +} + +/// Returns the classification of what kind of check should be applied +/// to `ty`, which may include a revised type where some of the type +/// parameters are re-mapped to `()` to reflect the destructor's +/// "purity" with respect to their actual contents. fn has_dtor_of_interest<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - ty: Ty<'tcx>) -> bool { + ty: Ty<'tcx>) + -> DropckKind<'tcx> { match ty.sty { - ty::TyAdt(def, _) => { - def.is_dtorck(tcx) + ty::TyAdt(adt_def, substs) => { + if !adt_def.is_dtorck(tcx) { + return DropckKind::NoBorrowedDataAccessedInMyDtor; + } + + // Find the `impl<..> Drop for _` to inspect any + // attributes attached to the impl's generics. + let dtor_method = adt_def.destructor() + .expect("dtorck type without destructor impossible"); + let method = tcx.impl_or_trait_item(dtor_method); + let impl_id: DefId = method.container().id(); + let revised_ty = revise_self_ty(tcx, adt_def, impl_id, substs); + return DropckKind::RevisedSelf(revised_ty); } ty::TyTrait(..) | ty::TyProjection(..) | ty::TyAnon(..) => { debug!("ty: {:?} isn't known, and therefore is a dropck type", ty); - true + return DropckKind::BorrowedDataMustStrictlyOutliveSelf; }, - _ => false + _ => { + return DropckKind::NoBorrowedDataAccessedInMyDtor; + } } } + +// Constructs new Ty just like the type defined by `adt_def` coupled +// with `substs`, except each type and lifetime parameter marked as +// `#[may_dangle]` in the Drop impl (identified by `impl_id`) is +// respectively mapped to `()` or `'static`. +// +// For example: If the `adt_def` maps to: +// +// enum Foo<'a, X, Y> { ... } +// +// and the `impl_id` maps to: +// +// impl<#[may_dangle] 'a, X, #[may_dangle] Y> Drop for Foo<'a, X, Y> { ... } +// +// then revises input: `Foo<'r,i64,&'r i64>` to: `Foo<'static,i64,()>` +fn revise_self_ty<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, + adt_def: ty::AdtDef<'tcx>, + impl_id: DefId, + substs: &Substs<'tcx>) + -> Ty<'tcx> { + // Get generics for `impl Drop` to query for `#[may_dangle]` attr. + let impl_bindings = tcx.lookup_generics(impl_id); + + // Get Substs attached to Self on `impl Drop`; process in parallel + // with `substs`, replacing dangling entries as appropriate. + let self_substs = { + let impl_self_ty: Ty<'tcx> = tcx.lookup_item_type(impl_id).ty; + if let ty::TyAdt(self_adt_def, self_substs) = impl_self_ty.sty { + assert_eq!(adt_def, self_adt_def); + self_substs + } else { + bug!("Self in `impl Drop for _` must be an Adt."); + } + }; + + // Walk `substs` + `self_substs`, build new substs appropriate for + // `adt_def`; each non-dangling param reuses entry from `substs`. + // + // Note: The manner we map from a right-hand side (i.e. Region or + // Ty) for a given `def` to generic parameter associated with that + // right-hand side is tightly coupled to `Drop` impl constraints. + // + // E.g. we know such a Ty must be `TyParam`, because a destructor + // for `struct Foo` is defined via `impl Drop for Foo`, + // and never by (for example) `impl Drop for Foo>`. + let substs = Substs::for_item( + tcx, + adt_def.did, + |def, _| { + let r_orig = substs.region_for_def(def); + let impl_self_orig = self_substs.region_for_def(def); + let r = if let ty::Region::ReEarlyBound(ref ebr) = *impl_self_orig { + if impl_bindings.region_param(ebr).pure_wrt_drop { + tcx.mk_region(ty::ReStatic) + } else { + r_orig + } + } else { + bug!("substs for an impl must map regions to ReEarlyBound"); + }; + debug!("has_dtor_of_interest mapping def {:?} orig {:?} to {:?}", + def, r_orig, r); + r + }, + |def, _| { + let t_orig = substs.type_for_def(def); + let impl_self_orig = self_substs.type_for_def(def); + let t = if let ty::TypeVariants::TyParam(ref pt) = impl_self_orig.sty { + if impl_bindings.type_param(pt).pure_wrt_drop { + tcx.mk_nil() + } else { + t_orig + } + } else { + bug!("substs for an impl must map types to TyParam"); + }; + debug!("has_dtor_of_interest mapping def {:?} orig {:?} {:?} to {:?} {:?}", + def, t_orig, t_orig.sty, t, t.sty); + t + }); + + return tcx.mk_adt(adt_def, &substs); +} diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs index ff55ce0e5eb55..cca6c88430672 100644 --- a/src/librustc_typeck/coherence/unsafety.rs +++ b/src/librustc_typeck/coherence/unsafety.rs @@ -13,7 +13,7 @@ use rustc::ty::TyCtxt; use rustc::hir::intravisit; -use rustc::hir; +use rustc::hir::{self, Unsafety}; pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let mut orphan = UnsafetyChecker { tcx: tcx }; @@ -27,6 +27,7 @@ struct UnsafetyChecker<'cx, 'tcx: 'cx> { impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> { fn check_unsafety_coherence(&mut self, item: &'v hir::Item, + impl_generics: Option<&hir::Generics>, unsafety: hir::Unsafety, polarity: hir::ImplPolarity) { match self.tcx.impl_trait_ref(self.tcx.map.local_def_id(item.id)) { @@ -47,15 +48,16 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> { Some(trait_ref) => { let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id); - match (trait_def.unsafety, unsafety, polarity) { - (hir::Unsafety::Unsafe, hir::Unsafety::Unsafe, hir::ImplPolarity::Negative) => { + let unsafe_attr = impl_generics.and_then(|g| g.carries_unsafe_attr()); + match (trait_def.unsafety, unsafe_attr, unsafety, polarity) { + (_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative) => { span_err!(self.tcx.sess, item.span, E0198, "negative implementations are not unsafe"); } - (hir::Unsafety::Normal, hir::Unsafety::Unsafe, _) => { + (Unsafety::Normal, None, Unsafety::Unsafe, _) => { span_err!(self.tcx.sess, item.span, E0199, @@ -63,7 +65,7 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> { trait_ref); } - (hir::Unsafety::Unsafe, hir::Unsafety::Normal, hir::ImplPolarity::Positive) => { + (Unsafety::Unsafe, _, Unsafety::Normal, hir::ImplPolarity::Positive) => { span_err!(self.tcx.sess, item.span, E0200, @@ -71,9 +73,19 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> { trait_ref); } - (hir::Unsafety::Unsafe, hir::Unsafety::Normal, hir::ImplPolarity::Negative) | - (hir::Unsafety::Unsafe, hir::Unsafety::Unsafe, hir::ImplPolarity::Positive) | - (hir::Unsafety::Normal, hir::Unsafety::Normal, _) => { + (Unsafety::Normal, Some(g), Unsafety::Normal, hir::ImplPolarity::Positive) => + { + span_err!(self.tcx.sess, + item.span, + E0569, + "requires an `unsafe impl` declaration due to `#[{}]` attribute", + g.attr_name()); + } + + (_, _, Unsafety::Normal, hir::ImplPolarity::Negative) | + (Unsafety::Unsafe, _, Unsafety::Unsafe, hir::ImplPolarity::Positive) | + (Unsafety::Normal, Some(_), Unsafety::Unsafe, hir::ImplPolarity::Positive) | + (Unsafety::Normal, None, Unsafety::Normal, _) => { // OK } } @@ -86,10 +98,10 @@ impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> { fn visit_item(&mut self, item: &'v hir::Item) { match item.node { hir::ItemDefaultImpl(unsafety, _) => { - self.check_unsafety_coherence(item, unsafety, hir::ImplPolarity::Positive); + self.check_unsafety_coherence(item, None, unsafety, hir::ImplPolarity::Positive); } - hir::ItemImpl(unsafety, polarity, ..) => { - self.check_unsafety_coherence(item, unsafety, polarity); + hir::ItemImpl(unsafety, polarity, ref generics, ..) => { + self.check_unsafety_coherence(item, Some(generics), unsafety, polarity); } _ => {} } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 128db6ef5848a..6e47f4ed8c6be 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1482,6 +1482,7 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, default_def_id: tcx.map.local_def_id(parent), default: None, object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault, + pure_wrt_drop: false, }; tcx.ty_param_defs.borrow_mut().insert(param_id, def.clone()); opt_self = Some(def); @@ -1526,7 +1527,8 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, def_id: tcx.map.local_def_id(l.lifetime.id), bounds: l.bounds.iter().map(|l| { ast_region_to_region(tcx, l) - }).collect() + }).collect(), + pure_wrt_drop: l.pure_wrt_drop, } }).collect::>(); @@ -1926,6 +1928,7 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, default_def_id: ccx.tcx.map.local_def_id(parent), default: default, object_lifetime_default: object_lifetime_default, + pure_wrt_drop: param.pure_wrt_drop, }; if def.name == keywords::SelfType.name() { diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 0d6b43b59c6ad..16f915c0011cb 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -2819,6 +2819,26 @@ not a distinct static type. Likewise, it's not legal to attempt to behavior for specific enum variants. "##, +E0569: r##" +If an impl has a generic parameter with the `#[may_dangle]` attribute, then +that impl must be declared as an `unsafe impl. For example: + +```compile_fail,E0569 +#![feature(generic_param_attrs)] +#![feature(dropck_eyepatch)] + +struct Foo(X); +impl<#[may_dangle] X> Drop for Foo { + fn drop(&mut self) { } +} +``` + +In this example, we are asserting that the destructor for `Foo` will not +access any data of type `X`, and require this assertion to be true for +overall safety in our program. The compiler does not currently attempt to +verify this assertion; therefore we must tag this `impl` as unsafe. +"##, + E0318: r##" Default impls for a trait must be located in the same crate where the trait was defined. For more information see the [opt-in builtin traits RFC](https://github diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index 9b13d54230078..504b3a76bd295 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -425,6 +425,9 @@ pub use self::hash_map::HashMap; #[stable(feature = "rust1", since = "1.0.0")] pub use self::hash_set::HashSet; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core_collections::range; + mod hash; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 5bb5183fd6a93..df5741d00a2c1 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -83,6 +83,7 @@ pub struct Metadata(fs_imp::FileAttr); /// /// [`io::Result`]: ../io/type.Result.html #[stable(feature = "rust1", since = "1.0.0")] +#[derive(Debug)] pub struct ReadDir(fs_imp::ReadDir); /// Entries returned by the [`ReadDir`] iterator. diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index c2f6a6f660c48..71e0ab0388f5b 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -224,6 +224,7 @@ #![feature(char_internals)] #![feature(collections)] #![feature(collections_bound)] +#![feature(collections_range)] #![feature(compiler_builtins_lib)] #![feature(const_fn)] #![feature(core_float)] diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index fe8cbc8421572..b77008676b16f 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -193,6 +193,14 @@ impl FromInner for FilePermissions { } } +impl fmt::Debug for ReadDir { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame. + // Thus the result will be e g 'ReadDir("/home")' + fmt::Debug::fmt(&*self.root, f) + } +} + impl Iterator for ReadDir { type Item = io::Result; diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index a927eae020dcf..98fd15f863ba1 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -81,6 +81,14 @@ pub struct FilePermissions { attrs: c::DWORD } pub struct DirBuilder; +impl fmt::Debug for ReadDir { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame. + // Thus the result will be e g 'ReadDir("C:\")' + fmt::Debug::fmt(&*self.root, f) + } +} + impl Iterator for ReadDir { type Item = io::Result; fn next(&mut self) -> Option> { diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 3b81ea4917f2b..01f81e5e2de17 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -9,7 +9,7 @@ // except according to those terms. use attr::HasAttrs; -use feature_gate::{emit_feature_err, EXPLAIN_STMT_ATTR_SYNTAX, Features, get_features, GateIssue}; +use feature_gate::{feature_err, EXPLAIN_STMT_ATTR_SYNTAX, Features, get_features, GateIssue}; use {fold, attr}; use ast; use codemap::{Spanned, respan}; @@ -157,11 +157,15 @@ impl<'a> StripUnconfigured<'a> { // flag the offending attributes for attr in attrs.iter() { if !self.features.map(|features| features.stmt_expr_attributes).unwrap_or(true) { - emit_feature_err(&self.sess, - "stmt_expr_attributes", - attr.span, - GateIssue::Language, - EXPLAIN_STMT_ATTR_SYNTAX); + let mut err = feature_err(&self.sess, + "stmt_expr_attributes", + attr.span, + GateIssue::Language, + EXPLAIN_STMT_ATTR_SYNTAX); + if attr.node.is_sugared_doc { + err.help("`///` is for documentation comments. For a plain comment, use `//`."); + } + err.emit(); } } } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index f7c88073c9d40..f3272960e8313 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -15,7 +15,7 @@ use attr::HasAttrs; use codemap::{self, CodeMap, ExpnInfo, Spanned, respan}; use syntax_pos::{Span, ExpnId, NO_EXPANSION}; use errors::DiagnosticBuilder; -use ext::expand::{self, Invocation, Expansion}; +use ext::expand::{self, Expansion}; use ext::hygiene::Mark; use fold::{self, Folder}; use parse::{self, parser}; @@ -508,6 +508,8 @@ pub enum SyntaxExtension { /// the block. /// IdentTT(Box, Option, bool), + + CustomDerive(Box), } pub type NamedSyntaxExtension = (Name, SyntaxExtension); @@ -522,9 +524,8 @@ pub trait Resolver { fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec); fn find_attr_invoc(&mut self, attrs: &mut Vec) -> Option; - fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation, force: bool) + fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, force: bool) -> Result, Determinacy>; - fn resolve_derive_mode(&mut self, ident: ast::Ident) -> Option>; } #[derive(Copy, Clone, Debug)] @@ -545,8 +546,7 @@ impl Resolver for DummyResolver { fn add_expansions_at_stmt(&mut self, _id: ast::NodeId, _macros: Vec) {} fn find_attr_invoc(&mut self, _attrs: &mut Vec) -> Option { None } - fn resolve_derive_mode(&mut self, _ident: ast::Ident) -> Option> { None } - fn resolve_invoc(&mut self, _scope: Mark, _invoc: &Invocation, _force: bool) + fn resolve_macro(&mut self, _scope: Mark, _path: &ast::Path, _force: bool) -> Result, Determinacy> { Err(Determinacy::Determined) } @@ -617,11 +617,11 @@ impl<'a> ExtCtxt<'a> { pub fn new_parser_from_tts(&self, tts: &[tokenstream::TokenTree]) -> parser::Parser<'a> { - parse::tts_to_parser(self.parse_sess, tts.to_vec(), self.cfg()) + parse::tts_to_parser(self.parse_sess, tts.to_vec(), self.cfg().clone()) } pub fn codemap(&self) -> &'a CodeMap { self.parse_sess.codemap() } pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess } - pub fn cfg(&self) -> ast::CrateConfig { self.cfg.clone() } + pub fn cfg(&self) -> &ast::CrateConfig { &self.cfg } pub fn call_site(&self) -> Span { self.codemap().with_expn_info(self.backtrace(), |ei| match ei { Some(expn_info) => expn_info.call_site, diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 363ceebf0f475..6aeb46fd52276 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -240,7 +240,17 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let scope = if self.monotonic { invoc.expansion_data.mark } else { orig_expansion_data.mark }; - let ext = match self.cx.resolver.resolve_invoc(scope, &invoc, force) { + let resolution = match invoc.kind { + InvocationKind::Bang { ref mac, .. } => { + self.cx.resolver.resolve_macro(scope, &mac.node.path, force) + } + InvocationKind::Attr { ref attr, .. } => { + let ident = ast::Ident::with_empty_ctxt(intern(&*attr.name())); + let path = ast::Path::from_ident(attr.span, ident); + self.cx.resolver.resolve_macro(scope, &path, force) + } + }; + let ext = match resolution { Ok(ext) => Some(ext), Err(Determinacy::Determined) => None, Err(Determinacy::Undetermined) => { @@ -354,7 +364,15 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let tok_result = mac.expand(self.cx, attr.span, attr_toks, item_toks); self.parse_expansion(tok_result, kind, name, attr.span) } - _ => unreachable!(), + SyntaxExtension::CustomDerive(_) => { + self.cx.span_err(attr.span, &format!("`{}` is a derive mode", name)); + kind.dummy(attr.span) + } + _ => { + let msg = &format!("macro `{}` may not be used in attributes", name); + self.cx.span_err(attr.span, &msg); + kind.dummy(attr.span) + } } } @@ -429,6 +447,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> { return kind.dummy(span); } + SyntaxExtension::CustomDerive(..) => { + self.cx.span_err(path.span, &format!("`{}` is a derive mode", extname)); + return kind.dummy(span); + } + SyntaxExtension::ProcMacro(ref expandfun) => { if ident.name != keywords::Invalid.name() { let msg = diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index b70e270df54d2..7f002d2816679 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -331,7 +331,7 @@ pub mod rt { panictry!(parse::parse_item_from_source_str( "".to_string(), s, - self.cfg(), + self.cfg().clone(), self.parse_sess())).expect("parse error") } @@ -339,7 +339,7 @@ pub mod rt { panictry!(parse::parse_stmt_from_source_str( "".to_string(), s, - self.cfg(), + self.cfg().clone(), self.parse_sess())).expect("parse error") } @@ -347,7 +347,7 @@ pub mod rt { panictry!(parse::parse_expr_from_source_str( "".to_string(), s, - self.cfg(), + self.cfg().clone(), self.parse_sess())) } @@ -355,7 +355,7 @@ pub mod rt { panictry!(parse::parse_tts_from_source_str( "".to_string(), s, - self.cfg(), + self.cfg().clone(), self.parse_sess())) } } @@ -924,6 +924,10 @@ fn expand_parse_call(cx: &ExtCtxt, sp, cx.expr_ident(sp, id_ext("ext_cx")), id_ext("cfg"), Vec::new()); + let cfg_clone_call = || cx.expr_method_call( + sp, cfg_call(), + id_ext("clone"), Vec::new()); + let parse_sess_call = || cx.expr_method_call( sp, cx.expr_ident(sp, id_ext("ext_cx")), id_ext("parse_sess"), Vec::new()); @@ -931,7 +935,7 @@ fn expand_parse_call(cx: &ExtCtxt, let new_parser_call = cx.expr_call(sp, cx.expr_ident(sp, id_ext("new_parser_from_tts")), - vec!(parse_sess_call(), cfg_call(), tts_expr)); + vec!(parse_sess_call(), cfg_clone_call(), tts_expr)); let path = vec![id_ext("syntax"), id_ext("ext"), id_ext("quote"), id_ext(parse_method)]; let mut args = vec![cx.expr_mut_addr_of(sp, new_parser_call)]; diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index e75e41d0c2d4b..30dc1823b370a 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -94,7 +94,7 @@ pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[tokenstream::T // The file will be added to the code map by the parser let p = parse::new_sub_parser_from_file(cx.parse_sess(), - cx.cfg(), + cx.cfg().clone(), &res_rel_file(cx, sp, Path::new(&file)), diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index b0696a986e3c0..ef2e466a04398 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -272,7 +272,7 @@ pub fn token_name_eq(t1 : &Token, t2 : &Token) -> bool { } pub fn parse(sess: &ParseSess, - cfg: ast::CrateConfig, + cfg: &ast::CrateConfig, mut rdr: TtReader, ms: &[TokenTree]) -> NamedParseResult { @@ -476,24 +476,21 @@ pub fn parse(sess: &ParseSess, } rdr.next_token(); } else /* bb_eis.len() == 1 */ { - let mut rust_parser = Parser::new(sess, cfg.clone(), Box::new(rdr.clone())); - - let mut ei = bb_eis.pop().unwrap(); - match ei.top_elts.get_tt(ei.idx) { - TokenTree::Token(span, MatchNt(_, ident)) => { + rdr.next_tok = { + let mut rust_parser = Parser::new(sess, cfg.clone(), Box::new(&mut rdr)); + 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( parse_nt(&mut rust_parser, span, &ident.name.as_str())))); ei.idx += 1; ei.match_cur += 1; + } else { + unreachable!() } - _ => panic!() - } - cur_eis.push(ei); - - for _ in 0..rust_parser.tokens_consumed { - let _ = rdr.next_token(); - } + cur_eis.push(ei); + Some(TokenAndSpan { tok: rust_parser.token, sp: rust_parser.span }) + }; } } diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 2e0c7ddb540f4..a74d335d6046d 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -120,7 +120,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt, Some(named_matches), imported_from, rhs); - let mut p = Parser::new(cx.parse_sess(), cx.cfg(), Box::new(trncbr)); + let mut p = Parser::new(cx.parse_sess(), cx.cfg().clone(), Box::new(trncbr)); p.directory = cx.current_expansion.module.directory.clone(); p.restrictions = match cx.current_expansion.no_noninline_mod { true => Restrictions::NO_NONINLINE_MOD, @@ -225,7 +225,7 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension { // Parse the macro_rules! invocation (`none` is for no interpolations): let arg_reader = new_tt_reader(&sess.span_diagnostic, None, None, def.body.clone()); - let argument_map = match parse(sess, Vec::new(), arg_reader, &argument_gram) { + let argument_map = match parse(sess, &Vec::new(), arg_reader, &argument_gram) { Success(m) => m, Failure(sp, str) | Error(sp, str) => { panic!(sess.span_diagnostic.span_fatal(sp.substitute_dummy(def.span), &str)); diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index 939425378def6..205c709d6cb40 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -48,6 +48,7 @@ pub struct TtReader<'a> { /* cached: */ pub cur_tok: Token, pub cur_span: Span, + pub next_tok: Option, /// Transform doc comments. Only useful in macro invocations pub desugar_doc_comments: bool, pub fatal_errs: Vec>, @@ -100,6 +101,7 @@ pub fn new_tt_reader_with_doc_flag(sp_diag: &Handler, /* dummy values, never read: */ cur_tok: token::Eof, cur_span: DUMMY_SP, + next_tok: None, fatal_errs: Vec::new(), }; tt_next_token(&mut r); /* get cur_tok and cur_span set up */ @@ -178,6 +180,9 @@ fn lockstep_iter_size(t: &TokenTree, r: &TtReader) -> LockstepIterSize { /// Return the next token from the TtReader. /// EFFECT: advances the reader's token field pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan { + if let Some(tok) = r.next_tok.take() { + return tok; + } // FIXME(pcwalton): Bad copy? let ret_val = TokenAndSpan { tok: r.cur_tok.clone(), diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 62b88888fc878..954fe330b54ca 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -30,7 +30,7 @@ use ast::{self, NodeId, PatKind}; use attr; use codemap::{CodeMap, Spanned}; use syntax_pos::Span; -use errors::Handler; +use errors::{DiagnosticBuilder, Handler}; use visit::{self, FnKind, Visitor}; use parse::ParseSess; use parse::token::InternedString; @@ -167,6 +167,9 @@ declare_features! ( // RFC 1238 (active, dropck_parametricity, "1.3.0", Some(28498)), + // Allows using the may_dangle attribute; RFC 1327 + (active, dropck_eyepatch, "1.10.0", Some(34761)), + // Allows the use of custom attributes; RFC 572 (active, custom_attribute, "1.0.0", Some(29642)), @@ -616,6 +619,11 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat "unsafe_destructor_blind_to_params has unstable semantics \ and may be removed in the future", cfg_fn!(dropck_parametricity))), + ("may_dangle", + Normal, + Gated("dropck_eyepatch", + "may_dangle has unstable semantics and may be removed in the future", + cfg_fn!(dropck_eyepatch))), ("unwind", Whitelisted, Gated("unwind_attributes", "#[unwind] is experimental", cfg_fn!(unwind_attributes))), @@ -792,6 +800,11 @@ pub enum GateIssue { pub fn emit_feature_err(sess: &ParseSess, feature: &str, span: Span, issue: GateIssue, explain: &str) { + feature_err(sess, feature, span, issue, explain).emit(); +} + +pub fn feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: GateIssue, + explain: &str) -> DiagnosticBuilder<'a> { let diag = &sess.span_diagnostic; let issue = match issue { @@ -812,7 +825,7 @@ pub fn emit_feature_err(sess: &ParseSess, feature: &str, span: Span, issue: Gate feature)); } - err.emit(); + err } const EXPLAIN_BOX_SYNTAX: &'static str = @@ -1317,15 +1330,12 @@ impl UnstableFeatures { pub fn from_environment() -> UnstableFeatures { // Whether this is a feature-staged build, i.e. on the beta or stable channel let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some(); - // The secret key needed to get through the rustc build itself by - // subverting the unstable features lints - let bootstrap_secret_key = option_env!("CFG_BOOTSTRAP_KEY"); - // The matching key to the above, only known by the build system - let bootstrap_provided_key = env::var("RUSTC_BOOTSTRAP_KEY").ok(); - match (disable_unstable_features, bootstrap_secret_key, bootstrap_provided_key) { - (_, Some(ref s), Some(ref p)) if s == p => UnstableFeatures::Cheat, - (true, _, _) => UnstableFeatures::Disallow, - (false, _, _) => UnstableFeatures::Allow + // Whether we should enable unstable features for bootstrapping + let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok(); + match (disable_unstable_features, bootstrap) { + (_, true) => UnstableFeatures::Cheat, + (true, _) => UnstableFeatures::Disallow, + (false, _) => UnstableFeatures::Allow } } diff --git a/src/libsyntax/parse/lexer/comments.rs b/src/libsyntax/parse/lexer/comments.rs index 38f811d54dab8..ba83a55ea7937 100644 --- a/src/libsyntax/parse/lexer/comments.rs +++ b/src/libsyntax/parse/lexer/comments.rs @@ -24,7 +24,7 @@ use str::char_at; use std::io::Read; use std::usize; -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy, PartialEq, Debug)] pub enum CommentStyle { /// No code on either side of each line of the comment Isolated, @@ -155,14 +155,13 @@ fn push_blank_line_comment(rdr: &StringReader, comments: &mut Vec) { fn consume_whitespace_counting_blank_lines(rdr: &mut StringReader, comments: &mut Vec) { while is_pattern_whitespace(rdr.ch) && !rdr.is_eof() { - if rdr.col == CharPos(0) && rdr.ch_is('\n') { + if rdr.ch_is('\n') { push_blank_line_comment(rdr, &mut *comments); } rdr.bump(); } } - fn read_shebang_comment(rdr: &mut StringReader, code_to_the_left: bool, comments: &mut Vec) { @@ -317,14 +316,22 @@ fn read_block_comment(rdr: &mut StringReader, } -fn consume_comment(rdr: &mut StringReader, code_to_the_left: bool, comments: &mut Vec) { +fn consume_comment(rdr: &mut StringReader, + comments: &mut Vec, + code_to_the_left: &mut bool, + anything_to_the_left: &mut bool) { debug!(">>> consume comment"); if rdr.ch_is('/') && rdr.nextch_is('/') { - read_line_comments(rdr, code_to_the_left, comments); + read_line_comments(rdr, *code_to_the_left, comments); + *code_to_the_left = false; + *anything_to_the_left = false; } else if rdr.ch_is('/') && rdr.nextch_is('*') { - read_block_comment(rdr, code_to_the_left, comments); + read_block_comment(rdr, *code_to_the_left, comments); + *anything_to_the_left = true; } else if rdr.ch_is('#') && rdr.nextch_is('!') { - read_shebang_comment(rdr, code_to_the_left, comments); + read_shebang_comment(rdr, *code_to_the_left, comments); + *code_to_the_left = false; + *anything_to_the_left = false; } else { panic!(); } @@ -352,23 +359,29 @@ pub fn gather_comments_and_literals(span_diagnostic: &errors::Handler, let mut comments: Vec = Vec::new(); let mut literals: Vec = Vec::new(); - let mut first_read: bool = true; + let mut code_to_the_left = false; // Only code + let mut anything_to_the_left = false; // Code or comments while !rdr.is_eof() { loop { - let mut code_to_the_left = !first_read; + // Eat all the whitespace and count blank lines. rdr.consume_non_eol_whitespace(); if rdr.ch_is('\n') { - code_to_the_left = false; + if anything_to_the_left { + rdr.bump(); // The line is not blank, do not count. + } consume_whitespace_counting_blank_lines(&mut rdr, &mut comments); + code_to_the_left = false; + anything_to_the_left = false; } - while rdr.peeking_at_comment() { - consume_comment(&mut rdr, code_to_the_left, &mut comments); - consume_whitespace_counting_blank_lines(&mut rdr, &mut comments); + // Eat one comment group + if rdr.peeking_at_comment() { + consume_comment(&mut rdr, &mut comments, + &mut code_to_the_left, &mut anything_to_the_left); + } else { + break } - break; } - let bstart = rdr.pos; rdr.next_token(); // discard, and look ahead; we're working with internal state @@ -384,7 +397,8 @@ pub fn gather_comments_and_literals(span_diagnostic: &errors::Handler, } else { debug!("tok: {}", pprust::token_to_string(&tok)); } - first_read = false; + code_to_the_left = true; + anything_to_the_left = true; } (comments, literals) diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index aca41bd7b5915..e62d0d925cd4f 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -144,7 +144,7 @@ impl<'a> Reader for StringReader<'a> { impl<'a> Reader for TtReader<'a> { fn is_eof(&self) -> bool { - self.cur_tok == token::Eof + self.peek().tok == token::Eof } fn try_next_token(&mut self) -> Result { assert!(self.fatal_errs.is_empty()); @@ -165,10 +165,31 @@ impl<'a> Reader for TtReader<'a> { self.fatal_errs.clear(); } fn peek(&self) -> TokenAndSpan { - TokenAndSpan { + self.next_tok.clone().unwrap_or(TokenAndSpan { tok: self.cur_tok.clone(), sp: self.cur_span, - } + }) + } +} + +impl<'a, 'b> Reader for &'b mut TtReader<'a> { + fn is_eof(&self) -> bool { + (**self).is_eof() + } + fn try_next_token(&mut self) -> Result { + (**self).try_next_token() + } + fn fatal(&self, m: &str) -> FatalError { + (**self).fatal(m) + } + fn err(&self, m: &str) { + (**self).err(m) + } + fn emit_fatal_errors(&mut self) { + (**self).emit_fatal_errors() + } + fn peek(&self) -> TokenAndSpan { + (**self).peek() } } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index ecb437f31a5ad..89834da28219c 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -545,15 +545,12 @@ pub trait PrintState<'a> { } fn maybe_print_comment(&mut self, pos: BytePos) -> io::Result<()> { - loop { - match self.next_comment() { - Some(ref cmnt) => { - if (*cmnt).pos < pos { - try!(self.print_comment(cmnt)); - self.cur_cmnt_and_lit().cur_cmnt += 1; - } else { break; } - } - _ => break + while let Some(ref cmnt) = self.next_comment() { + if cmnt.pos < pos { + try!(self.print_comment(cmnt)); + self.cur_cmnt_and_lit().cur_cmnt += 1; + } else { + break } } Ok(()) @@ -581,7 +578,9 @@ pub trait PrintState<'a> { Ok(()) } comments::Trailing => { - try!(word(self.writer(), " ")); + if !self.is_bol() { + try!(word(self.writer(), " ")); + } if cmnt.lines.len() == 1 { try!(word(self.writer(), &cmnt.lines[0])); hardbreak(self.writer()) @@ -1361,6 +1360,7 @@ impl<'a> State<'a> { if comma { try!(self.word_space(",")) } + try!(self.print_outer_attributes_inline(&lifetime_def.attrs)); try!(self.print_lifetime_bounds(&lifetime_def.lifetime, &lifetime_def.bounds)); comma = true; } @@ -1715,6 +1715,7 @@ impl<'a> State<'a> { for (i, st) in blk.stmts.iter().enumerate() { match st.node { ast::StmtKind::Expr(ref expr) if i == blk.stmts.len() - 1 => { + try!(self.maybe_print_comment(st.span.lo)); try!(self.space_if_not_bol()); try!(self.print_expr_outer_attr_style(&expr, false)); try!(self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi))); @@ -2604,6 +2605,7 @@ impl<'a> State<'a> { } try!(self.cbox(INDENT_UNIT)); try!(self.ibox(0)); + try!(self.maybe_print_comment(arm.pats[0].span.lo)); try!(self.print_outer_attributes(&arm.attrs)); let mut first = true; for p in &arm.pats { @@ -2803,6 +2805,7 @@ impl<'a> State<'a> { try!(self.commasep(Inconsistent, &ints[..], |s, &idx| { if idx < generics.lifetimes.len() { let lifetime_def = &generics.lifetimes[idx]; + try!(s.print_outer_attributes_inline(&lifetime_def.attrs)); s.print_lifetime_bounds(&lifetime_def.lifetime, &lifetime_def.bounds) } else { let idx = idx - generics.lifetimes.len(); @@ -2816,6 +2819,7 @@ impl<'a> State<'a> { } pub fn print_ty_param(&mut self, param: &ast::TyParam) -> io::Result<()> { + try!(self.print_outer_attributes_inline(¶m.attrs)); try!(self.print_ident(param.ident)); try!(self.print_bounds(":", ¶m.bounds)); match param.default { @@ -3007,15 +3011,11 @@ impl<'a> State<'a> { _ => return Ok(()) }; if let Some(ref cmnt) = self.next_comment() { - if (*cmnt).style != comments::Trailing { return Ok(()) } + if cmnt.style != comments::Trailing { return Ok(()) } let span_line = cm.lookup_char_pos(span.hi); - let comment_line = cm.lookup_char_pos((*cmnt).pos); - let mut next = (*cmnt).pos + BytePos(1); - if let Some(p) = next_pos { - next = p; - } - if span.hi < (*cmnt).pos && (*cmnt).pos < next && - span_line.line == comment_line.line { + let comment_line = cm.lookup_char_pos(cmnt.pos); + let next = next_pos.unwrap_or(cmnt.pos + BytePos(1)); + if span.hi < cmnt.pos && cmnt.pos < next && span_line.line == comment_line.line { self.print_comment(cmnt)?; self.cur_cmnt_and_lit.cur_cmnt += 1; } diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs index c16b7d2959411..1c97099d387f9 100644 --- a/src/libsyntax_ext/asm.rs +++ b/src/libsyntax_ext/asm.rs @@ -107,7 +107,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, if p2.token != token::Eof { let mut extra_tts = panictry!(p2.parse_all_token_trees()); extra_tts.extend(tts[first_colon..].iter().cloned()); - p = parse::tts_to_parser(cx.parse_sess, extra_tts, cx.cfg()); + p = parse::tts_to_parser(cx.parse_sess, extra_tts, cx.cfg().clone()); } asm = s; diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index 9f99919c89505..07401d59a15db 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -12,7 +12,7 @@ use syntax::ast::{self, MetaItem}; use syntax::attr::HasAttrs; -use syntax::ext::base::{Annotatable, ExtCtxt}; +use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension}; use syntax::ext::build::AstBuilder; use syntax::feature_gate; use syntax::codemap; @@ -158,10 +158,14 @@ pub fn expand_derive(cx: &mut ExtCtxt, let tword = titem.word().unwrap(); let tname = tword.name(); - let derive_mode = ast::Ident::with_empty_ctxt(intern(&tname)); - let derive_mode = cx.resolver.resolve_derive_mode(derive_mode); - if is_builtin_trait(&tname) || derive_mode.is_some() { - return true + if is_builtin_trait(&tname) || { + let derive_mode = + ast::Path::from_ident(titem.span, ast::Ident::with_empty_ctxt(intern(&tname))); + cx.resolver.resolve_macro(cx.current_expansion.mark, &derive_mode, false).map(|ext| { + if let SyntaxExtension::CustomDerive(_) = *ext { true } else { false } + }).unwrap_or(false) + } { + return true; } if !cx.ecfg.enable_custom_derive() { @@ -216,7 +220,9 @@ pub fn expand_derive(cx: &mut ExtCtxt, .next(); if let Some((i, titem)) = macros_11_derive { let tname = ast::Ident::with_empty_ctxt(intern(&titem.name().unwrap())); - let ext = cx.resolver.resolve_derive_mode(tname).unwrap(); + let path = ast::Path::from_ident(titem.span, tname); + let ext = cx.resolver.resolve_macro(cx.current_expansion.mark, &path, false).unwrap(); + traits.remove(i); if traits.len() > 0 { item = item.map(|mut i| { @@ -232,7 +238,11 @@ pub fn expand_derive(cx: &mut ExtCtxt, intern_and_get_ident("derive"), vec![titem]); let item = Annotatable::Item(item); - return ext.expand(cx, mitem.span, &mitem, item) + if let SyntaxExtension::CustomDerive(ref ext) = *ext { + return ext.expand(cx, mitem.span, &mitem, item); + } else { + unreachable!() + } } // Ok, at this point we know that there are no old-style `#[derive_Foo]` nor diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-auto-clean-trigger index b12e25bba694f..f4b5ca7a15724 100644 --- a/src/rustllvm/llvm-auto-clean-trigger +++ b/src/rustllvm/llvm-auto-clean-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be forcibly cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2016-10-10 +2016-10-10b diff --git a/src/stage0.txt b/src/stage0.txt index 05189f2011b0d..ac2050a6fc8f1 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -13,5 +13,4 @@ # released on `$date` rustc: beta-2016-09-28 -rustc_key: 62b3e239 cargo: nightly-2016-09-26 diff --git a/src/test/codegen/zip.rs b/src/test/codegen/zip.rs index 6c956364bf80f..d0051c5165fe1 100644 --- a/src/test/codegen/zip.rs +++ b/src/test/codegen/zip.rs @@ -20,3 +20,12 @@ pub fn zip_copy(xs: &[u8], ys: &mut [u8]) { *y = *x; } } + +// CHECK-LABEL: @zip_copy_mapped +#[no_mangle] +pub fn zip_copy_mapped(xs: &[u8], ys: &mut [u8]) { +// CHECK: memcpy + for (x, y) in xs.iter().map(|&x| x).zip(ys) { + *y = x; + } +} diff --git a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs b/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs index 5b1ecfed24278..2041abcf82c99 100644 --- a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs +++ b/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs @@ -57,7 +57,7 @@ fn expand_identity(cx: &mut ExtCtxt, _span: Span, tts: &[TokenTree]) -> Box { // Parse an expression and emit it unchanged. let mut parser = parse::new_parser_from_tts(cx.parse_sess(), - cx.cfg(), tts.to_vec()); + cx.cfg().clone(), tts.to_vec()); let expr = parser.parse_expr().unwrap(); MacEager::expr(quote_expr!(&mut *cx, $expr)) } diff --git a/src/test/compile-fail-fulldeps/proc-macro/shadow.rs b/src/test/compile-fail-fulldeps/proc-macro/shadow.rs index 7b1a73d50f6e0..a04756ca19ba7 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/shadow.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/shadow.rs @@ -9,13 +9,12 @@ // except according to those terms. // aux-build:derive-a.rs -// aux-build:derive-a-2.rs #![feature(proc_macro)] #[macro_use] extern crate derive_a; #[macro_use] -extern crate derive_a_2; //~ ERROR: cannot shadow existing derive mode `A` +extern crate derive_a; //~ ERROR `derive_a` has already been defined fn main() {} diff --git a/src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-a-2.rs b/src/test/compile-fail/E0198.rs similarity index 64% rename from src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-a-2.rs rename to src/test/compile-fail/E0198.rs index 4aa4238611d89..892989cc6a080 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-a-2.rs +++ b/src/test/compile-fail/E0198.rs @@ -8,18 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// force-host -// no-prefer-dynamic +#![feature(optin_builtin_traits)] -#![feature(proc_macro)] -#![feature(proc_macro_lib)] -#![crate_type = "proc-macro"] +struct Foo; -extern crate proc_macro; +unsafe impl !Clone for Foo { } //~ ERROR negative implementations are not unsafe [E0198] -use proc_macro::TokenStream; - -#[proc_macro_derive(A)] -pub fn derive_a(input: TokenStream) -> TokenStream { - input +fn main() { } diff --git a/src/test/compile-fail/E0199.rs b/src/test/compile-fail/E0199.rs index 8bd3ffdf6f6ee..1a5cd1941a9d1 100644 --- a/src/test/compile-fail/E0199.rs +++ b/src/test/compile-fail/E0199.rs @@ -12,7 +12,8 @@ struct Foo; -unsafe impl !Clone for Foo { } //~ ERROR E0199 +trait Bar { } +unsafe impl Bar for Foo { } //~ ERROR implementing the trait `Bar` is not unsafe [E0199] fn main() { } diff --git a/src/test/compile-fail/E0243.rs b/src/test/compile-fail/E0243.rs index 77c9856c261ff..4434723e12f82 100644 --- a/src/test/compile-fail/E0243.rs +++ b/src/test/compile-fail/E0243.rs @@ -11,7 +11,7 @@ struct Foo { x: T } struct Bar { x: Foo } //~^ ERROR E0243 - //~| NOTE expected 1 type arguments, found 0 + //~| NOTE expected 1 type argument, found 0 fn main() { } diff --git a/src/test/compile-fail/borrowck/borrowck-use-uninitialized-in-cast.rs b/src/test/compile-fail/borrowck/borrowck-use-uninitialized-in-cast.rs index a3d5af80b533b..3f429bbd4b634 100644 --- a/src/test/compile-fail/borrowck/borrowck-use-uninitialized-in-cast.rs +++ b/src/test/compile-fail/borrowck/borrowck-use-uninitialized-in-cast.rs @@ -12,8 +12,6 @@ // The problem was specified to casting to `*`, as creating unsafe // pointers was not being fully checked. Issue #20791. -// pretty-expanded FIXME #23616 - fn main() { let x: &i32; let y = x as *const i32; //~ ERROR use of possibly uninitialized variable: `*x` diff --git a/src/test/compile-fail/coherence-cow.rs b/src/test/compile-fail/coherence-cow.rs index 6a2d1bac49381..86ae5b44d9db0 100644 --- a/src/test/compile-fail/coherence-cow.rs +++ b/src/test/compile-fail/coherence-cow.rs @@ -12,8 +12,6 @@ // aux-build:coherence_lib.rs -// pretty-expanded FIXME #23616 - // Test that the `Pair` type reports an error if it contains type // parameters, even when they are covered by local types. This test // was originally intended to test the opposite, but the rules changed diff --git a/src/test/compile-fail/coherence-vec-local-2.rs b/src/test/compile-fail/coherence-vec-local-2.rs index 5f0b56af2c226..196c2f4ee3cd3 100644 --- a/src/test/compile-fail/coherence-vec-local-2.rs +++ b/src/test/compile-fail/coherence-vec-local-2.rs @@ -13,8 +13,6 @@ // aux-build:coherence_lib.rs -// pretty-expanded FIXME #23616 - extern crate coherence_lib as lib; use lib::Remote; diff --git a/src/test/compile-fail/coherence-vec-local.rs b/src/test/compile-fail/coherence-vec-local.rs index c354caac2b5c2..49822dcfcb3f0 100644 --- a/src/test/compile-fail/coherence-vec-local.rs +++ b/src/test/compile-fail/coherence-vec-local.rs @@ -13,8 +13,6 @@ // aux-build:coherence_lib.rs -// pretty-expanded FIXME #23616 - extern crate coherence_lib as lib; use lib::Remote; diff --git a/src/test/compile-fail/feature-gate-may-dangle.rs b/src/test/compile-fail/feature-gate-may-dangle.rs new file mode 100644 index 0000000000000..23f8ead0ca9dc --- /dev/null +++ b/src/test/compile-fail/feature-gate-may-dangle.rs @@ -0,0 +1,20 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that `may_dangle` is rejected if `dropck_eyepatch` feature gate is absent. + +#![feature(generic_param_attrs)] + +struct Pt(A); +impl<#[may_dangle] A> Drop for Pt { + //~^ ERROR may_dangle has unstable semantics and may be removed in the future + //~| HELP add #![feature(dropck_eyepatch)] to the crate attributes to enable + fn drop(&mut self) { } +} diff --git a/src/test/compile-fail/generic-type-less-params-with-defaults.rs b/src/test/compile-fail/generic-type-less-params-with-defaults.rs index d9ac715fa9548..9b1f3e51647cb 100644 --- a/src/test/compile-fail/generic-type-less-params-with-defaults.rs +++ b/src/test/compile-fail/generic-type-less-params-with-defaults.rs @@ -18,5 +18,5 @@ struct Vec( fn main() { let _: Vec; //~^ ERROR E0243 - //~| NOTE expected at least 1 type arguments, found 0 + //~| NOTE expected at least 1 type argument, found 0 } diff --git a/src/test/compile-fail/issue-13352.rs b/src/test/compile-fail/issue-13352.rs index 13e677d72bc1e..0c446f5fe4703 100644 --- a/src/test/compile-fail/issue-13352.rs +++ b/src/test/compile-fail/issue-13352.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 - fn foo(_: Box) {} fn main() { diff --git a/src/test/compile-fail/issue-14092.rs b/src/test/compile-fail/issue-14092.rs index dd02fa7ac151c..df8707ab823e5 100644 --- a/src/test/compile-fail/issue-14092.rs +++ b/src/test/compile-fail/issue-14092.rs @@ -10,6 +10,6 @@ fn fn1(0: Box) {} //~^ ERROR E0243 - //~| NOTE expected 1 type arguments, found 0 + //~| NOTE expected 1 type argument, found 0 fn main() {} diff --git a/src/test/compile-fail/issue-19482.rs b/src/test/compile-fail/issue-19482.rs index 21a50f24d5e5c..b54f008f8ce3a 100644 --- a/src/test/compile-fail/issue-19482.rs +++ b/src/test/compile-fail/issue-19482.rs @@ -11,8 +11,6 @@ // Test that a partially specified trait object with unspecified associated // type does not type-check. -// pretty-expanded FIXME #23616 - trait Foo { type A; diff --git a/src/test/compile-fail/meta-expected-error-correct-rev.rs b/src/test/compile-fail/meta-expected-error-correct-rev.rs index 95b4e1a33cccd..bd70879d13e5f 100644 --- a/src/test/compile-fail/meta-expected-error-correct-rev.rs +++ b/src/test/compile-fail/meta-expected-error-correct-rev.rs @@ -9,7 +9,6 @@ // except according to those terms. // revisions: a -// pretty-expanded FIXME #23616 // Counterpart to `meta-expected-error-wrong-rev.rs` diff --git a/src/test/compile-fail/meta-expected-error-wrong-rev.rs b/src/test/compile-fail/meta-expected-error-wrong-rev.rs index 084c6ed4f4b41..3c13050812c93 100644 --- a/src/test/compile-fail/meta-expected-error-wrong-rev.rs +++ b/src/test/compile-fail/meta-expected-error-wrong-rev.rs @@ -10,7 +10,6 @@ // revisions: a // should-fail -// pretty-expanded FIXME #23616 // This is a "meta-test" of the compilertest framework itself. In // particular, it includes the right error message, but the message diff --git a/src/test/compile-fail/object-lifetime-default-from-rptr-box-error.rs b/src/test/compile-fail/object-lifetime-default-from-rptr-box-error.rs index e351c84c8afc6..98301ef1a0a1d 100644 --- a/src/test/compile-fail/object-lifetime-default-from-rptr-box-error.rs +++ b/src/test/compile-fail/object-lifetime-default-from-rptr-box-error.rs @@ -11,8 +11,6 @@ // Test that the lifetime from the enclosing `&` is "inherited" // through the `Box` struct. -// pretty-expanded FIXME #23616 - #![allow(dead_code)] trait Test { diff --git a/src/test/compile-fail/object-lifetime-default-from-rptr-struct-error.rs b/src/test/compile-fail/object-lifetime-default-from-rptr-struct-error.rs index 93268559e8e51..836e4fa114263 100644 --- a/src/test/compile-fail/object-lifetime-default-from-rptr-struct-error.rs +++ b/src/test/compile-fail/object-lifetime-default-from-rptr-struct-error.rs @@ -11,8 +11,6 @@ // Test that the lifetime from the enclosing `&` is "inherited" // through the `MyBox` struct. -// pretty-expanded FIXME #23616 - #![allow(dead_code)] #![feature(rustc_error)] diff --git a/src/test/compile-fail/typeck_type_placeholder_lifetime_1.rs b/src/test/compile-fail/typeck_type_placeholder_lifetime_1.rs index f60d925a74864..f40445a030e01 100644 --- a/src/test/compile-fail/typeck_type_placeholder_lifetime_1.rs +++ b/src/test/compile-fail/typeck_type_placeholder_lifetime_1.rs @@ -18,5 +18,5 @@ struct Foo<'a, T:'a> { pub fn main() { let c: Foo<_, _> = Foo { r: &5 }; //~^ ERROR E0244 - //~| NOTE expected 1 type arguments, found 2 + //~| NOTE expected 1 type argument, found 2 } diff --git a/src/test/compile-fail/typeck_type_placeholder_lifetime_2.rs b/src/test/compile-fail/typeck_type_placeholder_lifetime_2.rs index ec2675ece74b0..47898690fcce4 100644 --- a/src/test/compile-fail/typeck_type_placeholder_lifetime_2.rs +++ b/src/test/compile-fail/typeck_type_placeholder_lifetime_2.rs @@ -18,5 +18,5 @@ struct Foo<'a, T:'a> { pub fn main() { let c: Foo<_, usize> = Foo { r: &5 }; //~^ ERROR E0244 - //~| NOTE expected 1 type arguments, found 2 + //~| NOTE expected 1 type argument, found 2 } diff --git a/src/test/compile-fail/variance-trait-matching.rs b/src/test/compile-fail/variance-trait-matching.rs index 49dc1e68c221f..2d78940ce4b9d 100644 --- a/src/test/compile-fail/variance-trait-matching.rs +++ b/src/test/compile-fail/variance-trait-matching.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 - #![allow(dead_code)] // Get is covariant in T diff --git a/src/test/incremental/change_private_impl_method/struct_point.rs b/src/test/incremental/change_private_impl_method/struct_point.rs new file mode 100644 index 0000000000000..8fa34bde17053 --- /dev/null +++ b/src/test/incremental/change_private_impl_method/struct_point.rs @@ -0,0 +1,114 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test where we change the body of a private method in an impl. +// We then test what sort of functions must be rebuilt as a result. + +// revisions:rpass1 rpass2 +// compile-flags: -Z query-dep-graph + +#![feature(rustc_attrs)] +#![feature(stmt_expr_attributes)] +#![allow(dead_code)] + +#![rustc_partition_translated(module="struct_point-point", cfg="rpass2")] + +// FIXME(#37121) -- the following two modules *should* be reused but are not +#![rustc_partition_translated(module="struct_point-fn_calls_methods_in_same_impl", cfg="rpass2")] +#![rustc_partition_translated(module="struct_point-fn_calls_methods_in_another_impl", cfg="rpass2")] +#![rustc_partition_reused(module="struct_point-fn_make_struct", cfg="rpass2")] +#![rustc_partition_reused(module="struct_point-fn_read_field", cfg="rpass2")] +#![rustc_partition_reused(module="struct_point-fn_write_field", cfg="rpass2")] + +mod point { + pub struct Point { + pub x: f32, + pub y: f32, + } + + impl Point { + fn distance_squared(&self) -> f32 { + #[cfg(rpass1)] + return self.x + self.y; + + #[cfg(rpass2)] + return self.x * self.x + self.y * self.y; + } + + pub fn distance_from_origin(&self) -> f32 { + self.distance_squared().sqrt() + } + } + + impl Point { + pub fn translate(&mut self, x: f32, y: f32) { + self.x += x; + self.y += y; + } + } + +} + +/// A fn item that calls (public) methods on `Point` from the same impl which changed +mod fn_calls_methods_in_same_impl { + use point::Point; + + // FIXME(#37121) -- we should not need to typeck this again + #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] + pub fn check() { + let x = Point { x: 2.0, y: 2.0 }; + x.distance_from_origin(); + } +} + +/// A fn item that calls (public) methods on `Point` from another impl +mod fn_calls_methods_in_another_impl { + use point::Point; + + // FIXME(#37121) -- we should not need to typeck this again + #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] + pub fn check() { + let mut x = Point { x: 2.0, y: 2.0 }; + x.translate(3.0, 3.0); + } +} + +/// A fn item that makes an instance of `Point` but does not invoke methods +mod fn_make_struct { + use point::Point; + + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] + pub fn make_origin() -> Point { + Point { x: 2.0, y: 2.0 } + } +} + +/// A fn item that reads fields from `Point` but does not invoke methods +mod fn_read_field { + use point::Point; + + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] + pub fn get_x(p: Point) -> f32 { + p.x + } +} + +/// A fn item that writes to a field of `Point` but does not invoke methods +mod fn_write_field { + use point::Point; + + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] + pub fn inc_x(p: &mut Point) { + p.x += 1.0; + } +} + +fn main() { +} diff --git a/src/test/pretty/for-comment.rs b/src/test/pretty/for-comment.rs index af76c1d940664..32837fbcf87bc 100644 --- a/src/test/pretty/for-comment.rs +++ b/src/test/pretty/for-comment.rs @@ -17,6 +17,5 @@ fn f(v: &[isize]) -> isize { for e in v { n = *e; // This comment once triggered pretty printer bug } - n } diff --git a/src/test/run-fail/divide-by-zero.rs b/src/test/run-fail/divide-by-zero.rs index c9c4a88c9b53e..1f9e069526ce9 100644 --- a/src/test/run-fail/divide-by-zero.rs +++ b/src/test/run-fail/divide-by-zero.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // error-pattern:attempt to divide by zero fn main() { diff --git a/src/test/run-fail/glob-use-std.rs b/src/test/run-fail/glob-use-std.rs index 6712b3b065908..a7ba283b25af3 100644 --- a/src/test/run-fail/glob-use-std.rs +++ b/src/test/run-fail/glob-use-std.rs @@ -10,10 +10,6 @@ // Issue #7580 -// ignore-pretty -// -// Expanded pretty printing causes resolve conflicts. - // error-pattern:panic works use std::*; diff --git a/src/test/run-fail/mod-zero.rs b/src/test/run-fail/mod-zero.rs index d2b598a7933bc..641d39e2324b8 100644 --- a/src/test/run-fail/mod-zero.rs +++ b/src/test/run-fail/mod-zero.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // error-pattern:attempt to calculate the remainder with a divisor of zero fn main() { diff --git a/src/test/run-fail/overflowing-add.rs b/src/test/run-fail/overflowing-add.rs index acc7676db457e..250f0726dc9d6 100644 --- a/src/test/run-fail/overflowing-add.rs +++ b/src/test/run-fail/overflowing-add.rs @@ -8,12 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // error-pattern:thread 'main' panicked at 'attempt to add with overflow' // compile-flags: -C debug-assertions - fn main() { let _x = 200u8 + 200u8 + 200u8; } diff --git a/src/test/run-fail/overflowing-lsh-1.rs b/src/test/run-fail/overflowing-lsh-1.rs index 29ce3b0e6a16d..baa1e05d559b6 100644 --- a/src/test/run-fail/overflowing-lsh-1.rs +++ b/src/test/run-fail/overflowing-lsh-1.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // error-pattern:thread 'main' panicked at 'attempt to shift left with overflow' // compile-flags: -C debug-assertions diff --git a/src/test/run-fail/overflowing-lsh-2.rs b/src/test/run-fail/overflowing-lsh-2.rs index 62fc9230f353d..3438ed2c77c18 100644 --- a/src/test/run-fail/overflowing-lsh-2.rs +++ b/src/test/run-fail/overflowing-lsh-2.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // error-pattern:thread 'main' panicked at 'attempt to shift left with overflow' // compile-flags: -C debug-assertions diff --git a/src/test/run-fail/overflowing-lsh-3.rs b/src/test/run-fail/overflowing-lsh-3.rs index 1bc1703a89ce3..ef5c43db6e285 100644 --- a/src/test/run-fail/overflowing-lsh-3.rs +++ b/src/test/run-fail/overflowing-lsh-3.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // error-pattern:thread 'main' panicked at 'attempt to shift left with overflow' // compile-flags: -C debug-assertions diff --git a/src/test/run-fail/overflowing-lsh-4.rs b/src/test/run-fail/overflowing-lsh-4.rs index 8de44f25e0489..226ece6020db4 100644 --- a/src/test/run-fail/overflowing-lsh-4.rs +++ b/src/test/run-fail/overflowing-lsh-4.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // error-pattern:thread 'main' panicked at 'attempt to shift left with overflow' // compile-flags: -C debug-assertions diff --git a/src/test/run-fail/overflowing-mul.rs b/src/test/run-fail/overflowing-mul.rs index a09c0f06a5cc6..b47d0fc4136cc 100644 --- a/src/test/run-fail/overflowing-mul.rs +++ b/src/test/run-fail/overflowing-mul.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // error-pattern:thread 'main' panicked at 'attempt to multiply with overflow' // compile-flags: -C debug-assertions diff --git a/src/test/run-fail/overflowing-neg.rs b/src/test/run-fail/overflowing-neg.rs index 96853fc565b71..836d7e37319e9 100644 --- a/src/test/run-fail/overflowing-neg.rs +++ b/src/test/run-fail/overflowing-neg.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // error-pattern:thread 'main' panicked at 'attempt to negate with overflow' // compile-flags: -C debug-assertions diff --git a/src/test/run-fail/overflowing-rsh-1.rs b/src/test/run-fail/overflowing-rsh-1.rs index ef4a503cfe425..8f198c887e491 100644 --- a/src/test/run-fail/overflowing-rsh-1.rs +++ b/src/test/run-fail/overflowing-rsh-1.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // error-pattern:thread 'main' panicked at 'attempt to shift right with overflow' // compile-flags: -C debug-assertions diff --git a/src/test/run-fail/overflowing-rsh-2.rs b/src/test/run-fail/overflowing-rsh-2.rs index da072b5a9a5a9..e4f260b2bbbbb 100644 --- a/src/test/run-fail/overflowing-rsh-2.rs +++ b/src/test/run-fail/overflowing-rsh-2.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // error-pattern:thread 'main' panicked at 'attempt to shift right with overflow' // compile-flags: -C debug-assertions diff --git a/src/test/run-fail/overflowing-rsh-3.rs b/src/test/run-fail/overflowing-rsh-3.rs index 0b7809402e6db..11aa98a0c3cbc 100644 --- a/src/test/run-fail/overflowing-rsh-3.rs +++ b/src/test/run-fail/overflowing-rsh-3.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // error-pattern:thread 'main' panicked at 'attempt to shift right with overflow' // compile-flags: -C debug-assertions diff --git a/src/test/run-fail/overflowing-rsh-4.rs b/src/test/run-fail/overflowing-rsh-4.rs index 1e0cc18fbdcd6..742720e83c10c 100644 --- a/src/test/run-fail/overflowing-rsh-4.rs +++ b/src/test/run-fail/overflowing-rsh-4.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // error-pattern:thread 'main' panicked at 'attempt to shift right with overflow' // compile-flags: -C debug-assertions diff --git a/src/test/run-fail/overflowing-rsh-5.rs b/src/test/run-fail/overflowing-rsh-5.rs index 690901ff0c25b..6106fdcb16a46 100644 --- a/src/test/run-fail/overflowing-rsh-5.rs +++ b/src/test/run-fail/overflowing-rsh-5.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // error-pattern:thread 'main' panicked at 'attempt to shift right with overflow' // compile-flags: -C debug-assertions diff --git a/src/test/run-fail/overflowing-rsh-6.rs b/src/test/run-fail/overflowing-rsh-6.rs index 6a6ed4f11f20e..d419550fcc570 100644 --- a/src/test/run-fail/overflowing-rsh-6.rs +++ b/src/test/run-fail/overflowing-rsh-6.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // error-pattern:thread 'main' panicked at 'attempt to shift right with overflow' // compile-flags: -C debug-assertions diff --git a/src/test/run-fail/overflowing-sub.rs b/src/test/run-fail/overflowing-sub.rs index 083e8d24467fd..f94cb31b16884 100644 --- a/src/test/run-fail/overflowing-sub.rs +++ b/src/test/run-fail/overflowing-sub.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // error-pattern:thread 'main' panicked at 'attempt to subtract with overflow' // compile-flags: -C debug-assertions diff --git a/src/test/run-fail/run-unexported-tests.rs b/src/test/run-fail/run-unexported-tests.rs index 8158333ade818..3f75229948df0 100644 --- a/src/test/run-fail/run-unexported-tests.rs +++ b/src/test/run-fail/run-unexported-tests.rs @@ -11,7 +11,6 @@ // error-pattern:runned an unexported test // compile-flags:--test // check-stdout -// ignore-pretty: does not work well with `--test` mod m { pub fn exported() {} diff --git a/src/test/run-fail/test-panic.rs b/src/test/run-fail/test-panic.rs index 21ced01d9d69e..bb6f4abe1fc96 100644 --- a/src/test/run-fail/test-panic.rs +++ b/src/test/run-fail/test-panic.rs @@ -11,7 +11,6 @@ // check-stdout // error-pattern:thread 'test_foo' panicked at // compile-flags: --test -// ignore-pretty: does not work well with `--test` // ignore-emscripten #[test] diff --git a/src/test/run-fail/test-should-fail-bad-message.rs b/src/test/run-fail/test-should-fail-bad-message.rs index 74b5f17bcf9ba..eac9813f180ae 100644 --- a/src/test/run-fail/test-should-fail-bad-message.rs +++ b/src/test/run-fail/test-should-fail-bad-message.rs @@ -11,7 +11,6 @@ // check-stdout // error-pattern:thread 'test_foo' panicked at // compile-flags: --test -// ignore-pretty: does not work well with `--test` // ignore-emscripten #[test] diff --git a/src/test/run-fail/test-tasks-invalid-value.rs b/src/test/run-fail/test-tasks-invalid-value.rs index b5c222764d243..fcf3559e7da66 100644 --- a/src/test/run-fail/test-tasks-invalid-value.rs +++ b/src/test/run-fail/test-tasks-invalid-value.rs @@ -14,7 +14,6 @@ // error-pattern:should be a positive integer // compile-flags: --test // exec-env:RUST_TEST_THREADS=foo -// ignore-pretty: does not work well with `--test` // ignore-emscripten #[test] diff --git a/src/test/run-make/dep-info-spaces/Makefile b/src/test/run-make/dep-info-spaces/Makefile index eda8cb700810d..82686ffdd9d93 100644 --- a/src/test/run-make/dep-info-spaces/Makefile +++ b/src/test/run-make/dep-info-spaces/Makefile @@ -5,9 +5,12 @@ ifneq ($(shell uname),FreeBSD) ifndef IS_WINDOWS all: - $(RUSTC) --emit link,dep-info --crate-type=lib lib.rs + cp lib.rs $(TMPDIR)/ + cp 'foo foo.rs' $(TMPDIR)/ + cp bar.rs $(TMPDIR)/ + $(RUSTC) --emit link,dep-info --crate-type=lib $(TMPDIR)/lib.rs sleep 1 - touch 'foo foo.rs' + touch $(TMPDIR)/'foo foo.rs' -rm -f $(TMPDIR)/done $(MAKE) -drf Makefile.foo rm $(TMPDIR)/done diff --git a/src/test/run-make/dep-info-spaces/Makefile.foo b/src/test/run-make/dep-info-spaces/Makefile.foo index 2f4cc486d8667..80a5d4333cdc2 100644 --- a/src/test/run-make/dep-info-spaces/Makefile.foo +++ b/src/test/run-make/dep-info-spaces/Makefile.foo @@ -1,7 +1,7 @@ -LIB := $(shell $(RUSTC) --print file-names --crate-type=lib lib.rs) +LIB := $(shell $(RUSTC) --print file-names --crate-type=lib $(TMPDIR)/lib.rs) $(TMPDIR)/$(LIB): - $(RUSTC) --emit link,dep-info --crate-type=lib lib.rs + $(RUSTC) --emit link,dep-info --crate-type=lib $(TMPDIR)/lib.rs touch $(TMPDIR)/done -include $(TMPDIR)/lib.d diff --git a/src/test/run-make/llvm-phase/test.rs b/src/test/run-make/llvm-phase/test.rs index 05c1713561a3e..ca58e007852bd 100644 --- a/src/test/run-make/llvm-phase/test.rs +++ b/src/test/run-make/llvm-phase/test.rs @@ -22,6 +22,7 @@ use rustc_driver::driver::CompileController; use rustc_trans::ModuleSource; use rustc::session::Session; use syntax::codemap::FileLoader; +use std::env; use std::io; use std::path::{PathBuf, Path}; @@ -75,9 +76,11 @@ fn main() { path.pop(); path.pop(); - let args: Vec = + let mut args: Vec = format!("_ _ --sysroot {} --crate-type dylib", path.to_str().unwrap()) .split(' ').map(|s| s.to_string()).collect(); + args.push("--out-dir".to_string()); + args.push(env::var("TMPDIR").unwrap()); let (result, _) = rustc_driver::run_compiler( &args, &mut JitCalls, Some(box JitLoader), None); diff --git a/src/test/run-make/tools.mk b/src/test/run-make/tools.mk index 38afa42a2935a..1db87d474bd72 100644 --- a/src/test/run-make/tools.mk +++ b/src/test/run-make/tools.mk @@ -22,9 +22,6 @@ RLIB_GLOB = lib$(1)*.rlib BIN = $(1) UNAME = $(shell uname) -ifneq (,$(findstring MINGW,$(UNAME))) -IS_WINDOWS=1 -endif ifeq ($(UNAME),Darwin) RUN = $(TARGET_RPATH_ENV) $(RUN_BINFILE) diff --git a/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs b/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs index 4885863122c3b..2c814a5433baa 100644 --- a/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs +++ b/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs @@ -60,7 +60,7 @@ fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box Box { // Parse an expression and emit it unchanged. - let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(), tts.to_vec()); + let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg().clone(), tts.to_vec()); let expr = parser.parse_expr().unwrap(); MacEager::expr(quote_expr!(&mut *cx, $expr)) } diff --git a/src/test/run-pass-fulldeps/custom-derive-partial-eq.rs b/src/test/run-pass-fulldeps/custom-derive-partial-eq.rs index 8cc7ab4219dc5..47f5f8397d1c5 100644 --- a/src/test/run-pass-fulldeps/custom-derive-partial-eq.rs +++ b/src/test/run-pass-fulldeps/custom-derive-partial-eq.rs @@ -10,8 +10,6 @@ // aux-build:custom_derive_partial_eq.rs // ignore-stage1 -// ignore-pretty : (#23623) problems when ending with // comments - #![feature(plugin, custom_derive)] #![plugin(custom_derive_partial_eq)] #![allow(unused)] diff --git a/src/test/run-pass-fulldeps/issue-16992.rs b/src/test/run-pass-fulldeps/issue-16992.rs index a439e2bb25b8c..3ab7f8429e601 100644 --- a/src/test/run-pass-fulldeps/issue-16992.rs +++ b/src/test/run-pass-fulldeps/issue-16992.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty // ignore-cross-compile #![feature(quote, rustc_private)] diff --git a/src/test/run-pass-fulldeps/issue-18763-quote-token-tree.rs b/src/test/run-pass-fulldeps/issue-18763-quote-token-tree.rs index 829fdb176bd31..03311d76e46d4 100644 --- a/src/test/run-pass-fulldeps/issue-18763-quote-token-tree.rs +++ b/src/test/run-pass-fulldeps/issue-18763-quote-token-tree.rs @@ -9,8 +9,6 @@ // except according to those terms. // ignore-cross-compile -// ignore-pretty: does not work well with `--test` - #![feature(quote, rustc_private)] extern crate syntax; diff --git a/src/test/run-pass-fulldeps/lint-group-plugin.rs b/src/test/run-pass-fulldeps/lint-group-plugin.rs index 21942b84bff9c..978a78cee4f1e 100644 --- a/src/test/run-pass-fulldeps/lint-group-plugin.rs +++ b/src/test/run-pass-fulldeps/lint-group-plugin.rs @@ -10,8 +10,6 @@ // aux-build:lint_group_plugin_test.rs // ignore-stage1 -// ignore-pretty - #![feature(plugin)] #![plugin(lint_group_plugin_test)] #![allow(dead_code)] diff --git a/src/test/run-pass-fulldeps/lint-plugin-cmdline-load.rs b/src/test/run-pass-fulldeps/lint-plugin-cmdline-load.rs index 2a6daa5040b71..2e86e11bd6a5f 100644 --- a/src/test/run-pass-fulldeps/lint-plugin-cmdline-load.rs +++ b/src/test/run-pass-fulldeps/lint-plugin-cmdline-load.rs @@ -10,7 +10,6 @@ // aux-build:lint_plugin_test.rs // ignore-stage1 -// ignore-pretty: Random space appears with the pretty test // compile-flags: -Z extra-plugins=lint_plugin_test #![allow(dead_code)] diff --git a/src/test/run-pass-fulldeps/lint-plugin.rs b/src/test/run-pass-fulldeps/lint-plugin.rs index b694a1c332079..753ad33bd01e9 100644 --- a/src/test/run-pass-fulldeps/lint-plugin.rs +++ b/src/test/run-pass-fulldeps/lint-plugin.rs @@ -10,8 +10,6 @@ // aux-build:lint_plugin_test.rs // ignore-stage1 -// ignore-pretty - #![feature(plugin)] #![plugin(lint_plugin_test)] #![allow(dead_code)] diff --git a/src/test/run-pass-fulldeps/quote-tokens.rs b/src/test/run-pass-fulldeps/quote-tokens.rs index 710e2fd1d07a3..9e9b7ce5bf29d 100644 --- a/src/test/run-pass-fulldeps/quote-tokens.rs +++ b/src/test/run-pass-fulldeps/quote-tokens.rs @@ -9,8 +9,6 @@ // except according to those terms. // ignore-cross-compile -// ignore-pretty: does not work well with `--test` - #![feature(quote, rustc_private)] extern crate syntax; diff --git a/src/test/run-pass-fulldeps/quote-unused-sp-no-warning.rs b/src/test/run-pass-fulldeps/quote-unused-sp-no-warning.rs index 460eab998c6fb..d3be1ddcb8c32 100644 --- a/src/test/run-pass-fulldeps/quote-unused-sp-no-warning.rs +++ b/src/test/run-pass-fulldeps/quote-unused-sp-no-warning.rs @@ -9,8 +9,6 @@ // except according to those terms. // ignore-cross-compile -// ignore-pretty: does not work well with `--test` - #![feature(quote, rustc_private)] #![deny(unused_variables)] diff --git a/src/test/run-pass-valgrind/cast-enum-with-dtor.rs b/src/test/run-pass-valgrind/cast-enum-with-dtor.rs index 7cf75924a28c0..2815863fe9961 100644 --- a/src/test/run-pass-valgrind/cast-enum-with-dtor.rs +++ b/src/test/run-pass-valgrind/cast-enum-with-dtor.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // no-prefer-dynamic #![allow(dead_code)] diff --git a/src/test/run-pass/auxiliary/dropck_eyepatch_extern_crate.rs b/src/test/run-pass/auxiliary/dropck_eyepatch_extern_crate.rs new file mode 100644 index 0000000000000..1266e589b127e --- /dev/null +++ b/src/test/run-pass/auxiliary/dropck_eyepatch_extern_crate.rs @@ -0,0 +1,61 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generic_param_attrs)] +#![feature(dropck_eyepatch)] + +// The point of this test is to illustrate that the `#[may_dangle]` +// attribute specifically allows, in the context of a type +// implementing `Drop`, a generic parameter to be instantiated with a +// lifetime that does not strictly outlive the owning type itself, +// and that this attributes effects are preserved when importing +// the type from another crate. +// +// See also dropck-eyepatch.rs for more information about the general +// structure of the test. + +use std::cell::RefCell; + +pub trait Foo { fn foo(&self, _: &str); } + +pub struct Dt(pub &'static str, pub A); +pub struct Dr<'a, B:'a+Foo>(pub &'static str, pub &'a B); +pub struct Pt(pub &'static str, pub A, pub B); +pub struct Pr<'a, 'b, B:'a+'b+Foo>(pub &'static str, pub &'a B, pub &'b B); +pub struct St(pub &'static str, pub A); +pub struct Sr<'a, B:'a+Foo>(pub &'static str, pub &'a B); + +impl Drop for Dt { + fn drop(&mut self) { println!("drop {}", self.0); self.1.foo(self.0); } +} +impl<'a, B: Foo> Drop for Dr<'a, B> { + fn drop(&mut self) { println!("drop {}", self.0); self.1.foo(self.0); } +} +unsafe impl<#[may_dangle] A, B: Foo> Drop for Pt { + // (unsafe to access self.1 due to #[may_dangle] on A) + fn drop(&mut self) { println!("drop {}", self.0); self.2.foo(self.0); } +} +unsafe impl<#[may_dangle] 'a, 'b, B: Foo> Drop for Pr<'a, 'b, B> { + // (unsafe to access self.1 due to #[may_dangle] on 'a) + fn drop(&mut self) { println!("drop {}", self.0); self.2.foo(self.0); } +} + +impl Foo for RefCell { + fn foo(&self, s: &str) { + let s2 = format!("{}|{}", *self.borrow(), s); + *self.borrow_mut() = s2; + } +} + +impl<'a, T:Foo> Foo for &'a T { + fn foo(&self, s: &str) { + (*self).foo(s); + } +} diff --git a/src/test/run-pass/backtrace-debuginfo.rs b/src/test/run-pass/backtrace-debuginfo.rs index 838005cbc9119..72cf109fd5974 100644 --- a/src/test/run-pass/backtrace-debuginfo.rs +++ b/src/test/run-pass/backtrace-debuginfo.rs @@ -16,7 +16,7 @@ // "enable" to 0 instead. // compile-flags:-g -Cllvm-args=-enable-tail-merge=0 -// ignore-pretty as this critically relies on line numbers +// ignore-pretty issue #37195 // ignore-emscripten spawning processes is not supported use std::io; diff --git a/src/test/run-pass/backtrace.rs b/src/test/run-pass/backtrace.rs index f26706d1754e0..c438c17f51e3a 100644 --- a/src/test/run-pass/backtrace.rs +++ b/src/test/run-pass/backtrace.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// no-pretty-expanded FIXME #15189 // ignore-android FIXME #17520 // ignore-emscripten spawning processes is not supported // compile-flags:-g diff --git a/src/test/run-pass/borrowck/borrowck-pat-enum.rs b/src/test/run-pass/borrowck/borrowck-pat-enum.rs index b29cb63f6fa3b..8de45e4205dfb 100644 --- a/src/test/run-pass/borrowck/borrowck-pat-enum.rs +++ b/src/test/run-pass/borrowck/borrowck-pat-enum.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty +// ignore-pretty issue #37199 fn match_ref(v: Option) -> isize { match v { diff --git a/src/test/run-pass/cfg-in-crate-1.rs b/src/test/run-pass/cfg-in-crate-1.rs index 06f679b7fca9a..5dd6fa45bb96e 100644 --- a/src/test/run-pass/cfg-in-crate-1.rs +++ b/src/test/run-pass/cfg-in-crate-1.rs @@ -9,8 +9,6 @@ // except according to those terms. // compile-flags: --cfg bar -D warnings -// ignore-pretty - #![cfg(bar)] fn main() {} diff --git a/src/test/run-pass/command-exec.rs b/src/test/run-pass/command-exec.rs index 130526e72b19c..5be9b97aac7e6 100644 --- a/src/test/run-pass/command-exec.rs +++ b/src/test/run-pass/command-exec.rs @@ -9,9 +9,8 @@ // except according to those terms. // ignore-windows - this is a unix-specific test +// ignore-pretty issue #37199 // ignore-emscripten -// ignore-pretty - #![feature(process_exec)] use std::env; diff --git a/src/test/run-pass/core-run-destroy.rs b/src/test/run-pass/core-run-destroy.rs index ffcc1891c579e..c5b5b6b24ab1c 100644 --- a/src/test/run-pass/core-run-destroy.rs +++ b/src/test/run-pass/core-run-destroy.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty // compile-flags:--test // ignore-emscripten diff --git a/src/test/run-pass/deprecated-macro_escape-inner.rs b/src/test/run-pass/deprecated-macro_escape-inner.rs index 7960a91bdc4fc..1a2be7a719e17 100644 --- a/src/test/run-pass/deprecated-macro_escape-inner.rs +++ b/src/test/run-pass/deprecated-macro_escape-inner.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - mod foo { #![macro_escape] //~ WARNING macro_escape is a deprecated synonym for macro_use //~^ HELP consider an outer attribute diff --git a/src/test/run-pass/deprecated-macro_escape.rs b/src/test/run-pass/deprecated-macro_escape.rs index b03905e1a0d63..b9f756cc79c8f 100644 --- a/src/test/run-pass/deprecated-macro_escape.rs +++ b/src/test/run-pass/deprecated-macro_escape.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - #[macro_escape] //~ WARNING macro_escape is a deprecated synonym for macro_use mod foo { } diff --git a/src/test/run-pass/deriving-cmp-generic-enum.rs b/src/test/run-pass/deriving-cmp-generic-enum.rs index b1cd1877a7667..b2add21dcd487 100644 --- a/src/test/run-pass/deriving-cmp-generic-enum.rs +++ b/src/test/run-pass/deriving-cmp-generic-enum.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// no-pretty-expanded FIXME #15189 - - #[derive(PartialEq, Eq, PartialOrd, Ord)] enum E { E0, diff --git a/src/test/run-pass/deriving-meta-empty-trait-list.rs b/src/test/run-pass/deriving-meta-empty-trait-list.rs index ff513325d5e68..ed8a50998daee 100644 --- a/src/test/run-pass/deriving-meta-empty-trait-list.rs +++ b/src/test/run-pass/deriving-meta-empty-trait-list.rs @@ -1,5 +1,3 @@ -// ignore-pretty - // Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. diff --git a/src/test/run-pass/dropck-eyepatch-extern-crate.rs b/src/test/run-pass/dropck-eyepatch-extern-crate.rs new file mode 100644 index 0000000000000..20f069f77ea15 --- /dev/null +++ b/src/test/run-pass/dropck-eyepatch-extern-crate.rs @@ -0,0 +1,48 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:dropck_eyepatch_extern_crate.rs + +extern crate dropck_eyepatch_extern_crate as other; + +use other::{Dt,Dr,Pt,Pr,St,Sr}; + +fn main() { + use std::cell::RefCell; + + struct CheckOnDrop(RefCell, &'static str); + impl Drop for CheckOnDrop { + fn drop(&mut self) { assert_eq!(*self.0.borrow(), self.1); } + } + + let c_long; + let (c, dt, dr, pt, pr, st, sr) + : (CheckOnDrop, Dt<_>, Dr<_>, Pt<_, _>, Pr<_>, St<_>, Sr<_>); + c_long = CheckOnDrop(RefCell::new("c_long".to_string()), + "c_long|pr|pt|dr|dt"); + c = CheckOnDrop(RefCell::new("c".to_string()), + "c"); + + // No error: sufficiently long-lived state can be referenced in dtors + dt = Dt("dt", &c_long.0); + dr = Dr("dr", &c_long.0); + + // No error: Drop impl asserts .1 (A and &'a _) are not accessed + pt = Pt("pt", &c.0, &c_long.0); + pr = Pr("pr", &c.0, &c_long.0); + + // No error: St and Sr have no destructor. + st = St("st", &c.0); + sr = Sr("sr", &c.0); + + println!("{:?}", (dt.0, dr.0, pt.0, pr.0, st.0, sr.0)); + assert_eq!(*c_long.0.borrow(), "c_long"); + assert_eq!(*c.0.borrow(), "c"); +} diff --git a/src/test/run-pass/dropck-eyepatch-reorder.rs b/src/test/run-pass/dropck-eyepatch-reorder.rs new file mode 100644 index 0000000000000..bbf8bb8c35238 --- /dev/null +++ b/src/test/run-pass/dropck-eyepatch-reorder.rs @@ -0,0 +1,89 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generic_param_attrs)] +#![feature(dropck_eyepatch)] + +// The point of this test is to test uses of `#[may_dangle]` attribute +// where the formal declaration order (in the impl generics) does not +// match the actual usage order (in the type instantiation). +// +// See also dropck-eyepatch.rs for more information about the general +// structure of the test. + +trait Foo { fn foo(&self, _: &str); } + +struct Dt(&'static str, A); +struct Dr<'a, B:'a+Foo>(&'static str, &'a B); +struct Pt(&'static str, A, B); +struct Pr<'a, 'b, B:'a+'b+Foo>(&'static str, &'a B, &'b B); +struct St(&'static str, A); +struct Sr<'a, B:'a+Foo>(&'static str, &'a B); + +impl Drop for Dt { + fn drop(&mut self) { println!("drop {}", self.0); self.1.foo(self.0); } +} +impl<'a, B: Foo> Drop for Dr<'a, B> { + fn drop(&mut self) { println!("drop {}", self.0); self.1.foo(self.0); } +} +unsafe impl Drop for Pt { + // (unsafe to access self.1 due to #[may_dangle] on A) + fn drop(&mut self) { println!("drop {}", self.0); self.2.foo(self.0); } +} +unsafe impl<'b, #[may_dangle] 'a, B: Foo> Drop for Pr<'a, 'b, B> { + // (unsafe to access self.1 due to #[may_dangle] on 'a) + fn drop(&mut self) { println!("drop {}", self.0); self.2.foo(self.0); } +} + +fn main() { + use std::cell::RefCell; + + impl Foo for RefCell { + fn foo(&self, s: &str) { + let s2 = format!("{}|{}", *self.borrow(), s); + *self.borrow_mut() = s2; + } + } + + impl<'a, T:Foo> Foo for &'a T { + fn foo(&self, s: &str) { + (*self).foo(s); + } + } + + struct CheckOnDrop(RefCell, &'static str); + impl Drop for CheckOnDrop { + fn drop(&mut self) { assert_eq!(*self.0.borrow(), self.1); } + } + + let c_long; + let (c, dt, dr, pt, pr, st, sr) + : (CheckOnDrop, Dt<_>, Dr<_>, Pt<_, _>, Pr<_>, St<_>, Sr<_>); + c_long = CheckOnDrop(RefCell::new("c_long".to_string()), + "c_long|pr|pt|dr|dt"); + c = CheckOnDrop(RefCell::new("c".to_string()), + "c"); + + // No error: sufficiently long-lived state can be referenced in dtors + dt = Dt("dt", &c_long.0); + dr = Dr("dr", &c_long.0); + + // No error: Drop impl asserts .1 (A and &'a _) are not accessed + pt = Pt("pt", &c.0, &c_long.0); + pr = Pr("pr", &c.0, &c_long.0); + + // No error: St and Sr have no destructor. + st = St("st", &c.0); + sr = Sr("sr", &c.0); + + println!("{:?}", (dt.0, dr.0, pt.0, pr.0, st.0, sr.0)); + assert_eq!(*c_long.0.borrow(), "c_long"); + assert_eq!(*c.0.borrow(), "c"); +} diff --git a/src/test/run-pass/dropck-eyepatch.rs b/src/test/run-pass/dropck-eyepatch.rs new file mode 100644 index 0000000000000..4a09ba05dff5e --- /dev/null +++ b/src/test/run-pass/dropck-eyepatch.rs @@ -0,0 +1,112 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generic_param_attrs)] +#![feature(dropck_eyepatch)] + +// The point of this test is to illustrate that the `#[may_dangle]` +// attribute specifically allows, in the context of a type +// implementing `Drop`, a generic parameter to be instantiated with a +// lifetime that does not strictly outlive the owning type itself. +// +// Here we test that a model use of `#[may_dangle]` will compile and run. +// +// The illustration is made concrete by comparison with two variations +// on the type with `#[may_dangle]`: +// +// 1. an analogous type that does not implement `Drop` (and thus +// should exhibit maximal flexibility with respect to dropck), and +// +// 2. an analogous type that does not use `#[may_dangle]` (and thus +// should exhibit the standard limitations imposed by dropck. +// +// The types in this file follow a pattern, {D,P,S}{t,r}, where: +// +// - D means "I implement Drop" +// +// - P means "I implement Drop but guarantee my (first) parameter is +// pure, i.e. not accessed from the destructor"; no other parameters +// are pure. +// +// - S means "I do not implement Drop" +// +// - t suffix is used when the first generic is a type +// +// - r suffix is used when the first generic is a lifetime. + +trait Foo { fn foo(&self, _: &str); } + +struct Dt(&'static str, A); +struct Dr<'a, B:'a+Foo>(&'static str, &'a B); +struct Pt(&'static str, A, B); +struct Pr<'a, 'b, B:'a+'b+Foo>(&'static str, &'a B, &'b B); +struct St(&'static str, A); +struct Sr<'a, B:'a+Foo>(&'static str, &'a B); + +impl Drop for Dt { + fn drop(&mut self) { println!("drop {}", self.0); self.1.foo(self.0); } +} +impl<'a, B: Foo> Drop for Dr<'a, B> { + fn drop(&mut self) { println!("drop {}", self.0); self.1.foo(self.0); } +} +unsafe impl<#[may_dangle] A, B: Foo> Drop for Pt { + // (unsafe to access self.1 due to #[may_dangle] on A) + fn drop(&mut self) { println!("drop {}", self.0); self.2.foo(self.0); } +} +unsafe impl<#[may_dangle] 'a, 'b, B: Foo> Drop for Pr<'a, 'b, B> { + // (unsafe to access self.1 due to #[may_dangle] on 'a) + fn drop(&mut self) { println!("drop {}", self.0); self.2.foo(self.0); } +} + +fn main() { + use std::cell::RefCell; + + impl Foo for RefCell { + fn foo(&self, s: &str) { + let s2 = format!("{}|{}", *self.borrow(), s); + *self.borrow_mut() = s2; + } + } + + impl<'a, T:Foo> Foo for &'a T { + fn foo(&self, s: &str) { + (*self).foo(s); + } + } + + struct CheckOnDrop(RefCell, &'static str); + impl Drop for CheckOnDrop { + fn drop(&mut self) { assert_eq!(*self.0.borrow(), self.1); } + } + + let c_long; + let (c, dt, dr, pt, pr, st, sr) + : (CheckOnDrop, Dt<_>, Dr<_>, Pt<_, _>, Pr<_>, St<_>, Sr<_>); + c_long = CheckOnDrop(RefCell::new("c_long".to_string()), + "c_long|pr|pt|dr|dt"); + c = CheckOnDrop(RefCell::new("c".to_string()), + "c"); + + // No error: sufficiently long-lived state can be referenced in dtors + dt = Dt("dt", &c_long.0); + dr = Dr("dr", &c_long.0); + + // No error: Drop impl asserts .1 (A and &'a _) are not accessed + pt = Pt("pt", &c.0, &c_long.0); + pr = Pr("pr", &c.0, &c_long.0); + + // No error: St and Sr have no destructor. + st = St("st", &c.0); + sr = Sr("sr", &c.0); + + println!("{:?}", (dt.0, dr.0, pt.0, pr.0, st.0, sr.0)); + assert_eq!(*c_long.0.borrow(), "c_long"); + assert_eq!(*c.0.borrow(), "c"); +} diff --git a/src/test/run-pass/enum-size-variance.rs b/src/test/run-pass/enum-size-variance.rs index 21996c5fabf1a..26deb0ed72ade 100644 --- a/src/test/run-pass/enum-size-variance.rs +++ b/src/test/run-pass/enum-size-variance.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. // -// ignore-pretty - #![warn(variant_size_differences)] #![allow(dead_code)] diff --git a/src/test/run-pass/hygienic-labels-in-let.rs b/src/test/run-pass/hygienic-labels-in-let.rs index 5b45f1e0d3928..2aa5f59cda62d 100644 --- a/src/test/run-pass/hygienic-labels-in-let.rs +++ b/src/test/run-pass/hygienic-labels-in-let.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty: pprust doesn't print hygiene output - // Test that labels injected by macros do not break hygiene. This // checks cases where the macros invocations are under the rhs of a // let statement. diff --git a/src/test/run-pass/ifmt.rs b/src/test/run-pass/ifmt.rs index 0ebe1ca07c771..c9af2b190b21c 100644 --- a/src/test/run-pass/ifmt.rs +++ b/src/test/run-pass/ifmt.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// no-pretty-expanded unnecessary unsafe block generated - #![deny(warnings)] #![allow(unused_must_use)] #![allow(unused_features)] diff --git a/src/test/run-pass/imports.rs b/src/test/run-pass/imports.rs index 9851dfe0262f8..195b99c9788e8 100644 --- a/src/test/run-pass/imports.rs +++ b/src/test/run-pass/imports.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - #![feature(item_like_imports)] #![allow(unused)] diff --git a/src/test/run-pass/issue-11709.rs b/src/test/run-pass/issue-11709.rs index cfff7eb339522..88d74a65813be 100644 --- a/src/test/run-pass/issue-11709.rs +++ b/src/test/run-pass/issue-11709.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty +// ignore-pretty issue #37199 // Don't panic on blocks without results // There are several tests in this run-pass that raised diff --git a/src/test/run-pass/issue-15189.rs b/src/test/run-pass/issue-15189.rs index 24340ac3f13d7..35faa5789a9c8 100644 --- a/src/test/run-pass/issue-15189.rs +++ b/src/test/run-pass/issue-15189.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - macro_rules! third { ($e:expr) => ({let x = 2; $e[x]}) } diff --git a/src/test/run-pass/issue-16492.rs b/src/test/run-pass/issue-16492.rs index 975557726ce8b..177550a0dd4a1 100644 --- a/src/test/run-pass/issue-16492.rs +++ b/src/test/run-pass/issue-16492.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - use std::rc::Rc; use std::cell::Cell; diff --git a/src/test/run-pass/issue-16597-empty.rs b/src/test/run-pass/issue-16597-empty.rs index a6a1c5f16b31c..c51e33c01040b 100644 --- a/src/test/run-pass/issue-16597-empty.rs +++ b/src/test/run-pass/issue-16597-empty.rs @@ -9,7 +9,6 @@ // except according to those terms. // compile-flags:--test -// no-pretty-expanded // This verifies that the test generation doesn't crash when we have // no tests - for more information, see PR #16892. diff --git a/src/test/run-pass/issue-16597.rs b/src/test/run-pass/issue-16597.rs index 7f0a341f14715..583d8d46235d6 100644 --- a/src/test/run-pass/issue-16597.rs +++ b/src/test/run-pass/issue-16597.rs @@ -9,7 +9,6 @@ // except according to those terms. // compile-flags:--test -// ignore-pretty turns out the pretty-printer doesn't handle gensym'd things... mod tests { use super::*; diff --git a/src/test/run-pass/issue-16668.rs b/src/test/run-pass/issue-16668.rs index 0fd9965028489..18861feb1997a 100644 --- a/src/test/run-pass/issue-16668.rs +++ b/src/test/run-pass/issue-16668.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - #![allow(unknown_features)] struct Parser<'a, I, O> { diff --git a/src/test/run-pass/issue-18464.rs b/src/test/run-pass/issue-18464.rs index 70217868a54b8..dff86bc1b4527 100644 --- a/src/test/run-pass/issue-18464.rs +++ b/src/test/run-pass/issue-18464.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - #![deny(dead_code)] const LOW_RANGE: char = '0'; diff --git a/src/test/run-pass/issue-20427.rs b/src/test/run-pass/issue-20427.rs index dd3d952224c05..985ca067350a3 100644 --- a/src/test/run-pass/issue-20427.rs +++ b/src/test/run-pass/issue-20427.rs @@ -9,7 +9,7 @@ // except according to those terms. // aux-build:i8.rs -// ignore-pretty (#23623) +// ignore-pretty issue #37201 extern crate i8; use std::string as i16; diff --git a/src/test/run-pass/issue-20823.rs b/src/test/run-pass/issue-20823.rs index c297998b6493a..4d31d0cedb6d5 100644 --- a/src/test/run-pass/issue-20823.rs +++ b/src/test/run-pass/issue-20823.rs @@ -9,7 +9,6 @@ // except according to those terms. // compile-flags: --test -// no-pretty-expanded #![deny(unstable)] diff --git a/src/test/run-pass/issue-22992.rs b/src/test/run-pass/issue-22992.rs index ca8f804482aa1..dc612fc0bc71c 100644 --- a/src/test/run-pass/issue-22992.rs +++ b/src/test/run-pass/issue-22992.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty +// ignore-pretty issue #37201 struct X { val: i32 } impl std::ops::Deref for X { diff --git a/src/test/run-pass/issue-23338-ensure-param-drop-order.rs b/src/test/run-pass/issue-23338-ensure-param-drop-order.rs index fb84e7bae514d..9d0612f2a8daa 100644 --- a/src/test/run-pass/issue-23338-ensure-param-drop-order.rs +++ b/src/test/run-pass/issue-23338-ensure-param-drop-order.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments +// ignore-pretty issue #37201 // This test is ensuring that parameters are indeed dropped after // temporaries in a fn body. diff --git a/src/test/run-pass/issue-26873-multifile.rs b/src/test/run-pass/issue-26873-multifile.rs index aa525ae95192e..51bf4bfe0e13e 100644 --- a/src/test/run-pass/issue-26873-multifile.rs +++ b/src/test/run-pass/issue-26873-multifile.rs @@ -7,10 +7,9 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -// -// ignore-pretty + +// ignore-pretty issue #37195 mod issue_26873_multifile; fn main() {} - diff --git a/src/test/run-pass/issue-27401-dropflag-reinit.rs b/src/test/run-pass/issue-27401-dropflag-reinit.rs index ab8f22e78be72..37dc060d5d64d 100644 --- a/src/test/run-pass/issue-27401-dropflag-reinit.rs +++ b/src/test/run-pass/issue-27401-dropflag-reinit.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty #27582 +// ignore-pretty issue #37201 // Check that when a `let`-binding occurs in a loop, its associated // drop-flag is reinitialized (to indicate "needs-drop" at the end of diff --git a/src/test/run-pass/issue-27639.rs b/src/test/run-pass/issue-27639.rs index 44c1eb86de8df..ce1abb163d53b 100644 --- a/src/test/run-pass/issue-27639.rs +++ b/src/test/run-pass/issue-27639.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - fn main() { const iter: i32 = 0; diff --git a/src/test/run-pass/issue-28839.rs b/src/test/run-pass/issue-28839.rs index a1012296626e2..2ff4403a42f97 100644 --- a/src/test/run-pass/issue-28839.rs +++ b/src/test/run-pass/issue-28839.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems with newlines before // comments +// ignore-pretty issue #37199 pub struct Foo; diff --git a/src/test/run-pass/issue-29740.rs b/src/test/run-pass/issue-29740.rs index 75bcd431ec8e1..eb7b740db6e4b 100644 --- a/src/test/run-pass/issue-29740.rs +++ b/src/test/run-pass/issue-29740.rs @@ -11,8 +11,6 @@ // Regression test for #29740. Inefficient MIR matching algorithms // generated way too much code for this sort of case, leading to OOM. -// ignore-pretty - pub mod KeyboardEventConstants { pub const DOM_KEY_LOCATION_STANDARD: u32 = 0; pub const DOM_KEY_LOCATION_LEFT: u32 = 1; diff --git a/src/test/run-pass/issue-34932.rs b/src/test/run-pass/issue-34932.rs index e83939e7aec6b..dca387dcc2117 100644 --- a/src/test/run-pass/issue-34932.rs +++ b/src/test/run-pass/issue-34932.rs @@ -10,8 +10,6 @@ // compile-flags:--test // rustc-env:RUSTC_BOOTSTRAP_KEY= -// ignore-pretty : (#23623) problems when ending with // comments - #![cfg(any())] // This test should be configured away #![feature(rustc_attrs)] // Test that this is allowed on stable/beta #![feature(iter_arith_traits)] // Test that this is not unused diff --git a/src/test/run-pass/issue-37175.rs b/src/test/run-pass/issue-37175.rs new file mode 100644 index 0000000000000..0d3613b573e12 --- /dev/null +++ b/src/test/run-pass/issue-37175.rs @@ -0,0 +1,14 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +macro_rules! m { (<$t:ty>) => { stringify!($t) } } +fn main() { + println!("{}", m!(>)); +} diff --git a/src/test/run-pass/issue-7911.rs b/src/test/run-pass/issue-7911.rs index 5324ddb49e79f..764d6fa791805 100644 --- a/src/test/run-pass/issue-7911.rs +++ b/src/test/run-pass/issue-7911.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - // (Closes #7911) Test that we can use the same self expression // with different mutability in macro in two methods diff --git a/src/test/run-pass/issue-8460.rs b/src/test/run-pass/issue-8460.rs index f16057ccab16c..5148be5af8307 100644 --- a/src/test/run-pass/issue-8460.rs +++ b/src/test/run-pass/issue-8460.rs @@ -9,8 +9,6 @@ // except according to those terms. // ignore-emscripten no threads support -// ignore-pretty : (#23623) problems when ending with // comments - #![feature(rustc_attrs, zero_one)] use std::num::Zero; diff --git a/src/test/run-pass/issue-9129.rs b/src/test/run-pass/issue-9129.rs index 99db47c172e21..c46e8494e73b8 100644 --- a/src/test/run-pass/issue-9129.rs +++ b/src/test/run-pass/issue-9129.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty +// ignore-pretty unreported #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/iter-zip.rs b/src/test/run-pass/iter-zip.rs new file mode 100644 index 0000000000000..b0503bc2048e7 --- /dev/null +++ b/src/test/run-pass/iter-zip.rs @@ -0,0 +1,112 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that .zip() specialization preserves side effects +// in sideeffectful iterator adaptors. + +use std::cell::Cell; + +#[derive(Debug)] +struct CountClone(Cell); + +fn count_clone() -> CountClone { CountClone(Cell::new(0)) } + +impl PartialEq for CountClone { + fn eq(&self, rhs: &i32) -> bool { + self.0.get() == *rhs + } +} + +impl Clone for CountClone { + fn clone(&self) -> Self { + let ret = CountClone(self.0.clone()); + let n = self.0.get(); + self.0.set(n + 1); + ret + } +} + +fn test_zip_cloned_sideffectful() { + let xs = [count_clone(), count_clone(), count_clone(), count_clone()]; + let ys = [count_clone(), count_clone()]; + + for _ in xs.iter().cloned().zip(ys.iter().cloned()) { } + + assert_eq!(&xs, &[1, 1, 1, 0][..]); + assert_eq!(&ys, &[1, 1][..]); + + let xs = [count_clone(), count_clone()]; + let ys = [count_clone(), count_clone(), count_clone(), count_clone()]; + + for _ in xs.iter().cloned().zip(ys.iter().cloned()) { } + + assert_eq!(&xs, &[1, 1][..]); + assert_eq!(&ys, &[1, 1, 0, 0][..]); +} + +fn test_zip_map_sideffectful() { + let mut xs = [0; 6]; + let mut ys = [0; 4]; + + for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) { } + + assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]); + assert_eq!(&ys, &[1, 1, 1, 1]); + + let mut xs = [0; 4]; + let mut ys = [0; 6]; + + for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) { } + + assert_eq!(&xs, &[1, 1, 1, 1]); + assert_eq!(&ys, &[1, 1, 1, 1, 0, 0]); +} + +fn test_zip_map_rev_sideffectful() { + let mut xs = [0; 6]; + let mut ys = [0; 4]; + + { + let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)); + it.next_back(); + } + assert_eq!(&xs, &[0, 0, 0, 1, 1, 1]); + assert_eq!(&ys, &[0, 0, 0, 1]); + + let mut xs = [0; 6]; + let mut ys = [0; 4]; + + { + let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)); + (&mut it).take(5).count(); + it.next_back(); + } + assert_eq!(&xs, &[1, 1, 1, 1, 1, 1]); + assert_eq!(&ys, &[1, 1, 1, 1]); +} + +fn test_zip_nested_sideffectful() { + let mut xs = [0; 6]; + let ys = [0; 4]; + + { + // test that it has the side effect nested inside enumerate + let it = xs.iter_mut().map(|x| *x = 1).enumerate().zip(&ys); + it.count(); + } + assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]); +} + +fn main() { + test_zip_cloned_sideffectful(); + test_zip_map_sideffectful(); + test_zip_map_rev_sideffectful(); + test_zip_nested_sideffectful(); +} diff --git a/src/test/run-pass/lexer-crlf-line-endings-string-literal-doc-comment.rs b/src/test/run-pass/lexer-crlf-line-endings-string-literal-doc-comment.rs index 5c8db524cc2ed..05f1f1bfea0fb 100644 --- a/src/test/run-pass/lexer-crlf-line-endings-string-literal-doc-comment.rs +++ b/src/test/run-pass/lexer-crlf-line-endings-string-literal-doc-comment.rs @@ -15,7 +15,7 @@ // NB: this file needs CRLF line endings. The .gitattributes file in // this directory should enforce it. -// ignore-pretty +// ignore-pretty issue #37195 /// Doc comment that ends in CRLF pub fn foo() {} diff --git a/src/test/run-pass/linear-for-loop.rs b/src/test/run-pass/linear-for-loop.rs index ddb4e40aea633..3da2fc8ceacf7 100644 --- a/src/test/run-pass/linear-for-loop.rs +++ b/src/test/run-pass/linear-for-loop.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// no-pretty-expanded FIXME #15189 - pub fn main() { let x = vec!(1, 2, 3); let mut y = 0; diff --git a/src/test/run-pass/macro-2.rs b/src/test/run-pass/macro-2.rs index 2cac9226117a2..801d92b6dcb16 100644 --- a/src/test/run-pass/macro-2.rs +++ b/src/test/run-pass/macro-2.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - token trees can't pretty print - pub fn main() { macro_rules! mylambda_tt { diff --git a/src/test/run-pass/macro-attribute-expansion.rs b/src/test/run-pass/macro-attribute-expansion.rs index 60217139cd778..c3de9f736fbe5 100644 --- a/src/test/run-pass/macro-attribute-expansion.rs +++ b/src/test/run-pass/macro-attribute-expansion.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - token trees can't pretty print - macro_rules! descriptions { ($name:ident is $desc:expr) => { // Check that we will correctly expand attributes diff --git a/src/test/run-pass/macro-attributes.rs b/src/test/run-pass/macro-attributes.rs index 2752fc88b456b..839fee3a2d214 100644 --- a/src/test/run-pass/macro-attributes.rs +++ b/src/test/run-pass/macro-attributes.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - token trees can't pretty print - #![feature(custom_attribute)] macro_rules! compiles_fine { diff --git a/src/test/run-pass/macro-include-items.rs b/src/test/run-pass/macro-include-items.rs index 1e31c85afad62..f8728ebb91517 100644 --- a/src/test/run-pass/macro-include-items.rs +++ b/src/test/run-pass/macro-include-items.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty +// ignore-pretty issue #37195 fn bar() {} diff --git a/src/test/run-pass/macro-meta-items.rs b/src/test/run-pass/macro-meta-items.rs index 605cade2b3f7e..9c1e1fca3413e 100644 --- a/src/test/run-pass/macro-meta-items.rs +++ b/src/test/run-pass/macro-meta-items.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - token trees can't pretty print // compile-flags: --cfg foo macro_rules! compiles_fine { diff --git a/src/test/run-pass/macro-multiple-items.rs b/src/test/run-pass/macro-multiple-items.rs index f78f93e84810c..190bfc53a9edb 100644 --- a/src/test/run-pass/macro-multiple-items.rs +++ b/src/test/run-pass/macro-multiple-items.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - token trees can't pretty print - macro_rules! make_foo { () => ( struct Foo; diff --git a/src/test/run-pass/macro-stmt.rs b/src/test/run-pass/macro-stmt.rs index 0d8b86012d6e0..027df9f93a88d 100644 --- a/src/test/run-pass/macro-stmt.rs +++ b/src/test/run-pass/macro-stmt.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - token trees can't pretty print - macro_rules! myfn { ( $f:ident, ( $( $x:ident ),* ), $body:block ) => ( fn $f( $( $x : isize),* ) -> isize $body diff --git a/src/test/run-pass/mir_raw_fat_ptr.rs b/src/test/run-pass/mir_raw_fat_ptr.rs index c9fd88f2fb3cf..846318ec4fd34 100644 --- a/src/test/run-pass/mir_raw_fat_ptr.rs +++ b/src/test/run-pass/mir_raw_fat_ptr.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // check raw fat pointer ops in mir // FIXME: please improve this when we get monomorphization support diff --git a/src/test/run-pass/mod_dir_implicit.rs b/src/test/run-pass/mod_dir_implicit.rs index 1b89464c543ce..f8034f9e07386 100644 --- a/src/test/run-pass/mod_dir_implicit.rs +++ b/src/test/run-pass/mod_dir_implicit.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty +// ignore-pretty issue #37195 mod mod_dir_implicit_aux; diff --git a/src/test/run-pass/mod_dir_path.rs b/src/test/run-pass/mod_dir_path.rs index 28dee15cfa043..e2f33963c4bad 100644 --- a/src/test/run-pass/mod_dir_path.rs +++ b/src/test/run-pass/mod_dir_path.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty +// ignore-pretty issue #37195 mod mod_dir_simple { #[path = "test.rs"] diff --git a/src/test/run-pass/mod_dir_path2.rs b/src/test/run-pass/mod_dir_path2.rs index 2b5e67a6e8396..b96c1ae072243 100644 --- a/src/test/run-pass/mod_dir_path2.rs +++ b/src/test/run-pass/mod_dir_path2.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty +// ignore-pretty issue #37195 #[path = "mod_dir_simple"] mod pancakes { diff --git a/src/test/run-pass/mod_dir_path3.rs b/src/test/run-pass/mod_dir_path3.rs index d6037bef6e576..3160064d7c244 100644 --- a/src/test/run-pass/mod_dir_path3.rs +++ b/src/test/run-pass/mod_dir_path3.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty +// ignore-pretty issue #37195 #[path = "mod_dir_simple"] mod pancakes { diff --git a/src/test/run-pass/mod_dir_path_multi.rs b/src/test/run-pass/mod_dir_path_multi.rs index f1bf83ed767f7..12b28cf98af0b 100644 --- a/src/test/run-pass/mod_dir_path_multi.rs +++ b/src/test/run-pass/mod_dir_path_multi.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty +// ignore-pretty issue #37195 #[path = "mod_dir_simple"] mod biscuits { diff --git a/src/test/run-pass/mod_dir_recursive.rs b/src/test/run-pass/mod_dir_recursive.rs index d7121ef769078..8964d9ccd2527 100644 --- a/src/test/run-pass/mod_dir_recursive.rs +++ b/src/test/run-pass/mod_dir_recursive.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty +// ignore-pretty issue #37195 // Testing that the parser for each file tracks its modules // and paths independently. The load_another_mod module should diff --git a/src/test/run-pass/mod_dir_simple.rs b/src/test/run-pass/mod_dir_simple.rs index 41c810b6fddab..429b4ebe63970 100644 --- a/src/test/run-pass/mod_dir_simple.rs +++ b/src/test/run-pass/mod_dir_simple.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty +// ignore-pretty issue #37195 mod mod_dir_simple { pub mod test; diff --git a/src/test/run-pass/mod_file.rs b/src/test/run-pass/mod_file.rs index ddda38bafd369..c18fecd7c569e 100644 --- a/src/test/run-pass/mod_file.rs +++ b/src/test/run-pass/mod_file.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty +// ignore-pretty issue #37195 // Testing that a plain .rs file can load modules from other source files diff --git a/src/test/run-pass/mod_file_with_path_attr.rs b/src/test/run-pass/mod_file_with_path_attr.rs index c6e51daaaf054..d9f28ceb0ecac 100644 --- a/src/test/run-pass/mod_file_with_path_attr.rs +++ b/src/test/run-pass/mod_file_with_path_attr.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty +// ignore-pretty issue #37195 // Testing that a plain .rs file can load modules from other source files diff --git a/src/test/run-pass/nonzero-enum.rs b/src/test/run-pass/nonzero-enum.rs new file mode 100644 index 0000000000000..266506e04b74d --- /dev/null +++ b/src/test/run-pass/nonzero-enum.rs @@ -0,0 +1,39 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::mem::size_of; + +enum E { + A = 1, + B = 2, + C = 3, +} + +struct S { + a: u16, + b: u8, + e: E, +} + +fn main() { + assert_eq!(size_of::(), 1); + assert_eq!(size_of::>(), 1); + assert_eq!(size_of::>(), 1); + assert_eq!(size_of::(), 4); + assert_eq!(size_of::>(), 4); + let enone = None::; + let esome = Some(E::A); + if let Some(..) = enone { + panic!(); + } + if let None = esome { + panic!(); + } +} diff --git a/src/test/run-pass/numeric-method-autoexport.rs b/src/test/run-pass/numeric-method-autoexport.rs index b1d71abc78599..15ece09abd80f 100644 --- a/src/test/run-pass/numeric-method-autoexport.rs +++ b/src/test/run-pass/numeric-method-autoexport.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// no-pretty-expanded - // This file is intended to test only that methods are automatically // reachable for each numeric type, for each exported impl, with no imports // necessary. Testing the methods of the impls is done within the source diff --git a/src/test/run-pass/reexport-test-harness-main.rs b/src/test/run-pass/reexport-test-harness-main.rs index 309ae1bcc56ec..88e3e6ba4acd3 100644 --- a/src/test/run-pass/reexport-test-harness-main.rs +++ b/src/test/run-pass/reexport-test-harness-main.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty // compile-flags:--test #![reexport_test_harness_main = "test_main"] diff --git a/src/test/run-pass/regions-bound-lists-feature-gate-2.rs b/src/test/run-pass/regions-bound-lists-feature-gate-2.rs index a06e0f6da785a..47d2fe363d369 100644 --- a/src/test/run-pass/regions-bound-lists-feature-gate-2.rs +++ b/src/test/run-pass/regions-bound-lists-feature-gate-2.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - #![feature(issue_5723_bootstrap)] trait Foo { diff --git a/src/test/run-pass/regions-bound-lists-feature-gate.rs b/src/test/run-pass/regions-bound-lists-feature-gate.rs index 996583dc6de93..72db92aa93ce0 100644 --- a/src/test/run-pass/regions-bound-lists-feature-gate.rs +++ b/src/test/run-pass/regions-bound-lists-feature-gate.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - #![feature(issue_5723_bootstrap)] trait Foo { diff --git a/src/test/run-pass/shebang.rs b/src/test/run-pass/shebang.rs index 15ab21bbc8da7..a0947cd49a42d 100644 --- a/src/test/run-pass/shebang.rs +++ b/src/test/run-pass/shebang.rs @@ -9,7 +9,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty: `expand` adds some preludes before shebang -// - pub fn main() { println!("Hello World"); } diff --git a/src/test/run-pass/simd-intrinsic-generic-elements.rs b/src/test/run-pass/simd-intrinsic-generic-elements.rs index 5cb57b63ada2c..f0444c2717056 100644 --- a/src/test/run-pass/simd-intrinsic-generic-elements.rs +++ b/src/test/run-pass/simd-intrinsic-generic-elements.rs @@ -10,8 +10,6 @@ #![feature(repr_simd, platform_intrinsics)] -// ignore-pretty : (#23623) problems when ending with // comments - #[repr(simd)] #[derive(Copy, Clone, Debug, PartialEq)] #[allow(non_camel_case_types)] diff --git a/src/test/run-pass/super-fast-paren-parsing.rs b/src/test/run-pass/super-fast-paren-parsing.rs index b764a983a0c09..a1bbd19021127 100644 --- a/src/test/run-pass/super-fast-paren-parsing.rs +++ b/src/test/run-pass/super-fast-paren-parsing.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty -// // exec-env:RUST_MIN_STACK=16000000 // rustc-env:RUST_MIN_STACK=16000000 // diff --git a/src/test/run-pass/syntax-extension-source-utils.rs b/src/test/run-pass/syntax-extension-source-utils.rs index 2f52e424936ea..3b5f033d07b7d 100644 --- a/src/test/run-pass/syntax-extension-source-utils.rs +++ b/src/test/run-pass/syntax-extension-source-utils.rs @@ -8,10 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(core)] - -// This test is brittle! -// ignore-pretty - the pretty tests lose path information, breaking include! +// ignore-pretty issue #37195 pub mod m1 { pub mod m2 { @@ -24,9 +21,9 @@ pub mod m1 { macro_rules! indirect_line { () => ( line!() ) } pub fn main() { - assert_eq!(line!(), 27); + assert_eq!(line!(), 24); assert_eq!(column!(), 4); - assert_eq!(indirect_line!(), 29); + assert_eq!(indirect_line!(), 26); assert!((file!().ends_with("syntax-extension-source-utils.rs"))); assert_eq!(stringify!((2*3) + 5).to_string(), "( 2 * 3 ) + 5".to_string()); assert!(include!("syntax-extension-source-utils-files/includeme.\ @@ -43,5 +40,5 @@ pub fn main() { // The Windows tests are wrapped in an extra module for some reason assert!((m1::m2::where_am_i().ends_with("m1::m2"))); - assert_eq!((46, "( 2 * 3 ) + 5"), (line!(), stringify!((2*3) + 5))); + assert_eq!((43, "( 2 * 3 ) + 5"), (line!(), stringify!((2*3) + 5))); } diff --git a/src/test/run-pass/task-comm-3.rs b/src/test/run-pass/task-comm-3.rs index 0e8542bababdd..78f29f46edf4a 100644 --- a/src/test/run-pass/task-comm-3.rs +++ b/src/test/run-pass/task-comm-3.rs @@ -11,7 +11,6 @@ #![feature(std_misc)] // ignore-emscripten no threads support -// no-pretty-expanded FIXME #15189 use std::thread; use std::sync::mpsc::{channel, Sender}; diff --git a/src/test/run-pass/test-fn-signature-verification-for-explicit-return-type.rs b/src/test/run-pass/test-fn-signature-verification-for-explicit-return-type.rs index d58b5d3a00fec..10ad838d3cb87 100644 --- a/src/test/run-pass/test-fn-signature-verification-for-explicit-return-type.rs +++ b/src/test/run-pass/test-fn-signature-verification-for-explicit-return-type.rs @@ -11,7 +11,6 @@ #![feature(test)] // compile-flags: --test -// no-pretty-expanded extern crate test; #[bench] diff --git a/src/test/run-pass/test-runner-hides-main.rs b/src/test/run-pass/test-runner-hides-main.rs index 839e91f3793d4..7b696c1f8d27c 100644 --- a/src/test/run-pass/test-runner-hides-main.rs +++ b/src/test/run-pass/test-runner-hides-main.rs @@ -9,8 +9,6 @@ // except according to those terms. // compile-flags:--test -// ignore-pretty: does not work well with `--test` - // Building as a test runner means that a synthetic main will be run, // not ours pub fn main() { panic!(); } diff --git a/src/test/run-pass/test-should-fail-good-message.rs b/src/test/run-pass/test-should-fail-good-message.rs index 28698499303a9..e665fa4fc7b58 100644 --- a/src/test/run-pass/test-should-fail-good-message.rs +++ b/src/test/run-pass/test-should-fail-good-message.rs @@ -9,8 +9,6 @@ // except according to those terms. // compile-flags: --test -// ignore-pretty: does not work well with `--test` - #[test] #[should_panic(expected = "foo")] pub fn test_foo() { diff --git a/src/test/run-pass/trait-bounds-in-arc.rs b/src/test/run-pass/trait-bounds-in-arc.rs index 0de6fbc91cc6b..f7fd86c957070 100644 --- a/src/test/run-pass/trait-bounds-in-arc.rs +++ b/src/test/run-pass/trait-bounds-in-arc.rs @@ -12,8 +12,6 @@ // and shared between threads as long as all types fulfill Send. // ignore-emscripten no threads support -// ignore-pretty - #![allow(unknown_features)] #![feature(box_syntax, std_misc)] diff --git a/src/test/run-pass/union/union-with-drop-fields-lint.rs b/src/test/run-pass/union/union-with-drop-fields-lint.rs index 5a1424830d074..6cb7e82d6b740 100644 --- a/src/test/run-pass/union/union-with-drop-fields-lint.rs +++ b/src/test/run-pass/union/union-with-drop-fields-lint.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - #![feature(untagged_unions)] #![allow(dead_code)] #![allow(unions_with_drop_fields)] diff --git a/src/test/ui/dropck/auxiliary/dropck_eyepatch_extern_crate.rs b/src/test/ui/dropck/auxiliary/dropck_eyepatch_extern_crate.rs new file mode 100644 index 0000000000000..1b00d88dcb3df --- /dev/null +++ b/src/test/ui/dropck/auxiliary/dropck_eyepatch_extern_crate.rs @@ -0,0 +1,48 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generic_param_attrs)] +#![feature(dropck_eyepatch)] + +// This is a support file for ../dropck-eyepatch-extern-crate.rs +// +// The point of this test is to illustrate that the `#[may_dangle]` +// attribute specifically allows, in the context of a type +// implementing `Drop`, a generic parameter to be instantiated with a +// lifetime that does not strictly outlive the owning type itself, +// and that this attribute's effects are preserved when importing +// the type from another crate. +// +// See also ../dropck-eyepatch.rs for more information about the general +// structure of the test. + +use std::fmt; + +pub struct Dt(pub &'static str, pub A); +pub struct Dr<'a, B:'a+fmt::Debug>(pub &'static str, pub &'a B); +pub struct Pt(pub &'static str, pub A, pub B); +pub struct Pr<'a, 'b, B:'a+'b+fmt::Debug>(pub &'static str, pub &'a B, pub &'b B); +pub struct St(pub &'static str, pub A); +pub struct Sr<'a, B:'a+fmt::Debug>(pub &'static str, pub &'a B); + +impl Drop for Dt { + fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); } +} +impl<'a, B: fmt::Debug> Drop for Dr<'a, B> { + fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); } +} +unsafe impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt { + // (unsafe to access self.1 due to #[may_dangle] on A) + fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); } +} +unsafe impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> { + // (unsafe to access self.1 due to #[may_dangle] on 'a) + fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); } +} diff --git a/src/test/ui/dropck/dropck-eyepatch-extern-crate.rs b/src/test/ui/dropck/dropck-eyepatch-extern-crate.rs new file mode 100644 index 0000000000000..5e200dbdbfa01 --- /dev/null +++ b/src/test/ui/dropck/dropck-eyepatch-extern-crate.rs @@ -0,0 +1,55 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:dropck_eyepatch_extern_crate.rs + +// The point of this test is to illustrate that the `#[may_dangle]` +// attribute specifically allows, in the context of a type +// implementing `Drop`, a generic parameter to be instantiated with a +// lifetime that does not strictly outlive the owning type itself, +// and that this attribute's effects are preserved when importing +// the type from another crate. +// +// See also dropck-eyepatch.rs for more information about the general +// structure of the test. + +extern crate dropck_eyepatch_extern_crate as other; + +use other::{Dt,Dr,Pt,Pr,St,Sr}; + +fn main() { + use std::cell::Cell; + let c_long; + let (c, mut dt, mut dr, mut pt, mut pr, st, sr) + : (Cell<_>, Dt<_>, Dr<_>, Pt<_, _>, Pr<_>, St<_>, Sr<_>); + c_long = Cell::new(1); + c = Cell::new(1); + + // No error: sufficiently long-lived state can be referenced in dtors + dt = Dt("dt", &c_long); + dr = Dr("dr", &c_long); + // Error: destructor order imprecisely modelled + dt = Dt("dt", &c); //~ ERROR `c` does not live long enough + dr = Dr("dr", &c); //~ ERROR `c` does not live long enough + + // No error: Drop impl asserts .1 (A and &'a _) are not accessed + pt = Pt("pt", &c, &c_long); + pr = Pr("pr", &c, &c_long); + + // Error: Drop impl's assertion does not apply to `B` nor `&'b _` + pt = Pt("pt", &c_long, &c); //~ ERROR `c` does not live long enough + pr = Pr("pr", &c_long, &c); //~ ERROR `c` does not live long enough + + // No error: St and Sr have no destructor. + st = St("st", &c); + sr = Sr("sr", &c); + + println!("{:?}", (dt.0, dr.0, pt.0, pr.0, st.0, sr.0)); +} diff --git a/src/test/ui/dropck/dropck-eyepatch-extern-crate.stderr b/src/test/ui/dropck/dropck-eyepatch-extern-crate.stderr new file mode 100644 index 0000000000000..5d2096e8b07a4 --- /dev/null +++ b/src/test/ui/dropck/dropck-eyepatch-extern-crate.stderr @@ -0,0 +1,46 @@ +error: `c` does not live long enough + --> $DIR/dropck-eyepatch-extern-crate.rs:39:20 + | +39 | dt = Dt("dt", &c); //~ ERROR `c` does not live long enough + | ^ does not live long enough +... +55 | } + | - borrowed value dropped before borrower + | + = note: values in a scope are dropped in the opposite order they are created + +error: `c` does not live long enough + --> $DIR/dropck-eyepatch-extern-crate.rs:40:20 + | +40 | dr = Dr("dr", &c); //~ ERROR `c` does not live long enough + | ^ does not live long enough +... +55 | } + | - borrowed value dropped before borrower + | + = note: values in a scope are dropped in the opposite order they are created + +error: `c` does not live long enough + --> $DIR/dropck-eyepatch-extern-crate.rs:47:29 + | +47 | pt = Pt("pt", &c_long, &c); //~ ERROR `c` does not live long enough + | ^ does not live long enough +... +55 | } + | - borrowed value dropped before borrower + | + = note: values in a scope are dropped in the opposite order they are created + +error: `c` does not live long enough + --> $DIR/dropck-eyepatch-extern-crate.rs:48:29 + | +48 | pr = Pr("pr", &c_long, &c); //~ ERROR `c` does not live long enough + | ^ does not live long enough +... +55 | } + | - borrowed value dropped before borrower + | + = note: values in a scope are dropped in the opposite order they are created + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.rs b/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.rs new file mode 100644 index 0000000000000..f92c8703dc927 --- /dev/null +++ b/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.rs @@ -0,0 +1,46 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generic_param_attrs)] +#![feature(dropck_eyepatch)] + +// This test ensures that a use of `#[may_dangle]` is rejected if +// it is not attached to an `unsafe impl`. + +use std::fmt; + +struct Dt(&'static str, A); +struct Dr<'a, B:'a+fmt::Debug>(&'static str, &'a B); +struct Pt(&'static str, A, B); +struct Pr<'a, 'b, B:'a+'b+fmt::Debug>(&'static str, &'a B, &'b B); +struct St(&'static str, A); +struct Sr<'a, B:'a+fmt::Debug>(&'static str, &'a B); + +impl Drop for Dt { + fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); } +} +impl<'a, B: fmt::Debug> Drop for Dr<'a, B> { + fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); } +} +impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt { + //~^ ERROR requires an `unsafe impl` declaration due to `#[may_dangle]` attribute + + // (unsafe to access self.1 due to #[may_dangle] on A) + fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); } +} +impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> { + //~^ ERROR requires an `unsafe impl` declaration due to `#[may_dangle]` attribute + + // (unsafe to access self.1 due to #[may_dangle] on 'a) + fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); } +} + +fn main() { +} diff --git a/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr b/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr new file mode 100644 index 0000000000000..c53cf020a9bc5 --- /dev/null +++ b/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr @@ -0,0 +1,14 @@ +error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attribute + --> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:32:1 + | +32 | impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt { + | ^ + +error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attribute + --> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:38:1 + | +38 | impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> { + | ^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/dropck/dropck-eyepatch-reorder.rs b/src/test/ui/dropck/dropck-eyepatch-reorder.rs new file mode 100644 index 0000000000000..68b0ff3b5f096 --- /dev/null +++ b/src/test/ui/dropck/dropck-eyepatch-reorder.rs @@ -0,0 +1,73 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generic_param_attrs)] +#![feature(dropck_eyepatch)] + +// The point of this test is to test uses of `#[may_dangle]` attribute +// where the formal declaration order (in the impl generics) does not +// match the actual usage order (in the type instantiation). +// +// See also dropck-eyepatch.rs for more information about the general +// structure of the test. + +use std::fmt; + +struct Dt(&'static str, A); +struct Dr<'a, B:'a+fmt::Debug>(&'static str, &'a B); +struct Pt(&'static str, A, B); +struct Pr<'a, 'b, B:'a+'b+fmt::Debug>(&'static str, &'a B, &'b B); +struct St(&'static str, A); +struct Sr<'a, B:'a+fmt::Debug>(&'static str, &'a B); + +impl Drop for Dt { + fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); } +} +impl<'a, B: fmt::Debug> Drop for Dr<'a, B> { + fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); } +} +unsafe impl Drop for Pt { + // (unsafe to access self.1 due to #[may_dangle] on A) + fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); } +} +unsafe impl<'b, #[may_dangle] 'a, B: fmt::Debug> Drop for Pr<'a, 'b, B> { + // (unsafe to access self.1 due to #[may_dangle] on 'a) + fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); } +} + +fn main() { + use std::cell::Cell; + let c_long; + let (c, mut dt, mut dr, mut pt, mut pr, st, sr) + : (Cell<_>, Dt<_>, Dr<_>, Pt<_, _>, Pr<_>, St<_>, Sr<_>); + c_long = Cell::new(1); + c = Cell::new(1); + + // No error: sufficiently long-lived state can be referenced in dtors + dt = Dt("dt", &c_long); + dr = Dr("dr", &c_long); + // Error: destructor order imprecisely modelled + dt = Dt("dt", &c); //~ ERROR `c` does not live long enough + dr = Dr("dr", &c); //~ ERROR `c` does not live long enough + + // No error: Drop impl asserts .1 (A and &'a _) are not accessed + pt = Pt("pt", &c, &c_long); + pr = Pr("pr", &c, &c_long); + + // Error: Drop impl's assertion does not apply to `B` nor `&'b _` + pt = Pt("pt", &c_long, &c); //~ ERROR `c` does not live long enough + pr = Pr("pr", &c_long, &c); //~ ERROR `c` does not live long enough + + // No error: St and Sr have no destructor. + st = St("st", &c); + sr = Sr("sr", &c); + + println!("{:?}", (dt.0, dr.0, pt.0, pr.0, st.0, sr.0)); +} diff --git a/src/test/ui/dropck/dropck-eyepatch-reorder.stderr b/src/test/ui/dropck/dropck-eyepatch-reorder.stderr new file mode 100644 index 0000000000000..33b18f6f02e0f --- /dev/null +++ b/src/test/ui/dropck/dropck-eyepatch-reorder.stderr @@ -0,0 +1,46 @@ +error: `c` does not live long enough + --> $DIR/dropck-eyepatch-reorder.rs:57:20 + | +57 | dt = Dt("dt", &c); //~ ERROR `c` does not live long enough + | ^ does not live long enough +... +73 | } + | - borrowed value dropped before borrower + | + = note: values in a scope are dropped in the opposite order they are created + +error: `c` does not live long enough + --> $DIR/dropck-eyepatch-reorder.rs:58:20 + | +58 | dr = Dr("dr", &c); //~ ERROR `c` does not live long enough + | ^ does not live long enough +... +73 | } + | - borrowed value dropped before borrower + | + = note: values in a scope are dropped in the opposite order they are created + +error: `c` does not live long enough + --> $DIR/dropck-eyepatch-reorder.rs:65:29 + | +65 | pt = Pt("pt", &c_long, &c); //~ ERROR `c` does not live long enough + | ^ does not live long enough +... +73 | } + | - borrowed value dropped before borrower + | + = note: values in a scope are dropped in the opposite order they are created + +error: `c` does not live long enough + --> $DIR/dropck-eyepatch-reorder.rs:66:29 + | +66 | pr = Pr("pr", &c_long, &c); //~ ERROR `c` does not live long enough + | ^ does not live long enough +... +73 | } + | - borrowed value dropped before borrower + | + = note: values in a scope are dropped in the opposite order they are created + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/dropck/dropck-eyepatch.rs b/src/test/ui/dropck/dropck-eyepatch.rs new file mode 100644 index 0000000000000..e442fade19730 --- /dev/null +++ b/src/test/ui/dropck/dropck-eyepatch.rs @@ -0,0 +1,96 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generic_param_attrs)] +#![feature(dropck_eyepatch)] + +// The point of this test is to illustrate that the `#[may_dangle]` +// attribute specifically allows, in the context of a type +// implementing `Drop`, a generic parameter to be instantiated with a +// lifetime that does not strictly outlive the owning type itself. +// +// Here we test that only the expected errors are issued. +// +// The illustration is made concrete by comparison with two variations +// on the type with `#[may_dangle]`: +// +// 1. an analogous type that does not implement `Drop` (and thus +// should exhibit maximal flexibility with respect to dropck), and +// +// 2. an analogous type that does not use `#[may_dangle]` (and thus +// should exhibit the standard limitations imposed by dropck. +// +// The types in this file follow a pattern, {D,P,S}{t,r}, where: +// +// - D means "I implement Drop" +// +// - P means "I implement Drop but guarantee my (first) parameter is +// pure, i.e. not accessed from the destructor"; no other parameters +// are pure. +// +// - S means "I do not implement Drop" +// +// - t suffix is used when the first generic is a type +// +// - r suffix is used when the first generic is a lifetime. + +use std::fmt; + +struct Dt(&'static str, A); +struct Dr<'a, B:'a+fmt::Debug>(&'static str, &'a B); +struct Pt(&'static str, A, B); +struct Pr<'a, 'b, B:'a+'b+fmt::Debug>(&'static str, &'a B, &'b B); +struct St(&'static str, A); +struct Sr<'a, B:'a+fmt::Debug>(&'static str, &'a B); + +impl Drop for Dt { + fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); } +} +impl<'a, B: fmt::Debug> Drop for Dr<'a, B> { + fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); } +} +unsafe impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt { + // (unsafe to access self.1 due to #[may_dangle] on A) + fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); } +} +unsafe impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> { + // (unsafe to access self.1 due to #[may_dangle] on 'a) + fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); } +} + +fn main() { + use std::cell::Cell; + let c_long; + let (c, mut dt, mut dr, mut pt, mut pr, st, sr) + : (Cell<_>, Dt<_>, Dr<_>, Pt<_, _>, Pr<_>, St<_>, Sr<_>); + c_long = Cell::new(1); + c = Cell::new(1); + + // No error: sufficiently long-lived state can be referenced in dtors + dt = Dt("dt", &c_long); + dr = Dr("dr", &c_long); + // Error: destructor order imprecisely modelled + dt = Dt("dt", &c); //~ ERROR `c` does not live long enough + dr = Dr("dr", &c); //~ ERROR `c` does not live long enough + + // No error: Drop impl asserts .1 (A and &'a _) are not accessed + pt = Pt("pt", &c, &c_long); + pr = Pr("pr", &c, &c_long); + + // Error: Drop impl's assertion does not apply to `B` nor `&'b _` + pt = Pt("pt", &c_long, &c); //~ ERROR `c` does not live long enough + pr = Pr("pr", &c_long, &c); //~ ERROR `c` does not live long enough + + // No error: St and Sr have no destructor. + st = St("st", &c); + sr = Sr("sr", &c); + + println!("{:?}", (dt.0, dr.0, pt.0, pr.0, st.0, sr.0)); +} diff --git a/src/test/ui/dropck/dropck-eyepatch.stderr b/src/test/ui/dropck/dropck-eyepatch.stderr new file mode 100644 index 0000000000000..75e612ca9c8f1 --- /dev/null +++ b/src/test/ui/dropck/dropck-eyepatch.stderr @@ -0,0 +1,46 @@ +error: `c` does not live long enough + --> $DIR/dropck-eyepatch.rs:80:20 + | +80 | dt = Dt("dt", &c); //~ ERROR `c` does not live long enough + | ^ does not live long enough +... +96 | } + | - borrowed value dropped before borrower + | + = note: values in a scope are dropped in the opposite order they are created + +error: `c` does not live long enough + --> $DIR/dropck-eyepatch.rs:81:20 + | +81 | dr = Dr("dr", &c); //~ ERROR `c` does not live long enough + | ^ does not live long enough +... +96 | } + | - borrowed value dropped before borrower + | + = note: values in a scope are dropped in the opposite order they are created + +error: `c` does not live long enough + --> $DIR/dropck-eyepatch.rs:88:29 + | +88 | pt = Pt("pt", &c_long, &c); //~ ERROR `c` does not live long enough + | ^ does not live long enough +... +96 | } + | - borrowed value dropped before borrower + | + = note: values in a scope are dropped in the opposite order they are created + +error: `c` does not live long enough + --> $DIR/dropck-eyepatch.rs:89:29 + | +89 | pr = Pr("pr", &c_long, &c); //~ ERROR `c` does not live long enough + | ^ does not live long enough +... +96 | } + | - borrowed value dropped before borrower + | + = note: values in a scope are dropped in the opposite order they are created + +error: aborting due to 4 previous errors + diff --git a/src/tools/cargotest/main.rs b/src/tools/cargotest/main.rs index 633ff6271b7cc..978e991d50874 100644 --- a/src/tools/cargotest/main.rs +++ b/src/tools/cargotest/main.rs @@ -36,6 +36,20 @@ const TEST_REPOS: &'static [Test] = &[Test { fn main() { + // One of the projects being tested here is Cargo, and when being tested + // Cargo will at some point call `nmake.exe` on Windows MSVC. Unfortunately + // `nmake` will read these two environment variables below and try to + // intepret them. We're likely being run, however, from MSYS `make` which + // uses the same variables. + // + // As a result, to prevent confusion and errors, we remove these variables + // from our environment to prevent passing MSYS make flags to nmake, causing + // it to blow up. + if cfg!(target_env = "msvc") { + env::remove_var("MAKE"); + env::remove_var("MAKEFLAGS"); + } + let args = env::args().collect::>(); let ref cargo = args[1]; let out_dir = Path::new(&args[2]); diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 35b93392baf2c..e10420bf291e7 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2105,12 +2105,17 @@ actual:\n\ .collect::>().join(" "); cmd.env("IS_MSVC", "1") + .env("IS_WINDOWS", "1") .env("MSVC_LIB", format!("'{}' -nologo", lib.display())) .env("CC", format!("'{}' {}", self.config.cc, cflags)) .env("CXX", &self.config.cxx); } else { cmd.env("CC", format!("{} {}", self.config.cc, self.config.cflags)) .env("CXX", format!("{} {}", self.config.cxx, self.config.cflags)); + + if self.config.target.contains("windows") { + cmd.env("IS_WINDOWS", "1"); + } } let output = cmd.output().expect("failed to spawn `make`");