diff options
452 files changed, 12948 insertions, 3605 deletions
diff --git a/src/Cargo.lock b/src/Cargo.lock index 69c3789f337..0263c74595f 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -491,11 +491,11 @@ dependencies = [ [[package]] name = "derive-new" -version = "0.3.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quote 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1349,11 +1349,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "quote" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "quote" version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1452,7 +1447,7 @@ version = "0.1.0" [[package]] name = "rls" -version = "0.122.0" +version = "0.123.0" dependencies = [ "cargo 0.24.0", "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1461,12 +1456,12 @@ dependencies = [ "lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "racer 2.0.10 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-analysis 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-data 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-analysis 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-data 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-rustc 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-vfs 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rustfmt-nightly 0.2.13", + "rustfmt-nightly 0.2.14", "serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1475,19 +1470,19 @@ dependencies = [ [[package]] name = "rls-analysis" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "derive-new 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "derive-new 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-data 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-data 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rls-data" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1839,6 +1834,7 @@ dependencies = [ "arena 0.0.0", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", + "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", @@ -1849,7 +1845,7 @@ name = "rustc_save_analysis" version = "0.0.0" dependencies = [ "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-data 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-data 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1873,6 +1869,7 @@ dependencies = [ "rustc 0.0.0", "rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_allocator 0.0.0", + "rustc_apfloat 0.0.0", "rustc_back 0.0.0", "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", @@ -1950,7 +1947,7 @@ dependencies = [ [[package]] name = "rustfmt-nightly" -version = "0.2.13" +version = "0.2.14" dependencies = [ "diff 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2189,15 +2186,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "syn" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quote 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "syn" version = "0.11.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ @@ -2244,6 +2232,7 @@ version = "0.0.0" dependencies = [ "rustc_data_structures 0.0.0", "serialize 0.0.0", + "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2639,7 +2628,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum curl-sys 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "4bee31aa3a079d5f3ff9579ea4dcfb1b1a17a40886f5f467436d383e78134b55" "checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850" "checksum debug_unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9a032eac705ca39214d169f83e3d3da290af06d8d1d344d1baad2fd002dca4b3" -"checksum derive-new 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "41be6ca3b99e0c0483fb2389685448f650459c3ecbe4e18d7705d8010ec4ab8e" +"checksum derive-new 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "415f627ab054041c3eb748c2e1da0ef751989f5f0c386b63a098e545854a98ba" "checksum diff 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0a515461b6c8c08419850ced27bc29e86166dcdcde8fbe76f8b1f0589bb49472" "checksum docopt 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3b5b93718f8b3e5544fcc914c43de828ca6c6ace23e0332c6080a2977b49787a" "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" @@ -2726,7 +2715,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum pulldown-cmark 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a656fdb8b6848f896df5e478a0eb9083681663e37dcb77dd16981ff65329fe8b" "checksum quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eda5fe9b71976e62bc81b781206aaa076401769b2143379d3eb2118388babac4" "checksum quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45" -"checksum quote 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4c5cf478fe1006dbcc72567121d23dbdae5f1632386068c5c86ff4f645628504" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" "checksum racer 2.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "f120c7510ef7aff254aeb06067fb6fac573ec96a1660e194787cf9dced412bf0" "checksum rand 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "61efcbcd9fa8d8fbb07c84e34a8af18a1ff177b449689ad38a6e9457ecc7b2ae" @@ -2736,8 +2724,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b" "checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957" "checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db" -"checksum rls-analysis 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd4e96e3a7d4cf3f31d789080ddd88fbe3251df2feb168049a24eda8b6046ed8" -"checksum rls-data 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6aea328fa69702c1b0fc395f2c71eae954bf984ac1e418c72f69221b6e3d15ff" +"checksum rls-analysis 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "10fbe17ed9da2fa3686ebb018958e194a4a25f0b3a78382bfe334d09d3c641f4" +"checksum rls-data 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "48257ceade23c2e01a3ca8d2fc4226101b107f6a3c868f829cf3fd2f204a1fe6" "checksum rls-rustc 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b21ea952e9bf1569929abf1bb920262cde04b7b1b26d8e0260286302807299d2" "checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a" "checksum rls-vfs 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ffd34691a510938bb67fe0444fb363103c73ffb31c121d1e16bc92d8945ea8ff" @@ -2767,7 +2755,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum strings 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da75d8bf2c4d210d63dd09581a041b036001f9f6e03d9b151dbff810fb7ba26a" "checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" -"checksum syn 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6ae6fb0dcc9bd85f89a1a4adc0df2fd90c90c98849d61433983dd7a9df6363f7" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum syntex_errors 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9e52bffe6202cfb67587784cf23e0ec5bf26d331eef4922a16d5c42e12aa1e9b" "checksum syntex_pos 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)" = "955ef4b16af4c468e4680d1497f873ff288f557d338180649e18f915af5e15ac" diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index 608924c9c28..c150459bee5 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -27,10 +27,8 @@ pub fn install_docs(builder: &Builder, stage: u32, host: Interned<String>) { install_sh(builder, "docs", "rust-docs", stage, Some(host)); } -pub fn install_std(builder: &Builder, stage: u32) { - for target in &builder.build.targets { - install_sh(builder, "std", "rust-std", stage, Some(*target)); - } +pub fn install_std(builder: &Builder, stage: u32, target: Interned<String>) { + install_sh(builder, "std", "rust-std", stage, Some(target)); } pub fn install_cargo(builder: &Builder, stage: u32, host: Interned<String>) { @@ -175,19 +173,24 @@ install!((self, builder, _config), install_docs(builder, self.stage, self.target); }; Std, "src/libstd", true, only_hosts: true, { - builder.ensure(dist::Std { - compiler: builder.compiler(self.stage, self.host), - target: self.target - }); - install_std(builder, self.stage); + for target in &builder.build.targets { + builder.ensure(dist::Std { + compiler: builder.compiler(self.stage, self.host), + target: *target + }); + install_std(builder, self.stage, *target); + } }; Cargo, "cargo", _config.extended, only_hosts: true, { builder.ensure(dist::Cargo { stage: self.stage, target: self.target }); install_cargo(builder, self.stage, self.target); }; Rls, "rls", _config.extended, only_hosts: true, { - builder.ensure(dist::Rls { stage: self.stage, target: self.target }); - install_rls(builder, self.stage, self.target); + if builder.ensure(dist::Rls { stage: self.stage, target: self.target }).is_some() { + install_rls(builder, self.stage, self.target); + } else { + println!("skipping Install RLS stage{} ({})", self.stage, self.target); + } }; Analysis, "analysis", _config.extended, only_hosts: false, { builder.ensure(dist::Analysis { diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 19409ef779e..fce6755aea9 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -323,9 +323,9 @@ impl Step for TestHelpers { } } -const OPENSSL_VERS: &'static str = "1.0.2k"; +const OPENSSL_VERS: &'static str = "1.0.2m"; const OPENSSL_SHA256: &'static str = - "6b3977c61f2aedf0f96367dcfb5c6e578cf37e7b8d913b4ecb6643c3cb88d8c0"; + "8c6ff15ec6b319b50788f42c7abc2890c08ba5a1cdcd3810eb9092deada37b0f"; #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Openssl { diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 688ee6ba295..7175fed5410 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -415,7 +415,8 @@ impl Step for Clippy { const ONLY_HOSTS: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/tools/clippy") + let builder = run.builder; + run.path("src/tools/clippy").default_condition(builder.build.config.extended) } fn make_run(run: RunConfig) { diff --git a/src/ci/docker/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh b/src/ci/docker/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh index 4d3e638916d..f231d20b197 100755 --- a/src/ci/docker/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh +++ b/src/ci/docker/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh @@ -23,9 +23,9 @@ SYSROOT=/usr/local/$TARGET/sysroot mkdir -p $SYSROOT pushd $SYSROOT -centos_base=http://mirror.centos.org/altarch/7.3.1611/os/ppc64le/Packages -glibc_v=2.17-157.el7 -kernel_v=3.10.0-514.el7 +centos_base=http://mirror.centos.org/altarch/7/os/ppc64le/Packages +glibc_v=2.17-196.el7 +kernel_v=3.10.0-693.el7 for package in glibc{,-devel,-headers}-$glibc_v kernel-headers-$kernel_v; do curl $centos_base/$package.ppc64le.rpm | \ rpm2cpio - | cpio -idm diff --git a/src/doc/not_found.md b/src/doc/not_found.md index 5d632ebc68f..ebe7c59313f 100644 --- a/src/doc/not_found.md +++ b/src/doc/not_found.md @@ -22,7 +22,7 @@ Some things that might be helpful to you though: # Reference * [The Rust official site](https://www.rust-lang.org) -* [The Rust reference](https://doc.rust-lang.org/reference.html) +* [The Rust reference](https://doc.rust-lang.org/reference/index.html) # Docs diff --git a/src/doc/unstable-book/src/language-features/non-exhaustive.md b/src/doc/unstable-book/src/language-features/non-exhaustive.md new file mode 100644 index 00000000000..f9840e1b83f --- /dev/null +++ b/src/doc/unstable-book/src/language-features/non-exhaustive.md @@ -0,0 +1,75 @@ +# `non_exhaustive` + +The tracking issue for this feature is: [#44109] + +[#44109]: https://github.com/rust-lang/rust/issues/44109 + +------------------------ + +The `non_exhaustive` gate allows you to use the `#[non_exhaustive]` attribute +on structs and enums. When applied within a crate, users of the crate will need +to use the `_` pattern when matching enums and use the `..` pattern when +matching structs. Structs marked as `non_exhaustive` will not be able to be +created normally outside of the defining crate. This is demonstrated below: + +```rust,ignore (pseudo-Rust) +use std::error::Error as StdError; + +#[non_exhaustive] +pub enum Error { + Message(String), + Other, +} +impl StdError for Error { + fn description(&self) -> &str { + // This will not error, despite being marked as non_exhaustive, as this + // enum is defined within the current crate, it can be matched + // exhaustively. + match *self { + Message(ref s) => s, + Other => "other or unknown error", + } + } +} +``` + +```rust,ignore (pseudo-Rust) +use mycrate::Error; + +// This will not error as the non_exhaustive Error enum has been matched with +// a wildcard. +match error { + Message(ref s) => ..., + Other => ..., + _ => ..., +} +``` + +```rust,ignore (pseudo-Rust) +#[non_exhaustive] +pub struct Config { + pub window_width: u16, + pub window_height: u16, +} + +// We can create structs as normal within the defining crate when marked as +// non_exhaustive. +let config = Config { window_width: 640, window_height: 480 }; + +// We can match structs exhaustively when within the defining crate. +if let Ok(Config { window_width, window_height }) = load_config() { + // ... +} +``` + +```rust,ignore (pseudo-Rust) +use mycrate::Config; + +// We cannot create a struct like normal if it has been marked as +// non_exhaustive. +let config = Config { window_width: 640, window_height: 480 }; +// By adding the `..` we can match the config as below outside of the crate +// when marked non_exhaustive. +let &Config { window_width, window_height, .. } = config; +``` + diff --git a/src/doc/unstable-book/src/language-features/optin-builtin-traits.md b/src/doc/unstable-book/src/language-features/optin-builtin-traits.md index ee24dd87d90..97b57c690fc 100644 --- a/src/doc/unstable-book/src/language-features/optin-builtin-traits.md +++ b/src/doc/unstable-book/src/language-features/optin-builtin-traits.md @@ -24,9 +24,7 @@ Example: ```rust #![feature(optin_builtin_traits)] -trait Valid {} - -impl Valid for .. {} +auto trait Valid {} struct True; struct False; diff --git a/src/etc/char_private.py b/src/etc/char_private.py index 75ab3f1a17b..cfe5b01e934 100644 --- a/src/etc/char_private.py +++ b/src/etc/char_private.py @@ -177,7 +177,7 @@ def main(): normal1 = compress_normal(normal1) print("""\ -// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -226,7 +226,7 @@ fn check(x: u16, singletonuppers: &[(u8, u8)], singletonlowers: &[u8], current } -pub fn is_printable(x: char) -> bool { +pub(crate) fn is_printable(x: char) -> bool { let x = x as u32; let lower = x as u16; if x < 0x10000 { diff --git a/src/liballoc/benches/str.rs b/src/liballoc/benches/str.rs index fc4063fae92..38c94d4d8b5 100644 --- a/src/liballoc/benches/str.rs +++ b/src/liballoc/benches/str.rs @@ -272,15 +272,12 @@ make_test!(match_indices_a_str, s, s.match_indices("a").count()); make_test!(split_a_str, s, s.split("a").count()); make_test!(trim_ascii_char, s, { - use std::ascii::AsciiExt; s.trim_matches(|c: char| c.is_ascii()) }); make_test!(trim_left_ascii_char, s, { - use std::ascii::AsciiExt; s.trim_left_matches(|c: char| c.is_ascii()) }); make_test!(trim_right_ascii_char, s, { - use std::ascii::AsciiExt; s.trim_right_matches(|c: char| c.is_ascii()) }); diff --git a/src/liballoc/borrow.rs b/src/liballoc/borrow.rs index a662e4b1f4f..e8aff099871 100644 --- a/src/liballoc/borrow.rs +++ b/src/liballoc/borrow.rs @@ -191,7 +191,6 @@ impl<'a, B: ?Sized> Cow<'a, B> /// # Examples /// /// ``` - /// use std::ascii::AsciiExt; /// use std::borrow::Cow; /// /// let mut cow = Cow::Borrowed("foo"); diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 0cbfc9e9dac..a40ed060604 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -83,6 +83,7 @@ #![cfg_attr(not(test), feature(generator_trait))] #![cfg_attr(test, feature(rand, test))] #![feature(allow_internal_unstable)] +#![feature(ascii_ctype)] #![feature(box_patterns)] #![feature(box_syntax)] #![feature(cfg_target_has_atomic)] @@ -93,6 +94,7 @@ #![feature(dropck_eyepatch)] #![feature(exact_size_is_empty)] #![feature(fmt_internals)] +#![feature(from_ref)] #![feature(fundamental)] #![feature(fused)] #![feature(generic_param_attrs)] diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 841f9dc6414..dbf1fb1367d 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -114,7 +114,7 @@ impl<T, A: Alloc> RawVec<T, A> { impl<T> RawVec<T, Heap> { /// Creates the biggest possible RawVec (on the system heap) /// without allocating. If T has positive size, then this makes a - /// RawVec with capacity 0. If T has 0 size, then it it makes a + /// RawVec with capacity 0. If T has 0 size, then it makes a /// RawVec with capacity `usize::MAX`. Useful for implementing /// delayed allocation. pub fn new() -> Self { diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index 2045d5ddd97..b41cb912fe7 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -119,6 +119,8 @@ pub use core::slice::{SplitN, RSplitN, SplitNMut, RSplitNMut}; pub use core::slice::{RSplit, RSplitMut}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{from_raw_parts, from_raw_parts_mut}; +#[unstable(feature = "from_ref", issue = "45703")] +pub use core::slice::{from_ref, from_ref_mut}; #[unstable(feature = "slice_get_slice", issue = "35729")] pub use core::slice::SliceIndex; @@ -1531,6 +1533,215 @@ impl<T> [T] { } } +// FIXME(LukasKalbertodt): the `not(stage0)` constraint can be removed in the +// future once the stage0 compiler is new enough to know about the `slice_u8` +// lang item. +#[lang = "slice_u8"] +#[cfg(all(not(stage0), not(test)))] +impl [u8] { + /// Checks if all bytes in this slice are within the ASCII range. + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")] + #[inline] + pub fn is_ascii(&self) -> bool { + self.iter().all(|b| b.is_ascii()) + } + + /// Returns a vector containing a copy of this slice where each byte + /// is mapped to its ASCII upper case equivalent. + /// + /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', + /// but non-ASCII letters are unchanged. + /// + /// To uppercase the value in-place, use [`make_ascii_uppercase`]. + /// + /// [`make_ascii_uppercase`]: #method.make_ascii_uppercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")] + #[inline] + pub fn to_ascii_uppercase(&self) -> Vec<u8> { + let mut me = self.to_vec(); + me.make_ascii_uppercase(); + me + } + + /// Returns a vector containing a copy of this slice where each byte + /// is mapped to its ASCII lower case equivalent. + /// + /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', + /// but non-ASCII letters are unchanged. + /// + /// To lowercase the value in-place, use [`make_ascii_lowercase`]. + /// + /// [`make_ascii_lowercase`]: #method.make_ascii_lowercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")] + #[inline] + pub fn to_ascii_lowercase(&self) -> Vec<u8> { + let mut me = self.to_vec(); + me.make_ascii_lowercase(); + me + } + + /// Checks that two slices are an ASCII case-insensitive match. + /// + /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, + /// but without allocating and copying temporaries. + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")] + #[inline] + pub fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool { + self.len() == other.len() && + self.iter().zip(other).all(|(a, b)| { + a.eq_ignore_ascii_case(b) + }) + } + + /// Converts this slice to its ASCII upper case equivalent in-place. + /// + /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', + /// but non-ASCII letters are unchanged. + /// + /// To return a new uppercased value without modifying the existing one, use + /// [`to_ascii_uppercase`]. + /// + /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")] + #[inline] + pub fn make_ascii_uppercase(&mut self) { + for byte in self { + byte.make_ascii_uppercase(); + } + } + + /// Converts this slice to its ASCII lower case equivalent in-place. + /// + /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', + /// but non-ASCII letters are unchanged. + /// + /// To return a new lowercased value without modifying the existing one, use + /// [`to_ascii_lowercase`]. + /// + /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")] + #[inline] + pub fn make_ascii_lowercase(&mut self) { + for byte in self { + byte.make_ascii_lowercase(); + } + } + + /// Checks if all bytes of this slice are ASCII alphabetic characters: + /// + /// - U+0041 'A' ... U+005A 'Z', or + /// - U+0061 'a' ... U+007A 'z'. + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_alphabetic(&self) -> bool { + self.iter().all(|b| b.is_ascii_alphabetic()) + } + + /// Checks if all bytes of this slice are ASCII uppercase characters: + /// U+0041 'A' ... U+005A 'Z'. + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_uppercase(&self) -> bool { + self.iter().all(|b| b.is_ascii_uppercase()) + } + + /// Checks if all bytes of this slice are ASCII lowercase characters: + /// U+0061 'a' ... U+007A 'z'. + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_lowercase(&self) -> bool { + self.iter().all(|b| b.is_ascii_lowercase()) + } + + /// Checks if all bytes of this slice are ASCII alphanumeric characters: + /// + /// - U+0041 'A' ... U+005A 'Z', or + /// - U+0061 'a' ... U+007A 'z', or + /// - U+0030 '0' ... U+0039 '9'. + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_alphanumeric(&self) -> bool { + self.iter().all(|b| b.is_ascii_alphanumeric()) + } + + /// Checks if all bytes of this slice are ASCII decimal digit: + /// U+0030 '0' ... U+0039 '9'. + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_digit(&self) -> bool { + self.iter().all(|b| b.is_ascii_digit()) + } + + /// Checks if all bytes of this slice are ASCII hexadecimal digits: + /// + /// - U+0030 '0' ... U+0039 '9', or + /// - U+0041 'A' ... U+0046 'F', or + /// - U+0061 'a' ... U+0066 'f'. + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_hexdigit(&self) -> bool { + self.iter().all(|b| b.is_ascii_hexdigit()) + } + + /// Checks if all bytes of this slice are ASCII punctuation characters: + /// + /// - U+0021 ... U+002F `! " # $ % & ' ( ) * + , - . /`, or + /// - U+003A ... U+0040 `: ; < = > ? @`, or + /// - U+005B ... U+0060 `[ \\ ] ^ _ \``, or + /// - U+007B ... U+007E `{ | } ~` + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_punctuation(&self) -> bool { + self.iter().all(|b| b.is_ascii_punctuation()) + } + + /// Checks if all bytes of this slice are ASCII graphic characters: + /// U+0021 '@' ... U+007E '~'. + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_graphic(&self) -> bool { + self.iter().all(|b| b.is_ascii_graphic()) + } + + /// Checks if all bytes of this slice are ASCII whitespace characters: + /// U+0020 SPACE, U+0009 HORIZONTAL TAB, U+000A LINE FEED, + /// U+000C FORM FEED, or U+000D CARRIAGE RETURN. + /// + /// Rust uses the WhatWG Infra Standard's [definition of ASCII + /// whitespace][infra-aw]. There are several other definitions in + /// wide use. For instance, [the POSIX locale][pct] includes + /// U+000B VERTICAL TAB as well as all the above characters, + /// but—from the very same specification—[the default rule for + /// "field splitting" in the Bourne shell][bfs] considers *only* + /// SPACE, HORIZONTAL TAB, and LINE FEED as whitespace. + /// + /// If you are writing a program that will process an existing + /// file format, check what that format's definition of whitespace is + /// before using this function. + /// + /// [infra-aw]: https://infra.spec.whatwg.org/#ascii-whitespace + /// [pct]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_01 + /// [bfs]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_whitespace(&self) -> bool { + self.iter().all(|b| b.is_ascii_whitespace()) + } + + /// Checks if all bytes of this slice are ASCII control characters: + /// + /// - U+0000 NUL ... U+001F UNIT SEPARATOR, or + /// - U+007F DELETE. + /// + /// Note that most ASCII whitespace characters are control + /// characters, but SPACE is not. + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_control(&self) -> bool { + self.iter().all(|b| b.is_ascii_control()) + } +} + //////////////////////////////////////////////////////////////////////////////// // Extension traits for slices over specific kinds of data //////////////////////////////////////////////////////////////////////////////// diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index 895607ff8d4..5f0b4088fc0 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -390,8 +390,6 @@ impl str { /// # Examples /// /// ``` - /// use std::ascii::AsciiExt; - /// /// let mut v = String::from("hello"); /// // correct length /// assert!(v.get_mut(0..5).is_some()); @@ -617,8 +615,6 @@ impl str { /// Basic usage: /// /// ``` - /// use std::ascii::AsciiExt; - /// /// let mut s = "Per Martin-Löf".to_string(); /// { /// let (first, last) = s.split_at_mut(3); @@ -2070,6 +2066,286 @@ impl str { s.extend((0..n).map(|_| self)); s } + + /// Checks if all characters in this string are within the ASCII range. + /// + /// # Examples + /// + /// ``` + /// let ascii = "hello!\n"; + /// let non_ascii = "Grüße, Jürgen ❤"; + /// + /// assert!(ascii.is_ascii()); + /// assert!(!non_ascii.is_ascii()); + /// ``` + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")] + #[inline] + pub fn is_ascii(&self) -> bool { + // We can treat each byte as character here: all multibyte characters + // start with a byte that is not in the ascii range, so we will stop + // there already. + self.bytes().all(|b| b.is_ascii()) + } + + /// Returns a copy of this string where each character is mapped to its + /// ASCII upper case equivalent. + /// + /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', + /// but non-ASCII letters are unchanged. + /// + /// To uppercase the value in-place, use [`make_ascii_uppercase`]. + /// + /// To uppercase ASCII characters in addition to non-ASCII characters, use + /// [`to_uppercase`]. + /// + /// # Examples + /// + /// ``` + /// let s = "Grüße, Jürgen ❤"; + /// + /// assert_eq!("GRüßE, JüRGEN ❤", s.to_ascii_uppercase()); + /// ``` + /// + /// [`make_ascii_uppercase`]: #method.make_ascii_uppercase + /// [`to_uppercase`]: #method.to_uppercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")] + #[inline] + #[cfg(not(stage0))] + pub fn to_ascii_uppercase(&self) -> String { + let mut bytes = self.as_bytes().to_vec(); + bytes.make_ascii_uppercase(); + // make_ascii_uppercase() preserves the UTF-8 invariant. + unsafe { String::from_utf8_unchecked(bytes) } + } + + /// Returns a copy of this string where each character is mapped to its + /// ASCII lower case equivalent. + /// + /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', + /// but non-ASCII letters are unchanged. + /// + /// To lowercase the value in-place, use [`make_ascii_lowercase`]. + /// + /// To lowercase ASCII characters in addition to non-ASCII characters, use + /// [`to_lowercase`]. + /// + /// # Examples + /// + /// ``` + /// let s = "Grüße, Jürgen ❤"; + /// + /// assert_eq!("grüße, jürgen ❤", s.to_ascii_lowercase()); + /// ``` + /// + /// [`make_ascii_lowercase`]: #method.make_ascii_lowercase + /// [`to_lowercase`]: #method.to_lowercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")] + #[inline] + #[cfg(not(stage0))] + pub fn to_ascii_lowercase(&self) -> String { + let mut bytes = self.as_bytes().to_vec(); + bytes.make_ascii_lowercase(); + // make_ascii_lowercase() preserves the UTF-8 invariant. + unsafe { String::from_utf8_unchecked(bytes) } + } + + /// Checks that two strings are an ASCII case-insensitive match. + /// + /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, + /// but without allocating and copying temporaries. + /// + /// # Examples + /// + /// ``` + /// assert!("Ferris".eq_ignore_ascii_case("FERRIS")); + /// assert!("Ferrös".eq_ignore_ascii_case("FERRöS")); + /// assert!(!"Ferrös".eq_ignore_ascii_case("FERRÖS")); + /// ``` + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")] + #[inline] + #[cfg(not(stage0))] + pub fn eq_ignore_ascii_case(&self, other: &str) -> bool { + self.as_bytes().eq_ignore_ascii_case(other.as_bytes()) + } + + /// Converts this string to its ASCII upper case equivalent in-place. + /// + /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', + /// but non-ASCII letters are unchanged. + /// + /// To return a new uppercased value without modifying the existing one, use + /// [`to_ascii_uppercase`]. + /// + /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")] + #[cfg(not(stage0))] + pub fn make_ascii_uppercase(&mut self) { + let me = unsafe { self.as_bytes_mut() }; + me.make_ascii_uppercase() + } + + /// Converts this string to its ASCII lower case equivalent in-place. + /// + /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', + /// but non-ASCII letters are unchanged. + /// + /// To return a new lowercased value without modifying the existing one, use + /// [`to_ascii_lowercase`]. + /// + /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")] + #[cfg(not(stage0))] + pub fn make_ascii_lowercase(&mut self) { + let me = unsafe { self.as_bytes_mut() }; + me.make_ascii_lowercase() + } + + /// Checks if all characters of this string are ASCII alphabetic + /// characters: + /// + /// - U+0041 'A' ... U+005A 'Z', or + /// - U+0061 'a' ... U+007A 'z'. + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_alphabetic(&self) -> bool { + self.bytes().all(|b| b.is_ascii_alphabetic()) + } + + /// Checks if all characters of this string are ASCII uppercase characters: + /// U+0041 'A' ... U+005A 'Z'. + /// + /// # Example + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// // Only ascii uppercase characters + /// assert!("HELLO".is_ascii_uppercase()); + /// + /// // While all characters are ascii, 'y' and 'e' are not uppercase + /// assert!(!"Bye".is_ascii_uppercase()); + /// + /// // While all characters are uppercase, 'Ü' is not ascii + /// assert!(!"TSCHÜSS".is_ascii_uppercase()); + /// ``` + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_uppercase(&self) -> bool { + self.bytes().all(|b| b.is_ascii_uppercase()) + } + + /// Checks if all characters of this string are ASCII lowercase characters: + /// U+0061 'a' ... U+007A 'z'. + /// + /// # Example + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// // Only ascii uppercase characters + /// assert!("hello".is_ascii_lowercase()); + /// + /// // While all characters are ascii, 'B' is not lowercase + /// assert!(!"Bye".is_ascii_lowercase()); + /// + /// // While all characters are lowercase, 'Ü' is not ascii + /// assert!(!"tschüss".is_ascii_lowercase()); + /// ``` + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_lowercase(&self) -> bool { + self.bytes().all(|b| b.is_ascii_lowercase()) + } + + /// Checks if all characters of this string are ASCII alphanumeric + /// characters: + /// + /// - U+0041 'A' ... U+005A 'Z', or + /// - U+0061 'a' ... U+007A 'z', or + /// - U+0030 '0' ... U+0039 '9'. + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_alphanumeric(&self) -> bool { + self.bytes().all(|b| b.is_ascii_alphanumeric()) + } + + /// Checks if all characters of this string are ASCII decimal digit: + /// U+0030 '0' ... U+0039 '9'. + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_digit(&self) -> bool { + self.bytes().all(|b| b.is_ascii_digit()) + } + + /// Checks if all characters of this string are ASCII hexadecimal digits: + /// + /// - U+0030 '0' ... U+0039 '9', or + /// - U+0041 'A' ... U+0046 'F', or + /// - U+0061 'a' ... U+0066 'f'. + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_hexdigit(&self) -> bool { + self.bytes().all(|b| b.is_ascii_hexdigit()) + } + + /// Checks if all characters of this string are ASCII punctuation + /// characters: + /// + /// - U+0021 ... U+002F `! " # $ % & ' ( ) * + , - . /`, or + /// - U+003A ... U+0040 `: ; < = > ? @`, or + /// - U+005B ... U+0060 `[ \\ ] ^ _ \``, or + /// - U+007B ... U+007E `{ | } ~` + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_punctuation(&self) -> bool { + self.bytes().all(|b| b.is_ascii_punctuation()) + } + + /// Checks if all characters of this string are ASCII graphic characters: + /// U+0021 '@' ... U+007E '~'. + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_graphic(&self) -> bool { + self.bytes().all(|b| b.is_ascii_graphic()) + } + + /// Checks if all characters of this string are ASCII whitespace characters: + /// U+0020 SPACE, U+0009 HORIZONTAL TAB, U+000A LINE FEED, + /// U+000C FORM FEED, or U+000D CARRIAGE RETURN. + /// + /// Rust uses the WhatWG Infra Standard's [definition of ASCII + /// whitespace][infra-aw]. There are several other definitions in + /// wide use. For instance, [the POSIX locale][pct] includes + /// U+000B VERTICAL TAB as well as all the above characters, + /// but—from the very same specification—[the default rule for + /// "field splitting" in the Bourne shell][bfs] considers *only* + /// SPACE, HORIZONTAL TAB, and LINE FEED as whitespace. + /// + /// If you are writing a program that will process an existing + /// file format, check what that format's definition of whitespace is + /// before using this function. + /// + /// [infra-aw]: https://infra.spec.whatwg.org/#ascii-whitespace + /// [pct]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_01 + /// [bfs]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_whitespace(&self) -> bool { + self.bytes().all(|b| b.is_ascii_whitespace()) + } + + /// Checks if all characters of this string are ASCII control characters: + /// + /// - U+0000 NUL ... U+001F UNIT SEPARATOR, or + /// - U+007F DELETE. + /// + /// Note that most ASCII whitespace characters are control + /// characters, but SPACE is not. + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_control(&self) -> bool { + self.bytes().all(|b| b.is_ascii_control()) + } } /// Converts a boxed slice of bytes to a boxed string slice without checking diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 6d0bb264df1..25fcc1ccdab 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -773,8 +773,6 @@ impl String { /// Basic usage: /// /// ``` - /// use std::ascii::AsciiExt; - /// /// let mut s = String::from("foobar"); /// let s_mut_str = s.as_mut_str(); /// diff --git a/src/liballoc/tests/str.rs b/src/liballoc/tests/str.rs index b3178064505..6b075e7ac0e 100644 --- a/src/liballoc/tests/str.rs +++ b/src/liballoc/tests/str.rs @@ -706,7 +706,6 @@ fn test_split_at() { #[test] fn test_split_at_mut() { - use std::ascii::AsciiExt; let mut s = "Hello World".to_string(); { let (a, b) = s.split_at_mut(5); diff --git a/src/liballoc/tests/vec.rs b/src/liballoc/tests/vec.rs index 0e25da5bd30..9cfde5dcc73 100644 --- a/src/liballoc/tests/vec.rs +++ b/src/liballoc/tests/vec.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::ascii::AsciiExt; use std::borrow::Cow; use std::mem::size_of; use std::panic; @@ -966,5 +965,3 @@ fn drain_filter_complex() { assert_eq!(vec, vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19]); } } - - diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index cf34e195dea..5aca199cf40 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -853,8 +853,6 @@ impl<T> Vec<T> { /// # Examples /// /// ``` - /// use std::ascii::AsciiExt; - /// /// let mut vec = vec!["foo", "bar", "Bar", "baz", "bar"]; /// /// vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b)); diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index d153f19c462..f060f6d79c1 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -107,7 +107,7 @@ mod contents { // ABI #[no_mangle] - #[linkage = "external"] + #[rustc_std_internal_symbol] pub unsafe extern fn __rde_alloc(size: usize, align: usize, err: *mut u8) -> *mut u8 { @@ -122,13 +122,13 @@ mod contents { } #[no_mangle] - #[linkage = "external"] + #[rustc_std_internal_symbol] pub unsafe extern fn __rde_oom(err: *const u8) -> ! { System.oom((*(err as *const AllocErr)).clone()) } #[no_mangle] - #[linkage = "external"] + #[rustc_std_internal_symbol] pub unsafe extern fn __rde_dealloc(ptr: *mut u8, size: usize, align: usize) { @@ -137,7 +137,7 @@ mod contents { } #[no_mangle] - #[linkage = "external"] + #[rustc_std_internal_symbol] pub unsafe extern fn __rde_usable_size(layout: *const u8, min: *mut usize, max: *mut usize) { @@ -153,7 +153,7 @@ mod contents { } #[no_mangle] - #[linkage = "external"] + #[rustc_std_internal_symbol] pub unsafe extern fn __rde_realloc(ptr: *mut u8, _old_size: usize, old_align: usize, @@ -177,7 +177,7 @@ mod contents { } #[no_mangle] - #[linkage = "external"] + #[rustc_std_internal_symbol] pub unsafe extern fn __rde_alloc_zeroed(size: usize, align: usize, err: *mut u8) -> *mut u8 { @@ -196,20 +196,21 @@ mod contents { } #[no_mangle] - #[linkage = "external"] + #[rustc_std_internal_symbol] pub unsafe extern fn __rde_alloc_excess(size: usize, align: usize, excess: *mut usize, err: *mut u8) -> *mut u8 { let p = __rde_alloc(size, align, err); if !p.is_null() { - *excess = size; + let flags = align_to_flags(align); + *excess = nallocx(size, flags) as usize; } return p } #[no_mangle] - #[linkage = "external"] + #[rustc_std_internal_symbol] pub unsafe extern fn __rde_realloc_excess(ptr: *mut u8, old_size: usize, old_align: usize, @@ -219,13 +220,14 @@ mod contents { err: *mut u8) -> *mut u8 { let p = __rde_realloc(ptr, old_size, old_align, new_size, new_align, err); if !p.is_null() { - *excess = new_size; + let flags = align_to_flags(new_align); + *excess = nallocx(new_size, flags) as usize; } - return p + p } #[no_mangle] - #[linkage = "external"] + #[rustc_std_internal_symbol] pub unsafe extern fn __rde_grow_in_place(ptr: *mut u8, old_size: usize, old_align: usize, @@ -235,7 +237,7 @@ mod contents { } #[no_mangle] - #[linkage = "external"] + #[rustc_std_internal_symbol] pub unsafe extern fn __rde_shrink_in_place(ptr: *mut u8, _old_size: usize, old_align: usize, diff --git a/src/libbacktrace/configure b/src/libbacktrace/configure index df6497fc646..873220794bd 100755 --- a/src/libbacktrace/configure +++ b/src/libbacktrace/configure @@ -12323,6 +12323,12 @@ fi fi fi + +case "${host_os}" in +darwin*) + have_mmap=no ;; +esac + if test "$have_mmap" = "no"; then VIEW_FILE=read.lo ALLOC_FILE=alloc.lo diff --git a/src/libbacktrace/configure.ac b/src/libbacktrace/configure.ac index 7ae21b8d1a6..ea1b27d807e 100644 --- a/src/libbacktrace/configure.ac +++ b/src/libbacktrace/configure.ac @@ -283,6 +283,12 @@ else AC_CHECK_FUNC(mmap, [have_mmap=yes], [have_mmap=no]) fi fi + +case "${host_os}" in +darwin*) + have_mmap=no ;; +esac + if test "$have_mmap" = "no"; then VIEW_FILE=read.lo ALLOC_FILE=alloc.lo diff --git a/src/libcore/char_private.rs b/src/libcore/char_private.rs index 2c0f449b276..e6803745ab5 100644 --- a/src/libcore/char_private.rs +++ b/src/libcore/char_private.rs @@ -1,4 +1,4 @@ -// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -47,7 +47,7 @@ fn check(x: u16, singletonuppers: &[(u8, u8)], singletonlowers: &[u8], current } -pub fn is_printable(x: char) -> bool { +pub(crate) fn is_printable(x: char) -> bool { let x = x as u32; let lower = x as u16; if x < 0x10000 { @@ -64,7 +64,10 @@ pub fn is_printable(x: char) -> bool { if 0x2b81e <= x && x < 0x2b820 { return false; } - if 0x2cea2 <= x && x < 0x2f800 { + if 0x2cea2 <= x && x < 0x2ceb0 { + return false; + } + if 0x2ebe1 <= x && x < 0x2f800 { return false; } if 0x2fa1e <= x && x < 0xe0100 { @@ -83,12 +86,12 @@ const SINGLETONS0U: &'static [(u8, u8)] = &[ (0x05, 8), (0x06, 3), (0x07, 4), - (0x08, 7), + (0x08, 8), (0x09, 16), (0x0a, 27), - (0x0b, 24), + (0x0b, 25), (0x0c, 22), - (0x0d, 20), + (0x0d, 18), (0x0e, 22), (0x0f, 4), (0x10, 3), @@ -99,16 +102,15 @@ const SINGLETONS0U: &'static [(u8, u8)] = &[ (0x18, 2), (0x19, 3), (0x1a, 7), - (0x1c, 1), + (0x1d, 1), (0x1f, 22), (0x20, 3), - (0x23, 1), (0x2b, 5), (0x2c, 2), (0x2d, 11), (0x2e, 1), (0x30, 3), - (0x31, 1), + (0x31, 3), (0x32, 2), (0xa7, 1), (0xa8, 2), @@ -125,19 +127,19 @@ const SINGLETONS0L: &'static [u8] = &[ 0xad, 0x78, 0x79, 0x8b, 0x8d, 0xa2, 0x30, 0x57, 0x58, 0x60, 0x88, 0x8b, 0x8c, 0x90, 0x1c, 0x1d, 0xdd, 0x0e, 0x0f, 0x4b, 0x4c, 0x2e, 0x2f, 0x3f, - 0x5c, 0x5d, 0xb5, 0xe2, 0x84, 0x8d, 0x8e, 0x91, - 0x92, 0xa9, 0xb1, 0xba, 0xbb, 0xc5, 0xc6, 0xc9, - 0xca, 0xde, 0xe4, 0xe5, 0x04, 0x11, 0x12, 0x29, - 0x31, 0x34, 0x37, 0x3a, 0x3b, 0x3d, 0x49, 0x4a, - 0x5d, 0x84, 0x8e, 0x92, 0xa9, 0xb1, 0xb4, 0xba, - 0xbb, 0xc6, 0xca, 0xce, 0xcf, 0xe4, 0xe5, 0x04, - 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a, - 0x3b, 0x45, 0x46, 0x49, 0x4a, 0x5e, 0x64, 0x65, - 0x84, 0x91, 0x9b, 0x9d, 0xc9, 0xce, 0xcf, 0x04, - 0x0d, 0x11, 0x29, 0x45, 0x49, 0x57, 0x64, 0x65, - 0x84, 0x8d, 0x91, 0xa9, 0xb4, 0xba, 0xbb, 0xc5, - 0xc9, 0xdf, 0xe4, 0xe5, 0xf0, 0x04, 0x0d, 0x11, - 0x3b, 0x3c, 0x45, 0x49, 0x64, 0x65, 0x80, 0x81, + 0x5c, 0x5d, 0x5f, 0xb5, 0xe2, 0x84, 0x8d, 0x8e, + 0x91, 0x92, 0xa9, 0xb1, 0xba, 0xbb, 0xc5, 0xc6, + 0xc9, 0xca, 0xde, 0xe4, 0xe5, 0x04, 0x11, 0x12, + 0x29, 0x31, 0x34, 0x37, 0x3a, 0x3b, 0x3d, 0x49, + 0x4a, 0x5d, 0x84, 0x8e, 0x92, 0xa9, 0xb1, 0xb4, + 0xba, 0xbb, 0xc6, 0xca, 0xce, 0xcf, 0xe4, 0xe5, + 0x00, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, + 0x34, 0x3a, 0x3b, 0x45, 0x46, 0x49, 0x4a, 0x5e, + 0x64, 0x65, 0x84, 0x91, 0x9b, 0x9d, 0xc9, 0xce, + 0xcf, 0x04, 0x0d, 0x11, 0x29, 0x45, 0x49, 0x57, + 0x64, 0x65, 0x84, 0x8d, 0x91, 0xa9, 0xb4, 0xba, + 0xbb, 0xc5, 0xc9, 0xdf, 0xe4, 0xe5, 0xf0, 0x04, + 0x0d, 0x11, 0x45, 0x49, 0x64, 0x65, 0x80, 0x81, 0x84, 0xb2, 0xbc, 0xbe, 0xbf, 0xd5, 0xd7, 0xf0, 0xf1, 0x83, 0x85, 0x86, 0x89, 0x8b, 0x8c, 0x98, 0xa0, 0xa4, 0xa6, 0xa8, 0xa9, 0xac, 0xba, 0xbe, @@ -148,18 +150,18 @@ const SINGLETONS0L: &'static [u8] = &[ 0x11, 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7, 0xfe, 0xff, 0x80, 0x0d, 0x6d, 0x71, 0xde, 0xdf, 0x0e, 0x0f, 0x1f, 0x6e, 0x6f, 0x1c, 0x1d, 0x5f, 0x7d, - 0x7e, 0xae, 0xaf, 0xf7, 0x16, 0x17, 0x1e, 0x1f, + 0x7e, 0xae, 0xaf, 0xfa, 0x16, 0x17, 0x1e, 0x1f, 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, 0x5e, 0x7e, 0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, 0xf0, - 0xf1, 0xf5, 0x72, 0x73, 0x8f, 0xff, 0x74, 0x75, - 0x96, 0x97, 0xc9, 0x2f, 0x5f, 0x26, 0x2e, 0x2f, - 0xa7, 0xaf, 0xb7, 0xbf, 0xc7, 0xcf, 0xd7, 0xdf, - 0x9a, 0x40, 0x97, 0x98, 0x8f, 0x1f, 0xff, 0xaf, - 0xfe, 0xff, 0xce, 0xff, 0x4e, 0x4f, 0x5a, 0x5b, - 0x07, 0x08, 0x0f, 0x10, 0x27, 0x2f, 0xee, 0xef, - 0x6e, 0x6f, 0x37, 0x3d, 0x3f, 0x42, 0x45, 0x90, - 0x91, 0xfe, 0xff, 0x53, 0x67, 0x75, 0xc8, 0xc9, - 0xd0, 0xd1, 0xd8, 0xd9, 0xe7, 0xfe, 0xff, + 0xf1, 0xf5, 0x72, 0x73, 0x8f, 0x74, 0x75, 0x96, + 0x97, 0xc9, 0x2f, 0x5f, 0x26, 0x2e, 0x2f, 0xa7, + 0xaf, 0xb7, 0xbf, 0xc7, 0xcf, 0xd7, 0xdf, 0x9a, + 0x40, 0x97, 0x98, 0x2f, 0x30, 0x8f, 0x1f, 0xff, + 0xaf, 0xfe, 0xff, 0xce, 0xff, 0x4e, 0x4f, 0x5a, + 0x5b, 0x07, 0x08, 0x0f, 0x10, 0x27, 0x2f, 0xee, + 0xef, 0x6e, 0x6f, 0x37, 0x3d, 0x3f, 0x42, 0x45, + 0x90, 0x91, 0xfe, 0xff, 0x53, 0x67, 0x75, 0xc8, + 0xc9, 0xd0, 0xd1, 0xd8, 0xd9, 0xe7, 0xfe, 0xff, ]; const SINGLETONS1U: &'static [(u8, u8)] = &[ (0x00, 6), @@ -176,7 +178,9 @@ const SINGLETONS1U: &'static [(u8, u8)] = &[ (0x13, 18), (0x14, 2), (0x15, 2), + (0x1a, 3), (0x1c, 5), + (0x1d, 4), (0x24, 1), (0x6a, 3), (0x6b, 2), @@ -192,7 +196,7 @@ const SINGLETONS1U: &'static [(u8, u8)] = &[ (0xee, 32), (0xf0, 4), (0xf1, 1), - (0xf9, 4), + (0xf9, 1), ]; const SINGLETONS1L: &'static [u8] = &[ 0x0c, 0x27, 0x3b, 0x3e, 0x4e, 0x4f, 0x8f, 0x9e, @@ -202,18 +206,18 @@ const SINGLETONS1L: &'static [u8] = &[ 0x89, 0x8e, 0x9e, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a, 0x3b, 0x45, 0x46, 0x49, 0x4a, 0x4e, 0x4f, 0x64, 0x65, 0x5a, 0x5c, 0xb6, - 0xb7, 0x09, 0x37, 0x90, 0x91, 0xa8, 0x6f, 0x5f, - 0xee, 0xef, 0x5a, 0x62, 0x9a, 0x9b, 0x27, 0x28, - 0x55, 0x9d, 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, - 0xad, 0xba, 0xbc, 0xc4, 0x06, 0x0b, 0x0c, 0x15, - 0x1d, 0x3a, 0x3f, 0x45, 0x51, 0xa6, 0xa7, 0xcc, - 0xcd, 0xa0, 0x07, 0x19, 0x1a, 0x22, 0x25, 0xc5, - 0xc6, 0x04, 0x20, 0x23, 0x25, 0x26, 0x28, 0x33, - 0x38, 0x3a, 0x48, 0x4a, 0x4c, 0x50, 0x53, 0x55, - 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x63, 0x65, - 0x66, 0x6b, 0x73, 0x78, 0x7d, 0x7f, 0x8a, 0xa4, - 0xaa, 0xaf, 0xb0, 0xc0, 0xd0, 0x2f, 0x1f, 0x31, - 0x32, 0x3f, + 0xb7, 0x84, 0x85, 0x9d, 0x09, 0x37, 0x90, 0x91, + 0xa8, 0x07, 0x0a, 0x3b, 0x3e, 0x6f, 0x5f, 0xee, + 0xef, 0x5a, 0x62, 0x9a, 0x9b, 0x27, 0x28, 0x55, + 0x9d, 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, 0xad, + 0xba, 0xbc, 0xc4, 0x06, 0x0b, 0x0c, 0x15, 0x1d, + 0x3a, 0x3f, 0x45, 0x51, 0xa6, 0xa7, 0xcc, 0xcd, + 0xa0, 0x07, 0x19, 0x1a, 0x22, 0x25, 0xc5, 0xc6, + 0x04, 0x20, 0x23, 0x25, 0x26, 0x28, 0x33, 0x38, + 0x3a, 0x48, 0x4a, 0x4c, 0x50, 0x53, 0x55, 0x56, + 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x63, 0x65, 0x66, + 0x6b, 0x73, 0x78, 0x7d, 0x7f, 0x8a, 0xa4, 0xaa, + 0xaf, 0xb0, 0xc0, 0xd0, 0x2f, 0x3f, ]; const NORMAL0: &'static [u8] = &[ 0x00, 0x20, @@ -224,12 +228,12 @@ const NORMAL0: &'static [u8] = &[ 0x05, 0x11, 0x81, 0xac, 0x0e, 0x3b, 0x05, - 0x5f, 0x41, + 0x6b, 0x35, 0x1e, 0x16, 0x80, 0xdf, 0x03, 0x19, 0x08, 0x01, 0x04, - 0x20, 0x05, + 0x22, 0x03, 0x0a, 0x04, 0x34, 0x04, 0x07, 0x03, @@ -238,8 +242,7 @@ const NORMAL0: &'static [u8] = &[ 0x10, 0x0b, 0x50, 0x0f, 0x12, 0x07, - 0x01, 0x07, - 0x4d, 0x08, + 0x55, 0x08, 0x02, 0x04, 0x1c, 0x0a, 0x09, 0x03, @@ -258,8 +261,8 @@ const NORMAL0: &'static [u8] = &[ 0x10, 0x08, 0x56, 0x07, 0x02, 0x07, - 0x15, 0x0e, - 0x4f, 0x04, + 0x15, 0x0d, + 0x50, 0x04, 0x43, 0x03, 0x2d, 0x03, 0x01, 0x04, @@ -304,34 +307,32 @@ const NORMAL0: &'static [u8] = &[ 0x3c, 0x37, 0x08, 0x08, 0x2a, 0x06, - 0x80, 0xf6, 0x05, - 0x82, 0x04, 0x11, + 0x82, 0xff, 0x11, 0x18, 0x08, 0x2f, 0x11, 0x2d, 0x03, - 0x1f, 0x11, + 0x20, 0x10, 0x21, 0x0f, 0x80, 0x8c, 0x04, 0x82, 0x97, 0x19, 0x0b, 0x15, 0x87, 0x5a, 0x03, - 0x15, 0x1a, + 0x16, 0x19, 0x04, 0x10, 0x80, 0xf4, 0x05, 0x2f, 0x05, 0x3b, 0x07, 0x02, 0x0e, 0x18, 0x09, - 0x80, 0xa5, 0x3b, + 0x80, 0xaa, 0x36, 0x74, 0x0c, 0x80, 0xd6, 0x1a, 0x0c, 0x05, 0x80, 0xff, 0x05, - 0x29, 0x03, - 0x80, 0x8a, 0x05, + 0x80, 0xb6, 0x05, 0x24, 0x0c, 0x9b, 0xc6, 0x0a, - 0xd2, 0x16, 0x2a, + 0xd2, 0x2b, 0x15, 0x84, 0x8d, 0x03, 0x37, 0x09, 0x81, 0x5c, 0x14, @@ -378,8 +379,8 @@ const NORMAL1: &'static [u8] = &[ 0x1d, 0x03, 0x31, 0x0f, 0x1c, 0x04, - 0x24, 0x0c, - 0x1b, 0x05, + 0x24, 0x09, + 0x1e, 0x05, 0x2b, 0x05, 0x44, 0x04, 0x0e, 0x2a, @@ -447,11 +448,16 @@ const NORMAL1: &'static [u8] = &[ 0x0f, 0x04, 0x10, 0x81, 0x60, 0x53, 0x0c, - 0x01, 0x81, 0xc0, + 0x01, 0x81, 0x00, + 0x48, 0x08, + 0x53, 0x1d, 0x39, 0x81, 0x07, 0x46, 0x0a, 0x1d, 0x03, - 0x47, 0x83, 0x49, + 0x47, 0x49, + 0x37, 0x03, + 0x0e, 0x08, + 0x0a, 0x82, 0xa6, 0x83, 0x9a, 0x66, 0x75, 0x0b, 0x80, 0xc4, 0x8a, 0xbc, @@ -467,10 +473,11 @@ const NORMAL1: &'static [u8] = &[ 0x45, 0x0b, 0x2f, 0x10, 0x11, 0x40, - 0x01, 0x1f, + 0x02, 0x1e, 0x97, 0xed, 0x13, 0x82, 0xf3, 0xa5, 0x0d, - 0x02, 0x8b, 0xfe, + 0x81, 0x1f, 0x51, + 0x81, 0x8c, 0x89, 0x04, 0x6b, 0x05, 0x0d, 0x03, 0x09, 0x07, @@ -503,20 +510,22 @@ const NORMAL1: &'static [u8] = &[ 0x1d, 0x0d, 0x2c, 0x04, 0x09, 0x07, - 0x02, 0x80, 0xae, - 0x83, 0xd3, 0x0d, + 0x02, 0x0e, + 0x06, 0x80, 0x9a, + 0x83, 0xd5, 0x0b, 0x0d, 0x03, - 0x07, 0x09, + 0x09, 0x07, 0x74, 0x0c, 0x55, 0x2b, 0x0c, 0x04, 0x38, 0x08, 0x0a, 0x06, 0x28, 0x08, - 0x1e, 0x62, - 0x18, 0x08, - 0x1c, 0x04, - 0x0f, 0x21, - 0x12, 0x2e, - 0x01, 0x86, 0x3f, + 0x1e, 0x52, + 0x0c, 0x04, + 0x3d, 0x03, + 0x1c, 0x14, + 0x18, 0x28, + 0x01, 0x0f, + 0x17, 0x86, 0x19, ]; diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 5659d5b8d66..4a57417e86a 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -189,3 +189,4 @@ pub mod fmt; mod char_private; mod iter_private; mod tuple; +mod unit; diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index f56a9a40332..e47b99ed552 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -46,6 +46,8 @@ pub unsafe trait Send { } #[stable(feature = "rust1", since = "1.0.0")] +#[allow(unknown_lints)] +#[allow(auto_impl)] unsafe impl Send for .. { } #[stable(feature = "rust1", since = "1.0.0")] @@ -349,6 +351,8 @@ pub unsafe trait Sync { } #[stable(feature = "rust1", since = "1.0.0")] +#[allow(unknown_lints)] +#[allow(auto_impl)] unsafe impl Sync for .. { } #[stable(feature = "rust1", since = "1.0.0")] @@ -562,6 +566,8 @@ mod impls { #[lang = "freeze"] unsafe trait Freeze {} +#[allow(unknown_lints)] +#[allow(auto_impl)] unsafe impl Freeze for .. {} impl<T: ?Sized> !Freeze for UnsafeCell<T> {} diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 5799d37c19c..7fe0aabeec9 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -15,6 +15,7 @@ use convert::{Infallible, TryFrom}; use fmt; use intrinsics; +use ops; use str::FromStr; /// Provides intentionally-wrapped arithmetic on `T`. @@ -2223,7 +2224,8 @@ macro_rules! uint_impl { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn next_power_of_two(self) -> Self { - self.one_less_than_next_power_of_two() + 1 + // Call the trait to get overflow checks + ops::Add::add(self.one_less_than_next_power_of_two(), 1) } /// Returns the smallest power of two greater than or equal to `n`. If @@ -2257,6 +2259,547 @@ impl u8 { intrinsics::add_with_overflow, intrinsics::sub_with_overflow, intrinsics::mul_with_overflow } + + + /// Checks if the value is within the ASCII range. + /// + /// # Examples + /// + /// ``` + /// let ascii = 97u8; + /// let non_ascii = 150u8; + /// + /// assert!(ascii.is_ascii()); + /// assert!(!non_ascii.is_ascii()); + /// ``` + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")] + #[inline] + pub fn is_ascii(&self) -> bool { + *self & 128 == 0 + } + + /// Makes a copy of the value in its ASCII upper case equivalent. + /// + /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', + /// but non-ASCII letters are unchanged. + /// + /// To uppercase the value in-place, use [`make_ascii_uppercase`]. + /// + /// # Examples + /// + /// ``` + /// let lowercase_a = 97u8; + /// + /// assert_eq!(65, lowercase_a.to_ascii_uppercase()); + /// ``` + /// + /// [`make_ascii_uppercase`]: #method.make_ascii_uppercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")] + #[inline] + pub fn to_ascii_uppercase(&self) -> u8 { + ASCII_UPPERCASE_MAP[*self as usize] + } + + /// Makes a copy of the value in its ASCII lower case equivalent. + /// + /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', + /// but non-ASCII letters are unchanged. + /// + /// To lowercase the value in-place, use [`make_ascii_lowercase`]. + /// + /// # Examples + /// + /// ``` + /// let uppercase_a = 65u8; + /// + /// assert_eq!(97, uppercase_a.to_ascii_lowercase()); + /// ``` + /// + /// [`make_ascii_lowercase`]: #method.make_ascii_lowercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")] + #[inline] + pub fn to_ascii_lowercase(&self) -> u8 { + ASCII_LOWERCASE_MAP[*self as usize] + } + + /// Checks that two values are an ASCII case-insensitive match. + /// + /// This is equivalent to `to_ascii_lowercase(a) == to_ascii_lowercase(b)`. + /// + /// # Examples + /// + /// ``` + /// let lowercase_a = 97u8; + /// let uppercase_a = 65u8; + /// + /// assert!(lowercase_a.eq_ignore_ascii_case(&uppercase_a)); + /// ``` + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")] + #[inline] + pub fn eq_ignore_ascii_case(&self, other: &u8) -> bool { + self.to_ascii_lowercase() == other.to_ascii_lowercase() + } + + /// Converts this value to its ASCII upper case equivalent in-place. + /// + /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', + /// but non-ASCII letters are unchanged. + /// + /// To return a new uppercased value without modifying the existing one, use + /// [`to_ascii_uppercase`]. + /// + /// # Examples + /// + /// ``` + /// let mut byte = b'a'; + /// + /// byte.make_ascii_uppercase(); + /// + /// assert_eq!(b'A', byte); + /// ``` + /// + /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")] + #[inline] + pub fn make_ascii_uppercase(&mut self) { + *self = self.to_ascii_uppercase(); + } + + /// Converts this value to its ASCII lower case equivalent in-place. + /// + /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', + /// but non-ASCII letters are unchanged. + /// + /// To return a new lowercased value without modifying the existing one, use + /// [`to_ascii_lowercase`]. + /// + /// # Examples + /// + /// ``` + /// let mut byte = b'A'; + /// + /// byte.make_ascii_lowercase(); + /// + /// assert_eq!(b'a', byte); + /// ``` + /// + /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")] + #[inline] + pub fn make_ascii_lowercase(&mut self) { + *self = self.to_ascii_lowercase(); + } + + /// Checks if the value is an ASCII alphabetic character: + /// + /// - U+0041 'A' ... U+005A 'Z', or + /// - U+0061 'a' ... U+007A 'z'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = b'A'; + /// let uppercase_g = b'G'; + /// let a = b'a'; + /// let g = b'g'; + /// let zero = b'0'; + /// let percent = b'%'; + /// let space = b' '; + /// let lf = b'\n'; + /// let esc = 0x1b_u8; + /// + /// assert!(uppercase_a.is_ascii_alphabetic()); + /// assert!(uppercase_g.is_ascii_alphabetic()); + /// assert!(a.is_ascii_alphabetic()); + /// assert!(g.is_ascii_alphabetic()); + /// assert!(!zero.is_ascii_alphabetic()); + /// assert!(!percent.is_ascii_alphabetic()); + /// assert!(!space.is_ascii_alphabetic()); + /// assert!(!lf.is_ascii_alphabetic()); + /// assert!(!esc.is_ascii_alphabetic()); + /// ``` + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_alphabetic(&self) -> bool { + if *self >= 0x80 { return false; } + match ASCII_CHARACTER_CLASS[*self as usize] { + L | Lx | U | Ux => true, + _ => false + } + } + + /// Checks if the value is an ASCII uppercase character: + /// U+0041 'A' ... U+005A 'Z'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = b'A'; + /// let uppercase_g = b'G'; + /// let a = b'a'; + /// let g = b'g'; + /// let zero = b'0'; + /// let percent = b'%'; + /// let space = b' '; + /// let lf = b'\n'; + /// let esc = 0x1b_u8; + /// + /// assert!(uppercase_a.is_ascii_uppercase()); + /// assert!(uppercase_g.is_ascii_uppercase()); + /// assert!(!a.is_ascii_uppercase()); + /// assert!(!g.is_ascii_uppercase()); + /// assert!(!zero.is_ascii_uppercase()); + /// assert!(!percent.is_ascii_uppercase()); + /// assert!(!space.is_ascii_uppercase()); + /// assert!(!lf.is_ascii_uppercase()); + /// assert!(!esc.is_ascii_uppercase()); + /// ``` + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_uppercase(&self) -> bool { + if *self >= 0x80 { return false } + match ASCII_CHARACTER_CLASS[*self as usize] { + U | Ux => true, + _ => false + } + } + + /// Checks if the value is an ASCII lowercase character: + /// U+0061 'a' ... U+007A 'z'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = b'A'; + /// let uppercase_g = b'G'; + /// let a = b'a'; + /// let g = b'g'; + /// let zero = b'0'; + /// let percent = b'%'; + /// let space = b' '; + /// let lf = b'\n'; + /// let esc = 0x1b_u8; + /// + /// assert!(!uppercase_a.is_ascii_lowercase()); + /// assert!(!uppercase_g.is_ascii_lowercase()); + /// assert!(a.is_ascii_lowercase()); + /// assert!(g.is_ascii_lowercase()); + /// assert!(!zero.is_ascii_lowercase()); + /// assert!(!percent.is_ascii_lowercase()); + /// assert!(!space.is_ascii_lowercase()); + /// assert!(!lf.is_ascii_lowercase()); + /// assert!(!esc.is_ascii_lowercase()); + /// ``` + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_lowercase(&self) -> bool { + if *self >= 0x80 { return false } + match ASCII_CHARACTER_CLASS[*self as usize] { + L | Lx => true, + _ => false + } + } + + /// Checks if the value is an ASCII alphanumeric character: + /// + /// - U+0041 'A' ... U+005A 'Z', or + /// - U+0061 'a' ... U+007A 'z', or + /// - U+0030 '0' ... U+0039 '9'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = b'A'; + /// let uppercase_g = b'G'; + /// let a = b'a'; + /// let g = b'g'; + /// let zero = b'0'; + /// let percent = b'%'; + /// let space = b' '; + /// let lf = b'\n'; + /// let esc = 0x1b_u8; + /// + /// assert!(uppercase_a.is_ascii_alphanumeric()); + /// assert!(uppercase_g.is_ascii_alphanumeric()); + /// assert!(a.is_ascii_alphanumeric()); + /// assert!(g.is_ascii_alphanumeric()); + /// assert!(zero.is_ascii_alphanumeric()); + /// assert!(!percent.is_ascii_alphanumeric()); + /// assert!(!space.is_ascii_alphanumeric()); + /// assert!(!lf.is_ascii_alphanumeric()); + /// assert!(!esc.is_ascii_alphanumeric()); + /// ``` + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_alphanumeric(&self) -> bool { + if *self >= 0x80 { return false } + match ASCII_CHARACTER_CLASS[*self as usize] { + D | L | Lx | U | Ux => true, + _ => false + } + } + + /// Checks if the value is an ASCII decimal digit: + /// U+0030 '0' ... U+0039 '9'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = b'A'; + /// let uppercase_g = b'G'; + /// let a = b'a'; + /// let g = b'g'; + /// let zero = b'0'; + /// let percent = b'%'; + /// let space = b' '; + /// let lf = b'\n'; + /// let esc = 0x1b_u8; + /// + /// assert!(!uppercase_a.is_ascii_digit()); + /// assert!(!uppercase_g.is_ascii_digit()); + /// assert!(!a.is_ascii_digit()); + /// assert!(!g.is_ascii_digit()); + /// assert!(zero.is_ascii_digit()); + /// assert!(!percent.is_ascii_digit()); + /// assert!(!space.is_ascii_digit()); + /// assert!(!lf.is_ascii_digit()); + /// assert!(!esc.is_ascii_digit()); + /// ``` + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_digit(&self) -> bool { + if *self >= 0x80 { return false } + match ASCII_CHARACTER_CLASS[*self as usize] { + D => true, + _ => false + } + } + + /// Checks if the value is an ASCII hexadecimal digit: + /// + /// - U+0030 '0' ... U+0039 '9', or + /// - U+0041 'A' ... U+0046 'F', or + /// - U+0061 'a' ... U+0066 'f'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = b'A'; + /// let uppercase_g = b'G'; + /// let a = b'a'; + /// let g = b'g'; + /// let zero = b'0'; + /// let percent = b'%'; + /// let space = b' '; + /// let lf = b'\n'; + /// let esc = 0x1b_u8; + /// + /// assert!(uppercase_a.is_ascii_hexdigit()); + /// assert!(!uppercase_g.is_ascii_hexdigit()); + /// assert!(a.is_ascii_hexdigit()); + /// assert!(!g.is_ascii_hexdigit()); + /// assert!(zero.is_ascii_hexdigit()); + /// assert!(!percent.is_ascii_hexdigit()); + /// assert!(!space.is_ascii_hexdigit()); + /// assert!(!lf.is_ascii_hexdigit()); + /// assert!(!esc.is_ascii_hexdigit()); + /// ``` + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_hexdigit(&self) -> bool { + if *self >= 0x80 { return false } + match ASCII_CHARACTER_CLASS[*self as usize] { + D | Lx | Ux => true, + _ => false + } + } + + /// Checks if the value is an ASCII punctuation character: + /// + /// - U+0021 ... U+002F `! " # $ % & ' ( ) * + , - . /`, or + /// - U+003A ... U+0040 `: ; < = > ? @`, or + /// - U+005B ... U+0060 `[ \\ ] ^ _ \``, or + /// - U+007B ... U+007E `{ | } ~` + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = b'A'; + /// let uppercase_g = b'G'; + /// let a = b'a'; + /// let g = b'g'; + /// let zero = b'0'; + /// let percent = b'%'; + /// let space = b' '; + /// let lf = b'\n'; + /// let esc = 0x1b_u8; + /// + /// assert!(!uppercase_a.is_ascii_punctuation()); + /// assert!(!uppercase_g.is_ascii_punctuation()); + /// assert!(!a.is_ascii_punctuation()); + /// assert!(!g.is_ascii_punctuation()); + /// assert!(!zero.is_ascii_punctuation()); + /// assert!(percent.is_ascii_punctuation()); + /// assert!(!space.is_ascii_punctuation()); + /// assert!(!lf.is_ascii_punctuation()); + /// assert!(!esc.is_ascii_punctuation()); + /// ``` + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_punctuation(&self) -> bool { + if *self >= 0x80 { return false } + match ASCII_CHARACTER_CLASS[*self as usize] { + P => true, + _ => false + } + } + + /// Checks if the value is an ASCII graphic character: + /// U+0021 '@' ... U+007E '~'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = b'A'; + /// let uppercase_g = b'G'; + /// let a = b'a'; + /// let g = b'g'; + /// let zero = b'0'; + /// let percent = b'%'; + /// let space = b' '; + /// let lf = b'\n'; + /// let esc = 0x1b_u8; + /// + /// assert!(uppercase_a.is_ascii_graphic()); + /// assert!(uppercase_g.is_ascii_graphic()); + /// assert!(a.is_ascii_graphic()); + /// assert!(g.is_ascii_graphic()); + /// assert!(zero.is_ascii_graphic()); + /// assert!(percent.is_ascii_graphic()); + /// assert!(!space.is_ascii_graphic()); + /// assert!(!lf.is_ascii_graphic()); + /// assert!(!esc.is_ascii_graphic()); + /// ``` + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_graphic(&self) -> bool { + if *self >= 0x80 { return false; } + match ASCII_CHARACTER_CLASS[*self as usize] { + Ux | U | Lx | L | D | P => true, + _ => false + } + } + + /// Checks if the value is an ASCII whitespace character: + /// U+0020 SPACE, U+0009 HORIZONTAL TAB, U+000A LINE FEED, + /// U+000C FORM FEED, or U+000D CARRIAGE RETURN. + /// + /// Rust uses the WhatWG Infra Standard's [definition of ASCII + /// whitespace][infra-aw]. There are several other definitions in + /// wide use. For instance, [the POSIX locale][pct] includes + /// U+000B VERTICAL TAB as well as all the above characters, + /// but—from the very same specification—[the default rule for + /// "field splitting" in the Bourne shell][bfs] considers *only* + /// SPACE, HORIZONTAL TAB, and LINE FEED as whitespace. + /// + /// If you are writing a program that will process an existing + /// file format, check what that format's definition of whitespace is + /// before using this function. + /// + /// [infra-aw]: https://infra.spec.whatwg.org/#ascii-whitespace + /// [pct]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_01 + /// [bfs]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = b'A'; + /// let uppercase_g = b'G'; + /// let a = b'a'; + /// let g = b'g'; + /// let zero = b'0'; + /// let percent = b'%'; + /// let space = b' '; + /// let lf = b'\n'; + /// let esc = 0x1b_u8; + /// + /// assert!(!uppercase_a.is_ascii_whitespace()); + /// assert!(!uppercase_g.is_ascii_whitespace()); + /// assert!(!a.is_ascii_whitespace()); + /// assert!(!g.is_ascii_whitespace()); + /// assert!(!zero.is_ascii_whitespace()); + /// assert!(!percent.is_ascii_whitespace()); + /// assert!(space.is_ascii_whitespace()); + /// assert!(lf.is_ascii_whitespace()); + /// assert!(!esc.is_ascii_whitespace()); + /// ``` + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_whitespace(&self) -> bool { + if *self >= 0x80 { return false; } + match ASCII_CHARACTER_CLASS[*self as usize] { + Cw | W => true, + _ => false + } + } + + /// Checks if the value is an ASCII control character: + /// U+0000 NUL ... U+001F UNIT SEPARATOR, or U+007F DELETE. + /// Note that most ASCII whitespace characters are control + /// characters, but SPACE is not. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = b'A'; + /// let uppercase_g = b'G'; + /// let a = b'a'; + /// let g = b'g'; + /// let zero = b'0'; + /// let percent = b'%'; + /// let space = b' '; + /// let lf = b'\n'; + /// let esc = 0x1b_u8; + /// + /// assert!(!uppercase_a.is_ascii_control()); + /// assert!(!uppercase_g.is_ascii_control()); + /// assert!(!a.is_ascii_control()); + /// assert!(!g.is_ascii_control()); + /// assert!(!zero.is_ascii_control()); + /// assert!(!percent.is_ascii_control()); + /// assert!(!space.is_ascii_control()); + /// assert!(lf.is_ascii_control()); + /// assert!(esc.is_ascii_control()); + /// ``` + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_control(&self) -> bool { + if *self >= 0x80 { return false; } + match ASCII_CHARACTER_CLASS[*self as usize] { + C | Cw => true, + _ => false + } + } } #[lang = "u16"] @@ -2926,3 +3469,106 @@ impl_from! { u32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0" // Float -> Float impl_from! { f32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } + +static ASCII_LOWERCASE_MAP: [u8; 256] = [ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + b' ', b'!', b'"', b'#', b'$', b'%', b'&', b'\'', + b'(', b')', b'*', b'+', b',', b'-', b'.', b'/', + b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', + b'8', b'9', b':', b';', b'<', b'=', b'>', b'?', + b'@', + + b'a', b'b', b'c', b'd', b'e', b'f', b'g', + b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o', + b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', + b'x', b'y', b'z', + + b'[', b'\\', b']', b'^', b'_', + b'`', b'a', b'b', b'c', b'd', b'e', b'f', b'g', + b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o', + b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', + b'x', b'y', b'z', b'{', b'|', b'}', b'~', 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, +]; + +static ASCII_UPPERCASE_MAP: [u8; 256] = [ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + b' ', b'!', b'"', b'#', b'$', b'%', b'&', b'\'', + b'(', b')', b'*', b'+', b',', b'-', b'.', b'/', + b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', + b'8', b'9', b':', b';', b'<', b'=', b'>', b'?', + b'@', b'A', b'B', b'C', b'D', b'E', b'F', b'G', + b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', + b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', + b'X', b'Y', b'Z', b'[', b'\\', b']', b'^', b'_', + b'`', + + b'A', b'B', b'C', b'D', b'E', b'F', b'G', + b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', + b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', + b'X', b'Y', b'Z', + + b'{', b'|', b'}', b'~', 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, +]; + +enum AsciiCharacterClass { + C, // control + Cw, // control whitespace + W, // whitespace + D, // digit + L, // lowercase + Lx, // lowercase hex digit + U, // uppercase + Ux, // uppercase hex digit + P, // punctuation +} +use self::AsciiCharacterClass::*; + +static ASCII_CHARACTER_CLASS: [AsciiCharacterClass; 128] = [ +// _0 _1 _2 _3 _4 _5 _6 _7 _8 _9 _a _b _c _d _e _f + C, C, C, C, C, C, C, C, C, Cw,Cw,C, Cw,Cw,C, C, // 0_ + C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, // 1_ + W, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, // 2_ + D, D, D, D, D, D, D, D, D, D, P, P, P, P, P, P, // 3_ + P, Ux,Ux,Ux,Ux,Ux,Ux,U, U, U, U, U, U, U, U, U, // 4_ + U, U, U, U, U, U, U, U, U, U, U, P, P, P, P, P, // 5_ + P, Lx,Lx,Lx,Lx,Lx,Lx,L, L, L, L, L, L, L, L, L, // 6_ + L, L, L, L, L, L, L, L, L, L, L, P, P, P, P, C, // 7_ +]; diff --git a/src/libcore/ops/deref.rs b/src/libcore/ops/deref.rs index 4cb6e8405f3..80c48c7b28e 100644 --- a/src/libcore/ops/deref.rs +++ b/src/libcore/ops/deref.rs @@ -18,7 +18,7 @@ /// Implementing `Deref` for smart pointers makes accessing the data behind them /// convenient, which is why they implement `Deref`. On the other hand, the /// rules regarding `Deref` and [`DerefMut`] were designed specifically to -/// accomodate smart pointers. Because of this, **`Deref` should only be +/// accommodate smart pointers. Because of this, **`Deref` should only be /// implemented for smart pointers** to avoid confusion. /// /// For similar reasons, **this trait should never fail**. Failure during @@ -103,7 +103,7 @@ impl<'a, T: ?Sized> Deref for &'a mut T { /// Implementing `DerefMut` for smart pointers makes mutating the data behind /// them convenient, which is why they implement `DerefMut`. On the other hand, /// the rules regarding [`Deref`] and `DerefMut` were designed specifically to -/// accomodate smart pointers. Because of this, **`DerefMut` should only be +/// accommodate smart pointers. Because of this, **`DerefMut` should only be /// implemented for smart pointers** to avoid confusion. /// /// For similar reasons, **this trait should never fail**. Failure during diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 5cd672b03ff..126558e3025 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -517,8 +517,10 @@ impl<T: ?Sized> *const T { /// ``` #[stable(feature = "ptr_as_ref", since = "1.9.0")] #[inline] - pub unsafe fn as_ref<'a>(self) -> Option<&'a T> where T: Sized { - if self.is_null() { + pub unsafe fn as_ref<'a>(self) -> Option<&'a T> { + // Check for null via a cast to a thin pointer, so fat pointers are only + // considering their "data" part for null-ness. + if (self as *const u8).is_null() { None } else { Some(&*self) @@ -1148,8 +1150,10 @@ impl<T: ?Sized> *mut T { /// ``` #[stable(feature = "ptr_as_ref", since = "1.9.0")] #[inline] - pub unsafe fn as_ref<'a>(self) -> Option<&'a T> where T: Sized { - if self.is_null() { + pub unsafe fn as_ref<'a>(self) -> Option<&'a T> { + // Check for null via a cast to a thin pointer, so fat pointers are only + // considering their "data" part for null-ness. + if (self as *const u8).is_null() { None } else { Some(&*self) @@ -1272,8 +1276,10 @@ impl<T: ?Sized> *mut T { /// ``` #[stable(feature = "ptr_as_ref", since = "1.9.0")] #[inline] - pub unsafe fn as_mut<'a>(self) -> Option<&'a mut T> where T: Sized { - if self.is_null() { + pub unsafe fn as_mut<'a>(self) -> Option<&'a mut T> { + // Check for null via a cast to a thin pointer, so fat pointers are only + // considering their "data" part for null-ness. + if (self as *mut u8).is_null() { None } else { Some(&mut *self) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 5039bef631e..57e5ae28664 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -2450,6 +2450,22 @@ pub unsafe fn from_raw_parts_mut<'a, T>(p: *mut T, len: usize) -> &'a mut [T] { mem::transmute(Repr { data: p, len: len }) } +/// Converts a reference to T into a slice of length 1 (without copying). +#[unstable(feature = "from_ref", issue = "45703")] +pub fn from_ref<T>(s: &T) -> &[T] { + unsafe { + from_raw_parts(s, 1) + } +} + +/// Converts a reference to T into a slice of length 1 (without copying). +#[unstable(feature = "from_ref", issue = "45703")] +pub fn from_ref_mut<T>(s: &mut T) -> &mut [T] { + unsafe { + from_raw_parts_mut(s, 1) + } +} + // This function is public only because there is no other way to unit test heapsort. #[unstable(feature = "sort_internals", reason = "internal to sort module", issue = "0")] #[doc(hidden)] diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 53b056d2b8b..cd3dd9ce139 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -927,6 +927,12 @@ impl<T> AtomicPtr<T> { } } +#[stable(feature = "atomic_from", since = "1.23.0")] +impl<T> From<*mut T> for AtomicPtr<T> { + #[inline] + fn from(p: *mut T) -> Self { Self::new(p) } +} + #[cfg(target_has_atomic = "ptr")] macro_rules! atomic_int { ($stable:meta, $const_unstable:meta, @@ -967,6 +973,12 @@ macro_rules! atomic_int { } } + #[stable(feature = "atomic_from", since = "1.23.0")] + impl From<$int_type> for $atomic_type { + #[inline] + fn from(v: $int_type) -> Self { Self::new(v) } + } + #[$stable_debug] impl fmt::Debug for $atomic_type { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/src/libcore/tests/ptr.rs b/src/libcore/tests/ptr.rs index c2d53840f8f..e93e9be0cd5 100644 --- a/src/libcore/tests/ptr.rs +++ b/src/libcore/tests/ptr.rs @@ -85,6 +85,39 @@ fn test_as_ref() { let p = &u as *const isize; assert_eq!(p.as_ref().unwrap(), &2); } + + // Pointers to unsized types -- slices + let s: &mut [u8] = &mut [1, 2, 3]; + let cs: *const [u8] = s; + assert_eq!(cs.as_ref(), Some(&*s)); + + let ms: *mut [u8] = s; + assert_eq!(ms.as_ref(), Some(&*s)); + + let cz: *const [u8] = &[]; + assert_eq!(cz.as_ref(), Some(&[][..])); + + let mz: *mut [u8] = &mut []; + assert_eq!(mz.as_ref(), Some(&[][..])); + + let ncs: *const [u8] = null::<[u8; 3]>(); + assert_eq!(ncs.as_ref(), None); + + let nms: *mut [u8] = null_mut::<[u8; 3]>(); + assert_eq!(nms.as_ref(), None); + + // Pointers to unsized types -- trait objects + let ci: *const ToString = &3; + assert!(ci.as_ref().is_some()); + + let mi: *mut ToString = &mut 3; + assert!(mi.as_ref().is_some()); + + let nci: *const ToString = null::<isize>(); + assert!(nci.as_ref().is_none()); + + let nmi: *mut ToString = null_mut::<isize>(); + assert!(nmi.as_ref().is_none()); } } @@ -103,6 +136,24 @@ fn test_as_mut() { let p = &mut u as *mut isize; assert!(p.as_mut().unwrap() == &mut 2); } + + // Pointers to unsized types -- slices + let s: &mut [u8] = &mut [1, 2, 3]; + let ms: *mut [u8] = s; + assert_eq!(ms.as_mut(), Some(s)); + + let mz: *mut [u8] = &mut []; + assert_eq!(mz.as_mut(), Some(&mut [][..])); + + let nms: *mut [u8] = null_mut::<[u8; 3]>(); + assert_eq!(nms.as_mut(), None); + + // Pointers to unsized types -- trait objects + let mi: *mut ToString = &mut 3; + assert!(mi.as_mut().is_some()); + + let nmi: *mut ToString = null_mut::<isize>(); + assert!(nmi.as_mut().is_none()); } } diff --git a/src/libcore/unit.rs b/src/libcore/unit.rs new file mode 100644 index 00000000000..087ddf9688a --- /dev/null +++ b/src/libcore/unit.rs @@ -0,0 +1,31 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use iter::FromIterator; + +/// Collapses all unit items from an iterator into one. +/// +/// This is more useful when combined with higher-level abstractions, like +/// collecting to a `Result<(), E>` where you only care about errors: +/// +/// ``` +/// use std::io::*; +/// let data = vec![1, 2, 3, 4, 5]; +/// let res: Result<()> = data.iter() +/// .map(|x| writeln!(stdout(), "{}", x)) +/// .collect(); +/// assert!(res.is_ok()); +/// ``` +#[stable(feature = "unit_from_iter", since = "1.23.0")] +impl FromIterator<()> for () { + fn from_iter<I: IntoIterator<Item=()>>(iter: I) -> Self { + iter.into_iter().for_each(|()| {}) + } +} diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 4a763d4144e..89ce4bf928a 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -459,10 +459,6 @@ define_dep_nodes!( <'tcx> // Represents metadata from an extern crate. [input] CrateMetadata(CrateNum), - // Represents some artifact that we save to disk. Note that these - // do not have a def-id as part of their identifier. - [] WorkProduct(WorkProductId), - // Represents different phases in the compiler. [] RegionScopeTree(DefId), [eval_always] Coherence, @@ -498,7 +494,7 @@ define_dep_nodes!( <'tcx> [] SuperPredicatesOfItem(DefId), [] TraitDefOfItem(DefId), [] AdtDefOfItem(DefId), - [] IsDefaultImpl(DefId), + [] IsAutoImpl(DefId), [] ImplTraitRef(DefId), [] ImplPolarity(DefId), [] ClosureKind(DefId), @@ -537,38 +533,19 @@ define_dep_nodes!( <'tcx> // The set of impls for a given trait. [] TraitImpls(DefId), - [] AllLocalTraitImpls, - - // Trait selection cache is a little funny. Given a trait - // reference like `Foo: SomeTrait<Bar>`, there could be - // arbitrarily many def-ids to map on in there (e.g., `Foo`, - // `SomeTrait`, `Bar`). We could have a vector of them, but it - // requires heap-allocation, and trait sel in general can be a - // surprisingly hot path. So instead we pick two def-ids: the - // trait def-id, and the first def-id in the input types. If there - // is no def-id in the input types, then we use the trait def-id - // again. So for example: - // - // - `i32: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }` - // - `u32: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }` - // - `Clone: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }` - // - `Vec<i32>: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Vec }` - // - `String: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: String }` - // - `Foo: Trait<Bar>` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }` - // - `Foo: Trait<i32>` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }` - // - `(Foo, Bar): Trait` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }` - // - `i32: Trait<Foo>` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }` - // - // You can see that we map many trait refs to the same - // trait-select node. This is not a problem, it just means - // imprecision in our dep-graph tracking. The important thing is - // that for any given trait-ref, we always map to the **same** - // trait-select node. + [input] AllLocalTraitImpls, + [anon] TraitSelect, [] ParamEnv(DefId), [] DescribeDef(DefId), - [] DefSpan(DefId), + + // FIXME(mw): DefSpans are not really inputs since they are derived from + // HIR. But at the moment HIR hashing still contains some hacks that allow + // to make type debuginfo to be source location independent. Declaring + // DefSpan an input makes sure that changes to these are always detected + // regardless of HIR hashing. + [input] DefSpan(DefId), [] LookupStability(DefId), [] LookupDeprecationEntry(DefId), [] ItemBodyNestedBodies(DefId), @@ -588,7 +565,7 @@ define_dep_nodes!( <'tcx> [eval_always] LintLevels, [] Specializes { impl1: DefId, impl2: DefId }, [input] InScopeTraits(DefIndex), - [] ModuleExports(DefId), + [input] ModuleExports(DefId), [] IsSanitizerRuntime(CrateNum), [] IsProfilerRuntime(CrateNum), [] GetPanicStrategy(CrateNum), @@ -598,9 +575,9 @@ define_dep_nodes!( <'tcx> [] NativeLibraries(CrateNum), [] PluginRegistrarFn(CrateNum), [] DeriveRegistrarFn(CrateNum), - [] CrateDisambiguator(CrateNum), - [] CrateHash(CrateNum), - [] OriginalCrateName(CrateNum), + [input] CrateDisambiguator(CrateNum), + [input] CrateHash(CrateNum), + [input] OriginalCrateName(CrateNum), [] ImplementationsOfTrait { krate: CrateNum, trait_id: DefId }, [] AllTraitImplementations(CrateNum), @@ -608,27 +585,27 @@ define_dep_nodes!( <'tcx> [] IsDllimportForeignItem(DefId), [] IsStaticallyIncludedForeignItem(DefId), [] NativeLibraryKind(DefId), - [] LinkArgs, + [input] LinkArgs, - [] NamedRegion(DefIndex), - [] IsLateBound(DefIndex), - [] ObjectLifetimeDefaults(DefIndex), + [input] NamedRegion(DefIndex), + [input] IsLateBound(DefIndex), + [input] ObjectLifetimeDefaults(DefIndex), [] Visibility(DefId), [] DepKind(CrateNum), - [] CrateName(CrateNum), + [input] CrateName(CrateNum), [] ItemChildren(DefId), [] ExternModStmtCnum(DefId), - [] GetLangItems, + [input] GetLangItems, [] DefinedLangItems(CrateNum), [] MissingLangItems(CrateNum), [] ExternConstBody(DefId), [] VisibleParentMap, [] MissingExternCrateItem(CrateNum), [] UsedCrateSource(CrateNum), - [] PostorderCnums, - [] HasCloneClosures(CrateNum), - [] HasCopyClosures(CrateNum), + [input] PostorderCnums, + [input] HasCloneClosures(CrateNum), + [input] HasCopyClosures(CrateNum), // This query is not expected to have inputs -- as a result, it's // not a good candidate for "replay" because it's essentially a @@ -638,11 +615,11 @@ define_dep_nodes!( <'tcx> // may save a bit of time. [anon] EraseRegionsTy { ty: Ty<'tcx> }, - [] Freevars(DefId), - [] MaybeUnusedTraitImport(DefId), + [input] Freevars(DefId), + [input] MaybeUnusedTraitImport(DefId), [] MaybeUnusedExternCrates, [] StabilityIndex, - [] AllCrateNums, + [input] AllCrateNums, [] ExportedSymbols(CrateNum), [eval_always] CollectAndPartitionTranslationItems, [] ExportName(DefId), @@ -650,7 +627,7 @@ define_dep_nodes!( <'tcx> [] IsTranslatedFunction(DefId), [] CodegenUnit(InternedString), [] CompileCodegenUnit(InternedString), - [] OutputFilenames, + [input] OutputFilenames, [anon] NormalizeTy, // We use this for most things when incr. comp. is turned off. [] Null, @@ -800,13 +777,6 @@ impl WorkProductId { hash: fingerprint } } - - pub fn to_dep_node(self) -> DepNode { - DepNode { - kind: DepKind::WorkProduct, - hash: self.hash, - } - } } impl_stable_hash_for!(struct ::dep_graph::WorkProductId { diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index ec709b301eb..1433fa81f33 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use errors::DiagnosticBuilder; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHashingContextProvider}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -44,25 +45,10 @@ pub struct DepGraph { } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub struct DepNodeIndex { - index: u32, -} - -impl Idx for DepNodeIndex { - fn new(idx: usize) -> Self { - debug_assert!((idx & 0xFFFF_FFFF) == idx); - DepNodeIndex { index: idx as u32 } - } - fn index(self) -> usize { - self.index as usize - } -} +newtype_index!(DepNodeIndex); impl DepNodeIndex { - const INVALID: DepNodeIndex = DepNodeIndex { - index: ::std::u32::MAX, - }; + const INVALID: DepNodeIndex = DepNodeIndex(::std::u32::MAX); } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] @@ -342,7 +328,12 @@ impl DepGraph { } pub fn fingerprint_of(&self, dep_node: &DepNode) -> Fingerprint { - self.fingerprints.borrow()[dep_node] + match self.fingerprints.borrow().get(dep_node) { + Some(&fingerprint) => fingerprint, + None => { + bug!("Could not find current fingerprint for {:?}", dep_node) + } + } } pub fn prev_fingerprint_of(&self, dep_node: &DepNode) -> Option<Fingerprint> { @@ -520,60 +511,67 @@ impl DepGraph { return None } None => { - if dep_dep_node.kind.is_input() { - // This input does not exist anymore. - debug_assert!(dep_dep_node.extract_def_id(tcx).is_none(), - "Encountered input {:?} without color", - dep_dep_node); - debug!("try_mark_green({:?}) - END - dependency {:?} \ - was deleted input", dep_node, dep_dep_node); - return None; + // We don't know the state of this dependency. If it isn't + // an input node, let's try to mark it green recursively. + if !dep_dep_node.kind.is_input() { + debug!("try_mark_green({:?}) --- state of dependency {:?} \ + is unknown, trying to mark it green", dep_node, + dep_dep_node); + + if let Some(node_index) = self.try_mark_green(tcx, dep_dep_node) { + debug!("try_mark_green({:?}) --- managed to MARK \ + dependency {:?} as green", dep_node, dep_dep_node); + current_deps.push(node_index); + continue; + } + } else if cfg!(debug_assertions) { + match dep_dep_node.kind { + DepKind::Hir | + DepKind::HirBody | + DepKind::CrateMetadata => { + assert!(dep_dep_node.extract_def_id(tcx).is_none(), + "Input {:?} should have been pre-allocated but wasn't.", + dep_dep_node); + } + _ => { + // For other kinds of inputs it's OK to be + // forced. + } + } } - debug!("try_mark_green({:?}) --- state of dependency {:?} \ - is unknown, trying to mark it green", dep_node, - dep_dep_node); - - // We don't know the state of this dependency. Let's try to - // mark it green. - if let Some(node_index) = self.try_mark_green(tcx, dep_dep_node) { - debug!("try_mark_green({:?}) --- managed to MARK \ - dependency {:?} as green", dep_node, dep_dep_node); - current_deps.push(node_index); - } else { - // We failed to mark it green, so we try to force the query. - debug!("try_mark_green({:?}) --- trying to force \ - dependency {:?}", dep_node, dep_dep_node); - if ::ty::maps::force_from_dep_node(tcx, dep_dep_node) { - let dep_dep_node_color = data.colors - .borrow() - .get(dep_dep_node) - .cloned(); - match dep_dep_node_color { - Some(DepNodeColor::Green(node_index)) => { - debug!("try_mark_green({:?}) --- managed to \ - FORCE dependency {:?} to green", - dep_node, dep_dep_node); - current_deps.push(node_index); - } - Some(DepNodeColor::Red) => { - debug!("try_mark_green({:?}) - END - \ - dependency {:?} was red after forcing", - dep_node, - dep_dep_node); - return None - } - None => { - bug!("try_mark_green() - Forcing the DepNode \ - should have set its color") - } + // We failed to mark it green, so we try to force the query. + debug!("try_mark_green({:?}) --- trying to force \ + dependency {:?}", dep_node, dep_dep_node); + if ::ty::maps::force_from_dep_node(tcx, dep_dep_node) { + let dep_dep_node_color = data.colors + .borrow() + .get(dep_dep_node) + .cloned(); + match dep_dep_node_color { + Some(DepNodeColor::Green(node_index)) => { + debug!("try_mark_green({:?}) --- managed to \ + FORCE dependency {:?} to green", + dep_node, dep_dep_node); + current_deps.push(node_index); + } + Some(DepNodeColor::Red) => { + debug!("try_mark_green({:?}) - END - \ + dependency {:?} was red after forcing", + dep_node, + dep_dep_node); + return None + } + None => { + bug!("try_mark_green() - Forcing the DepNode \ + should have set its color") } - } else { - // The DepNode could not be forced. - debug!("try_mark_green({:?}) - END - dependency {:?} \ - could not be forced", dep_node, dep_dep_node); - return None } + } else { + // The DepNode could not be forced. + debug!("try_mark_green({:?}) - END - dependency {:?} \ + could not be forced", dep_node, dep_dep_node); + return None } } } @@ -600,6 +598,24 @@ impl DepGraph { "DepGraph::try_mark_green() - Duplicate fingerprint \ insertion for {:?}", dep_node); + // ... emitting any stored diagnostic ... + { + let diagnostics = tcx.on_disk_query_result_cache + .load_diagnostics(prev_dep_node_index); + + if diagnostics.len() > 0 { + let handle = tcx.sess.diagnostic(); + + // Promote the previous diagnostics to the current session. + tcx.on_disk_query_result_cache + .store_diagnostics(dep_node_index, diagnostics.clone()); + + for diagnostic in diagnostics { + DiagnosticBuilder::new_diagnostic(handle, diagnostic).emit(); + } + } + } + // ... and finally storing a "Green" entry in the color map. let old_color = data.colors .borrow_mut() @@ -768,7 +784,30 @@ impl CurrentDepGraph { read_set: _, reads } = popped_node { - debug_assert_eq!(node, key); + assert_eq!(node, key); + + // If this is an input node, we expect that it either has no + // dependencies, or that it just depends on DepKind::CrateMetadata + // or DepKind::Krate. This happens for some "thin wrapper queries" + // like `crate_disambiguator` which sometimes have zero deps (for + // when called for LOCAL_CRATE) or they depend on a CrateMetadata + // node. + if cfg!(debug_assertions) { + if node.kind.is_input() && reads.len() > 0 && + // FIXME(mw): Special case for DefSpan until Spans are handled + // better in general. + node.kind != DepKind::DefSpan && + reads.iter().any(|&i| { + !(self.nodes[i].kind == DepKind::CrateMetadata || + self.nodes[i].kind == DepKind::Krate) + }) + { + bug!("Input node {:?} with unexpected reads: {:?}", + node, + reads.iter().map(|&i| self.nodes[i]).collect::<Vec<_>>()) + } + } + self.alloc_node(node, reads) } else { bug!("pop_task() - Expected regular task to be popped") @@ -789,6 +828,8 @@ impl CurrentDepGraph { read_set: _, reads } = popped_node { + debug_assert!(!kind.is_input()); + let mut fingerprint = self.anon_id_seed; let mut hasher = StableHasher::new(); diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index fe0212423f6..a472183698a 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -26,4 +26,4 @@ pub use self::prev::PreviousDepGraph; pub use self::query::DepGraphQuery; pub use self::safe::AssertDepGraphSafe; pub use self::safe::DepGraphSafe; -pub use self::serialized::SerializedDepGraph; +pub use self::serialized::{SerializedDepGraph, SerializedDepNodeIndex}; diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs index 69d23504cda..428f154c1b6 100644 --- a/src/librustc/hir/def_id.rs +++ b/src/librustc/hir/def_id.rs @@ -16,30 +16,23 @@ use serialize::{self, Encoder, Decoder}; use std::fmt; use std::u32; -#[derive(Clone, Copy, Eq, Ord, PartialOrd, PartialEq, Hash, Debug)] -pub struct CrateNum(u32); +newtype_index!(CrateNum + { + derive[Debug] + ENCODABLE = custom -impl Idx for CrateNum { - fn new(value: usize) -> Self { - assert!(value < (u32::MAX) as usize); - CrateNum(value as u32) - } - - fn index(self) -> usize { - self.0 as usize - } -} - -/// Item definitions in the currently-compiled crate would have the CrateNum -/// LOCAL_CRATE in their DefId. -pub const LOCAL_CRATE: CrateNum = CrateNum(0); + /// Item definitions in the currently-compiled crate would have the CrateNum + /// LOCAL_CRATE in their DefId. + const LOCAL_CRATE = 0, -/// Virtual crate for builtin macros -// FIXME(jseyfried): this is also used for custom derives until proc-macro crates get `CrateNum`s. -pub const BUILTIN_MACROS_CRATE: CrateNum = CrateNum(u32::MAX); + /// Virtual crate for builtin macros + // FIXME(jseyfried): this is also used for custom derives until proc-macro crates get + // `CrateNum`s. + const BUILTIN_MACROS_CRATE = u32::MAX, -/// A CrateNum value that indicates that something is wrong. -pub const INVALID_CRATE: CrateNum = CrateNum(u32::MAX - 1); + /// A CrateNum value that indicates that something is wrong. + const INVALID_CRATE = u32::MAX - 1, + }); impl CrateNum { pub fn new(x: usize) -> CrateNum { @@ -93,20 +86,17 @@ impl serialize::UseSpecializedDecodable for CrateNum { /// /// Since the DefIndex is mostly treated as an opaque ID, you probably /// don't have to care about these ranges. -#[derive(Clone, Eq, Ord, PartialOrd, PartialEq, RustcEncodable, - RustcDecodable, Hash, Copy)] -pub struct DefIndex(u32); +newtype_index!(DefIndex + { + DEBUG_FORMAT = custom, -impl Idx for DefIndex { - fn new(value: usize) -> Self { - assert!(value < (u32::MAX) as usize); - DefIndex(value as u32) - } + /// The start of the "high" range of DefIndexes. + const DEF_INDEX_HI_START = 1 << 31, - fn index(self) -> usize { - self.0 as usize - } -} + /// The crate root is always assigned index 0 by the AST Map code, + /// thanks to `NodeCollector::new`. + const CRATE_DEF_INDEX = 0, + }); impl fmt::Debug for DefIndex { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -119,12 +109,6 @@ impl fmt::Debug for DefIndex { impl DefIndex { #[inline] - pub fn new(x: usize) -> DefIndex { - assert!(x < (u32::MAX as usize)); - DefIndex(x as u32) - } - - #[inline] pub fn from_u32(x: u32) -> DefIndex { DefIndex(x) } @@ -162,13 +146,6 @@ impl DefIndex { } } -/// The start of the "high" range of DefIndexes. -const DEF_INDEX_HI_START: DefIndex = DefIndex(1 << 31); - -/// The crate root is always assigned index 0 by the AST Map code, -/// thanks to `NodeCollector::new`. -pub const CRATE_DEF_INDEX: DefIndex = DefIndex(0); - #[derive(Copy, Clone, Eq, PartialEq, Hash)] pub enum DefIndexAddressSpace { Low = 0, diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index ae25924ab42..c23a5fb1f7e 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -503,7 +503,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { // visit_enum_def() takes care of visiting the Item's NodeId visitor.visit_enum_def(enum_definition, type_parameters, item.id, item.span) } - ItemDefaultImpl(_, ref trait_ref) => { + ItemAutoImpl(_, ref trait_ref) => { visitor.visit_id(item.id); visitor.visit_trait_ref(trait_ref) } @@ -520,7 +520,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { visitor.visit_id(item.id); visitor.visit_variant_data(struct_definition, item.name, generics, item.id, item.span); } - ItemTrait(_, ref generics, ref bounds, ref trait_item_refs) => { + ItemTrait(.., ref generics, ref bounds, ref trait_item_refs) => { visitor.visit_id(item.id); visitor.visit_generics(generics); walk_list!(visitor, visit_ty_param_bound, bounds); diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 3834852cac5..ba89961adc6 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -96,7 +96,7 @@ pub struct LoweringContext<'a> { exported_macros: Vec<hir::MacroDef>, trait_impls: BTreeMap<DefId, Vec<NodeId>>, - trait_default_impl: BTreeMap<DefId, NodeId>, + trait_auto_impl: BTreeMap<DefId, NodeId>, is_generator: bool, @@ -146,7 +146,7 @@ pub fn lower_crate(sess: &Session, impl_items: BTreeMap::new(), bodies: BTreeMap::new(), trait_impls: BTreeMap::new(), - trait_default_impl: BTreeMap::new(), + trait_auto_impl: BTreeMap::new(), exported_macros: Vec::new(), catch_scopes: Vec::new(), loop_scopes: Vec::new(), @@ -198,7 +198,7 @@ impl<'a> LoweringContext<'a> { ItemKind::Union(_, ref generics) | ItemKind::Enum(_, ref generics) | ItemKind::Ty(_, ref generics) | - ItemKind::Trait(_, ref generics, ..) => { + ItemKind::Trait(_, _, ref generics, ..) => { let def_id = self.lctx.resolver.definitions().local_def_id(item.id); let count = generics.lifetimes.len(); self.lctx.type_def_lifetime_params.insert(def_id, count); @@ -284,7 +284,7 @@ impl<'a> LoweringContext<'a> { bodies: self.bodies, body_ids, trait_impls: self.trait_impls, - trait_default_impl: self.trait_default_impl, + trait_auto_impl: self.trait_auto_impl, } } @@ -838,7 +838,10 @@ impl<'a> LoweringContext<'a> { return n; } assert!(!def_id.is_local()); - let n = self.cstore.item_generics_cloned_untracked(def_id).regions.len(); + let n = self.cstore + .item_generics_cloned_untracked(def_id, self.sess) + .regions + .len(); self.type_def_lifetime_params.insert(def_id, n); n }); @@ -1479,14 +1482,14 @@ impl<'a> LoweringContext<'a> { let vdata = self.lower_variant_data(vdata); hir::ItemUnion(vdata, self.lower_generics(generics)) } - ItemKind::DefaultImpl(unsafety, ref trait_ref) => { + ItemKind::AutoImpl(unsafety, ref trait_ref) => { let trait_ref = self.lower_trait_ref(trait_ref); if let Def::Trait(def_id) = trait_ref.path.def { - self.trait_default_impl.insert(def_id, id); + self.trait_auto_impl.insert(def_id, id); } - hir::ItemDefaultImpl(self.lower_unsafety(unsafety), + hir::ItemAutoImpl(self.lower_unsafety(unsafety), trait_ref) } ItemKind::Impl(unsafety, @@ -1515,10 +1518,11 @@ impl<'a> LoweringContext<'a> { self.lower_ty(ty), new_impl_items) } - ItemKind::Trait(unsafety, ref generics, ref bounds, ref items) => { + ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref items) => { let bounds = self.lower_bounds(bounds); let items = items.iter().map(|item| self.lower_trait_item_ref(item)).collect(); - hir::ItemTrait(self.lower_unsafety(unsafety), + hir::ItemTrait(self.lower_is_auto(is_auto), + self.lower_unsafety(unsafety), self.lower_generics(generics), bounds, items) @@ -1741,6 +1745,13 @@ impl<'a> LoweringContext<'a> { } } + fn lower_is_auto(&mut self, a: IsAuto) -> hir::IsAuto { + match a { + IsAuto::Yes => hir::IsAuto::Yes, + IsAuto::No => hir::IsAuto::No, + } + } + fn lower_unsafety(&mut self, u: Unsafety) -> hir::Unsafety { match u { Unsafety::Unsafe => hir::Unsafety::Unsafe, diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index 2f4b62dcbf7..5c1e74dcf43 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -71,7 +71,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { impl_items: _, bodies: _, trait_impls: _, - trait_default_impl: _, + trait_auto_impl: _, body_ids: _, } = *krate; diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index 9d49776749b..d8590c1de94 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -104,7 +104,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { // Pick the def data. This need not be unique, but the more // information we encapsulate into let def_data = match i.node { - ItemKind::DefaultImpl(..) | ItemKind::Impl(..) => + ItemKind::AutoImpl(..) | ItemKind::Impl(..) => DefPathData::Impl, ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) | ItemKind::Trait(..) | ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::Ty(..) => diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index 6418df47952..b30cc0b09c9 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -19,7 +19,7 @@ use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE, DefIndexAddressSpace, CRATE_DEF_INDEX}; use ich::Fingerprint; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::indexed_vec::IndexVec; +use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc_data_structures::stable_hasher::StableHasher; use serialize::{Encodable, Decodable, Encoder, Decoder}; use session::CrateDisambiguator; diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index a23658664dc..453d30dde75 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -416,6 +416,12 @@ impl<'hir> Map<'hir> { /// if the node is a body owner, otherwise returns `None`. pub fn maybe_body_owned_by(&self, id: NodeId) -> Option<BodyId> { if let Some(entry) = self.find_entry(id) { + if self.dep_graph.is_fully_enabled() { + let hir_id_owner = self.node_to_hir_id(id).owner; + let def_path_hash = self.definitions.def_path_hash(hir_id_owner); + self.dep_graph.read(def_path_hash.to_dep_node(DepKind::HirBody)); + } + if let Some(body_id) = entry.associated_body() { // For item-like things and closures, the associated // body has its own distinct id, and that is returned @@ -474,16 +480,16 @@ impl<'hir> Map<'hir> { self.forest.krate.trait_impls.get(&trait_did).map_or(&[], |xs| &xs[..]) } - pub fn trait_default_impl(&self, trait_did: DefId) -> Option<NodeId> { + pub fn trait_auto_impl(&self, trait_did: DefId) -> Option<NodeId> { self.dep_graph.read(DepNode::new_no_params(DepKind::AllLocalTraitImpls)); // NB: intentionally bypass `self.forest.krate()` so that we // do not trigger a read of the whole krate here - self.forest.krate.trait_default_impl.get(&trait_did).cloned() + self.forest.krate.trait_auto_impl.get(&trait_did).cloned() } pub fn trait_is_auto(&self, trait_did: DefId) -> bool { - self.trait_default_impl(trait_did).is_some() + self.trait_auto_impl(trait_did).is_some() } /// Get the attributes on the krate. This is preferable to @@ -530,6 +536,12 @@ impl<'hir> Map<'hir> { /// from a node to the root of the ast (unless you get the same id back here /// that can happen if the id is not in the map itself or is just weird). pub fn get_parent_node(&self, id: NodeId) -> NodeId { + if self.dep_graph.is_fully_enabled() { + let hir_id_owner = self.node_to_hir_id(id).owner; + let def_path_hash = self.definitions.def_path_hash(hir_id_owner); + self.dep_graph.read(def_path_hash.to_dep_node(DepKind::HirBody)); + } + self.find_entry(id).and_then(|x| x.parent_node()).unwrap_or(id) } @@ -1140,7 +1152,7 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String { ItemUnion(..) => "union", ItemTrait(..) => "trait", ItemImpl(..) => "impl", - ItemDefaultImpl(..) => "default impl", + ItemAutoImpl(..) => "default impl", }; format!("{} {}{}", item_str, path_str(), id_str) } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index e23e2acefb7..c9b1d70e7b6 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -499,7 +499,7 @@ pub struct Crate { pub impl_items: BTreeMap<ImplItemId, ImplItem>, pub bodies: BTreeMap<BodyId, Body>, pub trait_impls: BTreeMap<DefId, Vec<NodeId>>, - pub trait_default_impl: BTreeMap<DefId, NodeId>, + pub trait_auto_impl: BTreeMap<DefId, NodeId>, /// A list of the body ids written out in the order in which they /// appear in the crate. If you're going to process all the bodies @@ -1500,6 +1500,13 @@ pub struct FnDecl { pub has_implicit_self: bool, } +/// Is the trait definition an auto trait? +#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum IsAuto { + Yes, + No +} + #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum Unsafety { Unsafe, @@ -1811,12 +1818,12 @@ pub enum Item_ { /// A union definition, e.g. `union Foo<A, B> {x: A, y: B}` ItemUnion(VariantData, Generics), /// Represents a Trait Declaration - ItemTrait(Unsafety, Generics, TyParamBounds, HirVec<TraitItemRef>), + ItemTrait(IsAuto, Unsafety, Generics, TyParamBounds, HirVec<TraitItemRef>), - // Default trait implementations + /// Auto trait implementations /// /// `impl Trait for .. {}` - ItemDefaultImpl(Unsafety, TraitRef), + ItemAutoImpl(Unsafety, TraitRef), /// An implementation, eg `impl<A> Trait for Foo { .. }` ItemImpl(Unsafety, ImplPolarity, @@ -1844,7 +1851,7 @@ impl Item_ { ItemUnion(..) => "union", ItemTrait(..) => "trait", ItemImpl(..) | - ItemDefaultImpl(..) => "item", + ItemAutoImpl(..) => "item", } } @@ -1864,7 +1871,7 @@ impl Item_ { ItemEnum(_, ref generics) | ItemStruct(_, ref generics) | ItemUnion(_, ref generics) | - ItemTrait(_, ref generics, _, _) | + ItemTrait(_, _, ref generics, _, _) | ItemImpl(_, _, _, ref generics, _, _, _)=> generics, _ => return None }) diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 24a0b5fcea9..7d0f26ba34d 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -660,7 +660,7 @@ impl<'a> State<'a> { self.head(&visibility_qualified(&item.vis, "union"))?; self.print_struct(struct_def, generics, item.name, item.span, true)?; } - hir::ItemDefaultImpl(unsafety, ref trait_ref) => { + hir::ItemAutoImpl(unsafety, ref trait_ref) => { self.head("")?; self.print_visibility(&item.vis)?; self.print_unsafety(unsafety)?; @@ -717,9 +717,10 @@ impl<'a> State<'a> { } self.bclose(item.span)?; } - hir::ItemTrait(unsafety, ref generics, ref bounds, ref trait_items) => { + hir::ItemTrait(is_auto, unsafety, ref generics, ref bounds, ref trait_items) => { self.head("")?; self.print_visibility(&item.vis)?; + self.print_is_auto(is_auto)?; self.print_unsafety(unsafety)?; self.word_nbsp("trait")?; self.print_name(item.name)?; @@ -1253,6 +1254,15 @@ impl<'a> State<'a> { Fixity::None => (prec + 1, prec + 1), }; + let left_prec = match (&lhs.node, op.node) { + // These cases need parens: `x as i32 < y` has the parser thinking that `i32 < y` is + // the beginning of a path type. It starts trying to parse `x as (i32 < y ...` instead + // of `(x as i32) < ...`. We need to convince it _not_ to do that. + (&hir::ExprCast { .. }, hir::BinOp_::BiLt) | + (&hir::ExprCast { .. }, hir::BinOp_::BiShl) => parser::PREC_FORCE_PAREN, + _ => left_prec, + }; + self.print_expr_maybe_paren(lhs, left_prec)?; self.s.space()?; self.word_space(op.node.as_str())?; @@ -2274,6 +2284,13 @@ impl<'a> State<'a> { hir::Unsafety::Unsafe => self.word_nbsp("unsafe"), } } + + pub fn print_is_auto(&mut self, s: hir::IsAuto) -> io::Result<()> { + match s { + hir::IsAuto::Yes => self.word_nbsp("auto"), + hir::IsAuto::No => Ok(()), + } + } } // Dup'ed from parse::classify, but adapted for the HIR. diff --git a/src/librustc/ich/fingerprint.rs b/src/librustc/ich/fingerprint.rs index f3bb3b38566..3d089d8e75f 100644 --- a/src/librustc/ich/fingerprint.rs +++ b/src/librustc/ich/fingerprint.rs @@ -30,6 +30,11 @@ impl Fingerprint { } #[inline] + pub fn as_value(&self) -> (u64, u64) { + (self.0, self.1) + } + + #[inline] pub fn combine(self, other: Fingerprint) -> Fingerprint { // See https://stackoverflow.com/a/27952689 on why this function is // implemented this way. diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs index d24344e4e21..f204d352842 100644 --- a/src/librustc/ich/hcx.rs +++ b/src/librustc/ich/hcx.rs @@ -227,6 +227,8 @@ impl<'gcx> StableHashingContext<'gcx> { match binop { hir::BiAdd | hir::BiSub | + hir::BiShl | + hir::BiShr | hir::BiMul => self.overflow_checks_enabled, hir::BiDiv | @@ -237,8 +239,6 @@ impl<'gcx> StableHashingContext<'gcx> { hir::BiBitXor | hir::BiBitAnd | hir::BiBitOr | - hir::BiShl | - hir::BiShr | hir::BiEq | hir::BiLt | hir::BiLe | diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 5a36c420462..6b78cd473be 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -356,33 +356,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Block { targeted_by_break, } = *self; - let non_item_stmts = || stmts.iter().filter(|stmt| { - match stmt.node { - hir::StmtDecl(ref decl, _) => { - match decl.node { - // If this is a declaration of a nested item, we don't - // want to leave any trace of it in the hash value, not - // even that it exists. Otherwise changing the position - // of nested items would invalidate the containing item - // even though that does not constitute a semantic - // change. - hir::DeclItem(_) => false, - hir::DeclLocal(_) => true - } - } - hir::StmtExpr(..) | - hir::StmtSemi(..) => true - } - }); - - let count = non_item_stmts().count(); - - count.hash_stable(hcx, hasher); - - for stmt in non_item_stmts() { - stmt.hash_stable(hcx, hasher); - } - + stmts.hash_stable(hcx, hasher); expr.hash_stable(hcx, hasher); rules.hash_stable(hcx, hasher); span.hash_stable(hcx, hasher); @@ -898,7 +872,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Item { hir::ItemForeignMod(..) | hir::ItemGlobalAsm(..) | hir::ItemMod(..) | - hir::ItemDefaultImpl(..) | + hir::ItemAutoImpl(..) | hir::ItemTrait(..) | hir::ItemImpl(..) | hir::ItemTy(..) | @@ -944,8 +918,8 @@ impl_stable_hash_for!(enum hir::Item_ { ItemEnum(enum_def, generics), ItemStruct(variant_data, generics), ItemUnion(variant_data, generics), - ItemTrait(unsafety, generics, bounds, item_refs), - ItemDefaultImpl(unsafety, trait_ref), + ItemTrait(is_auto, unsafety, generics, bounds, item_refs), + ItemAutoImpl(unsafety, trait_ref), ItemImpl(unsafety, impl_polarity, impl_defaultness, generics, trait_ref, ty, impl_item_refs) }); @@ -1126,6 +1100,10 @@ impl_stable_hash_for!(enum hir::Mutability { MutImmutable }); +impl_stable_hash_for!(enum hir::IsAuto { + Yes, + No +}); impl_stable_hash_for!(enum hir::Unsafety { Unsafe, diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index 4bda89690b7..05436201e7a 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -62,7 +62,8 @@ for mir::Terminator<'gcx> { mir::TerminatorKind::Drop { .. } | mir::TerminatorKind::DropAndReplace { .. } | mir::TerminatorKind::Yield { .. } | - mir::TerminatorKind::Call { .. } => false, + mir::TerminatorKind::Call { .. } | + mir::TerminatorKind::FalseEdges { .. } => false, }; if hash_spans_unconditionally { @@ -210,6 +211,12 @@ for mir::TerminatorKind<'gcx> { target.hash_stable(hcx, hasher); cleanup.hash_stable(hcx, hasher); } + mir::TerminatorKind::FalseEdges { ref real_target, ref imaginary_targets } => { + real_target.hash_stable(hcx, hasher); + for target in imaginary_targets { + target.hash_stable(hcx, hasher); + } + } } } } diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 799e790b85f..fea4e283db1 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -364,6 +364,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for FileMap { end_pos: _, ref lines, ref multibyte_chars, + ref non_narrow_chars, } = *self; name.hash_stable(hcx, hasher); @@ -389,6 +390,12 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for FileMap { for &char_pos in multibyte_chars.iter() { stable_multibyte_char(char_pos, start_pos).hash_stable(hcx, hasher); } + + let non_narrow_chars = non_narrow_chars.borrow(); + non_narrow_chars.len().hash_stable(hcx, hasher); + for &char_pos in non_narrow_chars.iter() { + stable_non_narrow_char(char_pos, start_pos).hash_stable(hcx, hasher); + } } } @@ -408,3 +415,12 @@ fn stable_multibyte_char(mbc: ::syntax_pos::MultiByteChar, (pos.0 - filemap_start.0, bytes as u32) } + +fn stable_non_narrow_char(swc: ::syntax_pos::NonNarrowChar, + filemap_start: ::syntax_pos::BytePos) + -> (u32, u32) { + let pos = swc.pos(); + let width = swc.width(); + + (pos.0 - filemap_start.0, width as u32) +} diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 48d3017f597..e7627b110fa 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -731,13 +731,13 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::TraitDef { def_id: _, unsafety, paren_sugar, - has_default_impl, + has_auto_impl, def_path_hash, } = *self; unsafety.hash_stable(hcx, hasher); paren_sugar.hash_stable(hcx, hasher); - has_default_impl.hash_stable(hcx, hasher); + has_auto_impl.hash_stable(hcx, hasher); def_path_hash.hash_stable(hcx, hasher); } } @@ -856,7 +856,7 @@ for traits::Vtable<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> { match self { &VtableImpl(ref table_impl) => table_impl.hash_stable(hcx, hasher), - &VtableDefaultImpl(ref table_def_impl) => table_def_impl.hash_stable(hcx, hasher), + &VtableAutoImpl(ref table_def_impl) => table_def_impl.hash_stable(hcx, hasher), &VtableParam(ref table_param) => table_param.hash_stable(hcx, hasher), &VtableObject(ref table_obj) => table_obj.hash_stable(hcx, hasher), &VtableBuiltin(ref table_builtin) => table_builtin.hash_stable(hcx, hasher), @@ -884,11 +884,11 @@ for traits::VtableImplData<'gcx, N> where N: HashStable<StableHashingContext<'gc } impl<'gcx, N> HashStable<StableHashingContext<'gcx>> -for traits::VtableDefaultImplData<N> where N: HashStable<StableHashingContext<'gcx>> { +for traits::VtableAutoImplData<N> where N: HashStable<StableHashingContext<'gcx>> { fn hash_stable<W: StableHasherResult>(&self, hcx: &mut StableHashingContext<'gcx>, hasher: &mut StableHasher<W>) { - let traits::VtableDefaultImplData { + let traits::VtableAutoImplData { trait_def_id, ref nested, } = *self; diff --git a/src/librustc/infer/README.md b/src/librustc/infer/README.md index b4075f69730..6c1478531f1 100644 --- a/src/librustc/infer/README.md +++ b/src/librustc/infer/README.md @@ -90,7 +90,7 @@ holds trivially because A==B. However, we have now lost some flexibility, because perhaps the user intended for A and B to end up as different types and not the same type. -Pictorally, what this does is to take two distinct variables with +Pictorially, what this does is to take two distinct variables with (hopefully not completely) distinct type ranges and produce one with the intersection. diff --git a/src/librustc/infer/error_reporting/different_lifetimes.rs b/src/librustc/infer/error_reporting/different_lifetimes.rs index ee30db26255..d7e0877d95c 100644 --- a/src/librustc/infer/error_reporting/different_lifetimes.rs +++ b/src/librustc/infer/error_reporting/different_lifetimes.rs @@ -21,25 +21,42 @@ use hir::intravisit::{self, Visitor, NestedVisitorMap}; use infer::error_reporting::util::AnonymousArgInfo; impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { - // This method prints the error message for lifetime errors when both the concerned regions - // are anonymous. - // Consider a case where we have - // fn foo(x: &mut Vec<&u8>, y: &u8) - // { x.push(y); }. - // The example gives - // fn foo(x: &mut Vec<&u8>, y: &u8) { - // --- --- these references are declared with different lifetimes... - // x.push(y); - // ^ ...but data from `y` flows into `x` here - // It has been extended for the case of structs too. - // Consider the example - // struct Ref<'a> { x: &'a u32 } - // fn foo(mut x: Vec<Ref>, y: Ref) { - // --- --- these structs are declared with different lifetimes... - // x.push(y); - // ^ ...but data from `y` flows into `x` here - // } - // It will later be extended to trait objects. + /// Print the error message for lifetime errors when both the concerned regions are anonymous. + /// + /// Consider a case where we have + /// + /// ```no_run + /// fn foo(x: &mut Vec<&u8>, y: &u8) { + /// x.push(y); + /// } + /// ``` + /// + /// The example gives + /// + /// ```text + /// fn foo(x: &mut Vec<&u8>, y: &u8) { + /// --- --- these references are declared with different lifetimes... + /// x.push(y); + /// ^ ...but data from `y` flows into `x` here + /// ``` + /// + /// It has been extended for the case of structs too. + /// + /// Consider the example + /// + /// ```no_run + /// struct Ref<'a> { x: &'a u32 } + /// ``` + /// + /// ```text + /// fn foo(mut x: Vec<Ref>, y: Ref) { + /// --- --- these structs are declared with different lifetimes... + /// x.push(y); + /// ^ ...but data from `y` flows into `x` here + /// } + /// ```` + /// + /// It will later be extended to trait objects. pub fn try_report_anon_anon_conflict(&self, error: &RegionResolutionError<'tcx>) -> bool { let (span, sub, sup) = match *error { ConcreteFailure(ref origin, sub, sup) => (origin.span(), sub, sup), diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 895894a0bb2..e9916bd77e7 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -66,7 +66,7 @@ use hir::map as hir_map; use hir::def_id::DefId; use middle::region; use traits::{ObligationCause, ObligationCauseCode}; -use ty::{self, Region, Ty, TyCtxt, TypeFoldable}; +use ty::{self, Region, Ty, TyCtxt, TypeFoldable, TypeVariants}; use ty::error::TypeError; use syntax::ast::DUMMY_NODE_ID; use syntax_pos::{Pos, Span}; @@ -262,6 +262,27 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { errors: &Vec<RegionResolutionError<'tcx>>) { debug!("report_region_errors(): {} errors to start", errors.len()); + if self.tcx.sess.opts.debugging_opts.nll { + for error in errors { + match *error { + RegionResolutionError::ConcreteFailure(ref origin, ..) | + RegionResolutionError::GenericBoundFailure(ref origin, ..) => { + self.tcx.sess.span_warn( + origin.span(), + "not reporting region error due to -Znll"); + } + + RegionResolutionError::SubSupConflict(ref rvo, ..) => { + self.tcx.sess.span_warn( + rvo.span(), + "not reporting region error due to -Znll"); + } + } + } + + return; + } + // try to pre-process the errors, which will group some of them // together into a `ProcessedErrors` group: let errors = self.process_errors(errors); @@ -673,14 +694,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { values: Option<ValuePairs<'tcx>>, terr: &TypeError<'tcx>) { - let (expected_found, is_simple_error) = match values { - None => (None, false), + let (expected_found, exp_found, is_simple_error) = match values { + None => (None, None, false), Some(values) => { - let is_simple_error = match values { + let (is_simple_error, exp_found) = match values { ValuePairs::Types(exp_found) => { - exp_found.expected.is_primitive() && exp_found.found.is_primitive() + let is_simple_err = exp_found.expected.is_primitive() + && exp_found.found.is_primitive(); + + (is_simple_err, Some(exp_found)) } - _ => false, + _ => (false, None), }; let vals = match self.values_str(&values) { Some((expected, found)) => Some((expected, found)), @@ -690,12 +714,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { return } }; - (vals, is_simple_error) + (vals, exp_found, is_simple_error) } }; let span = cause.span; + diag.span_label(span, terr.to_string()); + if let Some((sp, msg)) = secondary_span { + diag.span_label(sp, msg); + } + if let Some((expected, found)) = expected_found { match (terr, is_simple_error, expected == found) { (&TypeError::Sorts(ref values), false, true) => { @@ -704,18 +733,37 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { &format!(" ({})", values.expected.sort_string(self.tcx)), &format!(" ({})", values.found.sort_string(self.tcx))); } - (_, false, _) => { + (_, false, _) => { + if let Some(exp_found) = exp_found { + let (def_id, ret_ty) = match exp_found.found.sty { + TypeVariants::TyFnDef(def, _) => { + (Some(def), Some(self.tcx.fn_sig(def).output())) + } + _ => (None, None) + }; + + let exp_is_struct = match exp_found.expected.sty { + TypeVariants::TyAdt(def, _) => def.is_struct(), + _ => false + }; + + if let (Some(def_id), Some(ret_ty)) = (def_id, ret_ty) { + if exp_is_struct && exp_found.expected == ret_ty.0 { + let message = format!( + "did you mean `{}(/* fields */)`?", + self.tcx.item_path_str(def_id) + ); + diag.span_label(cause.span, message); + } + } + } + diag.note_expected_found(&"type", expected, found); } _ => (), } } - diag.span_label(span, terr.to_string()); - if let Some((sp, msg)) = secondary_span { - diag.span_label(sp, msg); - } - self.note_error_origin(diag, &cause); self.check_and_note_conflicting_crates(diag, terr, span); self.tcx.note_and_explain_type_err(diag, terr, span); diff --git a/src/librustc/infer/error_reporting/named_anon_conflict.rs b/src/librustc/infer/error_reporting/named_anon_conflict.rs index 80fb4ce8e03..6d3b9507840 100644 --- a/src/librustc/infer/error_reporting/named_anon_conflict.rs +++ b/src/librustc/infer/error_reporting/named_anon_conflict.rs @@ -16,18 +16,15 @@ use infer::region_inference::RegionResolutionError; use ty; impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { - // This method generates the error message for the case when - // the function arguments consist of a named region and an anonymous - // region and corresponds to `ConcreteFailure(..)` + /// When given a `ConcreteFailure` for a function with arguments containing a named region and + /// an anonymous region, emit an descriptive diagnostic error. pub fn try_report_named_anon_conflict(&self, error: &RegionResolutionError<'tcx>) -> bool { let (span, sub, sup) = match *error { ConcreteFailure(ref origin, sub, sup) => (origin.span(), sub, sup), _ => return false, // inapplicable }; - debug!("try_report_named_anon_conflict(sub={:?}, sup={:?})", - sub, - sup); + debug!("try_report_named_anon_conflict(sub={:?}, sup={:?})", sub, sup); // Determine whether the sub and sup consist of one named region ('a) // and one anonymous (elided) region. If so, find the parameter arg @@ -53,10 +50,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { }; debug!("try_report_named_anon_conflict: named = {:?}", named); - debug!("try_report_named_anon_conflict: anon_arg_info = {:?}", - anon_arg_info); - debug!("try_report_named_anon_conflict: region_info = {:?}", - region_info); + debug!("try_report_named_anon_conflict: anon_arg_info = {:?}", anon_arg_info); + debug!("try_report_named_anon_conflict: region_info = {:?}", region_info); let (arg, new_ty, br, is_first, scope_def_id, is_impl_item) = (anon_arg_info.arg, anon_arg_info.arg_ty, @@ -101,6 +96,5 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { .span_label(span, format!("lifetime `{}` required", named)) .emit(); return true; - } } diff --git a/src/librustc/infer/error_reporting/util.rs b/src/librustc/infer/error_reporting/util.rs index 47db3f1b792..6bcd98a7a68 100644 --- a/src/librustc/infer/error_reporting/util.rs +++ b/src/librustc/infer/error_reporting/util.rs @@ -221,6 +221,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { _ => false, } } + ty::ReEarlyBound(_) => true, _ => false, } } diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index 0d02420457e..6736751a5a2 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -155,7 +155,10 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { .filter(|&&r| !skol_resolution_map.contains_key(r)) .cloned() .next() - .expect("no representative region"); + .unwrap_or_else(|| { + bug!("no representative region for `{:?}` in `{:?}`", + skol, regions) + }); (skol, representative) }) diff --git a/src/librustc/infer/region_inference/graphviz.rs b/src/librustc/infer/region_inference/graphviz.rs index 5cf6aa350bd..49f57d9aef5 100644 --- a/src/librustc/infer/region_inference/graphviz.rs +++ b/src/librustc/infer/region_inference/graphviz.rs @@ -19,6 +19,7 @@ use graphviz as dot; use hir::def_id::DefIndex; +use rustc_data_structures::indexed_vec::Idx; use ty; use middle::free_region::RegionRelations; use middle::region; diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 0cec26d339c..498e1aa3520 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -46,6 +46,7 @@ #![feature(const_fn)] #![feature(core_intrinsics)] #![feature(i128_type)] +#![feature(inclusive_range_syntax)] #![cfg_attr(windows, feature(libc))] #![feature(macro_vis_matcher)] #![feature(never_type)] diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 52dcbfdedef..d648099d74d 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -33,11 +33,12 @@ pub use self::LintSource::*; use std::rc::Rc; -use errors::DiagnosticBuilder; +use errors::{DiagnosticBuilder, DiagnosticId}; use hir::def_id::{CrateNum, LOCAL_CRATE}; use hir::intravisit::{self, FnKind}; use hir; use session::Session; +#[cfg(stage0)] use std::ascii::AsciiExt; use std::hash; use syntax::ast; @@ -463,6 +464,8 @@ pub fn struct_lint_level<'a>(sess: &'a Session, } } + err.code(DiagnosticId::Lint(name)); + // Check for future incompatibility lints and issue a stronger warning. let lints = sess.lint_store.borrow(); if let Some(future_incompatible) = lints.future_incompatible(LintId::of(lint)) { diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index f4ba7890b17..628538b41c5 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -273,7 +273,7 @@ pub trait CrateStore { fn item_children_untracked(&self, did: DefId, sess: &Session) -> Vec<def::Export>; fn load_macro_untracked(&self, did: DefId, sess: &Session) -> LoadedMacro; fn extern_mod_stmt_cnum_untracked(&self, emod_id: ast::NodeId) -> Option<CrateNum>; - fn item_generics_cloned_untracked(&self, def: DefId) -> ty::Generics; + fn item_generics_cloned_untracked(&self, def: DefId, sess: &Session) -> ty::Generics; fn associated_item_cloned_untracked(&self, def: DefId) -> ty::AssociatedItem; fn postorder_cnums_untracked(&self) -> Vec<CrateNum>; @@ -327,7 +327,7 @@ impl CrateStore for DummyCrateStore { { bug!("crate_data_as_rc_any") } // item info fn visibility_untracked(&self, def: DefId) -> ty::Visibility { bug!("visibility") } - fn item_generics_cloned_untracked(&self, def: DefId) -> ty::Generics + fn item_generics_cloned_untracked(&self, def: DefId, sess: &Session) -> ty::Generics { bug!("item_generics_cloned") } // trait/impl-item info diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 259794e9d0e..a42ff543227 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -562,7 +562,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> { hir::ItemStruct(..) | hir::ItemUnion(..) | hir::ItemTrait(..) | - hir::ItemDefaultImpl(..) | + hir::ItemAutoImpl(..) | hir::ItemImpl(..) => self.tcx.sess.codemap().def_span(item.span), _ => item.span, }; diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index 49a241b86e0..3bcdc4f7e2c 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -182,6 +182,19 @@ impl<'tcx> FreeRegionMap<'tcx> { debug!("lub_free_regions(r_a={:?}, r_b={:?}) = {:?}", r_a, r_b, result); result } + + /// Returns all regions that are known to outlive `r_a`. For + /// example, in a function: + /// + /// ``` + /// fn foo<'a, 'b: 'a, 'c: 'b>() { .. } + /// ``` + /// + /// if `r_a` represents `'a`, this function would return `{'b, 'c}`. + pub fn regions_that_outlive<'a, 'gcx>(&self, r_a: Region<'tcx>) -> Vec<&Region<'tcx>> { + assert!(is_free(r_a)); + self.relation.greater_than(&r_a) + } } fn is_free(r: Region) -> bool { diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 679c4f17a6c..a38b37ff745 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -211,6 +211,7 @@ language_item_table! { CharImplItem, "char", char_impl; StrImplItem, "str", str_impl; SliceImplItem, "slice", slice_impl; + SliceU8ImplItem, "slice_u8", slice_u8_impl; ConstPtrImplItem, "const_ptr", const_ptr_impl; MutPtrImplItem, "mut_ptr", mut_ptr_impl; I8ImplItem, "i8", i8_impl; diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 2037bc01a5b..d5f26d1117c 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -270,7 +270,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { hir::ItemMod(..) | hir::ItemForeignMod(..) | hir::ItemImpl(..) | hir::ItemTrait(..) | hir::ItemStruct(..) | hir::ItemEnum(..) | - hir::ItemUnion(..) | hir::ItemDefaultImpl(..) | + hir::ItemUnion(..) | hir::ItemAutoImpl(..) | hir::ItemGlobalAsm(..) => {} } } diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index fa4ee7c0092..89707839144 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -158,8 +158,8 @@ pub struct BlockRemainder { newtype_index!(FirstStatementIndex { - DEBUG_NAME = "", - MAX = SCOPE_DATA_REMAINDER_MAX, + pub idx + MAX = SCOPE_DATA_REMAINDER_MAX }); impl From<ScopeData> for Scope { diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index ee0e580920e..ffd06ee8a2e 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -313,7 +313,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir::ItemExternCrate(_) | hir::ItemUse(..) | hir::ItemMod(..) | - hir::ItemDefaultImpl(..) | + hir::ItemAutoImpl(..) | hir::ItemForeignMod(..) | hir::ItemGlobalAsm(..) => { // These sorts of items have no lifetime parameters at all. @@ -332,7 +332,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir::ItemEnum(_, ref generics) | hir::ItemStruct(_, ref generics) | hir::ItemUnion(_, ref generics) | - hir::ItemTrait(_, ref generics, ..) | + hir::ItemTrait(_, _, ref generics, ..) | hir::ItemImpl(_, _, _, ref generics, ..) => { // These kinds of items have only early bound lifetime parameters. let mut index = if let hir::ItemTrait(..) = item.node { @@ -688,7 +688,7 @@ fn compute_object_lifetime_defaults(sess: &Session, hir_map: &Map) hir::ItemUnion(_, ref generics) | hir::ItemEnum(_, ref generics) | hir::ItemTy(_, ref generics) | - hir::ItemTrait(_, ref generics, ..) => { + hir::ItemTrait(_, _, ref generics, ..) => { let result = object_lifetime_defaults_for_item(hir_map, generics); // Debugging aid. @@ -844,7 +844,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { index += 1; // Self comes first. } match parent.node { - hir::ItemTrait(_, ref generics, ..) | + hir::ItemTrait(_, _, ref generics, ..) | hir::ItemImpl(_, _, _, ref generics, ..) => { index += (generics.lifetimes.len() + generics.ty_params.len()) as u32; } @@ -1001,8 +1001,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { &map.object_lifetime_defaults[&id] } else { let cstore = self.cstore; + let sess = self.sess; self.xcrate_object_lifetime_defaults.entry(def_id).or_insert_with(|| { - cstore.item_generics_cloned_untracked(def_id).types.into_iter().map(|def| { + cstore.item_generics_cloned_untracked(def_id, sess) + .types + .into_iter() + .map(|def| { def.object_lifetime_default }).collect() }) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index f5a3c1989cf..2fc27de137f 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -417,7 +417,7 @@ pub enum BorrowKind { newtype_index!(Local { - DEBUG_NAME = "_", + DEBUG_FORMAT = "_{}", const RETURN_POINTER = 0, }); @@ -553,7 +553,7 @@ pub struct UpvarDecl { /////////////////////////////////////////////////////////////////////////// // BasicBlock -newtype_index!(BasicBlock { DEBUG_NAME = "bb" }); +newtype_index!(BasicBlock { DEBUG_FORMAT = "bb{}" }); /////////////////////////////////////////////////////////////////////////// // BasicBlockData and Terminator @@ -682,6 +682,11 @@ pub enum TerminatorKind<'tcx> { /// Indicates the end of the dropping of a generator GeneratorDrop, + + FalseEdges { + real_target: BasicBlock, + imaginary_targets: Vec<BasicBlock> + }, } impl<'tcx> Terminator<'tcx> { @@ -731,6 +736,11 @@ impl<'tcx> TerminatorKind<'tcx> { } Assert { target, cleanup: Some(unwind), .. } => vec![target, unwind].into_cow(), Assert { ref target, .. } => slice::ref_slice(target).into_cow(), + FalseEdges { ref real_target, ref imaginary_targets } => { + let mut s = vec![*real_target]; + s.extend_from_slice(imaginary_targets); + s.into_cow() + } } } @@ -757,7 +767,12 @@ impl<'tcx> TerminatorKind<'tcx> { vec![target] } Assert { ref mut target, cleanup: Some(ref mut unwind), .. } => vec![target, unwind], - Assert { ref mut target, .. } => vec![target] + Assert { ref mut target, .. } => vec![target], + FalseEdges { ref mut real_target, ref mut imaginary_targets } => { + let mut s = vec![real_target]; + s.extend(imaginary_targets.iter_mut()); + s + } } } } @@ -874,7 +889,8 @@ impl<'tcx> TerminatorKind<'tcx> { } write!(fmt, ")") - } + }, + FalseEdges { .. } => write!(fmt, "falseEdges") } } @@ -910,7 +926,12 @@ impl<'tcx> TerminatorKind<'tcx> { } Assert { cleanup: None, .. } => vec!["".into()], Assert { .. } => - vec!["success".into_cow(), "unwind".into_cow()] + vec!["success".into_cow(), "unwind".into_cow()], + FalseEdges { ref imaginary_targets, .. } => { + let mut l = vec!["real".into()]; + l.resize(imaginary_targets.len() + 1, "imaginary".into()); + l + } } } } @@ -1135,7 +1156,7 @@ pub type LvalueProjection<'tcx> = Projection<'tcx, Lvalue<'tcx>, Local, Ty<'tcx> /// and the index is a local. pub type LvalueElem<'tcx> = ProjectionElem<'tcx, Local, Ty<'tcx>>; -newtype_index!(Field { DEBUG_NAME = "field" }); +newtype_index!(Field { DEBUG_FORMAT = "field[{}]" }); impl<'tcx> Lvalue<'tcx> { pub fn field(self, f: Field, ty: Ty<'tcx>) -> Lvalue<'tcx> { @@ -1202,7 +1223,7 @@ impl<'tcx> Debug for Lvalue<'tcx> { newtype_index!(VisibilityScope { - DEBUG_NAME = "scope", + DEBUG_FORMAT = "scope[{}]", const ARGUMENT_VISIBILITY_SCOPE = 0, }); @@ -1529,7 +1550,8 @@ pub struct Constant<'tcx> { pub literal: Literal<'tcx>, } -newtype_index!(Promoted { DEBUG_NAME = "promoted" }); +newtype_index!(Promoted { DEBUG_FORMAT = "promoted[{}]" }); + #[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub enum Literal<'tcx> { @@ -1637,6 +1659,14 @@ impl fmt::Debug for Location { } impl Location { + /// Returns the location immediately after this one within the enclosing block. + /// + /// Note that if this location represents a terminator, then the + /// resulting location would be out of bounds and invalid. + pub fn successor_within_block(&self) -> Location { + Location { block: self.block, statement_index: self.statement_index + 1 } + } + pub fn dominates(&self, other: &Location, dominators: &Dominators<BasicBlock>) -> bool { if self.block == other.block { self.statement_index <= other.statement_index @@ -1870,6 +1900,8 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { Resume => Resume, Return => Return, Unreachable => Unreachable, + FalseEdges { real_target, ref imaginary_targets } => + FalseEdges { real_target, imaginary_targets: imaginary_targets.clone() } }; Terminator { source_info: self.source_info, @@ -1909,7 +1941,8 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { Resume | Return | GeneratorDrop | - Unreachable => false + Unreachable | + FalseEdges { .. } => false } } } diff --git a/src/librustc/mir/transform.rs b/src/librustc/mir/transform.rs index f29405e6650..6c90a5f38d0 100644 --- a/src/librustc/mir/transform.rs +++ b/src/librustc/mir/transform.rs @@ -39,13 +39,13 @@ pub enum MirSource { GeneratorDrop(NodeId), } -impl<'a, 'tcx> MirSource { - pub fn from_local_def_id(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> MirSource { +impl<'a, 'gcx, 'tcx> MirSource { + pub fn from_local_def_id(tcx: TyCtxt<'a, 'gcx, 'tcx>, def_id: DefId) -> MirSource { let id = tcx.hir.as_local_node_id(def_id).expect("mir source requires local def-id"); Self::from_node(tcx, id) } - pub fn from_node(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: NodeId) -> MirSource { + pub fn from_node(tcx: TyCtxt<'a, 'gcx, 'tcx>, id: NodeId) -> MirSource { use hir::*; // Handle constants in enum discriminants, types, and repeat expressions. diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 63652980f9b..00863abc84d 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -209,7 +209,7 @@ macro_rules! make_mir_visitor { fn visit_ty(&mut self, ty: & $($mutability)* Ty<'tcx>, - _: Lookup) { + _: TyContext) { self.super_ty(ty); } @@ -256,8 +256,9 @@ macro_rules! make_mir_visitor { } fn visit_local_decl(&mut self, + local: Local, local_decl: & $($mutability)* LocalDecl<'tcx>) { - self.super_local_decl(local_decl); + self.super_local_decl(local, local_decl); } fn visit_local(&mut self, @@ -291,14 +292,14 @@ macro_rules! make_mir_visitor { self.visit_visibility_scope_data(scope); } - let lookup = Lookup::Src(SourceInfo { + let lookup = TyContext::SourceInfo(SourceInfo { span: mir.span, scope: ARGUMENT_VISIBILITY_SCOPE, }); self.visit_ty(&$($mutability)* mir.return_ty, lookup); - for local_decl in &$($mutability)* mir.local_decls { - self.visit_local_decl(local_decl); + for local in mir.local_decls.indices() { + self.visit_local_decl(local, & $($mutability)* mir.local_decls[local]); } self.visit_span(&$($mutability)* mir.span); @@ -359,7 +360,8 @@ macro_rules! make_mir_visitor { for operand in lvalues { self.visit_lvalue(& $($mutability)* operand.lval, LvalueContext::Validate, location); - self.visit_ty(& $($mutability)* operand.ty, Lookup::Loc(location)); + self.visit_ty(& $($mutability)* operand.ty, + TyContext::Location(location)); } } StatementKind::SetDiscriminant{ ref $($mutability)* lvalue, .. } => { @@ -421,7 +423,7 @@ macro_rules! make_mir_visitor { ref values, ref targets } => { self.visit_operand(discr, source_location); - self.visit_ty(switch_ty, Lookup::Loc(source_location)); + self.visit_ty(switch_ty, TyContext::Location(source_location)); for value in &values[..] { self.visit_const_int(value, source_location); } @@ -486,8 +488,15 @@ macro_rules! make_mir_visitor { self.visit_operand(value, source_location); self.visit_branch(block, resume); drop.map(|t| self.visit_branch(block, t)); + } + TerminatorKind::FalseEdges { real_target, ref imaginary_targets } => { + self.visit_branch(block, real_target); + for target in imaginary_targets { + self.visit_branch(block, *target); + } + } } } @@ -538,7 +547,7 @@ macro_rules! make_mir_visitor { ref $($mutability)* operand, ref $($mutability)* ty) => { self.visit_operand(operand, location); - self.visit_ty(ty, Lookup::Loc(location)); + self.visit_ty(ty, TyContext::Location(location)); } Rvalue::BinaryOp(_bin_op, @@ -560,7 +569,7 @@ macro_rules! make_mir_visitor { } Rvalue::NullaryOp(_op, ref $($mutability)* ty) => { - self.visit_ty(ty, Lookup::Loc(location)); + self.visit_ty(ty, TyContext::Location(location)); } Rvalue::Aggregate(ref $($mutability)* kind, @@ -568,7 +577,7 @@ macro_rules! make_mir_visitor { let kind = &$($mutability)* **kind; match *kind { AggregateKind::Array(ref $($mutability)* ty) => { - self.visit_ty(ty, Lookup::Loc(location)); + self.visit_ty(ty, TyContext::Location(location)); } AggregateKind::Tuple => { } @@ -638,7 +647,7 @@ macro_rules! make_mir_visitor { ref $($mutability)* ty, } = *static_; self.visit_def_id(def_id, location); - self.visit_ty(ty, Lookup::Loc(location)); + self.visit_ty(ty, TyContext::Location(location)); } fn super_projection(&mut self, @@ -668,7 +677,7 @@ macro_rules! make_mir_visitor { ProjectionElem::Subslice { from: _, to: _ } => { } ProjectionElem::Field(_field, ref $($mutability)* ty) => { - self.visit_ty(ty, Lookup::Loc(location)); + self.visit_ty(ty, TyContext::Location(location)); } ProjectionElem::Index(ref $($mutability)* local) => { self.visit_local(local, LvalueContext::Consume, location); @@ -683,6 +692,7 @@ macro_rules! make_mir_visitor { } fn super_local_decl(&mut self, + local: Local, local_decl: & $($mutability)* LocalDecl<'tcx>) { let LocalDecl { mutability: _, @@ -694,7 +704,10 @@ macro_rules! make_mir_visitor { is_user_variable: _, } = *local_decl; - self.visit_ty(ty, Lookup::Src(*source_info)); + self.visit_ty(ty, TyContext::LocalDecl { + local, + source_info: *source_info, + }); self.visit_source_info(source_info); self.visit_visibility_scope(lexical_scope); } @@ -718,7 +731,7 @@ macro_rules! make_mir_visitor { } = *constant; self.visit_span(span); - self.visit_ty(ty, Lookup::Loc(location)); + self.visit_ty(ty, TyContext::Location(location)); self.visit_literal(literal, location); } @@ -796,10 +809,21 @@ macro_rules! make_mir_visitor { make_mir_visitor!(Visitor,); make_mir_visitor!(MutVisitor,mut); +/// Extra information passed to `visit_ty` and friends to give context +/// about where the type etc appears. #[derive(Copy, Clone, Debug)] -pub enum Lookup { - Loc(Location), - Src(SourceInfo), +pub enum TyContext { + LocalDecl { + /// The index of the local variable we are visiting. + local: Local, + + /// The source location where this local variable was declared. + source_info: SourceInfo, + }, + + Location(Location), + + SourceInfo(SourceInfo), } #[derive(Copy, Clone, Debug, PartialEq, Eq)] diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 0f8312abc3f..ffb8144e07e 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -138,6 +138,34 @@ impl OutputType { } } + fn from_shorthand(shorthand: &str) -> Option<Self> { + Some(match shorthand { + "asm" => OutputType::Assembly, + "llvm-ir" => OutputType::LlvmAssembly, + "mir" => OutputType::Mir, + "llvm-bc" => OutputType::Bitcode, + "obj" => OutputType::Object, + "metadata" => OutputType::Metadata, + "link" => OutputType::Exe, + "dep-info" => OutputType::DepInfo, + _ => return None, + }) + } + + fn shorthands_display() -> String { + format!( + "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`", + OutputType::Bitcode.shorthand(), + OutputType::Assembly.shorthand(), + OutputType::LlvmAssembly.shorthand(), + OutputType::Mir.shorthand(), + OutputType::Object.shorthand(), + OutputType::Metadata.shorthand(), + OutputType::Exe.shorthand(), + OutputType::DepInfo.shorthand(), + ) + } + pub fn extension(&self) -> &'static str { match *self { OutputType::Bitcode => "bc", @@ -155,7 +183,7 @@ impl OutputType { #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum ErrorOutputType { HumanReadable(ColorConfig), - Json, + Json(bool), Short(ColorConfig), } @@ -368,6 +396,7 @@ pub enum PrintRequest { TargetFeatures, RelocationModels, CodeModels, + TlsModels, TargetSpec, NativeStaticLibs, } @@ -410,7 +439,7 @@ impl_stable_hash_for!(struct self::OutputFilenames { outputs }); -pub const RUST_CGU_EXT: &str = "rust-cgu"; +pub const RUST_CGU_EXT: &str = "rcgu"; impl OutputFilenames { pub fn path(&self, flavor: OutputType) -> PathBuf { @@ -1017,6 +1046,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "print high-level information about incremental reuse (or the lack thereof)"), incremental_dump_hash: bool = (false, parse_bool, [UNTRACKED], "dump hash information in textual format to stdout"), + incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED], + "verify incr. comp. hashes of green query instances"), dump_dep_graph: bool = (false, parse_bool, [UNTRACKED], "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv)"), query_dep_graph: bool = (false, parse_bool, [UNTRACKED], @@ -1104,6 +1135,11 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "enable ThinLTO when possible"), inline_in_all_cgus: Option<bool> = (None, parse_opt_bool, [TRACKED], "control whether #[inline] functions are in all cgus"), + tls_model: Option<String> = (None, parse_opt_string, [TRACKED], + "choose the TLS model to use (rustc --print tls-models for details)"), + saturating_float_casts: bool = (false, parse_bool, [TRACKED], + "make casts between integers and floats safe: clip out-of-range inputs to the min/max \ + integer or to infinity respectively, and turn `NAN` into 0 when casting to integers"), } pub fn default_lib_output() -> CrateType { @@ -1330,7 +1366,7 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> { print on stdout", "[crate-name|file-names|sysroot|cfg|target-list|\ target-cpus|target-features|relocation-models|\ - code-models|target-spec-json|native-static-libs]"), + code-models|tls-models|target-spec-json|native-static-libs]"), opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"), opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"), opt::opt_s("o", "", "Write output to <filename>", "FILENAME"), @@ -1433,7 +1469,8 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) let error_format = if matches.opts_present(&["error-format".to_owned()]) { match matches.opt_str("error-format").as_ref().map(|s| &s[..]) { Some("human") => ErrorOutputType::HumanReadable(color), - Some("json") => ErrorOutputType::Json, + Some("json") => ErrorOutputType::Json(false), + Some("pretty-json") => ErrorOutputType::Json(true), Some("short") => ErrorOutputType::Short(color), None => ErrorOutputType::HumanReadable(color), @@ -1472,26 +1509,25 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) }) }); - let debugging_opts = build_debugging_options(matches, error_format); + let mut debugging_opts = build_debugging_options(matches, error_format); + + if !debugging_opts.unstable_options && error_format == ErrorOutputType::Json(true) { + early_error(ErrorOutputType::Json(false), + "--error-format=pretty-json is unstable"); + } let mut output_types = BTreeMap::new(); if !debugging_opts.parse_only { for list in matches.opt_strs("emit") { for output_type in list.split(',') { let mut parts = output_type.splitn(2, '='); - let output_type = match parts.next().unwrap() { - "asm" => OutputType::Assembly, - "llvm-ir" => OutputType::LlvmAssembly, - "mir" => OutputType::Mir, - "llvm-bc" => OutputType::Bitcode, - "obj" => OutputType::Object, - "metadata" => OutputType::Metadata, - "link" => OutputType::Exe, - "dep-info" => OutputType::DepInfo, - part => { - early_error(error_format, &format!("unknown emission type: `{}`", - part)) - } + let shorthand = parts.next().unwrap(); + let output_type = match OutputType::from_shorthand(shorthand) { + Some(output_type) => output_type, + None => early_error(error_format, &format!( + "unknown emission type: `{}` - expected one of: {}", + shorthand, OutputType::shorthands_display(), + )), }; let path = parts.next().map(PathBuf::from); output_types.insert(output_type, path); @@ -1573,6 +1609,10 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) prints.push(PrintRequest::CodeModels); cg.code_model = None; } + if debugging_opts.tls_model.as_ref().map_or(false, |s| s == "help") { + prints.push(PrintRequest::TlsModels); + debugging_opts.tls_model = None; + } let cg = cg; @@ -1672,6 +1712,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) "target-features" => PrintRequest::TargetFeatures, "relocation-models" => PrintRequest::RelocationModels, "code-models" => PrintRequest::CodeModels, + "tls-models" => PrintRequest::TlsModels, "native-static-libs" => PrintRequest::NativeStaticLibs, "target-spec-json" => { if nightly_options::is_unstable_enabled(matches) { @@ -2254,46 +2295,46 @@ mod tests { let mut v5 = super::basic_options(); // Reference - v1.search_paths.add_path("native=abc", super::ErrorOutputType::Json); - v1.search_paths.add_path("crate=def", super::ErrorOutputType::Json); - v1.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json); - v1.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json); - v1.search_paths.add_path("all=mno", super::ErrorOutputType::Json); + v1.search_paths.add_path("native=abc", super::ErrorOutputType::Json(false)); + v1.search_paths.add_path("crate=def", super::ErrorOutputType::Json(false)); + v1.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json(false)); + v1.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json(false)); + v1.search_paths.add_path("all=mno", super::ErrorOutputType::Json(false)); // Native changed - v2.search_paths.add_path("native=XXX", super::ErrorOutputType::Json); - v2.search_paths.add_path("crate=def", super::ErrorOutputType::Json); - v2.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json); - v2.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json); - v2.search_paths.add_path("all=mno", super::ErrorOutputType::Json); + v2.search_paths.add_path("native=XXX", super::ErrorOutputType::Json(false)); + v2.search_paths.add_path("crate=def", super::ErrorOutputType::Json(false)); + v2.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json(false)); + v2.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json(false)); + v2.search_paths.add_path("all=mno", super::ErrorOutputType::Json(false)); // Crate changed - v2.search_paths.add_path("native=abc", super::ErrorOutputType::Json); - v2.search_paths.add_path("crate=XXX", super::ErrorOutputType::Json); - v2.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json); - v2.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json); - v2.search_paths.add_path("all=mno", super::ErrorOutputType::Json); + v2.search_paths.add_path("native=abc", super::ErrorOutputType::Json(false)); + v2.search_paths.add_path("crate=XXX", super::ErrorOutputType::Json(false)); + v2.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json(false)); + v2.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json(false)); + v2.search_paths.add_path("all=mno", super::ErrorOutputType::Json(false)); // Dependency changed - v3.search_paths.add_path("native=abc", super::ErrorOutputType::Json); - v3.search_paths.add_path("crate=def", super::ErrorOutputType::Json); - v3.search_paths.add_path("dependency=XXX", super::ErrorOutputType::Json); - v3.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json); - v3.search_paths.add_path("all=mno", super::ErrorOutputType::Json); + v3.search_paths.add_path("native=abc", super::ErrorOutputType::Json(false)); + v3.search_paths.add_path("crate=def", super::ErrorOutputType::Json(false)); + v3.search_paths.add_path("dependency=XXX", super::ErrorOutputType::Json(false)); + v3.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json(false)); + v3.search_paths.add_path("all=mno", super::ErrorOutputType::Json(false)); // Framework changed - v4.search_paths.add_path("native=abc", super::ErrorOutputType::Json); - v4.search_paths.add_path("crate=def", super::ErrorOutputType::Json); - v4.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json); - v4.search_paths.add_path("framework=XXX", super::ErrorOutputType::Json); - v4.search_paths.add_path("all=mno", super::ErrorOutputType::Json); + v4.search_paths.add_path("native=abc", super::ErrorOutputType::Json(false)); + v4.search_paths.add_path("crate=def", super::ErrorOutputType::Json(false)); + v4.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json(false)); + v4.search_paths.add_path("framework=XXX", super::ErrorOutputType::Json(false)); + v4.search_paths.add_path("all=mno", super::ErrorOutputType::Json(false)); // All changed - v5.search_paths.add_path("native=abc", super::ErrorOutputType::Json); - v5.search_paths.add_path("crate=def", super::ErrorOutputType::Json); - v5.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json); - v5.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json); - v5.search_paths.add_path("all=XXX", super::ErrorOutputType::Json); + v5.search_paths.add_path("native=abc", super::ErrorOutputType::Json(false)); + v5.search_paths.add_path("crate=def", super::ErrorOutputType::Json(false)); + v5.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json(false)); + v5.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json(false)); + v5.search_paths.add_path("all=XXX", super::ErrorOutputType::Json(false)); assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash()); assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash()); @@ -2316,29 +2357,29 @@ mod tests { let mut v4 = super::basic_options(); // Reference - v1.search_paths.add_path("native=abc", super::ErrorOutputType::Json); - v1.search_paths.add_path("crate=def", super::ErrorOutputType::Json); - v1.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json); - v1.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json); - v1.search_paths.add_path("all=mno", super::ErrorOutputType::Json); - - v2.search_paths.add_path("native=abc", super::ErrorOutputType::Json); - v2.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json); - v2.search_paths.add_path("crate=def", super::ErrorOutputType::Json); - v2.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json); - v2.search_paths.add_path("all=mno", super::ErrorOutputType::Json); - - v3.search_paths.add_path("crate=def", super::ErrorOutputType::Json); - v3.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json); - v3.search_paths.add_path("native=abc", super::ErrorOutputType::Json); - v3.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json); - v3.search_paths.add_path("all=mno", super::ErrorOutputType::Json); - - v4.search_paths.add_path("all=mno", super::ErrorOutputType::Json); - v4.search_paths.add_path("native=abc", super::ErrorOutputType::Json); - v4.search_paths.add_path("crate=def", super::ErrorOutputType::Json); - v4.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json); - v4.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json); + v1.search_paths.add_path("native=abc", super::ErrorOutputType::Json(false)); + v1.search_paths.add_path("crate=def", super::ErrorOutputType::Json(false)); + v1.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json(false)); + v1.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json(false)); + v1.search_paths.add_path("all=mno", super::ErrorOutputType::Json(false)); + + v2.search_paths.add_path("native=abc", super::ErrorOutputType::Json(false)); + v2.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json(false)); + v2.search_paths.add_path("crate=def", super::ErrorOutputType::Json(false)); + v2.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json(false)); + v2.search_paths.add_path("all=mno", super::ErrorOutputType::Json(false)); + + v3.search_paths.add_path("crate=def", super::ErrorOutputType::Json(false)); + v3.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json(false)); + v3.search_paths.add_path("native=abc", super::ErrorOutputType::Json(false)); + v3.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json(false)); + v3.search_paths.add_path("all=mno", super::ErrorOutputType::Json(false)); + + v4.search_paths.add_path("all=mno", super::ErrorOutputType::Json(false)); + v4.search_paths.add_path("native=abc", super::ErrorOutputType::Json(false)); + v4.search_paths.add_path("crate=def", super::ErrorOutputType::Json(false)); + v4.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json(false)); + v4.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json(false)); assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash()); assert!(v1.dep_tracking_hash() == v3.dep_tracking_hash()); @@ -2515,6 +2556,10 @@ mod tests { assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); opts = reference.clone(); + opts.debugging_opts.tls_model = Some(String::from("tls model")); + assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); + + opts = reference.clone(); opts.cg.metadata = vec![String::from("A"), String::from("B")]; assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index be35cc8e4a1..39cf50787ef 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -24,7 +24,7 @@ use util::nodemap::{FxHashMap, FxHashSet}; use util::common::{duration_to_secs_str, ErrorReported}; use syntax::ast::NodeId; -use errors::{self, DiagnosticBuilder}; +use errors::{self, DiagnosticBuilder, DiagnosticId}; use errors::emitter::{Emitter, EmitterWriter}; use syntax::json::JsonEmitter; use syntax::feature_gate; @@ -187,7 +187,7 @@ impl Session { pub fn struct_span_warn_with_code<'a, S: Into<MultiSpan>>(&'a self, sp: S, msg: &str, - code: &str) + code: DiagnosticId) -> DiagnosticBuilder<'a> { self.diagnostic().struct_span_warn_with_code(sp, msg, code) } @@ -203,7 +203,7 @@ impl Session { pub fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self, sp: S, msg: &str, - code: &str) + code: DiagnosticId) -> DiagnosticBuilder<'a> { self.diagnostic().struct_span_err_with_code(sp, msg, code) } @@ -211,7 +211,11 @@ impl Session { pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> { self.diagnostic().struct_err(msg) } - pub fn struct_err_with_code<'a>(&'a self, msg: &str, code: &str) -> DiagnosticBuilder<'a> { + pub fn struct_err_with_code<'a>( + &'a self, + msg: &str, + code: DiagnosticId, + ) -> DiagnosticBuilder<'a> { self.diagnostic().struct_err_with_code(msg, code) } pub fn struct_span_fatal<'a, S: Into<MultiSpan>>(&'a self, @@ -223,7 +227,7 @@ impl Session { pub fn struct_span_fatal_with_code<'a, S: Into<MultiSpan>>(&'a self, sp: S, msg: &str, - code: &str) + code: DiagnosticId) -> DiagnosticBuilder<'a> { self.diagnostic().struct_span_fatal_with_code(sp, msg, code) } @@ -234,7 +238,12 @@ impl Session { pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! { panic!(self.diagnostic().span_fatal(sp, msg)) } - pub fn span_fatal_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) -> ! { + pub fn span_fatal_with_code<S: Into<MultiSpan>>( + &self, + sp: S, + msg: &str, + code: DiagnosticId, + ) -> ! { panic!(self.diagnostic().span_fatal_with_code(sp, msg, code)) } pub fn fatal(&self, msg: &str) -> ! { @@ -250,7 +259,7 @@ impl Session { pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) { self.diagnostic().span_err(sp, msg) } - pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) { + pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) { self.diagnostic().span_err_with_code(sp, &msg, code) } pub fn err(&self, msg: &str) { @@ -283,7 +292,7 @@ impl Session { pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) { self.diagnostic().span_warn(sp, msg) } - pub fn span_warn_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) { + pub fn span_warn_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) { self.diagnostic().span_warn_with_code(sp, msg, code) } pub fn warn(&self, msg: &str) { @@ -363,7 +372,7 @@ impl Session { match self.opts.error_format { // when outputting JSON for tool consumption, the tool might want // the duplicates - config::ErrorOutputType::Json => { + config::ErrorOutputType::Json(_) => { do_method() }, _ => { @@ -727,11 +736,11 @@ pub fn build_session_with_codemap(sopts: config::Options, (config::ErrorOutputType::HumanReadable(_), Some(dst)) => { Box::new(EmitterWriter::new(dst, Some(codemap.clone()), false)) } - (config::ErrorOutputType::Json, None) => { - Box::new(JsonEmitter::stderr(Some(registry), codemap.clone())) + (config::ErrorOutputType::Json(pretty), None) => { + Box::new(JsonEmitter::stderr(Some(registry), codemap.clone(), pretty)) } - (config::ErrorOutputType::Json, Some(dst)) => { - Box::new(JsonEmitter::new(dst, Some(registry), codemap.clone())) + (config::ErrorOutputType::Json(pretty), Some(dst)) => { + Box::new(JsonEmitter::new(dst, Some(registry), codemap.clone(), pretty)) } (config::ErrorOutputType::Short(color_config), None) => { Box::new(EmitterWriter::stderr(color_config, Some(codemap.clone()), true)) @@ -909,7 +918,7 @@ pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! { config::ErrorOutputType::HumanReadable(color_config) => { Box::new(EmitterWriter::stderr(color_config, None, false)) } - config::ErrorOutputType::Json => Box::new(JsonEmitter::basic()), + config::ErrorOutputType::Json(pretty) => Box::new(JsonEmitter::basic(pretty)), config::ErrorOutputType::Short(color_config) => { Box::new(EmitterWriter::stderr(color_config, None, true)) } @@ -924,7 +933,7 @@ pub fn early_warn(output: config::ErrorOutputType, msg: &str) { config::ErrorOutputType::HumanReadable(color_config) => { Box::new(EmitterWriter::stderr(color_config, None, false)) } - config::ErrorOutputType::Json => Box::new(JsonEmitter::basic()), + config::ErrorOutputType::Json(pretty) => Box::new(JsonEmitter::basic(pretty)), config::ErrorOutputType::Short(color_config) => { Box::new(EmitterWriter::stderr(color_config, None, true)) } diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 1fddb186417..c08fe187f99 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -288,11 +288,11 @@ pub enum Vtable<'tcx, N> { /// Vtable identifying a particular impl. VtableImpl(VtableImplData<'tcx, N>), - /// Vtable for default trait implementations + /// Vtable for auto trait implementations /// This carries the information and nested obligations with regards - /// to a default implementation for a trait `Trait`. The nested obligations + /// to an auto implementation for a trait `Trait`. The nested obligations /// ensure the trait implementation holds for all the constituent types. - VtableDefaultImpl(VtableDefaultImplData<N>), + VtableAutoImpl(VtableAutoImplData<N>), /// Successful resolution to an obligation provided by the caller /// for some type parameter. The `Vec<N>` represents the @@ -354,7 +354,7 @@ pub struct VtableClosureData<'tcx, N> { } #[derive(Clone)] -pub struct VtableDefaultImplData<N> { +pub struct VtableAutoImplData<N> { pub trait_def_id: DefId, pub nested: Vec<N> } @@ -758,7 +758,7 @@ impl<'tcx, N> Vtable<'tcx, N> { VtableImpl(i) => i.nested, VtableParam(n) => n, VtableBuiltin(i) => i.nested, - VtableDefaultImpl(d) => d.nested, + VtableAutoImpl(d) => d.nested, VtableClosure(c) => c.nested, VtableGenerator(c) => c.nested, VtableObject(d) => d.nested, @@ -771,7 +771,7 @@ impl<'tcx, N> Vtable<'tcx, N> { &mut VtableImpl(ref mut i) => &mut i.nested, &mut VtableParam(ref mut n) => n, &mut VtableBuiltin(ref mut i) => &mut i.nested, - &mut VtableDefaultImpl(ref mut d) => &mut d.nested, + &mut VtableAutoImpl(ref mut d) => &mut d.nested, &mut VtableGenerator(ref mut c) => &mut c.nested, &mut VtableClosure(ref mut c) => &mut c.nested, &mut VtableObject(ref mut d) => &mut d.nested, @@ -795,7 +795,7 @@ impl<'tcx, N> Vtable<'tcx, N> { vtable_base: o.vtable_base, nested: o.nested.into_iter().map(f).collect(), }), - VtableDefaultImpl(d) => VtableDefaultImpl(VtableDefaultImplData { + VtableAutoImpl(d) => VtableAutoImpl(VtableAutoImplData { trait_def_id: d.trait_def_id, nested: d.nested.into_iter().map(f).collect(), }), diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 0fa1b32ceb7..9c56df058c3 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -1116,7 +1116,7 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( // projection. And the projection where clause is handled // in `assemble_candidates_from_param_env`. } - super::VtableDefaultImpl(..) | + super::VtableAutoImpl(..) | super::VtableBuiltin(..) => { // These traits have no associated types. span_bug!( @@ -1182,7 +1182,7 @@ fn confirm_select_candidate<'cx, 'gcx, 'tcx>( confirm_fn_pointer_candidate(selcx, obligation, data), super::VtableObject(_) => confirm_object_candidate(selcx, obligation, obligation_trait_ref), - super::VtableDefaultImpl(..) | + super::VtableAutoImpl(..) | super::VtableParam(..) | super::VtableBuiltin(..) => // we don't create Select candidates with this kind of resolution diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 6c573acf07d..7716770d318 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -25,9 +25,9 @@ use super::TraitNotObjectSafe; use super::Selection; use super::SelectionResult; use super::{VtableBuiltin, VtableImpl, VtableParam, VtableClosure, VtableGenerator, - VtableFnPointer, VtableObject, VtableDefaultImpl}; + VtableFnPointer, VtableObject, VtableAutoImpl}; use super::{VtableImplData, VtableObjectData, VtableBuiltinData, VtableGeneratorData, - VtableClosureData, VtableDefaultImplData, VtableFnPointerData}; + VtableClosureData, VtableAutoImplData, VtableFnPointerData}; use super::util; use dep_graph::{DepNodeIndex, DepKind}; @@ -225,7 +225,7 @@ enum SelectionCandidate<'tcx> { BuiltinCandidate { has_nested: bool }, ParamCandidate(ty::PolyTraitRef<'tcx>), ImplCandidate(DefId), - DefaultImplCandidate(DefId), + AutoImplCandidate(DefId), /// This is a trait matching with a projected type as `Self`, and /// we found an applicable bound in the trait definition. @@ -260,7 +260,7 @@ impl<'a, 'tcx> ty::Lift<'tcx> for SelectionCandidate<'a> { } } ImplCandidate(def_id) => ImplCandidate(def_id), - DefaultImplCandidate(def_id) => DefaultImplCandidate(def_id), + AutoImplCandidate(def_id) => AutoImplCandidate(def_id), ProjectionCandidate => ProjectionCandidate, FnPointerCandidate => FnPointerCandidate, ObjectCandidate => ObjectCandidate, @@ -910,7 +910,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn coinductive_predicate(&self, predicate: ty::Predicate<'tcx>) -> bool { let result = match predicate { ty::Predicate::Trait(ref data) => { - self.tcx().trait_has_default_impl(data.def_id()) + self.tcx().trait_is_auto(data.def_id()) } _ => { false @@ -1368,10 +1368,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { self.assemble_candidates_from_projected_tys(obligation, &mut candidates); self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?; - // Default implementations have lower priority, so we only + // Auto implementations have lower priority, so we only // consider triggering a default if there is no other impl that can apply. if candidates.vec.is_empty() { - self.assemble_candidates_from_default_impls(obligation, &mut candidates)?; + self.assemble_candidates_from_auto_impls(obligation, &mut candidates)?; } debug!("candidate list size: {}", candidates.vec.len()); Ok(candidates) @@ -1686,18 +1686,18 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Ok(()) } - fn assemble_candidates_from_default_impls(&mut self, + fn assemble_candidates_from_auto_impls(&mut self, obligation: &TraitObligation<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>) -> Result<(), SelectionError<'tcx>> { // OK to skip binder here because the tests we do below do not involve bound regions let self_ty = *obligation.self_ty().skip_binder(); - debug!("assemble_candidates_from_default_impls(self_ty={:?})", self_ty); + debug!("assemble_candidates_from_auto_impls(self_ty={:?})", self_ty); let def_id = obligation.predicate.def_id(); - if self.tcx().trait_has_default_impl(def_id) { + if self.tcx().trait_is_auto(def_id) { match self_ty.sty { ty::TyDynamic(..) => { // For object types, we don't know what the closed @@ -1728,11 +1728,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // this path. } ty::TyInfer(ty::TyVar(_)) => { - // the defaulted impl might apply, we don't know + // the auto impl might apply, we don't know candidates.ambiguous = true; } _ => { - candidates.vec.push(DefaultImplCandidate(def_id.clone())) + candidates.vec.push(AutoImplCandidate(def_id.clone())) } } } @@ -1933,7 +1933,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { match other.candidate { ObjectCandidate | ParamCandidate(_) | ProjectionCandidate => match victim.candidate { - DefaultImplCandidate(..) => { + AutoImplCandidate(..) => { bug!( "default implementations shouldn't be recorded \ when there are other valid candidates"); @@ -2282,9 +2282,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Ok(VtableParam(obligations)) } - DefaultImplCandidate(trait_def_id) => { - let data = self.confirm_default_impl_candidate(obligation, trait_def_id); - Ok(VtableDefaultImpl(data)) + AutoImplCandidate(trait_def_id) => { + let data = self.confirm_auto_impl_candidate(obligation, trait_def_id); + Ok(VtableAutoImpl(data)) } ImplCandidate(impl_def_id) => { @@ -2417,29 +2417,29 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { /// /// 1. For each constituent type `Y` in `X`, `Y : Foo` holds /// 2. For each where-clause `C` declared on `Foo`, `[Self => X] C` holds. - fn confirm_default_impl_candidate(&mut self, + fn confirm_auto_impl_candidate(&mut self, obligation: &TraitObligation<'tcx>, trait_def_id: DefId) - -> VtableDefaultImplData<PredicateObligation<'tcx>> + -> VtableAutoImplData<PredicateObligation<'tcx>> { - debug!("confirm_default_impl_candidate({:?}, {:?})", + debug!("confirm_auto_impl_candidate({:?}, {:?})", obligation, trait_def_id); // binder is moved below let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty()); let types = self.constituent_types_for_ty(self_ty); - self.vtable_default_impl(obligation, trait_def_id, ty::Binder(types)) + self.vtable_auto_impl(obligation, trait_def_id, ty::Binder(types)) } - /// See `confirm_default_impl_candidate` - fn vtable_default_impl(&mut self, + /// See `confirm_auto_impl_candidate` + fn vtable_auto_impl(&mut self, obligation: &TraitObligation<'tcx>, trait_def_id: DefId, nested: ty::Binder<Vec<Ty<'tcx>>>) - -> VtableDefaultImplData<PredicateObligation<'tcx>> + -> VtableAutoImplData<PredicateObligation<'tcx>> { - debug!("vtable_default_impl: nested={:?}", nested); + debug!("vtable_auto_impl: nested={:?}", nested); let cause = obligation.derived_cause(BuiltinDerivedObligation); let mut obligations = self.collect_predicates_for_types( @@ -2465,9 +2465,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligations.extend(trait_obligations); - debug!("vtable_default_impl: obligations={:?}", obligations); + debug!("vtable_auto_impl: obligations={:?}", obligations); - VtableDefaultImplData { + VtableAutoImplData { trait_def_id, nested: obligations } diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 19ed03aa149..fd93aa162a6 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -47,7 +47,7 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::Vtable<'tcx, N> { super::VtableImpl(ref v) => write!(f, "{:?}", v), - super::VtableDefaultImpl(ref t) => + super::VtableAutoImpl(ref t) => write!(f, "{:?}", t), super::VtableClosure(ref d) => @@ -104,9 +104,9 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableBuiltinData<N> { } } -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableDefaultImplData<N> { +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableAutoImplData<N> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "VtableDefaultImplData(trait_def_id={:?}, nested={:?})", + write!(f, "VtableAutoImplData(trait_def_id={:?}, nested={:?})", self.trait_def_id, self.nested) } @@ -292,7 +292,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> { }) }) } - traits::VtableDefaultImpl(t) => Some(traits::VtableDefaultImpl(t)), + traits::VtableAutoImpl(t) => Some(traits::VtableAutoImpl(t)), traits::VtableGenerator(traits::VtableGeneratorData { closure_def_id, substs, @@ -407,9 +407,9 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableClosureDa } } -impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableDefaultImplData<N> { +impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableAutoImplData<N> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - traits::VtableDefaultImplData { + traits::VtableAutoImplData { trait_def_id: self.trait_def_id, nested: self.nested.fold_with(folder), } @@ -463,7 +463,7 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N> fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { match *self { traits::VtableImpl(ref v) => traits::VtableImpl(v.fold_with(folder)), - traits::VtableDefaultImpl(ref t) => traits::VtableDefaultImpl(t.fold_with(folder)), + traits::VtableAutoImpl(ref t) => traits::VtableAutoImpl(t.fold_with(folder)), traits::VtableGenerator(ref d) => { traits::VtableGenerator(d.fold_with(folder)) } @@ -482,7 +482,7 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N> fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { match *self { traits::VtableImpl(ref v) => v.visit_with(visitor), - traits::VtableDefaultImpl(ref t) => t.visit_with(visitor), + traits::VtableAutoImpl(ref t) => t.visit_with(visitor), traits::VtableGenerator(ref d) => d.visit_with(visitor), traits::VtableClosure(ref d) => d.visit_with(visitor), traits::VtableFnPointer(ref d) => d.visit_with(visitor), diff --git a/src/librustc/traits/trans/mod.rs b/src/librustc/traits/trans/mod.rs index 761e7259204..73fdbfe8831 100644 --- a/src/librustc/traits/trans/mod.rs +++ b/src/librustc/traits/trans/mod.rs @@ -99,6 +99,26 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { let substituted = self.erase_regions(&substituted); AssociatedTypeNormalizer::new(self).fold(&substituted) } + + pub fn trans_apply_param_substs_env<T>( + self, + param_substs: &Substs<'tcx>, + param_env: ty::ParamEnv<'tcx>, + value: &T, + ) -> T + where + T: TransNormalize<'tcx>, + { + debug!( + "apply_param_substs_env(param_substs={:?}, value={:?}, param_env={:?})", + param_substs, + value, + param_env, + ); + let substituted = value.subst(self, param_substs); + let substituted = self.erase_regions(&substituted); + AssociatedTypeNormalizerEnv::new(self, param_env).fold(&substituted) + } } struct AssociatedTypeNormalizer<'a, 'gcx: 'a> { @@ -134,6 +154,40 @@ impl<'a, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'gcx> { } } +struct AssociatedTypeNormalizerEnv<'a, 'gcx: 'a> { + tcx: TyCtxt<'a, 'gcx, 'gcx>, + param_env: ty::ParamEnv<'gcx>, +} + +impl<'a, 'gcx> AssociatedTypeNormalizerEnv<'a, 'gcx> { + fn new(tcx: TyCtxt<'a, 'gcx, 'gcx>, param_env: ty::ParamEnv<'gcx>) -> Self { + Self { tcx, param_env } + } + + fn fold<T: TypeFoldable<'gcx>>(&mut self, value: &T) -> T { + if !value.has_projections() { + value.clone() + } else { + value.fold_with(self) + } + } +} + +impl<'a, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizerEnv<'a, 'gcx> { + fn tcx<'c>(&'c self) -> TyCtxt<'c, 'gcx, 'gcx> { + self.tcx + } + + fn fold_ty(&mut self, ty: Ty<'gcx>) -> Ty<'gcx> { + if !ty.has_projections() { + ty + } else { + debug!("AssociatedTypeNormalizerEnv: ty={:?}", ty); + self.tcx.normalize_associated_type_in_env(&ty, self.param_env) + } + } +} + // Implement DepTrackingMapConfig for `trait_cache` pub struct TraitSelectionCache<'tcx> { data: PhantomData<&'tcx ()> diff --git a/src/librustc/ty/codec.rs b/src/librustc/ty/codec.rs new file mode 100644 index 00000000000..1c793920bf2 --- /dev/null +++ b/src/librustc/ty/codec.rs @@ -0,0 +1,243 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This module contains some shared code for encoding and decoding various +// things from the `ty` module, and in particular implements support for +// "shorthands" which allow to have pointers back into the already encoded +// stream instead of re-encoding the same thing twice. +// +// The functionality in here is shared between persisting to crate metadata and +// persisting to incr. comp. caches. + +use hir::def_id::{DefId, CrateNum}; +use middle::const_val::ByteArray; +use rustc_data_structures::fx::FxHashMap; +use rustc_serialize::{Decodable, Decoder, Encoder, Encodable}; +use std::hash::Hash; +use std::intrinsics; +use ty::{self, Ty, TyCtxt}; +use ty::subst::Substs; + +/// The shorthand encoding uses an enum's variant index `usize` +/// and is offset by this value so it never matches a real variant. +/// This offset is also chosen so that the first byte is never < 0x80. +pub const SHORTHAND_OFFSET: usize = 0x80; + +pub trait EncodableWithShorthand: Clone + Eq + Hash { + type Variant: Encodable; + fn variant(&self) -> &Self::Variant; +} + +impl<'tcx> EncodableWithShorthand for Ty<'tcx> { + type Variant = ty::TypeVariants<'tcx>; + fn variant(&self) -> &Self::Variant { + &self.sty + } +} + +impl<'tcx> EncodableWithShorthand for ty::Predicate<'tcx> { + type Variant = ty::Predicate<'tcx>; + fn variant(&self) -> &Self::Variant { + self + } +} + +pub trait TyEncoder: Encoder { + fn position(&self) -> usize; +} + +/// Encode the given value or a previously cached shorthand. +pub fn encode_with_shorthand<E, T, M>(encoder: &mut E, + value: &T, + cache: M) + -> Result<(), E::Error> + where E: TyEncoder, + M: for<'b> Fn(&'b mut E) -> &'b mut FxHashMap<T, usize>, + T: EncodableWithShorthand, +{ + let existing_shorthand = cache(encoder).get(value).cloned(); + if let Some(shorthand) = existing_shorthand { + return encoder.emit_usize(shorthand); + } + + let variant = value.variant(); + + let start = encoder.position(); + variant.encode(encoder)?; + let len = encoder.position() - start; + + // The shorthand encoding uses the same usize as the + // discriminant, with an offset so they can't conflict. + let discriminant = unsafe { intrinsics::discriminant_value(variant) }; + assert!(discriminant < SHORTHAND_OFFSET as u64); + let shorthand = start + SHORTHAND_OFFSET; + + // Get the number of bits that leb128 could fit + // in the same space as the fully encoded type. + let leb128_bits = len * 7; + + // Check that the shorthand is a not longer than the + // full encoding itself, i.e. it's an obvious win. + if leb128_bits >= 64 || (shorthand as u64) < (1 << leb128_bits) { + cache(encoder).insert(value.clone(), shorthand); + } + + Ok(()) +} + +pub fn encode_predicates<'tcx, E, C>(encoder: &mut E, + predicates: &ty::GenericPredicates<'tcx>, + cache: C) + -> Result<(), E::Error> + where E: TyEncoder, + C: for<'b> Fn(&'b mut E) -> &'b mut FxHashMap<ty::Predicate<'tcx>, usize>, +{ + predicates.parent.encode(encoder)?; + predicates.predicates.len().encode(encoder)?; + for predicate in &predicates.predicates { + encode_with_shorthand(encoder, predicate, &cache)? + } + Ok(()) +} + +pub trait TyDecoder<'a, 'tcx: 'a>: Decoder { + + fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx>; + + fn peek_byte(&self) -> u8; + + fn cached_ty_for_shorthand<F>(&mut self, + shorthand: usize, + or_insert_with: F) + -> Result<Ty<'tcx>, Self::Error> + where F: FnOnce(&mut Self) -> Result<Ty<'tcx>, Self::Error>; + + fn with_position<F, R>(&mut self, pos: usize, f: F) -> R + where F: FnOnce(&mut Self) -> R; + + fn map_encoded_cnum_to_current(&self, cnum: CrateNum) -> CrateNum; + + fn positioned_at_shorthand(&self) -> bool { + (self.peek_byte() & (SHORTHAND_OFFSET as u8)) != 0 + } +} + +pub fn decode_cnum<'a, 'tcx, D>(decoder: &mut D) -> Result<CrateNum, D::Error> + where D: TyDecoder<'a, 'tcx>, + 'tcx: 'a, +{ + let cnum = CrateNum::from_u32(u32::decode(decoder)?); + Ok(decoder.map_encoded_cnum_to_current(cnum)) +} + +pub fn decode_ty<'a, 'tcx, D>(decoder: &mut D) -> Result<Ty<'tcx>, D::Error> + where D: TyDecoder<'a, 'tcx>, + 'tcx: 'a, +{ + // Handle shorthands first, if we have an usize > 0x80. + // if self.opaque.data[self.opaque.position()] & 0x80 != 0 { + if decoder.positioned_at_shorthand() { + let pos = decoder.read_usize()?; + assert!(pos >= SHORTHAND_OFFSET); + let shorthand = pos - SHORTHAND_OFFSET; + + decoder.cached_ty_for_shorthand(shorthand, |decoder| { + decoder.with_position(shorthand, Ty::decode) + }) + } else { + let tcx = decoder.tcx(); + Ok(tcx.mk_ty(ty::TypeVariants::decode(decoder)?)) + } +} + +pub fn decode_predicates<'a, 'tcx, D>(decoder: &mut D) + -> Result<ty::GenericPredicates<'tcx>, D::Error> + where D: TyDecoder<'a, 'tcx>, + 'tcx: 'a, +{ + Ok(ty::GenericPredicates { + parent: Decodable::decode(decoder)?, + predicates: (0..decoder.read_usize()?).map(|_| { + // Handle shorthands first, if we have an usize > 0x80. + if decoder.positioned_at_shorthand() { + let pos = decoder.read_usize()?; + assert!(pos >= SHORTHAND_OFFSET); + let shorthand = pos - SHORTHAND_OFFSET; + + decoder.with_position(shorthand, ty::Predicate::decode) + } else { + ty::Predicate::decode(decoder) + } + }) + .collect::<Result<Vec<_>, _>>()?, + }) +} + +pub fn decode_substs<'a, 'tcx, D>(decoder: &mut D) -> Result<&'tcx Substs<'tcx>, D::Error> + where D: TyDecoder<'a, 'tcx>, + 'tcx: 'a, +{ + let len = decoder.read_usize()?; + let tcx = decoder.tcx(); + Ok(tcx.mk_substs((0..len).map(|_| Decodable::decode(decoder)))?) +} + +pub fn decode_region<'a, 'tcx, D>(decoder: &mut D) -> Result<ty::Region<'tcx>, D::Error> + where D: TyDecoder<'a, 'tcx>, + 'tcx: 'a, +{ + Ok(decoder.tcx().mk_region(Decodable::decode(decoder)?)) +} + +pub fn decode_ty_slice<'a, 'tcx, D>(decoder: &mut D) + -> Result<&'tcx ty::Slice<Ty<'tcx>>, D::Error> + where D: TyDecoder<'a, 'tcx>, + 'tcx: 'a, +{ + let len = decoder.read_usize()?; + Ok(decoder.tcx().mk_type_list((0..len).map(|_| Decodable::decode(decoder)))?) +} + +pub fn decode_adt_def<'a, 'tcx, D>(decoder: &mut D) + -> Result<&'tcx ty::AdtDef, D::Error> + where D: TyDecoder<'a, 'tcx>, + 'tcx: 'a, +{ + let def_id = DefId::decode(decoder)?; + Ok(decoder.tcx().adt_def(def_id)) +} + +pub fn decode_existential_predicate_slice<'a, 'tcx, D>(decoder: &mut D) + -> Result<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>, D::Error> + where D: TyDecoder<'a, 'tcx>, + 'tcx: 'a, +{ + let len = decoder.read_usize()?; + Ok(decoder.tcx() + .mk_existential_predicates((0..len).map(|_| Decodable::decode(decoder)))?) +} + +pub fn decode_byte_array<'a, 'tcx, D>(decoder: &mut D) + -> Result<ByteArray<'tcx>, D::Error> + where D: TyDecoder<'a, 'tcx>, + 'tcx: 'a, +{ + Ok(ByteArray { + data: decoder.tcx().alloc_byte_array(&Vec::decode(decoder)?) + }) +} + +pub fn decode_const<'a, 'tcx, D>(decoder: &mut D) + -> Result<&'tcx ty::Const<'tcx>, D::Error> + where D: TyDecoder<'a, 'tcx>, + 'tcx: 'a, +{ + Ok(decoder.tcx().mk_const(Decodable::decode(decoder)?)) +} diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 6ab81a41d68..37c4346a7dc 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -855,6 +855,11 @@ pub struct GlobalCtxt<'tcx> { pub dep_graph: DepGraph, + /// This provides access to the incr. comp. on-disk cache for query results. + /// Do not access this directly. It is only meant to be used by + /// `DepGraph::try_mark_green()` and the query infrastructure in `ty::maps`. + pub(crate) on_disk_query_result_cache: maps::OnDiskCache<'tcx>, + /// Common types, pre-interned for your convenience. pub types: CommonTypes<'tcx>, @@ -1056,6 +1061,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { resolutions: ty::Resolutions, named_region_map: resolve_lifetime::NamedRegionMap, hir: hir_map::Map<'tcx>, + on_disk_query_result_cache: maps::OnDiskCache<'tcx>, crate_name: &str, tx: mpsc::Sender<Box<Any + Send>>, output_filenames: &OutputFilenames, @@ -1139,6 +1145,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { global_arenas: arenas, global_interners: interners, dep_graph: dep_graph.clone(), + on_disk_query_result_cache, types: common_types, named_region_map: NamedRegionMap { defs, @@ -1300,6 +1307,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.in_scope_traits_map(def_index); } } + + pub fn serialize_query_result_cache<E>(self, + encoder: &mut E) + -> Result<(), E::Error> + where E: ::rustc_serialize::Encoder + { + self.on_disk_query_result_cache.serialize(encoder) + } + } impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index edd4329fa41..149999e0eee 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -218,6 +218,43 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { { value.fold_with(&mut RegionFolder::new(self, skipped_regions, &mut f)) } + + pub fn for_each_free_region<T,F>(self, + value: &T, + callback: F) + where F: FnMut(ty::Region<'tcx>), + T: TypeFoldable<'tcx>, + { + value.visit_with(&mut RegionVisitor { current_depth: 0, callback }); + + struct RegionVisitor<F> { + current_depth: u32, + callback: F, + } + + impl<'tcx, F> TypeVisitor<'tcx> for RegionVisitor<F> + where F : FnMut(ty::Region<'tcx>) + { + fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> bool { + self.current_depth += 1; + t.skip_binder().visit_with(self); + self.current_depth -= 1; + + false // keep visiting + } + + fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { + match *r { + ty::ReLateBound(debruijn, _) if debruijn.depth < self.current_depth => { + /* ignore bound regions */ + } + _ => (self.callback)(r), + } + + false // keep visiting + } + } + } } /// Folds over the substructure of a type, visiting its component diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 442c79393fd..6ea953c3f73 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -144,7 +144,7 @@ impl<'a, 'b, 'tcx> Instance<'tcx> { resolve_associated_item(tcx, &item, param_env, trait_def_id, substs) } else { let ty = tcx.type_of(def_id); - let item_type = tcx.trans_apply_param_substs(substs, &ty); + let item_type = tcx.trans_apply_param_substs_env(substs, param_env, &ty); let def = match item_type.sty { ty::TyFnDef(..) if { @@ -256,7 +256,7 @@ fn resolve_associated_item<'a, 'tcx>( None } } - traits::VtableDefaultImpl(..) | traits::VtableParam(..) => None + traits::VtableAutoImpl(..) | traits::VtableParam(..) => None } } diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 98c55331f8a..24c19bfc3f3 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -218,7 +218,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // Always use types for non-local impls, where types are always // available, and filename/line-number is mostly uninteresting. - let use_types = !self.is_default_impl(impl_def_id) && (!impl_def_id.is_local() || { + let use_types = !self.is_auto_impl(impl_def_id) && (!impl_def_id.is_local() || { // Otherwise, use filename/line-number if forced. let force_no_types = FORCE_IMPL_FILENAME_LINE.with(|f| f.get()); !force_no_types diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 79fee8bf930..7d8586741fb 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -70,6 +70,9 @@ mod config; pub use self::config::QueryConfig; use self::config::QueryDescription; +mod on_disk_cache; +pub use self::on_disk_cache::OnDiskCache; + // Each of these maps also corresponds to a method on a // `Provider` trait for requesting a value of that type, // and a method on `Maps` itself for doing that in a @@ -110,8 +113,8 @@ define_maps! { <'tcx> /// True if this is a foreign item (i.e., linked via `extern { ... }`). [] fn is_foreign_item: IsForeignItem(DefId) -> bool, - /// True if this is a default impl (aka impl Foo for ..) - [] fn is_default_impl: IsDefaultImpl(DefId) -> bool, + /// True if this is an auto impl (aka impl Foo for ..) + [] fn is_auto_impl: IsAutoImpl(DefId) -> bool, /// Get a map with the variance of every item; use `item_variance` /// instead. diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs new file mode 100644 index 00000000000..26581501234 --- /dev/null +++ b/src/librustc/ty/maps/on_disk_cache.rs @@ -0,0 +1,231 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use dep_graph::{DepNodeIndex, SerializedDepNodeIndex}; +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::indexed_vec::Idx; +use errors::Diagnostic; +use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, opaque, + SpecializedDecoder}; +use session::Session; +use std::borrow::Cow; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::mem; +use syntax::codemap::{CodeMap, StableFilemapId}; +use syntax_pos::{BytePos, Span, NO_EXPANSION, DUMMY_SP}; + +/// `OnDiskCache` provides an interface to incr. comp. data cached from the +/// previous compilation session. This data will eventually include the results +/// of a few selected queries (like `typeck_tables_of` and `mir_optimized`) and +/// any diagnostics that have been emitted during a query. +pub struct OnDiskCache<'sess> { + // The diagnostics emitted during the previous compilation session. + prev_diagnostics: FxHashMap<SerializedDepNodeIndex, Vec<Diagnostic>>, + + // This field collects all Diagnostics emitted during the current + // compilation session. + current_diagnostics: RefCell<FxHashMap<DepNodeIndex, Vec<Diagnostic>>>, + + // This will eventually be needed for creating Decoders that can rebase + // spans. + _prev_filemap_starts: BTreeMap<BytePos, StableFilemapId>, + codemap: &'sess CodeMap, +} + +// This type is used only for (de-)serialization. +#[derive(RustcEncodable, RustcDecodable)] +struct Header { + prev_filemap_starts: BTreeMap<BytePos, StableFilemapId>, +} + +// This type is used only for (de-)serialization. +#[derive(RustcEncodable, RustcDecodable)] +struct Body { + diagnostics: Vec<(SerializedDepNodeIndex, Vec<Diagnostic>)>, +} + +impl<'sess> OnDiskCache<'sess> { + /// Create a new OnDiskCache instance from the serialized data in `data`. + /// Note that the current implementation (which only deals with diagnostics + /// so far) will eagerly deserialize the complete cache. Once we are + /// dealing with larger amounts of data (i.e. cached query results), + /// deserialization will need to happen lazily. + pub fn new(sess: &'sess Session, data: &[u8]) -> OnDiskCache<'sess> { + debug_assert!(sess.opts.incremental.is_some()); + + let mut decoder = opaque::Decoder::new(&data[..], 0); + let header = Header::decode(&mut decoder).unwrap(); + + let prev_diagnostics: FxHashMap<_, _> = { + let mut decoder = CacheDecoder { + opaque: decoder, + codemap: sess.codemap(), + prev_filemap_starts: &header.prev_filemap_starts, + }; + let body = Body::decode(&mut decoder).unwrap(); + body.diagnostics.into_iter().collect() + }; + + OnDiskCache { + prev_diagnostics, + _prev_filemap_starts: header.prev_filemap_starts, + codemap: sess.codemap(), + current_diagnostics: RefCell::new(FxHashMap()), + } + } + + pub fn new_empty(codemap: &'sess CodeMap) -> OnDiskCache<'sess> { + OnDiskCache { + prev_diagnostics: FxHashMap(), + _prev_filemap_starts: BTreeMap::new(), + codemap, + current_diagnostics: RefCell::new(FxHashMap()), + } + } + + pub fn serialize<'a, 'tcx, E>(&self, + encoder: &mut E) + -> Result<(), E::Error> + where E: Encoder + { + let prev_filemap_starts: BTreeMap<_, _> = self + .codemap + .files() + .iter() + .map(|fm| (fm.start_pos, StableFilemapId::new(fm))) + .collect(); + + Header { prev_filemap_starts }.encode(encoder)?; + + let diagnostics: Vec<(SerializedDepNodeIndex, Vec<Diagnostic>)> = + self.current_diagnostics + .borrow() + .iter() + .map(|(k, v)| (SerializedDepNodeIndex::new(k.index()), v.clone())) + .collect(); + + Body { diagnostics }.encode(encoder)?; + + Ok(()) + } + + /// Load a diagnostic emitted during the previous compilation session. + pub fn load_diagnostics(&self, + dep_node_index: SerializedDepNodeIndex) + -> Vec<Diagnostic> { + self.prev_diagnostics.get(&dep_node_index).cloned().unwrap_or(vec![]) + } + + /// Store a diagnostic emitted during the current compilation session. + /// Anything stored like this will be available via `load_diagnostics` in + /// the next compilation session. + pub fn store_diagnostics(&self, + dep_node_index: DepNodeIndex, + diagnostics: Vec<Diagnostic>) { + let mut current_diagnostics = self.current_diagnostics.borrow_mut(); + let prev = current_diagnostics.insert(dep_node_index, diagnostics); + debug_assert!(prev.is_none()); + } + + /// Store a diagnostic emitted during computation of an anonymous query. + /// Since many anonymous queries can share the same `DepNode`, we aggregate + /// them -- as opposed to regular queries where we assume that there is a + /// 1:1 relationship between query-key and `DepNode`. + pub fn store_diagnostics_for_anon_node(&self, + dep_node_index: DepNodeIndex, + mut diagnostics: Vec<Diagnostic>) { + let mut current_diagnostics = self.current_diagnostics.borrow_mut(); + + let x = current_diagnostics.entry(dep_node_index).or_insert_with(|| { + mem::replace(&mut diagnostics, Vec::new()) + }); + + x.extend(diagnostics.into_iter()); + } +} + +/// A decoder that can read the incr. comp. cache. It is similar to the one +/// we use for crate metadata decoding in that it can rebase spans and +/// eventually will also handle things that contain `Ty` instances. +struct CacheDecoder<'a> { + opaque: opaque::Decoder<'a>, + codemap: &'a CodeMap, + prev_filemap_starts: &'a BTreeMap<BytePos, StableFilemapId>, +} + +impl<'a> CacheDecoder<'a> { + fn find_filemap_prev_bytepos(&self, + prev_bytepos: BytePos) + -> Option<(BytePos, StableFilemapId)> { + for (start, id) in self.prev_filemap_starts.range(BytePos(0) ... prev_bytepos).rev() { + return Some((*start, *id)) + } + + None + } +} + +macro_rules! decoder_methods { + ($($name:ident -> $ty:ty;)*) => { + $(fn $name(&mut self) -> Result<$ty, Self::Error> { + self.opaque.$name() + })* + } +} + +impl<'sess> Decoder for CacheDecoder<'sess> { + type Error = String; + + decoder_methods! { + read_nil -> (); + + read_u128 -> u128; + read_u64 -> u64; + read_u32 -> u32; + read_u16 -> u16; + read_u8 -> u8; + read_usize -> usize; + + read_i128 -> i128; + read_i64 -> i64; + read_i32 -> i32; + read_i16 -> i16; + read_i8 -> i8; + read_isize -> isize; + + read_bool -> bool; + read_f64 -> f64; + read_f32 -> f32; + read_char -> char; + read_str -> Cow<str>; + } + + fn error(&mut self, err: &str) -> Self::Error { + self.opaque.error(err) + } +} + +impl<'a> SpecializedDecoder<Span> for CacheDecoder<'a> { + fn specialized_decode(&mut self) -> Result<Span, Self::Error> { + let lo = BytePos::decode(self)?; + let hi = BytePos::decode(self)?; + + if let Some((prev_filemap_start, filemap_id)) = self.find_filemap_prev_bytepos(lo) { + if let Some(current_filemap) = self.codemap.filemap_by_stable_id(filemap_id) { + let lo = (lo + current_filemap.start_pos) - prev_filemap_start; + let hi = (hi + current_filemap.start_pos) - prev_filemap_start; + return Ok(Span::new(lo, hi, NO_EXPANSION)); + } + } + + Ok(DUMMY_SP) + } +} diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index bb042be5254..24148bcc83f 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -13,14 +13,14 @@ //! provider, manage the caches, and so forth. use dep_graph::{DepNodeIndex, DepNode, DepKind, DepNodeColor}; -use errors::{Diagnostic, DiagnosticBuilder}; +use errors::DiagnosticBuilder; use ty::{TyCtxt}; use ty::maps::Query; // NB: actually generated by the macros in this file use ty::maps::config::QueryDescription; use ty::item_path; use rustc_data_structures::fx::{FxHashMap}; -use std::cell::{RefMut, Cell}; +use std::cell::RefMut; use std::marker::PhantomData; use std::mem; use syntax_pos::Span; @@ -33,34 +33,19 @@ pub(super) struct QueryMap<D: QueryDescription> { pub(super) struct QueryValue<T> { pub(super) value: T, pub(super) index: DepNodeIndex, - pub(super) diagnostics: Option<Box<QueryDiagnostics>>, } impl<T> QueryValue<T> { pub(super) fn new(value: T, - dep_node_index: DepNodeIndex, - diagnostics: Vec<Diagnostic>) + dep_node_index: DepNodeIndex) -> QueryValue<T> { QueryValue { value, index: dep_node_index, - diagnostics: if diagnostics.len() == 0 { - None - } else { - Some(Box::new(QueryDiagnostics { - diagnostics, - emitted_diagnostics: Cell::new(true), - })) - }, } } } -pub(super) struct QueryDiagnostics { - pub(super) diagnostics: Vec<Diagnostic>, - pub(super) emitted_diagnostics: Cell<bool>, -} - impl<M: QueryDescription> QueryMap<M> { pub(super) fn new() -> QueryMap<M> { QueryMap { @@ -284,16 +269,6 @@ macro_rules! define_maps { ); if let Some(value) = tcx.maps.$name.borrow().map.get(&key) { - if let Some(ref d) = value.diagnostics { - if !d.emitted_diagnostics.get() { - d.emitted_diagnostics.set(true); - let handle = tcx.sess.diagnostic(); - for diagnostic in d.diagnostics.iter() { - DiagnosticBuilder::new_diagnostic(handle, diagnostic.clone()) - .emit(); - } - } - } profq_msg!(tcx, ProfileQueriesMsg::CacheHit); tcx.dep_graph.read_index(value.index); return Ok((&value.value).clone()); @@ -331,7 +306,11 @@ macro_rules! define_maps { let ((result, dep_node_index), diagnostics) = res; tcx.dep_graph.read_index(dep_node_index); - let value = QueryValue::new(result, dep_node_index, diagnostics); + + tcx.on_disk_query_result_cache + .store_diagnostics_for_anon_node(dep_node_index, diagnostics); + + let value = QueryValue::new(result, dep_node_index); return Ok((&tcx.maps .$name @@ -348,7 +327,8 @@ macro_rules! define_maps { return Self::load_from_disk_and_cache_in_memory(tcx, key, span, - dep_node_index) + dep_node_index, + &dep_node) } } @@ -393,13 +373,17 @@ macro_rules! define_maps { fn load_from_disk_and_cache_in_memory(tcx: TyCtxt<'a, $tcx, 'lcx>, key: $K, span: Span, - dep_node_index: DepNodeIndex) + dep_node_index: DepNodeIndex, + dep_node: &DepNode) -> Result<$V, CycleError<'a, $tcx>> { debug_assert!(tcx.dep_graph.is_green(dep_node_index)); - // We don't do any caching yet, so recompute - let (result, diagnostics) = tcx.cycle_check(span, Query::$name(key), || { + // We don't do any caching yet, so recompute. + // The diagnostics for this query have already been promoted to + // the current session during try_mark_green(), so we can ignore + // them here. + let (result, _) = tcx.cycle_check(span, Query::$name(key), || { tcx.sess.diagnostic().track_diagnostics(|| { // The dep-graph for this computation is already in place tcx.dep_graph.with_ignore(|| { @@ -408,11 +392,37 @@ macro_rules! define_maps { }) })?; + // If -Zincremental-verify-ich is specified, re-hash results from + // the cache and make sure that they have the expected fingerprint. + if tcx.sess.opts.debugging_opts.incremental_verify_ich { + use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; + use ich::Fingerprint; + + assert!(Some(tcx.dep_graph.fingerprint_of(dep_node)) == + tcx.dep_graph.prev_fingerprint_of(dep_node), + "Fingerprint for green query instance not loaded \ + from cache: {:?}", dep_node); + + debug!("BEGIN verify_ich({:?})", dep_node); + let mut hcx = tcx.create_stable_hashing_context(); + let mut hasher = StableHasher::new(); + + result.hash_stable(&mut hcx, &mut hasher); + + let new_hash: Fingerprint = hasher.finish(); + debug!("END verify_ich({:?})", dep_node); + + let old_hash = tcx.dep_graph.fingerprint_of(dep_node); + + assert!(new_hash == old_hash, "Found unstable fingerprints \ + for {:?}", dep_node); + } + if tcx.sess.opts.debugging_opts.query_dep_graph { tcx.dep_graph.mark_loaded_from_cache(dep_node_index, true); } - let value = QueryValue::new(result, dep_node_index, diagnostics); + let value = QueryValue::new(result, dep_node_index); Ok((&tcx.maps .$name @@ -454,7 +464,12 @@ macro_rules! define_maps { tcx.dep_graph.mark_loaded_from_cache(dep_node_index, false); } - let value = QueryValue::new(result, dep_node_index, diagnostics); + if dep_node.kind != ::dep_graph::DepKind::Null { + tcx.on_disk_query_result_cache + .store_diagnostics(dep_node_index, diagnostics); + } + + let value = QueryValue::new(result, dep_node_index); Ok(((&tcx.maps .$name @@ -706,9 +721,8 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::EraseRegionsTy | DepKind::NormalizeTy | - // These are just odd - DepKind::Null | - DepKind::WorkProduct => { + // This one should never occur in this context + DepKind::Null => { bug!("force_from_dep_node() - Encountered {:?}", dep_node.kind) } @@ -744,7 +758,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::SuperPredicatesOfItem => { force!(super_predicates_of, def_id!()); } DepKind::TraitDefOfItem => { force!(trait_def, def_id!()); } DepKind::AdtDefOfItem => { force!(adt_def, def_id!()); } - DepKind::IsDefaultImpl => { force!(is_default_impl, def_id!()); } + DepKind::IsAutoImpl => { force!(is_auto_impl, def_id!()); } DepKind::ImplTraitRef => { force!(impl_trait_ref, def_id!()); } DepKind::ImplPolarity => { force!(impl_polarity, def_id!()); } DepKind::ClosureKind => { force!(closure_kind, def_id!()); } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index b3f2886cdf9..0deababd218 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -89,6 +89,7 @@ pub use self::maps::queries; pub mod adjustment; pub mod binding; pub mod cast; +pub mod codec; pub mod error; mod erase_regions; pub mod fast_reject; @@ -1325,6 +1326,12 @@ bitflags! { const IS_FUNDAMENTAL = 1 << 2; const IS_UNION = 1 << 3; const IS_BOX = 1 << 4; + /// Indicates whether this abstract data type will be expanded on in future (new + /// fields/variants) and as such, whether downstream crates must match exhaustively on the + /// fields/variants of this data type. + /// + /// See RFC 2008 (https://github.com/rust-lang/rfcs/pull/2008). + const IS_NON_EXHAUSTIVE = 1 << 5; } } @@ -1525,6 +1532,9 @@ impl<'a, 'gcx, 'tcx> AdtDef { if Some(did) == tcx.lang_items().owned_box() { flags = flags | AdtFlags::IS_BOX; } + if tcx.has_attr(did, "non_exhaustive") { + flags = flags | AdtFlags::IS_NON_EXHAUSTIVE; + } match kind { AdtKind::Enum => flags = flags | AdtFlags::IS_ENUM, AdtKind::Union => flags = flags | AdtFlags::IS_UNION, @@ -1553,6 +1563,11 @@ impl<'a, 'gcx, 'tcx> AdtDef { self.flags.intersects(AdtFlags::IS_ENUM) } + #[inline] + pub fn is_non_exhaustive(&self) -> bool { + self.flags.intersects(AdtFlags::IS_NON_EXHAUSTIVE) + } + /// Returns the kind of the ADT - Struct or Enum. #[inline] pub fn adt_kind(&self) -> AdtKind { @@ -2307,8 +2322,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.get_attrs(did).iter().any(|item| item.check_name(attr)) } - pub fn trait_has_default_impl(self, trait_def_id: DefId) -> bool { - self.trait_def(trait_def_id).has_default_impl + /// Returns true if this is an `auto trait`. + /// + /// NB. For a limited time, also returns true if `impl Trait for .. { }` is in the code-base. + pub fn trait_is_auto(self, trait_def_id: DefId) -> bool { + self.trait_def(trait_def_id).has_auto_impl } pub fn generator_layout(self, def_id: DefId) -> &'tcx GeneratorLayout<'tcx> { diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs index e0b05c2ba39..0fbf9f1bd58 100644 --- a/src/librustc/ty/trait_def.rs +++ b/src/librustc/ty/trait_def.rs @@ -34,7 +34,7 @@ pub struct TraitDef { /// be usable with the sugar (or without it). pub paren_sugar: bool, - pub has_default_impl: bool, + pub has_auto_impl: bool, /// The ICH of this trait's DefPath, cached here so it doesn't have to be /// recomputed all the time. @@ -51,14 +51,14 @@ impl<'a, 'gcx, 'tcx> TraitDef { pub fn new(def_id: DefId, unsafety: hir::Unsafety, paren_sugar: bool, - has_default_impl: bool, + has_auto_impl: bool, def_path_hash: DefPathHash) -> TraitDef { TraitDef { def_id, paren_sugar, unsafety, - has_default_impl, + has_auto_impl, def_path_hash, } } diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs index eafb4c5c800..352184c1efa 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -177,9 +177,13 @@ impl<'a> AllocFnFactory<'a> { let no_mangle = Symbol::intern("no_mangle"); let no_mangle = self.cx.meta_word(self.span, no_mangle); + + let special = Symbol::intern("rustc_std_internal_symbol"); + let special = self.cx.meta_word(self.span, special); vec![ self.cx.attribute(self.span, linkage), self.cx.attribute(self.span, no_mangle), + self.cx.attribute(self.span, special), ] } diff --git a/src/librustc_apfloat/lib.rs b/src/librustc_apfloat/lib.rs index 9e348f62223..09c9cecdcee 100644 --- a/src/librustc_apfloat/lib.rs +++ b/src/librustc_apfloat/lib.rs @@ -96,7 +96,7 @@ impl Status { } impl<T> StatusAnd<T> { - fn map<F: FnOnce(T) -> U, U>(self, f: F) -> StatusAnd<U> { + pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> StatusAnd<U> { StatusAnd { status: self.status, value: f(self.value), @@ -378,7 +378,7 @@ pub trait Float fn from_bits(input: u128) -> Self; fn from_i128_r(input: i128, round: Round) -> StatusAnd<Self> { if input < 0 { - Self::from_u128_r(-input as u128, -round).map(|r| -r) + Self::from_u128_r(input.wrapping_neg() as u128, -round).map(|r| -r) } else { Self::from_u128_r(input as u128, round) } diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index a56d0678158..8fd4aad89c6 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -311,6 +311,9 @@ pub struct TargetOptions { pub relocation_model: String, /// Code model to use. Corresponds to `llc -code-model=$code_model`. Defaults to "default". pub code_model: String, + /// TLS model to use. Options are "global-dynamic" (default), "local-dynamic", "initial-exec" + /// and "local-exec". This is similar to the -ftls-model option in GCC/Clang. + pub tls_model: String, /// Do not emit code that uses the "red zone", if the ABI has one. Defaults to false. pub disable_redzone: bool, /// Eliminate frame pointers from stack frames if possible. Defaults to true. @@ -450,6 +453,7 @@ impl Default for TargetOptions { executables: false, relocation_model: "pic".to_string(), code_model: "default".to_string(), + tls_model: "global-dynamic".to_string(), disable_redzone: false, eliminate_frame_pointer: true, function_sections: true, @@ -696,6 +700,7 @@ impl Target { key!(executables, bool); key!(relocation_model); key!(code_model); + key!(tls_model); key!(disable_redzone, bool); key!(eliminate_frame_pointer, bool); key!(function_sections, bool); @@ -888,6 +893,7 @@ impl ToJson for Target { target_option_val!(executables); target_option_val!(relocation_model); target_option_val!(code_model); + target_option_val!(tls_model); target_option_val!(disable_redzone); target_option_val!(eliminate_frame_pointer); target_option_val!(function_sections); diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index c1d0d849dfb..908737669c5 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -484,7 +484,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { // 3. Where does old loan expire. let previous_end_span = - old_loan.kill_scope.span(self.tcx(), &self.bccx.region_scope_tree).end_point(); + Some(old_loan.kill_scope.span(self.tcx(), &self.bccx.region_scope_tree) + .end_point()); let mut err = match (new_loan.kind, old_loan.kind) { (ty::MutBorrow, ty::MutBorrow) => diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index add128cc2cf..6be07878487 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -47,7 +47,7 @@ use std::rc::Rc; use std::hash::{Hash, Hasher}; use syntax::ast; use syntax_pos::{MultiSpan, Span}; -use errors::DiagnosticBuilder; +use errors::{DiagnosticBuilder, DiagnosticId}; use rustc::hir; use rustc::hir::intravisit::{self, Visitor}; @@ -256,7 +256,7 @@ impl<'b, 'tcx: 'b> BorrowckErrors for BorrowckCtxt<'b, 'tcx> { fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self, sp: S, msg: &str, - code: &str) + code: DiagnosticId) -> DiagnosticBuilder<'a> { self.tcx.sess.struct_span_err_with_code(sp, msg, code) @@ -755,12 +755,17 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { pub fn struct_span_err_with_code<S: Into<MultiSpan>>(&self, s: S, msg: &str, - code: &str) + code: DiagnosticId) -> DiagnosticBuilder<'a> { self.tcx.sess.struct_span_err_with_code(s, msg, code) } - pub fn span_err_with_code<S: Into<MultiSpan>>(&self, s: S, msg: &str, code: &str) { + pub fn span_err_with_code<S: Into<MultiSpan>>( + &self, + s: S, + msg: &str, + code: DiagnosticId, + ) { self.tcx.sess.span_err_with_code(s, msg, code); } diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs index 08f3b0a4c5f..6ebe3c67966 100644 --- a/src/librustc_const_eval/_match.rs +++ b/src/librustc_const_eval/_match.rs @@ -208,6 +208,20 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { } } + fn is_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool { + match ty.sty { + ty::TyAdt(adt_def, ..) => adt_def.is_enum() && adt_def.is_non_exhaustive(), + _ => false, + } + } + + fn is_local(&self, ty: Ty<'tcx>) -> bool { + match ty.sty { + ty::TyAdt(adt_def, ..) => adt_def.did.is_local(), + _ => false, + } + } + fn is_variant_uninhabited(&self, variant: &'tcx ty::VariantDef, substs: &'tcx ty::subst::Substs<'tcx>) @@ -628,9 +642,16 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, let is_privately_empty = all_ctors.is_empty() && !cx.is_uninhabited(pcx.ty); - debug!("missing_ctors={:?} is_privately_empty={:?}", missing_ctors, - is_privately_empty); - if missing_ctors.is_empty() && !is_privately_empty { + let is_declared_nonexhaustive = + cx.is_non_exhaustive_enum(pcx.ty) && !cx.is_local(pcx.ty); + debug!("missing_ctors={:?} is_privately_empty={:?} is_declared_nonexhaustive={:?}", + missing_ctors, is_privately_empty, is_declared_nonexhaustive); + + // For privately empty and non-exhaustive enums, we work as if there were an "extra" + // `_` constructor for the type, so we can never match over all constructors. + let is_non_exhaustive = is_privately_empty || is_declared_nonexhaustive; + + if missing_ctors.is_empty() && !is_non_exhaustive { all_ctors.into_iter().map(|c| { is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness) }).find(|result| result.is_useful()).unwrap_or(NotUseful) @@ -645,7 +666,51 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, match is_useful(cx, &matrix, &v[1..], witness) { UsefulWithWitness(pats) => { let cx = &*cx; - let new_witnesses = if used_ctors.is_empty() { + // In this case, there's at least one "free" + // constructor that is only matched against by + // wildcard patterns. + // + // There are 2 ways we can report a witness here. + // Commonly, we can report all the "free" + // constructors as witnesses, e.g. if we have: + // + // ``` + // enum Direction { N, S, E, W } + // let Direction::N = ...; + // ``` + // + // we can report 3 witnesses: `S`, `E`, and `W`. + // + // However, there are 2 cases where we don't want + // to do this and instead report a single `_` witness: + // + // 1) If the user is matching against a non-exhaustive + // enum, there is no point in enumerating all possible + // variants, because the user can't actually match + // against them himself, e.g. in an example like: + // ``` + // let err: io::ErrorKind = ...; + // match err { + // io::ErrorKind::NotFound => {}, + // } + // ``` + // we don't want to show every possible IO error, + // but instead have `_` as the witness (this is + // actually *required* if the user specified *all* + // IO errors, but is probably what we want in every + // case). + // + // 2) If the user didn't actually specify a constructor + // in this arm, e.g. in + // ``` + // let x: (Direction, Direction, bool) = ...; + // let (_, _, false) = x; + // ``` + // we don't want to show all 16 possible witnesses + // `(<direction-1>, <direction-2>, true)` - we are + // satisfied with `(_, _, true)`. In this case, + // `used_ctors` is empty. + let new_witnesses = if is_non_exhaustive || used_ctors.is_empty() { // All constructors are unused. Add wild patterns // rather than each individual constructor pats.into_iter().map(|mut witness| { diff --git a/src/librustc_const_math/float.rs b/src/librustc_const_math/float.rs index b67048939e4..9d820ea8cbe 100644 --- a/src/librustc_const_math/float.rs +++ b/src/librustc_const_math/float.rs @@ -203,3 +203,11 @@ impl ::std::ops::Neg for ConstFloat { ConstFloat { bits, ty: self.ty } } } + +/// This is `f32::MAX + (0.5 ULP)` as an integer. Numbers greater or equal to this +/// are rounded to infinity when converted to `f32`. +/// +/// NB: Computed as maximum significand with an extra 1 bit added (for the half ULP) +/// shifted by the maximum exponent (accounting for normalization). +pub const MAX_F32_PLUS_HALF_ULP: u128 = ((1 << (Single::PRECISION + 1)) - 1) + << (Single::MAX_EXP - Single::PRECISION as i16); diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs index e8f9a672087..94edaa746f9 100644 --- a/src/librustc_data_structures/bitvec.rs +++ b/src/librustc_data_structures/bitvec.rs @@ -145,7 +145,7 @@ pub struct BitMatrix { } impl BitMatrix { - // Create a new `rows x columns` matrix, initially empty. + /// Create a new `rows x columns` matrix, initially empty. pub fn new(rows: usize, columns: usize) -> BitMatrix { // For every element, we need one bit for every other // element. Round up to an even number of u64s. @@ -163,9 +163,13 @@ impl BitMatrix { (start, start + u64s_per_row) } - pub fn add(&mut self, source: usize, target: usize) -> bool { - let (start, _) = self.range(source); - let (word, mask) = word_mask(target); + /// Sets the cell at `(row, column)` to true. Put another way, add + /// `column` to the bitset for `row`. + /// + /// Returns true if this changed the matrix, and false otherwies. + pub fn add(&mut self, row: usize, column: usize) -> bool { + let (start, _) = self.range(row); + let (word, mask) = word_mask(column); let vector = &mut self.vector[..]; let v1 = vector[start + word]; let v2 = v1 | mask; @@ -173,19 +177,19 @@ impl BitMatrix { v1 != v2 } - /// Do the bits from `source` contain `target`? - /// - /// Put another way, if the matrix represents (transitive) - /// reachability, can `source` reach `target`? - pub fn contains(&self, source: usize, target: usize) -> bool { - let (start, _) = self.range(source); - let (word, mask) = word_mask(target); + /// Do the bits from `row` contain `column`? Put another way, is + /// the matrix cell at `(row, column)` true? Put yet another way, + /// if the matrix represents (transitive) reachability, can + /// `row` reach `column`? + pub fn contains(&self, row: usize, column: usize) -> bool { + let (start, _) = self.range(row); + let (word, mask) = word_mask(column); (self.vector[start + word] & mask) != 0 } - /// Returns those indices that are reachable from both `a` and - /// `b`. This is an O(n) operation where `n` is the number of - /// elements (somewhat independent from the actual size of the + /// Returns those indices that are true in rows `a` and `b`. This + /// is an O(n) operation where `n` is the number of elements + /// (somewhat independent from the actual size of the /// intersection, in particular). pub fn intersection(&self, a: usize, b: usize) -> Vec<usize> { let (a_start, a_end) = self.range(a); @@ -206,7 +210,7 @@ impl BitMatrix { result } - /// Add the bits from `read` to the bits from `write`, + /// Add the bits from row `read` to the bits from row `write`, /// return true if anything changed. /// /// This is used when computing transitive reachability because if @@ -227,6 +231,8 @@ impl BitMatrix { changed } + /// Iterates through all the columns set to true in a given row of + /// the matrix. pub fn iter<'a>(&'a self, row: usize) -> BitVectorIter<'a> { let (start, end) = self.range(row); BitVectorIter { diff --git a/src/librustc_data_structures/indexed_set.rs b/src/librustc_data_structures/indexed_set.rs index c790463e47a..c5ffb003399 100644 --- a/src/librustc_data_structures/indexed_set.rs +++ b/src/librustc_data_structures/indexed_set.rs @@ -53,11 +53,19 @@ pub struct IdxSet<T: Idx> { } impl<T: Idx> fmt::Debug for IdxSetBuf<T> { - fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { self.bits.fmt(w) } + fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { + w.debug_list() + .entries(self.iter()) + .finish() + } } impl<T: Idx> fmt::Debug for IdxSet<T> { - fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { self.bits.fmt(w) } + fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { + w.debug_list() + .entries(self.iter()) + .finish() + } } impl<T: Idx> IdxSetBuf<T> { diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index 1d1b367de20..a733e9de5a1 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -45,74 +45,282 @@ macro_rules! newtype_index { // Use default constants ($name:ident) => ( newtype_index!( - @type[$name] - @max[::std::u32::MAX] - @debug_name[unsafe {::std::intrinsics::type_name::<$name>() }]); + // Leave out derives marker so we can use its absence to ensure it comes first + @type [$name] + @max [::std::u32::MAX] + @debug_format ["{}"]); ); // Define any constants ($name:ident { $($tokens:tt)+ }) => ( newtype_index!( - @type[$name] - @max[::std::u32::MAX] - @debug_name[unsafe {::std::intrinsics::type_name::<$name>() }] - $($tokens)+); + // Leave out derives marker so we can use its absence to ensure it comes first + @type [$name] + @max [::std::u32::MAX] + @debug_format ["{}"] + $($tokens)+); ); // ---- private rules ---- // Base case, user-defined constants (if any) have already been defined - (@type[$type:ident] @max[$max:expr] @debug_name[$debug_name:expr]) => ( - #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, - RustcEncodable, RustcDecodable)] - pub struct $type(pub u32); + (@derives [$($derives:ident,)*] + @pub [$($pub:tt)*] + @type [$type:ident] + @max [$max:expr] + @debug_format [$debug_format:tt]) => ( + #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, $($derives),*)] + pub struct $type($($pub)* u32); impl Idx for $type { fn new(value: usize) -> Self { assert!(value < ($max) as usize); $type(value as u32) } + fn index(self) -> usize { self.0 as usize } } + newtype_index!( + @handle_debug + @derives [$($derives,)*] + @type [$type] + @debug_format [$debug_format]); + ); + + // base case for handle_debug where format is custom. No Debug implementation is emitted. + (@handle_debug + @derives [$($_derives:ident,)*] + @type [$type:ident] + @debug_format [custom]) => (); + + // base case for handle_debug, no debug overrides found, so use default + (@handle_debug + @derives [] + @type [$type:ident] + @debug_format [$debug_format:tt]) => ( impl ::std::fmt::Debug for $type { fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - write!(fmt, "{}{}", $debug_name, self.0) + write!(fmt, $debug_format, self.0) } } ); + // Debug is requested for derive, don't generate any Debug implementation. + (@handle_debug + @derives [Debug, $($derives:ident,)*] + @type [$type:ident] + @debug_format [$debug_format:tt]) => (); + + // It's not Debug, so just pop it off the front of the derives stack and check the rest. + (@handle_debug + @derives [$_derive:ident, $($derives:ident,)*] + @type [$type:ident] + @debug_format [$debug_format:tt]) => ( + newtype_index!( + @handle_debug + @derives [$($derives,)*] + @type [$type] + @debug_format [$debug_format]); + ); + + // Handle the case where someone wants to make the internal field public + (@type [$type:ident] + @max [$max:expr] + @debug_format [$debug_format:tt] + pub idx + $($tokens:tt)*) => ( + newtype_index!( + @pub [pub] + @type [$type] + @max [$max] + @debug_format [$debug_format] + $($tokens)*); + ); + + // The default case is that the internal field is private + (@type [$type:ident] + @max [$max:expr] + @debug_format [$debug_format:tt] + $($tokens:tt)*) => ( + newtype_index!( + @pub [] + @type [$type] + @max [$max] + @debug_format [$debug_format] + $($tokens)*); + ); + + // Append comma to end of derives list if it's missing + (@pub [$($pub:tt)*] + @type [$type:ident] + @max [$max:expr] + @debug_format [$debug_format:tt] + derive [$($derives:ident),*] + $($tokens:tt)*) => ( + newtype_index!( + @pub [$($pub)*] + @type [$type] + @max [$max] + @debug_format [$debug_format] + derive [$($derives,)*] + $($tokens)*); + ); + + // By not including the @derives marker in this list nor in the default args, we can force it + // to come first if it exists. When encodable is custom, just use the derives list as-is. + (@pub [$($pub:tt)*] + @type [$type:ident] + @max [$max:expr] + @debug_format [$debug_format:tt] + derive [$($derives:ident,)+] + ENCODABLE = custom + $($tokens:tt)*) => ( + newtype_index!( + @derives [$($derives,)+] + @pub [$($pub)*] + @type [$type] + @max [$max] + @debug_format [$debug_format] + $($tokens)*); + ); + + // By not including the @derives marker in this list nor in the default args, we can force it + // to come first if it exists. When encodable isn't custom, add serialization traits by default. + (@pub [$($pub:tt)*] + @type [$type:ident] + @max [$max:expr] + @debug_format [$debug_format:tt] + derive [$($derives:ident,)+] + $($tokens:tt)*) => ( + newtype_index!( + @derives [$($derives,)+ RustcDecodable, RustcEncodable,] + @pub [$($pub)*] + @type [$type] + @max [$max] + @debug_format [$debug_format] + $($tokens)*); + ); + + // The case where no derives are added, but encodable is overriden. Don't + // derive serialization traits + (@pub [$($pub:tt)*] + @type [$type:ident] + @max [$max:expr] + @debug_format [$debug_format:tt] + ENCODABLE = custom + $($tokens:tt)*) => ( + newtype_index!( + @derives [] + @pub [$($pub)*] + @type [$type] + @max [$max] + @debug_format [$debug_format] + $($tokens)*); + ); + + // The case where no derives are added, add serialization derives by default + (@pub [$($pub:tt)*] + @type [$type:ident] + @max [$max:expr] + @debug_format [$debug_format:tt] + $($tokens:tt)*) => ( + newtype_index!( + @derives [RustcDecodable, RustcEncodable,] + @pub [$($pub)*] + @type [$type] + @max [$max] + @debug_format [$debug_format] + $($tokens)*); + ); + // Rewrite final without comma to one that includes comma - (@type[$type:ident] @max[$max:expr] @debug_name[$debug_name:expr] - $name:ident = $constant:expr) => ( - newtype_index!(@type[$type] @max[$max] @debug_name[$debug_name] $name = $constant,); + (@derives [$($derives:ident,)*] + @pub [$($pub:tt)*] + @type [$type:ident] + @max [$max:expr] + @debug_format [$debug_format:tt] + $name:ident = $constant:expr) => ( + newtype_index!( + @derives [$($derives,)*] + @pub [$($pub)*] + @type [$type] + @max [$max] + @debug_format [$debug_format] + $name = $constant,); ); // Rewrite final const without comma to one that includes comma - (@type[$type:ident] @max[$_max:expr] @debug_name[$debug_name:expr] - const $name:ident = $constant:expr) => ( - newtype_index!(@type[$type] @max[$max] @debug_name[$debug_name] const $name = $constant,); + (@derives [$($derives:ident,)*] + @pub [$($pub:tt)*] + @type [$type:ident] + @max [$_max:expr] + @debug_format [$debug_format:tt] + $(#[doc = $doc:expr])* + const $name:ident = $constant:expr) => ( + newtype_index!( + @derives [$($derives,)*] + @pub [$($pub)*] + @type [$type] + @max [$max] + @debug_format [$debug_format] + $(#[doc = $doc])* const $name = $constant,); ); // Replace existing default for max - (@type[$type:ident] @max[$_max:expr] @debug_name[$debug_name:expr] - MAX = $max:expr, $($tokens:tt)*) => ( - newtype_index!(@type[$type] @max[$max] @debug_name[$debug_name] $($tokens)*); + (@derives [$($derives:ident,)*] + @pub [$($pub:tt)*] + @type [$type:ident] + @max [$_max:expr] + @debug_format [$debug_format:tt] + MAX = $max:expr, + $($tokens:tt)*) => ( + newtype_index!( + @derives [$($derives,)*] + @pub [$($pub)*] + @type [$type] + @max [$max] + @debug_format [$debug_format] + $($tokens)*); ); - // Replace existing default for debug_name - (@type[$type:ident] @max[$max:expr] @debug_name[$_debug_name:expr] - DEBUG_NAME = $debug_name:expr, $($tokens:tt)*) => ( - newtype_index!(@type[$type] @max[$max] @debug_name[$debug_name] $($tokens)*); + // Replace existing default for debug_format + (@derives [$($derives:ident,)*] + @pub [$($pub:tt)*] + @type [$type:ident] + @max [$max:expr] + @debug_format [$_debug_format:tt] + DEBUG_FORMAT = $debug_format:tt, + $($tokens:tt)*) => ( + newtype_index!( + @derives [$($derives,)*] + @pub [$($pub)*] + @type [$type] + @max [$max] + @debug_format [$debug_format] + $($tokens)*); ); - // Assign a user-defined constant (as final param) - (@type[$type:ident] @max[$max:expr] @debug_name[$debug_name:expr] - const $name:ident = $constant:expr, $($tokens:tt)*) => ( + // Assign a user-defined constant + (@derives [$($derives:ident,)*] + @pub [$($pub:tt)*] + @type [$type:ident] + @max [$max:expr] + @debug_format [$debug_format:tt] + $(#[doc = $doc:expr])* + const $name:ident = $constant:expr, + $($tokens:tt)*) => ( + $(#[doc = $doc])* pub const $name: $type = $type($constant); - newtype_index!(@type[$type] @max[$max] @debug_name[$debug_name] $($tokens)*); + newtype_index!( + @derives [$($derives,)*] + @pub [$($pub)*] + @type [$type] + @max [$max] + @debug_format [$debug_format] + $($tokens)*); ); } diff --git a/src/librustc_data_structures/transitive_relation.rs b/src/librustc_data_structures/transitive_relation.rs index 7cb386b0197..933e08811ce 100644 --- a/src/librustc_data_structures/transitive_relation.rs +++ b/src/librustc_data_structures/transitive_relation.rs @@ -134,12 +134,12 @@ impl<T: Clone + Debug + Eq + Hash + Clone> TransitiveRelation<T> { } } - /// Returns a vector of all things less than `a`. + /// Returns a vector of all things greater than `a`. /// /// Really this probably ought to be `impl Iterator<Item=&T>`, but /// I'm too lazy to make that work, and -- given the caching /// strategy -- it'd be a touch tricky anyhow. - pub fn less_than(&self, a: &T) -> Vec<&T> { + pub fn greater_than(&self, a: &T) -> Vec<&T> { match self.index(a) { Some(a) => self.with_closure(|closure| { closure.iter(a.0).map(|i| &self.elements[i]).collect() diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index cd3740f72e0..855362cf645 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -940,6 +940,10 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, let time_passes = sess.time_passes(); + let query_result_on_disk_cache = time(time_passes, + "load query result cache", + || rustc_incremental::load_query_result_cache(sess)); + let named_region_map = time(time_passes, "lifetime resolution", || middle::resolve_lifetime::krate(sess, cstore, &hir_map))?; @@ -1003,7 +1007,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, passes.push_pass(MIR_VALIDATED, mir::transform::qualify_consts::QualifyAndPromoteConstants); passes.push_pass(MIR_VALIDATED, mir::transform::simplify::SimplifyCfg::new("qualify-consts")); - passes.push_pass(MIR_VALIDATED, mir::transform::nll::NLL); // borrowck runs between MIR_VALIDATED and MIR_OPTIMIZED. @@ -1048,6 +1051,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, resolutions, named_region_map, hir_map, + query_result_on_disk_cache, name, tx, output_filenames, diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index fc503f4eb4b..c5cce70c945 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -177,6 +177,7 @@ mod rustc_trans { pub mod write { pub const RELOC_MODEL_ARGS: [(&'static str, ()); 0] = []; pub const CODE_GEN_MODEL_ARGS: [(&'static str, ()); 0] = []; + pub const TLS_MODEL_ARGS: [(&'static str, ()); 0] = []; } } } @@ -797,6 +798,13 @@ impl RustcDefaultCalls { } println!(""); } + PrintRequest::TlsModels => { + println!("Available TLS models:"); + for &(name, _) in rustc_trans::back::write::TLS_MODEL_ARGS.iter(){ + println!(" {}", name); + } + println!(""); + } PrintRequest::TargetCPUs | PrintRequest::TargetFeatures => { rustc_trans::print(*req, sess); } diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 6de36820f0c..5ff75351b63 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -23,6 +23,7 @@ use rustc::middle::resolve_lifetime; use rustc::ty::subst::{Kind, Subst}; use rustc::traits::{ObligationCause, Reveal}; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::maps::OnDiskCache; use rustc::infer::{self, InferOk, InferResult}; use rustc::infer::type_variable::TypeVariableOrigin; use rustc_metadata::cstore::CStore; @@ -156,6 +157,7 @@ fn test_env<F>(source_string: &str, resolutions, named_region_map.unwrap(), hir_map, + OnDiskCache::new_empty(sess.codemap()), "test_crate", tx, &outputs, @@ -251,7 +253,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { hir::ItemUnion(..) | hir::ItemTrait(..) | hir::ItemImpl(..) | - hir::ItemDefaultImpl(..) => None, + hir::ItemAutoImpl(..) => None, hir::ItemMod(ref m) => search_mod(this, m, idx, names), }; diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs index 5e0e624082e..2d70de89355 100644 --- a/src/librustc_errors/diagnostic.rs +++ b/src/librustc_errors/diagnostic.rs @@ -21,12 +21,18 @@ use snippet::Style; pub struct Diagnostic { pub level: Level, pub message: Vec<(String, Style)>, - pub code: Option<String>, + pub code: Option<DiagnosticId>, pub span: MultiSpan, pub children: Vec<SubDiagnostic>, pub suggestions: Vec<CodeSuggestion>, } +#[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)] +pub enum DiagnosticId { + Error(String), + Lint(String), +} + /// For example a note attached to an error. #[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)] pub struct SubDiagnostic { @@ -81,7 +87,7 @@ impl Diagnostic { Diagnostic::new_with_code(level, None, message) } - pub fn new_with_code(level: Level, code: Option<String>, message: &str) -> Self { + pub fn new_with_code(level: Level, code: Option<DiagnosticId>, message: &str) -> Self { Diagnostic { level, message: vec![(message.to_owned(), Style::NoStyle)], @@ -267,7 +273,7 @@ impl Diagnostic { self } - pub fn code(&mut self, s: String) -> &mut Self { + pub fn code(&mut self, s: DiagnosticId) -> &mut Self { self.code = Some(s); self } diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs index 2cd433bfe3a..40b5810454b 100644 --- a/src/librustc_errors/diagnostic_builder.rs +++ b/src/librustc_errors/diagnostic_builder.rs @@ -9,6 +9,7 @@ // except according to those terms. use Diagnostic; +use DiagnosticId; use DiagnosticStyledString; use Level; @@ -192,7 +193,7 @@ impl<'a> DiagnosticBuilder<'a> { suggestions: Vec<String>) -> &mut Self); forward!(pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self); - forward!(pub fn code(&mut self, s: String) -> &mut Self); + forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self); /// Convenience function for internal use, clients should use one of the /// struct_* methods on Handler. @@ -204,7 +205,7 @@ impl<'a> DiagnosticBuilder<'a> { /// struct_* methods on Handler. pub fn new_with_code(handler: &'a Handler, level: Level, - code: Option<String>, + code: Option<DiagnosticId>, message: &str) -> DiagnosticBuilder<'a> { let diagnostic = Diagnostic::new_with_code(level, code, message); diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 5db5a9a1133..6c43c60686e 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -10,9 +10,9 @@ use self::Destination::*; -use syntax_pos::{DUMMY_SP, FileMap, Span, MultiSpan, CharPos}; +use syntax_pos::{DUMMY_SP, FileMap, Span, MultiSpan}; -use {Level, CodeSuggestion, DiagnosticBuilder, SubDiagnostic, CodeMapper}; +use {Level, CodeSuggestion, DiagnosticBuilder, SubDiagnostic, CodeMapper, DiagnosticId}; use RenderSpan::*; use snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, StyledString, Style}; use styled_buffer::StyledBuffer; @@ -201,8 +201,8 @@ impl EmitterWriter { // 6..7. This is degenerate input, but it's best to degrade // gracefully -- and the parser likes to supply a span like // that for EOF, in particular. - if lo.col == hi.col && lo.line == hi.line { - hi.col = CharPos(lo.col.0 + 1); + if lo.col_display == hi.col_display && lo.line == hi.line { + hi.col_display += 1; } let ann_type = if lo.line != hi.line { @@ -210,8 +210,8 @@ impl EmitterWriter { depth: 1, line_start: lo.line, line_end: hi.line, - start_col: lo.col.0, - end_col: hi.col.0, + start_col: lo.col_display, + end_col: hi.col_display, is_primary: span_label.is_primary, label: span_label.label.clone(), }; @@ -221,8 +221,8 @@ impl EmitterWriter { AnnotationType::Singleline }; let ann = Annotation { - start_col: lo.col.0, - end_col: hi.col.0, + start_col: lo.col_display, + end_col: hi.col_display, is_primary: span_label.is_primary, label: span_label.label.clone(), annotation_type: ann_type, @@ -886,7 +886,7 @@ impl EmitterWriter { fn emit_message_default(&mut self, msp: &MultiSpan, msg: &Vec<(String, Style)>, - code: &Option<String>, + code: &Option<DiagnosticId>, level: &Level, max_line_num_len: usize, is_secondary: bool) @@ -905,13 +905,11 @@ impl EmitterWriter { self.msg_to_buffer(&mut buffer, msg, max_line_num_len, "note", None); } else { buffer.append(0, &level.to_string(), Style::Level(level.clone())); - match code { - &Some(ref code) => { - buffer.append(0, "[", Style::Level(level.clone())); - buffer.append(0, &code, Style::Level(level.clone())); - buffer.append(0, "]", Style::Level(level.clone())); - } - _ => {} + // only render error codes, not lint codes + if let Some(DiagnosticId::Error(ref code)) = *code { + buffer.append(0, "[", Style::Level(level.clone())); + buffer.append(0, &code, Style::Level(level.clone())); + buffer.append(0, "]", Style::Level(level.clone())); } buffer.append(0, ": ", Style::HeaderMsg); for &(ref text, _) in msg.iter() { @@ -1174,7 +1172,7 @@ impl EmitterWriter { fn emit_messages_default(&mut self, level: &Level, message: &Vec<(String, Style)>, - code: &Option<String>, + code: &Option<DiagnosticId>, span: &MultiSpan, children: &Vec<SubDiagnostic>) { let max_line_num = self.get_max_line_num(span, children); diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index ba7268a4bc3..b30ee7016ab 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -262,7 +262,7 @@ impl error::Error for ExplicitBug { } } -pub use diagnostic::{Diagnostic, SubDiagnostic, DiagnosticStyledString}; +pub use diagnostic::{Diagnostic, SubDiagnostic, DiagnosticStyledString, DiagnosticId}; pub use diagnostic_builder::DiagnosticBuilder; /// A handler deals with errors; certain errors @@ -337,11 +337,11 @@ impl Handler { pub fn struct_span_warn_with_code<'a, S: Into<MultiSpan>>(&'a self, sp: S, msg: &str, - code: &str) + code: DiagnosticId) -> DiagnosticBuilder<'a> { let mut result = DiagnosticBuilder::new(self, Level::Warning, msg); result.set_span(sp); - result.code(code.to_owned()); + result.code(code); if !self.can_emit_warnings { result.cancel(); } @@ -365,20 +365,24 @@ impl Handler { pub fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self, sp: S, msg: &str, - code: &str) + code: DiagnosticId) -> DiagnosticBuilder<'a> { let mut result = DiagnosticBuilder::new(self, Level::Error, msg); result.set_span(sp); - result.code(code.to_owned()); + result.code(code); result } // FIXME: This method should be removed (every error should have an associated error code). pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> { DiagnosticBuilder::new(self, Level::Error, msg) } - pub fn struct_err_with_code<'a>(&'a self, msg: &str, code: &str) -> DiagnosticBuilder<'a> { + pub fn struct_err_with_code<'a>( + &'a self, + msg: &str, + code: DiagnosticId, + ) -> DiagnosticBuilder<'a> { let mut result = DiagnosticBuilder::new(self, Level::Error, msg); - result.code(code.to_owned()); + result.code(code); result } pub fn struct_span_fatal<'a, S: Into<MultiSpan>>(&'a self, @@ -392,11 +396,11 @@ impl Handler { pub fn struct_span_fatal_with_code<'a, S: Into<MultiSpan>>(&'a self, sp: S, msg: &str, - code: &str) + code: DiagnosticId) -> DiagnosticBuilder<'a> { let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg); result.set_span(sp); - result.code(code.to_owned()); + result.code(code); result } pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> { @@ -420,7 +424,7 @@ impl Handler { pub fn span_fatal_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, - code: &str) + code: DiagnosticId) -> FatalError { self.emit_with_code(&sp.into(), msg, code, Fatal); FatalError @@ -436,13 +440,13 @@ impl Handler { result.set_span(sp); result } - pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) { + pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) { self.emit_with_code(&sp.into(), msg, code, Error); } pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) { self.emit(&sp.into(), msg, Warning); } - pub fn span_warn_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) { + pub fn span_warn_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) { self.emit_with_code(&sp.into(), msg, code, Warning); } pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! { @@ -546,11 +550,11 @@ impl Handler { self.abort_if_errors(); } } - pub fn emit_with_code(&self, msp: &MultiSpan, msg: &str, code: &str, lvl: Level) { + pub fn emit_with_code(&self, msp: &MultiSpan, msg: &str, code: DiagnosticId, lvl: Level) { if lvl == Warning && !self.can_emit_warnings { return; } - let mut db = DiagnosticBuilder::new_with_code(self, lvl, Some(code.to_owned()), msg); + let mut db = DiagnosticBuilder::new_with_code(self, lvl, Some(code), msg); db.set_span(msp.clone()); db.emit(); if !self.continue_after_error.get() { diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 0294adb3f5d..e82c2897d21 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -17,6 +17,9 @@ #![feature(rand)] #![feature(conservative_impl_trait)] +#![feature(i128_type)] +#![feature(inclusive_range_syntax)] +#![feature(specialization)] extern crate graphviz; #[macro_use] extern crate rustc; @@ -31,8 +34,9 @@ mod assert_dep_graph; mod persist; pub use assert_dep_graph::assert_dep_graph; -pub use persist::load_dep_graph; pub use persist::dep_graph_tcx_init; +pub use persist::load_dep_graph; +pub use persist::load_query_result_cache; pub use persist::save_dep_graph; pub use persist::save_trans_partition; pub use persist::save_work_products; diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index 0cb920a111d..e871c0dbdab 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -409,7 +409,7 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> { //HirItem::ItemTrait(..) => ("ItemTrait", LABELS_TRAIT), // `impl Trait for .. {}` - HirItem::ItemDefaultImpl(..) => ("ItemDefaultImpl", LABELS_IMPL), + HirItem::ItemAutoImpl(..) => ("ItemAutoImpl", LABELS_IMPL), // An implementation, eg `impl<A> Trait for Foo { .. }` HirItem::ItemImpl(..) => ("ItemImpl", LABELS_IMPL), diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs index 89310b9d6f5..458f47a1602 100644 --- a/src/librustc_incremental/persist/fs.rs +++ b/src/librustc_incremental/persist/fs.rs @@ -131,6 +131,7 @@ const LOCK_FILE_EXT: &'static str = ".lock"; const DEP_GRAPH_FILENAME: &'static str = "dep-graph.bin"; const WORK_PRODUCTS_FILENAME: &'static str = "work-products.bin"; const METADATA_HASHES_FILENAME: &'static str = "metadata.bin"; +const QUERY_CACHE_FILENAME: &'static str = "query-cache.bin"; // We encode integers using the following base, so they are shorter than decimal // or hexadecimal numbers (we want short file and directory names). Since these @@ -150,6 +151,10 @@ pub fn metadata_hash_export_path(sess: &Session) -> PathBuf { in_incr_comp_dir_sess(sess, METADATA_HASHES_FILENAME) } +pub fn query_cache_path(sess: &Session) -> PathBuf { + in_incr_comp_dir_sess(sess, QUERY_CACHE_FILENAME) +} + pub fn lock_file_path(session_dir: &Path) -> PathBuf { let crate_dir = session_dir.parent().unwrap(); diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index 63cfbcac145..158e9f2677a 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -15,6 +15,7 @@ use rustc::hir::svh::Svh; use rustc::ich::Fingerprint; use rustc::session::Session; use rustc::ty::TyCtxt; +use rustc::ty::maps::OnDiskCache; use rustc::util::nodemap::DefIdMap; use rustc_serialize::Decodable as RustcDecodable; use rustc_serialize::opaque::Decoder; @@ -195,3 +196,15 @@ pub fn load_dep_graph(sess: &Session) -> PreviousDepGraph { empty } } + +pub fn load_query_result_cache<'sess>(sess: &'sess Session) -> OnDiskCache<'sess> { + if sess.opts.incremental.is_none() { + return OnDiskCache::new_empty(sess.codemap()); + } + + if let Some(bytes) = load_data(sess, &query_cache_path(sess)) { + OnDiskCache::new(sess, &bytes[..]) + } else { + OnDiskCache::new_empty(sess.codemap()) + } +} diff --git a/src/librustc_incremental/persist/mod.rs b/src/librustc_incremental/persist/mod.rs index 88d49e7aedc..82a43d85bc6 100644 --- a/src/librustc_incremental/persist/mod.rs +++ b/src/librustc_incremental/persist/mod.rs @@ -23,8 +23,9 @@ mod file_format; pub use self::fs::prepare_session_directory; pub use self::fs::finalize_session_directory; pub use self::fs::in_incr_comp_dir; -pub use self::load::load_dep_graph; pub use self::load::dep_graph_tcx_init; +pub use self::load::load_dep_graph; +pub use self::load::load_query_result_cache; pub use self::save::save_dep_graph; pub use self::save::save_work_products; pub use self::work_product::save_trans_partition; diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index b9f73500e27..711550c27d1 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -63,6 +63,12 @@ pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e)); } + time(sess.time_passes(), "persist query result cache", || { + save_in(sess, + query_cache_path(sess), + |e| encode_query_cache(tcx, e)); + }); + time(sess.time_passes(), "persist dep-graph", || { save_in(sess, dep_graph_path(sess), @@ -298,3 +304,9 @@ fn encode_work_products(dep_graph: &DepGraph, work_products.encode(encoder) } + +fn encode_query_cache(tcx: TyCtxt, + encoder: &mut Encoder) + -> io::Result<()> { + tcx.serialize_query_result_cache(encoder) +} diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs index 027ed84faf0..d14a6943fc1 100644 --- a/src/librustc_lint/bad_style.rs +++ b/src/librustc_lint/bad_style.rs @@ -23,7 +23,7 @@ use rustc::hir::intravisit::FnKind; #[derive(PartialEq)] pub enum MethodLateContext { - TraitDefaultImpl, + TraitAutoImpl, TraitImpl, PlainImpl, } @@ -32,7 +32,7 @@ pub fn method_context(cx: &LateContext, id: ast::NodeId) -> MethodLateContext { let def_id = cx.tcx.hir.local_def_id(id); let item = cx.tcx.associated_item(def_id); match item.container { - ty::TraitContainer(..) => MethodLateContext::TraitDefaultImpl, + ty::TraitContainer(..) => MethodLateContext::TraitAutoImpl, ty::ImplContainer(cid) => { match cx.tcx.impl_trait_ref(cid) { Some(_) => MethodLateContext::TraitImpl, @@ -245,7 +245,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase { MethodLateContext::PlainImpl => { self.check_snake_case(cx, "method", &name.as_str(), Some(span)) } - MethodLateContext::TraitDefaultImpl => { + MethodLateContext::TraitAutoImpl => { self.check_snake_case(cx, "trait method", &name.as_str(), Some(span)) } _ => (), diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 70cac419648..07874a8cc69 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -56,6 +56,31 @@ use bad_style::{MethodLateContext, method_context}; pub use lint::builtin::*; declare_lint! { + pub AUTO_IMPL, + Deny, + "The form `impl Foo for .. {}` will be removed, please use `auto trait Foo {}`" +} + +#[derive(Copy, Clone)] +pub struct AutoImpl; + +impl LintPass for AutoImpl { + fn get_lints(&self) -> LintArray { + lint_array!(AUTO_IMPL) + } +} + +impl EarlyLintPass for AutoImpl { + fn check_item(&mut self, cx: &EarlyContext, item: &ast::Item) { + let msg = "The form `impl Foo for .. {}` will be removed, please use `auto trait Foo {}`"; + match item.node { + ast::ItemKind::AutoImpl(..) => cx.span_lint(AUTO_IMPL, item.span, msg), + _ => () + } + } +} + +declare_lint! { WHILE_TRUE, Warn, "suggest using `loop { }` instead of `while true { }`" @@ -228,7 +253,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnsafeCode { fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { match it.node { - hir::ItemTrait(hir::Unsafety::Unsafe, ..) => { + hir::ItemTrait(_, hir::Unsafety::Unsafe, ..) => { self.report_unsafe(cx, it.span, "declaration of an `unsafe` trait") } @@ -1301,3 +1326,60 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnionsWithDropFields { } } } + +/// Lint for items marked `pub` that aren't reachable from other crates +pub struct UnreachablePub; + +declare_lint! { + UNREACHABLE_PUB, + Allow, + "`pub` items not reachable from crate root" +} + +impl LintPass for UnreachablePub { + fn get_lints(&self) -> LintArray { + lint_array!(UNREACHABLE_PUB) + } +} + +impl UnreachablePub { + fn perform_lint(&self, cx: &LateContext, what: &str, id: ast::NodeId, + vis: &hir::Visibility, span: Span, exportable: bool) { + if !cx.access_levels.is_reachable(id) && *vis == hir::Visibility::Public { + let def_span = cx.tcx.sess.codemap().def_span(span); + let mut err = cx.struct_span_lint(UNREACHABLE_PUB, def_span, + &format!("unreachable `pub` {}", what)); + // visibility is token at start of declaration (can be macro + // variable rather than literal `pub`) + let pub_span = cx.tcx.sess.codemap().span_until_char(def_span, ' '); + let replacement = if cx.tcx.sess.features.borrow().crate_visibility_modifier { + "crate" + } else { + "pub(crate)" + }.to_owned(); + err.span_suggestion(pub_span, "consider restricting its visibility", replacement); + if exportable { + err.help("or consider exporting it for use by other crates"); + } + err.emit(); + } + } +} + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnreachablePub { + fn check_item(&mut self, cx: &LateContext, item: &hir::Item) { + self.perform_lint(cx, "item", item.id, &item.vis, item.span, true); + } + + fn check_foreign_item(&mut self, cx: &LateContext, foreign_item: &hir::ForeignItem) { + self.perform_lint(cx, "item", foreign_item.id, &foreign_item.vis, foreign_item.span, true); + } + + fn check_struct_field(&mut self, cx: &LateContext, field: &hir::StructField) { + self.perform_lint(cx, "field", field.id, &field.vis, field.span, false); + } + + fn check_impl_item(&mut self, cx: &LateContext, impl_item: &hir::ImplItem) { + self.perform_lint(cx, "item", impl_item.id, &impl_item.vis, impl_item.span, false); + } +} diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 42fcf377d65..1a8ad9718cf 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -109,6 +109,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { AnonymousParameters, IllegalFloatLiteralPattern, UnusedDocComment, + AutoImpl, ); add_early_builtin_with_new!(sess, @@ -137,6 +138,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { PluginAsLibrary, MutableTransmutes, UnionsWithDropFields, + UnreachablePub, ); add_builtin_with_new!(sess, @@ -182,6 +184,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { store.register_future_incompatible(sess, vec![ FutureIncompatibleInfo { + id: LintId::of(AUTO_IMPL), + reference: "issue #13231 <https://github.com/rust-lang/rust/issues/13231>", + }, + FutureIncompatibleInfo { id: LintId::of(PRIVATE_IN_PUBLIC), reference: "issue #34537 <https://github.com/rust-lang/rust/issues/34537>", }, diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 3399bf2acd8..ac0e4dde0c1 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -359,6 +359,17 @@ pub struct ThinLTOModule { pub len: usize, } +/// LLVMThreadLocalMode +#[derive(Copy, Clone)] +#[repr(C)] +pub enum ThreadLocalMode { + NotThreadLocal, + GeneralDynamic, + LocalDynamic, + InitialExec, + LocalExec +} + // Opaque pointer types #[allow(missing_copy_implementations)] pub enum Module_opaque {} @@ -709,6 +720,7 @@ extern "C" { pub fn LLVMGetInitializer(GlobalVar: ValueRef) -> ValueRef; pub fn LLVMSetInitializer(GlobalVar: ValueRef, ConstantVal: ValueRef); pub fn LLVMSetThreadLocal(GlobalVar: ValueRef, IsThreadLocal: Bool); + pub fn LLVMSetThreadLocalMode(GlobalVar: ValueRef, Mode: ThreadLocalMode); pub fn LLVMIsGlobalConstant(GlobalVar: ValueRef) -> Bool; pub fn LLVMSetGlobalConstant(GlobalVar: ValueRef, IsConstant: Bool); pub fn LLVMRustGetNamedValue(M: ModuleRef, Name: *const c_char) -> ValueRef; diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 98172bca177..5ccce8de706 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -172,6 +172,11 @@ pub fn set_thread_local(global: ValueRef, is_thread_local: bool) { LLVMSetThreadLocal(global, is_thread_local as Bool); } } +pub fn set_thread_local_mode(global: ValueRef, mode: ThreadLocalMode) { + unsafe { + LLVMSetThreadLocalMode(global, mode); + } +} impl Attribute { pub fn apply_llfn(&self, idx: AttributePlace, llfn: ValueRef) { diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index cfc8d271327..155097cdbe2 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -258,14 +258,15 @@ impl<'a> CrateLoader<'a> { let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span, dep_kind); let def_path_table = record_time(&self.sess.perf_stats.decode_def_path_tables_time, || { - crate_root.def_path_table.decode(&metadata) + crate_root.def_path_table.decode((&metadata, self.sess)) }); - let exported_symbols = crate_root.exported_symbols.decode(&metadata).collect(); - + let exported_symbols = crate_root.exported_symbols + .decode((&metadata, self.sess)) + .collect(); let trait_impls = crate_root .impls - .decode(&metadata) + .decode((&metadata, self.sess)) .map(|trait_impls| (trait_impls.trait_id, trait_impls.impls)) .collect(); @@ -298,7 +299,7 @@ impl<'a> CrateLoader<'a> { let dllimports: FxHashSet<_> = cmeta .root .native_libraries - .decode(&cmeta) + .decode((&cmeta, self.sess)) .filter(|lib| relevant_lib(self.sess, lib) && lib.kind == cstore::NativeLibraryKind::NativeUnknown) .flat_map(|lib| { @@ -685,14 +686,15 @@ impl<'a> CrateLoader<'a> { let mut needs_panic_runtime = attr::contains_name(&krate.attrs, "needs_panic_runtime"); + let sess = self.sess; self.cstore.iter_crate_data(|cnum, data| { needs_panic_runtime = needs_panic_runtime || - data.needs_panic_runtime(); - if data.is_panic_runtime() { + data.needs_panic_runtime(sess); + if data.is_panic_runtime(sess) { // Inject a dependency from all #![needs_panic_runtime] to this // #![panic_runtime] crate. self.inject_dependency_if(cnum, "a panic runtime", - &|data| data.needs_panic_runtime()); + &|data| data.needs_panic_runtime(sess)); runtime_found = runtime_found || data.dep_kind.get() == DepKind::Explicit; } }); @@ -728,7 +730,7 @@ impl<'a> CrateLoader<'a> { // Sanity check the loaded crate to ensure it is indeed a panic runtime // and the panic strategy is indeed what we thought it was. - if !data.is_panic_runtime() { + if !data.is_panic_runtime(self.sess) { self.sess.err(&format!("the crate `{}` is not a panic runtime", name)); } @@ -740,7 +742,7 @@ impl<'a> CrateLoader<'a> { self.sess.injected_panic_runtime.set(Some(cnum)); self.inject_dependency_if(cnum, "a panic runtime", - &|data| data.needs_panic_runtime()); + &|data| data.needs_panic_runtime(self.sess)); } fn inject_sanitizer_runtime(&mut self) { @@ -835,7 +837,7 @@ impl<'a> CrateLoader<'a> { PathKind::Crate, dep_kind); // Sanity check the loaded crate to ensure it is indeed a sanitizer runtime - if !data.is_sanitizer_runtime() { + if !data.is_sanitizer_runtime(self.sess) { self.sess.err(&format!("the crate `{}` is not a sanitizer runtime", name)); } @@ -856,7 +858,7 @@ impl<'a> CrateLoader<'a> { PathKind::Crate, dep_kind); // Sanity check the loaded crate to ensure it is indeed a profiler runtime - if !data.is_profiler_runtime() { + if !data.is_profiler_runtime(self.sess) { self.sess.err(&format!("the crate `profiler_builtins` is not \ a profiler runtime")); } @@ -875,7 +877,7 @@ impl<'a> CrateLoader<'a> { let mut needs_allocator = attr::contains_name(&krate.attrs, "needs_allocator"); self.cstore.iter_crate_data(|_, data| { - needs_allocator = needs_allocator || data.needs_allocator(); + needs_allocator = needs_allocator || data.needs_allocator(self.sess); }); if !needs_allocator { return @@ -997,7 +999,7 @@ impl<'a> CrateLoader<'a> { Some(data) => { // We have an allocator. We detect separately what kind it is, to allow for some // flexibility in misconfiguration. - let attrs = data.get_item_attrs(CRATE_DEF_INDEX); + let attrs = data.get_item_attrs(CRATE_DEF_INDEX, self.sess); let kind_interned = attr::first_attr_value_str_by_name(&attrs, "rustc_alloc_kind") .map(Symbol::as_str); let kind_str = kind_interned diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index c688b4c408a..a86b55e269d 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -17,7 +17,7 @@ use rustc::hir::def_id::{CRATE_DEF_INDEX, CrateNum, DefIndex}; use rustc::hir::map::definitions::DefPathTable; use rustc::hir::svh::Svh; use rustc::middle::cstore::{DepKind, ExternCrate, MetadataLoader}; -use rustc::session::CrateDisambiguator; +use rustc::session::{Session, CrateDisambiguator}; use rustc_back::PanicStrategy; use rustc_data_structures::indexed_vec::IndexVec; use rustc::util::nodemap::{FxHashMap, FxHashSet, NodeMap}; @@ -176,8 +176,8 @@ impl CrateMetadata { self.root.disambiguator } - pub fn needs_allocator(&self) -> bool { - let attrs = self.get_item_attrs(CRATE_DEF_INDEX); + pub fn needs_allocator(&self, sess: &Session) -> bool { + let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess); attr::contains_name(&attrs, "needs_allocator") } @@ -189,43 +189,43 @@ impl CrateMetadata { self.root.has_default_lib_allocator.clone() } - pub fn is_panic_runtime(&self) -> bool { - let attrs = self.get_item_attrs(CRATE_DEF_INDEX); + pub fn is_panic_runtime(&self, sess: &Session) -> bool { + let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess); attr::contains_name(&attrs, "panic_runtime") } - pub fn needs_panic_runtime(&self) -> bool { - let attrs = self.get_item_attrs(CRATE_DEF_INDEX); + pub fn needs_panic_runtime(&self, sess: &Session) -> bool { + let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess); attr::contains_name(&attrs, "needs_panic_runtime") } - pub fn is_compiler_builtins(&self) -> bool { - let attrs = self.get_item_attrs(CRATE_DEF_INDEX); + pub fn is_compiler_builtins(&self, sess: &Session) -> bool { + let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess); attr::contains_name(&attrs, "compiler_builtins") } - pub fn is_sanitizer_runtime(&self) -> bool { - let attrs = self.get_item_attrs(CRATE_DEF_INDEX); + pub fn is_sanitizer_runtime(&self, sess: &Session) -> bool { + let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess); attr::contains_name(&attrs, "sanitizer_runtime") } - pub fn is_profiler_runtime(&self) -> bool { - let attrs = self.get_item_attrs(CRATE_DEF_INDEX); + pub fn is_profiler_runtime(&self, sess: &Session) -> bool { + let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess); attr::contains_name(&attrs, "profiler_runtime") } - pub fn is_no_builtins(&self) -> bool { - let attrs = self.get_item_attrs(CRATE_DEF_INDEX); + pub fn is_no_builtins(&self, sess: &Session) -> bool { + let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess); attr::contains_name(&attrs, "no_builtins") } - pub fn has_copy_closures(&self) -> bool { - let attrs = self.get_item_attrs(CRATE_DEF_INDEX); + pub fn has_copy_closures(&self, sess: &Session) -> bool { + let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess); attr::contains_feature_attr(&attrs, "copy_closures") } - pub fn has_clone_closures(&self) -> bool { - let attrs = self.get_item_attrs(CRATE_DEF_INDEX); + pub fn has_clone_closures(&self, sess: &Session) -> bool { + let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess); attr::contains_feature_attr(&attrs, "clone_closures") } diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index fbe63e0ab4a..8dcfb4c34b5 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -99,11 +99,13 @@ impl IntoArgs for (CrateNum, DefId) { provide! { <'tcx> tcx, def_id, other, cdata, type_of => { cdata.get_type(def_id.index, tcx) } - generics_of => { tcx.alloc_generics(cdata.get_generics(def_id.index)) } + generics_of => { + tcx.alloc_generics(cdata.get_generics(def_id.index, tcx.sess)) + } predicates_of => { cdata.get_predicates(def_id.index, tcx) } super_predicates_of => { cdata.get_super_predicates(def_id.index, tcx) } trait_def => { - tcx.alloc_trait_def(cdata.get_trait_def(def_id.index)) + tcx.alloc_trait_def(cdata.get_trait_def(def_id.index, tcx.sess)) } adt_def => { cdata.get_adt_def(def_id.index, tcx) } adt_destructor => { @@ -144,7 +146,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, inherent_impls => { Rc::new(cdata.get_inherent_implementations_for_type(def_id.index)) } is_const_fn => { cdata.is_const_fn(def_id.index) } is_foreign_item => { cdata.is_foreign_item(def_id.index) } - is_default_impl => { cdata.is_default_impl(def_id.index) } + is_auto_impl => { cdata.is_auto_impl(def_id.index) } describe_def => { cdata.get_def(def_id.index) } def_span => { cdata.get_span(def_id.index, &tcx.sess) } lookup_stability => { @@ -153,7 +155,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, lookup_deprecation_entry => { cdata.get_deprecation(def_id.index).map(DeprecationEntry::external) } - item_attrs => { cdata.get_item_attrs(def_id.index) } + item_attrs => { cdata.get_item_attrs(def_id.index, tcx.sess) } // FIXME(#38501) We've skipped a `read` on the `HirBody` of // a `fn` when encoding, so the dep-tracking wouldn't work. // This is only used by rustdoc anyway, which shouldn't have @@ -171,17 +173,17 @@ provide! { <'tcx> tcx, def_id, other, cdata, is_mir_available => { cdata.is_item_mir_available(def_id.index) } dylib_dependency_formats => { Rc::new(cdata.get_dylib_dependency_formats()) } - is_panic_runtime => { cdata.is_panic_runtime() } - is_compiler_builtins => { cdata.is_compiler_builtins() } + is_panic_runtime => { cdata.is_panic_runtime(tcx.sess) } + is_compiler_builtins => { cdata.is_compiler_builtins(tcx.sess) } has_global_allocator => { cdata.has_global_allocator() } - is_sanitizer_runtime => { cdata.is_sanitizer_runtime() } - is_profiler_runtime => { cdata.is_profiler_runtime() } + is_sanitizer_runtime => { cdata.is_sanitizer_runtime(tcx.sess) } + is_profiler_runtime => { cdata.is_profiler_runtime(tcx.sess) } panic_strategy => { cdata.panic_strategy() } extern_crate => { Rc::new(cdata.extern_crate.get()) } - is_no_builtins => { cdata.is_no_builtins() } + is_no_builtins => { cdata.is_no_builtins(tcx.sess) } impl_defaultness => { cdata.get_impl_defaultness(def_id.index) } exported_symbol_ids => { Rc::new(cdata.get_exported_symbols()) } - native_libraries => { Rc::new(cdata.get_native_libraries()) } + native_libraries => { Rc::new(cdata.get_native_libraries(tcx.sess)) } plugin_registrar_fn => { cdata.root.plugin_registrar_fn.map(|index| { DefId { krate: def_id.krate, index } @@ -237,8 +239,8 @@ provide! { <'tcx> tcx, def_id, other, cdata, used_crate_source => { Rc::new(cdata.source.clone()) } - has_copy_closures => { cdata.has_copy_closures() } - has_clone_closures => { cdata.has_clone_closures() } + has_copy_closures => { cdata.has_copy_closures(tcx.sess) } + has_clone_closures => { cdata.has_clone_closures(tcx.sess) } } pub fn provide_local<'tcx>(providers: &mut Providers<'tcx>) { @@ -358,8 +360,8 @@ impl CrateStore for cstore::CStore { self.get_crate_data(def.krate).get_visibility(def.index) } - fn item_generics_cloned_untracked(&self, def: DefId) -> ty::Generics { - self.get_crate_data(def.krate).get_generics(def.index) + fn item_generics_cloned_untracked(&self, def: DefId, sess: &Session) -> ty::Generics { + self.get_crate_data(def.krate).get_generics(def.index, sess) } fn associated_item_cloned_untracked(&self, def: DefId) -> ty::AssociatedItem @@ -454,7 +456,7 @@ impl CrateStore for cstore::CStore { let body = filemap_to_stream(&sess.parse_sess, filemap, None); // Mark the attrs as used - let attrs = data.get_item_attrs(id.index); + let attrs = data.get_item_attrs(id.index, sess); for attr in attrs.iter() { attr::mark_used(attr); } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 909e01376b9..e63037f4da1 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -25,6 +25,7 @@ use rustc::ich::Fingerprint; use rustc::middle::lang_items; use rustc::session::Session; use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::codec::{self as ty_codec, TyDecoder}; use rustc::ty::subst::Substs; use rustc::util::nodemap::DefIdSet; @@ -40,6 +41,7 @@ use std::str; use std::u32; use rustc_serialize::{Decodable, Decoder, SpecializedDecoder, opaque}; +use rustc_data_structures::indexed_vec::Idx; use syntax::attr; use syntax::ast::{self, Ident}; use syntax::codemap; @@ -85,6 +87,20 @@ impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a MetadataBlob { } } + +impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a MetadataBlob, &'a Session) { + fn raw_bytes(self) -> &'a [u8] { + let (blob, _) = self; + &blob.0 + } + + fn sess(self) -> Option<&'a Session> { + let (_, sess) = self; + Some(sess) + } +} + + impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a CrateMetadata { fn raw_bytes(self) -> &'a [u8] { self.blob.raw_bytes() @@ -143,16 +159,6 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> { self.cdata.expect("missing CrateMetadata in DecodeContext") } - fn with_position<F: FnOnce(&mut Self) -> R, R>(&mut self, pos: usize, f: F) -> R { - let new_opaque = opaque::Decoder::new(self.opaque.data, pos); - let old_opaque = mem::replace(&mut self.opaque, new_opaque); - let old_state = mem::replace(&mut self.lazy_state, LazyState::NoNode); - let r = f(self); - self.opaque = old_opaque; - self.lazy_state = old_state; - r - } - fn read_lazy_distance(&mut self, min_size: usize) -> Result<usize, <Self as Decoder>::Error> { let distance = self.read_usize()?; let position = match self.lazy_state { @@ -208,6 +214,60 @@ impl<'doc, 'tcx> Decoder for DecodeContext<'doc, 'tcx> { } } + +impl<'a, 'tcx: 'a> TyDecoder<'a, 'tcx> for DecodeContext<'a, 'tcx> { + + fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { + self.tcx.expect("missing TyCtxt in DecodeContext") + } + + fn peek_byte(&self) -> u8 { + self.opaque.data[self.opaque.position()] + } + + fn cached_ty_for_shorthand<F>(&mut self, + shorthand: usize, + or_insert_with: F) + -> Result<Ty<'tcx>, Self::Error> + where F: FnOnce(&mut Self) -> Result<Ty<'tcx>, Self::Error> + { + let tcx = self.tcx(); + + let key = ty::CReaderCacheKey { + cnum: self.cdata().cnum, + pos: shorthand, + }; + + if let Some(&ty) = tcx.rcache.borrow().get(&key) { + return Ok(ty); + } + + let ty = or_insert_with(self)?; + tcx.rcache.borrow_mut().insert(key, ty); + Ok(ty) + } + + fn with_position<F, R>(&mut self, pos: usize, f: F) -> R + where F: FnOnce(&mut Self) -> R + { + let new_opaque = opaque::Decoder::new(self.opaque.data, pos); + let old_opaque = mem::replace(&mut self.opaque, new_opaque); + let old_state = mem::replace(&mut self.lazy_state, LazyState::NoNode); + let r = f(self); + self.opaque = old_opaque; + self.lazy_state = old_state; + r + } + + fn map_encoded_cnum_to_current(&self, cnum: CrateNum) -> CrateNum { + if cnum == LOCAL_CRATE { + self.cdata().cnum + } else { + self.cdata().cnum_map.borrow()[cnum] + } + } +} + impl<'a, 'tcx, T> SpecializedDecoder<Lazy<T>> for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result<Lazy<T>, Self::Error> { Ok(Lazy::with_position(self.read_lazy_distance(Lazy::<T>::min_size())?)) @@ -245,7 +305,7 @@ impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> { let sess = if let Some(sess) = self.sess { sess } else { - return Ok(Span::new(lo, hi, NO_EXPANSION)); + bug!("Cannot decode Span without Session.") }; let (lo, hi) = if lo > hi { @@ -267,7 +327,8 @@ impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> { // originate from the same filemap. let last_filemap = &imported_filemaps[self.last_filemap_index]; - if lo >= last_filemap.original_start_pos && lo <= last_filemap.original_end_pos && + if lo >= last_filemap.original_start_pos && + lo <= last_filemap.original_end_pos && hi >= last_filemap.original_start_pos && hi <= last_filemap.original_end_pos { last_filemap @@ -289,8 +350,8 @@ impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> { } }; - let lo = (lo - filemap.original_start_pos) + filemap.translated_filemap.start_pos; - let hi = (hi - filemap.original_start_pos) + filemap.translated_filemap.start_pos; + let lo = (lo + filemap.translated_filemap.start_pos) - filemap.original_start_pos; + let hi = (hi + filemap.translated_filemap.start_pos) - filemap.original_start_pos; Ok(Span::new(lo, hi, NO_EXPANSION)) } @@ -302,73 +363,37 @@ impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> { impl<'a, 'tcx> SpecializedDecoder<Ty<'tcx>> for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result<Ty<'tcx>, Self::Error> { - let tcx = self.tcx(); - - // Handle shorthands first, if we have an usize > 0x80. - if self.opaque.data[self.opaque.position()] & 0x80 != 0 { - let pos = self.read_usize()?; - assert!(pos >= SHORTHAND_OFFSET); - let key = ty::CReaderCacheKey { - cnum: self.cdata().cnum, - pos: pos - SHORTHAND_OFFSET, - }; - if let Some(ty) = tcx.rcache.borrow().get(&key).cloned() { - return Ok(ty); - } - - let ty = self.with_position(key.pos, Ty::decode)?; - tcx.rcache.borrow_mut().insert(key, ty); - Ok(ty) - } else { - Ok(tcx.mk_ty(ty::TypeVariants::decode(self)?)) - } + ty_codec::decode_ty(self) } } - impl<'a, 'tcx> SpecializedDecoder<ty::GenericPredicates<'tcx>> for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result<ty::GenericPredicates<'tcx>, Self::Error> { - Ok(ty::GenericPredicates { - parent: Decodable::decode(self)?, - predicates: (0..self.read_usize()?).map(|_| { - // Handle shorthands first, if we have an usize > 0x80. - if self.opaque.data[self.opaque.position()] & 0x80 != 0 { - let pos = self.read_usize()?; - assert!(pos >= SHORTHAND_OFFSET); - let pos = pos - SHORTHAND_OFFSET; - - self.with_position(pos, ty::Predicate::decode) - } else { - ty::Predicate::decode(self) - } - }) - .collect::<Result<Vec<_>, _>>()?, - }) + ty_codec::decode_predicates(self) } } impl<'a, 'tcx> SpecializedDecoder<&'tcx Substs<'tcx>> for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result<&'tcx Substs<'tcx>, Self::Error> { - Ok(self.tcx().mk_substs((0..self.read_usize()?).map(|_| Decodable::decode(self)))?) + ty_codec::decode_substs(self) } } impl<'a, 'tcx> SpecializedDecoder<ty::Region<'tcx>> for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result<ty::Region<'tcx>, Self::Error> { - Ok(self.tcx().mk_region(Decodable::decode(self)?)) + ty_codec::decode_region(self) } } impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::Slice<Ty<'tcx>>> for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result<&'tcx ty::Slice<Ty<'tcx>>, Self::Error> { - Ok(self.tcx().mk_type_list((0..self.read_usize()?).map(|_| Decodable::decode(self)))?) + ty_codec::decode_ty_slice(self) } } impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::AdtDef> for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result<&'tcx ty::AdtDef, Self::Error> { - let def_id = DefId::decode(self)?; - Ok(self.tcx().adt_def(def_id)) + ty_codec::decode_adt_def(self) } } @@ -376,22 +401,19 @@ impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx> for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>, Self::Error> { - Ok(self.tcx().mk_existential_predicates((0..self.read_usize()?) - .map(|_| Decodable::decode(self)))?) + ty_codec::decode_existential_predicate_slice(self) } } impl<'a, 'tcx> SpecializedDecoder<ByteArray<'tcx>> for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result<ByteArray<'tcx>, Self::Error> { - Ok(ByteArray { - data: self.tcx().alloc_byte_array(&Vec::decode(self)?) - }) + ty_codec::decode_byte_array(self) } } impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::Const<'tcx>> for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result<&'tcx ty::Const<'tcx>, Self::Error> { - Ok(self.tcx().mk_const(Decodable::decode(self)?)) + ty_codec::decode_const(self) } } @@ -453,7 +475,7 @@ impl<'tcx> EntryKind<'tcx> { EntryKind::ForeignMod | EntryKind::Impl(_) | - EntryKind::DefaultImpl(_) | + EntryKind::AutoImpl(_) | EntryKind::Field | EntryKind::Generator(_) | EntryKind::Closure(_) => return None, @@ -514,16 +536,16 @@ impl<'a, 'tcx> CrateMetadata { } } - pub fn get_trait_def(&self, item_id: DefIndex) -> ty::TraitDef { + pub fn get_trait_def(&self, item_id: DefIndex, sess: &Session) -> ty::TraitDef { let data = match self.entry(item_id).kind { - EntryKind::Trait(data) => data.decode(self), + EntryKind::Trait(data) => data.decode((self, sess)), _ => bug!(), }; ty::TraitDef::new(self.local_def_id(item_id), data.unsafety, data.paren_sugar, - data.has_default_impl, + data.has_auto_impl, self.def_path_table.def_path_hash(item_id)) } @@ -600,8 +622,11 @@ impl<'a, 'tcx> CrateMetadata { } } - pub fn get_generics(&self, item_id: DefIndex) -> ty::Generics { - self.entry(item_id).generics.unwrap().decode(self) + pub fn get_generics(&self, + item_id: DefIndex, + sess: &Session) + -> ty::Generics { + self.entry(item_id).generics.unwrap().decode((self, sess)) } pub fn get_type(&self, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> { @@ -729,7 +754,7 @@ impl<'a, 'tcx> CrateMetadata { continue; } EntryKind::Impl(_) | - EntryKind::DefaultImpl(_) => continue, + EntryKind::AutoImpl(_) => continue, _ => {} } @@ -901,7 +926,7 @@ impl<'a, 'tcx> CrateMetadata { } } - pub fn get_item_attrs(&self, node_id: DefIndex) -> Rc<[ast::Attribute]> { + pub fn get_item_attrs(&self, node_id: DefIndex, sess: &Session) -> Rc<[ast::Attribute]> { let (node_as, node_index) = (node_id.address_space().index(), node_id.as_array_index()); if self.is_proc_macro(node_id) { @@ -921,7 +946,7 @@ impl<'a, 'tcx> CrateMetadata { if def_key.disambiguated_data.data == DefPathData::StructCtor { item = self.entry(def_key.parent.unwrap()); } - let result: Rc<[ast::Attribute]> = Rc::from(self.get_attributes(&item)); + let result: Rc<[ast::Attribute]> = Rc::from(self.get_attributes(&item, sess)); let vec_ = &mut self.attribute_cache.borrow_mut()[node_as]; if vec_.len() < node_index + 1 { vec_.resize(node_index + 1, None); @@ -938,9 +963,9 @@ impl<'a, 'tcx> CrateMetadata { .collect() } - fn get_attributes(&self, item: &Entry<'tcx>) -> Vec<ast::Attribute> { + fn get_attributes(&self, item: &Entry<'tcx>, sess: &Session) -> Vec<ast::Attribute> { item.attributes - .decode(self) + .decode((self, sess)) .map(|mut attr| { // Need new unique IDs: old thread-local IDs won't map to new threads. attr.id = attr::mk_attr_id(); @@ -1006,8 +1031,8 @@ impl<'a, 'tcx> CrateMetadata { } - pub fn get_native_libraries(&self) -> Vec<NativeLibrary> { - self.root.native_libraries.decode(self).collect() + pub fn get_native_libraries(&self, sess: &Session) -> Vec<NativeLibrary> { + self.root.native_libraries.decode((self, sess)).collect() } pub fn get_dylib_dependency_formats(&self) -> Vec<(CrateNum, LinkagePreference)> { @@ -1076,9 +1101,9 @@ impl<'a, 'tcx> CrateMetadata { self.dllimport_foreign_items.contains(&id) } - pub fn is_default_impl(&self, impl_id: DefIndex) -> bool { + pub fn is_auto_impl(&self, impl_id: DefIndex) -> bool { match self.entry(impl_id).kind { - EntryKind::DefaultImpl(_) => true, + EntryKind::AutoImpl(_) => true, _ => false, } } @@ -1183,6 +1208,7 @@ impl<'a, 'tcx> CrateMetadata { end_pos, lines, multibyte_chars, + non_narrow_chars, .. } = filemap_to_import; let source_length = (end_pos - start_pos).to_usize(); @@ -1200,6 +1226,10 @@ impl<'a, 'tcx> CrateMetadata { for mbc in &mut multibyte_chars { mbc.pos = mbc.pos - start_pos; } + let mut non_narrow_chars = non_narrow_chars.into_inner(); + for swc in &mut non_narrow_chars { + *swc = *swc - start_pos; + } let local_version = local_codemap.new_imported_filemap(name, name_was_remapped, @@ -1207,7 +1237,8 @@ impl<'a, 'tcx> CrateMetadata { src_hash, source_length, lines, - multibyte_chars); + multibyte_chars, + non_narrow_chars); debug!("CrateMetaData::imported_filemaps alloc \ filemap {:?} original (start_pos {:?} end_pos {:?}) \ translated (start_pos {:?} end_pos {:?})", diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index abe2b6d0c1b..d5eee14bf50 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -25,14 +25,13 @@ use rustc::middle::lang_items; use rustc::mir; use rustc::traits::specialization_graph; use rustc::ty::{self, Ty, TyCtxt, ReprOptions}; +use rustc::ty::codec::{self as ty_codec, TyEncoder}; use rustc::session::config::{self, CrateTypeProcMacro}; use rustc::util::nodemap::{FxHashMap, NodeSet}; use rustc_serialize::{Encodable, Encoder, SpecializedEncoder, opaque}; -use std::hash::Hash; -use std::intrinsics; use std::io::prelude::*; use std::io::Cursor; use std::path::Path; @@ -119,7 +118,7 @@ impl<'a, 'tcx, T> SpecializedEncoder<LazySeq<T>> for EncodeContext<'a, 'tcx> { impl<'a, 'tcx> SpecializedEncoder<Ty<'tcx>> for EncodeContext<'a, 'tcx> { fn specialized_encode(&mut self, ty: &Ty<'tcx>) -> Result<(), Self::Error> { - self.encode_with_shorthand(ty, &ty.sty, |ecx| &mut ecx.type_shorthands) + ty_codec::encode_with_shorthand(self, ty, |ecx| &mut ecx.type_shorthands) } } @@ -127,20 +126,17 @@ impl<'a, 'tcx> SpecializedEncoder<ty::GenericPredicates<'tcx>> for EncodeContext fn specialized_encode(&mut self, predicates: &ty::GenericPredicates<'tcx>) -> Result<(), Self::Error> { - predicates.parent.encode(self)?; - predicates.predicates.len().encode(self)?; - for predicate in &predicates.predicates { - self.encode_with_shorthand(predicate, predicate, |ecx| &mut ecx.predicate_shorthands)? - } - Ok(()) + ty_codec::encode_predicates(self, predicates, |ecx| &mut ecx.predicate_shorthands) } } -impl<'a, 'tcx> EncodeContext<'a, 'tcx> { - - pub fn position(&self) -> usize { +impl<'a, 'tcx> TyEncoder for EncodeContext<'a, 'tcx> { + fn position(&self) -> usize { self.opaque.position() } +} + +impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn emit_node<F: FnOnce(&mut Self, usize) -> R, R>(&mut self, f: F) -> R { assert_eq!(self.lazy_state, LazyState::NoNode); @@ -204,44 +200,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }) } - /// Encode the given value or a previously cached shorthand. - fn encode_with_shorthand<T, U, M>(&mut self, - value: &T, - variant: &U, - map: M) - -> Result<(), <Self as Encoder>::Error> - where M: for<'b> Fn(&'b mut Self) -> &'b mut FxHashMap<T, usize>, - T: Clone + Eq + Hash, - U: Encodable - { - let existing_shorthand = map(self).get(value).cloned(); - if let Some(shorthand) = existing_shorthand { - return self.emit_usize(shorthand); - } - - let start = self.position(); - variant.encode(self)?; - let len = self.position() - start; - - // The shorthand encoding uses the same usize as the - // discriminant, with an offset so they can't conflict. - let discriminant = unsafe { intrinsics::discriminant_value(variant) }; - assert!(discriminant < SHORTHAND_OFFSET as u64); - let shorthand = start + SHORTHAND_OFFSET; - - // Get the number of bits that leb128 could fit - // in the same space as the fully encoded type. - let leb128_bits = len * 7; - - // Check that the shorthand is a not longer than the - // full encoding itself, i.e. it's an obvious win. - if leb128_bits >= 64 || (shorthand as u64) < (1 << leb128_bits) { - map(self).insert(value.clone(), shorthand); - } - - Ok(()) - } - // Encodes something that corresponds to a single DepNode::GlobalMetaData // and registers the Fingerprint in the `metadata_hashes` map. pub fn tracked<'x, DATA, R>(&'x mut self, @@ -626,7 +584,8 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { fn encode_struct_ctor(&mut self, (adt_def_id, def_id): (DefId, DefId)) -> Entry<'tcx> { debug!("IsolatedEncoder::encode_struct_ctor({:?})", def_id); let tcx = self.tcx; - let variant = tcx.adt_def(adt_def_id).struct_variant(); + let adt_def = tcx.adt_def(adt_def_id); + let variant = adt_def.struct_variant(); let data = VariantData { ctor_kind: variant.ctor_kind, @@ -648,6 +607,12 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { } } + // If the structure is marked as non_exhaustive then lower the visibility + // to within the crate. + if adt_def.is_non_exhaustive() && ctor_vis == ty::Visibility::Public { + ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)); + } + let repr_options = get_repr_options(&tcx, adt_def_id); Entry { @@ -961,7 +926,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { ctor_sig: None, }), repr_options) } - hir::ItemDefaultImpl(..) => { + hir::ItemAutoImpl(..) => { let data = ImplData { polarity: hir::ImplPolarity::Positive, defaultness: hir::Defaultness::Final, @@ -970,7 +935,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { trait_ref: tcx.impl_trait_ref(def_id).map(|trait_ref| self.lazy(&trait_ref)), }; - EntryKind::DefaultImpl(self.lazy(&data)) + EntryKind::AutoImpl(self.lazy(&data)) } hir::ItemImpl(_, polarity, defaultness, ..) => { let trait_ref = tcx.impl_trait_ref(def_id); @@ -1012,7 +977,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { let data = TraitData { unsafety: trait_def.unsafety, paren_sugar: trait_def.paren_sugar, - has_default_impl: tcx.trait_has_default_impl(def_id), + has_auto_impl: tcx.trait_is_auto(def_id), super_predicates: self.lazy(&tcx.super_predicates_of(def_id)), }; @@ -1559,7 +1524,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { hir::ItemGlobalAsm(..) | hir::ItemExternCrate(..) | hir::ItemUse(..) | - hir::ItemDefaultImpl(..) | + hir::ItemAutoImpl(..) | hir::ItemTy(..) => { // no sub-item recording needed in these cases } diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 54dbb68667b..20bdfaea0d0 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -15,7 +15,6 @@ #![feature(box_patterns)] #![feature(conservative_impl_trait)] -#![feature(core_intrinsics)] #![feature(i128_type)] #![feature(proc_macro_internals)] #![feature(quote)] diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 3c3162bcb51..3efe74bfecc 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -54,11 +54,6 @@ pub const METADATA_VERSION: u8 = 4; pub const METADATA_HEADER: &'static [u8; 12] = &[0, 0, 0, 0, b'r', b'u', b's', b't', 0, 0, 0, METADATA_VERSION]; -/// The shorthand encoding uses an enum's variant index `usize` -/// and is offset by this value so it never matches a real variant. -/// This offset is also chosen so that the first byte is never < 0x80. -pub const SHORTHAND_OFFSET: usize = 0x80; - /// A value of type T referred to by its absolute position /// in the metadata, and which can be decoded lazily. /// @@ -308,7 +303,7 @@ pub enum EntryKind<'tcx> { Generator(Lazy<GeneratorData<'tcx>>), Trait(Lazy<TraitData<'tcx>>), Impl(Lazy<ImplData<'tcx>>), - DefaultImpl(Lazy<ImplData<'tcx>>), + AutoImpl(Lazy<ImplData<'tcx>>), Method(Lazy<MethodData<'tcx>>), AssociatedType(AssociatedContainer), AssociatedConst(AssociatedContainer, u8), @@ -364,7 +359,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for EntryKind<'gcx> { EntryKind::Trait(ref trait_data) => { trait_data.hash_stable(hcx, hasher); } - EntryKind::DefaultImpl(ref impl_data) | + EntryKind::AutoImpl(ref impl_data) | EntryKind::Impl(ref impl_data) => { impl_data.hash_stable(hcx, hasher); } @@ -431,14 +426,14 @@ impl_stable_hash_for!(struct VariantData<'tcx> { pub struct TraitData<'tcx> { pub unsafety: hir::Unsafety, pub paren_sugar: bool, - pub has_default_impl: bool, + pub has_auto_impl: bool, pub super_predicates: Lazy<ty::GenericPredicates<'tcx>>, } impl_stable_hash_for!(struct TraitData<'tcx> { unsafety, paren_sugar, - has_default_impl, + has_auto_impl, super_predicates }); diff --git a/src/librustc_mir/borrow_check.rs b/src/librustc_mir/borrow_check.rs index ee2ef00be57..2cb1a23ef5a 100644 --- a/src/librustc_mir/borrow_check.rs +++ b/src/librustc_mir/borrow_check.rs @@ -17,7 +17,8 @@ use rustc::ty::maps::Providers; use rustc::mir::{AssertMessage, BasicBlock, BorrowKind, Location, Lvalue, Local}; use rustc::mir::{Mir, Mutability, Operand, Projection, ProjectionElem, Rvalue}; use rustc::mir::{Statement, StatementKind, Terminator, TerminatorKind}; -use rustc::mir::transform::{MirSource}; +use rustc::mir::transform::MirSource; +use transform::nll; use rustc_data_structures::indexed_set::{self, IdxSetBuf}; use rustc_data_structures::indexed_vec::{Idx}; @@ -46,93 +47,120 @@ pub fn provide(providers: &mut Providers) { } fn mir_borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { - let mir = tcx.mir_validated(def_id); + let input_mir = tcx.mir_validated(def_id); let src = MirSource::from_local_def_id(tcx, def_id); debug!("run query mir_borrowck: {}", tcx.node_path_str(src.item_id())); - let mir: &Mir<'tcx> = &mir.borrow(); - if !tcx.has_attr(def_id, "rustc_mir_borrowck") && !tcx.sess.opts.debugging_opts.borrowck_mir { + if { + !tcx.has_attr(def_id, "rustc_mir_borrowck") && + !tcx.sess.opts.debugging_opts.borrowck_mir && + !tcx.sess.opts.debugging_opts.nll + } { return; } - let id = src.item_id(); + tcx.infer_ctxt().enter(|infcx| { + let input_mir: &Mir = &input_mir.borrow(); + do_mir_borrowck(&infcx, input_mir, def_id, src); + }); + debug!("mir_borrowck done"); +} + +fn do_mir_borrowck<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, + input_mir: &Mir<'gcx>, + def_id: DefId, + src: MirSource) +{ + let tcx = infcx.tcx; let attributes = tcx.get_attrs(def_id); let param_env = tcx.param_env(def_id); - tcx.infer_ctxt().enter(|_infcx| { - - let move_data = match MoveData::gather_moves(mir, tcx, param_env) { - Ok(move_data) => move_data, - Err((move_data, move_errors)) => { - for move_error in move_errors { - let (span, kind): (Span, IllegalMoveOriginKind) = match move_error { - MoveError::UnionMove { .. } => - unimplemented!("dont know how to report union move errors yet."), - MoveError::IllegalMove { cannot_move_out_of: o } => (o.span, o.kind), - }; - let origin = Origin::Mir; - let mut err = match kind { - IllegalMoveOriginKind::Static => - tcx.cannot_move_out_of(span, "static item", origin), - IllegalMoveOriginKind::BorrowedContent => - tcx.cannot_move_out_of(span, "borrowed_content", origin), - IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => - tcx.cannot_move_out_of_interior_of_drop(span, ty, origin), - IllegalMoveOriginKind::InteriorOfSlice { elem_ty: ty, is_index } => - tcx.cannot_move_out_of_interior_noncopy(span, ty, is_index, origin), - IllegalMoveOriginKind::InteriorOfArray { elem_ty: ty, is_index } => - tcx.cannot_move_out_of_interior_noncopy(span, ty, is_index, origin), - }; - err.emit(); - } - move_data + + let id = src.item_id(); + + let move_data: MoveData<'tcx> = match MoveData::gather_moves(input_mir, tcx, param_env) { + Ok(move_data) => move_data, + Err((move_data, move_errors)) => { + for move_error in move_errors { + let (span, kind): (Span, IllegalMoveOriginKind) = match move_error { + MoveError::UnionMove { .. } => + unimplemented!("dont know how to report union move errors yet."), + MoveError::IllegalMove { cannot_move_out_of: o } => (o.span, o.kind), + }; + let origin = Origin::Mir; + let mut err = match kind { + IllegalMoveOriginKind::Static => + tcx.cannot_move_out_of(span, "static item", origin), + IllegalMoveOriginKind::BorrowedContent => + tcx.cannot_move_out_of(span, "borrowed_content", origin), + IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => + tcx.cannot_move_out_of_interior_of_drop(span, ty, origin), + IllegalMoveOriginKind::InteriorOfSlice { elem_ty: ty, is_index } => + tcx.cannot_move_out_of_interior_noncopy(span, ty, is_index, origin), + IllegalMoveOriginKind::InteriorOfArray { elem_ty: ty, is_index } => + tcx.cannot_move_out_of_interior_noncopy(span, ty, is_index, origin), + }; + err.emit(); } - }; - let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env }; - let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len()); - let flow_borrows = do_dataflow(tcx, mir, id, &attributes, &dead_unwinds, - Borrows::new(tcx, mir), - |bd, i| bd.location(i)); - let flow_inits = do_dataflow(tcx, mir, id, &attributes, &dead_unwinds, - MaybeInitializedLvals::new(tcx, mir, &mdpe), - |bd, i| &bd.move_data().move_paths[i]); - let flow_uninits = do_dataflow(tcx, mir, id, &attributes, &dead_unwinds, - MaybeUninitializedLvals::new(tcx, mir, &mdpe), - |bd, i| &bd.move_data().move_paths[i]); - - let mut mbcx = MirBorrowckCtxt { - tcx: tcx, - mir: mir, - node_id: id, - move_data: &mdpe.move_data, - param_env: param_env, - fake_infer_ctxt: &_infcx, - }; + move_data + } + }; - let mut state = InProgress::new(flow_borrows, - flow_inits, - flow_uninits); + // Make our own copy of the MIR. This copy will be modified (in place) to + // contain non-lexical lifetimes. It will have a lifetime tied + // to the inference context. + let mut mir: Mir<'tcx> = input_mir.clone(); + let mir = &mut mir; + + // If we are in non-lexical mode, compute the non-lexical lifetimes. + let opt_regioncx = if !tcx.sess.opts.debugging_opts.nll { + None + } else { + Some(nll::compute_regions(infcx, src, mir)) + }; - mbcx.analyze_results(&mut state); // entry point for DataflowResultsConsumer - }); + let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env }; + let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len()); + let flow_borrows = do_dataflow(tcx, mir, id, &attributes, &dead_unwinds, + Borrows::new(tcx, mir, opt_regioncx.as_ref()), + |bd, i| bd.location(i)); + let flow_inits = do_dataflow(tcx, mir, id, &attributes, &dead_unwinds, + MaybeInitializedLvals::new(tcx, mir, &mdpe), + |bd, i| &bd.move_data().move_paths[i]); + let flow_uninits = do_dataflow(tcx, mir, id, &attributes, &dead_unwinds, + MaybeUninitializedLvals::new(tcx, mir, &mdpe), + |bd, i| &bd.move_data().move_paths[i]); + + let mut mbcx = MirBorrowckCtxt { + tcx: tcx, + mir: mir, + node_id: id, + move_data: &mdpe.move_data, + param_env: param_env, + fake_infer_ctxt: &infcx, + }; - debug!("mir_borrowck done"); + let mut state = InProgress::new(flow_borrows, + flow_inits, + flow_uninits); + + mbcx.analyze_results(&mut state); // entry point for DataflowResultsConsumer } #[allow(dead_code)] pub struct MirBorrowckCtxt<'c, 'b, 'a: 'b+'c, 'gcx: 'a+'tcx, 'tcx: 'a> { - tcx: TyCtxt<'a, 'gcx, 'gcx>, - mir: &'b Mir<'gcx>, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + mir: &'b Mir<'tcx>, node_id: ast::NodeId, - move_data: &'b MoveData<'gcx>, + move_data: &'b MoveData<'tcx>, param_env: ParamEnv<'tcx>, fake_infer_ctxt: &'c InferCtxt<'c, 'gcx, 'tcx>, } // (forced to be `pub` due to its use as an associated type below.) -pub struct InProgress<'b, 'tcx: 'b> { - borrows: FlowInProgress<Borrows<'b, 'tcx>>, - inits: FlowInProgress<MaybeInitializedLvals<'b, 'tcx>>, - uninits: FlowInProgress<MaybeUninitializedLvals<'b, 'tcx>>, +pub struct InProgress<'b, 'gcx: 'tcx, 'tcx: 'b> { + borrows: FlowInProgress<Borrows<'b, 'gcx, 'tcx>>, + inits: FlowInProgress<MaybeInitializedLvals<'b, 'gcx, 'tcx>>, + uninits: FlowInProgress<MaybeUninitializedLvals<'b, 'gcx, 'tcx>>, } struct FlowInProgress<BD> where BD: BitDenotation { @@ -147,12 +175,12 @@ struct FlowInProgress<BD> where BD: BitDenotation { // 2. loans made in overlapping scopes do not conflict // 3. assignments do not affect things loaned out as immutable // 4. moves do not affect things loaned out in any way -impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> DataflowResultsConsumer<'b, 'gcx> +impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> DataflowResultsConsumer<'b, 'tcx> for MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> { - type FlowState = InProgress<'b, 'gcx>; + type FlowState = InProgress<'b, 'gcx, 'tcx>; - fn mir(&self) -> &'b Mir<'gcx> { self.mir } + fn mir(&self) -> &'b Mir<'tcx> { self.mir } fn reset_to_entry_of(&mut self, bb: BasicBlock, flow_state: &mut Self::FlowState) { flow_state.each_flow(|b| b.reset_to_entry_of(bb), @@ -193,7 +221,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> DataflowResultsConsumer<'b, 'gcx> fn visit_statement_entry(&mut self, location: Location, - stmt: &Statement<'gcx>, + stmt: &Statement<'tcx>, flow_state: &Self::FlowState) { let summary = flow_state.summary(); debug!("MirBorrowckCtxt::process_statement({:?}, {:?}): {}", location, stmt, summary); @@ -261,7 +289,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> DataflowResultsConsumer<'b, 'gcx> fn visit_terminator_entry(&mut self, location: Location, - term: &Terminator<'gcx>, + term: &Terminator<'tcx>, flow_state: &Self::FlowState) { let loc = location; let summary = flow_state.summary(); @@ -336,7 +364,8 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> DataflowResultsConsumer<'b, 'gcx> TerminatorKind::Resume | TerminatorKind::Return | TerminatorKind::GeneratorDrop | - TerminatorKind::Unreachable => { + TerminatorKind::Unreachable | + TerminatorKind::FalseEdges { .. } => { // no data used, thus irrelevant to borrowck } } @@ -405,9 +434,9 @@ enum WriteKind { impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> { fn access_lvalue(&mut self, context: Context, - lvalue_span: (&Lvalue<'gcx>, Span), + lvalue_span: (&Lvalue<'tcx>, Span), kind: (ShallowOrDeep, ReadOrWrite), - flow_state: &InProgress<'b, 'gcx>) { + flow_state: &InProgress<'b, 'gcx, 'tcx>) { // FIXME: also need to check permissions (e.g. reject mut // borrow of immutable ref, moves through non-`Box`-ref) let (sd, rw) = kind; @@ -425,8 +454,8 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> context, lvalue_span, borrow), ReadKind::Borrow(bk) => { let end_issued_loan_span = - flow_state.borrows.base_results.operator().region_span( - &borrow.region).end_point(); + flow_state.borrows.base_results.operator().opt_region_end_span( + &borrow.region); this.report_conflicting_borrow( context, common_prefix, lvalue_span, bk, &borrow, end_issued_loan_span) @@ -438,8 +467,8 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> match kind { WriteKind::MutableBorrow(bk) => { let end_issued_loan_span = - flow_state.borrows.base_results.operator().region_span( - &borrow.region).end_point(); + flow_state.borrows.base_results.operator().opt_region_end_span( + &borrow.region); this.report_conflicting_borrow( context, common_prefix, lvalue_span, bk, &borrow, end_issued_loan_span) @@ -460,10 +489,10 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> fn mutate_lvalue(&mut self, context: Context, - lvalue_span: (&Lvalue<'gcx>, Span), + lvalue_span: (&Lvalue<'tcx>, Span), kind: ShallowOrDeep, mode: MutateMode, - flow_state: &InProgress<'b, 'gcx>) { + flow_state: &InProgress<'b, 'gcx, 'tcx>) { // Write of P[i] or *P, or WriteAndRead of any P, requires P init'd. match mode { MutateMode::WriteAndRead => { @@ -482,9 +511,9 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> fn consume_rvalue(&mut self, context: Context, - (rvalue, span): (&Rvalue<'gcx>, Span), + (rvalue, span): (&Rvalue<'tcx>, Span), _location: Location, - flow_state: &InProgress<'b, 'gcx>) { + flow_state: &InProgress<'b, 'gcx, 'tcx>) { match *rvalue { Rvalue::Ref(_/*rgn*/, bk, ref lvalue) => { let access_kind = match bk { @@ -540,8 +569,8 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> fn consume_operand(&mut self, context: Context, consume_via_drop: ConsumeKind, - (operand, span): (&Operand<'gcx>, Span), - flow_state: &InProgress<'b, 'gcx>) { + (operand, span): (&Operand<'tcx>, Span), + flow_state: &InProgress<'b, 'gcx, 'tcx>) { match *operand { Operand::Consume(ref lvalue) => { self.consume_lvalue(context, consume_via_drop, (lvalue, span), flow_state) @@ -553,8 +582,8 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> fn consume_lvalue(&mut self, context: Context, consume_via_drop: ConsumeKind, - lvalue_span: (&Lvalue<'gcx>, Span), - flow_state: &InProgress<'b, 'gcx>) { + lvalue_span: (&Lvalue<'tcx>, Span), + flow_state: &InProgress<'b, 'gcx, 'tcx>) { let lvalue = lvalue_span.0; let ty = lvalue.ty(self.mir, self.tcx).to_ty(self.tcx); let moves_by_default = @@ -584,8 +613,8 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> { fn check_if_reassignment_to_immutable_state(&mut self, context: Context, - (lvalue, span): (&Lvalue<'gcx>, Span), - flow_state: &InProgress<'b, 'gcx>) { + (lvalue, span): (&Lvalue<'tcx>, Span), + flow_state: &InProgress<'b, 'gcx, 'tcx>) { let move_data = self.move_data; // determine if this path has a non-mut owner (and thus needs checking). @@ -635,8 +664,8 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> fn check_if_path_is_moved(&mut self, context: Context, desired_action: &str, - lvalue_span: (&Lvalue<'gcx>, Span), - flow_state: &InProgress<'b, 'gcx>) { + lvalue_span: (&Lvalue<'tcx>, Span), + flow_state: &InProgress<'b, 'gcx, 'tcx>) { // FIXME: analogous code in check_loans first maps `lvalue` to // its base_path ... but is that what we want here? let lvalue = self.base_path(lvalue_span.0); @@ -725,7 +754,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> /// An Err result includes a tag indicated why the search failed. /// Currenly this can only occur if the lvalue is built off of a /// static variable, as we do not track those in the MoveData. - fn move_path_closest_to(&mut self, lvalue: &Lvalue<'gcx>) + fn move_path_closest_to(&mut self, lvalue: &Lvalue<'tcx>) -> Result<MovePathIndex, NoMovePathFound> { let mut last_prefix = lvalue; @@ -743,7 +772,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> } fn move_path_for_lvalue(&mut self, - lvalue: &Lvalue<'gcx>) + lvalue: &Lvalue<'tcx>) -> Option<MovePathIndex> { // If returns None, then there is no move path corresponding @@ -758,8 +787,8 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> fn check_if_assigned_path_is_moved(&mut self, context: Context, - (lvalue, span): (&Lvalue<'gcx>, Span), - flow_state: &InProgress<'b, 'gcx>) { + (lvalue, span): (&Lvalue<'tcx>, Span), + flow_state: &InProgress<'b, 'gcx, 'tcx>) { // recur down lvalue; dispatch to check_if_path_is_moved when necessary let mut lvalue = lvalue; loop { @@ -827,10 +856,10 @@ enum NoMovePathFound { impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> { fn each_borrow_involving_path<F>(&mut self, _context: Context, - access_lvalue: (ShallowOrDeep, &Lvalue<'gcx>), - flow_state: &InProgress<'b, 'gcx>, + access_lvalue: (ShallowOrDeep, &Lvalue<'tcx>), + flow_state: &InProgress<'b, 'gcx, 'tcx>, mut op: F) - where F: FnMut(&mut Self, BorrowIndex, &BorrowData<'gcx>, &Lvalue) -> Control + where F: FnMut(&mut Self, BorrowIndex, &BorrowData<'tcx>, &Lvalue) -> Control { let (access, lvalue) = access_lvalue; @@ -928,9 +957,9 @@ mod prefixes { } - pub(super) struct Prefixes<'c, 'tcx: 'c> { + pub(super) struct Prefixes<'c, 'gcx: 'tcx, 'tcx: 'c> { mir: &'c Mir<'tcx>, - tcx: TyCtxt<'c, 'tcx, 'tcx>, + tcx: TyCtxt<'c, 'gcx, 'tcx>, kind: PrefixSet, next: Option<&'c Lvalue<'tcx>>, } @@ -951,15 +980,15 @@ mod prefixes { /// (inclusive) from longest to smallest, potentially /// terminating the iteration early based on `kind`. pub(super) fn prefixes<'d>(&self, - lvalue: &'d Lvalue<'gcx>, + lvalue: &'d Lvalue<'tcx>, kind: PrefixSet) - -> Prefixes<'d, 'gcx> where 'b: 'd + -> Prefixes<'d, 'gcx, 'tcx> where 'b: 'd { Prefixes { next: Some(lvalue), kind, mir: self.mir, tcx: self.tcx } } } - impl<'c, 'tcx> Iterator for Prefixes<'c, 'tcx> { + impl<'c, 'gcx, 'tcx> Iterator for Prefixes<'c, 'gcx, 'tcx> { type Item = &'c Lvalue<'tcx>; fn next(&mut self) -> Option<Self::Item> { let mut cursor = match self.next { @@ -1101,7 +1130,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> (lvalue, span): (&Lvalue, Span), gen_borrow_kind: BorrowKind, issued_borrow: &BorrowData, - end_issued_loan_span: Span) { + end_issued_loan_span: Option<Span>) { use self::prefixes::IsPrefixOf; assert!(common_prefix.is_prefix_of(lvalue)); @@ -1315,7 +1344,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> // moves out of a Box. They should be removed when/if we stop // treating Box specially (e.g. when/if DerefMove is added...) - fn base_path<'d>(&self, lvalue: &'d Lvalue<'gcx>) -> &'d Lvalue<'gcx> { + fn base_path<'d>(&self, lvalue: &'d Lvalue<'tcx>) -> &'d Lvalue<'tcx> { //! Returns the base of the leftmost (deepest) dereference of an //! Box in `lvalue`. If there is no dereference of an Box //! in `lvalue`, then it just returns `lvalue` itself. @@ -1364,10 +1393,10 @@ impl ContextKind { fn new(self, loc: Location) -> Context { Context { kind: self, loc: loc } } } -impl<'b, 'tcx: 'b> InProgress<'b, 'tcx> { - pub(super) fn new(borrows: DataflowResults<Borrows<'b, 'tcx>>, - inits: DataflowResults<MaybeInitializedLvals<'b, 'tcx>>, - uninits: DataflowResults<MaybeUninitializedLvals<'b, 'tcx>>) +impl<'b, 'gcx, 'tcx> InProgress<'b, 'gcx, 'tcx> { + pub(super) fn new(borrows: DataflowResults<Borrows<'b, 'gcx, 'tcx>>, + inits: DataflowResults<MaybeInitializedLvals<'b, 'gcx, 'tcx>>, + uninits: DataflowResults<MaybeUninitializedLvals<'b, 'gcx, 'tcx>>) -> Self { InProgress { borrows: FlowInProgress::new(borrows), @@ -1380,9 +1409,9 @@ impl<'b, 'tcx: 'b> InProgress<'b, 'tcx> { mut xform_borrows: XB, mut xform_inits: XI, mut xform_uninits: XU) where - XB: FnMut(&mut FlowInProgress<Borrows<'b, 'tcx>>), - XI: FnMut(&mut FlowInProgress<MaybeInitializedLvals<'b, 'tcx>>), - XU: FnMut(&mut FlowInProgress<MaybeUninitializedLvals<'b, 'tcx>>), + XB: FnMut(&mut FlowInProgress<Borrows<'b, 'gcx, 'tcx>>), + XI: FnMut(&mut FlowInProgress<MaybeInitializedLvals<'b, 'gcx, 'tcx>>), + XU: FnMut(&mut FlowInProgress<MaybeUninitializedLvals<'b, 'gcx, 'tcx>>), { xform_borrows(&mut self.borrows); xform_inits(&mut self.inits); @@ -1438,7 +1467,7 @@ impl<'b, 'tcx: 'b> InProgress<'b, 'tcx> { } } -impl<'b, 'tcx> FlowInProgress<MaybeUninitializedLvals<'b, 'tcx>> { +impl<'b, 'gcx, 'tcx> FlowInProgress<MaybeUninitializedLvals<'b, 'gcx, 'tcx>> { fn has_any_child_of(&self, mpi: MovePathIndex) -> Option<MovePathIndex> { let move_data = self.base_results.operator().move_data(); diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 56c926eaa61..b65d859e7d7 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -21,7 +21,7 @@ use rustc::mir::*; use rustc::hir; use hair::*; use syntax::ast::{Name, NodeId}; -use syntax_pos::{DUMMY_SP, Span}; +use syntax_pos::Span; // helper functions, broken out by category: mod simplify; @@ -54,11 +54,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { (body, scope.unwrap_or(self.visibility_scope)) }).collect(); + // create binding start block for link them by false edges + let candidate_count = arms.iter().fold(0, |ac, c| ac + c.patterns.len()); + let pre_binding_blocks: Vec<_> = (0..candidate_count + 1) + .map(|_| self.cfg.start_new_block()).collect(); + // assemble a list of candidates: there is one candidate per // pattern, which means there may be more than one candidate // *per arm*. These candidates are kept sorted such that the // highest priority candidate comes first in the list. // (i.e. same order as in source) + let candidates: Vec<_> = arms.iter() .enumerate() @@ -66,17 +72,25 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { arm.patterns.iter() .map(move |pat| (arm_index, pat, arm.guard.clone())) }) - .map(|(arm_index, pattern, guard)| { + .zip(pre_binding_blocks.iter().zip(pre_binding_blocks.iter().skip(1))) + .map(|((arm_index, pattern, guard), + (pre_binding_block, next_candidate_pre_binding_block))| { Candidate { span: pattern.span, match_pairs: vec![MatchPair::new(discriminant_lvalue.clone(), pattern)], bindings: vec![], guard, arm_index, + pre_binding_block: *pre_binding_block, + next_candidate_pre_binding_block: *next_candidate_pre_binding_block, } }) .collect(); + let outer_source_info = self.source_info(span); + self.cfg.terminate(*pre_binding_blocks.last().unwrap(), + outer_source_info, TerminatorKind::Unreachable); + // this will generate code to test discriminant_lvalue and // branch to the appropriate arm block let otherwise = self.match_candidates(span, &mut arm_blocks, candidates, block); @@ -148,7 +162,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { match_pairs: vec![MatchPair::new(initializer.clone(), &irrefutable_pat)], bindings: vec![], guard: None, - arm_index: 0, // since we don't call `match_candidates`, this field is unused + + // since we don't call `match_candidates`, next fields is unused + arm_index: 0, + pre_binding_block: block, + next_candidate_pre_binding_block: block }; // Simplify the candidate. Since the pattern is irrefutable, this should @@ -278,6 +296,10 @@ pub struct Candidate<'pat, 'tcx:'pat> { // ...and then we branch to arm with this index. arm_index: usize, + + // ...and the blocks for add false edges between candidates + pre_binding_block: BasicBlock, + next_candidate_pre_binding_block: BasicBlock, } #[derive(Clone, Debug)] @@ -398,17 +420,43 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { candidates.iter().take_while(|c| c.match_pairs.is_empty()).count(); debug!("match_candidates: {:?} candidates fully matched", fully_matched); let mut unmatched_candidates = candidates.split_off(fully_matched); - for (index, candidate) in candidates.into_iter().enumerate() { + + let fully_matched_with_guard = + candidates.iter().take_while(|c| c.guard.is_some()).count(); + + let unreachable_candidates = if fully_matched_with_guard + 1 < candidates.len() { + candidates.split_off(fully_matched_with_guard + 1) + } else { + vec![] + }; + + for candidate in candidates { // If so, apply any bindings, test the guard (if any), and // branch to the arm. - let is_last = index == fully_matched - 1; - if let Some(b) = self.bind_and_guard_matched_candidate(block, arm_blocks, - candidate, is_last) { + if let Some(b) = self.bind_and_guard_matched_candidate(block, arm_blocks, candidate) { block = b; } else { // if None is returned, then any remaining candidates // are unreachable (at least not through this path). - return vec![]; + // Link them with false edges. + debug!("match_candidates: add false edges for unreachable {:?} and unmatched {:?}", + unreachable_candidates, unmatched_candidates); + for candidate in unreachable_candidates { + let source_info = self.source_info(candidate.span); + let target = self.cfg.start_new_block(); + if let Some(otherwise) = self.bind_and_guard_matched_candidate(target, + arm_blocks, + candidate) { + self.cfg.terminate(otherwise, source_info, TerminatorKind::Unreachable); + } + } + + if unmatched_candidates.is_empty() { + return vec![] + } else { + let target = self.cfg.start_new_block(); + return self.match_candidates(span, arm_blocks, unmatched_candidates, target); + } } } @@ -423,9 +471,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.test_candidates(span, arm_blocks, &unmatched_candidates, block); // If the target candidates were exhaustive, then we are done. - if otherwise.is_empty() { - return vec![]; - } + // But for borrowck continue build decision tree. // If all candidates were sorted into `target_candidates` somewhere, then // the initial set was inexhaustive. @@ -666,17 +712,27 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn bind_and_guard_matched_candidate<'pat>(&mut self, mut block: BasicBlock, arm_blocks: &mut ArmBlocks, - candidate: Candidate<'pat, 'tcx>, - is_last_arm: bool) + candidate: Candidate<'pat, 'tcx>) -> Option<BasicBlock> { debug!("bind_and_guard_matched_candidate(block={:?}, candidate={:?})", block, candidate); debug_assert!(candidate.match_pairs.is_empty()); - self.bind_matched_candidate(block, candidate.bindings); - let arm_block = arm_blocks.blocks[candidate.arm_index]; + let candidate_source_info = self.source_info(candidate.span); + + self.cfg.terminate(block, candidate_source_info, + TerminatorKind::Goto { target: candidate.pre_binding_block }); + + block = self.cfg.start_new_block(); + self.cfg.terminate(candidate.pre_binding_block, candidate_source_info, + TerminatorKind::FalseEdges { + real_target: block, + imaginary_targets: + vec![candidate.next_candidate_pre_binding_block]}); + + self.bind_matched_candidate(block, candidate.bindings); if let Some(guard) = candidate.guard { // the block to branch to if the guard fails; if there is no @@ -684,30 +740,22 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let guard = self.hir.mirror(guard); let source_info = self.source_info(guard.span); let cond = unpack!(block = self.as_local_operand(block, guard)); - let otherwise = self.cfg.start_new_block(); + + let false_edge_block = self.cfg.start_new_block(); self.cfg.terminate(block, source_info, - TerminatorKind::if_(self.hir.tcx(), cond, arm_block, otherwise)); - Some(otherwise) - } else if !is_last_arm { - // Add always true guard in case of more than one arm - // it creates false edges and allow MIR borrowck detects errors - // FIXME(#45184) -- permit "false edges" - let source_info = self.source_info(candidate.span); - let true_expr = Expr { - temp_lifetime: None, - ty: self.hir.tcx().types.bool, - span: DUMMY_SP, - kind: ExprKind::Literal{literal: self.hir.true_literal()}, - }; - let cond = unpack!(block = self.as_local_operand(block, true_expr)); + TerminatorKind::if_(self.hir.tcx(), cond, arm_block, + false_edge_block)); + let otherwise = self.cfg.start_new_block(); - self.cfg.terminate(block, source_info, - TerminatorKind::if_(self.hir.tcx(), cond, arm_block, otherwise)); + self.cfg.terminate(false_edge_block, source_info, + TerminatorKind::FalseEdges { + real_target: otherwise, + imaginary_targets: + vec![candidate.next_candidate_pre_binding_block] }); Some(otherwise) } else { - let source_info = self.source_info(candidate.span); - self.cfg.terminate(block, source_info, - TerminatorKind::Goto { target: arm_block }); + self.cfg.terminate(block, candidate_source_info, + TerminatorKind::Goto { target: arm_block }); None } } diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 7b91c43aa37..4792bf2b213 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -598,6 +598,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { bindings: candidate.bindings.clone(), guard: candidate.guard.clone(), arm_index: candidate.arm_index, + pre_binding_block: candidate.pre_binding_block, + next_candidate_pre_binding_block: candidate.next_candidate_pre_binding_block, } } @@ -659,6 +661,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { bindings: candidate.bindings.clone(), guard: candidate.guard.clone(), arm_index: candidate.arm_index, + pre_binding_block: candidate.pre_binding_block, + next_candidate_pre_binding_block: candidate.next_candidate_pre_binding_block, } } diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index b2f0ff57b62..2073d495300 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -17,7 +17,7 @@ use rustc::hir::def_id::DefId; use rustc::middle::region; use rustc::mir::*; use rustc::mir::transform::MirSource; -use rustc::mir::visit::{MutVisitor, Lookup}; +use rustc::mir::visit::{MutVisitor, TyContext}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::Substs; use rustc::util::nodemap::NodeMap; @@ -165,7 +165,7 @@ struct GlobalizeMir<'a, 'gcx: 'a> { } impl<'a, 'gcx: 'tcx, 'tcx> MutVisitor<'tcx> for GlobalizeMir<'a, 'gcx> { - fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: Lookup) { + fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) { if let Some(lifted) = self.tcx.lift(ty) { *ty = lifted; } else { @@ -240,10 +240,10 @@ fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, /////////////////////////////////////////////////////////////////////////// // BuildMir -- walks a crate, looking for fn items and methods to build MIR from -pub fn closure_self_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - closure_expr_id: ast::NodeId, - body_id: hir::BodyId) - -> Ty<'tcx> { +pub fn closure_self_ty<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, + closure_expr_id: ast::NodeId, + body_id: hir::BodyId) + -> Ty<'tcx> { let closure_expr_hir_id = tcx.hir.node_to_hir_id(closure_expr_id); let closure_ty = tcx.body_tables(body_id).node_id_to_type(closure_expr_hir_id); diff --git a/src/librustc_mir/dataflow/drop_flag_effects.rs b/src/librustc_mir/dataflow/drop_flag_effects.rs index bd41bce67da..e35bd34c40b 100644 --- a/src/librustc_mir/dataflow/drop_flag_effects.rs +++ b/src/librustc_mir/dataflow/drop_flag_effects.rs @@ -58,9 +58,9 @@ pub fn move_path_children_matching<'tcx, F>(move_data: &MoveData<'tcx>, /// is no need to maintain separate drop flags to track such state. /// /// FIXME: we have to do something for moving slice patterns. -fn lvalue_contents_drop_state_cannot_differ<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - mir: &Mir<'tcx>, - lv: &mir::Lvalue<'tcx>) -> bool { +fn lvalue_contents_drop_state_cannot_differ<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, + mir: &Mir<'tcx>, + lv: &mir::Lvalue<'tcx>) -> bool { let ty = lv.ty(mir, tcx).to_ty(tcx); match ty.sty { ty::TyArray(..) | ty::TySlice(..) | ty::TyRef(..) | ty::TyRawPtr(..) => { @@ -79,8 +79,8 @@ fn lvalue_contents_drop_state_cannot_differ<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx } } -pub(crate) fn on_lookup_result_bits<'a, 'tcx, F>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub(crate) fn on_lookup_result_bits<'a, 'gcx, 'tcx, F>( + tcx: TyCtxt<'a, 'gcx, 'tcx>, mir: &Mir<'tcx>, move_data: &MoveData<'tcx>, lookup_result: LookupResult, @@ -97,16 +97,16 @@ pub(crate) fn on_lookup_result_bits<'a, 'tcx, F>( } } -pub(crate) fn on_all_children_bits<'a, 'tcx, F>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub(crate) fn on_all_children_bits<'a, 'gcx, 'tcx, F>( + tcx: TyCtxt<'a, 'gcx, 'tcx>, mir: &Mir<'tcx>, move_data: &MoveData<'tcx>, move_path_index: MovePathIndex, mut each_child: F) where F: FnMut(MovePathIndex) { - fn is_terminal_path<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, + fn is_terminal_path<'a, 'gcx, 'tcx>( + tcx: TyCtxt<'a, 'gcx, 'tcx>, mir: &Mir<'tcx>, move_data: &MoveData<'tcx>, path: MovePathIndex) -> bool @@ -115,8 +115,8 @@ pub(crate) fn on_all_children_bits<'a, 'tcx, F>( tcx, mir, &move_data.move_paths[path].lvalue) } - fn on_all_children_bits<'a, 'tcx, F>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, + fn on_all_children_bits<'a, 'gcx, 'tcx, F>( + tcx: TyCtxt<'a, 'gcx, 'tcx>, mir: &Mir<'tcx>, move_data: &MoveData<'tcx>, move_path_index: MovePathIndex, @@ -138,10 +138,10 @@ pub(crate) fn on_all_children_bits<'a, 'tcx, F>( on_all_children_bits(tcx, mir, move_data, move_path_index, &mut each_child); } -pub(crate) fn on_all_drop_children_bits<'a, 'tcx, F>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub(crate) fn on_all_drop_children_bits<'a, 'gcx, 'tcx, F>( + tcx: TyCtxt<'a, 'gcx, 'tcx>, mir: &Mir<'tcx>, - ctxt: &MoveDataParamEnv<'tcx>, + ctxt: &MoveDataParamEnv<'gcx, 'tcx>, path: MovePathIndex, mut each_child: F) where F: FnMut(MovePathIndex) @@ -151,7 +151,9 @@ pub(crate) fn on_all_drop_children_bits<'a, 'tcx, F>( let ty = lvalue.ty(mir, tcx).to_ty(tcx); debug!("on_all_drop_children_bits({:?}, {:?} : {:?})", path, lvalue, ty); - if ty.needs_drop(tcx, ctxt.param_env) { + let gcx = tcx.global_tcx(); + let erased_ty = gcx.lift(&tcx.erase_regions(&ty)).unwrap(); + if erased_ty.needs_drop(gcx, ctxt.param_env) { each_child(child); } else { debug!("on_all_drop_children_bits - skipping") @@ -159,10 +161,10 @@ pub(crate) fn on_all_drop_children_bits<'a, 'tcx, F>( }) } -pub(crate) fn drop_flag_effects_for_function_entry<'a, 'tcx, F>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub(crate) fn drop_flag_effects_for_function_entry<'a, 'gcx, 'tcx, F>( + tcx: TyCtxt<'a, 'gcx, 'tcx>, mir: &Mir<'tcx>, - ctxt: &MoveDataParamEnv<'tcx>, + ctxt: &MoveDataParamEnv<'gcx, 'tcx>, mut callback: F) where F: FnMut(MovePathIndex, DropFlagState) { @@ -176,10 +178,10 @@ pub(crate) fn drop_flag_effects_for_function_entry<'a, 'tcx, F>( } } -pub(crate) fn drop_flag_effects_for_location<'a, 'tcx, F>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub(crate) fn drop_flag_effects_for_location<'a, 'gcx, 'tcx, F>( + tcx: TyCtxt<'a, 'gcx, 'tcx>, mir: &Mir<'tcx>, - ctxt: &MoveDataParamEnv<'tcx>, + ctxt: &MoveDataParamEnv<'gcx, 'tcx>, loc: Location, mut callback: F) where F: FnMut(MovePathIndex, DropFlagState) @@ -196,7 +198,9 @@ pub(crate) fn drop_flag_effects_for_location<'a, 'tcx, F>( // don't move out of non-Copy things let lvalue = &move_data.move_paths[path].lvalue; let ty = lvalue.ty(mir, tcx).to_ty(tcx); - if !ty.moves_by_default(tcx, param_env, DUMMY_SP) { + let gcx = tcx.global_tcx(); + let erased_ty = gcx.lift(&tcx.erase_regions(&ty)).unwrap(); + if !erased_ty.moves_by_default(gcx, param_env, DUMMY_SP) { continue; } diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index 9321121fe15..e8bf543b70b 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -21,6 +21,8 @@ use rustc_data_structures::indexed_vec::{IndexVec}; use dataflow::{BitDenotation, BlockSets, DataflowOperator}; pub use dataflow::indexes::BorrowIndex; +use transform::nll::region_infer::RegionInferenceContext; +use transform::nll::ToRegionIndex; use syntax_pos::Span; @@ -29,13 +31,14 @@ use std::fmt; // `Borrows` maps each dataflow bit to an `Rvalue::Ref`, which can be // uniquely identified in the MIR by the `Location` of the assigment // statement in which it appears on the right hand side. -pub struct Borrows<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub struct Borrows<'a, 'gcx: 'tcx, 'tcx: 'a> { + tcx: TyCtxt<'a, 'gcx, 'tcx>, mir: &'a Mir<'tcx>, borrows: IndexVec<BorrowIndex, BorrowData<'tcx>>, location_map: FxHashMap<Location, BorrowIndex>, region_map: FxHashMap<Region<'tcx>, FxHashSet<BorrowIndex>>, region_span_map: FxHashMap<RegionKind, Span>, + nonlexical_regioncx: Option<&'a RegionInferenceContext<'tcx>>, } // temporarily allow some dead fields: `kind` and `region` will be @@ -63,8 +66,11 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> { } } -impl<'a, 'tcx> Borrows<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &'a Mir<'tcx>) -> Self { +impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> { + pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, + mir: &'a Mir<'tcx>, + nonlexical_regioncx: Option<&'a RegionInferenceContext<'tcx>>) + -> Self { let mut visitor = GatherBorrows { idx_vec: IndexVec::new(), location_map: FxHashMap(), region_map: FxHashMap(), @@ -75,7 +81,8 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { borrows: visitor.idx_vec, location_map: visitor.location_map, region_map: visitor.region_map, - region_span_map: visitor.region_span_map}; + region_span_map: visitor.region_span_map, + nonlexical_regioncx }; struct GatherBorrows<'tcx> { idx_vec: IndexVec<BorrowIndex, BorrowData<'tcx>>, @@ -116,14 +123,44 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { &self.borrows[idx].location } - pub fn region_span(&self, region: &Region) -> Span { + /// Returns the span for the "end point" given region. This will + /// return `None` if NLL is enabled, since that concept has no + /// meaning there. Otherwise, it should return some. + pub fn opt_region_end_span(&self, region: &Region) -> Option<Span> { let opt_span = self.region_span_map.get(region); - assert!(opt_span.is_some(), "end region not found for {:?}", region); - *opt_span.unwrap() + assert!(self.nonlexical_regioncx.is_some() || + opt_span.is_some(), "end region not found for {:?}", region); + opt_span.map(|s| s.end_point()) + } + + /// Add all borrows to the kill set, if those borrows are out of scope at `location`. + fn kill_loans_out_of_scope_at_location(&self, + sets: &mut BlockSets<BorrowIndex>, + location: Location) { + if let Some(regioncx) = self.nonlexical_regioncx { + for (borrow_index, borrow_data) in self.borrows.iter_enumerated() { + let borrow_region = borrow_data.region.to_region_index(); + if !regioncx.region_contains_point(borrow_region, location) { + // The region checker really considers the borrow + // to start at the point **after** the location of + // the borrow, but the borrow checker puts the gen + // directly **on** the location of the + // borrow. This results in a gen/kill both being + // generated for same point if we are not + // careful. Probably we should change the point of + // the gen, but for now we hackily account for the + // mismatch here by not generating a kill for the + // location on the borrow itself. + if location != borrow_data.location { + sets.kill(&borrow_index); + } + } + } + } } } -impl<'a, 'tcx> BitDenotation for Borrows<'a, 'tcx> { +impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> { type Idx = BorrowIndex; fn name() -> &'static str { "borrows" } fn bits_per_block(&self) -> usize { @@ -146,6 +183,7 @@ impl<'a, 'tcx> BitDenotation for Borrows<'a, 'tcx> { match stmt.kind { mir::StatementKind::EndRegion(region_scope) => { if let Some(borrow_indexes) = self.region_map.get(&ReScope(region_scope)) { + assert!(self.nonlexical_regioncx.is_none()); for idx in borrow_indexes { sets.kill(&idx); } } else { // (if there is no entry, then there are no borrows to be tracked) @@ -172,11 +210,14 @@ impl<'a, 'tcx> BitDenotation for Borrows<'a, 'tcx> { mir::StatementKind::Nop => {} } + + self.kill_loans_out_of_scope_at_location(sets, location); } + fn terminator_effect(&self, - _sets: &mut BlockSets<BorrowIndex>, - _location: Location) { - // no terminators start nor end region scopes. + sets: &mut BlockSets<BorrowIndex>, + location: Location) { + self.kill_loans_out_of_scope_at_location(sets, location); } fn propagate_call_return(&self, @@ -188,14 +229,14 @@ impl<'a, 'tcx> BitDenotation for Borrows<'a, 'tcx> { } } -impl<'a, 'tcx> BitwiseOperator for Borrows<'a, 'tcx> { +impl<'a, 'gcx, 'tcx> BitwiseOperator for Borrows<'a, 'gcx, 'tcx> { #[inline] fn join(&self, pred1: usize, pred2: usize) -> usize { pred1 | pred2 // union effects of preds when computing borrows } } -impl<'a, 'tcx> DataflowOperator for Borrows<'a, 'tcx> { +impl<'a, 'gcx, 'tcx> DataflowOperator for Borrows<'a, 'gcx, 'tcx> { #[inline] fn bottom_value() -> bool { false // bottom = no Rvalue::Refs are active by default diff --git a/src/librustc_mir/dataflow/impls/mod.rs b/src/librustc_mir/dataflow/impls/mod.rs index 19a595622b9..af99706be81 100644 --- a/src/librustc_mir/dataflow/impls/mod.rs +++ b/src/librustc_mir/dataflow/impls/mod.rs @@ -69,23 +69,23 @@ pub(super) mod borrows; /// Similarly, at a given `drop` statement, the set-intersection /// between this data and `MaybeUninitializedLvals` yields the set of /// l-values that would require a dynamic drop-flag at that statement. -pub struct MaybeInitializedLvals<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub struct MaybeInitializedLvals<'a, 'gcx: 'tcx, 'tcx: 'a> { + tcx: TyCtxt<'a, 'gcx, 'tcx>, mir: &'a Mir<'tcx>, - mdpe: &'a MoveDataParamEnv<'tcx>, + mdpe: &'a MoveDataParamEnv<'gcx, 'tcx>, } -impl<'a, 'tcx: 'a> MaybeInitializedLvals<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, +impl<'a, 'gcx: 'tcx, 'tcx> MaybeInitializedLvals<'a, 'gcx, 'tcx> { + pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, mir: &'a Mir<'tcx>, - mdpe: &'a MoveDataParamEnv<'tcx>) + mdpe: &'a MoveDataParamEnv<'gcx, 'tcx>) -> Self { MaybeInitializedLvals { tcx: tcx, mir: mir, mdpe: mdpe } } } -impl<'a, 'tcx: 'a> HasMoveData<'tcx> for MaybeInitializedLvals<'a, 'tcx> { +impl<'a, 'gcx, 'tcx> HasMoveData<'tcx> for MaybeInitializedLvals<'a, 'gcx, 'tcx> { fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data } } @@ -124,23 +124,23 @@ impl<'a, 'tcx: 'a> HasMoveData<'tcx> for MaybeInitializedLvals<'a, 'tcx> { /// Similarly, at a given `drop` statement, the set-intersection /// between this data and `MaybeInitializedLvals` yields the set of /// l-values that would require a dynamic drop-flag at that statement. -pub struct MaybeUninitializedLvals<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub struct MaybeUninitializedLvals<'a, 'gcx: 'tcx, 'tcx: 'a> { + tcx: TyCtxt<'a, 'gcx, 'tcx>, mir: &'a Mir<'tcx>, - mdpe: &'a MoveDataParamEnv<'tcx>, + mdpe: &'a MoveDataParamEnv<'gcx, 'tcx>, } -impl<'a, 'tcx: 'a> MaybeUninitializedLvals<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, +impl<'a, 'gcx, 'tcx> MaybeUninitializedLvals<'a, 'gcx, 'tcx> { + pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, mir: &'a Mir<'tcx>, - mdpe: &'a MoveDataParamEnv<'tcx>) + mdpe: &'a MoveDataParamEnv<'gcx, 'tcx>) -> Self { MaybeUninitializedLvals { tcx: tcx, mir: mir, mdpe: mdpe } } } -impl<'a, 'tcx: 'a> HasMoveData<'tcx> for MaybeUninitializedLvals<'a, 'tcx> { +impl<'a, 'gcx, 'tcx> HasMoveData<'tcx> for MaybeUninitializedLvals<'a, 'gcx, 'tcx> { fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data } } @@ -185,27 +185,27 @@ impl<'a, 'tcx: 'a> HasMoveData<'tcx> for MaybeUninitializedLvals<'a, 'tcx> { /// Similarly, at a given `drop` statement, the set-difference between /// this data and `MaybeInitializedLvals` yields the set of l-values /// that would require a dynamic drop-flag at that statement. -pub struct DefinitelyInitializedLvals<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub struct DefinitelyInitializedLvals<'a, 'gcx: 'tcx, 'tcx: 'a> { + tcx: TyCtxt<'a, 'gcx, 'tcx>, mir: &'a Mir<'tcx>, - mdpe: &'a MoveDataParamEnv<'tcx>, + mdpe: &'a MoveDataParamEnv<'gcx, 'tcx>, } -impl<'a, 'tcx: 'a> DefinitelyInitializedLvals<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, +impl<'a, 'gcx, 'tcx: 'a> DefinitelyInitializedLvals<'a, 'gcx, 'tcx> { + pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, mir: &'a Mir<'tcx>, - mdpe: &'a MoveDataParamEnv<'tcx>) + mdpe: &'a MoveDataParamEnv<'gcx, 'tcx>) -> Self { DefinitelyInitializedLvals { tcx: tcx, mir: mir, mdpe: mdpe } } } -impl<'a, 'tcx: 'a> HasMoveData<'tcx> for DefinitelyInitializedLvals<'a, 'tcx> { +impl<'a, 'gcx, 'tcx: 'a> HasMoveData<'tcx> for DefinitelyInitializedLvals<'a, 'gcx, 'tcx> { fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data } } -impl<'a, 'tcx> MaybeInitializedLvals<'a, 'tcx> { +impl<'a, 'gcx, 'tcx> MaybeInitializedLvals<'a, 'gcx, 'tcx> { fn update_bits(sets: &mut BlockSets<MovePathIndex>, path: MovePathIndex, state: DropFlagState) { @@ -216,7 +216,7 @@ impl<'a, 'tcx> MaybeInitializedLvals<'a, 'tcx> { } } -impl<'a, 'tcx> MaybeUninitializedLvals<'a, 'tcx> { +impl<'a, 'gcx, 'tcx> MaybeUninitializedLvals<'a, 'gcx, 'tcx> { fn update_bits(sets: &mut BlockSets<MovePathIndex>, path: MovePathIndex, state: DropFlagState) { @@ -227,7 +227,7 @@ impl<'a, 'tcx> MaybeUninitializedLvals<'a, 'tcx> { } } -impl<'a, 'tcx> DefinitelyInitializedLvals<'a, 'tcx> { +impl<'a, 'gcx, 'tcx> DefinitelyInitializedLvals<'a, 'gcx, 'tcx> { fn update_bits(sets: &mut BlockSets<MovePathIndex>, path: MovePathIndex, state: DropFlagState) { @@ -238,7 +238,7 @@ impl<'a, 'tcx> DefinitelyInitializedLvals<'a, 'tcx> { } } -impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> { +impl<'a, 'gcx, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'gcx, 'tcx> { type Idx = MovePathIndex; fn name() -> &'static str { "maybe_init" } fn bits_per_block(&self) -> usize { @@ -290,7 +290,7 @@ impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> { } } -impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> { +impl<'a, 'gcx, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'gcx, 'tcx> { type Idx = MovePathIndex; fn name() -> &'static str { "maybe_uninit" } fn bits_per_block(&self) -> usize { @@ -345,7 +345,7 @@ impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> { } } -impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> { +impl<'a, 'gcx, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'gcx, 'tcx> { type Idx = MovePathIndex; fn name() -> &'static str { "definite_init" } fn bits_per_block(&self) -> usize { @@ -399,21 +399,21 @@ impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> { } } -impl<'a, 'tcx> BitwiseOperator for MaybeInitializedLvals<'a, 'tcx> { +impl<'a, 'gcx, 'tcx> BitwiseOperator for MaybeInitializedLvals<'a, 'gcx, 'tcx> { #[inline] fn join(&self, pred1: usize, pred2: usize) -> usize { pred1 | pred2 // "maybe" means we union effects of both preds } } -impl<'a, 'tcx> BitwiseOperator for MaybeUninitializedLvals<'a, 'tcx> { +impl<'a, 'gcx, 'tcx> BitwiseOperator for MaybeUninitializedLvals<'a, 'gcx, 'tcx> { #[inline] fn join(&self, pred1: usize, pred2: usize) -> usize { pred1 | pred2 // "maybe" means we union effects of both preds } } -impl<'a, 'tcx> BitwiseOperator for DefinitelyInitializedLvals<'a, 'tcx> { +impl<'a, 'gcx, 'tcx> BitwiseOperator for DefinitelyInitializedLvals<'a, 'gcx, 'tcx> { #[inline] fn join(&self, pred1: usize, pred2: usize) -> usize { pred1 & pred2 // "definitely" means we intersect effects of both preds @@ -430,21 +430,21 @@ impl<'a, 'tcx> BitwiseOperator for DefinitelyInitializedLvals<'a, 'tcx> { // propagating, or you start at all-ones and then use Intersect as // your merge when propagating. -impl<'a, 'tcx> DataflowOperator for MaybeInitializedLvals<'a, 'tcx> { +impl<'a, 'gcx, 'tcx> DataflowOperator for MaybeInitializedLvals<'a, 'gcx, 'tcx> { #[inline] fn bottom_value() -> bool { false // bottom = uninitialized } } -impl<'a, 'tcx> DataflowOperator for MaybeUninitializedLvals<'a, 'tcx> { +impl<'a, 'gcx, 'tcx> DataflowOperator for MaybeUninitializedLvals<'a, 'gcx, 'tcx> { #[inline] fn bottom_value() -> bool { false // bottom = initialized (start_block_effect counters this at outset) } } -impl<'a, 'tcx> DataflowOperator for DefinitelyInitializedLvals<'a, 'tcx> { +impl<'a, 'gcx, 'tcx> DataflowOperator for DefinitelyInitializedLvals<'a, 'gcx, 'tcx> { #[inline] fn bottom_value() -> bool { true // bottom = initialized (start_block_effect counters this at outset) diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs index 9fa5691d647..f5517096e3a 100644 --- a/src/librustc_mir/dataflow/mod.rs +++ b/src/librustc_mir/dataflow/mod.rs @@ -91,19 +91,19 @@ pub(crate) fn has_rustc_mir_with(attrs: &[ast::Attribute], name: &str) -> Option return None; } -pub struct MoveDataParamEnv<'tcx> { +pub struct MoveDataParamEnv<'gcx, 'tcx> { pub(crate) move_data: MoveData<'tcx>, - pub(crate) param_env: ty::ParamEnv<'tcx>, + pub(crate) param_env: ty::ParamEnv<'gcx>, } -pub(crate) fn do_dataflow<'a, 'tcx, BD, P>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - mir: &Mir<'tcx>, - node_id: ast::NodeId, - attributes: &[ast::Attribute], - dead_unwinds: &IdxSet<BasicBlock>, - bd: BD, - p: P) - -> DataflowResults<BD> +pub(crate) fn do_dataflow<'a, 'gcx, 'tcx, BD, P>(tcx: TyCtxt<'a, 'gcx, 'tcx>, + mir: &Mir<'tcx>, + node_id: ast::NodeId, + attributes: &[ast::Attribute], + dead_unwinds: &IdxSet<BasicBlock>, + bd: BD, + p: P) + -> DataflowResults<BD> where BD: BitDenotation, P: Fn(&BD, BD::Idx) -> &fmt::Debug { @@ -612,9 +612,9 @@ pub trait BitDenotation: DataflowOperator { dest_lval: &mir::Lvalue); } -impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation +impl<'a, 'gcx, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation { - pub fn new(_tcx: TyCtxt<'a, 'tcx, 'tcx>, + pub fn new(_tcx: TyCtxt<'a, 'gcx, 'tcx>, mir: &'a Mir<'tcx>, dead_unwinds: &'a IdxSet<mir::BasicBlock>, denotation: D) -> Self { @@ -721,6 +721,12 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation self.propagate_bits_into_entry_set_for(in_out, changed, dest_bb); } } + mir::TerminatorKind::FalseEdges { ref real_target, ref imaginary_targets } => { + self.propagate_bits_into_entry_set_for(in_out, changed, real_target); + for target in imaginary_targets { + self.propagate_bits_into_entry_set_for(in_out, changed, target); + } + } } } diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index 0790d937ceb..79ea745125c 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -25,18 +25,18 @@ use super::{LocationMap, MoveData, MovePath, MovePathLookup, MovePathIndex, Move use super::{MoveError}; use super::IllegalMoveOriginKind::*; -struct MoveDataBuilder<'a, 'tcx: 'a> { +struct MoveDataBuilder<'a, 'gcx: 'tcx, 'tcx: 'a> { mir: &'a Mir<'tcx>, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'gcx>, data: MoveData<'tcx>, errors: Vec<MoveError<'tcx>>, } -impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { +impl<'a, 'gcx, 'tcx> MoveDataBuilder<'a, 'gcx, 'tcx> { fn new(mir: &'a Mir<'tcx>, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>) + tcx: TyCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'gcx>) -> Self { let mut move_paths = IndexVec::new(); let mut path_map = IndexVec::new(); @@ -86,7 +86,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { } } -impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { +impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> { /// This creates a MovePath for a given lvalue, returning an `MovePathError` /// if that lvalue can't be moved from. /// @@ -175,7 +175,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { } } -impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { +impl<'a, 'gcx, 'tcx> MoveDataBuilder<'a, 'gcx, 'tcx> { fn finalize(self) -> Result<MoveData<'tcx>, (MoveData<'tcx>, Vec<MoveError<'tcx>>)> { debug!("{}", { debug!("moves for {:?}:", self.mir.span); @@ -197,11 +197,11 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { } } -pub(super) fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>) - -> Result<MoveData<'tcx>, - (MoveData<'tcx>, Vec<MoveError<'tcx>>)> { +pub(super) fn gather_moves<'a, 'gcx, 'tcx>(mir: &Mir<'tcx>, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'gcx>) + -> Result<MoveData<'tcx>, + (MoveData<'tcx>, Vec<MoveError<'tcx>>)> { let mut builder = MoveDataBuilder::new(mir, tcx, param_env); for (bb, block) in mir.basic_blocks().iter_enumerated() { @@ -220,7 +220,7 @@ pub(super) fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, builder.finalize() } -impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { +impl<'a, 'gcx, 'tcx> MoveDataBuilder<'a, 'gcx, 'tcx> { fn gather_statement(&mut self, loc: Location, stmt: &Statement<'tcx>) { debug!("gather_statement({:?}, {:?})", loc, stmt); (Gatherer { builder: self, loc }).gather_statement(stmt); @@ -232,12 +232,12 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { } } -struct Gatherer<'b, 'a: 'b, 'tcx: 'a> { - builder: &'b mut MoveDataBuilder<'a, 'tcx>, +struct Gatherer<'b, 'a: 'b, 'gcx: 'tcx, 'tcx: 'a> { + builder: &'b mut MoveDataBuilder<'a, 'gcx, 'tcx>, loc: Location, } -impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { +impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> { fn gather_statement(&mut self, stmt: &Statement<'tcx>) { match stmt.kind { StatementKind::Assign(ref lval, ref rval) => { @@ -305,6 +305,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { TerminatorKind::Goto { target: _ } | TerminatorKind::Resume | TerminatorKind::GeneratorDrop | + TerminatorKind::FalseEdges { .. } | TerminatorKind::Unreachable => { } TerminatorKind::Return => { @@ -352,8 +353,10 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { debug!("gather_move({:?}, {:?})", self.loc, lval); let tcx = self.builder.tcx; + let gcx = tcx.global_tcx(); let lv_ty = lval.ty(self.builder.mir, tcx).to_ty(tcx); - if !lv_ty.moves_by_default(tcx, self.builder.param_env, DUMMY_SP) { + let erased_ty = gcx.lift(&tcx.erase_regions(&lv_ty)).unwrap(); + if !erased_ty.moves_by_default(gcx, self.builder.param_env, DUMMY_SP) { debug!("gather_move({:?}, {:?}) - {:?} is Copy. skipping", self.loc, lval, lv_ty); return } diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs index 9369156a223..5bfecd01aaa 100644 --- a/src/librustc_mir/dataflow/move_paths/mod.rs +++ b/src/librustc_mir/dataflow/move_paths/mod.rs @@ -256,10 +256,10 @@ impl<'tcx> MoveError<'tcx> { } } -impl<'a, 'tcx> MoveData<'tcx> { +impl<'a, 'gcx, 'tcx> MoveData<'tcx> { pub fn gather_moves(mir: &Mir<'tcx>, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>) + tcx: TyCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'gcx>) -> Result<Self, (Self, Vec<MoveError<'tcx>>)> { builder::gather_moves(mir, tcx, param_env) } diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 7e4206e14c5..b72823dff2b 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -18,13 +18,14 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(box_patterns)] #![feature(box_syntax)] +#![feature(conservative_impl_trait)] #![feature(const_fn)] -#![feature(core_intrinsics)] #![feature(i128_type)] #![feature(rustc_diagnostic_macros)] #![feature(placement_in_syntax)] #![feature(collection_placement)] #![feature(nonzero)] +#![feature(underscore_lifetimes)] #[macro_use] extern crate bitflags; diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 49ce3622399..80c8f22c102 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -73,7 +73,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { TerminatorKind::GeneratorDrop | TerminatorKind::Resume | TerminatorKind::Return | - TerminatorKind::Unreachable => { + TerminatorKind::Unreachable | + TerminatorKind::FalseEdges { .. } => { // safe (at least as emitted during MIR construction) } diff --git a/src/librustc_mir/transform/clean_end_regions.rs b/src/librustc_mir/transform/clean_end_regions.rs index a6750f400ba..d356d3b5a85 100644 --- a/src/librustc_mir/transform/clean_end_regions.rs +++ b/src/librustc_mir/transform/clean_end_regions.rs @@ -24,7 +24,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc::middle::region; use rustc::mir::transform::{MirPass, MirSource}; use rustc::mir::{BasicBlock, Location, Mir, Rvalue, Statement, StatementKind}; -use rustc::mir::visit::{MutVisitor, Visitor, Lookup}; +use rustc::mir::visit::{MutVisitor, Visitor, TyContext}; use rustc::ty::{Ty, RegionKind, TyCtxt}; pub struct CleanEndRegions; @@ -67,7 +67,7 @@ impl<'tcx> Visitor<'tcx> for GatherBorrowedRegions { self.super_rvalue(rvalue, location); } - fn visit_ty(&mut self, ty: &Ty<'tcx>, _: Lookup) { + fn visit_ty(&mut self, ty: &Ty<'tcx>, _: TyContext) { // Gather regions that occur in types for re in ty.walk().flat_map(|t| t.regions()) { match *re { diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index be1b794ecdf..94da1f31a96 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -83,7 +83,7 @@ fn find_dead_unwinds<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &Mir<'tcx>, id: ast::NodeId, - env: &MoveDataParamEnv<'tcx>) + env: &MoveDataParamEnv<'tcx, 'tcx>) -> IdxSetBuf<BasicBlock> { debug!("find_dead_unwinds({:?})", mir.span); @@ -146,7 +146,7 @@ impl InitializationData { fn apply_location<'a,'tcx>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &Mir<'tcx>, - env: &MoveDataParamEnv<'tcx>, + env: &MoveDataParamEnv<'tcx, 'tcx>, loc: Location) { drop_flag_effects_for_location(tcx, mir, env, loc, |path, df| { @@ -280,9 +280,9 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> { struct ElaborateDropsCtxt<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &'a Mir<'tcx>, - env: &'a MoveDataParamEnv<'tcx>, - flow_inits: DataflowResults<MaybeInitializedLvals<'a, 'tcx>>, - flow_uninits: DataflowResults<MaybeUninitializedLvals<'a, 'tcx>>, + env: &'a MoveDataParamEnv<'tcx, 'tcx>, + flow_inits: DataflowResults<MaybeInitializedLvals<'a, 'tcx, 'tcx>>, + flow_uninits: DataflowResults<MaybeUninitializedLvals<'a, 'tcx, 'tcx>>, drop_flags: FxHashMap<MovePathIndex, Local>, patch: MirPatch<'tcx>, } diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs index dc18cdd8f0d..08ca20e50eb 100644 --- a/src/librustc_mir/transform/erase_regions.rs +++ b/src/librustc_mir/transform/erase_regions.rs @@ -17,7 +17,7 @@ use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TyCtxt}; use rustc::mir::*; -use rustc::mir::visit::{MutVisitor, Lookup}; +use rustc::mir::visit::{MutVisitor, TyContext}; use rustc::mir::transform::{MirPass, MirSource}; struct EraseRegionsVisitor<'a, 'tcx: 'a> { @@ -35,7 +35,7 @@ impl<'a, 'tcx> EraseRegionsVisitor<'a, 'tcx> { } impl<'a, 'tcx> MutVisitor<'tcx> for EraseRegionsVisitor<'a, 'tcx> { - fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: Lookup) { + fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) { if !self.in_validation_statement { *ty = self.tcx.erase_regions(ty); } diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 7d0814b67fb..52a50333f45 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -68,7 +68,7 @@ use rustc::mir::visit::{LvalueContext, Visitor, MutVisitor}; use rustc::ty::{self, TyCtxt, AdtDef, Ty, GeneratorInterior}; use rustc::ty::subst::{Kind, Substs}; use util::dump_mir; -use util::liveness; +use util::liveness::{self, LivenessMode}; use rustc_const_math::ConstInt; use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_set::IdxSetBuf; @@ -348,7 +348,10 @@ fn locals_live_across_suspend_points<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ignored.visit_mir(mir); let mut set = liveness::LocalSet::new_empty(mir.local_decls.len()); - let liveness = liveness::liveness_of_locals(mir); + let liveness = liveness::liveness_of_locals(mir, LivenessMode { + include_regular_use: true, + include_drops: true, + }); liveness::dump_mir(tcx, "generator_liveness", source, mir, &liveness); let mut storage_liveness_map = HashMap::new(); diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 9d32861aeda..f2453d39461 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -720,6 +720,12 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { } } TerminatorKind::Unreachable => { } + TerminatorKind::FalseEdges { ref mut real_target, ref mut imaginary_targets } => { + *real_target = self.update_target(*real_target); + for target in imaginary_targets { + *target = self.update_target(*target); + } + } } } diff --git a/src/librustc_mir/transform/nll/constraint_generation.rs b/src/librustc_mir/transform/nll/constraint_generation.rs new file mode 100644 index 00000000000..a2f9bbb174e --- /dev/null +++ b/src/librustc_mir/transform/nll/constraint_generation.rs @@ -0,0 +1,274 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc::hir; +use rustc::mir::{BasicBlock, BorrowKind, Location, Lvalue, Mir, Rvalue, Statement, StatementKind}; +use rustc::mir::transform::MirSource; +use rustc::mir::visit::Visitor; +use rustc::mir::Lvalue::Projection; +use rustc::mir::{LvalueProjection, ProjectionElem}; +use rustc::infer::InferCtxt; +use rustc::traits::{self, ObligationCause}; +use rustc::ty::{self, Ty}; +use rustc::ty::fold::TypeFoldable; +use rustc::util::common::ErrorReported; +use rustc_data_structures::fx::FxHashSet; +use syntax::codemap::DUMMY_SP; + +use super::subtype; +use super::LivenessResults; +use super::ToRegionIndex; +use super::region_infer::RegionInferenceContext; + +pub(super) fn generate_constraints<'a, 'gcx, 'tcx>( + infcx: &InferCtxt<'a, 'gcx, 'tcx>, + regioncx: &mut RegionInferenceContext<'tcx>, + mir: &Mir<'tcx>, + mir_source: MirSource, + liveness: &LivenessResults, +) { + ConstraintGeneration { + infcx, + regioncx, + mir, + liveness, + mir_source, + }.add_constraints(); +} + +struct ConstraintGeneration<'cx, 'gcx: 'tcx, 'tcx: 'cx> { + infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, + regioncx: &'cx mut RegionInferenceContext<'tcx>, + mir: &'cx Mir<'tcx>, + liveness: &'cx LivenessResults, + mir_source: MirSource, +} + +impl<'cx, 'gcx, 'tcx> ConstraintGeneration<'cx, 'gcx, 'tcx> { + fn add_constraints(&mut self) { + self.add_liveness_constraints(); + self.add_borrow_constraints(); + } + + /// Liveness constraints: + /// + /// > If a variable V is live at point P, then all regions R in the type of V + /// > must include the point P. + fn add_liveness_constraints(&mut self) { + debug!("add_liveness_constraints()"); + for bb in self.mir.basic_blocks().indices() { + debug!("add_liveness_constraints: bb={:?}", bb); + + self.liveness + .regular + .simulate_block(self.mir, bb, |location, live_locals| { + for live_local in live_locals.iter() { + let live_local_ty = self.mir.local_decls[live_local].ty; + self.add_regular_live_constraint(live_local_ty, location); + } + }); + + self.liveness + .drop + .simulate_block(self.mir, bb, |location, live_locals| { + for live_local in live_locals.iter() { + let live_local_ty = self.mir.local_decls[live_local].ty; + self.add_drop_live_constraint(live_local_ty, location); + } + }); + } + } + + /// Some variable with type `live_ty` is "regular live" at + /// `location` -- i.e., it may be used later. This means that all + /// regions appearing in the type `live_ty` must be live at + /// `location`. + fn add_regular_live_constraint<T>(&mut self, live_ty: T, location: Location) + where + T: TypeFoldable<'tcx>, + { + debug!( + "add_regular_live_constraint(live_ty={:?}, location={:?})", + live_ty, + location + ); + + self.infcx + .tcx + .for_each_free_region(&live_ty, |live_region| { + let vid = live_region.to_region_index(); + self.regioncx.add_live_point(vid, location); + }); + } + + /// Some variable with type `live_ty` is "drop live" at `location` + /// -- i.e., it may be dropped later. This means that *some* of + /// the regions in its type must be live at `location`. The + /// precise set will depend on the dropck constraints, and in + /// particular this takes `#[may_dangle]` into account. + fn add_drop_live_constraint(&mut self, dropped_ty: Ty<'tcx>, location: Location) { + debug!( + "add_drop_live_constraint(dropped_ty={:?}, location={:?})", + dropped_ty, + location + ); + + let tcx = self.infcx.tcx; + let mut types = vec![(dropped_ty, 0)]; + let mut known = FxHashSet(); + while let Some((ty, depth)) = types.pop() { + let span = DUMMY_SP; // FIXME + let result = match tcx.dtorck_constraint_for_ty(span, dropped_ty, depth, ty) { + Ok(result) => result, + Err(ErrorReported) => { + continue; + } + }; + + let ty::DtorckConstraint { + outlives, + dtorck_types, + } = result; + + // All things in the `outlives` array may be touched by + // the destructor and must be live at this point. + for outlive in outlives { + if let Some(ty) = outlive.as_type() { + self.add_regular_live_constraint(ty, location); + } else if let Some(r) = outlive.as_region() { + self.add_regular_live_constraint(r, location); + } else { + bug!() + } + } + + // However, there may also be some types that + // `dtorck_constraint_for_ty` could not resolve (e.g., + // associated types and parameters). We need to normalize + // associated types here and possibly recursively process. + let def_id = tcx.hir.local_def_id(self.mir_source.item_id()); + let param_env = self.infcx.tcx.param_env(def_id); + for ty in dtorck_types { + // FIXME -- I think that this may disregard some region obligations + // or something. Do we care? -nmatsakis + let cause = ObligationCause::dummy(); + match traits::fully_normalize(self.infcx, cause, param_env, &ty) { + Ok(ty) => match ty.sty { + ty::TyParam(..) | ty::TyProjection(..) | ty::TyAnon(..) => { + self.add_regular_live_constraint(ty, location); + } + + _ => if known.insert(ty) { + types.push((ty, depth + 1)); + }, + }, + + Err(errors) => { + self.infcx.report_fulfillment_errors(&errors, None); + } + } + } + } + } + + fn add_borrow_constraints(&mut self) { + self.visit_mir(self.mir); + } + + fn add_borrow_constraint( + &mut self, + location: Location, + destination_lv: &Lvalue<'tcx>, + borrow_region: ty::Region<'tcx>, + _borrow_kind: BorrowKind, + _borrowed_lv: &Lvalue<'tcx>, + ) { + let tcx = self.infcx.tcx; + let span = self.mir.source_info(location).span; + let destination_ty = destination_lv.ty(self.mir, tcx).to_ty(tcx); + + let destination_region = match destination_ty.sty { + ty::TyRef(r, _) => r, + _ => bug!() + }; + + self.regioncx.add_outlives(span, + borrow_region.to_region_index(), + destination_region.to_region_index(), + location.successor_within_block()); + } + + fn add_reborrow_constraint( + &mut self, + location: Location, + borrow_region: ty::Region<'tcx>, + borrowed_lv: &Lvalue<'tcx>, + ) { + if let Projection(ref proj) = *borrowed_lv { + let LvalueProjection { ref base, ref elem } = **proj; + + if let ProjectionElem::Deref = *elem { + let tcx = self.infcx.tcx; + let base_ty = base.ty(self.mir, tcx).to_ty(tcx); + let base_sty = &base_ty.sty; + + if let ty::TyRef(base_region, ty::TypeAndMut{ ty: _, mutbl }) = *base_sty { + match mutbl { + hir::Mutability::MutImmutable => { }, + + hir::Mutability::MutMutable => { + self.add_reborrow_constraint(location, borrow_region, base); + }, + } + + let span = self.mir.source_info(location).span; + self.regioncx.add_outlives(span, + base_region.to_region_index(), + borrow_region.to_region_index(), + location.successor_within_block()); + } + } + } + } +} + +impl<'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cx, 'gcx, 'tcx> { + fn visit_statement(&mut self, + block: BasicBlock, + statement: &Statement<'tcx>, + location: Location) { + + debug!("visit_statement(statement={:?}, location={:?})", statement, location); + + // Look for a statement like: + // + // D = & L + // + // where D is the path to which we are assigning, and + // L is the path that is borrowed. + if let StatementKind::Assign(ref destination_lv, ref rv) = statement.kind { + if let Rvalue::Ref(region, bk, ref borrowed_lv) = *rv { + self.add_borrow_constraint(location, destination_lv, region, bk, borrowed_lv); + self.add_reborrow_constraint(location, region, borrowed_lv); + } + + let tcx = self.infcx.tcx; + let destination_ty = destination_lv.ty(self.mir, tcx).to_ty(tcx); + let rv_ty = rv.ty(self.mir, tcx); + + let span = self.mir.source_info(location).span; + for (a, b) in subtype::outlives_pairs(tcx, rv_ty, destination_ty) { + self.regioncx.add_outlives(span, a, b, location.successor_within_block()); + } + } + + self.super_statement(block, statement, location); + } +} diff --git a/src/librustc_mir/transform/nll/free_regions.rs b/src/librustc_mir/transform/nll/free_regions.rs new file mode 100644 index 00000000000..006a2f9047a --- /dev/null +++ b/src/librustc_mir/transform/nll/free_regions.rs @@ -0,0 +1,88 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Code to extract the free regions declared on a function and the +//! relationships between them. For example: +//! +//! ``` +//! fn foo<'a, 'b, 'c: 'b>() { } +//! ``` +//! +//! here we would be returning a map assigning each of `{'a, 'b, 'c}` +//! to an index, as well as the `FreeRegionMap` which can compute +//! relationships between them. +//! +//! The code in this file doesn't *do anything* with those results; it +//! just returns them for other code to use. + +use rustc::infer::InferCtxt; +use rustc::middle::free_region::FreeRegionMap; +use rustc::mir::transform::MirSource; +use rustc::ty; +use rustc::ty::subst::Substs; +use rustc::util::nodemap::FxHashMap; + +#[derive(Debug)] +pub struct FreeRegions<'tcx> { + /// Given a free region defined on this function (either early- or + /// late-bound), this maps it to its internal region index. The + /// corresponding variable will be "capped" so that it cannot + /// grow. + pub indices: FxHashMap<ty::Region<'tcx>, usize>, + + /// The map from the typeck tables telling us how to relate free regions. + pub free_region_map: &'tcx FreeRegionMap<'tcx>, +} + +pub fn free_regions<'a, 'gcx, 'tcx>( + infcx: &InferCtxt<'a, 'gcx, 'tcx>, + source: MirSource, +) -> FreeRegions<'tcx> { + debug!("free_regions(source={:?})", source); + + let item_id = source.item_id(); + let item_def_id = infcx.tcx.hir.local_def_id(item_id); + + let mut indices = FxHashMap(); + + // Extract the early regions. + let item_substs = Substs::identity_for_item(infcx.tcx, item_def_id); + for item_subst in item_substs { + if let Some(region) = item_subst.as_region() { + insert_free_region(&mut indices, region); + } + } + + // Extract the late-bound regions. Use the liberated fn sigs, + // where the late-bound regions will have been converted into free + // regions, and add them to the map. + let fn_hir_id = infcx.tcx.hir.node_to_hir_id(item_id); + let tables = infcx.tcx.typeck_tables_of(item_def_id); + let fn_sig = tables.liberated_fn_sigs()[fn_hir_id].clone(); + infcx + .tcx + .for_each_free_region(&fn_sig.inputs_and_output, |region| { + if let ty::ReFree(_) = *region { + insert_free_region(&mut indices, region); + } + }); + + debug!("free_regions: indices={:#?}", indices); + + FreeRegions { indices, free_region_map: &tables.free_region_map } +} + +fn insert_free_region<'tcx>( + free_regions: &mut FxHashMap<ty::Region<'tcx>, usize>, + region: ty::Region<'tcx>, +) { + let len = free_regions.len(); + free_regions.entry(region).or_insert(len); +} diff --git a/src/librustc_mir/transform/nll/infer.rs b/src/librustc_mir/transform/nll/infer.rs deleted file mode 100644 index e6e00f295ca..00000000000 --- a/src/librustc_mir/transform/nll/infer.rs +++ /dev/null @@ -1,222 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use super::{Region, RegionIndex}; -use std::mem; -use rustc::infer::InferCtxt; -use rustc::mir::{Location, Mir}; -use rustc_data_structures::indexed_vec::{Idx, IndexVec}; -use rustc_data_structures::fx::FxHashSet; - -pub struct InferenceContext { - definitions: IndexVec<RegionIndex, VarDefinition>, - constraints: IndexVec<ConstraintIndex, Constraint>, - errors: IndexVec<InferenceErrorIndex, InferenceError>, -} - -pub struct InferenceError { - pub constraint_point: Location, - pub name: (), // FIXME(nashenas88) RegionName -} - -newtype_index!(InferenceErrorIndex); - -struct VarDefinition { - name: (), // FIXME(nashenas88) RegionName - value: Region, - capped: bool, -} - -impl VarDefinition { - pub fn new(value: Region) -> Self { - Self { - name: (), - value, - capped: false, - } - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub struct Constraint { - sub: RegionIndex, - sup: RegionIndex, - point: Location, -} - -newtype_index!(ConstraintIndex); - -impl InferenceContext { - pub fn new(values: IndexVec<RegionIndex, Region>) -> Self { - Self { - definitions: values.into_iter().map(VarDefinition::new).collect(), - constraints: IndexVec::new(), - errors: IndexVec::new(), - } - } - - #[allow(dead_code)] - pub fn cap_var(&mut self, v: RegionIndex) { - self.definitions[v].capped = true; - } - - #[allow(dead_code)] - pub fn add_live_point(&mut self, v: RegionIndex, point: Location) { - debug!("add_live_point({:?}, {:?})", v, point); - let definition = &mut self.definitions[v]; - if definition.value.add_point(point) { - if definition.capped { - self.errors.push(InferenceError { - constraint_point: point, - name: definition.name, - }); - } - } - } - - #[allow(dead_code)] - pub fn add_outlives(&mut self, sup: RegionIndex, sub: RegionIndex, point: Location) { - debug!("add_outlives({:?}: {:?} @ {:?}", sup, sub, point); - self.constraints.push(Constraint { sup, sub, point }); - } - - #[allow(dead_code)] - pub fn region(&self, v: RegionIndex) -> &Region { - &self.definitions[v].value - } - - pub fn solve<'a, 'gcx, 'tcx>( - &mut self, - infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, - mir: &'a Mir<'tcx>, - ) -> IndexVec<InferenceErrorIndex, InferenceError> - where - 'gcx: 'tcx + 'a, - 'tcx: 'a, - { - let mut changed = true; - let mut dfs = Dfs::new(infcx, mir); - while changed { - changed = false; - for constraint in &self.constraints { - let sub = &self.definitions[constraint.sub].value.clone(); - let sup_def = &mut self.definitions[constraint.sup]; - debug!("constraint: {:?}", constraint); - debug!(" sub (before): {:?}", sub); - debug!(" sup (before): {:?}", sup_def.value); - - if dfs.copy(sub, &mut sup_def.value, constraint.point) { - changed = true; - if sup_def.capped { - // This is kind of a hack, but when we add a - // constraint, the "point" is always the point - // AFTER the action that induced the - // constraint. So report the error on the - // action BEFORE that. - assert!(constraint.point.statement_index > 0); - let p = Location { - block: constraint.point.block, - statement_index: constraint.point.statement_index - 1, - }; - - self.errors.push(InferenceError { - constraint_point: p, - name: sup_def.name, - }); - } - } - - debug!(" sup (after) : {:?}", sup_def.value); - debug!(" changed : {:?}", changed); - } - debug!("\n"); - } - - mem::replace(&mut self.errors, IndexVec::new()) - } -} - -struct Dfs<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> { - #[allow(dead_code)] - infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, - mir: &'a Mir<'tcx>, -} - -impl<'a, 'gcx: 'tcx, 'tcx: 'a> Dfs<'a, 'gcx, 'tcx> { - fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, mir: &'a Mir<'tcx>) -> Self { - Self { infcx, mir } - } - - fn copy( - &mut self, - from_region: &Region, - to_region: &mut Region, - start_point: Location, - ) -> bool { - let mut changed = false; - - let mut stack = vec![]; - let mut visited = FxHashSet(); - - stack.push(start_point); - while let Some(p) = stack.pop() { - debug!(" dfs: p={:?}", p); - - if !from_region.may_contain(p) { - debug!(" not in from-region"); - continue; - } - - if !visited.insert(p) { - debug!(" already visited"); - continue; - } - - changed |= to_region.add_point(p); - - let block_data = &self.mir[p.block]; - let successor_points = if p.statement_index < block_data.statements.len() { - vec![Location { - statement_index: p.statement_index + 1, - ..p - }] - } else { - block_data.terminator() - .successors() - .iter() - .map(|&basic_block| Location { - statement_index: 0, - block: basic_block, - }) - .collect::<Vec<_>>() - }; - - if successor_points.is_empty() { - // FIXME handle free regions - // If we reach the END point in the graph, then copy - // over any skolemized end points in the `from_region` - // and make sure they are included in the `to_region`. - // for region_decl in self.infcx.tcx.tables.borrow().free_region_map() { - // // FIXME(nashenas88) figure out skolemized_end points - // let block = self.env.graph.skolemized_end(region_decl.name); - // let skolemized_end_point = Location { - // block, - // statement_index: 0, - // }; - // changed |= to_region.add_point(skolemized_end_point); - // } - } else { - stack.extend(successor_points); - } - } - - changed - } -} diff --git a/src/librustc_mir/transform/nll/mod.rs b/src/librustc_mir/transform/nll/mod.rs index 805e9c976e4..e24def2292e 100644 --- a/src/librustc_mir/transform/nll/mod.rs +++ b/src/librustc_mir/transform/nll/mod.rs @@ -8,185 +8,194 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use self::infer::InferenceContext; -use rustc::ty::TypeFoldable; -use rustc::ty::subst::{Kind, Substs}; -use rustc::ty::{Ty, TyCtxt, ClosureSubsts, RegionVid, RegionKind}; -use rustc::mir::{Mir, Location, Rvalue, BasicBlock, Statement, StatementKind}; -use rustc::mir::visit::{MutVisitor, Lookup}; -use rustc::mir::transform::{MirPass, MirSource}; -use rustc::infer::{self as rustc_infer, InferCtxt}; -use rustc::util::nodemap::FxHashSet; -use rustc_data_structures::indexed_vec::{IndexVec, Idx}; -use syntax_pos::DUMMY_SP; -use std::collections::HashMap; -use std::fmt; +use rustc::ty::{self, RegionKind}; +use rustc::mir::Mir; +use rustc::mir::transform::MirSource; +use rustc::infer::InferCtxt; +use rustc::util::nodemap::FxHashMap; +use rustc_data_structures::indexed_vec::Idx; +use std::collections::BTreeSet; +use util::liveness::{self, LivenessMode, LivenessResult, LocalSet}; use util as mir_util; use self::mir_util::PassWhere; -mod infer; - -#[allow(dead_code)] -struct NLLVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { - lookup_map: HashMap<RegionVid, Lookup>, - regions: IndexVec<RegionIndex, Region>, - #[allow(dead_code)] - infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, +mod constraint_generation; +mod free_regions; +mod subtype; + +pub(crate) mod region_infer; +use self::region_infer::RegionInferenceContext; + +mod renumber; + +/// Computes the (non-lexical) regions from the input MIR. +/// +/// This may result in errors being reported. +pub fn compute_regions<'a, 'gcx, 'tcx>( + infcx: &InferCtxt<'a, 'gcx, 'tcx>, + source: MirSource, + mir: &mut Mir<'tcx>, +) -> RegionInferenceContext<'tcx> { + // Compute named region information. + let free_regions = &free_regions::free_regions(infcx, source); + + // Replace all regions with fresh inference variables. + let num_region_variables = renumber::renumber_mir(infcx, free_regions, mir); + + // Compute what is live where. + let liveness = &LivenessResults { + regular: liveness::liveness_of_locals( + &mir, + LivenessMode { + include_regular_use: true, + include_drops: false, + }, + ), + + drop: liveness::liveness_of_locals( + &mir, + LivenessMode { + include_regular_use: false, + include_drops: true, + }, + ), + }; + + // Create the region inference context, generate the constraints, + // and then solve them. + let mut regioncx = RegionInferenceContext::new(free_regions, num_region_variables, mir); + constraint_generation::generate_constraints(infcx, &mut regioncx, &mir, source, liveness); + regioncx.solve(infcx, &mir); + + // Dump MIR results into a file, if that is enabled. This let us + // write unit-tests. + dump_mir_results(infcx, liveness, source, &mir, ®ioncx); + + regioncx } -impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> { - pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>) -> Self { - NLLVisitor { - infcx, - lookup_map: HashMap::new(), - regions: IndexVec::new(), - } - } +struct LivenessResults { + regular: LivenessResult, + drop: LivenessResult, +} - pub fn into_results(self) -> (HashMap<RegionVid, Lookup>, IndexVec<RegionIndex, Region>) { - (self.lookup_map, self.regions) +fn dump_mir_results<'a, 'gcx, 'tcx>( + infcx: &InferCtxt<'a, 'gcx, 'tcx>, + liveness: &LivenessResults, + source: MirSource, + mir: &Mir<'tcx>, + regioncx: &RegionInferenceContext, +) { + if !mir_util::dump_enabled(infcx.tcx, "nll", source) { + return; } - fn renumber_regions<T>(&mut self, value: &T) -> T where T: TypeFoldable<'tcx> { - self.infcx.tcx.fold_regions(value, &mut false, |_region, _depth| { - self.regions.push(Region::default()); - self.infcx.next_region_var(rustc_infer::MiscVariable(DUMMY_SP)) + let regular_liveness_per_location: FxHashMap<_, _> = mir.basic_blocks() + .indices() + .flat_map(|bb| { + let mut results = vec![]; + liveness + .regular + .simulate_block(&mir, bb, |location, local_set| { + results.push((location, local_set.clone())); + }); + results }) - } - - fn store_region(&mut self, region: &RegionKind, lookup: Lookup) { - if let RegionKind::ReVar(rid) = *region { - self.lookup_map.entry(rid).or_insert(lookup); - } - } + .collect(); + + let drop_liveness_per_location: FxHashMap<_, _> = mir.basic_blocks() + .indices() + .flat_map(|bb| { + let mut results = vec![]; + liveness + .drop + .simulate_block(&mir, bb, |location, local_set| { + results.push((location, local_set.clone())); + }); + results + }) + .collect(); + + mir_util::dump_mir(infcx.tcx, None, "nll", &0, source, mir, |pass_where, out| { + match pass_where { + // Before the CFG, dump out the values for each region variable. + PassWhere::BeforeCFG => for region in regioncx.regions() { + writeln!( + out, + "| {:?}: {:?}", + region, + regioncx.region_value(region) + )?; + }, + + // Before each basic block, dump out the values + // that are live on entry to the basic block. + PassWhere::BeforeBlock(bb) => { + let s = live_variable_set(&liveness.regular.ins[bb], &liveness.drop.ins[bb]); + writeln!(out, " | Live variables on entry to {:?}: {}", bb, s)?; + } - fn store_ty_regions(&mut self, ty: &Ty<'tcx>, lookup: Lookup) { - for region in ty.regions() { - self.store_region(region, lookup); - } - } + PassWhere::InCFG(location) => { + let s = live_variable_set( + ®ular_liveness_per_location[&location], + &drop_liveness_per_location[&location], + ); + writeln!(out, " | Live variables at {:?}: {}", location, s)?; + } - fn store_kind_regions(&mut self, kind: &'tcx Kind, lookup: Lookup) { - if let Some(ty) = kind.as_type() { - self.store_ty_regions(&ty, lookup); - } else if let Some(region) = kind.as_region() { - self.store_region(region, lookup); + PassWhere::AfterCFG => {} } - } + Ok(()) + }); } -impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> { - fn visit_ty(&mut self, ty: &mut Ty<'tcx>, lookup: Lookup) { - let old_ty = *ty; - *ty = self.renumber_regions(&old_ty); - self.store_ty_regions(ty, lookup); - } - - fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>, location: Location) { - *substs = self.renumber_regions(&{*substs}); - let lookup = Lookup::Loc(location); - for kind in *substs { - self.store_kind_regions(kind, lookup); - } - } - - fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) { - match *rvalue { - Rvalue::Ref(ref mut r, _, _) => { - let old_r = *r; - *r = self.renumber_regions(&old_r); - let lookup = Lookup::Loc(location); - self.store_region(r, lookup); - } - Rvalue::Use(..) | - Rvalue::Repeat(..) | - Rvalue::Len(..) | - Rvalue::Cast(..) | - Rvalue::BinaryOp(..) | - Rvalue::CheckedBinaryOp(..) | - Rvalue::UnaryOp(..) | - Rvalue::Discriminant(..) | - Rvalue::NullaryOp(..) | - Rvalue::Aggregate(..) => { - // These variants don't contain regions. - } - } - self.super_rvalue(rvalue, location); - } - - fn visit_closure_substs(&mut self, - substs: &mut ClosureSubsts<'tcx>, - location: Location) { - *substs = self.renumber_regions(substs); - let lookup = Lookup::Loc(location); - for kind in substs.substs { - self.store_kind_regions(kind, lookup); - } - } +newtype_index!(RegionIndex { + DEBUG_FORMAT = "'_#{}r", +}); + +/// Right now, we piggy back on the `ReVar` to store our NLL inference +/// regions. These are indexed with `RegionIndex`. This method will +/// assert that the region is a `ReVar` and convert the internal index +/// into a `RegionIndex`. This is reasonable because in our MIR we +/// replace all free regions with inference variables. +pub trait ToRegionIndex { + fn to_region_index(&self) -> RegionIndex; +} - fn visit_statement(&mut self, - block: BasicBlock, - statement: &mut Statement<'tcx>, - location: Location) { - if let StatementKind::EndRegion(_) = statement.kind { - statement.kind = StatementKind::Nop; +impl ToRegionIndex for RegionKind { + fn to_region_index(&self) -> RegionIndex { + if let &ty::ReVar(vid) = self { + RegionIndex::new(vid.index as usize) + } else { + bug!("region is not an ReVar: {:?}", self) } - self.super_statement(block, statement, location); } } -// MIR Pass for non-lexical lifetimes -pub struct NLL; +fn live_variable_set(regular: &LocalSet, drops: &LocalSet) -> String { + // sort and deduplicate: + let all_locals: BTreeSet<_> = regular.iter().chain(drops.iter()).collect(); -impl MirPass for NLL { - fn run_pass<'a, 'tcx>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - source: MirSource, - mir: &mut Mir<'tcx>) { - if !tcx.sess.opts.debugging_opts.nll { - return; - } + // construct a string with each local, including `(drop)` if it is + // only dropped, versus a regular use. + let mut string = String::new(); + for local in all_locals { + string.push_str(&format!("{:?}", local)); - tcx.infer_ctxt().enter(|infcx| { - // Clone mir so we can mutate it without disturbing the rest of the compiler - let mut renumbered_mir = mir.clone(); - let mut visitor = NLLVisitor::new(&infcx); - visitor.visit_mir(&mut renumbered_mir); - mir_util::dump_mir(tcx, None, "nll", &0, source, mir, |pass_where, out| { - if let PassWhere::BeforeCFG = pass_where { - for (index, value) in visitor.regions.iter_enumerated() { - writeln!(out, "// R{:03}: {:?}", index.0, value)?; - } - } - Ok(()) - }); - let (_lookup_map, regions) = visitor.into_results(); - let mut inference_context = InferenceContext::new(regions); - inference_context.solve(&infcx, &renumbered_mir); - }) - } -} - -#[derive(Clone, Default, PartialEq, Eq)] -pub struct Region { - points: FxHashSet<Location>, -} + if !regular.contains(&local) { + assert!(drops.contains(&local)); + string.push_str(" (drop)"); + } -impl fmt::Debug for Region { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write!(formatter, "{:?}", self.points) + string.push_str(", "); } -} -impl Region { - pub fn add_point(&mut self, point: Location) -> bool { - self.points.insert(point) - } + let len = if string.is_empty() { + 0 + } else { + string.len() - 2 + }; - pub fn may_contain(&self, point: Location) -> bool { - self.points.contains(&point) - } + format!("[{}]", &string[..len]) } - -newtype_index!(RegionIndex); diff --git a/src/librustc_mir/transform/nll/region_infer.rs b/src/librustc_mir/transform/nll/region_infer.rs new file mode 100644 index 00000000000..553d5ad4a32 --- /dev/null +++ b/src/librustc_mir/transform/nll/region_infer.rs @@ -0,0 +1,400 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use super::RegionIndex; +use super::free_regions::FreeRegions; +use rustc::infer::InferCtxt; +use rustc::mir::{Location, Mir}; +use rustc::ty; +use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use rustc_data_structures::fx::FxHashSet; +use std::collections::BTreeSet; +use std::fmt; +use syntax_pos::Span; + +pub struct RegionInferenceContext<'tcx> { + /// Contains the definition for every region variable. Region + /// variables are identified by their index (`RegionIndex`). The + /// definition contains information about where the region came + /// from as well as its final inferred value. + definitions: IndexVec<RegionIndex, RegionDefinition<'tcx>>, + + /// The indices of all "free regions" in scope. These are the + /// lifetime parameters (anonymous and named) declared in the + /// function signature: + /// + /// fn foo<'a, 'b>(x: &Foo<'a, 'b>) + /// ^^ ^^ ^ + /// + /// These indices will be from 0..N, as it happens, but we collect + /// them into a vector for convenience. + free_regions: Vec<RegionIndex>, + + /// The constraints we have accumulated and used during solving. + constraints: Vec<Constraint>, +} + +#[derive(Default)] +struct RegionDefinition<'tcx> { + /// If this is a free-region, then this is `Some(X)` where `X` is + /// the name of the region. + name: Option<ty::Region<'tcx>>, + + /// If true, this is a constant region which cannot grow larger. + /// This is used for named regions as well as `'static`. + constant: bool, + + /// The current value of this inference variable. This starts out + /// empty, but grows as we add constraints. The final value is + /// determined when `solve()` is executed. + value: Region, +} + +/// The value of an individual region variable. Region variables +/// consist of a set of points in the CFG as well as a set of "free +/// regions", which are sometimes written as `end(R)`. These +/// correspond to the named lifetimes and refer to portions of the +/// caller's control-flow graph -- specifically some portion that can +/// be reached after we return. +#[derive(Clone, Default, PartialEq, Eq)] +struct Region { + points: BTreeSet<Location>, + free_regions: BTreeSet<RegionIndex>, +} + +impl fmt::Debug for Region { + fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + formatter + .debug_set() + .entries(&self.points) + .entries(&self.free_regions) + .finish() + } +} + +impl Region { + fn add_point(&mut self, point: Location) -> bool { + self.points.insert(point) + } + + fn add_free_region(&mut self, region: RegionIndex) -> bool { + self.free_regions.insert(region) + } + + fn contains_point(&self, point: Location) -> bool { + self.points.contains(&point) + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub struct Constraint { + /// Where did this constraint arise? + span: Span, + + /// The region SUP must outlive SUB... + sup: RegionIndex, + + /// Region that must be outlived. + sub: RegionIndex, + + /// At this location. + point: Location, +} + +impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> { + /// Creates a new region inference context with a total of + /// `num_region_variables` valid inference variables; the first N + /// of those will be constant regions representing the free + /// regions defined in `free_regions`. + pub fn new( + free_regions: &FreeRegions<'tcx>, + num_region_variables: usize, + mir: &Mir<'tcx>, + ) -> Self { + let mut result = Self { + definitions: (0..num_region_variables) + .map(|_| RegionDefinition::default()) + .collect(), + constraints: Vec::new(), + free_regions: Vec::new(), + }; + + result.init_free_regions(free_regions, mir); + + result + } + + /// Initializes the region variables for each free region + /// (lifetime parameter). The first N variables always correspond + /// to the free regions appearing in the function signature (both + /// named and anonymous) and where clauses. This function iterates + /// over those regions and initializes them with minimum values. + /// + /// For example: + /// + /// fn foo<'a, 'b>(..) where 'a: 'b + /// + /// would initialize two variables like so: + /// + /// R0 = { CFG, R0 } // 'a + /// R1 = { CFG, R0, R1 } // 'b + /// + /// Here, R0 represents `'a`, and it contains (a) the entire CFG + /// and (b) any free regions that it outlives, which in this case + /// is just itself. R1 (`'b`) in contrast also outlives `'a` and + /// hence contains R0 and R1. + fn init_free_regions(&mut self, free_regions: &FreeRegions<'tcx>, mir: &Mir<'tcx>) { + let &FreeRegions { + ref indices, + ref free_region_map, + } = free_regions; + + // For each free region X: + for (free_region, index) in indices { + let variable = RegionIndex::new(*index); + + self.free_regions.push(variable); + + // Initialize the name and a few other details. + self.definitions[variable].name = Some(free_region); + self.definitions[variable].constant = true; + + // Add all nodes in the CFG to `definition.value`. + for (block, block_data) in mir.basic_blocks().iter_enumerated() { + let definition = &mut self.definitions[variable]; + for statement_index in 0..block_data.statements.len() + 1 { + let location = Location { + block, + statement_index, + }; + definition.value.add_point(location); + } + } + + // Add `end(X)` into the set for X. + self.definitions[variable].value.add_free_region(variable); + + // Go through each region Y that outlives X (i.e., where + // Y: X is true). Add `end(X)` into the set for `Y`. + for superregion in free_region_map.regions_that_outlive(&free_region) { + let superregion_index = RegionIndex::new(indices[superregion]); + self.definitions[superregion_index] + .value + .add_free_region(variable); + } + + debug!( + "init_free_regions: region variable for `{:?}` is `{:?}` with value `{:?}`", + free_region, + variable, + self.definitions[variable].value + ); + } + } + + /// Returns an iterator over all the region indices. + pub fn regions(&self) -> impl Iterator<Item = RegionIndex> { + self.definitions.indices() + } + + /// Returns true if the region `r` contains the point `p`. + /// + /// Until `solve()` executes, this value is not particularly meaningful. + pub fn region_contains_point(&self, r: RegionIndex, p: Location) -> bool { + self.definitions[r].value.contains_point(p) + } + + /// Returns access to the value of `r` for debugging purposes. + pub(super) fn region_value(&self, r: RegionIndex) -> &fmt::Debug { + &self.definitions[r].value + } + + /// Indicates that the region variable `v` is live at the point `point`. + pub(super) fn add_live_point(&mut self, v: RegionIndex, point: Location) { + debug!("add_live_point({:?}, {:?})", v, point); + let definition = &mut self.definitions[v]; + if !definition.constant { + definition.value.add_point(point); + } else { + // Constants are used for free regions, which already + // contain all the points in the control-flow graph. + assert!(definition.value.contains_point(point)); + } + } + + /// Indicates that the region variable `sup` must outlive `sub` is live at the point `point`. + pub(super) fn add_outlives( + &mut self, + span: Span, + sup: RegionIndex, + sub: RegionIndex, + point: Location, + ) { + debug!("add_outlives({:?}: {:?} @ {:?}", sup, sub, point); + self.constraints.push(Constraint { + span, + sup, + sub, + point, + }); + } + + /// Perform region inference. + pub(super) fn solve(&mut self, infcx: &InferCtxt<'a, 'gcx, 'tcx>, mir: &Mir<'tcx>) { + let errors = self.propagate_constraints(mir); + + // worst error msg ever + for (fr1, span, fr2) in errors { + infcx.tcx.sess.span_err( + span, + &format!( + "free region `{}` does not outlive `{}`", + self.definitions[fr1].name.unwrap(), + self.definitions[fr2].name.unwrap() + ), + ); + } + } + + /// Propagate the region constraints: this will grow the values + /// for each region variable until all the constraints are + /// satisfied. Note that some values may grow **too** large to be + /// feasible, but we check this later. + fn propagate_constraints( + &mut self, + mir: &Mir<'tcx>, + ) -> Vec<(RegionIndex, Span, RegionIndex)> { + let mut changed = true; + let mut dfs = Dfs::new(mir); + let mut error_regions = FxHashSet(); + let mut errors = vec![]; + while changed { + changed = false; + for constraint in &self.constraints { + debug!("constraint: {:?}", constraint); + let sub = &self.definitions[constraint.sub].value.clone(); + let sup_def = &mut self.definitions[constraint.sup]; + + debug!(" sub (before): {:?}", sub); + debug!(" sup (before): {:?}", sup_def.value); + + if !sup_def.constant { + // If this is not a constant, then grow the value as needed to + // accommodate the outlives constraint. + + if dfs.copy(sub, &mut sup_def.value, constraint.point) { + changed = true; + } + + debug!(" sup (after) : {:?}", sup_def.value); + debug!(" changed : {:?}", changed); + } else { + // If this is a constant, check whether it *would + // have* to grow in order for the constraint to be + // satisfied. If so, create an error. + + let mut sup_value = sup_def.value.clone(); + if dfs.copy(sub, &mut sup_value, constraint.point) { + // Constant values start out with the entire + // CFG, so it must be some new free region + // that was added. Find one. + let &new_region = sup_value + .free_regions + .difference(&sup_def.value.free_regions) + .next() + .unwrap(); + debug!(" new_region : {:?}", new_region); + if error_regions.insert(constraint.sup) { + errors.push((constraint.sup, constraint.span, new_region)); + } + } + } + } + debug!("\n"); + } + errors + } +} + +struct Dfs<'a, 'tcx: 'a> { + mir: &'a Mir<'tcx>, +} + +impl<'a, 'tcx> Dfs<'a, 'tcx> { + fn new(mir: &'a Mir<'tcx>) -> Self { + Self { mir } + } + + fn copy( + &mut self, + from_region: &Region, + to_region: &mut Region, + start_point: Location, + ) -> bool { + let mut changed = false; + + let mut stack = vec![]; + let mut visited = FxHashSet(); + + stack.push(start_point); + while let Some(p) = stack.pop() { + debug!(" dfs: p={:?}", p); + + if !from_region.contains_point(p) { + debug!(" not in from-region"); + continue; + } + + if !visited.insert(p) { + debug!(" already visited"); + continue; + } + + changed |= to_region.add_point(p); + + let block_data = &self.mir[p.block]; + let successor_points = if p.statement_index < block_data.statements.len() { + vec![ + Location { + statement_index: p.statement_index + 1, + ..p + }, + ] + } else { + block_data + .terminator() + .successors() + .iter() + .map(|&basic_block| { + Location { + statement_index: 0, + block: basic_block, + } + }) + .collect::<Vec<_>>() + }; + + if successor_points.is_empty() { + // If we reach the END point in the graph, then copy + // over any skolemized end points in the `from_region` + // and make sure they are included in the `to_region`. + + debug!(" dfs: free_regions={:?}", from_region.free_regions); + for &fr in &from_region.free_regions { + changed |= to_region.free_regions.insert(fr); + } + } else { + stack.extend(successor_points); + } + } + + changed + } +} diff --git a/src/librustc_mir/transform/nll/renumber.rs b/src/librustc_mir/transform/nll/renumber.rs new file mode 100644 index 00000000000..a3ff7a041ca --- /dev/null +++ b/src/librustc_mir/transform/nll/renumber.rs @@ -0,0 +1,182 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc_data_structures::indexed_vec::Idx; +use rustc::ty::subst::{Kind, Substs}; +use rustc::ty::{self, ClosureSubsts, RegionKind, RegionVid, Ty, TypeFoldable}; +use rustc::mir::{BasicBlock, Local, Location, Mir, Rvalue, Statement, StatementKind}; +use rustc::mir::visit::{MutVisitor, TyContext}; +use rustc::infer::{self as rustc_infer, InferCtxt}; +use syntax_pos::DUMMY_SP; +use std::collections::HashMap; + +use super::free_regions::FreeRegions; + +/// Replaces all free regions appearing in the MIR with fresh +/// inference variables, returning the number of variables created. +pub fn renumber_mir<'a, 'gcx, 'tcx>( + infcx: &InferCtxt<'a, 'gcx, 'tcx>, + free_regions: &FreeRegions<'tcx>, + mir: &mut Mir<'tcx>, +) -> usize { + // Create inference variables for each of the free regions + // declared on the function signature. + let free_region_inference_vars = (0..free_regions.indices.len()) + .map(|_| { + infcx.next_region_var(rustc_infer::MiscVariable(DUMMY_SP)) + }) + .collect(); + + let mut visitor = NLLVisitor { + infcx, + lookup_map: HashMap::new(), + num_region_variables: free_regions.indices.len(), + free_regions, + free_region_inference_vars, + arg_count: mir.arg_count, + }; + visitor.visit_mir(mir); + visitor.num_region_variables +} + +struct NLLVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { + lookup_map: HashMap<RegionVid, TyContext>, + num_region_variables: usize, + infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + free_regions: &'a FreeRegions<'tcx>, + free_region_inference_vars: Vec<ty::Region<'tcx>>, + arg_count: usize, +} + +impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> { + /// Replaces all regions appearing in `value` with fresh inference + /// variables. This is what we do for almost the entire MIR, with + /// the exception of the declared types of our arguments. + fn renumber_regions<T>(&mut self, value: &T) -> T + where + T: TypeFoldable<'tcx>, + { + self.infcx + .tcx + .fold_regions(value, &mut false, |_region, _depth| { + self.num_region_variables += 1; + self.infcx + .next_region_var(rustc_infer::MiscVariable(DUMMY_SP)) + }) + } + + /// Renumbers the regions appearing in `value`, but those regions + /// are expected to be free regions from the function signature. + fn renumber_free_regions<T>(&mut self, value: &T) -> T + where + T: TypeFoldable<'tcx>, + { + self.infcx + .tcx + .fold_regions(value, &mut false, |region, _depth| { + let index = self.free_regions.indices[®ion]; + self.free_region_inference_vars[index] + }) + } + + fn store_region(&mut self, region: &RegionKind, lookup: TyContext) { + if let RegionKind::ReVar(rid) = *region { + self.lookup_map.entry(rid).or_insert(lookup); + } + } + + fn store_ty_regions(&mut self, ty: &Ty<'tcx>, ty_context: TyContext) { + for region in ty.regions() { + self.store_region(region, ty_context); + } + } + + fn store_kind_regions(&mut self, kind: &'tcx Kind, ty_context: TyContext) { + if let Some(ty) = kind.as_type() { + self.store_ty_regions(&ty, ty_context); + } else if let Some(region) = kind.as_region() { + self.store_region(region, ty_context); + } + } + + fn is_argument_or_return_slot(&self, local: Local) -> bool { + // The first argument is return slot, next N are arguments. + local.index() <= self.arg_count + } +} + +impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> { + fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) { + let is_arg = match ty_context { + TyContext::LocalDecl { local, .. } => self.is_argument_or_return_slot(local), + _ => false, + }; + + let old_ty = *ty; + *ty = if is_arg { + self.renumber_free_regions(&old_ty) + } else { + self.renumber_regions(&old_ty) + }; + self.store_ty_regions(ty, ty_context); + } + + fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>, location: Location) { + *substs = self.renumber_regions(&{ *substs }); + let ty_context = TyContext::Location(location); + for kind in *substs { + self.store_kind_regions(kind, ty_context); + } + } + + fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) { + match *rvalue { + Rvalue::Ref(ref mut r, _, _) => { + let old_r = *r; + *r = self.renumber_regions(&old_r); + let ty_context = TyContext::Location(location); + self.store_region(r, ty_context); + } + Rvalue::Use(..) | + Rvalue::Repeat(..) | + Rvalue::Len(..) | + Rvalue::Cast(..) | + Rvalue::BinaryOp(..) | + Rvalue::CheckedBinaryOp(..) | + Rvalue::UnaryOp(..) | + Rvalue::Discriminant(..) | + Rvalue::NullaryOp(..) | + Rvalue::Aggregate(..) => { + // These variants don't contain regions. + } + } + self.super_rvalue(rvalue, location); + } + + fn visit_closure_substs(&mut self, substs: &mut ClosureSubsts<'tcx>, location: Location) { + *substs = self.renumber_regions(substs); + let ty_context = TyContext::Location(location); + for kind in substs.substs { + self.store_kind_regions(kind, ty_context); + } + } + + fn visit_statement( + &mut self, + block: BasicBlock, + statement: &mut Statement<'tcx>, + location: Location, + ) { + if let StatementKind::EndRegion(_) = statement.kind { + statement.kind = StatementKind::Nop; + } + self.super_statement(block, statement, location); + } +} diff --git a/src/librustc_mir/transform/nll/subtype.rs b/src/librustc_mir/transform/nll/subtype.rs new file mode 100644 index 00000000000..953fc0eb733 --- /dev/null +++ b/src/librustc_mir/transform/nll/subtype.rs @@ -0,0 +1,99 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use super::RegionIndex; +use transform::nll::ToRegionIndex; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::relate::{self, Relate, RelateResult, TypeRelation}; + +pub fn outlives_pairs<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, + a: Ty<'tcx>, + b: Ty<'tcx>) + -> Vec<(RegionIndex, RegionIndex)> +{ + let mut subtype = Subtype::new(tcx); + match subtype.relate(&a, &b) { + Ok(_) => subtype.outlives_pairs, + + Err(_) => bug!("Fail to relate a = {:?} and b = {:?}", a, b) + } +} + +struct Subtype<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { + tcx: TyCtxt<'a, 'gcx, 'tcx>, + outlives_pairs: Vec<(RegionIndex, RegionIndex)>, + ambient_variance: ty::Variance, +} + +impl<'a, 'gcx, 'tcx> Subtype<'a, 'gcx, 'tcx> { + pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Subtype<'a, 'gcx, 'tcx> { + Subtype { + tcx, + outlives_pairs: vec![], + ambient_variance: ty::Covariant, + } + } +} + +impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Subtype<'a, 'gcx, 'tcx> { + fn tag(&self) -> &'static str { "Subtype" } + fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.tcx } + fn a_is_expected(&self) -> bool { true } // irrelevant + + fn relate_with_variance<T: Relate<'tcx>>(&mut self, + variance: ty::Variance, + a: &T, + b: &T) + -> RelateResult<'tcx, T> + { + let old_ambient_variance = self.ambient_variance; + self.ambient_variance = self.ambient_variance.xform(variance); + + let result = self.relate(a, b); + self.ambient_variance = old_ambient_variance; + result + } + + fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + relate::super_relate_tys(self, t, t2) + } + + fn regions(&mut self, r_a: ty::Region<'tcx>, r_b: ty::Region<'tcx>) + -> RelateResult<'tcx, ty::Region<'tcx>> { + let a = r_a.to_region_index(); + let b = r_b.to_region_index(); + + match self.ambient_variance { + ty::Covariant => { + self.outlives_pairs.push((b, a)); + }, + + ty::Invariant => { + self.outlives_pairs.push((a, b)); + self.outlives_pairs.push((b, a)); + }, + + ty::Contravariant => { + self.outlives_pairs.push((a, b)); + }, + + ty::Bivariant => {}, + } + + Ok(r_a) + } + + fn binders<T>(&mut self, _a: &ty::Binder<T>, _b: &ty::Binder<T>) + -> RelateResult<'tcx, ty::Binder<T>> + where T: Relate<'tcx> + { + unimplemented!(); + } +} diff --git a/src/librustc_mir/transform/no_landing_pads.rs b/src/librustc_mir/transform/no_landing_pads.rs index fa6bb644871..7de8de3c96b 100644 --- a/src/librustc_mir/transform/no_landing_pads.rs +++ b/src/librustc_mir/transform/no_landing_pads.rs @@ -45,7 +45,8 @@ impl<'tcx> MutVisitor<'tcx> for NoLandingPads { TerminatorKind::Unreachable | TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } | - TerminatorKind::SwitchInt { .. } => { + TerminatorKind::SwitchInt { .. } | + TerminatorKind::FalseEdges { .. } => { /* nothing to do */ }, TerminatorKind::Call { cleanup: ref mut unwind, .. } | diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 3f3b9d177d7..583dfd9b616 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -317,7 +317,8 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { TerminatorKind::Resume | TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } | - TerminatorKind::Unreachable => None, + TerminatorKind::Unreachable | + TerminatorKind::FalseEdges { .. } => None, TerminatorKind::Return => { // Check for unused values. This usually means diff --git a/src/librustc_mir/transform/simplify_branches.rs b/src/librustc_mir/transform/simplify_branches.rs index 0dff145ecbc..edbbe5305e9 100644 --- a/src/librustc_mir/transform/simplify_branches.rs +++ b/src/librustc_mir/transform/simplify_branches.rs @@ -61,6 +61,9 @@ impl MirPass for SimplifyBranches { }), expected, .. } if cond == expected => { TerminatorKind::Goto { target: target } }, + TerminatorKind::FalseEdges { real_target, .. } => { + TerminatorKind::Goto { target: real_target } + }, _ => continue }; } diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index ab5998a3480..b07e818ee87 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -92,8 +92,8 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> { self.sanitize_type(rvalue, rval_ty); } - fn visit_local_decl(&mut self, local_decl: &LocalDecl<'tcx>) { - self.super_local_decl(local_decl); + fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) { + self.super_local_decl(local, local_decl); self.sanitize_type(local_decl, local_decl.ty); } @@ -441,7 +441,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { TerminatorKind::Return | TerminatorKind::GeneratorDrop | TerminatorKind::Unreachable | - TerminatorKind::Drop { .. } => { + TerminatorKind::Drop { .. } | + TerminatorKind::FalseEdges { .. } => { // no checks needed for these } @@ -685,6 +686,12 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { self.assert_iscleanup(mir, block, cleanup, true); } } + TerminatorKind::FalseEdges { real_target, ref imaginary_targets } => { + self.assert_iscleanup(mir, block, real_target, is_cleanup); + for target in imaginary_targets { + self.assert_iscleanup(mir, block, *target, is_cleanup); + } + } } } diff --git a/src/librustc_mir/util/borrowck_errors.rs b/src/librustc_mir/util/borrowck_errors.rs index 5451da2148e..2f29b79eeb6 100644 --- a/src/librustc_mir/util/borrowck_errors.rs +++ b/src/librustc_mir/util/borrowck_errors.rs @@ -9,7 +9,7 @@ // except according to those terms. use rustc::ty::{self, TyCtxt}; -use rustc_errors::DiagnosticBuilder; +use rustc_errors::{DiagnosticBuilder, DiagnosticId}; use syntax_pos::{MultiSpan, Span}; use std::fmt; @@ -41,7 +41,7 @@ pub trait BorrowckErrors { fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self, sp: S, msg: &str, - code: &str) + code: DiagnosticId) -> DiagnosticBuilder<'a>; fn struct_span_err<'a, S: Into<MultiSpan>>(&'a self, @@ -93,7 +93,7 @@ pub trait BorrowckErrors { opt_via: &str, old_loan_span: Span, old_opt_via: &str, - old_load_end_span:Span, + old_load_end_span: Option<Span>, o: Origin) -> DiagnosticBuilder { @@ -106,13 +106,17 @@ pub trait BorrowckErrors { err.span_label(new_loan_span, format!("mutable borrow starts here in previous \ iteration of loop{}", opt_via)); - err.span_label(old_load_end_span, "mutable borrow ends here"); + if let Some(old_load_end_span) = old_load_end_span { + err.span_label(old_load_end_span, "mutable borrow ends here"); + } } else { err.span_label(old_loan_span, format!("first mutable borrow occurs here{}", old_opt_via)); err.span_label(new_loan_span, format!("second mutable borrow occurs here{}", opt_via)); - err.span_label(old_load_end_span, "first borrow ends here"); + if let Some(old_load_end_span) = old_load_end_span { + err.span_label(old_load_end_span, "first borrow ends here"); + } } err } @@ -121,7 +125,7 @@ pub trait BorrowckErrors { new_loan_span: Span, desc: &str, old_loan_span: Span, - old_load_end_span: Span, + old_load_end_span: Option<Span>, o: Origin) -> DiagnosticBuilder { @@ -134,9 +138,11 @@ pub trait BorrowckErrors { err.span_label( new_loan_span, "second closure is constructed here"); - err.span_label( - old_load_end_span, - "borrow from first closure ends here"); + if let Some(old_load_end_span) = old_load_end_span { + err.span_label( + old_load_end_span, + "borrow from first closure ends here"); + } err } @@ -147,7 +153,7 @@ pub trait BorrowckErrors { old_loan_span: Span, noun_old: &str, old_opt_via: &str, - previous_end_span: Span, + previous_end_span: Option<Span>, o: Origin) -> DiagnosticBuilder { @@ -158,7 +164,9 @@ pub trait BorrowckErrors { format!("closure construction occurs here{}", opt_via)); err.span_label(old_loan_span, format!("borrow occurs here{}", old_opt_via)); - err.span_label(previous_end_span, "borrow ends here"); + if let Some(previous_end_span) = previous_end_span { + err.span_label(previous_end_span, "borrow ends here"); + } err } @@ -169,7 +177,7 @@ pub trait BorrowckErrors { kind_new: &str, old_loan_span: Span, old_opt_via: &str, - previous_end_span: Span, + previous_end_span: Option<Span>, o: Origin) -> DiagnosticBuilder { @@ -181,7 +189,9 @@ pub trait BorrowckErrors { format!("borrow occurs here{}", opt_via)); err.span_label(old_loan_span, format!("closure construction occurs here{}", old_opt_via)); - err.span_label(previous_end_span, "borrow from closure ends here"); + if let Some(previous_end_span) = previous_end_span { + err.span_label(previous_end_span, "borrow from closure ends here"); + } err } @@ -194,7 +204,7 @@ pub trait BorrowckErrors { noun_old: &str, kind_old: &str, msg_old: &str, - old_load_end_span: Span, + old_load_end_span: Option<Span>, o: Origin) -> DiagnosticBuilder { @@ -203,7 +213,9 @@ pub trait BorrowckErrors { desc_new, msg_new, kind_new, noun_old, kind_old, msg_old, OGN=o); err.span_label(span, format!("{} borrow occurs here{}", kind_new, msg_new)); err.span_label(old_span, format!("{} borrow occurs here{}", kind_old, msg_old)); - err.span_label(old_load_end_span, format!("{} borrow ends here", kind_old)); + if let Some(old_load_end_span) = old_load_end_span { + err.span_label(old_load_end_span, format!("{} borrow ends here", kind_old)); + } err } @@ -429,11 +441,11 @@ pub trait BorrowckErrors { } } -impl<'b, 'tcx, 'gcx> BorrowckErrors for TyCtxt<'b, 'tcx, 'gcx> { +impl<'b, 'gcx, 'tcx> BorrowckErrors for TyCtxt<'b, 'gcx, 'tcx> { fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self, sp: S, msg: &str, - code: &str) + code: DiagnosticId) -> DiagnosticBuilder<'a> { self.sess.struct_span_err_with_code(sp, msg, code) diff --git a/src/librustc_mir/util/graphviz.rs b/src/librustc_mir/util/graphviz.rs index cec8067530b..a38d317b823 100644 --- a/src/librustc_mir/util/graphviz.rs +++ b/src/librustc_mir/util/graphviz.rs @@ -21,10 +21,10 @@ use rustc_data_structures::indexed_vec::Idx; use super::pretty::dump_mir_def_ids; /// Write a graphviz DOT graph of a list of MIRs. -pub fn write_mir_graphviz<'a, 'tcx, W>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - single: Option<DefId>, - w: &mut W) - -> io::Result<()> +pub fn write_mir_graphviz<'tcx, W>(tcx: TyCtxt<'_, '_, 'tcx>, + single: Option<DefId>, + w: &mut W) + -> io::Result<()> where W: Write { for def_id in dump_mir_def_ids(tcx, single) { @@ -36,10 +36,10 @@ pub fn write_mir_graphviz<'a, 'tcx, W>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } /// Write a graphviz DOT graph of the MIR. -pub fn write_mir_fn_graphviz<'a, 'tcx, W>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - nodeid: NodeId, - mir: &Mir, - w: &mut W) -> io::Result<()> +pub fn write_mir_fn_graphviz<'tcx, W>(tcx: TyCtxt<'_, '_, 'tcx>, + nodeid: NodeId, + mir: &Mir, + w: &mut W) -> io::Result<()> where W: Write { writeln!(w, "digraph Mir_{} {{", nodeid)?; @@ -137,11 +137,11 @@ fn write_edges<W: Write>(source: BasicBlock, mir: &Mir, w: &mut W) -> io::Result /// Write the graphviz DOT label for the overall graph. This is essentially a block of text that /// will appear below the graph, showing the type of the `fn` this MIR represents and the types of /// all the variables and temporaries. -fn write_graph_label<'a, 'tcx, W: Write>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - nid: NodeId, - mir: &Mir, - w: &mut W) - -> io::Result<()> { +fn write_graph_label<'a, 'gcx, 'tcx, W: Write>(tcx: TyCtxt<'a, 'gcx, 'tcx>, + nid: NodeId, + mir: &Mir, + w: &mut W) + -> io::Result<()> { write!(w, " label=<fn {}(", dot::escape_html(&tcx.node_path_str(nid)))?; // fn argument types. diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs index 1424c063d73..7658e49ea5e 100644 --- a/src/librustc_mir/util/liveness.rs +++ b/src/librustc_mir/util/liveness.rs @@ -35,48 +35,235 @@ use rustc::mir::*; use rustc::mir::visit::{LvalueContext, Visitor}; -use rustc_data_structures::indexed_vec::{IndexVec, Idx}; +use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc_data_structures::indexed_set::IdxSetBuf; -use util::pretty::{write_basic_block, dump_enabled, write_mir_intro}; +use util::pretty::{dump_enabled, write_basic_block, write_mir_intro}; use rustc::mir::transform::MirSource; use rustc::ty::item_path; -use std::path::{PathBuf, Path}; +use std::path::{Path, PathBuf}; use std::fs; use rustc::ty::TyCtxt; use std::io::{self, Write}; pub type LocalSet = IdxSetBuf<Local>; +/// This gives the result of the liveness analysis at the boundary of +/// basic blocks. You can use `simulate_block` to obtain the +/// intra-block results. +pub struct LivenessResult { + /// Liveness mode in use when these results were computed. + pub mode: LivenessMode, + + /// Live variables on entry to each basic block. + pub ins: IndexVec<BasicBlock, LocalSet>, + + /// Live variables on exit to each basic block. This is equal to + /// the union of the `ins` for each successor. + pub outs: IndexVec<BasicBlock, LocalSet>, +} + +#[derive(Copy, Clone, Debug)] +pub struct LivenessMode { + /// If true, then we will consider "regular uses" of a variable to be live. + /// For example, if the user writes `foo(x)`, then this is a regular use of + /// the variable `x`. + pub include_regular_use: bool, + + /// If true, then we will consider (implicit) drops of a variable + /// to be live. For example, if the user writes `{ let x = + /// vec![...]; .. }`, then the drop at the end of the block is an + /// implicit drop. + /// + /// NB. Despite its name, a call like `::std::mem::drop(x)` is + /// **not** considered a drop for this purposes, but rather a + /// regular use. + pub include_drops: bool, +} + +/// Compute which local variables are live within the given function +/// `mir`. The liveness mode `mode` determines what sorts of uses are +/// considered to make a variable live (e.g., do drops count?). +pub fn liveness_of_locals<'tcx>(mir: &Mir<'tcx>, mode: LivenessMode) -> LivenessResult { + let locals = mir.local_decls.len(); + let def_use: IndexVec<_, _> = mir.basic_blocks() + .iter() + .map(|b| block(mode, b, locals)) + .collect(); + + let mut ins: IndexVec<_, _> = mir.basic_blocks() + .indices() + .map(|_| LocalSet::new_empty(locals)) + .collect(); + let mut outs = ins.clone(); + + let mut changed = true; + let mut bits = LocalSet::new_empty(locals); + while changed { + changed = false; + + for b in mir.basic_blocks().indices().rev() { + // outs[b] = ∪ {ins of successors} + bits.clear(); + for &successor in mir.basic_blocks()[b].terminator().successors().into_iter() { + bits.union(&ins[successor]); + } + outs[b].clone_from(&bits); + + // bits = use ∪ (bits - def) + def_use[b].apply(&mut bits); + + // update bits on entry and flag if they have changed + if ins[b] != bits { + ins[b].clone_from(&bits); + changed = true; + } + } + } + + LivenessResult { mode, ins, outs } +} + +impl LivenessResult { + /// Walks backwards through the statements/terminator in the given + /// basic block `block`. At each point within `block`, invokes + /// the callback `op` with the current location and the set of + /// variables that are live on entry to that location. + pub fn simulate_block<'tcx, OP>(&self, mir: &Mir<'tcx>, block: BasicBlock, mut callback: OP) + where + OP: FnMut(Location, &LocalSet), + { + let data = &mir[block]; + + // Get a copy of the bits on exit from the block. + let mut bits = self.outs[block].clone(); + + // Start with the maximal statement index -- i.e., right before + // the terminator executes. + let mut statement_index = data.statements.len(); + + // Compute liveness right before terminator and invoke callback. + let terminator_location = Location { + block, + statement_index, + }; + let terminator_defs_uses = self.defs_uses(mir, terminator_location, &data.terminator); + terminator_defs_uses.apply(&mut bits); + callback(terminator_location, &bits); + + // Compute liveness before each statement (in rev order) and invoke callback. + for statement in data.statements.iter().rev() { + statement_index -= 1; + let statement_location = Location { + block, + statement_index, + }; + let statement_defs_uses = self.defs_uses(mir, statement_location, statement); + statement_defs_uses.apply(&mut bits); + callback(statement_location, &bits); + } + + assert_eq!(bits, self.ins[block]); + } + + fn defs_uses<'tcx, V>(&self, mir: &Mir<'tcx>, location: Location, thing: &V) -> DefsUses + where + V: MirVisitable<'tcx>, + { + let locals = mir.local_decls.len(); + let mut visitor = DefsUsesVisitor { + mode: self.mode, + defs_uses: DefsUses { + defs: LocalSet::new_empty(locals), + uses: LocalSet::new_empty(locals), + }, + }; + + // Visit the various parts of the basic block in reverse. If we go + // forward, the logic in `add_def` and `add_use` would be wrong. + thing.apply(location, &mut visitor); + + visitor.defs_uses + } +} + +struct DefsUsesVisitor { + mode: LivenessMode, + defs_uses: DefsUses, +} + #[derive(Eq, PartialEq, Clone)] -struct BlockInfo { +struct DefsUses { defs: LocalSet, uses: LocalSet, } -struct BlockInfoVisitor { - pre_defs: LocalSet, - defs: LocalSet, - uses: LocalSet, +impl DefsUses { + fn apply(&self, bits: &mut LocalSet) -> bool { + bits.subtract(&self.defs) | bits.union(&self.uses) + } + + fn add_def(&mut self, index: Local) { + // If it was used already in the block, remove that use + // now that we found a definition. + // + // Example: + // + // // Defs = {X}, Uses = {} + // X = 5 + // // Defs = {}, Uses = {X} + // use(X) + self.uses.remove(&index); + self.defs.add(&index); + } + + fn add_use(&mut self, index: Local) { + // Inverse of above. + // + // Example: + // + // // Defs = {}, Uses = {X} + // use(X) + // // Defs = {X}, Uses = {} + // X = 5 + // // Defs = {}, Uses = {X} + // use(X) + self.defs.remove(&index); + self.uses.add(&index); + } } -impl<'tcx> Visitor<'tcx> for BlockInfoVisitor { - fn visit_local(&mut self, - &local: &Local, - context: LvalueContext<'tcx>, - _: Location) { +impl<'tcx> Visitor<'tcx> for DefsUsesVisitor { + fn visit_local(&mut self, &local: &Local, context: LvalueContext<'tcx>, _: Location) { match context { + /////////////////////////////////////////////////////////////////////////// + // DEFS + LvalueContext::Store | - // We let Call defined the result in both the success and unwind cases. - // This may not be right. + // We let Call define the result in both the success and + // unwind cases. This is not really correct, however it + // does not seem to be observable due to the way that we + // generate MIR. See the test case + // `mir-opt/nll/liveness-call-subtlety.rs`. To do things + // properly, we would apply the def in call only to the + // input from the success path and not the unwind + // path. -nmatsakis LvalueContext::Call | // Storage live and storage dead aren't proper defines, but we can ignore // values that come before them. LvalueContext::StorageLive | LvalueContext::StorageDead => { - self.defs.add(&local); + self.defs_uses.add_def(local); } + + /////////////////////////////////////////////////////////////////////////// + // REGULAR USES + // + // These are uses that occur *outside* of a drop. For the + // purposes of NLL, these are special in that **all** the + // lifetimes appearing in the variable must be live for each regular use. + LvalueContext::Projection(..) | // Borrows only consider their local used at the point of the borrow. @@ -87,124 +274,108 @@ impl<'tcx> Visitor<'tcx> for BlockInfoVisitor { LvalueContext::Inspect | LvalueContext::Consume | - LvalueContext::Validate | + LvalueContext::Validate => { + if self.mode.include_regular_use { + self.defs_uses.add_use(local); + } + } + + /////////////////////////////////////////////////////////////////////////// + // DROP USES + // + // These are uses that occur in a DROP (a MIR drop, not a + // call to `std::mem::drop()`). For the purposes of NLL, + // uses in drop are special because `#[may_dangle]` + // attributes can affect whether lifetimes must be live. - // We consider drops to always be uses of locals. - // Drop eloboration should be run before this analysis otherwise - // the results might be too pessimistic. LvalueContext::Drop => { - // Ignore uses which are already defined in this block - if !self.pre_defs.contains(&local) { - self.uses.add(&local); + if self.mode.include_drops { + self.defs_uses.add_use(local); } } } } } -fn block<'tcx>(b: &BasicBlockData<'tcx>, locals: usize) -> BlockInfo { - let mut visitor = BlockInfoVisitor { - pre_defs: LocalSet::new_empty(locals), - defs: LocalSet::new_empty(locals), - uses: LocalSet::new_empty(locals), +fn block<'tcx>(mode: LivenessMode, b: &BasicBlockData<'tcx>, locals: usize) -> DefsUses { + let mut visitor = DefsUsesVisitor { + mode, + defs_uses: DefsUses { + defs: LocalSet::new_empty(locals), + uses: LocalSet::new_empty(locals), + }, }; - let dummy_location = Location { block: BasicBlock::new(0), statement_index: 0 }; + let dummy_location = Location { + block: BasicBlock::new(0), + statement_index: 0, + }; - for statement in &b.statements { + // Visit the various parts of the basic block in reverse. If we go + // forward, the logic in `add_def` and `add_use` would be wrong. + visitor.visit_terminator(BasicBlock::new(0), b.terminator(), dummy_location); + for statement in b.statements.iter().rev() { visitor.visit_statement(BasicBlock::new(0), statement, dummy_location); - visitor.pre_defs.union(&visitor.defs); } - visitor.visit_terminator(BasicBlock::new(0), b.terminator(), dummy_location); - BlockInfo { - defs: visitor.defs, - uses: visitor.uses, - } + visitor.defs_uses } -// This gives the result of the liveness analysis at the boundary of basic blocks -pub struct LivenessResult { - pub ins: IndexVec<BasicBlock, LocalSet>, - pub outs: IndexVec<BasicBlock, LocalSet>, +trait MirVisitable<'tcx> { + fn apply<V>(&self, location: Location, visitor: &mut V) + where + V: Visitor<'tcx>; } -pub fn liveness_of_locals<'tcx>(mir: &Mir<'tcx>) -> LivenessResult { - let locals = mir.local_decls.len(); - let def_use: IndexVec<_, _> = mir.basic_blocks().iter().map(|b| { - block(b, locals) - }).collect(); - - let copy = |from: &IndexVec<BasicBlock, LocalSet>, to: &mut IndexVec<BasicBlock, LocalSet>| { - for (i, set) in to.iter_enumerated_mut() { - set.clone_from(&from[i]); - } - }; - - let mut ins: IndexVec<_, _> = mir.basic_blocks() - .indices() - .map(|_| LocalSet::new_empty(locals)).collect(); - let mut outs = ins.clone(); - - let mut ins_ = ins.clone(); - let mut outs_ = outs.clone(); - - loop { - copy(&ins, &mut ins_); - copy(&outs, &mut outs_); - - for b in mir.basic_blocks().indices().rev() { - // out = ∪ {ins of successors} - outs[b].clear(); - for &successor in mir.basic_blocks()[b].terminator().successors().into_iter() { - outs[b].union(&ins[successor]); - } - - // in = use ∪ (out - def) - ins[b].clone_from(&outs[b]); - ins[b].subtract(&def_use[b].defs); - ins[b].union(&def_use[b].uses); - } - - if ins_ == ins && outs_ == outs { - break; - } +impl<'tcx> MirVisitable<'tcx> for Statement<'tcx> { + fn apply<V>(&self, location: Location, visitor: &mut V) + where + V: Visitor<'tcx>, + { + visitor.visit_statement(location.block, self, location) } +} - LivenessResult { - ins, - outs, +impl<'tcx> MirVisitable<'tcx> for Option<Terminator<'tcx>> { + fn apply<V>(&self, location: Location, visitor: &mut V) + where + V: Visitor<'tcx>, + { + visitor.visit_terminator(location.block, self.as_ref().unwrap(), location) } } -pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - pass_name: &str, - source: MirSource, - mir: &Mir<'tcx>, - result: &LivenessResult) { +pub fn dump_mir<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + pass_name: &str, + source: MirSource, + mir: &Mir<'tcx>, + result: &LivenessResult, +) { if !dump_enabled(tcx, pass_name, source) { return; } - let node_path = item_path::with_forced_impl_filename_line(|| { // see notes on #41697 below + let node_path = item_path::with_forced_impl_filename_line(|| { + // see notes on #41697 below tcx.item_path_str(tcx.hir.local_def_id(source.item_id())) }); - dump_matched_mir_node(tcx, pass_name, &node_path, - source, mir, result); + dump_matched_mir_node(tcx, pass_name, &node_path, source, mir, result); } -fn dump_matched_mir_node<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - pass_name: &str, - node_path: &str, - source: MirSource, - mir: &Mir<'tcx>, - result: &LivenessResult) { +fn dump_matched_mir_node<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + pass_name: &str, + node_path: &str, + source: MirSource, + mir: &Mir<'tcx>, + result: &LivenessResult, +) { let mut file_path = PathBuf::new(); if let Some(ref file_dir) = tcx.sess.opts.debugging_opts.dump_mir_dir { let p = Path::new(file_dir); file_path.push(p); }; - let file_name = format!("rustc.node{}{}-liveness.mir", - source.item_id(), pass_name); + let file_name = format!("rustc.node{}{}-liveness.mir", source.item_id(), pass_name); file_path.push(&file_name); let _ = fs::File::create(&file_path).and_then(|mut file| { writeln!(file, "// MIR local liveness analysis for `{}`", node_path)?; @@ -216,16 +387,18 @@ fn dump_matched_mir_node<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }); } -pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - src: MirSource, - mir: &Mir<'tcx>, - w: &mut Write, - result: &LivenessResult) - -> io::Result<()> { +pub fn write_mir_fn<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + src: MirSource, + mir: &Mir<'tcx>, + w: &mut Write, + result: &LivenessResult, +) -> io::Result<()> { write_mir_intro(tcx, src, mir, w)?; for block in mir.basic_blocks().indices() { let print = |w: &mut Write, prefix, result: &IndexVec<BasicBlock, LocalSet>| { - let live: Vec<String> = mir.local_decls.indices() + let live: Vec<String> = mir.local_decls + .indices() .filter(|i| result[block].contains(i)) .map(|i| format!("{:?}", i)) .collect(); @@ -242,4 +415,3 @@ pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, writeln!(w, "}}")?; Ok(()) } - diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index 9f61feabe41..1d924175b21 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -56,13 +56,13 @@ pub enum PassWhere { /// - `substring1&substring2,...` -- `&`-separated list of substrings /// that can appear in the pass-name or the `item_path_str` for the given /// node-id. If any one of the substrings match, the data is dumped out. -pub fn dump_mir<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - pass_num: Option<(MirSuite, MirPassIndex)>, - pass_name: &str, - disambiguator: &Display, - source: MirSource, - mir: &Mir<'tcx>, - extra_data: F) +pub fn dump_mir<'a, 'gcx, 'tcx, F>(tcx: TyCtxt<'a, 'gcx, 'tcx>, + pass_num: Option<(MirSuite, MirPassIndex)>, + pass_name: &str, + disambiguator: &Display, + source: MirSource, + mir: &Mir<'tcx>, + extra_data: F) where F: FnMut(PassWhere, &mut Write) -> io::Result<()> { @@ -77,10 +77,10 @@ where disambiguator, source, mir, extra_data); } -pub fn dump_enabled<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - pass_name: &str, - source: MirSource) - -> bool { +pub fn dump_enabled<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, + pass_name: &str, + source: MirSource) + -> bool { let filters = match tcx.sess.opts.debugging_opts.dump_mir { None => return false, Some(ref filters) => filters, @@ -101,14 +101,14 @@ pub fn dump_enabled<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // `item_path_str()` would otherwise trigger `type_of`, and this can // run while we are already attempting to evaluate `type_of`. -fn dump_matched_mir_node<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - pass_num: Option<(MirSuite, MirPassIndex)>, - pass_name: &str, - node_path: &str, - disambiguator: &Display, - source: MirSource, - mir: &Mir<'tcx>, - mut extra_data: F) +fn dump_matched_mir_node<'a, 'gcx, 'tcx, F>(tcx: TyCtxt<'a, 'gcx, 'tcx>, + pass_num: Option<(MirSuite, MirPassIndex)>, + pass_name: &str, + node_path: &str, + disambiguator: &Display, + source: MirSource, + mir: &Mir<'tcx>, + mut extra_data: F) where F: FnMut(PassWhere, &mut Write) -> io::Result<()> { @@ -161,10 +161,10 @@ where } /// Write out a human-readable textual representation for the given MIR. -pub fn write_mir_pretty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - single: Option<DefId>, - w: &mut Write) - -> io::Result<()> +pub fn write_mir_pretty<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, + single: Option<DefId>, + w: &mut Write) + -> io::Result<()> { writeln!(w, "// WARNING: This output format is intended for human consumers only")?; writeln!(w, "// and is subject to change without notice. Knock yourself out.")?; @@ -192,12 +192,12 @@ pub fn write_mir_pretty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Ok(()) } -pub fn write_mir_fn<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - src: MirSource, - mir: &Mir<'tcx>, - extra_data: &mut F, - w: &mut Write) - -> io::Result<()> +pub fn write_mir_fn<'a, 'gcx, 'tcx, F>(tcx: TyCtxt<'a, 'gcx, 'tcx>, + src: MirSource, + mir: &Mir<'tcx>, + extra_data: &mut F, + w: &mut Write) + -> io::Result<()> where F: FnMut(PassWhere, &mut Write) -> io::Result<()> { @@ -321,11 +321,11 @@ fn write_scope_tree(tcx: TyCtxt, /// Write out a human-readable textual representation of the MIR's `fn` type and the types of its /// local variables (both user-defined bindings and compiler temporaries). -pub fn write_mir_intro<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - src: MirSource, - mir: &Mir, - w: &mut Write) - -> io::Result<()> { +pub fn write_mir_intro<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, + src: MirSource, + mir: &Mir, + w: &mut Write) + -> io::Result<()> { write_mir_sig(tcx, src, mir, w)?; writeln!(w, " {{")?; diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index e44f3f39824..6d9c2948841 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -42,6 +42,15 @@ impl<'a> AstValidator<'a> { } } + fn invalid_non_exhaustive_attribute(&self, variant: &Variant) { + let has_non_exhaustive = variant.node.attrs.iter() + .any(|attr| attr.check_name("non_exhaustive")); + if has_non_exhaustive { + self.err_handler().span_err(variant.span, + "#[non_exhaustive] is not yet supported on variants"); + } + } + fn invalid_visibility(&self, vis: &Visibility, span: Span, note: Option<&str>) { if vis != &Visibility::Inherited { let mut err = struct_span_err!(self.session, @@ -213,7 +222,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { item.span, Some("place qualifiers on individual impl items instead")); } - ItemKind::DefaultImpl(..) => { + ItemKind::AutoImpl(..) => { self.invalid_visibility(&item.vis, item.span, None); } ItemKind::ForeignMod(..) => { @@ -224,12 +233,28 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } ItemKind::Enum(ref def, _) => { for variant in &def.variants { + self.invalid_non_exhaustive_attribute(variant); for field in variant.node.data.fields() { self.invalid_visibility(&field.vis, field.span, None); } } } - ItemKind::Trait(.., ref bounds, ref trait_items) => { + ItemKind::Trait(is_auto, _, ref generics, ref bounds, ref trait_items) => { + if is_auto == IsAuto::Yes { + // Auto traits cannot have generics, super traits nor contain items. + if !generics.ty_params.is_empty() { + self.err_handler().span_err(item.span, + "auto traits cannot have generics"); + } + if !bounds.is_empty() { + self.err_handler().span_err(item.span, + "auto traits cannot have super traits"); + } + if !trait_items.is_empty() { + self.err_handler().span_err(item.span, + "auto traits cannot contain items"); + } + } self.no_questions_in_bounds(bounds, "supertraits", true); for trait_item in trait_items { if let TraitItemKind::Method(ref sig, ref block) = trait_item.node { diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs index 1fa49614580..ab41ad1e099 100644 --- a/src/librustc_passes/mir_stats.rs +++ b/src/librustc_passes/mir_stats.rs @@ -14,7 +14,7 @@ use rustc_const_math::{ConstUsize}; use rustc::mir::{AggregateKind, AssertMessage, BasicBlock, BasicBlockData}; -use rustc::mir::{Constant, Literal, Location, LocalDecl}; +use rustc::mir::{Constant, Literal, Location, Local, LocalDecl}; use rustc::mir::{Lvalue, LvalueElem, LvalueProjection}; use rustc::mir::{Mir, Operand, ProjectionElem}; use rustc::mir::{Rvalue, SourceInfo, Statement, StatementKind}; @@ -121,6 +121,7 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> { TerminatorKind::Assert { .. } => "TerminatorKind::Assert", TerminatorKind::GeneratorDrop => "TerminatorKind::GeneratorDrop", TerminatorKind::Yield { .. } => "TerminatorKind::Yield", + TerminatorKind::FalseEdges { .. } => "TerminatorKind::FalseEdges", }, kind); self.super_terminator_kind(block, kind, location); } @@ -269,9 +270,10 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> { } fn visit_local_decl(&mut self, + local: Local, local_decl: &LocalDecl<'tcx>) { self.record("LocalDecl", local_decl); - self.super_local_decl(local_decl); + self.super_local_decl(local, local_decl); } fn visit_visibility_scope(&mut self, diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 3beba03ee14..630260feed7 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -147,7 +147,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { let def_id = self.tcx.hir.local_def_id(item.id); cmp::min(self.item_ty_level(def_id), self.impl_trait_level(def_id)) } - hir::ItemDefaultImpl(..) => { + hir::ItemAutoImpl(..) => { let def_id = self.tcx.hir.local_def_id(item.id); self.impl_trait_level(def_id) } @@ -213,7 +213,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { } hir::ItemUse(..) | hir::ItemStatic(..) | hir::ItemConst(..) | hir::ItemGlobalAsm(..) | hir::ItemTy(..) | hir::ItemMod(..) | - hir::ItemFn(..) | hir::ItemExternCrate(..) | hir::ItemDefaultImpl(..) => {} + hir::ItemFn(..) | hir::ItemExternCrate(..) | hir::ItemAutoImpl(..) => {} } // Mark all items in interfaces of reachable items as reachable @@ -225,7 +225,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { // Reexports are handled in visit_mod hir::ItemUse(..) => {} // The interface is empty - hir::ItemDefaultImpl(..) => {} + hir::ItemAutoImpl(..) => {} // The interface is empty hir::ItemGlobalAsm(..) => {} // Visit everything @@ -627,6 +627,16 @@ impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> { ctor_vis = field_vis; } } + + // If the structure is marked as non_exhaustive then lower the + // visibility to within the crate. + let struct_def_id = self.tcx.hir.get_parent_did(node_id); + let adt_def = self.tcx.adt_def(struct_def_id); + if adt_def.is_non_exhaustive() && ctor_vis == ty::Visibility::Public { + ctor_vis = ty::Visibility::Restricted( + DefId::local(CRATE_DEF_INDEX)); + } + return ctor_vis; } node => bug!("unexpected node kind: {:?}", node) @@ -1504,7 +1514,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> } } // The interface is empty - hir::ItemDefaultImpl(..) => {} + hir::ItemAutoImpl(..) => {} // An inherent impl is public when its type is public // Subitems of inherent impls have their own publicity hir::ItemImpl(.., None, _, ref impl_item_refs) => { diff --git a/src/librustc_resolve/Cargo.toml b/src/librustc_resolve/Cargo.toml index 0968ea31b75..ab2d152b724 100644 --- a/src/librustc_resolve/Cargo.toml +++ b/src/librustc_resolve/Cargo.toml @@ -16,3 +16,4 @@ rustc = { path = "../librustc" } arena = { path = "../libarena" } rustc_errors = { path = "../librustc_errors" } syntax_pos = { path = "../libsyntax_pos" } +rustc_data_structures = { path = "../librustc_data_structures" } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 880b370c7f6..a10bce29342 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -338,11 +338,22 @@ impl<'a> Resolver<'a> { // These items live in both the type and value namespaces. ItemKind::Struct(ref struct_def, _) => { // Define a name in the type namespace. - let def = Def::Struct(self.definitions.local_def_id(item.id)); + let def_id = self.definitions.local_def_id(item.id); + let def = Def::Struct(def_id); self.define(parent, ident, TypeNS, (def, vis, sp, expansion)); - // Record field names for error reporting. let mut ctor_vis = vis; + + let has_non_exhaustive = item.attrs.iter() + .any(|item| item.check_name("non_exhaustive")); + + // If the structure is marked as non_exhaustive then lower the visibility + // to within the crate. + if has_non_exhaustive && vis == ty::Visibility::Public { + ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)); + } + + // Record field names for error reporting. let field_names = struct_def.fields().iter().filter_map(|field| { let field_vis = self.resolve_visibility(&field.vis); if ctor_vis.is_at_least(field_vis, &*self) { @@ -376,7 +387,7 @@ impl<'a> Resolver<'a> { self.insert_field_names(item_def_id, field_names); } - ItemKind::DefaultImpl(..) | ItemKind::Impl(..) => {} + ItemKind::AutoImpl(..) | ItemKind::Impl(..) => {} ItemKind::Trait(..) => { let def_id = self.definitions.local_def_id(item.id); @@ -414,6 +425,7 @@ impl<'a> Resolver<'a> { // value namespace, they are reserved for possible future use. let ctor_kind = CtorKind::from_ast(&variant.node.data); let ctor_def = Def::VariantCtor(def_id, ctor_kind); + self.define(parent, ident, ValueNS, (ctor_def, vis, variant.span, expansion)); } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 3b27890013a..f3d4e0a7848 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -24,6 +24,7 @@ extern crate rustc_errors as errors; extern crate arena; #[macro_use] extern crate rustc; +extern crate rustc_data_structures; use self::Namespace::*; use self::TypeParameters::*; @@ -59,7 +60,7 @@ use syntax::ast::{QSelf, TraitItemKind, TraitRef, Ty, TyKind}; use syntax::feature_gate::{feature_err, emit_feature_err, GateIssue}; use syntax_pos::{Span, DUMMY_SP, MultiSpan}; -use errors::DiagnosticBuilder; +use errors::{DiagnosticBuilder, DiagnosticId}; use std::cell::{Cell, RefCell}; use std::cmp; @@ -223,7 +224,11 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver, let target_sp = binding_error.target.iter().map(|x| *x).collect::<Vec<_>>(); let msp = MultiSpan::from_spans(target_sp.clone()); let msg = format!("variable `{}` is not bound in all patterns", binding_error.name); - let mut err = resolver.session.struct_span_err_with_code(msp, &msg, "E0408"); + let mut err = resolver.session.struct_span_err_with_code( + msp, + &msg, + DiagnosticId::Error("E0408".into()), + ); for sp in target_sp { err.span_label(sp, format!("pattern doesn't bind `{}`", binding_error.name)); } @@ -1841,7 +1846,7 @@ impl<'a> Resolver<'a> { |this| visit::walk_item(this, item)); } - ItemKind::DefaultImpl(_, ref trait_ref) => { + ItemKind::AutoImpl(_, ref trait_ref) => { self.with_optional_trait_ref(Some(trait_ref), |this, _| { // Resolve type arguments in trait path visit::walk_trait_ref(this, trait_ref); @@ -1854,7 +1859,7 @@ impl<'a> Resolver<'a> { item.id, impl_items), - ItemKind::Trait(_, ref generics, ref bounds, ref trait_items) => { + ItemKind::Trait(.., ref generics, ref bounds, ref trait_items) => { // Create a new rib for the trait-wide type parameters. self.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind), |this| { let local_def_id = this.definitions.local_def_id(item.id); @@ -2490,18 +2495,19 @@ impl<'a> Resolver<'a> { (format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str), format!("not found in {}", mod_str), item_span) }; + let code = DiagnosticId::Error(code.into()); let mut err = this.session.struct_span_err_with_code(base_span, &base_msg, code); // Emit special messages for unresolved `Self` and `self`. if is_self_type(path, ns) { __diagnostic_used!(E0411); - err.code("E0411".into()); + err.code(DiagnosticId::Error("E0411".into())); err.span_label(span, "`Self` is only available in traits and impls"); return (err, Vec::new()); } if is_self_value(path, ns) { __diagnostic_used!(E0424); - err.code("E0424".into()); + err.code(DiagnosticId::Error("E0424".into())); err.span_label(span, format!("`self` value is only available in \ methods with `self` parameter")); return (err, Vec::new()); @@ -2597,7 +2603,7 @@ impl<'a> Resolver<'a> { } } err.span_label(span, format!("did you mean `{} {{ /* fields */ }}`?", - path_str)); + path_str)); return (err, candidates); } _ => {} diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 064032b8884..a52e6fcad14 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -13,6 +13,7 @@ use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult}; use Namespace::{self, MacroNS}; use build_reduced_graph::BuildReducedGraphVisitor; use resolve_imports::ImportResolver; +use rustc_data_structures::indexed_vec::Idx; use rustc::hir::def_id::{DefId, BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, DefIndex}; use rustc::hir::def::{Def, Export}; use rustc::hir::map::{self, DefCollector}; diff --git a/src/librustc_save_analysis/Cargo.toml b/src/librustc_save_analysis/Cargo.toml index 12897050164..1b5ab10fc70 100644 --- a/src/librustc_save_analysis/Cargo.toml +++ b/src/librustc_save_analysis/Cargo.toml @@ -15,7 +15,7 @@ rustc_data_structures = { path = "../librustc_data_structures" } rustc_typeck = { path = "../librustc_typeck" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } -rls-data = "0.11" +rls-data = "0.12" rls-span = "0.4" # FIXME(#40527) should move rustc serialize out of tree rustc-serialize = "0.3" diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 4eac4398c18..d190ae1431f 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -46,8 +46,8 @@ use json_dumper::{JsonDumper, DumpOutput}; use span_utils::SpanUtils; use sig; -use rls_data::{CratePreludeData, Import, ImportKind, SpanData, Ref, RefKind, - Def, DefKind, Relation, RelationKind}; +use rls_data::{CratePreludeData, GlobalCrateId, Import, ImportKind, SpanData, + Ref, RefKind, Def, DefKind, Relation, RelationKind}; macro_rules! down_cast_data { ($id:ident, $kind:ident, $sp:expr) => { @@ -131,7 +131,11 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { }); let data = CratePreludeData { - crate_name: name.into(), + crate_id: GlobalCrateId { + name: name.into(), + disambiguator: self.tcx.sess.local_crate_disambiguator() + .to_fingerprint().as_value(), + }, crate_root: crate_root.unwrap_or("<no source>".to_owned()), external_crates: self.save_ctxt.get_external_crates(), span: self.span_from_span(krate.span), @@ -318,16 +322,15 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { let mut collector = PathCollector::new(); collector.visit_pat(&arg.pat); let span_utils = self.span.clone(); - for &(id, ref p, ..) in &collector.collected_paths { + + for (id, i, sp, ..) in collector.collected_idents { let hir_id = self.tcx.hir.node_to_hir_id(id); let typ = match self.save_ctxt.tables.node_id_to_type_opt(hir_id) { Some(s) => s.to_string(), None => continue, }; - // get the span only for the name of the variable (I hope the path is only ever a - // variable name, but who knows?) - let sub_span = span_utils.span_for_last_ident(p.span); - if !self.span.filter_generated(sub_span, p.span) { + let sub_span = span_utils.span_for_last_ident(sp); + if !self.span.filter_generated(sub_span, sp) { let id = ::id_from_node_id(id, &self.save_ctxt); let span = self.span_from_span(sub_span.expect("No span found for variable")); @@ -335,8 +338,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { kind: DefKind::Local, id, span, - name: path_to_string(p), - qualname: format!("{}::{}", qualname, path_to_string(p)), + name: i.to_string(), + qualname: format!("{}::{}", qualname, i.to_string()), value: typ, parent: None, children: vec![], @@ -391,14 +394,6 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { } } - fn process_trait_ref(&mut self, trait_ref: &'l ast::TraitRef) { - let trait_ref_data = self.save_ctxt.get_trait_ref_data(trait_ref); - if let Some(trait_ref_data) = trait_ref_data { - self.dumper.dump_ref(trait_ref_data); - } - self.process_path(trait_ref.ref_id, &trait_ref.path); - } - fn process_struct_field_def(&mut self, field: &ast::StructField, parent_id: NodeId) { let field_data = self.save_ctxt.get_field_data(field, parent_id); if let Some(field_data) = field_data { @@ -526,36 +521,43 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { item: &'l ast::Item, def: &'l ast::VariantData, ty_params: &'l ast::Generics) { + debug!("process_struct {:?} {:?}", item, item.span); let name = item.ident.to_string(); let qualname = format!("::{}", self.tcx.node_path_str(item.id)); - let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Struct); - let (value, fields) = - if let ast::ItemKind::Struct(ast::VariantData::Struct(ref fields, _), _) = item.node - { - let include_priv_fields = !self.save_ctxt.config.pub_only; - let fields_str = fields - .iter() - .enumerate() - .filter_map(|(i, f)| { - if include_priv_fields || f.vis == ast::Visibility::Public { - f.ident.map(|i| i.to_string()).or_else(|| Some(i.to_string())) - } else { - None - } - }) - .collect::<Vec<_>>() - .join(", "); - let value = format!("{} {{ {} }}", name, fields_str); - (value, fields.iter().map(|f| ::id_from_node_id(f.id, &self.save_ctxt)).collect()) - } else { - (String::new(), vec![]) + let (kind, keyword) = match item.node { + ast::ItemKind::Struct(_, _) => (DefKind::Struct, keywords::Struct), + ast::ItemKind::Union(_, _) => (DefKind::Union, keywords::Union), + _ => unreachable!(), + }; + + let sub_span = self.span.sub_span_after_keyword(item.span, keyword); + let (value, fields) = match item.node { + ast::ItemKind::Struct(ast::VariantData::Struct(ref fields, _), _) | + ast::ItemKind::Union(ast::VariantData::Struct(ref fields, _), _) => { + let include_priv_fields = !self.save_ctxt.config.pub_only; + let fields_str = fields + .iter() + .enumerate() + .filter_map(|(i, f)| { + if include_priv_fields || f.vis == ast::Visibility::Public { + f.ident.map(|i| i.to_string()).or_else(|| Some(i.to_string())) + } else { + None + } + }) + .collect::<Vec<_>>() + .join(", "); + let value = format!("{} {{ {} }}", name, fields_str); + (value, fields.iter().map(|f| ::id_from_node_id(f.id, &self.save_ctxt)).collect()) + } + _ => (String::new(), vec![]) }; if !self.span.filter_generated(sub_span, item.span) { let span = self.span_from_span(sub_span.expect("No span found for struct")); self.dumper.dump_def(item.vis == ast::Visibility::Public, Def { - kind: DefKind::Struct, + kind, id: ::id_from_node_id(item.id, &self.save_ctxt), span, name, @@ -783,7 +785,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { } } - fn process_path(&mut self, id: NodeId, path: &ast::Path) { + fn process_path(&mut self, id: NodeId, path: &'l ast::Path) { + debug!("process_path {:?}", path); let path_data = self.save_ctxt.get_path_data(id, path); if generated_code(path.span) && path_data.is_none() { return; @@ -798,6 +801,27 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { self.dumper.dump_ref(path_data); + // Type parameters + for seg in &path.segments { + if let Some(ref params) = seg.parameters { + match **params { + ast::PathParameters::AngleBracketed(ref data) => { + for t in &data.types { + self.visit_ty(t); + } + } + ast::PathParameters::Parenthesized(ref data) => { + for t in &data.inputs { + self.visit_ty(t); + } + if let Some(ref t) = data.output { + self.visit_ty(t); + } + } + } + } + } + // Modules or types in the path prefix. match self.save_ctxt.get_path_def(id) { HirDef::Method(did) => { @@ -850,7 +874,11 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { walk_list!(self, visit_expr, base); } - fn process_method_call(&mut self, ex: &'l ast::Expr, args: &'l [P<ast::Expr>]) { + fn process_method_call(&mut self, + ex: &'l ast::Expr, + seg: &'l ast::PathSegment, + args: &'l [P<ast::Expr>]) { + debug!("process_method_call {:?} {:?}", ex, ex.span); if let Some(mcd) = self.save_ctxt.get_expr_data(ex) { down_cast_data!(mcd, RefData, ex.span); if !generated_code(ex.span) { @@ -858,6 +886,15 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { } } + // Explicit types in the turbo-fish. + if let Some(ref params) = seg.parameters { + if let ast::PathParameters::AngleBracketed(ref data) = **params { + for t in &data.types { + self.visit_ty(t); + } + } + } + // walk receiver and args walk_list!(self, visit_expr, args); } @@ -904,7 +941,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { collector.visit_pat(&p); self.visit_pat(&p); - for &(id, ref p, immut) in &collector.collected_paths { + for (id, i, sp, immut) in collector.collected_idents { let mut value = match immut { ast::Mutability::Immutable => value.to_string(), _ => String::new(), @@ -924,10 +961,10 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { // Get the span only for the name of the variable (I hope the path // is only ever a variable name, but who knows?). - let sub_span = self.span.span_for_last_ident(p.span); + let sub_span = self.span.span_for_last_ident(sp); // Rust uses the id of the pattern for var lookups, so we'll use it too. - if !self.span.filter_generated(sub_span, p.span) { - let qualname = format!("{}${}", path_to_string(p), id); + if !self.span.filter_generated(sub_span, sp) { + let qualname = format!("{}${}", i.to_string(), id); let id = ::id_from_node_id(id, &self.save_ctxt); let span = self.span_from_span(sub_span.expect("No span found for variable")); @@ -935,7 +972,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { kind: DefKind::Local, id, span, - name: path_to_string(p), + name: i.to_string(), qualname, value: typ, parent: None, @@ -1212,7 +1249,9 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc self.process_static_or_const_item(item, typ, expr), Const(ref typ, ref expr) => self.process_static_or_const_item(item, &typ, &expr), - Struct(ref def, ref ty_params) => self.process_struct(item, def, ty_params), + Struct(ref def, ref ty_params) | Union(ref def, ref ty_params) => { + self.process_struct(item, def, ty_params) + } Enum(ref def, ref ty_params) => self.process_enum(item, def, ty_params), Impl(.., ref ty_params, @@ -1221,7 +1260,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc ref impl_items) => { self.process_impl(item, ty_params, trait_ref, &typ, impl_items) } - Trait(_, ref generics, ref trait_refs, ref methods) => + Trait(_, _, ref generics, ref trait_refs, ref methods) => self.process_trait(item, generics, trait_refs, methods), Mod(ref m) => { self.process_mod(item); @@ -1263,7 +1302,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc for param in generics.ty_params.iter() { for bound in param.bounds.iter() { if let ast::TraitTyParamBound(ref trait_ref, _) = *bound { - self.process_trait_ref(&trait_ref.trait_ref); + self.process_path(trait_ref.trait_ref.ref_id, &trait_ref.trait_ref.path) } } if let Some(ref ty) = param.default { @@ -1318,7 +1357,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc let def = self.save_ctxt.get_path_def(hir_expr.id); self.process_struct_lit(ex, path, fields, adt.variant_of_def(def), base) } - ast::ExprKind::MethodCall(.., ref args) => self.process_method_call(ex, args), + ast::ExprKind::MethodCall(ref seg, ref args) => self.process_method_call(ex, seg, args), ast::ExprKind::Field(ref sub_ex, _) => { self.visit_expr(&sub_ex); @@ -1390,15 +1429,15 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc let value = self.span.snippet(subexpression.span); self.process_var_decl(pattern, value); debug!("for loop, walk sub-expr: {:?}", subexpression.node); - visit::walk_expr(self, subexpression); + self.visit_expr(subexpression); visit::walk_block(self, block); } ast::ExprKind::IfLet(ref pattern, ref subexpression, ref block, ref opt_else) => { let value = self.span.snippet(subexpression.span); self.process_var_decl(pattern, value); - visit::walk_expr(self, subexpression); + self.visit_expr(subexpression); visit::walk_block(self, block); - opt_else.as_ref().map(|el| visit::walk_expr(self, el)); + opt_else.as_ref().map(|el| self.visit_expr(el)); } ast::ExprKind::Repeat(ref element, ref count) => { self.visit_expr(element); @@ -1430,15 +1469,12 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc self.visit_pat(&pattern); } - // This is to get around borrow checking, because we need mut self to call process_path. - let mut paths_to_process = vec![]; - // process collected paths - for &(id, ref p, immut) in &collector.collected_paths { + for (id, i, sp, immut) in collector.collected_idents { match self.save_ctxt.get_path_def(id) { HirDef::Local(id) => { let mut value = if immut == ast::Mutability::Immutable { - self.span.snippet(p.span).to_string() + self.span.snippet(sp).to_string() } else { "<mutable>".to_string() }; @@ -1451,18 +1487,16 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc value.push_str(": "); value.push_str(&typ); - assert!(p.segments.len() == 1, - "qualified path for local variable def in arm"); - if !self.span.filter_generated(Some(p.span), p.span) { - let qualname = format!("{}${}", path_to_string(p), id); + if !self.span.filter_generated(Some(sp), sp) { + let qualname = format!("{}${}", i.to_string(), id); let id = ::id_from_node_id(id, &self.save_ctxt); - let span = self.span_from_span(p.span); + let span = self.span_from_span(sp); self.dumper.dump_def(false, Def { kind: DefKind::Local, id, span, - name: path_to_string(p), + name: i.to_string(), qualname, value: typ, parent: None, @@ -1474,19 +1508,12 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc }); } } - HirDef::StructCtor(..) | HirDef::VariantCtor(..) | - HirDef::Const(..) | HirDef::AssociatedConst(..) | - HirDef::Struct(..) | HirDef::Variant(..) | - HirDef::TyAlias(..) | HirDef::AssociatedTy(..) | - HirDef::SelfTy(..) => { - paths_to_process.push((id, p.clone())) - } - def => error!("unexpected definition kind when processing collected paths: {:?}", + def => error!("unexpected definition kind when processing collected idents: {:?}", def), } } - for &(id, ref path) in &paths_to_process { + for (id, ref path) in collector.collected_paths { self.process_path(id, path); } walk_list!(self, visit_expr, &arm.guard); diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index cf2cad1b38c..edb51ae59e1 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -63,7 +63,7 @@ use dump_visitor::DumpVisitor; use span_utils::SpanUtils; use rls_data::{Ref, RefKind, SpanData, MacroRef, Def, DefKind, Relation, RelationKind, - ExternalCrateData}; + ExternalCrateData, GlobalCrateId}; use rls_data::config::Config; @@ -82,10 +82,6 @@ pub enum Data { RelationData(Relation), } -macro_rules! option_try( - ($e:expr) => (match $e { Some(e) => e, None => return None }) -); - impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { fn span_from_span(&self, span: Span) -> SpanData { use rls_span::{Row, Column}; @@ -119,9 +115,13 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { }; let lo_loc = self.span_utils.sess.codemap().lookup_char_pos(span.lo()); result.push(ExternalCrateData { - name: self.tcx.crate_name(n).to_string(), - num: n.as_u32(), file_name: SpanUtils::make_path_string(&lo_loc.file.name), + num: n.as_u32(), + id: GlobalCrateId { + name: self.tcx.crate_name(n).to_string(), + disambiguator: self.tcx.crate_disambiguator(n) + .to_fingerprint().as_value(), + }, }); } @@ -546,16 +546,16 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } } } - ast::ExprKind::MethodCall(..) => { + ast::ExprKind::MethodCall(ref seg, ..) => { let expr_hir_id = self.tcx.hir.definitions().node_to_hir_id(expr.id); let method_id = self.tables.type_dependent_defs()[expr_hir_id].def_id(); let (def_id, decl_id) = match self.tcx.associated_item(method_id).container { ty::ImplContainer(_) => (Some(method_id), None), ty::TraitContainer(_) => (None, Some(method_id)), }; - let sub_span = self.span_utils.sub_span_for_meth_name(expr.span); - filter!(self.span_utils, sub_span, expr.span, None); - let span = self.span_from_span(sub_span.unwrap()); + let sub_span = seg.span; + filter!(self.span_utils, Some(sub_span), expr.span, None); + let span = self.span_from_span(sub_span); Some(Data::RefData(Ref { kind: RefKind::Function, span, @@ -579,8 +579,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { Node::NodeItem(&hir::Item { node: hir::ItemUse(ref path, _), .. }) | Node::NodeVisibility(&hir::Visibility::Restricted { ref path, .. }) => path.def, - Node::NodeExpr(&hir::Expr { node: hir::ExprPath(ref qpath), .. }) | Node::NodeExpr(&hir::Expr { node: hir::ExprStruct(ref qpath, ..), .. }) | + Node::NodeExpr(&hir::Expr { node: hir::ExprPath(ref qpath), .. }) | Node::NodePat(&hir::Pat { node: hir::PatKind::Path(ref qpath), .. }) | Node::NodePat(&hir::Pat { node: hir::PatKind::Struct(ref qpath, ..), .. }) | Node::NodePat(&hir::Pat { node: hir::PatKind::TupleStruct(ref qpath, ..), .. }) => { @@ -614,13 +614,31 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } pub fn get_path_data(&self, id: NodeId, path: &ast::Path) -> Option<Ref> { + // Returns true if the path is function type sugar, e.g., `Fn(A) -> B`. + fn fn_type(path: &ast::Path) -> bool { + if path.segments.len() != 1 { + return false; + } + if let Some(ref params) = path.segments[0].parameters { + if let ast::PathParameters::Parenthesized(_) = **params { + return true; + } + } + false + } + + if path.segments.is_empty() { + return None; + } + let def = self.get_path_def(id); - let sub_span = self.span_utils.span_for_last_ident(path.span); - filter!(self.span_utils, sub_span, path.span, None); + let last_seg = &path.segments[path.segments.len() - 1]; + let sub_span = last_seg.span; + filter!(self.span_utils, Some(sub_span), path.span, None); match def { HirDef::Upvar(id, ..) | HirDef::Local(id) => { - let span = self.span_from_span(sub_span.unwrap()); + let span = self.span_from_span(sub_span); Some(Ref { kind: RefKind::Variable, span, @@ -630,15 +648,24 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { HirDef::Static(..) | HirDef::Const(..) | HirDef::AssociatedConst(..) | - HirDef::StructCtor(..) | HirDef::VariantCtor(..) => { - let span = self.span_from_span(sub_span.unwrap()); + let span = self.span_from_span(sub_span); Some(Ref { kind: RefKind::Variable, span, ref_id: id_from_def_id(def.def_id()), }) } + HirDef::Trait(def_id) if fn_type(path) => { + // Function type bounds are desugared in the parser, so we have to + // special case them here. + let fn_span = self.span_utils.span_for_first_ident(path.span); + fn_span.map(|span| Ref { + kind: RefKind::Type, + span: self.span_from_span(span), + ref_id: id_from_def_id(def_id), + }) + } HirDef::Struct(def_id) | HirDef::Variant(def_id, ..) | HirDef::Union(def_id) | @@ -648,16 +675,26 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { HirDef::AssociatedTy(def_id) | HirDef::Trait(def_id) | HirDef::TyParam(def_id) => { - let span = self.span_from_span(sub_span.unwrap()); + let span = self.span_from_span(sub_span); Some(Ref { kind: RefKind::Type, span, ref_id: id_from_def_id(def_id), }) } + HirDef::StructCtor(def_id, _) => { + // This is a reference to a tuple struct where the def_id points + // to an invisible constructor function. That is not a very useful + // def, so adjust to point to the tuple struct itself. + let span = self.span_from_span(sub_span); + let parent_def_id = self.tcx.parent_def_id(def_id).unwrap(); + Some(Ref { + kind: RefKind::Type, + span, + ref_id: id_from_def_id(parent_def_id), + }) + } HirDef::Method(decl_id) => { - let sub_span = self.span_utils.sub_span_for_meth_name(path.span); - filter!(self.span_utils, sub_span, path.span, None); let def_id = if decl_id.is_local() { let ti = self.tcx.associated_item(decl_id); self.tcx.associated_items(ti.container.id()) @@ -666,7 +703,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } else { None }; - let span = self.span_from_span(sub_span.unwrap()); + let span = self.span_from_span(sub_span); Some(Ref { kind: RefKind::Function, span, @@ -674,7 +711,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { }) } HirDef::Fn(def_id) => { - let span = self.span_from_span(sub_span.unwrap()); + let span = self.span_from_span(sub_span); Some(Ref { kind: RefKind::Function, span, @@ -682,7 +719,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { }) } HirDef::Mod(def_id) => { - let span = self.span_from_span(sub_span.unwrap()); + let span = self.span_from_span(sub_span); Some(Ref { kind: RefKind::Mod, span, @@ -728,8 +765,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { // macro uses. let callsite = span.source_callsite(); let callsite_span = self.span_from_span(callsite); - let callee = option_try!(span.source_callee()); - let callee_span = option_try!(callee.span); + let callee = span.source_callee()?; + let callee_span = callee.span?; // Ignore attribute macros, their spans are usually mangled if let MacroAttribute(_) = callee.format { @@ -818,29 +855,31 @@ fn make_signature(decl: &ast::FnDecl, generics: &ast::Generics) -> String { sig } -// An AST visitor for collecting paths from patterns. -struct PathCollector { - // The Row field identifies the kind of pattern. - collected_paths: Vec<(NodeId, ast::Path, ast::Mutability)>, +// An AST visitor for collecting paths (e.g., the names of structs) and formal +// variables (idents) from patterns. +struct PathCollector<'l> { + collected_paths: Vec<(NodeId, &'l ast::Path)>, + collected_idents: Vec<(NodeId, ast::Ident, Span, ast::Mutability)>, } -impl PathCollector { - fn new() -> PathCollector { - PathCollector { collected_paths: vec![] } +impl<'l> PathCollector<'l> { + fn new() -> PathCollector<'l> { + PathCollector { + collected_paths: vec![], + collected_idents: vec![], + } } } -impl<'a> Visitor<'a> for PathCollector { - fn visit_pat(&mut self, p: &ast::Pat) { +impl<'l, 'a: 'l> Visitor<'a> for PathCollector<'l> { + fn visit_pat(&mut self, p: &'a ast::Pat) { match p.node { PatKind::Struct(ref path, ..) => { - self.collected_paths.push((p.id, path.clone(), - ast::Mutability::Mutable)); + self.collected_paths.push((p.id, path)); } PatKind::TupleStruct(ref path, ..) | PatKind::Path(_, ref path) => { - self.collected_paths.push((p.id, path.clone(), - ast::Mutability::Mutable)); + self.collected_paths.push((p.id, path)); } PatKind::Ident(bm, ref path1, _) => { debug!("PathCollector, visit ident in pat {}: {:?} {:?}", @@ -854,9 +893,7 @@ impl<'a> Visitor<'a> for PathCollector { ast::BindingMode::ByRef(_) => ast::Mutability::Immutable, ast::BindingMode::ByValue(mt) => mt, }; - // collect path for either visit_local or visit_arm - let path = ast::Path::from_ident(path1.span, path1.node); - self.collected_paths.push((p.id, path, immut)); + self.collected_idents.push((p.id, path1.node, path1.span, immut)); } _ => {} } diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index b0844d1b824..80c1b0ebeb0 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -477,8 +477,13 @@ impl Sig for ast::Item { sig.text.push_str(" {}"); Ok(sig) } - ast::ItemKind::Trait(unsafety, ref generics, ref bounds, _) => { + ast::ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, _) => { let mut text = String::new(); + + if is_auto == ast::IsAuto::Yes { + text.push_str("auto "); + } + if unsafety == ast::Unsafety::Unsafe { text.push_str("unsafe "); } @@ -499,7 +504,7 @@ impl Sig for ast::Item { Ok(sig) } - ast::ItemKind::DefaultImpl(unsafety, ref trait_ref) => { + ast::ItemKind::AutoImpl(unsafety, ref trait_ref) => { let mut text = String::new(); if unsafety == ast::Unsafety::Unsafe { text.push_str("unsafe "); diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs index b9d82b8e251..5bfb4d1b3b2 100644 --- a/src/librustc_save_analysis/span_utils.rs +++ b/src/librustc_save_analysis/span_utils.rs @@ -103,47 +103,6 @@ impl<'a> SpanUtils<'a> { } } - // Return the span for the last ident before a `(` or `<` or '::<' and outside any - // any brackets, or the last span. - pub fn sub_span_for_meth_name(&self, span: Span) -> Option<Span> { - let mut toks = self.retokenise_span(span); - let mut prev = toks.real_token(); - let mut result = None; - let mut bracket_count = 0; - let mut prev_span = None; - while prev.tok != token::Eof { - prev_span = None; - let mut next = toks.real_token(); - - if (next.tok == token::OpenDelim(token::Paren) || next.tok == token::Lt) && - bracket_count == 0 && prev.tok.is_ident() { - result = Some(prev.sp); - } - - if bracket_count == 0 && next.tok == token::ModSep { - let old = prev; - prev = next; - next = toks.real_token(); - if next.tok == token::Lt && old.tok.is_ident() { - result = Some(old.sp); - } - } - - bracket_count += match prev.tok { - token::OpenDelim(token::Paren) | token::Lt => 1, - token::CloseDelim(token::Paren) | token::Gt => -1, - token::BinOp(token::Shr) => -2, - _ => 0, - }; - - if prev.tok.is_ident() && bracket_count == 0 { - prev_span = Some(prev.sp); - } - prev = next; - } - result.or(prev_span) - } - // Return the span for the last ident before a `<` and outside any // angle brackets, or the last span. pub fn sub_span_for_type_name(&self, span: Span) -> Option<Span> { @@ -330,7 +289,7 @@ impl<'a> SpanUtils<'a> { } macro_rules! filter { - ($util: expr, $span: ident, $parent: expr, None) => { + ($util: expr, $span: expr, $parent: expr, None) => { if $util.filter_generated($span, $parent) { return None; } diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml index 5b7879ea58e..f797464c1f8 100644 --- a/src/librustc_trans/Cargo.toml +++ b/src/librustc_trans/Cargo.toml @@ -19,6 +19,7 @@ owning_ref = "0.3.3" rustc-demangle = "0.1.4" rustc = { path = "../librustc" } rustc_allocator = { path = "../librustc_allocator" } +rustc_apfloat = { path = "../librustc_apfloat" } rustc_back = { path = "../librustc_back" } rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index b203bd640cf..907693ea8a3 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -1222,7 +1222,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker, let canonical = f.replace("-", "_"); let canonical_name = name.replace("-", "_"); - // Look for `.rust-cgu.o` at the end of the filename to conclude + // Look for `.rcgu.o` at the end of the filename to conclude // that this is a Rust-related object file. fn looks_like_rust(s: &str) -> bool { let path = Path::new(s); diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index eb1c5cb7881..23890905718 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -21,6 +21,7 @@ use rustc::ty::TyCtxt; use rustc::ty::maps::Providers; use rustc::util::nodemap::FxHashMap; use rustc_allocator::ALLOCATOR_METHODS; +use syntax::attr; pub type ExportedSymbols = FxHashMap< CrateNum, @@ -124,6 +125,12 @@ pub fn provide_local(providers: &mut Providers) { None, SymbolExportLevel::Rust)); } + + // Sort so we get a stable incr. comp. hash. + local_crate.sort_unstable_by(|&(ref name1, ..), &(ref name2, ..)| { + name1.cmp(name2) + }); + Arc::new(local_crate) }; } @@ -147,7 +154,7 @@ pub fn provide_extern(providers: &mut Providers) { let special_runtime_crate = tcx.is_panic_runtime(cnum) || tcx.is_compiler_builtins(cnum); - let crate_exports = tcx + let mut crate_exports: Vec<_> = tcx .exported_symbol_ids(cnum) .iter() .map(|&def_id| { @@ -175,12 +182,25 @@ pub fn provide_extern(providers: &mut Providers) { }) .collect(); + // Sort so we get a stable incr. comp. hash. + crate_exports.sort_unstable_by(|&(ref name1, ..), &(ref name2, ..)| { + name1.cmp(name2) + }); + Arc::new(crate_exports) }; } fn export_level(tcx: TyCtxt, sym_def_id: DefId) -> SymbolExportLevel { - if tcx.contains_extern_indicator(sym_def_id) { + // We export anything that's not mangled at the "C" layer as it probably has + // to do with ABI concerns. We do not, however, apply such treatment to + // special symbols in the standard library for various plumbing between + // core/std/allocators/etc. For example symbols used to hook up allocation + // are not considered for export + let is_extern = tcx.contains_extern_indicator(sym_def_id); + let std_internal = attr::contains_name(&tcx.get_attrs(sym_def_id), + "rustc_std_internal_symbol"); + if is_extern && !std_internal { SymbolExportLevel::C } else { SymbolExportLevel::Rust diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 5550ab9fa55..d59d8ca1a78 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -32,7 +32,7 @@ use rustc::hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc::ty::TyCtxt; use rustc::util::common::{time, time_depth, set_time_depth, path2cstr, print_time_passes_entry}; use rustc::util::fs::{link_or_copy, rename_or_copy_remove}; -use errors::{self, Handler, Level, DiagnosticBuilder, FatalError}; +use errors::{self, Handler, Level, DiagnosticBuilder, FatalError, DiagnosticId}; use errors::emitter::{Emitter}; use syntax::attr; use syntax::ext::hygiene::Mark; @@ -76,6 +76,13 @@ pub const CODE_GEN_MODEL_ARGS : [(&'static str, llvm::CodeModel); 5] = [ ("large", llvm::CodeModel::Large), ]; +pub const TLS_MODEL_ARGS : [(&'static str, llvm::ThreadLocalMode); 4] = [ + ("global-dynamic", llvm::ThreadLocalMode::GeneralDynamic), + ("local-dynamic", llvm::ThreadLocalMode::LocalDynamic), + ("initial-exec", llvm::ThreadLocalMode::InitialExec), + ("local-exec", llvm::ThreadLocalMode::LocalExec), +]; + pub fn llvm_err(handler: &errors::Handler, msg: String) -> FatalError { match llvm::last_error() { Some(err) => handler.fatal(&format!("{}: {}", msg, err)), @@ -173,9 +180,7 @@ pub fn target_machine_factory(sess: &Session) Some(x) => x.1, _ => { sess.err(&format!("{:?} is not a valid code model", - sess.opts - .cg - .code_model)); + code_model_arg)); sess.abort_if_errors(); bug!(); } @@ -1262,7 +1267,7 @@ enum Message { struct Diagnostic { msg: String, - code: Option<String>, + code: Option<DiagnosticId>, lvl: Level, } @@ -2015,7 +2020,7 @@ impl SharedEmitterMain { Some(ref code) => { handler.emit_with_code(&MultiSpan::new(), &diag.msg, - &code, + code.clone(), diag.lvl); } None => { diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index eaf7392aab5..4ae289cfada 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -196,7 +196,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef { for attr in attrs { if attr.check_name("thread_local") { - llvm::set_thread_local(g, true); + llvm::set_thread_local_mode(g, ccx.tls_model()); } } @@ -215,7 +215,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef { // symbol and another one doesn't. for attr in ccx.tcx().get_attrs(def_id).iter() { if attr.check_name("thread_local") { - llvm::set_thread_local(g, true); + llvm::set_thread_local_mode(g, ccx.tls_model()); } } if ccx.use_dll_storage_attrs() && !ccx.tcx().is_foreign_item(def_id) { @@ -305,9 +305,8 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, debuginfo::create_global_var_metadata(ccx, id, g); - if attr::contains_name(attrs, - "thread_local") { - llvm::set_thread_local(g, true); + if attr::contains_name(attrs, "thread_local") { + llvm::set_thread_local_mode(g, ccx.tls_model()); } base::set_link_section(ccx, g, attrs); diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 9df057c77a9..cb71ef104d3 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -52,6 +52,7 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, check_overflow: bool, use_dll_storage_attrs: bool, + tls_model: llvm::ThreadLocalMode, } /// The local portion of a `CrateContext`. There is one `LocalCrateContext` @@ -159,9 +160,25 @@ pub fn get_reloc_model(sess: &Session) -> llvm::RelocMode { Some(x) => x.1, _ => { sess.err(&format!("{:?} is not a valid relocation mode", - sess.opts - .cg - .code_model)); + reloc_model_arg)); + sess.abort_if_errors(); + bug!(); + } + } +} + +fn get_tls_model(sess: &Session) -> llvm::ThreadLocalMode { + let tls_model_arg = match sess.opts.debugging_opts.tls_model { + Some(ref s) => &s[..], + None => &sess.target.target.options.tls_model[..], + }; + + match ::back::write::TLS_MODEL_ARGS.iter().find( + |&&arg| arg.0 == tls_model_arg) { + Some(x) => x.1, + _ => { + sess.err(&format!("{:?} is not a valid TLS model", + tls_model_arg)); sess.abort_if_errors(); bug!(); } @@ -283,10 +300,13 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { let check_overflow = tcx.sess.overflow_checks(); + let tls_model = get_tls_model(&tcx.sess); + SharedCrateContext { tcx, check_overflow, use_dll_storage_attrs, + tls_model, } } @@ -528,6 +548,10 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { self.shared.use_dll_storage_attrs() } + pub fn tls_model(&self) -> llvm::ThreadLocalMode { + self.shared.tls_model + } + /// Generate a new symbol name with the given prefix. This symbol name must /// only be used for definitions with `internal` or `private` linkage. pub fn generate_local_symbol_name(&self, prefix: &str) -> String { diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index c0460fb4852..29394af3396 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -24,6 +24,7 @@ #![feature(custom_attribute)] #![allow(unused_attributes)] #![feature(i128_type)] +#![feature(i128)] #![feature(libc)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] @@ -43,6 +44,7 @@ extern crate libc; extern crate owning_ref; #[macro_use] extern crate rustc; extern crate rustc_allocator; +extern crate rustc_apfloat; extern crate rustc_back; extern crate rustc_data_structures; extern crate rustc_incremental; diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index 00815be278e..73f60ff29a8 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -228,7 +228,8 @@ pub fn cleanup_kinds<'a, 'tcx>(mir: &mir::Mir<'tcx>) -> IndexVec<mir::BasicBlock TerminatorKind::GeneratorDrop | TerminatorKind::Unreachable | TerminatorKind::SwitchInt { .. } | - TerminatorKind::Yield { .. } => { + TerminatorKind::Yield { .. } | + TerminatorKind::FalseEdges { .. } => { /* nothing to do */ } TerminatorKind::Call { cleanup: unwind, .. } | diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 591aa974666..11d992bd4cf 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -583,7 +583,8 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { cleanup); } mir::TerminatorKind::GeneratorDrop | - mir::TerminatorKind::Yield { .. } => bug!("generator ops in trans"), + mir::TerminatorKind::Yield { .. } | + mir::TerminatorKind::FalseEdges { .. } => bug!("generator ops in trans"), } } diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index cea7b9585d8..6573e507bd3 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -11,7 +11,7 @@ use llvm::{self, ValueRef}; use rustc::middle::const_val::{ConstEvalErr, ConstVal, ErrKind}; use rustc_const_math::ConstInt::*; -use rustc_const_math::{ConstInt, ConstMathErr}; +use rustc_const_math::{ConstInt, ConstMathErr, MAX_F32_PLUS_HALF_ULP}; use rustc::hir::def_id::DefId; use rustc::infer::TransNormalize; use rustc::traits; @@ -21,6 +21,7 @@ use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::layout::{self, LayoutTyper}; use rustc::ty::cast::{CastTy, IntTy}; use rustc::ty::subst::{Kind, Substs, Subst}; +use rustc_apfloat::{ieee, Float, Status}; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use {adt, base, machine}; use abi::{self, Abi}; @@ -689,20 +690,18 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { llvm::LLVMConstIntCast(llval, ll_t_out.to_ref(), s) } (CastTy::Int(_), CastTy::Float) => { - if signed { - llvm::LLVMConstSIToFP(llval, ll_t_out.to_ref()) - } else { - llvm::LLVMConstUIToFP(llval, ll_t_out.to_ref()) - } + cast_const_int_to_float(self.ccx, llval, signed, ll_t_out) } (CastTy::Float, CastTy::Float) => { llvm::LLVMConstFPCast(llval, ll_t_out.to_ref()) } (CastTy::Float, CastTy::Int(IntTy::I)) => { - llvm::LLVMConstFPToSI(llval, ll_t_out.to_ref()) + cast_const_float_to_int(self.ccx, &operand, + true, ll_t_out, span) } (CastTy::Float, CastTy::Int(_)) => { - llvm::LLVMConstFPToUI(llval, ll_t_out.to_ref()) + cast_const_float_to_int(self.ccx, &operand, + false, ll_t_out, span) } (CastTy::Ptr(_), CastTy::Ptr(_)) | (CastTy::FnPtr, CastTy::Ptr(_)) | @@ -955,6 +954,64 @@ pub fn const_scalar_checked_binop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } +unsafe fn cast_const_float_to_int(ccx: &CrateContext, + operand: &Const, + signed: bool, + int_ty: Type, + span: Span) -> ValueRef { + let llval = operand.llval; + let float_bits = match operand.ty.sty { + ty::TyFloat(fty) => fty.bit_width(), + _ => bug!("cast_const_float_to_int: operand not a float"), + }; + // Note: this breaks if llval is a complex constant expression rather than a simple constant. + // One way that might happen would be if addresses could be turned into integers in constant + // expressions, but that doesn't appear to be possible? + // In any case, an ICE is better than producing undef. + let llval_bits = consts::bitcast(llval, Type::ix(ccx, float_bits as u64)); + let bits = const_to_opt_u128(llval_bits, false).unwrap_or_else(|| { + panic!("could not get bits of constant float {:?}", + Value(llval)); + }); + let int_width = int_ty.int_width() as usize; + // Try to convert, but report an error for overflow and NaN. This matches HIR const eval. + let cast_result = match float_bits { + 32 if signed => ieee::Single::from_bits(bits).to_i128(int_width).map(|v| v as u128), + 64 if signed => ieee::Double::from_bits(bits).to_i128(int_width).map(|v| v as u128), + 32 => ieee::Single::from_bits(bits).to_u128(int_width), + 64 => ieee::Double::from_bits(bits).to_u128(int_width), + n => bug!("unsupported float width {}", n), + }; + if cast_result.status.contains(Status::INVALID_OP) { + let err = ConstEvalErr { span: span, kind: ErrKind::CannotCast }; + err.report(ccx.tcx(), span, "expression"); + } + C_big_integral(int_ty, cast_result.value) +} + +unsafe fn cast_const_int_to_float(ccx: &CrateContext, + llval: ValueRef, + signed: bool, + float_ty: Type) -> ValueRef { + // Note: this breaks if llval is a complex constant expression rather than a simple constant. + // One way that might happen would be if addresses could be turned into integers in constant + // expressions, but that doesn't appear to be possible? + // In any case, an ICE is better than producing undef. + let value = const_to_opt_u128(llval, signed).unwrap_or_else(|| { + panic!("could not get z128 value of constant integer {:?}", + Value(llval)); + }); + if signed { + llvm::LLVMConstSIToFP(llval, float_ty.to_ref()) + } else if float_ty.float_width() == 32 && value >= MAX_F32_PLUS_HALF_ULP { + // We're casting to f32 and the value is > f32::MAX + 0.5 ULP -> round up to infinity. + let infinity_bits = C_u32(ccx, ieee::Single::INFINITY.to_bits() as u32); + consts::bitcast(infinity_bits, float_ty) + } else { + llvm::LLVMConstUIToFP(llval, float_ty.to_ref()) + } +} + impl<'a, 'tcx> MirContext<'a, 'tcx> { pub fn trans_constant(&mut self, bcx: &Builder<'a, 'tcx>, diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 777b86387e8..19131a68d86 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -15,11 +15,15 @@ use rustc::ty::layout::{Layout, LayoutTyper}; use rustc::mir::tcx::LvalueTy; use rustc::mir; use rustc::middle::lang_items::ExchangeMallocFnLangItem; +use rustc_apfloat::{ieee, Float, Status, Round}; +use rustc_const_math::MAX_F32_PLUS_HALF_ULP; +use std::{u128, i128}; use base; use builder::Builder; use callee; -use common::{self, val_ty, C_bool, C_i32, C_null, C_usize, C_uint}; +use common::{self, val_ty, C_bool, C_i32, C_u32, C_u64, C_null, C_usize, C_uint, C_big_integral}; +use consts; use adt; use machine; use monomorphize; @@ -333,14 +337,12 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { bcx.ptrtoint(llval, ll_t_out), (CastTy::Int(_), CastTy::Ptr(_)) => bcx.inttoptr(llval, ll_t_out), - (CastTy::Int(_), CastTy::Float) if signed => - bcx.sitofp(llval, ll_t_out), (CastTy::Int(_), CastTy::Float) => - bcx.uitofp(llval, ll_t_out), + cast_int_to_float(&bcx, signed, llval, ll_t_in, ll_t_out), (CastTy::Float, CastTy::Int(IntTy::I)) => - bcx.fptosi(llval, ll_t_out), + cast_float_to_int(&bcx, true, llval, ll_t_in, ll_t_out), (CastTy::Float, CastTy::Int(_)) => - bcx.fptoui(llval, ll_t_out), + cast_float_to_int(&bcx, false, llval, ll_t_in, ll_t_out), _ => bug!("unsupported cast: {:?} to {:?}", operand.ty, cast_ty) }; OperandValue::Immediate(newval) @@ -815,3 +817,158 @@ fn get_overflow_intrinsic(oop: OverflowOp, bcx: &Builder, ty: Ty) -> ValueRef { bcx.ccx.get_intrinsic(&name) } + +fn cast_int_to_float(bcx: &Builder, + signed: bool, + x: ValueRef, + int_ty: Type, + float_ty: Type) -> ValueRef { + // Most integer types, even i128, fit into [-f32::MAX, f32::MAX] after rounding. + // It's only u128 -> f32 that can cause overflows (i.e., should yield infinity). + // LLVM's uitofp produces undef in those cases, so we manually check for that case. + let is_u128_to_f32 = !signed && int_ty.int_width() == 128 && float_ty.float_width() == 32; + if is_u128_to_f32 && bcx.sess().opts.debugging_opts.saturating_float_casts { + // All inputs greater or equal to (f32::MAX + 0.5 ULP) are rounded to infinity, + // and for everything else LLVM's uitofp works just fine. + let max = C_big_integral(int_ty, MAX_F32_PLUS_HALF_ULP); + let overflow = bcx.icmp(llvm::IntUGE, x, max); + let infinity_bits = C_u32(bcx.ccx, ieee::Single::INFINITY.to_bits() as u32); + let infinity = consts::bitcast(infinity_bits, float_ty); + bcx.select(overflow, infinity, bcx.uitofp(x, float_ty)) + } else { + if signed { + bcx.sitofp(x, float_ty) + } else { + bcx.uitofp(x, float_ty) + } + } +} + +fn cast_float_to_int(bcx: &Builder, + signed: bool, + x: ValueRef, + float_ty: Type, + int_ty: Type) -> ValueRef { + let fptosui_result = if signed { + bcx.fptosi(x, int_ty) + } else { + bcx.fptoui(x, int_ty) + }; + + if !bcx.sess().opts.debugging_opts.saturating_float_casts { + return fptosui_result; + } + // LLVM's fpto[su]i returns undef when the input x is infinite, NaN, or does not fit into the + // destination integer type after rounding towards zero. This `undef` value can cause UB in + // safe code (see issue #10184), so we implement a saturating conversion on top of it: + // Semantically, the mathematical value of the input is rounded towards zero to the next + // mathematical integer, and then the result is clamped into the range of the destination + // integer type. Positive and negative infinity are mapped to the maximum and minimum value of + // the destination integer type. NaN is mapped to 0. + // + // Define f_min and f_max as the largest and smallest (finite) floats that are exactly equal to + // a value representable in int_ty. + // They are exactly equal to int_ty::{MIN,MAX} if float_ty has enough significand bits. + // Otherwise, int_ty::MAX must be rounded towards zero, as it is one less than a power of two. + // int_ty::MIN, however, is either zero or a negative power of two and is thus exactly + // representable. Note that this only works if float_ty's exponent range is sufficently large. + // f16 or 256 bit integers would break this property. Right now the smallest float type is f32 + // with exponents ranging up to 127, which is barely enough for i128::MIN = -2^127. + // On the other hand, f_max works even if int_ty::MAX is greater than float_ty::MAX. Because + // we're rounding towards zero, we just get float_ty::MAX (which is always an integer). + // This already happens today with u128::MAX = 2^128 - 1 > f32::MAX. + fn compute_clamp_bounds<F: Float>(signed: bool, int_ty: Type) -> (u128, u128) { + let rounded_min = F::from_i128_r(int_min(signed, int_ty), Round::TowardZero); + assert_eq!(rounded_min.status, Status::OK); + let rounded_max = F::from_u128_r(int_max(signed, int_ty), Round::TowardZero); + assert!(rounded_max.value.is_finite()); + (rounded_min.value.to_bits(), rounded_max.value.to_bits()) + } + fn int_max(signed: bool, int_ty: Type) -> u128 { + let shift_amount = 128 - int_ty.int_width(); + if signed { + i128::MAX as u128 >> shift_amount + } else { + u128::MAX >> shift_amount + } + } + fn int_min(signed: bool, int_ty: Type) -> i128 { + if signed { + i128::MIN >> (128 - int_ty.int_width()) + } else { + 0 + } + } + let float_bits_to_llval = |bits| { + let bits_llval = match float_ty.float_width() { + 32 => C_u32(bcx.ccx, bits as u32), + 64 => C_u64(bcx.ccx, bits as u64), + n => bug!("unsupported float width {}", n), + }; + consts::bitcast(bits_llval, float_ty) + }; + let (f_min, f_max) = match float_ty.float_width() { + 32 => compute_clamp_bounds::<ieee::Single>(signed, int_ty), + 64 => compute_clamp_bounds::<ieee::Double>(signed, int_ty), + n => bug!("unsupported float width {}", n), + }; + let f_min = float_bits_to_llval(f_min); + let f_max = float_bits_to_llval(f_max); + // To implement saturation, we perform the following steps: + // + // 1. Cast x to an integer with fpto[su]i. This may result in undef. + // 2. Compare x to f_min and f_max, and use the comparison results to select: + // a) int_ty::MIN if x < f_min or x is NaN + // b) int_ty::MAX if x > f_max + // c) the result of fpto[su]i otherwise + // 3. If x is NaN, return 0.0, otherwise return the result of step 2. + // + // This avoids resulting undef because values in range [f_min, f_max] by definition fit into the + // destination type. It creates an undef temporary, but *producing* undef is not UB. Our use of + // undef does not introduce any non-determinism either. + // More importantly, the above procedure correctly implements saturating conversion. + // Proof (sketch): + // If x is NaN, 0 is returned by definition. + // Otherwise, x is finite or infinite and thus can be compared with f_min and f_max. + // This yields three cases to consider: + // (1) if x in [f_min, f_max], the result of fpto[su]i is returned, which agrees with + // saturating conversion for inputs in that range. + // (2) if x > f_max, then x is larger than int_ty::MAX. This holds even if f_max is rounded + // (i.e., if f_max < int_ty::MAX) because in those cases, nextUp(f_max) is already larger + // than int_ty::MAX. Because x is larger than int_ty::MAX, the return value of int_ty::MAX + // is correct. + // (3) if x < f_min, then x is smaller than int_ty::MIN. As shown earlier, f_min exactly equals + // int_ty::MIN and therefore the return value of int_ty::MIN is correct. + // QED. + + // Step 1 was already performed above. + + // Step 2: We use two comparisons and two selects, with %s1 being the result: + // %less_or_nan = fcmp ult %x, %f_min + // %greater = fcmp olt %x, %f_max + // %s0 = select %less_or_nan, int_ty::MIN, %fptosi_result + // %s1 = select %greater, int_ty::MAX, %s0 + // Note that %less_or_nan uses an *unordered* comparison. This comparison is true if the + // operands are not comparable (i.e., if x is NaN). The unordered comparison ensures that s1 + // becomes int_ty::MIN if x is NaN. + // Performance note: Unordered comparison can be lowered to a "flipped" comparison and a + // negation, and the negation can be merged into the select. Therefore, it not necessarily any + // more expensive than a ordered ("normal") comparison. Whether these optimizations will be + // performed is ultimately up to the backend, but at least x86 does perform them. + let less_or_nan = bcx.fcmp(llvm::RealULT, x, f_min); + let greater = bcx.fcmp(llvm::RealOGT, x, f_max); + let int_max = C_big_integral(int_ty, int_max(signed, int_ty)); + let int_min = C_big_integral(int_ty, int_min(signed, int_ty) as u128); + let s0 = bcx.select(less_or_nan, int_min, fptosui_result); + let s1 = bcx.select(greater, int_max, s0); + + // Step 3: NaN replacement. + // For unsigned types, the above step already yielded int_ty::MIN == 0 if x is NaN. + // Therefore we only need to execute this step for signed integer types. + if signed { + // LLVM has no isNaN predicate, so we use (x == x) instead + bcx.select(bcx.fcmp(llvm::RealOEQ, x, x), s1, C_uint(int_ty, 0)) + } else { + s1 + } +} diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index 6980ba8a525..03c0f13e2f5 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -104,7 +104,7 @@ use collector::InliningMap; use common; -use rustc::dep_graph::{DepNode, WorkProductId}; +use rustc::dep_graph::WorkProductId; use rustc::hir::def_id::DefId; use rustc::hir::map::DefPathData; use rustc::middle::trans::{Linkage, Visibility}; @@ -147,10 +147,6 @@ pub trait CodegenUnitExt<'tcx> { WorkProductId::from_cgu_name(self.name()) } - fn work_product_dep_node(&self) -> DepNode { - self.work_product_id().to_dep_node() - } - fn items_in_deterministic_order<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Vec<(TransItem<'tcx>, @@ -253,14 +249,6 @@ pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cgu1.name().cmp(cgu2.name()) }); - if tcx.sess.opts.enable_dep_node_debug_strs() { - for cgu in &result { - let dep_node = cgu.work_product_dep_node(); - tcx.dep_graph.register_dep_node_debug_str(dep_node, - || cgu.name().to_string()); - } - } - result } diff --git a/src/librustc_trans_utils/collector.rs b/src/librustc_trans_utils/collector.rs index cf9b80e5ed4..429471221c6 100644 --- a/src/librustc_trans_utils/collector.rs +++ b/src/librustc_trans_utils/collector.rs @@ -211,6 +211,8 @@ use trans_item::{TransItemExt, DefPathBasedNames, InstantiationMode}; use rustc_data_structures::bitvec::BitVector; +use syntax::attr; + #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)] pub enum TransItemCollectionMode { Eager, @@ -324,9 +326,14 @@ fn collect_roots<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut roots = Vec::new(); { + let entry_fn = tcx.sess.entry_fn.borrow().map(|(node_id, _)| { + tcx.hir.local_def_id(node_id) + }); + let mut visitor = RootCollector { tcx, mode, + entry_fn, output: &mut roots, }; @@ -623,7 +630,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { mir::TerminatorKind::Unreachable | mir::TerminatorKind::Assert { .. } => {} mir::TerminatorKind::GeneratorDrop | - mir::TerminatorKind::Yield { .. } => bug!(), + mir::TerminatorKind::Yield { .. } | + mir::TerminatorKind::FalseEdges { .. } => bug!(), } self.super_terminator_kind(block, kind, location); @@ -874,6 +882,7 @@ struct RootCollector<'b, 'a: 'b, 'tcx: 'a + 'b> { tcx: TyCtxt<'a, 'tcx, 'tcx>, mode: TransItemCollectionMode, output: &'b mut Vec<TransItem<'tcx>>, + entry_fn: Option<DefId>, } impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { @@ -883,7 +892,7 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { hir::ItemUse(..) | hir::ItemForeignMod(..) | hir::ItemTy(..) | - hir::ItemDefaultImpl(..) | + hir::ItemAutoImpl(..) | hir::ItemTrait(..) | hir::ItemMod(..) => { // Nothing to do, just keep recursing... @@ -931,10 +940,7 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { let tcx = self.tcx; let def_id = tcx.hir.local_def_id(item.id); - if (self.mode == TransItemCollectionMode::Eager || - !tcx.is_const_fn(def_id) || tcx.is_exported_symbol(def_id)) && - !item_has_type_parameters(tcx, def_id) { - + if self.is_root(def_id) { debug!("RootCollector: ItemFn({})", def_id_to_string(tcx, def_id)); @@ -956,10 +962,7 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { let tcx = self.tcx; let def_id = tcx.hir.local_def_id(ii.id); - if (self.mode == TransItemCollectionMode::Eager || - !tcx.is_const_fn(def_id) || - tcx.is_exported_symbol(def_id)) && - !item_has_type_parameters(tcx, def_id) { + if self.is_root(def_id) { debug!("RootCollector: MethodImplItem({})", def_id_to_string(tcx, def_id)); @@ -972,6 +975,22 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { } } +impl<'b, 'a, 'v> RootCollector<'b, 'a, 'v> { + fn is_root(&self, def_id: DefId) -> bool { + !item_has_type_parameters(self.tcx, def_id) && match self.mode { + TransItemCollectionMode::Eager => { + true + } + TransItemCollectionMode::Lazy => { + self.entry_fn == Some(def_id) || + self.tcx.is_exported_symbol(def_id) || + attr::contains_name(&self.tcx.get_attrs(def_id), + "rustc_std_internal_symbol") + } + } + } +} + fn item_has_type_parameters<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool { let generics = tcx.generics_of(def_id); generics.parent_types as usize + generics.types.len() > 0 diff --git a/src/librustc_trans_utils/common.rs b/src/librustc_trans_utils/common.rs index ec9c5b1119b..47968afd70d 100644 --- a/src/librustc_trans_utils/common.rs +++ b/src/librustc_trans_utils/common.rs @@ -51,7 +51,8 @@ pub fn requests_inline<'a, 'tcx>( // available to normal end-users. return true } - attr::requests_inline(&instance.def.attrs(tcx)[..]) + attr::requests_inline(&instance.def.attrs(tcx)[..]) || + tcx.is_const_fn(instance.def.def_id()) } pub fn is_inline_instance<'a, 'tcx>( diff --git a/src/librustc_trans_utils/lib.rs b/src/librustc_trans_utils/lib.rs index 6a341a1e7d3..d6f8707b874 100644 --- a/src/librustc_trans_utils/lib.rs +++ b/src/librustc_trans_utils/lib.rs @@ -40,14 +40,12 @@ extern crate rustc_data_structures; extern crate syntax; extern crate syntax_pos; -use rustc::ty::TyCtxt; +use rustc::ty::{TyCtxt, Instance}; use rustc::hir; use rustc::hir::def_id::LOCAL_CRATE; use rustc::hir::map as hir_map; use rustc::util::nodemap::NodeSet; -use syntax::attr; - pub mod common; pub mod link; pub mod collector; @@ -77,7 +75,7 @@ pub fn check_for_rustc_errors_attr(tcx: TyCtxt) { /// /// This list is later used by linkers to determine the set of symbols needed to /// be exposed from a dynamic library and it's also encoded into the metadata. -pub fn find_exported_symbols(tcx: TyCtxt) -> NodeSet { +pub fn find_exported_symbols<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> NodeSet { tcx.reachable_set(LOCAL_CRATE).0.iter().cloned().filter(|&id| { // Next, we want to ignore some FFI functions that are not exposed from // this crate. Reachable FFI functions can be lumped into two @@ -107,11 +105,10 @@ pub fn find_exported_symbols(tcx: TyCtxt) -> NodeSet { node: hir::ImplItemKind::Method(..), .. }) => { let def_id = tcx.hir.local_def_id(id); let generics = tcx.generics_of(def_id); - let attributes = tcx.get_attrs(def_id); (generics.parent_types == 0 && generics.types.is_empty()) && // Functions marked with #[inline] are only ever translated // with "internal" linkage and are never exported. - !attr::requests_inline(&attributes) + !common::requests_inline(tcx, &Instance::mono(tcx, def_id)) } _ => false diff --git a/src/librustc_typeck/README.md b/src/librustc_typeck/README.md index a38f04e304b..1abc914e7d6 100644 --- a/src/librustc_typeck/README.md +++ b/src/librustc_typeck/README.md @@ -12,7 +12,7 @@ The `rustc_typeck` crate contains the source for "type collection" and ## Type collection -Type "collection" is the process of convering the types found in the +Type "collection" is the process of converting the types found in the HIR (`hir::Ty`), which represent the syntactic things that the user wrote, into the **internal representation** used by the compiler (`Ty<'tcx>`) -- we also do similar conversions for where-clauses and diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index c7f7e62fd61..1471e235156 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1206,60 +1206,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { bare_fn_ty } - pub fn ty_of_closure(&self, - unsafety: hir::Unsafety, - decl: &hir::FnDecl, - abi: abi::Abi, - expected_sig: Option<ty::FnSig<'tcx>>) - -> ty::PolyFnSig<'tcx> - { - debug!("ty_of_closure(expected_sig={:?})", - expected_sig); - - let input_tys = decl.inputs.iter().enumerate().map(|(i, a)| { - let expected_arg_ty = expected_sig.as_ref().and_then(|e| { - // no guarantee that the correct number of expected args - // were supplied - if i < e.inputs().len() { - Some(e.inputs()[i]) - } else { - None - } - }); - self.ty_of_arg(a, expected_arg_ty) - }); - - let expected_ret_ty = expected_sig.as_ref().map(|e| e.output()); - - let output_ty = match decl.output { - hir::Return(ref output) => { - if let (&hir::TyInfer, Some(expected_ret_ty)) = (&output.node, expected_ret_ty) { - self.record_ty(output.hir_id, expected_ret_ty, output.span); - expected_ret_ty - } else { - self.ast_ty_to_ty(&output) - } - } - hir::DefaultReturn(span) => { - if let Some(expected_ret_ty) = expected_ret_ty { - expected_ret_ty - } else { - self.ty_infer(span) - } - } - }; - - debug!("ty_of_closure: output_ty={:?}", output_ty); - - ty::Binder(self.tcx().mk_fn_sig( - input_tys, - output_ty, - decl.variadic, - unsafety, - abi - )) - } - /// Given the bounds on an object, determines what single region bound (if any) we can /// use to summarize this type. The basic idea is that we will use the bound the user /// provided, if they provided one, and otherwise search the supertypes of trait bounds diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index ab8994bcae2..272f13b2803 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -23,6 +23,7 @@ use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::cmp; use syntax::ast; use syntax::codemap::Spanned; +use syntax::feature_gate; use syntax::ptr::P; use syntax_pos::Span; @@ -68,7 +69,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { PatKind::Binding(..) | PatKind::Ref(..) => false, }; - if is_non_ref_pat && tcx.sess.features.borrow().match_default_bindings { + if is_non_ref_pat { debug!("pattern is non reference pattern"); let mut exp_ty = self.resolve_type_vars_with_obligations(&expected); @@ -113,10 +114,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }; if pat_adjustments.len() > 0 { - debug!("default binding mode is now {:?}", def_bm); - self.inh.tables.borrow_mut() - .pat_adjustments_mut() - .insert(pat.hir_id, pat_adjustments); + if tcx.sess.features.borrow().match_default_bindings { + debug!("default binding mode is now {:?}", def_bm); + self.inh.tables.borrow_mut() + .pat_adjustments_mut() + .insert(pat.hir_id, pat_adjustments); + } else { + let mut err = feature_gate::feature_err( + &tcx.sess.parse_sess, + "match_default_bindings", + pat.span, + feature_gate::GateIssue::Language, + "non-reference pattern used to match a reference", + ); + if let Ok(snippet) = tcx.sess.codemap().span_to_snippet(pat.span) { + err.span_suggestion(pat.span, "consider using", format!("&{}", &snippet)); + } + err.emit(); + } } } @@ -325,8 +340,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(mut err) = err { if is_arg { if let PatKind::Binding(..) = inner.node { - if let Ok(snippet) = self.sess().codemap() - .span_to_snippet(pat.span) + if let Ok(snippet) = tcx.sess.codemap() + .span_to_snippet(pat.span) { err.help(&format!("did you mean `{}: &{}`?", &snippet[1..], @@ -810,10 +825,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { def_bm: ty::BindingMode) { let tcx = self.tcx; - let (substs, kind_name) = match adt_ty.sty { - ty::TyAdt(adt, substs) => (substs, adt.variant_descr()), + let (substs, adt) = match adt_ty.sty { + ty::TyAdt(adt, substs) => (substs, adt), _ => span_bug!(span, "struct pattern is not an ADT") }; + let kind_name = adt.variant_descr(); // Index the struct fields' types. let field_map = variant.fields @@ -867,6 +883,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.check_pat_walk(&field.pat, field_ty, def_bm, true); } + // Require `..` if struct has non_exhaustive attribute. + if adt.is_struct() && adt.is_non_exhaustive() && !adt.did.is_local() && !etc { + span_err!(tcx.sess, span, E0638, + "`..` required with {} marked as non-exhaustive", + kind_name); + } + // Report an error if incorrect number of the fields were specified. if kind_name == "union" { if fields.len() != 1 { diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 7b35b466830..d68c139894b 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -83,28 +83,30 @@ enum PointerKind<'tcx> { impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// Returns the kind of unsize information of t, or None - /// if t is sized or it is unknown. - fn pointer_kind(&self, t: Ty<'tcx>, span: Span) -> PointerKind<'tcx> { + /// if t is unknown. + fn pointer_kind(&self, t: Ty<'tcx>, span: Span) -> Option<PointerKind<'tcx>> { if self.type_is_known_to_be_sized(t, span) { - return PointerKind::Thin; + return Some(PointerKind::Thin); } match t.sty { - ty::TySlice(_) | ty::TyStr => PointerKind::Length, + ty::TySlice(_) | ty::TyStr => Some(PointerKind::Length), ty::TyDynamic(ref tty, ..) => - PointerKind::Vtable(tty.principal().map(|p| p.def_id())), + Some(PointerKind::Vtable(tty.principal().map(|p| p.def_id()))), ty::TyAdt(def, substs) if def.is_struct() => { // FIXME(arielb1): do some kind of normalization match def.struct_variant().fields.last() { - None => PointerKind::Thin, + None => Some(PointerKind::Thin), Some(f) => self.pointer_kind(f.ty(self.tcx, substs), span), } } // Pointers to foreign types are thin, despite being unsized - ty::TyForeign(..) => PointerKind::Thin, + ty::TyForeign(..) => Some(PointerKind::Thin), // We should really try to normalize here. - ty::TyProjection(ref pi) => PointerKind::OfProjection(pi), - ty::TyParam(ref p) => PointerKind::OfParam(p), + ty::TyProjection(ref pi) => Some(PointerKind::OfProjection(pi)), + ty::TyParam(ref p) => Some(PointerKind::OfParam(p)), + // Insufficient type information. + ty::TyInfer(_) => None, _ => panic!(), } } @@ -123,6 +125,8 @@ enum CastError { NeedViaThinPtr, NeedViaInt, NonScalar, + UnknownExprPtrKind, + UnknownCastPtrKind, } fn make_invalid_casting_error<'a, 'gcx, 'tcx>(sess: &'a Session, @@ -241,6 +245,25 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { self.expr_ty, fcx.ty_to_string(self.cast_ty)).emit(); } + CastError::UnknownCastPtrKind | + CastError::UnknownExprPtrKind => { + let unknown_cast_to = match e { + CastError::UnknownCastPtrKind => true, + CastError::UnknownExprPtrKind => false, + _ => bug!(), + }; + let mut err = struct_span_err!(fcx.tcx.sess, self.span, E0641, + "cannot cast {} a pointer of an unknown kind", + if unknown_cast_to { "to" } else { "from" }); + err.note("The type information given here is insufficient to check whether \ + the pointer cast is valid"); + if unknown_cast_to { + err.span_suggestion_short(self.cast_span, + "consider giving more type information", + String::new()); + } + err.emit(); + } } } @@ -457,14 +480,27 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { debug!("check_ptr_ptr_cast m_expr={:?} m_cast={:?}", m_expr, m_cast); // ptr-ptr cast. vtables must match. - // Cast to thin pointer is OK + let expr_kind = fcx.pointer_kind(m_expr.ty, self.span); let cast_kind = fcx.pointer_kind(m_cast.ty, self.span); + + let cast_kind = match cast_kind { + // We can't cast if target pointer kind is unknown + None => return Err(CastError::UnknownCastPtrKind), + Some(cast_kind) => cast_kind, + }; + + // Cast to thin pointer is OK if cast_kind == PointerKind::Thin { return Ok(CastKind::PtrPtrCast); } + let expr_kind = match expr_kind { + // We can't cast to fat pointer if source pointer kind is unknown + None => return Err(CastError::UnknownExprPtrKind), + Some(expr_kind) => expr_kind, + }; + // thin -> fat? report invalid cast (don't complain about vtable kinds) - let expr_kind = fcx.pointer_kind(m_expr.ty, self.span); if expr_kind == PointerKind::Thin { return Err(CastError::SizedUnsizedCast); } @@ -483,10 +519,10 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { -> Result<CastKind, CastError> { // fptr-ptr cast. must be to thin ptr - if fcx.pointer_kind(m_cast.ty, self.span) == PointerKind::Thin { - Ok(CastKind::FnPtrPtrCast) - } else { - Err(CastError::IllegalCast) + match fcx.pointer_kind(m_cast.ty, self.span) { + None => Err(CastError::UnknownCastPtrKind), + Some(PointerKind::Thin) => Ok(CastKind::FnPtrPtrCast), + _ => Err(CastError::IllegalCast), } } @@ -496,10 +532,10 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { -> Result<CastKind, CastError> { // ptr-addr cast. must be from thin ptr - if fcx.pointer_kind(m_expr.ty, self.span) == PointerKind::Thin { - Ok(CastKind::PtrAddrCast) - } else { - Err(CastError::NeedViaThinPtr) + match fcx.pointer_kind(m_expr.ty, self.span) { + None => Err(CastError::UnknownExprPtrKind), + Some(PointerKind::Thin) => Ok(CastKind::PtrAddrCast), + _ => Err(CastError::NeedViaThinPtr), } } @@ -533,10 +569,10 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { m_cast: &'tcx ty::TypeAndMut<'tcx>) -> Result<CastKind, CastError> { // ptr-addr cast. pointer must be thin. - if fcx.pointer_kind(m_cast.ty, self.span) == PointerKind::Thin { - Ok(CastKind::AddrPtrCast) - } else { - Err(CastError::IllegalCast) + match fcx.pointer_kind(m_cast.ty, self.span) { + None => Err(CastError::UnknownCastPtrKind), + Some(PointerKind::Thin) => Ok(CastKind::AddrPtrCast), + _ => Err(CastError::IllegalCast), } } diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 07159770d5b..d475fb0cf1a 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -13,25 +13,37 @@ use super::{check_fn, Expectation, FnCtxt}; use astconv::AstConv; +use rustc::hir::def_id::DefId; +use rustc::infer::{InferOk, InferResult}; +use rustc::infer::LateBoundRegionConversionTime; use rustc::infer::type_variable::TypeVariableOrigin; use rustc::ty::{self, ToPolyTraitRef, Ty}; use rustc::ty::subst::Substs; +use rustc::ty::TypeFoldable; use std::cmp; use std::iter; use syntax::abi::Abi; use rustc::hir; +struct ClosureSignatures<'tcx> { + bound_sig: ty::PolyFnSig<'tcx>, + liberated_sig: ty::FnSig<'tcx>, +} + impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { - pub fn check_expr_closure(&self, - expr: &hir::Expr, - _capture: hir::CaptureClause, - decl: &'gcx hir::FnDecl, - body_id: hir::BodyId, - expected: Expectation<'tcx>) - -> Ty<'tcx> { - debug!("check_expr_closure(expr={:?},expected={:?})", - expr, - expected); + pub fn check_expr_closure( + &self, + expr: &hir::Expr, + _capture: hir::CaptureClause, + decl: &'gcx hir::FnDecl, + body_id: hir::BodyId, + expected: Expectation<'tcx>, + ) -> Ty<'tcx> { + debug!( + "check_expr_closure(expr={:?},expected={:?})", + expr, + expected + ); // It's always helpful for inference if we know the kind of // closure sooner rather than later, so first examine the expected @@ -44,70 +56,84 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.check_closure(expr, expected_kind, decl, body, expected_sig) } - fn check_closure(&self, - expr: &hir::Expr, - opt_kind: Option<ty::ClosureKind>, - decl: &'gcx hir::FnDecl, - body: &'gcx hir::Body, - expected_sig: Option<ty::FnSig<'tcx>>) - -> Ty<'tcx> { - debug!("check_closure opt_kind={:?} expected_sig={:?}", - opt_kind, - expected_sig); + fn check_closure( + &self, + expr: &hir::Expr, + opt_kind: Option<ty::ClosureKind>, + decl: &'gcx hir::FnDecl, + body: &'gcx hir::Body, + expected_sig: Option<ty::FnSig<'tcx>>, + ) -> Ty<'tcx> { + debug!( + "check_closure(opt_kind={:?}, expected_sig={:?})", + opt_kind, + expected_sig + ); let expr_def_id = self.tcx.hir.local_def_id(expr.id); - let sig = AstConv::ty_of_closure(self, - hir::Unsafety::Normal, - decl, - Abi::RustCall, - expected_sig); - // `deduce_expectations_from_expected_type` introduces late-bound - // lifetimes defined elsewhere, which we need to anonymize away. - let sig = self.tcx.anonymize_late_bound_regions(&sig); + + let ClosureSignatures { + bound_sig, + liberated_sig, + } = self.sig_of_closure(expr_def_id, decl, body, expected_sig); + + debug!("check_closure: ty_of_closure returns {:?}", liberated_sig); + + let interior = check_fn( + self, + self.param_env, + liberated_sig, + decl, + expr.id, + body, + true, + ).1; // Create type variables (for now) to represent the transformed // types of upvars. These will be unified during the upvar // inference phase (`upvar.rs`). - let base_substs = Substs::identity_for_item(self.tcx, - self.tcx.closure_base_def_id(expr_def_id)); - let substs = base_substs.extend_to(self.tcx, expr_def_id, - |_, _| span_bug!(expr.span, "closure has region param"), - |_, _| self.infcx.next_ty_var(TypeVariableOrigin::TransformedUpvar(expr.span)) + let base_substs = + Substs::identity_for_item(self.tcx, self.tcx.closure_base_def_id(expr_def_id)); + let substs = base_substs.extend_to( + self.tcx, + expr_def_id, + |_, _| span_bug!(expr.span, "closure has region param"), + |_, _| { + self.infcx + .next_ty_var(TypeVariableOrigin::TransformedUpvar(expr.span)) + }, ); - - let fn_sig = self.liberate_late_bound_regions(expr_def_id, &sig); - let fn_sig = self.inh.normalize_associated_types_in(body.value.span, - body.value.id, - self.param_env, - &fn_sig); - - let interior = check_fn(self, self.param_env, fn_sig, decl, expr.id, body, true).1; + let closure_type = self.tcx.mk_closure(expr_def_id, substs); if let Some(interior) = interior { - let closure_substs = ty::ClosureSubsts { - substs: substs, - }; + let closure_substs = ty::ClosureSubsts { substs: substs }; return self.tcx.mk_generator(expr_def_id, closure_substs, interior); } - let closure_type = self.tcx.mk_closure(expr_def_id, substs); - - debug!("check_closure: expr.id={:?} closure_type={:?}", expr.id, closure_type); + debug!( + "check_closure: expr.id={:?} closure_type={:?}", + expr.id, + closure_type + ); // Tuple up the arguments and insert the resulting function type into // the `closures` table. - let sig = sig.map_bound(|sig| self.tcx.mk_fn_sig( - iter::once(self.tcx.intern_tup(sig.inputs(), false)), - sig.output(), - sig.variadic, - sig.unsafety, - sig.abi - )); - - debug!("closure for {:?} --> sig={:?} opt_kind={:?}", - expr_def_id, - sig, - opt_kind); + let sig = bound_sig.map_bound(|sig| { + self.tcx.mk_fn_sig( + iter::once(self.tcx.intern_tup(sig.inputs(), false)), + sig.output(), + sig.variadic, + sig.unsafety, + sig.abi, + ) + }); + + debug!( + "check_closure: expr_def_id={:?}, sig={:?}, opt_kind={:?}", + expr_def_id, + sig, + opt_kind + ); { let mut tables = self.tables.borrow_mut(); @@ -123,22 +149,26 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { closure_type } - fn deduce_expectations_from_expected_type - (&self, - expected_ty: Ty<'tcx>) - -> (Option<ty::FnSig<'tcx>>, Option<ty::ClosureKind>) { - debug!("deduce_expectations_from_expected_type(expected_ty={:?})", - expected_ty); + fn deduce_expectations_from_expected_type( + &self, + expected_ty: Ty<'tcx>, + ) -> (Option<ty::FnSig<'tcx>>, Option<ty::ClosureKind>) { + debug!( + "deduce_expectations_from_expected_type(expected_ty={:?})", + expected_ty + ); match expected_ty.sty { ty::TyDynamic(ref object_type, ..) => { - let sig = object_type.projection_bounds() + let sig = object_type + .projection_bounds() .filter_map(|pb| { let pb = pb.with_self_ty(self.tcx, self.tcx.types.err); self.deduce_sig_from_projection(&pb) }) .next(); - let kind = object_type.principal() + let kind = object_type + .principal() .and_then(|p| self.tcx.lang_items().fn_trait_kind(p.def_id())); (sig, kind) } @@ -148,19 +178,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - fn deduce_expectations_from_obligations - (&self, - expected_vid: ty::TyVid) - -> (Option<ty::FnSig<'tcx>>, Option<ty::ClosureKind>) { + fn deduce_expectations_from_obligations( + &self, + expected_vid: ty::TyVid, + ) -> (Option<ty::FnSig<'tcx>>, Option<ty::ClosureKind>) { let fulfillment_cx = self.fulfillment_cx.borrow(); // Here `expected_ty` is known to be a type inference variable. - let expected_sig = fulfillment_cx.pending_obligations() + let expected_sig = fulfillment_cx + .pending_obligations() .iter() .map(|obligation| &obligation.obligation) .filter_map(|obligation| { - debug!("deduce_expectations_from_obligations: obligation.predicate={:?}", - obligation.predicate); + debug!( + "deduce_expectations_from_obligations: obligation.predicate={:?}", + obligation.predicate + ); match obligation.predicate { // Given a Projection predicate, we can potentially infer @@ -179,7 +212,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // infer the kind. This can occur if there is a trait-reference // like `F : Fn<A>`. Note that due to subtyping we could encounter // many viable options, so pick the most restrictive. - let expected_kind = fulfillment_cx.pending_obligations() + let expected_kind = fulfillment_cx + .pending_obligations() .iter() .map(|obligation| &obligation.obligation) .filter_map(|obligation| { @@ -204,20 +238,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // inference variable. ty::Predicate::ClosureKind(..) => None, }; - opt_trait_ref.and_then(|tr| self.self_type_matches_expected_vid(tr, expected_vid)) + opt_trait_ref + .and_then(|tr| self.self_type_matches_expected_vid(tr, expected_vid)) .and_then(|tr| self.tcx.lang_items().fn_trait_kind(tr.def_id())) }) - .fold(None, - |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur)))); + .fold(None, |best, cur| { + Some(best.map_or(cur, |best| cmp::min(best, cur))) + }); (expected_sig, expected_kind) } /// Given a projection like "<F as Fn(X)>::Result == Y", we can deduce /// everything we need to know about a closure. - fn deduce_sig_from_projection(&self, - projection: &ty::PolyProjectionPredicate<'tcx>) - -> Option<ty::FnSig<'tcx>> { + fn deduce_sig_from_projection( + &self, + projection: &ty::PolyProjectionPredicate<'tcx>, + ) -> Option<ty::FnSig<'tcx>> { let tcx = self.tcx; debug!("deduce_sig_from_projection({:?})", projection); @@ -230,8 +267,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let arg_param_ty = trait_ref.substs().type_at(1); let arg_param_ty = self.resolve_type_vars_if_possible(&arg_param_ty); - debug!("deduce_sig_from_projection: arg_param_ty {:?}", - arg_param_ty); + debug!( + "deduce_sig_from_projection: arg_param_ty {:?}", + arg_param_ty + ); let input_tys = match arg_param_ty.sty { ty::TyTuple(tys, _) => tys.into_iter(), @@ -242,31 +281,291 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let ret_param_ty = projection.0.ty; let ret_param_ty = self.resolve_type_vars_if_possible(&ret_param_ty); - debug!("deduce_sig_from_projection: ret_param_ty {:?}", ret_param_ty); + debug!( + "deduce_sig_from_projection: ret_param_ty {:?}", + ret_param_ty + ); let fn_sig = self.tcx.mk_fn_sig( input_tys.cloned(), ret_param_ty, false, hir::Unsafety::Normal, - Abi::Rust + Abi::Rust, ); debug!("deduce_sig_from_projection: fn_sig {:?}", fn_sig); Some(fn_sig) } - fn self_type_matches_expected_vid(&self, - trait_ref: ty::PolyTraitRef<'tcx>, - expected_vid: ty::TyVid) - -> Option<ty::PolyTraitRef<'tcx>> { + fn self_type_matches_expected_vid( + &self, + trait_ref: ty::PolyTraitRef<'tcx>, + expected_vid: ty::TyVid, + ) -> Option<ty::PolyTraitRef<'tcx>> { let self_ty = self.shallow_resolve(trait_ref.self_ty()); - debug!("self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?})", - trait_ref, - self_ty); + debug!( + "self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?})", + trait_ref, + self_ty + ); match self_ty.sty { ty::TyInfer(ty::TyVar(v)) if expected_vid == v => Some(trait_ref), _ => None, } } + + fn sig_of_closure( + &self, + expr_def_id: DefId, + decl: &hir::FnDecl, + body: &hir::Body, + expected_sig: Option<ty::FnSig<'tcx>>, + ) -> ClosureSignatures<'tcx> { + if let Some(e) = expected_sig { + self.sig_of_closure_with_expectation(expr_def_id, decl, body, e) + } else { + self.sig_of_closure_no_expectation(expr_def_id, decl, body) + } + } + + /// If there is no expected signature, then we will convert the + /// types that the user gave into a signature. + fn sig_of_closure_no_expectation( + &self, + expr_def_id: DefId, + decl: &hir::FnDecl, + body: &hir::Body, + ) -> ClosureSignatures<'tcx> { + debug!("sig_of_closure_no_expectation()"); + + let bound_sig = self.supplied_sig_of_closure(decl); + + self.closure_sigs(expr_def_id, body, bound_sig) + } + + /// Invoked to compute the signature of a closure expression. This + /// combines any user-provided type annotations (e.g., `|x: u32| + /// -> u32 { .. }`) with the expected signature. + /// + /// The approach is as follows: + /// + /// - Let `S` be the (higher-ranked) signature that we derive from the user's annotations. + /// - Let `E` be the (higher-ranked) signature that we derive from the expectations, if any. + /// - If we have no expectation `E`, then the signature of the closure is `S`. + /// - Otherwise, the signature of the closure is E. Moreover: + /// - Skolemize the late-bound regions in `E`, yielding `E'`. + /// - Instantiate all the late-bound regions bound in the closure within `S` + /// with fresh (existential) variables, yielding `S'` + /// - Require that `E' = S'` + /// - We could use some kind of subtyping relationship here, + /// I imagine, but equality is easier and works fine for + /// our purposes. + /// + /// The key intuition here is that the user's types must be valid + /// from "the inside" of the closure, but the expectation + /// ultimately drives the overall signature. + /// + /// # Examples + /// + /// ``` + /// fn with_closure<F>(_: F) + /// where F: Fn(&u32) -> &u32 { .. } + /// + /// with_closure(|x: &u32| { ... }) + /// ``` + /// + /// Here: + /// - E would be `fn(&u32) -> &u32`. + /// - S would be `fn(&u32) -> + /// - E' is `&'!0 u32 -> &'!0 u32` + /// - S' is `&'?0 u32 -> ?T` + /// + /// S' can be unified with E' with `['?0 = '!0, ?T = &'!10 u32]`. + /// + /// # Arguments + /// + /// - `expr_def_id`: the def-id of the closure expression + /// - `decl`: the HIR declaration of the closure + /// - `body`: the body of the closure + /// - `expected_sig`: the expected signature (if any). Note that + /// this is missing a binder: that is, there may be late-bound + /// regions with depth 1, which are bound then by the closure. + fn sig_of_closure_with_expectation( + &self, + expr_def_id: DefId, + decl: &hir::FnDecl, + body: &hir::Body, + expected_sig: ty::FnSig<'tcx>, + ) -> ClosureSignatures<'tcx> { + debug!( + "sig_of_closure_with_expectation(expected_sig={:?})", + expected_sig + ); + + // Watch out for some surprises and just ignore the + // expectation if things don't see to match up with what we + // expect. + if expected_sig.variadic != decl.variadic { + return self.sig_of_closure_no_expectation(expr_def_id, decl, body); + } else if expected_sig.inputs_and_output.len() != decl.inputs.len() + 1 { + // we could probably handle this case more gracefully + return self.sig_of_closure_no_expectation(expr_def_id, decl, body); + } + + // Create a `PolyFnSig`. Note the oddity that late bound + // regions appearing free in `expected_sig` are now bound up + // in this binder we are creating. + assert!(!expected_sig.has_regions_escaping_depth(1)); + let bound_sig = ty::Binder(self.tcx.mk_fn_sig( + expected_sig.inputs().iter().cloned(), + expected_sig.output(), + decl.variadic, + hir::Unsafety::Normal, + Abi::RustCall, + )); + + // `deduce_expectations_from_expected_type` introduces + // late-bound lifetimes defined elsewhere, which we now + // anonymize away, so as not to confuse the user. + let bound_sig = self.tcx.anonymize_late_bound_regions(&bound_sig); + + let closure_sigs = self.closure_sigs(expr_def_id, body, bound_sig); + + // Up till this point, we have ignored the annotations that the user + // gave. This function will check that they unify successfully. + // Along the way, it also writes out entries for types that the user + // wrote into our tables, which are then later used by the privacy + // check. + match self.check_supplied_sig_against_expectation(decl, &closure_sigs) { + Ok(infer_ok) => self.register_infer_ok_obligations(infer_ok), + Err(_) => return self.sig_of_closure_no_expectation(expr_def_id, decl, body), + } + + closure_sigs + } + + /// Enforce the user's types against the expectation. See + /// `sig_of_closure_with_expectation` for details on the overall + /// strategy. + fn check_supplied_sig_against_expectation( + &self, + decl: &hir::FnDecl, + expected_sigs: &ClosureSignatures<'tcx>, + ) -> InferResult<'tcx, ()> { + // Get the signature S that the user gave. + // + // (See comment on `sig_of_closure_with_expectation` for the + // meaning of these letters.) + let supplied_sig = self.supplied_sig_of_closure(decl); + + debug!( + "check_supplied_sig_against_expectation: supplied_sig={:?}", + supplied_sig + ); + + // FIXME(#45727): As discussed in [this comment][c1], naively + // forcing equality here actually results in suboptimal error + // messages in some cases. For now, if there would have been + // an obvious error, we fallback to declaring the type of the + // closure to be the one the user gave, which allows other + // error message code to trigger. + // + // However, I think [there is potential to do even better + // here][c2], since in *this* code we have the precise span of + // the type parameter in question in hand when we report the + // error. + // + // [c1]: https://github.com/rust-lang/rust/pull/45072#issuecomment-341089706 + // [c2]: https://github.com/rust-lang/rust/pull/45072#issuecomment-341096796 + self.infcx.commit_if_ok(|_| { + let mut all_obligations = vec![]; + + // The liberated version of this signature should be be a subtype + // of the liberated form of the expectation. + for ((hir_ty, &supplied_ty), expected_ty) in decl.inputs.iter() + .zip(*supplied_sig.inputs().skip_binder()) // binder moved to (*) below + .zip(expected_sigs.liberated_sig.inputs()) + // `liberated_sig` is E'. + { + // Instantiate (this part of..) S to S', i.e., with fresh variables. + let (supplied_ty, _) = self.infcx.replace_late_bound_regions_with_fresh_var( + hir_ty.span, + LateBoundRegionConversionTime::FnCall, + &ty::Binder(supplied_ty), + ); // recreated from (*) above + + // Check that E' = S'. + let cause = &self.misc(hir_ty.span); + let InferOk { + value: (), + obligations, + } = self.at(cause, self.param_env) + .eq(*expected_ty, supplied_ty)?; + all_obligations.extend(obligations); + } + + let (supplied_output_ty, _) = self.infcx.replace_late_bound_regions_with_fresh_var( + decl.output.span(), + LateBoundRegionConversionTime::FnCall, + &supplied_sig.output(), + ); + let cause = &self.misc(decl.output.span()); + let InferOk { + value: (), + obligations, + } = self.at(cause, self.param_env) + .eq(expected_sigs.liberated_sig.output(), supplied_output_ty)?; + all_obligations.extend(obligations); + + Ok(InferOk { + value: (), + obligations: all_obligations, + }) + }) + } + + /// If there is no expected signature, then we will convert the + /// types that the user gave into a signature. + fn supplied_sig_of_closure(&self, decl: &hir::FnDecl) -> ty::PolyFnSig<'tcx> { + let astconv: &AstConv = self; + + // First, convert the types that the user supplied (if any). + let supplied_arguments = decl.inputs.iter().map(|a| astconv.ast_ty_to_ty(a)); + let supplied_return = match decl.output { + hir::Return(ref output) => astconv.ast_ty_to_ty(&output), + hir::DefaultReturn(_) => astconv.ty_infer(decl.output.span()), + }; + + let result = ty::Binder(self.tcx.mk_fn_sig( + supplied_arguments, + supplied_return, + decl.variadic, + hir::Unsafety::Normal, + Abi::RustCall, + )); + + debug!("supplied_sig_of_closure: result={:?}", result); + + result + } + + fn closure_sigs( + &self, + expr_def_id: DefId, + body: &hir::Body, + bound_sig: ty::PolyFnSig<'tcx>, + ) -> ClosureSignatures<'tcx> { + let liberated_sig = self.liberate_late_bound_regions(expr_def_id, &bound_sig); + let liberated_sig = self.inh.normalize_associated_types_in( + body.value.span, + body.value.id, + self.param_env, + &liberated_sig, + ); + ClosureSignatures { + bound_sig, + liberated_sig, + } + } } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index a24f420af80..81e5b2fe00a 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -431,6 +431,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { ty::TySlice(_) => { let lang_def_id = lang_items.slice_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); + + let lang_def_id = lang_items.slice_u8_impl(); + self.assemble_inherent_impl_for_primitive(lang_def_id); } ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => { let lang_def_id = lang_items.const_ptr_impl(); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 26f7a7a3784..82d59ecfc92 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -100,7 +100,7 @@ use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc::ty::fold::{BottomUpFolder, TypeFoldable}; use rustc::ty::maps::Providers; use rustc::ty::util::{Representability, IntTypeExt}; -use errors::DiagnosticBuilder; +use errors::{DiagnosticBuilder, DiagnosticId}; use require_c_abi_if_variadic; use session::{CompileIncomplete, Session}; use TypeAndSubsts; @@ -2467,7 +2467,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if expected_count == 1 {""} else {"s"}, arg_count, if arg_count == 1 {" was"} else {"s were"}), - error_code); + DiagnosticId::Error(error_code.to_owned())); if let Some(def_s) = def_span { err.span_label(def_s, "defined here"); @@ -3448,6 +3448,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::QPath::TypeRelative(ref qself, _) => qself.span }; + // Prohibit struct expressions when non exhaustive flag is set. + if let ty::TyAdt(adt, _) = struct_ty.sty { + if !adt.did.is_local() && adt.is_non_exhaustive() { + span_err!(self.tcx.sess, expr.span, E0639, + "cannot create non-exhaustive {} using struct expression", + adt.variant_descr()); + } + } + self.check_expr_struct_fields(struct_ty, expected, expr.id, path_span, variant, fields, base_expr.is_none()); if let &Some(ref base_expr) = base_expr { diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index ddbdd204305..483af08cabf 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -114,7 +114,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { // FIXME(#27579) what amount of WF checking do we need for neg impls? let trait_ref = tcx.impl_trait_ref(tcx.hir.local_def_id(item.id)).unwrap(); - if !tcx.trait_has_default_impl(trait_ref.def_id) { + if !tcx.trait_is_auto(trait_ref.def_id) { error_192(tcx, item.span); } } @@ -318,7 +318,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { fn check_trait(&mut self, item: &hir::Item) { let trait_def_id = self.tcx.hir.local_def_id(item.id); - if self.tcx.trait_has_default_impl(trait_def_id) { + if self.tcx.trait_is_auto(trait_def_id) { self.check_auto_trait(trait_def_id, item.span); } diff --git a/src/librustc_typeck/coherence/inherent_impls.rs b/src/librustc_typeck/coherence/inherent_impls.rs index c56a3b91ca3..569b6a2febb 100644 --- a/src/librustc_typeck/coherence/inherent_impls.rs +++ b/src/librustc_typeck/coherence/inherent_impls.rs @@ -137,6 +137,13 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { "str", item.span); } + ty::TySlice(slice_item) if slice_item == self.tcx.types.u8 => { + self.check_primitive_impl(def_id, + lang_items.slice_u8_impl(), + "slice_u8", + "[u8]", + item.span); + } ty::TySlice(_) => { self.check_primitive_impl(def_id, lang_items.slice_impl(), diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 6109fc57b0d..90a0952af04 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -132,7 +132,7 @@ pub fn check_coherence<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { unsafety::check(tcx); orphan::check(tcx); - overlap::check_default_impls(tcx); + overlap::check_auto_impls(tcx); // these queries are executed for side-effects (error reporting): tcx.crate_inherent_impls(LOCAL_CRATE); diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index a5edc95b79b..9f183973621 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -100,11 +100,11 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> { // This final impl is legal according to the orpan // rules, but it invalidates the reasoning from // `two_foos` above. - debug!("trait_ref={:?} trait_def_id={:?} trait_has_default_impl={}", + debug!("trait_ref={:?} trait_def_id={:?} trait_is_auto={}", trait_ref, trait_def_id, - self.tcx.trait_has_default_impl(trait_def_id)); - if self.tcx.trait_has_default_impl(trait_def_id) && + self.tcx.trait_is_auto(trait_def_id)); + if self.tcx.trait_is_auto(trait_def_id) && !trait_def_id.is_local() { let self_ty = trait_ref.self_ty(); let opt_self_def_id = match self_ty.sty { @@ -142,7 +142,7 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> { } } } - hir::ItemDefaultImpl(_, ref item_trait_ref) => { + hir::ItemAutoImpl(_, ref item_trait_ref) => { // "Trait" impl debug!("coherence2::orphan check: default trait impl {}", self.tcx.hir.node_to_string(item.id)); diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index 59ebae16d08..5cc6eaa5602 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -18,7 +18,7 @@ use syntax::ast; use rustc::hir; use rustc::hir::itemlikevisit::ItemLikeVisitor; -pub fn check_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { +pub fn check_auto_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let mut overlap = OverlapChecker { tcx }; // this secondary walk specifically checks for some other cases, @@ -74,19 +74,19 @@ struct OverlapChecker<'cx, 'tcx: 'cx> { impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OverlapChecker<'cx, 'tcx> { fn visit_item(&mut self, item: &'v hir::Item) { match item.node { - hir::ItemDefaultImpl(..) => { - // look for another default impl; note that due to the + hir::ItemAutoImpl(..) => { + // look for another auto impl; note that due to the // general orphan/coherence rules, it must always be // in this crate. let impl_def_id = self.tcx.hir.local_def_id(item.id); let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap(); - let prev_id = self.tcx.hir.trait_default_impl(trait_ref.def_id).unwrap(); + let prev_id = self.tcx.hir.trait_auto_impl(trait_ref.def_id).unwrap(); if prev_id != item.id { let mut err = struct_span_err!(self.tcx.sess, self.tcx.span_of_impl(impl_def_id).unwrap(), E0521, - "redundant default implementations of trait \ + "redundant auto implementations of trait \ `{}`:", trait_ref); err.span_note(self.tcx diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs index 4672975d056..280fb04e040 100644 --- a/src/librustc_typeck/coherence/unsafety.rs +++ b/src/librustc_typeck/coherence/unsafety.rs @@ -84,7 +84,7 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> { impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for UnsafetyChecker<'cx, 'tcx> { fn visit_item(&mut self, item: &'v hir::Item) { match item.node { - hir::ItemDefaultImpl(unsafety, _) => { + hir::ItemAutoImpl(unsafety, _) => { self.check_unsafety_coherence(item, None, unsafety, hir::ImplPolarity::Positive); } hir::ItemImpl(unsafety, polarity, _, ref generics, ..) => { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 75e864d07a6..81447097428 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -73,7 +73,7 @@ pub fn provide(providers: &mut Providers) { impl_trait_ref, impl_polarity, is_foreign_item, - is_default_impl, + is_auto_impl, ..*providers }; } @@ -273,7 +273,7 @@ fn type_param_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ItemEnum(_, ref generics) | ItemStruct(_, ref generics) | ItemUnion(_, ref generics) => generics, - ItemTrait(_, ref generics, ..) => { + ItemTrait(_, _, ref generics, ..) => { // Implied `Self: Trait` and supertrait bounds. if param_id == item_node_id { result.predicates.push(ty::TraitRef { @@ -425,7 +425,7 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) { tcx.predicates_of(def_id); convert_enum_variant_types(tcx, def_id, &enum_definition.variants); }, - hir::ItemDefaultImpl(..) => { + hir::ItemAutoImpl(..) => { tcx.impl_trait_ref(def_id); } hir::ItemImpl(..) => { @@ -670,7 +670,7 @@ fn super_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; let (generics, bounds) = match item.node { - hir::ItemTrait(_, ref generics, ref supertraits, _) => (generics, supertraits), + hir::ItemTrait(.., ref generics, ref supertraits, _) => (generics, supertraits), _ => span_bug!(item.span, "super_predicates invoked on non-trait"), }; @@ -713,7 +713,7 @@ fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let item = tcx.hir.expect_item(node_id); let unsafety = match item.node { - hir::ItemTrait(unsafety, ..) => unsafety, + hir::ItemTrait(_, unsafety, ..) => unsafety, _ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"), }; @@ -730,11 +730,14 @@ fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } let def_path_hash = tcx.def_path_hash(def_id); - let has_default_impl = tcx.hir.trait_is_auto(def_id); + let is_auto = match item.node { + hir::ItemTrait(hir::IsAuto::Yes, ..) => true, + _ => tcx.hir.trait_is_auto(def_id), + }; let def = ty::TraitDef::new(def_id, unsafety, paren_sugar, - has_default_impl, + is_auto, def_path_hash); tcx.alloc_trait_def(def) } @@ -888,7 +891,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, generics } - ItemTrait(_, ref generics, ..) => { + ItemTrait(_, _, ref generics, ..) => { // Add in the self type parameter. // // Something of a hack: use the node id for the trait, also as @@ -1074,7 +1077,7 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let substs = Substs::identity_for_item(tcx, def_id); tcx.mk_adt(def, substs) } - ItemDefaultImpl(..) | + ItemAutoImpl(..) | ItemTrait(..) | ItemMod(..) | ItemForeignMod(..) | @@ -1223,7 +1226,7 @@ fn impl_trait_ref<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); match tcx.hir.expect_item(node_id).node { - hir::ItemDefaultImpl(_, ref ast_trait_ref) => { + hir::ItemAutoImpl(_, ref ast_trait_ref) => { Some(AstConv::instantiate_mono_trait_ref(&icx, ast_trait_ref, tcx.mk_self_type())) @@ -1350,7 +1353,7 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, generics } - ItemTrait(_, ref generics, .., ref items) => { + ItemTrait(_, _, ref generics, .., ref items) => { is_trait = Some((ty::TraitRef { def_id, substs: Substs::identity_for_item(tcx, def_id) @@ -1665,13 +1668,13 @@ fn is_foreign_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -fn is_default_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, +fn is_auto_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool { match tcx.hir.get_if_local(def_id) { - Some(hir_map::NodeItem(&hir::Item { node: hir::ItemDefaultImpl(..), .. })) + Some(hir_map::NodeItem(&hir::Item { node: hir::ItemAutoImpl(..), .. })) => true, Some(_) => false, - _ => bug!("is_default_impl applied to non-local def-id {:?}", def_id) + _ => bug!("is_auto_impl applied to non-local def-id {:?}", def_id) } } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 594cd0878cb..a23c7ded526 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1854,7 +1854,7 @@ unsafe impl !Clone for Foo { } This will compile: -``` +```ignore (ignore auto_trait future compatibility warning) #![feature(optin_builtin_traits)] struct Foo; @@ -4606,6 +4606,65 @@ foo.method(); // Ok! ``` "##, +E0638: r##" +This error indicates that the struct or enum must be matched non-exhaustively +as it has been marked as `non_exhaustive`. + +When applied within a crate, downstream users of the crate will need to use the +`_` pattern when matching enums and use the `..` pattern when matching structs. + +For example, in the below example, since the enum is marked as +`non_exhaustive`, it is required that downstream crates match non-exhaustively +on it. + +```rust,ignore (pseudo-Rust) +use std::error::Error as StdError; + +#[non_exhaustive] pub enum Error { + Message(String), + Other, +} + +impl StdError for Error { + fn description(&self) -> &str { + // This will not error, despite being marked as non_exhaustive, as this + // enum is defined within the current crate, it can be matched + // exhaustively. + match *self { + Message(ref s) => s, + Other => "other or unknown error", + } + } +} +``` + +An example of matching non-exhaustively on the above enum is provided below: + +```rust,ignore (pseudo-Rust) +use mycrate::Error; + +// This will not error as the non_exhaustive Error enum has been matched with a +// wildcard. +match error { + Message(ref s) => ..., + Other => ..., + _ => ..., +} +``` + +Similarly, for structs, match with `..` to avoid this error. +"##, + +E0639: r##" +This error indicates that the struct or enum cannot be instantiated from +outside of the defining crate as it has been marked as `non_exhaustive` and as +such more fields/variants may be added in future that could cause adverse side +effects for this code. + +It is recommended that you look for a `new` function or equivalent in the +crate's documentation. +"##, + } register_diagnostics! { @@ -4669,7 +4728,7 @@ register_diagnostics! { // E0372, // coherence not object safe E0377, // the trait `CoerceUnsized` may only be implemented for a coercion // between structures with the same definition - E0521, // redundant default implementations of trait + E0521, // redundant auto implementations of trait E0533, // `{}` does not name a unit variant, unit struct or a constant // E0563, // cannot determine a type for this `impl Trait`: {} // removed in 6383de15 E0564, // only named lifetimes are allowed in `impl Trait`, @@ -4684,4 +4743,5 @@ register_diagnostics! { E0627, // yield statement outside of generator literal E0632, // cannot provide explicit type parameters when `impl Trait` is used in // argument position. + E0641, // cannot cast to/from a pointer with an unknown kind } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 49ba0499f78..5227955d7b9 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -76,6 +76,7 @@ This API is completely unstable and subject to change. #![feature(box_patterns)] #![feature(box_syntax)] #![feature(conservative_impl_trait)] +#![feature(match_default_bindings)] #![feature(never_type)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index e3ce403f3c1..915383d8189 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -15,6 +15,7 @@ use std::mem; use std::fmt::{self, Write}; use std::ops; +#[cfg(stage0)] use std::ascii::AsciiExt; use syntax::symbol::Symbol; diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 3a4dcc32173..9fb9437e1bc 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -292,10 +292,10 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) { } } - // If this is a defaulted impl, then bail out early here - if tcx.is_default_impl(did) { + // If this is an auto impl, then bail out early here + if tcx.is_auto_impl(did) { return ret.push(clean::Item { - inner: clean::DefaultImplItem(clean::DefaultImpl { + inner: clean::AutoImplItem(clean::AutoImpl { // FIXME: this should be decoded unsafety: hir::Unsafety::Normal, trait_: match associated_trait.as_ref().unwrap().clean(cx) { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index f8fea643d5e..4b60536e1d1 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -425,7 +425,7 @@ pub enum ItemEnum { PrimitiveItem(PrimitiveType), AssociatedConstItem(Type, Option<String>), AssociatedTypeItem(Vec<TyParamBound>, Option<Type>), - DefaultImplItem(DefaultImpl), + AutoImplItem(AutoImpl), /// An item that has been stripped by a rustdoc pass StrippedItem(Box<ItemEnum>), } @@ -2733,12 +2733,12 @@ fn build_deref_target_impls(cx: &DocContext, } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] -pub struct DefaultImpl { +pub struct AutoImpl { pub unsafety: hir::Unsafety, pub trait_: Type, } -impl Clean<Item> for doctree::DefaultImpl { +impl Clean<Item> for doctree::AutoImpl { fn clean(&self, cx: &DocContext) -> Item { Item { name: None, @@ -2748,7 +2748,7 @@ impl Clean<Item> for doctree::DefaultImpl { visibility: Some(Public), stability: None, deprecation: None, - inner: DefaultImplItem(DefaultImpl { + inner: AutoImplItem(AutoImpl { unsafety: self.unsafety, trait_: self.trait_.clean(cx), }), diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 71594825cdb..c21bfd8842f 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -44,7 +44,7 @@ pub struct Module { pub stab: Option<attr::Stability>, pub depr: Option<attr::Deprecation>, pub impls: Vec<Impl>, - pub def_traits: Vec<DefaultImpl>, + pub def_traits: Vec<AutoImpl>, pub foreigns: Vec<hir::ForeignMod>, pub macros: Vec<Macro>, pub is_crate: bool, @@ -227,7 +227,7 @@ pub struct Impl { pub id: ast::NodeId, } -pub struct DefaultImpl { +pub struct AutoImpl { pub unsafety: hir::Unsafety, pub trait_: hir::TraitRef, pub id: ast::NodeId, diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs index c9c5f01f0ae..c214c15ed4b 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -82,7 +82,7 @@ impl<'a> From<&'a clean::Item> for ItemType { clean::PrimitiveItem(..) => ItemType::Primitive, clean::AssociatedConstItem(..) => ItemType::AssociatedConst, clean::AssociatedTypeItem(..) => ItemType::AssociatedType, - clean::DefaultImplItem(..) => ItemType::Impl, + clean::AutoImplItem(..) => ItemType::Impl, clean::ForeignTypeItem => ItemType::ForeignType, clean::StrippedItem(..) => unreachable!(), } diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 79eaabe31e8..8c14d1bbe8f 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -105,7 +105,7 @@ r##"<!DOCTYPE html> <dd>Switch tab</dd> <dt>⏎</dt> <dd>Go to active search result</dd> - <dt>+</dt> + <dt style="width:31px;">+ / -</dt> <dd>Collapse/expand all sections</dd> </dl> </div> diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 001e773098e..c132cf75e40 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -30,7 +30,6 @@ use libc; use std::slice; -use std::ascii::AsciiExt; use std::cell::RefCell; use std::collections::{HashMap, VecDeque}; use std::default::Default; diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index edd01a66075..eb59c57603a 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -34,6 +34,7 @@ //! both occur before the crate is rendered. pub use self::ExternalLocation::*; +#[cfg(stage0)] use std::ascii::AsciiExt; use std::cell::RefCell; use std::cmp::Ordering; @@ -1325,7 +1326,7 @@ impl DocFolder for Cache { // Figure out the id of this impl. This may map to a // primitive rather than always to a struct/enum. // Note: matching twice to restrict the lifetime of the `i` borrow. - let mut dids = vec![]; + let mut dids = FxHashSet(); if let clean::Item { inner: clean::ImplItem(ref i), .. } = item { let masked_trait = i.trait_.def_id().map_or(false, |d| self.masked_crates.contains(&d.krate)); @@ -1335,7 +1336,7 @@ impl DocFolder for Cache { clean::BorrowedRef { type_: box clean::ResolvedPath { did, .. }, .. } => { - dids.push(did); + dids.insert(did); } ref t => { let did = t.primitive_type().and_then(|t| { @@ -1343,7 +1344,7 @@ impl DocFolder for Cache { }); if let Some(did) = did { - dids.push(did); + dids.insert(did); } } } @@ -1352,7 +1353,7 @@ impl DocFolder for Cache { if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) { for bound in generics { if let Some(did) = bound.def_id() { - dids.push(did); + dids.insert(did); } } } @@ -1929,7 +1930,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, document(w, cx, item)?; let mut indices = (0..items.len()).filter(|i| { - if let clean::DefaultImplItem(..) = items[*i].inner { + if let clean::AutoImplItem(..) = items[*i].inner { return false; } !items[*i].is_stripped() @@ -2497,7 +2498,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, if !foreign.is_empty() { write!(w, " - <h2 id='foreign-impls' class='section-header'> + <h2 id='foreign-impls' class='small-section-header'> Implementations on Foreign Types<a href='#foreign-impls' class='anchor'></a> </h2> ")?; @@ -3590,7 +3591,8 @@ fn sidebar_assoc_items(it: &clean::Item) -> String { let mut links = HashSet::new(); let ret = v.iter() .filter_map(|i| if let Some(ref i) = i.inner_impl().trait_ { - let out = format!("{:#}", i).replace("<", "<").replace(">", ">"); + let i_display = format!("{:#}", i); + let out = Escape(&i_display); let encoded = small_url_encode(&format!("{:#}", i)); let generated = format!("<a href=\"#impl-{}\">{}</a>", encoded, out); if !links.contains(&generated) && links.insert(generated.clone()) { @@ -3616,11 +3618,12 @@ fn sidebar_assoc_items(it: &clean::Item) -> String { fn sidebar_struct(fmt: &mut fmt::Formatter, it: &clean::Item, s: &clean::Struct) -> fmt::Result { let mut sidebar = String::new(); + let fields = get_struct_fields_name(&s.fields); - if s.fields.iter() - .any(|f| if let clean::StructFieldItem(..) = f.inner { true } else { false }) { + if !fields.is_empty() { if let doctree::Plain = s.struct_type { - sidebar.push_str("<li><a href=\"#fields\">Fields</a></li>"); + sidebar.push_str(&format!("<a class=\"sidebar-title\" href=\"#fields\">Fields</a>\ + <div class=\"sidebar-links\">{}</div>", fields)); } } @@ -3632,40 +3635,122 @@ fn sidebar_struct(fmt: &mut fmt::Formatter, it: &clean::Item, Ok(()) } +fn extract_for_impl_name(item: &clean::Item) -> Option<(String, String)> { + match item.inner { + clean::ItemEnum::ImplItem(ref i) => { + if let Some(ref trait_) = i.trait_ { + Some((format!("{:#}", i.for_), format!("{:#}", trait_))) + } else { + None + } + }, + _ => None, + } +} + fn sidebar_trait(fmt: &mut fmt::Formatter, it: &clean::Item, t: &clean::Trait) -> fmt::Result { let mut sidebar = String::new(); - let has_types = t.items.iter().any(|m| m.is_associated_type()); - let has_consts = t.items.iter().any(|m| m.is_associated_const()); - let has_required = t.items.iter().any(|m| m.is_ty_method()); - let has_provided = t.items.iter().any(|m| m.is_method()); + let types = t.items + .iter() + .filter_map(|m| { + match m.name { + Some(ref name) if m.is_associated_type() => { + Some(format!("<a href=\"#associatedtype.{name}\">{name}</a>", + name=name)) + } + _ => None, + } + }) + .collect::<String>(); + let consts = t.items + .iter() + .filter_map(|m| { + match m.name { + Some(ref name) if m.is_associated_const() => { + Some(format!("<a href=\"#associatedconstant.{name}\">{name}</a>", + name=name)) + } + _ => None, + } + }) + .collect::<String>(); + let required = t.items + .iter() + .filter_map(|m| { + match m.name { + Some(ref name) if m.is_ty_method() => { + Some(format!("<a href=\"#tymethod.{name}\">{name}</a>", + name=name)) + } + _ => None, + } + }) + .collect::<String>(); + let provided = t.items + .iter() + .filter_map(|m| { + match m.name { + Some(ref name) if m.is_method() => { + Some(format!("<a href=\"#method.{name}\">{name}</a>", name=name)) + } + _ => None, + } + }) + .collect::<String>(); - if has_types { - sidebar.push_str("<li><a href=\"#associated-types\">Associated Types</a></li>"); + if !types.is_empty() { + sidebar.push_str(&format!("<a class=\"sidebar-title\" href=\"#associated-types\">\ + Associated Types</a><div class=\"sidebar-links\">{}</div>", + types)); } - if has_consts { - sidebar.push_str("<li><a href=\"#associated-const\">Associated Constants</a></li>"); + if !consts.is_empty() { + sidebar.push_str(&format!("<a class=\"sidebar-title\" href=\"#associated-const\">\ + Associated Constants</a><div class=\"sidebar-links\">{}</div>", + consts)); } - if has_required { - sidebar.push_str("<li><a href=\"#required-methods\">Required Methods</a></li>"); + if !required.is_empty() { + sidebar.push_str(&format!("<a class=\"sidebar-title\" href=\"#required-methods\">\ + Required Methods</a><div class=\"sidebar-links\">{}</div>", + required)); } - if has_provided { - sidebar.push_str("<li><a href=\"#provided-methods\">Provided Methods</a></li>"); + if !provided.is_empty() { + sidebar.push_str(&format!("<a class=\"sidebar-title\" href=\"#provided-methods\">\ + Provided Methods</a><div class=\"sidebar-links\">{}</div>", + provided)); } let c = cache(); if let Some(implementors) = c.implementors.get(&it.def_id) { - if implementors.iter().any(|i| i.impl_.for_.def_id() - .map_or(false, |d| !c.paths.contains_key(&d))) - { - sidebar.push_str("<li><a href=\"#foreign-impls\">\ - Implementations on Foreign Types</a></li>"); - } - } - - sidebar.push_str("<li><a href=\"#implementors\">Implementors</a></li>"); + let res = implementors.iter() + .filter(|i| i.impl_.for_.def_id() + .map_or(false, |d| !c.paths.contains_key(&d))) + .filter_map(|i| { + if let Some(item) = implementor2item(&c, i) { + match extract_for_impl_name(&item) { + Some((ref name, ref url)) => { + Some(format!("<a href=\"#impl-{}\">{}</a>", + small_url_encode(url), + Escape(name))) + } + _ => None, + } + } else { + None + } + }) + .collect::<String>(); + if !res.is_empty() { + sidebar.push_str(&format!("<a class=\"sidebar-title\" href=\"#foreign-impls\">\ + Implementations on Foreign Types</a><div \ + class=\"sidebar-links\">{}</div>", + res)); + } + } + + sidebar.push_str("<a class=\"sidebar-title\" href=\"#implementors\">Implementors</a>"); sidebar.push_str(&sidebar_assoc_items(it)); @@ -3692,13 +3777,29 @@ fn sidebar_typedef(fmt: &mut fmt::Formatter, it: &clean::Item, Ok(()) } +fn get_struct_fields_name(fields: &[clean::Item]) -> String { + fields.iter() + .filter(|f| if let clean::StructFieldItem(..) = f.inner { + true + } else { + false + }) + .filter_map(|f| match f.name { + Some(ref name) => Some(format!("<a href=\"#structfield.{name}\">\ + {name}</a>", name=name)), + _ => None, + }) + .collect() +} + fn sidebar_union(fmt: &mut fmt::Formatter, it: &clean::Item, u: &clean::Union) -> fmt::Result { let mut sidebar = String::new(); + let fields = get_struct_fields_name(&u.fields); - if u.fields.iter() - .any(|f| if let clean::StructFieldItem(..) = f.inner { true } else { false }) { - sidebar.push_str("<li><a href=\"#fields\">Fields</a></li>"); + if !fields.is_empty() { + sidebar.push_str(&format!("<a class=\"sidebar-title\" href=\"#fields\">Fields</a>\ + <div class=\"sidebar-links\">{}</div>", fields)); } sidebar.push_str(&sidebar_assoc_items(it)); @@ -3713,8 +3814,16 @@ fn sidebar_enum(fmt: &mut fmt::Formatter, it: &clean::Item, e: &clean::Enum) -> fmt::Result { let mut sidebar = String::new(); - if !e.variants.is_empty() { - sidebar.push_str("<li><a href=\"#variants\">Variants</a></li>"); + let variants = e.variants.iter() + .filter_map(|v| match v.name { + Some(ref name) => Some(format!("<a href=\"#variant.{name}\">{name}\ + </a>", name = name)), + _ => None, + }) + .collect::<String>(); + if !variants.is_empty() { + sidebar.push_str(&format!("<a class=\"sidebar-title\" href=\"#variants\">Variants</a>\ + <div class=\"sidebar-links\">{}</div>", variants)); } sidebar.push_str(&sidebar_assoc_items(it)); @@ -3744,7 +3853,7 @@ fn sidebar_module(fmt: &mut fmt::Formatter, _it: &clean::Item, ItemType::TyMethod, ItemType::Method, ItemType::StructField, ItemType::Variant, ItemType::AssociatedType, ItemType::AssociatedConst, ItemType::ForeignType] { if items.iter().any(|it| { - if let clean::DefaultImplItem(..) = it.inner { + if let clean::AutoImplItem(..) = it.inner { false } else { !it.is_stripped() && it.type_() == myty diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 04bf466a780..1d9bfa260bf 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -213,6 +213,7 @@ break; case "+": + case "-": ev.preventDefault(); toggleAllDocs(); break; @@ -349,7 +350,7 @@ var valLower = query.query.toLowerCase(), val = valLower, typeFilter = itemTypeFromName(query.type), - results = [], + results = {}, split = valLower.split("::"); // remove empty keywords @@ -360,15 +361,52 @@ } } + function min(a, b) { + if (a < b) { + return a; + } + return b; + } + + function nbElements(obj) { + var size = 0, key; + for (key in obj) { + if (obj.hasOwnProperty(key)) { + size += 1; + } + } + return size; + } + function findArg(obj, val) { + var lev_distance = MAX_LEV_DISTANCE + 1; if (obj && obj.type && obj.type.inputs.length > 0) { for (var i = 0; i < obj.type.inputs.length; i++) { if (obj.type.inputs[i].name === val) { - return true; + // No need to check anything else: we found it. Let's just move on. + return 0; + } + lev_distance = min(levenshtein(obj.type.inputs[i].name, val), lev_distance); + if (lev_distance === 0) { + return 0; } } } - return false; + return lev_distance; + } + + function checkReturned(obj, val) { + var lev_distance = MAX_LEV_DISTANCE + 1; + if (obj && obj.type && obj.type.output) { + if (obj.type.output.name.toLowerCase() === val) { + return 0; + } + lev_distance = min(levenshtein(obj.type.output.name, val)); + if (lev_distance === 0) { + return 0; + } + } + return lev_distance; } function typePassesFilter(filter, type) { @@ -398,22 +436,27 @@ if ((val.charAt(0) === "\"" || val.charAt(0) === "'") && val.charAt(val.length - 1) === val.charAt(0)) { - val = val.substr(1, val.length - 2); + val = val.substr(1, val.length - 2).toLowerCase(); for (var i = 0; i < nSearchWords; ++i) { + var ty = searchIndex[i]; if (searchWords[i] === val) { // filter type: ... queries if (typePassesFilter(typeFilter, searchIndex[i].ty)) { - results.push({id: i, index: -1}); + results[ty.path + ty.name] = {id: i, index: -1}; } - } else if (findArg(searchIndex[i], val.toLowerCase()) || - (searchIndex[i].type && - searchIndex[i].type.output && - searchIndex[i].type.output.name === val.toLowerCase())) { + } else if (findArg(searchIndex[i], val) || + (ty.type && + ty.type.output && + ty.type.output.name === val)) { if (typePassesFilter(typeFilter, searchIndex[i].ty)) { - results.push({id: i, index: -1, dontValidate: true}); + results[ty.path + ty.name] = { + id: i, + index: -1, + dontValidate: true, + }; } } - if (results.length === max) { + if (nbElements(results) === max) { break; } } @@ -431,6 +474,7 @@ for (var i = 0; i < nSearchWords; ++i) { var type = searchIndex[i].type; + var ty = searchIndex[i]; if (!type) { continue; } @@ -444,7 +488,7 @@ var typeOutput = type.output ? type.output.name : ""; if (output === "*" || output == typeOutput) { if (input === "*") { - results.push({id: i, index: -1, dontValidate: true}); + results[ty.path + ty.name] = {id: i, index: -1, dontValidate: true}; } else { var allFound = true; for (var it = 0; allFound === true && it < inputs.length; it++) { @@ -455,7 +499,11 @@ allFound = found; } if (allFound === true) { - results.push({id: i, index: -1, dontValidate: true}); + results[ty.path + ty.name] = { + id: i, + index: -1, + dontValidate: true, + }; } } } @@ -471,46 +519,77 @@ for (var i = 0; i < split.length; ++i) { for (var j = 0; j < nSearchWords; ++j) { var lev_distance; + var ty = searchIndex[j]; + if (!ty) { + continue; + } if (searchWords[j].indexOf(split[i]) > -1 || searchWords[j].indexOf(val) > -1 || searchWords[j].replace(/_/g, "").indexOf(val) > -1) { // filter type: ... queries if (typePassesFilter(typeFilter, searchIndex[j].ty)) { - results.push({ + results[ty.path + ty.name] = { id: j, index: searchWords[j].replace(/_/g, "").indexOf(val), lev: 0, - }); + }; } } else if ( - (lev_distance = levenshtein(searchWords[j], val)) <= - MAX_LEV_DISTANCE) { + (lev_distance = levenshtein(searchWords[j], val)) <= MAX_LEV_DISTANCE) { if (typePassesFilter(typeFilter, searchIndex[j].ty)) { - results.push({ - id: j, - index: 0, - // we want lev results to go lower than others - lev: lev_distance, - }); + if (results[ty.path + ty.name] === undefined || + results[ty.path + ty.name].lev > lev_distance) { + results[ty.path + ty.name] = { + id: j, + index: 0, + // we want lev results to go lower than others + lev: lev_distance, + }; + } } - } else if (findArg(searchIndex[j], val)) { + } else if ( + (lev_distance = findArg(searchIndex[j], val)) <= MAX_LEV_DISTANCE) { if (typePassesFilter(typeFilter, searchIndex[j].ty)) { - results.push({ - id: j, - index: 0, - // we want lev results to go lower than others - lev: lev_distance, - }); + if (results[ty.path + ty.name] === undefined || + results[ty.path + ty.name].lev > lev_distance) { + results[ty.path + ty.name] = { + id: j, + index: 0, + // we want lev results to go lower than others + lev: lev_distance, + }; + } + } + } else if ( + (lev_distance = checkReturned(searchIndex[j], val)) <= + MAX_LEV_DISTANCE) { + if (typePassesFilter(typeFilter, searchIndex[j].ty)) { + if (results[ty.path + ty.name] === undefined || + results[ty.path + ty.name].lev > lev_distance) { + results[ty.path + ty.name] = { + id: j, + index: 0, + // we want lev results to go lower than others + lev: lev_distance, + }; + } } } - if (results.length === max) { + if (nbElements(results) === max) { break; } } } } + var ar = []; + for (var entry in results) { + if (results.hasOwnProperty(entry)) { + ar.push(results[entry]); + } + } + results = ar; var nresults = results.length; for (var i = 0; i < nresults; ++i) { results[i].word = searchWords[results[i].id]; @@ -586,16 +665,6 @@ return 0; }); - // remove duplicates, according to the data provided - for (var i = results.length - 1; i > 0; i -= 1) { - if (results[i].word === results[i - 1].word && - results[i].item.ty === results[i - 1].item.ty && - results[i].item.path === results[i - 1].item.path && - (results[i].item.parent || {}).name === (results[i - 1].item.parent || {}).name) - { - results[i].id = -1; - } - } for (var i = 0; i < results.length; ++i) { var result = results[i], name = result.item.name.toLowerCase(), @@ -884,6 +953,7 @@ elems[0].onclick = function() { printTab(0); }; elems[1].onclick = function() { printTab(1); }; elems[2].onclick = function() { printTab(2); }; + printTab(currentTab); } function search(e) { @@ -951,7 +1021,8 @@ } } if (results['others'].length < maxResults && - ((query.search && obj.name.indexOf(query.search)) || added === false)) { + ((query.search && obj.name.indexOf(query.search) !== -1) || + added === false)) { results['others'].push(obj); } } diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 398a692f8df..599b032b630 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -582,13 +582,14 @@ body.blur > :not(#help) { display: block; margin-top: -1px; } -#help dd { margin: 5px 33px; } +#help dd { margin: 5px 35px; } #help .infos { padding-left: 0; } #help h1, #help h2 { margin-top: 0; } #help > div div { width: 50%; float: left; padding: 20px; + padding-left: 17px; } .stab { diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 20da99a6b13..fcb25f7aef3 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -14,6 +14,7 @@ html_playground_url = "https://play.rust-lang.org/")] #![deny(warnings)] +#![feature(ascii_ctype)] #![feature(rustc_private)] #![feature(box_patterns)] #![feature(box_syntax)] @@ -23,7 +24,6 @@ #![feature(test)] #![feature(unicode)] #![feature(vec_remove_item)] -#![feature(ascii_ctype)] extern crate arena; extern crate getopts; diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 959543404d8..77d97c84c99 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -116,7 +116,7 @@ impl<'a> fold::DocFolder for Stripper<'a> { // handled in the `strip-priv-imports` pass clean::ExternCrateItem(..) | clean::ImportItem(..) => {} - clean::DefaultImplItem(..) | clean::ImplItem(..) => {} + clean::AutoImplItem(..) | clean::ImplItem(..) => {} // tymethods/macros have no control over privacy clean::MacroItem(..) | clean::TyMethodItem(..) => {} diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 9316805b932..9bbd16355be 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -337,15 +337,23 @@ pub fn make_test(s: &str, let mut prog = String::new(); - // First push any outer attributes from the example, assuming they - // are intended to be crate attributes. - prog.push_str(&crate_attrs); + if opts.attrs.is_empty() { + // If there aren't any attributes supplied by #![doc(test(attr(...)))], then allow some + // lints that are commonly triggered in doctests. The crate-level test attributes are + // commonly used to make tests fail in case they trigger warnings, so having this there in + // that case may cause some tests to pass when they shouldn't have. + prog.push_str("#![allow(unused)]\n"); + } - // Next, any attributes for other aspects such as lints. + // Next, any attributes that came from the crate root via #![doc(test(attr(...)))]. for attr in &opts.attrs { prog.push_str(&format!("#![{}]\n", attr)); } + // Now push any outer attributes from the example, assuming they + // are intended to be crate attributes. + prog.push_str(&crate_attrs); + // Don't inject `extern crate std` because it's already injected by the // compiler. if !s.contains("extern crate") && !opts.no_crate_inject && cratename != Some("std") { diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 327a330c2a2..b55076a01af 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -481,7 +481,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { }; om.constants.push(s); }, - hir::ItemTrait(unsafety, ref gen, ref b, ref item_ids) => { + hir::ItemTrait(_, unsafety, ref gen, ref b, ref item_ids) => { let items = item_ids.iter() .map(|ti| self.cx.tcx.hir.trait_item(ti.id).clone()) .collect(); @@ -532,10 +532,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { om.impls.push(i); } }, - hir::ItemDefaultImpl(unsafety, ref trait_ref) => { + hir::ItemAutoImpl(unsafety, ref trait_ref) => { // See comment above about ItemImpl. if !self.inlining { - let i = DefaultImpl { + let i = AutoImpl { unsafety, trait_: trait_ref.clone(), id: item.id, diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index 5dd5f8953a0..d239b79d4ba 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -3,6 +3,9 @@ authors = ["The Rust Project Developers"] name = "std" version = "0.0.0" build = "build.rs" +license = "MIT/Apache-2.0" +repository = "https://github.com/rust-lang/rust.git" +description = "The Rust Standard Library" [lib] name = "std" diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index 327deb9b419..96d719c528c 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -38,8 +38,8 @@ use iter::FusedIterator; /// ``` /// use std::ascii::AsciiExt; /// -/// assert_eq!("café".to_ascii_uppercase(), "CAFÉ"); -/// assert_eq!("café".to_ascii_uppercase(), "CAFé"); +/// assert_eq!(AsciiExt::to_ascii_uppercase("café"), "CAFÉ"); +/// assert_eq!(AsciiExt::to_ascii_uppercase("café"), "CAFé"); /// ``` /// /// In the first example, the lowercased string is represented `"cafe\u{301}"` @@ -60,19 +60,10 @@ pub trait AsciiExt { /// Checks if the value is within the ASCII range. /// - /// # Examples + /// # Note /// - /// ``` - /// use std::ascii::AsciiExt; - /// - /// let ascii = 'a'; - /// let non_ascii = '❤'; - /// let int_ascii = 97; - /// - /// assert!(ascii.is_ascii()); - /// assert!(!non_ascii.is_ascii()); - /// assert!(int_ascii.is_ascii()); - /// ``` + /// This method will be deprecated in favor of the identically-named + /// inherent methods on `u8`, `char`, `[u8]` and `str`. #[stable(feature = "rust1", since = "1.0.0")] fn is_ascii(&self) -> bool; @@ -86,19 +77,10 @@ pub trait AsciiExt { /// To uppercase ASCII characters in addition to non-ASCII characters, use /// [`str::to_uppercase`]. /// - /// # Examples - /// - /// ``` - /// use std::ascii::AsciiExt; - /// - /// let ascii = 'a'; - /// let non_ascii = '❤'; - /// let int_ascii = 97; + /// # Note /// - /// assert_eq!('A', ascii.to_ascii_uppercase()); - /// assert_eq!('❤', non_ascii.to_ascii_uppercase()); - /// assert_eq!(65, int_ascii.to_ascii_uppercase()); - /// ``` + /// This method will be deprecated in favor of the identically-named + /// inherent methods on `u8`, `char`, `[u8]` and `str`. /// /// [`make_ascii_uppercase`]: #tymethod.make_ascii_uppercase /// [`str::to_uppercase`]: ../primitive.str.html#method.to_uppercase @@ -115,19 +97,10 @@ pub trait AsciiExt { /// To lowercase ASCII characters in addition to non-ASCII characters, use /// [`str::to_lowercase`]. /// - /// # Examples + /// # Note /// - /// ``` - /// use std::ascii::AsciiExt; - /// - /// let ascii = 'A'; - /// let non_ascii = '❤'; - /// let int_ascii = 65; - /// - /// assert_eq!('a', ascii.to_ascii_lowercase()); - /// assert_eq!('❤', non_ascii.to_ascii_lowercase()); - /// assert_eq!(97, int_ascii.to_ascii_lowercase()); - /// ``` + /// This method will be deprecated in favor of the identically-named + /// inherent methods on `u8`, `char`, `[u8]` and `str`. /// /// [`make_ascii_lowercase`]: #tymethod.make_ascii_lowercase /// [`str::to_lowercase`]: ../primitive.str.html#method.to_lowercase @@ -139,20 +112,10 @@ pub trait AsciiExt { /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, /// but without allocating and copying temporaries. /// - /// # Examples - /// - /// ``` - /// use std::ascii::AsciiExt; - /// - /// let ascii1 = 'A'; - /// let ascii2 = 'a'; - /// let ascii3 = 'A'; - /// let ascii4 = 'z'; + /// # Note /// - /// assert!(ascii1.eq_ignore_ascii_case(&ascii2)); - /// assert!(ascii1.eq_ignore_ascii_case(&ascii3)); - /// assert!(!ascii1.eq_ignore_ascii_case(&ascii4)); - /// ``` + /// This method will be deprecated in favor of the identically-named + /// inherent methods on `u8`, `char`, `[u8]` and `str`. #[stable(feature = "rust1", since = "1.0.0")] fn eq_ignore_ascii_case(&self, other: &Self) -> bool; @@ -164,17 +127,10 @@ pub trait AsciiExt { /// To return a new uppercased value without modifying the existing one, use /// [`to_ascii_uppercase`]. /// - /// # Examples + /// # Note /// - /// ``` - /// use std::ascii::AsciiExt; - /// - /// let mut ascii = 'a'; - /// - /// ascii.make_ascii_uppercase(); - /// - /// assert_eq!('A', ascii); - /// ``` + /// This method will be deprecated in favor of the identically-named + /// inherent methods on `u8`, `char`, `[u8]` and `str`. /// /// [`to_ascii_uppercase`]: #tymethod.to_ascii_uppercase #[stable(feature = "ascii", since = "1.9.0")] @@ -188,17 +144,10 @@ pub trait AsciiExt { /// To return a new lowercased value without modifying the existing one, use /// [`to_ascii_lowercase`]. /// - /// # Examples - /// - /// ``` - /// use std::ascii::AsciiExt; + /// # Note /// - /// let mut ascii = 'A'; - /// - /// ascii.make_ascii_lowercase(); - /// - /// assert_eq!('a', ascii); - /// ``` + /// This method will be deprecated in favor of the identically-named + /// inherent methods on `u8`, `char`, `[u8]` and `str`. /// /// [`to_ascii_lowercase`]: #tymethod.to_ascii_lowercase #[stable(feature = "ascii", since = "1.9.0")] @@ -209,32 +158,10 @@ pub trait AsciiExt { /// For strings, true if all characters in the string are /// ASCII alphabetic. /// - /// # Examples + /// # Note /// - /// ``` - /// #![feature(ascii_ctype)] - /// # #![allow(non_snake_case)] - /// use std::ascii::AsciiExt; - /// let A = 'A'; - /// let G = 'G'; - /// let a = 'a'; - /// let g = 'g'; - /// let zero = '0'; - /// let percent = '%'; - /// let space = ' '; - /// let lf = '\n'; - /// let esc = '\u{001b}'; - /// - /// assert!(A.is_ascii_alphabetic()); - /// assert!(G.is_ascii_alphabetic()); - /// assert!(a.is_ascii_alphabetic()); - /// assert!(g.is_ascii_alphabetic()); - /// assert!(!zero.is_ascii_alphabetic()); - /// assert!(!percent.is_ascii_alphabetic()); - /// assert!(!space.is_ascii_alphabetic()); - /// assert!(!lf.is_ascii_alphabetic()); - /// assert!(!esc.is_ascii_alphabetic()); - /// ``` + /// This method will be deprecated in favor of the identically-named + /// inherent methods on `u8`, `char`, `[u8]` and `str`. #[unstable(feature = "ascii_ctype", issue = "39658")] fn is_ascii_alphabetic(&self) -> bool { unimplemented!(); } @@ -243,32 +170,10 @@ pub trait AsciiExt { /// For strings, true if all characters in the string are /// ASCII uppercase. /// - /// # Examples - /// - /// ``` - /// #![feature(ascii_ctype)] - /// # #![allow(non_snake_case)] - /// use std::ascii::AsciiExt; - /// let A = 'A'; - /// let G = 'G'; - /// let a = 'a'; - /// let g = 'g'; - /// let zero = '0'; - /// let percent = '%'; - /// let space = ' '; - /// let lf = '\n'; - /// let esc = '\u{001b}'; + /// # Note /// - /// assert!(A.is_ascii_uppercase()); - /// assert!(G.is_ascii_uppercase()); - /// assert!(!a.is_ascii_uppercase()); - /// assert!(!g.is_ascii_uppercase()); - /// assert!(!zero.is_ascii_uppercase()); - /// assert!(!percent.is_ascii_uppercase()); - /// assert!(!space.is_ascii_uppercase()); - /// assert!(!lf.is_ascii_uppercase()); - /// assert!(!esc.is_ascii_uppercase()); - /// ``` + /// This method will be deprecated in favor of the identically-named + /// inherent methods on `u8`, `char`, `[u8]` and `str`. #[unstable(feature = "ascii_ctype", issue = "39658")] fn is_ascii_uppercase(&self) -> bool { unimplemented!(); } @@ -277,32 +182,10 @@ pub trait AsciiExt { /// For strings, true if all characters in the string are /// ASCII lowercase. /// - /// # Examples + /// # Note /// - /// ``` - /// #![feature(ascii_ctype)] - /// # #![allow(non_snake_case)] - /// use std::ascii::AsciiExt; - /// let A = 'A'; - /// let G = 'G'; - /// let a = 'a'; - /// let g = 'g'; - /// let zero = '0'; - /// let percent = '%'; - /// let space = ' '; - /// let lf = '\n'; - /// let esc = '\u{001b}'; - /// - /// assert!(!A.is_ascii_lowercase()); - /// assert!(!G.is_ascii_lowercase()); - /// assert!(a.is_ascii_lowercase()); - /// assert!(g.is_ascii_lowercase()); - /// assert!(!zero.is_ascii_lowercase()); - /// assert!(!percent.is_ascii_lowercase()); - /// assert!(!space.is_ascii_lowercase()); - /// assert!(!lf.is_ascii_lowercase()); - /// assert!(!esc.is_ascii_lowercase()); - /// ``` + /// This method will be deprecated in favor of the identically-named + /// inherent methods on `u8`, `char`, `[u8]` and `str`. #[unstable(feature = "ascii_ctype", issue = "39658")] fn is_ascii_lowercase(&self) -> bool { unimplemented!(); } @@ -312,32 +195,10 @@ pub trait AsciiExt { /// For strings, true if all characters in the string are /// ASCII alphanumeric. /// - /// # Examples - /// - /// ``` - /// #![feature(ascii_ctype)] - /// # #![allow(non_snake_case)] - /// use std::ascii::AsciiExt; - /// let A = 'A'; - /// let G = 'G'; - /// let a = 'a'; - /// let g = 'g'; - /// let zero = '0'; - /// let percent = '%'; - /// let space = ' '; - /// let lf = '\n'; - /// let esc = '\u{001b}'; + /// # Note /// - /// assert!(A.is_ascii_alphanumeric()); - /// assert!(G.is_ascii_alphanumeric()); - /// assert!(a.is_ascii_alphanumeric()); - /// assert!(g.is_ascii_alphanumeric()); - /// assert!(zero.is_ascii_alphanumeric()); - /// assert!(!percent.is_ascii_alphanumeric()); - /// assert!(!space.is_ascii_alphanumeric()); - /// assert!(!lf.is_ascii_alphanumeric()); - /// assert!(!esc.is_ascii_alphanumeric()); - /// ``` + /// This method will be deprecated in favor of the identically-named + /// inherent methods on `u8`, `char`, `[u8]` and `str`. #[unstable(feature = "ascii_ctype", issue = "39658")] fn is_ascii_alphanumeric(&self) -> bool { unimplemented!(); } @@ -346,32 +207,10 @@ pub trait AsciiExt { /// For strings, true if all characters in the string are /// ASCII digits. /// - /// # Examples + /// # Note /// - /// ``` - /// #![feature(ascii_ctype)] - /// # #![allow(non_snake_case)] - /// use std::ascii::AsciiExt; - /// let A = 'A'; - /// let G = 'G'; - /// let a = 'a'; - /// let g = 'g'; - /// let zero = '0'; - /// let percent = '%'; - /// let space = ' '; - /// let lf = '\n'; - /// let esc = '\u{001b}'; - /// - /// assert!(!A.is_ascii_digit()); - /// assert!(!G.is_ascii_digit()); - /// assert!(!a.is_ascii_digit()); - /// assert!(!g.is_ascii_digit()); - /// assert!(zero.is_ascii_digit()); - /// assert!(!percent.is_ascii_digit()); - /// assert!(!space.is_ascii_digit()); - /// assert!(!lf.is_ascii_digit()); - /// assert!(!esc.is_ascii_digit()); - /// ``` + /// This method will be deprecated in favor of the identically-named + /// inherent methods on `u8`, `char`, `[u8]` and `str`. #[unstable(feature = "ascii_ctype", issue = "39658")] fn is_ascii_digit(&self) -> bool { unimplemented!(); } @@ -381,32 +220,10 @@ pub trait AsciiExt { /// For strings, true if all characters in the string are /// ASCII hex digits. /// - /// # Examples - /// - /// ``` - /// #![feature(ascii_ctype)] - /// # #![allow(non_snake_case)] - /// use std::ascii::AsciiExt; - /// let A = 'A'; - /// let G = 'G'; - /// let a = 'a'; - /// let g = 'g'; - /// let zero = '0'; - /// let percent = '%'; - /// let space = ' '; - /// let lf = '\n'; - /// let esc = '\u{001b}'; + /// # Note /// - /// assert!(A.is_ascii_hexdigit()); - /// assert!(!G.is_ascii_hexdigit()); - /// assert!(a.is_ascii_hexdigit()); - /// assert!(!g.is_ascii_hexdigit()); - /// assert!(zero.is_ascii_hexdigit()); - /// assert!(!percent.is_ascii_hexdigit()); - /// assert!(!space.is_ascii_hexdigit()); - /// assert!(!lf.is_ascii_hexdigit()); - /// assert!(!esc.is_ascii_hexdigit()); - /// ``` + /// This method will be deprecated in favor of the identically-named + /// inherent methods on `u8`, `char`, `[u8]` and `str`. #[unstable(feature = "ascii_ctype", issue = "39658")] fn is_ascii_hexdigit(&self) -> bool { unimplemented!(); } @@ -420,32 +237,10 @@ pub trait AsciiExt { /// For strings, true if all characters in the string are /// ASCII punctuation. /// - /// # Examples + /// # Note /// - /// ``` - /// #![feature(ascii_ctype)] - /// # #![allow(non_snake_case)] - /// use std::ascii::AsciiExt; - /// let A = 'A'; - /// let G = 'G'; - /// let a = 'a'; - /// let g = 'g'; - /// let zero = '0'; - /// let percent = '%'; - /// let space = ' '; - /// let lf = '\n'; - /// let esc = '\u{001b}'; - /// - /// assert!(!A.is_ascii_punctuation()); - /// assert!(!G.is_ascii_punctuation()); - /// assert!(!a.is_ascii_punctuation()); - /// assert!(!g.is_ascii_punctuation()); - /// assert!(!zero.is_ascii_punctuation()); - /// assert!(percent.is_ascii_punctuation()); - /// assert!(!space.is_ascii_punctuation()); - /// assert!(!lf.is_ascii_punctuation()); - /// assert!(!esc.is_ascii_punctuation()); - /// ``` + /// This method will be deprecated in favor of the identically-named + /// inherent methods on `u8`, `char`, `[u8]` and `str`. #[unstable(feature = "ascii_ctype", issue = "39658")] fn is_ascii_punctuation(&self) -> bool { unimplemented!(); } @@ -454,32 +249,10 @@ pub trait AsciiExt { /// For strings, true if all characters in the string are /// ASCII punctuation. /// - /// # Examples - /// - /// ``` - /// #![feature(ascii_ctype)] - /// # #![allow(non_snake_case)] - /// use std::ascii::AsciiExt; - /// let A = 'A'; - /// let G = 'G'; - /// let a = 'a'; - /// let g = 'g'; - /// let zero = '0'; - /// let percent = '%'; - /// let space = ' '; - /// let lf = '\n'; - /// let esc = '\u{001b}'; + /// # Note /// - /// assert!(A.is_ascii_graphic()); - /// assert!(G.is_ascii_graphic()); - /// assert!(a.is_ascii_graphic()); - /// assert!(g.is_ascii_graphic()); - /// assert!(zero.is_ascii_graphic()); - /// assert!(percent.is_ascii_graphic()); - /// assert!(!space.is_ascii_graphic()); - /// assert!(!lf.is_ascii_graphic()); - /// assert!(!esc.is_ascii_graphic()); - /// ``` + /// This method will be deprecated in favor of the identically-named + /// inherent methods on `u8`, `char`, `[u8]` and `str`. #[unstable(feature = "ascii_ctype", issue = "39658")] fn is_ascii_graphic(&self) -> bool { unimplemented!(); } @@ -505,32 +278,10 @@ pub trait AsciiExt { /// [pct]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_01 /// [bfs]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 /// - /// # Examples + /// # Note /// - /// ``` - /// #![feature(ascii_ctype)] - /// # #![allow(non_snake_case)] - /// use std::ascii::AsciiExt; - /// let A = 'A'; - /// let G = 'G'; - /// let a = 'a'; - /// let g = 'g'; - /// let zero = '0'; - /// let percent = '%'; - /// let space = ' '; - /// let lf = '\n'; - /// let esc = '\u{001b}'; - /// - /// assert!(!A.is_ascii_whitespace()); - /// assert!(!G.is_ascii_whitespace()); - /// assert!(!a.is_ascii_whitespace()); - /// assert!(!g.is_ascii_whitespace()); - /// assert!(!zero.is_ascii_whitespace()); - /// assert!(!percent.is_ascii_whitespace()); - /// assert!(space.is_ascii_whitespace()); - /// assert!(lf.is_ascii_whitespace()); - /// assert!(!esc.is_ascii_whitespace()); - /// ``` + /// This method will be deprecated in favor of the identically-named + /// inherent methods on `u8`, `char`, `[u8]` and `str`. #[unstable(feature = "ascii_ctype", issue = "39658")] fn is_ascii_whitespace(&self) -> bool { unimplemented!(); } @@ -539,36 +290,18 @@ pub trait AsciiExt { /// Note that most ASCII whitespace characters are control /// characters, but SPACE is not. /// - /// # Examples - /// - /// ``` - /// #![feature(ascii_ctype)] - /// # #![allow(non_snake_case)] - /// use std::ascii::AsciiExt; - /// let A = 'A'; - /// let G = 'G'; - /// let a = 'a'; - /// let g = 'g'; - /// let zero = '0'; - /// let percent = '%'; - /// let space = ' '; - /// let lf = '\n'; - /// let esc = '\u{001b}'; + /// # Note /// - /// assert!(!A.is_ascii_control()); - /// assert!(!G.is_ascii_control()); - /// assert!(!a.is_ascii_control()); - /// assert!(!g.is_ascii_control()); - /// assert!(!zero.is_ascii_control()); - /// assert!(!percent.is_ascii_control()); - /// assert!(!space.is_ascii_control()); - /// assert!(lf.is_ascii_control()); - /// assert!(esc.is_ascii_control()); - /// ``` + /// This method will be deprecated in favor of the identically-named + /// inherent methods on `u8`, `char`, `[u8]` and `str`. #[unstable(feature = "ascii_ctype", issue = "39658")] fn is_ascii_control(&self) -> bool { unimplemented!(); } } +// FIXME(LukasKalbertodt): this impl block can be removed in the future. This is +// possible once the stage0 compiler is new enough to contain the inherent +// ascii methods for `[str]`. See FIXME comment further down. +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl AsciiExt for str { type Owned = String; @@ -660,6 +393,10 @@ impl AsciiExt for str { } } +// FIXME(LukasKalbertodt): this impl block can be removed in the future. This is +// possible once the stage0 compiler is new enough to contain the inherent +// ascii methods for `[u8]`. See FIXME comment further down. +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl AsciiExt for [u8] { type Owned = Vec<u8>; @@ -753,201 +490,77 @@ impl AsciiExt for [u8] { } } -#[stable(feature = "rust1", since = "1.0.0")] -impl AsciiExt for u8 { - type Owned = u8; - #[inline] - fn is_ascii(&self) -> bool { *self & 128 == 0 } - #[inline] - fn to_ascii_uppercase(&self) -> u8 { ASCII_UPPERCASE_MAP[*self as usize] } - #[inline] - fn to_ascii_lowercase(&self) -> u8 { ASCII_LOWERCASE_MAP[*self as usize] } - #[inline] - fn eq_ignore_ascii_case(&self, other: &u8) -> bool { - self.to_ascii_lowercase() == other.to_ascii_lowercase() - } - #[inline] - fn make_ascii_uppercase(&mut self) { *self = self.to_ascii_uppercase(); } - #[inline] - fn make_ascii_lowercase(&mut self) { *self = self.to_ascii_lowercase(); } +macro_rules! impl_by_delegating { + ($ty:ty, $owned:ty) => { + #[stable(feature = "rust1", since = "1.0.0")] + impl AsciiExt for $ty { + type Owned = $owned; - #[inline] - fn is_ascii_alphabetic(&self) -> bool { - if *self >= 0x80 { return false; } - match ASCII_CHARACTER_CLASS[*self as usize] { - L|Lx|U|Ux => true, - _ => false - } - } + #[inline] + fn is_ascii(&self) -> bool { self.is_ascii() } - #[inline] - fn is_ascii_uppercase(&self) -> bool { - if *self >= 0x80 { return false } - match ASCII_CHARACTER_CLASS[*self as usize] { - U|Ux => true, - _ => false - } - } + #[inline] + fn to_ascii_uppercase(&self) -> Self::Owned { self.to_ascii_uppercase() } - #[inline] - fn is_ascii_lowercase(&self) -> bool { - if *self >= 0x80 { return false } - match ASCII_CHARACTER_CLASS[*self as usize] { - L|Lx => true, - _ => false - } - } + #[inline] + fn to_ascii_lowercase(&self) -> Self::Owned { self.to_ascii_lowercase() } - #[inline] - fn is_ascii_alphanumeric(&self) -> bool { - if *self >= 0x80 { return false } - match ASCII_CHARACTER_CLASS[*self as usize] { - D|L|Lx|U|Ux => true, - _ => false - } - } + #[inline] + fn eq_ignore_ascii_case(&self, o: &Self) -> bool { self.eq_ignore_ascii_case(o) } - #[inline] - fn is_ascii_digit(&self) -> bool { - if *self >= 0x80 { return false } - match ASCII_CHARACTER_CLASS[*self as usize] { - D => true, - _ => false - } - } + #[inline] + fn make_ascii_uppercase(&mut self) { self.make_ascii_uppercase(); } - #[inline] - fn is_ascii_hexdigit(&self) -> bool { - if *self >= 0x80 { return false } - match ASCII_CHARACTER_CLASS[*self as usize] { - D|Lx|Ux => true, - _ => false - } - } + #[inline] + fn make_ascii_lowercase(&mut self) { self.make_ascii_lowercase(); } - #[inline] - fn is_ascii_punctuation(&self) -> bool { - if *self >= 0x80 { return false } - match ASCII_CHARACTER_CLASS[*self as usize] { - P => true, - _ => false - } - } + #[inline] + fn is_ascii_alphabetic(&self) -> bool { self.is_ascii_alphabetic() } - #[inline] - fn is_ascii_graphic(&self) -> bool { - if *self >= 0x80 { return false; } - match ASCII_CHARACTER_CLASS[*self as usize] { - Ux|U|Lx|L|D|P => true, - _ => false - } - } + #[inline] + fn is_ascii_uppercase(&self) -> bool { self.is_ascii_uppercase() } - #[inline] - fn is_ascii_whitespace(&self) -> bool { - if *self >= 0x80 { return false; } - match ASCII_CHARACTER_CLASS[*self as usize] { - Cw|W => true, - _ => false - } - } - - #[inline] - fn is_ascii_control(&self) -> bool { - if *self >= 0x80 { return false; } - match ASCII_CHARACTER_CLASS[*self as usize] { - C|Cw => true, - _ => false - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsciiExt for char { - type Owned = char; - #[inline] - fn is_ascii(&self) -> bool { - *self as u32 <= 0x7F - } + #[inline] + fn is_ascii_lowercase(&self) -> bool { self.is_ascii_lowercase() } - #[inline] - fn to_ascii_uppercase(&self) -> char { - if self.is_ascii() { - (*self as u8).to_ascii_uppercase() as char - } else { - *self - } - } + #[inline] + fn is_ascii_alphanumeric(&self) -> bool { self.is_ascii_alphanumeric() } - #[inline] - fn to_ascii_lowercase(&self) -> char { - if self.is_ascii() { - (*self as u8).to_ascii_lowercase() as char - } else { - *self - } - } + #[inline] + fn is_ascii_digit(&self) -> bool { self.is_ascii_digit() } - #[inline] - fn eq_ignore_ascii_case(&self, other: &char) -> bool { - self.to_ascii_lowercase() == other.to_ascii_lowercase() - } + #[inline] + fn is_ascii_hexdigit(&self) -> bool { self.is_ascii_hexdigit() } - #[inline] - fn make_ascii_uppercase(&mut self) { *self = self.to_ascii_uppercase(); } - #[inline] - fn make_ascii_lowercase(&mut self) { *self = self.to_ascii_lowercase(); } + #[inline] + fn is_ascii_punctuation(&self) -> bool { self.is_ascii_punctuation() } - #[inline] - fn is_ascii_alphabetic(&self) -> bool { - (*self as u32 <= 0x7f) && (*self as u8).is_ascii_alphabetic() - } + #[inline] + fn is_ascii_graphic(&self) -> bool { self.is_ascii_graphic() } - #[inline] - fn is_ascii_uppercase(&self) -> bool { - (*self as u32 <= 0x7f) && (*self as u8).is_ascii_uppercase() - } + #[inline] + fn is_ascii_whitespace(&self) -> bool { self.is_ascii_whitespace() } - #[inline] - fn is_ascii_lowercase(&self) -> bool { - (*self as u32 <= 0x7f) && (*self as u8).is_ascii_lowercase() - } - - #[inline] - fn is_ascii_alphanumeric(&self) -> bool { - (*self as u32 <= 0x7f) && (*self as u8).is_ascii_alphanumeric() - } - - #[inline] - fn is_ascii_digit(&self) -> bool { - (*self as u32 <= 0x7f) && (*self as u8).is_ascii_digit() - } - - #[inline] - fn is_ascii_hexdigit(&self) -> bool { - (*self as u32 <= 0x7f) && (*self as u8).is_ascii_hexdigit() - } - - #[inline] - fn is_ascii_punctuation(&self) -> bool { - (*self as u32 <= 0x7f) && (*self as u8).is_ascii_punctuation() + #[inline] + fn is_ascii_control(&self) -> bool { self.is_ascii_control() } + } } +} - #[inline] - fn is_ascii_graphic(&self) -> bool { - (*self as u32 <= 0x7f) && (*self as u8).is_ascii_graphic() - } +impl_by_delegating!(u8, u8); +impl_by_delegating!(char, char); - #[inline] - fn is_ascii_whitespace(&self) -> bool { - (*self as u32 <= 0x7f) && (*self as u8).is_ascii_whitespace() - } +// FIXME(LukasKalbertodt): the macro invocation should replace the impl block +// for `[u8]` above. But this is not possible until the stage0 compiler is new +// enough to contain the inherent ascii methods for `[u8]`. +#[cfg(not(stage0))] +impl_by_delegating!([u8], Vec<u8>); - #[inline] - fn is_ascii_control(&self) -> bool { - (*self as u32 <= 0x7f) && (*self as u8).is_ascii_control() - } -} +// FIXME(LukasKalbertodt): the macro invocation should replace the impl block +// for `str` above. But this is not possible until the stage0 compiler is new +// enough to contain the inherent ascii methods for `str`. +#[cfg(not(stage0))] +impl_by_delegating!(str, String); /// An iterator over the escaped version of a byte. /// @@ -1066,112 +679,11 @@ impl fmt::Debug for EscapeDefault { } -static ASCII_LOWERCASE_MAP: [u8; 256] = [ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, - b' ', b'!', b'"', b'#', b'$', b'%', b'&', b'\'', - b'(', b')', b'*', b'+', b',', b'-', b'.', b'/', - b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', - b'8', b'9', b':', b';', b'<', b'=', b'>', b'?', - b'@', - - b'a', b'b', b'c', b'd', b'e', b'f', b'g', - b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o', - b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', - b'x', b'y', b'z', - - b'[', b'\\', b']', b'^', b'_', - b'`', b'a', b'b', b'c', b'd', b'e', b'f', b'g', - b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o', - b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', - b'x', b'y', b'z', b'{', b'|', b'}', b'~', 0x7f, - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, -]; - -static ASCII_UPPERCASE_MAP: [u8; 256] = [ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, - b' ', b'!', b'"', b'#', b'$', b'%', b'&', b'\'', - b'(', b')', b'*', b'+', b',', b'-', b'.', b'/', - b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', - b'8', b'9', b':', b';', b'<', b'=', b'>', b'?', - b'@', b'A', b'B', b'C', b'D', b'E', b'F', b'G', - b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', - b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', - b'X', b'Y', b'Z', b'[', b'\\', b']', b'^', b'_', - b'`', - - b'A', b'B', b'C', b'D', b'E', b'F', b'G', - b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', - b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', - b'X', b'Y', b'Z', - - b'{', b'|', b'}', b'~', 0x7f, - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, -]; - -enum AsciiCharacterClass { - C, // control - Cw, // control whitespace - W, // whitespace - D, // digit - L, // lowercase - Lx, // lowercase hex digit - U, // uppercase - Ux, // uppercase hex digit - P, // punctuation -} -use self::AsciiCharacterClass::*; - -static ASCII_CHARACTER_CLASS: [AsciiCharacterClass; 128] = [ -// _0 _1 _2 _3 _4 _5 _6 _7 _8 _9 _a _b _c _d _e _f - C, C, C, C, C, C, C, C, C, Cw,Cw,C, Cw,Cw,C, C, // 0_ - C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, // 1_ - W, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, // 2_ - D, D, D, D, D, D, D, D, D, D, P, P, P, P, P, P, // 3_ - P, Ux,Ux,Ux,Ux,Ux,Ux,U, U, U, U, U, U, U, U, U, // 4_ - U, U, U, U, U, U, U, U, U, U, U, P, P, P, P, P, // 5_ - P, Lx,Lx,Lx,Lx,Lx,Lx,L, L, L, L, L, L, L, L, L, // 6_ - L, L, L, L, L, L, L, L, L, L, L, P, P, P, P, C, // 7_ -]; - #[cfg(test)] mod tests { - use super::*; + //! Note that most of these tests are not testing `AsciiExt` methods, but + //! test inherent ascii methods of char, u8, str and [u8]. `AsciiExt` is + //! just using those methods, though. use char::from_u32; #[test] diff --git a/src/libstd/env.rs b/src/libstd/env.rs index f81adad3ebe..457c6e1409d 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -671,6 +671,10 @@ pub struct ArgsOs { inner: sys::args::Args } /// set to arbitrary text, and may not even exist. This means this property should /// not be relied upon for security purposes. /// +/// On Unix systems shell usually expands unquoted arguments with glob patterns +/// (such as `*` and `?`). On Windows this is not done, and such arguments are +/// passed as-is. +/// /// # Panics /// /// The returned iterator will panic during iteration if any argument to the diff --git a/src/libstd/heap.rs b/src/libstd/heap.rs index d76ab31862b..4d5e4df6f95 100644 --- a/src/libstd/heap.rs +++ b/src/libstd/heap.rs @@ -17,6 +17,7 @@ pub use alloc_system::System; #[cfg(not(test))] #[doc(hidden)] +#[allow(unused_attributes)] pub mod __default_lib_allocator { use super::{System, Layout, Alloc, AllocErr}; use ptr; @@ -28,6 +29,7 @@ pub mod __default_lib_allocator { // ABI #[no_mangle] + #[rustc_std_internal_symbol] pub unsafe extern fn __rdl_alloc(size: usize, align: usize, err: *mut u8) -> *mut u8 { @@ -42,11 +44,13 @@ pub mod __default_lib_allocator { } #[no_mangle] + #[rustc_std_internal_symbol] pub unsafe extern fn __rdl_oom(err: *const u8) -> ! { System.oom((*(err as *const AllocErr)).clone()) } #[no_mangle] + #[rustc_std_internal_symbol] pub unsafe extern fn __rdl_dealloc(ptr: *mut u8, size: usize, align: usize) { @@ -54,6 +58,7 @@ pub mod __default_lib_allocator { } #[no_mangle] + #[rustc_std_internal_symbol] pub unsafe extern fn __rdl_usable_size(layout: *const u8, min: *mut usize, max: *mut usize) { @@ -63,6 +68,7 @@ pub mod __default_lib_allocator { } #[no_mangle] + #[rustc_std_internal_symbol] pub unsafe extern fn __rdl_realloc(ptr: *mut u8, old_size: usize, old_align: usize, @@ -81,6 +87,7 @@ pub mod __default_lib_allocator { } #[no_mangle] + #[rustc_std_internal_symbol] pub unsafe extern fn __rdl_alloc_zeroed(size: usize, align: usize, err: *mut u8) -> *mut u8 { @@ -95,6 +102,7 @@ pub mod __default_lib_allocator { } #[no_mangle] + #[rustc_std_internal_symbol] pub unsafe extern fn __rdl_alloc_excess(size: usize, align: usize, excess: *mut usize, @@ -113,6 +121,7 @@ pub mod __default_lib_allocator { } #[no_mangle] + #[rustc_std_internal_symbol] pub unsafe extern fn __rdl_realloc_excess(ptr: *mut u8, old_size: usize, old_align: usize, @@ -135,6 +144,7 @@ pub mod __default_lib_allocator { } #[no_mangle] + #[rustc_std_internal_symbol] pub unsafe extern fn __rdl_grow_in_place(ptr: *mut u8, old_size: usize, old_align: usize, @@ -149,6 +159,7 @@ pub mod __default_lib_allocator { } #[no_mangle] + #[rustc_std_internal_symbol] pub unsafe extern fn __rdl_shrink_in_place(ptr: *mut u8, old_size: usize, old_align: usize, diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 4ebd3554fd1..6d3fbc9d268 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -147,6 +147,31 @@ impl<R: Read> BufReader<R> { #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self) -> &mut R { &mut self.inner } + /// Returns `true` if there are no bytes in the internal buffer. + /// + /// # Examples + /// ``` + /// # #![feature(bufreader_is_empty)] + /// use std::io::BufReader; + /// use std::io::BufRead; + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let f1 = File::open("log.txt")?; + /// let mut reader = BufReader::new(f1); + /// assert!(reader.is_empty()); + /// + /// if reader.fill_buf()?.len() > 0 { + /// assert!(!reader.is_empty()); + /// } + /// # Ok(()) + /// # } + /// ``` + #[unstable(feature = "bufreader_is_empty", issue = "45323", reason = "recently added")] + pub fn is_empty(&self) -> bool { + self.pos == self.cap + } + /// Unwraps this `BufReader`, returning the underlying reader. /// /// Note that any leftover data in the internal buffer is lost. diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 5cf1d225b90..429153dc58b 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -244,6 +244,7 @@ #![feature(allow_internal_unstable)] #![feature(align_offset)] #![feature(array_error_internals)] +#![feature(ascii_ctype)] #![feature(asm)] #![feature(attr_literals)] #![feature(box_syntax)] diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 97b09b7e2ad..385076e50dd 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -188,6 +188,8 @@ pub struct AssertUnwindSafe<T>( // * Types like Mutex/RwLock which are explicilty poisoned are unwind safe // * Our custom AssertUnwindSafe wrapper is indeed unwind safe #[stable(feature = "catch_unwind", since = "1.9.0")] +#[allow(unknown_lints)] +#[allow(auto_impl)] impl UnwindSafe for .. {} #[stable(feature = "catch_unwind", since = "1.9.0")] impl<'a, T: ?Sized> !UnwindSafe for &'a mut T {} @@ -221,6 +223,8 @@ impl<T: RefUnwindSafe + ?Sized> UnwindSafe for Arc<T> {} // only thing which doesn't implement it (which then transitively applies to // everything else). #[stable(feature = "catch_unwind", since = "1.9.0")] +#[allow(unknown_lints)] +#[allow(auto_impl)] impl RefUnwindSafe for .. {} #[stable(feature = "catch_unwind", since = "1.9.0")] impl<T: ?Sized> !RefUnwindSafe for UnsafeCell<T> {} diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 294743ed2cc..270878dc029 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -77,7 +77,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use ascii::*; use borrow::{Borrow, Cow}; use cmp; use error::Error; diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index 5555f364e6e..d59a0b65a69 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -10,7 +10,6 @@ use cell::UnsafeCell; use fmt; -use marker; use mem; use ops::{Deref, DerefMut}; use ptr; @@ -102,7 +101,10 @@ pub struct RwLockReadGuard<'a, T: ?Sized + 'a> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: ?Sized> !marker::Send for RwLockReadGuard<'a, T> {} +impl<'a, T: ?Sized> !Send for RwLockReadGuard<'a, T> {} + +#[stable(feature = "rwlock_guard_sync", since = "1.23.0")] +unsafe impl<'a, T: ?Sized + Sync> Sync for RwLockReadGuard<'a, T> {} /// RAII structure used to release the exclusive write access of a lock when /// dropped. @@ -121,7 +123,10 @@ pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: ?Sized> !marker::Send for RwLockWriteGuard<'a, T> {} +impl<'a, T: ?Sized> !Send for RwLockWriteGuard<'a, T> {} + +#[stable(feature = "rwlock_guard_sync", since = "1.23.0")] +unsafe impl<'a, T: ?Sized + Sync> Sync for RwLockWriteGuard<'a, T> {} impl<T> RwLock<T> { /// Creates a new instance of an `RwLock<T>` which is unlocked. diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs index 3e631ad40ac..15f858bca16 100644 --- a/src/libstd/sys/unix/ext/fs.rs +++ b/src/libstd/sys/unix/ext/fs.rs @@ -20,7 +20,9 @@ use sys; use sys_common::{FromInner, AsInner, AsInnerMut}; use sys::platform::fs::MetadataExt as UnixMetadataExt; -/// Unix-specific extensions to `File` +/// Unix-specific extensions to [`File`]. +/// +/// [`File`]: ../../../../std/fs/struct.File.html #[stable(feature = "file_offset", since = "1.15.0")] pub trait FileExt { /// Reads a number of bytes starting from a given offset. @@ -215,36 +217,282 @@ impl OpenOptionsExt for OpenOptions { // casts and rely on manual lowering to `stat` if the raw type is desired. #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { + /// Returns the ID of the device containing the file. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::os::unix::fs::MetadataExt; + /// + /// # use std::io; + /// # fn f() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let dev_id = meta.dev(); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn dev(&self) -> u64; + /// Returns the inode number. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::os::unix::fs::MetadataExt; + /// + /// # use std::io; + /// # fn f() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let inode = meta.ino(); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn ino(&self) -> u64; + /// Returns the rights applied to this file. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::os::unix::fs::MetadataExt; + /// + /// # use std::io; + /// # fn f() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let mode = meta.mode(); + /// let user_has_write_access = mode & 0o200; + /// let user_has_read_write_access = mode & 0o600; + /// let group_has_read_access = mode & 0o040; + /// let others_have_exec_access = mode & 0o001; + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn mode(&self) -> u32; + /// Returns the number of hard links pointing to this file. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::os::unix::fs::MetadataExt; + /// + /// # use std::io; + /// # fn f() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let nb_hard_links = meta.nlink(); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn nlink(&self) -> u64; + /// Returns the user ID of the owner of this file. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::os::unix::fs::MetadataExt; + /// + /// # use std::io; + /// # fn f() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let user_id = meta.uid(); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn uid(&self) -> u32; + /// Returns the group ID of the owner of this file. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::os::unix::fs::MetadataExt; + /// + /// # use std::io; + /// # fn f() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let group_id = meta.gid(); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn gid(&self) -> u32; + /// Returns the device ID of this file (if it is a special one). + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::os::unix::fs::MetadataExt; + /// + /// # use std::io; + /// # fn f() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let device_id = meta.rdev(); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn rdev(&self) -> u64; + /// Returns the total size of this file in bytes. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::os::unix::fs::MetadataExt; + /// + /// # use std::io; + /// # fn f() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let file_size = meta.size(); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn size(&self) -> u64; + /// Returns the time of the last access to the file. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::os::unix::fs::MetadataExt; + /// + /// # use std::io; + /// # fn f() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let last_access_time = meta.atime(); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn atime(&self) -> i64; + /// Returns the time of the last access to the file in nanoseconds. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::os::unix::fs::MetadataExt; + /// + /// # use std::io; + /// # fn f() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let nano_last_access_time = meta.atime_nsec(); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn atime_nsec(&self) -> i64; + /// Returns the time of the last modification of the file. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::os::unix::fs::MetadataExt; + /// + /// # use std::io; + /// # fn f() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let last_modification_time = meta.mtime(); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn mtime(&self) -> i64; + /// Returns the time of the last modification of the file in nanoseconds. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::os::unix::fs::MetadataExt; + /// + /// # use std::io; + /// # fn f() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let nano_last_modification_time = meta.mtime_nsec(); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn mtime_nsec(&self) -> i64; + /// Returns the time of the last status change of the file. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::os::unix::fs::MetadataExt; + /// + /// # use std::io; + /// # fn f() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let last_status_change_time = meta.ctime(); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn ctime(&self) -> i64; + /// Returns the time of the last status change of the file in nanoseconds. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::os::unix::fs::MetadataExt; + /// + /// # use std::io; + /// # fn f() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let nano_last_status_change_time = meta.ctime_nsec(); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn ctime_nsec(&self) -> i64; + /// Returns the blocksize for filesystem I/O. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::os::unix::fs::MetadataExt; + /// + /// # use std::io; + /// # fn f() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let blocksize = meta.blksize(); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn blksize(&self) -> u64; + /// Returns the number of blocks allocated to the file, in 512-byte units. + /// + /// Please note that this may be smaller than `st_size / 512` when the file has holes. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::os::unix::fs::MetadataExt; + /// + /// # use std::io; + /// # fn f() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let blocks = meta.blocks(); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn blocks(&self) -> u64; } @@ -269,19 +517,79 @@ impl MetadataExt for fs::Metadata { fn blocks(&self) -> u64 { self.st_blocks() } } -/// Add special unix types (block/char device, fifo and socket) +/// Add support for special unix types (block/char device, fifo and socket). #[stable(feature = "file_type_ext", since = "1.5.0")] pub trait FileTypeExt { /// Returns whether this file type is a block device. + /// + /// # Examples + /// + /// ``` + /// use std::fs; + /// use std::os::unix::fs::FileTypeExt; + /// + /// # use std::io; + /// # fn f() -> io::Result<()> { + /// let meta = fs::metadata("block_device_file")?; + /// let file_type = meta.file_type(); + /// assert!(file_type.is_block_device()); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "file_type_ext", since = "1.5.0")] fn is_block_device(&self) -> bool; /// Returns whether this file type is a char device. + /// + /// # Examples + /// + /// ``` + /// use std::fs; + /// use std::os::unix::fs::FileTypeExt; + /// + /// # use std::io; + /// # fn f() -> io::Result<()> { + /// let meta = fs::metadata("char_device_file")?; + /// let file_type = meta.file_type(); + /// assert!(file_type.is_char_device()); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "file_type_ext", since = "1.5.0")] fn is_char_device(&self) -> bool; /// Returns whether this file type is a fifo. + /// + /// # Examples + /// + /// ``` + /// use std::fs; + /// use std::os::unix::fs::FileTypeExt; + /// + /// # use std::io; + /// # fn f() -> io::Result<()> { + /// let meta = fs::metadata("fifo_file")?; + /// let file_type = meta.file_type(); + /// assert!(file_type.is_fifo()); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "file_type_ext", since = "1.5.0")] fn is_fifo(&self) -> bool; /// Returns whether this file type is a socket. + /// + /// # Examples + /// + /// ``` + /// use std::fs; + /// use std::os::unix::fs::FileTypeExt; + /// + /// # use std::io; + /// # fn f() -> io::Result<()> { + /// let meta = fs::metadata("unix.socket")?; + /// let file_type = meta.file_type(); + /// assert!(file_type.is_socket()); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "file_type_ext", since = "1.5.0")] fn is_socket(&self) -> bool; } @@ -294,7 +602,9 @@ impl FileTypeExt for fs::FileType { fn is_socket(&self) -> bool { self.as_inner().is(libc::S_IFSOCK) } } -/// Unix-specific extension methods for `fs::DirEntry` +/// Unix-specific extension methods for [`fs::DirEntry`]. +/// +/// [`fs::DirEntry`]: ../../../../std/fs/struct.DirEntry.html #[stable(feature = "dir_entry_ext", since = "1.1.0")] pub trait DirEntryExt { /// Returns the underlying `d_ino` field in the contained `dirent` @@ -354,7 +664,9 @@ pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> } #[stable(feature = "dir_builder", since = "1.6.0")] -/// An extension trait for `fs::DirBuilder` for unix-specific options. +/// An extension trait for [`fs::DirBuilder`] for unix-specific options. +/// +/// [`fs::DirBuilder`]: ../../../../std/fs/struct.DirBuilder.html pub trait DirBuilderExt { /// Sets the mode to create new directories with. This option defaults to /// 0o777. diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index 39e00270233..6e0cccff001 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -1228,7 +1228,7 @@ compat_fn! { } } -#[cfg(target_env = "gnu")] +#[cfg(all(target_env = "gnu", feature = "backtrace"))] mod gnu { use super::*; @@ -1256,5 +1256,5 @@ mod gnu { } } -#[cfg(target_env = "gnu")] +#[cfg(all(target_env = "gnu", feature = "backtrace"))] pub use self::gnu::*; diff --git a/src/libstd/sys/windows/path.rs b/src/libstd/sys/windows/path.rs index 2b47808451b..98d62a0c953 100644 --- a/src/libstd/sys/windows/path.rs +++ b/src/libstd/sys/windows/path.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ascii::*; - use path::Prefix; use ffi::OsStr; use mem; diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index 0d1766d5aec..631d69b05e1 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ascii::*; +use ascii::AsciiExt; use collections::HashMap; use collections; use env::split_paths; diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 28a33c7ec14..ee49bf796b8 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -25,11 +25,15 @@ //! //! Fatal logic errors in Rust cause *thread panic*, during which //! a thread will unwind the stack, running destructors and freeing -//! owned resources. Thread panic is unrecoverable from within -//! the panicking thread (i.e. there is no 'try/catch' in Rust), but -//! the panic may optionally be detected from a different thread. If -//! the main thread panics, the application will exit with a non-zero -//! exit code. +//! owned resources. While not meant as a 'try/catch' mechanism, panics +//! in Rust can nonetheless be caught (unless compiling with `panic=abort`) with +//! [`catch_unwind`](../../std/panic/fn.catch_unwind.html) and recovered +//! from, or alternatively be resumed with +//! [`resume_unwind`](../../std/panic/fn.resume_unwind.html). If the panic +//! is not caught the thread will exit, but the panic may optionally be +//! detected from a different thread with [`join`]. If the main thread panics +//! without the panic being caught, the application will exit with a +//! non-zero exit code. //! //! When the main thread of a Rust program terminates, the entire program shuts //! down, even if other threads are still running. However, this module provides diff --git a/src/libstd_unicode/char.rs b/src/libstd_unicode/char.rs index 5c0c7a4fbca..c012bdcb6db 100644 --- a/src/libstd_unicode/char.rs +++ b/src/libstd_unicode/char.rs @@ -923,6 +923,529 @@ impl char { pub fn to_uppercase(self) -> ToUppercase { ToUppercase(CaseMappingIter::new(conversions::to_upper(self))) } + + /// Checks if the value is within the ASCII range. + /// + /// # Examples + /// + /// ``` + /// let ascii = 'a'; + /// let non_ascii = '❤'; + /// + /// assert!(ascii.is_ascii()); + /// assert!(!non_ascii.is_ascii()); + /// ``` + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")] + #[inline] + pub fn is_ascii(&self) -> bool { + *self as u32 <= 0x7F + } + + /// Makes a copy of the value in its ASCII upper case equivalent. + /// + /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', + /// but non-ASCII letters are unchanged. + /// + /// To uppercase the value in-place, use [`make_ascii_uppercase`]. + /// + /// To uppercase ASCII characters in addition to non-ASCII characters, use + /// [`to_uppercase`]. + /// + /// # Examples + /// + /// ``` + /// let ascii = 'a'; + /// let non_ascii = '❤'; + /// + /// assert_eq!('A', ascii.to_ascii_uppercase()); + /// assert_eq!('❤', non_ascii.to_ascii_uppercase()); + /// ``` + /// + /// [`make_ascii_uppercase`]: #method.make_ascii_uppercase + /// [`to_uppercase`]: #method.to_uppercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")] + #[inline] + pub fn to_ascii_uppercase(&self) -> char { + if self.is_ascii() { + (*self as u8).to_ascii_uppercase() as char + } else { + *self + } + } + + /// Makes a copy of the value in its ASCII lower case equivalent. + /// + /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', + /// but non-ASCII letters are unchanged. + /// + /// To lowercase the value in-place, use [`make_ascii_lowercase`]. + /// + /// To lowercase ASCII characters in addition to non-ASCII characters, use + /// [`to_lowercase`]. + /// + /// # Examples + /// + /// ``` + /// let ascii = 'A'; + /// let non_ascii = '❤'; + /// + /// assert_eq!('a', ascii.to_ascii_lowercase()); + /// assert_eq!('❤', non_ascii.to_ascii_lowercase()); + /// ``` + /// + /// [`make_ascii_lowercase`]: #method.make_ascii_lowercase + /// [`to_lowercase`]: #method.to_lowercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")] + #[inline] + pub fn to_ascii_lowercase(&self) -> char { + if self.is_ascii() { + (*self as u8).to_ascii_lowercase() as char + } else { + *self + } + } + + /// Checks that two values are an ASCII case-insensitive match. + /// + /// Equivalent to `to_ascii_lowercase(a) == to_ascii_lowercase(b)`. + /// + /// # Examples + /// + /// ``` + /// let upper_a = 'A'; + /// let lower_a = 'a'; + /// let lower_z = 'z'; + /// + /// assert!(upper_a.eq_ignore_ascii_case(&lower_a)); + /// assert!(upper_a.eq_ignore_ascii_case(&upper_a)); + /// assert!(!upper_a.eq_ignore_ascii_case(&lower_z)); + /// ``` + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")] + #[inline] + pub fn eq_ignore_ascii_case(&self, other: &char) -> bool { + self.to_ascii_lowercase() == other.to_ascii_lowercase() + } + + /// Converts this type to its ASCII upper case equivalent in-place. + /// + /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', + /// but non-ASCII letters are unchanged. + /// + /// To return a new uppercased value without modifying the existing one, use + /// [`to_ascii_uppercase`]. + /// + /// # Examples + /// + /// ``` + /// let mut ascii = 'a'; + /// + /// ascii.make_ascii_uppercase(); + /// + /// assert_eq!('A', ascii); + /// ``` + /// + /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")] + #[inline] + pub fn make_ascii_uppercase(&mut self) { + *self = self.to_ascii_uppercase(); + } + + /// Converts this type to its ASCII lower case equivalent in-place. + /// + /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', + /// but non-ASCII letters are unchanged. + /// + /// To return a new lowercased value without modifying the existing one, use + /// [`to_ascii_lowercase`]. + /// + /// # Examples + /// + /// ``` + /// let mut ascii = 'A'; + /// + /// ascii.make_ascii_lowercase(); + /// + /// assert_eq!('a', ascii); + /// ``` + /// + /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")] + #[inline] + pub fn make_ascii_lowercase(&mut self) { + *self = self.to_ascii_lowercase(); + } + + /// Checks if the value is an ASCII alphabetic character: + /// + /// - U+0041 'A' ... U+005A 'Z', or + /// - U+0061 'a' ... U+007A 'z'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = 'A'; + /// let uppercase_g = 'G'; + /// let a = 'a'; + /// let g = 'g'; + /// let zero = '0'; + /// let percent = '%'; + /// let space = ' '; + /// let lf = '\n'; + /// let esc: char = 0x1b_u8.into(); + /// + /// assert!(uppercase_a.is_ascii_alphabetic()); + /// assert!(uppercase_g.is_ascii_alphabetic()); + /// assert!(a.is_ascii_alphabetic()); + /// assert!(g.is_ascii_alphabetic()); + /// assert!(!zero.is_ascii_alphabetic()); + /// assert!(!percent.is_ascii_alphabetic()); + /// assert!(!space.is_ascii_alphabetic()); + /// assert!(!lf.is_ascii_alphabetic()); + /// assert!(!esc.is_ascii_alphabetic()); + /// ``` + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_alphabetic(&self) -> bool { + self.is_ascii() && (*self as u8).is_ascii_alphabetic() + } + + /// Checks if the value is an ASCII uppercase character: + /// U+0041 'A' ... U+005A 'Z'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = 'A'; + /// let uppercase_g = 'G'; + /// let a = 'a'; + /// let g = 'g'; + /// let zero = '0'; + /// let percent = '%'; + /// let space = ' '; + /// let lf = '\n'; + /// let esc: char = 0x1b_u8.into(); + /// + /// assert!(uppercase_a.is_ascii_uppercase()); + /// assert!(uppercase_g.is_ascii_uppercase()); + /// assert!(!a.is_ascii_uppercase()); + /// assert!(!g.is_ascii_uppercase()); + /// assert!(!zero.is_ascii_uppercase()); + /// assert!(!percent.is_ascii_uppercase()); + /// assert!(!space.is_ascii_uppercase()); + /// assert!(!lf.is_ascii_uppercase()); + /// assert!(!esc.is_ascii_uppercase()); + /// ``` + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_uppercase(&self) -> bool { + self.is_ascii() && (*self as u8).is_ascii_uppercase() + } + + /// Checks if the value is an ASCII lowercase character: + /// U+0061 'a' ... U+007A 'z'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = 'A'; + /// let uppercase_g = 'G'; + /// let a = 'a'; + /// let g = 'g'; + /// let zero = '0'; + /// let percent = '%'; + /// let space = ' '; + /// let lf = '\n'; + /// let esc: char = 0x1b_u8.into(); + /// + /// assert!(!uppercase_a.is_ascii_lowercase()); + /// assert!(!uppercase_g.is_ascii_lowercase()); + /// assert!(a.is_ascii_lowercase()); + /// assert!(g.is_ascii_lowercase()); + /// assert!(!zero.is_ascii_lowercase()); + /// assert!(!percent.is_ascii_lowercase()); + /// assert!(!space.is_ascii_lowercase()); + /// assert!(!lf.is_ascii_lowercase()); + /// assert!(!esc.is_ascii_lowercase()); + /// ``` + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_lowercase(&self) -> bool { + self.is_ascii() && (*self as u8).is_ascii_lowercase() + } + + /// Checks if the value is an ASCII alphanumeric character: + /// + /// - U+0041 'A' ... U+005A 'Z', or + /// - U+0061 'a' ... U+007A 'z', or + /// - U+0030 '0' ... U+0039 '9'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = 'A'; + /// let uppercase_g = 'G'; + /// let a = 'a'; + /// let g = 'g'; + /// let zero = '0'; + /// let percent = '%'; + /// let space = ' '; + /// let lf = '\n'; + /// let esc: char = 0x1b_u8.into(); + /// + /// assert!(uppercase_a.is_ascii_alphanumeric()); + /// assert!(uppercase_g.is_ascii_alphanumeric()); + /// assert!(a.is_ascii_alphanumeric()); + /// assert!(g.is_ascii_alphanumeric()); + /// assert!(zero.is_ascii_alphanumeric()); + /// assert!(!percent.is_ascii_alphanumeric()); + /// assert!(!space.is_ascii_alphanumeric()); + /// assert!(!lf.is_ascii_alphanumeric()); + /// assert!(!esc.is_ascii_alphanumeric()); + /// ``` + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_alphanumeric(&self) -> bool { + self.is_ascii() && (*self as u8).is_ascii_alphanumeric() + } + + /// Checks if the value is an ASCII decimal digit: + /// U+0030 '0' ... U+0039 '9'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = 'A'; + /// let uppercase_g = 'G'; + /// let a = 'a'; + /// let g = 'g'; + /// let zero = '0'; + /// let percent = '%'; + /// let space = ' '; + /// let lf = '\n'; + /// let esc: char = 0x1b_u8.into(); + /// + /// assert!(!uppercase_a.is_ascii_digit()); + /// assert!(!uppercase_g.is_ascii_digit()); + /// assert!(!a.is_ascii_digit()); + /// assert!(!g.is_ascii_digit()); + /// assert!(zero.is_ascii_digit()); + /// assert!(!percent.is_ascii_digit()); + /// assert!(!space.is_ascii_digit()); + /// assert!(!lf.is_ascii_digit()); + /// assert!(!esc.is_ascii_digit()); + /// ``` + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_digit(&self) -> bool { + self.is_ascii() && (*self as u8).is_ascii_digit() + } + + /// Checks if the value is an ASCII hexadecimal digit: + /// + /// - U+0030 '0' ... U+0039 '9', or + /// - U+0041 'A' ... U+0046 'F', or + /// - U+0061 'a' ... U+0066 'f'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = 'A'; + /// let uppercase_g = 'G'; + /// let a = 'a'; + /// let g = 'g'; + /// let zero = '0'; + /// let percent = '%'; + /// let space = ' '; + /// let lf = '\n'; + /// let esc: char = 0x1b_u8.into(); + /// + /// assert!(uppercase_a.is_ascii_hexdigit()); + /// assert!(!uppercase_g.is_ascii_hexdigit()); + /// assert!(a.is_ascii_hexdigit()); + /// assert!(!g.is_ascii_hexdigit()); + /// assert!(zero.is_ascii_hexdigit()); + /// assert!(!percent.is_ascii_hexdigit()); + /// assert!(!space.is_ascii_hexdigit()); + /// assert!(!lf.is_ascii_hexdigit()); + /// assert!(!esc.is_ascii_hexdigit()); + /// ``` + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_hexdigit(&self) -> bool { + self.is_ascii() && (*self as u8).is_ascii_hexdigit() + } + + /// Checks if the value is an ASCII punctuation character: + /// + /// - U+0021 ... U+002F `! " # $ % & ' ( ) * + , - . /`, or + /// - U+003A ... U+0040 `: ; < = > ? @`, or + /// - U+005B ... U+0060 `[ \\ ] ^ _ \``, or + /// - U+007B ... U+007E `{ | } ~` + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = 'A'; + /// let uppercase_g = 'G'; + /// let a = 'a'; + /// let g = 'g'; + /// let zero = '0'; + /// let percent = '%'; + /// let space = ' '; + /// let lf = '\n'; + /// let esc: char = 0x1b_u8.into(); + /// + /// assert!(!uppercase_a.is_ascii_punctuation()); + /// assert!(!uppercase_g.is_ascii_punctuation()); + /// assert!(!a.is_ascii_punctuation()); + /// assert!(!g.is_ascii_punctuation()); + /// assert!(!zero.is_ascii_punctuation()); + /// assert!(percent.is_ascii_punctuation()); + /// assert!(!space.is_ascii_punctuation()); + /// assert!(!lf.is_ascii_punctuation()); + /// assert!(!esc.is_ascii_punctuation()); + /// ``` + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_punctuation(&self) -> bool { + self.is_ascii() && (*self as u8).is_ascii_punctuation() + } + + /// Checks if the value is an ASCII graphic character: + /// U+0021 '@' ... U+007E '~'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = 'A'; + /// let uppercase_g = 'G'; + /// let a = 'a'; + /// let g = 'g'; + /// let zero = '0'; + /// let percent = '%'; + /// let space = ' '; + /// let lf = '\n'; + /// let esc: char = 0x1b_u8.into(); + /// + /// assert!(uppercase_a.is_ascii_graphic()); + /// assert!(uppercase_g.is_ascii_graphic()); + /// assert!(a.is_ascii_graphic()); + /// assert!(g.is_ascii_graphic()); + /// assert!(zero.is_ascii_graphic()); + /// assert!(percent.is_ascii_graphic()); + /// assert!(!space.is_ascii_graphic()); + /// assert!(!lf.is_ascii_graphic()); + /// assert!(!esc.is_ascii_graphic()); + /// ``` + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_graphic(&self) -> bool { + self.is_ascii() && (*self as u8).is_ascii_graphic() + } + + /// Checks if the value is an ASCII whitespace character: + /// U+0020 SPACE, U+0009 HORIZONTAL TAB, U+000A LINE FEED, + /// U+000C FORM FEED, or U+000D CARRIAGE RETURN. + /// + /// Rust uses the WhatWG Infra Standard's [definition of ASCII + /// whitespace][infra-aw]. There are several other definitions in + /// wide use. For instance, [the POSIX locale][pct] includes + /// U+000B VERTICAL TAB as well as all the above characters, + /// but—from the very same specification—[the default rule for + /// "field splitting" in the Bourne shell][bfs] considers *only* + /// SPACE, HORIZONTAL TAB, and LINE FEED as whitespace. + /// + /// If you are writing a program that will process an existing + /// file format, check what that format's definition of whitespace is + /// before using this function. + /// + /// [infra-aw]: https://infra.spec.whatwg.org/#ascii-whitespace + /// [pct]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_01 + /// [bfs]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = 'A'; + /// let uppercase_g = 'G'; + /// let a = 'a'; + /// let g = 'g'; + /// let zero = '0'; + /// let percent = '%'; + /// let space = ' '; + /// let lf = '\n'; + /// let esc: char = 0x1b_u8.into(); + /// + /// assert!(!uppercase_a.is_ascii_whitespace()); + /// assert!(!uppercase_g.is_ascii_whitespace()); + /// assert!(!a.is_ascii_whitespace()); + /// assert!(!g.is_ascii_whitespace()); + /// assert!(!zero.is_ascii_whitespace()); + /// assert!(!percent.is_ascii_whitespace()); + /// assert!(space.is_ascii_whitespace()); + /// assert!(lf.is_ascii_whitespace()); + /// assert!(!esc.is_ascii_whitespace()); + /// ``` + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_whitespace(&self) -> bool { + self.is_ascii() && (*self as u8).is_ascii_whitespace() + } + + /// Checks if the value is an ASCII control character: + /// U+0000 NUL ... U+001F UNIT SEPARATOR, or U+007F DELETE. + /// Note that most ASCII whitespace characters are control + /// characters, but SPACE is not. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = 'A'; + /// let uppercase_g = 'G'; + /// let a = 'a'; + /// let g = 'g'; + /// let zero = '0'; + /// let percent = '%'; + /// let space = ' '; + /// let lf = '\n'; + /// let esc: char = 0x1b_u8.into(); + /// + /// assert!(!uppercase_a.is_ascii_control()); + /// assert!(!uppercase_g.is_ascii_control()); + /// assert!(!a.is_ascii_control()); + /// assert!(!g.is_ascii_control()); + /// assert!(!zero.is_ascii_control()); + /// assert!(!percent.is_ascii_control()); + /// assert!(!space.is_ascii_control()); + /// assert!(lf.is_ascii_control()); + /// assert!(esc.is_ascii_control()); + /// ``` + #[unstable(feature = "ascii_ctype", issue = "39658")] + #[inline] + pub fn is_ascii_control(&self) -> bool { + self.is_ascii() && (*self as u8).is_ascii_control() + } } /// An iterator that decodes UTF-16 encoded code points from an iterator of `u16`s. diff --git a/src/libstd_unicode/lib.rs b/src/libstd_unicode/lib.rs index e5a114caed0..65058b6554a 100644 --- a/src/libstd_unicode/lib.rs +++ b/src/libstd_unicode/lib.rs @@ -30,6 +30,7 @@ #![deny(warnings)] #![no_std] +#![feature(ascii_ctype)] #![feature(core_char_ext)] #![feature(str_internals)] #![feature(decode_utf8)] diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index be0af8052eb..99dff4edaad 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1581,6 +1581,13 @@ impl FnDecl { } } +/// Is the trait definition an auto trait? +#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum IsAuto { + Yes, + No +} + #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum Unsafety { Unsafe, @@ -1942,12 +1949,12 @@ pub enum ItemKind { Union(VariantData, Generics), /// A Trait declaration (`trait` or `pub trait`). /// - /// E.g. `trait Foo { .. }` or `trait Foo<T> { .. }` - Trait(Unsafety, Generics, TyParamBounds, Vec<TraitItem>), + /// E.g. `trait Foo { .. }`, `trait Foo<T> { .. }` or `auto trait Foo {}` + Trait(IsAuto, Unsafety, Generics, TyParamBounds, Vec<TraitItem>), /// Auto trait implementation. /// /// E.g. `impl Trait for .. {}` or `impl<T> Trait<T> for .. {}` - DefaultImpl(Unsafety, TraitRef), + AutoImpl(Unsafety, TraitRef), /// An implementation. /// /// E.g. `impl<A> Foo<A> { .. }` or `impl<A> Trait for Foo<A> { .. }` @@ -1986,7 +1993,7 @@ impl ItemKind { ItemKind::Mac(..) | ItemKind::MacroDef(..) | ItemKind::Impl(..) | - ItemKind::DefaultImpl(..) => "item" + ItemKind::AutoImpl(..) => "item" } } } diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index dd46903bb88..3464db2a811 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -17,11 +17,15 @@ //! within the CodeMap, which upon request can be converted to line and column //! information, source code snippets, etc. + pub use syntax_pos::*; pub use syntax_pos::hygiene::{ExpnFormat, ExpnInfo, NameAndSpan}; pub use self::ExpnFormat::*; +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::stable_hasher::StableHasher; use std::cell::{RefCell, Ref}; +use std::hash::Hash; use std::path::{Path, PathBuf}; use std::rc::Rc; @@ -98,6 +102,24 @@ impl FileLoader for RealFileLoader { } } +// This is a FileMap identifier that is used to correlate FileMaps between +// subsequent compilation sessions (which is something we need to do during +// incremental compilation). +#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +pub struct StableFilemapId(u128); + +impl StableFilemapId { + pub fn new(filemap: &FileMap) -> StableFilemapId { + let mut hasher = StableHasher::new(); + + filemap.name.hash(&mut hasher); + filemap.name_was_remapped.hash(&mut hasher); + filemap.unmapped_path.hash(&mut hasher); + + StableFilemapId(hasher.finish()) + } +} + // _____________________________________________________________________________ // CodeMap // @@ -108,6 +130,7 @@ pub struct CodeMap { // This is used to apply the file path remapping as specified via // -Zremap-path-prefix to all FileMaps allocated within this CodeMap. path_mapping: FilePathMapping, + stable_id_to_filemap: RefCell<FxHashMap<StableFilemapId, Rc<FileMap>>>, } impl CodeMap { @@ -116,6 +139,7 @@ impl CodeMap { files: RefCell::new(Vec::new()), file_loader: Box::new(RealFileLoader), path_mapping, + stable_id_to_filemap: RefCell::new(FxHashMap()), } } @@ -126,6 +150,7 @@ impl CodeMap { files: RefCell::new(Vec::new()), file_loader, path_mapping, + stable_id_to_filemap: RefCell::new(FxHashMap()), } } @@ -146,6 +171,10 @@ impl CodeMap { self.files.borrow() } + pub fn filemap_by_stable_id(&self, stable_id: StableFilemapId) -> Option<Rc<FileMap>> { + self.stable_id_to_filemap.borrow().get(&stable_id).map(|fm| fm.clone()) + } + fn next_start_pos(&self) -> usize { let files = self.files.borrow(); match files.last() { @@ -180,6 +209,10 @@ impl CodeMap { files.push(filemap.clone()); + self.stable_id_to_filemap + .borrow_mut() + .insert(StableFilemapId::new(&filemap), filemap.clone()); + filemap } @@ -209,7 +242,8 @@ impl CodeMap { src_hash: u128, source_len: usize, mut file_local_lines: Vec<BytePos>, - mut file_local_multibyte_chars: Vec<MultiByteChar>) + mut file_local_multibyte_chars: Vec<MultiByteChar>, + mut file_local_non_narrow_chars: Vec<NonNarrowChar>) -> Rc<FileMap> { let start_pos = self.next_start_pos(); let mut files = self.files.borrow_mut(); @@ -225,6 +259,10 @@ impl CodeMap { mbc.pos = mbc.pos + start_pos; } + for swc in &mut file_local_non_narrow_chars { + *swc = *swc + start_pos; + } + let filemap = Rc::new(FileMap { name: filename, name_was_remapped, @@ -237,10 +275,15 @@ impl CodeMap { end_pos, lines: RefCell::new(file_local_lines), multibyte_chars: RefCell::new(file_local_multibyte_chars), + non_narrow_chars: RefCell::new(file_local_non_narrow_chars), }); files.push(filemap.clone()); + self.stable_id_to_filemap + .borrow_mut() + .insert(StableFilemapId::new(&filemap), filemap.clone()); + filemap } @@ -260,6 +303,24 @@ impl CodeMap { let line = a + 1; // Line numbers start at 1 let linebpos = (*f.lines.borrow())[a]; let linechpos = self.bytepos_to_file_charpos(linebpos); + let col = chpos - linechpos; + + let col_display = { + let non_narrow_chars = f.non_narrow_chars.borrow(); + let start_width_idx = non_narrow_chars + .binary_search_by_key(&linebpos, |x| x.pos()) + .unwrap_or_else(|x| x); + let end_width_idx = non_narrow_chars + .binary_search_by_key(&pos, |x| x.pos()) + .unwrap_or_else(|x| x); + let special_chars = end_width_idx - start_width_idx; + let non_narrow: usize = + non_narrow_chars[start_width_idx..end_width_idx] + .into_iter() + .map(|x| x.width()) + .sum(); + col.0 - special_chars + non_narrow + }; debug!("byte pos {:?} is on the line at byte pos {:?}", pos, linebpos); debug!("char pos {:?} is on the line at char pos {:?}", @@ -269,14 +330,28 @@ impl CodeMap { Loc { file: f, line, - col: chpos - linechpos, + col, + col_display, } } Err(f) => { + let col_display = { + let non_narrow_chars = f.non_narrow_chars.borrow(); + let end_width_idx = non_narrow_chars + .binary_search_by_key(&pos, |x| x.pos()) + .unwrap_or_else(|x| x); + let non_narrow: usize = + non_narrow_chars[0..end_width_idx] + .into_iter() + .map(|x| x.width()) + .sum(); + chpos.0 - end_width_idx + non_narrow + }; Loc { file: f, line: 0, col: chpos, + col_display, } } } diff --git a/src/libsyntax/diagnostics/macros.rs b/src/libsyntax/diagnostics/macros.rs index e8ecf58072a..c01836b6194 100644 --- a/src/libsyntax/diagnostics/macros.rs +++ b/src/libsyntax/diagnostics/macros.rs @@ -18,7 +18,11 @@ macro_rules! register_diagnostic { macro_rules! span_fatal { ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({ __diagnostic_used!($code); - $session.span_fatal_with_code($span, &format!($($message)*), stringify!($code)) + $session.span_fatal_with_code( + $span, + &format!($($message)*), + $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()), + ) }) } @@ -26,7 +30,11 @@ macro_rules! span_fatal { macro_rules! span_err { ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({ __diagnostic_used!($code); - $session.span_err_with_code($span, &format!($($message)*), stringify!($code)) + $session.span_err_with_code( + $span, + &format!($($message)*), + $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()), + ) }) } @@ -34,7 +42,11 @@ macro_rules! span_err { macro_rules! span_warn { ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({ __diagnostic_used!($code); - $session.span_warn_with_code($span, &format!($($message)*), stringify!($code)) + $session.span_warn_with_code( + $span, + &format!($($message)*), + $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()), + ) }) } @@ -42,7 +54,10 @@ macro_rules! span_warn { macro_rules! struct_err { ($session:expr, $code:ident, $($message:tt)*) => ({ __diagnostic_used!($code); - $session.struct_err_with_code(&format!($($message)*), stringify!($code)) + $session.struct_err_with_code( + &format!($($message)*), + $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()), + ) }) } @@ -51,9 +66,17 @@ macro_rules! span_err_or_warn { ($is_warning:expr, $session:expr, $span:expr, $code:ident, $($message:tt)*) => ({ __diagnostic_used!($code); if $is_warning { - $session.span_warn_with_code($span, &format!($($message)*), stringify!($code)) + $session.span_warn_with_code( + $span, + &format!($($message)*), + $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()), + ) } else { - $session.span_err_with_code($span, &format!($($message)*), stringify!($code)) + $session.span_err_with_code( + $span, + &format!($($message)*), + $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()), + ) } }) } @@ -62,7 +85,11 @@ macro_rules! span_err_or_warn { macro_rules! struct_span_fatal { ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({ __diagnostic_used!($code); - $session.struct_span_fatal_with_code($span, &format!($($message)*), stringify!($code)) + $session.struct_span_fatal_with_code( + $span, + &format!($($message)*), + $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()), + ) }) } @@ -70,7 +97,11 @@ macro_rules! struct_span_fatal { macro_rules! struct_span_err { ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({ __diagnostic_used!($code); - $session.struct_span_err_with_code($span, &format!($($message)*), stringify!($code)) + $session.struct_span_err_with_code( + $span, + &format!($($message)*), + $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()), + ) }) } @@ -89,7 +120,11 @@ macro_rules! type_error_struct { macro_rules! struct_span_warn { ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({ __diagnostic_used!($code); - $session.struct_span_warn_with_code($span, &format!($($message)*), stringify!($code)) + $session.struct_span_warn_with_code( + $span, + &format!($($message)*), + $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()), + ) }) } @@ -98,9 +133,17 @@ macro_rules! struct_span_err_or_warn { ($is_warning:expr, $session:expr, $span:expr, $code:ident, $($message:tt)*) => ({ __diagnostic_used!($code); if $is_warning { - $session.struct_span_warn_with_code($span, &format!($($message)*), stringify!($code)) + $session.struct_span_warn_with_code( + $span, + &format!($($message)*), + $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()), + ) } else { - $session.struct_span_err_with_code($span, &format!($($message)*), stringify!($code)) + $session.struct_span_err_with_code( + $span, + &format!($($message)*), + $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()), + ) } }) } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 30451ec757a..a69bf53ee14 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -35,7 +35,6 @@ use visit::{self, FnKind, Visitor}; use parse::ParseSess; use symbol::Symbol; -use std::ascii::AsciiExt; use std::env; macro_rules! set { @@ -386,6 +385,9 @@ declare_features! ( // allow '|' at beginning of match arms (RFC 1925) (active, match_beginning_vert, "1.21.0", Some(44101)), + // Future-proofing enums/structs with #[non_exhaustive] attribute (RFC 2008) + (active, non_exhaustive, "1.22.0", Some(44109)), + // Copy/Clone closures (RFC 2132) (active, clone_closures, "1.22.0", Some(44490)), (active, copy_closures, "1.22.0", Some(44490)), @@ -614,6 +616,12 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG not yet settled", cfg_fn!(structural_match))), + // RFC #2008 + ("non_exhaustive", Whitelisted, Gated(Stability::Unstable, + "non_exhaustive", + "non exhaustive is an experimental feature", + cfg_fn!(non_exhaustive))), + ("plugin", CrateLevel, Gated(Stability::Unstable, "plugin", "compiler plugins are experimental \ @@ -908,6 +916,12 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG "allow_fail attribute is currently unstable", cfg_fn!(allow_fail))), + ("rustc_std_internal_symbol", Whitelisted, Gated(Stability::Unstable, + "rustc_attrs", + "this is an internal attribute that will \ + never be stable", + cfg_fn!(rustc_attrs))), + // Crate level attributes ("crate_name", CrateLevel, Ungated), ("crate_type", CrateLevel, Ungated), @@ -1357,10 +1371,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } - ast::ItemKind::DefaultImpl(..) => { + ast::ItemKind::AutoImpl(..) => { gate_feature_post!(&self, optin_builtin_traits, i.span, - "default trait implementations are experimental \ + "auto trait implementations are experimental \ and possibly buggy"); } @@ -1389,6 +1403,12 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } + ast::ItemKind::Trait(ast::IsAuto::Yes, ..) => { + gate_feature_post!(&self, optin_builtin_traits, + i.span, + "auto traits are experimental and possibly buggy"); + } + ast::ItemKind::MacroDef(ast::MacroDef { legacy: false, .. }) => { let msg = "`macro` is experimental"; gate_feature_post!(&self, decl_macro, i.span, msg); diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index fea49424dc8..cc63bffec48 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -908,8 +908,8 @@ pub fn noop_fold_item_kind<T: Folder>(i: ItemKind, folder: &mut T) -> ItemKind { let generics = folder.fold_generics(generics); ItemKind::Union(folder.fold_variant_data(struct_def), generics) } - ItemKind::DefaultImpl(unsafety, ref trait_ref) => { - ItemKind::DefaultImpl(unsafety, folder.fold_trait_ref((*trait_ref).clone())) + ItemKind::AutoImpl(unsafety, ref trait_ref) => { + ItemKind::AutoImpl(unsafety, folder.fold_trait_ref((*trait_ref).clone())) } ItemKind::Impl(unsafety, polarity, @@ -926,7 +926,8 @@ pub fn noop_fold_item_kind<T: Folder>(i: ItemKind, folder: &mut T) -> ItemKind { folder.fold_ty(ty), impl_items.move_flat_map(|item| folder.fold_impl_item(item)), ), - ItemKind::Trait(unsafety, generics, bounds, items) => ItemKind::Trait( + ItemKind::Trait(is_auto, unsafety, generics, bounds, items) => ItemKind::Trait( + is_auto, unsafety, folder.fold_generics(generics), folder.fold_bounds(bounds), diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs index b8151819bff..74a762f2f62 100644 --- a/src/libsyntax/json.rs +++ b/src/libsyntax/json.rs @@ -23,42 +23,48 @@ use codemap::{CodeMap, FilePathMapping}; use syntax_pos::{self, MacroBacktrace, Span, SpanLabel, MultiSpan}; use errors::registry::Registry; use errors::{DiagnosticBuilder, SubDiagnostic, RenderSpan, CodeSuggestion, CodeMapper}; +use errors::DiagnosticId; use errors::emitter::Emitter; use std::rc::Rc; use std::io::{self, Write}; use std::vec; -use rustc_serialize::json::as_json; +use rustc_serialize::json::{as_json, as_pretty_json}; pub struct JsonEmitter { dst: Box<Write + Send>, registry: Option<Registry>, cm: Rc<CodeMapper + 'static>, + pretty: bool, } impl JsonEmitter { pub fn stderr(registry: Option<Registry>, - code_map: Rc<CodeMap>) -> JsonEmitter { + code_map: Rc<CodeMap>, + pretty: bool) -> JsonEmitter { JsonEmitter { dst: Box::new(io::stderr()), registry, cm: code_map, + pretty, } } - pub fn basic() -> JsonEmitter { + pub fn basic(pretty: bool) -> JsonEmitter { let file_path_mapping = FilePathMapping::empty(); - JsonEmitter::stderr(None, Rc::new(CodeMap::new(file_path_mapping))) + JsonEmitter::stderr(None, Rc::new(CodeMap::new(file_path_mapping)), pretty) } pub fn new(dst: Box<Write + Send>, registry: Option<Registry>, - code_map: Rc<CodeMap>) -> JsonEmitter { + code_map: Rc<CodeMap>, + pretty: bool) -> JsonEmitter { JsonEmitter { dst, registry, cm: code_map, + pretty, } } } @@ -66,7 +72,12 @@ impl JsonEmitter { impl Emitter for JsonEmitter { fn emit(&mut self, db: &DiagnosticBuilder) { let data = Diagnostic::from_diagnostic_builder(db, self); - if let Err(e) = writeln!(&mut self.dst, "{}", as_json(&data)) { + let result = if self.pretty { + writeln!(&mut self.dst, "{}", as_pretty_json(&data)) + } else { + writeln!(&mut self.dst, "{}", as_json(&data)) + }; + if let Err(e) = result { panic!("failed to print diagnostics: {:?}", e); } } @@ -84,9 +95,7 @@ struct Diagnostic { spans: Vec<DiagnosticSpan>, /// Associated diagnostic messages. children: Vec<Diagnostic>, - /// The message as rustc would render it. Currently this is only - /// `Some` for "suggestions", but eventually it will include all - /// snippets. + /// The message as rustc would render it. Currently this is always `None` rendered: Option<String>, } @@ -109,9 +118,7 @@ struct DiagnosticSpan { /// Label that should be placed at this location (if any) label: Option<String>, /// If we are suggesting a replacement, this will contain text - /// that should be sliced in atop this span. You may prefer to - /// load the fully rendered version from the parent `Diagnostic`, - /// however. + /// that should be sliced in atop this span. suggested_replacement: Option<String>, /// Macro invocations that created the code at this span, if any. expansion: Option<Box<DiagnosticSpanMacroExpansion>>, @@ -340,9 +347,12 @@ impl DiagnosticSpanLine { } impl DiagnosticCode { - fn map_opt_string(s: Option<String>, je: &JsonEmitter) -> Option<DiagnosticCode> { + fn map_opt_string(s: Option<DiagnosticId>, je: &JsonEmitter) -> Option<DiagnosticCode> { s.map(|s| { - + let s = match s { + DiagnosticId::Error(s) => s, + DiagnosticId::Lint(s) => s, + }; let explanation = je.registry .as_ref() .and_then(|registry| registry.find_description(&s)); diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index d9c3dbb630d..951163d35fa 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -433,6 +433,7 @@ impl<'a> StringReader<'a> { self.filemap.record_multibyte_char(self.pos, new_ch_len); } } + self.filemap.record_width(self.pos, new_ch); } else { self.ch = None; self.pos = new_pos; diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a3a265450ab..6c6bcb2cc82 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -21,7 +21,7 @@ use ast::EnumDef; use ast::{Expr, ExprKind, RangeLimits}; use ast::{Field, FnDecl}; use ast::{ForeignItem, ForeignItemKind, FunctionRetTy}; -use ast::{Ident, ImplItem, Item, ItemKind}; +use ast::{Ident, ImplItem, IsAuto, Item, ItemKind}; use ast::{Lifetime, LifetimeDef, Lit, LitKind, UintTy}; use ast::Local; use ast::MacStmtStyle; @@ -974,11 +974,12 @@ impl<'a> Parser<'a> { pub fn eat_to_tokens(&mut self, kets: &[&token::Token]) { let handler = self.diagnostic(); - self.parse_seq_to_before_tokens(kets, - SeqSep::none(), - TokenExpectType::Expect, - |p| Ok(p.parse_token_tree()), - |mut e| handler.cancel(&mut e)); + if let Err(ref mut err) = self.parse_seq_to_before_tokens(kets, + SeqSep::none(), + TokenExpectType::Expect, + |p| Ok(p.parse_token_tree())) { + handler.cancel(err); + } } /// Parse a sequence, including the closing delimiter. The function @@ -991,7 +992,7 @@ impl<'a> Parser<'a> { -> PResult<'a, Vec<T>> where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, { - let val = self.parse_seq_to_before_end(ket, sep, f); + let val = self.parse_seq_to_before_end(ket, sep, f)?; self.bump(); Ok(val) } @@ -1003,22 +1004,19 @@ impl<'a> Parser<'a> { ket: &token::Token, sep: SeqSep, f: F) - -> Vec<T> - where F: FnMut(&mut Parser<'a>) -> PResult<'a, T> + -> PResult<'a, Vec<T>> + where F: FnMut(&mut Parser<'a>) -> PResult<'a, T> { - self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f, |mut e| e.emit()) + self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f) } - // `fe` is an error handler. - fn parse_seq_to_before_tokens<T, F, Fe>(&mut self, + fn parse_seq_to_before_tokens<T, F>(&mut self, kets: &[&token::Token], sep: SeqSep, expect: TokenExpectType, - mut f: F, - mut fe: Fe) - -> Vec<T> - where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, - Fe: FnMut(DiagnosticBuilder) + mut f: F) + -> PResult<'a, Vec<T>> + where F: FnMut(&mut Parser<'a>) -> PResult<'a, T> { let mut first: bool = true; let mut v = vec![]; @@ -1031,14 +1029,14 @@ impl<'a> Parser<'a> { if first { first = false; } else { - if let Err(e) = self.expect(t) { - fe(e); + if let Err(mut e) = self.expect(t) { // Attempt to keep parsing if it was a similar separator if let Some(ref tokens) = t.similar_tokens() { if tokens.contains(&self.token) { self.bump(); } } + e.emit(); // Attempt to keep parsing if it was an omitted separator match f(self) { Ok(t) => { @@ -1062,16 +1060,11 @@ impl<'a> Parser<'a> { break; } - match f(self) { - Ok(t) => v.push(t), - Err(e) => { - fe(e); - break; - } - } + let t = f(self)?; + v.push(t); } - v + Ok(v) } /// Parse a sequence, including the closing delimiter. The function @@ -1086,7 +1079,7 @@ impl<'a> Parser<'a> { F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, { self.expect(bra)?; - let result = self.parse_seq_to_before_end(ket, sep, f); + let result = self.parse_seq_to_before_end(ket, sep, f)?; if self.token == *ket { self.bump(); } @@ -1105,7 +1098,7 @@ impl<'a> Parser<'a> { { let lo = self.span; self.expect(bra)?; - let result = self.parse_seq_to_before_end(ket, sep, f); + let result = self.parse_seq_to_before_end(ket, sep, f)?; let hi = self.span; self.bump(); Ok(respan(lo.to(hi), result)) @@ -1551,7 +1544,7 @@ impl<'a> Parser<'a> { }; let span = lo.to(self.prev_span); - let ty = Ty { node: node, span: span, id: ast::DUMMY_NODE_ID }; + let ty = Ty { node, span, id: ast::DUMMY_NODE_ID }; // Try to recover from use of `+` with incorrect priority. self.maybe_recover_from_bad_type_plus(allow_plus, &ty)?; @@ -1868,8 +1861,11 @@ impl<'a> Parser<'a> { self.parse_path(style) } - fn parse_path_segments(&mut self, segments: &mut Vec<PathSegment>, style: PathStyle, - enable_warning: bool) -> PResult<'a, ()> { + fn parse_path_segments(&mut self, + segments: &mut Vec<PathSegment>, + style: PathStyle, + enable_warning: bool) + -> PResult<'a, ()> { loop { segments.push(self.parse_path_segment(style, enable_warning)?); @@ -1914,9 +1910,12 @@ impl<'a> Parser<'a> { } else { // `(T, U) -> R` self.bump(); // `(` - let inputs = self.parse_seq_to_end(&token::CloseDelim(token::Paren), - SeqSep::trailing_allowed(token::Comma), - |p| p.parse_ty())?; + let inputs = self.parse_seq_to_before_tokens( + &[&token::CloseDelim(token::Paren)], + SeqSep::trailing_allowed(token::Comma), + TokenExpectType::Expect, + |p| p.parse_ty())?; + self.bump(); // `)` let output = if self.eat(&token::RArrow) { Some(self.parse_ty_no_plus()?) } else { @@ -3154,7 +3153,13 @@ impl<'a> Parser<'a> { // Parse: `for <src_pat> in <src_expr> <src_loop_block>` let pat = self.parse_pat()?; - self.expect_keyword(keywords::In)?; + if !self.eat_keyword(keywords::In) { + let in_span = self.prev_span.between(self.span); + let mut err = self.sess.span_diagnostic + .struct_span_err(in_span, "missing `in` in `for` loop"); + err.span_suggestion_short(in_span, "try adding `in` here", " in ".into()); + err.emit(); + } let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?; let (iattrs, loop_block) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); @@ -3309,10 +3314,12 @@ impl<'a> Parser<'a> { } /// Parse the RHS of a local variable declaration (e.g. '= 14;') - fn parse_initializer(&mut self) -> PResult<'a, Option<P<Expr>>> { + fn parse_initializer(&mut self, skip_eq: bool) -> PResult<'a, Option<P<Expr>>> { if self.check(&token::Eq) { self.bump(); Ok(Some(self.parse_expr()?)) + } else if skip_eq { + Ok(Some(self.parse_expr()?)) } else { Ok(None) } @@ -3719,12 +3726,56 @@ impl<'a> Parser<'a> { let lo = self.prev_span; let pat = self.parse_pat()?; - let ty = if self.eat(&token::Colon) { - Some(self.parse_ty()?) + let (err, ty) = if self.eat(&token::Colon) { + // Save the state of the parser before parsing type normally, in case there is a `:` + // instead of an `=` typo. + let parser_snapshot_before_type = self.clone(); + let colon_sp = self.prev_span; + match self.parse_ty() { + Ok(ty) => (None, Some(ty)), + Err(mut err) => { + // Rewind to before attempting to parse the type and continue parsing + let parser_snapshot_after_type = self.clone(); + mem::replace(self, parser_snapshot_before_type); + + let snippet = self.sess.codemap().span_to_snippet(pat.span).unwrap(); + err.span_label(pat.span, format!("while parsing the type for `{}`", snippet)); + (Some((parser_snapshot_after_type, colon_sp, err)), None) + } + } } else { - None + (None, None) + }; + let init = match (self.parse_initializer(err.is_some()), err) { + (Ok(init), None) => { // init parsed, ty parsed + init + } + (Ok(init), Some((_, colon_sp, mut err))) => { // init parsed, ty error + // Could parse the type as if it were the initializer, it is likely there was a + // typo in the code: `:` instead of `=`. Add suggestion and emit the error. + err.span_suggestion_short(colon_sp, + "use `=` if you meant to assign", + "=".to_string()); + err.emit(); + // As this was parsed successfuly, continue as if the code has been fixed for the + // rest of the file. It will still fail due to the emitted error, but we avoid + // extra noise. + init + } + (Err(mut init_err), Some((snapshot, _, ty_err))) => { // init error, ty error + init_err.cancel(); + // Couldn't parse the type nor the initializer, only raise the type error and + // return to the parser state before parsing the type as the initializer. + // let x: <parse_error>; + mem::replace(self, snapshot); + return Err(ty_err); + } + (Err(err), None) => { // init error, ty parsed + // Couldn't parse the initializer and we're not attempting to recover a failed + // parse of the type, return the error. + return Err(err); + } }; - let init = self.parse_initializer()?; let hi = if self.token == token::Semi { self.span } else { @@ -3873,6 +3924,16 @@ impl<'a> Parser<'a> { self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident()) } + fn eat_auto_trait(&mut self) -> bool { + if self.token.is_keyword(keywords::Auto) + && self.look_ahead(1, |t| t.is_keyword(keywords::Trait)) + { + self.eat_keyword(keywords::Auto) && self.eat_keyword(keywords::Trait) + } else { + false + } + } + fn is_defaultness(&self) -> bool { // `pub` is included for better error messages self.token.is_keyword(keywords::Default) && @@ -4781,14 +4842,14 @@ impl<'a> Parser<'a> { } else if self.eat(&token::Comma) { let mut fn_inputs = vec![self_arg]; fn_inputs.append(&mut self.parse_seq_to_before_end( - &token::CloseDelim(token::Paren), sep, parse_arg_fn) + &token::CloseDelim(token::Paren), sep, parse_arg_fn)? ); fn_inputs } else { return self.unexpected(); } } else { - self.parse_seq_to_before_end(&token::CloseDelim(token::Paren), sep, parse_arg_fn) + self.parse_seq_to_before_end(&token::CloseDelim(token::Paren), sep, parse_arg_fn)? }; // Parse closing paren and return type. @@ -4811,9 +4872,8 @@ impl<'a> Parser<'a> { &[&token::BinOp(token::Or), &token::OrOr], SeqSep::trailing_allowed(token::Comma), TokenExpectType::NoExpect, - |p| p.parse_fn_block_arg(), - |mut e| e.emit() - ); + |p| p.parse_fn_block_arg() + )?; self.expect_or()?; args } @@ -5051,7 +5111,7 @@ impl<'a> Parser<'a> { } /// Parse trait Foo { ... } - fn parse_item_trait(&mut self, unsafety: Unsafety) -> PResult<'a, ItemInfo> { + fn parse_item_trait(&mut self, is_auto: IsAuto, unsafety: Unsafety) -> PResult<'a, ItemInfo> { let ident = self.parse_ident()?; let mut tps = self.parse_generics()?; @@ -5078,7 +5138,7 @@ impl<'a> Parser<'a> { } } } - Ok((ident, ItemKind::Trait(unsafety, tps, bounds, trait_items), None)) + Ok((ident, ItemKind::Trait(is_auto, unsafety, tps, bounds, trait_items), None)) } /// Parses items implementations variants @@ -5133,19 +5193,19 @@ impl<'a> Parser<'a> { if opt_trait.is_some() && self.eat(&token::DotDot) { if generics.is_parameterized() { - self.span_err(impl_span, "default trait implementations are not \ + self.span_err(impl_span, "auto trait implementations are not \ allowed to have generics"); } if let ast::Defaultness::Default = defaultness { self.span_err(impl_span, "`default impl` is not allowed for \ - default trait implementations"); + auto trait implementations"); } self.expect(&token::OpenDelim(token::Brace))?; self.expect(&token::CloseDelim(token::Brace))?; Ok((keywords::Invalid.ident(), - ItemKind::DefaultImpl(unsafety, opt_trait.unwrap()), None)) + ItemKind::AutoImpl(unsafety, opt_trait.unwrap()), None)) } else { if opt_trait.is_some() { ty = self.parse_ty()?; @@ -5988,13 +6048,19 @@ impl<'a> Parser<'a> { return Ok(Some(item)); } if self.check_keyword(keywords::Unsafe) && - self.look_ahead(1, |t| t.is_keyword(keywords::Trait)) + (self.look_ahead(1, |t| t.is_keyword(keywords::Trait)) || + self.look_ahead(1, |t| t.is_keyword(keywords::Auto))) { // UNSAFE TRAIT ITEM self.expect_keyword(keywords::Unsafe)?; - self.expect_keyword(keywords::Trait)?; + let is_auto = if self.eat_keyword(keywords::Trait) { + IsAuto::No + } else { + self.eat_auto_trait(); + IsAuto::Yes + }; let (ident, item_, extra_attrs) = - self.parse_item_trait(ast::Unsafety::Unsafe)?; + self.parse_item_trait(is_auto, ast::Unsafety::Unsafe)?; let prev_span = self.prev_span; let item = self.mk_item(lo.to(prev_span), ident, @@ -6097,10 +6163,19 @@ impl<'a> Parser<'a> { maybe_append(attrs, extra_attrs)); return Ok(Some(item)); } - if self.eat_keyword(keywords::Trait) { + if self.check_keyword(keywords::Trait) + || (self.check_keyword(keywords::Auto) + && self.look_ahead(1, |t| t.is_keyword(keywords::Trait))) + { + let is_auto = if self.eat_keyword(keywords::Trait) { + IsAuto::No + } else { + self.eat_auto_trait(); + IsAuto::Yes + }; // TRAIT ITEM let (ident, item_, extra_attrs) = - self.parse_item_trait(ast::Unsafety::Normal)?; + self.parse_item_trait(is_auto, ast::Unsafety::Normal)?; let prev_span = self.prev_span; let item = self.mk_item(lo.to(prev_span), ident, diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 8a970fd4098..5cb8e8694cf 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1287,7 +1287,7 @@ impl<'a> State<'a> { self.head(&visibility_qualified(&item.vis, "union"))?; self.print_struct(struct_def, generics, item.ident, item.span, true)?; } - ast::ItemKind::DefaultImpl(unsafety, ref trait_ref) => { + ast::ItemKind::AutoImpl(unsafety, ref trait_ref) => { self.head("")?; self.print_visibility(&item.vis)?; self.print_unsafety(unsafety)?; @@ -1338,10 +1338,11 @@ impl<'a> State<'a> { } self.bclose(item.span)?; } - ast::ItemKind::Trait(unsafety, ref generics, ref bounds, ref trait_items) => { + ast::ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref trait_items) => { self.head("")?; self.print_visibility(&item.vis)?; self.print_unsafety(unsafety)?; + self.print_is_auto(is_auto)?; self.word_nbsp("trait")?; self.print_ident(item.ident)?; self.print_generics(generics)?; @@ -1986,6 +1987,15 @@ impl<'a> State<'a> { Fixity::None => (prec + 1, prec + 1), }; + let left_prec = match (&lhs.node, op.node) { + // These cases need parens: `x as i32 < y` has the parser thinking that `i32 < y` is + // the beginning of a path type. It starts trying to parse `x as (i32 < y ...` instead + // of `(x as i32) < ...`. We need to convince it _not_ to do that. + (&ast::ExprKind::Cast { .. }, ast::BinOpKind::Lt) | + (&ast::ExprKind::Cast { .. }, ast::BinOpKind::Shl) => parser::PREC_FORCE_PAREN, + _ => left_prec, + }; + self.print_expr_maybe_paren(lhs, left_prec)?; self.s.space()?; self.word_space(op.node.to_string())?; @@ -3123,6 +3133,13 @@ impl<'a> State<'a> { ast::Unsafety::Unsafe => self.word_nbsp("unsafe"), } } + + pub fn print_is_auto(&mut self, s: ast::IsAuto) -> io::Result<()> { + match s { + ast::IsAuto::Yes => self.word_nbsp("auto"), + ast::IsAuto::No => Ok(()), + } + } } fn repeat(s: &str, n: usize) -> String { iter::repeat(s).take(n).collect() } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 96e47a6cc0f..c2e90f0bb13 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -281,7 +281,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { visitor.visit_generics(type_parameters); visitor.visit_enum_def(enum_definition, type_parameters, item.id, item.span) } - ItemKind::DefaultImpl(_, ref trait_ref) => { + ItemKind::AutoImpl(_, ref trait_ref) => { visitor.visit_trait_ref(trait_ref) } ItemKind::Impl(_, _, _, @@ -300,7 +300,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { visitor.visit_variant_data(struct_definition, item.ident, generics, item.id, item.span); } - ItemKind::Trait(_, ref generics, ref bounds, ref methods) => { + ItemKind::Trait(.., ref generics, ref bounds, ref methods) => { visitor.visit_generics(generics); walk_list!(visitor, visit_ty_param_bound, bounds); walk_list!(visitor, visit_trait_item, methods); diff --git a/src/libsyntax_pos/Cargo.toml b/src/libsyntax_pos/Cargo.toml index dd8129bab51..aad2155157d 100644 --- a/src/libsyntax_pos/Cargo.toml +++ b/src/libsyntax_pos/Cargo.toml @@ -11,3 +11,4 @@ crate-type = ["dylib"] [dependencies] serialize = { path = "../libserialize" } rustc_data_structures = { path = "../librustc_data_structures" } +unicode-width = "0.1.4" diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 44e73d876e8..47755dc1d54 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -44,6 +44,8 @@ use serialize::{Encodable, Decodable, Encoder, Decoder}; extern crate serialize; extern crate serialize as rustc_serialize; // used by deriving +extern crate unicode_width; + pub mod hygiene; pub use hygiene::{SyntaxContext, ExpnInfo, ExpnFormat, NameAndSpan, CompilerDesugaringKind}; @@ -494,6 +496,63 @@ pub struct MultiByteChar { pub bytes: usize, } +/// Identifies an offset of a non-narrow character in a FileMap +#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Eq, PartialEq)] +pub enum NonNarrowChar { + /// Represents a zero-width character + ZeroWidth(BytePos), + /// Represents a wide (fullwidth) character + Wide(BytePos), +} + +impl NonNarrowChar { + fn new(pos: BytePos, width: usize) -> Self { + match width { + 0 => NonNarrowChar::ZeroWidth(pos), + 2 => NonNarrowChar::Wide(pos), + _ => panic!("width {} given for non-narrow character", width), + } + } + + /// Returns the absolute offset of the character in the CodeMap + pub fn pos(&self) -> BytePos { + match *self { + NonNarrowChar::ZeroWidth(p) | + NonNarrowChar::Wide(p) => p, + } + } + + /// Returns the width of the character, 0 (zero-width) or 2 (wide) + pub fn width(&self) -> usize { + match *self { + NonNarrowChar::ZeroWidth(_) => 0, + NonNarrowChar::Wide(_) => 2, + } + } +} + +impl Add<BytePos> for NonNarrowChar { + type Output = Self; + + fn add(self, rhs: BytePos) -> Self { + match self { + NonNarrowChar::ZeroWidth(pos) => NonNarrowChar::ZeroWidth(pos + rhs), + NonNarrowChar::Wide(pos) => NonNarrowChar::Wide(pos + rhs), + } + } +} + +impl Sub<BytePos> for NonNarrowChar { + type Output = Self; + + fn sub(self, rhs: BytePos) -> Self { + match self { + NonNarrowChar::ZeroWidth(pos) => NonNarrowChar::ZeroWidth(pos - rhs), + NonNarrowChar::Wide(pos) => NonNarrowChar::Wide(pos - rhs), + } + } +} + /// The state of the lazy external source loading mechanism of a FileMap. #[derive(PartialEq, Eq, Clone)] pub enum ExternalSource { @@ -552,11 +611,13 @@ pub struct FileMap { pub lines: RefCell<Vec<BytePos>>, /// Locations of multi-byte characters in the source code pub multibyte_chars: RefCell<Vec<MultiByteChar>>, + /// Width of characters that are not narrow in the source code + pub non_narrow_chars: RefCell<Vec<NonNarrowChar>>, } impl Encodable for FileMap { fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_struct("FileMap", 7, |s| { + s.emit_struct("FileMap", 8, |s| { s.emit_struct_field("name", 0, |s| self.name.encode(s))?; s.emit_struct_field("name_was_remapped", 1, |s| self.name_was_remapped.encode(s))?; s.emit_struct_field("src_hash", 6, |s| self.src_hash.encode(s))?; @@ -610,6 +671,9 @@ impl Encodable for FileMap { })?; s.emit_struct_field("multibyte_chars", 5, |s| { (*self.multibyte_chars.borrow()).encode(s) + })?; + s.emit_struct_field("non_narrow_chars", 7, |s| { + (*self.non_narrow_chars.borrow()).encode(s) }) }) } @@ -618,7 +682,7 @@ impl Encodable for FileMap { impl Decodable for FileMap { fn decode<D: Decoder>(d: &mut D) -> Result<FileMap, D::Error> { - d.read_struct("FileMap", 6, |d| { + d.read_struct("FileMap", 8, |d| { let name: String = d.read_struct_field("name", 0, |d| Decodable::decode(d))?; let name_was_remapped: bool = d.read_struct_field("name_was_remapped", 1, |d| Decodable::decode(d))?; @@ -657,6 +721,8 @@ impl Decodable for FileMap { })?; let multibyte_chars: Vec<MultiByteChar> = d.read_struct_field("multibyte_chars", 5, |d| Decodable::decode(d))?; + let non_narrow_chars: Vec<NonNarrowChar> = + d.read_struct_field("non_narrow_chars", 7, |d| Decodable::decode(d))?; Ok(FileMap { name, name_was_remapped, @@ -671,7 +737,8 @@ impl Decodable for FileMap { src_hash, external_src: RefCell::new(ExternalSource::AbsentOk), lines: RefCell::new(lines), - multibyte_chars: RefCell::new(multibyte_chars) + multibyte_chars: RefCell::new(multibyte_chars), + non_narrow_chars: RefCell::new(non_narrow_chars) }) }) } @@ -709,6 +776,7 @@ impl FileMap { end_pos: Pos::from_usize(end_pos), lines: RefCell::new(Vec::new()), multibyte_chars: RefCell::new(Vec::new()), + non_narrow_chars: RefCell::new(Vec::new()), } } @@ -798,6 +866,23 @@ impl FileMap { self.multibyte_chars.borrow_mut().push(mbc); } + pub fn record_width(&self, pos: BytePos, ch: char) { + let width = match ch { + '\t' | '\n' => + // Tabs will consume one column. + // Make newlines take one column so that displayed spans can point them. + 1, + ch => + // Assume control characters are zero width. + // FIXME: How can we decide between `width` and `width_cjk`? + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(0), + }; + // Only record non-narrow characters. + if width != 1 { + self.non_narrow_chars.borrow_mut().push(NonNarrowChar::new(pos, width)); + } + } + pub fn is_real_file(&self) -> bool { !(self.name.starts_with("<") && self.name.ends_with(">")) @@ -944,7 +1029,9 @@ pub struct Loc { /// The (1-based) line number pub line: usize, /// The (0-based) column offset - pub col: CharPos + pub col: CharPos, + /// The (0-based) column offset when displayed + pub col_display: usize, } /// A source code location used as the result of lookup_char_pos_adj diff --git a/src/libsyntax_pos/span_encoding.rs b/src/libsyntax_pos/span_encoding.rs index c2b32171a9a..b23e40ce7a9 100644 --- a/src/libsyntax_pos/span_encoding.rs +++ b/src/libsyntax_pos/span_encoding.rs @@ -59,9 +59,11 @@ const LEN_INDEX: usize = 1; const CTXT_INDEX: usize = 2; // Tag = 0, inline format. -// ----------------------------------- -// | base 31:8 | len 7:1 | tag 0:0 | -// ----------------------------------- +// ------------------------------------------------------------- +// | base 31:8 | len 7:1 | ctxt (currently 0 bits) | tag 0:0 | +// ------------------------------------------------------------- +// Since there are zero bits for ctxt, only SpanData with a 0 SyntaxContext +// can be inline. const INLINE_SIZES: [u32; 3] = [24, 7, 0]; const INLINE_OFFSETS: [u32; 3] = [8, 1, 1]; diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 872fc031cfb..26e6f27e20f 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -309,11 +309,12 @@ declare_keywords! { (54, Yield, "yield") // Weak keywords, have special meaning only in specific contexts. - (55, Catch, "catch") - (56, Default, "default") - (57, Dyn, "dyn") - (58, StaticLifetime, "'static") - (59, Union, "union") + (55, Auto, "auto") + (56, Catch, "catch") + (57, Default, "default") + (58, Dyn, "dyn") + (59, StaticLifetime, "'static") + (60, Union, "union") } // If an interner exists in TLS, return it. Otherwise, prepare a fresh one. diff --git a/src/rtstartup/rsbegin.rs b/src/rtstartup/rsbegin.rs index 8733c7436d5..d33b5248629 100644 --- a/src/rtstartup/rsbegin.rs +++ b/src/rtstartup/rsbegin.rs @@ -14,7 +14,7 @@ // When an executable or dylib image is linked, all user code and libraries are // "sandwiched" between these two object files, so code or data from rsbegin.o // become first in the respective sections of the image, whereas code and data -// from rsend.o become the last ones. This effect can be used to place symbols +// from rsend.o become the last ones. This effect can be used to place symbols // at the beginning or at the end of a section, as well as to insert any required // headers or footers. // @@ -31,11 +31,15 @@ trait Sized {} #[lang = "sync"] trait Sync {} +#[allow(unknown_lints)] +#[allow(auto_impl)] impl Sync for .. {} #[lang = "copy"] trait Copy {} #[lang = "freeze"] trait Freeze {} +#[allow(unknown_lints)] +#[allow(auto_impl)] impl Freeze for .. {} #[lang = "drop_in_place"] diff --git a/src/rtstartup/rsend.rs b/src/rtstartup/rsend.rs index a6aed3540dd..410366d0d7f 100644 --- a/src/rtstartup/rsend.rs +++ b/src/rtstartup/rsend.rs @@ -23,6 +23,8 @@ impl<T> Sync for T {} trait Copy {} #[lang = "freeze"] trait Freeze {} +#[allow(unknown_lints)] +#[allow(auto_impl)] impl Freeze for .. {} #[lang = "drop_in_place"] diff --git a/src/test/codegen-units/item-collection/unreferenced-const-fn.rs b/src/test/codegen-units/item-collection/unreferenced-const-fn.rs new file mode 100644 index 00000000000..59b25d8beca --- /dev/null +++ b/src/test/codegen-units/item-collection/unreferenced-const-fn.rs @@ -0,0 +1,22 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-tidy-linelength +// compile-flags:-Zprint-trans-items=lazy + +// NB: We do not expect *any* translation item to be generated here. + +#![feature(const_fn)] +#![deny(dead_code)] +#![crate_type = "rlib"] + +pub const fn foo(x: u32) -> u32 { + x + 0xf00 +} diff --git a/src/test/codegen-units/item-collection/unreferenced-inline-function.rs b/src/test/codegen-units/item-collection/unreferenced-inline-function.rs new file mode 100644 index 00000000000..75d41a38012 --- /dev/null +++ b/src/test/codegen-units/item-collection/unreferenced-inline-function.rs @@ -0,0 +1,23 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-tidy-linelength +// compile-flags:-Zprint-trans-items=lazy + +// NB: We do not expect *any* translation item to be generated here. + +#![deny(dead_code)] +#![crate_type = "rlib"] + +#[inline] +pub fn foo() -> bool { + [1, 2] == [3, 4] +} + diff --git a/src/test/codegen-units/partitioning/extern-drop-glue.rs b/src/test/codegen-units/partitioning/extern-drop-glue.rs index 29528644ed0..da96c5e183d 100644 --- a/src/test/codegen-units/partitioning/extern-drop-glue.rs +++ b/src/test/codegen-units/partitioning/extern-drop-glue.rs @@ -16,7 +16,7 @@ // compile-flags:-Zinline-in-all-cgus #![allow(dead_code)] -#![crate_type="lib"] +#![crate_type="rlib"] // aux-build:cgu_extern_drop_glue.rs extern crate cgu_extern_drop_glue; @@ -25,20 +25,20 @@ extern crate cgu_extern_drop_glue; struct LocalStruct(cgu_extern_drop_glue::Struct); -//~ TRANS_ITEM fn extern_drop_glue::user[0] @@ extern_drop_glue[Internal] -fn user() +//~ TRANS_ITEM fn extern_drop_glue::user[0] @@ extern_drop_glue[External] +pub fn user() { //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<extern_drop_glue::LocalStruct[0]> @@ extern_drop_glue[Internal] let _ = LocalStruct(cgu_extern_drop_glue::Struct(0)); } -mod mod1 { +pub mod mod1 { use cgu_extern_drop_glue; struct LocalStruct(cgu_extern_drop_glue::Struct); - //~ TRANS_ITEM fn extern_drop_glue::mod1[0]::user[0] @@ extern_drop_glue-mod1[Internal] - fn user() + //~ TRANS_ITEM fn extern_drop_glue::mod1[0]::user[0] @@ extern_drop_glue-mod1[External] + pub fn user() { //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<extern_drop_glue::mod1[0]::LocalStruct[0]> @@ extern_drop_glue-mod1[Internal] let _ = LocalStruct(cgu_extern_drop_glue::Struct(0)); diff --git a/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs b/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs index 4bfd35b59bc..01600c03ba2 100644 --- a/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs +++ b/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs @@ -35,10 +35,10 @@ pub fn user() cgu_explicit_inlining::never_inlined(); } -mod mod1 { +pub mod mod1 { use cgu_explicit_inlining; - //~ TRANS_ITEM fn inlining_from_extern_crate::mod1[0]::user[0] @@ inlining_from_extern_crate-mod1[Internal] + //~ TRANS_ITEM fn inlining_from_extern_crate::mod1[0]::user[0] @@ inlining_from_extern_crate-mod1[External] pub fn user() { cgu_explicit_inlining::inlined(); @@ -48,10 +48,10 @@ mod mod1 { } } -mod mod2 { +pub mod mod2 { use cgu_explicit_inlining; - //~ TRANS_ITEM fn inlining_from_extern_crate::mod2[0]::user[0] @@ inlining_from_extern_crate-mod2[Internal] + //~ TRANS_ITEM fn inlining_from_extern_crate::mod2[0]::user[0] @@ inlining_from_extern_crate-mod2[External] pub fn user() { cgu_explicit_inlining::always_inlined(); diff --git a/src/test/codegen-units/partitioning/local-drop-glue.rs b/src/test/codegen-units/partitioning/local-drop-glue.rs index 65e91343ccf..f7c05285ed6 100644 --- a/src/test/codegen-units/partitioning/local-drop-glue.rs +++ b/src/test/codegen-units/partitioning/local-drop-glue.rs @@ -15,7 +15,7 @@ // compile-flags:-Zinline-in-all-cgus #![allow(dead_code)] -#![crate_type="lib"] +#![crate_type="rlib"] //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<local_drop_glue::Struct[0]> @@ local_drop_glue[Internal] local_drop_glue-mod1[Internal] struct Struct { @@ -32,8 +32,8 @@ struct Outer { _a: Struct } -//~ TRANS_ITEM fn local_drop_glue::user[0] @@ local_drop_glue[Internal] -fn user() +//~ TRANS_ITEM fn local_drop_glue::user[0] @@ local_drop_glue[External] +pub fn user() { let _ = Outer { _a: Struct { @@ -42,7 +42,7 @@ fn user() }; } -mod mod1 +pub mod mod1 { use super::Struct; @@ -53,8 +53,8 @@ mod mod1 _b: (u32, Struct), } - //~ TRANS_ITEM fn local_drop_glue::mod1[0]::user[0] @@ local_drop_glue-mod1[Internal] - fn user() + //~ TRANS_ITEM fn local_drop_glue::mod1[0]::user[0] @@ local_drop_glue-mod1[External] + pub fn user() { let _ = Struct2 { _a: Struct { _a: 0 }, diff --git a/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs b/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs index 84464a627be..cf197301eec 100644 --- a/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs +++ b/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs @@ -27,28 +27,28 @@ mod inline { } } -mod user1 { +pub mod user1 { use super::inline; - //~ TRANS_ITEM fn local_inlining_but_not_all::user1[0]::foo[0] @@ local_inlining_but_not_all-user1[Internal] - fn foo() { + //~ TRANS_ITEM fn local_inlining_but_not_all::user1[0]::foo[0] @@ local_inlining_but_not_all-user1[External] + pub fn foo() { inline::inlined_function(); } } -mod user2 { +pub mod user2 { use super::inline; - //~ TRANS_ITEM fn local_inlining_but_not_all::user2[0]::bar[0] @@ local_inlining_but_not_all-user2[Internal] - fn bar() { + //~ TRANS_ITEM fn local_inlining_but_not_all::user2[0]::bar[0] @@ local_inlining_but_not_all-user2[External] + pub fn bar() { inline::inlined_function(); } } -mod non_user { +pub mod non_user { - //~ TRANS_ITEM fn local_inlining_but_not_all::non_user[0]::baz[0] @@ local_inlining_but_not_all-non_user[Internal] - fn baz() { + //~ TRANS_ITEM fn local_inlining_but_not_all::non_user[0]::baz[0] @@ local_inlining_but_not_all-non_user[External] + pub fn baz() { } } diff --git a/src/test/codegen-units/partitioning/local-inlining.rs b/src/test/codegen-units/partitioning/local-inlining.rs index f3176191241..3502aa59fdc 100644 --- a/src/test/codegen-units/partitioning/local-inlining.rs +++ b/src/test/codegen-units/partitioning/local-inlining.rs @@ -28,28 +28,28 @@ mod inline { } } -mod user1 { +pub mod user1 { use super::inline; - //~ TRANS_ITEM fn local_inlining::user1[0]::foo[0] @@ local_inlining-user1[Internal] - fn foo() { + //~ TRANS_ITEM fn local_inlining::user1[0]::foo[0] @@ local_inlining-user1[External] + pub fn foo() { inline::inlined_function(); } } -mod user2 { +pub mod user2 { use super::inline; - //~ TRANS_ITEM fn local_inlining::user2[0]::bar[0] @@ local_inlining-user2[Internal] - fn bar() { + //~ TRANS_ITEM fn local_inlining::user2[0]::bar[0] @@ local_inlining-user2[External] + pub fn bar() { inline::inlined_function(); } } -mod non_user { +pub mod non_user { - //~ TRANS_ITEM fn local_inlining::non_user[0]::baz[0] @@ local_inlining-non_user[Internal] - fn baz() { + //~ TRANS_ITEM fn local_inlining::non_user[0]::baz[0] @@ local_inlining-non_user[External] + pub fn baz() { } } diff --git a/src/test/codegen-units/partitioning/local-transitive-inlining.rs b/src/test/codegen-units/partitioning/local-transitive-inlining.rs index bda76a8789f..ed883954f3f 100644 --- a/src/test/codegen-units/partitioning/local-transitive-inlining.rs +++ b/src/test/codegen-units/partitioning/local-transitive-inlining.rs @@ -15,7 +15,7 @@ // compile-flags:-Zinline-in-all-cgus #![allow(dead_code)] -#![crate_type="lib"] +#![crate_type="rlib"] mod inline { @@ -37,19 +37,19 @@ mod direct_user { } } -mod indirect_user { +pub mod indirect_user { use super::direct_user; - //~ TRANS_ITEM fn local_transitive_inlining::indirect_user[0]::bar[0] @@ local_transitive_inlining-indirect_user[Internal] - fn bar() { + //~ TRANS_ITEM fn local_transitive_inlining::indirect_user[0]::bar[0] @@ local_transitive_inlining-indirect_user[External] + pub fn bar() { direct_user::foo(); } } -mod non_user { +pub mod non_user { - //~ TRANS_ITEM fn local_transitive_inlining::non_user[0]::baz[0] @@ local_transitive_inlining-non_user[Internal] - fn baz() { + //~ TRANS_ITEM fn local_transitive_inlining::non_user[0]::baz[0] @@ local_transitive_inlining-non_user[External] + pub fn baz() { } } diff --git a/src/test/codegen-units/partitioning/statics.rs b/src/test/codegen-units/partitioning/statics.rs index 8cbce12b52c..12ef34441ff 100644 --- a/src/test/codegen-units/partitioning/statics.rs +++ b/src/test/codegen-units/partitioning/statics.rs @@ -13,7 +13,7 @@ // incremental compilation // compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp/partitioning-tests/statics -#![crate_type="lib"] +#![crate_type="rlib"] //~ TRANS_ITEM static statics::FOO[0] @@ statics[Internal] static FOO: u32 = 0; @@ -21,8 +21,8 @@ static FOO: u32 = 0; //~ TRANS_ITEM static statics::BAR[0] @@ statics[Internal] static BAR: u32 = 0; -//~ TRANS_ITEM fn statics::function[0] @@ statics[Internal] -fn function() { +//~ TRANS_ITEM fn statics::function[0] @@ statics[External] +pub fn function() { //~ TRANS_ITEM static statics::function[0]::FOO[0] @@ statics[Internal] static FOO: u32 = 0; @@ -30,15 +30,15 @@ fn function() { static BAR: u32 = 0; } -mod mod1 { +pub mod mod1 { //~ TRANS_ITEM static statics::mod1[0]::FOO[0] @@ statics-mod1[Internal] static FOO: u32 = 0; //~ TRANS_ITEM static statics::mod1[0]::BAR[0] @@ statics-mod1[Internal] static BAR: u32 = 0; - //~ TRANS_ITEM fn statics::mod1[0]::function[0] @@ statics-mod1[Internal] - fn function() { + //~ TRANS_ITEM fn statics::mod1[0]::function[0] @@ statics-mod1[External] + pub fn function() { //~ TRANS_ITEM static statics::mod1[0]::function[0]::FOO[0] @@ statics-mod1[Internal] static FOO: u32 = 0; diff --git a/src/test/codegen/adjustments.rs b/src/test/codegen/adjustments.rs index bd85e303143..342a4f0d085 100644 --- a/src/test/codegen/adjustments.rs +++ b/src/test/codegen/adjustments.rs @@ -15,7 +15,7 @@ // Hack to get the correct size for the length part in slices // CHECK: @helper([[USIZE:i[0-9]+]] %arg0) #[no_mangle] -fn helper(_: usize) { +pub fn helper(_: usize) { } // CHECK-LABEL: @no_op_slice_adjustment diff --git a/src/test/codegen/fastcall-inreg.rs b/src/test/codegen/fastcall-inreg.rs index cc13d4a7b68..346c5da8d1b 100644 --- a/src/test/codegen/fastcall-inreg.rs +++ b/src/test/codegen/fastcall-inreg.rs @@ -59,28 +59,28 @@ #![crate_type = "lib"] -mod tests { +pub mod tests { // CHECK: @f1(i32 inreg %arg0, i32 inreg %arg1, i32 %arg2) #[no_mangle] - extern "fastcall" fn f1(_: i32, _: i32, _: i32) {} + pub extern "fastcall" fn f1(_: i32, _: i32, _: i32) {} // CHECK: @f2(i32* inreg %arg0, i32* inreg %arg1, i32* %arg2) #[no_mangle] - extern "fastcall" fn f2(_: *const i32, _: *const i32, _: *const i32) {} + pub extern "fastcall" fn f2(_: *const i32, _: *const i32, _: *const i32) {} // CHECK: @f3(float %arg0, i32 inreg %arg1, i32 inreg %arg2, i32 %arg3) #[no_mangle] - extern "fastcall" fn f3(_: f32, _: i32, _: i32, _: i32) {} + pub extern "fastcall" fn f3(_: f32, _: i32, _: i32, _: i32) {} // CHECK: @f4(i32 inreg %arg0, float %arg1, i32 inreg %arg2, i32 %arg3) #[no_mangle] - extern "fastcall" fn f4(_: i32, _: f32, _: i32, _: i32) {} + pub extern "fastcall" fn f4(_: i32, _: f32, _: i32, _: i32) {} // CHECK: @f5(i64 %arg0, i32 %arg1) #[no_mangle] - extern "fastcall" fn f5(_: i64, _: i32) {} + pub extern "fastcall" fn f5(_: i64, _: i32) {} // CHECK: @f6(i1 inreg zeroext %arg0, i32 inreg %arg1, i32 %arg2) #[no_mangle] - extern "fastcall" fn f6(_: bool, _: i32, _: i32) {} + pub extern "fastcall" fn f6(_: bool, _: i32, _: i32) {} } diff --git a/src/test/codegen/function-arguments.rs b/src/test/codegen/function-arguments.rs index d4c7fe9e80a..29e2840c881 100644 --- a/src/test/codegen/function-arguments.rs +++ b/src/test/codegen/function-arguments.rs @@ -93,20 +93,20 @@ pub fn struct_return() -> S { // Hack to get the correct size for the length part in slices // CHECK: @helper([[USIZE:i[0-9]+]] %arg0) #[no_mangle] -fn helper(_: usize) { +pub fn helper(_: usize) { } // CHECK: @slice(i8* noalias nonnull readonly %arg0.ptr, [[USIZE]] %arg0.meta) // FIXME #25759 This should also have `nocapture` #[no_mangle] -fn slice(_: &[u8]) { +pub fn slice(_: &[u8]) { } // CHECK: @mutable_slice(i8* nonnull %arg0.ptr, [[USIZE]] %arg0.meta) // FIXME #25759 This should also have `nocapture` // ... there's this LLVM bug that forces us to not use noalias, see #29485 #[no_mangle] -fn mutable_slice(_: &mut [u8]) { +pub fn mutable_slice(_: &mut [u8]) { } // CHECK: @unsafe_slice(%UnsafeInner* nonnull %arg0.ptr, [[USIZE]] %arg0.meta) @@ -118,23 +118,23 @@ pub fn unsafe_slice(_: &[UnsafeInner]) { // CHECK: @str(i8* noalias nonnull readonly %arg0.ptr, [[USIZE]] %arg0.meta) // FIXME #25759 This should also have `nocapture` #[no_mangle] -fn str(_: &[u8]) { +pub fn str(_: &[u8]) { } // CHECK: @trait_borrow({}* nonnull, {}* noalias nonnull readonly) // FIXME #25759 This should also have `nocapture` #[no_mangle] -fn trait_borrow(_: &Drop) { +pub fn trait_borrow(_: &Drop) { } // CHECK: @trait_box({}* noalias nonnull, {}* noalias nonnull readonly) #[no_mangle] -fn trait_box(_: Box<Drop>) { +pub fn trait_box(_: Box<Drop>) { } // CHECK: { i16*, [[USIZE]] } @return_slice(i16* noalias nonnull readonly %x.ptr, [[USIZE]] %x.meta) #[no_mangle] -fn return_slice(x: &[u16]) -> &[u16] { +pub fn return_slice(x: &[u16]) -> &[u16] { x } diff --git a/src/test/codegen/mir_zst_stores.rs b/src/test/codegen/mir_zst_stores.rs index 36602196cef..884cf59c1c1 100644 --- a/src/test/codegen/mir_zst_stores.rs +++ b/src/test/codegen/mir_zst_stores.rs @@ -19,7 +19,7 @@ struct Zst { phantom: PhantomData<Zst> } // CHECK-LABEL: @mir // CHECK-NOT: store{{.*}}undef #[no_mangle] -fn mir() { +pub fn mir() { let x = Zst { phantom: PhantomData }; let y = (x, 0); drop(y); diff --git a/src/test/codegen/naked-functions.rs b/src/test/codegen/naked-functions.rs index 9883ca6b35d..aab5f1bfb4f 100644 --- a/src/test/codegen/naked-functions.rs +++ b/src/test/codegen/naked-functions.rs @@ -16,10 +16,10 @@ #![feature(naked_functions)] // CHECK: Function Attrs: naked uwtable -// CHECK-NEXT: define internal void @naked_empty() +// CHECK-NEXT: define void @naked_empty() #[no_mangle] #[naked] -fn naked_empty() { +pub fn naked_empty() { // CHECK-NEXT: {{.+}}: // CHECK-NEXT: ret void } @@ -27,8 +27,8 @@ fn naked_empty() { // CHECK: Function Attrs: naked uwtable #[no_mangle] #[naked] -// CHECK-NEXT: define internal void @naked_with_args(i{{[0-9]+}}) -fn naked_with_args(a: isize) { +// CHECK-NEXT: define void @naked_with_args(i{{[0-9]+}}) +pub fn naked_with_args(a: isize) { // CHECK-NEXT: {{.+}}: // CHECK-NEXT: %a = alloca i{{[0-9]+}} &a; // keep variable in an alloca @@ -36,20 +36,20 @@ fn naked_with_args(a: isize) { } // CHECK: Function Attrs: naked uwtable -// CHECK-NEXT: define internal i{{[0-9]+}} @naked_with_return() +// CHECK-NEXT: define i{{[0-9]+}} @naked_with_return() #[no_mangle] #[naked] -fn naked_with_return() -> isize { +pub fn naked_with_return() -> isize { // CHECK-NEXT: {{.+}}: // CHECK-NEXT: ret i{{[0-9]+}} 0 0 } // CHECK: Function Attrs: naked uwtable -// CHECK-NEXT: define internal i{{[0-9]+}} @naked_with_args_and_return(i{{[0-9]+}}) +// CHECK-NEXT: define i{{[0-9]+}} @naked_with_args_and_return(i{{[0-9]+}}) #[no_mangle] #[naked] -fn naked_with_args_and_return(a: isize) -> isize { +pub fn naked_with_args_and_return(a: isize) -> isize { // CHECK-NEXT: {{.+}}: // CHECK-NEXT: %a = alloca i{{[0-9]+}} &a; // keep variable in an alloca @@ -58,10 +58,10 @@ fn naked_with_args_and_return(a: isize) -> isize { } // CHECK: Function Attrs: naked uwtable -// CHECK-NEXT: define internal void @naked_recursive() +// CHECK-NEXT: define void @naked_recursive() #[no_mangle] #[naked] -fn naked_recursive() { +pub fn naked_recursive() { // CHECK-NEXT: {{.+}}: // CHECK-NEXT: call void @naked_empty() diff --git a/src/test/codegen/refs.rs b/src/test/codegen/refs.rs index fd1a14020d8..4b713e28b05 100644 --- a/src/test/codegen/refs.rs +++ b/src/test/codegen/refs.rs @@ -15,7 +15,7 @@ // Hack to get the correct size for the length part in slices // CHECK: @helper([[USIZE:i[0-9]+]] %arg0) #[no_mangle] -fn helper(_: usize) { +pub fn helper(_: usize) { } // CHECK-LABEL: @ref_dst diff --git a/src/test/codegen/unchecked-float-casts.rs b/src/test/codegen/unchecked-float-casts.rs new file mode 100644 index 00000000000..64ab19cceee --- /dev/null +++ b/src/test/codegen/unchecked-float-casts.rs @@ -0,0 +1,65 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -C no-prepopulate-passes + +// This file tests that we don't generate any code for saturation if +// -Z saturating-float-casts is not enabled. + +#![crate_type = "lib"] +#![feature(i128_type)] + +// CHECK-LABEL: @f32_to_u32 +#[no_mangle] +pub fn f32_to_u32(x: f32) -> u32 { + // CHECK: fptoui + // CHECK-NOT: fcmp + // CHECK-NOT: icmp + // CHECK-NOT: select + x as u32 +} + +// CHECK-LABEL: @f32_to_i32 +#[no_mangle] +pub fn f32_to_i32(x: f32) -> i32 { + // CHECK: fptosi + // CHECK-NOT: fcmp + // CHECK-NOT: icmp + // CHECK-NOT: select + x as i32 +} + +#[no_mangle] +pub fn f64_to_u8(x: f32) -> u16 { + // CHECK-NOT: fcmp + // CHECK-NOT: icmp + // CHECK-NOT: select + x as u16 +} + +// CHECK-LABEL: @i32_to_f64 +#[no_mangle] +pub fn i32_to_f64(x: i32) -> f64 { + // CHECK: sitofp + // CHECK-NOT: fcmp + // CHECK-NOT: icmp + // CHECK-NOT: select + x as f64 +} + +// CHECK-LABEL: @u128_to_f32 +#[no_mangle] +pub fn u128_to_f32(x: u128) -> f32 { + // CHECK: uitofp + // CHECK-NOT: fcmp + // CHECK-NOT: icmp + // CHECK-NOT: select + x as f32 +} diff --git a/src/test/compile-fail/E0029.rs b/src/test/compile-fail/E0029.rs index ec84e2a3f8a..e43290bb154 100644 --- a/src/test/compile-fail/E0029.rs +++ b/src/test/compile-fail/E0029.rs @@ -17,6 +17,7 @@ fn main() { //~| NOTE ranges require char or numeric types //~| NOTE start type: &'static str //~| NOTE end type: &'static str + //~| ERROR non-reference pattern used to match a reference _ => {} } } diff --git a/src/test/compile-fail/E0534.rs b/src/test/compile-fail/E0534.rs index 8c036e6076d..fc465b26869 100644 --- a/src/test/compile-fail/E0534.rs +++ b/src/test/compile-fail/E0534.rs @@ -11,4 +11,6 @@ #[inline()] //~ ERROR E0534 pub fn something() {} -fn main() {} +fn main() { + something(); +} diff --git a/src/test/compile-fail/auto-impl-future-compat.rs b/src/test/compile-fail/auto-impl-future-compat.rs new file mode 100644 index 00000000000..5c32a756398 --- /dev/null +++ b/src/test/compile-fail/auto-impl-future-compat.rs @@ -0,0 +1,16 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(optin_builtin_traits)] + +trait Foo {} +impl Foo for .. {} +//~^ ERROR The form `impl Foo for .. {}` will be removed, please use `auto trait Foo {}` +//~^^ WARN this was previously accepted by the compiler diff --git a/src/test/compile-fail/auto-trait-validation.rs b/src/test/compile-fail/auto-trait-validation.rs new file mode 100644 index 00000000000..b28b776d9c2 --- /dev/null +++ b/src/test/compile-fail/auto-trait-validation.rs @@ -0,0 +1,22 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(optin_builtin_traits)] + +auto trait Generic<T> {} +//~^ ERROR auto traits cannot have generics +//~^^ traits with auto impls (`e.g. impl Trait for ..`) can not have type parameters +auto trait Bound : Copy {} +//~^ ERROR auto traits cannot have super traits +//~^^ traits with auto impls (`e.g. impl Trait for ..`) cannot have predicates +auto trait MyTrait { fn foo() {} } +//~^ ERROR auto traits cannot contain items +//~^^ traits with default impls (`e.g. impl Trait for ..`) must have no methods or associated items +fn main() {} diff --git a/src/test/compile-fail/auxiliary/tdticc_coherence_lib.rs b/src/test/compile-fail/auxiliary/tdticc_coherence_lib.rs index 2e425ac96c5..1e1c55de87e 100644 --- a/src/test/compile-fail/auxiliary/tdticc_coherence_lib.rs +++ b/src/test/compile-fail/auxiliary/tdticc_coherence_lib.rs @@ -12,6 +12,7 @@ #![crate_type = "rlib"] pub trait DefaultedTrait { } +#[allow(auto_impl)] impl DefaultedTrait for .. { } pub struct Something<T> { t: T } diff --git a/src/test/compile-fail/bad-intrinsic-monomorphization.rs b/src/test/compile-fail/bad-intrinsic-monomorphization.rs index cfb64f80767..2fe94d43acd 100644 --- a/src/test/compile-fail/bad-intrinsic-monomorphization.rs +++ b/src/test/compile-fail/bad-intrinsic-monomorphization.rs @@ -10,6 +10,7 @@ #![feature(repr_simd, platform_intrinsics, core_intrinsics)] #![allow(warnings)] +#![crate_type = "rlib"] // Bad monomorphizations could previously cause LLVM asserts even though the // error was caught in the compiler. @@ -21,21 +22,19 @@ extern "platform-intrinsic" { use std::intrinsics; #[derive(Copy, Clone)] -struct Foo(i64); +pub struct Foo(i64); -unsafe fn test_cttz(v: Foo) -> Foo { +pub unsafe fn test_cttz(v: Foo) -> Foo { intrinsics::cttz(v) //~^ ERROR `cttz` intrinsic: expected basic integer type, found `Foo` } -unsafe fn test_fadd_fast(a: Foo, b: Foo) -> Foo { +pub unsafe fn test_fadd_fast(a: Foo, b: Foo) -> Foo { intrinsics::fadd_fast(a, b) //~^ ERROR `fadd_fast` intrinsic: expected basic float type, found `Foo` } -unsafe fn test_simd_add(a: Foo, b: Foo) -> Foo { +pub unsafe fn test_simd_add(a: Foo, b: Foo) -> Foo { simd_add(a, b) //~^ ERROR `simd_add` intrinsic: expected SIMD input type, found non-SIMD `Foo` } - -fn main() {} diff --git a/src/test/compile-fail/borrowck/borrowck-drop-from-guard.rs b/src/test/compile-fail/borrowck/borrowck-drop-from-guard.rs new file mode 100644 index 00000000000..8bab6e8dfce --- /dev/null +++ b/src/test/compile-fail/borrowck/borrowck-drop-from-guard.rs @@ -0,0 +1,24 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +//compile-flags: -Z emit-end-regions -Z borrowck-mir + +fn foo(_:String) {} + +fn main() +{ + let my_str = "hello".to_owned(); + match Some(42) { + Some(_) if { drop(my_str); false } => {} + Some(_) => {} + None => { foo(my_str); } //~ ERROR (Mir) [E0381] + } +} diff --git a/src/test/compile-fail/borrowck/borrowck-match-already-borrowed.rs b/src/test/compile-fail/borrowck/borrowck-match-already-borrowed.rs index 1d21f40fcca..5f236014457 100644 --- a/src/test/compile-fail/borrowck/borrowck-match-already-borrowed.rs +++ b/src/test/compile-fail/borrowck/borrowck-match-already-borrowed.rs @@ -11,6 +11,24 @@ // revisions: ast mir //[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir +enum Foo { + A(i32), + B +} + +fn match_enum() { + let mut foo = Foo::B; + let p = &mut foo; + let _ = match foo { + Foo::B => 1, //[mir]~ ERROR (Mir) [E0503] + _ => 2, + Foo::A(x) => x //[ast]~ ERROR [E0503] + //[mir]~^ ERROR (Ast) [E0503] + //[mir]~| ERROR (Mir) [E0503] + }; +} + + fn main() { let mut x = 1; let _x = &mut x; diff --git a/src/test/compile-fail/closure-expected-type/README.md b/src/test/compile-fail/closure-expected-type/README.md new file mode 100644 index 00000000000..9995b00a9a7 --- /dev/null +++ b/src/test/compile-fail/closure-expected-type/README.md @@ -0,0 +1 @@ +See `src/test/run-pass/closure-expected-type`. diff --git a/src/test/compile-fail/closure-expected-type/expect-fn-supply-fn-multiple.rs b/src/test/compile-fail/closure-expected-type/expect-fn-supply-fn-multiple.rs new file mode 100644 index 00000000000..f1b198a0591 --- /dev/null +++ b/src/test/compile-fail/closure-expected-type/expect-fn-supply-fn-multiple.rs @@ -0,0 +1,49 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// must-compile-successfully + +#![feature(underscore_lifetimes)] +#![allow(warnings)] + +type Different<'a, 'b> = &'a mut (&'a (), &'b ()); +type Same<'a> = Different<'a, 'a>; + +fn with_closure_expecting_different<F>(_: F) + where F: for<'a, 'b> FnOnce(Different<'a, 'b>) +{ +} + +fn with_closure_expecting_different_anon<F>(_: F) + where F: FnOnce(Different<'_, '_>) +{ +} + +fn supplying_nothing_expecting_anon() { + with_closure_expecting_different_anon(|x: Different| { + }) +} + +fn supplying_nothing_expecting_named() { + with_closure_expecting_different(|x: Different| { + }) +} + +fn supplying_underscore_expecting_anon() { + with_closure_expecting_different_anon(|x: Different<'_, '_>| { + }) +} + +fn supplying_underscore_expecting_named() { + with_closure_expecting_different(|x: Different<'_, '_>| { + }) +} + +fn main() { } diff --git a/src/test/compile-fail/closure-expected-type/expect-fn-supply-fn.rs b/src/test/compile-fail/closure-expected-type/expect-fn-supply-fn.rs new file mode 100644 index 00000000000..645fd1f80ba --- /dev/null +++ b/src/test/compile-fail/closure-expected-type/expect-fn-supply-fn.rs @@ -0,0 +1,70 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(underscore_lifetimes)] + +fn with_closure_expecting_fn_with_free_region<F>(_: F) + where F: for<'a> FnOnce(fn(&'a u32), &i32) +{ +} + +fn with_closure_expecting_fn_with_bound_region<F>(_: F) + where F: FnOnce(fn(&u32), &i32) +{ +} + +fn expect_free_supply_free_from_fn<'x>(x: &'x u32) { + // Here, the type given for `'x` "obscures" a region from the + // expected signature that is bound at closure level. + with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {}); + //~^ ERROR mismatched types + //~| ERROR mismatched types +} + +fn expect_free_supply_free_from_closure() { + // A variant on the previous test. Here, the region `'a` will be + // bound at the closure level, just as is expected, so no error + // results. + type Foo<'a> = fn(&'a u32); + with_closure_expecting_fn_with_free_region(|_x: Foo<'_>, y| {}); +} + +fn expect_free_supply_bound() { + // Here, we are given a function whose region is bound at closure level, + // but we expect one bound in the argument. Error results. + with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {}); + //~^ ERROR type mismatch in closure arguments +} + +fn expect_bound_supply_free_from_fn<'x>(x: &'x u32) { + // Here, we are given a `fn(&u32)` but we expect a `fn(&'x + // u32)`. In principle, this could be ok, but we demand equality. + with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {}); + //~^ ERROR type mismatch in closure arguments +} + +fn expect_bound_supply_free_from_closure() { + // A variant on the previous test. Here, the region `'a` will be + // bound at the closure level, but we expect something bound at + // the argument level. + type Foo<'a> = fn(&'a u32); + with_closure_expecting_fn_with_bound_region(|_x: Foo<'_>, y| {}); + //~^ ERROR type mismatch in closure arguments +} + +fn expect_bound_supply_bound<'x>(x: &'x u32) { + // No error in this case. The supplied type supplies the bound + // regions, and hence we are able to figure out the type of `y` + // from the expected type + with_closure_expecting_fn_with_bound_region(|x: for<'z> fn(&'z u32), y| { + }); +} + +fn main() { } diff --git a/src/test/compile-fail/closure-expected-type/expect-infer-var-appearing-twice.rs b/src/test/compile-fail/closure-expected-type/expect-infer-var-appearing-twice.rs new file mode 100644 index 00000000000..bef69a4b0b9 --- /dev/null +++ b/src/test/compile-fail/closure-expected-type/expect-infer-var-appearing-twice.rs @@ -0,0 +1,35 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn with_closure<F, A>(_: F) + where F: FnOnce(A, A) +{ +} + +fn a() { + with_closure(|x: u32, y| { + // We deduce type of `y` from `x`. + }); +} + +fn b() { + // Here we take the supplied types, resulting in an error later on. + with_closure(|x: u32, y: i32| { + //~^ ERROR type mismatch in closure arguments + }); +} + +fn c() { + with_closure(|x, y: i32| { + // We deduce type of `x` from `y`. + }); +} + +fn main() { } diff --git a/src/test/compile-fail/closure-expected-type/expect-infer-var-supply-ty-with-bound-region.rs b/src/test/compile-fail/closure-expected-type/expect-infer-var-supply-ty-with-bound-region.rs new file mode 100644 index 00000000000..f8cb643c8d6 --- /dev/null +++ b/src/test/compile-fail/closure-expected-type/expect-infer-var-supply-ty-with-bound-region.rs @@ -0,0 +1,29 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// must-compile-successfully + +fn with_closure<F, A>(_: F) + where F: FnOnce(A, &u32) +{ +} + +fn foo() { + // This version works; we infer `A` to be `u32`, and take the type + // of `y` to be `&u32`. + with_closure(|x: u32, y| {}); +} + +fn bar() { + // This version also works. + with_closure(|x: &u32, y| {}); +} + +fn main() { } diff --git a/src/test/compile-fail/closure-expected-type/expect-infer-var-supply-ty-with-free-region.rs b/src/test/compile-fail/closure-expected-type/expect-infer-var-supply-ty-with-free-region.rs new file mode 100644 index 00000000000..d3c111c5daf --- /dev/null +++ b/src/test/compile-fail/closure-expected-type/expect-infer-var-supply-ty-with-free-region.rs @@ -0,0 +1,29 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// must-compile-successfully + +fn with_closure<F, A>(_: F) + where F: FnOnce(A, &u32) +{ +} + +fn foo() { + // This version works; we infer `A` to be `u32`, and take the type + // of `y` to be `&u32`. + with_closure(|x: u32, y| {}); +} + +fn bar<'x>(x: &'x u32) { + // Same. + with_closure(|x: &'x u32, y| {}); +} + +fn main() { } diff --git a/src/test/compile-fail/closure-expected-type/expect-region-supply-region.rs b/src/test/compile-fail/closure-expected-type/expect-region-supply-region.rs new file mode 100644 index 00000000000..9da12dc901f --- /dev/null +++ b/src/test/compile-fail/closure-expected-type/expect-region-supply-region.rs @@ -0,0 +1,80 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(warnings)] + +fn closure_expecting_bound<F>(_: F) + where F: FnOnce(&u32) +{ +} + +fn closure_expecting_free<'a, F>(_: F) + where F: FnOnce(&'a u32) +{ +} + +fn expect_bound_supply_nothing() { + // Because `x` is inferred to have a bound region, we cannot allow + // it to escape into `f`: + let mut f: Option<&u32> = None; + closure_expecting_bound(|x| { + f = Some(x); //~ ERROR E0495 + }); +} + +fn expect_bound_supply_bound() { + // Because `x` is inferred to have a bound region, we cannot allow + // it to escape into `f`, even with an explicit type annotation on + // closure: + let mut f: Option<&u32> = None; + closure_expecting_bound(|x: &u32| { + f = Some(x); //~ ERROR E0495 + }); +} + +fn expect_bound_supply_named<'x>() { + let mut f: Option<&u32> = None; + + // Here we give a type annotation that `x` should be free. We get + // an error because of that. + closure_expecting_bound(|x: &'x u32| { + //~^ ERROR mismatched types + //~| ERROR mismatched types + + // And we still cannot let `x` escape into `f`. + f = Some(x); + //~^ ERROR cannot infer + }); +} + +fn expect_free_supply_nothing() { + let mut f: Option<&u32> = None; + closure_expecting_free(|x| f = Some(x)); // OK +} + +fn expect_free_supply_bound() { + let mut f: Option<&u32> = None; + + // Here, even though the annotation `&u32` could be seen as being + // bound in the closure, we permit it to be defined as a free + // region (which is inferred to something in the fn body). + closure_expecting_free(|x: &u32| f = Some(x)); // OK +} + +fn expect_free_supply_named<'x>() { + let mut f: Option<&u32> = None; + + // Here, even though the annotation `&u32` could be seen as being + // bound in the closure, we permit it to be defined as a free + // region (which is inferred to something in the fn body). + closure_expecting_free(|x: &'x u32| f = Some(x)); // OK +} + +fn main() { } diff --git a/src/test/compile-fail/closure-expected-type/expect-two-infer-vars-supply-ty-with-bound-region.rs b/src/test/compile-fail/closure-expected-type/expect-two-infer-vars-supply-ty-with-bound-region.rs new file mode 100644 index 00000000000..377eaadbd6a --- /dev/null +++ b/src/test/compile-fail/closure-expected-type/expect-two-infer-vars-supply-ty-with-bound-region.rs @@ -0,0 +1,29 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn with_closure<F, A, B>(_: F) + where F: FnOnce(A, B) +{ +} + +fn a() { + // Type of `y` is unconstrained. + with_closure(|x: u32, y| {}); //~ ERROR E0282 +} + +fn b() { + with_closure(|x: u32, y: u32| {}); // OK +} + +fn c() { + with_closure(|x: u32, y: u32| {}); // OK +} + +fn main() { } diff --git a/src/test/compile-fail/coherence-default-trait-impl.rs b/src/test/compile-fail/coherence-default-trait-impl.rs index e6bf068156c..9c26b8b05f2 100644 --- a/src/test/compile-fail/coherence-default-trait-impl.rs +++ b/src/test/compile-fail/coherence-default-trait-impl.rs @@ -12,18 +12,22 @@ trait MyTrait { fn foo() {} } +#[allow(auto_impl)] impl MyTrait for .. {} -//~^ ERROR redundant default implementations of trait `MyTrait` +//~^ ERROR redundant auto implementations of trait `MyTrait` +#[allow(auto_impl)] impl MyTrait for .. {} trait MySafeTrait {} +#[allow(auto_impl)] unsafe impl MySafeTrait for .. {} //~^ ERROR implementing the trait `MySafeTrait` is not unsafe unsafe trait MyUnsafeTrait {} +#[allow(auto_impl)] impl MyUnsafeTrait for .. {} //~^ ERROR the trait `MyUnsafeTrait` requires an `unsafe impl` declaration diff --git a/src/test/compile-fail/dupe-symbols-2.rs b/src/test/compile-fail/dupe-symbols-2.rs index 976a65589b8..1f19bd2f249 100644 --- a/src/test/compile-fail/dupe-symbols-2.rs +++ b/src/test/compile-fail/dupe-symbols-2.rs @@ -11,13 +11,13 @@ #![crate_type="rlib"] #![allow(warnings)] -mod a { +pub mod a { #[no_mangle] pub extern fn fail() { } } -mod b { +pub mod b { #[no_mangle] pub extern fn fail() { //~^ symbol `fail` is already defined diff --git a/src/test/compile-fail/feature-gate-match_default_bindings.rs b/src/test/compile-fail/feature-gate-match_default_bindings.rs index 2b3bf94eadc..4ee2c1e2936 100644 --- a/src/test/compile-fail/feature-gate-match_default_bindings.rs +++ b/src/test/compile-fail/feature-gate-match_default_bindings.rs @@ -10,7 +10,8 @@ pub fn main() { match &Some(3) { - Some(n) => {}, //~ ERROR mismatched types [E0308] + Some(n) => {}, + //~^ ERROR non-reference pattern used to match a reference _ => panic!(), } } diff --git a/src/test/compile-fail/feature-gate-non_exhaustive.rs b/src/test/compile-fail/feature-gate-non_exhaustive.rs new file mode 100644 index 00000000000..d2711084a4d --- /dev/null +++ b/src/test/compile-fail/feature-gate-non_exhaustive.rs @@ -0,0 +1,20 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//#![feature(non_exhaustive)] + +#[non_exhaustive] //~ERROR non exhaustive is an experimental feature (see issue #44109) +pub enum NonExhaustiveEnum { + Unit, + Tuple(u32), + Struct { field: u32 } +} + +fn main() { } diff --git a/src/test/compile-fail/feature-gate-optin-builtin-traits.rs b/src/test/compile-fail/feature-gate-optin-builtin-traits.rs index 59d7473a741..4c5502cec18 100644 --- a/src/test/compile-fail/feature-gate-optin-builtin-traits.rs +++ b/src/test/compile-fail/feature-gate-optin-builtin-traits.rs @@ -17,8 +17,12 @@ trait DummyTrait { fn dummy(&self) {} } +auto trait AutoDummyTrait {} +//~^ ERROR auto traits are experimental and possibly buggy + +#[allow(auto_impl)] impl DummyTrait for .. {} -//~^ ERROR default trait implementations are experimental and possibly buggy +//~^ ERROR auto trait implementations are experimental and possibly buggy impl !DummyTrait for DummyStruct {} //~^ ERROR negative trait bounds are not yet fully implemented; use marker types for now diff --git a/src/test/compile-fail/float-int-invalid-const-cast.rs b/src/test/compile-fail/float-int-invalid-const-cast.rs new file mode 100644 index 00000000000..2efefd92691 --- /dev/null +++ b/src/test/compile-fail/float-int-invalid-const-cast.rs @@ -0,0 +1,61 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(i128_type)] +#![allow(const_err)] // this test is only about hard errors + +use std::{f32, f64}; + +// Forces evaluation of constants, triggering hard error +fn force<T>(_: T) {} + +fn main() { + { const X: u16 = -1. as u16; force(X); } //~ ERROR constant evaluation error + { const X: u128 = -100. as u128; force(X); } //~ ERROR constant evaluation error + + { const X: i8 = f32::NAN as i8; force(X); } //~ ERROR constant evaluation error + { const X: i32 = f32::NAN as i32; force(X); } //~ ERROR constant evaluation error + { const X: u64 = f32::NAN as u64; force(X); } //~ ERROR constant evaluation error + { const X: u128 = f32::NAN as u128; force(X); } //~ ERROR constant evaluation error + + { const X: i8 = f32::INFINITY as i8; force(X); } //~ ERROR constant evaluation error + { const X: u32 = f32::INFINITY as u32; force(X); } //~ ERROR constant evaluation error + { const X: i128 = f32::INFINITY as i128; force(X); } //~ ERROR constant evaluation error + { const X: u128 = f32::INFINITY as u128; force(X); } //~ ERROR constant evaluation error + + { const X: u8 = f32::NEG_INFINITY as u8; force(X); } //~ ERROR constant evaluation error + { const X: u16 = f32::NEG_INFINITY as u16; force(X); } //~ ERROR constant evaluation error + { const X: i64 = f32::NEG_INFINITY as i64; force(X); } //~ ERROR constant evaluation error + { const X: i128 = f32::NEG_INFINITY as i128; force(X); } //~ ERROR constant evaluation error + + { const X: i8 = f64::NAN as i8; force(X); } //~ ERROR constant evaluation error + { const X: i32 = f64::NAN as i32; force(X); } //~ ERROR constant evaluation error + { const X: u64 = f64::NAN as u64; force(X); } //~ ERROR constant evaluation error + { const X: u128 = f64::NAN as u128; force(X); } //~ ERROR constant evaluation error + + { const X: i8 = f64::INFINITY as i8; force(X); } //~ ERROR constant evaluation error + { const X: u32 = f64::INFINITY as u32; force(X); } //~ ERROR constant evaluation error + { const X: i128 = f64::INFINITY as i128; force(X); } //~ ERROR constant evaluation error + { const X: u128 = f64::INFINITY as u128; force(X); } //~ ERROR constant evaluation error + + { const X: u8 = f64::NEG_INFINITY as u8; force(X); } //~ ERROR constant evaluation error + { const X: u16 = f64::NEG_INFINITY as u16; force(X); } //~ ERROR constant evaluation error + { const X: i64 = f64::NEG_INFINITY as i64; force(X); } //~ ERROR constant evaluation error + { const X: i128 = f64::NEG_INFINITY as i128; force(X); } //~ ERROR constant evaluation error + + { const X: u8 = 256. as u8; force(X); } //~ ERROR constant evaluation error + { const X: i8 = -129. as i8; force(X); } //~ ERROR constant evaluation error + { const X: i8 = 128. as i8; force(X); } //~ ERROR constant evaluation error + { const X: i32 = 2147483648. as i32; force(X); } //~ ERROR constant evaluation error + { const X: i32 = -2147483904. as i32; force(X); } //~ ERROR constant evaluation error + { const X: u32 = 4294967296. as u32; force(X); } //~ ERROR constant evaluation error + { const X: u128 = 1e40 as u128; force(X); } //~ ERROR constant evaluation error + { const X: i128 = 1e40 as i128; force(X); } //~ ERROR constant evaluation error +} \ No newline at end of file diff --git a/src/test/compile-fail/invalid-inline.rs b/src/test/compile-fail/invalid-inline.rs index ad89087d660..93b985b4fb0 100644 --- a/src/test/compile-fail/invalid-inline.rs +++ b/src/test/compile-fail/invalid-inline.rs @@ -21,4 +21,8 @@ fn b() { fn c() { } -fn main() {} +fn main() { + a(); + b(); + c(); +} diff --git a/src/test/compile-fail/issue-16338.rs b/src/test/compile-fail/issue-16338.rs index a4517e60d66..6fdf8802e38 100644 --- a/src/test/compile-fail/issue-16338.rs +++ b/src/test/compile-fail/issue-16338.rs @@ -16,7 +16,6 @@ struct Slice<T> { fn main() { let Slice { data: data, len: len } = "foo"; //~^ ERROR mismatched types - //~| expected type `&str` //~| found type `Slice<_>` - //~| expected &str, found struct `Slice` + //~| ERROR non-reference pattern used to match a reference } diff --git a/src/test/compile-fail/issue-20261.rs b/src/test/compile-fail/issue-20261.rs index 7b5e61380f2..092aaa76955 100644 --- a/src/test/compile-fail/issue-20261.rs +++ b/src/test/compile-fail/issue-20261.rs @@ -10,7 +10,8 @@ fn main() { // NB: this (almost) typechecks when default binding modes are enabled. - for (ref i,) in [].iter() { //~ ERROR mismatched types [E0308] + for (ref i,) in [].iter() { + //~^ ERROR non-reference pattern used to match a reference i.clone(); } } diff --git a/src/test/compile-fail/issue-22638.rs b/src/test/compile-fail/issue-22638.rs index 65d1d837d7d..53b0d9f4e9f 100644 --- a/src/test/compile-fail/issue-22638.rs +++ b/src/test/compile-fail/issue-22638.rs @@ -12,6 +12,7 @@ #![recursion_limit = "20"] #![type_length_limit = "20000000"] +#![crate_type = "rlib"] #[derive(Clone)] struct A (B); @@ -66,5 +67,3 @@ impl D { pub fn matches() { A(B::Variant1).matches(&(|| ())) } - -fn main() {} diff --git a/src/test/compile-fail/issue-23080-2.rs b/src/test/compile-fail/issue-23080-2.rs index 9d20c17674b..bf44cd53f67 100644 --- a/src/test/compile-fail/issue-23080-2.rs +++ b/src/test/compile-fail/issue-23080-2.rs @@ -17,6 +17,7 @@ unsafe trait Trait { type Output; } +#[allow(auto_impl)] unsafe impl Trait for .. {} fn call_method<T: Trait>(x: T) {} diff --git a/src/test/compile-fail/issue-23080.rs b/src/test/compile-fail/issue-23080.rs index 2e8cba87be5..1fb63391d56 100644 --- a/src/test/compile-fail/issue-23080.rs +++ b/src/test/compile-fail/issue-23080.rs @@ -19,6 +19,7 @@ unsafe trait Trait { } } +#[allow(auto_impl)] unsafe impl Trait for .. {} fn call_method<T: Trait>(x: T) { diff --git a/src/test/compile-fail/keyword-false-as-identifier.rs b/src/test/compile-fail/keyword-false-as-identifier.rs index e8af94f16b1..f246d6e75df 100644 --- a/src/test/compile-fail/keyword-false-as-identifier.rs +++ b/src/test/compile-fail/keyword-false-as-identifier.rs @@ -9,5 +9,5 @@ // except according to those terms. fn main() { - let false = "foo"; //~ error: mismatched types + let false = 22; //~ error: mismatched types } diff --git a/src/test/compile-fail/keyword-self-as-identifier.rs b/src/test/compile-fail/keyword-self-as-identifier.rs index f01aab92356..b50fc68bed6 100644 --- a/src/test/compile-fail/keyword-self-as-identifier.rs +++ b/src/test/compile-fail/keyword-self-as-identifier.rs @@ -9,5 +9,5 @@ // except according to those terms. fn main() { - let Self = "foo"; //~ ERROR cannot find unit struct/variant or constant `Self` in this scope + let Self = 22; //~ ERROR cannot find unit struct/variant or constant `Self` in this scope } diff --git a/src/test/compile-fail/keyword-super-as-identifier.rs b/src/test/compile-fail/keyword-super-as-identifier.rs index 62649ba8a0f..54dac771f01 100644 --- a/src/test/compile-fail/keyword-super-as-identifier.rs +++ b/src/test/compile-fail/keyword-super-as-identifier.rs @@ -9,5 +9,5 @@ // except according to those terms. fn main() { - let super = "foo"; //~ ERROR failed to resolve. There are too many initial `super`s + let super = 22; //~ ERROR failed to resolve. There are too many initial `super`s } diff --git a/src/test/compile-fail/keyword-true-as-identifier.rs b/src/test/compile-fail/keyword-true-as-identifier.rs index 90414fa912d..b09d09db560 100644 --- a/src/test/compile-fail/keyword-true-as-identifier.rs +++ b/src/test/compile-fail/keyword-true-as-identifier.rs @@ -9,5 +9,5 @@ // except according to those terms. fn main() { - let true = "foo"; //~ error: mismatched types + let true = 22; //~ error: mismatched types } diff --git a/src/test/compile-fail/match-range-fail.rs b/src/test/compile-fail/match-range-fail.rs index f89b3e39390..355ff6404ce 100644 --- a/src/test/compile-fail/match-range-fail.rs +++ b/src/test/compile-fail/match-range-fail.rs @@ -15,6 +15,7 @@ fn main() { //~^^ ERROR only char and numeric types are allowed in range //~| start type: &'static str //~| end type: &'static str + //~| ERROR non-reference pattern used to match a reference match "wow" { 10 ... "what" => () @@ -22,6 +23,7 @@ fn main() { //~^^ ERROR only char and numeric types are allowed in range //~| start type: {integer} //~| end type: &'static str + //~| ERROR non-reference pattern used to match a reference match 5 { 'c' ... 100 => { } diff --git a/src/test/compile-fail/match-vec-mismatch.rs b/src/test/compile-fail/match-vec-mismatch.rs index d72ec8ba408..fed68da0068 100644 --- a/src/test/compile-fail/match-vec-mismatch.rs +++ b/src/test/compile-fail/match-vec-mismatch.rs @@ -19,7 +19,7 @@ fn main() { // Note that this one works with default binding modes. match &[0, 1, 2] { - [..] => {} //~ ERROR expected an array or slice, found `&[{integer}; 3]` [E0529] + [..] => {} //~ ERROR non-reference pattern used to match a reference }; match &[0, 1, 2] { diff --git a/src/test/compile-fail/nll/loan_ends_mid_block_pair.rs b/src/test/compile-fail/nll/loan_ends_mid_block_pair.rs new file mode 100644 index 00000000000..c02977f22ea --- /dev/null +++ b/src/test/compile-fail/nll/loan_ends_mid_block_pair.rs @@ -0,0 +1,50 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +// compile-flags:-Zborrowck-mir -Znll + +#![allow(warnings)] +#![feature(rustc_attrs)] + + +fn main() { +} + +fn nll_fail() { + let mut data = ('a', 'b', 'c'); + let c = &mut data.0; + capitalize(c); + data.0 = 'e'; + //~^ ERROR (Ast) [E0506] + //~| ERROR (Mir) [E0506] + data.0 = 'f'; + //~^ ERROR (Ast) [E0506] + //~| ERROR (Mir) [E0506] + data.0 = 'g'; + //~^ ERROR (Ast) [E0506] + //~| ERROR (Mir) [E0506] + capitalize(c); +} + +fn nll_ok() { + let mut data = ('a', 'b', 'c'); + let c = &mut data.0; + capitalize(c); + data.0 = 'e'; + //~^ ERROR (Ast) [E0506] + data.0 = 'f'; + //~^ ERROR (Ast) [E0506] + data.0 = 'g'; + //~^ ERROR (Ast) [E0506] +} + +fn capitalize(_: &mut char) { +} diff --git a/src/test/compile-fail/nll/loan_ends_mid_block_vec.rs b/src/test/compile-fail/nll/loan_ends_mid_block_vec.rs new file mode 100644 index 00000000000..5e3a003b54e --- /dev/null +++ b/src/test/compile-fail/nll/loan_ends_mid_block_vec.rs @@ -0,0 +1,49 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +// compile-flags:-Zborrowck-mir -Znll + +#![allow(warnings)] +#![feature(rustc_attrs)] + +fn main() { +} + +fn nll_fail() { + let mut data = vec!['a', 'b', 'c']; + let slice = &mut data; + capitalize(slice); + data.push('d'); + //~^ ERROR (Ast) [E0499] + //~| ERROR (Mir) [E0499] + data.push('e'); + //~^ ERROR (Ast) [E0499] + //~| ERROR (Mir) [E0499] + data.push('f'); + //~^ ERROR (Ast) [E0499] + //~| ERROR (Mir) [E0499] + capitalize(slice); +} + +fn nll_ok() { + let mut data = vec!['a', 'b', 'c']; + let slice = &mut data; + capitalize(slice); + data.push('d'); + //~^ ERROR (Ast) [E0499] + data.push('e'); + //~^ ERROR (Ast) [E0499] + data.push('f'); + //~^ ERROR (Ast) [E0499] +} + +fn capitalize(_: &mut [char]) { +} diff --git a/src/test/compile-fail/nll/region-ends-after-if-condition.rs b/src/test/compile-fail/nll/region-ends-after-if-condition.rs new file mode 100644 index 00000000000..bec56982c57 --- /dev/null +++ b/src/test/compile-fail/nll/region-ends-after-if-condition.rs @@ -0,0 +1,46 @@ +// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Basic test for liveness constraints: the region (`R1`) that appears +// in the type of `p` includes the points after `&v[0]` up to (but not +// including) the call to `use_x`. The `else` branch is not included. + +// compile-flags:-Zborrowck-mir -Znll + +#![allow(warnings)] +#![feature(rustc_attrs)] + +struct MyStruct { + field: String +} + +fn foo1() { + let mut my_struct = MyStruct { field: format!("Hello") }; + + let value = &my_struct.field; + if value.is_empty() { + my_struct.field.push_str("Hello, world!"); + //~^ ERROR (Ast) [E0502] + } +} + +fn foo2() { + let mut my_struct = MyStruct { field: format!("Hello") }; + + let value = &my_struct.field; + if value.is_empty() { + my_struct.field.push_str("Hello, world!"); + //~^ ERROR (Ast) [E0502] + //~| ERROR (Mir) [E0502] + } + drop(value); +} + +fn main() { } diff --git a/src/test/compile-fail/nll/return_from_loop.rs b/src/test/compile-fail/nll/return_from_loop.rs new file mode 100644 index 00000000000..6b287fd2272 --- /dev/null +++ b/src/test/compile-fail/nll/return_from_loop.rs @@ -0,0 +1,49 @@ +// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Basic test for liveness constraints: the region (`R1`) that appears +// in the type of `p` includes the points after `&v[0]` up to (but not +// including) the call to `use_x`. The `else` branch is not included. + +// compile-flags:-Zborrowck-mir -Znll + +#![allow(warnings)] +#![feature(rustc_attrs)] + +struct MyStruct { + field: String +} + +fn main() { +} + +fn nll_fail() { + let mut my_struct = MyStruct { field: format!("Hello") }; + + let value = &mut my_struct.field; + loop { + my_struct.field.push_str("Hello, world!"); + //~^ ERROR (Ast) [E0499] + //~| ERROR (Mir) [E0499] + value.len(); + return; + } +} + +fn nll_ok() { + let mut my_struct = MyStruct { field: format!("Hello") }; + + let value = &mut my_struct.field; + loop { + my_struct.field.push_str("Hello, world!"); + //~^ ERROR (Ast) [E0499] + return; + } +} diff --git a/src/test/compile-fail/non-interger-atomic.rs b/src/test/compile-fail/non-interger-atomic.rs index 50240b47557..a51a9e518ce 100644 --- a/src/test/compile-fail/non-interger-atomic.rs +++ b/src/test/compile-fail/non-interger-atomic.rs @@ -10,92 +10,91 @@ #![feature(core_intrinsics)] #![allow(warnings)] +#![crate_type = "rlib"] use std::intrinsics; #[derive(Copy, Clone)] -struct Foo(i64); -type Bar = &'static Fn(); -type Quux = [u8; 100]; +pub struct Foo(i64); +pub type Bar = &'static Fn(); +pub type Quux = [u8; 100]; -unsafe fn test_bool_load(p: &mut bool, v: bool) { +pub unsafe fn test_bool_load(p: &mut bool, v: bool) { intrinsics::atomic_load(p); //~^ ERROR `atomic_load` intrinsic: expected basic integer type, found `bool` } -unsafe fn test_bool_store(p: &mut bool, v: bool) { +pub unsafe fn test_bool_store(p: &mut bool, v: bool) { intrinsics::atomic_store(p, v); //~^ ERROR `atomic_store` intrinsic: expected basic integer type, found `bool` } -unsafe fn test_bool_xchg(p: &mut bool, v: bool) { +pub unsafe fn test_bool_xchg(p: &mut bool, v: bool) { intrinsics::atomic_xchg(p, v); //~^ ERROR `atomic_xchg` intrinsic: expected basic integer type, found `bool` } -unsafe fn test_bool_cxchg(p: &mut bool, v: bool) { +pub unsafe fn test_bool_cxchg(p: &mut bool, v: bool) { intrinsics::atomic_cxchg(p, v, v); //~^ ERROR `atomic_cxchg` intrinsic: expected basic integer type, found `bool` } -unsafe fn test_Foo_load(p: &mut Foo, v: Foo) { +pub unsafe fn test_Foo_load(p: &mut Foo, v: Foo) { intrinsics::atomic_load(p); //~^ ERROR `atomic_load` intrinsic: expected basic integer type, found `Foo` } -unsafe fn test_Foo_store(p: &mut Foo, v: Foo) { +pub unsafe fn test_Foo_store(p: &mut Foo, v: Foo) { intrinsics::atomic_store(p, v); //~^ ERROR `atomic_store` intrinsic: expected basic integer type, found `Foo` } -unsafe fn test_Foo_xchg(p: &mut Foo, v: Foo) { +pub unsafe fn test_Foo_xchg(p: &mut Foo, v: Foo) { intrinsics::atomic_xchg(p, v); //~^ ERROR `atomic_xchg` intrinsic: expected basic integer type, found `Foo` } -unsafe fn test_Foo_cxchg(p: &mut Foo, v: Foo) { +pub unsafe fn test_Foo_cxchg(p: &mut Foo, v: Foo) { intrinsics::atomic_cxchg(p, v, v); //~^ ERROR `atomic_cxchg` intrinsic: expected basic integer type, found `Foo` } -unsafe fn test_Bar_load(p: &mut Bar, v: Bar) { +pub unsafe fn test_Bar_load(p: &mut Bar, v: Bar) { intrinsics::atomic_load(p); //~^ ERROR expected basic integer type, found `&std::ops::Fn()` } -unsafe fn test_Bar_store(p: &mut Bar, v: Bar) { +pub unsafe fn test_Bar_store(p: &mut Bar, v: Bar) { intrinsics::atomic_store(p, v); //~^ ERROR expected basic integer type, found `&std::ops::Fn()` } -unsafe fn test_Bar_xchg(p: &mut Bar, v: Bar) { +pub unsafe fn test_Bar_xchg(p: &mut Bar, v: Bar) { intrinsics::atomic_xchg(p, v); //~^ ERROR expected basic integer type, found `&std::ops::Fn()` } -unsafe fn test_Bar_cxchg(p: &mut Bar, v: Bar) { +pub unsafe fn test_Bar_cxchg(p: &mut Bar, v: Bar) { intrinsics::atomic_cxchg(p, v, v); //~^ ERROR expected basic integer type, found `&std::ops::Fn()` } -unsafe fn test_Quux_load(p: &mut Quux, v: Quux) { +pub unsafe fn test_Quux_load(p: &mut Quux, v: Quux) { intrinsics::atomic_load(p); //~^ ERROR `atomic_load` intrinsic: expected basic integer type, found `[u8; 100]` } -unsafe fn test_Quux_store(p: &mut Quux, v: Quux) { +pub unsafe fn test_Quux_store(p: &mut Quux, v: Quux) { intrinsics::atomic_store(p, v); //~^ ERROR `atomic_store` intrinsic: expected basic integer type, found `[u8; 100]` } -unsafe fn test_Quux_xchg(p: &mut Quux, v: Quux) { +pub unsafe fn test_Quux_xchg(p: &mut Quux, v: Quux) { intrinsics::atomic_xchg(p, v); //~^ ERROR `atomic_xchg` intrinsic: expected basic integer type, found `[u8; 100]` } -unsafe fn test_Quux_cxchg(p: &mut Quux, v: Quux) { +pub unsafe fn test_Quux_cxchg(p: &mut Quux, v: Quux) { intrinsics::atomic_cxchg(p, v, v); //~^ ERROR `atomic_cxchg` intrinsic: expected basic integer type, found `[u8; 100]` } - -fn main() {} diff --git a/src/test/compile-fail/pat-slice-old-style.rs b/src/test/compile-fail/pat-slice-old-style.rs index 54028ffa63f..d49ce56ccf6 100644 --- a/src/test/compile-fail/pat-slice-old-style.rs +++ b/src/test/compile-fail/pat-slice-old-style.rs @@ -17,8 +17,9 @@ fn slice_pat(x: &[u8]) { // OLD! match x { [a, b..] => {}, - //~^ ERROR expected an array or slice, found `&[u8]` - //~| HELP the semantics of slice patterns changed recently; see issue #23121 + //~^ ERROR non-reference pattern used to match a reference + //~| HELP add #![feature(match_default_bindings)] to the crate attributes to enable + //~| HELP consider using _ => panic!(), } } diff --git a/src/test/compile-fail/phantom-oibit.rs b/src/test/compile-fail/phantom-oibit.rs index c84927ea266..1c1cb396a54 100644 --- a/src/test/compile-fail/phantom-oibit.rs +++ b/src/test/compile-fail/phantom-oibit.rs @@ -18,6 +18,7 @@ use std::marker::{PhantomData}; unsafe trait Zen {} +#[allow(auto_impl)] unsafe impl Zen for .. {} unsafe impl<'a, T: 'a> Zen for &'a T where T: Sync {} diff --git a/src/test/compile-fail/privacy-sanity.rs b/src/test/compile-fail/privacy-sanity.rs index 933ec3837df..34082adb8f9 100644 --- a/src/test/compile-fail/privacy-sanity.rs +++ b/src/test/compile-fail/privacy-sanity.rs @@ -21,6 +21,7 @@ pub struct S { } struct Ts(pub u8); +#[allow(auto_impl)] pub impl MarkerTr for .. {} //~ ERROR unnecessary visibility qualifier pub impl Tr for S { //~ ERROR unnecessary visibility qualifier pub fn f() {} //~ ERROR unnecessary visibility qualifier @@ -49,6 +50,7 @@ const MAIN: u8 = { } struct Ts(pub u8); + #[allow(auto_impl)] pub impl MarkerTr for .. {} //~ ERROR unnecessary visibility qualifier pub impl Tr for S { //~ ERROR unnecessary visibility qualifier pub fn f() {} //~ ERROR unnecessary visibility qualifier @@ -80,6 +82,7 @@ fn main() { } struct Ts(pub u8); + #[allow(auto_impl)] pub impl MarkerTr for .. {} //~ ERROR unnecessary visibility qualifier pub impl Tr for S { //~ ERROR unnecessary visibility qualifier pub fn f() {} //~ ERROR unnecessary visibility qualifier diff --git a/src/test/compile-fail/regions-infer-at-fn-not-param.rs b/src/test/compile-fail/regions-infer-at-fn-not-param.rs index 0c250e38258..ec73bf90b6e 100644 --- a/src/test/compile-fail/regions-infer-at-fn-not-param.rs +++ b/src/test/compile-fail/regions-infer-at-fn-not-param.rs @@ -21,7 +21,7 @@ struct not_parameterized2 { } fn take1<'a>(p: parameterized1) -> parameterized1<'a> { p } -//~^ ERROR mismatched types +//~^ ERROR explicit lifetime required in the type of `p` fn take3(p: not_parameterized1) -> not_parameterized1 { p } fn take4(p: not_parameterized2) -> not_parameterized2 { p } diff --git a/src/test/compile-fail/rfc-2008-non-exhaustive/auxiliary/enums.rs b/src/test/compile-fail/rfc-2008-non-exhaustive/auxiliary/enums.rs new file mode 100644 index 00000000000..12d1bf9ea91 --- /dev/null +++ b/src/test/compile-fail/rfc-2008-non-exhaustive/auxiliary/enums.rs @@ -0,0 +1,19 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "rlib"] +#![feature(non_exhaustive)] + +#[non_exhaustive] +pub enum NonExhaustiveEnum { + Unit, + Tuple(u32), + Struct { field: u32 } +} diff --git a/src/test/compile-fail/rfc-2008-non-exhaustive/auxiliary/structs.rs b/src/test/compile-fail/rfc-2008-non-exhaustive/auxiliary/structs.rs new file mode 100644 index 00000000000..4d083cc5315 --- /dev/null +++ b/src/test/compile-fail/rfc-2008-non-exhaustive/auxiliary/structs.rs @@ -0,0 +1,37 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(non_exhaustive)] + +#[non_exhaustive] +pub struct NormalStruct { + pub first_field: u16, + pub second_field: u16, +} + +#[non_exhaustive] +pub struct UnitStruct; + +#[non_exhaustive] +pub struct TupleStruct(pub u16, pub u16); + +#[derive(Debug)] +#[non_exhaustive] +pub struct FunctionalRecord { + pub first_field: u16, + pub second_field: u16, + pub third_field: bool +} + +impl Default for FunctionalRecord { + fn default() -> FunctionalRecord { + FunctionalRecord { first_field: 640, second_field: 480, third_field: false } + } +} diff --git a/src/test/compile-fail/rfc-2008-non-exhaustive/auxiliary/variants.rs b/src/test/compile-fail/rfc-2008-non-exhaustive/auxiliary/variants.rs new file mode 100644 index 00000000000..d04c1073ad9 --- /dev/null +++ b/src/test/compile-fail/rfc-2008-non-exhaustive/auxiliary/variants.rs @@ -0,0 +1,18 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "rlib"] +#![feature(non_exhaustive)] + +pub enum NonExhaustiveVariants { + #[non_exhaustive] Unit, + #[non_exhaustive] Tuple(u32), + #[non_exhaustive] Struct { field: u32 } +} diff --git a/src/test/compile-fail/rfc-2008-non-exhaustive/enum.rs b/src/test/compile-fail/rfc-2008-non-exhaustive/enum.rs new file mode 100644 index 00000000000..0c19210e4a0 --- /dev/null +++ b/src/test/compile-fail/rfc-2008-non-exhaustive/enum.rs @@ -0,0 +1,25 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:enums.rs +extern crate enums; + +use enums::NonExhaustiveEnum; + +fn main() { + let enum_unit = NonExhaustiveEnum::Unit; + + match enum_unit { + //~^ ERROR non-exhaustive patterns: `_` not covered [E0004] + NonExhaustiveEnum::Unit => "first", + NonExhaustiveEnum::Tuple(_) => "second", + NonExhaustiveEnum::Struct { .. } => "third" + }; +} diff --git a/src/test/compile-fail/rfc-2008-non-exhaustive/structs.rs b/src/test/compile-fail/rfc-2008-non-exhaustive/structs.rs new file mode 100644 index 00000000000..74c9c7c61ac --- /dev/null +++ b/src/test/compile-fail/rfc-2008-non-exhaustive/structs.rs @@ -0,0 +1,47 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:structs.rs +extern crate structs; + +use structs::{NormalStruct, UnitStruct, TupleStruct, FunctionalRecord}; + +fn main() { + let fr = FunctionalRecord { + //~^ ERROR cannot create non-exhaustive struct + first_field: 1920, + second_field: 1080, + ..FunctionalRecord::default() + }; + + let ns = NormalStruct { first_field: 640, second_field: 480 }; + //~^ ERROR cannot create non-exhaustive struct + + let NormalStruct { first_field, second_field } = ns; + //~^ ERROR `..` required with struct marked as non-exhaustive + + let ts = TupleStruct(640, 480); + //~^ ERROR expected function, found struct `TupleStruct` [E0423] + + let ts_explicit = structs::TupleStruct(640, 480); + //~^ ERROR tuple struct `TupleStruct` is private [E0603] + + let TupleStruct { 0: first_field, 1: second_field } = ts; + //~^ ERROR `..` required with struct marked as non-exhaustive + + let us = UnitStruct; + //~^ ERROR expected value, found struct `UnitStruct` [E0423] + + let us_explicit = structs::UnitStruct; + //~^ ERROR unit struct `UnitStruct` is private [E0603] + + let UnitStruct { } = us; + //~^ ERROR `..` required with struct marked as non-exhaustive +} diff --git a/src/test/compile-fail/rfc-2008-non-exhaustive/variants.rs b/src/test/compile-fail/rfc-2008-non-exhaustive/variants.rs new file mode 100644 index 00000000000..d1b65ac1f3e --- /dev/null +++ b/src/test/compile-fail/rfc-2008-non-exhaustive/variants.rs @@ -0,0 +1,36 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:variants.rs +extern crate variants; + +use variants::NonExhaustiveVariants; + +/* + * The initial implementation of #[non_exhaustive] (RFC 2008) does not include support for + * variants. See issue #44109 and PR 45394. + */ +// ignore-test + +fn main() { + let variant_struct = NonExhaustiveVariants::Struct { field: 640 }; + //~^ ERROR cannot create non-exhaustive variant + + let variant_tuple = NonExhaustiveVariants::Tuple { 0: 640 }; + //~^ ERROR cannot create non-exhaustive variant + + match variant_struct { + NonExhaustiveVariants::Unit => "", + NonExhaustiveVariants::Tuple(fe_tpl) => "", + //~^ ERROR `..` required with variant marked as non-exhaustive + NonExhaustiveVariants::Struct { field } => "" + //~^ ERROR `..` required with variant marked as non-exhaustive + }; +} diff --git a/src/test/compile-fail/rfc-2008-non-exhaustive/variants_create.rs b/src/test/compile-fail/rfc-2008-non-exhaustive/variants_create.rs new file mode 100644 index 00000000000..f4e4b1bb84b --- /dev/null +++ b/src/test/compile-fail/rfc-2008-non-exhaustive/variants_create.rs @@ -0,0 +1,27 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(non_exhaustive)] + +/* + * The initial implementation of #[non_exhaustive] (RFC 2008) does not include support for + * variants. See issue #44109 and PR 45394. + */ + +pub enum NonExhaustiveVariants { + #[non_exhaustive] Unit, + //~^ ERROR #[non_exhaustive] is not yet supported on variants + #[non_exhaustive] Tuple(u32), + //~^ ERROR #[non_exhaustive] is not yet supported on variants + #[non_exhaustive] Struct { field: u32 } + //~^ ERROR #[non_exhaustive] is not yet supported on variants +} + +fn main() { } diff --git a/src/test/compile-fail/self-vs-path-ambiguity.rs b/src/test/compile-fail/self-vs-path-ambiguity.rs index 9753014e781..b2dba3bd61b 100644 --- a/src/test/compile-fail/self-vs-path-ambiguity.rs +++ b/src/test/compile-fail/self-vs-path-ambiguity.rs @@ -17,7 +17,6 @@ impl S { fn g(&self::S: &S) {} fn h(&mut self::S: &mut S) {} fn i(&'a self::S: &S) {} //~ ERROR unexpected lifetime `'a` in pattern - //~^ ERROR expected one of `)` or `mut`, found `'a` } fn main() {} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-no-default-trait-implementations.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-no-default-trait-implementations.rs index c1746d765dd..cad43ffeace 100644 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-no-default-trait-implementations.rs +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-no-default-trait-implementations.rs @@ -13,7 +13,8 @@ trait Foo {} +#[allow(auto_impl)] default impl Foo for .. {} -//~^ ERROR `default impl` is not allowed for default trait implementations +//~^ ERROR `default impl` is not allowed for auto trait implementations fn main() {} diff --git a/src/test/compile-fail/specialization/specialization-polarity.rs b/src/test/compile-fail/specialization/specialization-polarity.rs index 27a3e31491b..c97cb3f6bb7 100644 --- a/src/test/compile-fail/specialization/specialization-polarity.rs +++ b/src/test/compile-fail/specialization/specialization-polarity.rs @@ -15,6 +15,7 @@ trait Foo {} +#[allow(auto_impl)] impl Foo for .. {} impl<T> Foo for T {} @@ -22,6 +23,7 @@ impl !Foo for u8 {} //~ ERROR E0119 trait Bar {} +#[allow(auto_impl)] impl Bar for .. {} impl<T> !Bar for T {} diff --git a/src/test/compile-fail/syntaxt-default-trait-impls.rs b/src/test/compile-fail/syntaxt-default-trait-impls.rs index 7d6a1c9c154..45303cbf700 100644 --- a/src/test/compile-fail/syntaxt-default-trait-impls.rs +++ b/src/test/compile-fail/syntaxt-default-trait-impls.rs @@ -10,9 +10,10 @@ #![feature(optin_builtin_traits)] -trait MyDefaultImpl {} +trait MyAutoImpl {} -impl<T> MyDefaultImpl for .. {} -//~^ ERROR default trait implementations are not allowed to have generics +#[allow(auto_impl)] +impl<T> MyAutoImpl for .. {} +//~^ ERROR auto trait implementations are not allowed to have generics fn main() {} diff --git a/src/test/compile-fail/traits-inductive-overflow-supertrait-oibit.rs b/src/test/compile-fail/traits-inductive-overflow-supertrait-oibit.rs index fe0e583b20a..6c7928f13f8 100644 --- a/src/test/compile-fail/traits-inductive-overflow-supertrait-oibit.rs +++ b/src/test/compile-fail/traits-inductive-overflow-supertrait-oibit.rs @@ -15,6 +15,7 @@ #![feature(optin_builtin_traits)] trait Magic: Copy {} //~ ERROR E0568 +#[allow(auto_impl)] impl Magic for .. {} fn copy<T: Magic>(x: T) -> (T, T) { (x, x) } diff --git a/src/test/compile-fail/typeck-auto-trait-no-supertraits-2.rs b/src/test/compile-fail/typeck-auto-trait-no-supertraits-2.rs index f6678ac7c2d..173582ed22f 100644 --- a/src/test/compile-fail/typeck-auto-trait-no-supertraits-2.rs +++ b/src/test/compile-fail/typeck-auto-trait-no-supertraits-2.rs @@ -11,6 +11,7 @@ #![feature(optin_builtin_traits)] trait Magic : Sized where Option<Self> : Magic {} //~ ERROR E0568 +#[allow(auto_impl)] impl Magic for .. {} impl<T:Magic> Magic for T {} diff --git a/src/test/compile-fail/typeck-auto-trait-no-supertraits.rs b/src/test/compile-fail/typeck-auto-trait-no-supertraits.rs index 9497dfb39d7..6802f72504b 100644 --- a/src/test/compile-fail/typeck-auto-trait-no-supertraits.rs +++ b/src/test/compile-fail/typeck-auto-trait-no-supertraits.rs @@ -35,6 +35,7 @@ #![feature(optin_builtin_traits)] trait Magic: Copy {} //~ ERROR E0568 +#[allow(auto_impl)] impl Magic for .. {} impl<T:Magic> Magic for T {} diff --git a/src/test/compile-fail/typeck-auto-trait-no-typeparams.rs b/src/test/compile-fail/typeck-auto-trait-no-typeparams.rs index 5a852c54869..3c409d1b371 100644 --- a/src/test/compile-fail/typeck-auto-trait-no-typeparams.rs +++ b/src/test/compile-fail/typeck-auto-trait-no-typeparams.rs @@ -11,4 +11,5 @@ #![feature(optin_builtin_traits)] trait Magic<T> {} //~ ERROR E0567 +#[allow(auto_impl)] impl Magic<isize> for .. {} diff --git a/src/test/compile-fail/typeck-default-trait-impl-constituent-types-2.rs b/src/test/compile-fail/typeck-default-trait-impl-constituent-types-2.rs index 8a46d6c76c3..a837d8c9ca7 100644 --- a/src/test/compile-fail/typeck-default-trait-impl-constituent-types-2.rs +++ b/src/test/compile-fail/typeck-default-trait-impl-constituent-types-2.rs @@ -12,6 +12,7 @@ trait MyTrait {} +#[allow(auto_impl)] impl MyTrait for .. {} struct MyS; diff --git a/src/test/compile-fail/typeck-default-trait-impl-constituent-types.rs b/src/test/compile-fail/typeck-default-trait-impl-constituent-types.rs index 3d7746b369c..bed184eb4cc 100644 --- a/src/test/compile-fail/typeck-default-trait-impl-constituent-types.rs +++ b/src/test/compile-fail/typeck-default-trait-impl-constituent-types.rs @@ -12,6 +12,7 @@ trait MyTrait {} +#[allow(auto_impl)] impl MyTrait for .. {} impl<T> !MyTrait for *mut T {} diff --git a/src/test/compile-fail/typeck-default-trait-impl-negation.rs b/src/test/compile-fail/typeck-default-trait-impl-negation.rs index 8c2658b89a5..f3a6d8a342e 100644 --- a/src/test/compile-fail/typeck-default-trait-impl-negation.rs +++ b/src/test/compile-fail/typeck-default-trait-impl-negation.rs @@ -12,10 +12,12 @@ trait MyTrait {} +#[allow(auto_impl)] impl MyTrait for .. {} unsafe trait MyUnsafeTrait {} +#[allow(auto_impl)] unsafe impl MyUnsafeTrait for .. {} struct ThisImplsTrait; diff --git a/src/test/compile-fail/typeck-default-trait-impl-outside-crate.rs b/src/test/compile-fail/typeck-default-trait-impl-outside-crate.rs index 4d71517e060..da3e926d6fc 100644 --- a/src/test/compile-fail/typeck-default-trait-impl-outside-crate.rs +++ b/src/test/compile-fail/typeck-default-trait-impl-outside-crate.rs @@ -10,6 +10,7 @@ #![feature(optin_builtin_traits)] +#[allow(auto_impl)] impl Copy for .. {} //~ ERROR E0318 //~^ NOTE `Copy` trait not defined in this crate fn main() {} diff --git a/src/test/compile-fail/typeck-default-trait-impl-precedence.rs b/src/test/compile-fail/typeck-default-trait-impl-precedence.rs index 66c7a1c75ff..bdd6487b86d 100644 --- a/src/test/compile-fail/typeck-default-trait-impl-precedence.rs +++ b/src/test/compile-fail/typeck-default-trait-impl-precedence.rs @@ -16,6 +16,7 @@ #![feature(optin_builtin_traits)] trait Defaulted { } +#[allow(auto_impl)] impl Defaulted for .. { } impl<'a,T:Signed> Defaulted for &'a T { } impl<'a,T:Signed> Defaulted for &'a mut T { } diff --git a/src/test/incremental/add_private_fn_at_krate_root_cc/struct_point.rs b/src/test/incremental/add_private_fn_at_krate_root_cc/struct_point.rs index 40067efd575..067ce51d0f7 100644 --- a/src/test/incremental/add_private_fn_at_krate_root_cc/struct_point.rs +++ b/src/test/incremental/add_private_fn_at_krate_root_cc/struct_point.rs @@ -12,27 +12,29 @@ // crate. This should not cause anything we use to be invalidated. // Regression test for #36168. -// revisions:rpass1 rpass2 +// revisions:cfail1 cfail2 // compile-flags: -Z query-dep-graph // aux-build:point.rs +// must-compile-successfully #![feature(rustc_attrs)] #![feature(stmt_expr_attributes)] #![allow(dead_code)] +#![crate_type = "rlib"] -#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_same_impl", cfg="rpass2")] -#![rustc_partition_reused(module="struct_point-fn_calls_free_fn", cfg="rpass2")] -#![rustc_partition_reused(module="struct_point-fn_read_field", cfg="rpass2")] -#![rustc_partition_reused(module="struct_point-fn_write_field", cfg="rpass2")] -#![rustc_partition_reused(module="struct_point-fn_make_struct", cfg="rpass2")] +#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_same_impl", cfg="cfail2")] +#![rustc_partition_reused(module="struct_point-fn_calls_free_fn", cfg="cfail2")] +#![rustc_partition_reused(module="struct_point-fn_read_field", cfg="cfail2")] +#![rustc_partition_reused(module="struct_point-fn_write_field", cfg="cfail2")] +#![rustc_partition_reused(module="struct_point-fn_make_struct", cfg="cfail2")] extern crate point; /// A fn item that calls (public) methods on `Point` from the same impl -mod fn_calls_methods_in_same_impl { +pub mod fn_calls_methods_in_same_impl { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] pub fn check() { let x = Point { x: 2.0, y: 2.0 }; x.distance_from_origin(); @@ -40,10 +42,10 @@ mod fn_calls_methods_in_same_impl { } /// A fn item that calls (public) methods on `Point` from another impl -mod fn_calls_free_fn { +pub mod fn_calls_free_fn { use point::{self, Point}; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] pub fn check() { let x = Point { x: 2.0, y: 2.0 }; point::distance_squared(&x); @@ -51,34 +53,31 @@ mod fn_calls_free_fn { } /// A fn item that makes an instance of `Point` but does not invoke methods -mod fn_make_struct { +pub mod fn_make_struct { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] 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 { +pub mod fn_read_field { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] 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 { +pub mod fn_write_field { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] pub fn inc_x(p: &mut Point) { p.x += 1.0; } } - -fn main() { -} diff --git a/src/test/incremental/change_add_field/struct_point.rs b/src/test/incremental/change_add_field/struct_point.rs index ac5c0d3b9e7..b1c566e1739 100644 --- a/src/test/incremental/change_add_field/struct_point.rs +++ b/src/test/incremental/change_add_field/struct_point.rs @@ -13,32 +13,34 @@ // Fns with that type used only in their body are also recompiled, but // their callers are not. -// revisions:rpass1 rpass2 +// revisions:cfail1 cfail2 // compile-flags: -Z query-dep-graph +// must-compile-successfully #![feature(rustc_attrs)] #![feature(stmt_expr_attributes)] #![allow(dead_code)] +#![crate_type = "rlib"] // These are expected to require translation. -#![rustc_partition_translated(module="struct_point-point", cfg="rpass2")] -#![rustc_partition_translated(module="struct_point-fn_with_type_in_sig", cfg="rpass2")] -#![rustc_partition_translated(module="struct_point-call_fn_with_type_in_sig", cfg="rpass2")] -#![rustc_partition_translated(module="struct_point-fn_with_type_in_body", cfg="rpass2")] -#![rustc_partition_translated(module="struct_point-fn_make_struct", cfg="rpass2")] -#![rustc_partition_translated(module="struct_point-fn_read_field", cfg="rpass2")] -#![rustc_partition_translated(module="struct_point-fn_write_field", cfg="rpass2")] - -#![rustc_partition_reused(module="struct_point-call_fn_with_type_in_body", cfg="rpass2")] - -mod point { - #[cfg(rpass1)] +#![rustc_partition_translated(module="struct_point-point", cfg="cfail2")] +#![rustc_partition_translated(module="struct_point-fn_with_type_in_sig", cfg="cfail2")] +#![rustc_partition_translated(module="struct_point-call_fn_with_type_in_sig", cfg="cfail2")] +#![rustc_partition_translated(module="struct_point-fn_with_type_in_body", cfg="cfail2")] +#![rustc_partition_translated(module="struct_point-fn_make_struct", cfg="cfail2")] +#![rustc_partition_translated(module="struct_point-fn_read_field", cfg="cfail2")] +#![rustc_partition_translated(module="struct_point-fn_write_field", cfg="cfail2")] + +#![rustc_partition_reused(module="struct_point-call_fn_with_type_in_body", cfg="cfail2")] + +pub mod point { + #[cfg(cfail1)] pub struct Point { pub x: f32, pub y: f32, } - #[cfg(rpass2)] + #[cfg(cfail2)] pub struct Point { pub x: f32, pub y: f32, @@ -47,18 +49,18 @@ mod point { impl Point { pub fn origin() -> Point { - #[cfg(rpass1)] + #[cfg(cfail1)] return Point { x: 0.0, y: 0.0 }; - #[cfg(rpass2)] + #[cfg(cfail2)] return Point { x: 0.0, y: 0.0, z: 0.0 }; } pub fn total(&self) -> f32 { - #[cfg(rpass1)] + #[cfg(cfail1)] return self.x + self.y; - #[cfg(rpass2)] + #[cfg(cfail2)] return self.x + self.y + self.z; } @@ -75,10 +77,10 @@ mod point { /// sufficiently "private", we might not need to type-check again. /// Rebuilding is probably always necessary since the layout may be /// affected. -mod fn_with_type_in_sig { +pub mod fn_with_type_in_sig { use point::Point; - #[rustc_dirty(label="TypeckTables", cfg="rpass2")] + #[rustc_dirty(label="TypeckTables", cfg="cfail2")] pub fn boop(p: Option<&Point>) -> f32 { p.map(|p| p.total()).unwrap_or(0.0) } @@ -91,10 +93,10 @@ mod fn_with_type_in_sig { /// sufficiently "private", we might not need to type-check again. /// Rebuilding is probably always necessary since the layout may be /// affected. -mod call_fn_with_type_in_sig { +pub mod call_fn_with_type_in_sig { use fn_with_type_in_sig; - #[rustc_dirty(label="TypeckTables", cfg="rpass2")] + #[rustc_dirty(label="TypeckTables", cfg="cfail2")] pub fn bip() -> f32 { fn_with_type_in_sig::boop(None) } @@ -107,10 +109,10 @@ mod call_fn_with_type_in_sig { /// sufficiently "private", we might not need to type-check again. /// Rebuilding is probably always necessary since the layout may be /// affected. -mod fn_with_type_in_body { +pub mod fn_with_type_in_body { use point::Point; - #[rustc_dirty(label="TypeckTables", cfg="rpass2")] + #[rustc_dirty(label="TypeckTables", cfg="cfail2")] pub fn boop() -> f32 { Point::origin().total() } @@ -120,44 +122,41 @@ mod fn_with_type_in_body { /// body. In this case, the effects of the change should be contained /// to Y; X should not have to be rebuilt, nor should it need to be /// typechecked again. -mod call_fn_with_type_in_body { +pub mod call_fn_with_type_in_body { use fn_with_type_in_body; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] pub fn bip() -> f32 { fn_with_type_in_body::boop() } } /// A fn item that makes an instance of `Point` but does not invoke methods -mod fn_make_struct { +pub mod fn_make_struct { use point::Point; - #[rustc_dirty(label="TypeckTables", cfg="rpass2")] + #[rustc_dirty(label="TypeckTables", cfg="cfail2")] pub fn make_origin(p: Point) -> Point { Point { ..p } } } /// A fn item that reads fields from `Point` but does not invoke methods -mod fn_read_field { +pub mod fn_read_field { use point::Point; - #[rustc_dirty(label="TypeckTables", cfg="rpass2")] + #[rustc_dirty(label="TypeckTables", cfg="cfail2")] 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 { +pub mod fn_write_field { use point::Point; - #[rustc_dirty(label="TypeckTables", cfg="rpass2")] + #[rustc_dirty(label="TypeckTables", cfg="cfail2")] pub fn inc_x(p: &mut Point) { p.x += 1.0; } } - -fn main() { -} diff --git a/src/test/incremental/change_private_fn/struct_point.rs b/src/test/incremental/change_private_fn/struct_point.rs index abfd55ba52c..d8251a4fbcf 100644 --- a/src/test/incremental/change_private_fn/struct_point.rs +++ b/src/test/incremental/change_private_fn/struct_point.rs @@ -11,32 +11,34 @@ // 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 +// revisions:cfail1 cfail2 // compile-flags: -Z query-dep-graph +// must-compile-successfully #![feature(rustc_attrs)] #![feature(stmt_expr_attributes)] #![allow(dead_code)] +#![crate_type = "rlib"] -#![rustc_partition_translated(module="struct_point-point", cfg="rpass2")] +#![rustc_partition_translated(module="struct_point-point", cfg="cfail2")] -#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_same_impl", cfg="rpass2")] -#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_another_impl", cfg="rpass2")] -#![rustc_partition_reused(module="struct_point-fn_make_struct", cfg="rpass2")] -#![rustc_partition_reused(module="struct_point-fn_read_field", cfg="rpass2")] -#![rustc_partition_reused(module="struct_point-fn_write_field", cfg="rpass2")] +#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_same_impl", cfg="cfail2")] +#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_another_impl", cfg="cfail2")] +#![rustc_partition_reused(module="struct_point-fn_make_struct", cfg="cfail2")] +#![rustc_partition_reused(module="struct_point-fn_read_field", cfg="cfail2")] +#![rustc_partition_reused(module="struct_point-fn_write_field", cfg="cfail2")] -mod point { +pub mod point { pub struct Point { pub x: f32, pub y: f32, } fn distance_squared(this: &Point) -> f32 { - #[cfg(rpass1)] + #[cfg(cfail1)] return this.x + this.y; - #[cfg(rpass2)] + #[cfg(cfail2)] return this.x * this.x + this.y * this.y; } @@ -56,10 +58,10 @@ mod point { } /// A fn item that calls (public) methods on `Point` from the same impl which changed -mod fn_calls_methods_in_same_impl { +pub mod fn_calls_methods_in_same_impl { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] pub fn check() { let x = Point { x: 2.0, y: 2.0 }; x.distance_from_origin(); @@ -67,10 +69,10 @@ mod fn_calls_methods_in_same_impl { } /// A fn item that calls (public) methods on `Point` from another impl -mod fn_calls_methods_in_another_impl { +pub mod fn_calls_methods_in_another_impl { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] pub fn check() { let mut x = Point { x: 2.0, y: 2.0 }; x.translate(3.0, 3.0); @@ -78,34 +80,31 @@ mod fn_calls_methods_in_another_impl { } /// A fn item that makes an instance of `Point` but does not invoke methods -mod fn_make_struct { +pub mod fn_make_struct { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] 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 { +pub mod fn_read_field { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] 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 { +pub mod fn_write_field { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] pub fn inc_x(p: &mut Point) { p.x += 1.0; } } - -fn main() { -} diff --git a/src/test/incremental/change_private_fn_cc/auxiliary/point.rs b/src/test/incremental/change_private_fn_cc/auxiliary/point.rs index dcc1ced635f..af20336806f 100644 --- a/src/test/incremental/change_private_fn_cc/auxiliary/point.rs +++ b/src/test/incremental/change_private_fn_cc/auxiliary/point.rs @@ -14,10 +14,10 @@ pub struct Point { } fn distance_squared(this: &Point) -> f32 { - #[cfg(rpass1)] + #[cfg(cfail1)] return this.x + this.y; - #[cfg(rpass2)] + #[cfg(cfail2)] return this.x * this.x + this.y * this.y; } diff --git a/src/test/incremental/change_private_fn_cc/struct_point.rs b/src/test/incremental/change_private_fn_cc/struct_point.rs index a6d029515d7..b3816b90194 100644 --- a/src/test/incremental/change_private_fn_cc/struct_point.rs +++ b/src/test/incremental/change_private_fn_cc/struct_point.rs @@ -11,27 +11,29 @@ // 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 +// revisions:cfail1 cfail2 // compile-flags: -Z query-dep-graph // aux-build:point.rs +// must-compile-successfully +#![crate_type = "rlib"] #![feature(rustc_attrs)] #![feature(stmt_expr_attributes)] #![allow(dead_code)] -#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_same_impl", cfg="rpass2")] -#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_another_impl", cfg="rpass2")] -#![rustc_partition_reused(module="struct_point-fn_read_field", cfg="rpass2")] -#![rustc_partition_reused(module="struct_point-fn_write_field", cfg="rpass2")] -#![rustc_partition_reused(module="struct_point-fn_make_struct", cfg="rpass2")] +#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_same_impl", cfg="cfail2")] +#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_another_impl", cfg="cfail2")] +#![rustc_partition_reused(module="struct_point-fn_read_field", cfg="cfail2")] +#![rustc_partition_reused(module="struct_point-fn_write_field", cfg="cfail2")] +#![rustc_partition_reused(module="struct_point-fn_make_struct", cfg="cfail2")] extern crate point; /// A fn item that calls (public) methods on `Point` from the same impl which changed -mod fn_calls_methods_in_same_impl { +pub mod fn_calls_methods_in_same_impl { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] pub fn check() { let x = Point { x: 2.0, y: 2.0 }; x.distance_from_origin(); @@ -39,10 +41,10 @@ mod fn_calls_methods_in_same_impl { } /// A fn item that calls (public) methods on `Point` from another impl -mod fn_calls_methods_in_another_impl { +pub mod fn_calls_methods_in_another_impl { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] pub fn check() { let mut x = Point { x: 2.0, y: 2.0 }; x.translate(3.0, 3.0); @@ -50,34 +52,31 @@ mod fn_calls_methods_in_another_impl { } /// A fn item that makes an instance of `Point` but does not invoke methods -mod fn_make_struct { +pub mod fn_make_struct { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] 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 { +pub mod fn_read_field { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] 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 { +pub mod fn_write_field { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] pub fn inc_x(p: &mut Point) { p.x += 1.0; } } - -fn main() { -} diff --git a/src/test/incremental/change_private_impl_method/struct_point.rs b/src/test/incremental/change_private_impl_method/struct_point.rs index d8c6cafe596..c18f95a6312 100644 --- a/src/test/incremental/change_private_impl_method/struct_point.rs +++ b/src/test/incremental/change_private_impl_method/struct_point.rs @@ -11,33 +11,35 @@ // 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 +// revisions:cfail1 cfail2 // compile-flags: -Z query-dep-graph +// must-compile-successfully #![feature(rustc_attrs)] #![feature(stmt_expr_attributes)] #![allow(dead_code)] +#![crate_type = "rlib"] -#![rustc_partition_translated(module="struct_point-point", cfg="rpass2")] +#![rustc_partition_translated(module="struct_point-point", cfg="cfail2")] -#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_same_impl", cfg="rpass2")] -#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_another_impl", cfg="rpass2")] -#![rustc_partition_reused(module="struct_point-fn_make_struct", cfg="rpass2")] -#![rustc_partition_reused(module="struct_point-fn_read_field", cfg="rpass2")] -#![rustc_partition_reused(module="struct_point-fn_write_field", cfg="rpass2")] +#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_same_impl", cfg="cfail2")] +#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_another_impl", cfg="cfail2")] +#![rustc_partition_reused(module="struct_point-fn_make_struct", cfg="cfail2")] +#![rustc_partition_reused(module="struct_point-fn_read_field", cfg="cfail2")] +#![rustc_partition_reused(module="struct_point-fn_write_field", cfg="cfail2")] -mod point { +pub mod point { pub struct Point { pub x: f32, pub y: f32, } impl Point { - fn distance_squared(&self) -> f32 { - #[cfg(rpass1)] + pub fn distance_squared(&self) -> f32 { + #[cfg(cfail1)] return self.x + self.y; - #[cfg(rpass2)] + #[cfg(cfail2)] return self.x * self.x + self.y * self.y; } @@ -56,10 +58,10 @@ mod point { } /// A fn item that calls (public) methods on `Point` from the same impl which changed -mod fn_calls_methods_in_same_impl { +pub mod fn_calls_methods_in_same_impl { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] pub fn check() { let x = Point { x: 2.0, y: 2.0 }; x.distance_from_origin(); @@ -67,10 +69,10 @@ mod fn_calls_methods_in_same_impl { } /// A fn item that calls (public) methods on `Point` from another impl -mod fn_calls_methods_in_another_impl { +pub mod fn_calls_methods_in_another_impl { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] pub fn check() { let mut x = Point { x: 2.0, y: 2.0 }; x.translate(3.0, 3.0); @@ -78,34 +80,31 @@ mod fn_calls_methods_in_another_impl { } /// A fn item that makes an instance of `Point` but does not invoke methods -mod fn_make_struct { +pub mod fn_make_struct { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] 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 { +pub mod fn_read_field { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] 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 { +pub mod fn_write_field { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] pub fn inc_x(p: &mut Point) { p.x += 1.0; } } - -fn main() { -} diff --git a/src/test/incremental/change_private_impl_method_cc/auxiliary/point.rs b/src/test/incremental/change_private_impl_method_cc/auxiliary/point.rs index 8df1cf54da2..f5e3a06051c 100644 --- a/src/test/incremental/change_private_impl_method_cc/auxiliary/point.rs +++ b/src/test/incremental/change_private_impl_method_cc/auxiliary/point.rs @@ -15,10 +15,10 @@ pub struct Point { impl Point { fn distance_squared(&self) -> f32 { - #[cfg(rpass1)] + #[cfg(cfail1)] return self.x + self.y; - #[cfg(rpass2)] + #[cfg(cfail2)] return self.x * self.x + self.y * self.y; } diff --git a/src/test/incremental/change_private_impl_method_cc/struct_point.rs b/src/test/incremental/change_private_impl_method_cc/struct_point.rs index 05c076b9f4b..55e1dffe9da 100644 --- a/src/test/incremental/change_private_impl_method_cc/struct_point.rs +++ b/src/test/incremental/change_private_impl_method_cc/struct_point.rs @@ -11,28 +11,30 @@ // 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 +// revisions:cfail1 cfail2 // compile-flags: -Z query-dep-graph // aux-build:point.rs +// must-compile-successfully +#![crate_type = "rlib"] #![feature(rustc_attrs)] #![feature(stmt_expr_attributes)] #![allow(dead_code)] -#![rustc_partition_reused(module="struct_point-fn_read_field", cfg="rpass2")] -#![rustc_partition_reused(module="struct_point-fn_write_field", cfg="rpass2")] -#![rustc_partition_reused(module="struct_point-fn_make_struct", cfg="rpass2")] +#![rustc_partition_reused(module="struct_point-fn_read_field", cfg="cfail2")] +#![rustc_partition_reused(module="struct_point-fn_write_field", cfg="cfail2")] +#![rustc_partition_reused(module="struct_point-fn_make_struct", cfg="cfail2")] -#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_same_impl", cfg="rpass2")] -#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_another_impl", cfg="rpass2")] +#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_same_impl", cfg="cfail2")] +#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_another_impl", cfg="cfail2")] extern crate point; /// A fn item that calls (public) methods on `Point` from the same impl which changed -mod fn_calls_methods_in_same_impl { +pub mod fn_calls_methods_in_same_impl { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] pub fn check() { let x = Point { x: 2.0, y: 2.0 }; x.distance_from_origin(); @@ -40,10 +42,10 @@ mod fn_calls_methods_in_same_impl { } /// A fn item that calls (public) methods on `Point` from another impl -mod fn_calls_methods_in_another_impl { +pub mod fn_calls_methods_in_another_impl { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] pub fn dirty() { let mut x = Point { x: 2.0, y: 2.0 }; x.translate(3.0, 3.0); @@ -51,34 +53,31 @@ mod fn_calls_methods_in_another_impl { } /// A fn item that makes an instance of `Point` but does not invoke methods -mod fn_make_struct { +pub mod fn_make_struct { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] 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 { +pub mod fn_read_field { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] 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 { +pub mod fn_write_field { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] pub fn inc_x(p: &mut Point) { p.x += 1.0; } } - -fn main() { -} diff --git a/src/test/incremental/change_pub_inherent_method_body/struct_point.rs b/src/test/incremental/change_pub_inherent_method_body/struct_point.rs index 5b29ee1435f..2cb7ef13f8e 100644 --- a/src/test/incremental/change_pub_inherent_method_body/struct_point.rs +++ b/src/test/incremental/change_pub_inherent_method_body/struct_point.rs @@ -10,22 +10,24 @@ // Test where we change the body of a public, inherent method. -// revisions:rpass1 rpass2 +// revisions:cfail1 cfail2 // compile-flags: -Z query-dep-graph +// must-compile-successfully +#![crate_type = "rlib"] #![feature(rustc_attrs)] #![feature(stmt_expr_attributes)] #![allow(dead_code)] -#![rustc_partition_translated(module="struct_point-point", cfg="rpass2")] +#![rustc_partition_translated(module="struct_point-point", cfg="cfail2")] -#![rustc_partition_reused(module="struct_point-fn_calls_changed_method", cfg="rpass2")] -#![rustc_partition_reused(module="struct_point-fn_calls_another_method", 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")] +#![rustc_partition_reused(module="struct_point-fn_calls_changed_method", cfg="cfail2")] +#![rustc_partition_reused(module="struct_point-fn_calls_another_method", cfg="cfail2")] +#![rustc_partition_reused(module="struct_point-fn_make_struct", cfg="cfail2")] +#![rustc_partition_reused(module="struct_point-fn_read_field", cfg="cfail2")] +#![rustc_partition_reused(module="struct_point-fn_write_field", cfg="cfail2")] -mod point { +pub mod point { pub struct Point { pub x: f32, pub y: f32, @@ -33,10 +35,10 @@ mod point { impl Point { pub fn distance_from_origin(&self) -> f32 { - #[cfg(rpass1)] + #[cfg(cfail1)] return self.x * self.x + self.y * self.y; - #[cfg(rpass2)] + #[cfg(cfail2)] return (self.x * self.x + self.y * self.y).sqrt(); } @@ -47,10 +49,10 @@ mod point { } /// A fn item that calls the method on `Point` which changed -mod fn_calls_changed_method { +pub mod fn_calls_changed_method { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] pub fn check() { let p = Point { x: 2.0, y: 2.0 }; p.distance_from_origin(); @@ -58,10 +60,10 @@ mod fn_calls_changed_method { } /// A fn item that calls a method on `Point` which did not change -mod fn_calls_another_method { +pub mod fn_calls_another_method { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] pub fn check() { let p = Point { x: 2.0, y: 2.0 }; p.x(); @@ -69,34 +71,31 @@ mod fn_calls_another_method { } /// A fn item that makes an instance of `Point` but does not invoke methods -mod fn_make_struct { +pub mod fn_make_struct { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] 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 { +pub mod fn_read_field { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] 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 { +pub mod fn_write_field { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] pub fn inc_x(p: &mut Point) { p.x += 1.0; } } - -fn main() { -} diff --git a/src/test/incremental/change_pub_inherent_method_sig/struct_point.rs b/src/test/incremental/change_pub_inherent_method_sig/struct_point.rs index 4d12b7b390c..f2485a876cc 100644 --- a/src/test/incremental/change_pub_inherent_method_sig/struct_point.rs +++ b/src/test/incremental/change_pub_inherent_method_sig/struct_point.rs @@ -10,30 +10,32 @@ // Test where we change the *signature* of a public, inherent method. -// revisions:rpass1 rpass2 +// revisions:cfail1 cfail2 // compile-flags: -Z query-dep-graph +// must-compile-successfully +#![crate_type = "rlib"] #![feature(rustc_attrs)] #![feature(stmt_expr_attributes)] #![allow(dead_code)] // These are expected to require translation. -#![rustc_partition_translated(module="struct_point-point", cfg="rpass2")] -#![rustc_partition_translated(module="struct_point-fn_calls_changed_method", cfg="rpass2")] +#![rustc_partition_translated(module="struct_point-point", cfg="cfail2")] +#![rustc_partition_translated(module="struct_point-fn_calls_changed_method", cfg="cfail2")] -#![rustc_partition_reused(module="struct_point-fn_calls_another_method", 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")] +#![rustc_partition_reused(module="struct_point-fn_calls_another_method", cfg="cfail2")] +#![rustc_partition_reused(module="struct_point-fn_make_struct", cfg="cfail2")] +#![rustc_partition_reused(module="struct_point-fn_read_field", cfg="cfail2")] +#![rustc_partition_reused(module="struct_point-fn_write_field", cfg="cfail2")] -mod point { +pub mod point { pub struct Point { pub x: f32, pub y: f32, } impl Point { - #[cfg(rpass1)] + #[cfg(cfail1)] pub fn distance_from_point(&self, p: Option<Point>) -> f32 { let p = p.unwrap_or(Point { x: 0.0, y: 0.0 }); let x_diff = self.x - p.x; @@ -41,7 +43,7 @@ mod point { return x_diff * x_diff + y_diff * y_diff; } - #[cfg(rpass2)] + #[cfg(cfail2)] pub fn distance_from_point(&self, p: Option<&Point>) -> f32 { const ORIGIN: &Point = &Point { x: 0.0, y: 0.0 }; let p = p.unwrap_or(ORIGIN); @@ -57,10 +59,10 @@ mod point { } /// A fn item that calls the method that was changed -mod fn_calls_changed_method { +pub mod fn_calls_changed_method { use point::Point; - #[rustc_dirty(label="TypeckTables", cfg="rpass2")] + #[rustc_dirty(label="TypeckTables", cfg="cfail2")] pub fn check() { let p = Point { x: 2.0, y: 2.0 }; p.distance_from_point(None); @@ -68,10 +70,10 @@ mod fn_calls_changed_method { } /// A fn item that calls a method that was not changed -mod fn_calls_another_method { +pub mod fn_calls_another_method { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] pub fn check() { let p = Point { x: 2.0, y: 2.0 }; p.x(); @@ -79,34 +81,31 @@ mod fn_calls_another_method { } /// A fn item that makes an instance of `Point` but does not invoke methods -mod fn_make_struct { +pub mod fn_make_struct { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] 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 { +pub mod fn_read_field { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] 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 { +pub mod fn_write_field { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] pub fn inc_x(p: &mut Point) { p.x += 1.0; } } - -fn main() { -} diff --git a/src/test/incremental/hashes/call_expressions.rs b/src/test/incremental/hashes/call_expressions.rs index 0090c2aeef9..b49609cbd17 100644 --- a/src/test/incremental/hashes/call_expressions.rs +++ b/src/test/incremental/hashes/call_expressions.rs @@ -190,7 +190,7 @@ impl Struct2 { } // Change UFCS Callee Indirectly ----------------------------------------------- -mod change_ufcs_callee_indirectly { +pub mod change_ufcs_callee_indirectly { #[cfg(cfail1)] use super::Struct as Struct; #[cfg(not(cfail1))] diff --git a/src/test/incremental/hashes/enum_constructors.rs b/src/test/incremental/hashes/enum_constructors.rs index f826d47c3e5..e38fd58d7d2 100644 --- a/src/test/incremental/hashes/enum_constructors.rs +++ b/src/test/incremental/hashes/enum_constructors.rs @@ -25,7 +25,7 @@ #![crate_type="rlib"] -enum Enum { +pub enum Enum { Struct { x: i32, y: i64, @@ -36,7 +36,7 @@ enum Enum { // Change field value (struct-like) ----------------------------------------- #[cfg(cfail1)] -fn change_field_value_struct_like() -> Enum { +pub fn change_field_value_struct_like() -> Enum { Enum::Struct { x: 0, y: 1, @@ -49,7 +49,7 @@ fn change_field_value_struct_like() -> Enum { #[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -fn change_field_value_struct_like() -> Enum { +pub fn change_field_value_struct_like() -> Enum { Enum::Struct { x: 0, y: 2, @@ -61,7 +61,7 @@ fn change_field_value_struct_like() -> Enum { // Change field order (struct-like) ----------------------------------------- #[cfg(cfail1)] -fn change_field_order_struct_like() -> Enum { +pub fn change_field_order_struct_like() -> Enum { Enum::Struct { x: 3, y: 4, @@ -76,7 +76,7 @@ fn change_field_order_struct_like() -> Enum { #[rustc_metadata_clean(cfg="cfail3")] // FIXME(michaelwoerister):Interesting. I would have thought that that changes the MIR. And it // would if it were not all constants -fn change_field_order_struct_like() -> Enum { +pub fn change_field_order_struct_like() -> Enum { Enum::Struct { y: 4, x: 3, @@ -85,7 +85,7 @@ fn change_field_order_struct_like() -> Enum { } -enum Enum2 { +pub enum Enum2 { Struct { x: i8, y: i8, @@ -102,7 +102,7 @@ enum Enum2 { // Change constructor path (struct-like) ------------------------------------ #[cfg(cfail1)] -fn change_constructor_path_struct_like() { +pub fn change_constructor_path_struct_like() { let _ = Enum::Struct { x: 0, y: 1, @@ -115,7 +115,7 @@ fn change_constructor_path_struct_like() { #[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -fn change_constructor_path_struct_like() { +pub fn change_constructor_path_struct_like() { let _ = Enum2::Struct { x: 0, y: 1, @@ -127,7 +127,7 @@ fn change_constructor_path_struct_like() { // Change variant (regular struct) ------------------------------------ #[cfg(cfail1)] -fn change_constructor_variant_struct_like() { +pub fn change_constructor_variant_struct_like() { let _ = Enum2::Struct { x: 0, y: 1, @@ -140,7 +140,7 @@ fn change_constructor_variant_struct_like() { #[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -fn change_constructor_variant_struct_like() { +pub fn change_constructor_variant_struct_like() { let _ = Enum2::Struct2 { x: 0, y: 1, @@ -150,7 +150,7 @@ fn change_constructor_variant_struct_like() { // Change constructor path indirectly (struct-like) ------------------------- -mod change_constructor_path_indirectly_struct_like { +pub mod change_constructor_path_indirectly_struct_like { #[cfg(cfail1)] use super::Enum as TheEnum; #[cfg(not(cfail1))] @@ -164,7 +164,7 @@ mod change_constructor_path_indirectly_struct_like { #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] - fn function() -> TheEnum { + pub fn function() -> TheEnum { TheEnum::Struct { x: 0, y: 1, @@ -175,7 +175,7 @@ mod change_constructor_path_indirectly_struct_like { // Change constructor variant indirectly (struct-like) --------------------------- -mod change_constructor_variant_indirectly_struct_like { +pub mod change_constructor_variant_indirectly_struct_like { use super::Enum2; #[cfg(cfail1)] use super::Enum2::Struct as Variant; @@ -186,7 +186,7 @@ mod change_constructor_variant_indirectly_struct_like { #[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] - fn function() -> Enum2 { + pub fn function() -> Enum2 { Variant { x: 0, y: 1, @@ -198,7 +198,7 @@ mod change_constructor_variant_indirectly_struct_like { // Change field value (tuple-like) ------------------------------------------- #[cfg(cfail1)] -fn change_field_value_tuple_like() -> Enum { +pub fn change_field_value_tuple_like() -> Enum { Enum::Tuple(0, 1, 2) } @@ -207,7 +207,7 @@ fn change_field_value_tuple_like() -> Enum { #[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -fn change_field_value_tuple_like() -> Enum { +pub fn change_field_value_tuple_like() -> Enum { Enum::Tuple(0, 1, 3) } @@ -215,7 +215,7 @@ fn change_field_value_tuple_like() -> Enum { // Change constructor path (tuple-like) -------------------------------------- #[cfg(cfail1)] -fn change_constructor_path_tuple_like() { +pub fn change_constructor_path_tuple_like() { let _ = Enum::Tuple(0, 1, 2); } @@ -227,7 +227,7 @@ fn change_constructor_path_tuple_like() { #[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -fn change_constructor_path_tuple_like() { +pub fn change_constructor_path_tuple_like() { let _ = Enum2::Tuple(0, 1, 2); } @@ -235,7 +235,7 @@ fn change_constructor_path_tuple_like() { // Change constructor variant (tuple-like) -------------------------------------- #[cfg(cfail1)] -fn change_constructor_variant_tuple_like() { +pub fn change_constructor_variant_tuple_like() { let _ = Enum2::Tuple(0, 1, 2); } @@ -247,13 +247,13 @@ fn change_constructor_variant_tuple_like() { #[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -fn change_constructor_variant_tuple_like() { +pub fn change_constructor_variant_tuple_like() { let _ = Enum2::Tuple2(0, 1, 2); } // Change constructor path indirectly (tuple-like) --------------------------- -mod change_constructor_path_indirectly_tuple_like { +pub mod change_constructor_path_indirectly_tuple_like { #[cfg(cfail1)] use super::Enum as TheEnum; #[cfg(not(cfail1))] @@ -267,7 +267,7 @@ mod change_constructor_path_indirectly_tuple_like { #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] - fn function() -> TheEnum { + pub fn function() -> TheEnum { TheEnum::Tuple(0, 1, 2) } } @@ -275,7 +275,7 @@ mod change_constructor_path_indirectly_tuple_like { // Change constructor variant indirectly (tuple-like) --------------------------- -mod change_constructor_variant_indirectly_tuple_like { +pub mod change_constructor_variant_indirectly_tuple_like { use super::Enum2; #[cfg(cfail1)] use super::Enum2::Tuple as Variant; @@ -286,19 +286,19 @@ mod change_constructor_variant_indirectly_tuple_like { #[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] - fn function() -> Enum2 { + pub fn function() -> Enum2 { Variant(0, 1, 2) } } -enum Clike { +pub enum Clike { A, B, C } -enum Clike2 { +pub enum Clike2 { B, C, D @@ -306,7 +306,7 @@ enum Clike2 { // Change constructor path (C-like) -------------------------------------- #[cfg(cfail1)] -fn change_constructor_path_c_like() { +pub fn change_constructor_path_c_like() { let _ = Clike::B; } @@ -314,7 +314,7 @@ fn change_constructor_path_c_like() { #[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated,TypeckTables")] #[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail3")] -fn change_constructor_path_c_like() { +pub fn change_constructor_path_c_like() { let _ = Clike2::B; } @@ -322,7 +322,7 @@ fn change_constructor_path_c_like() { // Change constructor variant (C-like) -------------------------------------- #[cfg(cfail1)] -fn change_constructor_variant_c_like() { +pub fn change_constructor_variant_c_like() { let _ = Clike::A; } @@ -331,13 +331,13 @@ fn change_constructor_variant_c_like() { #[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -fn change_constructor_variant_c_like() { +pub fn change_constructor_variant_c_like() { let _ = Clike::C; } // Change constructor path indirectly (C-like) --------------------------- -mod change_constructor_path_indirectly_c_like { +pub mod change_constructor_path_indirectly_c_like { #[cfg(cfail1)] use super::Clike as TheEnum; #[cfg(not(cfail1))] @@ -351,7 +351,7 @@ mod change_constructor_path_indirectly_c_like { #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] - fn function() -> TheEnum { + pub fn function() -> TheEnum { TheEnum::B } } @@ -359,7 +359,7 @@ mod change_constructor_path_indirectly_c_like { // Change constructor variant indirectly (C-like) --------------------------- -mod change_constructor_variant_indirectly_c_like { +pub mod change_constructor_variant_indirectly_c_like { use super::Clike; #[cfg(cfail1)] use super::Clike::A as Variant; @@ -370,7 +370,7 @@ mod change_constructor_variant_indirectly_c_like { #[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] - fn function() -> Clike { + pub fn function() -> Clike { Variant } } diff --git a/src/test/incremental/hashes/inherent_impls.rs b/src/test/incremental/hashes/inherent_impls.rs index 9351a4b05f1..f9e8fb026ca 100644 --- a/src/test/incremental/hashes/inherent_impls.rs +++ b/src/test/incremental/hashes/inherent_impls.rs @@ -25,7 +25,7 @@ #![feature(rustc_attrs)] #![crate_type="rlib"] -struct Foo; +pub struct Foo; // Change Method Name ----------------------------------------------------------- #[cfg(cfail1)] @@ -578,3 +578,19 @@ impl<T: Clone> Bar<T> { #[rustc_metadata_clean(cfg="cfail3")] pub fn add_trait_bound_to_impl_parameter(&self) { } } + + +// Force instantiation of some fns so we can check their hash. +pub fn instantiation_root() { + Foo::method_privacy(); + + #[cfg(cfail1)] + { + Bar(0u32).change_impl_self_type(); + } + + #[cfg(not(cfail1))] + { + Bar(0u64).change_impl_self_type(); + } +} diff --git a/src/test/incremental/hashes/panic_exprs.rs b/src/test/incremental/hashes/panic_exprs.rs index 5d4d434fd63..4a3e4bc49ce 100644 --- a/src/test/incremental/hashes/panic_exprs.rs +++ b/src/test/incremental/hashes/panic_exprs.rs @@ -152,13 +152,48 @@ pub fn mod_by_zero(val: i32) -> i32 { } +// shift left ------------------------------------------------------------------ +#[cfg(cfail1)] +pub fn shift_left(val: i32, shift: usize) -> i32 { + val << shift +} + +#[cfg(not(cfail1))] +#[rustc_clean(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="HirBody", cfg="cfail2")] +#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn shift_left(val: i32, shift: usize) -> i32 { + val << shift +} + + +// shift right ------------------------------------------------------------------ +#[cfg(cfail1)] +pub fn shift_right(val: i32, shift: usize) -> i32 { + val >> shift +} + +#[cfg(not(cfail1))] +#[rustc_clean(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="HirBody", cfg="cfail2")] +#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn shift_right(val: i32, shift: usize) -> i32 { + val >> shift +} + // THE FOLLOWING ITEMS SHOULD NOT BE INFLUENCED BY THEIR SOURCE LOCATION // bitwise --------------------------------------------------------------------- #[cfg(cfail1)] pub fn bitwise(val: i32) -> i32 { - !val & 0x101010101 | 0x45689 ^ 0x2372382 << 1 >> 1 + !val & 0x101010101 | 0x45689 ^ 0x2372382 } #[cfg(not(cfail1))] @@ -169,7 +204,7 @@ pub fn bitwise(val: i32) -> i32 { #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn bitwise(val: i32) -> i32 { - !val & 0x101010101 | 0x45689 ^ 0x2372382 << 1 >> 1 + !val & 0x101010101 | 0x45689 ^ 0x2372382 } diff --git a/src/test/incremental/hashes/struct_constructors.rs b/src/test/incremental/hashes/struct_constructors.rs index 231e29b79c4..67362e31b25 100644 --- a/src/test/incremental/hashes/struct_constructors.rs +++ b/src/test/incremental/hashes/struct_constructors.rs @@ -25,7 +25,7 @@ #![crate_type="rlib"] -struct RegularStruct { +pub struct RegularStruct { x: i32, y: i64, z: i16, @@ -33,7 +33,7 @@ struct RegularStruct { // Change field value (regular struct) ----------------------------------------- #[cfg(cfail1)] -fn change_field_value_regular_struct() -> RegularStruct { +pub fn change_field_value_regular_struct() -> RegularStruct { RegularStruct { x: 0, y: 1, @@ -46,7 +46,7 @@ fn change_field_value_regular_struct() -> RegularStruct { #[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -fn change_field_value_regular_struct() -> RegularStruct { +pub fn change_field_value_regular_struct() -> RegularStruct { RegularStruct { x: 0, y: 2, @@ -58,7 +58,7 @@ fn change_field_value_regular_struct() -> RegularStruct { // Change field order (regular struct) ----------------------------------------- #[cfg(cfail1)] -fn change_field_order_regular_struct() -> RegularStruct { +pub fn change_field_order_regular_struct() -> RegularStruct { RegularStruct { x: 3, y: 4, @@ -71,7 +71,7 @@ fn change_field_order_regular_struct() -> RegularStruct { #[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -fn change_field_order_regular_struct() -> RegularStruct { +pub fn change_field_order_regular_struct() -> RegularStruct { RegularStruct { y: 4, x: 3, @@ -83,7 +83,7 @@ fn change_field_order_regular_struct() -> RegularStruct { // Add field (regular struct) -------------------------------------------------- #[cfg(cfail1)] -fn add_field_regular_struct() -> RegularStruct { +pub fn add_field_regular_struct() -> RegularStruct { let struct1 = RegularStruct { x: 3, y: 4, @@ -101,7 +101,7 @@ fn add_field_regular_struct() -> RegularStruct { #[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -fn add_field_regular_struct() -> RegularStruct { +pub fn add_field_regular_struct() -> RegularStruct { let struct1 = RegularStruct { x: 3, y: 4, @@ -119,7 +119,7 @@ fn add_field_regular_struct() -> RegularStruct { // Change field label (regular struct) ----------------------------------------- #[cfg(cfail1)] -fn change_field_label_regular_struct() -> RegularStruct { +pub fn change_field_label_regular_struct() -> RegularStruct { let struct1 = RegularStruct { x: 3, y: 4, @@ -138,7 +138,7 @@ fn change_field_label_regular_struct() -> RegularStruct { #[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -fn change_field_label_regular_struct() -> RegularStruct { +pub fn change_field_label_regular_struct() -> RegularStruct { let struct1 = RegularStruct { x: 3, y: 4, @@ -154,7 +154,7 @@ fn change_field_label_regular_struct() -> RegularStruct { -struct RegularStruct2 { +pub struct RegularStruct2 { x: i8, y: i8, z: i8, @@ -162,7 +162,7 @@ struct RegularStruct2 { // Change constructor path (regular struct) ------------------------------------ #[cfg(cfail1)] -fn change_constructor_path_regular_struct() { +pub fn change_constructor_path_regular_struct() { let _ = RegularStruct { x: 0, y: 1, @@ -175,7 +175,7 @@ fn change_constructor_path_regular_struct() { #[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -fn change_constructor_path_regular_struct() { +pub fn change_constructor_path_regular_struct() { let _ = RegularStruct2 { x: 0, y: 1, @@ -186,7 +186,7 @@ fn change_constructor_path_regular_struct() { // Change constructor path indirectly (regular struct) ------------------------- -mod change_constructor_path_indirectly_regular_struct { +pub mod change_constructor_path_indirectly_regular_struct { #[cfg(cfail1)] use super::RegularStruct as Struct; #[cfg(not(cfail1))] @@ -199,7 +199,7 @@ mod change_constructor_path_indirectly_regular_struct { #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] - fn function() -> Struct { + pub fn function() -> Struct { Struct { x: 0, y: 1, @@ -210,11 +210,11 @@ mod change_constructor_path_indirectly_regular_struct { -struct TupleStruct(i32, i64, i16); +pub struct TupleStruct(i32, i64, i16); // Change field value (tuple struct) ------------------------------------------- #[cfg(cfail1)] -fn change_field_value_tuple_struct() -> TupleStruct { +pub fn change_field_value_tuple_struct() -> TupleStruct { TupleStruct(0, 1, 2) } @@ -223,17 +223,17 @@ fn change_field_value_tuple_struct() -> TupleStruct { #[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -fn change_field_value_tuple_struct() -> TupleStruct { +pub fn change_field_value_tuple_struct() -> TupleStruct { TupleStruct(0, 1, 3) } -struct TupleStruct2(u16, u16, u16); +pub struct TupleStruct2(u16, u16, u16); // Change constructor path (tuple struct) -------------------------------------- #[cfg(cfail1)] -fn change_constructor_path_tuple_struct() { +pub fn change_constructor_path_tuple_struct() { let _ = TupleStruct(0, 1, 2); } @@ -242,14 +242,14 @@ fn change_constructor_path_tuple_struct() { #[rustc_clean(cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -fn change_constructor_path_tuple_struct() { +pub fn change_constructor_path_tuple_struct() { let _ = TupleStruct2(0, 1, 2); } // Change constructor path indirectly (tuple struct) --------------------------- -mod change_constructor_path_indirectly_tuple_struct { +pub mod change_constructor_path_indirectly_tuple_struct { #[cfg(cfail1)] use super::TupleStruct as Struct; #[cfg(not(cfail1))] @@ -262,7 +262,7 @@ mod change_constructor_path_indirectly_tuple_struct { #[rustc_clean(cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] - fn function() -> Struct { + pub fn function() -> Struct { Struct(0, 1, 2) } } diff --git a/src/test/incremental/hashes/trait_defs.rs b/src/test/incremental/hashes/trait_defs.rs index 44950ee8a60..108363a4645 100644 --- a/src/test/incremental/hashes/trait_defs.rs +++ b/src/test/incremental/hashes/trait_defs.rs @@ -249,7 +249,7 @@ trait TraitChangeMethodParametersOrder { // Add default implementation to method ------------------------------------------- #[cfg(cfail1)] -trait TraitAddMethodDefaultImplementation { +trait TraitAddMethodAutoImplementation { fn method(); } @@ -258,7 +258,7 @@ trait TraitAddMethodDefaultImplementation { #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -trait TraitAddMethodDefaultImplementation { +trait TraitAddMethodAutoImplementation { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] diff --git a/src/test/incremental/ich_nested_items.rs b/src/test/incremental/ich_nested_items.rs index e8e40d57b1e..2e0f0ba0837 100644 --- a/src/test/incremental/ich_nested_items.rs +++ b/src/test/incremental/ich_nested_items.rs @@ -11,29 +11,29 @@ // Check that the hash of `foo` doesn't change just because we ordered // the nested items (or even added new ones). -// revisions: rpass1 rpass2 +// revisions: cfail1 cfail2 +// must-compile-successfully +#![crate_type = "rlib"] #![feature(rustc_attrs)] -#[cfg(rpass1)] -fn foo() { - fn bar() { } - fn baz() { } +#[cfg(cfail1)] +pub fn foo() { + pub fn bar() { } + pub fn baz() { } } -#[cfg(rpass2)] -#[rustc_clean(label="Hir", cfg="rpass2")] -#[rustc_clean(label="HirBody", cfg="rpass2")] -fn foo() { - #[rustc_clean(label="Hir", cfg="rpass2")] - #[rustc_clean(label="HirBody", cfg="rpass2")] - fn baz() { } // order is different... +#[cfg(cfail2)] +#[rustc_clean(label="Hir", cfg="cfail2")] +#[rustc_dirty(label="HirBody", cfg="cfail2")] +pub fn foo() { + #[rustc_clean(label="Hir", cfg="cfail2")] + #[rustc_clean(label="HirBody", cfg="cfail2")] + pub fn baz() { } // order is different... - #[rustc_clean(label="Hir", cfg="rpass2")] - #[rustc_clean(label="HirBody", cfg="rpass2")] - fn bar() { } // but that doesn't matter. + #[rustc_clean(label="Hir", cfg="cfail2")] + #[rustc_clean(label="HirBody", cfg="cfail2")] + pub fn bar() { } // but that doesn't matter. - fn bap() { } // neither does adding a new item + pub fn bap() { } // neither does adding a new item } - -fn main() { } diff --git a/src/test/incremental/issue-38222.rs b/src/test/incremental/issue-38222.rs index 410ff69bf69..7bb8af74eeb 100644 --- a/src/test/incremental/issue-38222.rs +++ b/src/test/incremental/issue-38222.rs @@ -33,10 +33,9 @@ pub fn main() { mod mod1 { pub fn some_fn() { - let _ = 1; - } + #[cfg(rpass2)] + {} - #[cfg(rpass2)] - fn _some_other_fn() { + let _ = 1; } } diff --git a/src/test/incremental/krate-inherent.rs b/src/test/incremental/krate-inherent.rs index ac6cc3e9826..bc3e3a78fd6 100644 --- a/src/test/incremental/krate-inherent.rs +++ b/src/test/incremental/krate-inherent.rs @@ -8,27 +8,27 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// revisions: rpass1 rpass2 +// revisions: cfail1 cfail2 // compile-flags: -Z query-dep-graph +// must-compile-successfully #![allow(warnings)] #![feature(rustc_attrs)] -#![rustc_partition_reused(module="krate_inherent-x", cfg="rpass2")] +#![rustc_partition_reused(module="krate_inherent-x", cfg="cfail2")] +#![crate_type = "rlib"] -fn main() { } - -mod x { - struct Foo; +pub mod x { + pub struct Foo; impl Foo { - fn foo(&self) { } + pub fn foo(&self) { } } - fn method() { + pub fn method() { let x: Foo = Foo; x.foo(); // inherent methods used to add an edge from Krate } } -#[cfg(rpass1)] -fn bar() { } // remove this unrelated fn in rpass2, which should not affect `x::method` +#[cfg(cfail1)] +pub fn bar() { } // remove this unrelated fn in cfail2, which should not affect `x::method` diff --git a/src/test/incremental/krate-inlined.rs b/src/test/incremental/krate-inlined.rs index 043cb761da0..83b75116c60 100644 --- a/src/test/incremental/krate-inlined.rs +++ b/src/test/incremental/krate-inlined.rs @@ -20,12 +20,14 @@ #![rustc_partition_reused(module="krate_inlined-x", cfg="rpass2")] fn main() { + x::method(); + #[cfg(rpass2)] () } mod x { - fn method() { + pub fn method() { // use some methods that require inlining HIR from another crate: let mut v = vec![]; v.push(1); diff --git a/src/test/incremental/remove_source_file/main.rs b/src/test/incremental/remove_source_file/main.rs index 4ba33f3bb3d..3ae26c6aa45 100644 --- a/src/test/incremental/remove_source_file/main.rs +++ b/src/test/incremental/remove_source_file/main.rs @@ -11,21 +11,24 @@ // This test case makes sure that the compiler doesn't crash due to a failing // table lookup when a source file is removed. -// revisions:rpass1 rpass2 +// revisions:cfail1 cfail2 // Note that we specify -g so that the FileMaps actually get referenced by the // incr. comp. cache: // compile-flags: -Z query-dep-graph -g +// must-compile-successfully -#[cfg(rpass1)] +#![crate_type= "rlib"] + +#[cfg(cfail1)] mod auxiliary; -#[cfg(rpass1)] -fn main() { +#[cfg(cfail1)] +pub fn foo() { auxiliary::print_hello(); } -#[cfg(rpass2)] -fn main() { +#[cfg(cfail2)] +pub fn foo() { println!("hello"); } diff --git a/src/test/incremental/spans_in_type_debuginfo.rs b/src/test/incremental/spans_in_type_debuginfo.rs index 7d8e6c9d9d7..e1369d92c5c 100644 --- a/src/test/incremental/spans_in_type_debuginfo.rs +++ b/src/test/incremental/spans_in_type_debuginfo.rs @@ -14,7 +14,6 @@ // revisions:rpass1 rpass2 // compile-flags: -Z query-dep-graph -g -#![rustc_partition_reused(module="spans_in_type_debuginfo", cfg="rpass2")] #![rustc_partition_reused(module="spans_in_type_debuginfo-structs", cfg="rpass2")] #![rustc_partition_reused(module="spans_in_type_debuginfo-enums", cfg="rpass2")] diff --git a/src/test/incremental/string_constant.rs b/src/test/incremental/string_constant.rs index 760975b292f..3e75fa985ac 100644 --- a/src/test/incremental/string_constant.rs +++ b/src/test/incremental/string_constant.rs @@ -8,47 +8,48 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// revisions: rpass1 rpass2 +// revisions: cfail1 cfail2 // compile-flags: -Z query-dep-graph +// must-compile-successfully #![allow(warnings)] #![feature(rustc_attrs)] +#![crate_type = "rlib"] // Here the only thing which changes is the string constant in `x`. // Therefore, the compiler deduces (correctly) that typeck is not // needed even for callers of `x`. -fn main() { } -mod x { - #[cfg(rpass1)] +pub mod x { + #[cfg(cfail1)] pub fn x() { println!("{}", "1"); } - #[cfg(rpass2)] - #[rustc_dirty(label="HirBody", cfg="rpass2")] - #[rustc_dirty(label="MirOptimized", cfg="rpass2")] + #[cfg(cfail2)] + #[rustc_dirty(label="HirBody", cfg="cfail2")] + #[rustc_dirty(label="MirOptimized", cfg="cfail2")] pub fn x() { println!("{}", "2"); } } -mod y { +pub mod y { use x; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] - #[rustc_clean(label="MirOptimized", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="MirOptimized", cfg="cfail2")] pub fn y() { x::x(); } } -mod z { +pub mod z { use y; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] - #[rustc_clean(label="MirOptimized", cfg="rpass2")] + #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="MirOptimized", cfg="cfail2")] pub fn z() { y::y(); } diff --git a/src/test/incremental/warnings-reemitted.rs b/src/test/incremental/warnings-reemitted.rs new file mode 100644 index 00000000000..bf66ac7829c --- /dev/null +++ b/src/test/incremental/warnings-reemitted.rs @@ -0,0 +1,19 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// revisions: cfail1 cfail2 cfail3 +// compile-flags: -Coverflow-checks=on +// must-compile-successfully + +#![allow(warnings)] + +fn main() { + 255u8 + 1; //~ WARNING this expression will panic at run-time +} diff --git a/src/test/mir-opt/copy_propagation.rs b/src/test/mir-opt/copy_propagation.rs index a45e7f21023..69486f46137 100644 --- a/src/test/mir-opt/copy_propagation.rs +++ b/src/test/mir-opt/copy_propagation.rs @@ -13,7 +13,10 @@ fn test(x: u32) -> u32 { y } -fn main() { } +fn main() { + // Make sure the function actually gets instantiated. + test(0); +} // END RUST SOURCE // START rustc.node4.CopyPropagation.before.mir diff --git a/src/test/mir-opt/deaggregator_test.rs b/src/test/mir-opt/deaggregator_test.rs index 9fe17a277a7..f4db00dab59 100644 --- a/src/test/mir-opt/deaggregator_test.rs +++ b/src/test/mir-opt/deaggregator_test.rs @@ -18,7 +18,10 @@ fn bar(a: usize) -> Baz { Baz { x: a, y: 0.0, z: false } } -fn main() {} +fn main() { + // Make sure the function actually gets instantiated. + bar(0); +} // END RUST SOURCE // START rustc.node13.Deaggregator.before.mir diff --git a/src/test/mir-opt/deaggregator_test_enum_2.rs b/src/test/mir-opt/deaggregator_test_enum_2.rs index 2780f11b9e6..8e7207af0c6 100644 --- a/src/test/mir-opt/deaggregator_test_enum_2.rs +++ b/src/test/mir-opt/deaggregator_test_enum_2.rs @@ -23,7 +23,10 @@ fn test1(x: bool, y: i32) -> Foo { } } -fn main() {} +fn main() { + // Make sure the function actually gets instantiated. + test1(false, 0); +} // END RUST SOURCE // START rustc.node12.Deaggregator.before.mir diff --git a/src/test/mir-opt/deaggregator_test_multiple.rs b/src/test/mir-opt/deaggregator_test_multiple.rs index ede3b2e6e29..bc06ab67eaa 100644 --- a/src/test/mir-opt/deaggregator_test_multiple.rs +++ b/src/test/mir-opt/deaggregator_test_multiple.rs @@ -19,7 +19,10 @@ fn test(x: i32) -> [Foo; 2] { [Foo::A(x), Foo::A(x)] } -fn main() { } +fn main() { + // Make sure the function actually gets instantiated. + test(0); +} // END RUST SOURCE // START rustc.node10.Deaggregator.before.mir diff --git a/src/test/mir-opt/end_region_destruction_extents_1.rs b/src/test/mir-opt/end_region_destruction_extents_1.rs index 1f9ad988acc..61dc1d20659 100644 --- a/src/test/mir-opt/end_region_destruction_extents_1.rs +++ b/src/test/mir-opt/end_region_destruction_extents_1.rs @@ -133,11 +133,11 @@ unsafe impl<'a, #[may_dangle] 'b> Drop for D1<'a, 'b> { // StorageLive(_3); // StorageLive(_4); // StorageLive(_5); -// _5 = promoted1; +// _5 = promoted[1]; // _4 = &'12ds (*_5); // StorageLive(_7); // StorageLive(_8); -// _8 = promoted0; +// _8 = promoted[0]; // _7 = &'10s (*_8); // _3 = D1<'12ds, '10s>::{{constructor}}(_4, _7); // EndRegion('10s); diff --git a/src/test/mir-opt/issue-41110.rs b/src/test/mir-opt/issue-41110.rs index 384201b7c12..bfac6c739a3 100644 --- a/src/test/mir-opt/issue-41110.rs +++ b/src/test/mir-opt/issue-41110.rs @@ -14,6 +14,8 @@ fn main() { let x = S.other(S.id()); } +// no_mangle to make sure this gets instantiated even in an executable. +#[no_mangle] pub fn test() { let u = S; let mut v = S; diff --git a/src/test/mir-opt/match_false_edges.rs b/src/test/mir-opt/match_false_edges.rs new file mode 100644 index 00000000000..56c5dd3be47 --- /dev/null +++ b/src/test/mir-opt/match_false_edges.rs @@ -0,0 +1,240 @@ +// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z emit-end-regions -Z borrowck-mir + +fn guard() -> bool { + false +} + +fn guard2(_:i32) -> bool { + true +} + +// no_mangle to make sure this gets instantiated even in an executable. +#[no_mangle] +pub fn full_tested_match() { + let _ = match Some(42) { + Some(x) if guard() => (1, x), + Some(y) => (2, y), + None => (3, 3), + }; +} + +// no_mangle to make sure this gets instantiated even in an executable. +#[no_mangle] +pub fn full_tested_match2() { + let _ = match Some(42) { + Some(x) if guard() => (1, x), + None => (3, 3), + Some(y) => (2, y), + }; +} + +fn main() { + let _ = match Some(1) { + Some(_w) if guard() => 1, + _x => 2, + Some(y) if guard2(y) => 3, + _z => 4, + }; +} + +// END RUST SOURCE +// +// START rustc.node17.SimplifyBranches-initial.before.mir +// bb0: { +// ... +// _2 = std::option::Option<i32>::Some(const 42i32,); +// _5 = discriminant(_2); +// switchInt(_5) -> [0isize: bb5, otherwise: bb3]; +// } +// bb1: { // arm1 +// StorageLive(_7); +// _7 = _3; +// _1 = (const 1i32, _7); +// StorageDead(_7); +// goto -> bb11; +// } +// bb2: { // binding3(empty) and arm3 +// _1 = (const 3i32, const 3i32); +// goto -> bb11; +// } +// bb3: { +// falseEdges -> [real: bb7, imaginary: bb4]; //pre_binding1 +// } +// bb4: { +// falseEdges -> [real: bb10, imaginary: bb5]; //pre_binding2 +// } +// bb5: { +// falseEdges -> [real: bb2, imaginary: bb6]; //pre_binding3 +// } +// bb6: { +// unreachable; +// } +// bb7: { // binding1 and guard +// StorageLive(_3); +// _3 = ((_2 as Some).0: i32); +// StorageLive(_6); +// _6 = const guard() -> bb8; +// } +// bb8: { // end of guard +// switchInt(_6) -> [0u8: bb9, otherwise: bb1]; +// } +// bb9: { // to pre_binding2 +// falseEdges -> [real: bb4, imaginary: bb4]; +// } +// bb10: { // bindingNoLandingPads.before.mir2 and arm2 +// StorageLive(_4); +// _4 = ((_2 as Some).0: i32); +// StorageLive(_8); +// _8 = _4; +// _1 = (const 2i32, _8); +// StorageDead(_8); +// goto -> bb11; +// } +// bb11: { +// ... +// return; +// } +// END rustc.node17.SimplifyBranches-initial.before.mir +// +// START rustc.node42.SimplifyBranches-initial.before.mir +// bb0: { +// ... +// _2 = std::option::Option<i32>::Some(const 42i32,); +// _5 = discriminant(_2); +// switchInt(_5) -> [0isize: bb4, otherwise: bb3]; +// } +// bb1: { // arm1 +// StorageLive(_7); +// _7 = _3; +// _1 = (const 1i32, _7); +// StorageDead(_7); +// goto -> bb11; +// } +// bb2: { // binding3(empty) and arm3 +// _1 = (const 3i32, const 3i32); +// goto -> bb11; +// } +// bb3: { +// falseEdges -> [real: bb7, imaginary: bb4]; //pre_binding1 +// } +// bb4: { +// falseEdges -> [real: bb2, imaginary: bb5]; //pre_binding2 +// } +// bb5: { +// falseEdges -> [real: bb10, imaginary: bb6]; //pre_binding3 +// } +// bb6: { +// unreachable; +// } +// bb7: { // binding1 and guard +// StorageLive(_3); +// _3 = ((_2 as Some).0: i32); +// StorageLive(_6); +// _6 = const guard() -> bb8; +// } +// bb8: { // end of guard +// switchInt(_6) -> [0u8: bb9, otherwise: bb1]; +// } +// bb9: { // to pre_binding2 +// falseEdges -> [real: bb5, imaginary: bb4]; +// } +// bb10: { // binding2 and arm2 +// StorageLive(_4); +// _4 = ((_2 as Some).0: i32); +// StorageLive(_8); +// _8 = _4; +// _1 = (const 2i32, _8); +// StorageDead(_8); +// goto -> bb11; +// } +// bb11: { +// ... +// return; +// } +// END rustc.node42.SimplifyBranches-initial.before.mir +// +// START rustc.node67.SimplifyBranches-initial.before.mir +// bb0: { +// ... +// _2 = std::option::Option<i32>::Some(const 1i32,); +// _7 = discriminant(_2); +// switchInt(_7) -> [1isize: bb3, otherwise: bb4]; +// } +// bb1: { // arm1 +// _1 = const 1i32; +// goto -> bb16; +// } +// bb2: { // arm3 +// _1 = const 3i32; +// goto -> bb16; +// } +// +// bb3: { +// falseEdges -> [real: bb8, imaginary: bb4]; //pre_binding1 +// } +// bb4: { +// falseEdges -> [real: bb11, imaginary: bb5]; //pre_binding2 +// } +// bb5: { +// falseEdges -> [real: bb12, imaginary: bb6]; //pre_binding3 +// } +// bb6: { +// falseEdges -> [real: bb15, imaginary: bb7]; //pre_binding4 +// } +// bb7: { +// unreachable; +// } +// bb8: { // binding1: Some(w) if guard() +// StorageLive(_3); +// _3 = ((_2 as Some).0: i32); +// StorageLive(_8); +// _8 = const guard() -> bb9; +// } +// bb9: { //end of guard +// switchInt(_8) -> [0u8: bb10, otherwise: bb1]; +// } +// bb10: { // to pre_binding2 +// falseEdges -> [real: bb4, imaginary: bb4]; +// } +// bb11: { // binding2 & arm2 +// StorageLive(_4); +// _4 = _2; +// _1 = const 2i32; +// goto -> bb16; +// } +// bb12: { // binding3: Some(y) if guard2(y) +// StorageLive(_5); +// _5 = ((_2 as Some).0: i32); +// StorageLive(_10); +// StorageLive(_11); +// _11 = _5; +// _10 = const guard2(_11) -> bb13; +// } +// bb13: { // end of guard2 +// StorageDead(_11); +// switchInt(_10) -> [0u8: bb14, otherwise: bb2]; +// } +// bb14: { // to pre_binding4 +// falseEdges -> [real: bb6, imaginary: bb6]; +// } +// bb15: { // binding4 & arm4 +// StorageLive(_6); +// _6 = _2; +// _1 = const 4i32; +// goto -> bb16; +// } +// bb16: { +// ... +// return; +// } +// END rustc.node67.SimplifyBranches-initial.before.mir diff --git a/src/test/mir-opt/nll/liveness-call-subtlety.rs b/src/test/mir-opt/nll/liveness-call-subtlety.rs new file mode 100644 index 00000000000..873431505f5 --- /dev/null +++ b/src/test/mir-opt/nll/liveness-call-subtlety.rs @@ -0,0 +1,51 @@ +// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-Znll + +fn can_panic() -> Box<usize> { + Box::new(44) +} + +fn main() { + let mut x = Box::new(22); + x = can_panic(); +} + +// Check that: +// - `_1` is the variable corresponding to `x` +// and +// - `_1` is live when `can_panic` is called (because it may be dropped) +// +// END RUST SOURCE +// START rustc.node12.nll.0.mir +// | Live variables on entry to bb0: [] +// bb0: { +// | Live variables at bb0[0]: [] +// StorageLive(_1); +// | Live variables at bb0[1]: [] +// StorageLive(_2); +// | Live variables at bb0[2]: [] +// _2 = const 22usize; +// | Live variables at bb0[3]: [_2] +// _1 = const <std::boxed::Box<T>>::new(_2) -> bb1; +// } +// END rustc.node12.nll.0.mir +// START rustc.node12.nll.0.mir +// | Live variables on entry to bb1: [_1 (drop)] +// bb1: { +// | Live variables at bb1[0]: [_1 (drop)] +// StorageDead(_2); +// | Live variables at bb1[1]: [_1 (drop)] +// StorageLive(_3); +// | Live variables at bb1[2]: [_1 (drop)] +// _3 = const can_panic() -> [return: bb2, unwind: bb4]; +// } +// END rustc.node12.nll.0.mir diff --git a/src/test/mir-opt/nll/liveness-drop-intra-block.rs b/src/test/mir-opt/nll/liveness-drop-intra-block.rs new file mode 100644 index 00000000000..96fd29dfe2f --- /dev/null +++ b/src/test/mir-opt/nll/liveness-drop-intra-block.rs @@ -0,0 +1,41 @@ +// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-Znll + +#![allow(warnings)] + +fn use_x(_: usize) -> bool { true } + +fn main() { + let mut x = 22; + loop { + // Key point: `x` not live on entry to this basic block. + x = 55; + if use_x(x) { break; } + } +} + +// END RUST SOURCE +// START rustc.node12.nll.0.mir +// | Live variables on entry to bb1: [] +// bb1: { +// | Live variables at bb1[0]: [] +// _1 = const 55usize; +// | Live variables at bb1[1]: [_1] +// StorageLive(_3); +// | Live variables at bb1[2]: [_1] +// StorageLive(_4); +// | Live variables at bb1[3]: [_1] +// _4 = _1; +// | Live variables at bb1[4]: [_4] +// _3 = const use_x(_4) -> bb2; +// } +// END rustc.node12.nll.0.mir diff --git a/src/test/mir-opt/nll/liveness-interblock.rs b/src/test/mir-opt/nll/liveness-interblock.rs new file mode 100644 index 00000000000..c557763c004 --- /dev/null +++ b/src/test/mir-opt/nll/liveness-interblock.rs @@ -0,0 +1,50 @@ +// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-Znll + +fn cond() -> bool { false } + +fn make_live(_: usize) { } + +fn make_dead() { } + +fn main() { + let x = 5; + + if cond() { + make_live(x); + } else { + // x should be dead on entry to this block + make_dead(); + } +} + +// END RUST SOURCE +// START rustc.node18.nll.0.mir +// | Live variables on entry to bb2: [_1] +// bb2: { +// | Live variables at bb2[0]: [_1] +// StorageLive(_4); +// | Live variables at bb2[1]: [_1] +// _4 = _1; +// | Live variables at bb2[2]: [_4] +// _3 = const make_live(_4) -> bb4; +// } +// END rustc.node18.nll.0.mir +// START rustc.node18.nll.0.mir +// | Live variables on entry to bb3: [] +// bb3: { +// | Live variables at bb3[0]: [] +// _5 = const make_dead() -> bb5; +// } +// END rustc.node18.nll.0.mir + + diff --git a/src/test/mir-opt/nll/named-lifetimes-basic.rs b/src/test/mir-opt/nll/named-lifetimes-basic.rs new file mode 100644 index 00000000000..c4f3a6fea53 --- /dev/null +++ b/src/test/mir-opt/nll/named-lifetimes-basic.rs @@ -0,0 +1,34 @@ +// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Basic test for named lifetime translation. Check that we +// instantiate the types that appear in function arguments with +// suitable variables and that we setup the outlives relationship +// between R0 and R1 properly. + +// compile-flags:-Znll -Zverbose +// ^^^^^^^^^ force compiler to dump more region information +// ignore-tidy-linelength + +#![allow(warnings)] + +fn use_x<'a, 'b: 'a, 'c>(w: &'a mut i32, x: &'b u32, y: &'a u32, z: &'c u32) -> bool { true } + +fn main() { +} + +// END RUST SOURCE +// START rustc.node4.nll.0.mir +// | '_#0r: {bb0[0], bb0[1], '_#0r} +// | '_#1r: {bb0[0], bb0[1], '_#0r, '_#1r} +// | '_#2r: {bb0[0], bb0[1], '_#2r} +// ... +// fn use_x(_1: &'_#0r mut i32, _2: &'_#1r u32, _3: &'_#0r u32, _4: &'_#2r u32) -> bool { +// END rustc.node4.nll.0.mir diff --git a/src/test/mir-opt/nll/reborrow-basic.rs b/src/test/mir-opt/nll/reborrow-basic.rs new file mode 100644 index 00000000000..60a4da430b9 --- /dev/null +++ b/src/test/mir-opt/nll/reborrow-basic.rs @@ -0,0 +1,39 @@ +// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Basic test for reborrow constraints: the region (`R5`) that appears +// in the type of `r_a` must outlive the region (`R7`) that appears in +// the type of `r_b` + +// compile-flags:-Znll -Zverbose +// ^^^^^^^^^ force compiler to dump more region information + +#![allow(warnings)] + +fn use_x(_: &mut i32) -> bool { true } + +fn main() { + let mut foo: i32 = 22; + let r_a: &mut i32 = &mut foo; + let r_b: &mut i32 = &mut *r_a; + use_x(r_b); +} + +// END RUST SOURCE +// START rustc.node13.nll.0.mir +// | '_#5r: {bb0[6], bb0[7], bb0[8], bb0[9], bb0[10], bb0[11], bb0[12], bb0[13], bb0[14]} +// ... +// | '_#7r: {bb0[11], bb0[12], bb0[13], bb0[14]} +// END rustc.node13.nll.0.mir +// START rustc.node13.nll.0.mir +// let _2: &'_#5r mut i32; +// ... +// let _4: &'_#7r mut i32; +// END rustc.node13.nll.0.mir diff --git a/src/test/mir-opt/nll/region-liveness-basic.rs b/src/test/mir-opt/nll/region-liveness-basic.rs new file mode 100644 index 00000000000..7792f0a36f3 --- /dev/null +++ b/src/test/mir-opt/nll/region-liveness-basic.rs @@ -0,0 +1,56 @@ +// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Basic test for liveness constraints: the region (`R1`) that appears +// in the type of `p` includes the points after `&v[0]` up to (but not +// including) the call to `use_x`. The `else` branch is not included. + +// compile-flags:-Znll -Zverbose +// ^^^^^^^^^ force compiler to dump more region information + +#![allow(warnings)] + +fn use_x(_: usize) -> bool { true } + +fn main() { + let mut v = [1, 2, 3]; + let p = &v[0]; + if true { + use_x(*p); + } else { + use_x(22); + } +} + +// END RUST SOURCE +// START rustc.node12.nll.0.mir +// | '_#0r: {bb1[1], bb2[0], bb2[1]} +// | '_#1r: {bb1[1], bb2[0], bb2[1]} +// ... +// let _2: &'_#1r usize; +// END rustc.node12.nll.0.mir +// START rustc.node12.nll.0.mir +// bb1: { +// | Live variables at bb1[0]: [_1, _3] +// _2 = &'_#0r _1[_3]; +// | Live variables at bb1[1]: [_2] +// switchInt(const true) -> [0u8: bb3, otherwise: bb2]; +// } +// END rustc.node12.nll.0.mir +// START rustc.node12.nll.0.mir +// bb2: { +// | Live variables at bb2[0]: [_2] +// StorageLive(_7); +// | Live variables at bb2[1]: [_2] +// _7 = (*_2); +// | Live variables at bb2[2]: [_7] +// _6 = const use_x(_7) -> bb4; +// } +// END rustc.node12.nll.0.mir diff --git a/src/test/mir-opt/nll/region-liveness-drop-may-dangle.rs b/src/test/mir-opt/nll/region-liveness-drop-may-dangle.rs new file mode 100644 index 00000000000..4f4bb596e5f --- /dev/null +++ b/src/test/mir-opt/nll/region-liveness-drop-may-dangle.rs @@ -0,0 +1,48 @@ +// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Basic test for liveness constraints: the region (`R1`) that appears +// in the type of `p` includes the points after `&v[0]` up to (but not +// including) the call to `use_x`. The `else` branch is not included. + +// compile-flags:-Znll -Zverbose +// ^^^^^^^^^ force compiler to dump more region information + +#![allow(warnings)] +#![feature(dropck_eyepatch)] +#![feature(generic_param_attrs)] + +fn use_x(_: usize) -> bool { true } + +fn main() { + let mut v = [1, 2, 3]; + let p: Wrap<& /* R4 */ usize> = Wrap { value: &v[0] }; + if true { + use_x(*p.value); + } else { + use_x(22); + } + + // `p` will get dropped here. However, because of the + // `#[may_dangle]` attribute, we do not need to consider R4 live. +} + +struct Wrap<T> { + value: T +} + +unsafe impl<#[may_dangle] T> Drop for Wrap<T> { + fn drop(&mut self) { } +} + +// END RUST SOURCE +// START rustc.node12.nll.0.mir +// | '_#4r: {bb1[3], bb1[4], bb1[5], bb2[0], bb2[1]} +// END rustc.node12.nll.0.mir diff --git a/src/test/mir-opt/nll/region-liveness-drop-no-may-dangle.rs b/src/test/mir-opt/nll/region-liveness-drop-no-may-dangle.rs new file mode 100644 index 00000000000..0ddb745b61f --- /dev/null +++ b/src/test/mir-opt/nll/region-liveness-drop-no-may-dangle.rs @@ -0,0 +1,50 @@ +// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Basic test for liveness constraints: the region (`R1`) that appears +// in the type of `p` includes the points after `&v[0]` up to (but not +// including) the call to `use_x`. The `else` branch is not included. + +// ignore-tidy-linelength +// compile-flags:-Znll -Zverbose +// ^^^^^^^^^ force compiler to dump more region information + +#![allow(warnings)] + +fn use_x(_: usize) -> bool { true } + +fn main() { + let mut v = [1, 2, 3]; + let p: Wrap<& /* R1 */ usize> = Wrap { value: &v[0] }; + if true { + use_x(*p.value); + } else { + use_x(22); + } + + // `p` will get dropped here. Because the `#[may_dangle]` + // attribute is not present on `Wrap`, we must conservatively + // assume that the dtor may access the `value` field, and hence we + // must consider R1 to be live. +} + +struct Wrap<T> { + value: T +} + +// Look ma, no `#[may_dangle]` attribute here. +impl<T> Drop for Wrap<T> { + fn drop(&mut self) { } +} + +// END RUST SOURCE +// START rustc.node12.nll.0.mir +// | '_#4r: {bb1[3], bb1[4], bb1[5], bb2[0], bb2[1], bb2[2], bb3[0], bb3[1], bb3[2], bb4[0], bb4[1], bb4[2], bb6[0], bb7[0], bb7[1], bb7[2], bb8[0]} +// END rustc.node12.nll.0.mir diff --git a/src/test/mir-opt/nll/region-liveness-two-disjoint-uses.rs b/src/test/mir-opt/nll/region-liveness-two-disjoint-uses.rs new file mode 100644 index 00000000000..664298b9374 --- /dev/null +++ b/src/test/mir-opt/nll/region-liveness-two-disjoint-uses.rs @@ -0,0 +1,49 @@ +// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test for the subregion constraints. In this case, the region R3 on +// `p` includes two disjoint regions of the control-flow graph. The +// borrows in `&v[0]` and `&v[1]` each (in theory) have to outlive R3, +// but only at a particular point, and hence they wind up including +// distinct regions. + +// compile-flags:-Znll -Zverbose +// ^^^^^^^^^ force compiler to dump more region information + +#![allow(warnings)] + +fn use_x(_: usize) -> bool { true } + +fn main() { + let mut v = [1, 2, 3]; + let mut p = &v[0]; + if true { + use_x(*p); + } else { + use_x(22); + } + + p = &v[1]; + use_x(*p); +} + +// END RUST SOURCE +// START rustc.node12.nll.0.mir +// | '_#0r: {bb1[1], bb2[0], bb2[1]} +// ... +// | '_#2r: {bb7[2], bb7[3], bb7[4]} +// | '_#3r: {bb1[1], bb2[0], bb2[1], bb7[2], bb7[3], bb7[4]} +// ... +// let mut _2: &'_#3r usize; +// ... +// _2 = &'_#0r _1[_3]; +// ... +// _2 = &'_#2r (*_11); +// END rustc.node12.nll.0.mir diff --git a/src/test/mir-opt/nll/region-subtyping-basic.rs b/src/test/mir-opt/nll/region-subtyping-basic.rs new file mode 100644 index 00000000000..4ae891f5b70 --- /dev/null +++ b/src/test/mir-opt/nll/region-subtyping-basic.rs @@ -0,0 +1,49 @@ +// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Basic test for liveness constraints: the region (`R1`) that appears +// in the type of `p` includes the points after `&v[0]` up to (but not +// including) the call to `use_x`. The `else` branch is not included. + +// compile-flags:-Znll -Zverbose +// ^^^^^^^^^ force compiler to dump more region information + +#![allow(warnings)] + +fn use_x(_: usize) -> bool { true } + +fn main() { + let mut v = [1, 2, 3]; + let p = &v[0]; + let q = p; + if true { + use_x(*q); + } else { + use_x(22); + } +} + +// END RUST SOURCE +// START rustc.node12.nll.0.mir +// | '_#0r: {bb1[1], bb1[2], bb1[3], bb1[4], bb1[5], bb1[6], bb2[0], bb2[1]} +// | '_#1r: {bb1[1], bb1[2], bb1[3], bb1[4], bb1[5], bb1[6], bb2[0], bb2[1]} +// | '_#2r: {bb1[5], bb1[6], bb2[0], bb2[1]} +// END rustc.node12.nll.0.mir +// START rustc.node12.nll.0.mir +// let _2: &'_#1r usize; +// ... +// let _6: &'_#2r usize; +// ... +// _2 = &'_#0r _1[_3]; +// ... +// _7 = _2; +// ... +// _6 = _7; +// END rustc.node12.nll.0.mir diff --git a/src/test/mir-opt/validate_1.rs b/src/test/mir-opt/validate_1.rs index 53454c0cc9a..a97ce4e8cbe 100644 --- a/src/test/mir-opt/validate_1.rs +++ b/src/test/mir-opt/validate_1.rs @@ -62,7 +62,7 @@ fn main() { // fn main::{{closure}}(_1: &ReErased [closure@NodeId(50)], _2: &ReErased mut i32) -> i32 { // ... // bb0: { -// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:11) => validate_1[317d]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(50)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:11) => validate_1[317d]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]); +// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:11) => validate_1[317d]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(50)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:11) => validate_1[317d]::main[0]::{{closure}}[0] }, BrAnon(0)) mut i32]); // StorageLive(_3); // Validate(Suspend(ReScope(Remainder(BlockRemainder { block: ItemLocalId(22), first_statement_index: 0 }))), [(*_2): i32]); // _3 = &ReErased (*_2); diff --git a/src/test/mir-opt/validate_4.rs b/src/test/mir-opt/validate_4.rs index 042edca82a6..3585ac0b8be 100644 --- a/src/test/mir-opt/validate_4.rs +++ b/src/test/mir-opt/validate_4.rs @@ -78,8 +78,8 @@ fn main() { // fn main::{{closure}}(_1: &ReErased [closure@NodeId(60)], _2: &ReErased mut i32) -> bool { // ... // bb0: { -// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[317d]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[317d]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]); -// Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[317d]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[317d]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]); +// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[317d]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[317d]::main[0]::{{closure}}[0] }, BrAnon(0)) mut i32]); +// Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[317d]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[317d]::main[0]::{{closure}}[0] }, BrAnon(0)) mut i32]); // StorageLive(_3); // ... // _0 = const write_42(_3) -> bb1; diff --git a/src/test/mir-opt/validate_5.rs b/src/test/mir-opt/validate_5.rs index fc849c5aee3..ae09d72942e 100644 --- a/src/test/mir-opt/validate_5.rs +++ b/src/test/mir-opt/validate_5.rs @@ -49,7 +49,7 @@ fn main() { // fn main::{{closure}}(_1: &ReErased [closure@NodeId(46)], _2: &ReErased mut i32) -> bool { // ... // bb0: { -// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_5[317d]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(46)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_5[317d]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]); +// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_5[317d]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(46)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_5[317d]::main[0]::{{closure}}[0] }, BrAnon(0)) mut i32]); // StorageLive(_3); // StorageLive(_4); // Validate(Suspend(ReScope(Node(ItemLocalId(9)))), [(*_2): i32]); diff --git a/src/test/parse-fail/issue-33413.rs b/src/test/parse-fail/issue-33413.rs index 699af8ca7ab..25ae7b4c55a 100644 --- a/src/test/parse-fail/issue-33413.rs +++ b/src/test/parse-fail/issue-33413.rs @@ -12,5 +12,4 @@ impl S { fn f(*, a: u8) -> u8 {} //~ ERROR expected pattern, found `*` - //~^ ERROR expected one of `)`, `-`, `box`, `false`, `mut`, `ref`, or `true`, found `*` } diff --git a/src/test/pretty/default-trait-impl.rs b/src/test/pretty/auto-trait.rs index a5246b9300c..842af49e8a7 100644 --- a/src/test/pretty/default-trait-impl.rs +++ b/src/test/pretty/auto-trait.rs @@ -12,8 +12,8 @@ // pp-exact -trait MyTrait { } +auto trait MyTrait { } -impl MyTrait for .. { } +unsafe auto trait UnsafeMyTrait { } pub fn main() { } diff --git a/src/test/pretty/cast-lt.pp b/src/test/pretty/cast-lt.pp new file mode 100644 index 00000000000..b21158abfe5 --- /dev/null +++ b/src/test/pretty/cast-lt.pp @@ -0,0 +1,24 @@ +#![feature(prelude_import)] +#![no_std] +#[prelude_import] +use std::prelude::v1::*; +#[macro_use] +extern crate std as std; +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// pretty-compare-only +// pretty-mode:expanded +// pp-exact:cast-lt.pp + +macro_rules! negative(( $ e : expr ) => { $ e < 0 }); + +fn main() { (1 as i32) < 0; } + diff --git a/src/test/pretty/cast-lt.rs b/src/test/pretty/cast-lt.rs new file mode 100644 index 00000000000..87b5274545f --- /dev/null +++ b/src/test/pretty/cast-lt.rs @@ -0,0 +1,22 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// pretty-compare-only +// pretty-mode:expanded +// pp-exact:cast-lt.pp + +macro_rules! negative { + ($e:expr) => { $e < 0 } +} + +fn main() { + negative!(1 as i32); +} + diff --git a/src/test/run-make/cdylib-fewer-symbols/Makefile b/src/test/run-make/cdylib-fewer-symbols/Makefile new file mode 100644 index 00000000000..954ee792460 --- /dev/null +++ b/src/test/run-make/cdylib-fewer-symbols/Makefile @@ -0,0 +1,17 @@ +# Test that allocator-related symbols don't show up as exported from a cdylib as +# they're internal to Rust and not part of the public ABI. + +-include ../tools.mk + +ifdef IS_MSVC +all: + true +else +all: + $(RUSTC) foo.rs + nm -g "$(call DYLIB,foo)" + nm -g "$(call DYLIB,foo)" | grep -vq __rdl_ + nm -g "$(call DYLIB,foo)" | grep -vq __rde_ + nm -g "$(call DYLIB,foo)" | grep -vq __rg_ + nm -g "$(call DYLIB,foo)" | grep -vq __rust_ +endif diff --git a/src/test/run-make/cdylib-fewer-symbols/foo.rs b/src/test/run-make/cdylib-fewer-symbols/foo.rs new file mode 100644 index 00000000000..4ec8d4ee860 --- /dev/null +++ b/src/test/run-make/cdylib-fewer-symbols/foo.rs @@ -0,0 +1,16 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "cdylib"] + +#[no_mangle] +pub extern fn foo() -> u32 { + 3 +} diff --git a/src/test/run-make/extra-filename-with-temp-outputs/Makefile b/src/test/run-make/extra-filename-with-temp-outputs/Makefile index 13ca397eaf2..6de4f97df0c 100644 --- a/src/test/run-make/extra-filename-with-temp-outputs/Makefile +++ b/src/test/run-make/extra-filename-with-temp-outputs/Makefile @@ -2,5 +2,5 @@ all: $(RUSTC) -C extra-filename=bar foo.rs -C save-temps - rm $(TMPDIR)/foobar.foo0.rust-cgu.o + rm $(TMPDIR)/foobar.foo0.rcgu.o rm $(TMPDIR)/$(call BIN,foobar) diff --git a/src/test/run-make/issue-7349/foo.rs b/src/test/run-make/issue-7349/foo.rs index 6c39b33be08..b75c82afb53 100644 --- a/src/test/run-make/issue-7349/foo.rs +++ b/src/test/run-make/issue-7349/foo.rs @@ -13,6 +13,7 @@ fn outer<T>() { fn inner() -> u32 { 8675309 } + inner(); } extern "C" fn outer_foreign<T>() { @@ -20,6 +21,7 @@ extern "C" fn outer_foreign<T>() { fn inner() -> u32 { 11235813 } + inner(); } fn main() { diff --git a/src/test/run-make/save-analysis/foo.rs b/src/test/run-make/save-analysis/foo.rs index 5cb363ac344..834a7554a55 100644 --- a/src/test/run-make/save-analysis/foo.rs +++ b/src/test/run-make/save-analysis/foo.rs @@ -441,6 +441,11 @@ fn test_format_args() { print!("x is {}, y is {1}, name is {n}", x, y, n = name); } + +union TestUnion { + f1: u32 +} + struct FrameBuffer; struct SilenceGenerator; diff --git a/src/test/run-make/sepcomp-separate/foo.rs b/src/test/run-make/sepcomp-separate/foo.rs index bfa2162e27d..64a76e9e0ed 100644 --- a/src/test/run-make/sepcomp-separate/foo.rs +++ b/src/test/run-make/sepcomp-separate/foo.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. + + fn magic_fn() -> usize { 1234 } @@ -24,4 +26,8 @@ mod b { } } -fn main() { } +fn main() { + magic_fn(); + a::magic_fn(); + b::magic_fn(); +} diff --git a/src/test/run-make/simd-ffi/simd.rs b/src/test/run-make/simd-ffi/simd.rs index 8ab8f471575..185476fb704 100644 --- a/src/test/run-make/simd-ffi/simd.rs +++ b/src/test/run-make/simd-ffi/simd.rs @@ -81,4 +81,5 @@ pub mod marker { #[lang = "freeze"] trait Freeze {} +#[allow(auto_impl)] impl Freeze for .. {} diff --git a/src/test/run-make/symbols-are-reasonable/lib.rs b/src/test/run-make/symbols-are-reasonable/lib.rs index ff56ed62869..b9285b24cd6 100644 --- a/src/test/run-make/symbols-are-reasonable/lib.rs +++ b/src/test/run-make/symbols-are-reasonable/lib.rs @@ -14,7 +14,8 @@ pub static Y: &'static [u8] = include_bytes!("lib.rs"); trait Foo { fn dummy(&self) { } } impl Foo for usize {} -pub fn dummy() { +#[no_mangle] +pub extern "C" fn dummy() { // force the vtable to be created let _x = &1usize as &Foo; } diff --git a/src/test/run-make/symbols-include-type-name/lib.rs b/src/test/run-make/symbols-include-type-name/lib.rs index 1c478ed2598..d84f1617db5 100644 --- a/src/test/run-make/symbols-include-type-name/lib.rs +++ b/src/test/run-make/symbols-include-type-name/lib.rs @@ -17,3 +17,8 @@ impl Def { Def { id: id } } } + +#[no_mangle] +pub fn user() { + let _ = Def::new(0); +} diff --git a/src/test/run-make/target-specs/foo.rs b/src/test/run-make/target-specs/foo.rs index af24c3b460b..a0feb727028 100644 --- a/src/test/run-make/target-specs/foo.rs +++ b/src/test/run-make/target-specs/foo.rs @@ -19,6 +19,7 @@ trait Sized { } #[lang = "freeze"] trait Freeze {} +#[allow(auto_impl)] impl Freeze for .. {} #[lang="start"] diff --git a/src/test/run-pass/auto-is-contextual.rs b/src/test/run-pass/auto-is-contextual.rs new file mode 100644 index 00000000000..ad433cc26a7 --- /dev/null +++ b/src/test/run-pass/auto-is-contextual.rs @@ -0,0 +1,24 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +macro_rules! auto { + () => (struct S;) +} + +auto!(); + +fn auto() {} + +fn main() { + auto(); + let auto = 10; + auto; + auto as u8; +} diff --git a/src/test/run-pass/auto-traits.rs b/src/test/run-pass/auto-traits.rs new file mode 100644 index 00000000000..752f5a11375 --- /dev/null +++ b/src/test/run-pass/auto-traits.rs @@ -0,0 +1,36 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(optin_builtin_traits)] + +auto trait Auto {} +// Redundant but accepted until we remove it. +#[allow(auto_impl)] +impl Auto for .. {} + +unsafe auto trait AutoUnsafe {} + +impl !Auto for bool {} +impl !AutoUnsafe for bool {} + +struct AutoBool(bool); + +impl Auto for AutoBool {} +unsafe impl AutoUnsafe for AutoBool {} + +fn take_auto<T: Auto>(_: T) {} +fn take_auto_unsafe<T: AutoUnsafe>(_: T) {} + +fn main() { + take_auto(0); + take_auto(AutoBool(true)); + take_auto_unsafe(0); + take_auto_unsafe(AutoBool(true)); +} diff --git a/src/test/run-pass/closure-expected-type/README.md b/src/test/run-pass/closure-expected-type/README.md new file mode 100644 index 00000000000..fd493e1ff37 --- /dev/null +++ b/src/test/run-pass/closure-expected-type/README.md @@ -0,0 +1,8 @@ +Some tests targeted at how we deduce the types of closure arguments. +This process is a result of some heuristics aimed at combining the +*expected type* we have with the *actual types* that we get from +inputs. This investigation was kicked off by #38714, which revealed +some pretty deep flaws in the ad-hoc way that we were doing things +before. + +See also `src/test/compile-fail/closure-expected-type`. diff --git a/src/test/run-pass/closure-expected-type/expect-infer-supply-two-infers.rs b/src/test/run-pass/closure-expected-type/expect-infer-supply-two-infers.rs new file mode 100644 index 00000000000..8a90a491f7e --- /dev/null +++ b/src/test/run-pass/closure-expected-type/expect-infer-supply-two-infers.rs @@ -0,0 +1,26 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn with_closure<A, F>(_: F) + where F: FnOnce(Vec<A>, A) +{ +} + +fn expect_free_supply_free<'x>(x: &'x u32) { + with_closure(|mut x: Vec<_>, y| { + // Shows that the call to `x.push()` is influencing type of `y`... + x.push(22_u32); + + // ...since we now know the type of `y` and can resolve the method call. + y.wrapping_add(1); + }); +} + +fn main() { } diff --git a/src/test/run-pass/closure-expected-type/issue-38714.rs b/src/test/run-pass/closure-expected-type/issue-38714.rs new file mode 100644 index 00000000000..a1d512105c9 --- /dev/null +++ b/src/test/run-pass/closure-expected-type/issue-38714.rs @@ -0,0 +1,26 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct UsizeRef<'a> { + a: &'a usize +} + +type RefTo = Box<for<'r> Fn(&'r Vec<usize>) -> UsizeRef<'r>>; + +fn ref_to<'a>(vec: &'a Vec<usize>) -> UsizeRef<'a> { + UsizeRef{ a: &vec[0]} +} + +fn main() { + // Regression test: this was causing ICEs; it should compile. + let a: RefTo = Box::new(|vec: &Vec<usize>| { + UsizeRef{ a: &vec[0] } + }); +} diff --git a/src/test/run-pass/closure-expected-type/supply-just-return-type.rs b/src/test/run-pass/closure-expected-type/supply-just-return-type.rs new file mode 100644 index 00000000000..0b930b338fd --- /dev/null +++ b/src/test/run-pass/closure-expected-type/supply-just-return-type.rs @@ -0,0 +1,35 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn with_closure<F, R>(f: F) -> Result<char, R> + where F: FnOnce(&char) -> Result<char, R>, +{ + f(&'a') +} + +fn main() { + // Test that supplying the `-> Result<char, ()>` manually here + // (which is needed to constrain `R`) still allows us to figure + // out that the type of `x` is `&'a char` where `'a` is bound in + // the closure (if we didn't, we'd get a type-error because + // `with_closure` requires a bound region). + // + // This pattern was found in the wild. + let z = with_closure(|x| -> Result<char, ()> { Ok(*x) }); + assert_eq!(z.unwrap(), 'a'); + + // It also works with `_`: + let z = with_closure(|x: _| -> Result<char, ()> { Ok(*x) }); + assert_eq!(z.unwrap(), 'a'); + + // It also works with `&_`: + let z = with_closure(|x: &_| -> Result<char, ()> { Ok(*x) }); + assert_eq!(z.unwrap(), 'a'); +} diff --git a/src/test/run-pass/closure-expected-type/supply-nothing.rs b/src/test/run-pass/closure-expected-type/supply-nothing.rs new file mode 100644 index 00000000000..15d8b393c15 --- /dev/null +++ b/src/test/run-pass/closure-expected-type/supply-nothing.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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn with_closure<F>(f: F) -> u32 + where F: FnOnce(&u32, &u32) -> u32 +{ + f(&22, &44) +} + +fn main() { + let z = with_closure(|x, y| x + y).wrapping_add(1); + assert_eq!(z, 22 + 44 + 1); +} diff --git a/src/test/run-pass/issue-29516.rs b/src/test/run-pass/issue-29516.rs index b586abc29e2..5fa0a002a10 100644 --- a/src/test/run-pass/issue-29516.rs +++ b/src/test/run-pass/issue-29516.rs @@ -11,6 +11,7 @@ #![feature(optin_builtin_traits)] trait NotSame {} +#[allow(auto_impl)] impl NotSame for .. {} impl<A> !NotSame for (A, A) {} diff --git a/src/test/run-pass/issue-45731.rs b/src/test/run-pass/issue-45731.rs new file mode 100644 index 00000000000..ec35035dab4 --- /dev/null +++ b/src/test/run-pass/issue-45731.rs @@ -0,0 +1,34 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:--test -g + +use std::{env, panic, fs}; + +#[cfg(target_os = "macos")] +#[test] +fn simple_test() { + // Find our dSYM and replace the DWARF binary with an empty file + let mut dsym_path = env::current_exe().unwrap(); + let executable_name = dsym_path.file_name().unwrap().to_str().unwrap().to_string(); + assert!(dsym_path.pop()); // Pop executable + dsym_path.push(format!("{}.dSYM/Contents/Resources/DWARF/{0}", executable_name)); + { + let file = fs::OpenOptions::new().read(false).write(true).truncate(true).create(false) + .open(&dsym_path).unwrap(); + } + + env::set_var("RUST_BACKTRACE", "1"); + + // We don't need to die of panic, just trigger a backtrace + let _ = panic::catch_unwind(|| { + assert!(false); + }); +} diff --git a/src/test/run-pass/mir-inlining/ice-issue-45493.rs b/src/test/run-pass/mir-inlining/ice-issue-45493.rs new file mode 100644 index 00000000000..bd178f0e5bd --- /dev/null +++ b/src/test/run-pass/mir-inlining/ice-issue-45493.rs @@ -0,0 +1,26 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-Zmir-opt-level=2 + +trait Array { + type Item; +} + +fn foo<A: Array>() { + let _: *mut A::Item = std::ptr::null_mut(); +} + +struct Foo; +impl Array for Foo { type Item = i32; } + +fn main() { + foo::<Foo>(); +} diff --git a/src/test/run-pass/next-power-of-two-overflow-debug.rs b/src/test/run-pass/next-power-of-two-overflow-debug.rs new file mode 100644 index 00000000000..a3e7ffd4e49 --- /dev/null +++ b/src/test/run-pass/next-power-of-two-overflow-debug.rs @@ -0,0 +1,36 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -C debug_assertions=yes + +#![feature(i128_type)] + +use std::panic; + +fn main() { + macro_rules! overflow_test { + ($t:ident) => ( + let r = panic::catch_unwind(|| { + ($t::max_value()).next_power_of_two() + }); + assert!(r.is_err()); + + let r = panic::catch_unwind(|| { + (($t::max_value() >> 1) + 2).next_power_of_two() + }); + assert!(r.is_err()); + ) + } + overflow_test!(u8); + overflow_test!(u16); + overflow_test!(u32); + overflow_test!(u64); + overflow_test!(u128); +} diff --git a/src/test/run-pass/next-power-of-two-overflow-ndebug.rs b/src/test/run-pass/next-power-of-two-overflow-ndebug.rs new file mode 100644 index 00000000000..f8bcb961c68 --- /dev/null +++ b/src/test/run-pass/next-power-of-two-overflow-ndebug.rs @@ -0,0 +1,24 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -C debug_assertions=no + +#![feature(i128_type)] + +fn main() { + for i in 129..256 { + assert_eq!((i as u8).next_power_of_two(), 0); + } + + assert_eq!(((1u16 << 15) + 1).next_power_of_two(), 0); + assert_eq!(((1u32 << 31) + 1).next_power_of_two(), 0); + assert_eq!(((1u64 << 63) + 1).next_power_of_two(), 0); + assert_eq!(((1u128 << 127) + 1).next_power_of_two(), 0); +} diff --git a/src/test/run-pass/rfc-2008-non-exhaustive/auxiliary/enums.rs b/src/test/run-pass/rfc-2008-non-exhaustive/auxiliary/enums.rs new file mode 100644 index 00000000000..12d1bf9ea91 --- /dev/null +++ b/src/test/run-pass/rfc-2008-non-exhaustive/auxiliary/enums.rs @@ -0,0 +1,19 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "rlib"] +#![feature(non_exhaustive)] + +#[non_exhaustive] +pub enum NonExhaustiveEnum { + Unit, + Tuple(u32), + Struct { field: u32 } +} diff --git a/src/test/run-pass/rfc-2008-non-exhaustive/auxiliary/structs.rs b/src/test/run-pass/rfc-2008-non-exhaustive/auxiliary/structs.rs new file mode 100644 index 00000000000..a2c6f8c05e2 --- /dev/null +++ b/src/test/run-pass/rfc-2008-non-exhaustive/auxiliary/structs.rs @@ -0,0 +1,23 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(non_exhaustive)] + +#[non_exhaustive] +pub struct NormalStruct { + pub first_field: u16, + pub second_field: u16, +} + +#[non_exhaustive] +pub struct UnitStruct; + +#[non_exhaustive] +pub struct TupleStruct (pub u16, pub u16); diff --git a/src/test/run-pass/rfc-2008-non-exhaustive/auxiliary/variants.rs b/src/test/run-pass/rfc-2008-non-exhaustive/auxiliary/variants.rs new file mode 100644 index 00000000000..d04c1073ad9 --- /dev/null +++ b/src/test/run-pass/rfc-2008-non-exhaustive/auxiliary/variants.rs @@ -0,0 +1,18 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "rlib"] +#![feature(non_exhaustive)] + +pub enum NonExhaustiveVariants { + #[non_exhaustive] Unit, + #[non_exhaustive] Tuple(u32), + #[non_exhaustive] Struct { field: u32 } +} diff --git a/src/test/run-pass/rfc-2008-non-exhaustive/enums.rs b/src/test/run-pass/rfc-2008-non-exhaustive/enums.rs new file mode 100644 index 00000000000..9d41eca8fe5 --- /dev/null +++ b/src/test/run-pass/rfc-2008-non-exhaustive/enums.rs @@ -0,0 +1,33 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:enums.rs +extern crate enums; + +// ignore-pretty issue #37199 + +use enums::NonExhaustiveEnum; + +fn main() { + let enum_unit = NonExhaustiveEnum::Unit; + + match enum_unit { + NonExhaustiveEnum::Unit => 1, + NonExhaustiveEnum::Tuple(_) => 2, + // This particular arm tests that a enum marked as non-exhaustive + // will not error if its variants are matched exhaustively. + NonExhaustiveEnum::Struct { field } => field, + _ => 0 // no error with wildcard + }; + + match enum_unit { + _ => "no error with only wildcard" + }; +} diff --git a/src/test/run-pass/rfc-2008-non-exhaustive/enums_same_crate.rs b/src/test/run-pass/rfc-2008-non-exhaustive/enums_same_crate.rs new file mode 100644 index 00000000000..8f1ba364b0e --- /dev/null +++ b/src/test/run-pass/rfc-2008-non-exhaustive/enums_same_crate.rs @@ -0,0 +1,28 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(non_exhaustive)] + +#[non_exhaustive] +pub enum NonExhaustiveEnum { + Unit, + Tuple(u32), + Struct { field: u32 } +} + +fn main() { + let enum_unit = NonExhaustiveEnum::Unit; + + match enum_unit { + NonExhaustiveEnum::Unit => "first", + NonExhaustiveEnum::Tuple(_) => "second", + NonExhaustiveEnum::Struct { .. } => "third", + }; +} diff --git a/src/test/run-pass/rfc-2008-non-exhaustive/structs.rs b/src/test/run-pass/rfc-2008-non-exhaustive/structs.rs new file mode 100644 index 00000000000..bb65e10da27 --- /dev/null +++ b/src/test/run-pass/rfc-2008-non-exhaustive/structs.rs @@ -0,0 +1,27 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:structs.rs +extern crate structs; + +use structs::{NormalStruct, UnitStruct, TupleStruct}; + +// We only test matching here as we cannot create non-exhaustive +// structs from another crate. ie. they'll never pass in run-pass tests. + +fn match_structs(ns: NormalStruct, ts: TupleStruct, us: UnitStruct) { + let NormalStruct { first_field, second_field, .. } = ns; + + let TupleStruct { 0: first, 1: second, .. } = ts; + + let UnitStruct { .. } = us; +} + +fn main() { } diff --git a/src/test/run-pass/rfc-2008-non-exhaustive/structs_same_crate.rs b/src/test/run-pass/rfc-2008-non-exhaustive/structs_same_crate.rs new file mode 100644 index 00000000000..175782f10fc --- /dev/null +++ b/src/test/run-pass/rfc-2008-non-exhaustive/structs_same_crate.rs @@ -0,0 +1,40 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(non_exhaustive)] + +#[non_exhaustive] +pub struct NormalStruct { + pub first_field: u16, + pub second_field: u16, +} + +#[non_exhaustive] +pub struct UnitStruct; + +#[non_exhaustive] +pub struct TupleStruct (pub u16, pub u16); + +fn main() { + let ns = NormalStruct { first_field: 640, second_field: 480 }; + + let NormalStruct { first_field, second_field } = ns; + + let ts = TupleStruct { 0: 340, 1: 480 }; + let ts_constructor = TupleStruct(340, 480); + + let TupleStruct { 0: first, 1: second } = ts; + let TupleStruct(first, second) = ts_constructor; + + let us = UnitStruct {}; + let us_constructor = UnitStruct; + + let UnitStruct { } = us; +} diff --git a/src/test/run-pass/rfc-2008-non-exhaustive/variants.rs b/src/test/run-pass/rfc-2008-non-exhaustive/variants.rs new file mode 100644 index 00000000000..2658c59a699 --- /dev/null +++ b/src/test/run-pass/rfc-2008-non-exhaustive/variants.rs @@ -0,0 +1,31 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:variants.rs +extern crate variants; + +use variants::NonExhaustiveVariants; + +/* + * The initial implementation of #[non_exhaustive] (RFC 2008) does not include support for + * variants. See issue #44109 and PR 45394. + */ +// ignore-test + +fn main() { + let variant_tuple = NonExhaustiveVariants::Tuple { 0: 340 }; + let variant_struct = NonExhaustiveVariants::Struct { field: 340 }; + + match variant_struct { + NonExhaustiveVariants::Unit => "", + NonExhaustiveVariants::Struct { field, .. } => "", + NonExhaustiveVariants::Tuple(fe_tpl, ..) => "" + }; +} diff --git a/src/test/run-pass/rfc-2008-non-exhaustive/variants_same_crate.rs b/src/test/run-pass/rfc-2008-non-exhaustive/variants_same_crate.rs new file mode 100644 index 00000000000..a1c376c1798 --- /dev/null +++ b/src/test/run-pass/rfc-2008-non-exhaustive/variants_same_crate.rs @@ -0,0 +1,34 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(non_exhaustive)] + +/* + * The initial implementation of #[non_exhaustive] (RFC 2008) does not include support for + * variants. See issue #44109 and PR 45394. + */ +// ignore-test + +pub enum NonExhaustiveVariants { + #[non_exhaustive] Unit, + #[non_exhaustive] Tuple(u32), + #[non_exhaustive] Struct { field: u32 } +} + +fn main() { + let variant_tuple = NonExhaustiveVariants::Tuple(340); + let variant_struct = NonExhaustiveVariants::Struct { field: 340 }; + + match variant_tuple { + NonExhaustiveVariants::Unit => "", + NonExhaustiveVariants::Tuple(fe_tpl) => "", + NonExhaustiveVariants::Struct { field } => "" + }; +} diff --git a/src/test/run-pass/saturating-float-casts.rs b/src/test/run-pass/saturating-float-casts.rs new file mode 100644 index 00000000000..6db4d7635f0 --- /dev/null +++ b/src/test/run-pass/saturating-float-casts.rs @@ -0,0 +1,164 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z saturating-float-casts + +#![feature(test, i128, i128_type, stmt_expr_attributes)] +#![deny(overflowing_literals)] +extern crate test; + +use std::{f32, f64}; +use std::{u8, i8, u16, i16, u32, i32, u64, i64}; +#[cfg(not(target_os="emscripten"))] +use std::{u128, i128}; +use test::black_box; + +macro_rules! test { + ($val:expr, $src_ty:ident -> $dest_ty:ident, $expected:expr) => ( + // black_box disables constant evaluation to test run-time conversions: + assert_eq!(black_box::<$src_ty>($val) as $dest_ty, $expected, + "run-time {} -> {}", stringify!($src_ty), stringify!($dest_ty)); + ); + + ($fval:expr, f* -> $ity:ident, $ival:expr) => ( + test!($fval, f32 -> $ity, $ival); + test!($fval, f64 -> $ity, $ival); + ) +} + +// This macro tests const eval in addition to run-time evaluation. +// If and when saturating casts are adopted, this macro should be merged with test!() to ensure +// that run-time and const eval agree on inputs that currently trigger a const eval error. +macro_rules! test_c { + ($val:expr, $src_ty:ident -> $dest_ty:ident, $expected:expr) => ({ + test!($val, $src_ty -> $dest_ty, $expected); + { + const X: $src_ty = $val; + const Y: $dest_ty = X as $dest_ty; + assert_eq!(Y, $expected, + "const eval {} -> {}", stringify!($src_ty), stringify!($dest_ty)); + } + }); + + ($fval:expr, f* -> $ity:ident, $ival:expr) => ( + test!($fval, f32 -> $ity, $ival); + test!($fval, f64 -> $ity, $ival); + ) +} + +macro_rules! common_fptoi_tests { + ($fty:ident -> $($ity:ident)+) => ({ $( + test!($fty::NAN, $fty -> $ity, 0); + test!($fty::INFINITY, $fty -> $ity, $ity::MAX); + test!($fty::NEG_INFINITY, $fty -> $ity, $ity::MIN); + // These two tests are not solely float->int tests, in particular the latter relies on + // `u128::MAX as f32` not being UB. But that's okay, since this file tests int->float + // as well, the test is just slightly misplaced. + test!($ity::MIN as $fty, $fty -> $ity, $ity::MIN); + test!($ity::MAX as $fty, $fty -> $ity, $ity::MAX); + test_c!(0., $fty -> $ity, 0); + test_c!($fty::MIN_POSITIVE, $fty -> $ity, 0); + test!(-0.9, $fty -> $ity, 0); + test_c!(1., $fty -> $ity, 1); + test_c!(42., $fty -> $ity, 42); + )+ }); + + (f* -> $($ity:ident)+) => ({ + common_fptoi_tests!(f32 -> $($ity)+); + common_fptoi_tests!(f64 -> $($ity)+); + }) +} + +macro_rules! fptoui_tests { + ($fty: ident -> $($ity: ident)+) => ({ $( + test!(-0., $fty -> $ity, 0); + test!(-$fty::MIN_POSITIVE, $fty -> $ity, 0); + test!(-0.99999994, $fty -> $ity, 0); + test!(-1., $fty -> $ity, 0); + test!(-100., $fty -> $ity, 0); + test!(#[allow(overflowing_literals)] -1e50, $fty -> $ity, 0); + test!(#[allow(overflowing_literals)] -1e130, $fty -> $ity, 0); + )+ }); + + (f* -> $($ity:ident)+) => ({ + fptoui_tests!(f32 -> $($ity)+); + fptoui_tests!(f64 -> $($ity)+); + }) +} + +pub fn main() { + common_fptoi_tests!(f* -> i8 i16 i32 i64 u8 u16 u32 u64); + fptoui_tests!(f* -> u8 u16 u32 u64); + // FIXME emscripten does not support i128 + #[cfg(not(target_os="emscripten"))] { + common_fptoi_tests!(f* -> i128 u128); + fptoui_tests!(f* -> u128); + } + + // The following tests cover edge cases for some integer types. + + // # u8 + test_c!(254., f* -> u8, 254); + test!(256., f* -> u8, 255); + + // # i8 + test_c!(-127., f* -> i8, -127); + test!(-129., f* -> i8, -128); + test_c!(126., f* -> i8, 126); + test!(128., f* -> i8, 127); + + // # i32 + // -2147483648. is i32::MIN (exactly) + test_c!(-2147483648., f* -> i32, i32::MIN); + // 2147483648. is i32::MAX rounded up + test!(2147483648., f32 -> i32, 2147483647); + // With 24 significand bits, floats with magnitude in [2^30 + 1, 2^31] are rounded to + // multiples of 2^7. Therefore, nextDown(round(i32::MAX)) is 2^31 - 128: + test_c!(2147483520., f32 -> i32, 2147483520); + // Similarly, nextUp(i32::MIN) is i32::MIN + 2^8 and nextDown(i32::MIN) is i32::MIN - 2^7 + test!(-2147483904., f* -> i32, i32::MIN); + test_c!(-2147483520., f* -> i32, -2147483520); + + // # u32 + // round(MAX) and nextUp(round(MAX)) + test_c!(4294967040., f* -> u32, 4294967040); + test!(4294967296., f* -> u32, 4294967295); + + // # u128 + #[cfg(not(target_os="emscripten"))] + { + // float->int: + test_c!(f32::MAX, f32 -> u128, 0xffffff00000000000000000000000000); + // nextDown(f32::MAX) = 2^128 - 2 * 2^104 + const SECOND_LARGEST_F32: f32 = 340282326356119256160033759537265639424.; + test_c!(SECOND_LARGEST_F32, f32 -> u128, 0xfffffe00000000000000000000000000); + + // int->float: + // f32::MAX - 0.5 ULP and smaller should be rounded down + test_c!(0xfffffe00000000000000000000000000, u128 -> f32, SECOND_LARGEST_F32); + test_c!(0xfffffe7fffffffffffffffffffffffff, u128 -> f32, SECOND_LARGEST_F32); + test_c!(0xfffffe80000000000000000000000000, u128 -> f32, SECOND_LARGEST_F32); + // numbers within < 0.5 ULP of f32::MAX it should be rounded to f32::MAX + test_c!(0xfffffe80000000000000000000000001, u128 -> f32, f32::MAX); + test_c!(0xfffffeffffffffffffffffffffffffff, u128 -> f32, f32::MAX); + test_c!(0xffffff00000000000000000000000000, u128 -> f32, f32::MAX); + test_c!(0xffffff00000000000000000000000001, u128 -> f32, f32::MAX); + test_c!(0xffffff7fffffffffffffffffffffffff, u128 -> f32, f32::MAX); + // f32::MAX + 0.5 ULP and greater should be rounded to infinity + test_c!(0xffffff80000000000000000000000000, u128 -> f32, f32::INFINITY); + test_c!(0xffffff80000000f00000000000000000, u128 -> f32, f32::INFINITY); + test_c!(0xffffff87ffffffffffffffff00000001, u128 -> f32, f32::INFINITY); + + // u128->f64 should not be affected by the u128->f32 checks + test_c!(0xffffff80000000000000000000000000, u128 -> f64, + 340282356779733661637539395458142568448.0); + test_c!(u128::MAX, u128 -> f64, 340282366920938463463374607431768211455.0); + } +} diff --git a/src/test/rustdoc/auxiliary/rustdoc-default-impl.rs b/src/test/rustdoc/auxiliary/rustdoc-default-impl.rs index 52bd386ba59..4fd55bd482c 100644 --- a/src/test/rustdoc/auxiliary/rustdoc-default-impl.rs +++ b/src/test/rustdoc/auxiliary/rustdoc-default-impl.rs @@ -16,6 +16,7 @@ pub mod bar { pub trait Bar {} + #[allow(auto_impl)] impl Bar for .. {} pub trait Foo { diff --git a/src/test/rustdoc/auxiliary/rustdoc-impl-parts-crosscrate.rs b/src/test/rustdoc/auxiliary/rustdoc-impl-parts-crosscrate.rs index 6e8f80c8f5f..d886778278d 100644 --- a/src/test/rustdoc/auxiliary/rustdoc-impl-parts-crosscrate.rs +++ b/src/test/rustdoc/auxiliary/rustdoc-impl-parts-crosscrate.rs @@ -12,4 +12,5 @@ pub trait AnOibit {} +#[allow(auto_impl)] impl AnOibit for .. {} diff --git a/src/test/rustdoc/impl-parts.rs b/src/test/rustdoc/impl-parts.rs index 48ef4b6be66..f74f66ce729 100644 --- a/src/test/rustdoc/impl-parts.rs +++ b/src/test/rustdoc/impl-parts.rs @@ -12,6 +12,7 @@ pub trait AnOibit {} +#[allow(auto_impl)] impl AnOibit for .. {} pub struct Foo<T> { field: T } diff --git a/src/test/rustdoc/issue-45584.rs b/src/test/rustdoc/issue-45584.rs new file mode 100644 index 00000000000..6d6ae3dc94a --- /dev/null +++ b/src/test/rustdoc/issue-45584.rs @@ -0,0 +1,25 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_name = "foo"] + +pub trait Bar<T, U> {} + +// @has 'foo/struct.Foo1.html' +pub struct Foo1; +// @count - '//*[@class="impl"]' 1 +// @has - '//*[@class="impl"]' "impl Bar<Foo1, &'static Foo1> for Foo1" +impl Bar<Foo1, &'static Foo1> for Foo1 {} + +// @has 'foo/struct.Foo2.html' +pub struct Foo2; +// @count - '//*[@class="impl"]' 1 +// @has - '//*[@class="impl"]' "impl Bar<&'static Foo2, Foo2> for u8" +impl Bar<&'static Foo2, Foo2> for u8 {} diff --git a/src/test/rustdoc/method-list.rs b/src/test/rustdoc/method-list.rs new file mode 100644 index 00000000000..b7112885e88 --- /dev/null +++ b/src/test/rustdoc/method-list.rs @@ -0,0 +1,30 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-tidy-linelength + +#![crate_name = "foo"] + +// @has foo/struct.Foo.html +// @has - '//*[@class="sidebar-links"]/a' 'super_long_name' +// @has - '//*[@class="sidebar-links"]/a' 'Disp' +pub struct Foo(usize); + +impl Foo { + pub fn super_long_name() {} +} + +pub trait Disp { + fn disp_trait_method(); +} + +impl Disp for Foo { + fn disp_trait_method() {} +} diff --git a/src/test/rustdoc/playground-arg.rs b/src/test/rustdoc/playground-arg.rs index f0d55ef6e9f..478477dea61 100644 --- a/src/test/rustdoc/playground-arg.rs +++ b/src/test/rustdoc/playground-arg.rs @@ -21,4 +21,4 @@ pub fn dummy() {} // ensure that `extern crate foo;` was inserted into code snips automatically: -// @matches foo/index.html '//a[@class="test-arrow"][@href="https://example.com/?code=extern%20crate%20foo%3B%0Afn%20main()%20%7B%0Ause%20foo%3A%3Adummy%3B%0Adummy()%3B%0A%7D"]' "Run" +// @matches foo/index.html '//a[@class="test-arrow"][@href="https://example.com/?code=%23!%5Ballow(unused)%5D%0Aextern%20crate%20foo%3B%0Afn%20main()%20%7B%0Ause%20foo%3A%3Adummy%3B%0Adummy()%3B%0A%7D"]' "Run" diff --git a/src/test/rustdoc/playground.rs b/src/test/rustdoc/playground.rs index 9eb8dec51a7..8e193efaf85 100644 --- a/src/test/rustdoc/playground.rs +++ b/src/test/rustdoc/playground.rs @@ -34,6 +34,6 @@ //! } //! ``` -// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=fn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D%0A"]' "Run" -// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=fn%20main()%20%7B%0Aprintln!(%22Hello%2C%20world!%22)%3B%0A%7D"]' "Run" -// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Bfeature(something)%5D%0A%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D%0A&version=nightly"]' "Run" +// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D%0A"]' "Run" +// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn%20main()%20%7B%0Aprintln!(%22Hello%2C%20world!%22)%3B%0A%7D"]' "Run" +// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0A%23!%5Bfeature(something)%5D%0A%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D%0A&version=nightly"]' "Run" diff --git a/src/test/rustdoc/sidebar-items.rs b/src/test/rustdoc/sidebar-items.rs new file mode 100644 index 00000000000..9be40441e9d --- /dev/null +++ b/src/test/rustdoc/sidebar-items.rs @@ -0,0 +1,59 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_name = "foo"] + +// @has foo/trait.Foo.html +// @has - '//*[@class="sidebar-title"][@href="#required-methods"]' 'Required Methods' +// @has - '//*[@class="sidebar-links"]/a' 'bar' +// @has - '//*[@class="sidebar-title"][@href="#provided-methods"]' 'Provided Methods' +// @has - '//*[@class="sidebar-links"]/a' 'foo' +// @has - '//*[@class="sidebar-title"][@href="#associated-const"]' 'Associated Constants' +// @has - '//*[@class="sidebar-links"]/a' 'BAR' +// @has - '//*[@class="sidebar-title"][@href="#associated-types"]' 'Associated Types' +// @has - '//*[@class="sidebar-links"]/a' 'Output' +pub trait Foo { + const BAR: u32 = 0; + type Output: ?Sized; + + fn foo() {} + fn bar() -> Self::Output; +} + +// @has foo/struct.Bar.html +// @has - '//*[@class="sidebar-title"][@href="#fields"]' 'Fields' +// @has - '//*[@class="sidebar-links"]/a[@href="#structfield.f"]' 'f' +// @has - '//*[@class="sidebar-links"]/a[@href="#structfield.u"]' 'u' +// @!has - '//*[@class="sidebar-links"]/a' 'w' +pub struct Bar { + pub f: u32, + pub u: u32, + w: u32, +} + +// @has foo/enum.En.html +// @has - '//*[@class="sidebar-title"][@href="#variants"]' 'Variants' +// @has - '//*[@class="sidebar-links"]/a' 'foo' +// @has - '//*[@class="sidebar-links"]/a' 'bar' +pub enum En { + foo, + bar, +} + +// @has foo/union.MyUnion.html +// @has - '//*[@class="sidebar-title"][@href="#fields"]' 'Fields' +// @has - '//*[@class="sidebar-links"]/a[@href="#structfield.f1"]' 'f1' +// @has - '//*[@class="sidebar-links"]/a[@href="#structfield.f2"]' 'f2' +// @!has - '//*[@class="sidebar-links"]/a' 'w' +pub union MyUnion { + pub f1: u32, + pub f2: f32, + w: u32, +} diff --git a/src/test/ui/codemap_tests/unicode.stderr b/src/test/ui/codemap_tests/unicode.stderr index 0828fd28b58..02a9d7ee0ef 100644 --- a/src/test/ui/codemap_tests/unicode.stderr +++ b/src/test/ui/codemap_tests/unicode.stderr @@ -2,7 +2,7 @@ error: invalid ABI: expected one of [cdecl, stdcall, fastcall, vectorcall, thisc --> $DIR/unicode.rs:11:8 | 11 | extern "路濫狼á́́" fn foo() {} - | ^^^^^^^^ + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/codemap_tests/unicode_2.rs b/src/test/ui/codemap_tests/unicode_2.rs new file mode 100644 index 00000000000..cc3eae90f90 --- /dev/null +++ b/src/test/ui/codemap_tests/unicode_2.rs @@ -0,0 +1,17 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(non_ascii_idents)] + +fn main() { + let _ = ("a̐éö̲", 0u7); + let _ = ("아あ", 1i42); + let _ = a̐é; +} diff --git a/src/test/ui/codemap_tests/unicode_2.stderr b/src/test/ui/codemap_tests/unicode_2.stderr new file mode 100644 index 00000000000..6cfa66730a2 --- /dev/null +++ b/src/test/ui/codemap_tests/unicode_2.stderr @@ -0,0 +1,24 @@ +error: invalid width `7` for integer literal + --> $DIR/unicode_2.rs:14:25 + | +14 | let _ = ("a̐éö̲", 0u7); + | ^^^ + | + = help: valid widths are 8, 16, 32, 64 and 128 + +error: invalid width `42` for integer literal + --> $DIR/unicode_2.rs:15:20 + | +15 | let _ = ("아あ", 1i42); + | ^^^^ + | + = help: valid widths are 8, 16, 32, 64 and 128 + +error[E0425]: cannot find value `a̐é` in this scope + --> $DIR/unicode_2.rs:16:13 + | +16 | let _ = a̐é; + | ^^ not found in this scope + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/codemap_tests/unicode_3.rs b/src/test/ui/codemap_tests/unicode_3.rs new file mode 100644 index 00000000000..5294eedb845 --- /dev/null +++ b/src/test/ui/codemap_tests/unicode_3.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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let s = "ZͨA͑ͦ͒͋ͤ͑̚L̄͑͋Ĝͨͥ̿͒̽̈́Oͥ͛ͭ!̏"; while true { break; } + println!("{}", s); +} diff --git a/src/test/ui/codemap_tests/unicode_3.stderr b/src/test/ui/codemap_tests/unicode_3.stderr new file mode 100644 index 00000000000..a7514a6b792 --- /dev/null +++ b/src/test/ui/codemap_tests/unicode_3.stderr @@ -0,0 +1,10 @@ +warning: denote infinite loops with `loop { ... }` + --> $DIR/unicode_3.rs:12:45 + | +12 | let s = "ZͨA͑ͦ͒͋ͤ͑̚L̄͑͋Ĝͨͥ̿͒̽̈́Oͥ͛ͭ!̏"; while true { break; } + | ----------^^^^^^^^^^^ + | | + | help: use `loop` + | + = note: #[warn(while_true)] on by default + diff --git a/src/test/ui/deref-suggestion.stderr b/src/test/ui/deref-suggestion.stderr index 5ad9c19fa8c..3ed3297e05e 100644 --- a/src/test/ui/deref-suggestion.stderr +++ b/src/test/ui/deref-suggestion.stderr @@ -10,8 +10,8 @@ error[E0308]: mismatched types - .escape_debug() - .escape_default() - .escape_unicode() - - .to_lowercase() - - .to_uppercase() + - .to_ascii_lowercase() + - .to_ascii_uppercase() error[E0308]: mismatched types --> $DIR/deref-suggestion.rs:23:10 diff --git a/src/test/ui/issue-35241.rs b/src/test/ui/issue-35241.rs new file mode 100644 index 00000000000..7ec3974854b --- /dev/null +++ b/src/test/ui/issue-35241.rs @@ -0,0 +1,15 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Foo(u32); + +fn test() -> Foo { Foo } + +fn main() {} diff --git a/src/test/ui/issue-35241.stderr b/src/test/ui/issue-35241.stderr new file mode 100644 index 00000000000..bb1bba152bb --- /dev/null +++ b/src/test/ui/issue-35241.stderr @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> $DIR/issue-35241.rs:13:20 + | +13 | fn test() -> Foo { Foo } + | --- ^^^ + | | | + | | expected struct `Foo`, found fn item + | | did you mean `Foo(/* fields */)`? + | expected `Foo` because of return type + | + = note: expected type `Foo` + found type `fn(u32) -> Foo {Foo::{{constructor}}}` + +error: aborting due to previous error + diff --git a/src/test/ui/issue-40782.rs b/src/test/ui/issue-40782.rs new file mode 100644 index 00000000000..56ee225105f --- /dev/null +++ b/src/test/ui/issue-40782.rs @@ -0,0 +1,15 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + for i 0..2 { + } +} + diff --git a/src/test/ui/issue-40782.stderr b/src/test/ui/issue-40782.stderr new file mode 100644 index 00000000000..0d49eebbdbf --- /dev/null +++ b/src/test/ui/issue-40782.stderr @@ -0,0 +1,8 @@ +error: missing `in` in `for` loop + --> $DIR/issue-40782.rs:12:10 + | +12 | for i 0..2 { + | ^ help: try adding `in` here + +error: aborting due to previous error + diff --git a/src/test/ui/issue-44078.stderr b/src/test/ui/issue-44078.stderr index 389f3b2479a..2ed4578d538 100644 --- a/src/test/ui/issue-44078.stderr +++ b/src/test/ui/issue-44078.stderr @@ -2,7 +2,7 @@ error: unterminated double quote string --> $DIR/issue-44078.rs:12:8 | 12 | "😊""; - | ________^ + | _________^ 13 | | } | |__^ diff --git a/src/test/ui/issue-44406.stderr b/src/test/ui/issue-44406.stderr index 9beae91540a..e7afbb574ef 100644 --- a/src/test/ui/issue-44406.stderr +++ b/src/test/ui/issue-44406.stderr @@ -13,14 +13,5 @@ error: expected type, found keyword `true` 18 | foo!(true); | ^^^^ expecting a type here because of type ascription -error: expected one of `!`, `&&`, `&`, `(`, `*`, `.`, `;`, `<`, `?`, `[`, `_`, `dyn`, `extern`, `fn`, `for`, `impl`, `unsafe`, `}`, an operator, or lifetime, found `true` - --> $DIR/issue-44406.rs:18:10 - | -13 | bar(baz: $rest) - | - expected one of 20 possible tokens here -... -18 | foo!(true); - | ^^^^ unexpected token - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/src/test/ui/issue-45730.rs b/src/test/ui/issue-45730.rs new file mode 100644 index 00000000000..f725d69ca65 --- /dev/null +++ b/src/test/ui/issue-45730.rs @@ -0,0 +1,19 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::fmt; +fn main() { + let x: *const _ = 0 as _; + + let x: *const _ = 0 as *const _; + let y: Option<*const fmt::Debug> = Some(x) as _; + + let x = 0 as *const i32 as *const _ as *mut _; +} diff --git a/src/test/ui/issue-45730.stderr b/src/test/ui/issue-45730.stderr new file mode 100644 index 00000000000..c4f2e856b7b --- /dev/null +++ b/src/test/ui/issue-45730.stderr @@ -0,0 +1,32 @@ +error[E0641]: cannot cast to a pointer of an unknown kind + --> $DIR/issue-45730.rs:13:23 + | +13 | let x: *const _ = 0 as _; + | ^^^^^- + | | + | help: consider giving more type information + | + = note: The type information given here is insufficient to check whether the pointer cast is valid + +error[E0641]: cannot cast to a pointer of an unknown kind + --> $DIR/issue-45730.rs:15:23 + | +15 | let x: *const _ = 0 as *const _; + | ^^^^^-------- + | | + | help: consider giving more type information + | + = note: The type information given here is insufficient to check whether the pointer cast is valid + +error[E0641]: cannot cast to a pointer of an unknown kind + --> $DIR/issue-45730.rs:18:13 + | +18 | let x = 0 as *const i32 as *const _ as *mut _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------ + | | + | help: consider giving more type information + | + = note: The type information given here is insufficient to check whether the pointer cast is valid + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-early-bound-in-struct.rs b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-early-bound-in-struct.rs new file mode 100644 index 00000000000..55752f753ef --- /dev/null +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-early-bound-in-struct.rs @@ -0,0 +1,30 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[derive(Clone)] +enum Foo<'a> { + Bar(&'a str), +} + +impl<'a> Foo<'a> { + fn bar(&self, other: Foo) -> Foo<'a> { + match *self { + Foo::Bar(s) => { + if s == "test" { + other + } else { + self.clone() + } + } + } + } +} + +fn main() { } diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-early-bound-in-struct.stderr b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-early-bound-in-struct.stderr new file mode 100644 index 00000000000..d1660a620b6 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-early-bound-in-struct.stderr @@ -0,0 +1,11 @@ +error[E0621]: explicit lifetime required in the type of `other` + --> $DIR/ex1-return-one-existing-name-early-bound-in-struct.rs:21:21 + | +17 | fn bar(&self, other: Foo) -> Foo<'a> { + | ----- consider changing the type of `other` to `Foo<'a>` +... +21 | other + | ^^^^^ lifetime `'a` required + +error: aborting due to previous error + diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-earlybound-regions.rs b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name-early-bound.rs index 5d182008209..5d182008209 100644 --- a/src/test/ui/lifetime-errors/ex3-both-anon-regions-earlybound-regions.rs +++ b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name-early-bound.rs diff --git a/src/test/ui/lifetime-errors/ex2a-push-one-existing-name-early-bound.stderr b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name-early-bound.stderr new file mode 100644 index 00000000000..980f14a51d9 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name-early-bound.stderr @@ -0,0 +1,11 @@ +error[E0621]: explicit lifetime required in the type of `y` + --> $DIR/ex2a-push-one-existing-name-early-bound.rs:17:12 + | +13 | fn baz<'a, 'b, T>(x: &mut Vec<&'a T>, y: &T) + | - consider changing the type of `y` to `&'a T` +... +17 | x.push(y); + | ^ lifetime `'a` required + +error: aborting due to previous error + diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-earlybound-regions.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-earlybound-regions.stderr deleted file mode 100644 index 58f2cb94cec..00000000000 --- a/src/test/ui/lifetime-errors/ex3-both-anon-regions-earlybound-regions.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0623]: lifetime mismatch - --> $DIR/ex3-both-anon-regions-earlybound-regions.rs:17:12 - | -13 | fn baz<'a, 'b, T>(x: &mut Vec<&'a T>, y: &T) - | ----- -- these two types are declared with different lifetimes... -... -17 | x.push(y); - | ^ ...but data from `y` flows into `x` here - -error: aborting due to previous error - diff --git a/src/test/ui/lint/unreachable_pub-pub_crate.rs b/src/test/ui/lint/unreachable_pub-pub_crate.rs new file mode 100644 index 00000000000..b794f6c9517 --- /dev/null +++ b/src/test/ui/lint/unreachable_pub-pub_crate.rs @@ -0,0 +1,74 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This is just like unreachable_pub.rs, but without the +// `crate_visibility_modifier` feature (so that we can test the suggestions to +// use `pub(crate)` that are given when that feature is off, as opposed to the +// suggestions to use `crate` given when it is on). When that feature becomes +// stable, this test can be deleted. + +#![feature(macro_vis_matcher)] + +#![allow(unused)] +#![warn(unreachable_pub)] + +mod private_mod { + // non-leaked `pub` items in private module should be linted + pub use std::fmt; + + pub struct Hydrogen { + // `pub` struct fields, too + pub neutrons: usize, + // (... but not more-restricted fields) + pub(crate) electrons: usize + } + impl Hydrogen { + // impls, too + pub fn count_neutrons(&self) -> usize { self.neutrons } + pub(crate) fn count_electrons(&self) -> usize { self.electrons } + } + + pub enum Helium {} + pub union Lithium { c1: usize, c2: u8 } + pub fn beryllium() {} + pub trait Boron {} + pub const CARBON: usize = 1; + pub static NITROGEN: usize = 2; + pub type Oxygen = bool; + + macro_rules! define_empty_struct_with_visibility { + ($visibility: vis, $name: ident) => { $visibility struct $name {} } + } + define_empty_struct_with_visibility!(pub, Fluorine); + + extern { + pub fn catalyze() -> bool; + } + + // items leaked through signatures (see `get_neon` below) are OK + pub struct Neon {} + + // crate-visible items are OK + pub(crate) struct Sodium {} +} + +pub mod public_mod { + // module is public: these are OK, too + pub struct Magnesium {} + pub(crate) struct Aluminum {} +} + +pub fn get_neon() -> private_mod::Neon { + private_mod::Neon {} +} + +fn main() { + let _ = get_neon(); +} diff --git a/src/test/ui/lint/unreachable_pub-pub_crate.stderr b/src/test/ui/lint/unreachable_pub-pub_crate.stderr new file mode 100644 index 00000000000..84cbf87c1a1 --- /dev/null +++ b/src/test/ui/lint/unreachable_pub-pub_crate.stderr @@ -0,0 +1,134 @@ +warning: unreachable `pub` item + --> $DIR/unreachable_pub-pub_crate.rs:24:5 + | +24 | pub use std::fmt; + | ---^^^^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `pub(crate)` + | +note: lint level defined here + --> $DIR/unreachable_pub-pub_crate.rs:20:9 + | +20 | #![warn(unreachable_pub)] + | ^^^^^^^^^^^^^^^ + = help: or consider exporting it for use by other crates + +warning: unreachable `pub` item + --> $DIR/unreachable_pub-pub_crate.rs:26:5 + | +26 | pub struct Hydrogen { + | ---^^^^^^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `pub(crate)` + | + = help: or consider exporting it for use by other crates + +warning: unreachable `pub` field + --> $DIR/unreachable_pub-pub_crate.rs:28:9 + | +28 | pub neutrons: usize, + | ---^^^^^^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `pub(crate)` + +warning: unreachable `pub` item + --> $DIR/unreachable_pub-pub_crate.rs:34:9 + | +34 | pub fn count_neutrons(&self) -> usize { self.neutrons } + | ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `pub(crate)` + +warning: unreachable `pub` item + --> $DIR/unreachable_pub-pub_crate.rs:38:5 + | +38 | pub enum Helium {} + | ---^^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `pub(crate)` + | + = help: or consider exporting it for use by other crates + +warning: unreachable `pub` item + --> $DIR/unreachable_pub-pub_crate.rs:39:5 + | +39 | pub union Lithium { c1: usize, c2: u8 } + | ---^^^^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `pub(crate)` + | + = help: or consider exporting it for use by other crates + +warning: unreachable `pub` item + --> $DIR/unreachable_pub-pub_crate.rs:40:5 + | +40 | pub fn beryllium() {} + | ---^^^^^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `pub(crate)` + | + = help: or consider exporting it for use by other crates + +warning: unreachable `pub` item + --> $DIR/unreachable_pub-pub_crate.rs:41:5 + | +41 | pub trait Boron {} + | ---^^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `pub(crate)` + | + = help: or consider exporting it for use by other crates + +warning: unreachable `pub` item + --> $DIR/unreachable_pub-pub_crate.rs:42:5 + | +42 | pub const CARBON: usize = 1; + | ---^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `pub(crate)` + | + = help: or consider exporting it for use by other crates + +warning: unreachable `pub` item + --> $DIR/unreachable_pub-pub_crate.rs:43:5 + | +43 | pub static NITROGEN: usize = 2; + | ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `pub(crate)` + | + = help: or consider exporting it for use by other crates + +warning: unreachable `pub` item + --> $DIR/unreachable_pub-pub_crate.rs:44:5 + | +44 | pub type Oxygen = bool; + | ---^^^^^^^^^^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `pub(crate)` + | + = help: or consider exporting it for use by other crates + +warning: unreachable `pub` item + --> $DIR/unreachable_pub-pub_crate.rs:47:47 + | +47 | ($visibility: vis, $name: ident) => { $visibility struct $name {} } + | -----------^^^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `pub(crate)` +48 | } +49 | define_empty_struct_with_visibility!(pub, Fluorine); + | ---------------------------------------------------- in this macro invocation + | + = help: or consider exporting it for use by other crates + +warning: unreachable `pub` item + --> $DIR/unreachable_pub-pub_crate.rs:52:9 + | +52 | pub fn catalyze() -> bool; + | ---^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `pub(crate)` + | + = help: or consider exporting it for use by other crates + diff --git a/src/test/ui/lint/unreachable_pub.rs b/src/test/ui/lint/unreachable_pub.rs new file mode 100644 index 00000000000..5812061dfdb --- /dev/null +++ b/src/test/ui/lint/unreachable_pub.rs @@ -0,0 +1,69 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(crate_visibility_modifier)] +#![feature(macro_vis_matcher)] + +#![allow(unused)] +#![warn(unreachable_pub)] + +mod private_mod { + // non-leaked `pub` items in private module should be linted + pub use std::fmt; + + pub struct Hydrogen { + // `pub` struct fields, too + pub neutrons: usize, + // (... but not more-restricted fields) + crate electrons: usize + } + impl Hydrogen { + // impls, too + pub fn count_neutrons(&self) -> usize { self.neutrons } + crate fn count_electrons(&self) -> usize { self.electrons } + } + + pub enum Helium {} + pub union Lithium { c1: usize, c2: u8 } + pub fn beryllium() {} + pub trait Boron {} + pub const CARBON: usize = 1; + pub static NITROGEN: usize = 2; + pub type Oxygen = bool; + + macro_rules! define_empty_struct_with_visibility { + ($visibility: vis, $name: ident) => { $visibility struct $name {} } + } + define_empty_struct_with_visibility!(pub, Fluorine); + + extern { + pub fn catalyze() -> bool; + } + + // items leaked through signatures (see `get_neon` below) are OK + pub struct Neon {} + + // crate-visible items are OK + crate struct Sodium {} +} + +pub mod public_mod { + // module is public: these are OK, too + pub struct Magnesium {} + crate struct Aluminum {} +} + +pub fn get_neon() -> private_mod::Neon { + private_mod::Neon {} +} + +fn main() { + let _ = get_neon(); +} diff --git a/src/test/ui/lint/unreachable_pub.stderr b/src/test/ui/lint/unreachable_pub.stderr new file mode 100644 index 00000000000..bdd016ff2df --- /dev/null +++ b/src/test/ui/lint/unreachable_pub.stderr @@ -0,0 +1,134 @@ +warning: unreachable `pub` item + --> $DIR/unreachable_pub.rs:19:5 + | +19 | pub use std::fmt; + | ---^^^^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `crate` + | +note: lint level defined here + --> $DIR/unreachable_pub.rs:15:9 + | +15 | #![warn(unreachable_pub)] + | ^^^^^^^^^^^^^^^ + = help: or consider exporting it for use by other crates + +warning: unreachable `pub` item + --> $DIR/unreachable_pub.rs:21:5 + | +21 | pub struct Hydrogen { + | ---^^^^^^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `crate` + | + = help: or consider exporting it for use by other crates + +warning: unreachable `pub` field + --> $DIR/unreachable_pub.rs:23:9 + | +23 | pub neutrons: usize, + | ---^^^^^^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `crate` + +warning: unreachable `pub` item + --> $DIR/unreachable_pub.rs:29:9 + | +29 | pub fn count_neutrons(&self) -> usize { self.neutrons } + | ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `crate` + +warning: unreachable `pub` item + --> $DIR/unreachable_pub.rs:33:5 + | +33 | pub enum Helium {} + | ---^^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `crate` + | + = help: or consider exporting it for use by other crates + +warning: unreachable `pub` item + --> $DIR/unreachable_pub.rs:34:5 + | +34 | pub union Lithium { c1: usize, c2: u8 } + | ---^^^^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `crate` + | + = help: or consider exporting it for use by other crates + +warning: unreachable `pub` item + --> $DIR/unreachable_pub.rs:35:5 + | +35 | pub fn beryllium() {} + | ---^^^^^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `crate` + | + = help: or consider exporting it for use by other crates + +warning: unreachable `pub` item + --> $DIR/unreachable_pub.rs:36:5 + | +36 | pub trait Boron {} + | ---^^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `crate` + | + = help: or consider exporting it for use by other crates + +warning: unreachable `pub` item + --> $DIR/unreachable_pub.rs:37:5 + | +37 | pub const CARBON: usize = 1; + | ---^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `crate` + | + = help: or consider exporting it for use by other crates + +warning: unreachable `pub` item + --> $DIR/unreachable_pub.rs:38:5 + | +38 | pub static NITROGEN: usize = 2; + | ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `crate` + | + = help: or consider exporting it for use by other crates + +warning: unreachable `pub` item + --> $DIR/unreachable_pub.rs:39:5 + | +39 | pub type Oxygen = bool; + | ---^^^^^^^^^^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `crate` + | + = help: or consider exporting it for use by other crates + +warning: unreachable `pub` item + --> $DIR/unreachable_pub.rs:42:47 + | +42 | ($visibility: vis, $name: ident) => { $visibility struct $name {} } + | -----------^^^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `crate` +43 | } +44 | define_empty_struct_with_visibility!(pub, Fluorine); + | ---------------------------------------------------- in this macro invocation + | + = help: or consider exporting it for use by other crates + +warning: unreachable `pub` item + --> $DIR/unreachable_pub.rs:47:9 + | +47 | pub fn catalyze() -> bool; + | ---^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `crate` + | + = help: or consider exporting it for use by other crates + diff --git a/src/test/ui/lint/unused_parens_json_suggestion.rs b/src/test/ui/lint/unused_parens_json_suggestion.rs index 15251795d5e..ad501e66809 100644 --- a/src/test/ui/lint/unused_parens_json_suggestion.rs +++ b/src/test/ui/lint/unused_parens_json_suggestion.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: --error-format json +// compile-flags: --error-format pretty-json -Zunstable-options // The output for humans should just highlight the whole span without showing // the suggested replacement, but we also want to test that suggested diff --git a/src/test/ui/lint/unused_parens_json_suggestion.stderr b/src/test/ui/lint/unused_parens_json_suggestion.stderr index ae5b53da175..e166f7011b5 100644 --- a/src/test/ui/lint/unused_parens_json_suggestion.stderr +++ b/src/test/ui/lint/unused_parens_json_suggestion.stderr @@ -1 +1,91 @@ -{"message":"unnecessary parentheses around assigned value","code":null,"level":"warning","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":1001,"byte_end":1014,"line_start":24,"line_end":24,"column_start":14,"column_end":27,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3));","highlight_start":14,"highlight_end":27}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"lint level defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":847,"byte_end":860,"line_start":19,"line_end":19,"column_start":9,"column_end":22,"is_primary":true,"text":[{"text":"#![warn(unused_parens)]","highlight_start":9,"highlight_end":22}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":1001,"byte_end":1014,"line_start":24,"line_end":24,"column_start":14,"column_end":27,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3));","highlight_start":14,"highlight_end":27}],"label":null,"suggested_replacement":"1 / (2 + 3)","expansion":null}],"children":[],"rendered":null}],"rendered":null} +{ + "message": "unnecessary parentheses around assigned value", + "code": { + "code": "unused_parens", + "explanation": null + }, + "level": "warning", + "spans": [ + { + "file_name": "$DIR/unused_parens_json_suggestion.rs", + "byte_start": 1027, + "byte_end": 1040, + "line_start": 24, + "line_end": 24, + "column_start": 14, + "column_end": 27, + "is_primary": true, + "text": [ + { + "text": " let _a = (1 / (2 + 3));", + "highlight_start": 14, + "highlight_end": 27 + } + ], + "label": null, + "suggested_replacement": null, + "expansion": null + } + ], + "children": [ + { + "message": "lint level defined here", + "code": null, + "level": "note", + "spans": [ + { + "file_name": "$DIR/unused_parens_json_suggestion.rs", + "byte_start": 873, + "byte_end": 886, + "line_start": 19, + "line_end": 19, + "column_start": 9, + "column_end": 22, + "is_primary": true, + "text": [ + { + "text": "#![warn(unused_parens)]", + "highlight_start": 9, + "highlight_end": 22 + } + ], + "label": null, + "suggested_replacement": null, + "expansion": null + } + ], + "children": [], + "rendered": null + }, + { + "message": "remove these parentheses", + "code": null, + "level": "help", + "spans": [ + { + "file_name": "$DIR/unused_parens_json_suggestion.rs", + "byte_start": 1027, + "byte_end": 1040, + "line_start": 24, + "line_end": 24, + "column_start": 14, + "column_end": 27, + "is_primary": true, + "text": [ + { + "text": " let _a = (1 / (2 + 3));", + "highlight_start": 14, + "highlight_end": 27 + } + ], + "label": null, + "suggested_replacement": "1 / (2 + 3)", + "expansion": null + } + ], + "children": [], + "rendered": null + } + ], + "rendered": null +} diff --git a/src/test/ui/lint/use_suggestion_json.rs b/src/test/ui/lint/use_suggestion_json.rs index 20c24d64050..27232c4fec4 100644 --- a/src/test/ui/lint/use_suggestion_json.rs +++ b/src/test/ui/lint/use_suggestion_json.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: --error-format json +// compile-flags: --error-format pretty-json -Zunstable-options // The output for humans should just highlight the whole span without showing // the suggested replacement, but we also want to test that suggested diff --git a/src/test/ui/lint/use_suggestion_json.stderr b/src/test/ui/lint/use_suggestion_json.stderr index 2ebe212b93d..fd3b5fe1ada 100644 --- a/src/test/ui/lint/use_suggestion_json.stderr +++ b/src/test/ui/lint/use_suggestion_json.stderr @@ -1,2 +1,290 @@ -{"message":"cannot find type `Iter` in this scope","code":{"code":"E0412","explanation":"/nThe type name used is not in scope./n/nErroneous code examples:/n/n```compile_fail,E0412/nimpl Something {} // error: type name `Something` is not in scope/n/n// or:/n/ntrait Foo {/n fn bar(N); // error: type name `N` is not in scope/n}/n/n// or:/n/nfn foo(x: T) {} // type name `T` is not in scope/n```/n/nTo fix this error, please verify you didn't misspell the type name, you did/ndeclare it or imported it into the scope. Examples:/n/n```/nstruct Something;/n/nimpl Something {} // ok!/n/n// or:/n/ntrait Foo {/n type N;/n/n fn bar(_: Self::N); // ok!/n}/n/n// or:/n/nfn foo<T>(x: T) {} // ok!/n```/n/nAnother case that causes this error is when a type is imported into a parent/nmodule. To fix this, you can follow the suggestion and use File directly or/n`use super::File;` which will import the types from the parent namespace. An/nexample that causes this error is below:/n/n```compile_fail,E0412/nuse std::fs::File;/n/nmod foo {/n fn some_function(f: File) {}/n}/n```/n/n```/nuse std::fs::File;/n/nmod foo {/n // either/n use super::File;/n // or/n // use std::fs::File;/n fn foo(f: File) {}/n}/n# fn main() {} // don't insert it for us; that'll break imports/n```/n"},"level":"error","spans":[{"file_name":"$DIR/use_suggestion_json.rs","byte_start":862,"byte_end":866,"line_start":20,"line_end":20,"column_start":12,"column_end":16,"is_primary":true,"text":[{"text":" let x: Iter;","highlight_start":12,"highlight_end":16}],"label":"not found in this scope","suggested_replacement":null,"expansion":null}],"children":[{"message":"possible candidates are found in other modules, you can import them into scope","code":null,"level":"help","spans":[{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::collections::binary_heap::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::collections::btree_map::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::collections::btree_set::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::collections::hash_map::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::collections::hash_set::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::collections::linked_list::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::collections::vec_deque::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::option::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::path::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::result::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::slice::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::sync::mpsc::Iter;/n/n","expansion":null}],"children":[],"rendered":null}],"rendered":null} -{"message":"aborting due to previous error","code":null,"level":"error","spans":[],"children":[],"rendered":null} +{ + "message": "cannot find type `Iter` in this scope", + "code": { + "code": "E0412", + "explanation": "/nThe type name used is not in scope./n/nErroneous code examples:/n/n```compile_fail,E0412/nimpl Something {} // error: type name `Something` is not in scope/n/n// or:/n/ntrait Foo {/n fn bar(N); // error: type name `N` is not in scope/n}/n/n// or:/n/nfn foo(x: T) {} // type name `T` is not in scope/n```/n/nTo fix this error, please verify you didn't misspell the type name, you did/ndeclare it or imported it into the scope. Examples:/n/n```/nstruct Something;/n/nimpl Something {} // ok!/n/n// or:/n/ntrait Foo {/n type N;/n/n fn bar(_: Self::N); // ok!/n}/n/n// or:/n/nfn foo<T>(x: T) {} // ok!/n```/n/nAnother case that causes this error is when a type is imported into a parent/nmodule. To fix this, you can follow the suggestion and use File directly or/n`use super::File;` which will import the types from the parent namespace. An/nexample that causes this error is below:/n/n```compile_fail,E0412/nuse std::fs::File;/n/nmod foo {/n fn some_function(f: File) {}/n}/n```/n/n```/nuse std::fs::File;/n/nmod foo {/n // either/n use super::File;/n // or/n // use std::fs::File;/n fn foo(f: File) {}/n}/n# fn main() {} // don't insert it for us; that'll break imports/n```/n" + }, + "level": "error", + "spans": [ + { + "file_name": "$DIR/use_suggestion_json.rs", + "byte_start": 888, + "byte_end": 892, + "line_start": 20, + "line_end": 20, + "column_start": 12, + "column_end": 16, + "is_primary": true, + "text": [ + { + "text": " let x: Iter;", + "highlight_start": 12, + "highlight_end": 16 + } + ], + "label": "not found in this scope", + "suggested_replacement": null, + "expansion": null + } + ], + "children": [ + { + "message": "possible candidates are found in other modules, you can import them into scope", + "code": null, + "level": "help", + "spans": [ + { + "file_name": "$DIR/use_suggestion_json.rs", + "byte_start": 865, + "byte_end": 865, + "line_start": 19, + "line_end": 19, + "column_start": 1, + "column_end": 1, + "is_primary": true, + "text": [ + { + "text": "fn main() {", + "highlight_start": 1, + "highlight_end": 1 + } + ], + "label": null, + "suggested_replacement": "use std::collections::binary_heap::Iter;/n/n", + "expansion": null + }, + { + "file_name": "$DIR/use_suggestion_json.rs", + "byte_start": 865, + "byte_end": 865, + "line_start": 19, + "line_end": 19, + "column_start": 1, + "column_end": 1, + "is_primary": true, + "text": [ + { + "text": "fn main() {", + "highlight_start": 1, + "highlight_end": 1 + } + ], + "label": null, + "suggested_replacement": "use std::collections::btree_map::Iter;/n/n", + "expansion": null + }, + { + "file_name": "$DIR/use_suggestion_json.rs", + "byte_start": 865, + "byte_end": 865, + "line_start": 19, + "line_end": 19, + "column_start": 1, + "column_end": 1, + "is_primary": true, + "text": [ + { + "text": "fn main() {", + "highlight_start": 1, + "highlight_end": 1 + } + ], + "label": null, + "suggested_replacement": "use std::collections::btree_set::Iter;/n/n", + "expansion": null + }, + { + "file_name": "$DIR/use_suggestion_json.rs", + "byte_start": 865, + "byte_end": 865, + "line_start": 19, + "line_end": 19, + "column_start": 1, + "column_end": 1, + "is_primary": true, + "text": [ + { + "text": "fn main() {", + "highlight_start": 1, + "highlight_end": 1 + } + ], + "label": null, + "suggested_replacement": "use std::collections::hash_map::Iter;/n/n", + "expansion": null + }, + { + "file_name": "$DIR/use_suggestion_json.rs", + "byte_start": 865, + "byte_end": 865, + "line_start": 19, + "line_end": 19, + "column_start": 1, + "column_end": 1, + "is_primary": true, + "text": [ + { + "text": "fn main() {", + "highlight_start": 1, + "highlight_end": 1 + } + ], + "label": null, + "suggested_replacement": "use std::collections::hash_set::Iter;/n/n", + "expansion": null + }, + { + "file_name": "$DIR/use_suggestion_json.rs", + "byte_start": 865, + "byte_end": 865, + "line_start": 19, + "line_end": 19, + "column_start": 1, + "column_end": 1, + "is_primary": true, + "text": [ + { + "text": "fn main() {", + "highlight_start": 1, + "highlight_end": 1 + } + ], + "label": null, + "suggested_replacement": "use std::collections::linked_list::Iter;/n/n", + "expansion": null + }, + { + "file_name": "$DIR/use_suggestion_json.rs", + "byte_start": 865, + "byte_end": 865, + "line_start": 19, + "line_end": 19, + "column_start": 1, + "column_end": 1, + "is_primary": true, + "text": [ + { + "text": "fn main() {", + "highlight_start": 1, + "highlight_end": 1 + } + ], + "label": null, + "suggested_replacement": "use std::collections::vec_deque::Iter;/n/n", + "expansion": null + }, + { + "file_name": "$DIR/use_suggestion_json.rs", + "byte_start": 865, + "byte_end": 865, + "line_start": 19, + "line_end": 19, + "column_start": 1, + "column_end": 1, + "is_primary": true, + "text": [ + { + "text": "fn main() {", + "highlight_start": 1, + "highlight_end": 1 + } + ], + "label": null, + "suggested_replacement": "use std::option::Iter;/n/n", + "expansion": null + }, + { + "file_name": "$DIR/use_suggestion_json.rs", + "byte_start": 865, + "byte_end": 865, + "line_start": 19, + "line_end": 19, + "column_start": 1, + "column_end": 1, + "is_primary": true, + "text": [ + { + "text": "fn main() {", + "highlight_start": 1, + "highlight_end": 1 + } + ], + "label": null, + "suggested_replacement": "use std::path::Iter;/n/n", + "expansion": null + }, + { + "file_name": "$DIR/use_suggestion_json.rs", + "byte_start": 865, + "byte_end": 865, + "line_start": 19, + "line_end": 19, + "column_start": 1, + "column_end": 1, + "is_primary": true, + "text": [ + { + "text": "fn main() {", + "highlight_start": 1, + "highlight_end": 1 + } + ], + "label": null, + "suggested_replacement": "use std::result::Iter;/n/n", + "expansion": null + }, + { + "file_name": "$DIR/use_suggestion_json.rs", + "byte_start": 865, + "byte_end": 865, + "line_start": 19, + "line_end": 19, + "column_start": 1, + "column_end": 1, + "is_primary": true, + "text": [ + { + "text": "fn main() {", + "highlight_start": 1, + "highlight_end": 1 + } + ], + "label": null, + "suggested_replacement": "use std::slice::Iter;/n/n", + "expansion": null + }, + { + "file_name": "$DIR/use_suggestion_json.rs", + "byte_start": 865, + "byte_end": 865, + "line_start": 19, + "line_end": 19, + "column_start": 1, + "column_end": 1, + "is_primary": true, + "text": [ + { + "text": "fn main() {", + "highlight_start": 1, + "highlight_end": 1 + } + ], + "label": null, + "suggested_replacement": "use std::sync::mpsc::Iter;/n/n", + "expansion": null + } + ], + "children": [], + "rendered": null + } + ], + "rendered": null +} +{ + "message": "aborting due to previous error", + "code": null, + "level": "error", + "spans": [], + "children": [], + "rendered": null +} diff --git a/src/test/ui/mismatched_types/closure-arg-count.stderr b/src/test/ui/mismatched_types/closure-arg-count.stderr index 9d4ac630546..9de5e8fea01 100644 --- a/src/test/ui/mismatched_types/closure-arg-count.stderr +++ b/src/test/ui/mismatched_types/closure-arg-count.stderr @@ -14,15 +14,6 @@ error[E0593]: closure is expected to take 2 arguments, but it takes 1 argument | | | expected closure that takes 2 arguments -error[E0308]: mismatched types - --> $DIR/closure-arg-count.rs:17:24 - | -17 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!()); - | ^^^^^^^^^^^^^^^ expected &{integer}, found tuple - | - = note: expected type `&{integer}` - found type `(_, _)` - error[E0593]: closure is expected to take 2 arguments, but it takes 1 argument --> $DIR/closure-arg-count.rs:17:15 | @@ -65,5 +56,5 @@ error[E0593]: closure is expected to take a single 2-tuple as argument, but it t | | | expected closure that takes a single 2-tuple as argument -error: aborting due to 8 previous errors +error: aborting due to 7 previous errors diff --git a/src/test/ui/nll/named-region-basic.rs b/src/test/ui/nll/named-region-basic.rs new file mode 100644 index 00000000000..539c2017ea6 --- /dev/null +++ b/src/test/ui/nll/named-region-basic.rs @@ -0,0 +1,22 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Basic test for free regions in the NLL code. This test ought to +// report an error due to a reborrowing constraint. Right now, we get +// a variety of errors from the older, AST-based machinery (notably +// borrowck), and then we get the NLL error at the end. + +// compile-flags:-Znll + +fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> &'b u32 { + &*x +} + +fn main() { } diff --git a/src/test/ui/nll/named-region-basic.stderr b/src/test/ui/nll/named-region-basic.stderr new file mode 100644 index 00000000000..42b2aea01f0 --- /dev/null +++ b/src/test/ui/nll/named-region-basic.stderr @@ -0,0 +1,29 @@ +warning: not reporting region error due to -Znll + --> $DIR/named-region-basic.rs:19:5 + | +19 | &*x + | ^^^ + +error[E0597]: `*x` does not live long enough + --> $DIR/named-region-basic.rs:19:6 + | +19 | &*x + | ^^ does not live long enough + | + = note: borrowed value must be valid for the static lifetime... +note: ...but borrowed value is only valid for the lifetime 'a as defined on the function body at 18:1 + --> $DIR/named-region-basic.rs:18:1 + | +18 | / fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> &'b u32 { +19 | | &*x +20 | | } + | |_^ + +error: free region `'a` does not outlive `'b` + --> $DIR/named-region-basic.rs:19:5 + | +19 | &*x + | ^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/resolve/token-error-correct.stderr b/src/test/ui/resolve/token-error-correct.stderr index 281c21f6f85..6bd63f4fbbb 100644 --- a/src/test/ui/resolve/token-error-correct.stderr +++ b/src/test/ui/resolve/token-error-correct.stderr @@ -28,29 +28,11 @@ error: expected expression, found `;` 14 | foo(bar(; | ^ -error: expected one of `)`, `,`, `.`, `<`, `?`, `break`, `continue`, `false`, `for`, `if`, `loop`, `match`, `move`, `return`, `true`, `unsafe`, `while`, `yield`, or an operator, found `;` - --> $DIR/token-error-correct.rs:14:13 - | -14 | foo(bar(; - | ^ expected one of 19 possible tokens here - error: expected expression, found `)` --> $DIR/token-error-correct.rs:23:1 | 23 | } | ^ -error[E0425]: cannot find function `foo` in this scope - --> $DIR/token-error-correct.rs:14:5 - | -14 | foo(bar(; - | ^^^ not found in this scope - -error[E0425]: cannot find function `bar` in this scope - --> $DIR/token-error-correct.rs:14:9 - | -14 | foo(bar(; - | ^^^ not found in this scope - -error: aborting due to 7 previous errors +error: aborting due to 4 previous errors diff --git a/src/test/ui/rfc-2005-default-binding-mode/suggestion.rs b/src/test/ui/rfc-2005-default-binding-mode/suggestion.rs new file mode 100644 index 00000000000..52ff817dff4 --- /dev/null +++ b/src/test/ui/rfc-2005-default-binding-mode/suggestion.rs @@ -0,0 +1,15 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + if let Some(y) = &Some(22) { + println!("{}", y); + } +} diff --git a/src/test/ui/rfc-2005-default-binding-mode/suggestion.stderr b/src/test/ui/rfc-2005-default-binding-mode/suggestion.stderr new file mode 100644 index 00000000000..0594f865f32 --- /dev/null +++ b/src/test/ui/rfc-2005-default-binding-mode/suggestion.stderr @@ -0,0 +1,10 @@ +error: non-reference pattern used to match a reference (see issue #42640) + --> $DIR/suggestion.rs:12:12 + | +12 | if let Some(y) = &Some(22) { + | ^^^^^^^ help: consider using: `&Some(y)` + | + = help: add #![feature(match_default_bindings)] to the crate attributes to enable + +error: aborting due to previous error + diff --git a/src/test/ui/span/E0535.rs b/src/test/ui/span/E0535.rs index 17558cc05c6..f9219436c78 100644 --- a/src/test/ui/span/E0535.rs +++ b/src/test/ui/span/E0535.rs @@ -11,4 +11,6 @@ #[inline(unknown)] //~ ERROR E0535 pub fn something() {} -fn main() {} +fn main() { + something(); +} diff --git a/src/test/ui/suggestions/type-ascription-instead-of-initializer.rs b/src/test/ui/suggestions/type-ascription-instead-of-initializer.rs new file mode 100644 index 00000000000..bcd965f10fa --- /dev/null +++ b/src/test/ui/suggestions/type-ascription-instead-of-initializer.rs @@ -0,0 +1,13 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let x: Vec::with_capacity(10, 20); +} diff --git a/src/test/ui/suggestions/type-ascription-instead-of-initializer.stderr b/src/test/ui/suggestions/type-ascription-instead-of-initializer.stderr new file mode 100644 index 00000000000..647e3f84685 --- /dev/null +++ b/src/test/ui/suggestions/type-ascription-instead-of-initializer.stderr @@ -0,0 +1,17 @@ +error: expected type, found `10` + --> $DIR/type-ascription-instead-of-initializer.rs:12:31 + | +12 | let x: Vec::with_capacity(10, 20); + | -- ^^ + | || + | |help: use `=` if you meant to assign + | while parsing the type for `x` + +error[E0061]: this function takes 1 parameter but 2 parameters were supplied + --> $DIR/type-ascription-instead-of-initializer.rs:12:31 + | +12 | let x: Vec::with_capacity(10, 20); + | ^^^^^^ expected 1 parameter + +error: aborting due to 2 previous errors + diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 859c2305b5d7ff820d7f7af158bbca999cbd8bf +Subproject b83550edc300e3d80dd16d0440123ffc1ad77bb diff --git a/src/tools/cargotest/main.rs b/src/tools/cargotest/main.rs index 4f4960efc9b..a6c56a13076 100644 --- a/src/tools/cargotest/main.rs +++ b/src/tools/cargotest/main.rs @@ -165,6 +165,8 @@ fn run_cargo_test(cargo_path: &Path, crate_path: &Path, packages: &[&str]) -> bo let status = command // Disable rust-lang/cargo's cross-compile tests .env("CFG_DISABLE_CROSS_TESTS", "1") + // Relax #![deny(warnings)] in some crates + .env("RUSTFLAGS", "--cap-lints warn") .current_dir(crate_path) .status() .expect(""); diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index aa98f818f40..660462ad419 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -34,6 +34,20 @@ pub enum Mode { MirOpt, } +impl Mode { + pub fn disambiguator(self) -> &'static str { + // Run-pass and pretty run-pass tests could run concurrently, and if they do, + // they need to keep their output segregated. Same is true for debuginfo tests that + // can be run both on gdb and lldb. + match self { + Pretty => ".pretty", + DebugInfoGdb => ".gdb", + DebugInfoLldb => ".lldb", + _ => "", + } + } +} + impl FromStr for Mode { type Err = (); fn from_str(s: &str) -> Result<Mode, ()> { diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 0473c2a5405..f02525c118a 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1384,6 +1384,7 @@ actual:\n\ if let Some(ref incremental_dir) = self.props.incremental_dir { rustc.args(&["-Z", &format!("incremental={}", incremental_dir.display())]); + rustc.args(&["-Z", "incremental-verify-ich"]); } match self.config.mode { @@ -1404,6 +1405,7 @@ actual:\n\ "-Zdump-mir-exclude-pass-number"]); let mir_dump_dir = self.get_mir_dump_dir(); + let _ = fs::remove_dir_all(&mir_dump_dir); create_dir_all(mir_dump_dir.as_path()).unwrap(); let mut dir_opt = "-Zdump-mir-dir=".to_string(); dir_opt.push_str(mir_dump_dir.to_str().unwrap()); @@ -1564,7 +1566,7 @@ actual:\n\ fn aux_output_dir_name(&self) -> PathBuf { let f = self.output_base_name(); let mut fname = f.file_name().unwrap().to_os_string(); - fname.push(&format!(".{}.libaux", self.config.mode)); + fname.push(&format!("{}.aux", self.config.mode.disambiguator())); f.with_file_name(&fname) } @@ -2285,6 +2287,10 @@ actual:\n\ output_file.push(test_name); debug!("comparing the contests of: {:?}", output_file); debug!("with: {:?}", expected_content); + if !output_file.exists() { + panic!("Output file `{}` from test does not exist", + output_file.into_os_string().to_string_lossy()); + } self.check_mir_test_timestamp(test_name, &output_file); let mut dumped_file = fs::File::open(output_file.clone()).unwrap(); @@ -2333,13 +2339,22 @@ actual:\n\ // We expect each non-empty line to appear consecutively, non-consecutive lines // must be separated by at least one Elision + let mut start_block_line = None; while let Some(dumped_line) = dumped_lines.next() { match expected_lines.next() { - Some(&ExpectedLine::Text(expected_line)) => + Some(&ExpectedLine::Text(expected_line)) => { + let normalized_expected_line = normalize_mir_line(expected_line); + if normalized_expected_line.contains(":{") { + start_block_line = Some(expected_line); + } + if !compare(expected_line, dumped_line) { + error!("{:?}", start_block_line); error(expected_line, - format!("Mismatch in lines\nExpected Line: {:?}", dumped_line)); - }, + format!("Mismatch in lines\nCurrnt block: {}\nExpected Line: {:?}", + start_block_line.unwrap_or("None"), dumped_line)); + } + }, Some(&ExpectedLine::Elision) => { // skip any number of elisions in a row. while let Some(&&ExpectedLine::Elision) = expected_lines.peek() { @@ -2367,19 +2382,18 @@ actual:\n\ } fn get_mir_dump_dir(&self) -> PathBuf { - let mut mir_dump_dir = PathBuf::from(self.config.build_base - .as_path() - .to_str() - .unwrap()); + let mut mir_dump_dir = PathBuf::from(self.config.build_base.as_path()); debug!("input_file: {:?}", self.testpaths.file); - mir_dump_dir.push(self.testpaths.file.file_stem().unwrap().to_str().unwrap()); + mir_dump_dir.push(&self.testpaths.relative_dir); + mir_dump_dir.push(self.testpaths.file.file_stem().unwrap()); mir_dump_dir } fn normalize_output(&self, output: &str, custom_rules: &[(String, String)]) -> String { let parent_dir = self.testpaths.file.parent().unwrap(); let cflags = self.props.compile_flags.join(" "); - let parent_dir_str = if cflags.contains("--error-format json") { + let parent_dir_str = if cflags.contains("--error-format json") + || cflags.contains("--error-format pretty-json") { parent_dir.display().to_string().replace("\\", "\\\\") } else { parent_dir.display().to_string() diff --git a/src/tools/rls b/src/tools/rls -Subproject e0348594a724571f1d2387e03943efeb4df20e1 +Subproject 9ad92e134ff56df52481cf19dc3da14b9e73506 diff --git a/src/tools/rustfmt b/src/tools/rustfmt -Subproject cf0d494dda7447bacaab743a70c47e28bea55c6 +Subproject 51b03c3aaf5e69afbb7508e566c5da2bf0bc366 |
