diff options
| author | Brad Gibson <b2b@humanenginuity.com> | 2018-05-06 07:56:53 -0700 |
|---|---|---|
| committer | Brad Gibson <b2b@humanenginuity.com> | 2018-05-06 07:56:53 -0700 |
| commit | 6a78c0a10f2e719117fe4bb929bfb38549acfeec (patch) | |
| tree | 0089dcdd34bfa5ba430ed33163264b147677be59 /src | |
| parent | e1d5509bf381d978a1894b6ba869c3b56dd3eeca (diff) | |
| parent | 6f721f54c6fb1de9cf00eb9d2d050f818c882871 (diff) | |
| download | rust-6a78c0a10f2e719117fe4bb929bfb38549acfeec.tar.gz rust-6a78c0a10f2e719117fe4bb929bfb38549acfeec.zip | |
resolved conflict with upstream commit
Diffstat (limited to 'src')
553 files changed, 10881 insertions, 4889 deletions
diff --git a/src/Cargo.lock b/src/Cargo.lock index e14b9da9713..a2767bd290d 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -390,10 +390,12 @@ dependencies = [ "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "rustfix 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", @@ -996,9 +998,10 @@ dependencies = [ [[package]] name = "languageserver-types" -version = "0.36.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1325,16 +1328,16 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "parking_lot_core" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1623,7 +1626,7 @@ dependencies = [ [[package]] name = "rls" -version = "0.126.0" +version = "0.127.0" dependencies = [ "cargo 0.28.0", "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1632,7 +1635,7 @@ dependencies = [ "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "languageserver-types 0.36.0 (registry+https://github.com/rust-lang/crates.io-index)", + "languageserver-types 0.39.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1644,7 +1647,7 @@ dependencies = [ "rls-rustc 0.2.2 (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.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rustfmt-nightly 0.6.0", + "rustfmt-nightly 0.6.1", "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1728,7 +1731,6 @@ dependencies = [ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro 0.0.0", "rustc_apfloat 0.0.0", - "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "rustc_target 0.0.0", @@ -1740,70 +1742,84 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_cratesio_shim" -version = "110.0.0" +version = "113.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc-ap-rustc_data_structures" -version = "110.0.0" +version = "113.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ena 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_cratesio_shim 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc-ap-rustc_errors" -version = "110.0.0" +version = "113.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_data_structures 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-syntax_pos 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_data_structures 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-syntax_pos 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] +name = "rustc-ap-rustc_target" +version = "113.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_cratesio_shim 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "rustc-ap-serialize" -version = "110.0.0" +version = "113.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rustc-ap-syntax" -version = "110.0.0" +version = "113.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_cratesio_shim 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_data_structures 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_errors 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-syntax_pos 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_data_structures 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_errors 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_target 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-syntax_pos 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc-ap-syntax_pos" -version = "110.0.0" +version = "113.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rustc-ap-rustc_data_structures 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_data_structures 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1873,15 +1889,6 @@ dependencies = [ ] [[package]] -name = "rustc_const_math" -version = "0.0.0" -dependencies = [ - "rustc_apfloat 0.0.0", - "serialize 0.0.0", - "syntax 0.0.0", -] - -[[package]] name = "rustc_cratesio_shim" version = "0.0.0" dependencies = [ @@ -1896,8 +1903,8 @@ dependencies = [ "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ena 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_cratesio_shim 0.0.0", "serialize 0.0.0", "stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2026,7 +2033,6 @@ dependencies = [ "log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_apfloat 0.0.0", - "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "rustc_target 0.0.0", @@ -2053,7 +2059,6 @@ version = "0.0.0" dependencies = [ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", - "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "rustc_mir 0.0.0", @@ -2154,7 +2159,6 @@ dependencies = [ "rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_allocator 0.0.0", "rustc_apfloat 0.0.0", - "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "rustc_incremental 0.0.0", @@ -2205,7 +2209,6 @@ dependencies = [ "fmt_macros 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", - "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "rustc_platform_intrinsics 0.0.0", @@ -2234,21 +2237,34 @@ dependencies = [ ] [[package]] +name = "rustfix" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "rustfmt-nightly" -version = "0.6.0" +version = "0.6.1" dependencies = [ "assert_cli 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-syntax 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_target 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-syntax 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3063,7 +3079,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9ad0485404155f45cce53a40d4b2d6ac356418300daed05273d9e26f91c390be" "checksum jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ddf83704f4e79979a424d1082dd2c1e52683058056c9280efa19ac5f6bc9033c" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum languageserver-types 0.36.0 (registry+https://github.com/rust-lang/crates.io-index)" = "174cdfb8bed13225bb419bec66ee1c970099c875688645f9c4a82e3af43ba69d" +"checksum languageserver-types 0.39.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad4cdd5e52d71aca47050e5b25f03082609c63a1e76b7362ebdd010895b3f854" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" "checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" "checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" @@ -3096,8 +3112,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum openssl-sys 0.9.28 (registry+https://github.com/rust-lang/crates.io-index)" = "0bbd90640b148b46305c1691eed6039b5c8509bed16991e3562a01eeb76902a3" "checksum ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063" "checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" -"checksum parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9fd9d732f2de194336fb02fe11f9eed13d9e76f13f4315b4d88a14ca411750cd" -"checksum parking_lot_core 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "538ef00b7317875071d5e00f603f24d16f0b474c1a5fc0ccb8b454ca72eafa79" +"checksum parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4d05f1349491390b1730afba60bb20d55761bef489a954546b58b4b34e1e2ac" +"checksum parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4db1a8ccf734a7bce794cc19b3df06ed87ab2f3907036b693c68f56b4d4537fa" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum pest 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0fce5d8b5cc33983fc74f78ad552b5522ab41442c4ca91606e4236eb4b5ceefc" "checksum pest_derive 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ab94faafeb93f4c5e3ce81ca0e5a779529a602ad5d09ae6d21996bfb8b6a52bf" @@ -3134,14 +3150,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rls-rustc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "885f66b92757420572cbb02e033d4a9558c7413ca9b7ac206f28fd58ffdb44ea" "checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a" "checksum rls-vfs 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "be231e1e559c315bc60ced5ad2cc2d7a9c208ed7d4e2c126500149836fda19bb" -"checksum rustc-ap-rustc_cratesio_shim 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0256e318ad99c467d24bd7188f2d4a3028360621bb92d769b4b65fc44717d514" -"checksum rustc-ap-rustc_data_structures 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83430df7f76ea85c1f70fe145041576eee8fd5d77053bf426df24b480918d185" -"checksum rustc-ap-rustc_errors 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2b03f874277103039816f6467b1ff30a81b1d6a29d4de6efccefe4c488f6535a" -"checksum rustc-ap-serialize 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a2e47cf949f06b0c7ab7566c2f69d49f28cb3ecf1bb8bf0bda48b1ba5b7945ae" -"checksum rustc-ap-syntax 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "625e6fb41fde299082cda3bceb08f81c9ba56b14a2ec737b4366f9c3c9be07d8" -"checksum rustc-ap-syntax_pos 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "474a23ef1a1245ae02c5fd6a1e9a0725ce6fd25ca2294703c03bddce041f867b" +"checksum rustc-ap-rustc_cratesio_shim 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a01334797c5c4cf56cc40bb9636d7b4c4a076665b9b9b7f100fd666cf0a02ffc" +"checksum rustc-ap-rustc_data_structures 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "03d6f8f7da0de905f6ef80dc14dce3bbc372430622b6aeb421cf13190bc70e8a" +"checksum rustc-ap-rustc_errors 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3dfd6183804a685c48601651d8c8c7b0daa8f83b0b5e24edfbcb6a0337085127" +"checksum rustc-ap-rustc_target 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5f223157f51bf0e0621bef099de862468892ee4c4b83056f48f63e1bc00ccb72" +"checksum rustc-ap-serialize 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2104a55a87d65cba8a845656f1f19a35da52af403863cd2a4bd5876ba522d879" +"checksum rustc-ap-syntax 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b50671adb9b0a7c57a4690ac6a40cb614879f543b64aada42f55b66212492323" +"checksum rustc-ap-syntax_pos 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "55793c2a775230c42661194c48d44b35d4c8439d79ad8528e56651e854c48c63" "checksum rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11fb43a206a04116ffd7cfcf9bcb941f8eb6cc7ff667272246b0a1c74259a3cb" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" +"checksum rustfix 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "165a212dd11124d7070892da20f71d82970ef1d1dd41cd804b70f39740a21c85" "checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" "checksum same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb6eded0b06a0b512c8ddbcf04089138c9b4362c2f696f3c3d76039d68f3637" "checksum schannel 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "85fd9df495640643ad2d00443b3d78aae69802ad488debab4f1dd52fc1806ade" diff --git a/src/Cargo.toml b/src/Cargo.toml index 814c054c51e..35858ee2868 100644 --- a/src/Cargo.toml +++ b/src/Cargo.toml @@ -40,14 +40,6 @@ members = [ "tools/rls/test_data/workspace_symbol", ] -# Curiously, compiletest will segfault if compiled with opt-level=3 on 64-bit -# MSVC when running the compile-fail test suite when a should-fail test panics. -# But hey if this is removed and it gets past the bots, sounds good to me. -[profile.release] -opt-level = 2 -[profile.bench] -opt-level = 2 - # These options are controlled from our rustc wrapper script, so turn them off # here and have them controlled elsewhere. [profile.dev] diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md index 9ff681ac680..98c353eb6ec 100644 --- a/src/bootstrap/README.md +++ b/src/bootstrap/README.md @@ -64,6 +64,10 @@ The script accepts commands, flags, and arguments to determine what to do: # execute tests in the standard library in stage0 ./x.py test --stage 0 src/libstd + # execute tests in the core and standard library in stage0, + # without running doc tests (thus avoid depending on building the compiler) + ./x.py test --stage 0 --no-doc src/libcore src/libstd + # execute all doc tests ./x.py test src/doc ``` diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index b6ae824c376..3f97accaa4d 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -107,6 +107,13 @@ fn main() { env::join_paths(&dylib_path).unwrap()); let mut maybe_crate = None; + // Print backtrace in case of ICE + if env::var("RUSTC_BACKTRACE_ON_ICE").is_ok() && env::var("RUST_BACKTRACE").is_err() { + cmd.env("RUST_BACKTRACE", "1"); + } + + cmd.env("RUSTC_BREAK_ON_ICE", "1"); + if let Some(target) = target { // The stage0 compiler has a special sysroot distinct from what we // actually downloaded, so we just always pass the `--sysroot` option. diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index b9c82127342..9c35cb7f506 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -25,7 +25,7 @@ use compile; use install; use dist; use util::{exe, libdir, add_lib_path}; -use {Build, Mode}; +use {Build, Mode, DocTests}; use cache::{INTERNER, Interned, Cache}; use check; use test; @@ -323,7 +323,7 @@ impl<'a> Builder<'a> { test::Cargotest, test::Cargo, test::Rls, test::ErrorIndex, test::Distcheck, test::RunMakeFullDeps, test::Nomicon, test::Reference, test::RustdocBook, test::RustByExample, - test::TheBook, test::UnstableBook, + test::TheBook, test::UnstableBook, test::RustcBook, test::Rustfmt, test::Miri, test::Clippy, test::RustdocJS, test::RustdocTheme, // Run run-make last, since these won't pass without make on Windows test::RunMake, test::RustdocUi), @@ -331,7 +331,7 @@ impl<'a> Builder<'a> { Kind::Doc => describe!(doc::UnstableBook, doc::UnstableBookGen, doc::TheBook, doc::Standalone, doc::Std, doc::Test, doc::WhitelistedRustc, doc::Rustc, doc::ErrorIndex, doc::Nomicon, doc::Reference, doc::Rustdoc, doc::RustByExample, - doc::CargoBook), + doc::RustcBook, doc::CargoBook), Kind::Dist => describe!(dist::Docs, dist::RustcDocs, dist::Mingw, dist::Rustc, dist::DebuggerScripts, dist::Std, dist::Analysis, dist::Src, dist::PlainSourceTarball, dist::Cargo, dist::Rls, dist::Rustfmt, dist::Extended, @@ -591,6 +591,8 @@ impl<'a> Builder<'a> { format!("{} {}", env::var("RUSTFLAGS").unwrap_or_default(), extra_args)); } + let want_rustdoc = self.doc_tests != DocTests::No; + // Customize the compiler we're running. Specify the compiler to cargo // as our shim and then pass it some various options used to configure // how the actual compiler itself is called. @@ -607,7 +609,7 @@ impl<'a> Builder<'a> { .env("RUSTC_LIBDIR", self.rustc_libdir(compiler)) .env("RUSTC_RPATH", self.config.rust_rpath.to_string()) .env("RUSTDOC", self.out.join("bootstrap/debug/rustdoc")) - .env("RUSTDOC_REAL", if cmd == "doc" || cmd == "test" { + .env("RUSTDOC_REAL", if cmd == "doc" || (cmd == "test" && want_rustdoc) { self.rustdoc(compiler.host) } else { PathBuf::from("/path/to/nowhere/rustdoc/not/required") @@ -624,7 +626,7 @@ impl<'a> Builder<'a> { if let Some(ref error_format) = self.config.rustc_error_format { cargo.env("RUSTC_ERROR_FORMAT", error_format); } - if cmd != "build" && cmd != "check" { + if cmd != "build" && cmd != "check" && want_rustdoc { cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(self.compiler(2, self.config.build))); } @@ -706,6 +708,10 @@ impl<'a> Builder<'a> { cargo.env("RUSTC_PRINT_STEP_TIMINGS", "1"); } + if self.config.backtrace_on_ice { + cargo.env("RUSTC_BACKTRACE_ON_ICE", "1"); + } + cargo.env("RUSTC_VERBOSE", format!("{}", self.verbosity)); // in std, we want to avoid denying warnings for stage 0 as that makes cfg's painful. @@ -1403,4 +1409,39 @@ mod __test { }, ]); } + + #[test] + fn test_with_no_doc_stage0() { + let mut config = configure(&[], &[]); + config.stage = Some(0); + config.cmd = Subcommand::Test { + paths: vec!["src/libstd".into()], + test_args: vec![], + rustc_args: vec![], + fail_fast: true, + doc_tests: DocTests::No, + }; + + let build = Build::new(config); + let mut builder = Builder::new(&build); + + let host = INTERNER.intern_str("A"); + + builder.run_step_descriptions( + &[StepDescription::from::<test::Crate>()], + &["src/libstd".into()], + ); + + // Ensure we don't build any compiler artifacts. + assert!(builder.cache.all::<compile::Rustc>().is_empty()); + assert_eq!(first(builder.cache.all::<test::Crate>()), &[ + test::Crate { + compiler: Compiler { host, stage: 0 }, + target: host, + mode: Mode::Libstd, + test_kind: test::TestKind::Test, + krate: INTERNER.intern_str("std"), + }, + ]); + } } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 1b4b2c5fb2a..6dd6291be23 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -72,6 +72,7 @@ pub struct Config { pub dry_run: bool, pub deny_warnings: bool, + pub backtrace_on_ice: bool, // llvm codegen options pub llvm_enabled: bool, @@ -306,6 +307,7 @@ struct Rust { wasm_syscall: Option<bool>, lld: Option<bool>, deny_warnings: Option<bool>, + backtrace_on_ice: Option<bool>, } /// TOML representation of how each build target is configured. @@ -325,6 +327,14 @@ struct TomlTarget { } impl Config { + fn path_from_python(var_key: &str) -> PathBuf { + match env::var_os(var_key) { + // Do not trust paths from Python and normalize them slightly (#49785). + Some(var_val) => Path::new(&var_val).components().collect(), + _ => panic!("expected '{}' to be set", var_key), + } + } + pub fn default_opts() -> Config { let mut config = Config::default(); config.llvm_enabled = true; @@ -348,9 +358,9 @@ impl Config { config.deny_warnings = true; // set by bootstrap.py - config.src = env::var_os("SRC").map(PathBuf::from).expect("'SRC' to be set"); config.build = INTERNER.intern_str(&env::var("BUILD").expect("'BUILD' to be set")); - config.out = env::var_os("BUILD_DIR").map(PathBuf::from).expect("'BUILD_DIR' set"); + config.src = Config::path_from_python("SRC"); + config.out = Config::path_from_python("BUILD_DIR"); let stage0_root = config.out.join(&config.build).join("stage0/bin"); config.initial_rustc = stage0_root.join(exe("rustc", &config.build)); @@ -523,6 +533,7 @@ impl Config { config.musl_root = rust.musl_root.clone().map(PathBuf::from); config.save_toolstates = rust.save_toolstates.clone().map(PathBuf::from); set(&mut config.deny_warnings, rust.deny_warnings.or(flags.warnings)); + set(&mut config.backtrace_on_ice, rust.backtrace_on_ice); if let Some(ref backends) = rust.codegen_backends { config.rust_codegen_backends = backends.iter() diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index a0123da6d8f..3574b7d210a 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -120,6 +120,8 @@ v("musl-root-arm", "target.arm-unknown-linux-musleabi.musl-root", "arm-unknown-linux-musleabi install directory") v("musl-root-armhf", "target.arm-unknown-linux-musleabihf.musl-root", "arm-unknown-linux-musleabihf install directory") +v("musl-root-armv5te", "target.armv5te-unknown-linux-musleabi.musl-root", + "armv5te-unknown-linux-musleabi install directory") v("musl-root-armv7", "target.armv7-unknown-linux-musleabihf.musl-root", "armv7-unknown-linux-musleabihf install directory") v("musl-root-aarch64", "target.aarch64-unknown-linux-musl.musl-root", diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index ae22260c564..16f4b29dcce 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -71,6 +71,7 @@ book!( Nomicon, "src/doc/nomicon", "nomicon"; Reference, "src/doc/reference", "reference"; Rustdoc, "src/doc/rustdoc", "rustdoc"; + RustcBook, "src/doc/rustc", "rustc"; RustByExample, "src/doc/rust-by-example", "rust-by-example"; ); diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 3eb9dca2aa8..5315a3028ff 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -19,7 +19,7 @@ use std::process; use getopts::Options; -use Build; +use {Build, DocTests}; use config::Config; use metadata; use builder::Builder; @@ -62,7 +62,7 @@ pub enum Subcommand { test_args: Vec<String>, rustc_args: Vec<String>, fail_fast: bool, - doc_tests: bool, + doc_tests: DocTests, }, Bench { paths: Vec<PathBuf>, @@ -171,7 +171,8 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`"); "extra options to pass the compiler when running tests", "ARGS", ); - opts.optflag("", "doc", "run doc tests"); + opts.optflag("", "no-doc", "do not run doc tests"); + opts.optflag("", "doc", "only run doc tests"); }, "bench" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); }, "clean" => { opts.optflag("", "all", "clean all build artifacts"); }, @@ -324,7 +325,13 @@ Arguments: test_args: matches.opt_strs("test-args"), rustc_args: matches.opt_strs("rustc-args"), fail_fast: !matches.opt_present("no-fail-fast"), - doc_tests: matches.opt_present("doc"), + doc_tests: if matches.opt_present("doc") { + DocTests::Only + } else if matches.opt_present("no-doc") { + DocTests::No + } else { + DocTests::Yes + } } } "bench" => { @@ -411,10 +418,10 @@ impl Subcommand { } } - pub fn doc_tests(&self) -> bool { + pub fn doc_tests(&self) -> DocTests { match *self { Subcommand::Test { doc_tests, .. } => doc_tests, - _ => false, + _ => DocTests::Yes, } } } diff --git a/src/bootstrap/job.rs b/src/bootstrap/job.rs index fa3ba02482f..6445ce8da33 100644 --- a/src/bootstrap/job.rs +++ b/src/bootstrap/job.rs @@ -122,12 +122,10 @@ struct JOBOBJECT_BASIC_LIMIT_INFORMATION { } pub unsafe fn setup(build: &mut Build) { - // Tell Windows to not show any UI on errors (such as not finding a required dll - // during startup or terminating abnormally). This is important for running tests, - // since some of them use abnormal termination by design. - // This mode is inherited by all child processes. - let mode = SetErrorMode(SEM_NOGPFAULTERRORBOX); // read inherited flags - SetErrorMode(mode | SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); + // Enable the Windows Error Reporting dialog which msys disables, + // so we can JIT debug rustc + let mode = SetErrorMode(0); + SetErrorMode(mode & !SEM_NOGPFAULTERRORBOX); // Create a new job object for us to use let job = CreateJobObjectW(0 as *mut _, 0 as *const _); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 0a7f0e5ff4e..e53fef06786 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -210,6 +210,16 @@ pub struct Compiler { host: Interned<String>, } +#[derive(PartialEq, Eq, Copy, Clone, Debug)] +pub enum DocTests { + // Default, run normal tests and doc tests. + Yes, + // Do not run any doc tests. + No, + // Only run doc tests. + Only, +} + /// Global configuration for the build system. /// /// This structure transitively contains all configuration for the build system. @@ -233,7 +243,7 @@ pub struct Build { rustfmt_info: channel::GitInfo, local_rebuild: bool, fail_fast: bool, - doc_tests: bool, + doc_tests: DocTests, verbosity: usize, // Targets for which to build. @@ -294,7 +304,7 @@ impl Crate { /// /// These entries currently correspond to the various output directories of the /// build system, with each mod generating output in a different directory. -#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub enum Mode { /// Build the standard library, placing output in the "stageN-std" directory. Libstd, diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 08bbd68c756..cbb952bab61 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -32,13 +32,13 @@ use dist; use native; use tool::{self, Tool}; use util::{self, dylib_path, dylib_path_var}; -use Mode; +use {Mode, DocTests}; use toolstate::ToolState; const ADB_TEST_DIR: &str = "/data/tmp/work"; /// The two modes of the test runner; tests or benchmarks. -#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] +#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, PartialOrd, Ord)] pub enum TestKind { /// Run `cargo test` Test, @@ -1212,6 +1212,7 @@ test_book!( Nomicon, "src/doc/nomicon", "nomicon", default=false; Reference, "src/doc/reference", "reference", default=false; RustdocBook, "src/doc/rustdoc", "rustdoc", default=true; + RustcBook, "src/doc/rustc", "rustc", default=true; RustByExample, "src/doc/rust-by-example", "rust-by-example", default=false; TheBook, "src/doc/book", "book", default=false; UnstableBook, "src/doc/unstable-book", "unstable-book", default=true; @@ -1406,13 +1407,13 @@ impl Step for CrateNotDefault { } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Crate { - compiler: Compiler, - target: Interned<String>, - mode: Mode, - test_kind: TestKind, - krate: Interned<String>, + pub compiler: Compiler, + pub target: Interned<String>, + pub mode: Mode, + pub test_kind: TestKind, + pub krate: Interned<String>, } impl Step for Crate { @@ -1518,8 +1519,14 @@ impl Step for Crate { if test_kind.subcommand() == "test" && !builder.fail_fast { cargo.arg("--no-fail-fast"); } - if builder.doc_tests { - cargo.arg("--doc"); + match builder.doc_tests { + DocTests::Only => { + cargo.arg("--doc"); + } + DocTests::No => { + cargo.args(&["--lib", "--bins", "--examples", "--tests", "--benches"]); + } + DocTests::Yes => {} } cargo.arg("-p").arg(krate); diff --git a/src/ci/docker/dist-various-1/Dockerfile b/src/ci/docker/dist-various-1/Dockerfile index 00366301aa1..b195decfcf5 100644 --- a/src/ci/docker/dist-various-1/Dockerfile +++ b/src/ci/docker/dist-various-1/Dockerfile @@ -43,6 +43,10 @@ ENV STAGING_DIR=/tmp COPY scripts/musl.sh /build RUN env \ + CC=arm-linux-gnueabi-gcc CFLAGS="-march=armv5te -marm -mfloat-abi=soft" \ + CXX=arm-linux-gnueabi-g++ CXXFLAGS="-march=armv5te -marm -mfloat-abi=soft" \ + bash musl.sh armv5te && \ + env \ CC=arm-linux-gnueabi-gcc CFLAGS="-march=armv6 -marm" \ CXX=arm-linux-gnueabi-g++ CXXFLAGS="-march=armv6 -marm" \ bash musl.sh arm && \ @@ -84,6 +88,7 @@ ENV TARGETS=$TARGETS,mipsel-unknown-linux-musl ENV TARGETS=$TARGETS,arm-unknown-linux-musleabi ENV TARGETS=$TARGETS,arm-unknown-linux-musleabihf ENV TARGETS=$TARGETS,armv5te-unknown-linux-gnueabi +ENV TARGETS=$TARGETS,armv5te-unknown-linux-musleabi ENV TARGETS=$TARGETS,armv7-unknown-linux-musleabihf ENV TARGETS=$TARGETS,aarch64-unknown-linux-musl ENV TARGETS=$TARGETS,sparc64-unknown-linux-gnu @@ -100,9 +105,12 @@ ENV CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \ CC_sparc64_unknown_linux_gnu=sparc64-linux-gnu-gcc \ CC_x86_64_unknown_redox=x86_64-unknown-redox-gcc \ CC_armv5te_unknown_linux_gnueabi=arm-linux-gnueabi-gcc \ - CFLAGS_armv5te_unknown_linux_gnueabi="-march=armv5te -marm -mfloat-abi=soft" + CFLAGS_armv5te_unknown_linux_gnueabi="-march=armv5te -marm -mfloat-abi=soft" \ + CC_armv5te_unknown_linux_musleabi=arm-linux-gnueabi-gcc \ + CFLAGS_armv5te_unknown_linux_musleabi="-march=armv5te -marm -mfloat-abi=soft" ENV RUST_CONFIGURE_ARGS \ + --musl-root-armv5te=/musl-armv5te \ --musl-root-arm=/musl-arm \ --musl-root-armhf=/musl-armhf \ --musl-root-armv7=/musl-armv7 \ diff --git a/src/ci/docker/mingw-check/Dockerfile b/src/ci/docker/mingw-check/Dockerfile index ae4641009cf..aab339f399c 100644 --- a/src/ci/docker/mingw-check/Dockerfile +++ b/src/ci/docker/mingw-check/Dockerfile @@ -19,4 +19,5 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh +ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1 ENV SCRIPT python2.7 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu diff --git a/src/ci/docker/x86_64-gnu-debug/Dockerfile b/src/ci/docker/x86_64-gnu-debug/Dockerfile index ff6ab1013b4..bdde7ad7fe8 100644 --- a/src/ci/docker/x86_64-gnu-debug/Dockerfile +++ b/src/ci/docker/x86_64-gnu-debug/Dockerfile @@ -16,7 +16,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -ENV PARALLEL_CHECK 1 +ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1 ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ --enable-debug \ diff --git a/src/ci/run.sh b/src/ci/run.sh index 119b239d6b2..456f8cc7317 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -78,9 +78,9 @@ fi # sccache server at the start of the build, but no need to worry if this fails. SCCACHE_IDLE_TIMEOUT=10800 sccache --start-server || true -if [ "$PARALLEL_CHECK" != "" ]; then +if [ "$RUN_CHECK_WITH_PARALLEL_QUERIES" != "" ]; then $SRC/configure --enable-experimental-parallel-queries - python2.7 ../x.py check + CARGO_INCREMENTAL=0 python2.7 ../x.py check rm -f config.toml rm -rf build fi diff --git a/src/doc/book b/src/doc/book -Subproject b889e1e30c5e9953834aa9fa6c982bb28df46ac +Subproject f51127530d46b9acbf4747c859da185e771cfcf diff --git a/src/doc/index.md b/src/doc/index.md index 2ea889da1fd..3a4f51069fc 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -43,6 +43,10 @@ Rust's standard library has [extensive API documentation](std/index.html), with explanations of how to use various things, as well as example code for accomplishing various tasks. +## The Rustc Book + +[The Rustc Book](rustc/index.html) describes the Rust compiler, `rustc`. + ## The Cargo Book [The Cargo Book](cargo/index.html) is a guide to Cargo, Rust's build tool and dependency manager. diff --git a/src/doc/nomicon b/src/doc/nomicon -Subproject 3c56329d1bd9038e5341f1962bcd8d043312a71 +Subproject 748a5e6742db4a21c4c630a58087f818828e8a0 diff --git a/src/doc/reference b/src/doc/reference -Subproject 76296346e97c3702974d3398fdb94af9e10111a +Subproject 134f419ee62714590b04712fe6072253bc2a782 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example -Subproject d5ec87eabe5733cc2348c7dada89fc67c086f39 +Subproject eebda16e4b45f2eed4310cf7b9872cc75227816 diff --git a/src/doc/rustc/.gitignore b/src/doc/rustc/.gitignore new file mode 100644 index 00000000000..7585238efed --- /dev/null +++ b/src/doc/rustc/.gitignore @@ -0,0 +1 @@ +book diff --git a/src/doc/rustc/book.toml b/src/doc/rustc/book.toml new file mode 100644 index 00000000000..8adc05c5137 --- /dev/null +++ b/src/doc/rustc/book.toml @@ -0,0 +1,5 @@ +[book] +authors = ["The Rust Project Developers"] +multilingual = false +src = "src" +title = "The rustc book" diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md new file mode 100644 index 00000000000..e4c0939fd46 --- /dev/null +++ b/src/doc/rustc/src/SUMMARY.md @@ -0,0 +1,16 @@ +# The Rustc Book + +- [What is rustc?](what-is-rustc.md) +- [Command-line arguments](command-line-arguments.md) +- [Lints](lints/index.md) + - [Lint levels](lints/levels.md) + - [Lint Groups](lints/groups.md) + - [Lint listing](lints/listing/index.md) + - [Allowed-by-default lints](lints/listing/allowed-by-default.md) + - [Warn-by-default lints](lints/listing/warn-by-default.md) + - [Deny-by-default lints](lints/listing/deny-by-default.md) +- [Codegen options](codegen-options/index.md) +- [Targets](targets/index.md) + - [Built-in Targets](targets/built-in.md) + - [Custom Targets](targets/custom.md) +- [Contributing to `rustc`](contributing.md) \ No newline at end of file diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md new file mode 100644 index 00000000000..eff09428902 --- /dev/null +++ b/src/doc/rustc/src/codegen-options/index.md @@ -0,0 +1,209 @@ +# Codegen options + +All of these options are passed to `rustc` via the `-C` flag, short for "codegen." You can see +a version of this list for your exact compiler by running `rustc -C help`. + +## ar + +This option is deprecated and does nothing. + +## linker + +This flag lets you control which linker `rustc` invokes to link your code. + +## link-arg=val + +This flag lets you append a single extra argument to the linker invocation. + +"Append" is significant; you can pass this flag multiple times to add multiple arguments. + +## link-args + +This flag lets you append multiple extra arguments to the linker invocation. The +options should be separated by spaces. + +## link-dead-code + +Normally, the linker will remove dead code. This flag disables this behavior. + +An example of when this flag might be useful is when trying to construct code coverage +metrics. + +## lto + +This flag instructs LLVM to use [link time +optimizations](https://llvm.org/docs/LinkTimeOptimization.html). + +It takes one of two values, `thin` and `fat`. 'thin' LTO [is a new feature of +LLVM](http://blog.llvm.org/2016/06/thinlto-scalable-and-incremental-lto.html), +'fat' referring to the classic version of LTO. + +## target-cpu + +This instructs `rustc` to generate code specifically for a particular processor. + +You can run `rustc --print target-cpus` to see the valid options to pass +here. Additionally, `native` can be passed to use the processor of the host +machine. + +## target-feature + +Individual targets will support different features; this flag lets you control +enabling or disabling a feature. + +To see the valid options and an example of use, run `rustc --print +target-features`. + +## passes + +This flag can be used to add extra LLVM passes to the compilation. + +The list must be separated by spaces. + +## llvm-args + +This flag can be used to pass a list of arguments directly to LLVM. + +The list must be separated by spaces. + +## save-temps + +`rustc` will generate temporary files during compilation; normally it will +delete them after it's done with its work. This option will cause them to be +preserved instead of removed. + +## rpath + +This option allows you to set the value of +[`rpath`](https://en.wikipedia.org/wiki/Rpath). + +## overflow-checks + +This flag allows you to control the behavior of integer overflow. This flag +can be passed many options: + +* To turn overflow checks on: `y`, `yes`, or `on`. +* To turn overflow checks off: `n`, `no`, or `off`. + +## no-prepopulate-passes + +The pass manager comes pre-populated with a list of passes; this flag +ensures that list is empty. + +## no-vectorize-loops + +By default, `rustc` will attempt to [vectorize +loops](https://llvm.org/docs/Vectorizers.html#the-loop-vectorizer). This +flag will turn that behavior off. + +## no-vectorize-slp + +By default, `rustc` will attempt to vectorize loops using [superword-level +parallelism](https://llvm.org/docs/Vectorizers.html#the-slp-vectorizer). This +flag will turn that behavior off. + +## soft-float + +This option will make `rustc` generate code using "soft floats." By default, +a lot of hardware supports floating point instructions, and so the code generated +will take advantage of this. "soft floats" emulate floating point instructions +in software. + +## prefer-dynamic + +By default, `rustc` prefers to statically link dependencies. This option will +make it use dynamic linking instead. + +## no-integrated-as + +LLVM comes with an internal assembler; this option will let you use an +external assembler instead. + +## no-redzone + +This flag allows you to disable [the +red zone](https://en.wikipedia.org/wiki/Red_zone_\(computing\)). This flag can +be passed many options: + +* To enable the red zone: `y`, `yes`, or `on`. +* To disable it: `n`, `no`, or `off`. + +## relocation-model + +This option lets you choose which relocation model to use. + +To find the valid options for this flag, run `rustc --print relocation-models`. + +## code-model=val + +This option lets you choose which code model to use. + +To find the valid options for this flag, run `rustc --print code-models`. + +## metadata + +This option allows you to control the metadata used for symbol mangling. + +## extra-filename + +This option allows you to put extra data in each output filename. + +## codegen-units + +This flag lets you control how many threads are used when doing +code generation. + +Increasing paralellism may speed up compile times, but may also +produce slower code. + +## remark + +This flag lets you print remarks for these optimization passes. + +The list of passes should be separated by spaces. + +`all` will remark on every pass. + +## no-stack-check + +This option is deprecated and does nothing. + +## debuginfo + +This flag lets you control debug information: + +* `0`: no debug info at all +* `1`: line tables only +* `2`: full debug info + +## opt-level + +This flag lets you control the optimization level. + +* `0`: no optimizations +* `1`: basic optimizations +* `2`: some optimizations +* `3`: all optimizations +* `s`: optimize for binary size +* `z`: optimize for binary size, but also turn off loop vectorization. + +## debug-assertions + +This flag lets you turn `cfg(debug_assertions)` on or off. + +## inline-threshold + +This option lets you set the threshold for inlining a function. + +The default is 225. + +## panic + +This option lets you control what happens when the code panics. + +* `abort`: terminate the process upon panic +* `unwind`: unwind the stack upon panic + +## incremental + +This flag allows you to enable incremental compilation. diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md new file mode 100644 index 00000000000..e2b001832fe --- /dev/null +++ b/src/doc/rustc/src/command-line-arguments.md @@ -0,0 +1,116 @@ +# Command-line arguments + +Here's a list of command-line arguments to `rustc` and what they do. + +## `-h`/`--help`: get help + +This flag will print out help information for `rustc`. + +## `--cfg`: configure the compilation environment + +This flag can turn on or off various `#[cfg]` settings. + +## `-L`: add a directory to the library search path + +When looking for external crates, a directory passed to this flag will be searched. + +## `-l`: link the generated crate to a native library + +This flag allows you to specify linking to a specific native library when building +a crate. + +## `--crate-type`: a list of types of crates for the compiler to emit + +This instructs `rustc` on which crate type to build. + +## `--crate-name`: specify the name of the crate being built + +This informs `rustc` of the name of your crate. + +## `--emit`: emit output other than a crate + +Instead of producing a crate, this flag can print out things like the assembly or LLVM-IR. + +## `--print`: print compiler information + +This flag prints out various information about the compiler. + +## `-g`: include debug information + +A synonym for `-C debug-level=2`. + +## `-O`: optimize your code + +A synonym for `-C opt-level=2`. + +## `-o`: filename of the output + +This flag controls the output filename. + +## `--out-dir`: directory to write the output in + +The outputted crate will be written to this directory. + +## `--explain`: provide a detailed explanation of an error message + +Each error of `rustc`'s comes with an error code; this will print +out a longer explanation of a given error. + +## `--test`: build a test harness + +When compiling this crate, `rustc` will ignore your `main` function +and instead produce a test harness. + +## `--target`: select a target triple to build + +This controls which [target](targets/index.html) to produce. + +## `-W`: set lint warnings + +This flag will set which lints should be set to the [warn level](lints/levels.html#warn). + +## `-A`: set lint allowed + +This flag will set which lints should be set to the [allow level](lints/levels.html#allow). + +## `-D`: set lint denied + +This flag will set which lints should be set to the [deny level](lints/levels.html#deny). + +## `-F`: set lint forbidden + +This flag will set which lints should be set to the [forbid level](lints/levels.html#forbid). + +## `--cap-lints`: set the most restrictive lint level + +This flag lets you 'cap' lints, for more, [see here](lints/levels.html#capping-lints). + +## `-C`/`--codegen`: code generation options + +This flag will allow you to set [codegen options](codegen-options/index.html). + +## `-V`/`--version`: print a version + +This flag will print out `rustc`'s version. + +## `-v`/`--verbose`: use verbose output + +This flag, when combined with other flags, makes them produce extra output. + +## `--extern`: specify where an external library is located + +This flag allows you to pass the name and location of an external crate that will +be linked into the crate you're buildling. + +## `--sysroot`: Override the system root + +The "sysroot" is where `rustc` looks for the crates that come with the Rust +distribution; this flag allows that to be overridden. + +## `--error-format`: control how errors are produced + +This flag lets you control the format of errors. + +## `--color`: configure coloring of output + +This flag lets you control color settings of the output. diff --git a/src/doc/rustc/src/contributing.md b/src/doc/rustc/src/contributing.md new file mode 100644 index 00000000000..fcb8e6b27db --- /dev/null +++ b/src/doc/rustc/src/contributing.md @@ -0,0 +1,6 @@ +# Contributing to rustc + +We'd love to have your help improving `rustc`! To that end, we've written [a +whole book](https://rust-lang-nursery.github.io/rustc-guide/) on its +internals, how it works, and how to get started working on it. To learn +more, you'll want to check that out. \ No newline at end of file diff --git a/src/doc/rustc/src/lints/groups.md b/src/doc/rustc/src/lints/groups.md new file mode 100644 index 00000000000..46b717f3387 --- /dev/null +++ b/src/doc/rustc/src/lints/groups.md @@ -0,0 +1,29 @@ +# Lint Groups + +`rustc` has the concept of a "lint group", where you can toggle several warnings +through one name. + +For example, the `nonstandard-style` lint sets `non-camel-case-types`, +`non-snake-case`, and `non-upper-case-globals` all at once. So these are +equivalent: + +```bash +$ rustc -D nonstandard-style +$ rustc -D non-camel-case-types -D non-snake-case -D non-upper-case-globals +``` + +Here's a list of each lint group, and the lints that they are made up of: + +| group | description | lints | +|---------------------|---------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| nonstandard-style | Violation of standard naming conventions | non-camel-case-types, non-snake-case, non-upper-case-globals | +| warnings | all lints that would be issuing warnings | all lints that would be issuing warnings | +| edition-2018 | Lints that will be turned into errors in Rust 2018 | tyvar-behind-raw-pointer | +| rust-2018-idioms | Lints to nudge you toward idiomatic features of Rust 2018 | bare-trait-object, unreachable-pub | +| unused | These lints detect things being declared but not used | unused-imports, unused-variables, unused-assignments, dead-code, unused-mut, unreachable-code, unreachable-patterns, unused-must-use, unused-unsafe, path-statements, unused-attributes, unused-macros, unused-allocation, unused-doc-comment, unused-extern-crates, unused-features, unused-parens | +| future-incompatible | Lints that detect code that has future-compatibility problems | private-in-public, pub-use-of-private-extern-crate, patterns-in-fns-without-body, safe-extern-statics, invalid-type-param-default, legacy-directory-ownership, legacy-imports, legacy-constructor-visibility, missing-fragment-specifier, illegal-floating-point-literal-pattern, anonymous-parameters, parenthesized-params-in-types-and-modules, late-bound-lifetime-arguments, safe-packed-borrows, incoherent-fundamental-impls, tyvar-behind-raw-pointer, unstable-name-collision | + +Additionally, there's a `bad-style` lint group that's a deprecated alias for `nonstandard-style`. + +Finally, you can also see the table above by invoking `rustc -W help`. This will give you the exact values for the specific +compiler you have installed. \ No newline at end of file diff --git a/src/doc/rustc/src/lints/index.md b/src/doc/rustc/src/lints/index.md new file mode 100644 index 00000000000..bf345a24389 --- /dev/null +++ b/src/doc/rustc/src/lints/index.md @@ -0,0 +1,28 @@ +# Lints + +In software, a "lint" is a tool used to help improve your source code. The +Rust compiler contains a number of lints, and when it compiles your code, it will +also run the lints. These lints may produce a warning, an error, or nothing at all, +depending on how you've configured things. + +Here's a small example: + +```bash +$ cat main.rs +fn main() { + let x = 5; +} +> rustc main.rs +warning: unused variable: `x` + --> main.rs:2:9 + | +2 | let x = 5; + | ^ + | + = note: #[warn(unused_variables)] on by default + = note: to avoid this warning, consider using `_x` instead +``` + +This is the `unused_variables` lint, and it tells you that you've introduced +a variable that you don't use in your code. That's not *wrong*, so it's not +an error, but it might be a bug, so you get a warning. diff --git a/src/doc/rustc/src/lints/levels.md b/src/doc/rustc/src/lints/levels.md new file mode 100644 index 00000000000..19bb6707d22 --- /dev/null +++ b/src/doc/rustc/src/lints/levels.md @@ -0,0 +1,252 @@ +# Lint levels + +In `rustc`, lints are divided into four *levels*: + +1. allow +2. warn +3. deny +4. forbid + +Each lint has a default level (explained in the lint listing later in this +chapter), and the compiler has a default warning level. First, let's explain +what these levels mean, and then we'll talk about configuration. + +## allow + +These lints exist, but by default, do nothing. For example, consider this +source: + +```rust +pub fn foo() {} +``` + +Compiling this file produces no warnings: + +```bash +$ rustc lib.rs --crate-type=lib +$ +``` + +But this code violates the `missing_docs` lint. + +These lints exist mostly to be manually turned on via configuration, as we'll +talk about later in this section. + +## warn + +The 'warn' lint level will produce a warning if you violate the lint. For example, +this code runs afoul of the `unused_variable` lint: + +```rust +pub fn foo() { + let x = 5; +} +``` + +This will produce this warning: + +```console +$ rustc lib.rs --crate-type=lib +warning: unused variable: `x` + --> lib.rs:2:9 + | +2 | let x = 5; + | ^ + | + = note: #[warn(unused_variables)] on by default + = note: to avoid this warning, consider using `_x` instead +``` + +## deny + +A 'deny' lint produces an error if you violate it. For example, this code +runs into the `exceeding_bitshifts` lint. + +```rust,ignore +fn main() { + 100u8 << 10; +} +``` + +```bash +> rustc main.rs +error: bitshift exceeds the type's number of bits + --> main.rs:2:13 + | +2 | 100u8 << 10; + | ^^^^^^^^^^^ + | + = note: #[deny(exceeding_bitshifts)] on by default +``` + +What's the difference between an error from a lint and a regular old error? +Lints are configurable via levels, so in a similar way to 'allow' lints, +warnings that are 'deny' by default let you allow them. Similarly, you may +wish to set up a lint that is `warn` by default to produce an error instead. +This lint level gives you that. + +## forbid + +'forbid' is a special lint level that's stronger than 'deny'. It's the same +as 'deny' in that a lint at this level will produce an error, but unlike the +'deny' level, the 'forbid' level can not be overridden to be anything lower +than an error. + +## Configuring warning levels + +Remember our `missing_docs` example from the 'allow' lint level? + +```bash +$ cat lib.rs +pub fn foo() {} +$ rustc lib.rs --crate-type=lib +$ +``` + +We can configure this lint to operate at a higher level, both with +compiler flags, as well as with an attribute in the source code. + +You can also "cap" lints so that the compiler can choose to ignore +certain lint levels. We'll talk about that last. + +### Via compiler flag + +The `-A`, `-W`, `-D`, and `-F` flags let you turn one or more lints +into allowed, warning, deny, or forbid levels, like this: + +```bash +$ rustc lib.rs --crate-type=lib -W missing-docs +warning: missing documentation for crate + --> lib.rs:1:1 + | +1 | pub fn foo() {} + | ^^^^^^^^^^^^ + | + = note: requested on the command line with `-W missing-docs` + +warning: missing documentation for a function + --> lib.rs:1:1 + | +1 | pub fn foo() {} + | ^^^^^^^^^^^^ +> rustc lib.rs --crate-type=lib -D missing-docs +error: missing documentation for crate + --> lib.rs:1:1 + | +1 | pub fn foo() {} + | ^^^^^^^^^^^^ + | + = note: requested on the command line with `-D missing-docs` + +error: missing documentation for a function + --> lib.rs:1:1 + | +1 | pub fn foo() {} + | ^^^^^^^^^^^^ + +error: aborting due to 2 previous errors +``` + +You can also pass each flag more than once for changing multiple lints: + +```bash +rustc lib.rs --crate-type=lib -D missing-docs -D unused-variables +``` + +And of course, you can mix these four flags together: + +```bash +rustc lib.rs --crate-type=lib -D missing-docs -A unused-variables +``` + +### Via an attribute + +You can also modify the lint level with a crate-wide attribute: + +```bash +> cat lib.rs +#![warn(missing_docs)] + +pub fn foo() {} +$ rustc lib.rs --crate-type=lib +warning: missing documentation for crate + --> lib.rs:1:1 + | +1 | / #![warn(missing_docs)] +2 | | +3 | | pub fn foo() {} + | |_______________^ + | +note: lint level defined here + --> lib.rs:1:9 + | +1 | #![warn(missing_docs)] + | ^^^^^^^^^^^^ + +warning: missing documentation for a function + --> lib.rs:3:1 + | +3 | pub fn foo() {} + | ^^^^^^^^^^^^ +``` + +All four, `warn`, `allow`, `deny`, and `forbid` all work this way. + +You can also pass in multiple lints per attribute: + +```rust +#![warn(missing_docs, unused_variables)] + +pub fn foo() {} +``` + +And use multiple attributes together: + +```rust +#![warn(missing_docs)] +#![deny(unused_variables)] + +pub fn foo() {} +``` + +### Capping lints + +`rustc` supports a flag, `--cap-lints LEVEL` that sets the "lint cap level." +This is the maximum level for all lints. So for example, if we take our +code sample from the "deny" lint level above: + +```rust,ignore +fn main() { + 100u8 << 10; +} +``` + +And we compile it, capping lints to warn: + +```bash +$ rustc lib.rs --cap-lints warn +warning: bitshift exceeds the type's number of bits + --> lib.rs:2:5 + | +2 | 100u8 << 10; + | ^^^^^^^^^^^ + | + = note: #[warn(exceeding_bitshifts)] on by default + +warning: this expression will panic at run-time + --> lib.rs:2:5 + | +2 | 100u8 << 10; + | ^^^^^^^^^^^ attempt to shift left with overflow +``` + +It now only warns, rather than errors. We can go further and allow all lints: + +```bash +$ rustc lib.rs --cap-lints allow +$ +``` + +This feature is used heavily by Cargo; it will pass `--cap-lints allow` when +compiling your dependencies, so that if they have any warnings, they do not +pollute the output of your build. diff --git a/src/doc/rustc/src/lints/listing/allowed-by-default.md b/src/doc/rustc/src/lints/listing/allowed-by-default.md new file mode 100644 index 00000000000..e1a3f96a6fe --- /dev/null +++ b/src/doc/rustc/src/lints/listing/allowed-by-default.md @@ -0,0 +1,453 @@ +# Allowed-by-default lints + +These lints are all set to the 'allow' level by default. As such, they won't show up +unless you set them to a higher lint level with a flag or attribute. + +## anonymous-parameters + +This lint detects anonymous parameters. Some example code that triggers this lint: + +```rust +trait Foo { + fn foo(usize); +} +``` + +When set to 'deny', this will produce: + +```text +error: use of deprecated anonymous parameter + --> src/lib.rs:5:11 + | +5 | fn foo(usize); + | ^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41686 <https://github.com/rust-lang/rust/issues/41686> +``` + +This syntax is mostly a historical accident, and can be worked around quite +easily: + +```rust +trait Foo { + fn foo(_: usize); +} +``` + +## bare-trait-object + +This lint suggests using `dyn Trait` for trait objects. Some example code +that triggers this lint: + +```rust +#![feature(dyn_trait)] + +trait Trait { } + +fn takes_trait_object(_: Box<Trait>) { +} +``` + +When set to 'deny', this will produce: + +```text +error: trait objects without an explicit `dyn` are deprecated + --> src/lib.rs:7:30 + | +7 | fn takes_trait_object(_: Box<Trait>) { + | ^^^^^ help: use `dyn`: `dyn Trait` + | +``` + +To fix it, do as the help message suggests: + +```rust +#![feature(dyn_trait)] +#![deny(bare_trait_object)] + +trait Trait { } + +fn takes_trait_object(_: Box<dyn Trait>) { +} +``` + +## box-pointers + +This lints use of the Box type. Some example code that triggers this lint: + +```rust +struct Foo { + x: Box<isize>, +} +``` + +When set to 'deny', this will produce: + +```text +error: type uses owned (Box type) pointers: std::boxed::Box<isize> + --> src/lib.rs:6:5 + | +6 | x: Box<isize> //~ ERROR type uses owned + | ^^^^^^^^^^^^^ + | +``` + +This lint is mostly historical, and not particularly useful. `Box<T>` used to +be built into the language, and the only way to do heap allocation. Today's +Rust can call into other allocators, etc. + +## elided-lifetime-in-path + +This lint detects the use of hidden lifetime parameters. Some example code +that triggers this lint: + +```rust +struct Foo<'a> { + x: &'a u32 +} + +fn foo(x: &Foo) { +} +``` + +When set to 'deny', this will produce: + +```text +error: hidden lifetime parameters are deprecated, try `Foo<'_>` + --> src/lib.rs:5:12 + | +5 | fn foo(x: &Foo) { + | ^^^ + | +``` + +Lifetime elision elides this lifetime, but that is being deprecated. + +## missing-copy-implementations + +This lint detects potentially-forgotten implementations of `Copy`. Some +example code that triggers this lint: + +```rust +pub struct Foo { + pub field: i32 +} +``` + +When set to 'deny', this will produce: + +```text +error: type could implement `Copy`; consider adding `impl Copy` + --> src/main.rs:3:1 + | +3 | / pub struct Foo { //~ ERROR type could implement `Copy`; consider adding `impl Copy` +4 | | pub field: i32 +5 | | } + | |_^ + | +``` + +You can fix the lint by deriving `Copy`. + +This lint is set to 'allow' because this code isn't bad; it's common to write +newtypes like this specifically so that a `Copy` type is no longer `Copy`. + +## missing-debug-implementations + +This lint detects missing implementations of `fmt::Debug`. Some example code +that triggers this lint: + +```rust +pub struct Foo; +``` + +When set to 'deny', this will produce: + +```text +error: type does not implement `fmt::Debug`; consider adding #[derive(Debug)] or a manual implementation + --> src/main.rs:3:1 + | +3 | pub struct Foo; + | ^^^^^^^^^^^^^^^ + | +``` + +You can fix the lint by deriving `Debug`. + +## missing-docs + +This lint detects missing documentation for public items. Some example code +that triggers this lint: + +```rust +pub fn foo() {} +``` + +When set to 'deny', this will produce: + +```text +error: missing documentation for crate + --> src/main.rs:1:1 + | +1 | / #![deny(missing_docs)] +2 | | +3 | | pub fn foo() {} +4 | | +5 | | fn main() {} + | |____________^ + | + +error: missing documentation for a function + --> src/main.rs:3:1 + | +3 | pub fn foo() {} + | ^^^^^^^^^^^^ + +``` + +To fix the lint, add documentation to all items. + +## single-use-lifetime + +This lint detects lifetimes that are only used once. Some example code that +triggers this lint: + +```rust +struct Foo<'x> { + x: &'x u32 +} +``` + +When set to 'deny', this will produce: + +```text +error: lifetime name `'x` only used once + --> src/main.rs:3:12 + | +3 | struct Foo<'x> { + | ^^ + | +``` + +## trivial-casts + +This lint detects trivial casts which could be removed. Some example code +that triggers this lint: + +```rust +let x: &u32 = &42; +let _ = x as *const u32; +``` + +When set to 'deny', this will produce: + +```text +error: trivial cast: `&u32` as `*const u32`. Cast can be replaced by coercion, this might require type ascription or a temporary variable + --> src/main.rs:5:13 + | +5 | let _ = x as *const u32; + | ^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> src/main.rs:1:9 + | +1 | #![deny(trivial_casts)] + | ^^^^^^^^^^^^^ +``` + +## trivial-numeric-casts + +This lint detects trivial casts of numeric types which could be removed. Some +example code that triggers this lint: + +```rust +let x = 42i32 as i32; +``` + +When set to 'deny', this will produce: + +```text +error: trivial numeric cast: `i32` as `i32`. Cast can be replaced by coercion, this might require type ascription or a temporary variable + --> src/main.rs:4:13 + | +4 | let x = 42i32 as i32; + | ^^^^^^^^^^^^ + | +``` + +## unreachable-pub + +This lint triggers for `pub` items not reachable from the crate root. Some +example code that triggers this lint: + +```rust +mod foo { + pub mod bar { + + } +} +``` + +When set to 'deny', this will produce: + +```text +error: unreachable `pub` item + --> src/main.rs:4:5 + | +4 | pub mod bar { + | ---^^^^^^^^ + | | + | help: consider restricting its visibility: `pub(crate)` + | +``` + +## unsafe-code + +This lint catches usage of `unsafe` code. Some example code that triggers this lint: + +```rust +fn main() { + unsafe { + + } +} +``` + +When set to 'deny', this will produce: + +```text +error: usage of an `unsafe` block + --> src/main.rs:4:5 + | +4 | / unsafe { +5 | | +6 | | } + | |_____^ + | +``` + +## unstable-features + +This lint is deprecated and no longer used. + +## unused-extern-crates + +This lint guards against `extern crate` items that are never used. Some +example code that triggers this lint: + +```rust,ignore +extern crate semver; +``` + +When set to 'deny', this will produce: + +```text +error: unused extern crate + --> src/main.rs:3:1 + | +3 | extern crate semver; + | ^^^^^^^^^^^^^^^^^^^^ + | +``` + +## unused-import-braces + +This lint catches unnecessary braces around an imported item. Some example +code that triggers this lint: + +```rust +use test::{A}; + +pub mod test { + pub struct A; +} +# fn main() {} +``` + +When set to 'deny', this will produce: + +```text +error: braces around A is unnecessary + --> src/main.rs:3:1 + | +3 | use test::{A}; + | ^^^^^^^^^^^^^^ + | +``` + +To fix it, `use test::A;` + +## unused-qualifications + +This lint detects unnecessarily qualified names. Some example code that triggers this lint: + +```rust +mod foo { + pub fn bar() {} +} + +fn main() { + use foo::bar; + foo::bar(); +} +``` + +When set to 'deny', this will produce: + +```text +error: unnecessary qualification + --> src/main.rs:9:5 + | +9 | foo::bar(); + | ^^^^^^^^ + | +``` + +You can call `bar()` directly, without the `foo::`. + +## unused-results + +This lint checks for the unused result of an expression in a statement. Some +example code that triggers this lint: + +```rust,no_run +fn foo<T>() -> T { panic!() } + +fn main() { + foo::<usize>(); +} +``` + +When set to 'deny', this will produce: + +```text +error: unused result + --> src/main.rs:6:5 + | +6 | foo::<usize>(); + | ^^^^^^^^^^^^^^^ + | +``` + +## variant-size-differences + +This lint detects enums with widely varying variant sizes. Some example code that triggers this lint: + +```rust +enum En { + V0(u8), + VBig([u8; 1024]), +} +``` + +When set to 'deny', this will produce: + +```text +error: enum variant is more than three times larger (1024 bytes) than the next largest + --> src/main.rs:5:5 + | +5 | VBig([u8; 1024]), //~ ERROR variant is more than three times larger + | ^^^^^^^^^^^^^^^^ + | +``` diff --git a/src/doc/rustc/src/lints/listing/deny-by-default.md b/src/doc/rustc/src/lints/listing/deny-by-default.md new file mode 100644 index 00000000000..e7ec6af8be1 --- /dev/null +++ b/src/doc/rustc/src/lints/listing/deny-by-default.md @@ -0,0 +1,241 @@ +# Deny-by-default lints + +These lints are all set to the 'deny' level by default. + +## exceeding-bitshifts + +This lint detects that a shift exceeds the type's number of bits. Some +example code that triggers this lint: + +```rust,ignore +1_i32 << 32; +``` + +This will produce: + +```text +error: bitshift exceeds the type's number of bits + --> src/main.rs:2:5 + | +2 | 1_i32 << 32; + | ^^^^^^^^^^^ + | +``` + +## invalid-type-param-default + +This lint detects type parameter default erroneously allowed in invalid location. Some +example code that triggers this lint: + +```rust,ignore +fn foo<T=i32>(t: T) {} +``` + +This will produce: + +```text +error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions. + --> src/main.rs:4:8 + | +4 | fn foo<T=i32>(t: T) {} + | ^ + | + = note: #[deny(invalid_type_param_default)] on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887> +``` + +## legacy-constructor-visibility + +[RFC 1506](https://github.com/rust-lang/rfcs/blob/master/text/1506-adt-kinds.md) modified some +visibility rules, and changed the visibility of struct constructors. Some +example code that triggers this lint: + +```rust,ignore +mod m { + pub struct S(u8); + + fn f() { + // this is trying to use S from the 'use' line, but becuase the `u8` is + // not pub, it is private + ::S; + } +} + +use m::S; +``` + +This will produce: + +```text +error: private struct constructors are not usable through re-exports in outer modules + --> src/main.rs:5:9 + | +5 | ::S; + | ^^^ + | + = note: #[deny(legacy_constructor_visibility)] on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #39207 <https://github.com/rust-lang/rust/issues/39207> +``` + + +## legacy-directory-ownership + +The legacy_directory_ownership warning is issued when + +* There is a non-inline module with a #[path] attribute (e.g. #[path = "foo.rs"] mod bar;), +* The module's file ("foo.rs" in the above example) is not named "mod.rs", and +* The module's file contains a non-inline child module without a #[path] attribute. + +The warning can be fixed by renaming the parent module to "mod.rs" and moving +it into its own directory if appropriate. + +## legacy-imports + +This lint detects names that resolve to ambiguous glob imports. Some example +code that triggers this lint: + +```rust,ignore +pub struct Foo; + +mod bar { + struct Foo; + + mod baz { + use *; + use bar::*; + fn f(_: Foo) {} + } +} +``` + +This will produce: + +```text +error: `Foo` is ambiguous + --> src/main.rs:9:17 + | +7 | use *; + | - `Foo` could refer to the name imported here +8 | use bar::*; + | ------ `Foo` could also refer to the name imported here +9 | fn f(_: Foo) {} + | ^^^ + | + = note: #[deny(legacy_imports)] on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #38260 <https://github.com/rust-lang/rust/issues/38260> +``` + + +## missing-fragment-specifier + +The missing_fragment_specifier warning is issued when an unused pattern in a +`macro_rules!` macro definition has a meta-variable (e.g. `$e`) that is not +followed by a fragment specifier (e.g. `:expr`). + +This warning can always be fixed by removing the unused pattern in the +`macro_rules!` macro definition. + +## mutable-transmutes + +This lint catches transmuting from `&T` to `&mut T` becuase it is undefined +behavior. Some example code that triggers this lint: + +```rust,ignore +unsafe { + let y = std::mem::transmute::<&i32, &mut i32>(&5); +} +``` + +This will produce: + +```text +error: mutating transmuted &mut T from &T may cause undefined behavior, consider instead using an UnsafeCell + --> src/main.rs:3:17 + | +3 | let y = std::mem::transmute::<&i32, &mut i32>(&5); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +``` + + +## no-mangle-const-items + +This lint detects any `const` items with the `#[no_mangle]` attribute. +Constants do not have their symbols exported, and therefore, this probably +means you meant to use a `static`, not a `const`. Some example code that +triggers this lint: + +```rust,ignore +#[no_mangle] +const FOO: i32 = 5; +``` + +This will produce: + +```text +error: const items should never be #[no_mangle] + --> src/main.rs:3:1 + | +3 | const FOO: i32 = 5; + | -----^^^^^^^^^^^^^^ + | | + | help: try a static value: `pub static` + | +``` + +## parenthesized-params-in-types-and-modules + +This lint detects incorrect parentheses. Some example code that triggers this +lint: + +```rust,ignore +let x = 5 as usize(); +``` + +This will produce: + +```text +error: parenthesized parameters may only be used with a trait + --> src/main.rs:2:21 + | +2 | let x = 5 as usize(); + | ^^ + | + = note: #[deny(parenthesized_params_in_types_and_modules)] on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #42238 <https://github.com/rust-lang/rust/issues/42238> +``` + +To fix it, remove the `()`s. + +## pub-use-of-private-extern-crate + +This lint detects a specific situation of re-exporting a private `extern crate`; + +## safe-extern-statics + +In older versions of Rust, there was a soundness issue where `extern static`s were allowed +to be accessed in safe code. This lint now catches and denies this kind of code. + +## unknown-crate-types + +This lint detects an unknown crate type found in a `#[crate_type]` directive. Some +example code that triggers this lint: + +```rust,ignore +#![crate_type="lol"] +``` + +This will produce: + +```text +error: invalid `crate_type` value + --> src/lib.rs:1:1 + | +1 | #![crate_type="lol"] + | ^^^^^^^^^^^^^^^^^^^^ + | +``` diff --git a/src/doc/rustc/src/lints/listing/index.md b/src/doc/rustc/src/lints/listing/index.md new file mode 100644 index 00000000000..18cd2fe32a3 --- /dev/null +++ b/src/doc/rustc/src/lints/listing/index.md @@ -0,0 +1,5 @@ +# Lint listing + +This section lists out all of the lints, grouped by their default lint levels. + +You can also see this list by running `rustc -W help`. \ No newline at end of file diff --git a/src/doc/rustc/src/lints/listing/warn-by-default.md b/src/doc/rustc/src/lints/listing/warn-by-default.md new file mode 100644 index 00000000000..1171f75caa1 --- /dev/null +++ b/src/doc/rustc/src/lints/listing/warn-by-default.md @@ -0,0 +1,1039 @@ +# Warn-by-default lints + +These lints are all set to the 'warn' level by default. + +## const-err + +This lint detects an erroneous expression while doing constant evaluation. Some +example code that triggers this lint: + +```rust,ignore +let b = 200u8 + 200u8; +``` + +This will produce: + +```text +warning: attempt to add with overflow + --> src/main.rs:2:9 + | +2 | let b = 200u8 + 200u8; + | ^^^^^^^^^^^^^ + | +``` + +## dead-code + +This lint detects detect unused, unexported items. Some +example code that triggers this lint: + +```rust +fn foo() {} +``` + +This will produce: + +```text +warning: function is never used: `foo` + --> src/lib.rs:2:1 + | +2 | fn foo() {} + | ^^^^^^^^ + | +``` + +## deprecated + +This lint detects detects use of deprecated items. Some +example code that triggers this lint: + +```rust +#[deprecated] +fn foo() {} + +fn bar() { + foo(); +} +``` + +This will produce: + +```text +warning: use of deprecated item 'foo' + --> src/lib.rs:7:5 + | +7 | foo(); + | ^^^ + | +``` + +## illegal-floating-point-literal-pattern + +This lint detects floating-point literals used in patterns. Some example code +that triggers this lint: + +```rust +let x = 42.0; + +match x { + 5.0 => {}, + _ => {}, +} +``` + +This will produce: + +```text +warning: floating-point literals cannot be used in patterns + --> src/main.rs:4:9 + | +4 | 5.0 => {}, + | ^^^ + | + = note: #[warn(illegal_floating_point_literal_pattern)] on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620> +``` + +## improper-ctypes + +This lint detects proper use of libc types in foreign modules. Some +example code that triggers this lint: + +```rust +extern "C" { + static STATIC: String; +} +``` + +This will produce: + +```text +warning: found struct without foreign-function-safe representation annotation in foreign module, consider adding a #[repr(C)] attribute to the type + --> src/main.rs:2:20 + | +2 | static STATIC: String; + | ^^^^^^ + | +``` + +## incoherent-fundamental-impls + +This lint detects potentially-conflicting impls that were erroneously allowed. Some +example code that triggers this lint: + +```rust +pub trait Trait1<X> { + type Output; +} + +pub trait Trait2<X> {} + +pub struct A; + +impl<X, T> Trait1<X> for T where T: Trait2<X> { + type Output = (); +} + +impl<X> Trait1<Box<X>> for A { + type Output = i32; +} +``` + +This will produce: + +```text +warning: conflicting implementations of trait `Trait1<std::boxed::Box<_>>` for type `A`: (E0119) + --> src/main.rs:13:1 + | +9 | impl<X, T> Trait1<X> for T where T: Trait2<X> { + | --------------------------------------------- first implementation here +... +13 | impl<X> Trait1<Box<X>> for A { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `A` + | + = note: #[warn(incoherent_fundamental_impls)] on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #46205 <https://github.com/rust-lang/rust/issues/46205> + = note: downstream crates may implement trait `Trait2<std::boxed::Box<_>>` for type `A` +``` + +## late-bound-lifetime-arguments + +This lint detects detects generic lifetime arguments in path segments with +late bound lifetime parameters. Some example code that triggers this lint: + +```rust +struct S; + +impl S { + fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} +} + +fn main() { + S.late::<'static>(&0, &0); +} +``` + +This will produce: + +```text +warning: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> src/main.rs:8:14 + | +4 | fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} + | -- the late bound lifetime parameter is introduced here +... +8 | S.late::<'static>(&0, &0); + | ^^^^^^^ + | + = note: #[warn(late_bound_lifetime_arguments)] on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868> +``` + +## non-camel-case-types + +This lint detects types, variants, traits and type parameters that don't have +camel case names. Some example code that triggers this lint: + +```rust +struct s; +``` + +This will produce: + +```text +warning: type `s` should have a camel case name such as `S` + --> src/main.rs:1:1 + | +1 | struct s; + | ^^^^^^^^^ + | +``` + +## non-shorthand-field-patterns + +This lint detects using `Struct { x: x }` instead of `Struct { x }` in a pattern. Some +example code that triggers this lint: + +```rust +struct Point { + x: i32, + y: i32, +} + + +fn main() { + let p = Point { + x: 5, + y: 5, + }; + + match p { + Point { x: x, y: y } => (), + } +} +``` + +This will produce: + +```text +warning: the `x:` in this pattern is redundant + --> src/main.rs:14:17 + | +14 | Point { x: x, y: y } => (), + | --^^ + | | + | help: remove this + | + +warning: the `y:` in this pattern is redundant + --> src/main.rs:14:23 + | +14 | Point { x: x, y: y } => (), + | --^^ + | | + | help: remove this + +``` + +## non-snake-case + +This lint detects variables, methods, functions, lifetime parameters and +modules that don't have snake case names. Some example code that triggers +this lint: + +```rust +let X = 5; +``` + +This will produce: + +```text +warning: variable `X` should have a snake case name such as `x` + --> src/main.rs:2:9 + | +2 | let X = 5; + | ^ + | +``` + +## non-upper-case-globals + +This lint detects static constants that don't have uppercase identifiers. +Some example code that triggers this lint: + +```rust +static x: i32 = 5; +``` + +This will produce: + +```text +warning: static variable `x` should have an upper case name such as `X` + --> src/main.rs:1:1 + | +1 | static x: i32 = 5; + | ^^^^^^^^^^^^^^^^^^ + | +``` + +## no-mangle-generic-items + +This lint detects generic items must be mangled. Some +example code that triggers this lint: + +```rust +#[no_mangle] +fn foo<T>(t: T) { + +} +``` + +This will produce: + +```text +warning: functions generic over types must be mangled + --> src/main.rs:2:1 + | +1 | #[no_mangle] + | ------------ help: remove this attribute +2 | / fn foo<T>(t: T) { +3 | | +4 | | } + | |_^ + | +``` + +## overflowing-literals + +This lint detects literal out of range for its type. Some +example code that triggers this lint: + +```rust +let x: u8 = 1000; +``` + +This will produce: + +```text +warning: literal out of range for u8 + --> src/main.rs:2:17 + | +2 | let x: u8 = 1000; + | ^^^^ + | +``` + +## path-statements + +This lint detects path statements with no effect. Some example code that +triggers this lint: + +```rust +let x = 42; + +x; +``` + +This will produce: + +```text +warning: path statement with no effect + --> src/main.rs:3:5 + | +3 | x; + | ^^ + | +``` + +## patterns-in-fns-without-body + +This lint detects patterns in functions without body were that were +previously erroneously allowed. Some example code that triggers this lint: + +```rust +trait Trait { + fn foo(mut arg: u8); +} +``` + +This will produce: + +```text +warning: patterns aren't allowed in methods without bodies + --> src/main.rs:2:12 + | +2 | fn foo(mut arg: u8); + | ^^^^^^^ + | + = note: #[warn(patterns_in_fns_without_body)] on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #35203 <https://github.com/rust-lang/rust/issues/35203> +``` + +To fix this, remove the pattern; it can be used in the implementation without +being used in the definition. That is: + +```rust +trait Trait { + fn foo(arg: u8); +} + +impl Trait for i32 { + fn foo(mut arg: u8) { + + } +} +``` + +## plugin-as-library + +This lint detects when compiler plugins are used as ordinary library in +non-plugin crate. Some example code that triggers this lint: + +```rust,ignore +#![feature(plugin)] +#![plugin(macro_crate_test)] + +extern crate macro_crate_test; +``` + +## private-in-public + +This lint detects detect private items in public interfaces not caught by the old implementation. Some +example code that triggers this lint: + +```rust,ignore +pub trait Trait { + type A; +} + +pub struct S; + +mod foo { + struct Z; + + impl ::Trait for ::S { + type A = Z; + } +} +# fn main() {} +``` + +This will produce: + +```text +error[E0446]: private type `foo::Z` in public interface + --> src/main.rs:11:9 + | +11 | type A = Z; + | ^^^^^^^^^^^ can't leak private type +``` + +## private-no-mangle-fns + +This lint detects functions marked `#[no_mangle]` that are also private. +Given that private functions aren't exposed publicly, and `#[no_mangle]` +controls the public symbol, this combination is erroneous. Some example code +that triggers this lint: + +```rust +#[no_mangle] +fn foo() {} +``` + +This will produce: + +```text +warning: function is marked #[no_mangle], but not exported + --> src/main.rs:2:1 + | +2 | fn foo() {} + | -^^^^^^^^^^ + | | + | help: try making it public: `pub` + | +``` + +To fix this, either make it public or remove the `#[no_mangle]`. + +## private-no-mangle-statics + +This lint detects any statics marked `#[no_mangle]` that are private. +Given that private statics aren't exposed publicly, and `#[no_mangle]` +controls the public symbol, this combination is erroneous. Some example code +that triggers this lint: + +```rust +#[no_mangle] +static X: i32 = 4; +``` + +This will produce: + +```text +warning: static is marked #[no_mangle], but not exported + --> src/main.rs:2:1 + | +2 | static X: i32 = 4; + | -^^^^^^^^^^^^^^^^^ + | | + | help: try making it public: `pub` + | +``` + +To fix this, either make it public or remove the `#[no_mangle]`. + +## renamed-and-removed-lints + +This lint detects lints that have been renamed or removed. Some +example code that triggers this lint: + +```rust +#![deny(raw_pointer_derive)] +``` + +This will produce: + +```text +warning: lint raw_pointer_derive has been removed: using derive with raw pointers is ok + --> src/main.rs:1:9 + | +1 | #![deny(raw_pointer_derive)] + | ^^^^^^^^^^^^^^^^^^ + | +``` + +To fix this, either remove the lint or use the new name. + +## safe-packed-borrows + +This lint detects borrowing a field in the interior of a packed structure +with alignment other than 1. Some example code that triggers this lint: + +```rust +#[repr(packed)] +pub struct Unaligned<T>(pub T); + +pub struct Foo { + start: u8, + data: Unaligned<u32>, +} + +fn main() { + let x = Foo { start: 0, data: Unaligned(1) }; + let y = &x.data.0; +} +``` + +This will produce: + +```text +warning: borrow of packed field requires unsafe function or block (error E0133) + --> src/main.rs:11:13 + | +11 | let y = &x.data.0; + | ^^^^^^^^^ + | + = note: #[warn(safe_packed_borrows)] on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043> +``` + +## stable-features + +This lint detects a `#[feature]` attribute that's since been made stable. Some +example code that triggers this lint: + +```rust +#![feature(test_accepted_feature)] +``` + +This will produce: + +```text +warning: this feature has been stable since 1.0.0. Attribute no longer needed + --> src/main.rs:1:12 + | +1 | #![feature(test_accepted_feature)] + | ^^^^^^^^^^^^^^^^^^^^^ + | +``` + +To fix, simply remove the `#![feature]` attribute, as it's no longer needed. + +## type-alias-bounds + +This lint detects bounds in type aliases. These are not currently enforced. +Some example code that triggers this lint: + +```rust +type SendVec<T: Send> = Vec<T>; +``` + +This will produce: + +```text +warning: type alias is never used: `SendVec` + --> src/main.rs:1:1 + | +1 | type SendVec<T: Send> = Vec<T>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +``` + +## tyvar-behind-raw-pointer + +This lint detects raw pointer to an inference variable. Some +example code that triggers this lint: + +```rust +let data = std::ptr::null(); +let _ = &data as *const *const (); + +if data.is_null() {} +``` + +This will produce: + +```text +warning: type annotations needed + --> src/main.rs:4:13 + | +4 | if data.is_null() {} + | ^^^^^^^ + | + = note: #[warn(tyvar_behind_raw_pointer)] on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #46906 <https://github.com/rust-lang/rust/issues/46906> +``` + +## unconditional-recursion + +This lint detects functions that cannot return without calling themselves. +Some example code that triggers this lint: + +```rust +fn foo() { + foo(); +} +``` + +This will produce: + +```text +warning: function cannot return without recurring + --> src/main.rs:1:1 + | +1 | fn foo() { + | ^^^^^^^^ cannot return without recurring +2 | foo(); + | ----- recursive call site + | +``` + +## unions-with-drop-fields + +This lint detects use of unions that contain fields with possibly non-trivial drop code. Some +example code that triggers this lint: + +```rust +#![feature(untagged_unions)] + +union U { + s: String, +} +``` + +This will produce: + +```text +warning: union contains a field with possibly non-trivial drop code, drop code of union fields is ignored when dropping the union + --> src/main.rs:4:5 + | +4 | s: String, + | ^^^^^^^^^ + | +``` + +## unknown-lints + +This lint detects unrecognized lint attribute. Some +example code that triggers this lint: + +```rust,ignore +#[allow(not_a_real_lint)] +``` + +This will produce: + +```text +warning: unknown lint: `not_a_real_lint` + --> src/main.rs:1:10 + | +1 | #![allow(not_a_real_lint)] + | ^^^^^^^^^^^^^^^ + | +``` + +## unreachable-code + +This lint detects detects unreachable code paths. Some example code that +triggers this lint: + +```rust,no_run +panic!("we never go past here!"); + +let x = 5; +``` + +This will produce: + +```text +warning: unreachable statement + --> src/main.rs:4:5 + | +4 | let x = 5; + | ^^^^^^^^^^ + | +``` + +## unreachable-patterns + +This lint detects detects unreachable patterns. Some +example code that triggers this lint: + +```rust +let x = 5; +match x { + y => (), + 5 => (), +} +``` + +This will produce: + +```text +warning: unreachable pattern + --> src/main.rs:5:5 + | +5 | 5 => (), + | ^ + | +``` + +The `y` pattern will always match, so the five is impossible to reach. +Remember, match arms match in order, you probably wanted to put the `5` case +above the `y` case. + +## unstable-name-collision + +This lint detects that you've used a name that the standard library plans to +add in the future, which means that your code may fail to compile without +additional type annotations in the future. Either rename, or add those +annotations now. + +## unused-allocation + +This lint detects detects unnecessary allocations that can be eliminated. + +## unused-assignments + +This lint detects detect assignments that will never be read. Some +example code that triggers this lint: + +```rust +let mut x = 5; +x = 6; +``` + +This will produce: + +```text +warning: value assigned to `x` is never read + --> src/main.rs:4:5 + | +4 | x = 6; + | ^ + | +``` + +## unused-attributes + +This lint detects detects attributes that were not used by the compiler. Some +example code that triggers this lint: + +```rust +#![feature(custom_attribute)] + +#![mutable_doc] +``` + +This will produce: + +```text +warning: unused attribute + --> src/main.rs:4:1 + | +4 | #![mutable_doc] + | ^^^^^^^^^^^^^^^ + | +``` + +## unused-comparisons + +This lint detects comparisons made useless by limits of the types involved. Some +example code that triggers this lint: + +```rust +fn foo(x: u8) { + x >= 0; +} +``` + +This will produce: + +```text +warning: comparison is useless due to type limits + --> src/main.rs:6:5 + | +6 | x >= 0; + | ^^^^^^ + | +``` + +## unused-doc-comment + +This lint detects detects doc comments that aren't used by rustdoc. Some +example code that triggers this lint: + +```rust +/// docs for x +let x = 12; +``` + +This will produce: + +```text +warning: doc comment not used by rustdoc + --> src/main.rs:2:5 + | +2 | /// docs for x + | ^^^^^^^^^^^^^^ + | +``` + +## unused-features + +This lint detects unused or unknown features found in crate-level #[feature] directives. +To fix this, simply remove the feature flag. + +## unused-imports + +This lint detects imports that are never used. Some +example code that triggers this lint: + +```rust +use std::collections::HashMap; +``` + +This will produce: + +```text +warning: unused import: `std::collections::HashMap` + --> src/main.rs:1:5 + | +1 | use std::collections::HashMap; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +``` + +## unused-macros + +This lint detects detects macros that were not used. Some example code that +triggers this lint: + +```rust +macro_rules! unused { + () => {}; +} + +fn main() { +} +``` + +This will produce: + +```text +warning: unused macro definition + --> src/main.rs:1:1 + | +1 | / macro_rules! unused { +2 | | () => {}; +3 | | } + | |_^ + | +``` + +## unused-must-use + +This lint detects unused result of a type flagged as #[must_use]. Some +example code that triggers this lint: + +```rust +fn returns_result() -> Result<(), ()> { + Ok(()) +} + +fn main() { + returns_result(); +} +``` + +This will produce: + +```text +warning: unused `std::result::Result` which must be used + --> src/main.rs:6:5 + | +6 | returns_result(); + | ^^^^^^^^^^^^^^^^^ + | +``` + +## unused-mut + +This lint detects detect mut variables which don't need to be mutable. Some +example code that triggers this lint: + +```rust +let mut x = 5; +``` + +This will produce: + +```text +warning: variable does not need to be mutable + --> src/main.rs:2:9 + | +2 | let mut x = 5; + | ----^ + | | + | help: remove this `mut` + | +``` + +## unused-parens + +This lint detects `if`, `match`, `while` and `return` with parentheses; they +do not need them. Some example code that triggers this lint: + +```rust +if(true) {} +``` + +This will produce: + +```text +warning: unnecessary parentheses around `if` condition + --> src/main.rs:2:7 + | +2 | if(true) {} + | ^^^^^^ help: remove these parentheses + | +``` + +## unused-unsafe + +This lint detects unnecessary use of an `unsafe` block. Some +example code that triggers this lint: + +```rust +unsafe {} +``` + +This will produce: + +```text +warning: unnecessary `unsafe` block + --> src/main.rs:2:5 + | +2 | unsafe {} + | ^^^^^^ unnecessary `unsafe` block + | +``` + +## unused-variables + +This lint detects detect variables which are not used in any way. Some +example code that triggers this lint: + +```rust +let x = 5; +``` + +This will produce: + +```text +warning: unused variable: `x` + --> src/main.rs:2:9 + | +2 | let x = 5; + | ^ help: consider using `_x` instead + | +``` + +## warnings + +This lint is a bit special; by changing its level, you change every other warning +that would produce a warning to whatever value you'd like: + +```rust +#![deny(warnings)] +``` + +As such, you won't ever trigger this lint in your code directly. + +## while-true + +This lint detects `while true { }`. Some example code that triggers this +lint: + +```rust,no_run +while true { + +} +``` + +This will produce: + +```text +warning: denote infinite loops with `loop { ... }` + --> src/main.rs:2:5 + | +2 | while true { + | ^^^^^^^^^^ help: use `loop` + | +``` diff --git a/src/doc/rustc/src/targets/built-in.md b/src/doc/rustc/src/targets/built-in.md new file mode 100644 index 00000000000..8620346e5b7 --- /dev/null +++ b/src/doc/rustc/src/targets/built-in.md @@ -0,0 +1,10 @@ +# Built-in Targets + +`rustc` ships with the ability to compile to many targets automatically, we +call these "built-in" targets, and they generally correspond to targets that +the team is supporting directly. + +To see the list of built-in targets, you can run `rustc --print target-list`, +or look at [the API +docs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_back/target/#modules). +Each module there defines a builder for a particular target. \ No newline at end of file diff --git a/src/doc/rustc/src/targets/custom.md b/src/doc/rustc/src/targets/custom.md new file mode 100644 index 00000000000..0691afc60ea --- /dev/null +++ b/src/doc/rustc/src/targets/custom.md @@ -0,0 +1,17 @@ +# Custom Targets + +If you'd like to build for a target that is not yet supported by `rustc`, you can use a +"custom target specification" to define a target. These target specification files +are JSON. To see the JSON for the host target, you can run: + +```bash +$ rustc +nightly -Z unstable-options --print target-spec-json +``` + +To see it for a different target, add the `--target` flag: + +```bash +$ rustc +nightly -Z unstable-options --target=wasm32-unknown-unknown --print target-spec-json +``` + +To use a custom target, see [`xargo`](https://github.com/japaric/xargo). \ No newline at end of file diff --git a/src/doc/rustc/src/targets/index.md b/src/doc/rustc/src/targets/index.md new file mode 100644 index 00000000000..07e3a79471f --- /dev/null +++ b/src/doc/rustc/src/targets/index.md @@ -0,0 +1,13 @@ +# Targets + +`rustc` is a cross-compiler by default. This means that you can use any compiler to build for any +architecture. The list of *targets* are the possible architectures that you can build for. + +To see all the options that you can set with a target, see the docs +[here](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_back/target/struct.Target.html). + +To compile to a particular target, use the `--target` flag: + +```bash +$ rustc src/main.rs --target=wasm32-unknown-unknown +``` diff --git a/src/doc/rustc/src/what-is-rustc.md b/src/doc/rustc/src/what-is-rustc.md new file mode 100644 index 00000000000..bed1b71c24e --- /dev/null +++ b/src/doc/rustc/src/what-is-rustc.md @@ -0,0 +1,68 @@ +# What is rustc? + +Welcome to "The rustc book"! `rustc` is the compiler for the Rust programming +language, provided by the project itself. Compilers take your source code and +produce binary code, either as a library or executable. + +Most Rust programmers don't invoke `rustc` directly, but instead do it through +[Cargo](../cargo/index.html). It's all in service of `rustc` though! If you +want to see how Cargo calls `rustc`, you can + +```bash +$ cargo build --verbose +``` + +And it will print out each `rustc` invocation. This book can help you +understand what each of these options does. Additionally, while most +Rustaceans use Cargo, not all do: sometimes they integrate `rustc` into other +build systems. This book should provide a guide to all of the options you'd +need to do so. + +## Basic usage + +Let's say you've got a little hello world program in a file `hello.rs`: + +```rust +fn main() { + println!("Hello, world!"); +} +``` + +To turn this source code into an executable, you can use `rustc`: + +```bash +$ rustc hello.rs +$ ./hello # on a *NIX +$ .\hello.exe # on Windows +``` + +Note that we only ever pass `rustc` the *crate root*, not every file we wish +to compile. For example, if we had a `main.rs` that looked like this: + +```rust,ignore +mod foo; + +fn main() { + foo::hello(); +} +``` + +And a `foo.rs` that had this: + +```rust,ignore +fn hello() { + println!("Hello, world!"); +} +``` + +To compile this, we'd run this command: + +```bash +$ rustc main.rs +``` + +No need to tell `rustc` about `foo.rs`; the `mod` statements give it +everything that it needs. This is different than how you would use a C +compiler, where you invoke the compiler on each file, and then link +everything together. In other words, the *crate* is a translation unit, not a +particular module. \ No newline at end of file diff --git a/src/doc/unstable-book/src/language-features/fn-must-use.md b/src/doc/unstable-book/src/language-features/fn-must-use.md deleted file mode 100644 index 71b6cd663a0..00000000000 --- a/src/doc/unstable-book/src/language-features/fn-must-use.md +++ /dev/null @@ -1,30 +0,0 @@ -# `fn_must_use` - -The tracking issue for this feature is [#43302]. - -[#43302]: https://github.com/rust-lang/rust/issues/43302 - ------------------------- - -The `fn_must_use` feature allows functions and methods to be annotated with -`#[must_use]`, indicating that the `unused_must_use` lint should require their -return values to be used (similarly to how types annotated with `must_use`, -most notably `Result`, are linted if not used). - -## Examples - -```rust -#![feature(fn_must_use)] - -#[must_use] -fn double(x: i32) -> i32 { - 2 * x -} - -fn main() { - double(4); // warning: unused return value of `double` which must be used - - let _ = double(4); // (no warning) -} - -``` diff --git a/src/doc/unstable-book/src/language-features/tool-attributes.md b/src/doc/unstable-book/src/language-features/tool-attributes.md new file mode 100644 index 00000000000..15fc84a3e2a --- /dev/null +++ b/src/doc/unstable-book/src/language-features/tool-attributes.md @@ -0,0 +1,26 @@ +# `tool_attributes` + +The tracking issue for this feature is: [#44690] + +[#44690]: https://github.com/rust-lang/rust/issues/44690 + +------------------------ + +Tool attributes let you use scoped attributes to control the behavior +of certain tools. + +Currently tool names which can be appear in scoped attributes are restricted to +`clippy` and `rustfmt`. + +## An example + +```rust +#![feature(tool_attributes)] + +#[rustfmt::skip] +fn foo() { println!("hello, world"); } + +fn main() { + foo(); +} +``` diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index c0372d24ed5..f59c9f7fd61 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -16,7 +16,7 @@ issue = "32838")] use core::intrinsics::{min_align_of_val, size_of_val}; -use core::ptr::NonNull; +use core::ptr::{NonNull, Unique}; use core::usize; #[doc(inline)] @@ -152,9 +152,17 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { } } -#[cfg_attr(not(test), lang = "box_free")] +#[cfg(stage0)] +#[lang = "box_free"] +#[inline] +unsafe fn old_box_free<T: ?Sized>(ptr: *mut T) { + box_free(Unique::new_unchecked(ptr)) +} + +#[cfg_attr(not(any(test, stage0)), lang = "box_free")] #[inline] -pub(crate) unsafe fn box_free<T: ?Sized>(ptr: *mut T) { +pub(crate) unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) { + let ptr = ptr.as_ptr(); let size = size_of_val(&*ptr); let align = min_align_of_val(&*ptr); // We do not allocate for Box<T> when T is ZST, so deallocation is also not necessary. diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index e52a0216dd3..d0950bff9ce 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -566,7 +566,8 @@ impl<T: ?Sized> Arc<T> { fn from_box(v: Box<T>) -> Arc<T> { unsafe { - let bptr = Box::into_raw(v); + let box_unique = Box::into_unique(v); + let bptr = box_unique.as_ptr(); let value_size = size_of_val(&*bptr); let ptr = Self::allocate_for_ptr(bptr); @@ -578,7 +579,7 @@ impl<T: ?Sized> Arc<T> { value_size); // Free the allocation without dropping its contents - box_free(bptr); + box_free(box_unique); Arc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData } } diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 5ebd2cc6146..1b4f86dcfac 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -184,6 +184,7 @@ impl<T: ?Sized> Box<T> { #[unstable(feature = "ptr_internals", issue = "0", reason = "use into_raw_non_null instead")] #[inline] + #[doc(hidden)] pub fn into_unique(b: Box<T>) -> Unique<T> { let unique = b.0; mem::forget(b); diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 021395d0c82..da4b76a4d52 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -96,7 +96,7 @@ #![feature(dropck_eyepatch)] #![feature(exact_size_is_empty)] #![feature(fmt_internals)] -#![feature(fn_must_use)] +#![cfg_attr(stage0, feature(fn_must_use))] #![feature(from_ref)] #![feature(fundamental)] #![feature(lang_items)] @@ -122,8 +122,9 @@ #![feature(on_unimplemented)] #![feature(exact_chunks)] #![feature(pointer_methods)] -#![feature(inclusive_range_fields)] +#![feature(inclusive_range_methods)] #![cfg_attr(stage0, feature(generic_param_attrs))] +#![feature(rustc_const_unstable)] #![cfg_attr(not(test), feature(fn_traits, i128))] #![cfg_attr(test, feature(test))] diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 7ef0a27fc72..eb25ae17511 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -56,14 +56,16 @@ pub struct RawVec<T, A: Alloc = Global> { impl<T, A: Alloc> RawVec<T, A> { /// Like `new` but parameterized over the choice of allocator for /// the returned RawVec. - pub fn new_in(a: A) -> Self { + pub const fn new_in(a: A) -> Self { // !0 is usize::MAX. This branch should be stripped at compile time. - let cap = if mem::size_of::<T>() == 0 { !0 } else { 0 }; + // FIXME(mark-i-m): use this line when `if`s are allowed in `const` + //let cap = if mem::size_of::<T>() == 0 { !0 } else { 0 }; // Unique::empty() doubles as "unallocated" and "zero-sized allocation" RawVec { ptr: Unique::empty(), - cap, + // FIXME(mark-i-m): use `cap` when ifs are allowed in const + cap: [0, !0][(mem::size_of::<T>() == 0) as usize], a, } } @@ -120,7 +122,7 @@ impl<T> RawVec<T, Global> { /// 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 { + pub const fn new() -> Self { Self::new_in(Global) } diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 8fb8e111754..d0188c6e828 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -681,7 +681,8 @@ impl<T: ?Sized> Rc<T> { fn from_box(v: Box<T>) -> Rc<T> { unsafe { - let bptr = Box::into_raw(v); + let box_unique = Box::into_unique(v); + let bptr = box_unique.as_ptr(); let value_size = size_of_val(&*bptr); let ptr = Self::allocate_for_ptr(bptr); @@ -693,7 +694,7 @@ impl<T: ?Sized> Rc<T> { value_size); // Free the allocation without dropping its contents - box_free(bptr); + box_free(box_unique); Rc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData } } diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index 32272169307..1c8ff316e55 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -25,7 +25,7 @@ #![feature(try_reserve)] #![feature(unboxed_closures)] #![feature(exact_chunks)] -#![feature(inclusive_range_fields)] +#![feature(inclusive_range_methods)] extern crate alloc_system; extern crate core; diff --git a/src/liballoc/tests/slice.rs b/src/liballoc/tests/slice.rs index 99d9c51efc7..6fd0b33f02a 100644 --- a/src/liballoc/tests/slice.rs +++ b/src/liballoc/tests/slice.rs @@ -1282,6 +1282,7 @@ fn test_box_slice_clone() { } #[test] +#[allow(unused_must_use)] // here, we care about the side effects of `.clone()` #[cfg_attr(target_os = "emscripten", ignore)] fn test_box_slice_clone_panics() { use std::sync::Arc; diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index b184404c15b..35d0a69a05a 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -322,7 +322,8 @@ impl<T> Vec<T> { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn new() -> Vec<T> { + #[rustc_const_unstable(feature = "const_vec_new")] + pub const fn new() -> Vec<T> { Vec { buf: RawVec::new(), len: 0, diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index c91aa06609d..13e838773a5 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -106,6 +106,8 @@ use self::Ordering::*; /// ``` #[lang = "eq"] #[stable(feature = "rust1", since = "1.0.0")] +#[doc(alias = "==")] +#[doc(alias = "!=")] #[rustc_on_unimplemented = "can't compare `{Self}` with `{Rhs}`"] pub trait PartialEq<Rhs: ?Sized = Self> { /// This method tests for `self` and `other` values to be equal, and is used @@ -160,6 +162,8 @@ pub trait PartialEq<Rhs: ?Sized = Self> { /// } /// impl Eq for Book {} /// ``` +#[doc(alias = "==")] +#[doc(alias = "!=")] #[stable(feature = "rust1", since = "1.0.0")] pub trait Eq: PartialEq<Self> { // this method is used solely by #[deriving] to assert @@ -428,6 +432,10 @@ impl<T: Ord> Ord for Reverse<T> { /// } /// ``` #[lang = "ord"] +#[doc(alias = "<")] +#[doc(alias = ">")] +#[doc(alias = "<=")] +#[doc(alias = ">=")] #[stable(feature = "rust1", since = "1.0.0")] pub trait Ord: Eq + PartialOrd<Self> { /// This method returns an `Ordering` between `self` and `other`. @@ -599,6 +607,10 @@ impl PartialOrd for Ordering { /// ``` #[lang = "partial_ord"] #[stable(feature = "rust1", since = "1.0.0")] +#[doc(alias = ">")] +#[doc(alias = "<")] +#[doc(alias = "<=")] +#[doc(alias = ">=")] #[rustc_on_unimplemented = "can't compare `{Self}` with `{Rhs}`"] pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> { /// This method returns an ordering between `self` and `other` values if one exists. diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index a8430f14410..5820fe58932 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -542,11 +542,12 @@ impl<'a> Display for Arguments<'a> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented( - on(crate_local, label="`{Self}` cannot be formatted using `:?`; \ - add `#[derive(Debug)]` or manually implement `{Debug}`"), + on(crate_local, label="`{Self}` cannot be formatted using `{{:?}}`", + note="add `#[derive(Debug)]` or manually implement `{Debug}`"), message="`{Self}` doesn't implement `{Debug}`", - label="`{Self}` cannot be formatted using `:?` because it doesn't implement `{Debug}`", + label="`{Self}` cannot be formatted using `{{:?}}` because it doesn't implement `{Debug}`", )] +#[doc(alias = "{:?}")] #[lang = "debug_trait"] pub trait Debug { /// Formats the value using the given formatter. @@ -609,9 +610,11 @@ pub trait Debug { /// ``` #[rustc_on_unimplemented( message="`{Self}` doesn't implement `{Display}`", - label="`{Self}` cannot be formatted with the default formatter; \ - try using `:?` instead if you are using a format string", + label="`{Self}` cannot be formatted with the default formatter", + note="in format strings you may be able to use `{{:?}}` \ + (or {{:#?}} for pretty-print) instead", )] +#[doc(alias = "{}")] #[stable(feature = "rust1", since = "1.0.0")] pub trait Display { /// Formats the value using the given formatter. diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 6a77de2c986..b27bd3142e1 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -1094,6 +1094,8 @@ pub trait Iterator { /// `flatten()` a three-dimensional array the result will be /// two-dimensional and not one-dimensional. To get a one-dimensional /// structure, you have to `flatten()` again. + /// + /// [`flat_map()`]: #method.flat_map #[inline] #[unstable(feature = "iterator_flatten", issue = "48213")] fn flatten(self) -> Flatten<Self> diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 0e21a3327fd..54f35d17974 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -50,6 +50,15 @@ // Since libcore defines many fundamental lang items, all tests live in a // separate crate, libcoretest, to avoid bizarre issues. +// +// Here we explicitly #[cfg]-out this whole crate when testing. If we don't do +// this, both the generated test artifact and the linked libtest (which +// transitively includes libcore) will both define the same set of lang items, +// and this will cause the E0152 "duplicate lang item found" error. See +// discussion in #50466 for details. +// +// This cfg won't affect doc tests. +#![cfg(not(test))] #![stable(feature = "core", since = "1.6.0")] #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", @@ -76,7 +85,6 @@ #![feature(doc_cfg)] #![feature(doc_spotlight)] #![feature(extern_types)] -#![feature(fn_must_use)] #![feature(fundamental)] #![feature(intrinsics)] #![feature(iterator_flatten)] @@ -103,6 +111,7 @@ #![feature(untagged_unions)] #![feature(unwind_attributes)] #![feature(doc_alias)] +#![feature(inclusive_range_methods)] #![cfg_attr(not(stage0), feature(mmx_target_feature))] #![cfg_attr(not(stage0), feature(tbm_target_feature))] @@ -114,6 +123,7 @@ #![cfg_attr(stage0, feature(target_feature))] #![cfg_attr(stage0, feature(cfg_target_feature))] +#![cfg_attr(stage0, feature(fn_must_use))] #[prelude_import] #[allow(unused)] diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index f9371ed0575..c830c22ee5f 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -606,8 +606,8 @@ mod builtin { #[macro_export] #[cfg(dox)] macro_rules! concat_idents { - ($($e:ident),*) => ({ /* compiler built-in */ }); - ($($e:ident,)*) => ({ /* compiler built-in */ }); + ($($e:ident),+) => ({ /* compiler built-in */ }); + ($($e:ident,)+) => ({ /* compiler built-in */ }); } /// Concatenates literals into a static string slice. diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index feb689dbc1f..c074adfd570 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -602,6 +602,8 @@ unsafe impl<'a, T: ?Sized> Freeze for &'a mut T {} /// `Pin` pointer. /// /// This trait is automatically implemented for almost every type. +/// +/// [`Pin`]: ../mem/struct.Pin.html #[unstable(feature = "pin", issue = "49150")] pub unsafe auto trait Unpin {} diff --git a/src/libcore/ops/arith.rs b/src/libcore/ops/arith.rs index a1f6030428f..a1bc5463f73 100644 --- a/src/libcore/ops/arith.rs +++ b/src/libcore/ops/arith.rs @@ -94,6 +94,7 @@ pub trait Add<RHS=Self> { type Output; /// Performs the `+` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn add(self, rhs: RHS) -> Self::Output; } @@ -191,6 +192,7 @@ pub trait Sub<RHS=Self> { type Output; /// Performs the `-` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn sub(self, rhs: RHS) -> Self::Output; } @@ -310,6 +312,7 @@ pub trait Mul<RHS=Self> { type Output; /// Performs the `*` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn mul(self, rhs: RHS) -> Self::Output; } @@ -433,6 +436,7 @@ pub trait Div<RHS=Self> { type Output; /// Performs the `/` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn div(self, rhs: RHS) -> Self::Output; } @@ -517,6 +521,7 @@ pub trait Rem<RHS=Self> { type Output = Self; /// Performs the `%` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn rem(self, rhs: RHS) -> Self::Output; } @@ -601,6 +606,7 @@ pub trait Neg { type Output; /// Performs the unary `-` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn neg(self) -> Self::Output; } diff --git a/src/libcore/ops/bit.rs b/src/libcore/ops/bit.rs index 81c4455cef4..3900f365b0a 100644 --- a/src/libcore/ops/bit.rs +++ b/src/libcore/ops/bit.rs @@ -46,6 +46,7 @@ pub trait Not { type Output; /// Performs the unary `!` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn not(self) -> Self::Output; } @@ -119,6 +120,7 @@ not_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// assert_eq!(bv1 & bv2, expected); /// ``` #[lang = "bitand"] +#[doc(alias = "&")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(message="no implementation for `{Self} & {RHS}`", label="no implementation for `{Self} & {RHS}`")] @@ -128,6 +130,7 @@ pub trait BitAnd<RHS=Self> { type Output; /// Performs the `&` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn bitand(self, rhs: RHS) -> Self::Output; } @@ -201,6 +204,7 @@ bitand_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// assert_eq!(bv1 | bv2, expected); /// ``` #[lang = "bitor"] +#[doc(alias = "|")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(message="no implementation for `{Self} | {RHS}`", label="no implementation for `{Self} | {RHS}`")] @@ -210,6 +214,7 @@ pub trait BitOr<RHS=Self> { type Output; /// Performs the `|` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn bitor(self, rhs: RHS) -> Self::Output; } @@ -286,6 +291,7 @@ bitor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// assert_eq!(bv1 ^ bv2, expected); /// ``` #[lang = "bitxor"] +#[doc(alias = "^")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(message="no implementation for `{Self} ^ {RHS}`", label="no implementation for `{Self} ^ {RHS}`")] @@ -295,6 +301,7 @@ pub trait BitXor<RHS=Self> { type Output; /// Performs the `^` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn bitxor(self, rhs: RHS) -> Self::Output; } @@ -372,6 +379,7 @@ bitxor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// SpinVector { vec: vec![2, 3, 4, 0, 1] }); /// ``` #[lang = "shl"] +#[doc(alias = "<<")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(message="no implementation for `{Self} << {RHS}`", label="no implementation for `{Self} << {RHS}`")] @@ -381,6 +389,7 @@ pub trait Shl<RHS=Self> { type Output; /// Performs the `<<` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn shl(self, rhs: RHS) -> Self::Output; } @@ -479,6 +488,7 @@ shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 isize i128 } /// SpinVector { vec: vec![3, 4, 0, 1, 2] }); /// ``` #[lang = "shr"] +#[doc(alias = ">>")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(message="no implementation for `{Self} >> {RHS}`", label="no implementation for `{Self} >> {RHS}`")] @@ -488,6 +498,7 @@ pub trait Shr<RHS=Self> { type Output; /// Performs the `>>` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn shr(self, rhs: RHS) -> Self::Output; } @@ -593,6 +604,7 @@ shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } /// assert_eq!(bv, expected); /// ``` #[lang = "bitand_assign"] +#[doc(alias = "&=")] #[stable(feature = "op_assign_traits", since = "1.8.0")] #[rustc_on_unimplemented(message="no implementation for `{Self} &= {Rhs}`", label="no implementation for `{Self} &= {Rhs}`")] @@ -641,6 +653,7 @@ bitand_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// assert_eq!(prefs, PersonalPreferences { likes_cats: true, likes_dogs: true }); /// ``` #[lang = "bitor_assign"] +#[doc(alias = "|=")] #[stable(feature = "op_assign_traits", since = "1.8.0")] #[rustc_on_unimplemented(message="no implementation for `{Self} |= {Rhs}`", label="no implementation for `{Self} |= {Rhs}`")] @@ -689,6 +702,7 @@ bitor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// assert_eq!(personality, Personality { has_soul: true, likes_knitting: false}); /// ``` #[lang = "bitxor_assign"] +#[doc(alias = "^=")] #[stable(feature = "op_assign_traits", since = "1.8.0")] #[rustc_on_unimplemented(message="no implementation for `{Self} ^= {Rhs}`", label="no implementation for `{Self} ^= {Rhs}`")] @@ -735,6 +749,7 @@ bitxor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// assert_eq!(scalar, Scalar(16)); /// ``` #[lang = "shl_assign"] +#[doc(alias = "<<=")] #[stable(feature = "op_assign_traits", since = "1.8.0")] #[rustc_on_unimplemented(message="no implementation for `{Self} <<= {Rhs}`", label="no implementation for `{Self} <<= {Rhs}`")] @@ -802,6 +817,7 @@ shl_assign_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } /// assert_eq!(scalar, Scalar(4)); /// ``` #[lang = "shr_assign"] +#[doc(alias = ">>=")] #[stable(feature = "op_assign_traits", since = "1.8.0")] #[rustc_on_unimplemented(message="no implementation for `{Self} >>= {Rhs}`", label="no implementation for `{Self} >>= {Rhs}`")] diff --git a/src/libcore/ops/deref.rs b/src/libcore/ops/deref.rs index 4ce0740130b..54eecc82e19 100644 --- a/src/libcore/ops/deref.rs +++ b/src/libcore/ops/deref.rs @@ -68,6 +68,8 @@ /// assert_eq!('a', *x); /// ``` #[lang = "deref"] +#[doc(alias = "*")] +#[doc(alias = "&*")] #[stable(feature = "rust1", since = "1.0.0")] pub trait Deref { /// The resulting type after dereferencing. @@ -75,6 +77,7 @@ pub trait Deref { type Target: ?Sized; /// Dereferences the value. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn deref(&self) -> &Self::Target; } @@ -162,6 +165,7 @@ impl<'a, T: ?Sized> Deref for &'a mut T { /// assert_eq!('b', *x); /// ``` #[lang = "deref_mut"] +#[doc(alias = "*")] #[stable(feature = "rust1", since = "1.0.0")] pub trait DerefMut: Deref { /// Mutably dereferences the value. diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 6f3e3b50885..b01a769eda7 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -45,6 +45,7 @@ use fmt; /// [`IntoIterator`]: ../iter/trait.Iterator.html /// [`Iterator`]: ../iter/trait.IntoIterator.html /// [slicing index]: ../slice/trait.SliceIndex.html +#[doc(alias = "..")] #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[stable(feature = "rust1", since = "1.0.0")] pub struct RangeFull; @@ -74,6 +75,7 @@ impl fmt::Debug for RangeFull { /// assert_eq!(arr[1.. ], [ 'b', 'c', 'd']); /// assert_eq!(arr[1..3], [ 'b', 'c' ]); // Range /// ``` +#[doc(alias = "..")] #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "rust1", since = "1.0.0")] pub struct Range<Idx> { @@ -175,6 +177,7 @@ impl<Idx: PartialOrd<Idx>> Range<Idx> { /// ``` /// /// [`Iterator`]: ../iter/trait.IntoIterator.html +#[doc(alias = "..")] #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "rust1", since = "1.0.0")] pub struct RangeFrom<Idx> { @@ -256,6 +259,7 @@ impl<Idx: PartialOrd<Idx>> RangeFrom<Idx> { /// [`IntoIterator`]: ../iter/trait.Iterator.html /// [`Iterator`]: ../iter/trait.IntoIterator.html /// [slicing index]: ../slice/trait.SliceIndex.html +#[doc(alias = "..")] #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[stable(feature = "rust1", since = "1.0.0")] pub struct RangeTo<Idx> { @@ -314,26 +318,101 @@ impl<Idx: PartialOrd<Idx>> RangeTo<Idx> { /// # Examples /// /// ``` -/// #![feature(inclusive_range_fields)] +/// #![feature(inclusive_range_methods)] /// -/// assert_eq!((3..=5), std::ops::RangeInclusive { start: 3, end: 5 }); +/// assert_eq!((3..=5), std::ops::RangeInclusive::new(3, 5)); /// assert_eq!(3 + 4 + 5, (3..=5).sum()); /// /// let arr = [0, 1, 2, 3]; /// assert_eq!(arr[ ..=2], [0,1,2 ]); /// assert_eq!(arr[1..=2], [ 1,2 ]); // RangeInclusive /// ``` +#[doc(alias = "..=")] #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "inclusive_range", since = "1.26.0")] pub struct RangeInclusive<Idx> { + // FIXME: The current representation follows RFC 1980, + // but it is known that LLVM is not able to optimize loops following that RFC. + // Consider adding an extra `bool` field to indicate emptiness of the range. + // See #45222 for performance test cases. + #[cfg(not(stage0))] + pub(crate) start: Idx, + #[cfg(not(stage0))] + pub(crate) end: Idx, /// The lower bound of the range (inclusive). + #[cfg(stage0)] #[unstable(feature = "inclusive_range_fields", issue = "49022")] pub start: Idx, /// The upper bound of the range (inclusive). + #[cfg(stage0)] #[unstable(feature = "inclusive_range_fields", issue = "49022")] pub end: Idx, } +impl<Idx> RangeInclusive<Idx> { + /// Creates a new inclusive range. Equivalent to writing `start..=end`. + /// + /// # Examples + /// + /// ``` + /// #![feature(inclusive_range_methods)] + /// use std::ops::RangeInclusive; + /// + /// assert_eq!(3..=5, RangeInclusive::new(3, 5)); + /// ``` + #[unstable(feature = "inclusive_range_methods", issue = "49022")] + #[inline] + pub const fn new(start: Idx, end: Idx) -> Self { + Self { start, end } + } + + /// Returns the lower bound of the range (inclusive). + /// + /// When using an inclusive range for iteration, the values of `start()` and + /// [`end()`] are unspecified after the iteration ended. To determine + /// whether the inclusive range is empty, use the [`is_empty()`] method + /// instead of comparing `start() > end()`. + /// + /// [`end()`]: #method.end + /// [`is_empty()`]: #method.is_empty + /// + /// # Examples + /// + /// ``` + /// #![feature(inclusive_range_methods)] + /// + /// assert_eq!((3..=5).start(), &3); + /// ``` + #[unstable(feature = "inclusive_range_methods", issue = "49022")] + #[inline] + pub fn start(&self) -> &Idx { + &self.start + } + + /// Returns the upper bound of the range (inclusive). + /// + /// When using an inclusive range for iteration, the values of [`start()`] + /// and `end()` are unspecified after the iteration ended. To determine + /// whether the inclusive range is empty, use the [`is_empty()`] method + /// instead of comparing `start() > end()`. + /// + /// [`start()`]: #method.start + /// [`is_empty()`]: #method.is_empty + /// + /// # Examples + /// + /// ``` + /// #![feature(inclusive_range_methods)] + /// + /// assert_eq!((3..=5).end(), &5); + /// ``` + #[unstable(feature = "inclusive_range_methods", issue = "49022")] + #[inline] + pub fn end(&self) -> &Idx { + &self.end + } +} + #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx: fmt::Debug> fmt::Debug for RangeInclusive<Idx> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { @@ -449,6 +528,7 @@ impl<Idx: PartialOrd<Idx>> RangeInclusive<Idx> { /// [`IntoIterator`]: ../iter/trait.Iterator.html /// [`Iterator`]: ../iter/trait.IntoIterator.html /// [slicing index]: ../slice/trait.SliceIndex.html +#[doc(alias = "..=")] #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[stable(feature = "inclusive_range", since = "1.26.0")] pub struct RangeToInclusive<Idx> { diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 74bb264cc67..5d0b675e8e4 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2513,6 +2513,7 @@ impl<T: ?Sized> PartialOrd for *mut T { reason = "use NonNull instead and consider PhantomData<T> \ (if you also use #[may_dangle]), Send, and/or Sync")] #[allow(deprecated)] +#[doc(hidden)] pub struct Unique<T: ?Sized> { pointer: NonZero<*const T>, // NOTE: this marker has no consequences for variance, but is necessary @@ -2551,10 +2552,9 @@ impl<T: Sized> Unique<T> { /// This is useful for initializing types which lazily allocate, like /// `Vec::new` does. // FIXME: rename to dangling() to match NonNull? - pub fn empty() -> Self { + pub const fn empty() -> Self { unsafe { - let ptr = mem::align_of::<T>() as *mut T; - Unique::new_unchecked(ptr) + Unique::new_unchecked(mem::align_of::<T>() as *mut T) } } } diff --git a/src/libcore/slice/memchr.rs b/src/libcore/slice/memchr.rs index 69c9cb37dcf..7b62e7b0620 100644 --- a/src/libcore/slice/memchr.rs +++ b/src/libcore/slice/memchr.rs @@ -39,21 +39,10 @@ fn repeat_byte(b: u8) -> usize { (b as usize) << 8 | b as usize } -#[cfg(target_pointer_width = "32")] +#[cfg(not(target_pointer_width = "16"))] #[inline] fn repeat_byte(b: u8) -> usize { - let mut rep = (b as usize) << 8 | b as usize; - rep = rep << 16 | rep; - rep -} - -#[cfg(target_pointer_width = "64")] -#[inline] -fn repeat_byte(b: u8) -> usize { - let mut rep = (b as usize) << 8 | b as usize; - rep = rep << 16 | rep; - rep = rep << 32 | rep; - rep + (b as usize) * (::usize::MAX / 255) } /// Return the first index matching the byte `x` in `text`. @@ -146,85 +135,3 @@ pub fn memrchr(x: u8, text: &[u8]) -> Option<usize> { // find the byte before the point the body loop stopped text[..offset].iter().rposition(|elt| *elt == x) } - -// test fallback implementations on all platforms -#[test] -fn matches_one() { - assert_eq!(Some(0), memchr(b'a', b"a")); -} - -#[test] -fn matches_begin() { - assert_eq!(Some(0), memchr(b'a', b"aaaa")); -} - -#[test] -fn matches_end() { - assert_eq!(Some(4), memchr(b'z', b"aaaaz")); -} - -#[test] -fn matches_nul() { - assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00")); -} - -#[test] -fn matches_past_nul() { - assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z")); -} - -#[test] -fn no_match_empty() { - assert_eq!(None, memchr(b'a', b"")); -} - -#[test] -fn no_match() { - assert_eq!(None, memchr(b'a', b"xyz")); -} - -#[test] -fn matches_one_reversed() { - assert_eq!(Some(0), memrchr(b'a', b"a")); -} - -#[test] -fn matches_begin_reversed() { - assert_eq!(Some(3), memrchr(b'a', b"aaaa")); -} - -#[test] -fn matches_end_reversed() { - assert_eq!(Some(0), memrchr(b'z', b"zaaaa")); -} - -#[test] -fn matches_nul_reversed() { - assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00")); -} - -#[test] -fn matches_past_nul_reversed() { - assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa")); -} - -#[test] -fn no_match_empty_reversed() { - assert_eq!(None, memrchr(b'a', b"")); -} - -#[test] -fn no_match_reversed() { - assert_eq!(None, memrchr(b'a', b"xyz")); -} - -#[test] -fn each_alignment_reversed() { - let mut data = [1u8; 64]; - let needle = 2; - let pos = 40; - data[pos] = needle; - for start in 0..16 { - assert_eq!(Some(pos - start), memrchr(needle, &data[start..])); - } -} diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index cc42acd77ae..83e8a6e4b68 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -880,7 +880,6 @@ macro_rules! slice_core_methods { () => { #[inline] pub fn split_last(&self) -> Option<(&T, &[T])> { SliceExt::split_last(self) - } /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty. diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 111cf58c2c6..28dac02654b 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -44,9 +44,10 @@ #![feature(exact_chunks)] #![cfg_attr(stage0, feature(atomic_nand))] #![feature(reverse_bits)] -#![feature(inclusive_range_fields)] +#![feature(inclusive_range_methods)] #![feature(iterator_find_map)] #![feature(inner_deref)] +#![feature(slice_internals)] extern crate core; extern crate test; @@ -75,4 +76,5 @@ mod result; mod slice; mod str; mod str_lossy; +mod time; mod tuple; diff --git a/src/libcore/tests/num/uint_macros.rs b/src/libcore/tests/num/uint_macros.rs index ca6906f7310..257f6ea20d4 100644 --- a/src/libcore/tests/num/uint_macros.rs +++ b/src/libcore/tests/num/uint_macros.rs @@ -98,6 +98,7 @@ mod tests { } #[test] + #[cfg(not(stage0))] fn test_reverse_bits() { assert_eq!(A.reverse_bits().reverse_bits(), A); assert_eq!(B.reverse_bits().reverse_bits(), B); diff --git a/src/libcore/tests/ops.rs b/src/libcore/tests/ops.rs index bed08f86d72..d66193b1687 100644 --- a/src/libcore/tests/ops.rs +++ b/src/libcore/tests/ops.rs @@ -50,21 +50,21 @@ fn test_full_range() { #[test] fn test_range_inclusive() { - let mut r = RangeInclusive { start: 1i8, end: 2 }; + let mut r = RangeInclusive::new(1i8, 2); assert_eq!(r.next(), Some(1)); assert_eq!(r.next(), Some(2)); assert_eq!(r.next(), None); - r = RangeInclusive { start: 127i8, end: 127 }; + r = RangeInclusive::new(127i8, 127); assert_eq!(r.next(), Some(127)); assert_eq!(r.next(), None); - r = RangeInclusive { start: -128i8, end: -128 }; + r = RangeInclusive::new(-128i8, -128); assert_eq!(r.next_back(), Some(-128)); assert_eq!(r.next_back(), None); // degenerate - r = RangeInclusive { start: 1, end: -1 }; + r = RangeInclusive::new(1, -1); assert_eq!(r.size_hint(), (0, Some(0))); assert_eq!(r.next(), None); } diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs index 53fdfa06827..c81e5e97cbb 100644 --- a/src/libcore/tests/slice.rs +++ b/src/libcore/tests/slice.rs @@ -550,3 +550,89 @@ fn sort_unstable() { v.sort_unstable(); assert!(v == [0xDEADBEEF]); } + +pub mod memchr { + use core::slice::memchr::{memchr, memrchr}; + + // test fallback implementations on all platforms + #[test] + fn matches_one() { + assert_eq!(Some(0), memchr(b'a', b"a")); + } + + #[test] + fn matches_begin() { + assert_eq!(Some(0), memchr(b'a', b"aaaa")); + } + + #[test] + fn matches_end() { + assert_eq!(Some(4), memchr(b'z', b"aaaaz")); + } + + #[test] + fn matches_nul() { + assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00")); + } + + #[test] + fn matches_past_nul() { + assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z")); + } + + #[test] + fn no_match_empty() { + assert_eq!(None, memchr(b'a', b"")); + } + + #[test] + fn no_match() { + assert_eq!(None, memchr(b'a', b"xyz")); + } + + #[test] + fn matches_one_reversed() { + assert_eq!(Some(0), memrchr(b'a', b"a")); + } + + #[test] + fn matches_begin_reversed() { + assert_eq!(Some(3), memrchr(b'a', b"aaaa")); + } + + #[test] + fn matches_end_reversed() { + assert_eq!(Some(0), memrchr(b'z', b"zaaaa")); + } + + #[test] + fn matches_nul_reversed() { + assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00")); + } + + #[test] + fn matches_past_nul_reversed() { + assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa")); + } + + #[test] + fn no_match_empty_reversed() { + assert_eq!(None, memrchr(b'a', b"")); + } + + #[test] + fn no_match_reversed() { + assert_eq!(None, memrchr(b'a', b"xyz")); + } + + #[test] + fn each_alignment_reversed() { + let mut data = [1u8; 64]; + let needle = 2; + let pos = 40; + data[pos] = needle; + for start in 0..16 { + assert_eq!(Some(pos - start), memrchr(needle, &data[start..])); + } + } +} diff --git a/src/libcore/tests/time.rs b/src/libcore/tests/time.rs new file mode 100644 index 00000000000..042c523f25f --- /dev/null +++ b/src/libcore/tests/time.rs @@ -0,0 +1,124 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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 core::time::Duration; + +#[test] +fn creation() { + assert!(Duration::from_secs(1) != Duration::from_secs(0)); + assert_eq!(Duration::from_secs(1) + Duration::from_secs(2), + Duration::from_secs(3)); + assert_eq!(Duration::from_millis(10) + Duration::from_secs(4), + Duration::new(4, 10 * 1_000_000)); + assert_eq!(Duration::from_millis(4000), Duration::new(4, 0)); +} + +#[test] +fn secs() { + assert_eq!(Duration::new(0, 0).as_secs(), 0); + assert_eq!(Duration::from_secs(1).as_secs(), 1); + assert_eq!(Duration::from_millis(999).as_secs(), 0); + assert_eq!(Duration::from_millis(1001).as_secs(), 1); +} + +#[test] +fn nanos() { + assert_eq!(Duration::new(0, 0).subsec_nanos(), 0); + assert_eq!(Duration::new(0, 5).subsec_nanos(), 5); + assert_eq!(Duration::new(0, 1_000_000_001).subsec_nanos(), 1); + assert_eq!(Duration::from_secs(1).subsec_nanos(), 0); + assert_eq!(Duration::from_millis(999).subsec_nanos(), 999 * 1_000_000); + assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1 * 1_000_000); +} + +#[test] +fn add() { + assert_eq!(Duration::new(0, 0) + Duration::new(0, 1), + Duration::new(0, 1)); + assert_eq!(Duration::new(0, 500_000_000) + Duration::new(0, 500_000_001), + Duration::new(1, 1)); +} + +#[test] +fn checked_add() { + assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), + Some(Duration::new(0, 1))); + assert_eq!(Duration::new(0, 500_000_000).checked_add(Duration::new(0, 500_000_001)), + Some(Duration::new(1, 1))); + assert_eq!(Duration::new(1, 0).checked_add(Duration::new(::core::u64::MAX, 0)), None); +} + +#[test] +fn sub() { + assert_eq!(Duration::new(0, 1) - Duration::new(0, 0), + Duration::new(0, 1)); + assert_eq!(Duration::new(0, 500_000_001) - Duration::new(0, 500_000_000), + Duration::new(0, 1)); + assert_eq!(Duration::new(1, 0) - Duration::new(0, 1), + Duration::new(0, 999_999_999)); +} + +#[test] +fn checked_sub() { + let zero = Duration::new(0, 0); + let one_nano = Duration::new(0, 1); + let one_sec = Duration::new(1, 0); + assert_eq!(one_nano.checked_sub(zero), Some(Duration::new(0, 1))); + assert_eq!(one_sec.checked_sub(one_nano), + Some(Duration::new(0, 999_999_999))); + assert_eq!(zero.checked_sub(one_nano), None); + assert_eq!(zero.checked_sub(one_sec), None); +} + +#[test] +#[should_panic] +fn sub_bad1() { + let _ = Duration::new(0, 0) - Duration::new(0, 1); +} + +#[test] +#[should_panic] +fn sub_bad2() { + let _ = Duration::new(0, 0) - Duration::new(1, 0); +} + +#[test] +fn mul() { + assert_eq!(Duration::new(0, 1) * 2, Duration::new(0, 2)); + assert_eq!(Duration::new(1, 1) * 3, Duration::new(3, 3)); + assert_eq!(Duration::new(0, 500_000_001) * 4, Duration::new(2, 4)); + assert_eq!(Duration::new(0, 500_000_001) * 4000, + Duration::new(2000, 4000)); +} + +#[test] +fn checked_mul() { + assert_eq!(Duration::new(0, 1).checked_mul(2), Some(Duration::new(0, 2))); + assert_eq!(Duration::new(1, 1).checked_mul(3), Some(Duration::new(3, 3))); + assert_eq!(Duration::new(0, 500_000_001).checked_mul(4), Some(Duration::new(2, 4))); + assert_eq!(Duration::new(0, 500_000_001).checked_mul(4000), + Some(Duration::new(2000, 4000))); + assert_eq!(Duration::new(::core::u64::MAX - 1, 0).checked_mul(2), None); +} + +#[test] +fn div() { + assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0)); + assert_eq!(Duration::new(1, 1) / 3, Duration::new(0, 333_333_333)); + assert_eq!(Duration::new(99, 999_999_000) / 100, + Duration::new(0, 999_999_990)); +} + +#[test] +fn checked_div() { + assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0))); + assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000))); + assert_eq!(Duration::new(2, 0).checked_div(0), None); +} diff --git a/src/libcore/time.rs b/src/libcore/time.rs index e22fe450bb1..8e8b1691c65 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -481,119 +481,3 @@ impl<'a> Sum<&'a Duration> for Duration { iter.fold(Duration::new(0, 0), |a, b| a + *b) } } - -#[cfg(test)] -mod tests { - use super::Duration; - - #[test] - fn creation() { - assert!(Duration::from_secs(1) != Duration::from_secs(0)); - assert_eq!(Duration::from_secs(1) + Duration::from_secs(2), - Duration::from_secs(3)); - assert_eq!(Duration::from_millis(10) + Duration::from_secs(4), - Duration::new(4, 10 * 1_000_000)); - assert_eq!(Duration::from_millis(4000), Duration::new(4, 0)); - } - - #[test] - fn secs() { - assert_eq!(Duration::new(0, 0).as_secs(), 0); - assert_eq!(Duration::from_secs(1).as_secs(), 1); - assert_eq!(Duration::from_millis(999).as_secs(), 0); - assert_eq!(Duration::from_millis(1001).as_secs(), 1); - } - - #[test] - fn nanos() { - assert_eq!(Duration::new(0, 0).subsec_nanos(), 0); - assert_eq!(Duration::new(0, 5).subsec_nanos(), 5); - assert_eq!(Duration::new(0, 1_000_000_001).subsec_nanos(), 1); - assert_eq!(Duration::from_secs(1).subsec_nanos(), 0); - assert_eq!(Duration::from_millis(999).subsec_nanos(), 999 * 1_000_000); - assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1 * 1_000_000); - } - - #[test] - fn add() { - assert_eq!(Duration::new(0, 0) + Duration::new(0, 1), - Duration::new(0, 1)); - assert_eq!(Duration::new(0, 500_000_000) + Duration::new(0, 500_000_001), - Duration::new(1, 1)); - } - - #[test] - fn checked_add() { - assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), - Some(Duration::new(0, 1))); - assert_eq!(Duration::new(0, 500_000_000).checked_add(Duration::new(0, 500_000_001)), - Some(Duration::new(1, 1))); - assert_eq!(Duration::new(1, 0).checked_add(Duration::new(::u64::MAX, 0)), None); - } - - #[test] - fn sub() { - assert_eq!(Duration::new(0, 1) - Duration::new(0, 0), - Duration::new(0, 1)); - assert_eq!(Duration::new(0, 500_000_001) - Duration::new(0, 500_000_000), - Duration::new(0, 1)); - assert_eq!(Duration::new(1, 0) - Duration::new(0, 1), - Duration::new(0, 999_999_999)); - } - - #[test] - fn checked_sub() { - let zero = Duration::new(0, 0); - let one_nano = Duration::new(0, 1); - let one_sec = Duration::new(1, 0); - assert_eq!(one_nano.checked_sub(zero), Some(Duration::new(0, 1))); - assert_eq!(one_sec.checked_sub(one_nano), - Some(Duration::new(0, 999_999_999))); - assert_eq!(zero.checked_sub(one_nano), None); - assert_eq!(zero.checked_sub(one_sec), None); - } - - #[test] #[should_panic] - fn sub_bad1() { - Duration::new(0, 0) - Duration::new(0, 1); - } - - #[test] #[should_panic] - fn sub_bad2() { - Duration::new(0, 0) - Duration::new(1, 0); - } - - #[test] - fn mul() { - assert_eq!(Duration::new(0, 1) * 2, Duration::new(0, 2)); - assert_eq!(Duration::new(1, 1) * 3, Duration::new(3, 3)); - assert_eq!(Duration::new(0, 500_000_001) * 4, Duration::new(2, 4)); - assert_eq!(Duration::new(0, 500_000_001) * 4000, - Duration::new(2000, 4000)); - } - - #[test] - fn checked_mul() { - assert_eq!(Duration::new(0, 1).checked_mul(2), Some(Duration::new(0, 2))); - assert_eq!(Duration::new(1, 1).checked_mul(3), Some(Duration::new(3, 3))); - assert_eq!(Duration::new(0, 500_000_001).checked_mul(4), Some(Duration::new(2, 4))); - assert_eq!(Duration::new(0, 500_000_001).checked_mul(4000), - Some(Duration::new(2000, 4000))); - assert_eq!(Duration::new(::u64::MAX - 1, 0).checked_mul(2), None); - } - - #[test] - fn div() { - assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0)); - assert_eq!(Duration::new(1, 1) / 3, Duration::new(0, 333_333_333)); - assert_eq!(Duration::new(99, 999_999_000) / 100, - Duration::new(0, 999_999_990)); - } - - #[test] - fn checked_div() { - assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0))); - assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000))); - assert_eq!(Duration::new(2, 0).checked_div(0), None); - } -} diff --git a/src/libcore/unicode/bool_trie.rs b/src/libcore/unicode/bool_trie.rs index 3e45b08f399..0e6437fded5 100644 --- a/src/libcore/unicode/bool_trie.rs +++ b/src/libcore/unicode/bool_trie.rs @@ -42,15 +42,15 @@ pub struct BoolTrie { } impl BoolTrie { pub fn lookup(&self, c: char) -> bool { - let c = c as usize; + let c = c as u32; if c < 0x800 { - trie_range_leaf(c, self.r1[c >> 6]) + trie_range_leaf(c, self.r1[(c >> 6) as usize]) } else if c < 0x10000 { - let child = self.r2[(c >> 6) - 0x20]; + let child = self.r2[(c >> 6) as usize - 0x20]; trie_range_leaf(c, self.r3[child as usize]) } else { - let child = self.r4[(c >> 12) - 0x10]; - let leaf = self.r5[((child as usize) << 6) + ((c >> 6) & 0x3f)]; + let child = self.r4[(c >> 12) as usize - 0x10]; + let leaf = self.r5[((child as usize) << 6) + ((c >> 6) as usize & 0x3f)]; trie_range_leaf(c, self.r6[leaf as usize]) } } @@ -63,14 +63,14 @@ pub struct SmallBoolTrie { impl SmallBoolTrie { pub fn lookup(&self, c: char) -> bool { - let c = c as usize; - match self.r1.get(c >> 6) { + let c = c as u32; + match self.r1.get((c >> 6) as usize) { Some(&child) => trie_range_leaf(c, self.r2[child as usize]), None => false, } } } -fn trie_range_leaf(c: usize, bitmap_chunk: u64) -> bool { +fn trie_range_leaf(c: u32, bitmap_chunk: u64) -> bool { ((bitmap_chunk >> (c & 63)) & 1) != 0 } diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index e171216523a..8451e5987e9 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -74,6 +74,11 @@ use syntax_pos::hygiene::Mark; #[derive(Clone)] pub struct TokenStream(tokenstream::TokenStream); +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Send for TokenStream {} +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Sync for TokenStream {} + /// Error returned from `TokenStream::from_str`. #[stable(feature = "proc_macro_lib", since = "1.15.0")] #[derive(Debug)] @@ -81,6 +86,11 @@ pub struct LexError { _inner: (), } +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Send for LexError {} +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Sync for LexError {} + impl TokenStream { /// Returns an empty `TokenStream`. #[unstable(feature = "proc_macro", issue = "38356")] @@ -231,6 +241,11 @@ pub fn quote_span(span: Span) -> TokenStream { #[derive(Copy, Clone)] pub struct Span(syntax_pos::Span); +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Send for Span {} +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Sync for Span {} + macro_rules! diagnostic_method { ($name:ident, $level:expr) => ( /// Create a new `Diagnostic` with the given `message` at the span @@ -270,7 +285,7 @@ impl Span { /// `self` was generated from, if any. #[unstable(feature = "proc_macro", issue = "38356")] pub fn parent(&self) -> Option<Span> { - self.0.ctxt().outer().expn_info().map(|i| Span(i.call_site)) + self.0.parent().map(Span) } /// The span for the origin source code that `self` was generated from. If @@ -363,6 +378,11 @@ pub struct LineColumn { pub column: usize } +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Send for LineColumn {} +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Sync for LineColumn {} + /// The source file of a given `Span`. #[unstable(feature = "proc_macro", issue = "38356")] #[derive(Clone)] @@ -393,7 +413,7 @@ impl SourceFile { /// Returns `true` if this source file is a real source file, and not generated by an external /// macro's expansion. - # [unstable(feature = "proc_macro", issue = "38356")] + #[unstable(feature = "proc_macro", issue = "38356")] pub fn is_real(&self) -> bool { // This is a hack until intercrate spans are implemented and we can have real source files // for spans generated in external macros. @@ -450,6 +470,11 @@ pub enum TokenTree { Literal(Literal), } +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Send for TokenTree {} +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Sync for TokenTree {} + impl TokenTree { /// Returns the span of this token, accessing the `span` method of each of /// the internal tokens. @@ -546,6 +571,11 @@ pub struct Group { span: Span, } +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Send for Group {} +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Sync for Group {} + /// Describes how a sequence of token trees is delimited. #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[unstable(feature = "proc_macro", issue = "38356")] @@ -628,6 +658,11 @@ pub struct Op { span: Span, } +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Send for Op {} +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Sync for Op {} + /// Whether an `Op` is either followed immediately by another `Op` or followed by whitespace. #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[unstable(feature = "proc_macro", issue = "38356")] @@ -694,6 +729,11 @@ pub struct Term { span: Span, } +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Send for Term {} +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Sync for Term {} + impl Term { /// Creates a new `Term` with the given `string` as well as the specified /// `span`. @@ -752,6 +792,11 @@ pub struct Literal { span: Span, } +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Send for Literal {} +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Sync for Literal {} + macro_rules! suffixed_int_literals { ($($name:ident => $kind:ident,)*) => ($( /// Creates a new suffixed integer literal with the specified value. diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index 357ebb89fb6..af108188ce0 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -19,7 +19,6 @@ log = { version = "0.4", features = ["release_max_level_info", "std"] } proc_macro = { path = "../libproc_macro" } rustc_apfloat = { path = "../librustc_apfloat" } rustc_target = { path = "../librustc_target" } -rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } serialize = { path = "../libserialize" } diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 18bf54297af..e4f432e7caf 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -70,7 +70,8 @@ use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; use std::fmt; use std::hash::Hash; use syntax_pos::symbol::InternedString; -use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal}; +use traits::query::{CanonicalProjectionGoal, + CanonicalTyGoal, CanonicalPredicateGoal}; use ty::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty}; use ty::subst::Substs; @@ -643,6 +644,7 @@ define_dep_nodes!( <'tcx> [] NormalizeProjectionTy(CanonicalProjectionGoal<'tcx>), [] NormalizeTyAfterErasingRegions(ParamEnvAnd<'tcx, Ty<'tcx>>), [] DropckOutlives(CanonicalTyGoal<'tcx>), + [] EvaluateObligation(CanonicalPredicateGoal<'tcx>), [] SubstituteNormalizeAndTestPredicates { key: (DefId, &'tcx Substs<'tcx>) }, diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index 956cd17f38f..24a1256c9d3 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -30,6 +30,8 @@ enum Target { ForeignMod, Expression, Statement, + Closure, + Static, Other, } @@ -42,6 +44,7 @@ impl Target { hir::ItemEnum(..) => Target::Enum, hir::ItemConst(..) => Target::Const, hir::ItemForeignMod(..) => Target::ForeignMod, + hir::ItemStatic(..) => Target::Static, _ => Target::Other, } } @@ -101,16 +104,17 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { } self.check_repr(item, target); + self.check_used(item, target); } - /// Check if an `#[inline]` is applied to a function. + /// Check if an `#[inline]` is applied to a function or a closure. fn check_inline(&self, attr: &hir::Attribute, span: &Span, target: Target) { - if target != Target::Fn { + if target != Target::Fn && target != Target::Closure { struct_span_err!(self.tcx.sess, attr.span, E0518, - "attribute should be applied to function") - .span_label(*span, "not a function") + "attribute should be applied to function or closure") + .span_label(*span, "not a function or closure") .emit(); } } @@ -149,10 +153,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { // ``` let hints: Vec<_> = item.attrs .iter() - .filter(|attr| match attr.name() { - Some(name) => name == "repr", - None => false, - }) + .filter(|attr| attr.name() == "repr") .filter_map(|attr| attr.meta_item_list()) .flat_map(|hints| hints) .collect(); @@ -286,9 +287,13 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { } fn check_expr_attributes(&self, expr: &hir::Expr) { + let target = match expr.node { + hir::ExprClosure(..) => Target::Closure, + _ => Target::Expression, + }; for attr in expr.attrs.iter() { if attr.check_name("inline") { - self.check_inline(attr, &expr.span, Target::Expression); + self.check_inline(attr, &expr.span, target); } if attr.check_name("repr") { self.emit_repr_error( @@ -300,6 +305,15 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { } } } + + fn check_used(&self, item: &hir::Item, target: Target) { + for attr in &item.attrs { + if attr.name() == "used" && target != Target::Static { + self.tcx.sess + .span_err(attr.span, "attribute must be applied to a `static` variable"); + } + } + } } impl<'a, 'tcx> Visitor<'tcx> for CheckAttrVisitor<'a, 'tcx> { diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 62f3f9f4486..3e5dcee113a 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -404,7 +404,7 @@ pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) { // Intentionally visiting the expr first - the initialization expr // dominates the local's definition. walk_list!(visitor, visit_expr, &local.init); - + walk_list!(visitor, visit_attribute, local.attrs.iter()); visitor.visit_id(local.id); visitor.visit_pat(&local.pat); walk_list!(visitor, visit_ty, &local.ty); @@ -731,6 +731,7 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Generi visitor.visit_name(ty_param.span, ty_param.name); walk_list!(visitor, visit_ty_param_bound, &ty_param.bounds); walk_list!(visitor, visit_ty, &ty_param.default); + walk_list!(visitor, visit_attribute, ty_param.attrs.iter()); } } } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 4023521147e..51f0c1d7047 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -655,7 +655,7 @@ impl<'a> LoweringContext<'a> { self.resolver.definitions().create_def_with_parent( parent_id.index, def_node_id, - DefPathData::LifetimeDef(str_name), + DefPathData::LifetimeDef(str_name.as_interned_str()), DefIndexAddressSpace::High, Mark::root(), span, @@ -1302,7 +1302,7 @@ impl<'a> LoweringContext<'a> { self.context.resolver.definitions().create_def_with_parent( self.parent, def_node_id, - DefPathData::LifetimeDef(name.name().as_str()), + DefPathData::LifetimeDef(name.name().as_interned_str()), DefIndexAddressSpace::High, Mark::root(), lifetime.span, @@ -3119,6 +3119,20 @@ impl<'a> LoweringContext<'a> { ExprKind::Index(ref el, ref er) => { hir::ExprIndex(P(self.lower_expr(el)), P(self.lower_expr(er))) } + // Desugar `<start>..=<end>` to `std::ops::RangeInclusive::new(<start>, <end>)` + ExprKind::Range(Some(ref e1), Some(ref e2), RangeLimits::Closed) => { + // FIXME: Use e.span directly after RangeInclusive::new() is stabilized in stage0. + let span = self.allow_internal_unstable(CompilerDesugaringKind::DotFill, e.span); + let id = self.next_id(); + let e1 = self.lower_expr(e1); + let e2 = self.lower_expr(e2); + let ty_path = P(self.std_path(span, &["ops", "RangeInclusive"], false)); + let ty = self.ty_path(id, span, hir::QPath::Resolved(None, ty_path)); + let new_seg = P(hir::PathSegment::from_name(Symbol::intern("new"))); + let new_path = hir::QPath::TypeRelative(ty, new_seg); + let new = P(self.expr(span, hir::ExprPath(new_path), ThinVec::new())); + hir::ExprCall(new, hir_vec![e1, e2]) + } ExprKind::Range(ref e1, ref e2, lims) => { use syntax::ast::RangeLimits::*; @@ -3128,7 +3142,7 @@ impl<'a> LoweringContext<'a> { (&None, &Some(..), HalfOpen) => "RangeTo", (&Some(..), &Some(..), HalfOpen) => "Range", (&None, &Some(..), Closed) => "RangeToInclusive", - (&Some(..), &Some(..), Closed) => "RangeInclusive", + (&Some(..), &Some(..), Closed) => unreachable!(), (_, &None, Closed) => self.diagnostic() .span_fatal(e.span, "inclusive range with no end") .raise(), @@ -4107,15 +4121,13 @@ impl<'a> LoweringContext<'a> { } fn maybe_lint_bare_trait(&self, span: Span, id: NodeId, is_global: bool) { - if self.sess.features_untracked().dyn_trait { - self.sess.buffer_lint_with_diagnostic( - builtin::BARE_TRAIT_OBJECT, - id, - span, - "trait objects without an explicit `dyn` are deprecated", - builtin::BuiltinLintDiagnostics::BareTraitObject(span, is_global), - ) - } + self.sess.buffer_lint_with_diagnostic( + builtin::BARE_TRAIT_OBJECT, + id, + span, + "trait objects without an explicit `dyn` are deprecated", + builtin::BuiltinLintDiagnostics::BareTraitObject(span, is_global), + ) } fn wrap_in_try_constructor( diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index bfe21549e45..ebd8e623582 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -107,18 +107,18 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { // information we encapsulate into let def_data = match i.node { ItemKind::Impl(..) => DefPathData::Impl, - ItemKind::Trait(..) => DefPathData::Trait(i.ident.name.as_str()), + ItemKind::Trait(..) => DefPathData::Trait(i.ident.name.as_interned_str()), ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) | ItemKind::TraitAlias(..) | ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::Ty(..) => - DefPathData::TypeNs(i.ident.name.as_str()), + DefPathData::TypeNs(i.ident.name.as_interned_str()), ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => { return visit::walk_item(self, i); } - ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_str()), + ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_interned_str()), ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) => - DefPathData::ValueNs(i.ident.name.as_str()), - ItemKind::MacroDef(..) => DefPathData::MacroDef(i.ident.name.as_str()), + DefPathData::ValueNs(i.ident.name.as_interned_str()), + ItemKind::MacroDef(..) => DefPathData::MacroDef(i.ident.name.as_interned_str()), ItemKind::Mac(..) => return self.visit_macro_invoc(i.id, false), ItemKind::GlobalAsm(..) => DefPathData::Misc, ItemKind::Use(..) => { @@ -133,7 +133,8 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { for v in &enum_definition.variants { let variant_def_index = this.create_def(v.node.data.id(), - DefPathData::EnumVariant(v.node.ident.name.as_str()), + DefPathData::EnumVariant(v.node.ident + .name.as_interned_str()), REGULAR_SPACE, v.span); this.with_parent(variant_def_index, |this| { @@ -141,7 +142,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { let name = field.ident.map(|ident| ident.name) .unwrap_or_else(|| Symbol::intern(&index.to_string())); this.create_def(field.id, - DefPathData::Field(name.as_str()), + DefPathData::Field(name.as_interned_str()), REGULAR_SPACE, field.span); } @@ -165,7 +166,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { let name = field.ident.map(|ident| ident.name) .unwrap_or_else(|| Symbol::intern(&index.to_string())); this.create_def(field.id, - DefPathData::Field(name.as_str()), + DefPathData::Field(name.as_interned_str()), REGULAR_SPACE, field.span); } @@ -187,7 +188,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { } let def = self.create_def(foreign_item.id, - DefPathData::ValueNs(foreign_item.ident.name.as_str()), + DefPathData::ValueNs(foreign_item.ident.name.as_interned_str()), REGULAR_SPACE, foreign_item.span); @@ -201,7 +202,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { GenericParam::Lifetime(ref lifetime_def) => { self.create_def( lifetime_def.lifetime.id, - DefPathData::LifetimeDef(lifetime_def.lifetime.ident.name.as_str()), + DefPathData::LifetimeDef(lifetime_def.lifetime.ident.name.as_interned_str()), REGULAR_SPACE, lifetime_def.lifetime.ident.span ); @@ -209,7 +210,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { GenericParam::Type(ref ty_param) => { self.create_def( ty_param.id, - DefPathData::TypeParam(ty_param.ident.name.as_str()), + DefPathData::TypeParam(ty_param.ident.name.as_interned_str()), REGULAR_SPACE, ty_param.ident.span ); @@ -222,8 +223,10 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { fn visit_trait_item(&mut self, ti: &'a TraitItem) { let def_data = match ti.node { TraitItemKind::Method(..) | TraitItemKind::Const(..) => - DefPathData::ValueNs(ti.ident.name.as_str()), - TraitItemKind::Type(..) => DefPathData::AssocTypeInTrait(ti.ident.name.as_str()), + DefPathData::ValueNs(ti.ident.name.as_interned_str()), + TraitItemKind::Type(..) => { + DefPathData::AssocTypeInTrait(ti.ident.name.as_interned_str()) + }, TraitItemKind::Macro(..) => return self.visit_macro_invoc(ti.id, false), }; @@ -240,8 +243,8 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { fn visit_impl_item(&mut self, ii: &'a ImplItem) { let def_data = match ii.node { ImplItemKind::Method(..) | ImplItemKind::Const(..) => - DefPathData::ValueNs(ii.ident.name.as_str()), - ImplItemKind::Type(..) => DefPathData::AssocTypeInImpl(ii.ident.name.as_str()), + DefPathData::ValueNs(ii.ident.name.as_interned_str()), + ImplItemKind::Type(..) => DefPathData::AssocTypeInImpl(ii.ident.name.as_interned_str()), ImplItemKind::Macro(..) => return self.visit_macro_invoc(ii.id, false), }; diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index 12f146ef491..616dc22486d 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -701,7 +701,7 @@ impl DefPathData { Typeof => "{{typeof}}", }; - Symbol::intern(s).as_str() + Symbol::intern(s).as_interned_str() } pub fn to_string(&self) -> String { @@ -731,7 +731,7 @@ macro_rules! define_global_metadata_kind { definitions.create_def_with_parent( CRATE_DEF_INDEX, ast::DUMMY_NODE_ID, - DefPathData::GlobalMetaData(instance.name().as_str()), + DefPathData::GlobalMetaData(instance.name().as_interned_str()), GLOBAL_MD_ADDRESS_SPACE, Mark::root(), DUMMY_SP @@ -746,7 +746,7 @@ macro_rules! define_global_metadata_kind { let def_key = DefKey { parent: Some(CRATE_DEF_INDEX), disambiguated_data: DisambiguatedDefPathData { - data: DefPathData::GlobalMetaData(self.name().as_str()), + data: DefPathData::GlobalMetaData(self.name().as_interned_str()), disambiguator: 0, } }; diff --git a/src/librustc/ich/impls_const_math.rs b/src/librustc/ich/impls_const_math.rs deleted file mode 100644 index 5f3ff461c0c..00000000000 --- a/src/librustc/ich/impls_const_math.rs +++ /dev/null @@ -1,44 +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. - -//! This module contains `HashStable` implementations for various data types -//! from `rustc_const_math` in no particular order. - -impl_stable_hash_for!(struct ::rustc_const_math::ConstFloat { - ty, - bits -}); - -impl_stable_hash_for!(enum ::rustc_const_math::ConstMathErr { - NotInRange, - CmpBetweenUnequalTypes, - UnequalTypes(op), - Overflow(op), - ShiftNegative, - DivisionByZero, - RemainderByZero, - UnsignedNegation, - ULitOutOfRange(int_ty), - LitOutOfRange(int_ty) -}); - -impl_stable_hash_for!(enum ::rustc_const_math::Op { - Add, - Sub, - Mul, - Div, - Rem, - Shr, - Shl, - Neg, - BitAnd, - BitOr, - BitXor -}); diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index c73f171806e..33f43e53394 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -227,27 +227,6 @@ for mir::TerminatorKind<'gcx> { } } -impl<'a, 'gcx> HashStable<StableHashingContext<'a>> -for mir::AssertMessage<'gcx> { - fn hash_stable<W: StableHasherResult>(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher<W>) { - mem::discriminant(self).hash_stable(hcx, hasher); - - match *self { - mir::AssertMessage::BoundsCheck { ref len, ref index } => { - len.hash_stable(hcx, hasher); - index.hash_stable(hcx, hasher); - } - mir::AssertMessage::Math(ref const_math_err) => { - const_math_err.hash_stable(hcx, hasher); - } - mir::AssertMessage::GeneratorResumedAfterReturn => (), - mir::AssertMessage::GeneratorResumedAfterPanic => (), - } - } -} - impl_stable_hash_for!(struct mir::Statement<'tcx> { source_info, kind }); impl<'a, 'gcx> HashStable<StableHashingContext<'a>> @@ -563,6 +542,11 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::Literal<'gcx> { impl_stable_hash_for!(struct mir::Location { block, statement_index }); +impl_stable_hash_for!(struct mir::BorrowCheckResult<'tcx> { + closure_requirements, + used_mut_upvars +}); + impl_stable_hash_for!(struct mir::ClosureRegionRequirements<'tcx> { num_external_vids, outlives_requirements diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index d7e16ab3620..1cf9b7bf478 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -19,7 +19,7 @@ use std::mem; use syntax::ast; use syntax::feature_gate; use syntax::parse::token; -use syntax::symbol::InternedString; +use syntax::symbol::{InternedString, LocalInternedString}; use syntax::tokenstream; use syntax_pos::FileMap; @@ -34,8 +34,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for InternedString { fn hash_stable<W: StableHasherResult>(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher<W>) { - let s: &str = &**self; - s.hash_stable(hcx, hasher); + self.with(|s| s.hash_stable(hcx, hasher)) } } @@ -50,6 +49,27 @@ impl<'a> ToStableHashKey<StableHashingContext<'a>> for InternedString { } } +impl<'a> HashStable<StableHashingContext<'a>> for LocalInternedString { + #[inline] + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher<W>) { + let s: &str = &**self; + s.hash_stable(hcx, hasher); + } +} + +impl<'a> ToStableHashKey<StableHashingContext<'a>> for LocalInternedString { + type KeyType = LocalInternedString; + + #[inline] + fn to_stable_hash_key(&self, + _: &StableHashingContext<'a>) + -> LocalInternedString { + self.clone() + } +} + impl<'a> HashStable<StableHashingContext<'a>> for ast::Name { #[inline] fn hash_stable<W: StableHasherResult>(&self, @@ -66,7 +86,7 @@ impl<'a> ToStableHashKey<StableHashingContext<'a>> for ast::Name { fn to_stable_hash_key(&self, _: &StableHashingContext<'a>) -> InternedString { - self.as_str() + self.as_interned_str() } } @@ -179,8 +199,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for [ast::Attribute] { let filtered: AccumulateVec<[&ast::Attribute; 8]> = self .iter() .filter(|attr| { - !attr.is_sugared_doc && - attr.name().map(|name| !hcx.is_ignored_attr(name)).unwrap_or(true) + !attr.is_sugared_doc && !hcx.is_ignored_attr(attr.name()) }) .collect(); @@ -191,12 +210,23 @@ impl<'a> HashStable<StableHashingContext<'a>> for [ast::Attribute] { } } +impl<'a> HashStable<StableHashingContext<'a>> for ast::Path { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher<W>) { + self.segments.len().hash_stable(hcx, hasher); + for segment in &self.segments { + segment.ident.name.hash_stable(hcx, hasher); + } + } +} + impl<'a> HashStable<StableHashingContext<'a>> for ast::Attribute { fn hash_stable<W: StableHasherResult>(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher<W>) { // Make sure that these have been filtered out. - debug_assert!(self.name().map(|name| !hcx.is_ignored_attr(name)).unwrap_or(true)); + debug_assert!(!hcx.is_ignored_attr(self.name())); debug_assert!(!self.is_sugared_doc); let ast::Attribute { @@ -209,10 +239,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for ast::Attribute { } = *self; style.hash_stable(hcx, hasher); - path.segments.len().hash_stable(hcx, hasher); - for segment in &path.segments { - segment.ident.name.hash_stable(hcx, hasher); - } + path.hash_stable(hcx, hasher); for tt in tokens.trees() { tt.hash_stable(hcx, hasher); } diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 5ab8d6eb7b3..a40d8e09277 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -505,9 +505,6 @@ for ::middle::const_val::ErrKind<'gcx> { len.hash_stable(hcx, hasher); index.hash_stable(hcx, hasher); } - Math(ref const_math_err) => { - const_math_err.hash_stable(hcx, hasher); - } LayoutError(ref layout_error) => { layout_error.hash_stable(hcx, hasher); } @@ -528,16 +525,26 @@ impl_stable_hash_for!(struct ty::GenericPredicates<'tcx> { predicates }); + impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for ::mir::interpret::EvalError<'gcx> { fn hash_stable<W: StableHasherResult>(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher<W>) { + self.kind.hash_stable(hcx, hasher) + } +} + +impl<'a, 'gcx, O: HashStable<StableHashingContext<'a>>> HashStable<StableHashingContext<'a>> +for ::mir::interpret::EvalErrorKind<'gcx, O> { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher<W>) { use mir::interpret::EvalErrorKind::*; - mem::discriminant(&self.kind).hash_stable(hcx, hasher); + mem::discriminant(&self).hash_stable(hcx, hasher); - match self.kind { + match *self { DanglingPointerDeref | DoubleFree | InvalidMemoryAccess | @@ -568,8 +575,12 @@ for ::mir::interpret::EvalError<'gcx> { TypeckError | DerefFunctionPointer | ExecuteMemory | - ReferencedConstant | - OverflowingMath => {} + OverflowNeg | + RemainderByZero | + DivisionByZero | + GeneratorResumedAfterReturn | + GeneratorResumedAfterPanic | + ReferencedConstant => {} MachineError(ref err) => err.hash_stable(hcx, hasher), FunctionPointerTyMismatch(a, b) => { a.hash_stable(hcx, hasher); @@ -588,14 +599,9 @@ for ::mir::interpret::EvalError<'gcx> { }, InvalidBoolOp(bop) => bop.hash_stable(hcx, hasher), Unimplemented(ref s) => s.hash_stable(hcx, hasher), - ArrayIndexOutOfBounds(sp, a, b) => { - sp.hash_stable(hcx, hasher); - a.hash_stable(hcx, hasher); - b.hash_stable(hcx, hasher) - }, - Math(sp, ref err) => { - sp.hash_stable(hcx, hasher); - err.hash_stable(hcx, hasher) + BoundsCheck { ref len, ref index } => { + len.hash_stable(hcx, hasher); + index.hash_stable(hcx, hasher) }, Intrinsic(ref s) => s.hash_stable(hcx, hasher), InvalidChar(c) => c.hash_stable(hcx, hasher), @@ -668,6 +674,7 @@ for ::mir::interpret::EvalError<'gcx> { Layout(lay) => lay.hash_stable(hcx, hasher), HeapAllocNonPowerOfTwoAlignment(n) => n.hash_stable(hcx, hasher), PathNotFound(ref v) => v.hash_stable(hcx, hasher), + Overflow(op) => op.hash_stable(hcx, hasher), } } } diff --git a/src/librustc/ich/mod.rs b/src/librustc/ich/mod.rs index 1b77a2e7c82..a0c6bbbb239 100644 --- a/src/librustc/ich/mod.rs +++ b/src/librustc/ich/mod.rs @@ -18,7 +18,6 @@ mod fingerprint; mod caching_codemap_view; mod hcx; -mod impls_const_math; mod impls_cstore; mod impls_hir; mod impls_mir; diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index 096aed85f55..ccba5a09cf6 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -407,7 +407,7 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, ' drop(variables); self.relate(&u, &u) } - TypeVariableValue::Unknown { .. } => { + TypeVariableValue::Unknown { universe } => { match self.ambient_variance { // Invariant: no need to make a fresh type variable. ty::Invariant => return Ok(t), @@ -424,7 +424,7 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, ' } let origin = *variables.var_origin(vid); - let new_var_id = variables.new_var(false, origin); + let new_var_id = variables.new_var(universe, false, origin); let u = self.tcx().mk_var(new_var_id); debug!("generalize: replacing original vid={:?} with new={:?}", vid, u); diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index c23836071ff..b8437e39ddc 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -19,7 +19,7 @@ use super::{CombinedSnapshot, use super::combine::CombineFields; use super::region_constraints::{TaintDirections}; -use std::collections::BTreeMap; +use rustc_data_structures::lazy_btree_map::LazyBTreeMap; use ty::{self, TyCtxt, Binder, TypeFoldable}; use ty::error::TypeError; use ty::relate::{Relate, RelateResult, TypeRelation}; @@ -62,7 +62,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { // Second, we instantiate each bound region in the supertype with a // fresh concrete region. let (b_prime, skol_map) = - self.infcx.skolemize_late_bound_regions(b, snapshot); + self.infcx.skolemize_late_bound_regions(b); debug!("a_prime={:?}", a_prime); debug!("b_prime={:?}", b_prime); @@ -114,7 +114,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { // First, we instantiate each bound region in the matcher // with a skolemized region. let ((a_match, a_value), skol_map) = - self.infcx.skolemize_late_bound_regions(a_pair, snapshot); + self.infcx.skolemize_late_bound_regions(a_pair); debug!("higher_ranked_match: a_match={:?}", a_match); debug!("higher_ranked_match: skol_map={:?}", skol_map); @@ -247,7 +247,8 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { snapshot: &CombinedSnapshot<'a, 'tcx>, debruijn: ty::DebruijnIndex, new_vars: &[ty::RegionVid], - a_map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>, + a_map: &LazyBTreeMap<ty::BoundRegion, + ty::Region<'tcx>>, r0: ty::Region<'tcx>) -> ty::Region<'tcx> { // Regions that pre-dated the LUB computation stay as they are. @@ -343,7 +344,8 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { snapshot: &CombinedSnapshot<'a, 'tcx>, debruijn: ty::DebruijnIndex, new_vars: &[ty::RegionVid], - a_map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>, + a_map: &LazyBTreeMap<ty::BoundRegion, + ty::Region<'tcx>>, a_vars: &[ty::RegionVid], b_vars: &[ty::RegionVid], r0: ty::Region<'tcx>) @@ -412,7 +414,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { fn rev_lookup<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, span: Span, - a_map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>, + a_map: &LazyBTreeMap<ty::BoundRegion, ty::Region<'tcx>>, r: ty::Region<'tcx>) -> ty::Region<'tcx> { for (a_br, a_r) in a_map { @@ -435,7 +437,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { } fn var_ids<'a, 'gcx, 'tcx>(fields: &CombineFields<'a, 'gcx, 'tcx>, - map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>) + map: &LazyBTreeMap<ty::BoundRegion, ty::Region<'tcx>>) -> Vec<ty::RegionVid> { map.iter() .map(|(_, &r)| match *r { @@ -585,14 +587,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// /// [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/trait-hrtb.html pub fn skolemize_late_bound_regions<T>(&self, - binder: &ty::Binder<T>, - snapshot: &CombinedSnapshot<'a, 'tcx>) + binder: &ty::Binder<T>) -> (T, SkolemizationMap<'tcx>) where T : TypeFoldable<'tcx> { let (result, map) = self.tcx.replace_late_bound_regions(binder, |br| { - self.borrow_region_constraints() - .push_skolemized(self.tcx, br, &snapshot.region_constraints_snapshot) + self.universe.set(self.universe().subuniverse()); + self.tcx.mk_region(ty::ReSkolemized(self.universe(), br)) }); debug!("skolemize_bound_regions(binder={:?}, result={:?}, map={:?})", @@ -777,7 +778,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { debug!("pop_skolemized({:?})", skol_map); let skol_regions: FxHashSet<_> = skol_map.values().cloned().collect(); self.borrow_region_constraints() - .pop_skolemized(self.tcx, &skol_regions, &snapshot.region_constraints_snapshot); + .pop_skolemized(self.universe(), &skol_regions, &snapshot.region_constraints_snapshot); + self.universe.set(snapshot.universe); if !skol_map.is_empty() { self.projection_cache.borrow_mut().rollback_skolemized( &snapshot.projection_cache_snapshot); diff --git a/src/librustc/infer/lexical_region_resolve/mod.rs b/src/librustc/infer/lexical_region_resolve/mod.rs index 00b2ac7449f..5984a831e6f 100644 --- a/src/librustc/infer/lexical_region_resolve/mod.rs +++ b/src/librustc/infer/lexical_region_resolve/mod.rs @@ -15,7 +15,7 @@ use infer::RegionVariableOrigin; use infer::region_constraints::Constraint; use infer::region_constraints::GenericKind; use infer::region_constraints::RegionConstraintData; -use infer::region_constraints::VarOrigins; +use infer::region_constraints::VarInfos; use infer::region_constraints::VerifyBound; use middle::free_region::RegionRelations; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; @@ -37,7 +37,7 @@ mod graphviz; /// all the variables as well as a set of errors that must be reported. pub fn resolve<'tcx>( region_rels: &RegionRelations<'_, '_, 'tcx>, - var_origins: VarOrigins, + var_infos: VarInfos, data: RegionConstraintData<'tcx>, ) -> ( LexicalRegionResolutions<'tcx>, @@ -47,7 +47,7 @@ pub fn resolve<'tcx>( let mut errors = vec![]; let mut resolver = LexicalResolver { region_rels, - var_origins, + var_infos, data, }; let values = resolver.infer_variable_values(&mut errors); @@ -103,7 +103,7 @@ type RegionGraph<'tcx> = graph::Graph<(), Constraint<'tcx>>; struct LexicalResolver<'cx, 'gcx: 'tcx, 'tcx: 'cx> { region_rels: &'cx RegionRelations<'cx, 'gcx, 'tcx>, - var_origins: VarOrigins, + var_infos: VarInfos, data: RegionConstraintData<'tcx>, } @@ -132,7 +132,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> { } fn num_vars(&self) -> usize { - self.var_origins.len() + self.var_infos.len() } /// Initially, the value for all variables is set to `'empty`, the @@ -279,7 +279,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> { (&ReVar(v_id), _) | (_, &ReVar(v_id)) => { span_bug!( - self.var_origins[v_id].span(), + self.var_infos[v_id].origin.span(), "lub_concrete_regions invoked with non-concrete \ regions: {:?}, {:?}", a, @@ -576,7 +576,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> { if !self.region_rels .is_subregion_of(lower_bound.region, upper_bound.region) { - let origin = self.var_origins[node_idx].clone(); + let origin = self.var_infos[node_idx].origin.clone(); debug!( "region inference error at {:?} for {:?}: SubSupConflict sub: {:?} \ sup: {:?}", @@ -598,7 +598,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> { } span_bug!( - self.var_origins[node_idx].span(), + self.var_infos[node_idx].origin.span(), "collect_error_for_expanding_node() could not find \ error for var {:?}, lower_bounds={:?}, \ upper_bounds={:?}", diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 40cc43c3ca6..c62e7f8d9b6 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -28,9 +28,9 @@ use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; use ty::fold::TypeFoldable; use ty::relate::RelateResult; use traits::{self, ObligationCause, PredicateObligations}; +use rustc_data_structures::lazy_btree_map::LazyBTreeMap; use rustc_data_structures::unify as ut; use std::cell::{Cell, RefCell, Ref, RefMut}; -use std::collections::BTreeMap; use std::fmt; use syntax::ast; use errors::DiagnosticBuilder; @@ -42,7 +42,7 @@ use arena::SyncDroplessArena; use self::combine::CombineFields; use self::higher_ranked::HrMatchResult; use self::region_constraints::{RegionConstraintCollector, RegionSnapshot}; -use self::region_constraints::{GenericKind, VerifyBound, RegionConstraintData, VarOrigins}; +use self::region_constraints::{GenericKind, VerifyBound, RegionConstraintData, VarInfos}; use self::lexical_region_resolve::LexicalRegionResolutions; use self::outlives::env::OutlivesEnvironment; use self::type_variable::TypeVariableOrigin; @@ -183,11 +183,22 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // obligations within. This is expected to be done 'late enough' // that all type inference variables have been bound and so forth. pub region_obligations: RefCell<Vec<(ast::NodeId, RegionObligation<'tcx>)>>, + + /// What is the innermost universe we have created? Starts out as + /// `UniverseIndex::root()` but grows from there as we enter + /// universal quantifiers. + /// + /// NB: At present, we exclude the universal quantifiers on the + /// item we are type-checking, and just consider those names as + /// part of the root universe. So this would only get incremented + /// when we enter into a higher-ranked (`for<..>`) type or trait + /// bound. + universe: Cell<ty::UniverseIndex>, } /// A map returned by `skolemize_late_bound_regions()` indicating the skolemized /// region that each late-bound region was replaced with. -pub type SkolemizationMap<'tcx> = BTreeMap<ty::BoundRegion, ty::Region<'tcx>>; +pub type SkolemizationMap<'tcx> = LazyBTreeMap<ty::BoundRegion, ty::Region<'tcx>>; /// See `error_reporting` module for more details #[derive(Clone, Debug)] @@ -455,6 +466,7 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { err_count_on_creation: tcx.sess.err_count(), in_snapshot: Cell::new(false), region_obligations: RefCell::new(vec![]), + universe: Cell::new(ty::UniverseIndex::ROOT), })) } } @@ -489,6 +501,7 @@ pub struct CombinedSnapshot<'a, 'tcx:'a> { float_snapshot: ut::Snapshot<ut::InPlace<ty::FloatVid>>, region_constraints_snapshot: RegionSnapshot, region_obligations_snapshot: usize, + universe: ty::UniverseIndex, was_in_snapshot: bool, _in_progress_tables: Option<Ref<'a, ty::TypeckTables<'tcx>>>, } @@ -618,6 +631,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { float_snapshot: self.float_unification_table.borrow_mut().snapshot(), region_constraints_snapshot: self.borrow_region_constraints().start_snapshot(), region_obligations_snapshot: self.region_obligations.borrow().len(), + universe: self.universe(), was_in_snapshot: in_snapshot, // Borrow tables "in progress" (i.e. during typeck) // to ban writes from within a snapshot to them. @@ -635,10 +649,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { float_snapshot, region_constraints_snapshot, region_obligations_snapshot, + universe, was_in_snapshot, _in_progress_tables } = snapshot; self.in_snapshot.set(was_in_snapshot); + self.universe.set(universe); self.projection_cache .borrow_mut() @@ -667,6 +683,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { float_snapshot, region_constraints_snapshot, region_obligations_snapshot: _, + universe: _, was_in_snapshot, _in_progress_tables } = snapshot; @@ -811,7 +828,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { Some(self.commit_if_ok(|snapshot| { let (ty::SubtypePredicate { a_is_expected, a, b}, skol_map) = - self.skolemize_late_bound_regions(predicate, snapshot); + self.skolemize_late_bound_regions(predicate); let cause_span = cause.span; let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?; @@ -828,7 +845,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { { self.commit_if_ok(|snapshot| { let (ty::OutlivesPredicate(r_a, r_b), skol_map) = - self.skolemize_late_bound_regions(predicate, snapshot); + self.skolemize_late_bound_regions(predicate); let origin = SubregionOrigin::from_obligation_cause(cause, || RelateRegionParamBound(cause.span)); @@ -841,7 +858,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn next_ty_var_id(&self, diverging: bool, origin: TypeVariableOrigin) -> TyVid { self.type_variables .borrow_mut() - .new_var(diverging, origin) + .new_var(self.universe(), diverging, origin) } pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { @@ -872,12 +889,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// during diagnostics / error-reporting. pub fn next_region_var(&self, origin: RegionVariableOrigin) -> ty::Region<'tcx> { - self.tcx.mk_region(ty::ReVar(self.borrow_region_constraints().new_region_var(origin))) + let region_var = self.borrow_region_constraints() + .new_region_var(self.universe(), origin); + self.tcx.mk_region(ty::ReVar(region_var)) } /// Number of region variables created so far. pub fn num_region_vars(&self) -> usize { - self.borrow_region_constraints().var_origins().len() + self.borrow_region_constraints().num_region_vars() } /// Just a convenient wrapper of `next_region_var` for using during NLL. @@ -909,7 +928,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { -> Ty<'tcx> { let ty_var_id = self.type_variables .borrow_mut() - .new_var(false, + .new_var(self.universe(), + false, TypeVariableOrigin::TypeParameterDefinition(span, def.name)); self.tcx.mk_var(ty_var_id) @@ -1004,12 +1024,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { region_context, region_map, outlives_env.free_region_map()); - let (var_origins, data) = self.region_constraints.borrow_mut() + let (var_infos, data) = self.region_constraints.borrow_mut() .take() .expect("regions already resolved") - .into_origins_and_data(); + .into_infos_and_data(); let (lexical_region_resolutions, errors) = - lexical_region_resolve::resolve(region_rels, var_origins, data); + lexical_region_resolve::resolve(region_rels, var_infos, data); let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions)); assert!(old_value.is_none()); @@ -1057,13 +1077,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// hence that `resolve_regions_and_report_errors` can never be /// called. This is used only during NLL processing to "hand off" ownership /// of the set of region vairables into the NLL region context. - pub fn take_region_var_origins(&self) -> VarOrigins { - let (var_origins, data) = self.region_constraints.borrow_mut() + pub fn take_region_var_origins(&self) -> VarInfos { + let (var_infos, data) = self.region_constraints.borrow_mut() .take() .expect("regions already resolved") - .into_origins_and_data(); + .into_infos_and_data(); assert!(data.is_empty()); - var_origins + var_infos } pub fn ty_to_string(&self, t: Ty<'tcx>) -> String { @@ -1216,7 +1236,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { span: Span, lbrct: LateBoundRegionConversionTime, value: &ty::Binder<T>) - -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>) + -> (T, LazyBTreeMap<ty::BoundRegion, ty::Region<'tcx>>) where T : TypeFoldable<'tcx> { self.tcx.replace_late_bound_regions( @@ -1356,6 +1376,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.evaluation_cache.clear(); self.projection_cache.borrow_mut().clear(); } + + fn universe(&self) -> ty::UniverseIndex { + self.universe.get() + } } impl<'a, 'gcx, 'tcx> TypeTrace<'tcx> { diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc/infer/region_constraints/mod.rs index 4113a2dd417..c388fa21371 100644 --- a/src/librustc/infer/region_constraints/mod.rs +++ b/src/librustc/infer/region_constraints/mod.rs @@ -22,18 +22,16 @@ use rustc_data_structures::unify as ut; use ty::{self, Ty, TyCtxt}; use ty::{Region, RegionVid}; use ty::ReStatic; -use ty::{BrFresh, ReLateBound, ReSkolemized, ReVar}; +use ty::{BrFresh, ReLateBound, ReVar}; use std::collections::BTreeMap; -use std::fmt; -use std::mem; -use std::u32; +use std::{cmp, fmt, mem, u32}; mod taint; pub struct RegionConstraintCollector<'tcx> { /// For each `RegionVid`, the corresponding `RegionVariableOrigin`. - var_origins: IndexVec<RegionVid, RegionVariableOrigin>, + var_infos: IndexVec<RegionVid, RegionVariableInfo>, data: RegionConstraintData<'tcx>, @@ -47,9 +45,6 @@ pub struct RegionConstraintCollector<'tcx> { /// exist). This prevents us from making many such regions. glbs: CombineMap<'tcx>, - /// Number of skolemized variables currently active. - skolemization_count: u32, - /// Global counter used during the GLB algorithm to create unique /// names for fresh bound regions bound_count: u32, @@ -76,7 +71,7 @@ pub struct RegionConstraintCollector<'tcx> { unification_table: ut::UnificationTable<ut::InPlace<ty::RegionVid>>, } -pub type VarOrigins = IndexVec<RegionVid, RegionVariableOrigin>; +pub type VarInfos = IndexVec<RegionVid, RegionVariableInfo>; /// The full set of region constraints gathered up by the collector. /// Describes constraints between the region variables and other @@ -230,10 +225,15 @@ enum CombineMapType { type CombineMap<'tcx> = FxHashMap<TwoRegions<'tcx>, RegionVid>; +#[derive(Debug, Clone, Copy)] +pub struct RegionVariableInfo { + pub origin: RegionVariableOrigin, + pub universe: ty::UniverseIndex, +} + pub struct RegionSnapshot { length: usize, region_snapshot: ut::Snapshot<ut::InPlace<ty::RegionVid>>, - skolemization_count: u32, } /// When working with skolemized regions, we often wish to find all of @@ -273,19 +273,18 @@ impl TaintDirections { impl<'tcx> RegionConstraintCollector<'tcx> { pub fn new() -> RegionConstraintCollector<'tcx> { RegionConstraintCollector { - var_origins: VarOrigins::default(), + var_infos: VarInfos::default(), data: RegionConstraintData::default(), lubs: FxHashMap(), glbs: FxHashMap(), - skolemization_count: 0, bound_count: 0, undo_log: Vec::new(), unification_table: ut::UnificationTable::new(), } } - pub fn var_origins(&self) -> &VarOrigins { - &self.var_origins + pub fn num_region_vars(&self) -> usize { + self.var_infos.len() } pub fn region_constraint_data(&self) -> &RegionConstraintData<'tcx> { @@ -295,9 +294,9 @@ impl<'tcx> RegionConstraintCollector<'tcx> { /// Once all the constraints have been gathered, extract out the final data. /// /// Not legal during a snapshot. - pub fn into_origins_and_data(self) -> (VarOrigins, RegionConstraintData<'tcx>) { + pub fn into_infos_and_data(self) -> (VarInfos, RegionConstraintData<'tcx>) { assert!(!self.in_snapshot()); - (self.var_origins, self.data) + (self.var_infos, self.data) } /// Takes (and clears) the current set of constraints. Note that @@ -319,18 +318,15 @@ impl<'tcx> RegionConstraintCollector<'tcx> { // should think carefully about whether it needs to be cleared // or updated in some way. let RegionConstraintCollector { - var_origins, + var_infos, data, lubs, glbs, - skolemization_count, bound_count: _, undo_log: _, unification_table, } = self; - assert_eq!(*skolemization_count, 0); - // Clear the tables of (lubs, glbs), so that we will create // fresh regions if we do a LUB operation. As it happens, // LUB/GLB are not performed by the MIR type-checker, which is @@ -343,7 +339,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> { // also insert `a <= b` and a `b <= a` edges, so the // `RegionConstraintData` contains the relationship here. *unification_table = ut::UnificationTable::new(); - for vid in var_origins.indices() { + for vid in var_infos.indices() { unification_table.new_key(unify_key::RegionVidKey { min_vid: vid }); } @@ -365,7 +361,6 @@ impl<'tcx> RegionConstraintCollector<'tcx> { RegionSnapshot { length, region_snapshot: self.unification_table.snapshot(), - skolemization_count: self.skolemization_count, } } @@ -373,12 +368,6 @@ impl<'tcx> RegionConstraintCollector<'tcx> { debug!("RegionConstraintCollector: commit({})", snapshot.length); assert!(self.undo_log.len() > snapshot.length); assert!(self.undo_log[snapshot.length] == OpenSnapshot); - assert!( - self.skolemization_count == snapshot.skolemization_count, - "failed to pop skolemized regions: {} now vs {} at start", - self.skolemization_count, - snapshot.skolemization_count - ); if snapshot.length == 0 { self.undo_log.truncate(0); @@ -398,7 +387,6 @@ impl<'tcx> RegionConstraintCollector<'tcx> { } let c = self.undo_log.pop().unwrap(); assert!(c == OpenSnapshot); - self.skolemization_count = snapshot.skolemization_count; self.unification_table.rollback_to(snapshot.region_snapshot); } @@ -411,8 +399,8 @@ impl<'tcx> RegionConstraintCollector<'tcx> { // nothing to do here } AddVar(vid) => { - self.var_origins.pop().unwrap(); - assert_eq!(self.var_origins.len(), vid.index() as usize); + self.var_infos.pop().unwrap(); + assert_eq!(self.var_infos.len(), vid.index() as usize); } AddConstraint(ref constraint) => { self.data.constraints.remove(constraint); @@ -433,8 +421,13 @@ impl<'tcx> RegionConstraintCollector<'tcx> { } } - pub fn new_region_var(&mut self, origin: RegionVariableOrigin) -> RegionVid { - let vid = self.var_origins.push(origin.clone()); + pub fn new_region_var(&mut self, + universe: ty::UniverseIndex, + origin: RegionVariableOrigin) -> RegionVid { + let vid = self.var_infos.push(RegionVariableInfo { + origin, + universe, + }); let u_vid = self.unification_table .new_key(unify_key::RegionVidKey { min_vid: vid }); @@ -450,44 +443,14 @@ impl<'tcx> RegionConstraintCollector<'tcx> { return vid; } - /// Returns the origin for the given variable. - pub fn var_origin(&self, vid: RegionVid) -> RegionVariableOrigin { - self.var_origins[vid].clone() + /// Returns the universe for the given variable. + pub fn var_universe(&self, vid: RegionVid) -> ty::UniverseIndex { + self.var_infos[vid].universe } - /// Creates a new skolemized region. Skolemized regions are fresh - /// regions used when performing higher-ranked computations. They - /// must be used in a very particular way and are never supposed - /// to "escape" out into error messages or the code at large. - /// - /// The idea is to always create a snapshot. Skolemized regions - /// can be created in the context of this snapshot, but before the - /// snapshot is committed or rolled back, they must be popped - /// (using `pop_skolemized_regions`), so that their numbers can be - /// recycled. Normally you don't have to think about this: you use - /// the APIs in `higher_ranked/mod.rs`, such as - /// `skolemize_late_bound_regions` and `plug_leaks`, which will - /// guide you on this path (ensure that the `SkolemizationMap` is - /// consumed and you are good). For more info on how skolemization - /// for HRTBs works, see the [rustc guide]. - /// - /// [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/trait-hrtb.html - /// - /// The `snapshot` argument to this function is not really used; - /// it's just there to make it explicit which snapshot bounds the - /// skolemized region that results. It should always be the top-most snapshot. - pub fn push_skolemized( - &mut self, - tcx: TyCtxt<'_, '_, 'tcx>, - br: ty::BoundRegion, - snapshot: &RegionSnapshot, - ) -> Region<'tcx> { - assert!(self.in_snapshot()); - assert!(self.undo_log[snapshot.length] == OpenSnapshot); - - let sc = self.skolemization_count; - self.skolemization_count = sc + 1; - tcx.mk_region(ReSkolemized(ty::SkolemizedRegionVid { index: sc }, br)) + /// Returns the origin for the given variable. + pub fn var_origin(&self, vid: RegionVid) -> RegionVariableOrigin { + self.var_infos[vid].origin } /// Removes all the edges to/from the skolemized regions that are @@ -496,7 +459,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> { /// created in that time. pub fn pop_skolemized( &mut self, - _tcx: TyCtxt<'_, '_, 'tcx>, + skolemization_count: ty::UniverseIndex, skols: &FxHashSet<ty::Region<'tcx>>, snapshot: &RegionSnapshot, ) { @@ -505,36 +468,28 @@ impl<'tcx> RegionConstraintCollector<'tcx> { assert!(self.in_snapshot()); assert!(self.undo_log[snapshot.length] == OpenSnapshot); assert!( - self.skolemization_count as usize >= skols.len(), + skolemization_count.as_usize() >= skols.len(), "popping more skolemized variables than actually exist, \ - sc now = {}, skols.len = {}", - self.skolemization_count, + sc now = {:?}, skols.len = {:?}", + skolemization_count, skols.len() ); - let last_to_pop = self.skolemization_count; - let first_to_pop = last_to_pop - (skols.len() as u32); + let last_to_pop = skolemization_count.subuniverse(); + let first_to_pop = ty::UniverseIndex::from(last_to_pop.as_u32() - skols.len() as u32); - assert!( - first_to_pop >= snapshot.skolemization_count, - "popping more regions than snapshot contains, \ - sc now = {}, sc then = {}, skols.len = {}", - self.skolemization_count, - snapshot.skolemization_count, - skols.len() - ); debug_assert! { skols.iter() .all(|&k| match *k { - ty::ReSkolemized(index, _) => - index.index >= first_to_pop && - index.index < last_to_pop, + ty::ReSkolemized(universe, _) => + universe >= first_to_pop && + universe < last_to_pop, _ => false }), - "invalid skolemization keys or keys out of range ({}..{}): {:?}", - snapshot.skolemization_count, - self.skolemization_count, + "invalid skolemization keys or keys out of range ({:?}..{:?}): {:?}", + first_to_pop, + last_to_pop, skols } @@ -551,7 +506,6 @@ impl<'tcx> RegionConstraintCollector<'tcx> { self.rollback_undo_entry(undo_entry); } - self.skolemization_count = snapshot.skolemization_count; return; fn kill_constraint<'tcx>( @@ -805,7 +759,10 @@ impl<'tcx> RegionConstraintCollector<'tcx> { if let Some(&c) = self.combine_map(t).get(&vars) { return tcx.mk_region(ReVar(c)); } - let c = self.new_region_var(MiscVariable(origin.span())); + let a_universe = self.universe(a); + let b_universe = self.universe(b); + let c_universe = cmp::max(a_universe, b_universe); + let c = self.new_region_var(c_universe, MiscVariable(origin.span())); self.combine_map(t).insert(vars, c); if self.in_snapshot() { self.undo_log.push(AddCombination(t, vars)); @@ -821,6 +778,24 @@ impl<'tcx> RegionConstraintCollector<'tcx> { new_r } + fn universe(&self, region: Region<'tcx>) -> ty::UniverseIndex { + match *region { + ty::ReScope(..) | + ty::ReStatic | + ty::ReEmpty | + ty::ReErased | + ty::ReFree(..) | + ty::ReEarlyBound(..) => ty::UniverseIndex::ROOT, + ty::ReSkolemized(universe, _) => universe, + ty::ReClosureBound(vid) | + ty::ReVar(vid) => self.var_universe(vid), + ty::ReLateBound(..) => + bug!("universe(): encountered bound region {:?}", region), + ty::ReCanonical(..) => + bug!("region_universe(): encountered canonical region {:?}", region), + } + } + pub fn vars_created_since_snapshot(&self, mark: &RegionSnapshot) -> Vec<RegionVid> { self.undo_log[mark.length..] .iter() @@ -865,12 +840,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> { impl fmt::Debug for RegionSnapshot { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "RegionSnapshot(length={},skolemization={})", - self.length, - self.skolemization_count - ) + write!(f, "RegionSnapshot(length={})", self.length) } } diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 5e96f4eb576..d40e1b3760f 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -78,10 +78,12 @@ struct TypeVariableData { #[derive(Copy, Clone, Debug)] pub enum TypeVariableValue<'tcx> { Known { value: Ty<'tcx> }, - Unknown, + Unknown { universe: ty::UniverseIndex }, } impl<'tcx> TypeVariableValue<'tcx> { + /// If this value is known, returns the type it is known to be. + /// Otherwise, `None`. pub fn known(&self) -> Option<Ty<'tcx>> { match *self { TypeVariableValue::Unknown { .. } => None, @@ -181,10 +183,11 @@ impl<'tcx> TypeVariableTable<'tcx> { /// The code in this module doesn't care, but it can be useful /// for improving error messages. pub fn new_var(&mut self, + universe: ty::UniverseIndex, diverging: bool, origin: TypeVariableOrigin) -> ty::TyVid { - let eq_key = self.eq_relations.new_key(TypeVariableValue::Unknown); + let eq_key = self.eq_relations.new_key(TypeVariableValue::Unknown { universe }); let sub_key = self.sub_relations.new_key(()); assert_eq!(eq_key.vid, sub_key); @@ -437,7 +440,16 @@ impl<'tcx> ut::UnifyValue for TypeVariableValue<'tcx> { (&TypeVariableValue::Unknown { .. }, &TypeVariableValue::Known { .. }) => Ok(*value2), // If both sides are *unknown*, it hardly matters, does it? - (&TypeVariableValue::Unknown, &TypeVariableValue::Unknown) => Ok(*value1), + (&TypeVariableValue::Unknown { universe: universe1 }, + &TypeVariableValue::Unknown { universe: universe2 }) => { + // If we unify two unbound variables, ?T and ?U, then whatever + // value they wind up taking (which must be the same value) must + // be nameable by both universes. Therefore, the resulting + // universe is the minimum of the two universes, because that is + // the one which contains the fewest names in scope. + let universe = cmp::min(universe1, universe2); + Ok(TypeVariableValue::Unknown { universe }) + } } } } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index f85d0a9bf0c..879d38c4894 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -45,8 +45,8 @@ #![feature(const_fn)] #![feature(core_intrinsics)] #![feature(drain_filter)] -#![feature(dyn_trait)] #![feature(entry_or_default)] +#![cfg_attr(stage0, feature(dyn_trait))] #![feature(from_ref)] #![feature(fs_read_write)] #![cfg_attr(windows, feature(libc))] @@ -58,6 +58,7 @@ #![feature(nonzero)] #![feature(proc_macro_internals)] #![feature(quote)] +#![feature(optin_builtin_traits)] #![feature(refcell_replace_swap)] #![feature(rustc_diagnostic_macros)] #![feature(slice_patterns)] @@ -68,7 +69,7 @@ #![feature(trusted_len)] #![feature(catch_expr)] #![feature(test)] -#![feature(inclusive_range_fields)] +#![feature(inclusive_range_methods)] #![recursion_limit="512"] @@ -84,7 +85,6 @@ extern crate libc; extern crate rustc_target; #[macro_use] extern crate rustc_data_structures; extern crate serialize; -extern crate rustc_const_math; extern crate rustc_errors as errors; #[macro_use] extern crate log; #[macro_use] extern crate syntax; diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs index e8b536d5267..d158f52c643 100644 --- a/src/librustc/lint/levels.rs +++ b/src/librustc/lint/levels.rs @@ -198,7 +198,7 @@ impl<'a> LintLevelsBuilder<'a> { "malformed lint attribute"); }; for attr in attrs { - let level = match attr.name().and_then(|name| Level::from_str(&name.as_str())) { + let level = match Level::from_str(&attr.name().as_str()) { None => continue, Some(lvl) => lvl, }; @@ -221,7 +221,7 @@ impl<'a> LintLevelsBuilder<'a> { continue } }; - let name = word.ident.name; + let name = word.name(); match store.check_lint_name(&name.as_str()) { CheckLintNameResult::Ok(ids) => { let src = LintSource::Node(name, li.span); @@ -260,7 +260,7 @@ impl<'a> LintLevelsBuilder<'a> { Some(li.span.into()), &msg); if name.as_str().chars().any(|c| c.is_uppercase()) { - let name_lower = name.as_str().to_lowercase(); + let name_lower = name.as_str().to_lowercase().to_string(); if let CheckLintNameResult::NoLint = store.check_lint_name(&name_lower) { db.emit(); diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 0d4fd99995f..d6c6f9dc0f6 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -507,7 +507,7 @@ pub fn struct_lint_level<'a>(sess: &'a Session, let explanation = if lint_id == LintId::of(::lint::builtin::UNSTABLE_NAME_COLLISION) { "once this method is added to the standard library, \ - there will be ambiguity here, which will cause a hard error!" + the ambiguity may cause an error or change in behavior!" .to_owned() } else if let Some(edition) = future_incompatible.edition { format!("{} in the {} edition!", STANDARD_MESSAGE, edition) diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index 19a7576b7ce..0ecab50dda2 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -11,7 +11,6 @@ use hir::def_id::DefId; use ty::{self, TyCtxt, layout}; use ty::subst::Substs; -use rustc_const_math::*; use mir::interpret::{Value, PrimVal}; use errors::DiagnosticBuilder; @@ -62,7 +61,6 @@ pub enum ErrKind<'tcx> { UnimplementedConstVal(&'static str), IndexOutOfBounds { len: u64, index: u64 }, - Math(ConstMathErr), LayoutError(layout::LayoutError<'tcx>), TypeckError, @@ -76,15 +74,6 @@ pub struct FrameInfo { pub location: String, } -impl<'tcx> From<ConstMathErr> for ErrKind<'tcx> { - fn from(err: ConstMathErr) -> ErrKind<'tcx> { - match err { - ConstMathErr::UnsignedNegation => ErrKind::TypeckError, - _ => ErrKind::Math(err) - } - } -} - #[derive(Clone, Debug)] pub enum ConstEvalErrDescription<'a, 'tcx: 'a> { Simple(Cow<'a, str>), @@ -122,7 +111,6 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { len, index) } - Math(ref err) => Simple(err.description().into_cow()), LayoutError(ref err) => Simple(err.to_string().into_cow()), TypeckError => simple!("type-checking failed"), diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 2cc5a4a8fe6..725fcf1e646 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -28,6 +28,7 @@ use ty::{self, TyCtxt, adjustment}; use hir::{self, PatKind}; use rustc_data_structures::sync::Lrc; +use std::rc::Rc; use syntax::ast; use syntax::ptr::P; use syntax_pos::Span; @@ -44,7 +45,7 @@ pub trait Delegate<'tcx> { fn consume(&mut self, consume_id: ast::NodeId, consume_span: Span, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, mode: ConsumeMode); // The value found at `cmt` has been determined to match the @@ -61,14 +62,14 @@ pub trait Delegate<'tcx> { // called on a subpart of an input passed to `matched_pat). fn matched_pat(&mut self, matched_pat: &hir::Pat, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, mode: MatchMode); // The value found at `cmt` is either copied or moved via the // pattern binding `consume_pat`, depending on mode. fn consume_pat(&mut self, consume_pat: &hir::Pat, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, mode: ConsumeMode); // The value found at `borrow` is being borrowed at the point @@ -76,7 +77,7 @@ pub trait Delegate<'tcx> { fn borrow(&mut self, borrow_id: ast::NodeId, borrow_span: Span, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, loan_region: ty::Region<'tcx>, bk: ty::BorrowKind, loan_cause: LoanCause); @@ -90,7 +91,7 @@ pub trait Delegate<'tcx> { fn mutate(&mut self, assignment_id: ast::NodeId, assignment_span: Span, - assignee_cmt: mc::cmt<'tcx>, + assignee_cmt: &mc::cmt_<'tcx>, mode: MutateMode); } @@ -316,11 +317,11 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { let fn_body_scope_r = self.tcx().mk_region(ty::ReScope(region::Scope::Node(body.value.hir_id.local_id))); - let arg_cmt = self.mc.cat_rvalue( + let arg_cmt = Rc::new(self.mc.cat_rvalue( arg.id, arg.pat.span, fn_body_scope_r, // Args live only as long as the fn body. - arg_ty); + arg_ty)); self.walk_irrefutable_pat(arg_cmt, &arg.pat); } @@ -335,11 +336,11 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { fn delegate_consume(&mut self, consume_id: ast::NodeId, consume_span: Span, - cmt: mc::cmt<'tcx>) { + cmt: &mc::cmt_<'tcx>) { debug!("delegate_consume(consume_id={}, cmt={:?})", consume_id, cmt); - let mode = copy_or_move(&self.mc, self.param_env, &cmt, DirectRefMove); + let mode = copy_or_move(&self.mc, self.param_env, cmt, DirectRefMove); self.delegate.consume(consume_id, consume_span, cmt, mode); } @@ -353,7 +354,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { debug!("consume_expr(expr={:?})", expr); let cmt = return_if_err!(self.mc.cat_expr(expr)); - self.delegate_consume(expr.id, expr.span, cmt); + self.delegate_consume(expr.id, expr.span, &cmt); self.walk_expr(expr); } @@ -362,7 +363,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { expr: &hir::Expr, mode: MutateMode) { let cmt = return_if_err!(self.mc.cat_expr(expr)); - self.delegate.mutate(assignment_expr.id, assignment_expr.span, cmt, mode); + self.delegate.mutate(assignment_expr.id, assignment_expr.span, &cmt, mode); self.walk_expr(expr); } @@ -375,7 +376,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { expr, r, bk); let cmt = return_if_err!(self.mc.cat_expr(expr)); - self.delegate.borrow(expr.id, expr.span, cmt, r, bk, cause); + self.delegate.borrow(expr.id, expr.span, &cmt, r, bk, cause); self.walk_expr(expr) } @@ -435,7 +436,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } hir::ExprMatch(ref discr, ref arms, _) => { - let discr_cmt = return_if_err!(self.mc.cat_expr(&discr)); + let discr_cmt = Rc::new(return_if_err!(self.mc.cat_expr(&discr))); let r = self.tcx().types.re_empty; self.borrow_expr(&discr, r, ty::ImmBorrow, MatchDiscriminant); @@ -619,7 +620,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // "assigns", which is handled by // `walk_pat`: self.walk_expr(&expr); - let init_cmt = return_if_err!(self.mc.cat_expr(&expr)); + let init_cmt = Rc::new(return_if_err!(self.mc.cat_expr(&expr))); self.walk_irrefutable_pat(init_cmt, &local.pat); } } @@ -652,7 +653,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { None => { return; } }; - let with_cmt = return_if_err!(self.mc.cat_expr(&with_expr)); + let with_cmt = Rc::new(return_if_err!(self.mc.cat_expr(&with_expr))); // Select just those fields of the `with` // expression that will actually be used @@ -671,7 +672,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { with_field.name, with_field.ty(self.tcx(), substs) ); - self.delegate_consume(with_expr.id, with_expr.span, cmt_field); + self.delegate_consume(with_expr.id, with_expr.span, &cmt_field); } } } @@ -710,7 +711,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { adjustment::Adjust::Unsize => { // Creating a closure/fn-pointer or unsizing consumes // the input and stores it into the resulting rvalue. - self.delegate_consume(expr.id, expr.span, cmt.clone()); + self.delegate_consume(expr.id, expr.span, &cmt); } adjustment::Adjust::Deref(None) => {} @@ -722,12 +723,11 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // this is an autoref of `x`. adjustment::Adjust::Deref(Some(ref deref)) => { let bk = ty::BorrowKind::from_mutbl(deref.mutbl); - self.delegate.borrow(expr.id, expr.span, cmt.clone(), - deref.region, bk, AutoRef); + self.delegate.borrow(expr.id, expr.span, &cmt, deref.region, bk, AutoRef); } adjustment::Adjust::Borrow(ref autoref) => { - self.walk_autoref(expr, cmt.clone(), autoref); + self.walk_autoref(expr, &cmt, autoref); } } cmt = return_if_err!(self.mc.cat_expr_adjusted(expr, cmt, &adjustment)); @@ -739,7 +739,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { /// after all relevant autoderefs have occurred. fn walk_autoref(&mut self, expr: &hir::Expr, - cmt_base: mc::cmt<'tcx>, + cmt_base: &mc::cmt_<'tcx>, autoref: &adjustment::AutoBorrow<'tcx>) { debug!("walk_autoref(expr.id={} cmt_base={:?} autoref={:?})", expr.id, @@ -852,7 +852,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // Each match binding is effectively an assignment to the // binding being produced. let def = Def::Local(canonical_id); - if let Ok(binding_cmt) = mc.cat_def(pat.id, pat.span, pat_ty, def) { + if let Ok(ref binding_cmt) = mc.cat_def(pat.id, pat.span, pat_ty, def) { delegate.mutate(pat.id, pat.span, binding_cmt, MutateMode::Init); } @@ -861,13 +861,13 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { ty::BindByReference(m) => { if let ty::TyRef(r, _) = pat_ty.sty { let bk = ty::BorrowKind::from_mutbl(m); - delegate.borrow(pat.id, pat.span, cmt_pat, r, bk, RefBinding); + delegate.borrow(pat.id, pat.span, &cmt_pat, r, bk, RefBinding); } } ty::BindByValue(..) => { let mode = copy_or_move(mc, param_env, &cmt_pat, PatBindingMove); debug!("walk_pat binding consuming pat"); - delegate.consume_pat(pat, cmt_pat, mode); + delegate.consume_pat(pat, &cmt_pat, mode); } } } @@ -891,12 +891,12 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { let downcast_cmt = mc.cat_downcast_if_needed(pat, cmt_pat, variant_did); debug!("variant downcast_cmt={:?} pat={:?}", downcast_cmt, pat); - delegate.matched_pat(pat, downcast_cmt, match_mode); + delegate.matched_pat(pat, &downcast_cmt, match_mode); } Def::Struct(..) | Def::StructCtor(..) | Def::Union(..) | Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => { debug!("struct cmt_pat={:?} pat={:?}", cmt_pat, pat); - delegate.matched_pat(pat, cmt_pat, match_mode); + delegate.matched_pat(pat, &cmt_pat, match_mode); } _ => {} } @@ -924,12 +924,12 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { self.param_env, &cmt_var, CaptureMove); - self.delegate.consume(closure_expr.id, freevar.span, cmt_var, mode); + self.delegate.consume(closure_expr.id, freevar.span, &cmt_var, mode); } ty::UpvarCapture::ByRef(upvar_borrow) => { self.delegate.borrow(closure_expr.id, fn_decl_span, - cmt_var, + &cmt_var, upvar_borrow.region, upvar_borrow.kind, ClosureCapture(freevar.span)); @@ -943,7 +943,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { closure_id: ast::NodeId, closure_span: Span, upvar: &hir::Freevar) - -> mc::McResult<mc::cmt<'tcx>> { + -> mc::McResult<mc::cmt_<'tcx>> { // Create the cmt for the variable being borrowed, from the // caller's perspective let var_hir_id = self.tcx().hir.node_to_hir_id(upvar.var_id()); @@ -954,7 +954,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { fn copy_or_move<'a, 'gcx, 'tcx>(mc: &mc::MemCategorizationContext<'a, 'gcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, - cmt: &mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, move_reason: MoveReason) -> ConsumeMode { diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 17c114bc3b3..d1a46f5f155 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -111,6 +111,7 @@ use ty::{self, TyCtxt}; use lint; use util::nodemap::{NodeMap, NodeSet}; +use std::collections::VecDeque; use std::{fmt, usize}; use std::io::prelude::*; use std::io; @@ -412,18 +413,43 @@ fn visit_local<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, local: &'tcx hir::Local) { } fn visit_arm<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, arm: &'tcx hir::Arm) { - for pat in &arm.pats { - // for struct patterns, take note of which fields used shorthand (`x` rather than `x: x`) + for mut pat in &arm.pats { + // For struct patterns, take note of which fields used shorthand + // (`x` rather than `x: x`). // - // FIXME: according to the rust-lang-nursery/rustc-guide book, `NodeId`s are to be phased - // out in favor of `HirId`s; however, we need to match the signature of `each_binding`, - // which uses `NodeIds`. + // FIXME: according to the rust-lang-nursery/rustc-guide book, `NodeId`s are to be + // phased out in favor of `HirId`s; however, we need to match the signature of + // `each_binding`, which uses `NodeIds`. let mut shorthand_field_ids = NodeSet(); - if let hir::PatKind::Struct(_, ref fields, _) = pat.node { - for field in fields { - if field.node.is_shorthand { - shorthand_field_ids.insert(field.node.pat.id); + let mut pats = VecDeque::new(); + pats.push_back(pat); + while let Some(pat) = pats.pop_front() { + use hir::PatKind::*; + match pat.node { + Binding(_, _, _, ref inner_pat) => { + pats.extend(inner_pat.iter()); } + Struct(_, ref fields, _) => { + for field in fields { + if field.node.is_shorthand { + shorthand_field_ids.insert(field.node.pat.id); + } + } + } + Ref(ref inner_pat, _) | + Box(ref inner_pat) => { + pats.push_back(inner_pat); + } + TupleStruct(_, ref inner_pats, _) | + Tuple(ref inner_pats, _) => { + pats.extend(inner_pats.iter()); + } + Slice(ref pre_pats, ref inner_pat, ref post_pats) => { + pats.extend(pre_pats.iter()); + pats.extend(inner_pat.iter()); + pats.extend(post_pats.iter()); + } + _ => {} } } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 6f41f07dce8..f40a41cd299 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -572,13 +572,13 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { Ok(ret_ty) } - pub fn cat_expr(&self, expr: &hir::Expr) -> McResult<cmt<'tcx>> { + pub fn cat_expr(&self, expr: &hir::Expr) -> McResult<cmt_<'tcx>> { // This recursion helper avoids going through *too many* // adjustments, since *only* non-overloaded deref recurses. fn helper<'a, 'gcx, 'tcx>(mc: &MemCategorizationContext<'a, 'gcx, 'tcx>, expr: &hir::Expr, adjustments: &[adjustment::Adjustment<'tcx>]) - -> McResult<cmt<'tcx>> { + -> McResult<cmt_<'tcx>> { match adjustments.split_last() { None => mc.cat_expr_unadjusted(expr), Some((adjustment, previous)) => { @@ -591,24 +591,24 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } pub fn cat_expr_adjusted(&self, expr: &hir::Expr, - previous: cmt<'tcx>, + previous: cmt_<'tcx>, adjustment: &adjustment::Adjustment<'tcx>) - -> McResult<cmt<'tcx>> { + -> McResult<cmt_<'tcx>> { self.cat_expr_adjusted_with(expr, || Ok(previous), adjustment) } fn cat_expr_adjusted_with<F>(&self, expr: &hir::Expr, previous: F, adjustment: &adjustment::Adjustment<'tcx>) - -> McResult<cmt<'tcx>> - where F: FnOnce() -> McResult<cmt<'tcx>> + -> McResult<cmt_<'tcx>> + where F: FnOnce() -> McResult<cmt_<'tcx>> { debug!("cat_expr_adjusted_with({:?}): {:?}", adjustment, expr); let target = self.resolve_type_vars_if_possible(&adjustment.target); match adjustment.kind { adjustment::Adjust::Deref(overloaded) => { // Equivalent to *expr or something similar. - let base = if let Some(deref) = overloaded { + let base = Rc::new(if let Some(deref) = overloaded { let ref_ty = self.tcx.mk_ref(deref.region, ty::TypeAndMut { ty: target, mutbl: deref.mutbl, @@ -616,7 +616,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { self.cat_rvalue_node(expr.id, expr.span, ref_ty) } else { previous()? - }; + }); self.cat_deref(expr, base, false) } @@ -633,7 +633,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } } - pub fn cat_expr_unadjusted(&self, expr: &hir::Expr) -> McResult<cmt<'tcx>> { + pub fn cat_expr_unadjusted(&self, expr: &hir::Expr) -> McResult<cmt_<'tcx>> { debug!("cat_expr: id={} expr={:?}", expr.id, expr); let expr_ty = self.expr_ty(expr)?; @@ -642,13 +642,13 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { if self.tables.is_method_call(expr) { self.cat_overloaded_place(expr, e_base, false) } else { - let base_cmt = self.cat_expr(&e_base)?; + let base_cmt = Rc::new(self.cat_expr(&e_base)?); self.cat_deref(expr, base_cmt, false) } } hir::ExprField(ref base, f_name) => { - let base_cmt = self.cat_expr(&base)?; + let base_cmt = Rc::new(self.cat_expr(&base)?); debug!("cat_expr(cat_field): id={} expr={:?} base={:?}", expr.id, expr, @@ -666,7 +666,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // dereferencing. self.cat_overloaded_place(expr, base, true) } else { - let base_cmt = self.cat_expr(&base)?; + let base_cmt = Rc::new(self.cat_expr(&base)?); self.cat_index(expr, base_cmt, expr_ty, InteriorOffsetKind::Index) } } @@ -701,7 +701,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { span: Span, expr_ty: Ty<'tcx>, def: Def) - -> McResult<cmt<'tcx>> { + -> McResult<cmt_<'tcx>> { debug!("cat_def: id={} expr={:?} def={:?}", id, expr_ty, def); @@ -718,14 +718,14 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { return Ok(self.cat_rvalue_node(id, span, expr_ty)); } } - Ok(Rc::new(cmt_ { + Ok(cmt_ { id:id, span:span, cat:Categorization::StaticItem, mutbl: if mutbl { McDeclared } else { McImmutable}, ty:expr_ty, note: NoteNone - })) + }) } Def::Upvar(var_id, _, fn_node_id) => { @@ -733,14 +733,14 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } Def::Local(vid) => { - Ok(Rc::new(cmt_ { + Ok(cmt_ { id, span, cat: Categorization::Local(vid), mutbl: MutabilityCategory::from_local(self.tcx, self.tables, vid), ty: expr_ty, note: NoteNone - })) + }) } def => span_bug!(span, "unexpected definition in memory categorization: {:?}", def) @@ -754,7 +754,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { span: Span, var_id: ast::NodeId, fn_node_id: ast::NodeId) - -> McResult<cmt<'tcx>> + -> McResult<cmt_<'tcx>> { let fn_hir_id = self.tcx.hir.node_to_hir_id(fn_node_id); @@ -861,7 +861,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } }; - let ret = Rc::new(cmt_result); + let ret = cmt_result; debug!("cat_upvar ret={:?}", ret); Ok(ret) } @@ -938,7 +938,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { id: ast::NodeId, span: Span, expr_ty: Ty<'tcx>) - -> cmt<'tcx> { + -> cmt_<'tcx> { let hir_id = self.tcx.hir.node_to_hir_id(id); let promotable = self.rvalue_promotable_map.as_ref().map(|m| m.contains(&hir_id.local_id)) .unwrap_or(false); @@ -966,15 +966,15 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { cmt_id: ast::NodeId, span: Span, temp_scope: ty::Region<'tcx>, - expr_ty: Ty<'tcx>) -> cmt<'tcx> { - let ret = Rc::new(cmt_ { + expr_ty: Ty<'tcx>) -> cmt_<'tcx> { + let ret = cmt_ { id:cmt_id, span:span, cat:Categorization::Rvalue(temp_scope), mutbl:McDeclared, ty:expr_ty, note: NoteNone - }); + }; debug!("cat_rvalue ret {:?}", ret); ret } @@ -985,15 +985,15 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { f_index: usize, f_name: Name, f_ty: Ty<'tcx>) - -> cmt<'tcx> { - let ret = Rc::new(cmt_ { + -> cmt_<'tcx> { + let ret = cmt_ { id: node.id(), span: node.span(), mutbl: base_cmt.mutbl.inherit(), cat: Categorization::Interior(base_cmt, InteriorField(FieldIndex(f_index, f_name))), ty: f_ty, note: NoteNone - }); + }; debug!("cat_field ret {:?}", ret); ret } @@ -1002,7 +1002,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { expr: &hir::Expr, base: &hir::Expr, implicit: bool) - -> McResult<cmt<'tcx>> { + -> McResult<cmt_<'tcx>> { debug!("cat_overloaded_place: implicit={}", implicit); // Reconstruct the output assuming it's a reference with the @@ -1022,7 +1022,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { mutbl, }); - let base_cmt = self.cat_rvalue_node(expr.id, expr.span, ref_ty); + let base_cmt = Rc::new(self.cat_rvalue_node(expr.id, expr.span, ref_ty)); self.cat_deref(expr, base_cmt, implicit) } @@ -1030,7 +1030,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { node: &N, base_cmt: cmt<'tcx>, implicit: bool) - -> McResult<cmt<'tcx>> { + -> McResult<cmt_<'tcx>> { debug!("cat_deref: base_cmt={:?}", base_cmt); let base_cmt_ty = base_cmt.ty; @@ -1052,7 +1052,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } ref ty => bug!("unexpected type in cat_deref: {:?}", ty) }; - let ret = Rc::new(cmt_ { + let ret = cmt_ { id: node.id(), span: node.span(), // For unique ptrs, we inherit mutability from the owning reference. @@ -1060,7 +1060,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { cat: Categorization::Deref(base_cmt, ptr), ty: deref_ty, note: NoteNone - }); + }; debug!("cat_deref ret {:?}", ret); Ok(ret) } @@ -1070,7 +1070,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { base_cmt: cmt<'tcx>, element_ty: Ty<'tcx>, context: InteriorOffsetKind) - -> McResult<cmt<'tcx>> { + -> McResult<cmt_<'tcx>> { //! Creates a cmt for an indexing operation (`[]`). //! //! One subtle aspect of indexing that may not be @@ -1089,8 +1089,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { //! - `base_cmt`: the cmt of `elt` let interior_elem = InteriorElement(context); - let ret = - self.cat_imm_interior(elt, base_cmt, element_ty, interior_elem); + let ret = self.cat_imm_interior(elt, base_cmt, element_ty, interior_elem); debug!("cat_index ret {:?}", ret); return Ok(ret); } @@ -1100,15 +1099,15 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { base_cmt: cmt<'tcx>, interior_ty: Ty<'tcx>, interior: InteriorKind) - -> cmt<'tcx> { - let ret = Rc::new(cmt_ { + -> cmt_<'tcx> { + let ret = cmt_ { id: node.id(), span: node.span(), mutbl: base_cmt.mutbl.inherit(), cat: Categorization::Interior(base_cmt, interior), ty: interior_ty, note: NoteNone - }); + }; debug!("cat_imm_interior ret={:?}", ret); ret } @@ -1232,7 +1231,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { .get(pat.hir_id) .map(|v| v.len()) .unwrap_or(0) { - cmt = self.cat_deref(pat, cmt, true /* implicit */)?; + cmt = Rc::new(self.cat_deref(pat, cmt, true /* implicit */)?); } let cmt = cmt; // lose mutability @@ -1279,7 +1278,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) { let subpat_ty = self.pat_ty(&subpat)?; // see (*2) let interior = InteriorField(FieldIndex(i, Name::intern(&i.to_string()))); - let subcmt = self.cat_imm_interior(pat, cmt.clone(), subpat_ty, interior); + let subcmt = Rc::new(self.cat_imm_interior(pat, cmt.clone(), subpat_ty, interior)); self.cat_pattern_(subcmt, &subpat, op)?; } } @@ -1302,7 +1301,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { for fp in field_pats { let field_ty = self.pat_ty(&fp.node.pat)?; // see (*2) let f_index = self.tcx.field_index(fp.node.id, self.tables); - let cmt_field = self.cat_field(pat, cmt.clone(), f_index, fp.node.name, field_ty); + let cmt_field = + Rc::new(self.cat_field(pat, cmt.clone(), f_index, fp.node.name, field_ty)); self.cat_pattern_(cmt_field, &fp.node.pat, op)?; } } @@ -1320,7 +1320,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) { let subpat_ty = self.pat_ty(&subpat)?; // see (*2) let interior = InteriorField(FieldIndex(i, Name::intern(&i.to_string()))); - let subcmt = self.cat_imm_interior(pat, cmt.clone(), subpat_ty, interior); + let subcmt = Rc::new(self.cat_imm_interior(pat, cmt.clone(), subpat_ty, interior)); self.cat_pattern_(subcmt, &subpat, op)?; } } @@ -1329,7 +1329,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // box p1, &p1, &mut p1. we can ignore the mutability of // PatKind::Ref since that information is already contained // in the type. - let subcmt = self.cat_deref(pat, cmt, false)?; + let subcmt = Rc::new(self.cat_deref(pat, cmt, false)?); self.cat_pattern_(subcmt, &subpat, op)?; } @@ -1342,7 +1342,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } }; let context = InteriorOffsetKind::Pattern; - let elt_cmt = self.cat_index(pat, cmt, element_ty, context)?; + let elt_cmt = Rc::new(self.cat_index(pat, cmt, element_ty, context)?); for before_pat in before { self.cat_pattern_(elt_cmt.clone(), &before_pat, op)?; } @@ -1379,7 +1379,7 @@ pub enum AliasableReason { } impl<'tcx> cmt_<'tcx> { - pub fn guarantor(&self) -> cmt<'tcx> { + pub fn guarantor(&self) -> cmt_<'tcx> { //! Returns `self` after stripping away any derefs or //! interior content. The return value is basically the `cmt` which //! determines how long the value in `self` remains live. @@ -1392,7 +1392,7 @@ impl<'tcx> cmt_<'tcx> { Categorization::Deref(_, BorrowedPtr(..)) | Categorization::Deref(_, Implicit(..)) | Categorization::Upvar(..) => { - Rc::new((*self).clone()) + (*self).clone() } Categorization::Downcast(ref b, _) | Categorization::Interior(ref b, _) | @@ -1442,16 +1442,17 @@ impl<'tcx> cmt_<'tcx> { } } - // Digs down through one or two layers of deref and grabs the cmt - // for the upvar if a note indicates there is one. - pub fn upvar(&self) -> Option<cmt<'tcx>> { + // Digs down through one or two layers of deref and grabs the + // Categorization of the cmt for the upvar if a note indicates there is + // one. + pub fn upvar_cat(&self) -> Option<&Categorization<'tcx>> { match self.note { NoteClosureEnv(..) | NoteUpvarRef(..) => { Some(match self.cat { Categorization::Deref(ref inner, _) => { match inner.cat { - Categorization::Deref(ref inner, _) => inner.clone(), - Categorization::Upvar(..) => inner.clone(), + Categorization::Deref(ref inner, _) => &inner.cat, + Categorization::Upvar(..) => &inner.cat, _ => bug!() } } @@ -1462,7 +1463,6 @@ impl<'tcx> cmt_<'tcx> { } } - pub fn descriptive_string(&self, tcx: TyCtxt) -> String { match self.cat { Categorization::StaticItem => { @@ -1479,8 +1479,7 @@ impl<'tcx> cmt_<'tcx> { } } Categorization::Deref(_, pk) => { - let upvar = self.upvar(); - match upvar.as_ref().map(|i| &i.cat) { + match self.upvar_cat() { Some(&Categorization::Upvar(ref var)) => { var.to_string() } diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 5f4efbeeaa8..bfc9ff6660d 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -690,21 +690,22 @@ impl<'tcx> ScopeTree { // the start. So this algorithm is faster. let mut ma = Some(scope_a); let mut mb = Some(scope_b); - let mut seen: SmallVec<[Scope; 32]> = SmallVec::new(); + let mut seen_a: SmallVec<[Scope; 32]> = SmallVec::new(); + let mut seen_b: SmallVec<[Scope; 32]> = SmallVec::new(); loop { if let Some(a) = ma { - if seen.iter().position(|s| *s == a).is_some() { + if seen_b.iter().position(|s| *s == a).is_some() { return a; } - seen.push(a); + seen_a.push(a); ma = self.parent_map.get(&a).map(|s| *s); } if let Some(b) = mb { - if seen.iter().position(|s| *s == b).is_some() { + if seen_a.iter().position(|s| *s == b).is_some() { return b; } - seen.push(b); + seen_b.push(b); mb = self.parent_map.get(&b).map(|s| *s); } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 328b2db2b58..279908d2b67 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -205,7 +205,7 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> { } else { // Emit errors for non-staged-api crates. for attr in attrs { - let tag = unwrap_or!(attr.name(), continue); + let tag = attr.name(); if tag == "unstable" || tag == "stable" || tag == "rustc_deprecated" { attr::mark_used(attr); self.tcx.sess.span_err(attr.span(), "stability attributes may not be used \ diff --git a/src/librustc/mir/cache.rs b/src/librustc/mir/cache.rs index 1ed5a22257c..41ba526b73f 100644 --- a/src/librustc/mir/cache.rs +++ b/src/librustc/mir/cache.rs @@ -68,7 +68,7 @@ fn calculate_predecessors(mir: &Mir) -> IndexVec<BasicBlock, Vec<BasicBlock>> { let mut result = IndexVec::from_elem(vec![], mir.basic_blocks()); for (bb, data) in mir.basic_blocks().iter_enumerated() { if let Some(ref term) = data.terminator { - for &tgt in term.successors().iter() { + for &tgt in term.successors() { result[tgt].push(bb); } } diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index b919f4d15a8..1e1d50c3fc0 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -1,4 +1,3 @@ -use std::error::Error; use std::{fmt, env}; use mir; @@ -8,18 +7,16 @@ use super::{ MemoryPointer, Lock, AccessKind }; -use rustc_const_math::ConstMathErr; -use syntax::codemap::Span; use backtrace::Backtrace; #[derive(Debug, Clone)] pub struct EvalError<'tcx> { - pub kind: EvalErrorKind<'tcx>, + pub kind: EvalErrorKind<'tcx, u64>, pub backtrace: Option<Backtrace>, } -impl<'tcx> From<EvalErrorKind<'tcx>> for EvalError<'tcx> { - fn from(kind: EvalErrorKind<'tcx>) -> Self { +impl<'tcx> From<EvalErrorKind<'tcx, u64>> for EvalError<'tcx> { + fn from(kind: EvalErrorKind<'tcx, u64>) -> Self { let backtrace = match env::var("MIRI_BACKTRACE") { Ok(ref val) if !val.is_empty() => Some(Backtrace::new_unresolved()), _ => None @@ -31,8 +28,10 @@ impl<'tcx> From<EvalErrorKind<'tcx>> for EvalError<'tcx> { } } -#[derive(Debug, Clone)] -pub enum EvalErrorKind<'tcx> { +pub type AssertMessage<'tcx> = EvalErrorKind<'tcx, mir::Operand<'tcx>>; + +#[derive(Clone, RustcEncodable, RustcDecodable)] +pub enum EvalErrorKind<'tcx, O> { /// This variant is used by machines to signal their own errors that do not /// match an existing variant MachineError(String), @@ -60,10 +59,12 @@ pub enum EvalErrorKind<'tcx> { Unimplemented(String), DerefFunctionPointer, ExecuteMemory, - ArrayIndexOutOfBounds(Span, u64, u64), - Math(Span, ConstMathErr), + BoundsCheck { len: O, index: O }, + Overflow(mir::BinOp), + OverflowNeg, + DivisionByZero, + RemainderByZero, Intrinsic(String), - OverflowingMath, InvalidChar(u128), StackFrameLimitReached, OutOfTls, @@ -121,14 +122,16 @@ pub enum EvalErrorKind<'tcx> { /// Cannot compute this constant because it depends on another one /// which already produced an error ReferencedConstant, + GeneratorResumedAfterReturn, + GeneratorResumedAfterPanic, } pub type EvalResult<'tcx, T = ()> = Result<T, EvalError<'tcx>>; -impl<'tcx> Error for EvalError<'tcx> { - fn description(&self) -> &str { +impl<'tcx, O> EvalErrorKind<'tcx, O> { + pub fn description(&self) -> &str { use self::EvalErrorKind::*; - match self.kind { + match *self { MachineError(ref inner) => inner, FunctionPointerTyMismatch(..) => "tried to call a function through a function pointer of a different type", @@ -175,14 +178,10 @@ impl<'tcx> Error for EvalError<'tcx> { "tried to dereference a function pointer", ExecuteMemory => "tried to treat a memory pointer as a function pointer", - ArrayIndexOutOfBounds(..) => + BoundsCheck{..} => "array index out of bounds", - Math(..) => - "mathematical operation failed", Intrinsic(..) => "intrinsic failed", - OverflowingMath => - "attempted to do overflowing math", NoMirFor(..) => "mir not found", InvalidChar(..) => @@ -232,7 +231,7 @@ impl<'tcx> Error for EvalError<'tcx> { "the evaluated program panicked", ReadFromReturnPointer => "tried to read from the return pointer", - EvalErrorKind::PathNotFound(_) => + PathNotFound(_) => "a path could not be resolved, maybe the crate is not loaded", UnimplementedTraitSelection => "there were unresolved type arguments during trait selection", @@ -240,14 +239,33 @@ impl<'tcx> Error for EvalError<'tcx> { "encountered constants with type errors, stopping evaluation", ReferencedConstant => "referenced constant has errors", + Overflow(mir::BinOp::Add) => "attempt to add with overflow", + Overflow(mir::BinOp::Sub) => "attempt to subtract with overflow", + Overflow(mir::BinOp::Mul) => "attempt to multiply with overflow", + Overflow(mir::BinOp::Div) => "attempt to divide with overflow", + Overflow(mir::BinOp::Rem) => "attempt to calculate the remainder with overflow", + OverflowNeg => "attempt to negate with overflow", + Overflow(mir::BinOp::Shr) => "attempt to shift right with overflow", + Overflow(mir::BinOp::Shl) => "attempt to shift left with overflow", + Overflow(op) => bug!("{:?} cannot overflow", op), + DivisionByZero => "attempt to divide by zero", + RemainderByZero => "attempt to calculate the remainder with a divisor of zero", + GeneratorResumedAfterReturn => "generator resumed after completion", + GeneratorResumedAfterPanic => "generator resumed after panicking", } } } impl<'tcx> fmt::Display for EvalError<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}", self.kind) + } +} + +impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use self::EvalErrorKind::*; - match self.kind { + match *self { PointerOutOfBounds { ptr, access, allocation_size } => { write!(f, "{} at offset {}, outside bounds of allocation {} which has size {}", if access { "memory access" } else { "pointer computed" }, @@ -275,14 +293,12 @@ impl<'tcx> fmt::Display for EvalError<'tcx> { NoMirFor(ref func) => write!(f, "no mir for `{}`", func), FunctionPointerTyMismatch(sig, got) => write!(f, "tried to call a function with sig {} through a function pointer of type {}", sig, got), - ArrayIndexOutOfBounds(span, len, index) => - write!(f, "index out of bounds: the len is {} but the index is {} at {:?}", len, index, span), + BoundsCheck { ref len, ref index } => + write!(f, "index out of bounds: the len is {:?} but the index is {:?}", len, index), ReallocatedWrongMemoryKind(ref old, ref new) => write!(f, "tried to reallocate memory from {} to {}", old, new), DeallocatedWrongMemoryKind(ref old, ref new) => write!(f, "tried to deallocate {} memory but gave {} as the kind", old, new), - Math(_, ref err) => - write!(f, "{}", err.description()), Intrinsic(ref err) => write!(f, "{}", err), InvalidChar(c) => diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index c9eed0e4a28..546c7a920d5 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -8,7 +8,7 @@ macro_rules! err { mod error; mod value; -pub use self::error::{EvalError, EvalResult, EvalErrorKind}; +pub use self::error::{EvalError, EvalResult, EvalErrorKind, AssertMessage}; pub use self::value::{PrimVal, PrimValKind, Value, Pointer}; @@ -23,7 +23,7 @@ use std::iter; use syntax::ast::Mutability; use rustc_serialize::{Encoder, Decoder, Decodable, Encodable}; -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)] pub enum Lock { NoLock, WriteLock(DynamicLifetime), @@ -31,13 +31,13 @@ pub enum Lock { ReadLock(Vec<DynamicLifetime>), } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct DynamicLifetime { pub frame: usize, pub region: Option<region::Scope>, // "None" indicates "until the function ends" } -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub enum AccessKind { Read, Write, @@ -88,12 +88,12 @@ pub trait PointerArithmetic: layout::HasDataLayout { fn signed_offset<'tcx>(self, val: u64, i: i64) -> EvalResult<'tcx, u64> { let (res, over) = self.overflowing_signed_offset(val, i as i128); - if over { err!(OverflowingMath) } else { Ok(res) } + if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) } } fn offset<'tcx>(self, val: u64, i: u64) -> EvalResult<'tcx, u64> { let (res, over) = self.overflowing_offset(val, i); - if over { err!(OverflowingMath) } else { Ok(res) } + if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) } } fn wrapping_signed_offset(self, val: u64, i: i64) -> u64 { diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index c525c4ed651..37f6d47ff84 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -15,17 +15,17 @@ use graphviz::IntoCow; use middle::const_val::ConstVal; use middle::region; -use rustc_const_math::ConstMathErr; use rustc_data_structures::sync::{Lrc}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc_data_structures::control_flow_graph::dominators::{Dominators, dominators}; use rustc_data_structures::control_flow_graph::{GraphPredecessors, GraphSuccessors}; use rustc_data_structures::control_flow_graph::ControlFlowGraph; +use rustc_data_structures::small_vec::SmallVec; use rustc_serialize as serialize; use hir::def::CtorKind; use hir::def_id::DefId; use mir::visit::MirVisitable; -use mir::interpret::{Value, PrimVal}; +use mir::interpret::{Value, PrimVal, EvalErrorKind}; use ty::subst::{Subst, Substs}; use ty::{self, AdtDef, CanonicalTy, ClosureSubsts, Region, Ty, TyCtxt, GeneratorInterior}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; @@ -36,12 +36,16 @@ use hir::{self, InlineAsm}; use std::borrow::{Cow}; use rustc_data_structures::sync::ReadGuard; use std::fmt::{self, Debug, Formatter, Write}; -use std::{iter, mem, u32}; +use std::{iter, mem, option, u32}; use std::ops::{Index, IndexMut}; use std::vec::IntoIter; use syntax::ast::{self, Name}; use syntax::symbol::InternedString; use syntax_pos::{Span, DUMMY_SP}; +use rustc_apfloat::ieee::{Single, Double}; +use rustc_apfloat::Float; + +pub use mir::interpret::AssertMessage; mod cache; pub mod tcx; @@ -247,6 +251,22 @@ impl<'tcx> Mir<'tcx> { }) } + /// Returns an iterator over all user-declared mutable arguments and locals. + #[inline] + pub fn mut_vars_and_args_iter<'a>(&'a self) -> impl Iterator<Item=Local> + 'a { + (1..self.local_decls.len()).filter_map(move |index| { + let local = Local::new(index); + let decl = &self.local_decls[local]; + if (decl.is_user_variable || index < self.arg_count + 1) + && decl.mutability == Mutability::Mut + { + Some(local) + } else { + None + } + }) + } + /// Returns an iterator over all function arguments. #[inline] pub fn args_iter(&self) -> impl Iterator<Item=Local> { @@ -842,12 +862,17 @@ pub enum TerminatorKind<'tcx> { }, } +pub type Successors<'a> = + iter::Chain<option::IntoIter<&'a BasicBlock>, slice::Iter<'a, BasicBlock>>; +pub type SuccessorsMut<'a> = + iter::Chain<option::IntoIter<&'a mut BasicBlock>, slice::IterMut<'a, BasicBlock>>; + impl<'tcx> Terminator<'tcx> { - pub fn successors(&self) -> Cow<[BasicBlock]> { + pub fn successors(&self) -> Successors { self.kind.successors() } - pub fn successors_mut(&mut self) -> Vec<&mut BasicBlock> { + pub fn successors_mut(&mut self) -> SuccessorsMut { self.kind.successors_mut() } @@ -868,72 +893,71 @@ impl<'tcx> TerminatorKind<'tcx> { } } - pub fn successors(&self) -> Cow<[BasicBlock]> { + pub fn successors(&self) -> Successors { use self::TerminatorKind::*; match *self { - Goto { target: ref b } => slice::from_ref(b).into_cow(), - SwitchInt { targets: ref b, .. } => b[..].into_cow(), - Resume | Abort | GeneratorDrop => (&[]).into_cow(), - Return => (&[]).into_cow(), - Unreachable => (&[]).into_cow(), - Call { destination: Some((_, t)), cleanup: Some(c), .. } => vec![t, c].into_cow(), - Call { destination: Some((_, ref t)), cleanup: None, .. } => - slice::from_ref(t).into_cow(), - Call { destination: None, cleanup: Some(ref c), .. } => slice::from_ref(c).into_cow(), - Call { destination: None, cleanup: None, .. } => (&[]).into_cow(), - Yield { resume: t, drop: Some(c), .. } => vec![t, c].into_cow(), - Yield { resume: ref t, drop: None, .. } => slice::from_ref(t).into_cow(), - DropAndReplace { target, unwind: Some(unwind), .. } | - Drop { target, unwind: Some(unwind), .. } => { - vec![target, unwind].into_cow() + Resume | Abort | GeneratorDrop | Return | Unreachable | + Call { destination: None, cleanup: None, .. } => { + None.into_iter().chain(&[]) + } + Goto { target: ref t } | + Call { destination: None, cleanup: Some(ref t), .. } | + Call { destination: Some((_, ref t)), cleanup: None, .. } | + Yield { resume: ref t, drop: None, .. } | + DropAndReplace { target: ref t, unwind: None, .. } | + Drop { target: ref t, unwind: None, .. } | + Assert { target: ref t, cleanup: None, .. } | + FalseUnwind { real_target: ref t, unwind: None } => { + Some(t).into_iter().chain(&[]) + } + Call { destination: Some((_, ref t)), cleanup: Some(ref u), .. } | + Yield { resume: ref t, drop: Some(ref u), .. } | + DropAndReplace { target: ref t, unwind: Some(ref u), .. } | + Drop { target: ref t, unwind: Some(ref u), .. } | + Assert { target: ref t, cleanup: Some(ref u), .. } | + FalseUnwind { real_target: ref t, unwind: Some(ref u) } => { + Some(t).into_iter().chain(slice::from_ref(u)) } - DropAndReplace { ref target, unwind: None, .. } | - Drop { ref target, unwind: None, .. } => { - slice::from_ref(target).into_cow() + SwitchInt { ref targets, .. } => { + None.into_iter().chain(&targets[..]) } - Assert { target, cleanup: Some(unwind), .. } => vec![target, unwind].into_cow(), - Assert { ref target, .. } => slice::from_ref(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() + Some(real_target).into_iter().chain(&imaginary_targets[..]) } - FalseUnwind { real_target: t, unwind: Some(u) } => vec![t, u].into_cow(), - FalseUnwind { real_target: ref t, unwind: None } => slice::from_ref(t).into_cow(), } } - // FIXME: no mootable cow. I’m honestly not sure what a “cow” between `&mut [BasicBlock]` and - // `Vec<&mut BasicBlock>` would look like in the first place. - pub fn successors_mut(&mut self) -> Vec<&mut BasicBlock> { + pub fn successors_mut(&mut self) -> SuccessorsMut { use self::TerminatorKind::*; match *self { - Goto { target: ref mut b } => vec![b], - SwitchInt { targets: ref mut b, .. } => b.iter_mut().collect(), - Resume | Abort | GeneratorDrop => Vec::new(), - Return => Vec::new(), - Unreachable => Vec::new(), - Call { destination: Some((_, ref mut t)), cleanup: Some(ref mut c), .. } => vec![t, c], - Call { destination: Some((_, ref mut t)), cleanup: None, .. } => vec![t], - Call { destination: None, cleanup: Some(ref mut c), .. } => vec![c], - Call { destination: None, cleanup: None, .. } => vec![], - Yield { resume: ref mut t, drop: Some(ref mut c), .. } => vec![t, c], - Yield { resume: ref mut t, drop: None, .. } => vec![t], - DropAndReplace { ref mut target, unwind: Some(ref mut unwind), .. } | - Drop { ref mut target, unwind: Some(ref mut unwind), .. } => vec![target, unwind], - DropAndReplace { ref mut target, unwind: None, .. } | - Drop { ref mut target, unwind: None, .. } => { - vec![target] + Resume | Abort | GeneratorDrop | Return | Unreachable | + Call { destination: None, cleanup: None, .. } => { + None.into_iter().chain(&mut []) + } + Goto { target: ref mut t } | + Call { destination: None, cleanup: Some(ref mut t), .. } | + Call { destination: Some((_, ref mut t)), cleanup: None, .. } | + Yield { resume: ref mut t, drop: None, .. } | + DropAndReplace { target: ref mut t, unwind: None, .. } | + Drop { target: ref mut t, unwind: None, .. } | + Assert { target: ref mut t, cleanup: None, .. } | + FalseUnwind { real_target: ref mut t, unwind: None } => { + Some(t).into_iter().chain(&mut []) + } + Call { destination: Some((_, ref mut t)), cleanup: Some(ref mut u), .. } | + Yield { resume: ref mut t, drop: Some(ref mut u), .. } | + DropAndReplace { target: ref mut t, unwind: Some(ref mut u), .. } | + Drop { target: ref mut t, unwind: Some(ref mut u), .. } | + Assert { target: ref mut t, cleanup: Some(ref mut u), .. } | + FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) } => { + Some(t).into_iter().chain(slice::from_ref_mut(u)) + } + SwitchInt { ref mut targets, .. } => { + None.into_iter().chain(&mut targets[..]) } - Assert { ref mut target, cleanup: Some(ref mut unwind), .. } => vec![target, unwind], - 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 + Some(real_target).into_iter().chain(&mut imaginary_targets[..]) } - FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) } => vec![t, u], - FalseUnwind { ref mut real_target, unwind: None } => vec![real_target], } } @@ -1053,18 +1077,18 @@ impl<'tcx> BasicBlockData<'tcx> { impl<'tcx> Debug for TerminatorKind<'tcx> { fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { self.fmt_head(fmt)?; - let successors = self.successors(); + let successor_count = self.successors().count(); let labels = self.fmt_successor_labels(); - assert_eq!(successors.len(), labels.len()); + assert_eq!(successor_count, labels.len()); - match successors.len() { + match successor_count { 0 => Ok(()), - 1 => write!(fmt, " -> {:?}", successors[0]), + 1 => write!(fmt, " -> {:?}", self.successors().nth(0).unwrap()), _ => { write!(fmt, " -> [")?; - for (i, target) in successors.iter().enumerate() { + for (i, target) in self.successors().enumerate() { if i > 0 { write!(fmt, ", ")?; } @@ -1113,26 +1137,7 @@ impl<'tcx> TerminatorKind<'tcx> { if !expected { write!(fmt, "!")?; } - write!(fmt, "{:?}, ", cond)?; - - match *msg { - AssertMessage::BoundsCheck { ref len, ref index } => { - write!(fmt, "{:?}, {:?}, {:?}", - "index out of bounds: the len is {} but the index is {}", - len, index)?; - } - AssertMessage::Math(ref err) => { - write!(fmt, "{:?}", err.description())?; - } - AssertMessage::GeneratorResumedAfterReturn => { - write!(fmt, "{:?}", "generator resumed after completion")?; - } - AssertMessage::GeneratorResumedAfterPanic => { - write!(fmt, "{:?}", "generator resumed after panicking")?; - } - } - - write!(fmt, ")") + write!(fmt, "{:?}, \"{:?}\")", cond, msg) }, FalseEdges { .. } => write!(fmt, "falseEdges"), FalseUnwind { .. } => write!(fmt, "falseUnwind"), @@ -1187,17 +1192,6 @@ impl<'tcx> TerminatorKind<'tcx> { } } -#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] -pub enum AssertMessage<'tcx> { - BoundsCheck { - len: Operand<'tcx>, - index: Operand<'tcx> - }, - Math(ConstMathErr), - GeneratorResumedAfterReturn, - GeneratorResumedAfterPanic, -} - /////////////////////////////////////////////////////////////////////////// // Statements @@ -1898,12 +1892,13 @@ fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ty::Const) -> fmt::Result { pub fn print_miri_value<W: Write>(value: Value, ty: Ty, f: &mut W) -> fmt::Result { use ty::TypeVariants::*; - use rustc_const_math::ConstFloat; match (value, &ty.sty) { (Value::ByVal(PrimVal::Bytes(0)), &TyBool) => write!(f, "false"), (Value::ByVal(PrimVal::Bytes(1)), &TyBool) => write!(f, "true"), - (Value::ByVal(PrimVal::Bytes(bits)), &TyFloat(fty)) => - write!(f, "{}", ConstFloat { bits, ty: fty }), + (Value::ByVal(PrimVal::Bytes(bits)), &TyFloat(ast::FloatTy::F32)) => + write!(f, "{}f32", Single::from_bits(bits)), + (Value::ByVal(PrimVal::Bytes(bits)), &TyFloat(ast::FloatTy::F64)) => + write!(f, "{}f64", Double::from_bits(bits)), (Value::ByVal(PrimVal::Bytes(n)), &TyUint(ui)) => write!(f, "{:?}{}", n, ui), (Value::ByVal(PrimVal::Bytes(n)), &TyInt(i)) => write!(f, "{:?}{}", n as i128, i), (Value::ByVal(PrimVal::Bytes(n)), &TyChar) => @@ -1952,7 +1947,7 @@ impl<'tcx> ControlFlowGraph for Mir<'tcx> { fn successors<'graph>(&'graph self, node: Self::Node) -> <Self as GraphSuccessors<'graph>>::Iter { - self.basic_blocks[node].terminator().successors().into_owned().into_iter() + self.basic_blocks[node].terminator().successors().cloned() } } @@ -1963,7 +1958,7 @@ impl<'a, 'b> GraphPredecessors<'b> for Mir<'a> { impl<'a, 'b> GraphSuccessors<'b> for Mir<'a> { type Item = BasicBlock; - type Iter = IntoIter<BasicBlock>; + type Iter = iter::Cloned<Successors<'b>>; } #[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] @@ -1983,6 +1978,11 @@ impl fmt::Debug for Location { } impl Location { + pub const START: Location = Location { + block: START_BLOCK, + statement_index: 0, + }; + /// Returns the location immediately after this one within the enclosing block. /// /// Note that if this location represents a terminator, then the @@ -2029,6 +2029,12 @@ pub struct GeneratorLayout<'tcx> { pub fields: Vec<LocalDecl<'tcx>>, } +#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] +pub struct BorrowCheckResult<'gcx> { + pub closure_requirements: Option<ClosureRegionRequirements<'gcx>>, + pub used_mut_upvars: SmallVec<[Field; 8]>, +} + /// After we borrow check a closure, we are left with various /// requirements that we have inferred between the free regions that /// appear in the closure's signature or on its field types. These @@ -2256,8 +2262,8 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { } }, Assert { ref cond, expected, ref msg, target, cleanup } => { - let msg = if let AssertMessage::BoundsCheck { ref len, ref index } = *msg { - AssertMessage::BoundsCheck { + let msg = if let EvalErrorKind::BoundsCheck { ref len, ref index } = *msg { + EvalErrorKind::BoundsCheck { len: len.fold_with(folder), index: index.fold_with(folder), } @@ -2306,7 +2312,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { }, Assert { ref cond, ref msg, .. } => { if cond.visit_with(visitor) { - if let AssertMessage::BoundsCheck { ref len, ref index } = *msg { + if let EvalErrorKind::BoundsCheck { ref len, ref index } = *msg { len.visit_with(visitor) || index.visit_with(visitor) } else { false diff --git a/src/librustc/mir/traversal.rs b/src/librustc/mir/traversal.rs index 666ca5eabe8..92888ed99e4 100644 --- a/src/librustc/mir/traversal.rs +++ b/src/librustc/mir/traversal.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::vec; - use rustc_data_structures::bitvec::BitVector; use rustc_data_structures::indexed_vec::Idx; @@ -67,7 +65,7 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> { let data = &self.mir[idx]; if let Some(ref term) = data.terminator { - for &succ in term.successors().iter() { + for &succ in term.successors() { self.worklist.push(succ); } } @@ -110,7 +108,7 @@ impl<'a, 'tcx> ExactSizeIterator for Preorder<'a, 'tcx> {} pub struct Postorder<'a, 'tcx: 'a> { mir: &'a Mir<'tcx>, visited: BitVector, - visit_stack: Vec<(BasicBlock, vec::IntoIter<BasicBlock>)> + visit_stack: Vec<(BasicBlock, Successors<'a>)> } impl<'a, 'tcx> Postorder<'a, 'tcx> { @@ -126,10 +124,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { if let Some(ref term) = data.terminator { po.visited.insert(root.index()); - - let succs = term.successors().into_owned().into_iter(); - - po.visit_stack.push((root, succs)); + po.visit_stack.push((root, term.successors())); po.traverse_successor(); } @@ -186,7 +181,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { // two iterations yield `C` and finally `A` for a final traversal of [E, D, B, C, A] loop { let bb = if let Some(&mut (_, ref mut iter)) = self.visit_stack.last_mut() { - if let Some(bb) = iter.next() { + if let Some(&bb) = iter.next() { bb } else { break; @@ -197,8 +192,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { if self.visited.insert(bb.index()) { if let Some(ref term) = self.mir[bb].terminator { - let succs = term.successors().into_owned().into_iter(); - self.visit_stack.push((bb, succs)); + self.visit_stack.push((bb, term.successors())); } } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index a3fdb6f73ab..59b6f369754 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -511,17 +511,13 @@ macro_rules! make_mir_visitor { fn super_assert_message(&mut self, msg: & $($mutability)* AssertMessage<'tcx>, location: Location) { - match *msg { - AssertMessage::BoundsCheck { + use mir::interpret::EvalErrorKind::*; + if let BoundsCheck { ref $($mutability)* len, ref $($mutability)* index - } => { - self.visit_operand(len, location); - self.visit_operand(index, location); - } - AssertMessage::Math(_) => {}, - AssertMessage::GeneratorResumedAfterReturn => {}, - AssertMessage::GeneratorResumedAfterPanic => {}, + } = *msg { + self.visit_operand(len, location); + self.visit_operand(index, location); } } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index ab703d423c6..0beda679e69 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1053,6 +1053,8 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options, 2 = full debug info with variable and type information"), opt_level: Option<String> = (None, parse_opt_string, [TRACKED], "optimize with possible levels 0-3, s, or z"), + force_frame_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED], + "force use of the frame pointers"), debug_assertions: Option<bool> = (None, parse_opt_bool, [TRACKED], "explicitly enable the cfg(debug_assertions) directive"), inline_threshold: Option<usize> = (None, parse_opt_uint, [TRACKED], @@ -1248,6 +1250,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "choose which RELRO level to use"), nll_subminimal_causes: bool = (false, parse_bool, [UNTRACKED], "when tracking region error causes, accept subminimal results for faster execution."), + nll_facts: bool = (false, parse_bool, [UNTRACKED], + "dump facts from NLL analysis into side files"), disable_nll_user_type_assert: bool = (false, parse_bool, [UNTRACKED], "disable user provided type assertion in NLL"), trans_time_graph: bool = (false, parse_bool, [UNTRACKED], @@ -1270,7 +1274,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED], "in dep-info output, omit targets for tracking dependencies of the dep-info files \ themselves"), - approximate_suggestions: bool = (false, parse_bool, [UNTRACKED], + suggestion_applicability: bool = (false, parse_bool, [UNTRACKED], "include machine-applicability of suggestions in JSON output"), unpretty: Option<String> = (None, parse_unpretty, [UNTRACKED], "Present the input source, unstable (and less-pretty) variants; @@ -1681,7 +1685,7 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> ast::CrateConfig { early_error(ErrorOutputType::default(), &msg) } - (meta_item.ident.name, meta_item.value_str()) + (meta_item.name(), meta_item.value_str()) }) .collect::<ast::CrateConfig>() } @@ -2966,6 +2970,10 @@ mod tests { assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); opts = reference.clone(); + opts.cg.force_frame_pointers = Some(false); + assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); + + opts = reference.clone(); opts.cg.debug_assertions = Some(true); assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index a0f11443425..2ab72ba20bf 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -20,7 +20,7 @@ use lint::builtin::BuiltinLintDiagnostics; use middle::allocator::AllocatorKind; use middle::dependency_format; use session::search_paths::PathKind; -use session::config::{DebugInfoLevel, OutputType}; +use session::config::{OutputType}; use ty::tls; use util::nodemap::{FxHashSet}; use util::common::{duration_to_secs_str, ErrorReported}; @@ -658,8 +658,11 @@ impl Session { } pub fn must_not_eliminate_frame_pointers(&self) -> bool { - self.opts.debuginfo != DebugInfoLevel::NoDebugInfo - || !self.target.target.options.eliminate_frame_pointer + if let Some(x) = self.opts.cg.force_frame_pointers { + x + } else { + !self.target.target.options.eliminate_frame_pointer + } } /// Returns the symbol name for the registrar function, @@ -1002,7 +1005,7 @@ pub fn build_session_with_codemap( Some(registry), codemap.clone(), pretty, - sopts.debugging_opts.approximate_suggestions, + sopts.debugging_opts.suggestion_applicability, ).ui_testing(sopts.debugging_opts.ui_testing), ), (config::ErrorOutputType::Json(pretty), Some(dst)) => Box::new( @@ -1011,7 +1014,7 @@ pub fn build_session_with_codemap( Some(registry), codemap.clone(), pretty, - sopts.debugging_opts.approximate_suggestions, + sopts.debugging_opts.suggestion_applicability, ).ui_testing(sopts.debugging_opts.ui_testing), ), (config::ErrorOutputType::Short(color_config), None) => Box::new( diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 31f8af1f968..5a626e7b82c 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -154,7 +154,10 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, recursion_depth: 0, predicate: p }) .chain(obligations) - .find(|o| !selcx.evaluate_obligation(o)); + .find(|o| !selcx.predicate_may_hold_fatal(o)); + // FIXME: the call to `selcx.predicate_may_hold_fatal` above should be ported + // to the canonical trait query form, `infcx.predicate_may_hold`, once + // the new system supports intercrate mode (which coherence needs). if let Some(failing_obligation) = opt_failing_obligation { debug!("overlap: obligation unsatisfiable {:?}", failing_obligation); diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 33abc0c7e15..047d4bb8930 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -24,6 +24,7 @@ use super::{ SelectionContext, SelectionError, ObjectSafetyViolation, + Overflow, }; use errors::DiagnosticBuilder; @@ -659,8 +660,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { predicate: ty::Predicate::Trait(predicate), .. obligation.clone() }; - let mut selcx = SelectionContext::new(self); - if selcx.evaluate_obligation(&unit_obligation) { + if self.predicate_may_hold(&unit_obligation) { err.note("the trait is implemented for `()`. \ Possibly this error has been caused by changes to \ Rust's type-inference algorithm \ @@ -830,6 +830,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } err.struct_error(self.tcx, span, "constant expression") } + + Overflow => { + bug!("overflow should be handled before the `report_selection_error` path"); + } }; self.note_obligation_cause(&mut err, obligation); err.emit(); @@ -872,7 +876,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { .count(); let mut trait_type = trait_ref.self_ty(); - let mut selcx = SelectionContext::new(self); for refs_remaining in 0..refs_number { if let ty::TypeVariants::TyRef(_, ty::TypeAndMut{ ty: t_type, mutbl: _ }) = @@ -886,7 +889,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { obligation.param_env, new_trait_ref.to_predicate()); - if selcx.evaluate_obligation(&new_obligation) { + if self.predicate_may_hold(&new_obligation) { let sp = self.tcx.sess.codemap() .span_take_while(span, |c| c.is_whitespace() || *c == '&'); @@ -976,6 +979,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ArgKind::Arg(format!("{}", field.name), "_".to_string()) }).collect::<Vec<_>>()) } + hir::map::NodeStructCtor(ref variant_data) => { + (self.tcx.sess.codemap().def_span(self.tcx.hir.span(variant_data.id())), + variant_data.fields() + .iter().map(|_| ArgKind::Arg("_".to_owned(), "_".to_owned())) + .collect()) + } _ => panic!("non-FnLike node found: {:?}", node), } } @@ -1322,7 +1331,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { cleaned_pred.to_predicate() ); - selcx.evaluate_obligation(&obligation) + self.predicate_may_hold(&obligation) }) } diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 1c091d68a2e..6e201507181 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -112,7 +112,7 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { selcx, register_region_obligations: self.register_region_obligations }); - debug!("select: outcome={:?}", outcome); + debug!("select: outcome={:#?}", outcome); // FIXME: if we kept the original cache key, we could mark projection // obligations as complete for the projection cache here. @@ -333,7 +333,7 @@ fn process_predicate<'a, 'gcx, 'tcx>( if data.is_global() { // no type variables present, can use evaluation for better caching. // FIXME: consider caching errors too. - if selcx.evaluate_obligation_conservatively(&obligation) { + if selcx.infcx().predicate_must_hold(&obligation) { debug!("selecting trait `{:?}` at depth {} evaluated to holds", data, obligation.recursion_depth); return Ok(Some(vec![])) diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 728d9f1a027..dd5208e908e 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -41,7 +41,7 @@ pub use self::object_safety::ObjectSafetyViolation; pub use self::object_safety::MethodViolationCode; pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote}; pub use self::select::{EvaluationCache, SelectionContext, SelectionCache}; -pub use self::select::IntercrateAmbiguityCause; +pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError}; pub use self::specialize::{OverlapError, specialization_graph, translate_substs}; pub use self::specialize::{SpecializesCache, find_associated_item}; pub use self::engine::TraitEngine; @@ -74,6 +74,19 @@ pub enum IntercrateMode { Fixed } +// The mode that trait queries run in +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum TraitQueryMode { + // Standard/un-canonicalized queries get accurate + // spans etc. passed in and hence can do reasonable + // error reporting on their own. + Standard, + // Canonicalized queries get dummy spans and hence + // must generally propagate errors to + // pre-canonicalization callsites. + Canonical, +} + /// An `Obligation` represents some trait reference (e.g. `int:Eq`) for /// which the vtable must be found. The process of finding a vtable is /// called "resolving" the `Obligation`. This process consists of @@ -349,6 +362,7 @@ pub enum SelectionError<'tcx> { ty::error::TypeError<'tcx>), TraitNotObjectSafe(DefId), ConstEvalFailure(ConstEvalErr<'tcx>), + Overflow, } pub struct FulfillmentError<'tcx> { @@ -550,8 +564,7 @@ pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx predicate: trait_ref.to_predicate(), }; - let result = SelectionContext::new(infcx) - .evaluate_obligation_conservatively(&obligation); + let result = infcx.predicate_must_hold(&obligation); debug!("type_known_to_meet_ty={:?} bound={} => {:?}", ty, infcx.tcx.item_path_str(def_id), result); diff --git a/src/librustc/traits/on_unimplemented.rs b/src/librustc/traits/on_unimplemented.rs index 405dafdff2b..3cf7af30b3d 100644 --- a/src/librustc/traits/on_unimplemented.rs +++ b/src/librustc/traits/on_unimplemented.rs @@ -18,10 +18,10 @@ use util::nodemap::FxHashMap; use syntax::ast::{MetaItem, NestedMetaItem}; use syntax::attr; use syntax_pos::Span; -use syntax_pos::symbol::InternedString; +use syntax_pos::symbol::LocalInternedString; #[derive(Clone, Debug)] -pub struct OnUnimplementedFormatString(InternedString); +pub struct OnUnimplementedFormatString(LocalInternedString); #[derive(Debug)] pub struct OnUnimplementedDirective { @@ -190,7 +190,7 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective { for command in self.subcommands.iter().chain(Some(self)).rev() { if let Some(ref condition) = command.condition { if !attr::eval_condition(condition, &tcx.sess.parse_sess, &mut |c| { - options.contains(&(c.ident.name.as_str().to_string(), + options.contains(&(c.name().as_str().to_string(), match c.value_str().map(|s| s.as_str().to_string()) { Some(s) => Some(s), None => None @@ -225,7 +225,7 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective { impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString { pub fn try_parse(tcx: TyCtxt<'a, 'gcx, 'tcx>, trait_def_id: DefId, - from: InternedString, + from: LocalInternedString, err_sp: Span) -> Result<Self, ErrorReported> { diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 1c7942139e9..45fa588bbf5 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -188,7 +188,7 @@ pub fn poly_project_and_unify_type<'cx, 'gcx, 'tcx>( let infcx = selcx.infcx(); infcx.commit_if_ok(|snapshot| { let (skol_predicate, skol_map) = - infcx.skolemize_late_bound_regions(&obligation.predicate, snapshot); + infcx.skolemize_late_bound_regions(&obligation.predicate); let skol_obligation = obligation.with(skol_predicate); let r = match project_and_unify_type(selcx, &skol_obligation) { @@ -196,7 +196,10 @@ pub fn poly_project_and_unify_type<'cx, 'gcx, 'tcx>( let span = obligation.cause.span; match infcx.leak_check(false, span, &skol_map, snapshot) { Ok(()) => Ok(infcx.plug_leaks(skol_map, snapshot, result)), - Err(e) => Err(MismatchedProjectionTypes { err: e }), + Err(e) => { + debug!("poly_project_and_unify_type: leak check encountered error {:?}", e); + Err(MismatchedProjectionTypes { err: e }) + } } } Err(e) => { @@ -243,7 +246,10 @@ fn project_and_unify_type<'cx, 'gcx, 'tcx>( obligations.extend(inferred_obligations); Ok(Some(obligations)) }, - Err(err) => Err(MismatchedProjectionTypes { err: err }), + Err(err) => { + debug!("project_and_unify_type: equating types encountered error {:?}", err); + Err(MismatchedProjectionTypes { err: err }) + } } } @@ -403,7 +409,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, if let ConstVal::Unevaluated(def_id, substs) = constant.val { let tcx = self.selcx.tcx().global_tcx(); if let Some(param_env) = self.tcx().lift_to_global(&self.param_env) { - if substs.needs_infer() { + if substs.needs_infer() || substs.has_skol() { let identity_substs = Substs::identity_for_item(tcx, def_id); let instance = ty::Instance::resolve(tcx, param_env, def_id, identity_substs); if let Some(instance) = instance { diff --git a/src/librustc/traits/query/evaluate_obligation.rs b/src/librustc/traits/query/evaluate_obligation.rs new file mode 100644 index 00000000000..4e028cac49a --- /dev/null +++ b/src/librustc/traits/query/evaluate_obligation.rs @@ -0,0 +1,70 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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 infer::InferCtxt; +use infer::canonical::{Canonical, Canonicalize}; +use traits::{EvaluationResult, PredicateObligation, SelectionContext, + TraitQueryMode, OverflowError}; +use traits::query::CanonicalPredicateGoal; +use ty::{ParamEnvAnd, Predicate, TyCtxt}; + +impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { + /// Evaluates whether the predicate can be satisfied (by any means) + /// in the given `ParamEnv`. + pub fn predicate_may_hold( + &self, + obligation: &PredicateObligation<'tcx>, + ) -> bool { + self.evaluate_obligation(obligation).may_apply() + } + + /// Evaluates whether the predicate can be satisfied in the given + /// `ParamEnv`, and returns `false` if not certain. However, this is + /// not entirely accurate if inference variables are involved. + pub fn predicate_must_hold( + &self, + obligation: &PredicateObligation<'tcx>, + ) -> bool { + self.evaluate_obligation(obligation) == EvaluationResult::EvaluatedToOk + } + + // Helper function that canonicalizes and runs the query, as well as handles + // overflow. + fn evaluate_obligation( + &self, + obligation: &PredicateObligation<'tcx>, + ) -> EvaluationResult { + let (c_pred, _) = + self.canonicalize_query(&obligation.param_env.and(obligation.predicate)); + // Run canonical query. If overflow occurs, rerun from scratch but this time + // in standard trait query mode so that overflow is handled appropriately + // within `SelectionContext`. + match self.tcx.global_tcx().evaluate_obligation(c_pred) { + Ok(result) => result, + Err(OverflowError) => { + let mut selcx = + SelectionContext::with_query_mode(&self, TraitQueryMode::Standard); + selcx.evaluate_obligation_recursively(obligation) + .expect("Overflow should be caught earlier in standard query mode") + } + } + } +} + +impl<'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for ParamEnvAnd<'tcx, Predicate<'tcx>> { + type Canonicalized = CanonicalPredicateGoal<'gcx>; + + fn intern( + _gcx: TyCtxt<'_, 'gcx, 'gcx>, + value: Canonical<'gcx, Self::Lifted>, + ) -> Self::Canonicalized { + value + } +} diff --git a/src/librustc/traits/query/mod.rs b/src/librustc/traits/query/mod.rs index f1f9256f825..096633ddab2 100644 --- a/src/librustc/traits/query/mod.rs +++ b/src/librustc/traits/query/mod.rs @@ -19,6 +19,7 @@ use infer::canonical::Canonical; use ty::{self, Ty}; pub mod dropck_outlives; +pub mod evaluate_obligation; pub mod normalize; pub mod normalize_erasing_regions; @@ -27,6 +28,9 @@ pub type CanonicalProjectionGoal<'tcx> = pub type CanonicalTyGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>>>; +pub type CanonicalPredicateGoal<'tcx> = + Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::Predicate<'tcx>>>; + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct NoSolution; diff --git a/src/librustc/traits/query/normalize.rs b/src/librustc/traits/query/normalize.rs index 5e0a4ca3305..f074e061653 100644 --- a/src/librustc/traits/query/normalize.rs +++ b/src/librustc/traits/query/normalize.rs @@ -196,7 +196,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx if let ConstVal::Unevaluated(def_id, substs) = constant.val { let tcx = self.infcx.tcx.global_tcx(); if let Some(param_env) = self.tcx().lift_to_global(&self.param_env) { - if substs.needs_infer() { + if substs.needs_infer() || substs.has_skol() { let identity_substs = Substs::identity_for_item(tcx, def_id); let instance = ty::Instance::resolve(tcx, param_env, def_id, identity_substs); if let Some(instance) = instance { diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index f43f5cf3e3f..54b2cf28082 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -17,12 +17,12 @@ use self::EvaluationResult::*; use super::coherence::{self, Conflict}; use super::DerivedObligationCause; -use super::IntercrateMode; +use super::{IntercrateMode, TraitQueryMode}; use super::project; use super::project::{normalize_with_depth, Normalized, ProjectionCacheKey}; use super::{PredicateObligation, TraitObligation, ObligationCause}; use super::{ObligationCauseCode, BuiltinDerivedObligation, ImplDerivedObligation}; -use super::{SelectionError, Unimplemented, OutputTypeParameterMismatch}; +use super::{SelectionError, Unimplemented, OutputTypeParameterMismatch, Overflow}; use super::{ObjectCastObligation, Obligation}; use super::TraitNotObjectSafe; use super::Selection; @@ -87,7 +87,12 @@ pub struct SelectionContext<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> { /// Controls whether or not to filter out negative impls when selecting. /// This is used in librustdoc to distinguish between the lack of an impl /// and a negative impl - allow_negative_impls: bool + allow_negative_impls: bool, + + /// The mode that trait queries run in, which informs our error handling + /// policy. In essence, canonicalized queries need their errors propagated + /// rather than immediately reported because we do not have accurate spans. + query_mode: TraitQueryMode, } #[derive(Clone, Debug)] @@ -319,7 +324,7 @@ enum BuiltinImplConditions<'tcx> { /// all the "potential success" candidates can potentially succeed, /// so they are no-ops when unioned with a definite error, and within /// the categories it's easy to see that the unions are correct. -enum EvaluationResult { +pub enum EvaluationResult { /// Evaluation successful EvaluatedToOk, /// Evaluation is known to be ambiguous - it *might* hold for some @@ -385,7 +390,7 @@ enum EvaluationResult { } impl EvaluationResult { - fn may_apply(self) -> bool { + pub fn may_apply(self) -> bool { match self { EvaluatedToOk | EvaluatedToAmbig | @@ -408,6 +413,26 @@ impl EvaluationResult { } } +impl_stable_hash_for!(enum self::EvaluationResult { + EvaluatedToOk, + EvaluatedToAmbig, + EvaluatedToUnknown, + EvaluatedToRecur, + EvaluatedToErr +}); + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +/// Indicates that trait evaluation caused overflow. +pub struct OverflowError; + +impl_stable_hash_for!(struct OverflowError { }); + +impl<'tcx> From<OverflowError> for SelectionError<'tcx> { + fn from(OverflowError: OverflowError) -> SelectionError<'tcx> { + SelectionError::Overflow + } +} + #[derive(Clone)] pub struct EvaluationCache<'tcx> { hashmap: RefCell<FxHashMap<ty::PolyTraitRef<'tcx>, WithDepNode<EvaluationResult>>> @@ -421,6 +446,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { intercrate: None, intercrate_ambiguity_causes: None, allow_negative_impls: false, + query_mode: TraitQueryMode::Standard, } } @@ -433,6 +459,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { intercrate: Some(mode), intercrate_ambiguity_causes: None, allow_negative_impls: false, + query_mode: TraitQueryMode::Standard, } } @@ -445,6 +472,20 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { intercrate: None, intercrate_ambiguity_causes: None, allow_negative_impls, + query_mode: TraitQueryMode::Standard, + } + } + + pub fn with_query_mode(infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, + query_mode: TraitQueryMode) -> SelectionContext<'cx, 'gcx, 'tcx> { + debug!("with_query_mode({:?})", query_mode); + SelectionContext { + infcx, + freshener: infcx.freshener(), + intercrate: None, + intercrate_ambiguity_causes: None, + allow_negative_impls: false, + query_mode, } } @@ -528,12 +569,27 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { assert!(!obligation.predicate.has_escaping_regions()); let stack = self.push_stack(TraitObligationStackList::empty(), obligation); - let ret = match self.candidate_from_obligation(&stack)? { - None => None, - Some(candidate) => Some(self.confirm_candidate(obligation, candidate)?) + + let candidate = match self.candidate_from_obligation(&stack) { + Err(SelectionError::Overflow) => { + // In standard mode, overflow must have been caught and reported + // earlier. + assert!(self.query_mode == TraitQueryMode::Canonical); + return Err(SelectionError::Overflow); + }, + Err(e) => { return Err(e); }, + Ok(None) => { return Ok(None); }, + Ok(Some(candidate)) => candidate }; - Ok(ret) + match self.confirm_candidate(obligation, candidate) { + Err(SelectionError::Overflow) => { + assert!(self.query_mode == TraitQueryMode::Canonical); + return Err(SelectionError::Overflow); + }, + Err(e) => Err(e), + Ok(candidate) => Ok(Some(candidate)) + } } /////////////////////////////////////////////////////////////////////////// @@ -547,32 +603,30 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // we can be sure it does not. /// Evaluates whether the obligation `obligation` can be satisfied (by any means). - pub fn evaluate_obligation(&mut self, - obligation: &PredicateObligation<'tcx>) - -> bool + pub fn predicate_may_hold_fatal(&mut self, + obligation: &PredicateObligation<'tcx>) + -> bool { - debug!("evaluate_obligation({:?})", + debug!("predicate_may_hold_fatal({:?})", obligation); - self.probe(|this, _| { - this.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation) - .may_apply() - }) + // This fatal query is a stopgap that should only be used in standard mode, + // where we do not expect overflow to be propagated. + assert!(self.query_mode == TraitQueryMode::Standard); + + self.evaluate_obligation_recursively(obligation) + .expect("Overflow should be caught earlier in standard query mode") + .may_apply() } - /// Evaluates whether the obligation `obligation` can be satisfied, - /// and returns `false` if not certain. However, this is not entirely - /// accurate if inference variables are involved. - pub fn evaluate_obligation_conservatively(&mut self, - obligation: &PredicateObligation<'tcx>) - -> bool + /// Evaluates whether the obligation `obligation` can be satisfied and returns + /// an `EvaluationResult`. + pub fn evaluate_obligation_recursively(&mut self, + obligation: &PredicateObligation<'tcx>) + -> Result<EvaluationResult, OverflowError> { - debug!("evaluate_obligation_conservatively({:?})", - obligation); - self.probe(|this, _| { this.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation) - == EvaluatedToOk }) } @@ -582,29 +636,29 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn evaluate_predicates_recursively<'a,'o,I>(&mut self, stack: TraitObligationStackList<'o, 'tcx>, predicates: I) - -> EvaluationResult + -> Result<EvaluationResult, OverflowError> where I : IntoIterator<Item=&'a PredicateObligation<'tcx>>, 'tcx:'a { let mut result = EvaluatedToOk; for obligation in predicates { - let eval = self.evaluate_predicate_recursively(stack, obligation); + let eval = self.evaluate_predicate_recursively(stack, obligation)?; debug!("evaluate_predicate_recursively({:?}) = {:?}", obligation, eval); if let EvaluatedToErr = eval { // fast-path - EvaluatedToErr is the top of the lattice, // so we don't need to look on the other predicates. - return EvaluatedToErr; + return Ok(EvaluatedToErr); } else { result = cmp::max(result, eval); } } - result + Ok(result) } fn evaluate_predicate_recursively<'o>(&mut self, previous_stack: TraitObligationStackList<'o, 'tcx>, obligation: &PredicateObligation<'tcx>) - -> EvaluationResult + -> Result<EvaluationResult, OverflowError> { debug!("evaluate_predicate_recursively({:?})", obligation); @@ -620,11 +674,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // does this code ever run? match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) { Some(Ok(InferOk { obligations, .. })) => { - self.evaluate_predicates_recursively(previous_stack, &obligations); - EvaluatedToOk + self.evaluate_predicates_recursively(previous_stack, &obligations) }, - Some(Err(_)) => EvaluatedToErr, - None => EvaluatedToAmbig, + Some(Err(_)) => Ok(EvaluatedToErr), + None => Ok(EvaluatedToAmbig), } } @@ -636,21 +689,21 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Some(obligations) => self.evaluate_predicates_recursively(previous_stack, obligations.iter()), None => - EvaluatedToAmbig, + Ok(EvaluatedToAmbig), } } ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) => { // we do not consider region relationships when // evaluating trait matches - EvaluatedToOk + Ok(EvaluatedToOk) } ty::Predicate::ObjectSafe(trait_def_id) => { if self.tcx().is_object_safe(trait_def_id) { - EvaluatedToOk + Ok(EvaluatedToOk) } else { - EvaluatedToErr + Ok(EvaluatedToErr) } } @@ -668,10 +721,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { result } Ok(None) => { - EvaluatedToAmbig + Ok(EvaluatedToAmbig) } Err(_) => { - EvaluatedToErr + Ok(EvaluatedToErr) } } } @@ -680,13 +733,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { match self.infcx.closure_kind(closure_def_id, closure_substs) { Some(closure_kind) => { if closure_kind.extends(kind) { - EvaluatedToOk + Ok(EvaluatedToOk) } else { - EvaluatedToErr + Ok(EvaluatedToErr) } } None => { - EvaluatedToAmbig + Ok(EvaluatedToAmbig) } } } @@ -707,16 +760,16 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { promoted: None }; match self.tcx().const_eval(param_env.and(cid)) { - Ok(_) => EvaluatedToOk, - Err(_) => EvaluatedToErr + Ok(_) => Ok(EvaluatedToOk), + Err(_) => Ok(EvaluatedToErr) } } else { - EvaluatedToErr + Ok(EvaluatedToErr) } } None => { // Inference variables still left in param_env or substs. - EvaluatedToAmbig + Ok(EvaluatedToAmbig) } } } @@ -726,7 +779,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn evaluate_trait_predicate_recursively<'o>(&mut self, previous_stack: TraitObligationStackList<'o, 'tcx>, mut obligation: TraitObligation<'tcx>) - -> EvaluationResult + -> Result<EvaluationResult, OverflowError> { debug!("evaluate_trait_predicate_recursively({:?})", obligation); @@ -745,22 +798,23 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { debug!("CACHE HIT: EVAL({:?})={:?}", fresh_trait_ref, result); - return result; + return Ok(result); } let (result, dep_node) = self.in_task(|this| this.evaluate_stack(&stack)); + let result = result?; debug!("CACHE MISS: EVAL({:?})={:?}", fresh_trait_ref, result); self.insert_evaluation_cache(obligation.param_env, fresh_trait_ref, dep_node, result); - result + Ok(result) } fn evaluate_stack<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) - -> EvaluationResult + -> Result<EvaluationResult, OverflowError> { // In intercrate mode, whenever any of the types are unbound, // there can always be an impl. Even if there are no impls in @@ -815,7 +869,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } } } - return EvaluatedToAmbig; + return Ok(EvaluatedToAmbig); } if unbound_input_types && stack.iter().skip(1).any( @@ -825,7 +879,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { { debug!("evaluate_stack({:?}) --> unbound argument, recursive --> giving up", stack.fresh_trait_ref); - return EvaluatedToUnknown; + return Ok(EvaluatedToUnknown); } // If there is any previous entry on the stack that precisely @@ -860,18 +914,19 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { if self.coinductive_match(cycle) { debug!("evaluate_stack({:?}) --> recursive, coinductive", stack.fresh_trait_ref); - return EvaluatedToOk; + return Ok(EvaluatedToOk); } else { debug!("evaluate_stack({:?}) --> recursive, inductive", stack.fresh_trait_ref); - return EvaluatedToRecur; + return Ok(EvaluatedToRecur); } } match self.candidate_from_obligation(stack) { Ok(Some(c)) => self.evaluate_candidate(stack, &c), - Ok(None) => EvaluatedToAmbig, - Err(..) => EvaluatedToErr + Ok(None) => Ok(EvaluatedToAmbig), + Err(Overflow) => Err(OverflowError), + Err(..) => Ok(EvaluatedToErr) } } @@ -909,7 +964,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn evaluate_candidate<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>, candidate: &SelectionCandidate<'tcx>) - -> EvaluationResult + -> Result<EvaluationResult, OverflowError> { debug!("evaluate_candidate: depth={} candidate={:?}", stack.obligation.recursion_depth, candidate); @@ -921,12 +976,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { stack.list(), selection.nested_obligations().iter()) } - Err(..) => EvaluatedToErr + Err(..) => Ok(EvaluatedToErr) } - }); + })?; debug!("evaluate_candidate: depth={} result={:?}", stack.obligation.recursion_depth, result); - result + Ok(result) } fn check_evaluation_cache(&self, @@ -1000,7 +1055,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // not update) the cache. let recursion_limit = *self.infcx.tcx.sess.recursion_limit.get(); if stack.obligation.recursion_depth >= recursion_limit { - self.infcx().report_overflow_error(&stack.obligation, true); + match self.query_mode { + TraitQueryMode::Standard => { + self.infcx().report_overflow_error(&stack.obligation, true); + }, + TraitQueryMode::Canonical => { + return Err(Overflow); + }, + } } // Check the cache. Note that we skolemize the trait-ref @@ -1081,9 +1143,15 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { debug!("evaluate_stack: intercrate_ambiguity_causes is some"); // Heuristics: show the diagnostics when there are no candidates in crate. if let Ok(candidate_set) = self.assemble_candidates(stack) { - if !candidate_set.ambiguous && candidate_set.vec.iter().all(|c| { - !self.evaluate_candidate(stack, &c).may_apply() - }) { + let no_candidates_apply = + candidate_set + .vec + .iter() + .map(|c| self.evaluate_candidate(stack, &c)) + .collect::<Result<Vec<_>, OverflowError>>()? + .iter() + .all(|r| !r.may_apply()); + if !candidate_set.ambiguous && no_candidates_apply { let trait_ref = stack.obligation.predicate.skip_binder().trait_ref; let self_ty = trait_ref.self_ty(); let trait_desc = trait_ref.to_string(); @@ -1151,18 +1219,21 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } // Winnow, but record the exact outcome of evaluation, which - // is needed for specialization. - let mut candidates: Vec<_> = candidates.into_iter().filter_map(|c| { - let eval = self.evaluate_candidate(stack, &c); - if eval.may_apply() { - Some(EvaluatedCandidate { + // is needed for specialization. Propagate overflow if it occurs. + let candidates: Result<Vec<Option<EvaluatedCandidate>>, _> = candidates + .into_iter() + .map(|c| match self.evaluate_candidate(stack, &c) { + Ok(eval) if eval.may_apply() => Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval, - }) - } else { - None - } - }).collect(); + })), + Ok(_) => Ok(None), + Err(OverflowError) => Err(Overflow), + }) + .collect(); + + let mut candidates: Vec<EvaluatedCandidate> = + candidates?.into_iter().filter_map(|c| c).collect(); // If there are STILL multiple candidate, we can further // reduce the list by dropping duplicates -- including @@ -1438,7 +1509,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let poly_trait_predicate = self.infcx().resolve_type_vars_if_possible(&obligation.predicate); let (skol_trait_predicate, skol_map) = - self.infcx().skolemize_late_bound_regions(&poly_trait_predicate, snapshot); + self.infcx().skolemize_late_bound_regions(&poly_trait_predicate); debug!("match_projection_obligation_against_definition_bounds: \ skol_trait_predicate={:?} skol_map={:?}", skol_trait_predicate, @@ -1537,12 +1608,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let matching_bounds = all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id()); - let matching_bounds = - matching_bounds.filter( - |bound| self.evaluate_where_clause(stack, bound.clone()).may_apply()); - - let param_candidates = - matching_bounds.map(|bound| ParamCandidate(bound)); + // keep only those bounds which may apply, and propagate overflow if it occurs + let mut param_candidates = vec![]; + for bound in matching_bounds { + let wc = self.evaluate_where_clause(stack, bound.clone())?; + if wc.may_apply() { + param_candidates.push(ParamCandidate(bound)); + } + } candidates.vec.extend(param_candidates); @@ -1552,14 +1625,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn evaluate_where_clause<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>, where_clause_trait_ref: ty::PolyTraitRef<'tcx>) - -> EvaluationResult + -> Result<EvaluationResult, OverflowError> { self.probe(move |this, _| { match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) { Ok(obligations) => { this.evaluate_predicates_recursively(stack.list(), obligations.iter()) } - Err(()) => EvaluatedToErr + Err(()) => Ok(EvaluatedToErr) } }) } @@ -2265,7 +2338,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { self.in_snapshot(|this, snapshot| { let (skol_ty, skol_map) = - this.infcx().skolemize_late_bound_regions(&ty, snapshot); + this.infcx().skolemize_late_bound_regions(&ty); let Normalized { value: normalized_ty, mut obligations } = project::normalize_with_depth(this, param_env, @@ -2486,7 +2559,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let trait_obligations = self.in_snapshot(|this, snapshot| { let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); let (trait_ref, skol_map) = - this.infcx().skolemize_late_bound_regions(&poly_trait_ref, snapshot); + this.infcx().skolemize_late_bound_regions(&poly_trait_ref); let cause = obligation.derived_cause(ImplDerivedObligation); this.impl_or_trait_obligations(cause, obligation.recursion_depth + 1, @@ -3069,8 +3142,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } let (skol_obligation, skol_map) = self.infcx().skolemize_late_bound_regions( - &obligation.predicate, - snapshot); + &obligation.predicate); let skol_obligation_trait_ref = skol_obligation.trait_ref; let impl_substs = self.infcx.fresh_substs_for_item(obligation.cause.span, diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 1e3e4160de1..d7e42655bbb 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -177,6 +177,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::SelectionError<'a> { super::ConstEvalFailure(ref err) => { tcx.lift(err).map(super::ConstEvalFailure) } + super::Overflow => bug!() // FIXME: ape ConstEvalFailure? } } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 4f49b159ad3..3d154e43a9a 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -34,7 +34,7 @@ use middle::resolve_lifetime::{self, ObjectLifetimeDefault}; use middle::stability; use mir::{self, Mir, interpret}; use mir::interpret::{Value, PrimVal}; -use ty::subst::{Kind, Substs}; +use ty::subst::{Kind, Substs, Subst}; use ty::ReprOptions; use ty::Instance; use traits; @@ -1467,6 +1467,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.borrowck_mode().use_mir() } + /// If true, pattern variables for use in guards on match arms + /// will be bound as references to the data, and occurrences of + /// those variables in the guard expression will implicitly + /// dereference those bindings. (See rust-lang/rust#27282.) + pub fn all_pat_vars_are_implicit_refs_within_guards(self) -> bool { + self.borrowck_mode().use_mir() + } + /// If true, we should enable two-phase borrows checks. This is /// done with either `-Ztwo-phase-borrows` or with /// `#![feature(nll)]`. @@ -2119,7 +2127,7 @@ macro_rules! intern_method { $alloc_method:ident, $alloc_to_key:expr, $alloc_to_ret:expr, - $needs_infer:expr) -> $ty:ty) => { + $keep_in_local_tcx:expr) -> $ty:ty) => { impl<'a, 'gcx, $lt_tcx> TyCtxt<'a, 'gcx, $lt_tcx> { pub fn $method(self, v: $alloc) -> &$lt_tcx $ty { { @@ -2137,7 +2145,7 @@ macro_rules! intern_method { // HACK(eddyb) Depend on flags being accurate to // determine that all contents are in the global tcx. // See comments on Lift for why we can't use that. - if !($needs_infer)(&v) { + if !($keep_in_local_tcx)(&v) { if !self.is_global() { let v = unsafe { mem::transmute(v) @@ -2165,7 +2173,7 @@ macro_rules! intern_method { } macro_rules! direct_interners { - ($lt_tcx:tt, $($name:ident: $method:ident($needs_infer:expr) -> $ty:ty),+) => { + ($lt_tcx:tt, $($name:ident: $method:ident($keep_in_local_tcx:expr) -> $ty:ty),+) => { $(impl<$lt_tcx> PartialEq for Interned<$lt_tcx, $ty> { fn eq(&self, other: &Self) -> bool { self.0 == other.0 @@ -2180,7 +2188,10 @@ macro_rules! direct_interners { } } - intern_method!($lt_tcx, $name: $method($ty, alloc, |x| x, |x| x, $needs_infer) -> $ty);)+ + intern_method!( + $lt_tcx, + $name: $method($ty, alloc, |x| x, |x| x, $keep_in_local_tcx) -> $ty + );)+ } } @@ -2189,12 +2200,7 @@ pub fn keep_local<'tcx, T: ty::TypeFoldable<'tcx>>(x: &T) -> bool { } direct_interners!('tcx, - region: mk_region(|r| { - match r { - &ty::ReVar(_) | &ty::ReSkolemized(..) => true, - _ => false - } - }) -> RegionKind, + region: mk_region(|r: &RegionKind| r.keep_in_local_tcx()) -> RegionKind, const_: mk_const(|c: &Const| keep_local(&c.ty) || keep_local(&c.val)) -> Const<'tcx> ); @@ -2328,7 +2334,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> { let def_id = self.require_lang_item(lang_items::OwnedBoxLangItem); let adt_def = self.adt_def(def_id); - let substs = self.mk_substs(iter::once(Kind::from(ty))); + let generics = self.generics_of(def_id); + let mut substs = vec![Kind::from(ty)]; + // Add defaults for other generic params if there are some. + for def in generics.types.iter().skip(1) { + assert!(def.has_default); + let ty = self.type_of(def.def_id).subst(self, &substs); + substs.push(ty.into()); + } + let substs = self.mk_substs(substs.into_iter()); self.mk_ty(TyAdt(adt_def, substs)) } @@ -2471,7 +2485,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn mk_self_type(self) -> Ty<'tcx> { - self.mk_param(0, keywords::SelfType.name().as_str()) + self.mk_param(0, keywords::SelfType.name().as_interned_str()) } pub fn mk_param_from_def(self, def: &ty::TypeParameterDef) -> Ty<'tcx> { diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index eb06852c65d..1793b5e1edb 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -43,8 +43,8 @@ use middle::const_val::ConstVal; use hir::def_id::DefId; use ty::{self, Binder, Ty, TyCtxt, TypeFlags}; +use rustc_data_structures::lazy_btree_map::LazyBTreeMap; use std::fmt; -use std::collections::BTreeMap; use util::nodemap::FxHashSet; /// The TypeFoldable trait is implemented for every type that can be folded. @@ -91,6 +91,9 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { fn needs_infer(&self) -> bool { self.has_type_flags(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_RE_INFER) } + fn has_skol(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_RE_SKOL) + } fn needs_subst(&self) -> bool { self.has_type_flags(TypeFlags::NEEDS_SUBST) } @@ -111,15 +114,6 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { self.has_type_flags(TypeFlags::HAS_FREE_REGIONS) } - fn is_normalized_for_trans(&self) -> bool { - !self.has_type_flags(TypeFlags::HAS_RE_INFER | - TypeFlags::HAS_FREE_REGIONS | - TypeFlags::HAS_TY_INFER | - TypeFlags::HAS_PARAMS | - TypeFlags::HAS_NORMALIZABLE_PROJECTION | - TypeFlags::HAS_TY_ERR | - TypeFlags::HAS_SELF) - } /// Indicates whether this value references only 'global' /// types/lifetimes that are the same regardless of what fn we are /// in. This is used for caching. Errs on the side of returning @@ -334,7 +328,7 @@ struct RegionReplacer<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { tcx: TyCtxt<'a, 'gcx, 'tcx>, current_depth: u32, fld_r: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a), - map: BTreeMap<ty::BoundRegion, ty::Region<'tcx>> + map: LazyBTreeMap<ty::BoundRegion, ty::Region<'tcx>> } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { @@ -349,7 +343,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn replace_late_bound_regions<T,F>(self, value: &Binder<T>, mut f: F) - -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>) + -> (T, LazyBTreeMap<ty::BoundRegion, ty::Region<'tcx>>) where F : FnMut(ty::BoundRegion) -> ty::Region<'tcx>, T : TypeFoldable<'tcx>, { @@ -462,7 +456,7 @@ impl<'a, 'gcx, 'tcx> RegionReplacer<'a, 'gcx, 'tcx> { tcx, current_depth: 1, fld_r, - map: BTreeMap::default() + map: LazyBTreeMap::default() } } } diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 2819141c81b..752b7f69a6a 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -14,7 +14,7 @@ use ty::{self, Ty, TyCtxt}; use middle::cstore::{ExternCrate, ExternCrateSource}; use syntax::ast; use syntax::symbol::Symbol; -use syntax::symbol::InternedString; +use syntax::symbol::LocalInternedString; use std::cell::Cell; @@ -131,7 +131,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { { let visible_parent_map = self.visible_parent_map(LOCAL_CRATE); - let (mut cur_def, mut cur_path) = (external_def_id, Vec::<InternedString>::new()); + let (mut cur_def, mut cur_path) = (external_def_id, Vec::<LocalInternedString>::new()); loop { // If `cur_def` is a direct or injected extern crate, push the path to the crate // followed by the path to the item within the crate and return. @@ -168,8 +168,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } let data = cur_def_key.disambiguated_data.data; - let symbol = - data.get_opt_name().unwrap_or_else(|| Symbol::intern("<unnamed>").as_str()); + let symbol = data.get_opt_name().map(|n| n.as_str()).unwrap_or_else(|| { + Symbol::intern("<unnamed>").as_str() + }); cur_path.push(symbol); match visible_parent_map.get(&cur_def) { @@ -221,7 +222,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { data @ DefPathData::GlobalMetaData(..) => { let parent_def_id = self.parent_def_id(def_id).unwrap(); self.push_item_path(buffer, parent_def_id); - buffer.push(&data.as_interned_str()); + buffer.push(&data.as_interned_str().as_symbol().as_str()); } DefPathData::StructCtor => { // present `X` instead of `X::{{constructor}}` let parent_def_id = self.parent_def_id(def_id).unwrap(); diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index ef2a4246628..a319b341ebb 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -19,7 +19,6 @@ use std::cmp; use std::fmt; use std::i128; use std::mem; -use std::ops::RangeInclusive; use ich::StableHashingContext; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, @@ -149,7 +148,7 @@ pub const FAT_PTR_ADDR: usize = 0; /// - For a slice, this is the length. pub const FAT_PTR_EXTRA: usize = 1; -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)] pub enum LayoutError<'tcx> { Unknown(Ty<'tcx>), SizeOverflow(Ty<'tcx>) @@ -492,7 +491,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { ty::TyFloat(FloatTy::F64) => scalar(F64), ty::TyFnPtr(_) => { let mut ptr = scalar_unit(Pointer); - ptr.valid_range.start = 1; + ptr.valid_range = 1..=*ptr.valid_range.end(); tcx.intern_layout(LayoutDetails::scalar(self, ptr)) } @@ -506,7 +505,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) => { let mut data_ptr = scalar_unit(Pointer); if !ty.is_unsafe_ptr() { - data_ptr.valid_range.start = 1; + data_ptr.valid_range = 1..=*data_ptr.valid_range.end(); } let pointee = tcx.normalize_erasing_regions(param_env, pointee); @@ -524,7 +523,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } ty::TyDynamic(..) => { let mut vtable = scalar_unit(Pointer); - vtable.valid_range.start = 1; + vtable.valid_range = 1..=*vtable.valid_range.end(); vtable } _ => return Err(LayoutError::Unknown(unsized_part)) @@ -751,8 +750,8 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { match st.abi { Abi::Scalar(ref mut scalar) | Abi::ScalarPair(ref mut scalar, _) => { - if scalar.valid_range.start == 0 { - scalar.valid_range.start = 1; + if *scalar.valid_range.start() == 0 { + scalar.valid_range = 1..=*scalar.valid_range.end(); } } _ => {} @@ -788,18 +787,15 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } } } - if niche_variants.start > v { - niche_variants.start = v; - } - niche_variants.end = v; + niche_variants = *niche_variants.start().min(&v)..=v; } - if niche_variants.start > niche_variants.end { + if niche_variants.start() > niche_variants.end() { dataful_variant = None; } if let Some(i) = dataful_variant { - let count = (niche_variants.end - niche_variants.start + 1) as u128; + let count = (niche_variants.end() - niche_variants.start() + 1) as u128; for (field_index, &field) in variants[i].iter().enumerate() { let (offset, niche, niche_start) = match self.find_niche(field, count)? { @@ -897,7 +893,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } // Create the set of structs that represent each variant. - let mut variants = variants.into_iter().enumerate().map(|(i, field_layouts)| { + let mut layout_variants = variants.iter().enumerate().map(|(i, field_layouts)| { let mut st = univariant_uninterned(&field_layouts, &def.repr, StructKind::Prefixed(min_ity.size(), prefix_align))?; st.variants = Variants::Single { index: i }; @@ -944,11 +940,15 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { // We increase the size of the discriminant to avoid LLVM copying // padding when it doesn't need to. This normally causes unaligned // load/stores and excessive memcpy/memset operations. By using a - // bigger integer size, LLVM can be sure about it's contents and + // bigger integer size, LLVM can be sure about its contents and // won't be so conservative. // Use the initial field alignment - let mut ity = Integer::for_abi_align(dl, start_align).unwrap_or(min_ity); + let mut ity = if def.repr.c() || def.repr.int.is_some() { + min_ity + } else { + Integer::for_abi_align(dl, start_align).unwrap_or(min_ity) + }; // If the alignment is not larger than the chosen discriminant size, // don't use the alignment as the final size. @@ -958,7 +958,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { // Patch up the variants' first few fields. let old_ity_size = min_ity.size(); let new_ity_size = ity.size(); - for variant in &mut variants { + for variant in &mut layout_variants { if variant.abi == Abi::Uninhabited { continue; } @@ -985,15 +985,80 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { value: Int(ity, signed), valid_range: (min as u128 & tag_mask)..=(max as u128 & tag_mask), }; - let abi = if tag.value.size(dl) == size { - Abi::Scalar(tag.clone()) - } else { - Abi::Aggregate { sized: true } - }; + let mut abi = Abi::Aggregate { sized: true }; + if tag.value.size(dl) == size { + abi = Abi::Scalar(tag.clone()); + } else if !tag.is_bool() { + // HACK(nox): Blindly using ScalarPair for all tagged enums + // where applicable leads to Option<u8> being handled as {i1, i8}, + // which later confuses SROA and some loop optimisations, + // ultimately leading to the repeat-trusted-len test + // failing. We make the trade-off of using ScalarPair only + // for types where the tag isn't a boolean. + let mut common_prim = None; + for (field_layouts, layout_variant) in variants.iter().zip(&layout_variants) { + let offsets = match layout_variant.fields { + FieldPlacement::Arbitrary { ref offsets, .. } => offsets, + _ => bug!(), + }; + let mut fields = field_layouts + .iter() + .zip(offsets) + .filter(|p| !p.0.is_zst()); + let (field, offset) = match (fields.next(), fields.next()) { + (None, None) => continue, + (Some(pair), None) => pair, + _ => { + common_prim = None; + break; + } + }; + let prim = match field.details.abi { + Abi::Scalar(ref scalar) => scalar.value, + _ => { + common_prim = None; + break; + } + }; + if let Some(pair) = common_prim { + // This is pretty conservative. We could go fancier + // by conflating things like i32 and u32, or even + // realising that (u8, u8) could just cohabit with + // u16 or even u32. + if pair != (prim, offset) { + common_prim = None; + break; + } + } else { + common_prim = Some((prim, offset)); + } + } + if let Some((prim, offset)) = common_prim { + let pair = scalar_pair(tag.clone(), scalar_unit(prim)); + let pair_offsets = match pair.fields { + FieldPlacement::Arbitrary { + ref offsets, + ref memory_index + } => { + assert_eq!(memory_index, &[0, 1]); + offsets + } + _ => bug!() + }; + if pair_offsets[0] == Size::from_bytes(0) && + pair_offsets[1] == *offset && + align == pair.align && + size == pair.size { + // We can use `ScalarPair` only when it matches our + // already computed layout (including `#[repr(C)]`). + abi = pair.abi; + } + } + } tcx.intern_layout(LayoutDetails { variants: Variants::Tagged { discr: tag, - variants + variants: layout_variants, }, fields: FieldPlacement::Arbitrary { offsets: vec![Size::from_bytes(0)], @@ -1594,10 +1659,10 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { let max_value = !0u128 >> (128 - bits); // Find out how many values are outside the valid range. - let niches = if v.start <= v.end { - v.start + (max_value - v.end) + let niches = if v.start() <= v.end() { + v.start() + (max_value - v.end()) } else { - v.start - v.end - 1 + v.start() - v.end() - 1 }; // Give up if we can't fit `count` consecutive niches. @@ -1605,11 +1670,11 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { return None; } - let niche_start = v.end.wrapping_add(1) & max_value; - let niche_end = v.end.wrapping_add(count) & max_value; + let niche_start = v.end().wrapping_add(1) & max_value; + let niche_end = v.end().wrapping_add(count) & max_value; Some((offset, Scalar { value, - valid_range: v.start..=niche_end + valid_range: *v.start()..=niche_end }, niche_start)) }; @@ -1679,14 +1744,14 @@ impl<'a> HashStable<StableHashingContext<'a>> for Variants { } NicheFilling { dataful_variant, - niche_variants: RangeInclusive { start, end }, + ref niche_variants, ref niche, niche_start, ref variants, } => { dataful_variant.hash_stable(hcx, hasher); - start.hash_stable(hcx, hasher); - end.hash_stable(hcx, hasher); + niche_variants.start().hash_stable(hcx, hasher); + niche_variants.end().hash_stable(hcx, hasher); niche.hash_stable(hcx, hasher); niche_start.hash_stable(hcx, hasher); variants.hash_stable(hcx, hasher); @@ -1749,10 +1814,10 @@ impl<'a> HashStable<StableHashingContext<'a>> for Scalar { fn hash_stable<W: StableHasherResult>(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher<W>) { - let Scalar { value, valid_range: RangeInclusive { start, end } } = *self; + let Scalar { value, ref valid_range } = *self; value.hash_stable(hcx, hasher); - start.hash_stable(hcx, hasher); - end.hash_stable(hcx, hasher); + valid_range.start().hash_stable(hcx, hasher); + valid_range.end().hash_stable(hcx, hasher); } } diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs index 735fe06560f..57c8c4f34e7 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -9,24 +9,45 @@ // except according to those terms. use dep_graph::SerializedDepNodeIndex; +use dep_graph::DepNode; use hir::def_id::{CrateNum, DefId, DefIndex}; use mir::interpret::{GlobalId}; -use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal}; +use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal}; use ty::{self, ParamEnvAnd, Ty, TyCtxt}; use ty::subst::Substs; use ty::maps::queries; +use ty::maps::Query; +use ty::maps::QueryMap; use std::hash::Hash; +use std::fmt::Debug; use syntax_pos::symbol::InternedString; +use rustc_data_structures::sync::Lock; +use rustc_data_structures::stable_hasher::HashStable; +use ich::StableHashingContext; /// Query configuration and description traits. -pub trait QueryConfig { - type Key: Eq + Hash + Clone; - type Value; +pub trait QueryConfig<'tcx> { + const NAME: &'static str; + + type Key: Eq + Hash + Clone + Debug; + type Value: Clone + for<'a> HashStable<StableHashingContext<'a>>; + + fn query(key: Self::Key) -> Query<'tcx>; + + // Don't use this method to access query results, instead use the methods on TyCtxt + fn query_map<'a>(tcx: TyCtxt<'a, 'tcx, '_>) -> &'a Lock<QueryMap<'tcx, Self>>; + + fn to_dep_node(tcx: TyCtxt<'_, 'tcx, '_>, key: &Self::Key) -> DepNode; + + // Don't use this method to compute query results, instead use the methods on TyCtxt + fn compute(tcx: TyCtxt<'_, 'tcx, '_>, key: Self::Key) -> Self::Value; + + fn handle_cycle_error(tcx: TyCtxt<'_, 'tcx, '_>) -> Self::Value; } -pub(super) trait QueryDescription<'tcx>: QueryConfig { +pub trait QueryDescription<'tcx>: QueryConfig<'tcx> { fn describe(tcx: TyCtxt, key: Self::Key) -> String; #[inline] @@ -41,7 +62,7 @@ pub(super) trait QueryDescription<'tcx>: QueryConfig { } } -impl<'tcx, M: QueryConfig<Key=DefId>> QueryDescription<'tcx> for M { +impl<'tcx, M: QueryConfig<'tcx, Key=DefId>> QueryDescription<'tcx> for M { default fn describe(tcx: TyCtxt, def_id: DefId) -> String { if !tcx.sess.verbose() { format!("processing `{}`", tcx.item_path_str(def_id)) @@ -73,6 +94,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::normalize_ty_after_erasing_region } } +impl<'tcx> QueryDescription<'tcx> for queries::evaluate_obligation<'tcx> { + fn describe(_tcx: TyCtxt, goal: CanonicalPredicateGoal<'tcx>) -> String { + format!("evaluating trait selection obligation `{}`", goal.value.value) + } +} + impl<'tcx> QueryDescription<'tcx> for queries::is_copy_raw<'tcx> { fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String { format!("computing whether `{}` is `Copy`", env.value) diff --git a/src/librustc/ty/maps/job.rs b/src/librustc/ty/maps/job.rs index 374406158c1..3b6af018d6b 100644 --- a/src/librustc/ty/maps/job.rs +++ b/src/librustc/ty/maps/job.rs @@ -17,13 +17,10 @@ use ty::context::TyCtxt; use errors::Diagnostic; /// Indicates the state of a query for a given key in a query map -pub(super) enum QueryResult<'tcx, T> { +pub(super) enum QueryResult<'tcx> { /// An already executing query. The query job can be used to await for its completion Started(Lrc<QueryJob<'tcx>>), - /// The query is complete and produced `T` - Complete(T), - /// The query panicked. Queries trying to wait on this will raise a fatal error / silently panic Poisoned, } diff --git a/src/librustc/ty/maps/keys.rs b/src/librustc/ty/maps/keys.rs index 72f2cb49abc..da29f23589e 100644 --- a/src/librustc/ty/maps/keys.rs +++ b/src/librustc/ty/maps/keys.rs @@ -11,7 +11,7 @@ //! Defines the set of legal keys that can be used in queries. use hir::def_id::{CrateNum, DefId, LOCAL_CRATE, DefIndex}; -use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal}; +use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal}; use ty::{self, Ty, TyCtxt}; use ty::subst::Substs; use ty::fast_reject::SimplifiedType; @@ -200,3 +200,13 @@ impl<'tcx> Key for CanonicalTyGoal<'tcx> { DUMMY_SP } } + +impl<'tcx> Key for CanonicalPredicateGoal<'tcx> { + fn map_crate(&self) -> CrateNum { + LOCAL_CRATE + } + + fn default_span(&self, _tcx: TyCtxt) -> Span { + DUMMY_SP + } +} diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index f5cb3643de8..d89846a75ef 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -9,7 +9,6 @@ // except according to those terms. use dep_graph::{DepConstructor, DepNode}; -use errors::DiagnosticBuilder; use hir::def_id::{CrateNum, DefId, DefIndex}; use hir::def::{Def, Export}; use hir::{self, TraitCandidate, ItemLocalId, TransFnAttrs}; @@ -32,8 +31,9 @@ use mir; use mir::interpret::{GlobalId}; use session::{CompileResult, CrateDisambiguator}; use session::config::OutputFilenames; -use traits::Vtable; -use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal, NoSolution}; +use traits::{self, Vtable}; +use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, + CanonicalTyGoal, NoSolution}; use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult}; use traits::query::normalize::NormalizationResult; use traits::specialization_graph; @@ -42,7 +42,7 @@ use ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt}; use ty::steal::Steal; use ty::subst::Substs; use util::nodemap::{DefIdSet, DefIdMap, ItemLocalSet}; -use util::common::{profq_msg, ErrorReported, ProfileQueriesMsg}; +use util::common::{ErrorReported}; use rustc_data_structures::indexed_set::IdxSetBuf; use rustc_target::spec::PanicStrategy; @@ -67,7 +67,6 @@ pub use self::plumbing::force_from_dep_node; mod job; pub use self::job::{QueryJob, QueryInfo}; -use self::job::QueryResult; mod keys; pub use self::keys::Key; @@ -212,7 +211,7 @@ define_maps! { <'tcx> /// Borrow checks the function body. If this is a closure, returns /// additional requirements that the closure's creator must verify. - [] fn mir_borrowck: MirBorrowCheck(DefId) -> Option<mir::ClosureRegionRequirements<'tcx>>, + [] fn mir_borrowck: MirBorrowCheck(DefId) -> mir::BorrowCheckResult<'tcx>, /// Gets a complete map from all types to their inherent impls. /// Not meant to be used directly outside of coherence. @@ -433,6 +432,12 @@ define_maps! { <'tcx> NoSolution, >, + /// Do not call this query directly: invoke `infcx.predicate_may_hold()` or + /// `infcx.predicate_must_hold()` instead. + [] fn evaluate_obligation: EvaluateObligation( + CanonicalPredicateGoal<'tcx> + ) -> Result<traits::EvaluationResult, traits::OverflowError>, + [] fn substitute_normalize_and_test_predicates: substitute_normalize_and_test_predicates_node((DefId, &'tcx Substs<'tcx>)) -> bool, diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs index f88e33c708e..cea2a03fd53 100644 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ b/src/librustc/ty/maps/on_disk_cache.rs @@ -30,7 +30,6 @@ use syntax::codemap::{CodeMap, StableFilemapId}; use syntax_pos::{BytePos, Span, DUMMY_SP, FileMap}; use syntax_pos::hygiene::{Mark, SyntaxContext, ExpnInfo}; use ty; -use ty::maps::job::QueryResult; use ty::codec::{self as ty_codec, TyDecoder, TyEncoder}; use ty::context::TyCtxt; use util::common::time; @@ -239,14 +238,12 @@ impl<'sess> OnDiskCache<'sess> { encode_query_results::<specialization_graph_of, _>(tcx, enc, qri)?; // const eval is special, it only encodes successfully evaluated constants - use ty::maps::plumbing::GetCacheInternal; - for (key, entry) in const_eval::get_cache_internal(tcx).map.iter() { + use ty::maps::QueryConfig; + let map = const_eval::query_map(tcx).borrow(); + assert!(map.active.is_empty()); + for (key, entry) in map.results.iter() { use ty::maps::config::QueryDescription; if const_eval::cache_on_disk(key.clone()) { - let entry = match *entry { - QueryResult::Complete(ref v) => v, - _ => panic!("incomplete query"), - }; if let Ok(ref value) = entry.value { let dep_node = SerializedDepNodeIndex::new(entry.index.index()); @@ -1124,7 +1121,7 @@ fn encode_query_results<'enc, 'a, 'tcx, Q, E>(tcx: TyCtxt<'a, 'tcx, 'tcx>, encoder: &mut CacheEncoder<'enc, 'a, 'tcx, E>, query_result_index: &mut EncodedQueryResultIndex) -> Result<(), E::Error> - where Q: super::plumbing::GetCacheInternal<'tcx>, + where Q: super::config::QueryDescription<'tcx>, E: 'enc + TyEncoder, Q::Value: Encodable, { @@ -1133,12 +1130,10 @@ fn encode_query_results<'enc, 'a, 'tcx, Q, E>(tcx: TyCtxt<'a, 'tcx, 'tcx>, time(tcx.sess, desc, || { - for (key, entry) in Q::get_cache_internal(tcx).map.iter() { + let map = Q::query_map(tcx).borrow(); + assert!(map.active.is_empty()); + for (key, entry) in map.results.iter() { if Q::cache_on_disk(key.clone()) { - let entry = match *entry { - QueryResult::Complete(ref v) => v, - _ => panic!("incomplete query"), - }; let dep_node = SerializedDepNodeIndex::new(entry.index.index()); // Record position of the cache entry diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index 61a4eb58531..37950463f74 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -15,21 +15,29 @@ use dep_graph::{DepNodeIndex, DepNode, DepKind, DepNodeColor}; use errors::DiagnosticBuilder; use errors::Level; +use errors::Diagnostic; +use errors::FatalError; use ty::tls; use ty::{TyCtxt}; use ty::maps::Query; +use ty::maps::config::QueryConfig; use ty::maps::config::QueryDescription; -use ty::maps::job::{QueryResult, QueryInfo}; +use ty::maps::job::{QueryJob, QueryResult, QueryInfo}; use ty::item_path; +use util::common::{profq_msg, ProfileQueriesMsg, QueryMsg}; + use rustc_data_structures::fx::{FxHashMap}; -use rustc_data_structures::sync::LockGuard; -use std::marker::PhantomData; +use rustc_data_structures::sync::{Lrc, Lock}; +use std::mem; +use std::ptr; +use std::collections::hash_map::Entry; use syntax_pos::Span; +use syntax::codemap::DUMMY_SP; -pub(super) struct QueryMap<'tcx, D: QueryDescription<'tcx>> { - phantom: PhantomData<(D, &'tcx ())>, - pub(super) map: FxHashMap<D::Key, QueryResult<'tcx, QueryValue<D::Value>>>, +pub struct QueryMap<'tcx, D: QueryConfig<'tcx> + ?Sized> { + pub(super) results: FxHashMap<D::Key, QueryValue<D::Value>>, + pub(super) active: FxHashMap<D::Key, QueryResult<'tcx>>, } pub(super) struct QueryValue<T> { @@ -48,18 +56,166 @@ impl<T> QueryValue<T> { } } -impl<'tcx, M: QueryDescription<'tcx>> QueryMap<'tcx, M> { +impl<'tcx, M: QueryConfig<'tcx>> QueryMap<'tcx, M> { pub(super) fn new() -> QueryMap<'tcx, M> { QueryMap { - phantom: PhantomData, - map: FxHashMap(), + results: FxHashMap(), + active: FxHashMap(), + } + } +} + +// If enabled, send a message to the profile-queries thread +macro_rules! profq_msg { + ($tcx:expr, $msg:expr) => { + if cfg!(debug_assertions) { + if $tcx.sess.profile_queries() { + profq_msg($tcx.sess, $msg) + } + } + } +} + +// If enabled, format a key using its debug string, which can be +// expensive to compute (in terms of time). +macro_rules! profq_query_msg { + ($query:expr, $tcx:expr, $key:expr) => {{ + let msg = if cfg!(debug_assertions) { + if $tcx.sess.profile_queries_and_keys() { + Some(format!("{:?}", $key)) + } else { None } + } else { None }; + QueryMsg { + query: $query, + msg, + } + }} +} + +/// A type representing the responsibility to execute the job in the `job` field. +/// This will poison the relevant query if dropped. +pub(super) struct JobOwner<'a, 'tcx: 'a, Q: QueryDescription<'tcx> + 'a> { + map: &'a Lock<QueryMap<'tcx, Q>>, + key: Q::Key, + job: Lrc<QueryJob<'tcx>>, +} + +impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { + /// Either gets a JobOwner corresponding the the query, allowing us to + /// start executing the query, or it returns with the result of the query. + /// If the query is executing elsewhere, this will wait for it. + /// If the query panicked, this will silently panic. + pub(super) fn try_get( + tcx: TyCtxt<'a, 'tcx, '_>, + span: Span, + key: &Q::Key, + ) -> TryGetJob<'a, 'tcx, Q> { + let map = Q::query_map(tcx); + loop { + let mut lock = map.borrow_mut(); + if let Some(value) = lock.results.get(key) { + profq_msg!(tcx, ProfileQueriesMsg::CacheHit); + let result = Ok((value.value.clone(), value.index)); + return TryGetJob::JobCompleted(result); + } + let job = match lock.active.entry((*key).clone()) { + Entry::Occupied(entry) => { + match *entry.get() { + QueryResult::Started(ref job) => job.clone(), + QueryResult::Poisoned => FatalError.raise(), + } + } + Entry::Vacant(entry) => { + // No job entry for this query. Return a new one to be started later + return tls::with_related_context(tcx, |icx| { + let info = QueryInfo { + span, + query: Q::query(key.clone()), + }; + let job = Lrc::new(QueryJob::new(info, icx.query.clone())); + let owner = JobOwner { + map, + job: job.clone(), + key: (*key).clone(), + }; + entry.insert(QueryResult::Started(job)); + TryGetJob::NotYetStarted(owner) + }) + } + }; + mem::drop(lock); + + if let Err(cycle) = job.await(tcx, span) { + return TryGetJob::JobCompleted(Err(cycle)); + } + } + } + + /// Completes the query by updating the query map with the `result`, + /// signals the waiter and forgets the JobOwner, so it won't poison the query + pub(super) fn complete(self, result: &Q::Value, dep_node_index: DepNodeIndex) { + // We can move out of `self` here because we `mem::forget` it below + let key = unsafe { ptr::read(&self.key) }; + let job = unsafe { ptr::read(&self.job) }; + let map = self.map; + + // Forget ourself so our destructor won't poison the query + mem::forget(self); + + let value = QueryValue::new(result.clone(), dep_node_index); + { + let mut lock = map.borrow_mut(); + lock.active.remove(&key); + lock.results.insert(key, value); } + + job.signal_complete(); + } + + /// Executes a job by changing the ImplicitCtxt to point to the + /// new query job while it executes. It returns the diagnostics + /// captured during execution and the actual result. + pub(super) fn start<'lcx, F, R>( + &self, + tcx: TyCtxt<'_, 'tcx, 'lcx>, + compute: F) + -> (R, Vec<Diagnostic>) + where + F: for<'b> FnOnce(TyCtxt<'b, 'tcx, 'lcx>) -> R + { + // The TyCtxt stored in TLS has the same global interner lifetime + // as `tcx`, so we use `with_related_context` to relate the 'gcx lifetimes + // when accessing the ImplicitCtxt + let r = tls::with_related_context(tcx, move |current_icx| { + // Update the ImplicitCtxt to point to our new query job + let new_icx = tls::ImplicitCtxt { + tcx, + query: Some(self.job.clone()), + layout_depth: current_icx.layout_depth, + task: current_icx.task, + }; + + // Use the ImplicitCtxt while we execute the query + tls::enter_context(&new_icx, |_| { + compute(tcx) + }) + }); + + // Extract the diagnostic from the job + let diagnostics = mem::replace(&mut *self.job.diagnostics.lock(), Vec::new()); + + (r, diagnostics) } } -pub(super) trait GetCacheInternal<'tcx>: QueryDescription<'tcx> + Sized { - fn get_cache_internal<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> LockGuard<'a, QueryMap<'tcx, Self>>; +impl<'a, 'tcx, Q: QueryDescription<'tcx>> Drop for JobOwner<'a, 'tcx, Q> { + fn drop(&mut self) { + // Poison the query so jobs waiting on it panic + self.map.borrow_mut().active.insert(self.key.clone(), QueryResult::Poisoned); + // Also signal the completion of the job, so waiters + // will continue execution + self.job.signal_complete(); + } } #[derive(Clone)] @@ -70,14 +226,14 @@ pub(super) struct CycleError<'tcx> { } /// The result of `try_get_lock` -pub(super) enum TryGetLock<'a, 'tcx: 'a, T, D: QueryDescription<'tcx> + 'a> { +pub(super) enum TryGetJob<'a, 'tcx: 'a, D: QueryDescription<'tcx> + 'a> { /// The query is not yet started. Contains a guard to the map eventually used to start it. - NotYetStarted(LockGuard<'a, QueryMap<'tcx, D>>), + NotYetStarted(JobOwner<'a, 'tcx, D>), /// The query was already completed. /// Returns the result of the query and its dep node index /// if it succeeded or a cycle error if it failed - JobCompleted(Result<(T, DepNodeIndex), CycleError<'tcx>>), + JobCompleted(Result<(D::Value, DepNodeIndex), CycleError<'tcx>>), } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { @@ -180,28 +336,277 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } } -} -// If enabled, send a message to the profile-queries thread -macro_rules! profq_msg { - ($tcx:expr, $msg:expr) => { - if cfg!(debug_assertions) { - if $tcx.sess.profile_queries() { - profq_msg($tcx.sess, $msg) + fn try_get_with<Q: QueryDescription<'gcx>>( + self, + span: Span, + key: Q::Key) + -> Result<Q::Value, CycleError<'gcx>> + { + debug!("ty::queries::{}::try_get_with(key={:?}, span={:?})", + Q::NAME, + key, + span); + + profq_msg!(self, + ProfileQueriesMsg::QueryBegin( + span.data(), + profq_query_msg!(Q::NAME, self, key), + ) + ); + + let job = match JobOwner::try_get(self, span, &key) { + TryGetJob::NotYetStarted(job) => job, + TryGetJob::JobCompleted(result) => { + return result.map(|(v, index)| { + self.dep_graph.read_index(index); + v + }) } + }; + + // Fast path for when incr. comp. is off. `to_dep_node` is + // expensive for some DepKinds. + if !self.dep_graph.is_fully_enabled() { + let null_dep_node = DepNode::new_no_params(::dep_graph::DepKind::Null); + return self.force_query_with_job::<Q>(key, job, null_dep_node).map(|(v, _)| v); + } + + let dep_node = Q::to_dep_node(self, &key); + + if dep_node.kind.is_anon() { + profq_msg!(self, ProfileQueriesMsg::ProviderBegin); + + let res = job.start(self, |tcx| { + tcx.dep_graph.with_anon_task(dep_node.kind, || { + Q::compute(tcx.global_tcx(), key) + }) + }); + + profq_msg!(self, ProfileQueriesMsg::ProviderEnd); + let ((result, dep_node_index), diagnostics) = res; + + self.dep_graph.read_index(dep_node_index); + + self.on_disk_query_result_cache + .store_diagnostics_for_anon_node(dep_node_index, diagnostics); + + job.complete(&result, dep_node_index); + + return Ok(result); + } + + if !dep_node.kind.is_input() { + if let Some(dep_node_index) = self.try_mark_green_and_read(&dep_node) { + profq_msg!(self, ProfileQueriesMsg::CacheHit); + return self.load_from_disk_and_cache_in_memory::<Q>(key, + job, + dep_node_index, + &dep_node) + } + } + + match self.force_query_with_job::<Q>(key, job, dep_node) { + Ok((result, dep_node_index)) => { + self.dep_graph.read_index(dep_node_index); + Ok(result) + } + Err(e) => Err(e) } } -} -// If enabled, format a key using its debug string, which can be -// expensive to compute (in terms of time). -macro_rules! profq_key { - ($tcx:expr, $key:expr) => { - if cfg!(debug_assertions) { - if $tcx.sess.profile_queries_and_keys() { - Some(format!("{:?}", $key)) - } else { None } - } else { None } + fn load_from_disk_and_cache_in_memory<Q: QueryDescription<'gcx>>( + self, + key: Q::Key, + job: JobOwner<'a, 'gcx, Q>, + dep_node_index: DepNodeIndex, + dep_node: &DepNode + ) -> Result<Q::Value, CycleError<'gcx>> + { + // Note this function can be called concurrently from the same query + // We must ensure that this is handled correctly + + debug_assert!(self.dep_graph.is_green(dep_node)); + + // First we try to load the result from the on-disk cache + let result = if Q::cache_on_disk(key.clone()) && + self.sess.opts.debugging_opts.incremental_queries { + let prev_dep_node_index = + self.dep_graph.prev_dep_node_index_of(dep_node); + let result = Q::try_load_from_disk(self.global_tcx(), + prev_dep_node_index); + + // We always expect to find a cached result for things that + // can be forced from DepNode. + debug_assert!(!dep_node.kind.can_reconstruct_query_key() || + result.is_some(), + "Missing on-disk cache entry for {:?}", + dep_node); + result + } else { + // Some things are never cached on disk. + None + }; + + let result = if let Some(result) = result { + result + } else { + // We could not load a result from the on-disk cache, 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, _) = job.start(self, |tcx| { + // The dep-graph for this computation is already in + // place + tcx.dep_graph.with_ignore(|| { + Q::compute(tcx, key) + }) + }); + result + }; + + // If -Zincremental-verify-ich is specified, re-hash results from + // the cache and make sure that they have the expected fingerprint. + if self.sess.opts.debugging_opts.incremental_verify_ich { + use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; + use ich::Fingerprint; + + assert!(Some(self.dep_graph.fingerprint_of(dep_node_index)) == + self.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 = self.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 = self.dep_graph.fingerprint_of(dep_node_index); + + assert!(new_hash == old_hash, "Found unstable fingerprints \ + for {:?}", dep_node); + } + + if self.sess.opts.debugging_opts.query_dep_graph { + self.dep_graph.mark_loaded_from_cache(dep_node_index, true); + } + + job.complete(&result, dep_node_index); + + Ok(result) + } + + fn force_query_with_job<Q: QueryDescription<'gcx>>( + self, + key: Q::Key, + job: JobOwner<'_, 'gcx, Q>, + dep_node: DepNode) + -> Result<(Q::Value, DepNodeIndex), CycleError<'gcx>> { + // If the following assertion triggers, it can have two reasons: + // 1. Something is wrong with DepNode creation, either here or + // in DepGraph::try_mark_green() + // 2. Two distinct query keys get mapped to the same DepNode + // (see for example #48923) + assert!(!self.dep_graph.dep_node_exists(&dep_node), + "Forcing query with already existing DepNode.\n\ + - query-key: {:?}\n\ + - dep-node: {:?}", + key, dep_node); + + profq_msg!(self, ProfileQueriesMsg::ProviderBegin); + let res = job.start(self, |tcx| { + if dep_node.kind.is_eval_always() { + tcx.dep_graph.with_eval_always_task(dep_node, + tcx, + key, + Q::compute) + } else { + tcx.dep_graph.with_task(dep_node, + tcx, + key, + Q::compute) + } + }); + profq_msg!(self, ProfileQueriesMsg::ProviderEnd); + + let ((result, dep_node_index), diagnostics) = res; + + if self.sess.opts.debugging_opts.query_dep_graph { + self.dep_graph.mark_loaded_from_cache(dep_node_index, false); + } + + if dep_node.kind != ::dep_graph::DepKind::Null { + self.on_disk_query_result_cache + .store_diagnostics(dep_node_index, diagnostics); + } + + job.complete(&result, dep_node_index); + + Ok((result, dep_node_index)) + } + + /// Ensure that either this query has all green inputs or been executed. + /// Executing query::ensure(D) is considered a read of the dep-node D. + /// + /// This function is particularly useful when executing passes for their + /// side-effects -- e.g., in order to report errors for erroneous programs. + /// + /// Note: The optimization is only available during incr. comp. + pub fn ensure_query<Q: QueryDescription<'gcx>>(self, key: Q::Key) -> () { + let dep_node = Q::to_dep_node(self, &key); + + // Ensuring an "input" or anonymous query makes no sense + assert!(!dep_node.kind.is_anon()); + assert!(!dep_node.kind.is_input()); + if self.try_mark_green_and_read(&dep_node).is_none() { + // A None return from `try_mark_green_and_read` means that this is either + // a new dep node or that the dep node has already been marked red. + // Either way, we can't call `dep_graph.read()` as we don't have the + // DepNodeIndex. We must invoke the query itself. The performance cost + // this introduces should be negligible as we'll immediately hit the + // in-memory cache, or another query down the line will. + let _ = self.get_query::<Q>(DUMMY_SP, key); + } + } + + #[allow(dead_code)] + fn force_query<Q: QueryDescription<'gcx>>( + self, + key: Q::Key, + span: Span, + dep_node: DepNode + ) -> Result<(Q::Value, DepNodeIndex), CycleError<'gcx>> { + // We may be concurrently trying both execute and force a query + // Ensure that only one of them runs the query + let job = match JobOwner::try_get(self, span, &key) { + TryGetJob::NotYetStarted(job) => job, + TryGetJob::JobCompleted(result) => return result, + }; + self.force_query_with_job::<Q>(key, job, dep_node) + } + + pub fn try_get_query<Q: QueryDescription<'gcx>>( + self, + span: Span, + key: Q::Key + ) -> Result<Q::Value, DiagnosticBuilder<'a>> { + match self.try_get_with::<Q>(span, key) { + Ok(e) => Ok(e), + Err(e) => Err(self.report_cycle(e)), + } + } + + pub fn get_query<Q: QueryDescription<'gcx>>(self, span: Span, key: Q::Key) -> Q::Value { + self.try_get_query::<Q>(span, key).unwrap_or_else(|mut e| { + e.emit(); + Q::handle_cycle_error(self) + }) } } @@ -210,7 +615,7 @@ macro_rules! handle_cycle_error { Value::from_cycle_error($this.global_tcx()) }}; ([fatal_cycle$(, $modifiers:ident)*][$this:expr]) => {{ - $this.tcx.sess.abort_if_errors(); + $this.sess.abort_if_errors(); unreachable!(); }}; ([$other:ident$(, $modifiers:ident)*][$($args:tt)*]) => { @@ -223,12 +628,7 @@ macro_rules! define_maps { $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident: $node:ident($K:ty) -> $V:ty,)*) => { - use dep_graph::DepNodeIndex; - use std::mem; - use errors::Diagnostic; - use errors::FatalError; - use rustc_data_structures::sync::{Lock, LockGuard}; - use rustc_data_structures::OnDrop; + use rustc_data_structures::sync::Lock; define_map_struct! { tcx: $tcx, @@ -251,12 +651,6 @@ macro_rules! define_maps { $($(#[$attr])* $name($K)),* } - #[allow(bad_style)] - #[derive(Clone, Debug, PartialEq, Eq)] - pub enum QueryMsg { - $($name(Option<String>)),* - } - impl<$tcx> Query<$tcx> { pub fn name(&self) -> &'static str { match *self { @@ -303,162 +697,38 @@ macro_rules! define_maps { })* } - $(impl<$tcx> QueryConfig for queries::$name<$tcx> { + $(impl<$tcx> QueryConfig<$tcx> for queries::$name<$tcx> { type Key = $K; type Value = $V; - } - impl<$tcx> GetCacheInternal<$tcx> for queries::$name<$tcx> { - fn get_cache_internal<'a>(tcx: TyCtxt<'a, $tcx, $tcx>) - -> LockGuard<'a, QueryMap<$tcx, Self>> { - tcx.maps.$name.borrow() + const NAME: &'static str = stringify!($name); + + fn query(key: Self::Key) -> Query<'tcx> { + Query::$name(key) } - } - impl<'a, $tcx, 'lcx> queries::$name<$tcx> { + fn query_map<'a>(tcx: TyCtxt<'a, $tcx, '_>) -> &'a Lock<QueryMap<$tcx, Self>> { + &tcx.maps.$name + } #[allow(unused)] - fn to_dep_node(tcx: TyCtxt<'a, $tcx, 'lcx>, key: &$K) -> DepNode { + fn to_dep_node(tcx: TyCtxt<'_, $tcx, '_>, key: &Self::Key) -> DepNode { use dep_graph::DepConstructor::*; DepNode::new(tcx, $node(*key)) } - /// Either get the lock of the query map, allowing us to - /// start executing the query, or it returns with the result of the query. - /// If the query already executed and panicked, this will fatal error / silently panic - fn try_get_lock( - tcx: TyCtxt<'a, $tcx, 'lcx>, - span: Span, - key: &$K - ) -> TryGetLock<'a, $tcx, $V, Self> - { - loop { - let lock = tcx.maps.$name.borrow_mut(); - let job = if let Some(value) = lock.map.get(key) { - match *value { - QueryResult::Started(ref job) => Some(job.clone()), - QueryResult::Complete(ref value) => { - profq_msg!(tcx, ProfileQueriesMsg::CacheHit); - let result = Ok(((&value.value).clone(), value.index)); - return TryGetLock::JobCompleted(result); - }, - QueryResult::Poisoned => FatalError.raise(), - } - } else { - None - }; - let job = if let Some(job) = job { - job - } else { - return TryGetLock::NotYetStarted(lock); - }; - mem::drop(lock); - - if let Err(cycle) = job.await(tcx, span) { - return TryGetLock::JobCompleted(Err(cycle)); - } - } + fn compute(tcx: TyCtxt<'_, 'tcx, '_>, key: Self::Key) -> Self::Value { + let provider = tcx.maps.providers[key.map_crate()].$name; + provider(tcx.global_tcx(), key) } - fn try_get_with(tcx: TyCtxt<'a, $tcx, 'lcx>, - span: Span, - key: $K) - -> Result<$V, CycleError<$tcx>> - { - debug!("ty::queries::{}::try_get_with(key={:?}, span={:?})", - stringify!($name), - key, - span); - - profq_msg!(tcx, - ProfileQueriesMsg::QueryBegin( - span.data(), - QueryMsg::$name(profq_key!(tcx, key)) - ) - ); - - /// Get the lock used to start the query or - /// return the result of the completed query - macro_rules! get_lock_or_return { - () => {{ - match Self::try_get_lock(tcx, span, &key) { - TryGetLock::NotYetStarted(lock) => lock, - TryGetLock::JobCompleted(result) => { - return result.map(|(v, index)| { - tcx.dep_graph.read_index(index); - v - }) - } - } - }} - } - - let mut lock = get_lock_or_return!(); - - // Fast path for when incr. comp. is off. `to_dep_node` is - // expensive for some DepKinds. - if !tcx.dep_graph.is_fully_enabled() { - let null_dep_node = DepNode::new_no_params(::dep_graph::DepKind::Null); - return Self::force_with_lock(tcx, key, span, lock, null_dep_node) - .map(|(v, _)| v); - } - - let dep_node = Self::to_dep_node(tcx, &key); - - if dep_node.kind.is_anon() { - profq_msg!(tcx, ProfileQueriesMsg::ProviderBegin); - - let res = Self::start_job(tcx, span, key, lock, |tcx| { - tcx.dep_graph.with_anon_task(dep_node.kind, || { - Self::compute_result(tcx.global_tcx(), key) - }) - })?; - - profq_msg!(tcx, ProfileQueriesMsg::ProviderEnd); - let (((result, dep_node_index), diagnostics), job) = res; - - tcx.dep_graph.read_index(dep_node_index); - - tcx.on_disk_query_result_cache - .store_diagnostics_for_anon_node(dep_node_index, diagnostics); - - let value = QueryValue::new(Clone::clone(&result), dep_node_index); - - tcx.maps - .$name - .borrow_mut() - .map - .insert(key, QueryResult::Complete(value)); - - job.signal_complete(); - - return Ok(result); - } - - if !dep_node.kind.is_input() { - // try_mark_green_and_read may force queries. So we must drop our lock here - mem::drop(lock); - if let Some(dep_node_index) = tcx.try_mark_green_and_read(&dep_node) { - profq_msg!(tcx, ProfileQueriesMsg::CacheHit); - return Self::load_from_disk_and_cache_in_memory(tcx, - key, - span, - dep_node_index, - &dep_node) - } - lock = get_lock_or_return!(); - } - - match Self::force_with_lock(tcx, key, span, lock, dep_node) { - Ok((result, dep_node_index)) => { - tcx.dep_graph.read_index(dep_node_index); - Ok(result) - } - Err(e) => Err(e) - } + fn handle_cycle_error(tcx: TyCtxt<'_, 'tcx, '_>) -> Self::Value { + handle_cycle_error!([$($modifiers)*][tcx]) } + } + impl<'a, $tcx, 'lcx> queries::$name<$tcx> { /// Ensure that either this query has all green inputs or been executed. /// Executing query::ensure(D) is considered a read of the dep-node D. /// @@ -467,282 +737,7 @@ macro_rules! define_maps { /// /// Note: The optimization is only available during incr. comp. pub fn ensure(tcx: TyCtxt<'a, $tcx, 'lcx>, key: $K) -> () { - let dep_node = Self::to_dep_node(tcx, &key); - - // Ensuring an "input" or anonymous query makes no sense - assert!(!dep_node.kind.is_anon()); - assert!(!dep_node.kind.is_input()); - if tcx.try_mark_green_and_read(&dep_node).is_none() { - // A None return from `try_mark_green_and_read` means that this is either - // a new dep node or that the dep node has already been marked red. - // Either way, we can't call `dep_graph.read()` as we don't have the - // DepNodeIndex. We must invoke the query itself. The performance cost - // this introduces should be negligible as we'll immediately hit the - // in-memory cache, or another query down the line will. - let _ = tcx.$name(key); - } - } - - /// Creates a job for the query and updates the query map indicating that it started. - /// Then it changes ImplicitCtxt to point to the new query job while it executes. - /// If the query panics, this updates the query map to indicate so. - fn start_job<F, R>(tcx: TyCtxt<'_, $tcx, 'lcx>, - span: Span, - key: $K, - mut map: LockGuard<'_, QueryMap<$tcx, Self>>, - compute: F) - -> Result<((R, Vec<Diagnostic>), Lrc<QueryJob<$tcx>>), CycleError<$tcx>> - where F: for<'b> FnOnce(TyCtxt<'b, $tcx, 'lcx>) -> R - { - let query = Query::$name(Clone::clone(&key)); - - let entry = QueryInfo { - span, - query, - }; - - // The TyCtxt stored in TLS has the same global interner lifetime - // as `tcx`, so we use `with_related_context` to relate the 'gcx lifetimes - // when accessing the ImplicitCtxt - let (r, job) = ty::tls::with_related_context(tcx, move |icx| { - let job = Lrc::new(QueryJob::new(entry, icx.query.clone())); - - // Store the job in the query map and drop the lock to allow - // others to wait it - map.map.entry(key).or_insert(QueryResult::Started(job.clone())); - mem::drop(map); - - let r = { - let on_drop = OnDrop(|| { - // Poison the query so jobs waiting on it panic - tcx.maps - .$name - .borrow_mut() - .map - .insert(key, QueryResult::Poisoned); - // Also signal the completion of the job, so waiters - // will continue execution - job.signal_complete(); - }); - - // Update the ImplicitCtxt to point to our new query job - let icx = ty::tls::ImplicitCtxt { - tcx, - query: Some(job.clone()), - layout_depth: icx.layout_depth, - task: icx.task, - }; - - // Use the ImplicitCtxt while we execute the query - let r = ty::tls::enter_context(&icx, |icx| { - compute(icx.tcx) - }); - - mem::forget(on_drop); - - r - }; - - (r, job) - }); - - // Extract the diagnostic from the job - let diagnostics: Vec<_> = mem::replace(&mut *job.diagnostics.lock(), Vec::new()); - - Ok(((r, diagnostics), job)) - } - - fn compute_result(tcx: TyCtxt<'a, $tcx, 'lcx>, key: $K) -> $V { - let provider = tcx.maps.providers[key.map_crate()].$name; - provider(tcx.global_tcx(), key) - } - - fn load_from_disk_and_cache_in_memory(tcx: TyCtxt<'a, $tcx, 'lcx>, - key: $K, - span: Span, - dep_node_index: DepNodeIndex, - dep_node: &DepNode) - -> Result<$V, CycleError<$tcx>> - { - // Note this function can be called concurrently from the same query - // We must ensure that this is handled correctly - - debug_assert!(tcx.dep_graph.is_green(dep_node)); - - // First we try to load the result from the on-disk cache - let result = if Self::cache_on_disk(key) && - tcx.sess.opts.debugging_opts.incremental_queries { - let prev_dep_node_index = - tcx.dep_graph.prev_dep_node_index_of(dep_node); - let result = Self::try_load_from_disk(tcx.global_tcx(), - prev_dep_node_index); - - // We always expect to find a cached result for things that - // can be forced from DepNode. - debug_assert!(!dep_node.kind.can_reconstruct_query_key() || - result.is_some(), - "Missing on-disk cache entry for {:?}", - dep_node); - result - } else { - // Some things are never cached on disk. - None - }; - - let (result, job) = if let Some(result) = result { - (result, None) - } else { - // We could not load a result from the on-disk cache, 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, _), job) = Self::start_job(tcx, - span, - key, - tcx.maps.$name.borrow_mut(), - |tcx| { - // The dep-graph for this computation is already in - // place - tcx.dep_graph.with_ignore(|| { - Self::compute_result(tcx, key) - }) - })?; - (result, Some(job)) - }; - - // 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_index)) == - 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_index); - - 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(Clone::clone(&result), dep_node_index); - - tcx.maps - .$name - .borrow_mut() - .map - .insert(key, QueryResult::Complete(value)); - - job.map(|j| j.signal_complete()); - - Ok(result) - } - - #[allow(dead_code)] - fn force(tcx: TyCtxt<'a, $tcx, 'lcx>, - key: $K, - span: Span, - dep_node: DepNode) - -> Result<($V, DepNodeIndex), CycleError<$tcx>> { - // We may be concurrently trying both execute and force a query - // Ensure that only one of them runs the query - let lock = match Self::try_get_lock(tcx, span, &key) { - TryGetLock::NotYetStarted(lock) => lock, - TryGetLock::JobCompleted(result) => return result, - }; - Self::force_with_lock(tcx, - key, - span, - lock, - dep_node) - } - - fn force_with_lock(tcx: TyCtxt<'a, $tcx, 'lcx>, - key: $K, - span: Span, - map: LockGuard<'_, QueryMap<$tcx, Self>>, - dep_node: DepNode) - -> Result<($V, DepNodeIndex), CycleError<$tcx>> { - // If the following assertion triggers, it can have two reasons: - // 1. Something is wrong with DepNode creation, either here or - // in DepGraph::try_mark_green() - // 2. Two distinct query keys get mapped to the same DepNode - // (see for example #48923) - assert!(!tcx.dep_graph.dep_node_exists(&dep_node), - "Forcing query with already existing DepNode.\n\ - - query-key: {:?}\n\ - - dep-node: {:?}", - key, dep_node); - - profq_msg!(tcx, ProfileQueriesMsg::ProviderBegin); - let res = Self::start_job(tcx, - span, - key, - map, - |tcx| { - if dep_node.kind.is_eval_always() { - tcx.dep_graph.with_eval_always_task(dep_node, - tcx, - key, - Self::compute_result) - } else { - tcx.dep_graph.with_task(dep_node, - tcx, - key, - Self::compute_result) - } - })?; - profq_msg!(tcx, ProfileQueriesMsg::ProviderEnd); - - let (((result, dep_node_index), diagnostics), job) = res; - - if tcx.sess.opts.debugging_opts.query_dep_graph { - tcx.dep_graph.mark_loaded_from_cache(dep_node_index, false); - } - - if dep_node.kind != ::dep_graph::DepKind::Null { - tcx.on_disk_query_result_cache - .store_diagnostics(dep_node_index, diagnostics); - } - - let value = QueryValue::new(Clone::clone(&result), dep_node_index); - - tcx.maps - .$name - .borrow_mut() - .map - .insert(key, QueryResult::Complete(value)); - - let job: Lrc<QueryJob> = job; - - job.signal_complete(); - - Ok((result, dep_node_index)) - } - - pub fn try_get(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K) - -> Result<$V, DiagnosticBuilder<'a>> { - match Self::try_get_with(tcx, span, key) { - Ok(e) => Ok(e), - Err(e) => Err(tcx.report_cycle(e)), - } + tcx.ensure_query::<queries::$name>(key); } })* @@ -778,10 +773,7 @@ macro_rules! define_maps { impl<'a, $tcx, 'lcx> TyCtxtAt<'a, $tcx, 'lcx> { $($(#[$attr])* pub fn $name(self, key: $K) -> $V { - queries::$name::try_get(self.tcx, self.span, key).unwrap_or_else(|mut e| { - e.emit(); - handle_cycle_error!([$($modifiers)*][self]) - }) + self.tcx.get_query::<queries::$name>(self.span, key) })* } @@ -872,7 +864,6 @@ macro_rules! define_provider_struct { pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, dep_node: &DepNode) -> bool { - use ty::maps::keys::Key; use hir::def_id::LOCAL_CRATE; // We must avoid ever having to call force_from_dep_node() for a @@ -915,23 +906,14 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, { use $crate::util::common::{ProfileQueriesMsg, profq_msg}; - // FIXME(eddyb) Get more valid Span's on queries. - // def_span guard is necessary to prevent a recursive loop, - // default_span calls def_span query internally. - let span = if stringify!($query) != "def_span" { - $key.default_span(tcx) - } else { - ::syntax_pos::DUMMY_SP - }; - profq_msg!(tcx, ProfileQueriesMsg::QueryBegin( - span.data(), - ::ty::maps::QueryMsg::$query(profq_key!(tcx, $key)) + DUMMY_SP.data(), + profq_query_msg!(::ty::maps::queries::$query::NAME, tcx, $key), ) ); - match ::ty::maps::queries::$query::force(tcx, $key, span, *dep_node) { + match tcx.force_query::<::ty::maps::queries::$query>($key, DUMMY_SP, *dep_node) { Ok(_) => {}, Err(e) => { tcx.report_cycle(e).emit(); @@ -977,6 +959,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::NormalizeProjectionTy | DepKind::NormalizeTyAfterErasingRegions | DepKind::DropckOutlives | + DepKind::EvaluateObligation | DepKind::SubstituteNormalizeAndTestPredicates | DepKind::InstanceDefSizeEstimate | DepKind::ProgramClausesForEnv | diff --git a/src/librustc/ty/maps/values.rs b/src/librustc/ty/maps/values.rs index 8d38d7dbbbb..d3d06248792 100644 --- a/src/librustc/ty/maps/values.rs +++ b/src/librustc/ty/maps/values.rs @@ -37,7 +37,7 @@ impl<'tcx> Value<'tcx> for Ty<'tcx> { impl<'tcx> Value<'tcx> for ty::SymbolName { fn from_cycle_error<'a>(_: TyCtxt<'a, 'tcx, 'tcx>) -> Self { - ty::SymbolName { name: Symbol::intern("<error>").as_str() } + ty::SymbolName { name: Symbol::intern("<error>").as_interned_str() } } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index de043668410..c4fe112a9e9 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -51,7 +51,7 @@ use std::mem; use syntax::ast::{self, DUMMY_NODE_ID, Name, Ident, NodeId}; use syntax::attr; use syntax::ext::hygiene::Mark; -use syntax::symbol::{Symbol, InternedString}; +use syntax::symbol::{Symbol, LocalInternedString, InternedString}; use syntax_pos::{DUMMY_SP, Span}; use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter; @@ -69,7 +69,7 @@ pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef}; pub use self::sty::{ExistentialProjection, PolyExistentialProjection, Const}; pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region}; pub use self::sty::RegionKind; -pub use self::sty::{TyVid, IntVid, FloatVid, RegionVid, SkolemizedRegionVid}; +pub use self::sty::{TyVid, IntVid, FloatVid, RegionVid}; pub use self::sty::BoundRegion::*; pub use self::sty::InferTy::*; pub use self::sty::RegionKind::*; @@ -1370,15 +1370,13 @@ impl<'tcx> InstantiatedPredicates<'tcx> { /// type name in a non-zero universe is a skolemized type -- an /// idealized representative of "types in general" that we use for /// checking generic functions. -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct UniverseIndex(u32); impl UniverseIndex { /// The root universe, where things that the user defined are /// visible. - pub fn root() -> UniverseIndex { - UniverseIndex(0) - } + pub const ROOT: Self = UniverseIndex(0); /// A "subuniverse" corresponds to being inside a `forall` quantifier. /// So, for example, suppose we have this type in universe `U`: @@ -1392,7 +1390,21 @@ impl UniverseIndex { /// region `'a`, but that region was not nameable from `U` because /// it was not in scope there. pub fn subuniverse(self) -> UniverseIndex { - UniverseIndex(self.0 + 1) + UniverseIndex(self.0.checked_add(1).unwrap()) + } + + pub fn as_u32(&self) -> u32 { + self.0 + } + + pub fn as_usize(&self) -> usize { + self.0 as usize + } +} + +impl From<u32> for UniverseIndex { + fn from(index: u32) -> Self { + UniverseIndex(index) } } @@ -1476,7 +1488,11 @@ impl<'tcx> ParamEnv<'tcx> { } Reveal::All => { - if value.needs_infer() || value.has_param_types() || value.has_self_ty() { + if value.has_skol() + || value.needs_infer() + || value.has_param_types() + || value.has_self_ty() + { ParamEnvAnd { param_env: self, value, @@ -2031,7 +2047,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { /// Due to normalization being eager, this applies even if /// the associated type is behind a pointer, e.g. issue #31299. pub fn sized_constraint(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> &'tcx [Ty<'tcx>] { - match queries::adt_sized_constraint::try_get(tcx, DUMMY_SP, self.did) { + match tcx.try_get_query::<queries::adt_sized_constraint>(DUMMY_SP, self.did) { Ok(tys) => tys, Err(mut bug) => { debug!("adt_sized_constraint: {:?} is recursive", self); @@ -2463,7 +2479,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn item_name(self, id: DefId) -> InternedString { if id.index == CRATE_DEF_INDEX { - self.original_crate_name(id.krate).as_str() + self.original_crate_name(id.krate).as_interned_str() } else { let def_key = self.def_key(id); // The name of a StructCtor is that of its struct parent. @@ -2820,15 +2836,13 @@ impl_stable_hash_for!(struct self::SymbolName { impl SymbolName { pub fn new(name: &str) -> SymbolName { SymbolName { - name: Symbol::intern(name).as_str() + name: Symbol::intern(name).as_interned_str() } } -} -impl Deref for SymbolName { - type Target = str; - - fn deref(&self) -> &str { &self.name } + pub fn as_str(&self) -> LocalInternedString { + self.name.as_str() + } } impl fmt::Display for SymbolName { diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 9b20fce6673..d4ed6c60e0e 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -474,8 +474,18 @@ impl<'a, 'tcx> Lift<'tcx> for ConstEvalErr<'a> { impl<'a, 'tcx> Lift<'tcx> for interpret::EvalError<'a> { type Lifted = interpret::EvalError<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> { + Some(interpret::EvalError { + kind: tcx.lift(&self.kind)?, + backtrace: self.backtrace.clone(), + }) + } +} + +impl<'a, 'tcx, O: Lift<'tcx>> Lift<'tcx> for interpret::EvalErrorKind<'a, O> { + type Lifted = interpret::EvalErrorKind<'tcx, <O as Lift<'tcx>>::Lifted>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> { use ::mir::interpret::EvalErrorKind::*; - let kind = match self.kind { + Some(match *self { MachineError(ref err) => MachineError(err.clone()), FunctionPointerTyMismatch(a, b) => FunctionPointerTyMismatch( tcx.lift(&a)?, @@ -504,10 +514,11 @@ impl<'a, 'tcx> Lift<'tcx> for interpret::EvalError<'a> { Unimplemented(ref s) => Unimplemented(s.clone()), DerefFunctionPointer => DerefFunctionPointer, ExecuteMemory => ExecuteMemory, - ArrayIndexOutOfBounds(sp, a, b) => ArrayIndexOutOfBounds(sp, a, b), - Math(sp, ref err) => Math(sp, err.clone()), + BoundsCheck { ref len, ref index } => BoundsCheck { + len: tcx.lift(len)?, + index: tcx.lift(index)?, + }, Intrinsic(ref s) => Intrinsic(s.clone()), - OverflowingMath => OverflowingMath, InvalidChar(c) => InvalidChar(c), StackFrameLimitReached => StackFrameLimitReached, OutOfTls => OutOfTls, @@ -568,10 +579,12 @@ impl<'a, 'tcx> Lift<'tcx> for interpret::EvalError<'a> { UnimplementedTraitSelection => UnimplementedTraitSelection, TypeckError => TypeckError, ReferencedConstant => ReferencedConstant, - }; - Some(interpret::EvalError { - kind: kind, - backtrace: self.backtrace.clone(), + OverflowNeg => OverflowNeg, + Overflow(op) => Overflow(op), + DivisionByZero => DivisionByZero, + RemainderByZero => RemainderByZero, + GeneratorResumedAfterReturn => GeneratorResumedAfterReturn, + GeneratorResumedAfterPanic => GeneratorResumedAfterPanic, }) } } @@ -585,7 +598,6 @@ impl<'a, 'tcx> Lift<'tcx> for const_val::ErrKind<'a> { NonConstPath => NonConstPath, UnimplementedConstVal(s) => UnimplementedConstVal(s), IndexOutOfBounds { len, index } => IndexOutOfBounds { len, index }, - Math(ref e) => Math(e.clone()), LayoutError(ref e) => { return tcx.lift(e).map(LayoutError) diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 0dfae13cc75..382db571b52 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -864,7 +864,7 @@ impl<'a, 'gcx, 'tcx> ParamTy { } pub fn for_self() -> ParamTy { - ParamTy::new(0, keywords::SelfType.name().as_str()) + ParamTy::new(0, keywords::SelfType.name().as_interned_str()) } pub fn for_def(def: &ty::TypeParameterDef) -> ParamTy { @@ -876,8 +876,10 @@ impl<'a, 'gcx, 'tcx> ParamTy { } pub fn is_self(&self) -> bool { - if self.name == keywords::SelfType.name().as_str() { - assert_eq!(self.idx, 0); + // FIXME(#50125): Ignoring `Self` with `idx != 0` might lead to weird behavior elsewhere, + // but this should only be possible when using `-Z continue-parse-after-error` like + // `compile-fail/issue-36638.rs`. + if self.name == keywords::SelfType.name().as_str() && self.idx == 0 { true } else { false @@ -1019,7 +1021,7 @@ pub enum RegionKind { /// A skolemized region - basically the higher-ranked version of ReFree. /// Should not exist after typeck. - ReSkolemized(SkolemizedRegionVid, BoundRegion), + ReSkolemized(ty::UniverseIndex, BoundRegion), /// Empty lifetime is for data that is never accessed. /// Bottom in the region lattice. We treat ReEmpty somewhat @@ -1073,11 +1075,6 @@ newtype_index!(RegionVid DEBUG_FORMAT = custom, }); -#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, PartialOrd, Ord)] -pub struct SkolemizedRegionVid { - pub index: u32, -} - #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub enum InferTy { TyVar(TyVid), @@ -1169,13 +1166,6 @@ impl RegionKind { } } - pub fn needs_infer(&self) -> bool { - match *self { - ty::ReVar(..) | ty::ReSkolemized(..) => true, - _ => false - } - } - pub fn escapes_depth(&self, depth: u32) -> bool { match *self { ty::ReLateBound(debruijn, _) => debruijn.depth > depth, @@ -1193,20 +1183,29 @@ impl RegionKind { } } + pub fn keep_in_local_tcx(&self) -> bool { + if let ty::ReVar(..) = self { + true + } else { + false + } + } + pub fn type_flags(&self) -> TypeFlags { let mut flags = TypeFlags::empty(); + if self.keep_in_local_tcx() { + flags = flags | TypeFlags::KEEP_IN_LOCAL_TCX; + } + match *self { ty::ReVar(..) => { flags = flags | TypeFlags::HAS_FREE_REGIONS; flags = flags | TypeFlags::HAS_RE_INFER; - flags = flags | TypeFlags::KEEP_IN_LOCAL_TCX; } ty::ReSkolemized(..) => { flags = flags | TypeFlags::HAS_FREE_REGIONS; - flags = flags | TypeFlags::HAS_RE_INFER; flags = flags | TypeFlags::HAS_RE_SKOL; - flags = flags | TypeFlags::KEEP_IN_LOCAL_TCX; } ty::ReLateBound(..) => { } ty::ReEarlyBound(..) => { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index a10ca132472..4aa70e1f7e0 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -1024,7 +1024,7 @@ fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let (param_env, ty) = query.into_parts(); let needs_drop = |ty: Ty<'tcx>| -> bool { - match ty::queries::needs_drop_raw::try_get(tcx, DUMMY_SP, param_env.and(ty)) { + match tcx.try_get_query::<ty::queries::needs_drop_raw>(DUMMY_SP, param_env.and(ty)) { Ok(v) => v, Err(mut bug) => { // Cycles should be reported as an error by `check_representable`. diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index bb6aa654c29..85533caffce 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -25,7 +25,6 @@ use std::time::{Duration, Instant}; use std::sync::mpsc::{Sender}; use syntax_pos::{SpanData}; -use ty::maps::{QueryMsg}; use ty::TyCtxt; use dep_graph::{DepNode}; use proc_macro; @@ -59,6 +58,17 @@ fn panic_hook(info: &panic::PanicInfo) { if backtrace { TyCtxt::try_print_query_stack(); } + + #[cfg(windows)] + unsafe { + if env::var("RUSTC_BREAK_ON_ICE").is_ok() { + extern "system" { + fn DebugBreak(); + } + // Trigger a debugger if we crashed during bootstrap + DebugBreak(); + } + } } } @@ -77,6 +87,13 @@ pub struct ProfQDumpParams { pub dump_profq_msg_log:bool, } +#[allow(bad_style)] +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct QueryMsg { + pub query: &'static str, + pub msg: Option<String>, +} + /// A sequence of these messages induce a trace of query-based incremental compilation. /// FIXME(matthewhammer): Determine whether we should include cycle detection here or not. #[derive(Clone,Debug)] diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 905776373bd..894a18b79cc 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -462,7 +462,7 @@ impl PrintContext { 0 => Symbol::intern("'r"), 1 => Symbol::intern("'s"), i => Symbol::intern(&format!("'t{}", i-2)), - }.as_str() + }.as_interned_str() } // Replace any anonymous late-bound regions with named @@ -808,8 +808,8 @@ define_print! { write!(f, "'?{}", c.index()) } - ty::ReSkolemized(id, ref bound_region) => { - write!(f, "ReSkolemized({}, {:?})", id.index, bound_region) + ty::ReSkolemized(universe, ref bound_region) => { + write!(f, "ReSkolemized({:?}, {:?})", universe, bound_region) } ty::ReEmpty => write!(f, "ReEmpty"), diff --git a/src/librustc_apfloat/ppc.rs b/src/librustc_apfloat/ppc.rs index dec88eb62cc..e662088e82f 100644 --- a/src/librustc_apfloat/ppc.rs +++ b/src/librustc_apfloat/ppc.rs @@ -20,7 +20,7 @@ use std::ops::Neg; pub struct DoubleFloat<F>(F, F); pub type DoubleDouble = DoubleFloat<ieee::Double>; -// These are legacy semantics for the Fallback, inaccrurate implementation of +// These are legacy semantics for the Fallback, inaccurate implementation of // IBM double-double, if the accurate DoubleDouble doesn't handle the // operation. It's equivalent to having an IEEE number with consecutive 106 // bits of mantissa and 11 bits of exponent. diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index a01b3cbf47b..79baf0ec151 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -99,7 +99,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> { fn consume(&mut self, consume_id: ast::NodeId, consume_span: Span, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, mode: euv::ConsumeMode) { debug!("consume(consume_id={}, cmt={:?}, mode={:?})", consume_id, cmt, mode); @@ -110,12 +110,12 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> { fn matched_pat(&mut self, _matched_pat: &hir::Pat, - _cmt: mc::cmt, + _cmt: &mc::cmt_, _mode: euv::MatchMode) { } fn consume_pat(&mut self, consume_pat: &hir::Pat, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, mode: euv::ConsumeMode) { debug!("consume_pat(consume_pat={:?}, cmt={:?}, mode={:?})", consume_pat, @@ -128,7 +128,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> { fn borrow(&mut self, borrow_id: ast::NodeId, borrow_span: Span, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, loan_region: ty::Region<'tcx>, bk: ty::BorrowKind, loan_cause: euv::LoanCause) @@ -139,7 +139,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> { bk, loan_cause); let hir_id = self.tcx().hir.node_to_hir_id(borrow_id); - if let Some(lp) = opt_loan_path(&cmt) { + if let Some(lp) = opt_loan_path(cmt) { let moved_value_use_kind = match loan_cause { euv::ClosureCapture(_) => MovedInCapture, _ => MovedInUse, @@ -155,13 +155,13 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> { fn mutate(&mut self, assignment_id: ast::NodeId, assignment_span: Span, - assignee_cmt: mc::cmt<'tcx>, + assignee_cmt: &mc::cmt_<'tcx>, mode: euv::MutateMode) { debug!("mutate(assignment_id={}, assignee_cmt={:?})", assignment_id, assignee_cmt); - if let Some(lp) = opt_loan_path(&assignee_cmt) { + if let Some(lp) = opt_loan_path(assignee_cmt) { match mode { MutateMode::Init | MutateMode::JustWrite => { // In a case like `path = 1`, then path does not @@ -363,10 +363,10 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { } pub fn check_for_loans_across_yields(&self, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, loan_region: ty::Region<'tcx>, borrow_span: Span) { - pub fn borrow_of_local_data<'tcx>(cmt: &mc::cmt<'tcx>) -> bool { + pub fn borrow_of_local_data<'tcx>(cmt: &mc::cmt_<'tcx>) -> bool { match cmt.cat { // Borrows of static items is allowed Categorization::StaticItem => false, @@ -401,7 +401,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { return; } - if !borrow_of_local_data(&cmt) { + if !borrow_of_local_data(cmt) { return; } @@ -649,9 +649,9 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { fn consume_common(&self, id: hir::ItemLocalId, span: Span, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, mode: euv::ConsumeMode) { - if let Some(lp) = opt_loan_path(&cmt) { + if let Some(lp) = opt_loan_path(cmt) { let moved_value_use_kind = match mode { euv::Copy => { self.check_for_copy_of_frozen_path(id, span, &lp); @@ -876,11 +876,11 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { fn check_assignment(&self, assignment_id: hir::ItemLocalId, assignment_span: Span, - assignee_cmt: mc::cmt<'tcx>) { + assignee_cmt: &mc::cmt_<'tcx>) { debug!("check_assignment(assignee_cmt={:?})", assignee_cmt); // Check that we don't invalidate any outstanding loans - if let Some(loan_path) = opt_loan_path(&assignee_cmt) { + if let Some(loan_path) = opt_loan_path(assignee_cmt) { let scope = region::Scope::Node(assignment_id); self.each_in_scope_loan_affecting_path(scope, &loan_path, |loan| { self.report_illegal_mutation(assignment_span, &loan_path, loan); @@ -892,7 +892,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { // needs to be done here instead of in check_loans because we // depend on move data. if let Categorization::Local(local_id) = assignee_cmt.cat { - let lp = opt_loan_path(&assignee_cmt).unwrap(); + let lp = opt_loan_path(assignee_cmt).unwrap(); self.move_data.each_assignment_of(assignment_id, &lp, |assign| { if assignee_cmt.mutbl.is_mutable() { let hir_id = self.bccx.tcx.hir.node_to_hir_id(local_id); diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs index 465457f5ab3..ac905d6de5d 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs @@ -26,10 +26,10 @@ use syntax_pos::Span; use rustc::hir::*; use rustc::hir::map::Node::*; -struct GatherMoveInfo<'tcx> { +struct GatherMoveInfo<'c, 'tcx: 'c> { id: hir::ItemLocalId, kind: MoveKind, - cmt: mc::cmt<'tcx>, + cmt: &'c mc::cmt_<'tcx>, span_path_opt: Option<MovePlace<'tcx>> } @@ -87,7 +87,7 @@ pub fn gather_move_from_expr<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, move_data: &MoveData<'tcx>, move_error_collector: &mut MoveErrorCollector<'tcx>, move_expr_id: hir::ItemLocalId, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, move_reason: euv::MoveReason) { let kind = match move_reason { euv::DirectRefMove | euv::PatBindingMove => MoveExpr, @@ -102,11 +102,11 @@ pub fn gather_move_from_expr<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, gather_move(bccx, move_data, move_error_collector, move_info); } -pub fn gather_move_from_pat<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, - move_data: &MoveData<'tcx>, - move_error_collector: &mut MoveErrorCollector<'tcx>, - move_pat: &hir::Pat, - cmt: mc::cmt<'tcx>) { +pub fn gather_move_from_pat<'a, 'c, 'tcx: 'c>(bccx: &BorrowckCtxt<'a, 'tcx>, + move_data: &MoveData<'tcx>, + move_error_collector: &mut MoveErrorCollector<'tcx>, + move_pat: &hir::Pat, + cmt: &'c mc::cmt_<'tcx>) { let source = get_pattern_source(bccx.tcx,move_pat); let pat_span_path_opt = match move_pat.node { PatKind::Binding(_, _, ref path1, _) => { @@ -132,18 +132,17 @@ pub fn gather_move_from_pat<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, gather_move(bccx, move_data, move_error_collector, move_info); } -fn gather_move<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, +fn gather_move<'a, 'c, 'tcx: 'c>(bccx: &BorrowckCtxt<'a, 'tcx>, move_data: &MoveData<'tcx>, move_error_collector: &mut MoveErrorCollector<'tcx>, - move_info: GatherMoveInfo<'tcx>) { + move_info: GatherMoveInfo<'c, 'tcx>) { debug!("gather_move(move_id={:?}, cmt={:?})", move_info.id, move_info.cmt); - let potentially_illegal_move = - check_and_get_illegal_move_origin(bccx, &move_info.cmt); + let potentially_illegal_move = check_and_get_illegal_move_origin(bccx, move_info.cmt); if let Some(illegal_move_origin) = potentially_illegal_move { debug!("illegal_move_origin={:?}", illegal_move_origin); - let error = MoveError::with_move_info(illegal_move_origin, + let error = MoveError::with_move_info(Rc::new(illegal_move_origin), move_info.span_path_opt); move_error_collector.add_error(error); return; @@ -177,8 +176,8 @@ pub fn gather_assignment<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, // (keep in sync with move_error::report_cannot_move_out_of ) fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, - cmt: &mc::cmt<'tcx>) - -> Option<mc::cmt<'tcx>> { + cmt: &mc::cmt_<'tcx>) + -> Option<mc::cmt_<'tcx>> { match cmt.cat { Categorization::Deref(_, mc::BorrowedPtr(..)) | Categorization::Deref(_, mc::Implicit(..)) | diff --git a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs index 97fa94b5e5c..6d73500d318 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs @@ -27,7 +27,7 @@ pub fn guarantee_lifetime<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, item_scope: region::Scope, span: Span, cause: euv::LoanCause, - cmt: mc::cmt<'tcx>, + cmt: &'a mc::cmt_<'tcx>, loan_region: ty::Region<'tcx>, _: ty::BorrowKind) -> Result<(),()> { @@ -41,8 +41,8 @@ pub fn guarantee_lifetime<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, span, cause, loan_region, - cmt_original: cmt.clone()}; - ctxt.check(&cmt, None) + cmt_original: cmt}; + ctxt.check(cmt, None) } /////////////////////////////////////////////////////////////////////////// @@ -57,12 +57,11 @@ struct GuaranteeLifetimeContext<'a, 'tcx: 'a> { span: Span, cause: euv::LoanCause, loan_region: ty::Region<'tcx>, - cmt_original: mc::cmt<'tcx> + cmt_original: &'a mc::cmt_<'tcx> } impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { - - fn check(&self, cmt: &mc::cmt<'tcx>, discr_scope: Option<ast::NodeId>) -> R { + fn check(&self, cmt: &mc::cmt_<'tcx>, discr_scope: Option<ast::NodeId>) -> R { //! Main routine. Walks down `cmt` until we find the //! "guarantor". Reports an error if `self.loan_region` is //! larger than scope of `cmt`. @@ -102,7 +101,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { } } - fn scope(&self, cmt: &mc::cmt<'tcx>) -> ty::Region<'tcx> { + fn scope(&self, cmt: &mc::cmt_<'tcx>) -> ty::Region<'tcx> { //! Returns the maximal region scope for the which the //! place `cmt` is guaranteed to be valid without any //! rooting etc, and presuming `cmt` is not mutated. @@ -136,7 +135,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { } fn report_error(&self, code: bckerr_code<'tcx>) { - self.bccx.report(BckError { cmt: self.cmt_original.clone(), + self.bccx.report(BckError { cmt: self.cmt_original, span: self.span, cause: BorrowViolation(self.cause), code: code }); diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 49234f4ed7f..a74eba39955 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -76,7 +76,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> { fn consume(&mut self, consume_id: ast::NodeId, _consume_span: Span, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, mode: euv::ConsumeMode) { debug!("consume(consume_id={}, cmt={:?}, mode={:?})", consume_id, cmt, mode); @@ -93,7 +93,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> { fn matched_pat(&mut self, matched_pat: &hir::Pat, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, mode: euv::MatchMode) { debug!("matched_pat(matched_pat={:?}, cmt={:?}, mode={:?})", matched_pat, @@ -103,7 +103,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> { fn consume_pat(&mut self, consume_pat: &hir::Pat, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, mode: euv::ConsumeMode) { debug!("consume_pat(consume_pat={:?}, cmt={:?}, mode={:?})", consume_pat, @@ -123,7 +123,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> { fn borrow(&mut self, borrow_id: ast::NodeId, borrow_span: Span, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, loan_region: ty::Region<'tcx>, bk: ty::BorrowKind, loan_cause: euv::LoanCause) @@ -144,7 +144,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> { fn mutate(&mut self, assignment_id: ast::NodeId, assignment_span: Span, - assignee_cmt: mc::cmt<'tcx>, + assignee_cmt: &mc::cmt_<'tcx>, mode: euv::MutateMode) { self.guarantee_assignment_valid(assignment_id, @@ -165,7 +165,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> { fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, borrow_span: Span, loan_cause: AliasableViolationKind, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, req_kind: ty::BorrowKind) -> Result<(),()> { @@ -206,7 +206,7 @@ fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, fn check_mutability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, borrow_span: Span, cause: AliasableViolationKind, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, req_kind: ty::BorrowKind) -> Result<(),()> { debug!("check_mutability(cause={:?} cmt={:?} req_kind={:?}", @@ -246,10 +246,10 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { fn guarantee_assignment_valid(&mut self, assignment_id: ast::NodeId, assignment_span: Span, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, mode: euv::MutateMode) { - let opt_lp = opt_loan_path(&cmt); + let opt_lp = opt_loan_path(cmt); debug!("guarantee_assignment_valid(assignment_id={}, cmt={:?}) opt_lp={:?}", assignment_id, cmt, opt_lp); @@ -259,14 +259,14 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { } else { // Check that we don't allow assignments to non-mutable data. if check_mutability(self.bccx, assignment_span, MutabilityViolation, - cmt.clone(), ty::MutBorrow).is_err() { + cmt, ty::MutBorrow).is_err() { return; // reported an error, no sense in reporting more. } } // Check that we don't allow assignments to aliasable data if check_aliasability(self.bccx, assignment_span, MutabilityViolation, - cmt.clone(), ty::MutBorrow).is_err() { + cmt, ty::MutBorrow).is_err() { return; // reported an error, no sense in reporting more. } @@ -300,7 +300,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { fn guarantee_valid(&mut self, borrow_id: hir::ItemLocalId, borrow_span: Span, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, req_kind: ty::BorrowKind, loan_region: ty::Region<'tcx>, cause: euv::LoanCause) { @@ -320,28 +320,26 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { // Check that the lifetime of the borrow does not exceed // the lifetime of the data being borrowed. if lifetime::guarantee_lifetime(self.bccx, self.item_ub, - borrow_span, cause, cmt.clone(), loan_region, - req_kind).is_err() { + borrow_span, cause, cmt, loan_region, req_kind).is_err() { return; // reported an error, no sense in reporting more. } // Check that we don't allow mutable borrows of non-mutable data. if check_mutability(self.bccx, borrow_span, BorrowViolation(cause), - cmt.clone(), req_kind).is_err() { + cmt, req_kind).is_err() { return; // reported an error, no sense in reporting more. } // Check that we don't allow mutable borrows of aliasable data. if check_aliasability(self.bccx, borrow_span, BorrowViolation(cause), - cmt.clone(), req_kind).is_err() { + cmt, req_kind).is_err() { return; // reported an error, no sense in reporting more. } // Compute the restrictions that are required to enforce the // loan is safe. let restr = restrictions::compute_restrictions( - self.bccx, borrow_span, cause, - cmt.clone(), loan_region); + self.bccx, borrow_span, cause, &cmt, loan_region); debug!("guarantee_valid(): restrictions={:?}", restr); diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs index e3adb51433b..0b90127cc7e 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs @@ -30,7 +30,7 @@ pub enum RestrictionResult<'tcx> { pub fn compute_restrictions<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, span: Span, cause: euv::LoanCause, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, loan_region: ty::Region<'tcx>) -> RestrictionResult<'tcx> { let ctxt = RestrictionsContext { @@ -55,7 +55,7 @@ struct RestrictionsContext<'a, 'tcx: 'a> { impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { fn restrict(&self, - cmt: mc::cmt<'tcx>) -> RestrictionResult<'tcx> { + cmt: &mc::cmt_<'tcx>) -> RestrictionResult<'tcx> { debug!("restrict(cmt={:?})", cmt); let new_lp = |v: LoanPathKind<'tcx>| Rc::new(LoanPath::new(v, cmt.ty)); @@ -86,7 +86,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { // When we borrow the interior of an enum, we have to // ensure the enum itself is not mutated, because that // could cause the type of the memory to change. - self.restrict(cmt_base) + self.restrict(&cmt_base) } Categorization::Interior(cmt_base, interior) => { @@ -101,7 +101,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { }; let interior = interior.cleaned(); let base_ty = cmt_base.ty; - let result = self.restrict(cmt_base); + let result = self.restrict(&cmt_base); // Borrowing one union field automatically borrows all its fields. match base_ty.sty { ty::TyAdt(adt_def, _) if adt_def.is_union() => match result { @@ -145,7 +145,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { // // Eventually we should make these non-special and // just rely on Deref<T> implementation. - let result = self.restrict(cmt_base); + let result = self.restrict(&cmt_base); self.extend(result, &cmt, LpDeref(pk)) } mc::Implicit(bk, lt) | mc::BorrowedPtr(bk, lt) => { @@ -155,7 +155,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { BckError { span: self.span, cause: BorrowViolation(self.cause), - cmt: cmt_base, + cmt: &cmt_base, code: err_borrowed_pointer_too_short( self.loan_region, lt)}); return RestrictionResult::Safe; @@ -169,7 +169,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { // The referent can be aliased after the // references lifetime ends (by a newly-unfrozen // borrow). - let result = self.restrict(cmt_base); + let result = self.restrict(&cmt_base); self.extend(result, &cmt, LpDeref(pk)) } } @@ -183,7 +183,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { fn extend(&self, result: RestrictionResult<'tcx>, - cmt: &mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, elem: LoanPathElem<'tcx>) -> RestrictionResult<'tcx> { match result { RestrictionResult::Safe => RestrictionResult::Safe, diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 6d832d4060a..9d0d8c2f909 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -144,7 +144,10 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) { check_loans::check_loans(&mut bccx, &loan_dfcx, &flowed_moves, &all_loans, body); } - unused::check(&mut bccx, body); + + if !tcx.use_mir_borrowck() { + unused::check(&mut bccx, body); + } Lrc::new(BorrowCheckResult { used_mut_nodes: bccx.used_mut_nodes.into_inner(), @@ -497,7 +500,7 @@ impl<'a, 'tcx> LoanPath<'tcx> { // Avoid "cannot borrow immutable field `self.x` as mutable" as that implies that a field *can* be // mutable independently of the struct it belongs to. (#35937) -pub fn opt_loan_path_is_field<'tcx>(cmt: &mc::cmt<'tcx>) -> (Option<Rc<LoanPath<'tcx>>>, bool) { +pub fn opt_loan_path_is_field<'tcx>(cmt: &mc::cmt_<'tcx>) -> (Option<Rc<LoanPath<'tcx>>>, bool) { let new_lp = |v: LoanPathKind<'tcx>| Rc::new(LoanPath::new(v, cmt.ty)); match cmt.cat { @@ -545,7 +548,7 @@ pub fn opt_loan_path_is_field<'tcx>(cmt: &mc::cmt<'tcx>) -> (Option<Rc<LoanPath< /// the method `compute()` found in `gather_loans::restrictions`, /// which allows it to share common loan path pieces as it /// traverses the CMT. -pub fn opt_loan_path<'tcx>(cmt: &mc::cmt<'tcx>) -> Option<Rc<LoanPath<'tcx>>> { +pub fn opt_loan_path<'tcx>(cmt: &mc::cmt_<'tcx>) -> Option<Rc<LoanPath<'tcx>>> { opt_loan_path_is_field(cmt).0 } @@ -564,10 +567,10 @@ pub enum bckerr_code<'tcx> { // Combination of an error code and the categorization of the expression // that caused it #[derive(Debug, PartialEq)] -pub struct BckError<'tcx> { +pub struct BckError<'c, 'tcx: 'c> { span: Span, cause: AliasableViolationKind, - cmt: mc::cmt<'tcx>, + cmt: &'c mc::cmt_<'tcx>, code: bckerr_code<'tcx> } @@ -599,7 +602,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { region_rels.is_subregion_of(r_sub, r_sup) } - pub fn report(&self, err: BckError<'tcx>) { + pub fn report(&self, err: BckError<'a, 'tcx>) { // Catch and handle some particular cases. match (&err.code, &err.cause) { (&err_out_of_scope(&ty::ReScope(_), &ty::ReStatic, _), @@ -800,7 +803,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { self.tcx.sess.span_err_with_code(s, msg, code); } - fn report_bckerr(&self, err: &BckError<'tcx>) { + fn report_bckerr(&self, err: &BckError<'a, 'tcx>) { let error_span = err.span.clone(); match err.code { @@ -1011,7 +1014,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { db.emit(); } err_borrowed_pointer_too_short(loan_scope, ptr_scope) => { - let descr = self.cmt_to_path_or_string(&err.cmt); + let descr = self.cmt_to_path_or_string(err.cmt); let mut db = self.lifetime_too_short_for_reborrow(error_span, &descr, Origin::Ast); let descr = match opt_loan_path(&err.cmt) { Some(lp) => { @@ -1042,7 +1045,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { span: Span, kind: AliasableViolationKind, cause: mc::AliasableReason, - cmt: mc::cmt<'tcx>) { + cmt: &mc::cmt_<'tcx>) { let mut is_closure = false; let prefix = match kind { MutabilityViolation => { @@ -1240,7 +1243,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } fn report_out_of_scope_escaping_closure_capture(&self, - err: &BckError<'tcx>, + err: &BckError<'a, 'tcx>, capture_span: Span) { let cmt_path_or_string = self.cmt_to_path_or_string(&err.cmt); @@ -1274,18 +1277,18 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } } - fn note_and_explain_mutbl_error(&self, db: &mut DiagnosticBuilder, err: &BckError<'tcx>, + fn note_and_explain_mutbl_error(&self, db: &mut DiagnosticBuilder, err: &BckError<'a, 'tcx>, error_span: &Span) { match err.cmt.note { mc::NoteClosureEnv(upvar_id) | mc::NoteUpvarRef(upvar_id) => { // If this is an `Fn` closure, it simply can't mutate upvars. // If it's an `FnMut` closure, the original variable was declared immutable. // We need to determine which is the case here. - let kind = match err.cmt.upvar().unwrap().cat { + let kind = match err.cmt.upvar_cat().unwrap() { Categorization::Upvar(mc::Upvar { kind, .. }) => kind, _ => bug!() }; - if kind == ty::ClosureKind::Fn { + if *kind == ty::ClosureKind::Fn { let closure_node_id = self.tcx.hir.local_def_id_to_node_id(upvar_id.closure_expr_id); db.span_help(self.tcx.hir.span(closure_node_id), @@ -1389,7 +1392,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { cmt.descriptive_string(self.tcx) } - pub fn cmt_to_path_or_string(&self, cmt: &mc::cmt<'tcx>) -> String { + pub fn cmt_to_path_or_string(&self, cmt: &mc::cmt_<'tcx>) -> String { match opt_loan_path(cmt) { Some(lp) => format!("`{}`", self.loan_path_to_string(&lp)), None => self.cmt_to_string(cmt), diff --git a/src/librustc_const_math/Cargo.toml b/src/librustc_const_math/Cargo.toml deleted file mode 100644 index 41310ede3e0..00000000000 --- a/src/librustc_const_math/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_const_math" -version = "0.0.0" - -[lib] -name = "rustc_const_math" -path = "lib.rs" -crate-type = ["dylib"] - -[dependencies] -rustc_apfloat = { path = "../librustc_apfloat" } -serialize = { path = "../libserialize" } -syntax = { path = "../libsyntax" } diff --git a/src/librustc_const_math/err.rs b/src/librustc_const_math/err.rs deleted file mode 100644 index bd0a332436e..00000000000 --- a/src/librustc_const_math/err.rs +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use syntax::ast; - -#[derive(Debug, PartialEq, Eq, Clone, RustcEncodable, RustcDecodable)] -pub enum ConstMathErr { - NotInRange, - CmpBetweenUnequalTypes, - UnequalTypes(Op), - Overflow(Op), - ShiftNegative, - DivisionByZero, - RemainderByZero, - UnsignedNegation, - ULitOutOfRange(ast::UintTy), - LitOutOfRange(ast::IntTy), -} -pub use self::ConstMathErr::*; - -#[derive(Debug, PartialEq, Eq, Clone, RustcEncodable, RustcDecodable)] -pub enum Op { - Add, - Sub, - Mul, - Div, - Rem, - Shr, - Shl, - Neg, - BitAnd, - BitOr, - BitXor, -} - -impl ConstMathErr { - pub fn description(&self) -> &'static str { - use self::Op::*; - match *self { - NotInRange => "inferred value out of range", - CmpBetweenUnequalTypes => "compared two values of different types", - UnequalTypes(Add) => "tried to add two values of different types", - UnequalTypes(Sub) => "tried to subtract two values of different types", - UnequalTypes(Mul) => "tried to multiply two values of different types", - UnequalTypes(Div) => "tried to divide two values of different types", - UnequalTypes(Rem) => { - "tried to calculate the remainder of two values of different types" - }, - UnequalTypes(BitAnd) => "tried to bitand two values of different types", - UnequalTypes(BitOr) => "tried to bitor two values of different types", - UnequalTypes(BitXor) => "tried to xor two values of different types", - UnequalTypes(_) => unreachable!(), - Overflow(Add) => "attempt to add with overflow", - Overflow(Sub) => "attempt to subtract with overflow", - Overflow(Mul) => "attempt to multiply with overflow", - Overflow(Div) => "attempt to divide with overflow", - Overflow(Rem) => "attempt to calculate the remainder with overflow", - Overflow(Neg) => "attempt to negate with overflow", - Overflow(Shr) => "attempt to shift right with overflow", - Overflow(Shl) => "attempt to shift left with overflow", - Overflow(_) => unreachable!(), - ShiftNegative => "attempt to shift by a negative amount", - DivisionByZero => "attempt to divide by zero", - RemainderByZero => "attempt to calculate the remainder with a divisor of zero", - UnsignedNegation => "unary negation of unsigned integer", - ULitOutOfRange(ast::UintTy::U8) => "literal out of range for u8", - ULitOutOfRange(ast::UintTy::U16) => "literal out of range for u16", - ULitOutOfRange(ast::UintTy::U32) => "literal out of range for u32", - ULitOutOfRange(ast::UintTy::U64) => "literal out of range for u64", - ULitOutOfRange(ast::UintTy::U128) => "literal out of range for u128", - ULitOutOfRange(ast::UintTy::Usize) => "literal out of range for usize", - LitOutOfRange(ast::IntTy::I8) => "literal out of range for i8", - LitOutOfRange(ast::IntTy::I16) => "literal out of range for i16", - LitOutOfRange(ast::IntTy::I32) => "literal out of range for i32", - LitOutOfRange(ast::IntTy::I64) => "literal out of range for i64", - LitOutOfRange(ast::IntTy::I128) => "literal out of range for i128", - LitOutOfRange(ast::IntTy::Isize) => "literal out of range for isize", - } - } -} diff --git a/src/librustc_const_math/float.rs b/src/librustc_const_math/float.rs deleted file mode 100644 index 9d820ea8cbe..00000000000 --- a/src/librustc_const_math/float.rs +++ /dev/null @@ -1,213 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::cmp::Ordering; -use std::num::ParseFloatError; - -use syntax::ast; - -use rustc_apfloat::{Float, FloatConvert, Status}; -use rustc_apfloat::ieee::{Single, Double}; - -use super::err::*; - -// Note that equality for `ConstFloat` means that the it is the same -// constant, not that the rust values are equal. In particular, `NaN -// == NaN` (at least if it's the same NaN; distinct encodings for NaN -// are considering unequal). -#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] -pub struct ConstFloat { - pub ty: ast::FloatTy, - - // This is a bit inefficient but it makes conversions below more - // ergonomic, and all of this will go away once `miri` is merged. - pub bits: u128, -} - -impl ConstFloat { - /// Description of the type, not the value - pub fn description(&self) -> &'static str { - self.ty.ty_to_string() - } - - /// Compares the values if they are of the same type - pub fn try_cmp(self, rhs: Self) -> Result<Ordering, ConstMathErr> { - match (self.ty, rhs.ty) { - (ast::FloatTy::F64, ast::FloatTy::F64) => { - let a = Double::from_bits(self.bits); - let b = Double::from_bits(rhs.bits); - // This is pretty bad but it is the existing behavior. - Ok(a.partial_cmp(&b).unwrap_or(Ordering::Greater)) - } - - (ast::FloatTy::F32, ast::FloatTy::F32) => { - let a = Single::from_bits(self.bits); - let b = Single::from_bits(rhs.bits); - Ok(a.partial_cmp(&b).unwrap_or(Ordering::Greater)) - } - - _ => Err(CmpBetweenUnequalTypes), - } - } - - pub fn from_i128(input: i128, ty: ast::FloatTy) -> Self { - let bits = match ty { - ast::FloatTy::F32 => Single::from_i128(input).value.to_bits(), - ast::FloatTy::F64 => Double::from_i128(input).value.to_bits() - }; - ConstFloat { bits, ty } - } - - pub fn from_u128(input: u128, ty: ast::FloatTy) -> Self { - let bits = match ty { - ast::FloatTy::F32 => Single::from_u128(input).value.to_bits(), - ast::FloatTy::F64 => Double::from_u128(input).value.to_bits() - }; - ConstFloat { bits, ty } - } - - pub fn from_str(num: &str, ty: ast::FloatTy) -> Result<Self, ParseFloatError> { - let bits = match ty { - ast::FloatTy::F32 => { - let rust_bits = num.parse::<f32>()?.to_bits() as u128; - let apfloat = num.parse::<Single>().unwrap_or_else(|e| { - panic!("apfloat::ieee::Single failed to parse `{}`: {:?}", num, e); - }); - let apfloat_bits = apfloat.to_bits(); - assert!(rust_bits == apfloat_bits, - "apfloat::ieee::Single gave different result for `{}`: \ - {}({:#x}) vs Rust's {}({:#x})", - num, apfloat, apfloat_bits, - Single::from_bits(rust_bits), rust_bits); - apfloat_bits - } - ast::FloatTy::F64 => { - let rust_bits = num.parse::<f64>()?.to_bits() as u128; - let apfloat = num.parse::<Double>().unwrap_or_else(|e| { - panic!("apfloat::ieee::Double failed to parse `{}`: {:?}", num, e); - }); - let apfloat_bits = apfloat.to_bits(); - assert!(rust_bits == apfloat_bits, - "apfloat::ieee::Double gave different result for `{}`: \ - {}({:#x}) vs Rust's {}({:#x})", - num, apfloat, apfloat_bits, - Double::from_bits(rust_bits), rust_bits); - apfloat_bits - } - }; - Ok(ConstFloat { bits, ty }) - } - - pub fn to_i128(self, width: usize) -> Option<i128> { - assert!(width <= 128); - let r = match self.ty { - ast::FloatTy::F32 => Single::from_bits(self.bits).to_i128(width), - ast::FloatTy::F64 => Double::from_bits(self.bits).to_i128(width) - }; - if r.status.intersects(Status::INVALID_OP) { - None - } else { - Some(r.value) - } - } - - pub fn to_u128(self, width: usize) -> Option<u128> { - assert!(width <= 128); - let r = match self.ty { - ast::FloatTy::F32 => Single::from_bits(self.bits).to_u128(width), - ast::FloatTy::F64 => Double::from_bits(self.bits).to_u128(width) - }; - if r.status.intersects(Status::INVALID_OP) { - None - } else { - Some(r.value) - } - } - - pub fn convert(self, to: ast::FloatTy) -> Self { - let bits = match (self.ty, to) { - (ast::FloatTy::F32, ast::FloatTy::F32) | - (ast::FloatTy::F64, ast::FloatTy::F64) => return self, - - (ast::FloatTy::F32, ast::FloatTy::F64) => { - Double::to_bits(Single::from_bits(self.bits).convert(&mut false).value) - } - (ast::FloatTy::F64, ast::FloatTy::F32) => { - Single::to_bits(Double::from_bits(self.bits).convert(&mut false).value) - } - }; - ConstFloat { bits, ty: to } - } -} - -impl ::std::fmt::Display for ConstFloat { - fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { - match self.ty { - ast::FloatTy::F32 => write!(fmt, "{:#}", Single::from_bits(self.bits))?, - ast::FloatTy::F64 => write!(fmt, "{:#}", Double::from_bits(self.bits))?, - } - write!(fmt, "{}", self.ty) - } -} - -impl ::std::fmt::Debug for ConstFloat { - fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { - ::std::fmt::Display::fmt(self, fmt) - } -} - -macro_rules! derive_binop { - ($op:ident, $func:ident) => { - impl ::std::ops::$op for ConstFloat { - type Output = Result<Self, ConstMathErr>; - fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> { - let bits = match (self.ty, rhs.ty) { - (ast::FloatTy::F32, ast::FloatTy::F32) =>{ - let a = Single::from_bits(self.bits); - let b = Single::from_bits(rhs.bits); - a.$func(b).value.to_bits() - } - (ast::FloatTy::F64, ast::FloatTy::F64) => { - let a = Double::from_bits(self.bits); - let b = Double::from_bits(rhs.bits); - a.$func(b).value.to_bits() - } - _ => return Err(UnequalTypes(Op::$op)), - }; - Ok(ConstFloat { bits, ty: self.ty }) - } - } - } -} - -derive_binop!(Add, add); -derive_binop!(Sub, sub); -derive_binop!(Mul, mul); -derive_binop!(Div, div); -derive_binop!(Rem, rem); - -impl ::std::ops::Neg for ConstFloat { - type Output = Self; - fn neg(self) -> Self { - let bits = match self.ty { - ast::FloatTy::F32 => (-Single::from_bits(self.bits)).to_bits(), - ast::FloatTy::F64 => (-Double::from_bits(self.bits)).to_bits(), - }; - 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_const_math/lib.rs b/src/librustc_const_math/lib.rs deleted file mode 100644 index 499c330be1d..00000000000 --- a/src/librustc_const_math/lib.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <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. - -//! Rusty Mathematics -//! -//! # Note -//! -//! This API is completely unstable and subject to change. - -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/")] - -extern crate rustc_apfloat; - -extern crate syntax; - -extern crate serialize as rustc_serialize; // used by deriving - -mod float; -mod err; - -pub use float::*; -pub use err::{ConstMathErr, Op}; diff --git a/src/librustc_data_structures/lazy_btree_map.rs b/src/librustc_data_structures/lazy_btree_map.rs new file mode 100644 index 00000000000..74f91af10fe --- /dev/null +++ b/src/librustc_data_structures/lazy_btree_map.rs @@ -0,0 +1,108 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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::collections::btree_map; +use std::collections::BTreeMap; + +/// A thin wrapper around BTreeMap that avoids allocating upon creation. +/// +/// Vec, HashSet and HashMap all have the nice feature that they don't do any +/// heap allocation when creating a new structure of the default size. In +/// contrast, BTreeMap *does* allocate in that situation. The compiler uses +/// B-Tree maps in some places such that many maps are created but few are +/// inserted into, so having a BTreeMap alternative that avoids allocating on +/// creation is a performance win. +/// +/// Only a fraction of BTreeMap's functionality is currently supported. +/// Additional functionality should be added on demand. +#[derive(Debug)] +pub struct LazyBTreeMap<K, V>(Option<BTreeMap<K, V>>); + +impl<K, V> LazyBTreeMap<K, V> { + pub fn new() -> LazyBTreeMap<K, V> { + LazyBTreeMap(None) + } + + pub fn iter(&self) -> Iter<K, V> { + Iter(self.0.as_ref().map(|btm| btm.iter())) + } + + pub fn is_empty(&self) -> bool { + self.0.as_ref().map_or(true, |btm| btm.is_empty()) + } +} + +impl<K: Ord, V> LazyBTreeMap<K, V> { + fn instantiate(&mut self) -> &mut BTreeMap<K, V> { + if let Some(ref mut btm) = self.0 { + btm + } else { + let btm = BTreeMap::new(); + self.0 = Some(btm); + self.0.as_mut().unwrap() + } + } + + pub fn insert(&mut self, key: K, value: V) -> Option<V> { + self.instantiate().insert(key, value) + } + + pub fn entry(&mut self, key: K) -> btree_map::Entry<K, V> { + self.instantiate().entry(key) + } + + pub fn values<'a>(&'a self) -> Values<'a, K, V> { + Values(self.0.as_ref().map(|btm| btm.values())) + } +} + +impl<K: Ord, V> Default for LazyBTreeMap<K, V> { + fn default() -> LazyBTreeMap<K, V> { + LazyBTreeMap::new() + } +} + +impl<'a, K: 'a, V: 'a> IntoIterator for &'a LazyBTreeMap<K, V> { + type Item = (&'a K, &'a V); + type IntoIter = Iter<'a, K, V>; + + fn into_iter(self) -> Iter<'a, K, V> { + self.iter() + } +} + +pub struct Iter<'a, K: 'a, V: 'a>(Option<btree_map::Iter<'a, K, V>>); + +impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> { + type Item = (&'a K, &'a V); + + fn next(&mut self) -> Option<(&'a K, &'a V)> { + self.0.as_mut().and_then(|iter| iter.next()) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + self.0.as_ref().map_or_else(|| (0, Some(0)), |iter| iter.size_hint()) + } +} + +pub struct Values<'a, K: 'a, V: 'a>(Option<btree_map::Values<'a, K, V>>); + +impl<'a, K, V> Iterator for Values<'a, K, V> { + type Item = &'a V; + + fn next(&mut self) -> Option<&'a V> { + self.0.as_mut().and_then(|values| values.next()) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + self.0.as_ref().map_or_else(|| (0, Some(0)), |values| values.size_hint()) + } +} + diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 1320fe75bc5..597d1627ada 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -60,6 +60,7 @@ pub mod bitvec; pub mod graph; pub mod indexed_set; pub mod indexed_vec; +pub mod lazy_btree_map; pub mod obligation_forest; pub mod sip128; pub mod snapshot_map; diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index b203f387e46..a1052ca6c3c 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -1060,7 +1060,7 @@ impl RustcDefaultCalls { let mut cfgs = Vec::new(); for &(name, ref value) in sess.parse_sess.config.iter() { let gated_cfg = GatedCfg::gate(&ast::MetaItem { - ident: ast::Ident::with_empty_ctxt(name), + ident: ast::Path::from_ident(name.to_ident()), node: ast::MetaItemKind::Word, span: DUMMY_SP, }); @@ -1526,7 +1526,8 @@ pub fn in_rustc_thread<F, R>(f: F) -> Result<R, Box<Any + Send>> let thread = cfg.spawn(f); thread.unwrap().join() } else { - Ok(f()) + let f = panic::AssertUnwindSafe(f); + panic::catch_unwind(f) } } diff --git a/src/librustc_driver/profile/trace.rs b/src/librustc_driver/profile/trace.rs index 280f3c8c796..6426286ccbc 100644 --- a/src/librustc_driver/profile/trace.rs +++ b/src/librustc_driver/profile/trace.rs @@ -10,7 +10,7 @@ use super::*; use syntax_pos::SpanData; -use rustc::ty::maps::QueryMsg; +use rustc::util::common::QueryMsg; use std::fs::File; use std::time::{Duration, Instant}; use std::collections::hash_map::HashMap; diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 47c49fbe9ef..d2ee3d8743c 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -303,11 +303,11 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { pub fn t_param(&self, index: u32) -> Ty<'tcx> { let name = format!("T{}", index); - self.infcx.tcx.mk_param(index, Symbol::intern(&name).as_str()) + self.infcx.tcx.mk_param(index, Symbol::intern(&name).as_interned_str()) } pub fn re_early_bound(&self, index: u32, name: &'static str) -> ty::Region<'tcx> { - let name = Symbol::intern(name).as_str(); + let name = Symbol::intern(name).as_interned_str(); self.infcx.tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { def_id: self.infcx.tcx.hir.local_def_id(ast::CRATE_NODE_ID), index, diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs index 40e4efb397d..75401f21862 100644 --- a/src/librustc_errors/diagnostic.rs +++ b/src/librustc_errors/diagnostic.rs @@ -11,6 +11,7 @@ use CodeSuggestion; use SubstitutionPart; use Substitution; +use Applicability; use Level; use std::fmt; use syntax_pos::{MultiSpan, Span}; @@ -222,7 +223,7 @@ impl Diagnostic { }], msg: msg.to_owned(), show_code_when_inline: false, - approximate: false, + applicability: Applicability::Unspecified, }); self } @@ -253,7 +254,7 @@ impl Diagnostic { }], msg: msg.to_owned(), show_code_when_inline: true, - approximate: false, + applicability: Applicability::Unspecified, }); self } @@ -269,15 +270,16 @@ impl Diagnostic { }).collect(), msg: msg.to_owned(), show_code_when_inline: true, - approximate: false, + applicability: Applicability::Unspecified, }); self } /// This is a suggestion that may contain mistakes or fillers and should /// be read and understood by a human. - pub fn span_approximate_suggestion(&mut self, sp: Span, msg: &str, - suggestion: String) -> &mut Self { + pub fn span_suggestion_with_applicability(&mut self, sp: Span, msg: &str, + suggestion: String, + applicability: Applicability) -> &mut Self { self.suggestions.push(CodeSuggestion { substitutions: vec![Substitution { parts: vec![SubstitutionPart { @@ -287,13 +289,14 @@ impl Diagnostic { }], msg: msg.to_owned(), show_code_when_inline: true, - approximate: true, + applicability, }); self } - pub fn span_approximate_suggestions(&mut self, sp: Span, msg: &str, - suggestions: Vec<String>) -> &mut Self { + pub fn span_suggestions_with_applicability(&mut self, sp: Span, msg: &str, + suggestions: Vec<String>, + applicability: Applicability) -> &mut Self { self.suggestions.push(CodeSuggestion { substitutions: suggestions.into_iter().map(|snippet| Substitution { parts: vec![SubstitutionPart { @@ -303,7 +306,7 @@ impl Diagnostic { }).collect(), msg: msg.to_owned(), show_code_when_inline: true, - approximate: true, + applicability, }); self } diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs index 945ecce7ab3..7e9ca8633a5 100644 --- a/src/librustc_errors/diagnostic_builder.rs +++ b/src/librustc_errors/diagnostic_builder.rs @@ -11,6 +11,7 @@ use Diagnostic; use DiagnosticId; use DiagnosticStyledString; +use Applicability; use Level; use Handler; @@ -187,15 +188,17 @@ impl<'a> DiagnosticBuilder<'a> { msg: &str, suggestions: Vec<String>) -> &mut Self); - forward!(pub fn span_approximate_suggestion(&mut self, + forward!(pub fn span_suggestion_with_applicability(&mut self, sp: Span, msg: &str, - suggestion: String) + suggestion: String, + applicability: Applicability) -> &mut Self); - forward!(pub fn span_approximate_suggestions(&mut self, + forward!(pub fn span_suggestions_with_applicability(&mut self, sp: Span, msg: &str, - suggestions: Vec<String>) + suggestions: Vec<String>, + applicability: Applicability) -> &mut Self); forward!(pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self); forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self); diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index ce3efef08cc..c2b442e9497 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -56,6 +56,14 @@ mod lock; use syntax_pos::{BytePos, Loc, FileLinesResult, FileMap, FileName, MultiSpan, Span, NO_EXPANSION}; +#[derive(Copy, Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)] +pub enum Applicability { + MachineApplicable, + HasPlaceholders, + MaybeIncorrect, + Unspecified +} + #[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)] pub struct CodeSuggestion { /// Each substitute can have multiple variants due to multiple @@ -87,7 +95,7 @@ pub struct CodeSuggestion { /// Sometimes we may show suggestions with placeholders, /// which are useful for users but not useful for /// tools like rustfix - pub approximate: bool, + pub applicability: Applicability, } #[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)] diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index 57311a7b588..38e891008f7 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -110,7 +110,7 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> { for list_item in attr.meta_item_list().unwrap_or_default() { match list_item.word() { Some(word) if value.is_none() => - value = Some(word.ident.name), + value = Some(word.name()), _ => // FIXME better-encapsulate meta_item (don't directly access `node`) span_bug!(list_item.span(), "unexpected meta-item {:?}", list_item.node), diff --git a/src/librustc_incremental/assert_module_sources.rs b/src/librustc_incremental/assert_module_sources.rs index 46ba94f2061..6906dacfc5e 100644 --- a/src/librustc_incremental/assert_module_sources.rs +++ b/src/librustc_incremental/assert_module_sources.rs @@ -74,7 +74,7 @@ impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> { let mname = self.field(attr, MODULE); let mangled_cgu_name = CodegenUnit::mangle_name(&mname.as_str()); - let mangled_cgu_name = Symbol::intern(&mangled_cgu_name).as_str(); + let mangled_cgu_name = Symbol::intern(&mangled_cgu_name).as_interned_str(); let dep_node = DepNode::new(self.tcx, DepConstructor::CompileCodegenUnit(mangled_cgu_name)); diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 91ce6f3854a..f06062fa4ac 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -675,9 +675,8 @@ impl LintPass for DeprecatedAttr { impl EarlyLintPass for DeprecatedAttr { fn check_attribute(&mut self, cx: &EarlyContext, attr: &ast::Attribute) { - let name = unwrap_or!(attr.name(), return); for &&(n, _, ref g) in &self.depr_attrs { - if name == n { + if attr.name() == n { if let &AttributeGate::Gated(Stability::Deprecated(link), ref name, ref reason, diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 65b340d6568..4f6d23dce6d 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -30,7 +30,6 @@ #![feature(quote)] #![feature(rustc_diagnostic_macros)] -#[macro_use] extern crate syntax; #[macro_use] extern crate rustc; diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index bf86f6a6952..8df40b62ddd 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use rustc::hir::def::Def; use rustc::hir::def_id::DefId; use rustc::ty; use rustc::ty::adjustment; @@ -72,40 +73,57 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { let mut fn_warned = false; let mut op_warned = false; - if cx.tcx.features().fn_must_use { - let maybe_def = match expr.node { - hir::ExprCall(ref callee, _) => { - match callee.node { - hir::ExprPath(ref qpath) => { - Some(cx.tables.qpath_def(qpath, callee.hir_id)) - }, - _ => None - } - }, - hir::ExprMethodCall(..) => { - cx.tables.type_dependent_defs().get(expr.hir_id).cloned() - }, - _ => None - }; - if let Some(def) = maybe_def { - let def_id = def.def_id(); - fn_warned = check_must_use(cx, def_id, s.span, "return value of "); - } - - if let hir::ExprBinary(bin_op, ..) = expr.node { + let maybe_def = match expr.node { + hir::ExprCall(ref callee, _) => { + match callee.node { + hir::ExprPath(ref qpath) => { + let def = cx.tables.qpath_def(qpath, callee.hir_id); + if let Def::Fn(_) = def { + Some(def) + } else { // `Def::Local` if it was a closure, for which we + None // do not currently support must-use linting + } + }, + _ => None + } + }, + hir::ExprMethodCall(..) => { + cx.tables.type_dependent_defs().get(expr.hir_id).cloned() + }, + _ => None + }; + if let Some(def) = maybe_def { + let def_id = def.def_id(); + fn_warned = check_must_use(cx, def_id, s.span, "return value of "); + } + let must_use_op = match expr.node { + // Hardcoding operators here seemed more expedient than the + // refactoring that would be needed to look up the `#[must_use]` + // attribute which does exist on the comparison trait methods + hir::ExprBinary(bin_op, ..) => { match bin_op.node { - // Hardcoding the comparison operators here seemed more - // expedient than the refactoring that would be needed to - // look up the `#[must_use]` attribute which does exist on - // the comparison trait methods hir::BiEq | hir::BiLt | hir::BiLe | hir::BiNe | hir::BiGe | hir::BiGt => { - let msg = "unused comparison which must be used"; - cx.span_lint(UNUSED_MUST_USE, expr.span, msg); - op_warned = true; + Some("comparison") + }, + hir::BiAdd | hir::BiSub | hir::BiDiv | hir::BiMul | hir::BiRem => { + Some("arithmetic operation") + }, + hir::BiAnd | hir::BiOr => { + Some("logical operation") + }, + hir::BiBitXor | hir::BiBitAnd | hir::BiBitOr | hir::BiShl | hir::BiShr => { + Some("bitwise operation") }, - _ => {}, } - } + }, + hir::ExprUnary(..) => Some("unary operation"), + _ => None + }; + + if let Some(must_use_op) = must_use_op { + cx.span_lint(UNUSED_MUST_USE, expr.span, + &format!("unused {} which must be used", must_use_op)); + op_warned = true; } if !(ty_warned || fn_warned || op_warned) { @@ -174,8 +192,6 @@ impl LintPass for UnusedAttributes { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes { fn check_attribute(&mut self, cx: &LateContext, attr: &ast::Attribute) { debug!("checking attribute: {:?}", attr); - let name = unwrap_or!(attr.name(), return); - // Note that check_name() marks the attribute as used if it matches. for &(ref name, ty, _) in BUILTIN_ATTRIBUTES { match ty { @@ -195,6 +211,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes { } } + let name = attr.name(); if !attr::is_used(attr) { debug!("Emitting warning for: {:?}", attr); cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute"); diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index a11b95cb5b6..fdfe2a98bf9 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -51,7 +51,7 @@ macro_rules! provide { pub fn provide_extern<$lt>(providers: &mut Providers<$lt>) { $(fn $name<'a, $lt:$lt, T>($tcx: TyCtxt<'a, $lt, $lt>, def_id_arg: T) -> <ty::queries::$name<$lt> as - QueryConfig>::Value + QueryConfig<$lt>>::Value where T: IntoArgs, { #[allow(unused_variables)] @@ -535,7 +535,7 @@ impl CrateStore for cstore::CStore { .insert(local_span, (name.to_string(), data.get_span(id.index, sess))); LoadedMacro::MacroDef(ast::Item { - ident: ast::Ident::from_str(&name), + ident: ast::Ident::from_str(&name.as_str()), id: ast::DUMMY_NODE_ID, span: local_span, attrs: attrs.iter().cloned().collect(), diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 0147e8dc607..57f92707ccf 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -40,7 +40,7 @@ use rustc_serialize::{Decodable, Decoder, SpecializedDecoder, opaque}; use syntax::attr; use syntax::ast::{self, Ident}; use syntax::codemap; -use syntax::symbol::{InternedString, Symbol}; +use syntax::symbol::InternedString; use syntax::ext::base::MacroKind; use syntax_pos::{self, Span, BytePos, Pos, DUMMY_SP, NO_EXPANSION}; @@ -537,12 +537,12 @@ impl<'a, 'tcx> CrateMetadata { ty::VariantDef { did: self.local_def_id(data.struct_ctor.unwrap_or(index)), - name: Symbol::intern(&self.item_name(index)), + name: self.item_name(index).as_symbol(), fields: item.children.decode(self).map(|index| { let f = self.entry(index); ty::FieldDef { did: self.local_def_id(index), - name: Symbol::intern(&self.item_name(index)), + name: self.item_name(index).as_symbol(), vis: f.visibility.decode(self) } }).collect(), @@ -730,7 +730,7 @@ impl<'a, 'tcx> CrateMetadata { if let Some(def) = self.get_def(child_index) { callback(def::Export { def, - ident: Ident::from_str(&self.item_name(child_index)), + ident: Ident::from_interned_str(self.item_name(child_index)), vis: self.get_visibility(child_index), span: self.entry(child_index).span.decode((self, sess)), is_import: false, @@ -748,7 +748,7 @@ impl<'a, 'tcx> CrateMetadata { let span = child.span.decode((self, sess)); if let (Some(def), Some(name)) = (self.get_def(child_index), def_key.disambiguated_data.data.get_opt_name()) { - let ident = Ident::from_str(&name); + let ident = Ident::from_interned_str(name); let vis = self.get_visibility(child_index); let is_import = false; callback(def::Export { def, ident, vis, span, is_import }); @@ -847,7 +847,7 @@ impl<'a, 'tcx> CrateMetadata { }; ty::AssociatedItem { - name: Symbol::intern(&name), + name: name.as_symbol(), kind, vis: item.visibility.decode(self), defaultness: container.defaultness(), @@ -914,7 +914,7 @@ impl<'a, 'tcx> CrateMetadata { self.entry(id) .children .decode(self) - .map(|index| Symbol::intern(&self.item_name(index))) + .map(|index| self.item_name(index).as_symbol()) .collect() } @@ -977,7 +977,13 @@ impl<'a, 'tcx> CrateMetadata { } pub fn get_trait_of_item(&self, id: DefIndex) -> Option<DefId> { - self.def_key(id).parent.and_then(|parent_index| { + let def_key = self.def_key(id); + match def_key.disambiguated_data.data { + DefPathData::TypeNs(..) | DefPathData::ValueNs(..) => (), + // Not an associated item + _ => return None, + } + def_key.parent.and_then(|parent_index| { match self.entry(parent_index).kind { EntryKind::Trait(_) => Some(self.local_def_id(parent_index)), _ => None, @@ -1106,7 +1112,7 @@ impl<'a, 'tcx> CrateMetadata { DefKey { parent: Some(CRATE_DEF_INDEX), disambiguated_data: DisambiguatedDefPathData { - data: DefPathData::MacroDef(name.as_str()), + data: DefPathData::MacroDef(name.as_interned_str()), disambiguator: 0, } } diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml index a1b348774b1..62964745b6f 100644 --- a/src/librustc_mir/Cargo.toml +++ b/src/librustc_mir/Cargo.toml @@ -16,7 +16,6 @@ log = "0.4" log_settings = "0.1.1" rustc = { path = "../librustc" } rustc_target = { path = "../librustc_target" } -rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } serialize = { path = "../libserialize" } diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 3dc5a7a8490..db2e078586e 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -471,7 +471,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { | (RegionKind::ReClosureBound(_), _) | (RegionKind::ReCanonical(_), _) | (RegionKind::ReErased, _) => { - span_bug!(drop_span, "region does not make sense in this context"); + span_bug!(drop_span, "region {:?} does not make sense in this context", + borrow.region); } } } diff --git a/src/librustc_mir/borrow_check/location.rs b/src/librustc_mir/borrow_check/location.rs new file mode 100644 index 00000000000..28da1b2d733 --- /dev/null +++ b/src/librustc_mir/borrow_check/location.rs @@ -0,0 +1,123 @@ +// 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::mir::{BasicBlock, Location, Mir}; +use rustc_data_structures::indexed_vec::{Idx, IndexVec}; + +/// Maps between a MIR Location, which identifies the a particular +/// statement within a basic block, to a "rich location", which +/// identifies at a finer granularity. In particular, we distinguish +/// the *start* of a statement and the *mid-point*. The mid-point is +/// the point *just* before the statement takes effect; in particular, +/// for an assignment `A = B`, it is the point where B is about to be +/// written into A. This mid-point is a kind of hack to work around +/// our inability to track the position information at sufficient +/// granularity through outlives relations; however, the rich location +/// table serves another purpose: it compresses locations from +/// multiple words into a single u32. +crate struct LocationTable { + num_points: usize, + statements_before_block: IndexVec<BasicBlock, usize>, +} + +newtype_index!(LocationIndex { DEBUG_FORMAT = "LocationIndex({})" }); + +#[derive(Copy, Clone, Debug)] +crate enum RichLocation { + Start(Location), + Mid(Location), +} + +impl LocationTable { + crate fn new(mir: &Mir<'_>) -> Self { + let mut num_points = 0; + let statements_before_block = mir.basic_blocks() + .iter() + .map(|block_data| { + let v = num_points; + num_points += (block_data.statements.len() + 1) * 2; + v + }) + .collect(); + + debug!( + "LocationTable(statements_before_block={:#?})", + statements_before_block + ); + debug!("LocationTable: num_points={:#?}", num_points); + + Self { + num_points, + statements_before_block, + } + } + + crate fn all_points(&self) -> impl Iterator<Item = LocationIndex> { + (0..self.num_points).map(LocationIndex::new) + } + + crate fn start_index(&self, location: Location) -> LocationIndex { + let Location { + block, + statement_index, + } = location; + let start_index = self.statements_before_block[block]; + LocationIndex::new(start_index + statement_index * 2) + } + + crate fn mid_index(&self, location: Location) -> LocationIndex { + let Location { + block, + statement_index, + } = location; + let start_index = self.statements_before_block[block]; + LocationIndex::new(start_index + statement_index * 2 + 1) + } + + crate fn to_location(&self, index: LocationIndex) -> RichLocation { + let point_index = index.index(); + + // Find the basic block. We have a vector with the + // starting index of the statement in each block. Imagine + // we have statement #22, and we have a vector like: + // + // [0, 10, 20] + // + // In that case, this represents point_index 2 of + // basic block BB2. We know this because BB0 accounts for + // 0..10, BB1 accounts for 11..20, and BB2 accounts for + // 20... + // + // To compute this, we could do a binary search, but + // because I am lazy we instead iterate through to find + // the last point where the "first index" (0, 10, or 20) + // was less than the statement index (22). In our case, this will + // be (BB2, 20). + let (block, &first_index) = self.statements_before_block + .iter_enumerated() + .filter(|(_, first_index)| **first_index <= point_index) + .last() + .unwrap(); + + let statement_index = (point_index - first_index) / 2; + if index.is_start() { + RichLocation::Start(Location { block, statement_index }) + } else { + RichLocation::Mid(Location { block, statement_index }) + } + } +} + +impl LocationIndex { + fn is_start(&self) -> bool { + // even indices are start points; odd indices are mid points + (self.index() % 2) == 0 + } +} diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 4dd8d245d3b..3e3f510e308 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -17,15 +17,17 @@ use rustc::hir::map::definitions::DefPathData; use rustc::infer::InferCtxt; use rustc::ty::{self, ParamEnv, TyCtxt}; use rustc::ty::maps::Providers; -use rustc::mir::{AssertMessage, BasicBlock, BorrowKind, Location, Place}; -use rustc::mir::{Mir, Mutability, Operand, Projection, ProjectionElem, Rvalue}; -use rustc::mir::{Field, Statement, StatementKind, Terminator, TerminatorKind}; -use rustc::mir::ClosureRegionRequirements; +use rustc::lint::builtin::UNUSED_MUT; +use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind}; +use rustc::mir::{ClearCrossCrate, Local, Location, Place, Mir, Mutability, Operand}; +use rustc::mir::{Projection, ProjectionElem, Rvalue, Field, Statement, StatementKind}; +use rustc::mir::{Terminator, TerminatorKind}; use rustc_data_structures::control_flow_graph::dominators::Dominators; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::indexed_set::IdxSetBuf; use rustc_data_structures::indexed_vec::Idx; +use rustc_data_structures::small_vec::SmallVec; use std::rc::Rc; @@ -48,12 +50,14 @@ use std::iter; use self::borrow_set::{BorrowSet, BorrowData}; use self::flows::Flows; +use self::location::LocationTable; use self::prefixes::PrefixSet; use self::MutateMode::{JustWrite, WriteAndRead}; crate mod borrow_set; mod error_reporting; mod flows; +mod location; crate mod place_ext; mod prefixes; @@ -69,12 +73,15 @@ pub fn provide(providers: &mut Providers) { fn mir_borrowck<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, -) -> Option<ClosureRegionRequirements<'tcx>> { +) -> BorrowCheckResult<'tcx> { let input_mir = tcx.mir_validated(def_id); debug!("run query mir_borrowck: {}", tcx.item_path_str(def_id)); if !tcx.has_attr(def_id, "rustc_mir_borrowck") && !tcx.use_mir_borrowck() { - return None; + return BorrowCheckResult { + closure_requirements: None, + used_mut_upvars: SmallVec::new(), + }; } let opt_closure_req = tcx.infer_ctxt().enter(|infcx| { @@ -90,7 +97,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( infcx: &InferCtxt<'a, 'gcx, 'tcx>, input_mir: &Mir<'gcx>, def_id: DefId, -) -> Option<ClosureRegionRequirements<'gcx>> { +) -> BorrowCheckResult<'gcx> { let tcx = infcx.tcx; let attributes = tcx.get_attrs(def_id); let param_env = tcx.param_env(def_id); @@ -105,6 +112,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( let mut mir: Mir<'tcx> = input_mir.clone(); let free_regions = nll::replace_regions_in_mir(infcx, def_id, param_env, &mut mir); let mir = &mir; // no further changes + let location_table = &LocationTable::new(mir); let move_data: MoveData<'tcx> = match MoveData::gather_moves(mir, tcx) { Ok(move_data) => move_data, @@ -194,6 +202,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( def_id, free_regions, mir, + location_table, param_env, &mut flow_inits, &mdpe.move_data, @@ -237,6 +246,8 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( reservation_error_reported: FxHashSet(), moved_error_reported: FxHashSet(), nonlexical_regioncx: regioncx, + used_mut: FxHashSet(), + used_mut_upvars: SmallVec::new(), nonlexical_cause_info: None, borrow_set, dominators, @@ -252,7 +263,66 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( mbcx.analyze_results(&mut state); // entry point for DataflowResultsConsumer - opt_closure_req + // For each non-user used mutable variable, check if it's been assigned from + // a user-declared local. If so, then put that local into the used_mut set. + // Note that this set is expected to be small - only upvars from closures + // would have a chance of erroneously adding non-user-defined mutable vars + // to the set. + let temporary_used_locals: FxHashSet<Local> = + mbcx.used_mut.iter() + .filter(|&local| !mbcx.mir.local_decls[*local].is_user_variable) + .cloned() + .collect(); + + for local in temporary_used_locals { + for location in mbcx.mir.find_assignments(local) { + for moi in &mbcx.move_data.loc_map[location] { + let mpi = &mbcx.move_data.moves[*moi].path; + let path = &mbcx.move_data.move_paths[*mpi]; + debug!("assignment of {:?} to {:?}, adding {:?} to used mutable set", + path.place, local, path.place); + if let Place::Local(user_local) = path.place { + mbcx.used_mut.insert(user_local); + } + } + } + } + + debug!("mbcx.used_mut: {:?}", mbcx.used_mut); + + for local in mbcx.mir.mut_vars_and_args_iter().filter(|local| !mbcx.used_mut.contains(local)) { + if let ClearCrossCrate::Set(ref vsi) = mbcx.mir.visibility_scope_info { + let local_decl = &mbcx.mir.local_decls[local]; + + // Skip implicit `self` argument for closures + if local.index() == 1 && tcx.is_closure(mbcx.mir_def_id) { + continue; + } + + // Skip over locals that begin with an underscore or have no name + match local_decl.name { + Some(name) => if name.as_str().starts_with("_") { continue; }, + None => continue, + } + + let source_info = local_decl.source_info; + let mut_span = tcx.sess.codemap().span_until_non_whitespace(source_info.span); + + tcx.struct_span_lint_node( + UNUSED_MUT, + vsi[local_decl.syntactic_scope].lint_root, + source_info.span, + "variable does not need to be mutable" + ) + .span_suggestion_short(mut_span, "remove this `mut`", "".to_owned()) + .emit(); + } + } + + BorrowCheckResult { + closure_requirements: opt_closure_req, + used_mut_upvars: mbcx.used_mut_upvars, + } } #[allow(dead_code)] @@ -287,6 +357,12 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> { /// This field keeps track of errors reported in the checking of moved variables, /// so that we don't report report seemingly duplicate errors. moved_error_reported: FxHashSet<Place<'tcx>>, + /// This field keeps track of all the local variables that are declared mut and are mutated. + /// Used for the warning issued by an unused mutable local variable. + used_mut: FxHashSet<Local>, + /// If the function we're checking is a closure, then we'll need to report back the list of + /// mutable upvars that have been used. This field keeps track of them. + used_mut_upvars: SmallVec<[Field; 8]>, /// Non-lexical region inference context, if NLL is enabled. This /// contains the results from region inference and lets us e.g. /// find out which CFG points are contained in each borrow region. @@ -514,18 +590,14 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx cleanup: _, } => { self.consume_operand(ContextKind::Assert.new(loc), (cond, span), flow_state); - match *msg { - AssertMessage::BoundsCheck { ref len, ref index } => { - self.consume_operand(ContextKind::Assert.new(loc), (len, span), flow_state); - self.consume_operand( - ContextKind::Assert.new(loc), - (index, span), - flow_state, - ); - } - AssertMessage::Math(_ /*const_math_err*/) => {} - AssertMessage::GeneratorResumedAfterReturn => {} - AssertMessage::GeneratorResumedAfterPanic => {} + use rustc::mir::interpret::EvalErrorKind::BoundsCheck; + if let BoundsCheck { ref len, ref index } = *msg { + self.consume_operand(ContextKind::Assert.new(loc), (len, span), flow_state); + self.consume_operand( + ContextKind::Assert.new(loc), + (index, span), + flow_state, + ); } } @@ -684,6 +756,11 @@ enum InitializationRequiringAction { Assignment, } +struct RootPlace<'d, 'tcx: 'd> { + place: &'d Place<'tcx>, + is_local_mutation_allowed: LocalMutationIsAllowed, +} + impl InitializationRequiringAction { fn as_noun(self) -> &'static str { match self { @@ -729,6 +806,17 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { erased_drop_place_ty: ty::Ty<'gcx>, span: Span, ) { + let gcx = self.tcx.global_tcx(); + let drop_field = | + mir: &mut MirBorrowckCtxt<'cx, 'gcx, 'tcx>, + (index, field): (usize, ty::Ty<'gcx>), + | { + let field_ty = gcx.normalize_erasing_regions(mir.param_env, field); + let place = drop_place.clone().field(Field::new(index), field_ty); + + mir.visit_terminator_drop(loc, term, flow_state, &place, field_ty, span); + }; + match erased_drop_place_ty.sty { // When a struct is being dropped, we need to check // whether it has a destructor, if it does, then we can @@ -737,14 +825,24 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // destructor but `bar` does not, we will only check for // borrows of `x.foo` and not `x.bar`. See #47703. ty::TyAdt(def, substs) if def.is_struct() && !def.has_dtor(self.tcx) => { - for (index, field) in def.all_fields().enumerate() { - let gcx = self.tcx.global_tcx(); - let field_ty = field.ty(gcx, substs); - let field_ty = gcx.normalize_erasing_regions(self.param_env, field_ty); - let place = drop_place.clone().field(Field::new(index), field_ty); - - self.visit_terminator_drop(loc, term, flow_state, &place, field_ty, span); - } + def.all_fields() + .map(|field| field.ty(gcx, substs)) + .enumerate() + .for_each(|field| drop_field(self, field)); + } + // Same as above, but for tuples. + ty::TyTuple(tys) => { + tys.iter().cloned().enumerate() + .for_each(|field| drop_field(self, field)); + } + // Closures and generators also have disjoint fields, but they are only + // directly accessed in the body of the closure/generator. + ty::TyClosure(def, substs) + | ty::TyGenerator(def, substs, ..) + if *drop_place == Place::Local(Local::new(1)) && !self.mir.upvar_decls.is_empty() + => { + substs.upvar_tys(def, self.tcx).enumerate() + .for_each(|field| drop_field(self, field)); } _ => { // We have now refined the type of the value being @@ -752,7 +850,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // subfield; so check whether that field's type still // "needs drop". If so, we assume that the destructor // may access any data it likes (i.e., a Deep Write). - let gcx = self.tcx.global_tcx(); if erased_drop_place_ty.needs_drop(gcx, self.param_env) { self.access_place( ContextKind::Drop.new(loc), @@ -810,7 +907,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } let mutability_error = - self.check_access_permissions(place_span, rw, is_local_mutation_allowed); + self.check_access_permissions(place_span, rw, is_local_mutation_allowed, flow_state); let conflict_error = self.check_access_for_conflict(context, place_span, sd, rw, flow_state); @@ -1077,9 +1174,34 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // `NullOp::Box`? } - Rvalue::Aggregate(ref _aggregate_kind, ref operands) => for operand in operands { - self.consume_operand(context, (operand, span), flow_state); - }, + Rvalue::Aggregate(ref aggregate_kind, ref operands) => { + // We need to report back the list of mutable upvars that were + // moved into the closure and subsequently used by the closure, + // in order to populate our used_mut set. + if let AggregateKind::Closure(def_id, _) = &**aggregate_kind { + let BorrowCheckResult { used_mut_upvars, .. } = self.tcx.mir_borrowck(*def_id); + debug!("{:?} used_mut_upvars={:?}", def_id, used_mut_upvars); + for field in used_mut_upvars { + match operands[field.index()] { + Operand::Move(Place::Local(local)) => { + self.used_mut.insert(local); + } + Operand::Move(ref place @ Place::Projection(_)) => { + if let Some(field) = self.is_upvar_field_projection(place) { + self.used_mut_upvars.push(field); + } + } + Operand::Move(Place::Static(..)) | + Operand::Copy(..) | + Operand::Constant(..) => {} + } + } + } + + for operand in operands { + self.consume_operand(context, (operand, span), flow_state); + } + } } } @@ -1280,7 +1402,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { ) { debug!("check_if_reassignment_to_immutable_state({:?})", place); // determine if this path has a non-mut owner (and thus needs checking). - if let Ok(()) = self.is_mutable(place, LocalMutationIsAllowed::No) { + if let Ok(..) = self.is_mutable(place, LocalMutationIsAllowed::No) { return; } debug!( @@ -1574,10 +1696,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { /// /// Returns true if an error is reported, false otherwise. fn check_access_permissions( - &self, + &mut self, (place, span): (&Place<'tcx>, Span), kind: ReadOrWrite, is_local_mutation_allowed: LocalMutationIsAllowed, + flow_state: &Flows<'cx, 'gcx, 'tcx>, ) -> bool { debug!( "check_access_permissions({:?}, {:?}, {:?})", @@ -1592,90 +1715,93 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } } Reservation(WriteKind::MutableBorrow(BorrowKind::Mut { .. })) - | Write(WriteKind::MutableBorrow(BorrowKind::Mut { .. })) => if let Err(place_err) = - self.is_mutable(place, is_local_mutation_allowed) - { - error_reported = true; - let item_msg = self.get_default_err_msg(place); - let mut err = self.tcx - .cannot_borrow_path_as_mutable(span, &item_msg, Origin::Mir); - err.span_label(span, "cannot borrow as mutable"); - - if place != place_err { - if let Some(name) = self.describe_place(place_err) { - err.note(&format!("the value which is causing this path not to be mutable \ - is...: `{}`", name)); - } - } - - err.emit(); - }, - Reservation(WriteKind::Mutate) | Write(WriteKind::Mutate) => { - - if let Err(place_err) = self.is_mutable(place, is_local_mutation_allowed) { - error_reported = true; - let mut err_info = None; - match *place_err { - - Place::Projection(box Projection { - ref base, elem:ProjectionElem::Deref}) => { - match *base { - Place::Local(local) => { - let locations = self.mir.find_assignments(local); - if locations.len() > 0 { - let item_msg = if error_reported { - self.get_secondary_err_msg(base) - } else { - self.get_default_err_msg(place) - }; - let sp = self.mir.source_info(locations[0]).span; - let mut to_suggest_span = String::new(); - if let Ok(src) = - self.tcx.sess.codemap().span_to_snippet(sp) { - to_suggest_span = src[1..].to_string(); - }; - err_info = Some(( - sp, - "consider changing this to be a \ - mutable reference", - to_suggest_span, - item_msg, - self.get_primary_err_msg(base))); - } - }, - _ => {}, - } - }, - _ => {}, - } + | Write(WriteKind::MutableBorrow(BorrowKind::Mut { .. })) => { + match self.is_mutable(place, is_local_mutation_allowed) { + Ok(root_place) => self.add_used_mut(root_place, flow_state), + Err(place_err) => { + error_reported = true; + let item_msg = self.get_default_err_msg(place); + let mut err = self.tcx + .cannot_borrow_path_as_mutable(span, &item_msg, Origin::Mir); + err.span_label(span, "cannot borrow as mutable"); - if let Some((err_help_span, - err_help_stmt, - to_suggest_span, - item_msg, - sec_span)) = err_info { - let mut err = self.tcx.cannot_assign(span, &item_msg, Origin::Mir); - err.span_suggestion(err_help_span, - err_help_stmt, - format!("&mut {}", to_suggest_span)); - if place != place_err { - err.span_label(span, sec_span); - } - err.emit() - } else { - let item_msg_ = self.get_default_err_msg(place); - let mut err = self.tcx.cannot_assign(span, &item_msg_, Origin::Mir); - err.span_label(span, "cannot mutate"); if place != place_err { if let Some(name) = self.describe_place(place_err) { err.note(&format!("the value which is causing this path not to be \ - mutable is...: `{}`", name)); + mutable is...: `{}`", name)); } } + err.emit(); } } } + Reservation(WriteKind::Mutate) | Write(WriteKind::Mutate) => { + match self.is_mutable(place, is_local_mutation_allowed) { + Ok(root_place) => self.add_used_mut(root_place, flow_state), + Err(place_err) => { + error_reported = true; + + let err_info = if let Place::Projection( + box Projection { + base: Place::Local(local), + elem: ProjectionElem::Deref + } + ) = *place_err { + let locations = self.mir.find_assignments(local); + if locations.len() > 0 { + let item_msg = if error_reported { + self.get_secondary_err_msg(&Place::Local(local)) + } else { + self.get_default_err_msg(place) + }; + let sp = self.mir.source_info(locations[0]).span; + let mut to_suggest_span = String::new(); + if let Ok(src) = + self.tcx.sess.codemap().span_to_snippet(sp) { + to_suggest_span = src[1..].to_string(); + }; + Some((sp, + "consider changing this to be a \ + mutable reference", + to_suggest_span, + item_msg, + self.get_primary_err_msg(&Place::Local(local)))) + } else { + None + } + } else { + None + }; + + if let Some((err_help_span, + err_help_stmt, + to_suggest_span, + item_msg, + sec_span)) = err_info { + let mut err = self.tcx.cannot_assign(span, &item_msg, Origin::Mir); + err.span_suggestion(err_help_span, + err_help_stmt, + format!("&mut {}", to_suggest_span)); + if place != place_err { + err.span_label(span, sec_span); + } + err.emit() + } else { + let item_msg = self.get_default_err_msg(place); + let mut err = self.tcx.cannot_assign(span, &item_msg, Origin::Mir); + err.span_label(span, "cannot mutate"); + if place != place_err { + if let Some(name) = self.describe_place(place_err) { + err.note(&format!("the value which is causing this path not \ + to be mutable is...: `{}`", name)); + } + } + err.emit(); + } + } + } + } Reservation(WriteKind::Move) | Reservation(WriteKind::StorageDeadOrDrop) | Reservation(WriteKind::MutableBorrow(BorrowKind::Shared)) @@ -1702,30 +1828,76 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { error_reported } - /// Can this value be written or borrowed mutably + /// Adds the place into the used mutable variables set + fn add_used_mut<'d>( + &mut self, + root_place: RootPlace<'d, 'tcx>, + flow_state: &Flows<'cx, 'gcx, 'tcx> + ) { + match root_place { + RootPlace { + place: Place::Local(local), + is_local_mutation_allowed, + } => { + if is_local_mutation_allowed != LocalMutationIsAllowed::Yes { + // If the local may be initialized, and it is now currently being + // mutated, then it is justified to be annotated with the `mut` + // keyword, since the mutation may be a possible reassignment. + let mpi = self.move_data.rev_lookup.find_local(*local); + if flow_state.inits.contains(&mpi) { + self.used_mut.insert(*local); + } + } + } + RootPlace { + place: place @ Place::Projection(_), + is_local_mutation_allowed: _, + } => { + if let Some(field) = self.is_upvar_field_projection(&place) { + self.used_mut_upvars.push(field); + } + } + RootPlace { + place: Place::Static(..), + is_local_mutation_allowed: _, + } => {} + } + } + + /// Whether this value be written or borrowed mutably. + /// Returns the root place if the place passed in is a projection. fn is_mutable<'d>( &self, place: &'d Place<'tcx>, is_local_mutation_allowed: LocalMutationIsAllowed, - ) -> Result<(), &'d Place<'tcx>> { + ) -> Result<RootPlace<'d, 'tcx>, &'d Place<'tcx>> { match *place { Place::Local(local) => { let local = &self.mir.local_decls[local]; match local.mutability { Mutability::Not => match is_local_mutation_allowed { - LocalMutationIsAllowed::Yes | LocalMutationIsAllowed::ExceptUpvars => { - Ok(()) + LocalMutationIsAllowed::Yes => { + Ok(RootPlace { + place, + is_local_mutation_allowed: LocalMutationIsAllowed::Yes + }) + } + LocalMutationIsAllowed::ExceptUpvars => { + Ok(RootPlace { + place, + is_local_mutation_allowed: LocalMutationIsAllowed::ExceptUpvars + }) } LocalMutationIsAllowed::No => Err(place), }, - Mutability::Mut => Ok(()), + Mutability::Mut => Ok(RootPlace { place, is_local_mutation_allowed }), } } Place::Static(ref static_) => if self.tcx.is_static(static_.def_id) != Some(hir::Mutability::MutMutable) { Err(place) } else { - Ok(()) + Ok(RootPlace { place, is_local_mutation_allowed }) }, Place::Projection(ref proj) => { match proj.elem { @@ -1761,9 +1933,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { match tnm.mutbl { // `*const` raw pointers are not mutable hir::MutImmutable => return Err(place), - // `*mut` raw pointers are always mutable, regardless of context - // The users have to check by themselve. - hir::MutMutable => return Ok(()), + // `*mut` raw pointers are always mutable, regardless of + // context. The users have to check by themselves. + hir::MutMutable => { + return Ok(RootPlace { place, is_local_mutation_allowed }); + } } } // `Box<T>` owns its content, so mutable if its location is mutable @@ -1794,7 +1968,34 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } (Mutability::Not, LocalMutationIsAllowed::Yes) | (Mutability::Mut, _) => { - self.is_mutable(&proj.base, is_local_mutation_allowed) + // Subtle: this is an upvar + // reference, so it looks like + // `self.foo` -- we want to double + // check that the context `*self` + // is mutable (i.e., this is not a + // `Fn` closure). But if that + // check succeeds, we want to + // *blame* the mutability on + // `place` (that is, + // `self.foo`). This is used to + // propagate the info about + // whether mutability declarations + // are used outwards, so that we register + // the outer variable as mutable. Otherwise a + // test like this fails to record the `mut` + // as needed: + // + // ``` + // fn foo<F: FnOnce()>(_f: F) { } + // fn main() { + // let var = Vec::new(); + // foo(move || { + // var.push(1); + // }); + // } + // ``` + let _ = self.is_mutable(&proj.base, is_local_mutation_allowed)?; + Ok(RootPlace { place, is_local_mutation_allowed }) } } } else { diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs index afaedecdf0a..d34e9434fbf 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs @@ -8,28 +8,37 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use borrow_check::borrow_set::BorrowSet; +use borrow_check::location::LocationTable; +use borrow_check::nll::facts::AllFacts; use rustc::hir; -use rustc::mir::{BasicBlock, BasicBlockData, Location, Place, Mir, Rvalue}; +use rustc::infer::InferCtxt; +use rustc::mir::visit::TyContext; use rustc::mir::visit::Visitor; use rustc::mir::Place::Projection; -use rustc::mir::{Local, PlaceProjection, ProjectionElem}; -use rustc::mir::visit::TyContext; -use rustc::infer::InferCtxt; -use rustc::ty::{self, CanonicalTy, ClosureSubsts}; -use rustc::ty::subst::Substs; +use rustc::mir::{BasicBlock, BasicBlockData, Location, Mir, Place, Rvalue}; +use rustc::mir::{Local, PlaceProjection, ProjectionElem, Statement, Terminator}; use rustc::ty::fold::TypeFoldable; +use rustc::ty::subst::Substs; +use rustc::ty::{self, CanonicalTy, ClosureSubsts}; +use super::region_infer::{Cause, RegionInferenceContext}; use super::ToRegionVid; -use super::region_infer::{RegionInferenceContext, Cause}; pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>( infcx: &InferCtxt<'cx, 'gcx, 'tcx>, regioncx: &mut RegionInferenceContext<'tcx>, + all_facts: &mut Option<AllFacts>, + location_table: &LocationTable, mir: &Mir<'tcx>, + borrow_set: &BorrowSet<'tcx>, ) { let mut cg = ConstraintGeneration { + borrow_set, infcx, regioncx, + location_table, + all_facts, mir, }; @@ -41,8 +50,11 @@ pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>( /// 'cg = the duration of the constraint generation process itself. struct ConstraintGeneration<'cg, 'cx: 'cg, 'gcx: 'tcx, 'tcx: 'cx> { infcx: &'cg InferCtxt<'cx, 'gcx, 'tcx>, + all_facts: &'cg mut Option<AllFacts>, + location_table: &'cg LocationTable, regioncx: &'cg mut RegionInferenceContext<'tcx>, mir: &'cg Mir<'tcx>, + borrow_set: &'cg BorrowSet<'tcx>, } impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx, 'tcx> { @@ -68,12 +80,14 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx /// call. Make them live at the location where they appear. fn visit_ty(&mut self, ty: &ty::Ty<'tcx>, ty_context: TyContext) { match ty_context { - TyContext::ReturnTy(source_info) | - TyContext::YieldTy(source_info) | - TyContext::LocalDecl { source_info, .. } => { - span_bug!(source_info.span, - "should not be visiting outside of the CFG: {:?}", - ty_context); + TyContext::ReturnTy(source_info) + | TyContext::YieldTy(source_info) + | TyContext::LocalDecl { source_info, .. } => { + span_bug!( + source_info.span, + "should not be visiting outside of the CFG: {:?}", + ty_context + ); } TyContext::Location(location) => { self.add_regular_live_constraint(*ty, location, Cause::LiveOther(location)); @@ -90,25 +104,117 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx self.super_closure_substs(substs); } + fn visit_statement( + &mut self, + block: BasicBlock, + statement: &Statement<'tcx>, + location: Location, + ) { + if let Some(all_facts) = self.all_facts { + all_facts.cfg_edge.push(( + self.location_table.start_index(location), + self.location_table.mid_index(location), + )); + + all_facts.cfg_edge.push(( + self.location_table.mid_index(location), + self.location_table + .start_index(location.successor_within_block()), + )); + } + + self.super_statement(block, statement, location); + } + + fn visit_assign( + &mut self, + block: BasicBlock, + place: &Place<'tcx>, + rvalue: &Rvalue<'tcx>, + location: Location, + ) { + // When we see `X = ...`, then kill borrows of + // `(*X).foo` and so forth. + if let Some(all_facts) = self.all_facts { + if let Place::Local(temp) = place { + if let Some(borrow_indices) = self.borrow_set.local_map.get(temp) { + for &borrow_index in borrow_indices { + let location_index = self.location_table.mid_index(location); + all_facts.killed.push((borrow_index, location_index)); + } + } + } + } + + self.super_assign(block, place, rvalue, location); + } + + fn visit_terminator( + &mut self, + block: BasicBlock, + terminator: &Terminator<'tcx>, + location: Location, + ) { + if let Some(all_facts) = self.all_facts { + all_facts.cfg_edge.push(( + self.location_table.start_index(location), + self.location_table.mid_index(location), + )); + + for successor_block in terminator.successors() { + all_facts.cfg_edge.push(( + self.location_table.mid_index(location), + self.location_table + .start_index(successor_block.start_location()), + )); + } + } + + self.super_terminator(block, terminator, location); + } + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { debug!("visit_rvalue(rvalue={:?}, location={:?})", rvalue, location); - // Look for an rvalue like: - // - // & L - // - // where L is the path that is borrowed. In that case, we have - // to add the reborrow constraints (which don't fall out - // naturally from the type-checker). - if let Rvalue::Ref(region, _bk, ref borrowed_lv) = *rvalue { - self.add_reborrow_constraint(location, region, borrowed_lv); + match rvalue { + Rvalue::Ref(region, _borrow_kind, borrowed_place) => { + // In some cases, e.g. when borrowing from an unsafe + // place, we don't bother to create a loan, since + // there are no conditions to validate. + if let Some(all_facts) = self.all_facts { + if let Some(borrow_index) = self.borrow_set.location_map.get(&location) { + let region_vid = region.to_region_vid(); + all_facts.borrow_region.push(( + region_vid, + *borrow_index, + self.location_table.mid_index(location), + )); + } + } + + // Look for an rvalue like: + // + // & L + // + // where L is the path that is borrowed. In that case, we have + // to add the reborrow constraints (which don't fall out + // naturally from the type-checker). + self.add_reborrow_constraint(location, region, borrowed_place); + } + + _ => { } } self.super_rvalue(rvalue, location); } - fn visit_user_assert_ty(&mut self, _c_ty: &CanonicalTy<'tcx>, - _local: &Local, _location: Location) { } + fn visit_user_assert_ty( + &mut self, + _c_ty: &CanonicalTy<'tcx>, + _local: &Local, + _location: Location, + ) { + } } impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> { @@ -122,8 +228,7 @@ impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> { { debug!( "add_regular_live_constraint(live_ty={:?}, location={:?})", - live_ty, - location + live_ty, location ); self.infcx @@ -144,8 +249,10 @@ impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> { ) { let mut borrowed_place = borrowed_place; - debug!("add_reborrow_constraint({:?}, {:?}, {:?})", - location, borrow_region, borrowed_place); + debug!( + "add_reborrow_constraint({:?}, {:?}, {:?})", + location, borrow_region, borrowed_place + ); while let Projection(box PlaceProjection { base, elem }) = borrowed_place { debug!("add_reborrow_constraint - iteration {:?}", borrowed_place); @@ -165,12 +272,20 @@ impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> { location.successor_within_block(), ); + if let Some(all_facts) = self.all_facts { + all_facts.outlives.push(( + ref_region.to_region_vid(), + borrow_region.to_region_vid(), + self.location_table.mid_index(location), + )); + } + match mutbl { hir::Mutability::MutImmutable => { // Immutable reference. We don't need the base // to be valid for the entire lifetime of // the borrow. - break + break; } hir::Mutability::MutMutable => { // Mutable reference. We *do* need the base @@ -199,19 +314,19 @@ impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> { } ty::TyRawPtr(..) => { // deref of raw pointer, guaranteed to be valid - break + break; } ty::TyAdt(def, _) if def.is_box() => { // deref of `Box`, need the base to be valid - propagate } - _ => bug!("unexpected deref ty {:?} in {:?}", base_ty, borrowed_place) + _ => bug!("unexpected deref ty {:?} in {:?}", base_ty, borrowed_place), } } - ProjectionElem::Field(..) | - ProjectionElem::Downcast(..) | - ProjectionElem::Index(..) | - ProjectionElem::ConstantIndex { .. } | - ProjectionElem::Subslice { .. } => { + ProjectionElem::Field(..) + | ProjectionElem::Downcast(..) + | ProjectionElem::Index(..) + | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } => { // other field access } } diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs index d5e11a312ec..56e388a5b60 100644 --- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs +++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs @@ -193,7 +193,6 @@ impl<'gcx, 'tcx> UseFinder<'gcx, 'tcx> { block_data .terminator() .successors() - .iter() .map(|&basic_block| Location { statement_index: 0, block: basic_block, diff --git a/src/librustc_mir/borrow_check/nll/facts.rs b/src/librustc_mir/borrow_check/nll/facts.rs new file mode 100644 index 00000000000..2802aa0dff4 --- /dev/null +++ b/src/librustc_mir/borrow_check/nll/facts.rs @@ -0,0 +1,194 @@ +// 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 borrow_check::location::{LocationIndex, LocationTable}; +use dataflow::indexes::BorrowIndex; +use rustc::ty::RegionVid; +use std::error::Error; +use std::fmt::Debug; +use std::fs::{self, File}; +use std::io::Write; +use std::path::Path; + +/// The "facts" which are the basis of the NLL borrow analysis. +#[derive(Default)] +crate struct AllFacts { + // `borrow_region(R, B, P)` -- the region R may refer to data from borrow B + // starting at the point P (this is usually the point *after* a borrow rvalue) + crate borrow_region: Vec<(RegionVid, BorrowIndex, LocationIndex)>, + + // universal_region(R) -- this is a "free region" within fn body + crate universal_region: Vec<RegionVid>, + + // `cfg_edge(P,Q)` for each edge P -> Q in the control flow + crate cfg_edge: Vec<(LocationIndex, LocationIndex)>, + + // `killed(B,P)` when some prefix of the path borrowed at B is assigned at point P + crate killed: Vec<(BorrowIndex, LocationIndex)>, + + // `outlives(R1, R2, P)` when we require `R1@P: R2@P` + crate outlives: Vec<(RegionVid, RegionVid, LocationIndex)>, + + // `region_live_at(R, P)` when the region R appears in a live variable at P + crate region_live_at: Vec<(RegionVid, LocationIndex)>, +} + +impl AllFacts { + crate fn write_to_dir( + &self, + dir: impl AsRef<Path>, + location_table: &LocationTable, + ) -> Result<(), Box<dyn Error>> { + let dir: &Path = dir.as_ref(); + fs::create_dir_all(dir)?; + let wr = FactWriter { location_table, dir }; + macro_rules! write_facts_to_path { + ($wr:ident . write_facts_to_path($this:ident . [ + $($field:ident,)* + ])) => { + $( + $wr.write_facts_to_path( + &$this.$field, + &format!("{}.facts", stringify!($field)) + )?; + )* + } + } + write_facts_to_path! { + wr.write_facts_to_path(self.[ + borrow_region, + universal_region, + cfg_edge, + killed, + outlives, + region_live_at, + ]) + } + Ok(()) + } +} + +struct FactWriter<'w> { + location_table: &'w LocationTable, + dir: &'w Path, +} + +impl<'w> FactWriter<'w> { + fn write_facts_to_path<T>( + &self, + rows: &Vec<T>, + file_name: &str, + ) -> Result<(), Box<dyn Error>> + where + T: FactRow, + { + let file = &self.dir.join(file_name); + let mut file = File::create(file)?; + for row in rows { + row.write(&mut file, self.location_table)?; + } + Ok(()) + } +} + +trait FactRow { + fn write( + &self, + out: &mut File, + location_table: &LocationTable, + ) -> Result<(), Box<dyn Error>>; +} + +impl FactRow for RegionVid { + fn write( + &self, + out: &mut File, + location_table: &LocationTable, + ) -> Result<(), Box<dyn Error>> { + write_row(out, location_table, &[self]) + } +} + +impl<A, B> FactRow for (A, B) +where + A: FactCell, + B: FactCell, +{ + fn write( + &self, + out: &mut File, + location_table: &LocationTable, + ) -> Result<(), Box<dyn Error>> { + write_row(out, location_table, &[&self.0, &self.1]) + } +} + +impl<A, B, C> FactRow for (A, B, C) +where + A: FactCell, + B: FactCell, + C: FactCell, +{ + fn write( + &self, + out: &mut File, + location_table: &LocationTable, + ) -> Result<(), Box<dyn Error>> { + write_row(out, location_table, &[&self.0, &self.1, &self.2]) + } +} + +impl<A, B, C, D> FactRow for (A, B, C, D) +where + A: FactCell, + B: FactCell, + C: FactCell, + D: FactCell, +{ + fn write( + &self, + out: &mut File, + location_table: &LocationTable, + ) -> Result<(), Box<dyn Error>> { + write_row(out, location_table, &[&self.0, &self.1, &self.2, &self.3]) + } +} + +fn write_row( + out: &mut dyn Write, + location_table: &LocationTable, + columns: &[&dyn FactCell], +) -> Result<(), Box<dyn Error>> { + for (index, c) in columns.iter().enumerate() { + let tail = if index == columns.len() - 1 { + "\n" + } else { + "\t" + }; + write!(out, "{:?}{}", c.to_string(location_table), tail)?; + } + Ok(()) +} + +trait FactCell { + fn to_string(&self, location_table: &LocationTable) -> String; +} + +impl<A: Debug> FactCell for A { + default fn to_string(&self, _location_table: &LocationTable) -> String { + format!("{:?}", self) + } +} + +impl FactCell for LocationIndex { + fn to_string(&self, location_table: &LocationTable) -> String { + format!("{:?}", location_table.to_location(*self)) + } +} diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index 3ca1bd23e86..0b1729294d8 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -9,36 +9,39 @@ // except according to those terms. use borrow_check::borrow_set::BorrowSet; +use borrow_check::location::LocationTable; +use dataflow::move_paths::MoveData; +use dataflow::FlowAtLocation; +use dataflow::MaybeInitializedPlaces; use rustc::hir::def_id::DefId; -use rustc::mir::{ClosureRegionRequirements, ClosureOutlivesSubject, Mir}; use rustc::infer::InferCtxt; +use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, Mir}; use rustc::ty::{self, RegionKind, RegionVid}; use rustc::util::nodemap::FxHashMap; use std::collections::BTreeSet; use std::fmt::Debug; use std::io; +use std::path::PathBuf; use transform::MirSource; use util::liveness::{LivenessResults, LocalSet}; -use dataflow::FlowAtLocation; -use dataflow::MaybeInitializedPlaces; -use dataflow::move_paths::MoveData; +use self::mir_util::PassWhere; use util as mir_util; use util::pretty::{self, ALIGN}; -use self::mir_util::PassWhere; mod constraint_generation; pub mod explain_borrow; -pub(crate) mod region_infer; +mod facts; +crate mod region_infer; mod renumber; mod subtype_constraint_generation; -pub(crate) mod type_check; +crate mod type_check; mod universal_regions; +use self::facts::AllFacts; use self::region_infer::RegionInferenceContext; use self::universal_regions::UniversalRegions; - /// Rewrites the regions in the MIR to use NLL variables, also /// scraping out the set of universal regions (e.g., region parameters) /// declared on the function. That set will need to be given to @@ -71,10 +74,11 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>( def_id: DefId, universal_regions: UniversalRegions<'tcx>, mir: &Mir<'tcx>, + location_table: &LocationTable, param_env: ty::ParamEnv<'gcx>, flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'cx, 'gcx, 'tcx>>, move_data: &MoveData<'tcx>, - _borrow_set: &BorrowSet<'tcx>, + borrow_set: &BorrowSet<'tcx>, ) -> ( RegionInferenceContext<'tcx>, Option<ClosureRegionRequirements<'gcx>>, @@ -92,15 +96,47 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>( move_data, ); + let mut all_facts = if infcx.tcx.sess.opts.debugging_opts.nll_facts { + Some(AllFacts::default()) + } else { + None + }; + + if let Some(all_facts) = &mut all_facts { + all_facts + .universal_region + .extend(universal_regions.universal_regions()); + } + // Create the region inference context, taking ownership of the region inference // data that was contained in `infcx`. let var_origins = infcx.take_region_var_origins(); - let mut regioncx = RegionInferenceContext::new(var_origins, universal_regions, mir); - subtype_constraint_generation::generate(&mut regioncx, mir, constraint_sets); - + let mut regioncx = + RegionInferenceContext::new(var_origins, universal_regions, mir); + + // Generate various constraints. + subtype_constraint_generation::generate( + &mut regioncx, + &mut all_facts, + location_table, + mir, + constraint_sets, + ); + constraint_generation::generate_constraints( + infcx, + &mut regioncx, + &mut all_facts, + location_table, + &mir, + borrow_set, + ); - // Generate non-subtyping constraints. - constraint_generation::generate_constraints(infcx, &mut regioncx, &mir); + // Dump facts if requested. + if let Some(all_facts) = all_facts { + let def_path = infcx.tcx.hir.def_path(def_id); + let dir_path = PathBuf::from("nll-facts").join(def_path.to_filename_friendly_no_crate()); + all_facts.write_to_dir(dir_path, location_table).unwrap(); + } // Solve the region constraints. let closure_region_requirements = regioncx.solve(infcx, &mir, def_id); diff --git a/src/librustc_mir/borrow_check/nll/region_infer/dfs.rs b/src/librustc_mir/borrow_check/nll/region_infer/dfs.rs index 4fcd3118f91..f68394d6149 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/dfs.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/dfs.rs @@ -95,7 +95,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { block_data .terminator() .successors() - .iter() .map(|&basic_block| Location { statement_index: 0, block: basic_block, diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index 08391401cc6..4d1f3e2b430 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -16,7 +16,7 @@ use rustc::infer::RegionObligation; use rustc::infer::RegionVariableOrigin; use rustc::infer::SubregionOrigin; use rustc::infer::error_reporting::nice_region_error::NiceRegionError; -use rustc::infer::region_constraints::{GenericKind, VarOrigins}; +use rustc::infer::region_constraints::{GenericKind, VarInfos}; use rustc::mir::{ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements, Local, Location, Mir}; use rustc::traits::ObligationCause; @@ -256,19 +256,19 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// of those will be constant regions representing the free /// regions defined in `universal_regions`. pub(crate) fn new( - var_origins: VarOrigins, + var_infos: VarInfos, universal_regions: UniversalRegions<'tcx>, mir: &Mir<'tcx>, ) -> Self { - let num_region_variables = var_origins.len(); + let num_region_variables = var_infos.len(); let num_universal_regions = universal_regions.len(); let elements = &Rc::new(RegionValueElements::new(mir, num_universal_regions)); // Create a RegionDefinition for each inference variable. - let definitions = var_origins + let definitions = var_infos .into_iter() - .map(|origin| RegionDefinition::new(origin)) + .map(|info| RegionDefinition::new(info.origin)) .collect(); let mut result = Self { diff --git a/src/librustc_mir/borrow_check/nll/subtype_constraint_generation.rs b/src/librustc_mir/borrow_check/nll/subtype_constraint_generation.rs index 32728145b29..9db19085a39 100644 --- a/src/librustc_mir/borrow_check/nll/subtype_constraint_generation.rs +++ b/src/librustc_mir/borrow_check/nll/subtype_constraint_generation.rs @@ -8,14 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::mir::Mir; +use borrow_check::location::LocationTable; +use borrow_check::nll::facts::AllFacts; use rustc::infer::region_constraints::Constraint; use rustc::infer::region_constraints::RegionConstraintData; use rustc::infer::region_constraints::{Verify, VerifyBound}; +use rustc::mir::{Location, Mir}; use rustc::ty; +use std::iter; use syntax::codemap::Span; -use super::region_infer::{TypeTest, RegionInferenceContext, RegionTest}; +use super::region_infer::{RegionInferenceContext, RegionTest, TypeTest}; use super::type_check::Locations; use super::type_check::MirTypeckRegionConstraints; use super::type_check::OutlivesSet; @@ -27,19 +30,30 @@ use super::type_check::OutlivesSet; /// them into the NLL `RegionInferenceContext`. pub(super) fn generate<'tcx>( regioncx: &mut RegionInferenceContext<'tcx>, + all_facts: &mut Option<AllFacts>, + location_table: &LocationTable, mir: &Mir<'tcx>, constraints: &MirTypeckRegionConstraints<'tcx>, ) { - SubtypeConstraintGenerator { regioncx, mir }.generate(constraints); + SubtypeConstraintGenerator { + regioncx, + location_table, + mir, + }.generate(constraints, all_facts); } struct SubtypeConstraintGenerator<'cx, 'tcx: 'cx> { regioncx: &'cx mut RegionInferenceContext<'tcx>, + location_table: &'cx LocationTable, mir: &'cx Mir<'tcx>, } impl<'cx, 'tcx> SubtypeConstraintGenerator<'cx, 'tcx> { - fn generate(&mut self, constraints: &MirTypeckRegionConstraints<'tcx>) { + fn generate( + &mut self, + constraints: &MirTypeckRegionConstraints<'tcx>, + all_facts: &mut Option<AllFacts>, + ) { let MirTypeckRegionConstraints { liveness_set, outlives_sets, @@ -57,6 +71,17 @@ impl<'cx, 'tcx> SubtypeConstraintGenerator<'cx, 'tcx> { self.regioncx.add_live_point(region_vid, *location, &cause); } + if let Some(all_facts) = all_facts { + all_facts + .region_live_at + .extend(liveness_set.into_iter().flat_map(|(region, location, _)| { + let r = self.to_region_vid(region); + let p1 = self.location_table.start_index(*location); + let p2 = self.location_table.mid_index(*location); + iter::once((r, p1)).chain(iter::once((r, p2))) + })); + } + for OutlivesSet { locations, data } in outlives_sets { debug!("generate: constraints at: {:#?}", locations); let RegionConstraintData { @@ -65,7 +90,11 @@ impl<'cx, 'tcx> SubtypeConstraintGenerator<'cx, 'tcx> { givens, } = data; - let span = self.mir.source_info(locations.from_location).span; + let span = self.mir + .source_info(locations.from_location().unwrap_or(Location::START)) + .span; + + let at_location = locations.at_location().unwrap_or(Location::START); for constraint in constraints.keys() { debug!("generate: constraint: {:?}", constraint); @@ -83,8 +112,24 @@ impl<'cx, 'tcx> SubtypeConstraintGenerator<'cx, 'tcx> { // reverse direction, because `regioncx` talks about // "outlives" (`>=`) whereas the region constraints // talk about `<=`. - self.regioncx - .add_outlives(span, b_vid, a_vid, locations.at_location); + self.regioncx.add_outlives(span, b_vid, a_vid, at_location); + + // In the new analysis, all outlives relations etc + // "take effect" at the mid point of the statement + // that requires them, so ignore the `at_location`. + if let Some(all_facts) = all_facts { + if let Some(from_location) = locations.from_location() { + all_facts.outlives.push(( + b_vid, + a_vid, + self.location_table.mid_index(from_location), + )); + } else { + for location in self.location_table.all_points() { + all_facts.outlives.push((b_vid, a_vid, location)); + } + } + } } for verify in verifys { @@ -109,7 +154,7 @@ impl<'cx, 'tcx> SubtypeConstraintGenerator<'cx, 'tcx> { let lower_bound = self.to_region_vid(verify.region); - let point = locations.at_location; + let point = locations.at_location().unwrap_or(Location::START); let test = self.verify_bound_to_region_test(&verify.bound); @@ -149,14 +194,6 @@ impl<'cx, 'tcx> SubtypeConstraintGenerator<'cx, 'tcx> { } fn to_region_vid(&self, r: ty::Region<'tcx>) -> ty::RegionVid { - // Every region that we see in the constraints came from the - // MIR or from the parameter environment. If the former, it - // will be a region variable. If the latter, it will be in - // the set of universal regions *somewhere*. - if let ty::ReVar(vid) = r { - *vid - } else { - self.regioncx.to_region_vid(r) - } + self.regioncx.to_region_vid(r) } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs b/src/librustc_mir/borrow_check/nll/type_check/input_output.rs index b1aeae0b76b..2b1878c33e9 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/input_output.rs @@ -29,7 +29,7 @@ use rustc::traits::PredicateObligations; use rustc_data_structures::indexed_vec::Idx; -use super::{AtLocation, TypeChecker}; +use super::{Locations, TypeChecker}; impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { pub(super) fn equate_inputs_and_outputs( @@ -47,26 +47,21 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } = universal_regions; let infcx = self.infcx; - let start_position = Location { - block: START_BLOCK, - statement_index: 0, - }; - // Equate expected input tys with those in the MIR. let argument_locals = (1..).map(Local::new); for (&unnormalized_input_ty, local) in unnormalized_input_tys.iter().zip(argument_locals) { - let input_ty = self.normalize(&unnormalized_input_ty, start_position); + let input_ty = self.normalize(&unnormalized_input_ty, Locations::All); let mir_input_ty = mir.local_decls[local].ty; - self.equate_normalized_input_or_output(start_position, input_ty, mir_input_ty); + self.equate_normalized_input_or_output(input_ty, mir_input_ty); } assert!( mir.yield_ty.is_some() && universal_regions.yield_ty.is_some() || mir.yield_ty.is_none() && universal_regions.yield_ty.is_none() - ); + ); if let Some(mir_yield_ty) = mir.yield_ty { let ur_yield_ty = universal_regions.yield_ty.unwrap(); - self.equate_normalized_input_or_output(start_position, ur_yield_ty, mir_yield_ty); + self.equate_normalized_input_or_output(ur_yield_ty, mir_yield_ty); } // Return types are a bit more complex. They may contain existential `impl Trait` @@ -75,13 +70,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { "equate_inputs_and_outputs: unnormalized_output_ty={:?}", unnormalized_output_ty ); - let output_ty = self.normalize(&unnormalized_output_ty, start_position); + let output_ty = self.normalize(&unnormalized_output_ty, Locations::All); debug!( "equate_inputs_and_outputs: normalized output_ty={:?}", output_ty ); let mir_output_ty = mir.local_decls[RETURN_PLACE].ty; - let anon_type_map = self.fully_perform_op(start_position.at_self(), |cx| { + let anon_type_map = self.fully_perform_op(Locations::All, |cx| { let mut obligations = ObligationAccumulator::default(); let (output_ty, anon_type_map) = obligations.add(infcx.instantiate_anon_types( @@ -112,7 +107,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let anon_defn_ty = anon_defn_ty.subst(tcx, anon_decl.substs); let anon_defn_ty = renumber::renumber_regions( cx.infcx, - TyContext::Location(start_position), + TyContext::Location(Location::START), &anon_defn_ty, ); debug!( @@ -134,7 +129,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { }).unwrap_or_else(|terr| { span_mirbug!( self, - start_position, + Location::START, "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`", output_ty, mir_output_ty, @@ -148,7 +143,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { // prove that `T: Iterator` where `T` is the type we // instantiated it with). if let Some(anon_type_map) = anon_type_map { - self.fully_perform_op(start_position.at_self(), |_cx| { + self.fully_perform_op(Locations::All, |_cx| { infcx.constrain_anon_types(&anon_type_map, universal_regions); Ok(InferOk { value: (), @@ -158,13 +153,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } - fn equate_normalized_input_or_output(&mut self, location: Location, a: Ty<'tcx>, b: Ty<'tcx>) { + fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) { debug!("equate_normalized_input_or_output(a={:?}, b={:?})", a, b); - if let Err(terr) = self.eq_types(a, b, location.at_self()) { + if let Err(terr) = self.eq_types(a, b, Locations::All) { span_mirbug!( self, - location, + Location::START, "equate_normalized_input_or_output: `{:?}=={:?}` failed with `{:?}`", a, b, diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index ec7ee466008..42a1745addf 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -22,6 +22,7 @@ use rustc::infer::region_constraints::{GenericKind, RegionConstraintData}; use rustc::infer::{InferCtxt, InferOk, InferResult, LateBoundRegionConversionTime, UnitResult}; use rustc::mir::tcx::PlaceTy; use rustc::mir::visit::{PlaceContext, Visitor}; +use rustc::mir::interpret::EvalErrorKind::BoundsCheck; use rustc::mir::*; use rustc::traits::query::NoSolution; use rustc::traits::{self, Normalized, TraitEngine}; @@ -617,17 +618,72 @@ pub struct OutlivesSet<'tcx> { pub data: RegionConstraintData<'tcx>, } +/// The `Locations` type summarizes *where* region constraints are +/// required to hold. Normally, this is at a particular point which +/// created the obligation, but for constraints that the user gave, we +/// want the constraint to hold at all points. #[derive(Copy, Clone, Debug)] -pub struct Locations { - /// The location in the MIR that generated these constraints. - /// This is intended for error reporting and diagnosis; the - /// constraints may *take effect* at a distinct spot. - pub from_location: Location, - - /// The constraints must be met at this location. In terms of the - /// NLL RFC, when you have a constraint `R1: R2 @ P`, this field - /// is the `P` value. - pub at_location: Location, +pub enum Locations { + /// Indicates that a type constraint should always be true. This + /// is particularly important in the new borrowck analysis for + /// things like the type of the return slot. Consider this + /// example: + /// + /// ``` + /// fn foo<'a>(x: &'a u32) -> &'a u32 { + /// let y = 22; + /// return &y; // error + /// } + /// ``` + /// + /// Here, we wind up with the signature from the return type being + /// something like `&'1 u32` where `'1` is a universal region. But + /// the type of the return slot `_0` is something like `&'2 u32` + /// where `'2` is an existential region variable. The type checker + /// requires that `&'2 u32 = &'1 u32` -- but at what point? In the + /// older NLL analysis, we required this only at the entry point + /// to the function. By the nature of the constraints, this wound + /// up propagating to all points reachable from start (because + /// `'1` -- as a universal region -- is live everywhere). In the + /// newer analysis, though, this doesn't work: `_0` is considered + /// dead at the start (it has no usable value) and hence this type + /// equality is basically a no-op. Then, later on, when we do `_0 + /// = &'3 y`, that region `'3` never winds up related to the + /// universal region `'1` and hence no error occurs. Therefore, we + /// use Locations::All instead, which ensures that the `'1` and + /// `'2` are equal everything. We also use this for other + /// user-given type annotations; e.g., if the user wrote `let mut + /// x: &'static u32 = ...`, we would ensure that all values + /// assigned to `x` are of `'static` lifetime. + All, + + Pair { + /// The location in the MIR that generated these constraints. + /// This is intended for error reporting and diagnosis; the + /// constraints may *take effect* at a distinct spot. + from_location: Location, + + /// The constraints must be met at this location. In terms of the + /// NLL RFC, when you have a constraint `R1: R2 @ P`, this field + /// is the `P` value. + at_location: Location, + } +} + +impl Locations { + pub fn from_location(&self) -> Option<Location> { + match self { + Locations::All => None, + Locations::Pair { from_location, .. } => Some(*from_location), + } + } + + pub fn at_location(&self) -> Option<Location> { + match self { + Locations::All => None, + Locations::Pair { at_location, .. } => Some(*at_location), + } + } } impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { @@ -769,7 +825,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { "check_stmt: user_assert_ty ty={:?} local_ty={:?}", ty, local_ty ); - if let Err(terr) = self.eq_types(ty, local_ty, location.at_self()) { + if let Err(terr) = self.eq_types(ty, local_ty, Locations::All) { span_mirbug!( self, stmt, @@ -819,7 +875,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let place_ty = location.ty(mir, tcx).to_ty(tcx); let rv_ty = value.ty(mir, tcx); - let locations = Locations { + let locations = Locations::Pair { from_location: term_location, at_location: target.start_location(), }; @@ -838,7 +894,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { // *both* blocks, so we need to ensure that it holds // at both locations. if let Some(unwind) = unwind { - let locations = Locations { + let locations = Locations::Pair { from_location: term_location, at_location: unwind.start_location(), }; @@ -918,11 +974,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { )); } - if self.is_box_free(func) { - self.check_box_free_inputs(mir, term, &sig, args, term_location); - } else { - self.check_call_inputs(mir, term, &sig, args, term_location); - } + self.check_call_inputs(mir, term, &sig, args, term_location); } TerminatorKind::Assert { ref cond, ref msg, .. @@ -932,7 +984,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty); } - if let AssertMessage::BoundsCheck { ref len, ref index } = *msg { + if let BoundsCheck { ref len, ref index } = *msg { if len.ty(mir, tcx) != tcx.types.usize { span_mirbug!(self, len, "bounds-check length non-usize {:?}", len) } @@ -974,7 +1026,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { match *destination { Some((ref dest, target_block)) => { let dest_ty = dest.ty(mir, tcx).to_ty(tcx); - let locations = Locations { + let locations = Locations::Pair { from_location: term_location, at_location: target_block.start_location(), }; @@ -1026,70 +1078,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } - fn is_box_free(&self, operand: &Operand<'tcx>) -> bool { - match *operand { - Operand::Constant(ref c) => match c.ty.sty { - ty::TyFnDef(ty_def_id, _) => { - Some(ty_def_id) == self.tcx().lang_items().box_free_fn() - } - _ => false, - }, - _ => false, - } - } - - fn check_box_free_inputs( - &mut self, - mir: &Mir<'tcx>, - term: &Terminator<'tcx>, - sig: &ty::FnSig<'tcx>, - args: &[Operand<'tcx>], - term_location: Location, - ) { - debug!("check_box_free_inputs"); - - // box_free takes a Box as a pointer. Allow for that. - - if sig.inputs().len() != 1 { - span_mirbug!(self, term, "box_free should take 1 argument"); - return; - } - - let pointee_ty = match sig.inputs()[0].sty { - ty::TyRawPtr(mt) => mt.ty, - _ => { - span_mirbug!(self, term, "box_free should take a raw ptr"); - return; - } - }; - - if args.len() != 1 { - span_mirbug!(self, term, "box_free called with wrong # of args"); - return; - } - - let ty = args[0].ty(mir, self.tcx()); - let arg_ty = match ty.sty { - ty::TyRawPtr(mt) => mt.ty, - ty::TyAdt(def, _) if def.is_box() => ty.boxed_ty(), - _ => { - span_mirbug!(self, term, "box_free called with bad arg ty"); - return; - } - }; - - if let Err(terr) = self.sub_types(arg_ty, pointee_ty, term_location.at_self()) { - span_mirbug!( - self, - term, - "bad box_free arg ({:?} <- {:?}): {:?}", - pointee_ty, - arg_ty, - terr - ); - } - } - fn check_iscleanup(&mut self, mir: &Mir<'tcx>, block_data: &BasicBlockData<'tcx>) { let is_cleanup = block_data.is_cleanup; self.last_span = block_data.terminator().source_info.span; @@ -1442,7 +1430,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { }; let operand_ty = operand.ty(mir, tcx); if let Err(terr) = - self.sub_types(operand_ty, field_ty, location.at_successor_within_block()) + self.sub_types(operand_ty, field_ty, location.at_self()) { span_mirbug!( self, @@ -1494,7 +1482,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { // these extra requirements are basically like where // clauses on the struct. AggregateKind::Closure(def_id, substs) => { - if let Some(closure_region_requirements) = tcx.mir_borrowck(*def_id) { + if let Some(closure_region_requirements) = + tcx.mir_borrowck(*def_id).closure_requirements + { closure_region_requirements.apply_requirements( self.infcx, self.body_id, @@ -1579,12 +1569,12 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } - fn normalize<T>(&mut self, value: &T, location: Location) -> T + fn normalize<T>(&mut self, value: &T, location: impl ToLocations) -> T where T: fmt::Debug + TypeFoldable<'tcx>, { debug!("normalize(value={:?}, location={:?})", value, location); - self.fully_perform_op(location.at_self(), |this| { + self.fully_perform_op(location.to_locations(), |this| { let Normalized { value, obligations } = this.infcx .at(&this.misc(this.last_span), this.param_env) .normalize(value) @@ -1650,16 +1640,32 @@ trait AtLocation { impl AtLocation for Location { fn at_self(self) -> Locations { - Locations { + Locations::Pair { from_location: self, at_location: self, } } fn at_successor_within_block(self) -> Locations { - Locations { + Locations::Pair { from_location: self, at_location: self.successor_within_block(), } } } + +trait ToLocations: fmt::Debug + Copy { + fn to_locations(self) -> Locations; +} + +impl ToLocations for Locations { + fn to_locations(self) -> Locations { + self + } +} + +impl ToLocations for Location { + fn to_locations(self) -> Locations { + self.at_self() + } +} diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index 94702927d26..fae06db3162 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -9,6 +9,8 @@ // except according to those terms. use build::{BlockAnd, BlockAndExtension, Builder}; +use build::ForGuard::OutsideGuard; +use build::matches::ArmHasGuard; use hair::*; use rustc::mir::*; use rustc::hir; @@ -113,7 +115,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Declare the bindings, which may create a visibility scope. let remainder_span = remainder_scope.span(this.hir.tcx(), &this.hir.region_scope_tree); - let scope = this.declare_bindings(None, remainder_span, lint_level, &pattern); + let scope = this.declare_bindings(None, remainder_span, lint_level, &pattern, + ArmHasGuard(false)); // Evaluate the initializer, if present. if let Some(init) = initializer { @@ -135,8 +138,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } this.visit_bindings(&pattern, &mut |this, _, _, node, span, _| { - this.storage_live_binding(block, node, span); - this.schedule_drop_for_binding(node, span); + this.storage_live_binding(block, node, span, OutsideGuard); + this.schedule_drop_for_binding(node, span, OutsideGuard); }) } diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs index 9e217908511..365b9babd08 100644 --- a/src/librustc_mir/build/expr/as_place.rs +++ b/src/librustc_mir/build/expr/as_place.rs @@ -11,9 +11,11 @@ //! See docs in build/expr/mod.rs use build::{BlockAnd, BlockAndExtension, Builder}; +use build::ForGuard::{OutsideGuard, WithinGuard}; use build::expr::category::Category; use hair::*; use rustc::mir::*; +use rustc::mir::interpret::EvalErrorKind::BoundsCheck; use rustc_data_structures::indexed_vec::Idx; @@ -73,7 +75,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Operand::Copy(Place::Local(idx)), Operand::Copy(len.clone()))); - let msg = AssertMessage::BoundsCheck { + let msg = BoundsCheck { len: Operand::Move(len), index: Operand::Copy(Place::Local(idx)) }; @@ -85,8 +87,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { block.and(Place::Local(Local::new(1))) } ExprKind::VarRef { id } => { - let index = this.var_indices[&id]; - block.and(Place::Local(index)) + let place = if this.is_bound_var_in_guard(id) { + let index = this.var_local_id(id, WithinGuard); + if this.hir.tcx().all_pat_vars_are_implicit_refs_within_guards() { + Place::Local(index).deref() + } else { + Place::Local(index) + } + } else { + let index = this.var_local_id(id, OutsideGuard); + Place::Local(index) + }; + block.and(place) } ExprKind::StaticRef { id } => { block.and(Place::Static(Box::new(Static { def_id: id, ty: expr.ty }))) diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index b7f402f61a9..9e96fdf8214 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -10,7 +10,6 @@ //! See docs in build/expr/mod.rs -use rustc_const_math::{ConstMathErr, Op}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::Idx; @@ -21,7 +20,7 @@ use rustc::middle::const_val::ConstVal; use rustc::middle::region; use rustc::ty::{self, Ty}; use rustc::mir::*; -use rustc::mir::interpret::{Value, PrimVal}; +use rustc::mir::interpret::{Value, PrimVal, EvalErrorKind}; use syntax_pos::Span; impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { @@ -86,9 +85,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { this.cfg.push_assign(block, source_info, &is_min, Rvalue::BinaryOp(BinOp::Eq, arg.to_copy(), minval)); - let err = ConstMathErr::Overflow(Op::Neg); block = this.assert(block, Operand::Move(is_min), false, - AssertMessage::Math(err), expr_span); + EvalErrorKind::OverflowNeg, expr_span); } block.and(Rvalue::UnaryOp(op, arg)) } @@ -311,19 +309,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let val = result_value.clone().field(val_fld, ty); let of = result_value.field(of_fld, bool_ty); - let err = ConstMathErr::Overflow(match op { - BinOp::Add => Op::Add, - BinOp::Sub => Op::Sub, - BinOp::Mul => Op::Mul, - BinOp::Shl => Op::Shl, - BinOp::Shr => Op::Shr, - _ => { - bug!("MIR build_binary_op: {:?} is not checkable", op) - } - }); + let err = EvalErrorKind::Overflow(op); block = self.assert(block, Operand::Move(of), false, - AssertMessage::Math(err), span); + err, span); block.and(Rvalue::Use(Operand::Move(val))) } else { @@ -332,11 +321,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // and 2. there are two possible failure cases, divide-by-zero and overflow. let (zero_err, overflow_err) = if op == BinOp::Div { - (ConstMathErr::DivisionByZero, - ConstMathErr::Overflow(Op::Div)) + (EvalErrorKind::DivisionByZero, + EvalErrorKind::Overflow(op)) } else { - (ConstMathErr::RemainderByZero, - ConstMathErr::Overflow(Op::Rem)) + (EvalErrorKind::RemainderByZero, + EvalErrorKind::Overflow(op)) }; // Check for / 0 @@ -346,7 +335,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Rvalue::BinaryOp(BinOp::Eq, rhs.to_copy(), zero)); block = self.assert(block, Operand::Move(is_zero), false, - AssertMessage::Math(zero_err), span); + zero_err, span); // We only need to check for the overflow in one case: // MIN / -1, and only for signed values. @@ -371,7 +360,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Rvalue::BinaryOp(BinOp::BitAnd, is_neg_1, is_min)); block = self.assert(block, Operand::Move(of), false, - AssertMessage::Math(overflow_err), span); + overflow_err, span); } } diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index c130b4f550f..562f890b4c0 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -220,7 +220,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let f = ty.fn_sig(this.hir.tcx()); if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic { - Some(this.hir.tcx().item_name(def_id)) + Some(this.hir.tcx().item_name(def_id).as_str()) } else { None } diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 7eb52a3cdee..6946ac4c7b2 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -14,6 +14,8 @@ //! details. use build::{BlockAnd, BlockAndExtension, Builder}; +use build::{GuardFrame, GuardFrameLocal, LocalsForNode}; +use build::ForGuard::{self, OutsideGuard, WithinGuard}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::bitvec::BitVector; use rustc::ty::{self, Ty}; @@ -28,6 +30,11 @@ mod simplify; mod test; mod util; +/// ArmHasGuard is isomorphic to a boolean flag. It indicates whether +/// a match arm has a guard expression attached to it. +#[derive(Copy, Clone, Debug)] +pub(crate) struct ArmHasGuard(pub bool); + impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pub fn match_expr(&mut self, destination: &Place<'tcx>, @@ -66,7 +73,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let body = self.hir.mirror(arm.body.clone()); let scope = self.declare_bindings(None, body.span, LintLevel::Inherited, - &arm.patterns[0]); + &arm.patterns[0], + ArmHasGuard(arm.guard.is_some())); (body, scope.unwrap_or(self.visibility_scope)) }).collect(); @@ -149,7 +157,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { var: NodeId, span: Span) { if self.hir.tcx().sess.opts.debugging_opts.disable_nll_user_type_assert { return; } - let local_id = self.var_indices[&var]; + let local_id = self.var_local_id(var, OutsideGuard); let source_info = self.source_info(span); debug!("user_assert_ty: local_id={:?}", hir_id.local_id); @@ -173,14 +181,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { PatternKind::Binding { mode: BindingMode::ByValue, var, subpattern: None, .. } => { - let place = self.storage_live_binding(block, var, irrefutable_pat.span); + let place = self.storage_live_binding(block, var, irrefutable_pat.span, + OutsideGuard); if let Some(ty) = ty { self.user_assert_ty(block, ty, var, irrefutable_pat.span); } unpack!(block = self.into(&place, block, initializer)); - self.schedule_drop_for_binding(var, irrefutable_pat.span); + self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard); block.unit() } _ => { @@ -220,7 +229,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } // now apply the bindings, which will also declare the variables - self.bind_matched_candidate(block, candidate.bindings); + self.bind_matched_candidate_for_arm_body(block, &candidate.bindings, false); block.unit() } @@ -232,7 +241,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { mut var_scope: Option<VisibilityScope>, scope_span: Span, lint_level: LintLevel, - pattern: &Pattern<'tcx>) + pattern: &Pattern<'tcx>, + has_guard: ArmHasGuard) -> Option<VisibilityScope> { assert!(!(var_scope.is_some() && lint_level.is_explicit()), "can't have both a var and a lint scope at the same time"); @@ -254,15 +264,20 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { span, scope: var_scope.unwrap() }; - this.declare_binding(source_info, syntactic_scope, mutability, name, var, ty); + this.declare_binding(source_info, syntactic_scope, mutability, name, var, + ty, has_guard); }); var_scope } - pub fn storage_live_binding(&mut self, block: BasicBlock, var: NodeId, span: Span) + pub fn storage_live_binding(&mut self, + block: BasicBlock, + var: NodeId, + span: Span, + for_guard: ForGuard) -> Place<'tcx> { - let local_id = self.var_indices[&var]; + let local_id = self.var_local_id(var, for_guard); let source_info = self.source_info(span); self.cfg.push(block, Statement { source_info, @@ -271,8 +286,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Place::Local(local_id) } - pub fn schedule_drop_for_binding(&mut self, var: NodeId, span: Span) { - let local_id = self.var_indices[&var]; + pub fn schedule_drop_for_binding(&mut self, + var: NodeId, + span: Span, + for_guard: ForGuard) { + let local_id = self.var_local_id(var, for_guard); let var_ty = self.local_decls[local_id].ty; let hir_id = self.hir.tcx().hir.node_to_hir_id(var); let region_scope = self.hir.region_scope_tree.var_scope(hir_id.local_id); @@ -770,14 +788,129 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { vec![candidate.next_candidate_pre_binding_block], }); - self.bind_matched_candidate(block, candidate.bindings); + // rust-lang/rust#27282: The `autoref` business deserves some + // explanation here. + // + // The intent of the `autoref` flag is that when it is true, + // then any pattern bindings of type T will map to a `&T` + // within the context of the guard expression, but will + // continue to map to a `T` in the context of the arm body. To + // avoid surfacing this distinction in the user source code + // (which would be a severe change to the language and require + // far more revision to the compiler), when `autoref` is true, + // then any occurrence of the identifier in the guard + // expression will automatically get a deref op applied to it. + // + // So an input like: + // + // ``` + // let place = Foo::new(); + // match place { foo if inspect(foo) + // => feed(foo), ... } + // ``` + // + // will be treated as if it were really something like: + // + // ``` + // let place = Foo::new(); + // match place { Foo { .. } if { let tmp1 = &place; inspect(*tmp1) } + // => { let tmp2 = place; feed(tmp2) }, ... } + // + // And an input like: + // + // ``` + // let place = Foo::new(); + // match place { ref mut foo if inspect(foo) + // => feed(foo), ... } + // ``` + // + // will be treated as if it were really something like: + // + // ``` + // let place = Foo::new(); + // match place { Foo { .. } if { let tmp1 = & &mut place; inspect(*tmp1) } + // => { let tmp2 = &mut place; feed(tmp2) }, ... } + // ``` + // + // In short, any pattern binding will always look like *some* + // kind of `&T` within the guard at least in terms of how the + // MIR-borrowck views it, and this will ensure that guard + // expressions cannot mutate their the match inputs via such + // bindings. (It also ensures that guard expressions can at + // most *copy* values from such bindings; non-Copy things + // cannot be moved via pattern bindings in guard expressions.) + // + // ---- + // + // Implementation notes (under assumption `autoref` is true). + // + // To encode the distinction above, we must inject the + // temporaries `tmp1` and `tmp2`. + // + // There are two cases of interest: binding by-value, and binding by-ref. + // + // 1. Binding by-value: Things are simple. + // + // * Establishing `tmp1` creates a reference into the + // matched place. This code is emitted by + // bind_matched_candidate_for_guard. + // + // * `tmp2` is only initialized "lazily", after we have + // checked the guard. Thus, the code that can trigger + // moves out of the candidate can only fire after the + // guard evaluated to true. This initialization code is + // emitted by bind_matched_candidate_for_arm. + // + // 2. Binding by-reference: Things are tricky. + // + // * Here, the guard expression wants a `&&` or `&&mut` + // into the original input. This means we need to borrow + // a reference that we do not immediately have at hand + // (because all we have is the places associated with the + // match input itself; it is up to us to create a place + // holding a `&` or `&mut` that we can then borrow). + // + // * Therefore, when the binding is by-reference, we + // *eagerly* introduce the binding for the arm body + // (`tmp2`) and then borrow it (`tmp1`). + // + // * This is documented with "NOTE tricky business" below. + // + // FIXME The distinction in how `tmp2` is initialized is + // currently encoded in a pretty awkward fashion; namely, by + // passing a boolean to bind_matched_candidate_for_arm_body + // indicating whether all of the by-ref bindings were already + // initialized. + // + // * Also: pnkfelix thinks "laziness" is natural; but since + // MIR-borrowck did not complain with earlier (universally + // eager) MIR codegen, laziness might not be *necessary*. + + let autoref = self.hir.tcx().all_pat_vars_are_implicit_refs_within_guards(); if let Some(guard) = candidate.guard { + if autoref { + self.bind_matched_candidate_for_guard(block, &candidate.bindings); + let guard_frame = GuardFrame { + locals: candidate.bindings.iter() + .map(|b| GuardFrameLocal::new(b.var_id, b.binding_mode)) + .collect(), + }; + debug!("Entering guard translation context: {:?}", guard_frame); + self.guard_context.push(guard_frame); + } else { + self.bind_matched_candidate_for_arm_body(block, &candidate.bindings, false); + } + // the block to branch to if the guard fails; if there is no // guard, this block is simply unreachable let guard = self.hir.mirror(guard); let source_info = self.source_info(guard.span); let cond = unpack!(block = self.as_local_operand(block, guard)); + if autoref { + let guard_frame = self.guard_context.pop().unwrap(); + debug!("Exiting guard translation context with locals: {:?}", guard_frame); + } let false_edge_block = self.cfg.start_new_block(); self.cfg.terminate(block, source_info, @@ -785,6 +918,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { false_edge_block)); let otherwise = self.cfg.start_new_block(); + if autoref { + self.bind_matched_candidate_for_arm_body(block, &candidate.bindings, true); + } self.cfg.terminate(false_edge_block, source_info, TerminatorKind::FalseEdges { real_target: otherwise, @@ -793,47 +929,137 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }); Some(otherwise) } else { + self.bind_matched_candidate_for_arm_body(block, &candidate.bindings, false); self.cfg.terminate(block, candidate_source_info, TerminatorKind::Goto { target: arm_block }); None } } - fn bind_matched_candidate(&mut self, - block: BasicBlock, - bindings: Vec<Binding<'tcx>>) { - debug!("bind_matched_candidate(block={:?}, bindings={:?})", + fn bind_matched_candidate_for_guard(&mut self, + block: BasicBlock, + bindings: &[Binding<'tcx>]) { + debug!("bind_matched_candidate_for_guard(block={:?}, bindings={:?})", block, bindings); + // Assign each of the bindings. Since we are binding for a + // guard expression, this will never trigger moves out of the + // candidate. + let re_empty = self.hir.tcx().types.re_empty; + for binding in bindings { + let source_info = self.source_info(binding.span); + let local_for_guard = self.storage_live_binding( + block, binding.var_id, binding.span, WithinGuard); + // Question: Why schedule drops if bindings are all + // shared-&'s? Answer: Because schedule_drop_for_binding + // also emits StorageDead's for those locals. + self.schedule_drop_for_binding(binding.var_id, binding.span, WithinGuard); + match binding.binding_mode { + BindingMode::ByValue => { + let rvalue = Rvalue::Ref(re_empty, BorrowKind::Shared, binding.source.clone()); + self.cfg.push_assign(block, source_info, &local_for_guard, rvalue); + } + BindingMode::ByRef(region, borrow_kind) => { + // NOTE tricky business: For `ref id` and `ref mut + // id` patterns, we want `id` within the guard to + // correspond to a temp of type `& &T` or `& &mut + // T`, while within the arm body it will + // correspond to a temp of type `&T` or `&mut T`, + // as usual. + // + // But to inject the level of indirection, we need + // something to point to. + // + // So: + // + // 1. First set up the local for the arm body + // (even though we have not yet evaluated the + // guard itself), + // + // 2. Then setup the local for the guard, which is + // just a reference to the local from step 1. + // + // Note that since we are setting up the local for + // the arm body a bit eagerly here (and likewise + // scheduling its drop code), we should *not* do + // it redundantly later on. + // + // While we could have kept track of this with a + // flag or collection of such bindings, the + // treatment of all of these cases is uniform, so + // we should be safe just avoiding the code + // without maintaining such state.) + let local_for_arm_body = self.storage_live_binding( + block, binding.var_id, binding.span, OutsideGuard); + self.schedule_drop_for_binding(binding.var_id, binding.span, OutsideGuard); + + // rust-lang/rust#27282: this potentially mutable + // borrow may require a cast in the future to + // avoid conflicting with an implicit borrow of + // the whole match input; or maybe it just + // requires an extension of our two-phase borrows + // system. See discussion on rust-lang/rust#49870. + let rvalue = Rvalue::Ref(region, borrow_kind, binding.source.clone()); + self.cfg.push_assign(block, source_info, &local_for_arm_body, rvalue); + let rvalue = Rvalue::Ref(region, BorrowKind::Shared, local_for_arm_body); + self.cfg.push_assign(block, source_info, &local_for_guard, rvalue); + } + } + } + } + + fn bind_matched_candidate_for_arm_body(&mut self, + block: BasicBlock, + bindings: &[Binding<'tcx>], + already_initialized_state_for_refs: bool) { + debug!("bind_matched_candidate_for_arm_body(block={:?}, bindings={:?}, \ + already_initialized_state_for_refs={:?})", + block, bindings, already_initialized_state_for_refs); + // Assign each of the bindings. This may trigger moves out of the candidate. for binding in bindings { + if let BindingMode::ByRef(..) = binding.binding_mode { + // See "NOTE tricky business" above + if already_initialized_state_for_refs { continue; } + } + let source_info = self.source_info(binding.span); - let local = self.storage_live_binding(block, binding.var_id, binding.span); - self.schedule_drop_for_binding(binding.var_id, binding.span); + let local = self.storage_live_binding(block, binding.var_id, binding.span, + OutsideGuard); + self.schedule_drop_for_binding(binding.var_id, binding.span, OutsideGuard); let rvalue = match binding.binding_mode { - BindingMode::ByValue => - Rvalue::Use(self.consume_by_copy_or_move(binding.source)), - BindingMode::ByRef(region, borrow_kind) => - Rvalue::Ref(region, borrow_kind, binding.source), + BindingMode::ByValue => { + Rvalue::Use(self.consume_by_copy_or_move(binding.source.clone())) + } + BindingMode::ByRef(region, borrow_kind) => { + Rvalue::Ref(region, borrow_kind, binding.source.clone()) + } }; self.cfg.push_assign(block, source_info, &local, rvalue); } } + /// Each binding (`ref mut var`/`ref var`/`mut var`/`var`, where + /// the bound `var` has type `T` in the arm body) in a pattern + /// maps to *two* locals. The first local is a binding for + /// occurrences of `var` in the guard, which will all have type + /// `&T`. The second local is a binding for occurrences of `var` + /// in the arm body, which will have type `T`. fn declare_binding(&mut self, source_info: SourceInfo, syntactic_scope: VisibilityScope, mutability: Mutability, name: Name, var_id: NodeId, - var_ty: Ty<'tcx>) - -> Local + var_ty: Ty<'tcx>, + has_guard: ArmHasGuard) { debug!("declare_binding(var_id={:?}, name={:?}, var_ty={:?}, source_info={:?}, \ syntactic_scope={:?})", var_id, name, var_ty, source_info, syntactic_scope); - let var = self.local_decls.push(LocalDecl::<'tcx> { + let tcx = self.hir.tcx(); + let for_arm_body = self.local_decls.push(LocalDecl::<'tcx> { mutability, ty: var_ty.clone(), name: Some(name), @@ -842,10 +1068,21 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { internal: false, is_user_variable: true, }); - self.var_indices.insert(var_id, var); - - debug!("declare_binding: var={:?}", var); - - var + let locals = if has_guard.0 && tcx.all_pat_vars_are_implicit_refs_within_guards() { + let for_guard = self.local_decls.push(LocalDecl::<'tcx> { + mutability, + ty: tcx.mk_imm_ref(tcx.types.re_empty, var_ty), + name: Some(name), + source_info, + syntactic_scope, + internal: false, + is_user_variable: true, + }); + LocalsForNode::Two { for_guard, for_arm_body } + } else { + LocalsForNode::One(for_arm_body) + }; + debug!("declare_binding: vars={:?}", locals); + self.var_indices.insert(var_id, locals); } } diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 0d836f5cb97..dd2a336af41 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -291,8 +291,14 @@ struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { visibility_scope_info: IndexVec<VisibilityScope, VisibilityScopeInfo>, visibility_scope: VisibilityScope, + /// the guard-context: each time we build the guard expression for + /// a match arm, we push onto this stack, and then pop when we + /// finish building it. + guard_context: Vec<GuardFrame>, + /// Maps node ids of variable bindings to the `Local`s created for them. - var_indices: NodeMap<Local>, + /// (A match binding can have two locals; the 2nd is for the arm's guard.) + var_indices: NodeMap<LocalsForNode>, local_decls: IndexVec<Local, LocalDecl<'tcx>>, unit_temp: Option<Place<'tcx>>, @@ -305,6 +311,74 @@ struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { cached_unreachable_block: Option<BasicBlock>, } +impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { + fn is_bound_var_in_guard(&self, id: ast::NodeId) -> bool { + self.guard_context.iter().any(|frame| frame.locals.iter().any(|local| local.id == id)) + } + + fn var_local_id(&self, id: ast::NodeId, for_guard: ForGuard) -> Local { + self.var_indices[&id].local_id(for_guard) + } +} + +#[derive(Debug)] +enum LocalsForNode { + One(Local), + Two { for_guard: Local, for_arm_body: Local }, +} + +#[derive(Debug)] +struct GuardFrameLocal { + id: ast::NodeId, +} + +impl GuardFrameLocal { + fn new(id: ast::NodeId, _binding_mode: BindingMode) -> Self { + GuardFrameLocal { + id: id, + } + } +} + +#[derive(Debug)] +struct GuardFrame { + /// These are the id's of names that are bound by patterns of the + /// arm of *this* guard. + /// + /// (Frames higher up the stack will have the id's bound in arms + /// further out, such as in a case like: + /// + /// match E1 { + /// P1(id1) if (... (match E2 { P2(id2) if ... => B2 })) => B1, + /// } + /// + /// here, when building for FIXME + locals: Vec<GuardFrameLocal>, +} + +/// ForGuard is isomorphic to a boolean flag. It indicates whether we are +/// talking about the temp for a local binding for a use within a guard expression, +/// or a temp for use outside of a guard expressions. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +enum ForGuard { + WithinGuard, + OutsideGuard, +} + +impl LocalsForNode { + fn local_id(&self, for_guard: ForGuard) -> Local { + match (self, for_guard) { + (&LocalsForNode::One(local_id), ForGuard::OutsideGuard) | + (&LocalsForNode::Two { for_guard: local_id, .. }, ForGuard::WithinGuard) | + (&LocalsForNode::Two { for_arm_body: local_id, .. }, ForGuard::OutsideGuard) => + local_id, + + (&LocalsForNode::One(_), ForGuard::WithinGuard) => + bug!("anything with one local should never be within a guard."), + } + } +} + struct CFG<'tcx> { basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>, } @@ -548,6 +622,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { visibility_scopes: IndexVec::new(), visibility_scope: ARGUMENT_VISIBILITY_SCOPE, visibility_scope_info: IndexVec::new(), + guard_context: vec![], push_unsafe_count: 0, unpushed_unsafe: safety, breakable_scopes: vec![], @@ -636,11 +711,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Don't introduce extra copies for simple bindings PatternKind::Binding { mutability, var, mode: BindingMode::ByValue, .. } => { self.local_decls[local].mutability = mutability; - self.var_indices.insert(var, local); + self.var_indices.insert(var, LocalsForNode::One(local)); } _ => { scope = self.declare_bindings(scope, ast_body.span, - LintLevel::Inherited, &pattern); + LintLevel::Inherited, &pattern, + matches::ArmHasGuard(false)); unpack!(block = self.place_into_pattern(block, pattern, &place)); } } diff --git a/src/librustc_mir/dataflow/graphviz.rs b/src/librustc_mir/dataflow/graphviz.rs index 07585c08f6a..9096ac1444c 100644 --- a/src/librustc_mir/dataflow/graphviz.rs +++ b/src/librustc_mir/dataflow/graphviz.rs @@ -73,8 +73,8 @@ pub type Node = BasicBlock; pub struct Edge { source: BasicBlock, index: usize } fn outgoing(mir: &Mir, bb: BasicBlock) -> Vec<Edge> { - let succ_len = mir[bb].terminator().successors().len(); - (0..succ_len).map(|index| Edge { source: bb, index: index}).collect() + mir[bb].terminator().successors().enumerate() + .map(|(index, _)| Edge { source: bb, index: index}).collect() } impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P> @@ -285,6 +285,6 @@ impl<'a, 'tcx, MWF, P> dot::GraphWalk<'a> for Graph<'a, 'tcx, MWF, P> fn target(&self, edge: &Edge) -> Node { let mir = self.mbcx.mir(); - mir[edge.source].terminator().successors()[edge.index] + *mir[edge.source].terminator().successors().nth(edge.index).unwrap() } } diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index a21691813a4..098ad8e558f 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -179,8 +179,14 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> { if let RegionKind::ReEmpty = region { // If the borrowed value dies before the borrow is used, the region for // the borrow can be empty. Don't track the borrow in that case. + debug!("Borrows::statement_effect_on_borrows \ + location: {:?} stmt: {:?} has empty region, killing {:?}", + location, stmt.kind, index); sets.kill(&index); return + } else { + debug!("Borrows::statement_effect_on_borrows location: {:?} stmt: {:?}", + location, stmt.kind); } assert!(self.borrow_set.region_map.get(region).unwrap_or_else(|| { diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index e6aa2d3abb7..5890ea5c9d0 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -30,9 +30,9 @@ use syntax::ast::{self, LitKind}; use syntax::attr; use syntax::symbol::Symbol; use rustc::hir; -use rustc_const_math::ConstFloat; use rustc_data_structures::sync::Lrc; use rustc::mir::interpret::{Value, PrimVal}; +use hair::pattern::parse_float; #[derive(Clone)] pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { @@ -170,12 +170,11 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { neg: bool, ) -> Literal<'tcx> { trace!("const_eval_literal: {:#?}, {:?}, {:?}, {:?}", lit, ty, sp, neg); - let tcx = self.tcx.global_tcx(); - let parse_float = |num: &str, fty| -> ConstFloat { - ConstFloat::from_str(num, fty).unwrap_or_else(|_| { + let parse_float = |num, fty| -> Value { + parse_float(num, fty, neg).unwrap_or_else(|_| { // FIXME(#31407) this is only necessary because float parsing is buggy - tcx.sess.span_fatal(sp, "could not evaluate float literal (see issue #31407)"); + self.tcx.sess.span_fatal(sp, "could not evaluate float literal (see issue #31407)"); }) }; @@ -213,26 +212,14 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { }, LitKind::Int(n, _) => Value::ByVal(PrimVal::Bytes(clamp(n))), LitKind::Float(n, fty) => { - let n = n.as_str(); - let mut f = parse_float(&n, fty); - if neg { - f = -f; - } - let bits = f.bits; - Value::ByVal(PrimVal::Bytes(bits)) + parse_float(n, fty) } LitKind::FloatUnsuffixed(n) => { let fty = match ty.sty { ty::TyFloat(fty) => fty, _ => bug!() }; - let n = n.as_str(); - let mut f = parse_float(&n, fty); - if neg { - f = -f; - } - let bits = f.bits; - Value::ByVal(PrimVal::Bytes(bits)) + parse_float(n, fty) } LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)), LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)), diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index d924baaf005..77bcd88cecb 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -17,7 +17,7 @@ use super::{Pattern, PatternContext, PatternError, PatternKind}; use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor}; use rustc::middle::expr_use_visitor::{LoanCause, MutateMode}; use rustc::middle::expr_use_visitor as euv; -use rustc::middle::mem_categorization::{cmt}; +use rustc::middle::mem_categorization::cmt_; use rustc::middle::region; use rustc::session::Session; use rustc::ty::{self, Ty, TyCtxt}; @@ -573,13 +573,13 @@ struct MutationChecker<'a, 'tcx: 'a> { } impl<'a, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'tcx> { - fn matched_pat(&mut self, _: &Pat, _: cmt, _: euv::MatchMode) {} - fn consume(&mut self, _: ast::NodeId, _: Span, _: cmt, _: ConsumeMode) {} - fn consume_pat(&mut self, _: &Pat, _: cmt, _: ConsumeMode) {} + fn matched_pat(&mut self, _: &Pat, _: &cmt_, _: euv::MatchMode) {} + fn consume(&mut self, _: ast::NodeId, _: Span, _: &cmt_, _: ConsumeMode) {} + fn consume_pat(&mut self, _: &Pat, _: &cmt_, _: ConsumeMode) {} fn borrow(&mut self, _: ast::NodeId, span: Span, - _: cmt, + _: &cmt_, _: ty::Region<'tcx>, kind:ty:: BorrowKind, _: LoanCause) { @@ -594,7 +594,7 @@ impl<'a, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'tcx> { } } fn decl_without_init(&mut self, _: ast::NodeId, _: Span) {} - fn mutate(&mut self, _: ast::NodeId, span: Span, _: cmt, mode: MutateMode) { + fn mutate(&mut self, _: ast::NodeId, span: Span, _: &cmt_, mode: MutateMode) { match mode { MutateMode::JustWrite | MutateMode::WriteAndRead => { struct_span_err!(self.cx.tcx.sess, span, E0302, "cannot assign in a pattern guard") diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index c2da8c11d87..623e0de478b 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -28,13 +28,13 @@ use rustc::hir::def::{Def, CtorKind}; use rustc::hir::pat_util::EnumerateAndAdjustIterator; use rustc_data_structures::indexed_vec::Idx; -use rustc_const_math::ConstFloat; use std::cmp::Ordering; use std::fmt; use syntax::ast; use syntax::ptr::P; use syntax_pos::Span; +use syntax_pos::symbol::Symbol; #[derive(Clone, Debug)] pub enum PatternError { @@ -792,7 +792,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ConstVal::Value(miri) => const_val_field( self.tcx, self.param_env, instance, variant_opt, field, miri, cv.ty, - ).unwrap(), + ).expect("field access failed"), _ => bug!("{:#?} is not a valid adt", cv), }; self.const_to_pat(instance, val, id, span) @@ -1053,24 +1053,22 @@ pub fn compare_const_vals<'a, 'tcx>( b: &ConstVal, ty: Ty<'tcx>, ) -> Option<Ordering> { - use rustc_const_math::ConstFloat; trace!("compare_const_vals: {:?}, {:?}", a, b); use rustc::mir::interpret::{Value, PrimVal}; match (a, b) { (&ConstVal::Value(Value::ByVal(PrimVal::Bytes(a))), &ConstVal::Value(Value::ByVal(PrimVal::Bytes(b)))) => { + use ::rustc_apfloat::Float; match ty.sty { - ty::TyFloat(ty) => { - let l = ConstFloat { - bits: a, - ty, - }; - let r = ConstFloat { - bits: b, - ty, - }; - // FIXME(oli-obk): report cmp errors? - l.try_cmp(r).ok() + ty::TyFloat(ast::FloatTy::F32) => { + let l = ::rustc_apfloat::ieee::Single::from_bits(a); + let r = ::rustc_apfloat::ieee::Single::from_bits(b); + l.partial_cmp(&r) + }, + ty::TyFloat(ast::FloatTy::F64) => { + let l = ::rustc_apfloat::ieee::Double::from_bits(a); + let r = ::rustc_apfloat::ieee::Double::from_bits(b); + l.partial_cmp(&r) }, ty::TyInt(_) => { let a = interpret::sign_extend(tcx, a, ty).expect("layout error for TyInt"); @@ -1148,26 +1146,14 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, Value::ByVal(PrimVal::Bytes(n)) }, LitKind::Float(n, fty) => { - let n = n.as_str(); - let mut f = parse_float(&n, fty)?; - if neg { - f = -f; - } - let bits = f.bits; - Value::ByVal(PrimVal::Bytes(bits)) + parse_float(n, fty, neg)? } LitKind::FloatUnsuffixed(n) => { let fty = match ty.sty { ty::TyFloat(fty) => fty, _ => bug!() }; - let n = n.as_str(); - let mut f = parse_float(&n, fty)?; - if neg { - f = -f; - } - let bits = f.bits; - Value::ByVal(PrimVal::Bytes(bits)) + parse_float(n, fty, neg)? } LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)), LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)), @@ -1175,7 +1161,36 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, Ok(ConstVal::Value(lit)) } -fn parse_float<'tcx>(num: &str, fty: ast::FloatTy) - -> Result<ConstFloat, ()> { - ConstFloat::from_str(num, fty).map_err(|_| ()) +pub fn parse_float( + num: Symbol, + fty: ast::FloatTy, + neg: bool, +) -> Result<Value, ()> { + let num = num.as_str(); + use rustc_apfloat::ieee::{Single, Double}; + use rustc_apfloat::Float; + let bits = match fty { + ast::FloatTy::F32 => { + num.parse::<f32>().map_err(|_| ())?; + let mut f = num.parse::<Single>().unwrap_or_else(|e| { + panic!("apfloat::ieee::Single failed to parse `{}`: {:?}", num, e) + }); + if neg { + f = -f; + } + f.to_bits() + } + ast::FloatTy::F64 => { + num.parse::<f64>().map_err(|_| ())?; + let mut f = num.parse::<Double>().unwrap_or_else(|e| { + panic!("apfloat::ieee::Single failed to parse `{}`: {:?}", num, e) + }); + if neg { + f = -f; + } + f.to_bits() + } + }; + + Ok(Value::ByVal(PrimVal::Bytes(bits))) } diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index e654142d216..002b5eb187d 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -2,10 +2,9 @@ use rustc::ty::Ty; use rustc::ty::layout::LayoutOf; use syntax::ast::{FloatTy, IntTy, UintTy}; -use rustc_const_math::ConstFloat; +use rustc_apfloat::ieee::{Single, Double}; use super::{EvalContext, Machine}; use rustc::mir::interpret::{PrimVal, EvalResult, MemoryPointer, PointerArithmetic}; -use rustc_apfloat::ieee::{Single, Double}; use rustc_apfloat::Float; impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { @@ -50,8 +49,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { Ok(PrimVal::Bytes(v)) } - TyFloat(fty) if signed => Ok(PrimVal::Bytes(ConstFloat::from_i128(v as i128, fty).bits)), - TyFloat(fty) => Ok(PrimVal::Bytes(ConstFloat::from_u128(v, fty).bits)), + TyFloat(FloatTy::F32) if signed => Ok(PrimVal::Bytes(Single::from_i128(v as i128).value.to_bits())), + TyFloat(FloatTy::F64) if signed => Ok(PrimVal::Bytes(Double::from_i128(v as i128).value.to_bits())), + TyFloat(FloatTy::F32) => Ok(PrimVal::Bytes(Single::from_u128(v).value.to_bits())), + TyFloat(FloatTy::F64) => Ok(PrimVal::Bytes(Double::from_u128(v).value.to_bits())), TyChar if v as u8 as u128 == v => Ok(PrimVal::Bytes(v)), TyChar => err!(InvalidChar(v)), diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index a25331f7279..dff9fa271ab 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -263,7 +263,7 @@ impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator { ) -> EvalResult<'tcx> { let substs = instance.substs; - let intrinsic_name = &ecx.tcx.item_name(instance.def_id())[..]; + let intrinsic_name = &ecx.tcx.item_name(instance.def_id()).as_str()[..]; match intrinsic_name { "min_align_of" => { let elem_ty = substs.type_at(0); diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 4b57c641546..bea29b6926a 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -513,7 +513,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M // it emits in debug mode) is performance, but it doesn't cost us any performance in miri. // If, however, the compiler ever starts transforming unchecked intrinsics into unchecked binops, // we have to go back to just ignoring the overflow here. - return err!(OverflowingMath); + return err!(Overflow(bin_op)); } } @@ -768,9 +768,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M } } - if log_enabled!(::log::Level::Trace) { - self.dump_local(dest); - } + self.dump_local(dest); Ok(()) } @@ -919,8 +917,8 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M niche_start, .. } => { - let variants_start = niche_variants.start as u128; - let variants_end = niche_variants.end as u128; + let variants_start = *niche_variants.start() as u128; + let variants_end = *niche_variants.end() as u128; match raw_discr { PrimVal::Ptr(_) => { assert!(niche_start == 0); @@ -986,7 +984,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M if variant_index != dataful_variant { let (niche_dest, niche) = self.place_field(dest, mir::Field::new(0), layout)?; - let niche_value = ((variant_index - niche_variants.start) as u128) + let niche_value = ((variant_index - niche_variants.start()) as u128) .wrapping_add(niche_start); self.write_primval(niche_dest, PrimVal::Bytes(niche_value), niche.ty)?; } @@ -1342,9 +1340,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M use syntax::ast::FloatTy; let layout = self.layout_of(ty)?; - // do the strongest layout check of the two - let align = layout.align.max(ptr_align); - self.memory.check_align(ptr, align)?; + self.memory.check_align(ptr, ptr_align)?; if layout.size.bytes() == 0 { return Ok(Some(Value::ByVal(PrimVal::Undef))); @@ -1572,6 +1568,9 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M pub fn dump_local(&self, place: Place) { // Debug output + if !log_enabled!(::log::Level::Trace) { + return; + } match place { Place::Local { frame, local } => { let mut allocs = Vec::new(); diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 5e156e9271f..7f8205b8327 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -334,11 +334,17 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { /// For debugging, print an allocation and all allocations it points to, recursively. pub fn dump_alloc(&self, id: AllocId) { + if !log_enabled!(::log::Level::Trace) { + return; + } self.dump_allocs(vec![id]); } /// For debugging, print a list of allocations and all allocations they point to, recursively. pub fn dump_allocs(&self, mut allocs: Vec<AllocId>) { + if !log_enabled!(::log::Level::Trace) { + return; + } use std::fmt::Write; allocs.sort(); allocs.dedup(); diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs index dfc0c4a824a..ef6deab0477 100644 --- a/src/librustc_mir/interpret/operator.rs +++ b/src/librustc_mir/interpret/operator.rs @@ -1,9 +1,10 @@ use rustc::mir; use rustc::ty::{self, Ty}; -use rustc_const_math::ConstFloat; use syntax::ast::FloatTy; use std::cmp::Ordering; use rustc::ty::layout::LayoutOf; +use rustc_apfloat::ieee::{Double, Single}; +use rustc_apfloat::Float; use super::{EvalContext, Place, Machine, ValTy}; @@ -125,31 +126,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { return err!(Unimplemented(msg)); } - let float_op = |op, l, r, ty| { - let l = ConstFloat { - bits: l, - ty, - }; - let r = ConstFloat { - bits: r, - ty, - }; - match op { - Eq => PrimVal::from_bool(l.try_cmp(r).unwrap() == Ordering::Equal), - Ne => PrimVal::from_bool(l.try_cmp(r).unwrap() != Ordering::Equal), - Lt => PrimVal::from_bool(l.try_cmp(r).unwrap() == Ordering::Less), - Le => PrimVal::from_bool(l.try_cmp(r).unwrap() != Ordering::Greater), - Gt => PrimVal::from_bool(l.try_cmp(r).unwrap() == Ordering::Greater), - Ge => PrimVal::from_bool(l.try_cmp(r).unwrap() != Ordering::Less), - Add => PrimVal::Bytes((l + r).unwrap().bits), - Sub => PrimVal::Bytes((l - r).unwrap().bits), - Mul => PrimVal::Bytes((l * r).unwrap().bits), - Div => PrimVal::Bytes((l / r).unwrap().bits), - Rem => PrimVal::Bytes((l % r).unwrap().bits), - _ => bug!("invalid float op: `{:?}`", op), - } - }; - if left_layout.abi.is_signed() { let op: Option<fn(&i128, &i128) -> bool> = match bin_op { Lt => Some(i128::lt), @@ -164,7 +140,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { return Ok((PrimVal::from_bool(op(&l, &r)), false)); } let op: Option<fn(i128, i128) -> (i128, bool)> = match bin_op { - Rem | Div if r == 0 => return Ok((PrimVal::Bytes(l), true)), + Div if r == 0 => return err!(DivisionByZero), + Rem if r == 0 => return err!(RemainderByZero), Div => Some(i128::overflowing_div), Rem => Some(i128::overflowing_rem), Add => Some(i128::overflowing_add), @@ -199,7 +176,31 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { } if let ty::TyFloat(fty) = left_ty.sty { - return Ok((float_op(bin_op, l, r, fty), false)); + macro_rules! float_math { + ($ty:path) => {{ + let l = <$ty>::from_bits(l); + let r = <$ty>::from_bits(r); + let val = match bin_op { + Eq => PrimVal::from_bool(l.partial_cmp(&r).unwrap_or(Ordering::Greater) == Ordering::Equal), + Ne => PrimVal::from_bool(l.partial_cmp(&r).unwrap_or(Ordering::Greater) != Ordering::Equal), + Lt => PrimVal::from_bool(l.partial_cmp(&r).unwrap_or(Ordering::Greater) == Ordering::Less), + Le => PrimVal::from_bool(l.partial_cmp(&r).unwrap_or(Ordering::Greater) != Ordering::Greater), + Gt => PrimVal::from_bool(l.partial_cmp(&r).unwrap_or(Ordering::Greater) == Ordering::Greater), + Ge => PrimVal::from_bool(l.partial_cmp(&r).unwrap_or(Ordering::Greater) != Ordering::Less), + Add => PrimVal::Bytes((l + r).value.to_bits()), + Sub => PrimVal::Bytes((l - r).value.to_bits()), + Mul => PrimVal::Bytes((l * r).value.to_bits()), + Div => PrimVal::Bytes((l / r).value.to_bits()), + Rem => PrimVal::Bytes((l % r).value.to_bits()), + _ => bug!("invalid float op: `{:?}`", bin_op), + }; + return Ok((val, false)); + }}; + } + match fty { + FloatTy::F32 => float_math!(Single), + FloatTy::F64 => float_math!(Double), + } } // only ints left @@ -221,7 +222,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { Add => u128::overflowing_add, Sub => u128::overflowing_sub, Mul => u128::overflowing_mul, - Rem | Div if r == 0 => return Ok((PrimVal::Bytes(l), true)), + Div if r == 0 => return err!(DivisionByZero), + Rem if r == 0 => return err!(RemainderByZero), Div => u128::overflowing_div, Rem => u128::overflowing_rem, _ => bug!(), @@ -269,7 +271,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { (Neg, ty::TyFloat(FloatTy::F32)) => Single::to_bits(-Single::from_bits(bytes)), (Neg, ty::TyFloat(FloatTy::F64)) => Double::to_bits(-Double::from_bits(bytes)), - (Neg, _) if bytes == (1 << (size - 1)) => return err!(OverflowingMath), + (Neg, _) if bytes == (1 << (size - 1)) => return err!(OverflowNeg), (Neg, _) => (-(bytes as i128)) as u128, }; diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 42cb149d682..d03204bfab1 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -219,9 +219,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { } }; - if log_enabled!(::log::Level::Trace) { - self.dump_local(place); - } + self.dump_local(place); Ok(place) } diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator/mod.rs index aa80ee7af18..0e0d91f4724 100644 --- a/src/librustc_mir/interpret/terminator/mod.rs +++ b/src/librustc_mir/interpret/terminator/mod.rs @@ -148,23 +148,24 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { if expected == cond_val { self.goto_block(target); } else { - use rustc::mir::AssertMessage::*; + use rustc::mir::interpret::EvalErrorKind::*; return match *msg { BoundsCheck { ref len, ref index } => { - let span = terminator.source_info.span; let len = self.eval_operand_to_primval(len) .expect("can't eval len") .to_u64()?; let index = self.eval_operand_to_primval(index) .expect("can't eval index") .to_u64()?; - err!(ArrayIndexOutOfBounds(span, len, index)) - } - Math(ref err) => { - err!(Math(terminator.source_info.span, err.clone())) + err!(BoundsCheck { len, index }) } + Overflow(op) => Err(Overflow(op).into()), + OverflowNeg => Err(OverflowNeg.into()), + DivisionByZero => Err(DivisionByZero.into()), + RemainderByZero => Err(RemainderByZero.into()), GeneratorResumedAfterReturn | GeneratorResumedAfterPanic => unimplemented!(), + _ => bug!(), }; } } diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 399892522a3..2545ba3a94a 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -24,16 +24,17 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(const_fn)] #![feature(core_intrinsics)] #![feature(decl_macro)] -#![feature(dyn_trait)] +#![cfg_attr(stage0, feature(dyn_trait))] #![feature(fs_read_write)] #![feature(macro_vis_matcher)] #![feature(exhaustive_patterns)] #![feature(range_contains)] #![feature(rustc_diagnostic_macros)] #![feature(nonzero)] -#![feature(inclusive_range_fields)] +#![feature(inclusive_range_methods)] #![feature(crate_visibility_modifier)] #![feature(never_type)] +#![feature(specialization)] #![cfg_attr(stage0, feature(try_trait))] extern crate arena; @@ -50,8 +51,6 @@ extern crate rustc_errors; extern crate syntax; extern crate syntax_pos; extern crate rustc_target; -extern crate rustc_const_math; -extern crate core; // for NonZero extern crate log_settings; extern crate rustc_apfloat; extern crate byteorder; diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs index 9e0c977a3f0..9e43bed1b63 100644 --- a/src/librustc_mir/monomorphize/item.rs +++ b/src/librustc_mir/monomorphize/item.rs @@ -76,7 +76,7 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug { MonoItem::GlobalAsm(node_id) => { let def_id = tcx.hir.local_def_id(node_id); ty::SymbolName { - name: Symbol::intern(&format!("global_asm_{:?}", def_id)).as_str() + name: Symbol::intern(&format!("global_asm_{:?}", def_id)).as_interned_str() } } } diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs index f29f86af4ab..3a65cd4ea77 100644 --- a/src/librustc_mir/monomorphize/partitioning.rs +++ b/src/librustc_mir/monomorphize/partitioning.rs @@ -146,7 +146,7 @@ pub trait CodegenUnitExt<'tcx> { } fn work_product_id(&self) -> WorkProductId { - WorkProductId::from_cgu_name(self.name()) + WorkProductId::from_cgu_name(&self.name().as_str()) } fn items_in_deterministic_order<'a>(&self, @@ -206,9 +206,9 @@ fn fallback_cgu_name(tcx: TyCtxt) -> InternedString { const FALLBACK_CODEGEN_UNIT: &'static str = "__rustc_fallback_codegen_unit"; if tcx.sess.opts.debugging_opts.human_readable_cgu_names { - Symbol::intern(FALLBACK_CODEGEN_UNIT).as_str() + Symbol::intern(FALLBACK_CODEGEN_UNIT).as_interned_str() } else { - Symbol::intern(&CodegenUnit::mangle_name(FALLBACK_CODEGEN_UNIT)).as_str() + Symbol::intern(&CodegenUnit::mangle_name(FALLBACK_CODEGEN_UNIT)).as_interned_str() } } @@ -740,7 +740,7 @@ fn compute_codegen_unit_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } }) { cgu_name.push_str("-"); - cgu_name.push_str(&part.data.as_interned_str()); + cgu_name.push_str(&part.data.as_interned_str().as_str()); } if volatile { @@ -753,11 +753,11 @@ fn compute_codegen_unit_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, CodegenUnit::mangle_name(&cgu_name) }; - Symbol::intern(&cgu_name[..]).as_str() + Symbol::intern(&cgu_name[..]).as_interned_str() } fn numbered_codegen_unit_name(crate_name: &str, index: usize) -> InternedString { - Symbol::intern(&format!("{}{}", crate_name, index)).as_str() + Symbol::intern(&format!("{}{}", crate_name, index)).as_interned_str() } fn debug_dump<'a, 'b, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -772,7 +772,7 @@ fn debug_dump<'a, 'b, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("CodegenUnit {}:", cgu.name()); for (trans_item, linkage) in cgu.items() { - let symbol_name = trans_item.symbol_name(tcx); + let symbol_name = trans_item.symbol_name(tcx).name.as_str(); let symbol_hash_start = symbol_name.rfind('h'); let symbol_hash = symbol_hash_start.map(|i| &symbol_name[i ..]) .unwrap_or("<no hash>"); diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index af60a83a4a2..699a5b17435 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -210,7 +210,7 @@ fn build_drop_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if let Some(..) = ty { let patch = { - let param_env = tcx.param_env(def_id); + let param_env = tcx.param_env(def_id).with_reveal_all(); let mut elaborator = DropShimElaborator { mir: &mir, patch: MirPatch::new(&mir), diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 31af7c21857..2bf5a49c97e 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -149,7 +149,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { self.visibility_scope_info[source_info.scope].lint_root; self.register_violations(&[UnsafetyViolation { source_info, - description: Symbol::intern("borrow of packed field").as_str(), + description: Symbol::intern("borrow of packed field").as_interned_str(), kind: UnsafetyViolationKind::BorrowPacked(lint_root) }], &[]); } @@ -214,7 +214,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { self.visibility_scope_info[source_info.scope].lint_root; self.register_violations(&[UnsafetyViolation { source_info, - description: Symbol::intern("use of extern static").as_str(), + description: Symbol::intern("use of extern static").as_interned_str(), kind: UnsafetyViolationKind::ExternStatic(lint_root) }], &[]); } @@ -231,7 +231,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { let source_info = self.source_info; self.register_violations(&[UnsafetyViolation { source_info, - description: Symbol::intern(description).as_str(), + description: Symbol::intern(description).as_interned_str(), kind: UnsafetyViolationKind::General, }], &[]); } @@ -444,7 +444,7 @@ pub fn check_unsafety<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { struct_span_err!( tcx.sess, source_info.span, E0133, "{} requires unsafe function or block", description) - .span_label(source_info.span, &description[..]) + .span_label(source_info.span, &description.as_str()[..]) .emit(); } UnsafetyViolationKind::ExternStatic(lint_node_id) => { @@ -452,7 +452,7 @@ pub fn check_unsafety<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { lint_node_id, source_info.span, &format!("{} requires unsafe function or \ - block (error E0133)", &description[..])); + block (error E0133)", &description.as_str()[..])); } UnsafetyViolationKind::BorrowPacked(lint_node_id) => { if let Some(impl_def_id) = builtin_derive_def_id(tcx, def_id) { @@ -462,7 +462,7 @@ pub fn check_unsafety<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { lint_node_id, source_info.span, &format!("{} requires unsafe function or \ - block (error E0133)", &description[..])); + block (error E0133)", &description.as_str()[..])); } } } diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 47b2f430bc7..e1db216b6bb 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -328,7 +328,7 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { } else { if overflow { use rustc::mir::interpret::EvalErrorKind; - let mut err = EvalErrorKind::OverflowingMath.into(); + let mut err = EvalErrorKind::Overflow(op).into(); ecx.report(&mut err, false, Some(span)); return None; } @@ -478,12 +478,12 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> { .hir .as_local_node_id(self.source.def_id) .expect("some part of a failing const eval must be local"); - use rustc::mir::AssertMessage::*; + use rustc::mir::interpret::EvalErrorKind::*; let msg = match msg { - // Need proper const propagator for these - GeneratorResumedAfterReturn | - GeneratorResumedAfterPanic => return, - Math(ref err) => err.description().to_owned(), + Overflow(_) | + OverflowNeg | + DivisionByZero | + RemainderByZero => msg.description().to_owned(), BoundsCheck { ref len, ref index } => { let len = self.eval_operand(len).expect("len must be const"); let len = match len.0 { @@ -504,6 +504,8 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> { index, ) }, + // Need proper const propagator for these + _ => return, }; self.tcx.lint_node( ::rustc::lint::builtin::CONST_ERR, diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs index 95fe99a1bec..fba60c7e8dc 100644 --- a/src/librustc_mir/transform/copy_prop.rs +++ b/src/librustc_mir/transform/copy_prop.rs @@ -29,7 +29,6 @@ //! (non-mutating) use of `SRC`. These restrictions are conservative and may be relaxed in the //! future. -use rustc::hir; use rustc::mir::{Constant, Local, LocalKind, Location, Place, Mir, Operand, Rvalue, StatementKind}; use rustc::mir::visit::MutVisitor; use rustc::ty::TyCtxt; @@ -41,26 +40,8 @@ pub struct CopyPropagation; impl MirPass for CopyPropagation { fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - source: MirSource, + _source: MirSource, mir: &mut Mir<'tcx>) { - // Don't run on constant MIR, because trans might not be able to - // evaluate the modified MIR. - // FIXME(eddyb) Remove check after miri is merged. - let id = tcx.hir.as_local_node_id(source.def_id).unwrap(); - match (tcx.hir.body_owner_kind(id), source.promoted) { - (_, Some(_)) | - (hir::BodyOwnerKind::Const, _) | - (hir::BodyOwnerKind::Static(_), _) => return, - - (hir::BodyOwnerKind::Fn, _) => { - if tcx.is_const_fn(source.def_id) { - // Don't run on const functions, as, again, trans might not be able to evaluate - // the optimized IR. - return - } - } - } - // We only run when the MIR optimization level is > 1. // This avoids a slow pass, and messing up debug info. if tcx.sess.opts.debugging_opts.mir_opt_level <= 1 { diff --git a/src/librustc_mir/transform/deaggregator.rs b/src/librustc_mir/transform/deaggregator.rs index 503354ebc4f..8b2b9ef7e81 100644 --- a/src/librustc_mir/transform/deaggregator.rs +++ b/src/librustc_mir/transform/deaggregator.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::hir; use rustc::ty::TyCtxt; use rustc::mir::*; use rustc_data_structures::indexed_vec::Idx; @@ -19,26 +18,8 @@ pub struct Deaggregator; impl MirPass for Deaggregator { fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - source: MirSource, + _source: MirSource, mir: &mut Mir<'tcx>) { - // Don't run on constant MIR, because trans might not be able to - // evaluate the modified MIR. - // FIXME(eddyb) Remove check after miri is merged. - let id = tcx.hir.as_local_node_id(source.def_id).unwrap(); - match (tcx.hir.body_owner_kind(id), source.promoted) { - (_, Some(_)) | - (hir::BodyOwnerKind::Const, _) | - (hir::BodyOwnerKind::Static(_), _) => return, - - (hir::BodyOwnerKind::Fn, _) => { - if tcx.is_const_fn(source.def_id) { - // Don't run on const functions, as, again, trans might not be able to evaluate - // the optimized IR. - return - } - } - } - let (basic_blocks, local_decls) = mir.basic_blocks_and_local_decls_mut(); let local_decls = &*local_decls; for bb in basic_blocks { diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index 2e8dd623d74..5397d18cdd7 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -15,7 +15,6 @@ use dataflow::{on_all_children_bits, on_all_drop_children_bits}; use dataflow::{drop_flag_effects_for_location, on_lookup_result_bits}; use dataflow::MoveDataParamEnv; use dataflow::{self, do_dataflow, DebugFormatted}; -use rustc::hir; use rustc::ty::{self, TyCtxt}; use rustc::mir::*; use rustc::middle::const_val::ConstVal; @@ -42,15 +41,8 @@ impl MirPass for ElaborateDrops { { debug!("elaborate_drops({:?} @ {:?})", src, mir.span); - // Don't run on constant MIR, because trans might not be able to - // evaluate the modified MIR. - // FIXME(eddyb) Remove check after miri is merged. let id = tcx.hir.as_local_node_id(src.def_id).unwrap(); - match (tcx.hir.body_owner_kind(id), src.promoted) { - (hir::BodyOwnerKind::Fn, None) => {}, - _ => return - } - let param_env = tcx.param_env(src.def_id); + let param_env = tcx.param_env(src.def_id).with_reveal_all(); let move_data = MoveData::gather_moves(mir, tcx).unwrap(); let elaborate_patch = { let mir = &*mir; @@ -558,7 +550,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } fn drop_flags_on_init(&mut self) { - let loc = Location { block: START_BLOCK, statement_index: 0 }; + let loc = Location::START; let span = self.patch.source_info_for_location(self.mir, loc).span; let false_ = self.constant_bool(span, false); for flag in self.drop_flags.values() { @@ -584,7 +576,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } fn drop_flags_for_args(&mut self) { - let loc = Location { block: START_BLOCK, statement_index: 0 }; + let loc = Location::START; dataflow::drop_flag_effects_for_function_entry( self.tcx, self.mir, self.env, |path, ds| { self.set_drop_flag(loc, path, ds); diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 0ff73569433..36735586e81 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -738,12 +738,17 @@ fn create_generator_resume_function<'a, 'tcx>( let mut cases = create_cases(mir, &transform, |point| Some(point.resume)); + use rustc::mir::interpret::EvalErrorKind::{ + GeneratorResumedAfterPanic, + GeneratorResumedAfterReturn, + }; + // Jump to the entry point on the 0 state cases.insert(0, (0, BasicBlock::new(0))); // Panic when resumed on the returned (1) state - cases.insert(1, (1, insert_panic_block(tcx, mir, AssertMessage::GeneratorResumedAfterReturn))); + cases.insert(1, (1, insert_panic_block(tcx, mir, GeneratorResumedAfterReturn))); // Panic when resumed on the poisoned (2) state - cases.insert(2, (2, insert_panic_block(tcx, mir, AssertMessage::GeneratorResumedAfterPanic))); + cases.insert(2, (2, insert_panic_block(tcx, mir, GeneratorResumedAfterPanic))); insert_switch(tcx, mir, cases, &transform, TerminatorKind::Unreachable); diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 2b491385d66..ee6d42b1fe5 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -126,7 +126,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { continue; } - let callee_mir = match ty::queries::optimized_mir::try_get(self.tcx, + let callee_mir = match self.tcx.try_get_query::<ty::queries::optimized_mir>( callsite.location.span, callsite.callee) { Ok(callee_mir) if self.should_inline(callsite, callee_mir) => { @@ -330,7 +330,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { } if !is_drop { - for &succ in &term.successors()[..] { + for &succ in term.successors() { work_list.push(succ); } } @@ -379,8 +379,6 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { TerminatorKind::Call { args, destination: Some(destination), cleanup, .. } => { debug!("Inlined {:?} into {:?}", callsite.callee, self.source); - let is_box_free = Some(callsite.callee) == self.tcx.lang_items().box_free_fn(); - let mut local_map = IndexVec::with_capacity(callee_mir.local_decls.len()); let mut scope_map = IndexVec::with_capacity(callee_mir.visibility_scopes.len()); let mut promoted_map = IndexVec::with_capacity(callee_mir.promoted.len()); @@ -460,24 +458,8 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let return_block = destination.1; - let args : Vec<_> = if is_box_free { - assert!(args.len() == 1); - // box_free takes a Box, but is defined with a *mut T, inlining - // needs to generate the cast. - // FIXME: we should probably just generate correct MIR in the first place... - - let arg = if let Operand::Move(ref place) = args[0] { - place.clone() - } else { - bug!("Constant arg to \"box_free\""); - }; - - let ptr_ty = args[0].ty(caller_mir, self.tcx); - vec![self.cast_box_free_arg(arg, ptr_ty, &callsite, caller_mir)] - } else { - // Copy the arguments if needed. - self.make_call_args(args, &callsite, caller_mir) - }; + // Copy the arguments if needed. + let args: Vec<_> = self.make_call_args(args, &callsite, caller_mir); let bb_len = caller_mir.basic_blocks().len(); let mut integrator = Integrator { @@ -518,49 +500,6 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { } } - fn cast_box_free_arg(&self, arg: Place<'tcx>, ptr_ty: Ty<'tcx>, - callsite: &CallSite<'tcx>, caller_mir: &mut Mir<'tcx>) -> Local { - let arg = Rvalue::Ref( - self.tcx.types.re_erased, - BorrowKind::Mut { allow_two_phase_borrow: false }, - arg.deref()); - - let ty = arg.ty(caller_mir, self.tcx); - let ref_tmp = LocalDecl::new_temp(ty, callsite.location.span); - let ref_tmp = caller_mir.local_decls.push(ref_tmp); - let ref_tmp = Place::Local(ref_tmp); - - let ref_stmt = Statement { - source_info: callsite.location, - kind: StatementKind::Assign(ref_tmp.clone(), arg) - }; - - caller_mir[callsite.bb] - .statements.push(ref_stmt); - - let pointee_ty = match ptr_ty.sty { - ty::TyRawPtr(tm) | ty::TyRef(_, tm) => tm.ty, - _ if ptr_ty.is_box() => ptr_ty.boxed_ty(), - _ => bug!("Invalid type `{:?}` for call to box_free", ptr_ty) - }; - let ptr_ty = self.tcx.mk_mut_ptr(pointee_ty); - - let raw_ptr = Rvalue::Cast(CastKind::Misc, Operand::Move(ref_tmp), ptr_ty); - - let cast_tmp = LocalDecl::new_temp(ptr_ty, callsite.location.span); - let cast_tmp = caller_mir.local_decls.push(cast_tmp); - - let cast_stmt = Statement { - source_info: callsite.location, - kind: StatementKind::Assign(Place::Local(cast_tmp), raw_ptr) - }; - - caller_mir[callsite.bb] - .statements.push(cast_stmt); - - cast_tmp - } - fn make_call_args( &self, args: Vec<Operand<'tcx>>, diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index ff7551ed6f4..4762c6aaa27 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -868,7 +868,7 @@ This does not pose a problem by itself because they can't be accessed directly." Abi::RustIntrinsic | Abi::PlatformIntrinsic => { assert!(!self.tcx.is_const_fn(def_id)); - match &self.tcx.item_name(def_id)[..] { + match &self.tcx.item_name(def_id).as_str()[..] { "size_of" | "min_align_of" | "type_id" => is_const_fn = Some(def_id), name if name.starts_with("simd_shuffle") => { diff --git a/src/librustc_mir/transform/remove_noop_landing_pads.rs b/src/librustc_mir/transform/remove_noop_landing_pads.rs index 6d365012525..bcc8fef18f0 100644 --- a/src/librustc_mir/transform/remove_noop_landing_pads.rs +++ b/src/librustc_mir/transform/remove_noop_landing_pads.rs @@ -78,7 +78,7 @@ impl RemoveNoopLandingPads { TerminatorKind::SwitchInt { .. } | TerminatorKind::FalseEdges { .. } | TerminatorKind::FalseUnwind { .. } => { - terminator.successors().iter().all(|succ| { + terminator.successors().all(|succ| { nop_landing_pads.contains(succ.index()) }) }, diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index 2c6ed1f19b7..691fdd130e5 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -91,7 +91,7 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> { for (_, data) in traversal::preorder(mir) { if let Some(ref term) = data.terminator { - for &tgt in term.successors().iter() { + for &tgt in term.successors() { pred_count[tgt] += 1; } } @@ -219,10 +219,10 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> { }; let first_succ = { - let successors = terminator.successors(); - if let Some(&first_succ) = terminator.successors().get(0) { - if successors.iter().all(|s| *s == first_succ) { - self.pred_count[first_succ] -= (successors.len()-1) as u32; + if let Some(&first_succ) = terminator.successors().nth(0) { + if terminator.successors().all(|s| *s == first_succ) { + let count = terminator.successors().count(); + self.pred_count[first_succ] -= (count - 1) as u32; first_succ } else { return false diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index 19f33ef5d45..4b7c581d3c8 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -13,6 +13,7 @@ use rustc::hir; use rustc::mir::*; use rustc::middle::const_val::ConstVal; use rustc::middle::lang_items; +use rustc::traits::Reveal; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::{Kind, Substs}; use rustc::ty::util::IntTypeExt; @@ -206,6 +207,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> let field = Field::new(i); let subpath = self.elaborator.field_subpath(variant_path, field); + assert_eq!(self.elaborator.param_env().reveal, Reveal::All); let field_ty = self.tcx().normalize_erasing_regions( self.elaborator.param_env(), f.ty(self.tcx(), substs), @@ -337,18 +339,19 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> self.drop_ladder(fields, succ, unwind).0 } - fn open_drop_for_box<'a>(&mut self, ty: Ty<'tcx>) -> BasicBlock + fn open_drop_for_box<'a>(&mut self, adt: &'tcx ty::AdtDef, substs: &'tcx Substs<'tcx>) + -> BasicBlock { - debug!("open_drop_for_box({:?}, {:?})", self, ty); + debug!("open_drop_for_box({:?}, {:?}, {:?})", self, adt, substs); let interior = self.place.clone().deref(); let interior_path = self.elaborator.deref_subpath(self.path); let succ = self.succ; // FIXME(#43234) let unwind = self.unwind; - let succ = self.box_free_block(ty, succ, unwind); + let succ = self.box_free_block(adt, substs, succ, unwind); let unwind_succ = self.unwind.map(|unwind| { - self.box_free_block(ty, unwind, Unwind::InCleanup) + self.box_free_block(adt, substs, unwind, Unwind::InCleanup) }); self.drop_subpath(&interior, interior_path, succ, unwind_succ) @@ -791,11 +794,12 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> ty::TyTuple(tys) => { self.open_drop_for_tuple(tys) } - ty::TyAdt(def, _) if def.is_box() => { - self.open_drop_for_box(ty.boxed_ty()) - } ty::TyAdt(def, substs) => { - self.open_drop_for_adt(def, substs) + if def.is_box() { + self.open_drop_for_box(def, substs) + } else { + self.open_drop_for_adt(def, substs) + } } ty::TyDynamic(..) => { let unwind = self.unwind; // FIXME(#43234) @@ -858,28 +862,34 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> fn box_free_block<'a>( &mut self, - ty: Ty<'tcx>, + adt: &'tcx ty::AdtDef, + substs: &'tcx Substs<'tcx>, target: BasicBlock, unwind: Unwind, ) -> BasicBlock { - let block = self.unelaborated_free_block(ty, target, unwind); + let block = self.unelaborated_free_block(adt, substs, target, unwind); self.drop_flag_test_block(block, target, unwind) } fn unelaborated_free_block<'a>( &mut self, - ty: Ty<'tcx>, + adt: &'tcx ty::AdtDef, + substs: &'tcx Substs<'tcx>, target: BasicBlock, unwind: Unwind ) -> BasicBlock { let tcx = self.tcx(); let unit_temp = Place::Local(self.new_temp(tcx.mk_nil())); let free_func = tcx.require_lang_item(lang_items::BoxFreeFnLangItem); - let substs = tcx.mk_substs(iter::once(Kind::from(ty))); + let args = adt.variants[0].fields.iter().enumerate().map(|(i, f)| { + let field = Field::new(i); + let field_ty = f.ty(self.tcx(), substs); + Operand::Move(self.place.clone().field(field, field_ty)) + }).collect(); let call = TerminatorKind::Call { func: Operand::function_handle(tcx, free_func, substs, self.source_info.span), - args: vec![Operand::Move(self.place.clone())], + args: args, destination: Some((unit_temp, target)), cleanup: None }; // FIXME(#43234) diff --git a/src/librustc_mir/util/graphviz.rs b/src/librustc_mir/util/graphviz.rs index 85b66c29be1..22e2b1b0b09 100644 --- a/src/librustc_mir/util/graphviz.rs +++ b/src/librustc_mir/util/graphviz.rs @@ -125,7 +125,7 @@ fn write_edges<W: Write>(source: BasicBlock, mir: &Mir, w: &mut W) -> io::Result let terminator = mir[source].terminator(); let labels = terminator.kind.fmt_successor_labels(); - for (&target, label) in terminator.successors().iter().zip(labels) { + for (&target, label) in terminator.successors().zip(labels) { writeln!(w, r#" {} -> {} [label="{}"];"#, node(source), node(target), label)?; } diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs index 42ddabddd2d..cfb1a2cd28b 100644 --- a/src/librustc_mir/util/liveness.rs +++ b/src/librustc_mir/util/liveness.rs @@ -138,7 +138,7 @@ pub fn liveness_of_locals<'tcx>(mir: &Mir<'tcx>, mode: LivenessMode) -> Liveness 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() { + for &successor in mir.basic_blocks()[b].terminator().successors() { bits.union(&ins[successor]); } outs[b].clone_from(&bits); diff --git a/src/librustc_passes/Cargo.toml b/src/librustc_passes/Cargo.toml index 4bab24ae139..2babb93eedb 100644 --- a/src/librustc_passes/Cargo.toml +++ b/src/librustc_passes/Cargo.toml @@ -12,7 +12,6 @@ crate-type = ["dylib"] log = "0.4" rustc = { path = "../librustc" } rustc_mir = { path = "../librustc_mir"} -rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs index e65c9de8df1..b6b5edc0940 100644 --- a/src/librustc_passes/lib.rs +++ b/src/librustc_passes/lib.rs @@ -23,7 +23,6 @@ #[macro_use] extern crate rustc; extern crate rustc_mir; -extern crate rustc_const_math; extern crate rustc_data_structures; #[macro_use] diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs index a4e056c6b58..45c6e89321d 100644 --- a/src/librustc_passes/mir_stats.rs +++ b/src/librustc_passes/mir_stats.rs @@ -18,6 +18,7 @@ use rustc::mir::{Place, PlaceElem, PlaceProjection}; use rustc::mir::{Mir, Operand, ProjectionElem}; use rustc::mir::{Rvalue, SourceInfo, Statement, StatementKind}; use rustc::mir::{Terminator, TerminatorKind, VisibilityScope, VisibilityScopeData}; +use rustc::mir::interpret::EvalErrorKind; use rustc::mir::visit as mir_visit; use rustc::ty::{self, ClosureSubsts, TyCtxt}; use rustc::util::nodemap::{FxHashMap}; @@ -133,14 +134,18 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> { location: Location) { self.record("AssertMessage", msg); self.record(match *msg { - AssertMessage::BoundsCheck { .. } => "AssertMessage::BoundsCheck", - AssertMessage::Math(..) => "AssertMessage::Math", - AssertMessage::GeneratorResumedAfterReturn => { + EvalErrorKind::BoundsCheck { .. } => "AssertMessage::BoundsCheck", + EvalErrorKind::Overflow(..) => "AssertMessage::Overflow", + EvalErrorKind::OverflowNeg => "AssertMessage::OverflowNeg", + EvalErrorKind::DivisionByZero => "AssertMessage::DivisionByZero", + EvalErrorKind::RemainderByZero => "AssertMessage::RemainderByZero", + EvalErrorKind::GeneratorResumedAfterReturn => { "AssertMessage::GeneratorResumedAfterReturn" } - AssertMessage::GeneratorResumedAfterPanic => { + EvalErrorKind::GeneratorResumedAfterPanic => { "AssertMessage::GeneratorResumedAfterPanic" } + _ => bug!(), }, msg); self.super_assert_message(msg, location); } diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs index c5d2f0041a0..3a577341f7e 100644 --- a/src/librustc_passes/rvalue_promotion.rs +++ b/src/librustc_passes/rvalue_promotion.rs @@ -468,13 +468,13 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'gcx> { fn consume(&mut self, _consume_id: ast::NodeId, _consume_span: Span, - _cmt: mc::cmt, + _cmt: &mc::cmt_, _mode: euv::ConsumeMode) {} fn borrow(&mut self, borrow_id: ast::NodeId, _borrow_span: Span, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, _loan_region: ty::Region<'tcx>, bk: ty::BorrowKind, loan_cause: euv::LoanCause) { @@ -489,7 +489,7 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'gcx> { _ => {} } - let mut cur = &cmt; + let mut cur = cmt; loop { match cur.cat { Categorization::Rvalue(..) => { @@ -521,11 +521,11 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'gcx> { fn mutate(&mut self, _assignment_id: ast::NodeId, _assignment_span: Span, - _assignee_cmt: mc::cmt, + _assignee_cmt: &mc::cmt_, _mode: euv::MutateMode) { } - fn matched_pat(&mut self, _: &hir::Pat, _: mc::cmt, _: euv::MatchMode) {} + fn matched_pat(&mut self, _: &hir::Pat, _: &mc::cmt_, _: euv::MatchMode) {} - fn consume_pat(&mut self, _consume_pat: &hir::Pat, _cmt: mc::cmt, _mode: euv::ConsumeMode) {} + fn consume_pat(&mut self, _consume_pat: &hir::Pat, _cmt: &mc::cmt_, _mode: euv::ConsumeMode) {} } diff --git a/src/librustc_plugin/lib.rs b/src/librustc_plugin/lib.rs index 622d8e51a6c..348aa6a7cef 100644 --- a/src/librustc_plugin/lib.rs +++ b/src/librustc_plugin/lib.rs @@ -65,7 +65,6 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(rustc_diagnostic_macros)] -#![feature(staged_api)] #[macro_use] extern crate syntax; diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs index ebfd8785a0a..7e3c411c1d2 100644 --- a/src/librustc_plugin/registry.rs +++ b/src/librustc_plugin/registry.rs @@ -128,8 +128,6 @@ impl<'a> Registry<'a> { /// This can be used in place of `register_syntax_extension` to register legacy custom derives /// (i.e. attribute syntax extensions whose name begins with `derive_`). Legacy custom /// derives defined by this function do not trigger deprecation warnings when used. - #[unstable(feature = "rustc_private", issue = "27812")] - #[rustc_deprecated(since = "1.15.0", reason = "replaced by macros 1.1 (RFC 1861)")] pub fn register_custom_derive(&mut self, name: ast::Name, extension: SyntaxExtension) { assert!(name.as_str().starts_with("derive_")); self.whitelisted_custom_derives.push(name); diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index f4e2136a5a1..ef5cc958283 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -17,7 +17,7 @@ use macros::{InvocationData, LegacyScope}; use resolve_imports::ImportDirective; use resolve_imports::ImportDirectiveSubclass::{self, GlobImport, SingleImport}; use {Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, ToNameBinding}; -use {Resolver, ResolverArenas}; +use {PerNS, Resolver, ResolverArenas}; use Namespace::{self, TypeNS, ValueNS, MacroNS}; use {resolve_error, resolve_struct_error, ResolutionError}; @@ -41,7 +41,6 @@ use syntax::ext::tt::macro_rules; use syntax::parse::token::{self, Token}; use syntax::std_inject::injected_crate_name; use syntax::symbol::keywords; -use syntax::symbol::Symbol; use syntax::visit::{self, Visitor}; use syntax_pos::{Span, DUMMY_SP}; @@ -72,7 +71,6 @@ impl<'a> ToNameBinding<'a> for (Def, ty::Visibility, Span, Mark) { struct LegacyMacroImports { import_all: Option<Span>, imports: Vec<(Name, Span)>, - reexports: Vec<(Name, Span)>, } impl<'a> Resolver<'a> { @@ -176,7 +174,11 @@ impl<'a> Resolver<'a> { let subclass = SingleImport { target: ident, source, - result: self.per_ns(|_, _| Cell::new(Err(Undetermined))), + result: PerNS { + type_ns: Cell::new(Err(Undetermined)), + value_ns: Cell::new(Err(Undetermined)), + macro_ns: Cell::new(Err(Undetermined)), + }, type_ns_only, }; self.add_import_directive( @@ -544,14 +546,14 @@ impl<'a> Resolver<'a> { } let (name, parent) = if def_id.index == CRATE_DEF_INDEX { - (self.cstore.crate_name_untracked(def_id.krate).as_str(), None) + (self.cstore.crate_name_untracked(def_id.krate).as_interned_str(), None) } else { let def_key = self.cstore.def_key(def_id); (def_key.disambiguated_data.data.get_opt_name().unwrap(), Some(self.get_module(DefId { index: def_key.parent.unwrap(), ..def_id }))) }; - let kind = ModuleKind::Def(Def::Mod(def_id), Symbol::intern(&name)); + let kind = ModuleKind::Def(Def::Mod(def_id), name.as_symbol()); let module = self.arenas.alloc_module(ModuleData::new(parent, kind, def_id, Mark::root(), DUMMY_SP)); self.extern_module_map.insert((def_id, macros_only), module); @@ -622,7 +624,7 @@ impl<'a> Resolver<'a> { let legacy_imports = self.legacy_macro_imports(&item.attrs); let mut used = legacy_imports != LegacyMacroImports::default(); - // `#[macro_use]` and `#[macro_reexport]` are only allowed at the crate root. + // `#[macro_use]` is only allowed at the crate root. if self.current_module.parent.is_some() && used { span_err!(self.session, item.span, E0468, "an `extern crate` loading macros must be at the crate root"); @@ -670,17 +672,6 @@ impl<'a> Resolver<'a> { } } } - for (name, span) in legacy_imports.reexports { - self.cstore.export_macros_untracked(module.def_id().unwrap().krate); - let ident = Ident::with_empty_ctxt(name); - let result = self.resolve_ident_in_module(module, ident, MacroNS, false, false, span); - if let Ok(binding) = result { - let (def, vis) = (binding.def(), binding.vis); - self.macro_exports.push(Export { ident, def, vis, span, is_import: true }); - } else { - span_err!(self.session, span, E0470, "re-exported macro not found"); - } - } used } @@ -715,28 +706,13 @@ impl<'a> Resolver<'a> { match attr.meta_item_list() { Some(names) => for attr in names { if let Some(word) = attr.word() { - imports.imports.push((word.ident.name, attr.span())); + imports.imports.push((word.name(), attr.span())); } else { span_err!(self.session, attr.span(), E0466, "bad macro import"); } }, None => imports.import_all = Some(attr.span), } - } else if attr.check_name("macro_reexport") { - let bad_macro_reexport = |this: &mut Self, span| { - span_err!(this.session, span, E0467, "bad macro re-export"); - }; - if let Some(names) = attr.meta_item_list() { - for attr in names { - if let Some(word) = attr.word() { - imports.reexports.push((word.ident.name, attr.span())); - } else { - bad_macro_reexport(self, attr.span()); - } - } - } else { - bad_macro_reexport(self, attr.span()); - } } } imports diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index a0fc5533f8e..232a32deb86 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -1395,35 +1395,6 @@ If you would like to import all exported macros, write `macro_use` with no arguments. "##, -E0467: r##" -Macro re-export declarations were empty or malformed. - -Erroneous code examples: - -```compile_fail,E0467 -#[macro_reexport] // error: no macros listed for export -extern crate core as macros_for_good; - -#[macro_reexport(fun_macro = "foo")] // error: not a macro identifier -extern crate core as other_macros_for_good; -``` - -This is a syntax error at the level of attribute declarations. - -Currently, `macro_reexport` requires at least one macro name to be listed. -Unlike `macro_use`, listing no names does not re-export all macros from the -given crate. - -Decide which macros you would like to export and list them properly. - -These are proper re-export declarations: - -```ignore (cannot-doctest-multicrate-project) -#[macro_reexport(some_macro, another_macro)] -extern crate macros_for_good; -``` -"##, - E0468: r##" A non-root module attempts to import macros from another crate. @@ -1496,48 +1467,6 @@ extern crate some_crate; //ok! ``` "##, -E0470: r##" -A macro listed for re-export was not found. - -Erroneous code example: - -```compile_fail,E0470 -#[macro_reexport(drink, be_merry)] -extern crate alloc; - -fn main() { - // ... -} -``` - -Either the listed macro is not contained in the imported crate, or it is not -exported from the given crate. - -This could be caused by a typo. Did you misspell the macro's name? - -Double-check the names of the macros listed for re-export, and that the crate -in question exports them. - -A working version: - -```ignore (cannot-doctest-multicrate-project) -// In some_crate crate: -#[macro_export] -macro_rules! eat { - ... -} - -#[macro_export] -macro_rules! drink { - ... -} - -// In your_crate: -#[macro_reexport(eat, drink)] -extern crate some_crate; -``` -"##, - E0530: r##" A binding shadowed something it shouldn't. @@ -1715,6 +1644,8 @@ register_diagnostics! { // E0421, merged into 531 E0531, // unresolved pattern path kind `name` // E0427, merged into 530 +// E0467, removed +// E0470, removed E0573, E0574, E0575, diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 127331152c1..d4b212a15d8 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -700,7 +700,7 @@ pub enum Namespace { pub struct PerNS<T> { value_ns: T, type_ns: T, - macro_ns: Option<T>, + macro_ns: T, } impl<T> ::std::ops::Index<Namespace> for PerNS<T> { @@ -709,7 +709,7 @@ impl<T> ::std::ops::Index<Namespace> for PerNS<T> { match ns { ValueNS => &self.value_ns, TypeNS => &self.type_ns, - MacroNS => self.macro_ns.as_ref().unwrap(), + MacroNS => &self.macro_ns, } } } @@ -719,7 +719,7 @@ impl<T> ::std::ops::IndexMut<Namespace> for PerNS<T> { match ns { ValueNS => &mut self.value_ns, TypeNS => &mut self.type_ns, - MacroNS => self.macro_ns.as_mut().unwrap(), + MacroNS => &mut self.macro_ns, } } } @@ -1407,6 +1407,7 @@ pub struct Resolver<'a> { graph_root: Module<'a>, prelude: Option<Module<'a>>, + extern_prelude: FxHashSet<Name>, /// n.b. This is used only for better diagnostics, not name resolution itself. has_self: FxHashSet<DefId>, @@ -1715,6 +1716,7 @@ impl<'a> Resolver<'a> { // AST. graph_root, prelude: None, + extern_prelude: session.opts.externs.iter().map(|kv| Symbol::intern(kv.0)).collect(), has_self: FxHashSet(), field_names: FxHashMap(), @@ -1726,7 +1728,7 @@ impl<'a> Resolver<'a> { ribs: PerNS { value_ns: vec![Rib::new(ModuleRibKind(graph_root))], type_ns: vec![Rib::new(ModuleRibKind(graph_root))], - macro_ns: Some(vec![Rib::new(ModuleRibKind(graph_root))]), + macro_ns: vec![Rib::new(ModuleRibKind(graph_root))], }, label_ribs: Vec::new(), @@ -1806,14 +1808,11 @@ impl<'a> Resolver<'a> { } /// Runs the function on each namespace. - fn per_ns<T, F: FnMut(&mut Self, Namespace) -> T>(&mut self, mut f: F) -> PerNS<T> { - PerNS { - type_ns: f(self, TypeNS), - value_ns: f(self, ValueNS), - macro_ns: match self.use_extern_macros { - true => Some(f(self, MacroNS)), - false => None, - }, + fn per_ns<F: FnMut(&mut Self, Namespace)>(&mut self, mut f: F) { + f(self, TypeNS); + f(self, ValueNS); + if self.use_extern_macros { + f(self, MacroNS); } } @@ -1970,13 +1969,32 @@ impl<'a> Resolver<'a> { } } - match self.prelude { - Some(prelude) if !module.no_implicit_prelude => { - self.resolve_ident_in_module_unadjusted(prelude, ident, ns, false, false, path_span) - .ok().map(LexicalScopeBinding::Item) + if !module.no_implicit_prelude { + // `record_used` means that we don't try to load crates during speculative resolution + if record_used && ns == TypeNS && self.extern_prelude.contains(&ident.name) { + if !self.session.features_untracked().extern_prelude { + feature_err(&self.session.parse_sess, "extern_prelude", + ident.span, GateIssue::Language, + "access to extern crates through prelude is experimental").emit(); + } + + let crate_id = self.crate_loader.process_path_extern(ident.name, ident.span); + let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }); + self.populate_module_if_necessary(crate_root); + + let binding = (crate_root, ty::Visibility::Public, + ident.span, Mark::root()).to_name_binding(self.arenas); + return Some(LexicalScopeBinding::Item(binding)); + } + if let Some(prelude) = self.prelude { + if let Ok(binding) = self.resolve_ident_in_module_unadjusted(prelude, ident, ns, + false, false, path_span) { + return Some(LexicalScopeBinding::Item(binding)); + } } - _ => None, } + + None } fn hygienic_lexical_parent(&mut self, mut module: Module<'a>, span: &mut Span) @@ -3587,8 +3605,9 @@ impl<'a> Resolver<'a> { // We can see through blocks } else { // Items from the prelude - if let Some(prelude) = self.prelude { - if !module.no_implicit_prelude { + if !module.no_implicit_prelude { + names.extend(self.extern_prelude.iter().cloned()); + if let Some(prelude) = self.prelude { add_module_candidates(prelude, &mut names); } } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index af1e17cd89c..4afc621ad8b 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -206,10 +206,10 @@ impl<'a> base::Resolver for Resolver<'a> { } // Resolves attribute and derive legacy macros from `#![plugin(..)]`. - fn find_legacy_attr_invoc(&mut self, attrs: &mut Vec<ast::Attribute>) + fn find_legacy_attr_invoc(&mut self, attrs: &mut Vec<ast::Attribute>, allow_derive: bool) -> Option<ast::Attribute> { for i in 0..attrs.len() { - let name = unwrap_or!(attrs[i].name(), continue); + let name = attrs[i].name(); if self.session.plugin_attributes.borrow().iter() .any(|&(ref attr_nm, _)| name == &**attr_nm) { @@ -227,9 +227,11 @@ impl<'a> base::Resolver for Resolver<'a> { } } + if !allow_derive { return None } + // Check for legacy derives for i in 0..attrs.len() { - let name = unwrap_or!(attrs[i].name(), continue); + let name = attrs[i].name(); if name == "derive" { let result = attrs[i].parse_list(&self.session.parse_sess, |parser| { @@ -397,7 +399,7 @@ impl<'a> Resolver<'a> { fn resolve_macro_to_def(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool) -> Result<Def, Determinacy> { - if path.segments.len() > 1 { + if kind != MacroKind::Bang && path.segments.len() > 1 { if !self.session.features_untracked().proc_macro_path_invoc { emit_feature_err( &self.session.parse_sess, @@ -409,6 +411,7 @@ impl<'a> Resolver<'a> { ); } } + let def = self.resolve_macro_to_def_inner(scope, path, kind, force); if def != Err(Determinacy::Undetermined) { // Do not report duplicated errors on every undetermined resolution. diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index e2a7f5668d2..17aa510b565 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -33,7 +33,7 @@ use syntax::util::lev_distance::find_best_match_for_name; use syntax_pos::Span; use std::cell::{Cell, RefCell}; -use std::mem; +use std::{mem, ptr}; /// Contains data for specific types of import directives. #[derive(Clone, Debug)] @@ -89,6 +89,8 @@ enum SingleImports<'a> { None, /// Only the given single import can define the name in the namespace. MaybeOne(&'a ImportDirective<'a>), + /// Only one of these two single imports can define the name in the namespace. + MaybeTwo(&'a ImportDirective<'a>, &'a ImportDirective<'a>), /// At least one single import will define the name in the namespace. AtLeastOne, } @@ -101,21 +103,28 @@ impl<'a> Default for SingleImports<'a> { } impl<'a> SingleImports<'a> { - fn add_directive(&mut self, directive: &'a ImportDirective<'a>) { + fn add_directive(&mut self, directive: &'a ImportDirective<'a>, use_extern_macros: bool) { match *self { SingleImports::None => *self = SingleImports::MaybeOne(directive), - // If two single imports can define the name in the namespace, we can assume that at - // least one of them will define it since otherwise both would have to define only one - // namespace, leading to a duplicate error. - SingleImports::MaybeOne(_) => *self = SingleImports::AtLeastOne, + SingleImports::MaybeOne(directive_one) => *self = if use_extern_macros { + SingleImports::MaybeTwo(directive_one, directive) + } else { + SingleImports::AtLeastOne + }, + // If three single imports can define the name in the namespace, we can assume that at + // least one of them will define it since otherwise we'd get duplicate errors in one of + // other namespaces. + SingleImports::MaybeTwo(..) => *self = SingleImports::AtLeastOne, SingleImports::AtLeastOne => {} }; } - fn directive_failed(&mut self) { + fn directive_failed(&mut self, dir: &'a ImportDirective<'a>) { match *self { SingleImports::None => unreachable!(), SingleImports::MaybeOne(_) => *self = SingleImports::None, + SingleImports::MaybeTwo(dir1, dir2) => + *self = SingleImports::MaybeOne(if ptr::eq(dir1, dir) { dir1 } else { dir2 }), SingleImports::AtLeastOne => {} } } @@ -199,23 +208,50 @@ impl<'a> Resolver<'a> { } // Check if a single import can still define the name. + let resolve_single_import = |this: &mut Self, directive: &'a ImportDirective<'a>| { + let module = match directive.imported_module.get() { + Some(module) => module, + None => return false, + }; + let ident = match directive.subclass { + SingleImport { source, .. } => source, + _ => unreachable!(), + }; + match this.resolve_ident_in_module(module, ident, ns, false, false, path_span) { + Err(Determined) => {} + _ => return false, + } + true + }; match resolution.single_imports { SingleImports::AtLeastOne => return Err(Undetermined), - SingleImports::MaybeOne(directive) if self.is_accessible(directive.vis.get()) => { - let module = match directive.imported_module.get() { - Some(module) => module, - None => return Err(Undetermined), - }; - let ident = match directive.subclass { - SingleImport { source, .. } => source, - _ => unreachable!(), - }; - match self.resolve_ident_in_module(module, ident, ns, false, false, path_span) { - Err(Determined) => {} - _ => return Err(Undetermined), + SingleImports::MaybeOne(directive) => { + let accessible = self.is_accessible(directive.vis.get()); + if accessible { + if !resolve_single_import(self, directive) { + return Err(Undetermined) + } + } + } + SingleImports::MaybeTwo(directive1, directive2) => { + let accessible1 = self.is_accessible(directive1.vis.get()); + let accessible2 = self.is_accessible(directive2.vis.get()); + if accessible1 && accessible2 { + if !resolve_single_import(self, directive1) && + !resolve_single_import(self, directive2) { + return Err(Undetermined) + } + } else if accessible1 { + if !resolve_single_import(self, directive1) { + return Err(Undetermined) + } + } else { + if !resolve_single_import(self, directive2) { + return Err(Undetermined) + } } } - SingleImports::MaybeOne(_) | SingleImports::None => {}, + SingleImports::None => {}, } let no_unresolved_invocations = @@ -281,7 +317,7 @@ impl<'a> Resolver<'a> { SingleImport { target, .. } => { self.per_ns(|this, ns| { let mut resolution = this.resolution(current_module, target, ns).borrow_mut(); - resolution.single_imports.add_directive(directive); + resolution.single_imports.add_directive(directive, this.use_extern_macros); }); } // We don't add prelude imports to the globs since they only affect lexical scopes, @@ -575,7 +611,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { Err(Undetermined) => indeterminate = true, Err(Determined) => { this.update_resolution(parent, target, ns, |_, resolution| { - resolution.single_imports.directive_failed() + resolution.single_imports.directive_failed(directive) }); } Ok(binding) if !binding.is_importable() => { diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index 18dd04c0ee8..fd1f779f9ec 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -14,7 +14,7 @@ pub use self::Primitive::*; use spec::Target; use std::cmp; -use std::ops::{Add, Deref, Sub, Mul, AddAssign, RangeInclusive}; +use std::ops::{Add, Deref, Sub, Mul, AddAssign, Range, RangeInclusive}; pub mod call; @@ -326,9 +326,9 @@ impl AddAssign for Size { } /// Alignment of a type in bytes, both ABI-mandated and preferred. -/// Each field is a power of two, giving the alignment a maximum value of -/// 2<sup>(2<sup>8</sup> - 1)</sup>, which is limited by LLVM to a i32, -/// with a maximum capacity of 2<sup>31</sup> - 1 or 2147483647. +/// Each field is a power of two, giving the alignment a maximum value +/// of 2<sup>(2<sup>8</sup> - 1)</sup>, which is limited by LLVM to a +/// maximum capacity of 2<sup>29</sup> or 536870912. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct Align { abi_pow2: u8, @@ -356,7 +356,7 @@ impl Align { } if bytes != 1 { Err(format!("`{}` is not a power of 2", align)) - } else if pow > 30 { + } else if pow > 29 { Err(format!("`{}` is too large", align)) } else { Ok(pow) @@ -544,6 +544,23 @@ impl Scalar { false } } + + /// Returns the valid range as a `x..y` range. + /// + /// If `x` and `y` are equal, the range is full, not empty. + pub fn valid_range_exclusive<C: HasDataLayout>(&self, cx: C) -> Range<u128> { + // For a (max) value of -1, max will be `-1 as usize`, which overflows. + // However, that is fine here (it would still represent the full range), + // i.e., if the range is everything. + let bits = self.value.size(cx).bits(); + assert!(bits <= 128); + let mask = !0u128 >> (128 - bits); + let start = *self.valid_range.start(); + let end = *self.valid_range.end(); + assert_eq!(start, start & mask); + assert_eq!(end, end & mask); + start..(end.wrapping_add(1) & mask) + } } /// Describes how the fields of a type are located in memory. diff --git a/src/librustc_target/lib.rs b/src/librustc_target/lib.rs index 8f491157439..45f2ee13bbd 100644 --- a/src/librustc_target/lib.rs +++ b/src/librustc_target/lib.rs @@ -29,6 +29,7 @@ #![feature(const_fn)] #![feature(fs_read_write)] #![feature(inclusive_range)] +#![feature(inclusive_range_methods)] #![feature(slice_patterns)] #[macro_use] diff --git a/src/librustc_target/spec/apple_ios_base.rs b/src/librustc_target/spec/apple_ios_base.rs index acbbab313fe..46bb01e7c42 100644 --- a/src/librustc_target/spec/apple_ios_base.rs +++ b/src/librustc_target/spec/apple_ios_base.rs @@ -98,6 +98,7 @@ pub fn opts(arch: Arch) -> Result<TargetOptions, String> { executables: true, pre_link_args, has_elf_tls: false, + eliminate_frame_pointer: false, // The following line is a workaround for jemalloc 4.5 being broken on // ios. jemalloc 5.0 is supposed to fix this. // see https://github.com/rust-lang/rust/issues/45262 diff --git a/src/librustc_target/spec/armv5te_unknown_linux_musleabi.rs b/src/librustc_target/spec/armv5te_unknown_linux_musleabi.rs new file mode 100644 index 00000000000..2d4e95ab01d --- /dev/null +++ b/src/librustc_target/spec/armv5te_unknown_linux_musleabi.rs @@ -0,0 +1,38 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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 spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; + +pub fn target() -> TargetResult { + let base = super::linux_musl_base::opts(); + Ok(Target { + // It's important we use "gnueabihf" and not "musleabihf" here. LLVM + // uses it to determine the calling convention and float ABI, and LLVM + // doesn't support the "musleabihf" value. + llvm_target: "armv5te-unknown-linux-gnueabi".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + target_c_int_width: "32".to_string(), + data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), + arch: "arm".to_string(), + target_os: "linux".to_string(), + target_env: "musl".to_string(), + target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, + + options: TargetOptions { + features: "+soft-float,+strict-align".to_string(), + // Atomic operations provided by compiler-builtins + max_atomic_width: Some(32), + abi_blacklist: super::arm_base::abi_blacklist(), + .. base + } + }) +} diff --git a/src/librustc_target/spec/i686_apple_darwin.rs b/src/librustc_target/spec/i686_apple_darwin.rs index 06ea1e4649b..d17789dfcc0 100644 --- a/src/librustc_target/spec/i686_apple_darwin.rs +++ b/src/librustc_target/spec/i686_apple_darwin.rs @@ -16,6 +16,7 @@ pub fn target() -> TargetResult { base.max_atomic_width = Some(64); base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".to_string()]); base.stack_probes = true; + base.eliminate_frame_pointer = false; Ok(Target { llvm_target: "i686-apple-darwin".to_string(), diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index 1e94f037885..48e771e0aaf 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -283,6 +283,7 @@ supported_targets! { ("arm-unknown-linux-musleabihf", arm_unknown_linux_musleabihf), ("armv4t-unknown-linux-gnueabi", armv4t_unknown_linux_gnueabi), ("armv5te-unknown-linux-gnueabi", armv5te_unknown_linux_gnueabi), + ("armv5te-unknown-linux-musleabi", armv5te_unknown_linux_musleabi), ("armv7-unknown-linux-gnueabihf", armv7_unknown_linux_gnueabihf), ("armv7-unknown-linux-musleabihf", armv7_unknown_linux_musleabihf), ("aarch64-unknown-linux-gnu", aarch64_unknown_linux_gnu), diff --git a/src/librustc_traits/dropck_outlives.rs b/src/librustc_traits/dropck_outlives.rs index 5f4daf0d568..ba31ce2692f 100644 --- a/src/librustc_traits/dropck_outlives.rs +++ b/src/librustc_traits/dropck_outlives.rs @@ -193,14 +193,38 @@ fn dtorck_constraint_for_ty<'a, 'gcx, 'tcx>( .map(|ty| dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty)) .collect(), - ty::TyGenerator(def_id, substs, _) => { - // Note that the interior types are ignored here. - // Any type reachable inside the interior must also be reachable - // through the upvars. - substs - .upvar_tys(def_id, tcx) - .map(|ty| dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty)) - .collect() + ty::TyGenerator(def_id, substs, _interior) => { + // rust-lang/rust#49918: types can be constructed, stored + // in the interior, and sit idle when generator yields + // (and is subsequently dropped). + // + // It would be nice to descend into interior of a + // generator to determine what effects dropping it might + // have (by looking at any drop effects associated with + // its interior). + // + // However, the interior's representation uses things like + // TyGeneratorWitness that explicitly assume they are not + // traversed in such a manner. So instead, we will + // simplify things for now by treating all generators as + // if they were like trait objects, where its upvars must + // all be alive for the generator's (potential) + // destructor. + // + // In particular, skipping over `_interior` is safe + // because any side-effects from dropping `_interior` can + // only take place through references with lifetimes + // derived from lifetimes attached to the upvars, and we + // *do* incorporate the upvars here. + + let constraint = DtorckConstraint { + outlives: substs.upvar_tys(def_id, tcx).map(|t| t.into()).collect(), + dtorck_types: vec![], + overflows: vec![], + }; + debug!("dtorck_constraint: generator {:?} => {:?}", def_id, constraint); + + Ok(constraint) } ty::TyAdt(def, substs) => { diff --git a/src/librustc_traits/evaluate_obligation.rs b/src/librustc_traits/evaluate_obligation.rs new file mode 100644 index 00000000000..21259bbcd38 --- /dev/null +++ b/src/librustc_traits/evaluate_obligation.rs @@ -0,0 +1,35 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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::traits::{EvaluationResult, Obligation, ObligationCause, + OverflowError, SelectionContext, TraitQueryMode}; +use rustc::traits::query::CanonicalPredicateGoal; +use rustc::ty::{ParamEnvAnd, TyCtxt}; +use syntax::codemap::DUMMY_SP; + +crate fn evaluate_obligation<'tcx>( + tcx: TyCtxt<'_, 'tcx, 'tcx>, + goal: CanonicalPredicateGoal<'tcx>, +) -> Result<EvaluationResult, OverflowError> { + tcx.infer_ctxt().enter(|ref infcx| { + let ( + ParamEnvAnd { + param_env, + value: predicate, + }, + _canonical_inference_vars, + ) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &goal); + + let mut selcx = SelectionContext::with_query_mode(&infcx, TraitQueryMode::Canonical); + let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate); + + selcx.evaluate_obligation_recursively(&obligation) + }) +} diff --git a/src/librustc_traits/lib.rs b/src/librustc_traits/lib.rs index 90c870096e1..7f18fac2db5 100644 --- a/src/librustc_traits/lib.rs +++ b/src/librustc_traits/lib.rs @@ -22,6 +22,7 @@ extern crate syntax; extern crate syntax_pos; mod dropck_outlives; +mod evaluate_obligation; mod normalize_projection_ty; mod normalize_erasing_regions; mod util; @@ -38,6 +39,7 @@ pub fn provide(p: &mut Providers) { normalize_erasing_regions::normalize_ty_after_erasing_regions, program_clauses_for: lowering::program_clauses_for, program_clauses_for_env: lowering::program_clauses_for_env, + evaluate_obligation: evaluate_obligation::evaluate_obligation, ..*p }; } diff --git a/src/librustc_traits/normalize_erasing_regions.rs b/src/librustc_traits/normalize_erasing_regions.rs index 1857df5717b..299433d479d 100644 --- a/src/librustc_traits/normalize_erasing_regions.rs +++ b/src/librustc_traits/normalize_erasing_regions.rs @@ -17,6 +17,8 @@ crate fn normalize_ty_after_erasing_regions<'tcx>( tcx: TyCtxt<'_, 'tcx, 'tcx>, goal: ParamEnvAnd<'tcx, Ty<'tcx>>, ) -> Ty<'tcx> { + debug!("normalize_ty_after_erasing_regions(goal={:#?})", goal); + let ParamEnvAnd { param_env, value } = goal; tcx.sess.perf_stats.normalize_ty_after_erasing_regions.fetch_add(1, Ordering::Relaxed); tcx.infer_ctxt().enter(|infcx| { diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml index 32432d6cc83..a4dd02e97b2 100644 --- a/src/librustc_trans/Cargo.toml +++ b/src/librustc_trans/Cargo.toml @@ -21,7 +21,6 @@ rustc-demangle = "0.1.4" rustc_allocator = { path = "../librustc_allocator" } rustc_apfloat = { path = "../librustc_apfloat" } rustc_target = { path = "../librustc_target" } -rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } rustc_incremental = { path = "../librustc_incremental" } diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 483f36afe27..1838dae049a 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -265,7 +265,7 @@ pub trait FnTypeExt<'a, 'tcx> { fn llvm_type(&self, cx: &CodegenCx<'a, 'tcx>) -> Type; fn llvm_cconv(&self) -> llvm::CallConv; fn apply_attrs_llfn(&self, llfn: ValueRef); - fn apply_attrs_callsite(&self, callsite: ValueRef); + fn apply_attrs_callsite(&self, bx: &Builder<'a, 'tcx>, callsite: ValueRef); } impl<'a, 'tcx> FnTypeExt<'a, 'tcx> for FnType<'tcx, Ty<'tcx>> { @@ -388,8 +388,8 @@ impl<'a, 'tcx> FnTypeExt<'a, 'tcx> for FnType<'tcx, Ty<'tcx>> { return; } - if scalar.valid_range.start < scalar.valid_range.end { - if scalar.valid_range.start > 0 { + if scalar.valid_range.start() < scalar.valid_range.end() { + if *scalar.valid_range.start() > 0 { attrs.set(ArgAttribute::NonNull); } } @@ -640,7 +640,7 @@ impl<'a, 'tcx> FnTypeExt<'a, 'tcx> for FnType<'tcx, Ty<'tcx>> { } } - fn apply_attrs_callsite(&self, callsite: ValueRef) { + fn apply_attrs_callsite(&self, bx: &Builder<'a, 'tcx>, callsite: ValueRef) { let mut i = 0; let mut apply = |attrs: &ArgAttributes| { attrs.apply_callsite(llvm::AttributePlace::Argument(i), callsite); @@ -653,6 +653,24 @@ impl<'a, 'tcx> FnTypeExt<'a, 'tcx> for FnType<'tcx, Ty<'tcx>> { PassMode::Indirect(ref attrs) => apply(attrs), _ => {} } + if let layout::Abi::Scalar(ref scalar) = self.ret.layout.abi { + // If the value is a boolean, the range is 0..2 and that ultimately + // become 0..0 when the type becomes i1, which would be rejected + // by the LLVM verifier. + match scalar.value { + layout::Int(..) if !scalar.is_bool() => { + let range = scalar.valid_range_exclusive(bx.cx); + if range.start != range.end { + // FIXME(nox): This causes very weird type errors about + // SHL operators in constants in stage 2 with LLVM 3.9. + if unsafe { llvm::LLVMRustVersionMajor() >= 4 } { + bx.range_metadata(callsite, range); + } + } + } + _ => {} + } + } for arg in &self.args { if arg.pad.is_some() { apply(&ArgAttributes::new()); diff --git a/src/librustc_trans/allocator.rs b/src/librustc_trans/allocator.rs index ffebb959ebf..871fe98ec01 100644 --- a/src/librustc_trans/allocator.rs +++ b/src/librustc_trans/allocator.rs @@ -11,6 +11,7 @@ use std::ffi::CString; use std::ptr; +use attributes; use libc::c_uint; use rustc::middle::allocator::AllocatorKind; use rustc::ty::TyCtxt; @@ -67,6 +68,9 @@ pub(crate) unsafe fn trans(tcx: TyCtxt, mods: &ModuleLlvm, kind: AllocatorKind) if tcx.sess.target.target.options.default_hidden_visibility { llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); } + if tcx.sess.target.target.options.requires_uwtable { + attributes::emit_uwtable(llfn, true); + } let callee = CString::new(kind.fn_name(method.name)).unwrap(); let callee = llvm::LLVMRustGetOrInsertFunction(llmod, diff --git a/src/librustc_trans/attributes.rs b/src/librustc_trans/attributes.rs index eb5c7396ae0..5baed57092d 100644 --- a/src/librustc_trans/attributes.rs +++ b/src/librustc_trans/attributes.rs @@ -14,6 +14,7 @@ use std::ffi::{CStr, CString}; use rustc::hir::{self, TransFnAttrFlags}; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::hir::itemlikevisit::ItemLikeVisitor; +use rustc::session::Session; use rustc::session::config::Sanitizer; use rustc::ty::TyCtxt; use rustc::ty::maps::Providers; @@ -68,8 +69,6 @@ pub fn naked(val: ValueRef, is_naked: bool) { } pub fn set_frame_pointer_elimination(cx: &CodegenCx, llfn: ValueRef) { - // FIXME: #11906: Omitting frame pointers breaks retrieving the value of a - // parameter. if cx.sess().must_not_eliminate_frame_pointers() { llvm::AddFunctionAttrStringValue( llfn, llvm::AttributePlace::Function, @@ -104,6 +103,18 @@ pub fn set_probestack(cx: &CodegenCx, llfn: ValueRef) { cstr("probe-stack\0"), cstr("__rust_probestack\0")); } +pub fn llvm_target_features(sess: &Session) -> impl Iterator<Item = &str> { + const RUSTC_SPECIFIC_FEATURES: &[&str] = &[ + "crt-static", + ]; + + let cmdline = sess.opts.cg.target_feature.split(',') + .filter(|f| !RUSTC_SPECIFIC_FEATURES.iter().any(|s| f.contains(s))); + sess.target.target.options.features.split(',') + .chain(cmdline) + .filter(|l| !l.is_empty()) +} + /// Composite function which sets LLVM attributes for function depending on its AST (#[attribute]) /// attributes. pub fn from_fn_attrs(cx: &CodegenCx, llfn: ValueRef, id: DefId) { @@ -131,13 +142,16 @@ pub fn from_fn_attrs(cx: &CodegenCx, llfn: ValueRef, id: DefId) { unwind(llfn, false); } - let features = - trans_fn_attrs.target_features - .iter() - .map(|f| { - let feature = &*f.as_str(); - format!("+{}", llvm_util::to_llvm_feature(cx.tcx.sess, feature)) - }) + let features = llvm_target_features(cx.tcx.sess) + .map(|s| s.to_string()) + .chain( + trans_fn_attrs.target_features + .iter() + .map(|f| { + let feature = &*f.as_str(); + format!("+{}", llvm_util::to_llvm_feature(cx.tcx.sess, feature)) + }) + ) .collect::<Vec<String>>() .join(","); diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index f9a8473464d..ea3f5b40860 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -959,7 +959,11 @@ impl Linker for WasmLd { } fn finalize(&mut self) -> Command { - self.cmd.arg("--threads"); + // There have been reports in the wild (rustwasm/wasm-bindgen#119) of + // using threads causing weird hangs and bugs. Disable it entirely as + // this isn't yet the bottleneck of compilation at all anyway. + self.cmd.arg("--no-threads"); + self.cmd.arg("-z").arg("stack-size=1048576"); // FIXME we probably shouldn't pass this but instead pass an explicit diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index 965a34eccb8..d8520b61d91 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -132,7 +132,7 @@ fn reachable_non_generics_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }) .map(|def_id| { let export_level = if special_runtime_crate { - let name = tcx.symbol_name(Instance::mono(tcx, def_id)); + let name = tcx.symbol_name(Instance::mono(tcx, def_id)).as_str(); // We can probably do better here by just ensuring that // it has hidden visibility rather than public // visibility, as this is primarily here to ensure it's diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 613a07cd269..148e3d0025c 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use attributes; use back::bytecode::{self, RLIB_BYTECODE_EXTENSION}; use back::lto::{self, ModuleBuffer, ThinBuffer}; use back::link::{self, get_linker, remove}; @@ -111,31 +112,6 @@ pub fn write_output_file( } } -// On android, we by default compile for armv7 processors. This enables -// things like double word CAS instructions (rather than emulating them) -// which are *far* more efficient. This is obviously undesirable in some -// cases, so if any sort of target feature is specified we don't append v7 -// to the feature list. -// -// On iOS only armv7 and newer are supported. So it is useful to -// get all hardware potential via VFP3 (hardware floating point) -// and NEON (SIMD) instructions supported by LLVM. -// Note that without those flags various linking errors might -// arise as some of intrinsics are converted into function calls -// and nobody provides implementations those functions -fn target_feature(sess: &Session) -> String { - let rustc_features = [ - "crt-static", - ]; - let requested_features = sess.opts.cg.target_feature.split(','); - let llvm_features = requested_features.filter(|f| { - !rustc_features.iter().any(|s| f.contains(s)) - }); - format!("{},{}", - sess.target.target.options.features, - llvm_features.collect::<Vec<_>>().join(",")) -} - fn get_llvm_opt_level(optimize: config::OptLevel) -> llvm::CodeGenOptLevel { match optimize { config::OptLevel::No => llvm::CodeGenOptLevel::None, @@ -203,7 +179,10 @@ pub fn target_machine_factory(sess: &Session, find_features: bool) None => &*sess.target.target.options.cpu }; let cpu = CString::new(cpu.as_bytes()).unwrap(); - let features = CString::new(target_feature(sess).as_bytes()).unwrap(); + let features = attributes::llvm_target_features(sess) + .collect::<Vec<_>>() + .join(","); + let features = CString::new(features).unwrap(); let is_pie_binary = !find_features && is_pie_binary(sess); let trap_unreachable = sess.target.target.options.trap_unreachable; diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 2323ec3ef11..b756a6695f9 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1037,7 +1037,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>( cgus.dedup(); for &(ref cgu_name, (linkage, _)) in cgus.iter() { output.push_str(" "); - output.push_str(&cgu_name); + output.push_str(&cgu_name.as_str()); let linkage_abbrev = match linkage { Linkage::External => "External", diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 5849437758a..9263d9a5f5d 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -52,7 +52,7 @@ pub fn get_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, return llfn; } - let sym = tcx.symbol_name(instance); + let sym = tcx.symbol_name(instance).as_str(); debug!("get_fn({:?}: {:?}) => {}", instance, fn_ty, sym); // Create a fn pointer with the substituted signature. diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 25ca2152b27..4a0619b2336 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -33,7 +33,7 @@ use libc::{c_uint, c_char}; use std::iter; use rustc_target::spec::abi::Abi; -use syntax::symbol::InternedString; +use syntax::symbol::LocalInternedString; use syntax_pos::{Span, DUMMY_SP}; pub use context::CodegenCx; @@ -183,7 +183,7 @@ pub fn C_u8(cx: &CodegenCx, i: u8) -> ValueRef { // This is a 'c-like' raw string, which differs from // our boxed-and-length-annotated strings. -pub fn C_cstr(cx: &CodegenCx, s: InternedString, null_terminated: bool) -> ValueRef { +pub fn C_cstr(cx: &CodegenCx, s: LocalInternedString, null_terminated: bool) -> ValueRef { unsafe { if let Some(&llval) = cx.const_cstr_cache.borrow().get(&s) { return llval; @@ -208,7 +208,7 @@ pub fn C_cstr(cx: &CodegenCx, s: InternedString, null_terminated: bool) -> Value // NB: Do not use `do_spill_noroot` to make this into a constant string, or // you will be kicked off fast isel. See issue #4352 for an example of this. -pub fn C_str_slice(cx: &CodegenCx, s: InternedString) -> ValueRef { +pub fn C_str_slice(cx: &CodegenCx, s: LocalInternedString) -> ValueRef { let len = s.len(); let cs = consts::ptrcast(C_cstr(cx, s, false), cx.layout_of(cx.tcx.mk_str()).llvm_type(cx).ptr_to()); diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 122b51dbbb7..405cb83ad4d 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -118,7 +118,7 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef { def_id); let ty = instance.ty(cx.tcx); - let sym = cx.tcx.symbol_name(instance); + let sym = cx.tcx.symbol_name(instance).as_str(); let g = if let Some(id) = cx.tcx.hir.as_local_node_id(def_id) { diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 76f8be9ee98..90b2fb4b59a 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -39,7 +39,7 @@ use std::ptr; use std::iter; use std::str; use std::sync::Arc; -use syntax::symbol::InternedString; +use syntax::symbol::LocalInternedString; use abi::Abi; /// There is one `CodegenCx` per compilation unit. Each one has its own LLVM @@ -62,7 +62,7 @@ pub struct CodegenCx<'a, 'tcx: 'a> { pub vtables: RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), ValueRef>>, /// Cache of constant strings, - pub const_cstr_cache: RefCell<FxHashMap<InternedString, ValueRef>>, + pub const_cstr_cache: RefCell<FxHashMap<LocalInternedString, ValueRef>>, /// Reverse-direction for const ptrs cast from globals. /// Key is a ValueRef holding a *T, @@ -273,7 +273,7 @@ impl<'a, 'tcx> CodegenCx<'a, 'tcx> { let dbg_cx = if tcx.sess.opts.debuginfo != NoDebugInfo { let dctx = debuginfo::CrateDebugContext::new(llmod); debuginfo::metadata::compile_unit_metadata(tcx, - codegen_unit.name(), + &codegen_unit.name().as_str(), &dctx); Some(dctx) } else { diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 5359e0e0405..2fc6c9d4433 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -1236,7 +1236,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { self.layout, self.layout.fields.offset(0), self.layout.field(cx, 0).size); - name.push_str(&adt.variants[niche_variants.start].name.as_str()); + name.push_str(&adt.variants[*niche_variants.start()].name.as_str()); // Create the (singleton) list of descriptions of union members. vec![ @@ -1399,7 +1399,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, (discr.size(cx), discr.align(cx)); let discriminant_base_type_metadata = type_metadata(cx, discr.to_ty(cx.tcx), syntax_pos::DUMMY_SP); - let discriminant_name = get_enum_discriminant_name(cx, enum_def_id); + let discriminant_name = get_enum_discriminant_name(cx, enum_def_id).as_str(); let name = CString::new(discriminant_name.as_bytes()).unwrap(); let discriminant_type_metadata = unsafe { diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 706dc3dca8a..30676b91620 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -271,7 +271,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, } None => {} }; - if sig.output().is_never() { + if cx.layout_of(sig.output()).abi == ty::layout::Abi::Uninhabited { flags = flags | DIFlags::FlagNoReturn; } @@ -394,7 +394,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, substs.types().zip(names).map(|(ty, name)| { let actual_type = cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty); let actual_type_metadata = type_metadata(cx, actual_type, syntax_pos::DUMMY_SP); - let name = CString::new(name.as_bytes()).unwrap(); + let name = CString::new(name.as_str().as_bytes()).unwrap(); unsafe { llvm::LLVMRustDIBuilderCreateTemplateTypeParameter( DIB(cx), diff --git a/src/librustc_trans/debuginfo/namespace.rs b/src/librustc_trans/debuginfo/namespace.rs index 891bf649c38..51c45de9dc2 100644 --- a/src/librustc_trans/debuginfo/namespace.rs +++ b/src/librustc_trans/debuginfo/namespace.rs @@ -47,7 +47,7 @@ pub fn item_namespace(cx: &CodegenCx, def_id: DefId) -> DIScope { let namespace_name = match def_key.disambiguated_data.data { DefPathData::CrateRoot => cx.tcx.crate_name(def_id.krate).as_str(), - data => data.as_interned_str() + data => data.as_interned_str().as_str() }; let namespace_name = CString::new(namespace_name.as_bytes()).unwrap(); diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index 96ed4e88471..825fac36c93 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_trans/debuginfo/type_names.rs @@ -190,10 +190,10 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, output.push_str(&cx.tcx.crate_name(def_id.krate).as_str()); for path_element in cx.tcx.def_path(def_id).data { output.push_str("::"); - output.push_str(&path_element.data.as_interned_str()); + output.push_str(&path_element.data.as_interned_str().as_str()); } } else { - output.push_str(&cx.tcx.item_name(def_id)); + output.push_str(&cx.tcx.item_name(def_id).as_str()); } } diff --git a/src/librustc_trans/declare.rs b/src/librustc_trans/declare.rs index bbe4e18b18c..97721ffbf06 100644 --- a/src/librustc_trans/declare.rs +++ b/src/librustc_trans/declare.rs @@ -23,6 +23,7 @@ use llvm::{self, ValueRef}; use llvm::AttributePlace::Function; use rustc::ty::{self, Ty}; +use rustc::ty::layout::{self, LayoutOf}; use rustc::session::config::Sanitizer; use rustc_target::spec::PanicStrategy; use abi::{Abi, FnType, FnTypeExt}; @@ -133,8 +134,7 @@ pub fn declare_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, name: &str, let fty = FnType::new(cx, sig, &[]); let llfn = declare_raw_fn(cx, name, fty.llvm_cconv(), fty.llvm_type(cx)); - // FIXME(canndrew): This is_never should really be an is_uninhabited - if sig.output().is_never() { + if cx.layout_of(sig.output()).abi == layout::Abi::Uninhabited { llvm::Attribute::NoReturn.apply_llfn(Function, llfn); } diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 103b04e6f13..49a207a2d8a 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -103,7 +103,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>, let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); let arg_tys = sig.inputs(); let ret_ty = sig.output(); - let name = &*tcx.item_name(def_id); + let name = &*tcx.item_name(def_id).as_str(); let llret_ty = cx.layout_of(ret_ty).llvm_type(cx); let result = PlaceRef::new_sized(llresult, fn_ty.ret.layout, fn_ty.ret.layout.align); diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index dab01abd335..7a152d6ded4 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -25,10 +25,11 @@ #![allow(unused_attributes)] #![feature(libc)] #![feature(quote)] +#![feature(range_contains)] #![feature(rustc_diagnostic_macros)] #![feature(slice_sort_by_cached_key)] #![feature(optin_builtin_traits)] -#![feature(inclusive_range_fields)] +#![feature(inclusive_range_methods)] use rustc::dep_graph::WorkProduct; use syntax_pos::symbol::Symbol; @@ -42,7 +43,6 @@ extern crate rustc_mir; extern crate rustc_allocator; extern crate rustc_apfloat; extern crate rustc_target; -extern crate rustc_const_math; #[macro_use] extern crate rustc_data_structures; extern crate rustc_demangle; extern crate rustc_incremental; diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index 0fe7163da7a..9e5298eb736 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -322,7 +322,7 @@ pub fn cleanup_kinds<'a, 'tcx>(mir: &mir::Mir<'tcx>) -> IndexVec<mir::BasicBlock debug!("cleanup_kinds: {:?}/{:?}/{:?} propagating funclet {:?}", bb, data, result[bb], funclet); - for &succ in data.terminator().successors().iter() { + for &succ in data.terminator().successors() { let kind = result[succ]; debug!("cleanup_kinds: propagating {:?} to {:?}/{:?}", funclet, succ, kind); diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 36f03605fea..b666c2b2115 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -13,6 +13,7 @@ use rustc::middle::lang_items; use rustc::ty::{self, Ty, TypeFoldable}; use rustc::ty::layout::{self, LayoutOf}; use rustc::mir; +use rustc::mir::interpret::EvalErrorKind; use abi::{Abi, ArgType, ArgTypeExt, FnType, FnTypeExt, LlvmType, PassMode}; use base; use callee; @@ -127,7 +128,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { ret_bx, llblock(this, cleanup), cleanup_bundle); - fn_ty.apply_attrs_callsite(invokeret); + fn_ty.apply_attrs_callsite(&bx, invokeret); if let Some((ret_dest, target)) = destination { let ret_bx = this.build_block(target); @@ -136,7 +137,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { } } else { let llret = bx.call(fn_ptr, &llargs, cleanup_bundle); - fn_ty.apply_attrs_callsite(llret); + fn_ty.apply_attrs_callsite(&bx, llret); if this.mir[bb].is_cleanup { // Cleanup is always the cold path. Don't inline // drop glue. Also, when there is a deeply-nested @@ -311,10 +312,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { // checked operation, just a comparison with the minimum // value, so we have to check for the assert message. if !bx.cx.check_overflow { - use rustc_const_math::ConstMathErr::Overflow; - use rustc_const_math::Op::Neg; - - if let mir::AssertMessage::Math(Overflow(Neg)) = *msg { + if let mir::interpret::EvalErrorKind::OverflowNeg = *msg { const_cond = Some(expected); } } @@ -354,7 +352,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { // Put together the arguments to the panic entry point. let (lang_item, args) = match *msg { - mir::AssertMessage::BoundsCheck { ref len, ref index } => { + EvalErrorKind::BoundsCheck { ref len, ref index } => { let len = self.trans_operand(&mut bx, len).immediate(); let index = self.trans_operand(&mut bx, index).immediate(); @@ -366,26 +364,8 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { (lang_items::PanicBoundsCheckFnLangItem, vec![file_line_col, index, len]) } - mir::AssertMessage::Math(ref err) => { - let msg_str = Symbol::intern(err.description()).as_str(); - let msg_str = C_str_slice(bx.cx, msg_str); - let msg_file_line_col = C_struct(bx.cx, - &[msg_str, filename, line, col], - false); - let msg_file_line_col = consts::addr_of(bx.cx, - msg_file_line_col, - align, - "panic_loc"); - (lang_items::PanicFnLangItem, - vec![msg_file_line_col]) - } - mir::AssertMessage::GeneratorResumedAfterReturn | - mir::AssertMessage::GeneratorResumedAfterPanic => { - let str = if let mir::AssertMessage::GeneratorResumedAfterReturn = *msg { - "generator resumed after completion" - } else { - "generator resumed after panicking" - }; + _ => { + let str = msg.description(); let msg_str = Symbol::intern(str).as_str(); let msg_str = C_str_slice(bx.cx, msg_str); let msg_file_line_col = C_struct(bx.cx, @@ -442,7 +422,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { // Handle intrinsics old trans wants Expr's for, ourselves. let intrinsic = match def { Some(ty::InstanceDef::Intrinsic(def_id)) - => Some(bx.tcx().item_name(def_id)), + => Some(bx.tcx().item_name(def_id).as_str()), _ => None }; let intrinsic = intrinsic.as_ref().map(|s| &s[..]); diff --git a/src/librustc_trans/mir/place.rs b/src/librustc_trans/mir/place.rs index b8b0c019ca6..79859aee64d 100644 --- a/src/librustc_trans/mir/place.rs +++ b/src/librustc_trans/mir/place.rs @@ -91,24 +91,15 @@ impl<'a, 'tcx> PlaceRef<'tcx> { } let scalar_load_metadata = |load, scalar: &layout::Scalar| { - let (min, max) = (scalar.valid_range.start, scalar.valid_range.end); - let max_next = max.wrapping_add(1); - let bits = scalar.value.size(bx.cx).bits(); - assert!(bits <= 128); - let mask = !0u128 >> (128 - bits); - // For a (max) value of -1, max will be `-1 as usize`, which overflows. - // However, that is fine here (it would still represent the full range), - // i.e., if the range is everything. The lo==hi case would be - // rejected by the LLVM verifier (it would mean either an - // empty set, which is impossible, or the entire range of the - // type, which is pointless). + let vr = scalar.valid_range.clone(); match scalar.value { - layout::Int(..) if max_next & mask != min & mask => { - // llvm::ConstantRange can deal with ranges that wrap around, - // so an overflow on (max + 1) is fine. - bx.range_metadata(load, min..max_next); + layout::Int(..) => { + let range = scalar.valid_range_exclusive(bx.cx); + if range.start != range.end { + bx.range_metadata(load, range); + } } - layout::Pointer if 0 < min && min < max => { + layout::Pointer if vr.start() < vr.end() && !vr.contains(&0) => { bx.nonnull_metadata(load); } _ => {} @@ -296,7 +287,7 @@ impl<'a, 'tcx> PlaceRef<'tcx> { .. } => { let niche_llty = discr.layout.immediate_llvm_type(bx.cx); - if niche_variants.start == niche_variants.end { + if niche_variants.start() == niche_variants.end() { // FIXME(eddyb) Check the actual primitive type here. let niche_llval = if niche_start == 0 { // HACK(eddyb) Using `C_null` as it works on all types. @@ -305,13 +296,13 @@ impl<'a, 'tcx> PlaceRef<'tcx> { C_uint_big(niche_llty, niche_start) }; bx.select(bx.icmp(llvm::IntEQ, lldiscr, niche_llval), - C_uint(cast_to, niche_variants.start as u64), + C_uint(cast_to, *niche_variants.start() as u64), C_uint(cast_to, dataful_variant as u64)) } else { // Rebase from niche values to discriminant values. - let delta = niche_start.wrapping_sub(niche_variants.start as u128); + let delta = niche_start.wrapping_sub(*niche_variants.start() as u128); let lldiscr = bx.sub(lldiscr, C_uint_big(niche_llty, delta)); - let lldiscr_max = C_uint(niche_llty, niche_variants.end as u64); + let lldiscr_max = C_uint(niche_llty, *niche_variants.end() as u64); bx.select(bx.icmp(llvm::IntULE, lldiscr, lldiscr_max), bx.intcast(lldiscr, cast_to, false), C_uint(cast_to, dataful_variant as u64)) @@ -361,7 +352,7 @@ impl<'a, 'tcx> PlaceRef<'tcx> { let niche = self.project_field(bx, 0); let niche_llty = niche.layout.immediate_llvm_type(bx.cx); - let niche_value = ((variant_index - niche_variants.start) as u128) + let niche_value = ((variant_index - *niche_variants.start()) as u128) .wrapping_add(niche_start); // FIXME(eddyb) Check the actual primitive type here. let niche_llval = if niche_value == 0 { diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index c932777402e..0cd823391b9 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -15,7 +15,6 @@ use rustc::ty::layout::{self, LayoutOf}; 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; @@ -301,7 +300,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { if let layout::Int(_, s) = scalar.value { signed = s; - if scalar.valid_range.end > scalar.valid_range.start { + if scalar.valid_range.end() > scalar.valid_range.start() { // We want `table[e as usize]` to not // have bound checks, and this is the most // convenient place to put the `assume`. @@ -309,7 +308,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { base::call_assume(&bx, bx.icmp( llvm::IntULE, llval, - C_uint_big(ll_t_in, scalar.valid_range.end) + C_uint_big(ll_t_in, *scalar.valid_range.end()) )); } } @@ -536,7 +535,6 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { let is_float = input_ty.is_fp(); let is_signed = input_ty.is_signed(); let is_nil = input_ty.is_nil(); - let is_bool = input_ty.is_bool(); match op { mir::BinOp::Add => if is_float { bx.fadd(lhs, rhs) @@ -586,15 +584,6 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { lhs, rhs ) } else { - let (lhs, rhs) = if is_bool { - // FIXME(#36856) -- extend the bools into `i8` because - // LLVM's i1 comparisons are broken. - (bx.zext(lhs, Type::i8(bx.cx)), - bx.zext(rhs, Type::i8(bx.cx))) - } else { - (lhs, rhs) - }; - bx.icmp( base::bin_op_to_icmp_predicate(op.to_hir_binop(), is_signed), lhs, rhs @@ -815,6 +804,10 @@ fn cast_int_to_float(bx: &Builder, if is_u128_to_f32 { // 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. + use rustc_apfloat::ieee::Single; + use rustc_apfloat::Float; + const MAX_F32_PLUS_HALF_ULP: u128 = ((1 << (Single::PRECISION + 1)) - 1) + << (Single::MAX_EXP - Single::PRECISION as i16); let max = C_uint_big(int_ty, MAX_F32_PLUS_HALF_ULP); let overflow = bx.icmp(llvm::IntUGE, x, max); let infinity_bits = C_u32(bx.cx, ieee::Single::INFINITY.to_bits() as u32); diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 06d94e8d155..d19b5af2527 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -88,7 +88,7 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> { self.to_raw_string(), cx.codegen_unit.name()); - let symbol_name = self.symbol_name(cx.tcx); + let symbol_name = self.symbol_name(cx.tcx).as_str(); debug!("symbol {}", &symbol_name); diff --git a/src/librustc_trans_utils/symbol_names.rs b/src/librustc_trans_utils/symbol_names.rs index f3b7326b210..be5bff60805 100644 --- a/src/librustc_trans_utils/symbol_names.rs +++ b/src/librustc_trans_utils/symbol_names.rs @@ -229,7 +229,7 @@ fn def_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) fn symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>) -> ty::SymbolName { - ty::SymbolName { name: Symbol::intern(&compute_symbol_name(tcx, instance)).as_str() } + ty::SymbolName { name: Symbol::intern(&compute_symbol_name(tcx, instance)).as_interned_str() } } fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>) @@ -355,12 +355,12 @@ impl SymbolPathBuffer { result: String::with_capacity(64), temp_buf: String::with_capacity(16) }; - result.result.push_str(&symbol.name); + result.result.push_str(&symbol.name.as_str()); result } fn into_interned(self) -> ty::SymbolName { - ty::SymbolName { name: Symbol::intern(&self.result).as_str() } + ty::SymbolName { name: Symbol::intern(&self.result).as_interned_str() } } fn finish(mut self, hash: u64) -> String { diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml index 70c13e9b7d6..c426533779c 100644 --- a/src/librustc_typeck/Cargo.toml +++ b/src/librustc_typeck/Cargo.toml @@ -15,7 +15,6 @@ syntax = { path = "../libsyntax" } arena = { path = "../libarena" } fmt_macros = { path = "../libfmt_macros" } rustc = { path = "../librustc" } -rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" } rustc_target = { path = "../librustc_target" } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 6cdce127308..93dbba6e873 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -101,7 +101,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { { let tcx = self.tcx(); let lifetime_name = |def_id| { - tcx.hir.name(tcx.hir.as_local_node_id(def_id).unwrap()).as_str() + tcx.hir.name(tcx.hir.as_local_node_id(def_id).unwrap()).as_interned_str() }; let hir_id = tcx.hir.node_to_hir_id(lifetime.id); @@ -981,7 +981,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let item_def_id = tcx.hir.local_def_id(item_id); let generics = tcx.generics_of(item_def_id); let index = generics.type_param_to_index[&tcx.hir.local_def_id(node_id)]; - tcx.mk_param(index, tcx.hir.name(node_id).as_str()) + tcx.mk_param(index, tcx.hir.name(node_id).as_interned_str()) } Def::SelfTy(_, Some(def_id)) => { // Self in impl (we know the concrete type). diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index a87058d1fa5..3199ff17ae9 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -120,15 +120,15 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id); - let mut selcx = traits::SelectionContext::new(self.fcx); let obligation = traits::Obligation::new(cause.clone(), self.fcx.param_env, trait_ref.to_predicate()); - if !selcx.evaluate_obligation(&obligation) { + if !self.fcx.predicate_may_hold(&obligation) { debug!("overloaded_deref_ty: cannot match obligation"); return None; } + let mut selcx = traits::SelectionContext::new(self.fcx); let normalized = traits::normalize_projection_type(&mut selcx, self.fcx.param_env, ty::ProjectionTy::from_ref_and_name( diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index c9e53fa7674..91264849cad 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -732,8 +732,7 @@ fn compare_synthetic_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if impl_ty.synthetic != trait_ty.synthetic { let impl_node_id = tcx.hir.as_local_node_id(impl_ty.def_id).unwrap(); let impl_span = tcx.hir.span(impl_node_id); - let trait_node_id = tcx.hir.as_local_node_id(trait_ty.def_id).unwrap(); - let trait_span = tcx.hir.span(trait_node_id); + let trait_span = tcx.def_span(trait_ty.def_id); let mut err = struct_span_err!(tcx.sess, impl_span, E0643, diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 283fbf8fecc..fcf7541a159 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -76,7 +76,7 @@ fn equate_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, /// and in libcore/intrinsics.rs pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::ForeignItem) { - let param = |n| tcx.mk_param(n, Symbol::intern(&format!("P{}", n)).as_str()); + let param = |n| tcx.mk_param(n, Symbol::intern(&format!("P{}", n)).as_interned_str()); let name = it.name.as_str(); let (n_tps, inputs, output) = if name.starts_with("atomic_") { let split : Vec<&str> = name.split('_').collect(); @@ -341,7 +341,7 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub fn check_platform_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::ForeignItem) { let param = |n| { - let name = Symbol::intern(&format!("P{}", n)).as_str(); + let name = Symbol::intern(&format!("P{}", n)).as_interned_str(); tcx.mk_param(n, name) }; diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 5f55ee6163b..5f904a9419b 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -277,8 +277,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { poly_trait_ref.to_predicate()); // Now we want to know if this can be matched - let mut selcx = traits::SelectionContext::new(self); - if !selcx.evaluate_obligation(&obligation) { + if !self.predicate_may_hold(&obligation) { debug!("--> Cannot match obligation"); return None; // Cannot be matched, no such method resolution is possible. } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index b41a6dcf384..907c80f0daf 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1173,7 +1173,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let predicate = trait_ref.to_predicate(); let obligation = traits::Obligation::new(cause.clone(), self.param_env, predicate); - if !selcx.evaluate_obligation(&obligation) { + if !self.predicate_may_hold(&obligation) { if self.probe(|_| self.select_trait_candidate(trait_ref).is_err()) { // This candidate's primary obligation doesn't even // select - don't bother registering anything in @@ -1201,7 +1201,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // Evaluate those obligations to see if they might possibly hold. for o in candidate_obligations.into_iter().chain(sub_obligations) { let o = self.resolve_type_vars_if_possible(&o); - if !selcx.evaluate_obligation(&o) { + if !self.predicate_may_hold(&o) { result = ProbeResult::NoMatch; if let &ty::Predicate::Trait(ref pred) = &o.predicate { possibly_unsatisfied_predicates.push(pred.skip_binder().trait_ref); @@ -1485,7 +1485,10 @@ impl<'tcx> Candidate<'tcx> { // inference variables or other artifacts. This // means they are safe to put into the // `WhereClausePick`. - assert!(!trait_ref.skip_binder().substs.needs_infer()); + assert!( + !trait_ref.skip_binder().substs.needs_infer() + && !trait_ref.skip_binder().substs.has_skol() + ); WhereClausePick(trait_ref.clone()) } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index d8907866467..2dc7c7fe71a 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -19,7 +19,7 @@ use hir::def::Def; use hir::def_id::{CRATE_DEF_INDEX, DefId}; use middle::lang_items::FnOnceTraitLangItem; use namespace::Namespace; -use rustc::traits::{Obligation, SelectionContext}; +use rustc::traits::Obligation; use util::nodemap::FxHashSet; use syntax::ast; @@ -65,7 +65,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.body_id, self.param_env, poly_trait_ref.to_predicate()); - SelectionContext::new(self).evaluate_obligation(&obligation) + self.predicate_may_hold(&obligation) }) }) } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 787df7c6479..db859e42057 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -124,7 +124,7 @@ use syntax::attr; use syntax::codemap::{original_sp, Spanned}; use syntax::feature_gate::{GateIssue, emit_feature_err}; use syntax::ptr::P; -use syntax::symbol::{Symbol, InternedString, keywords}; +use syntax::symbol::{Symbol, LocalInternedString, keywords}; use syntax::util::lev_distance::find_best_match_for_name; use syntax_pos::{self, BytePos, Span, MultiSpan}; @@ -3172,7 +3172,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Return an hint about the closest match in field names fn suggest_field_name(variant: &'tcx ty::VariantDef, field: &Spanned<ast::Name>, - skip: Vec<InternedString>) + skip: Vec<LocalInternedString>) -> Option<Symbol> { let name = field.node.as_str(); let names = variant.fields.iter().filter_map(|field| { diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index b5e862fac95..e7e70a19e49 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -96,6 +96,7 @@ use rustc::ty::adjustment; use std::mem; use std::ops::Deref; +use std::rc::Rc; use rustc_data_structures::sync::Lrc; use syntax::ast; use syntax_pos::Span; @@ -513,7 +514,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { // the adjusted form if there is an adjustment. match cmt_result { Ok(head_cmt) => { - self.check_safety_of_rvalue_destructor_if_necessary(head_cmt, expr.span); + self.check_safety_of_rvalue_destructor_if_necessary(&head_cmt, expr.span); } Err(..) => { self.tcx.sess.delay_span_bug(expr.span, "cat_expr Errd"); @@ -799,7 +800,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { /// Invoked on any adjustments that occur. Checks that if this is a region pointer being /// dereferenced, the lifetime of the pointer includes the deref expr. - fn constrain_adjustments(&mut self, expr: &hir::Expr) -> mc::McResult<mc::cmt<'tcx>> { + fn constrain_adjustments(&mut self, expr: &hir::Expr) -> mc::McResult<mc::cmt_<'tcx>> { debug!("constrain_adjustments(expr={:?})", expr); let mut cmt = self.with_mc(|mc| mc.cat_expr_unadjusted(expr))?; @@ -814,7 +815,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // If necessary, constrain destructors in the unadjusted form of this // expression. - self.check_safety_of_rvalue_destructor_if_necessary(cmt.clone(), expr.span); + self.check_safety_of_rvalue_destructor_if_necessary(&cmt, expr.span); let expr_region = self.tcx.mk_region(ty::ReScope( region::Scope::Node(expr.hir_id.local_id))); @@ -837,7 +838,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { }); self.link_region(expr.span, deref.region, - ty::BorrowKind::from_mutbl(deref.mutbl), cmt.clone()); + ty::BorrowKind::from_mutbl(deref.mutbl), &cmt); // Specialized version of constrain_call. self.type_must_outlive(infer::CallRcvr(expr.span), @@ -847,7 +848,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { } if let adjustment::Adjust::Borrow(ref autoref) = adjustment.kind { - self.link_autoref(expr, cmt.clone(), autoref); + self.link_autoref(expr, &cmt, autoref); // Require that the resulting region encompasses // the current node. @@ -878,7 +879,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { } fn check_safety_of_rvalue_destructor_if_necessary(&mut self, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, span: Span) { match cmt.cat { Categorization::Rvalue(region) => { @@ -980,7 +981,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { debug!("link_addr_of: cmt={:?}", cmt); - self.link_region_from_node_type(expr.span, expr.hir_id, mutability, cmt); + self.link_region_from_node_type(expr.span, expr.hir_id, mutability, &cmt); } /// Computes the guarantors for any ref bindings in a `let` and @@ -992,7 +993,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { None => { return; } Some(ref expr) => &**expr, }; - let discr_cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(init_expr))); + let discr_cmt = Rc::new(ignore_err!(self.with_mc(|mc| mc.cat_expr(init_expr)))); self.link_pattern(discr_cmt, &local.pat); } @@ -1001,7 +1002,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { /// linked to the lifetime of its guarantor (if any). fn link_match(&self, discr: &hir::Expr, arms: &[hir::Arm]) { debug!("regionck::for_match()"); - let discr_cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(discr))); + let discr_cmt = Rc::new(ignore_err!(self.with_mc(|mc| mc.cat_expr(discr)))); debug!("discr_cmt={:?}", discr_cmt); for arm in arms { for root_pat in &arm.pats { @@ -1019,7 +1020,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { let arg_ty = self.node_ty(arg.hir_id); let re_scope = self.tcx.mk_region(ty::ReScope(body_scope)); let arg_cmt = self.with_mc(|mc| { - mc.cat_rvalue(arg.id, arg.pat.span, re_scope, arg_ty) + Rc::new(mc.cat_rvalue(arg.id, arg.pat.span, re_scope, arg_ty)) }); debug!("arg_ty={:?} arg_cmt={:?} arg={:?}", arg_ty, @@ -1044,7 +1045,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { .expect("missing binding mode"); if let ty::BindByReference(mutbl) = bm { self.link_region_from_node_type(sub_pat.span, sub_pat.hir_id, - mutbl, sub_cmt); + mutbl, &sub_cmt); } } _ => {} @@ -1057,15 +1058,14 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { /// autoref'd. fn link_autoref(&self, expr: &hir::Expr, - expr_cmt: mc::cmt<'tcx>, + expr_cmt: &mc::cmt_<'tcx>, autoref: &adjustment::AutoBorrow<'tcx>) { debug!("link_autoref(autoref={:?}, expr_cmt={:?})", autoref, expr_cmt); match *autoref { adjustment::AutoBorrow::Ref(r, m) => { - self.link_region(expr.span, r, - ty::BorrowKind::from_mutbl(m.into()), expr_cmt); + self.link_region(expr.span, r, ty::BorrowKind::from_mutbl(m.into()), expr_cmt); } adjustment::AutoBorrow::RawPtr(m) => { @@ -1081,15 +1081,14 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { span: Span, id: hir::HirId, mutbl: hir::Mutability, - cmt_borrowed: mc::cmt<'tcx>) { + cmt_borrowed: &mc::cmt_<'tcx>) { debug!("link_region_from_node_type(id={:?}, mutbl={:?}, cmt_borrowed={:?})", id, mutbl, cmt_borrowed); let rptr_ty = self.resolve_node_type(id); if let ty::TyRef(r, _) = rptr_ty.sty { debug!("rptr_ty={}", rptr_ty); - self.link_region(span, r, ty::BorrowKind::from_mutbl(mutbl), - cmt_borrowed); + self.link_region(span, r, ty::BorrowKind::from_mutbl(mutbl), cmt_borrowed); } } @@ -1101,19 +1100,19 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { span: Span, borrow_region: ty::Region<'tcx>, borrow_kind: ty::BorrowKind, - borrow_cmt: mc::cmt<'tcx>) { - let mut borrow_cmt = borrow_cmt; - let mut borrow_kind = borrow_kind; - + borrow_cmt: &mc::cmt_<'tcx>) { let origin = infer::DataBorrowed(borrow_cmt.ty, span); self.type_must_outlive(origin, borrow_cmt.ty, borrow_region); + let mut borrow_kind = borrow_kind; + let mut borrow_cmt_cat = borrow_cmt.cat.clone(); + loop { debug!("link_region(borrow_region={:?}, borrow_kind={:?}, borrow_cmt={:?})", borrow_region, borrow_kind, borrow_cmt); - match borrow_cmt.cat.clone() { + match borrow_cmt_cat { Categorization::Deref(ref_cmt, mc::Implicit(ref_kind, ref_region)) | Categorization::Deref(ref_cmt, mc::BorrowedPtr(ref_kind, ref_region)) => { match self.link_reborrowed_region(span, @@ -1121,7 +1120,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { ref_cmt, ref_region, ref_kind, borrow_cmt.note) { Some((c, k)) => { - borrow_cmt = c; + borrow_cmt_cat = c.cat.clone(); borrow_kind = k; } None => { @@ -1135,7 +1134,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { Categorization::Interior(cmt_base, _) => { // Borrowing interior or owned data requires the base // to be valid and borrowable in the same fashion. - borrow_cmt = cmt_base; + borrow_cmt_cat = cmt_base.cat.clone(); borrow_kind = borrow_kind; } diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 4fc3344dab2..58dc5839578 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -298,7 +298,8 @@ struct InferBorrowKind<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { } impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { - fn adjust_upvar_borrow_kind_for_consume(&mut self, cmt: mc::cmt<'tcx>, mode: euv::ConsumeMode) { + fn adjust_upvar_borrow_kind_for_consume(&mut self, cmt: &mc::cmt_<'tcx>, + mode: euv::ConsumeMode) { debug!( "adjust_upvar_borrow_kind_for_consume(cmt={:?}, mode={:?})", cmt, @@ -377,7 +378,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { /// Indicates that `cmt` is being directly mutated (e.g., assigned /// to). If cmt contains any by-ref upvars, this implies that /// those upvars must be borrowed using an `&mut` borrow. - fn adjust_upvar_borrow_kind_for_mut(&mut self, cmt: mc::cmt<'tcx>) { + fn adjust_upvar_borrow_kind_for_mut(&mut self, cmt: &mc::cmt_<'tcx>) { debug!("adjust_upvar_borrow_kind_for_mut(cmt={:?})", cmt); match cmt.cat.clone() { @@ -386,7 +387,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { Categorization::Downcast(base, _) => { // Interior or owned data is mutable if base is // mutable, so iterate to the base. - self.adjust_upvar_borrow_kind_for_mut(base); + self.adjust_upvar_borrow_kind_for_mut(&base); } Categorization::Deref(base, mc::BorrowedPtr(..)) | @@ -396,7 +397,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { // borrowed pointer implies that the // pointer itself must be unique, but not // necessarily *mutable* - self.adjust_upvar_borrow_kind_for_unique(base); + self.adjust_upvar_borrow_kind_for_unique(&base); } } @@ -410,7 +411,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { } } - fn adjust_upvar_borrow_kind_for_unique(&mut self, cmt: mc::cmt<'tcx>) { + fn adjust_upvar_borrow_kind_for_unique(&mut self, cmt: &mc::cmt_<'tcx>) { debug!("adjust_upvar_borrow_kind_for_unique(cmt={:?})", cmt); match cmt.cat.clone() { @@ -419,7 +420,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { Categorization::Downcast(base, _) => { // Interior or owned data is unique if base is // unique. - self.adjust_upvar_borrow_kind_for_unique(base); + self.adjust_upvar_borrow_kind_for_unique(&base); } Categorization::Deref(base, mc::BorrowedPtr(..)) | @@ -427,7 +428,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { if !self.try_adjust_upvar_deref(cmt, ty::UniqueImmBorrow) { // for a borrowed pointer to be unique, its // base must be unique - self.adjust_upvar_borrow_kind_for_unique(base); + self.adjust_upvar_borrow_kind_for_unique(&base); } } @@ -439,7 +440,9 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { } } - fn try_adjust_upvar_deref(&mut self, cmt: mc::cmt<'tcx>, borrow_kind: ty::BorrowKind) -> bool { + fn try_adjust_upvar_deref(&mut self, cmt: &mc::cmt_<'tcx>, borrow_kind: ty::BorrowKind) + -> bool + { assert!(match borrow_kind { ty::MutBorrow => true, ty::UniqueImmBorrow => true, @@ -581,17 +584,19 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'gcx, 'tcx> { &mut self, _consume_id: ast::NodeId, _consume_span: Span, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, mode: euv::ConsumeMode, ) { debug!("consume(cmt={:?},mode={:?})", cmt, mode); self.adjust_upvar_borrow_kind_for_consume(cmt, mode); } - fn matched_pat(&mut self, _matched_pat: &hir::Pat, _cmt: mc::cmt<'tcx>, _mode: euv::MatchMode) { + fn matched_pat(&mut self, _matched_pat: &hir::Pat, _cmt: &mc::cmt_<'tcx>, + _mode: euv::MatchMode) { } - fn consume_pat(&mut self, _consume_pat: &hir::Pat, cmt: mc::cmt<'tcx>, mode: euv::ConsumeMode) { + fn consume_pat(&mut self, _consume_pat: &hir::Pat, cmt: &mc::cmt_<'tcx>, + mode: euv::ConsumeMode) { debug!("consume_pat(cmt={:?},mode={:?})", cmt, mode); self.adjust_upvar_borrow_kind_for_consume(cmt, mode); } @@ -600,7 +605,7 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'gcx, 'tcx> { &mut self, borrow_id: ast::NodeId, _borrow_span: Span, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, _loan_region: ty::Region<'tcx>, bk: ty::BorrowKind, _loan_cause: euv::LoanCause, @@ -629,7 +634,7 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'gcx, 'tcx> { &mut self, _assignment_id: ast::NodeId, _assignment_span: Span, - assignee_cmt: mc::cmt<'tcx>, + assignee_cmt: &mc::cmt_<'tcx>, _mode: euv::MutateMode, ) { debug!("mutate(assignee_cmt={:?})", assignee_cmt); diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 9c4807bec2f..d0ff44c8e7e 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -655,7 +655,7 @@ fn reject_shadowing_type_parameters(tcx: TyCtxt, def_id: DefId) { // local so it should be okay to just unwrap everything. let trait_def_id = impl_params[&method_param.name]; let trait_decl_span = tcx.def_span(trait_def_id); - error_194(tcx, type_span, trait_decl_span, &method_param.name[..]); + error_194(tcx, type_span, trait_decl_span, &method_param.name.as_str()[..]); } } } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 6e0d7dd8508..802e5375b6b 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -107,7 +107,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { fn write_ty_to_tables(&mut self, hir_id: hir::HirId, ty: Ty<'gcx>) { debug!("write_ty_to_tables({:?}, {:?})", hir_id, ty); - assert!(!ty.needs_infer()); + assert!(!ty.needs_infer() && !ty.has_skol()); self.tables.node_types_mut().insert(hir_id, ty); } @@ -431,7 +431,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { if let Some(substs) = self.fcx.tables.borrow().node_substs_opt(hir_id) { let substs = self.resolve(&substs, &span); debug!("write_substs_to_tcx({:?}, {:?})", hir_id, substs); - assert!(!substs.needs_infer()); + assert!(!substs.needs_infer() && !substs.has_skol()); self.tables.node_substs_mut().insert(hir_id, substs); } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 2ebbd64cab9..1b8f2e661c3 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -244,7 +244,7 @@ fn type_param_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let param_owner_def_id = tcx.hir.local_def_id(param_owner); let generics = tcx.generics_of(param_owner_def_id); let index = generics.type_param_to_index[&def_id]; - let ty = tcx.mk_param(index, tcx.hir.ty_param_name(param_id).as_str()); + let ty = tcx.mk_param(index, tcx.hir.ty_param_name(param_id).as_interned_str()); // Don't look for bounds where the type parameter isn't in scope. let parent = if item_def_id == param_owner_def_id { @@ -842,7 +842,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, opt_self = Some(ty::TypeParameterDef { index: 0, - name: keywords::SelfType.name().as_str(), + name: keywords::SelfType.name().as_interned_str(), def_id: tcx.hir.local_def_id(param_id), has_default: false, object_lifetime_default: rl::Set1::Empty, @@ -888,7 +888,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let early_lifetimes = early_bound_lifetimes_from_generics(tcx, ast_generics); let regions = early_lifetimes.enumerate().map(|(i, l)| { ty::RegionParameterDef { - name: l.lifetime.name.name().as_str(), + name: l.lifetime.name.name().as_interned_str(), index: own_start + i as u32, def_id: tcx.hir.local_def_id(l.lifetime.id), pure_wrt_drop: l.pure_wrt_drop, @@ -918,7 +918,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::TypeParameterDef { index: type_start + i as u32, - name: p.name.as_str(), + name: p.name.as_interned_str(), def_id: tcx.hir.local_def_id(p.id), has_default: p.default.is_some(), object_lifetime_default: @@ -937,7 +937,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // add a dummy parameter for the closure kind types.push(ty::TypeParameterDef { index: type_start, - name: Symbol::intern("<closure_kind>").as_str(), + name: Symbol::intern("<closure_kind>").as_interned_str(), def_id, has_default: false, object_lifetime_default: rl::Set1::Empty, @@ -948,7 +948,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // add a dummy parameter for the closure signature types.push(ty::TypeParameterDef { index: type_start + 1, - name: Symbol::intern("<closure_signature>").as_str(), + name: Symbol::intern("<closure_signature>").as_interned_str(), def_id, has_default: false, object_lifetime_default: rl::Set1::Empty, @@ -959,7 +959,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.with_freevars(node_id, |fv| { types.extend(fv.iter().zip(2..).map(|(_, i)| ty::TypeParameterDef { index: type_start + i, - name: Symbol::intern("<upvar>").as_str(), + name: Symbol::intern("<upvar>").as_interned_str(), def_id, has_default: false, object_lifetime_default: rl::Set1::Empty, @@ -1429,7 +1429,7 @@ pub fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let region = tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { def_id: tcx.hir.local_def_id(param.lifetime.id), index, - name: param.lifetime.name.name().as_str(), + name: param.lifetime.name.name().as_interned_str(), })); index += 1; @@ -1443,7 +1443,7 @@ pub fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Collect the predicates that were written inline by the user on each // type parameter (e.g., `<T:Foo>`). for param in ast_generics.ty_params() { - let param_ty = ty::ParamTy::new(index, param.name.as_str()).to_ty(tcx); + let param_ty = ty::ParamTy::new(index, param.name.as_interned_str()).to_ty(tcx); index += 1; let bounds = compute_bounds(&icx, diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 23fe91ffdeb..350b53a406b 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -71,6 +71,8 @@ This API is completely unstable and subject to change. #![allow(non_camel_case_types)] +#![cfg_attr(stage0, feature(dyn_trait))] + #![feature(box_patterns)] #![feature(box_syntax)] #![feature(crate_visibility_modifier)] @@ -81,7 +83,6 @@ This API is completely unstable and subject to change. #![feature(rustc_diagnostic_macros)] #![feature(slice_patterns)] #![feature(slice_sort_by_cached_key)] -#![feature(dyn_trait)] #![feature(never_type)] #[macro_use] extern crate log; @@ -91,7 +92,6 @@ extern crate syntax_pos; extern crate arena; #[macro_use] extern crate rustc; extern crate rustc_platform_intrinsics as intrinsics; -extern crate rustc_const_math; extern crate rustc_data_structures; extern crate rustc_errors as errors; extern crate rustc_target; diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 477b576ad21..221fc4dab72 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -224,7 +224,7 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> { let name = if p.name == "" { hir::LifetimeName::Static } else { - hir::LifetimeName::Name(Symbol::intern(&p.name)) + hir::LifetimeName::Name(p.name.as_symbol()) }; hir::Lifetime { @@ -261,7 +261,7 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> { span: DUMMY_SP, def: Def::TyParam(param.def_id), segments: HirVec::from_vec(vec![ - hir::PathSegment::from_name(Symbol::intern(¶m.name)) + hir::PathSegment::from_name(param.name.as_symbol()) ]), }), )), diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 7f89b3e6b3a..d5e0f95ddf4 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -67,7 +67,7 @@ impl Cfg { /// If the content is not properly formatted, it will return an error indicating what and where /// the error is. pub fn parse(cfg: &MetaItem) -> Result<Cfg, InvalidCfgError> { - let name = cfg.ident.name; + let name = cfg.name(); match cfg.node { MetaItemKind::Word => Ok(Cfg::Cfg(name, None)), MetaItemKind::NameValue(ref lit) => match lit.node { @@ -436,6 +436,42 @@ mod test { Cfg::Cfg(Symbol::intern(name), Some(Symbol::intern(value))) } + fn dummy_meta_item_word(name: &str) -> MetaItem { + MetaItem { + ident: Path::from_ident(Ident::from_str(name)), + node: MetaItemKind::Word, + span: DUMMY_SP, + } + } + + macro_rules! dummy_meta_item_list { + ($name:ident, [$($list:ident),* $(,)*]) => { + MetaItem { + ident: Path::from_ident(Ident::from_str(stringify!($name))), + node: MetaItemKind::List(vec![ + $( + dummy_spanned(NestedMetaItemKind::MetaItem( + dummy_meta_item_word(stringify!($list)), + )), + )* + ]), + span: DUMMY_SP, + } + }; + + ($name:ident, [$($list:expr),* $(,)*]) => { + MetaItem { + ident: Path::from_ident(Ident::from_str(stringify!($name))), + node: MetaItemKind::List(vec![ + $( + dummy_spanned(NestedMetaItemKind::MetaItem($list)), + )* + ]), + span: DUMMY_SP, + } + }; + } + #[test] fn test_cfg_not() { with_globals(|| { @@ -561,15 +597,11 @@ mod test { #[test] fn test_parse_ok() { with_globals(|| { - let mi = MetaItem { - ident: Ident::from_str("all"), - node: MetaItemKind::Word, - span: DUMMY_SP, - }; + let mi = dummy_meta_item_word("all"); assert_eq!(Cfg::parse(&mi), Ok(word_cfg("all"))); let mi = MetaItem { - ident: Ident::from_str("all"), + ident: Path::from_ident(Ident::from_str("all")), node: MetaItemKind::NameValue(dummy_spanned(LitKind::Str( Symbol::intern("done"), StrStyle::Cooked, @@ -578,111 +610,24 @@ mod test { }; assert_eq!(Cfg::parse(&mi), Ok(name_value_cfg("all", "done"))); - let mi = MetaItem { - ident: Ident::from_str("all"), - node: MetaItemKind::List(vec![ - dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { - ident: Ident::from_str("a"), - node: MetaItemKind::Word, - span: DUMMY_SP, - })), - dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { - ident: Ident::from_str("b"), - node: MetaItemKind::Word, - span: DUMMY_SP, - })), - ]), - span: DUMMY_SP, - }; + let mi = dummy_meta_item_list!(all, [a, b]); assert_eq!(Cfg::parse(&mi), Ok(word_cfg("a") & word_cfg("b"))); - let mi = MetaItem { - ident: Ident::from_str("any"), - node: MetaItemKind::List(vec![ - dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { - ident: Ident::from_str("a"), - node: MetaItemKind::Word, - span: DUMMY_SP, - })), - dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { - ident: Ident::from_str("b"), - node: MetaItemKind::Word, - span: DUMMY_SP, - })), - ]), - span: DUMMY_SP, - }; + let mi = dummy_meta_item_list!(any, [a, b]); assert_eq!(Cfg::parse(&mi), Ok(word_cfg("a") | word_cfg("b"))); - let mi = MetaItem { - ident: Ident::from_str("not"), - node: MetaItemKind::List(vec![ - dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { - ident: Ident::from_str("a"), - node: MetaItemKind::Word, - span: DUMMY_SP, - })), - ]), - span: DUMMY_SP, - }; + let mi = dummy_meta_item_list!(not, [a]); assert_eq!(Cfg::parse(&mi), Ok(!word_cfg("a"))); - let mi = MetaItem { - ident: Ident::from_str("not"), - node: MetaItemKind::List(vec![ - dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { - ident: Ident::from_str("any"), - node: MetaItemKind::List(vec![ - dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { - ident: Ident::from_str("a"), - node: MetaItemKind::Word, - span: DUMMY_SP, - })), - dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { - ident: Ident::from_str("all"), - node: MetaItemKind::List(vec![ - dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { - ident: Ident::from_str("b"), - node: MetaItemKind::Word, - span: DUMMY_SP, - })), - dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { - ident: Ident::from_str("c"), - node: MetaItemKind::Word, - span: DUMMY_SP, - })), - ]), - span: DUMMY_SP, - })), - ]), - span: DUMMY_SP, - })), + let mi = dummy_meta_item_list!(not, [ + dummy_meta_item_list!(any, [ + dummy_meta_item_word("a"), + dummy_meta_item_list!(all, [b, c]), ]), - span: DUMMY_SP, - }; + ]); assert_eq!(Cfg::parse(&mi), Ok(!(word_cfg("a") | (word_cfg("b") & word_cfg("c"))))); - let mi = MetaItem { - ident: Ident::from_str("all"), - node: MetaItemKind::List(vec![ - dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { - ident: Ident::from_str("a"), - node: MetaItemKind::Word, - span: DUMMY_SP, - })), - dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { - ident: Ident::from_str("b"), - node: MetaItemKind::Word, - span: DUMMY_SP, - })), - dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { - ident: Ident::from_str("c"), - node: MetaItemKind::Word, - span: DUMMY_SP, - })), - ]), - span: DUMMY_SP, - }; + let mi = dummy_meta_item_list!(all, [a, b, c]); assert_eq!(Cfg::parse(&mi), Ok(word_cfg("a") & word_cfg("b") & word_cfg("c"))); }) } @@ -691,97 +636,36 @@ mod test { fn test_parse_err() { with_globals(|| { let mi = MetaItem { - ident: Ident::from_str("foo"), + ident: Path::from_ident(Ident::from_str("foo")), node: MetaItemKind::NameValue(dummy_spanned(LitKind::Bool(false))), span: DUMMY_SP, }; assert!(Cfg::parse(&mi).is_err()); - let mi = MetaItem { - ident: Ident::from_str("not"), - node: MetaItemKind::List(vec![ - dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { - ident: Ident::from_str("a"), - node: MetaItemKind::Word, - span: DUMMY_SP, - })), - dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { - ident: Ident::from_str("b"), - node: MetaItemKind::Word, - span: DUMMY_SP, - })), - ]), - span: DUMMY_SP, - }; + let mi = dummy_meta_item_list!(not, [a, b]); assert!(Cfg::parse(&mi).is_err()); - let mi = MetaItem { - ident: Ident::from_str("not"), - node: MetaItemKind::List(vec![]), - span: DUMMY_SP, - }; + let mi = dummy_meta_item_list!(not, []); assert!(Cfg::parse(&mi).is_err()); - let mi = MetaItem { - ident: Ident::from_str("foo"), - node: MetaItemKind::List(vec![ - dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { - ident: Ident::from_str("a"), - node: MetaItemKind::Word, - span: DUMMY_SP, - })), - ]), - span: DUMMY_SP, - }; + let mi = dummy_meta_item_list!(foo, []); assert!(Cfg::parse(&mi).is_err()); - let mi = MetaItem { - ident: Ident::from_str("all"), - node: MetaItemKind::List(vec![ - dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { - ident: Ident::from_str("foo"), - node: MetaItemKind::List(vec![]), - span: DUMMY_SP, - })), - dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { - ident: Ident::from_str("b"), - node: MetaItemKind::Word, - span: DUMMY_SP, - })), - ]), - span: DUMMY_SP, - }; + let mi = dummy_meta_item_list!(all, [ + dummy_meta_item_list!(foo, []), + dummy_meta_item_word("b"), + ]); assert!(Cfg::parse(&mi).is_err()); - let mi = MetaItem { - ident: Ident::from_str("any"), - node: MetaItemKind::List(vec![ - dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { - ident: Ident::from_str("a"), - node: MetaItemKind::Word, - span: DUMMY_SP, - })), - dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { - ident: Ident::from_str("foo"), - node: MetaItemKind::List(vec![]), - span: DUMMY_SP, - })), - ]), - span: DUMMY_SP, - }; + let mi = dummy_meta_item_list!(any, [ + dummy_meta_item_word("a"), + dummy_meta_item_list!(foo, []), + ]); assert!(Cfg::parse(&mi).is_err()); - let mi = MetaItem { - ident: Ident::from_str("not"), - node: MetaItemKind::List(vec![ - dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { - ident: Ident::from_str("foo"), - node: MetaItemKind::List(vec![]), - span: DUMMY_SP, - })), - ]), - span: DUMMY_SP, - }; + let mi = dummy_meta_item_list!(not, [ + dummy_meta_item_list!(foo, []), + ]); assert!(Cfg::parse(&mi).is_err()); }) } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index fb05cbfe32c..edbf5f3abd2 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1367,7 +1367,7 @@ impl TyParamBound { fn maybe_sized(cx: &DocContext) -> TyParamBound { let did = cx.tcx.require_lang_item(lang_items::SizedTraitLangItem); let empty = cx.tcx.intern_substs(&[]); - let path = external_path(cx, &cx.tcx.item_name(did), + let path = external_path(cx, &cx.tcx.item_name(did).as_str(), Some(did), false, vec![], empty); inline::record_extern_fqn(cx, did, TypeKind::Trait); TraitBound(PolyTrait { @@ -1474,7 +1474,7 @@ impl<'a, 'tcx> Clean<TyParamBound> for (&'a ty::TraitRef<'tcx>, Vec<TypeBinding> fn clean(&self, cx: &DocContext) -> TyParamBound { let (trait_ref, ref bounds) = *self; inline::record_extern_fqn(cx, trait_ref.def_id, TypeKind::Trait); - let path = external_path(cx, &cx.tcx.item_name(trait_ref.def_id), + let path = external_path(cx, &cx.tcx.item_name(trait_ref.def_id).as_str(), Some(trait_ref.def_id), true, bounds.clone(), trait_ref.substs); debug!("ty::TraitRef\n subst: {:?}\n", trait_ref.substs); @@ -1755,8 +1755,18 @@ pub struct Generics { impl Clean<Generics> for hir::Generics { fn clean(&self, cx: &DocContext) -> Generics { + let mut params = Vec::with_capacity(self.params.len()); + for p in &self.params { + let p = p.clean(cx); + if let GenericParam::Type(ref tp) = p { + if tp.synthetic == Some(hir::SyntheticTyParamKind::ImplTrait) { + cx.impl_trait_bounds.borrow_mut().insert(tp.did, tp.bounds.clone()); + } + } + params.push(p); + } let mut g = Generics { - params: self.params.clean(cx), + params, where_predicates: self.where_clause.predicates.clean(cx) }; @@ -1869,9 +1879,11 @@ pub struct Method { impl<'a> Clean<Method> for (&'a hir::MethodSig, &'a hir::Generics, hir::BodyId) { fn clean(&self, cx: &DocContext) -> Method { - let generics = self.1.clean(cx); + let (generics, decl) = enter_impl_trait(cx, || { + (self.1.clean(cx), (&*self.0.decl, self.2).clean(cx)) + }); Method { - decl: enter_impl_trait(cx, &generics.params, || (&*self.0.decl, self.2).clean(cx)), + decl, generics, unsafety: self.0.unsafety, constness: self.0.constness, @@ -1899,8 +1911,9 @@ pub struct Function { impl Clean<Item> for doctree::Function { fn clean(&self, cx: &DocContext) -> Item { - let generics = self.generics.clean(cx); - let decl = enter_impl_trait(cx, &generics.params, || (&self.decl, self.body).clean(cx)); + let (generics, decl) = enter_impl_trait(cx, || { + (self.generics.clean(cx), (&self.decl, self.body).clean(cx)) + }); Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), @@ -2139,12 +2152,12 @@ impl Clean<Item> for hir::TraitItem { MethodItem((sig, &self.generics, body).clean(cx)) } hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(ref names)) => { - let generics = self.generics.clean(cx); + let (generics, decl) = enter_impl_trait(cx, || { + (self.generics.clean(cx), (&*sig.decl, &names[..]).clean(cx)) + }); TyMethodItem(TyMethod { unsafety: sig.unsafety.clone(), - decl: enter_impl_trait(cx, &generics.params, || { - (&*sig.decl, &names[..]).clean(cx) - }), + decl, generics, abi: sig.abi }) @@ -2801,7 +2814,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> { AdtKind::Enum => TypeKind::Enum, }; inline::record_extern_fqn(cx, did, kind); - let path = external_path(cx, &cx.tcx.item_name(did), + let path = external_path(cx, &cx.tcx.item_name(did).as_str(), None, false, vec![], substs); ResolvedPath { path, @@ -2812,7 +2825,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> { } ty::TyForeign(did) => { inline::record_extern_fqn(cx, did, TypeKind::Foreign); - let path = external_path(cx, &cx.tcx.item_name(did), + let path = external_path(cx, &cx.tcx.item_name(did).as_str(), None, false, vec![], Substs::empty()); ResolvedPath { path: path, @@ -2830,7 +2843,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> { reg.clean(cx).map(|b| typarams.push(RegionBound(b))); for did in obj.auto_traits() { let empty = cx.tcx.intern_substs(&[]); - let path = external_path(cx, &cx.tcx.item_name(did), + let path = external_path(cx, &cx.tcx.item_name(did).as_str(), Some(did), false, vec![], empty); inline::record_extern_fqn(cx, did, TypeKind::Trait); let bound = TraitBound(PolyTrait { @@ -2853,7 +2866,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> { }); } - let path = external_path(cx, &cx.tcx.item_name(did), Some(did), + let path = external_path(cx, &cx.tcx.item_name(did).as_str(), Some(did), false, bindings, principal.skip_binder().substs); ResolvedPath { path, @@ -3415,12 +3428,12 @@ pub struct BareFunctionDecl { impl Clean<BareFunctionDecl> for hir::BareFnTy { fn clean(&self, cx: &DocContext) -> BareFunctionDecl { - let generic_params = self.generic_params.clean(cx); + let (generic_params, decl) = enter_impl_trait(cx, || { + (self.generic_params.clean(cx), (&*self.decl, &self.arg_names[..]).clean(cx)) + }); BareFunctionDecl { unsafety: self.unsafety, - decl: enter_impl_trait(cx, &generic_params, || { - (&*self.decl, &self.arg_names[..]).clean(cx) - }), + decl, generic_params, abi: self.abi, } @@ -3661,7 +3674,7 @@ impl Clean<Vec<Item>> for doctree::Import { // #[doc(no_inline)] attribute is present. // Don't inline doc(hidden) imports so they can be stripped at a later stage. let denied = self.vis != hir::Public || self.attrs.iter().any(|a| { - a.name().unwrap() == "doc" && match a.meta_item_list() { + a.name() == "doc" && match a.meta_item_list() { Some(l) => attr::list_contains_name(&l, "no_inline") || attr::list_contains_name(&l, "hidden"), None => false, @@ -3722,11 +3735,11 @@ impl Clean<Item> for hir::ForeignItem { fn clean(&self, cx: &DocContext) -> Item { let inner = match self.node { hir::ForeignItemFn(ref decl, ref names, ref generics) => { - let generics = generics.clean(cx); + let (generics, decl) = enter_impl_trait(cx, || { + (generics.clean(cx), (&**decl, &names[..]).clean(cx)) + }); ForeignFunctionItem(Function { - decl: enter_impl_trait(cx, &generics.params, || { - (&**decl, &names[..]).clean(cx) - }), + decl, generics, unsafety: hir::Unsafety::Unsafe, abi: Abi::Rust, @@ -3881,6 +3894,7 @@ fn register_def(cx: &DocContext, def: Def) -> DefId { Def::Union(i) => (i, TypeKind::Union), Def::Mod(i) => (i, TypeKind::Module), Def::TyForeign(i) => (i, TypeKind::Foreign), + Def::Const(i) => (i, TypeKind::Const), Def::Static(i, _) => (i, TypeKind::Static), Def::Variant(i) => (cx.tcx.parent_def_id(i).unwrap(), TypeKind::Enum), Def::Macro(i, _) => (i, TypeKind::Macro), @@ -4029,23 +4043,11 @@ pub fn def_id_to_path(cx: &DocContext, did: DefId, name: Option<String>) -> Vec< once(crate_name).chain(relative).collect() } -pub fn enter_impl_trait<F, R>(cx: &DocContext, gps: &[GenericParam], f: F) -> R +pub fn enter_impl_trait<F, R>(cx: &DocContext, f: F) -> R where F: FnOnce() -> R, { - let bounds = gps.iter() - .filter_map(|p| { - if let GenericParam::Type(ref tp) = *p { - if tp.synthetic == Some(hir::SyntheticTyParamKind::ImplTrait) { - return Some((tp.did, tp.bounds.clone())); - } - } - - None - }) - .collect::<FxHashMap<DefId, Vec<TyParamBound>>>(); - - let old_bounds = mem::replace(&mut *cx.impl_trait_bounds.borrow_mut(), bounds); + let old_bounds = mem::replace(&mut *cx.impl_trait_bounds.borrow_mut(), Default::default()); let r = f(); assert!(cx.impl_trait_bounds.borrow().is_empty()); *cx.impl_trait_bounds.borrow_mut() = old_bounds; diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index d423203b996..61fb0b40c23 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -177,7 +177,7 @@ pub fn run_core(search_paths: SearchPaths, None, codemap.clone(), pretty, - sessopts.debugging_opts.approximate_suggestions, + sessopts.debugging_opts.suggestion_applicability, ).ui_testing(sessopts.debugging_opts.ui_testing) ), ErrorOutputType::Short(color_config) => Box::new( diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index fd54e9bd1e0..5e93b20ea17 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -146,9 +146,9 @@ pub fn render<T: fmt::Display, S: fmt::Display>( window.rootPath = \"{root_path}\";\ window.currentCrate = \"{krate}\";\ </script>\ + <script src=\"{root_path}aliases.js\"></script>\ <script src=\"{root_path}main{suffix}.js\"></script>\ <script defer src=\"{root_path}search-index.js\"></script>\ - <script defer src=\"{root_path}aliases.js\"></script>\ </body>\ </html>", css_extension = if css_file_extension { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 82449e9b5f9..21de2db1dfe 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1427,7 +1427,7 @@ impl<'a> Cache { } if let Some(ref item_name) = item.name { let path = self.paths.get(&item.def_id) - .map(|p| p.0.join("::").to_string()) + .map(|p| p.0[..p.0.len() - 1].join("::")) .unwrap_or("std".to_owned()); for alias in item.attrs.lists("doc") .filter(|a| a.check_name("alias")) @@ -1595,6 +1595,8 @@ impl<'a> Settings<'a> { settings: vec![ ("item-declarations", "Auto-hide item declarations.", true), ("item-attributes", "Auto-hide item attributes.", true), + ("go-to-only-result", "Directly go to item in search if there is only one result", + false), ], root_path, suffix, @@ -3282,7 +3284,7 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, } fn render_attribute(attr: &ast::MetaItem) -> Option<String> { - let name = attr.ident.name; + let name = attr.name(); if attr.is_word() { Some(format!("{}", name)) @@ -3317,7 +3319,7 @@ fn render_attributes(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result { let mut attrs = String::new(); for attr in &it.attrs.other_attrs { - let name = attr.name().unwrap(); + let name = attr.name(); if !ATTRIBUTE_WHITELIST.contains(&&*name.as_str()) { continue; } diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 58a57f43d37..6d80145b29c 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -1013,7 +1013,8 @@ 'returned': sortResults(results_returned, true), 'others': sortResults(results), }; - if (ALIASES[window.currentCrate][query.raw]) { + if (ALIASES && ALIASES[window.currentCrate] && + ALIASES[window.currentCrate][query.raw]) { var aliases = ALIASES[window.currentCrate][query.raw]; for (var i = 0; i < aliases.length; ++i) { ret['others'].unshift(aliases[i]); @@ -1188,6 +1189,44 @@ return '<span>' + path.replace(/::/g, '::</span><span>'); } + function buildHrefAndPath(item) { + var displayPath; + var href; + var type = itemTypes[item.ty]; + var name = item.name; + + if (type === 'mod') { + displayPath = item.path + '::'; + href = rootPath + item.path.replace(/::/g, '/') + '/' + + name + '/index.html'; + } else if (type === "primitive") { + displayPath = ""; + href = rootPath + item.path.replace(/::/g, '/') + + '/' + type + '.' + name + '.html'; + } else if (type === "externcrate") { + displayPath = ""; + href = rootPath + name + '/index.html'; + } else if (item.parent !== undefined) { + var myparent = item.parent; + var anchor = '#' + type + '.' + name; + var parentType = itemTypes[myparent.ty]; + if (parentType === "primitive") { + displayPath = myparent.name + '::'; + } else { + displayPath = item.path + '::' + myparent.name + '::'; + } + href = rootPath + item.path.replace(/::/g, '/') + + '/' + parentType + + '.' + myparent.name + + '.html' + anchor; + } else { + displayPath = item.path + '::'; + href = rootPath + item.path.replace(/::/g, '/') + + '/' + type + '.' + name + '.html'; + } + return [displayPath, href]; + } + function addTab(array, query, display) { var extraStyle = ''; if (display === false) { @@ -1211,35 +1250,9 @@ name = item.name; type = itemTypes[item.ty]; - if (type === 'mod') { - displayPath = item.path + '::'; - href = rootPath + item.path.replace(/::/g, '/') + '/' + - name + '/index.html'; - } else if (type === "primitive") { - displayPath = ""; - href = rootPath + item.path.replace(/::/g, '/') + - '/' + type + '.' + name + '.html'; - } else if (type === "externcrate") { - displayPath = ""; - href = rootPath + name + '/index.html'; - } else if (item.parent !== undefined) { - var myparent = item.parent; - var anchor = '#' + type + '.' + name; - var parentType = itemTypes[myparent.ty]; - if (parentType === "primitive") { - displayPath = myparent.name + '::'; - } else { - displayPath = item.path + '::' + myparent.name + '::'; - } - href = rootPath + item.path.replace(/::/g, '/') + - '/' + parentType + - '.' + myparent.name + - '.html' + anchor; - } else { - displayPath = item.path + '::'; - href = rootPath + item.path.replace(/::/g, '/') + - '/' + type + '.' + name + '.html'; - } + var res = buildHrefAndPath(item); + var href = res[1]; + var displayPath = res[0]; output += '<tr class="' + type + ' result"><td>' + '<a href="' + href + '">' + @@ -1268,6 +1281,16 @@ } function showResults(results) { + if (results['others'].length === 1 && + getCurrentValue('rustdoc-go-to-only-result') === "true") { + var elem = document.createElement('a'); + var res = buildHrefAndPath(results['others'][0]); + elem.href = res[1]; + elem.style.display = 'none'; + // For firefox, we need the element to be in the DOM so it can be clicked. + document.body.appendChild(elem); + elem.click(); + } var output, query = getQuery(search_input.value); currentResults = query.id; @@ -1721,6 +1744,9 @@ function toggleAllDocs(pageId) { var toggle = document.getElementById("toggle-all-docs"); + if (!toggle) { + return; + } if (hasClass(toggle, "will-expand")) { updateLocalStorage("rustdoc-collapse", "false"); removeClass(toggle, "will-expand"); @@ -1970,14 +1996,14 @@ if (e.parentNode.id === "main") { var otherMessage; if (hasClass(e, "type-decl")) { - otherMessage = ' Show type declaration'; + otherMessage = ' Show declaration'; } e.parentNode.insertBefore(createToggle(otherMessage), e); if (otherMessage && getCurrentValue('rustdoc-item-declarations') !== "false") { collapseDocs(e.previousSibling.childNodes[0], "toggle"); } } - }) + }); autoCollapseAllImpls(getPageId()); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 614386a583a..059d4169895 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -13,6 +13,8 @@ html_root_url = "https://doc.rust-lang.org/nightly/", html_playground_url = "https://play.rust-lang.org/")] +#![cfg_attr(stage0, feature(dyn_trait))] + #![feature(ascii_ctype)] #![feature(rustc_private)] #![feature(box_patterns)] @@ -23,14 +25,12 @@ #![feature(test)] #![feature(vec_remove_item)] #![feature(entry_and_modify)] -#![feature(dyn_trait)] extern crate arena; extern crate getopts; extern crate env_logger; extern crate rustc; extern crate rustc_data_structures; -extern crate rustc_const_math; extern crate rustc_trans_utils; extern crate rustc_driver; extern crate rustc_resolve; diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 967c50e62db..6db02cc6cc1 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -49,7 +49,6 @@ pub struct RustdocVisitor<'a, 'tcx: 'a, 'rcx: 'a> { inlining: bool, /// Is the current module and all of its parents public? inside_public_path: bool, - reexported_macros: FxHashSet<DefId>, exact_paths: Option<FxHashMap<DefId, Vec<String>>>, } @@ -66,7 +65,6 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { view_item_stack: stack, inlining: false, inside_public_path: true, - reexported_macros: FxHashSet(), exact_paths: Some(FxHashMap()), cstore, } @@ -221,7 +219,7 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { if let Some(exports) = self.cx.tcx.module_exports(def_id) { for export in exports.iter().filter(|e| e.vis == Visibility::Public) { if let Def::Macro(def_id, ..) = export.def { - if def_id.krate == LOCAL_CRATE || self.reexported_macros.contains(&def_id) { + if def_id.krate == LOCAL_CRATE { continue // These are `krate.exported_macros`, handled in `self.visit()`. } @@ -298,17 +296,6 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { let is_no_inline = use_attrs.lists("doc").has_word("no_inline") || use_attrs.lists("doc").has_word("hidden"); - // Memoize the non-inlined `pub use`'d macros so we don't push an extra - // declaration in `visit_mod_contents()` - if !def_did.is_local() { - if let Def::Macro(did, _) = def { - if please_inline { return true } - debug!("memoizing non-inlined macro export: {:?}", def); - self.reexported_macros.insert(did); - return false; - } - } - // For cross-crate impl inlining we need to know whether items are // reachable in documentation - a previously nonreachable item can be // made reachable by cross-crate inlining which we're checking here. diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index a8c70489f44..a7eb002d5a1 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -33,6 +33,7 @@ const MIN_NONZERO_RAW_CAPACITY: usize = 32; // must be a power of two struct DefaultResizePolicy; impl DefaultResizePolicy { + #[inline] fn new() -> DefaultResizePolicy { DefaultResizePolicy } diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 52c53dc3b12..b50652ed6b5 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -79,7 +79,7 @@ impl TaggedHashUintPtr { /// /// Essential invariants of this structure: /// -/// - if t.hashes[i] == EMPTY_BUCKET, then `Bucket::at_index(&t, i).raw` +/// - if `t.hashes[i] == EMPTY_BUCKET`, then `Bucket::at_index(&t, i).raw` /// points to 'undefined' contents. Don't read from it. This invariant is /// enforced outside this module with the `EmptyBucket`, `FullBucket`, /// and `SafeHash` types. diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 749b8ccc13d..817eea5eaf1 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -9,34 +9,6 @@ // except according to those terms. //! Traits for working with Errors. -//! -//! # The `Error` trait -//! -//! `Error` is a trait representing the basic expectations for error values, -//! i.e. values of type `E` in [`Result<T, E>`]. At a minimum, errors must provide -//! a description, but they may optionally provide additional detail (via -//! [`Display`]) and cause chain information: -//! -//! ``` -//! use std::fmt::Display; -//! -//! trait Error: Display { -//! fn description(&self) -> &str; -//! -//! fn cause(&self) -> Option<&Error> { None } -//! } -//! ``` -//! -//! The [`cause`] method is generally used when errors cross "abstraction -//! boundaries", i.e. when a one module must report an error that is "caused" -//! by an error from a lower-level module. This setup makes it possible for the -//! high-level module to provide its own errors that do not commit to any -//! particular implementation, but also reveal some of its implementation for -//! debugging via [`cause`] chains. -//! -//! [`Result<T, E>`]: ../result/enum.Result.html -//! [`Display`]: ../fmt/trait.Display.html -//! [`cause`]: trait.Error.html#method.cause #![stable(feature = "rust1", since = "1.0.0")] @@ -63,33 +35,48 @@ use num; use str; use string; -/// Base functionality for all errors in Rust. +/// `Error` is a trait representing the basic expectations for error values, +/// i.e. values of type `E` in [`Result<T, E>`]. Errors must describe +/// themselves through the [`Display`] and [`Debug`] traits, and may provide +/// cause chain information: +/// +/// The [`cause`] method is generally used when errors cross "abstraction +/// boundaries", i.e. when a one module must report an error that is "caused" +/// by an error from a lower-level module. This setup makes it possible for the +/// high-level module to provide its own errors that do not commit to any +/// particular implementation, but also reveal some of its implementation for +/// debugging via [`cause`] chains. +/// +/// [`Result<T, E>`]: ../result/enum.Result.html +/// [`Display`]: ../fmt/trait.Display.html +/// [`cause`]: trait.Error.html#method.cause #[stable(feature = "rust1", since = "1.0.0")] pub trait Error: Debug + Display { - /// A short description of the error. + /// **This method is soft-deprecated.** /// - /// The description should only be used for a simple message. - /// It should not contain newlines or sentence-ending punctuation, - /// to facilitate embedding in larger user-facing strings. - /// For showing formatted error messages with more information see - /// [`Display`]. + /// Although using it won’t cause compilation warning, + /// new code should use [`Display`] instead + /// and new `impl`s can omit it. + /// + /// To obtain error description as a string, use `to_string()`. /// /// [`Display`]: ../fmt/trait.Display.html /// /// # Examples /// /// ``` - /// use std::error::Error; - /// /// match "xc".parse::<u32>() { /// Err(e) => { - /// println!("Error: {}", e.description()); + /// // Print `e` itself, not `e.description()`. + /// println!("Error: {}", e); /// } /// _ => println!("No error"), /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - fn description(&self) -> &str; + fn description(&self) -> &str { + "description() is deprecated; use Display" + } /// The lower-level cause of this error, if any. /// diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index c88c2bc9137..7c358aafa9b 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -988,6 +988,7 @@ impl CStr { /// behavior when `ptr` is used inside the `unsafe` block: /// /// ```no_run + /// # #![allow(unused_must_use)] /// use std::ffi::{CString}; /// /// let ptr = CString::new("Hello").unwrap().as_ptr(); @@ -1003,6 +1004,7 @@ impl CStr { /// To fix the problem, bind the `CString` to a local variable: /// /// ```no_run + /// # #![allow(unused_must_use)] /// use std::ffi::{CString}; /// /// let hello = CString::new("Hello").unwrap(); @@ -1118,6 +1120,7 @@ impl CStr { /// /// [`Cow`]: ../borrow/enum.Cow.html /// [`Borrowed`]: ../borrow/enum.Cow.html#variant.Borrowed + /// [`Owned`]: ../borrow/enum.Cow.html#variant.Owned /// [`str`]: ../primitive.str.html /// [`String`]: ../string/struct.String.html /// diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 41992193135..d41739ab02c 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -273,7 +273,6 @@ #![feature(libc)] #![feature(link_args)] #![feature(linkage)] -#![feature(macro_reexport)] #![feature(macro_vis_matcher)] #![feature(needs_panic_runtime)] #![feature(never_type)] @@ -313,6 +312,7 @@ #![feature(unboxed_closures)] #![feature(untagged_unions)] #![feature(unwind_attributes)] +#![feature(use_extern_macros)] #![feature(vec_push_all)] #![feature(doc_cfg)] #![feature(doc_masked)] @@ -330,10 +330,10 @@ // with a rustc without jemalloc. // FIXME(#44236) shouldn't need MSVC logic #![cfg_attr(all(not(target_env = "msvc"), - any(stage0, feature = "force_alloc_system")), + any(all(stage0, not(test)), feature = "force_alloc_system")), feature(global_allocator))] #[cfg(all(not(target_env = "msvc"), - any(stage0, feature = "force_alloc_system")))] + any(all(stage0, not(test)), feature = "force_alloc_system")))] #[global_allocator] static ALLOC: alloc_system::System = alloc_system::System; @@ -347,15 +347,14 @@ use prelude::v1::*; #[cfg(test)] extern crate test; #[cfg(test)] extern crate rand; -// We want to re-export a few macros from core but libcore has already been -// imported by the compiler (via our #[no_std] attribute) In this case we just -// add a new crate name so we can attach the re-exports to it. -#[macro_reexport(assert_eq, assert_ne, debug_assert, debug_assert_eq, - debug_assert_ne, unreachable, unimplemented, write, writeln, try)] -extern crate core as __core; +// Re-export a few macros from core +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::{assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::{unreachable, unimplemented, write, writeln, try}; +#[allow(unused_imports)] // macros from `alloc` are not used on all platforms #[macro_use] -#[macro_reexport(vec, format)] extern crate alloc as alloc_crate; extern crate alloc_system; #[doc(masked)] @@ -450,6 +449,8 @@ pub use alloc_crate::borrow; #[stable(feature = "rust1", since = "1.0.0")] pub use alloc_crate::fmt; #[stable(feature = "rust1", since = "1.0.0")] +pub use alloc_crate::format; +#[stable(feature = "rust1", since = "1.0.0")] pub use alloc_crate::slice; #[stable(feature = "rust1", since = "1.0.0")] pub use alloc_crate::str; diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 6902ec82047..d1274a40900 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -450,8 +450,8 @@ pub mod builtin { #[unstable(feature = "concat_idents_macro", issue = "29599")] #[macro_export] macro_rules! concat_idents { - ($($e:ident),*) => ({ /* compiler built-in */ }); - ($($e:ident,)*) => ({ /* compiler built-in */ }); + ($($e:ident),+) => ({ /* compiler built-in */ }); + ($($e:ident,)+) => ({ /* compiler built-in */ }); } /// Concatenates literals into a static string slice. diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index bc2c9f522d3..e80c3eeb876 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -13,11 +13,10 @@ use hash; use io; use mem; use net::{ntoh, hton, IpAddr, Ipv4Addr, Ipv6Addr}; -#[allow(deprecated)] -use net::lookup_host; use option; use sys::net::netc as c; use sys_common::{FromInner, AsInner, IntoInner}; +use sys_common::net::lookup_host; use vec; use iter; use slice; @@ -856,7 +855,6 @@ impl ToSocketAddrs for (Ipv6Addr, u16) { } } -#[allow(deprecated)] fn resolve_socket_addr(s: &str, p: u16) -> io::Result<vec::IntoIter<SocketAddr>> { let ips = lookup_host(s)?; let v: Vec<_> = ips.map(|mut a| { a.set_port(p); a }).collect(); diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs index b0d5e563cb9..be4bcee8a68 100644 --- a/src/libstd/net/mod.rs +++ b/src/libstd/net/mod.rs @@ -38,9 +38,7 @@ #![stable(feature = "rust1", since = "1.0.0")] -use fmt; use io::{self, Error, ErrorKind}; -use sys_common::net as net_imp; #[stable(feature = "rust1", since = "1.0.0")] pub use self::ip::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope}; @@ -128,66 +126,3 @@ fn each_addr<A: ToSocketAddrs, F, T>(addr: A, mut f: F) -> io::Result<T> "could not resolve to any addresses") })) } - -/// An iterator over `SocketAddr` values returned from a host lookup operation. -#[unstable(feature = "lookup_host", reason = "unsure about the returned \ - iterator and returning socket \ - addresses", - issue = "27705")] -#[rustc_deprecated(since = "1.25.0", reason = "Use the ToSocketAddrs trait instead")] -pub struct LookupHost(net_imp::LookupHost); - -#[unstable(feature = "lookup_host", reason = "unsure about the returned \ - iterator and returning socket \ - addresses", - issue = "27705")] -#[rustc_deprecated(since = "1.25.0", reason = "Use the ToSocketAddrs trait instead")] -#[allow(deprecated)] -impl Iterator for LookupHost { - type Item = SocketAddr; - fn next(&mut self) -> Option<SocketAddr> { self.0.next() } -} - -#[unstable(feature = "lookup_host", reason = "unsure about the returned \ - iterator and returning socket \ - addresses", - issue = "27705")] -#[rustc_deprecated(since = "1.25.0", reason = "Use the ToSocketAddrs trait instead")] -#[allow(deprecated)] -impl fmt::Debug for LookupHost { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("LookupHost { .. }") - } -} - -/// Resolve the host specified by `host` as a number of `SocketAddr` instances. -/// -/// This method may perform a DNS query to resolve `host` and may also inspect -/// system configuration to resolve the specified hostname. -/// -/// The returned iterator will skip over any unknown addresses returned by the -/// operating system. -/// -/// # Examples -/// -/// ```no_run -/// #![feature(lookup_host)] -/// -/// use std::net; -/// -/// fn main() -> std::io::Result<()> { -/// for host in net::lookup_host("rust-lang.org")? { -/// println!("found address: {}", host); -/// } -/// Ok(()) -/// } -/// ``` -#[unstable(feature = "lookup_host", reason = "unsure about the returned \ - iterator and returning socket \ - addresses", - issue = "27705")] -#[rustc_deprecated(since = "1.25.0", reason = "Use the ToSocketAddrs trait instead")] -#[allow(deprecated)] -pub fn lookup_host(host: &str) -> io::Result<LookupHost> { - net_imp::lookup_host(host).map(LookupHost) -} diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 28c178307a5..229034eb779 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -31,10 +31,14 @@ pub use core::panic::{PanicInfo, Location}; /// A marker trait which represents "panic safe" types in Rust. /// /// This trait is implemented by default for many types and behaves similarly in -/// terms of inference of implementation to the `Send` and `Sync` traits. The -/// purpose of this trait is to encode what types are safe to cross a `catch_unwind` +/// terms of inference of implementation to the [`Send`] and [`Sync`] traits. The +/// purpose of this trait is to encode what types are safe to cross a [`catch_unwind`] /// boundary with no fear of unwind safety. /// +/// [`Send`]: ../marker/trait.Send.html +/// [`Sync`]: ../marker/trait.Sync.html +/// [`catch_unwind`]: ./fn.catch_unwind.html +/// /// ## What is unwind safety? /// /// In Rust a function can "return" early if it either panics or calls a @@ -95,12 +99,13 @@ pub use core::panic::{PanicInfo, Location}; /// /// ## When should `UnwindSafe` be used? /// -/// Is not intended that most types or functions need to worry about this trait. -/// It is only used as a bound on the `catch_unwind` function and as mentioned above, -/// the lack of `unsafe` means it is mostly an advisory. The `AssertUnwindSafe` -/// wrapper struct in this module can be used to force this trait to be -/// implemented for any closed over variables passed to the `catch_unwind` function -/// (more on this below). +/// It is not intended that most types or functions need to worry about this trait. +/// It is only used as a bound on the `catch_unwind` function and as mentioned +/// above, the lack of `unsafe` means it is mostly an advisory. The +/// [`AssertUnwindSafe`] wrapper struct can be used to force this trait to be +/// implemented for any closed over variables passed to `catch_unwind`. +/// +/// [`AssertUnwindSafe`]: ./struct.AssertUnwindSafe.html #[stable(feature = "catch_unwind", since = "1.9.0")] #[rustc_on_unimplemented = "the type {Self} may not be safely transferred \ across an unwind boundary"] @@ -109,11 +114,14 @@ pub auto trait UnwindSafe {} /// A marker trait representing types where a shared reference is considered /// unwind safe. /// -/// This trait is namely not implemented by `UnsafeCell`, the root of all +/// This trait is namely not implemented by [`UnsafeCell`], the root of all /// interior mutability. /// /// This is a "helper marker trait" used to provide impl blocks for the -/// `UnwindSafe` trait, for more information see that documentation. +/// [`UnwindSafe`] trait, for more information see that documentation. +/// +/// [`UnsafeCell`]: ../cell/struct.UnsafeCell.html +/// [`UnwindSafe`]: ./trait.UnwindSafe.html #[stable(feature = "catch_unwind", since = "1.9.0")] #[rustc_on_unimplemented = "the type {Self} may contain interior mutability \ and a reference may not be safely transferrable \ @@ -122,14 +130,15 @@ pub auto trait RefUnwindSafe {} /// A simple wrapper around a type to assert that it is unwind safe. /// -/// When using `catch_unwind` it may be the case that some of the closed over +/// When using [`catch_unwind`] it may be the case that some of the closed over /// variables are not unwind safe. For example if `&mut T` is captured the /// compiler will generate a warning indicating that it is not unwind safe. It /// may not be the case, however, that this is actually a problem due to the -/// specific usage of `catch_unwind` if unwind safety is specifically taken into +/// specific usage of [`catch_unwind`] if unwind safety is specifically taken into /// account. This wrapper struct is useful for a quick and lightweight /// annotation that a variable is indeed unwind safe. /// +/// [`catch_unwind`]: ./fn.catch_unwind.html /// # Examples /// /// One way to use `AssertUnwindSafe` is to assert that the entire closure @@ -318,18 +327,22 @@ impl<T: fmt::Debug> fmt::Debug for AssertUnwindSafe<T> { /// panic and allowing a graceful handling of the error. /// /// It is **not** recommended to use this function for a general try/catch -/// mechanism. The `Result` type is more appropriate to use for functions that +/// mechanism. The [`Result`] type is more appropriate to use for functions that /// can fail on a regular basis. Additionally, this function is not guaranteed /// to catch all panics, see the "Notes" section below. /// -/// The closure provided is required to adhere to the `UnwindSafe` trait to ensure +/// [`Result`]: ../result/enum.Result.html +/// +/// The closure provided is required to adhere to the [`UnwindSafe`] trait to ensure /// that all captured variables are safe to cross this boundary. The purpose of /// this bound is to encode the concept of [exception safety][rfc] in the type /// system. Most usage of this function should not need to worry about this /// bound as programs are naturally unwind safe without `unsafe` code. If it -/// becomes a problem the associated `AssertUnwindSafe` wrapper type in this -/// module can be used to quickly assert that the usage here is indeed unwind -/// safe. +/// becomes a problem the [`AssertUnwindSafe`] wrapper struct can be used to quickly +/// assert that the usage here is indeed unwind safe. +/// +/// [`AssertUnwindSafe`]: ./struct.AssertUnwindSafe.html +/// [`UnwindSafe`]: ./trait.UnwindSafe.html /// /// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md /// @@ -364,9 +377,11 @@ pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> { /// Triggers a panic without invoking the panic hook. /// -/// This is designed to be used in conjunction with `catch_unwind` to, for +/// This is designed to be used in conjunction with [`catch_unwind`] to, for /// example, carry a panic across a layer of C code. /// +/// [`catch_unwind`]: ./fn.catch_unwind.html +/// /// # Notes /// /// Note that panics in Rust are not always implemented via unwinding, but they diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 24eae6a4c82..403056240bf 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -76,7 +76,9 @@ static mut HOOK: Hook = Hook::Default; /// is invoked. As such, the hook will run with both the aborting and unwinding /// runtimes. The default hook prints a message to standard error and generates /// a backtrace if requested, but this behavior can be customized with the -/// `set_hook` and `take_hook` functions. +/// `set_hook` and [`take_hook`] functions. +/// +/// [`take_hook`]: ./fn.take_hook.html /// /// The hook is provided with a `PanicInfo` struct which contains information /// about the origin of the panic, including the payload passed to `panic!` and @@ -121,6 +123,10 @@ pub fn set_hook(hook: Box<Fn(&PanicInfo) + 'static + Sync + Send>) { /// Unregisters the current panic hook, returning it. /// +/// *See also the function [`set_hook`].* +/// +/// [`set_hook`]: ./fn.set_hook.html +/// /// If no custom hook is registered, the default hook will be returned. /// /// # Panics diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 955a6af1ae6..696711a70d4 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -87,7 +87,6 @@ use io; use iter::{self, FusedIterator}; use ops::{self, Deref}; use rc::Rc; -use str::FromStr; use sync::Arc; use ffi::{OsStr, OsString}; @@ -1441,32 +1440,6 @@ impl From<String> for PathBuf { } } -/// Error returned from [`PathBuf::from_str`][`from_str`]. -/// -/// Note that parsing a path will never fail. This error is just a placeholder -/// for implementing `FromStr` for `PathBuf`. -/// -/// [`from_str`]: struct.PathBuf.html#method.from_str -#[derive(Debug, Clone, PartialEq, Eq)] -#[stable(feature = "path_from_str", since = "1.26.0")] -pub enum ParsePathError {} - -#[stable(feature = "path_from_str", since = "1.26.0")] -impl fmt::Display for ParsePathError { - fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { - match *self {} - } -} - -#[stable(feature = "path_from_str", since = "1.26.0")] -impl FromStr for PathBuf { - type Err = ParsePathError; - - fn from_str(s: &str) -> Result<Self, Self::Err> { - Ok(PathBuf::from(s)) - } -} - #[stable(feature = "rust1", since = "1.0.0")] impl<P: AsRef<Path>> iter::FromIterator<P> for PathBuf { fn from_iter<I: IntoIterator<Item = P>>(iter: I) -> PathBuf { diff --git a/src/libstd/sync/mpsc/select.rs b/src/libstd/sync/mpsc/select.rs index a9f3cea243f..9310dad9172 100644 --- a/src/libstd/sync/mpsc/select.rs +++ b/src/libstd/sync/mpsc/select.rs @@ -518,6 +518,7 @@ mod tests { } } + #[allow(unused_must_use)] #[test] fn cloning() { let (tx1, rx1) = channel::<i32>(); @@ -540,6 +541,7 @@ mod tests { tx3.send(()).unwrap(); } + #[allow(unused_must_use)] #[test] fn cloning2() { let (tx1, rx1) = channel::<i32>(); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index cbfcad12f1e..f8cd6103bdf 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -474,10 +474,10 @@ pub enum NestedMetaItemKind { /// A spanned compile-time attribute item. /// -/// E.g. `#[test]`, `#[derive(..)]` or `#[feature = "foo"]` +/// E.g. `#[test]`, `#[derive(..)]`, `#[rustfmt::skip]` or `#[feature = "foo"]` #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct MetaItem { - pub ident: Ident, + pub ident: Path, pub node: MetaItemKind, pub span: Span, } @@ -821,7 +821,7 @@ impl Stmt { pub fn is_item(&self) -> bool { match self.node { - StmtKind::Local(_) => true, + StmtKind::Item(_) => true, _ => false, } } diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index c68a743303a..ace9904e0c0 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -15,10 +15,10 @@ pub use self::ReprAttr::*; pub use self::IntType::*; use ast; -use ast::{AttrId, Attribute, Name, Ident}; +use ast::{AttrId, Attribute, Name, Ident, Path, PathSegment}; use ast::{MetaItem, MetaItemKind, NestedMetaItem, NestedMetaItemKind}; use ast::{Lit, LitKind, Expr, ExprKind, Item, Local, Stmt, StmtKind}; -use codemap::{Spanned, respan, dummy_spanned}; +use codemap::{BytePos, Spanned, respan, dummy_spanned}; use syntax_pos::Span; use errors::Handler; use feature_gate::{Features, GatedCfg}; @@ -107,6 +107,14 @@ pub fn is_known(attr: &Attribute) -> bool { }) } +const RUST_KNOWN_TOOL: &[&str] = &["clippy", "rustfmt"]; + +pub fn is_known_tool(attr: &Attribute) -> bool { + let tool_name = + attr.path.segments.iter().next().expect("empty path in attribute").ident.name; + RUST_KNOWN_TOOL.contains(&tool_name.as_str().as_ref()) +} + impl NestedMetaItem { /// Returns the MetaItem if self is a NestedMetaItemKind::MetaItem. pub fn meta_item(&self) -> Option<&MetaItem> { @@ -137,7 +145,7 @@ impl NestedMetaItem { /// Returns the name of the meta item, e.g. `foo` in `#[foo]`, /// `#[foo="bar"]` and `#[foo(bar)]`, if self is a MetaItem pub fn name(&self) -> Option<Name> { - self.meta_item().and_then(|meta_item| Some(meta_item.ident.name)) + self.meta_item().and_then(|meta_item| Some(meta_item.name())) } /// Gets the string value if self is a MetaItem and the MetaItem is a @@ -154,7 +162,7 @@ impl NestedMetaItem { if meta_item_list.len() == 1 { let nested_item = &meta_item_list[0]; if nested_item.is_literal() { - Some((meta_item.ident.name, nested_item.literal().unwrap())) + Some((meta_item.name(), nested_item.literal().unwrap())) } else { None } @@ -204,6 +212,10 @@ impl NestedMetaItem { } } +fn name_from_path(path: &Path) -> Name { + path.segments.last().expect("empty path in attribute").ident.name +} + impl Attribute { pub fn check_name(&self, name: &str) -> bool { let matches = self.path == name; @@ -213,11 +225,10 @@ impl Attribute { matches } - pub fn name(&self) -> Option<Name> { - match self.path.segments.len() { - 1 => Some(self.path.segments[0].ident.name), - _ => None, - } + /// Returns the **last** segment of the name of this attribute. + /// E.g. `foo` for `#[foo]`, `skip` for `#[rustfmt::skip]`. + pub fn name(&self) -> Name { + name_from_path(&self.path) } pub fn value_str(&self) -> Option<Symbol> { @@ -247,9 +258,17 @@ impl Attribute { pub fn is_value_str(&self) -> bool { self.value_str().is_some() } + + pub fn is_scoped(&self) -> bool { + self.path.segments.len() > 1 + } } impl MetaItem { + pub fn name(&self) -> Name { + name_from_path(&self.ident) + } + pub fn value_str(&self) -> Option<Symbol> { match self.node { MetaItemKind::NameValue(ref v) => { @@ -279,7 +298,7 @@ impl MetaItem { pub fn span(&self) -> Span { self.span } pub fn check_name(&self, name: &str) -> bool { - self.ident.name == name + self.name() == name } pub fn is_value_str(&self) -> bool { @@ -296,10 +315,7 @@ impl Attribute { pub fn meta(&self) -> Option<MetaItem> { let mut tokens = self.tokens.trees().peekable(); Some(MetaItem { - ident: match self.path.segments.len() { - 1 => self.path.segments[0].ident, - _ => return None, - }, + ident: self.path.clone(), node: if let Some(node) = MetaItemKind::from_tokens(&mut tokens) { if tokens.peek().is_some() { return None; @@ -344,12 +360,8 @@ impl Attribute { } pub fn parse_meta<'a>(&self, sess: &'a ParseSess) -> PResult<'a, MetaItem> { - if self.path.segments.len() > 1 { - sess.span_diagnostic.span_err(self.path.span, "expected ident, found path"); - } - Ok(MetaItem { - ident: self.path.segments.last().unwrap().ident, + ident: self.path.clone(), node: self.parse(sess, |parser| parser.parse_meta_item_kind())?, span: self.span, }) @@ -387,16 +399,17 @@ pub fn mk_name_value_item_str(ident: Ident, value: Spanned<Symbol>) -> MetaItem } pub fn mk_name_value_item(span: Span, ident: Ident, value: ast::Lit) -> MetaItem { - MetaItem { ident, span, node: MetaItemKind::NameValue(value) } + MetaItem { ident: Path::from_ident(ident), span, node: MetaItemKind::NameValue(value) } } pub fn mk_list_item(span: Span, ident: Ident, items: Vec<NestedMetaItem>) -> MetaItem { - MetaItem { ident, span, node: MetaItemKind::List(items) } + MetaItem { ident: Path::from_ident(ident), span, node: MetaItemKind::List(items) } } pub fn mk_word_item(ident: Ident) -> MetaItem { - MetaItem { ident, span: ident.span, node: MetaItemKind::Word } + MetaItem { ident: Path::from_ident(ident), span: ident.span, node: MetaItemKind::Word } } + pub fn mk_nested_word_item(ident: Ident) -> NestedMetaItem { respan(ident.span, NestedMetaItemKind::MetaItem(mk_word_item(ident))) } @@ -422,7 +435,7 @@ pub fn mk_spanned_attr_inner(sp: Span, id: AttrId, item: MetaItem) -> Attribute Attribute { id, style: ast::AttrStyle::Inner, - path: ast::Path::from_ident(item.ident), + path: item.ident, tokens: item.node.tokens(item.span), is_sugared_doc: false, span: sp, @@ -440,7 +453,7 @@ pub fn mk_spanned_attr_outer(sp: Span, id: AttrId, item: MetaItem) -> Attribute Attribute { id, style: ast::AttrStyle::Outer, - path: ast::Path::from_ident(item.ident), + path: item.ident, tokens: item.node.tokens(item.span), is_sugared_doc: false, span: sp, @@ -453,7 +466,7 @@ pub fn mk_sugared_doc_attr(id: AttrId, text: Symbol, span: Span) -> Attribute { Attribute { id, style, - path: ast::Path::from_ident(Ident::from_str("doc").with_span_pos(span)), + path: Path::from_ident(Ident::from_str("doc").with_span_pos(span)), tokens: MetaItemKind::NameValue(lit).tokens(span), is_sugared_doc: true, span, @@ -489,7 +502,7 @@ pub fn contains_feature_attr(attrs: &[Attribute], feature_name: &str) -> bool { item.check_name("feature") && item.meta_item_list().map(|list| { list.iter().any(|mi| { - mi.word().map(|w| w.ident.name == feature_name) + mi.word().map(|w| w.name() == feature_name) .unwrap_or(false) }) }).unwrap_or(false) @@ -562,7 +575,7 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat if let (Some(feats), Some(gated_cfg)) = (features, GatedCfg::gate(cfg)) { gated_cfg.check_and_emit(sess, feats); } - sess.config.contains(&(cfg.ident.name, cfg.value_str())) + sess.config.contains(&(cfg.name(), cfg.value_str())) }) } @@ -583,7 +596,7 @@ pub fn eval_condition<F>(cfg: &ast::MetaItem, sess: &ParseSess, eval: &mut F) // The unwraps below may look dangerous, but we've already asserted // that they won't fail with the loop above. - match &*cfg.ident.name.as_str() { + match &*cfg.name().as_str() { "any" => mis.iter().any(|mi| { eval_condition(mi.meta_item().unwrap(), sess, eval) }), @@ -676,7 +689,7 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, let meta = meta.as_ref().unwrap(); let get = |meta: &MetaItem, item: &mut Option<Symbol>| { if item.is_some() { - handle_errors(diagnostic, meta.span, AttrError::MultipleItem(meta.ident.name)); + handle_errors(diagnostic, meta.span, AttrError::MultipleItem(meta.name())); return false } if let Some(v) = meta.value_str() { @@ -695,14 +708,14 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, )+ for meta in metas { if let Some(mi) = meta.meta_item() { - match &*mi.ident.name.as_str() { + match &*mi.name().as_str() { $( stringify!($name) => if !get(mi, &mut $name) { continue 'outer }, )+ _ => { handle_errors(diagnostic, mi.span, - AttrError::UnknownMetaItem(mi.ident.name)); + AttrError::UnknownMetaItem(mi.name())); continue 'outer } } @@ -714,7 +727,7 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, } } - match &*meta.ident.name.as_str() { + match &*meta.name().as_str() { "rustc_deprecated" => { if rustc_depr.is_some() { span_err!(diagnostic, item_sp, E0540, @@ -769,13 +782,13 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, let mut issue = None; for meta in metas { if let Some(mi) = meta.meta_item() { - match &*mi.ident.name.as_str() { + match &*mi.name().as_str() { "feature" => if !get(mi, &mut feature) { continue 'outer }, "reason" => if !get(mi, &mut reason) { continue 'outer }, "issue" => if !get(mi, &mut issue) { continue 'outer }, _ => { handle_errors(diagnostic, meta.span, - AttrError::UnknownMetaItem(mi.ident.name)); + AttrError::UnknownMetaItem(mi.name())); continue 'outer } } @@ -825,12 +838,12 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, let mut since = None; for meta in metas { if let NestedMetaItemKind::MetaItem(ref mi) = meta.node { - match &*mi.ident.name.as_str() { + match &*mi.name().as_str() { "feature" => if !get(mi, &mut feature) { continue 'outer }, "since" => if !get(mi, &mut since) { continue 'outer }, _ => { handle_errors(diagnostic, meta.span, - AttrError::UnknownMetaItem(mi.ident.name)); + AttrError::UnknownMetaItem(mi.name())); continue 'outer } } @@ -917,7 +930,7 @@ fn find_deprecation_generic<'a, I>(diagnostic: &Handler, depr = if let Some(metas) = attr.meta_item_list() { let get = |meta: &MetaItem, item: &mut Option<Symbol>| { if item.is_some() { - handle_errors(diagnostic, meta.span, AttrError::MultipleItem(meta.ident.name)); + handle_errors(diagnostic, meta.span, AttrError::MultipleItem(meta.name())); return false } if let Some(v) = meta.value_str() { @@ -933,12 +946,12 @@ fn find_deprecation_generic<'a, I>(diagnostic: &Handler, let mut note = None; for meta in metas { if let NestedMetaItemKind::MetaItem(ref mi) = meta.node { - match &*mi.ident.name.as_str() { + match &*mi.name().as_str() { "since" => if !get(mi, &mut since) { continue 'outer }, "note" => if !get(mi, &mut note) { continue 'outer }, _ => { handle_errors(diagnostic, meta.span, - AttrError::UnknownMetaItem(mi.ident.name)); + AttrError::UnknownMetaItem(mi.name())); continue 'outer } } @@ -990,7 +1003,7 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec<ReprAttr> let mut recognised = false; if let Some(mi) = item.word() { - let word = &*mi.ident.name.as_str(); + let word = &*mi.name().as_str(); let hint = match word { "C" => Some(ReprC), "packed" => Some(ReprPacked(1)), @@ -1012,11 +1025,11 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec<ReprAttr> let parse_alignment = |node: &ast::LitKind| -> Result<u32, &'static str> { if let ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed) = node { if literal.is_power_of_two() { - // rustc::ty::layout::Align restricts align to <= 2147483647 - if *literal <= 2147483647 { + // rustc::ty::layout::Align restricts align to <= 2^29 + if *literal <= 1 << 29 { Ok(*literal as u32) } else { - Err("larger than 2147483647") + Err("larger than 2^29") } } else { Err("not a power of two") @@ -1045,6 +1058,30 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec<ReprAttr> span_err!(diagnostic, item.span, E0589, "invalid `repr(align)` attribute: {}", literal_error); } + } else { + if let Some(meta_item) = item.meta_item() { + if meta_item.name() == "align" { + if let MetaItemKind::NameValue(ref value) = meta_item.node { + recognised = true; + let mut err = struct_span_err!(diagnostic, item.span, E0693, + "incorrect `repr(align)` attribute format"); + match value.node { + ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => { + err.span_suggestion(item.span, + "use parentheses instead", + format!("align({})", int)); + } + ast::LitKind::Str(s, _) => { + err.span_suggestion(item.span, + "use parentheses instead", + format!("align({})", s)); + } + _ => {} + } + err.emit(); + } + } + } } if !recognised { // Not a word we recognize @@ -1103,18 +1140,56 @@ impl IntType { impl MetaItem { fn tokens(&self) -> TokenStream { - let ident = TokenTree::Token(self.span, Token::from_ast_ident(self.ident)); - TokenStream::concat(vec![ident.into(), self.node.tokens(self.span)]) + let mut idents = vec![]; + let mut last_pos = BytePos(0 as u32); + for (i, segment) in self.ident.segments.iter().enumerate() { + let is_first = i == 0; + if !is_first { + let mod_sep_span = Span::new(last_pos, + segment.ident.span.lo(), + segment.ident.span.ctxt()); + idents.push(TokenTree::Token(mod_sep_span, Token::ModSep).into()); + } + idents.push(TokenTree::Token(segment.ident.span, + Token::from_ast_ident(segment.ident)).into()); + last_pos = segment.ident.span.hi(); + } + idents.push(self.node.tokens(self.span)); + TokenStream::concat(idents) } fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItem> where I: Iterator<Item = TokenTree>, { - let (span, ident) = match tokens.next() { - Some(TokenTree::Token(span, Token::Ident(ident, _))) => (span, ident), + // FIXME: Share code with `parse_path`. + let ident = match tokens.next() { + Some(TokenTree::Token(span, Token::Ident(ident, _))) => { + if let Some(TokenTree::Token(_, Token::ModSep)) = tokens.peek() { + let mut segments = vec![PathSegment::from_ident(ident.with_span_pos(span))]; + tokens.next(); + loop { + if let Some(TokenTree::Token(span, + Token::Ident(ident, _))) = tokens.next() { + segments.push(PathSegment::from_ident(ident.with_span_pos(span))); + } else { + return None; + } + if let Some(TokenTree::Token(_, Token::ModSep)) = tokens.peek() { + tokens.next(); + } else { + break; + } + } + let span = span.with_hi(segments.last().unwrap().ident.span.hi()); + Path { span, segments } + } else { + Path::from_ident(ident.with_span_pos(span)) + } + } Some(TokenTree::Token(_, Token::Interpolated(ref nt))) => match nt.0 { - token::Nonterminal::NtIdent(ident, _) => (ident.span, ident), + token::Nonterminal::NtIdent(ident, _) => Path::from_ident(ident), token::Nonterminal::NtMeta(ref meta) => return Some(meta.clone()), + token::Nonterminal::NtPath(ref path) => path.clone(), _ => return None, }, _ => return None, @@ -1123,10 +1198,11 @@ impl MetaItem { let node = MetaItemKind::from_tokens(tokens)?; let hi = match node { MetaItemKind::NameValue(ref lit) => lit.span.hi(), - MetaItemKind::List(..) => list_closing_paren_pos.unwrap_or(span.hi()), - _ => span.hi(), + MetaItemKind::List(..) => list_closing_paren_pos.unwrap_or(ident.span.hi()), + _ => ident.span.hi(), }; - Some(MetaItem { ident, node, span: span.with_hi(hi) }) + let span = ident.span.with_hi(hi); + Some(MetaItem { ident, node, span }) } } @@ -1228,10 +1304,7 @@ impl LitKind { match *self { LitKind::Str(string, ast::StrStyle::Cooked) => { - let mut escaped = String::new(); - for ch in string.as_str().chars() { - escaped.extend(ch.escape_unicode()); - } + let escaped = string.as_str().escape_default(); Token::Literal(token::Lit::Str_(Symbol::intern(&escaped)), None) } LitKind::Str(string, ast::StrStyle::Raw(n)) => { diff --git a/src/libsyntax/diagnostic_list.rs b/src/libsyntax/diagnostic_list.rs index bb7988e64bc..5f940437ab3 100644 --- a/src/libsyntax/diagnostic_list.rs +++ b/src/libsyntax/diagnostic_list.rs @@ -244,6 +244,18 @@ fn main() { ``` "##, +E0589: r##" +The value of `N` that was specified for `repr(align(N))` was not a power +of two, or was greater than 2^29. + +```compile_fail,E0589 +#[repr(align(15))] // error: invalid `repr(align)` attribute: not a power of two +enum Foo { + Bar(u64), +} +``` +"##, + E0658: r##" An unstable feature was used. @@ -321,7 +333,8 @@ register_diagnostics! { E0555, // malformed feature attribute, expected #![feature(...)] E0556, // malformed feature, expected just one word E0584, // file for module `..` found at both .. and .. - E0589, // invalid `repr(align)` attribute E0629, // missing 'feature' (rustc_const_unstable) E0630, // rustc_const_unstable attribute must be paired with stable/unstable attribute + E0693, // incorrect `repr(align)` attribute format + E0694, // an unknown tool name found in scoped attributes } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 0c313ab1489..3b76084f2fb 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -118,6 +118,20 @@ impl Annotatable { } } + pub fn expect_stmt(self) -> ast::Stmt { + match self { + Annotatable::Stmt(stmt) => stmt.into_inner(), + _ => panic!("expected statement"), + } + } + + pub fn expect_expr(self) -> P<ast::Expr> { + match self { + Annotatable::Expr(expr) => expr, + _ => panic!("expected expression"), + } + } + pub fn derive_allowed(&self) -> bool { match *self { Annotatable::Item(ref item) => match item.node { @@ -661,7 +675,9 @@ pub trait Resolver { fn resolve_imports(&mut self); // Resolves attribute and derive legacy macros from `#![plugin(..)]`. - fn find_legacy_attr_invoc(&mut self, attrs: &mut Vec<Attribute>) -> Option<Attribute>; + fn find_legacy_attr_invoc(&mut self, attrs: &mut Vec<Attribute>, allow_derive: bool) + -> Option<Attribute>; + fn resolve_invoc(&mut self, invoc: &mut Invocation, scope: Mark, force: bool) -> Result<Option<Lrc<SyntaxExtension>>, Determinacy>; fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool) @@ -687,7 +703,8 @@ impl Resolver for DummyResolver { fn add_builtin(&mut self, _ident: ast::Ident, _ext: Lrc<SyntaxExtension>) {} fn resolve_imports(&mut self) {} - fn find_legacy_attr_invoc(&mut self, _attrs: &mut Vec<Attribute>) -> Option<Attribute> { None } + fn find_legacy_attr_invoc(&mut self, _attrs: &mut Vec<Attribute>, _allow_derive: bool) + -> Option<Attribute> { None } fn resolve_invoc(&mut self, _invoc: &mut Invocation, _scope: Mark, _force: bool) -> Result<Option<Lrc<SyntaxExtension>>, Determinacy> { Err(Determinacy::Determined) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 1434e5fddea..584b9455a93 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -143,7 +143,7 @@ impl ExpansionKind { } fn expect_from_annotatables<I: IntoIterator<Item = Annotatable>>(self, items: I) -> Expansion { - let items = items.into_iter(); + let mut items = items.into_iter(); match self { ExpansionKind::Items => Expansion::Items(items.map(Annotatable::expect_item).collect()), @@ -153,7 +153,14 @@ impl ExpansionKind { Expansion::TraitItems(items.map(Annotatable::expect_trait_item).collect()), ExpansionKind::ForeignItems => Expansion::ForeignItems(items.map(Annotatable::expect_foreign_item).collect()), - _ => unreachable!(), + ExpansionKind::Stmts => Expansion::Stmts(items.map(Annotatable::expect_stmt).collect()), + ExpansionKind::Expr => Expansion::Expr( + items.next().expect("expected exactly one expression").expect_expr() + ), + ExpansionKind::OptExpr => + Expansion::OptExpr(items.next().map(Annotatable::expect_expr)), + ExpansionKind::Pat | ExpansionKind::Ty => + panic!("patterns and types aren't annotatable"), } } } @@ -803,7 +810,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { invoc.expansion_data.mark.set_expn_info(expn_info); let span = span.with_ctxt(self.cx.backtrace()); let dummy = ast::MetaItem { // FIXME(jseyfried) avoid this - ident: keywords::Invalid.ident(), + ident: Path::from_ident(keywords::Invalid.ident()), span: DUMMY_SP, node: ast::MetaItemKind::Word, }; @@ -956,14 +963,15 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { self.collect(kind, InvocationKind::Attr { attr, traits, item }) } - // If `item` is an attr invocation, remove and return the macro attribute. + /// If `item` is an attr invocation, remove and return the macro attribute and derive traits. fn classify_item<T>(&mut self, mut item: T) -> (Option<ast::Attribute>, Vec<Path>, T) where T: HasAttrs, { let (mut attr, mut traits) = (None, Vec::new()); item = item.map_attrs(|mut attrs| { - if let Some(legacy_attr_invoc) = self.cx.resolver.find_legacy_attr_invoc(&mut attrs) { + if let Some(legacy_attr_invoc) = self.cx.resolver.find_legacy_attr_invoc(&mut attrs, + true) { attr = Some(legacy_attr_invoc); return attrs; } @@ -978,6 +986,28 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { (attr, traits, item) } + /// Alternative of `classify_item()` that ignores `#[derive]` so invocations fallthrough + /// to the unused-attributes lint (making it an error on statements and expressions + /// is a breaking change) + fn classify_nonitem<T: HasAttrs>(&mut self, mut item: T) -> (Option<ast::Attribute>, T) { + let mut attr = None; + + item = item.map_attrs(|mut attrs| { + if let Some(legacy_attr_invoc) = self.cx.resolver.find_legacy_attr_invoc(&mut attrs, + false) { + attr = Some(legacy_attr_invoc); + return attrs; + } + + if self.cx.ecfg.proc_macro_enabled() { + attr = find_attr_invoc(&mut attrs); + } + attrs + }); + + (attr, item) + } + fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> { self.cfg.configure(node) } @@ -987,12 +1017,23 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { fn check_attributes(&mut self, attrs: &[ast::Attribute]) { let features = self.cx.ecfg.features.unwrap(); for attr in attrs.iter() { - feature_gate::check_attribute(attr, self.cx.parse_sess, features); + self.check_attribute_inner(attr, features); + + // macros are expanded before any lint passes so this warning has to be hardcoded + if attr.path == "derive" { + self.cx.struct_span_warn(attr.span, "`#[derive]` does nothing on macro invocations") + .note("this may become a hard error in a future release") + .emit(); + } } } fn check_attribute(&mut self, at: &ast::Attribute) { let features = self.cx.ecfg.features.unwrap(); + self.check_attribute_inner(at, features); + } + + fn check_attribute_inner(&mut self, at: &ast::Attribute, features: &Features) { feature_gate::check_attribute(at, self.cx.parse_sess, features); } } @@ -1008,15 +1049,16 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { let mut expr = self.cfg.configure_expr(expr).into_inner(); expr.node = self.cfg.configure_expr_kind(expr.node); - let (attr, derives, expr) = self.classify_item(expr); + // ignore derives so they remain unused + let (attr, expr) = self.classify_nonitem(expr); - if attr.is_some() || !derives.is_empty() { + if attr.is_some() { // collect the invoc regardless of whether or not attributes are permitted here // expansion will eat the attribute so it won't error later attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a)); // ExpansionKind::Expr requires the macro to emit an expression - return self.collect_attr(attr, derives, Annotatable::Expr(P(expr)), ExpansionKind::Expr) + return self.collect_attr(attr, vec![], Annotatable::Expr(P(expr)), ExpansionKind::Expr) .make_expr(); } @@ -1032,12 +1074,13 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { let mut expr = configure!(self, expr).into_inner(); expr.node = self.cfg.configure_expr_kind(expr.node); - let (attr, derives, expr) = self.classify_item(expr); + // ignore derives so they remain unused + let (attr, expr) = self.classify_nonitem(expr); - if attr.is_some() || !derives.is_empty() { + if attr.is_some() { attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a)); - return self.collect_attr(attr, derives, Annotatable::Expr(P(expr)), + return self.collect_attr(attr, vec![], Annotatable::Expr(P(expr)), ExpansionKind::OptExpr) .make_opt_expr(); } @@ -1071,7 +1114,14 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { // we'll expand attributes on expressions separately if !stmt.is_expr() { - let (attr, derives, stmt_) = self.classify_item(stmt); + let (attr, derives, stmt_) = if stmt.is_item() { + self.classify_item(stmt) + } else { + // ignore derives on non-item statements so it falls through + // to the unused-attributes lint + let (attr, stmt) = self.classify_nonitem(stmt); + (attr, vec![], stmt) + }; if attr.is_some() || !derives.is_empty() { return self.collect_attr(attr, derives, diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index d9c3deb30da..71634ada894 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -835,7 +835,13 @@ fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal { "path" => token::NtPath(panictry!(p.parse_path_common(PathStyle::Type, false))), "meta" => token::NtMeta(panictry!(p.parse_meta_item())), "vis" => token::NtVis(panictry!(p.parse_visibility(true))), - "lifetime" => token::NtLifetime(p.expect_lifetime().ident), + "lifetime" => if p.check_lifetime() { + token::NtLifetime(p.expect_lifetime().ident) + } else { + let token_str = pprust::token_to_string(&p.token); + p.fatal(&format!("expected a lifetime, found `{}`", &token_str)).emit(); + FatalError.raise(); + } // this is not supposed to happen, since it has been checked // when compiling the macro. _ => p.span_bug(sp, "invalid fragment specifier"), diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 0331e90164f..d8db76a95ff 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -90,24 +90,24 @@ macro_rules! declare_features { } }; - ($((removed, $feature: ident, $ver: expr, $issue: expr, None),)+) => { + ($((removed, $feature: ident, $ver: expr, $issue: expr, None, $reason: expr),)+) => { /// Represents unstable features which have since been removed (it was once Active) - const REMOVED_FEATURES: &'static [(&'static str, &'static str, Option<u32>)] = &[ - $((stringify!($feature), $ver, $issue)),+ + const REMOVED_FEATURES: &[(&str, &str, Option<u32>, Option<&str>)] = &[ + $((stringify!($feature), $ver, $issue, $reason)),+ ]; }; ($((stable_removed, $feature: ident, $ver: expr, $issue: expr, None),)+) => { /// Represents stable features which have since been removed (it was once Accepted) - const STABLE_REMOVED_FEATURES: &'static [(&'static str, &'static str, Option<u32>)] = &[ - $((stringify!($feature), $ver, $issue)),+ + const STABLE_REMOVED_FEATURES: &[(&str, &str, Option<u32>, Option<&str>)] = &[ + $((stringify!($feature), $ver, $issue, None)),+ ]; }; ($((accepted, $feature: ident, $ver: expr, $issue: expr, None),)+) => { /// Those language feature has since been Accepted (it was once Active) - const ACCEPTED_FEATURES: &'static [(&'static str, &'static str, Option<u32>)] = &[ - $((stringify!($feature), $ver, $issue)),+ + const ACCEPTED_FEATURES: &[(&str, &str, Option<u32>, Option<&str>)] = &[ + $((stringify!($feature), $ver, $issue, None)),+ ]; } } @@ -162,9 +162,6 @@ declare_features! ( // OIBIT specific features (active, optin_builtin_traits, "1.0.0", Some(13231), None), - // macro re-export needs more discussion and stabilization - (active, macro_reexport, "1.0.0", Some(29638), None), - // Allows use of #[staged_api] // rustc internal (active, staged_api, "1.0.0", None, None), @@ -369,15 +366,9 @@ declare_features! ( // #[doc(include="some-file")] (active, external_doc, "1.22.0", Some(44732), None), - // allow `#[must_use]` on functions and comparison operators (RFC 1940) - (active, fn_must_use, "1.21.0", Some(43302), None), - // Future-proofing enums/structs with #[non_exhaustive] attribute (RFC 2008) (active, non_exhaustive, "1.22.0", Some(44109), None), - // Trait object syntax with `dyn` prefix - (active, dyn_trait, "1.22.0", Some(44662), Some(Edition::Edition2018)), - // `crate` as visibility modifier, synonymous to `pub(crate)` (active, crate_visibility_modifier, "1.23.0", Some(45388), Some(Edition::Edition2018)), @@ -397,7 +388,7 @@ declare_features! ( (active, generic_associated_types, "1.23.0", Some(44265), None), // Resolve absolute paths as paths from other crates - (active, extern_absolute_paths, "1.24.0", Some(44660), None), + (active, extern_absolute_paths, "1.24.0", Some(44660), Some(Edition::Edition2018)), // `foo.rs` as an alternative to `foo/mod.rs` (active, non_modrs_mods, "1.24.0", Some(44660), Some(Edition::Edition2018)), @@ -466,30 +457,38 @@ declare_features! ( // #[doc(alias = "...")] (active, doc_alias, "1.27.0", Some(50146), None), + + // Access to crate names passed via `--extern` through prelude + (active, extern_prelude, "1.27.0", Some(44660), Some(Edition::Edition2018)), + + // Scoped attributes + (active, tool_attributes, "1.25.0", Some(44690), None), ); declare_features! ( - (removed, import_shadowing, "1.0.0", None, None), - (removed, managed_boxes, "1.0.0", None, None), + (removed, import_shadowing, "1.0.0", None, None, None), + (removed, managed_boxes, "1.0.0", None, None, None), // Allows use of unary negate on unsigned integers, e.g. -e for e: u8 - (removed, negate_unsigned, "1.0.0", Some(29645), None), - (removed, reflect, "1.0.0", Some(27749), None), + (removed, negate_unsigned, "1.0.0", Some(29645), None, None), + (removed, reflect, "1.0.0", Some(27749), None, None), // A way to temporarily opt out of opt in copy. This will *never* be accepted. - (removed, opt_out_copy, "1.0.0", None, None), - (removed, quad_precision_float, "1.0.0", None, None), - (removed, struct_inherit, "1.0.0", None, None), - (removed, test_removed_feature, "1.0.0", None, None), - (removed, visible_private_types, "1.0.0", None, None), - (removed, unsafe_no_drop_flag, "1.0.0", None, None), + (removed, opt_out_copy, "1.0.0", None, None, None), + (removed, quad_precision_float, "1.0.0", None, None, None), + (removed, struct_inherit, "1.0.0", None, None, None), + (removed, test_removed_feature, "1.0.0", None, None, None), + (removed, visible_private_types, "1.0.0", None, None, None), + (removed, unsafe_no_drop_flag, "1.0.0", None, None, None), // Allows using items which are missing stability attributes // rustc internal - (removed, unmarked_api, "1.0.0", None, None), - (removed, pushpop_unsafe, "1.2.0", None, None), - (removed, allocator, "1.0.0", None, None), - // Allows the `#[simd]` attribute -- removed in favor of `#[repr(simd)]` - (removed, simd, "1.0.0", Some(27731), None), - // Merged into `slice_patterns` - (removed, advanced_slice_patterns, "1.0.0", Some(23121), None), + (removed, unmarked_api, "1.0.0", None, None, None), + (removed, pushpop_unsafe, "1.2.0", None, None, None), + (removed, allocator, "1.0.0", None, None, None), + (removed, simd, "1.0.0", Some(27731), None, + Some("removed in favor of `#[repr(simd)]`")), + (removed, advanced_slice_patterns, "1.0.0", Some(23121), None, + Some("merged into `#![feature(slice_patterns)]`")), + (removed, macro_reexport, "1.0.0", Some(29638), None, + Some("subsumed by `#![feature(use_extern_macros)]` and `pub use`")), ); declare_features! ( @@ -592,6 +591,10 @@ declare_features! ( (accepted, cfg_target_feature, "1.27.0", Some(29717), None), // Allows #[target_feature(...)] (accepted, target_feature, "1.27.0", None, None), + // Trait object syntax with `dyn` prefix + (accepted, dyn_trait, "1.27.0", Some(44662), None), + // allow `#[must_use]` on functions; and, must-use operators (RFC 1940) + (accepted, fn_must_use, "1.27.0", Some(43302), None), ); // If you change this, please modify src/doc/unstable-book as well. You must @@ -675,7 +678,6 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG ("forbid", Normal, Ungated), ("deny", Normal, Ungated), - ("macro_reexport", Normal, Ungated), ("macro_use", Normal, Ungated), ("macro_export", Normal, Ungated), ("plugin_registrar", Normal, Ungated), @@ -1080,7 +1082,7 @@ pub struct GatedCfg { impl GatedCfg { pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> { - let name = cfg.ident.name.as_str(); + let name = cfg.name().as_str(); GATED_CFGS.iter() .position(|info| info.0 == name) .map(|idx| { @@ -1133,7 +1135,7 @@ macro_rules! gate_feature { impl<'a> Context<'a> { fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) { debug!("check_attribute(attr = {:?})", attr); - let name = unwrap_or!(attr.name(), return).as_str(); + let name = attr.name().as_str(); for &(n, ty, ref gateage) in BUILTIN_ATTRIBUTES { if name == n { if let Gated(_, name, desc, ref has_feature) = *gateage { @@ -1173,12 +1175,28 @@ impl<'a> Context<'a> { // before the plugin attributes are registered // so we skip this then if !is_macro { - gate_feature!(self, custom_attribute, attr.span, - &format!("The attribute `{}` is currently \ - unknown to the compiler and \ - may have meaning \ - added to it in the future", - attr.path)); + if attr.is_scoped() { + gate_feature!(self, tool_attributes, attr.span, + &format!("scoped attribute `{}` is experimental", attr.path)); + if attr::is_known_tool(attr) { + attr::mark_used(attr); + } else { + span_err!( + self.parse_sess.span_diagnostic, + attr.span, + E0694, + "an unknown tool name found in scoped attribute: `{}`.", + attr.path + ); + } + } else { + gate_feature!(self, custom_attribute, attr.span, + &format!("The attribute `{}` is currently \ + unknown to the compiler and \ + may have meaning \ + added to it in the future", + attr.path)); + } } } } @@ -1204,7 +1222,7 @@ fn find_lang_feature_issue(feature: &str) -> Option<u32> { let found = ACCEPTED_FEATURES.iter().chain(REMOVED_FEATURES).chain(STABLE_REMOVED_FEATURES) .find(|t| t.0 == feature); match found { - Some(&(_, _, issue)) => issue, + Some(&(_, _, issue, _)) => issue, None => panic!("Feature `{}` is not declared anywhere", feature), } } @@ -1518,11 +1536,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, underscore_imports, i.span, "renaming extern crates with `_` is unstable"); } - if let Some(attr) = attr::find_by_name(&i.attrs[..], "macro_reexport") { - gate_feature_post!(&self, macro_reexport, attr.span, - "macros re-exports are experimental \ - and possibly buggy"); - } } ast::ItemKind::ForeignMod(ref foreign_module) => { @@ -1546,11 +1559,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { function may change over time, for now \ a top-level `fn main()` is required"); } - if let Some(attr) = attr::find_by_name(&i.attrs[..], "must_use") { - gate_feature_post!(&self, fn_must_use, attr.span, - "`#[must_use]` on functions is experimental", - GateStrength::Soft); - } } ast::ItemKind::Struct(..) => { @@ -1582,7 +1590,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { "trait aliases are not yet fully implemented"); } - ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, ref impl_items) => { + ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, _) => { if polarity == ast::ImplPolarity::Negative { gate_feature_post!(&self, optin_builtin_traits, i.span, @@ -1595,16 +1603,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { i.span, "specialization is unstable"); } - - for impl_item in impl_items { - if let ast::ImplItemKind::Method(..) = impl_item.node { - if let Some(attr) = attr::find_by_name(&impl_item.attrs[..], "must_use") { - gate_feature_post!(&self, fn_must_use, attr.span, - "`#[must_use]` on methods is experimental", - GateStrength::Soft); - } - } - } } ast::ItemKind::Trait(ast::IsAuto::Yes, ..) => { @@ -1657,10 +1655,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, never_type, ty.span, "The `!` type is experimental"); } - ast::TyKind::TraitObject(_, ast::TraitObjectSyntax::Dyn) => { - gate_feature_post!(&self, dyn_trait, ty.span, - "`dyn Trait` syntax is unstable"); - } _ => {} } visit::walk_ty(self, ty) @@ -1842,8 +1836,12 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], crate_edition: Edition) -> Features { - fn feature_removed(span_handler: &Handler, span: Span) { - span_err!(span_handler, span, E0557, "feature has been removed"); + fn feature_removed(span_handler: &Handler, span: Span, reason: Option<&str>) { + let mut err = struct_span_err!(span_handler, span, E0557, "feature has been removed"); + if let Some(reason) = reason { + err.span_note(span, reason); + } + err.emit(); } let mut features = Features::new(); @@ -1864,7 +1862,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], for mi in list { let name = if let Some(word) = mi.word() { - word.ident.name + word.name() } else { span_err!(span_handler, mi.span, E0556, "malformed feature, expected just one word"); @@ -1876,19 +1874,19 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], set(&mut features, mi.span); feature_checker.collect(&features, mi.span); } - else if let Some(&(_, _, _)) = REMOVED_FEATURES.iter() - .find(|& &(n, _, _)| name == n) + else if let Some(&(.., reason)) = REMOVED_FEATURES.iter() + .find(|& &(n, ..)| name == n) .or_else(|| STABLE_REMOVED_FEATURES.iter() - .find(|& &(n, _, _)| name == n)) { - feature_removed(span_handler, mi.span); + .find(|& &(n, ..)| name == n)) { + feature_removed(span_handler, mi.span, reason); } - else if let Some(&(_, _, _)) = ACCEPTED_FEATURES.iter() - .find(|& &(n, _, _)| name == n) { + else if let Some(&(..)) = ACCEPTED_FEATURES.iter() + .find(|& &(n, ..)| name == n) { features.declared_stable_lang_features.push((name, mi.span)); } else if let Some(&edition) = ALL_EDITIONS.iter() .find(|e| name == e.feature_name()) { if edition <= crate_edition { - feature_removed(span_handler, mi.span); + feature_removed(span_handler, mi.span, None); } else { for &(.., f_edition, set) in ACTIVE_FEATURES.iter() { if let Some(f_edition) = f_edition { diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs index b4f34fb12e3..2f15e75093b 100644 --- a/src/libsyntax/json.rs +++ b/src/libsyntax/json.rs @@ -23,7 +23,7 @@ use codemap::{CodeMap, FilePathMapping}; use syntax_pos::{self, MacroBacktrace, Span, SpanLabel, MultiSpan}; use errors::registry::Registry; use errors::{DiagnosticBuilder, SubDiagnostic, CodeSuggestion, CodeMapper}; -use errors::DiagnosticId; +use errors::{DiagnosticId, Applicability}; use errors::emitter::{Emitter, EmitterWriter}; use rustc_data_structures::sync::{self, Lrc}; @@ -39,7 +39,7 @@ pub struct JsonEmitter { cm: Lrc<CodeMapper + sync::Send + sync::Sync>, pretty: bool, /// Whether "approximate suggestions" are enabled in the config - approximate_suggestions: bool, + suggestion_applicability: bool, ui_testing: bool, } @@ -47,13 +47,13 @@ impl JsonEmitter { pub fn stderr(registry: Option<Registry>, code_map: Lrc<CodeMap>, pretty: bool, - approximate_suggestions: bool) -> JsonEmitter { + suggestion_applicability: bool) -> JsonEmitter { JsonEmitter { dst: Box::new(io::stderr()), registry, cm: code_map, pretty, - approximate_suggestions, + suggestion_applicability, ui_testing: false, } } @@ -68,13 +68,13 @@ impl JsonEmitter { registry: Option<Registry>, code_map: Lrc<CodeMap>, pretty: bool, - approximate_suggestions: bool) -> JsonEmitter { + suggestion_applicability: bool) -> JsonEmitter { JsonEmitter { dst, registry, cm: code_map, pretty, - approximate_suggestions, + suggestion_applicability, ui_testing: false, } } @@ -138,7 +138,7 @@ struct DiagnosticSpan { suggested_replacement: Option<String>, /// If the suggestion is approximate #[rustc_serialize_exclude_null] - suggestion_approximate: Option<bool>, + suggestion_applicability: Option<Applicability>, /// Macro invocations that created the code at this span, if any. expansion: Option<Box<DiagnosticSpanMacroExpansion>>, } @@ -239,7 +239,7 @@ impl Diagnostic { impl DiagnosticSpan { fn from_span_label(span: SpanLabel, - suggestion: Option<(&String, bool)>, + suggestion: Option<(&String, Applicability)>, je: &JsonEmitter) -> DiagnosticSpan { Self::from_span_etc(span.span, @@ -252,7 +252,7 @@ impl DiagnosticSpan { fn from_span_etc(span: Span, is_primary: bool, label: Option<String>, - suggestion: Option<(&String, bool)>, + suggestion: Option<(&String, Applicability)>, je: &JsonEmitter) -> DiagnosticSpan { // obtain the full backtrace from the `macro_backtrace` @@ -272,7 +272,7 @@ impl DiagnosticSpan { fn from_span_full(span: Span, is_primary: bool, label: Option<String>, - suggestion: Option<(&String, bool)>, + suggestion: Option<(&String, Applicability)>, mut backtrace: vec::IntoIter<MacroBacktrace>, je: &JsonEmitter) -> DiagnosticSpan { @@ -301,7 +301,7 @@ impl DiagnosticSpan { }) }); - let suggestion_approximate = if je.approximate_suggestions { + let suggestion_applicability = if je.suggestion_applicability { suggestion.map(|x| x.1) } else { None @@ -318,7 +318,7 @@ impl DiagnosticSpan { is_primary, text: DiagnosticSpanLine::from_span(span, je), suggested_replacement: suggestion.map(|x| x.0.clone()), - suggestion_approximate, + suggestion_applicability, expansion: backtrace_step, label, } @@ -344,7 +344,7 @@ impl DiagnosticSpan { }; DiagnosticSpan::from_span_label(span_label, Some((&suggestion_inner.snippet, - suggestion.approximate)), + suggestion.applicability)), je) }) }) diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 870ce1926ad..f148aaf7267 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -25,6 +25,7 @@ #![feature(non_exhaustive)] #![feature(const_atomic_usize_new)] #![feature(rustc_attrs)] +#![feature(str_escape)] #![recursion_limit="256"] diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index 90f08ab1468..cceed589212 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -149,7 +149,7 @@ impl<'a> Parser<'a> { }; Ok(if let Some(meta) = meta { self.bump(); - (ast::Path::from_ident(meta.ident), meta.node.tokens(meta.span)) + (meta.ident, meta.node.tokens(meta.span)) } else { (self.parse_path(PathStyle::Mod)?, self.parse_tokens()) }) @@ -225,9 +225,10 @@ impl<'a> Parser<'a> { } let lo = self.span; - let ident = self.parse_ident()?; + let ident = self.parse_path(PathStyle::Mod)?; let node = self.parse_meta_item_kind()?; - Ok(ast::MetaItem { ident, node: node, span: lo.to(self.prev_span) }) + let span = lo.to(self.prev_span); + Ok(ast::MetaItem { ident, node, span }) } pub fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> { diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index ff09c6aa2f0..f252020bc31 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -298,14 +298,10 @@ pub fn char_lit(lit: &str, diag: Option<(Span, &Handler)>) -> (char, isize) { } } -pub fn escape_default(s: &str) -> String { - s.chars().map(char::escape_default).flat_map(|x| x).collect() -} - /// Parse a string representing a string literal into its final form. Does /// unescaping. pub fn str_lit(lit: &str, diag: Option<(Span, &Handler)>) -> String { - debug!("parse_str_lit: given {}", escape_default(lit)); + debug!("str_lit: given {}", lit.escape_default()); let mut res = String::with_capacity(lit.len()); let error = |i| format!("lexer should have rejected {} at {}", lit, i); @@ -374,7 +370,7 @@ pub fn str_lit(lit: &str, diag: Option<(Span, &Handler)>) -> String { /// Parse a string representing a raw string literal into its final form. The /// only operation this does is convert embedded CRLF into a single LF. pub fn raw_str_lit(lit: &str) -> String { - debug!("raw_str_lit: given {}", escape_default(lit)); + debug!("raw_str_lit: given {}", lit.escape_default()); let mut res = String::with_capacity(lit.len()); let mut chars = lit.chars().peekable(); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 324cadc84e8..bf4a68679df 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1958,16 +1958,16 @@ impl<'a> Parser<'a> { let meta_ident = match self.token { token::Interpolated(ref nt) => match nt.0 { token::NtMeta(ref meta) => match meta.node { - ast::MetaItemKind::Word => Some(meta.ident), + ast::MetaItemKind::Word => Some(meta.ident.clone()), _ => None, }, _ => None, }, _ => None, }; - if let Some(ident) = meta_ident { + if let Some(path) = meta_ident { self.bump(); - return Ok(ast::Path::from_ident(ident)); + return Ok(path); } self.parse_path(style) } @@ -2042,7 +2042,7 @@ impl<'a> Parser<'a> { }) } - fn check_lifetime(&mut self) -> bool { + pub fn check_lifetime(&mut self) -> bool { self.expected_tokens.push(TokenType::Lifetime); self.token.is_lifetime() } diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 44394384c7a..938711ca1d4 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -277,9 +277,10 @@ impl Token { DotDot | DotDotDot | DotDotEq | // range notation Lt | BinOp(Shl) | // associated path ModSep | // global path + Lifetime(..) | // labeled loop Pound => true, // expression attributes Interpolated(ref nt) => match nt.0 { - NtIdent(..) | NtExpr(..) | NtBlock(..) | NtPath(..) => true, + NtIdent(..) | NtExpr(..) | NtBlock(..) | NtPath(..) | NtLifetime(..) => true, _ => false, }, _ => false, diff --git a/src/libsyntax/print/pp.rs b/src/libsyntax/print/pp.rs index 5c4bf47a6db..e7bd369053c 100644 --- a/src/libsyntax/print/pp.rs +++ b/src/libsyntax/print/pp.rs @@ -247,12 +247,14 @@ pub fn mk_printer<'a>(out: Box<io::Write+'a>, linewidth: usize) -> Printer<'a> { debug!("mk_printer {}", linewidth); Printer { out, - buf_len: n, + buf_max_len: n, margin: linewidth as isize, space: linewidth as isize, left: 0, right: 0, - buf: vec![BufEntry { token: Token::Eof, size: 0 }; n], + // Initialize a single entry; advance_right() will extend it on demand + // up to `buf_max_len` elements. + buf: vec![BufEntry::default()], left_total: 0, right_total: 0, scan_stack: VecDeque::new(), @@ -263,7 +265,7 @@ pub fn mk_printer<'a>(out: Box<io::Write+'a>, linewidth: usize) -> Printer<'a> { pub struct Printer<'a> { out: Box<io::Write+'a>, - buf_len: usize, + buf_max_len: usize, /// Width of lines we're constrained to margin: isize, /// Number of spaces left on line @@ -297,6 +299,12 @@ struct BufEntry { size: isize, } +impl Default for BufEntry { + fn default() -> Self { + BufEntry { token: Token::Eof, size: 0 } + } +} + impl<'a> Printer<'a> { pub fn last_token(&mut self) -> Token { self.buf[self.right].token.clone() @@ -322,7 +330,9 @@ impl<'a> Printer<'a> { self.right_total = 1; self.left = 0; self.right = 0; - } else { self.advance_right(); } + } else { + self.advance_right(); + } debug!("pp Begin({})/buffer Vec<{},{}>", b.offset, self.left, self.right); self.buf[self.right] = BufEntry { token: token, size: -self.right_total }; @@ -349,7 +359,9 @@ impl<'a> Printer<'a> { self.right_total = 1; self.left = 0; self.right = 0; - } else { self.advance_right(); } + } else { + self.advance_right(); + } debug!("pp Break({})/buffer Vec<{},{}>", b.offset, self.left, self.right); self.check_stack(0); @@ -408,7 +420,11 @@ impl<'a> Printer<'a> { } pub fn advance_right(&mut self) { self.right += 1; - self.right %= self.buf_len; + self.right %= self.buf_max_len; + // Extend the buf if necessary. + if self.right == self.buf.len() { + self.buf.push(BufEntry::default()); + } assert_ne!(self.right, self.left); } pub fn advance_left(&mut self) -> io::Result<()> { @@ -438,7 +454,7 @@ impl<'a> Printer<'a> { } self.left += 1; - self.left %= self.buf_len; + self.left %= self.buf_max_len; left_size = self.buf[self.left].size; } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 88860df10e2..d8228e2b28b 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -656,7 +656,7 @@ pub trait PrintState<'a> { style: ast::StrStyle) -> io::Result<()> { let st = match style { ast::StrStyle::Cooked => { - (format!("\"{}\"", parse::escape_default(st))) + (format!("\"{}\"", st.escape_default())) } ast::StrStyle::Raw(n) => { (format!("r{delim}\"{string}\"{delim}", @@ -714,6 +714,22 @@ pub trait PrintState<'a> { Ok(()) } + fn print_attribute_path(&mut self, path: &ast::Path) -> io::Result<()> { + for (i, segment) in path.segments.iter().enumerate() { + if i > 0 { + self.writer().word("::")? + } + if segment.ident.name != keywords::CrateRoot.name() && + segment.ident.name != keywords::DollarCrate.name() + { + self.writer().word(&segment.ident.name.as_str())?; + } else if segment.ident.name == keywords::DollarCrate.name() { + self.print_dollar_crate(segment.ident.span.ctxt())?; + } + } + Ok(()) + } + fn print_attribute(&mut self, attr: &ast::Attribute) -> io::Result<()> { self.print_attribute_inline(attr, false) } @@ -735,17 +751,7 @@ pub trait PrintState<'a> { if let Some(mi) = attr.meta() { self.print_meta_item(&mi)? } else { - for (i, segment) in attr.path.segments.iter().enumerate() { - if i > 0 { - self.writer().word("::")? - } - if segment.ident.name != keywords::CrateRoot.name() && - segment.ident.name != keywords::DollarCrate.name() { - self.writer().word(&segment.ident.name.as_str())?; - } else if segment.ident.name == keywords::DollarCrate.name() { - self.print_dollar_crate(segment.ident.span.ctxt())?; - } - } + self.print_attribute_path(&attr.path)?; self.writer().space()?; self.print_tts(attr.tokens.clone())?; } @@ -767,16 +773,15 @@ pub trait PrintState<'a> { fn print_meta_item(&mut self, item: &ast::MetaItem) -> io::Result<()> { self.ibox(INDENT_UNIT)?; match item.node { - ast::MetaItemKind::Word => { - self.writer().word(&item.ident.name.as_str())?; - } + ast::MetaItemKind::Word => self.print_attribute_path(&item.ident)?, ast::MetaItemKind::NameValue(ref value) => { - self.word_space(&item.ident.name.as_str())?; + self.print_attribute_path(&item.ident)?; + self.writer().space()?; self.word_space("=")?; self.print_literal(value)?; } ast::MetaItemKind::List(ref items) => { - self.writer().word(&item.ident.name.as_str())?; + self.print_attribute_path(&item.ident)?; self.popen()?; self.commasep(Consistent, &items[..], diff --git a/src/libsyntax_ext/concat_idents.rs b/src/libsyntax_ext/concat_idents.rs index 544b1410d3d..b8345e7cf40 100644 --- a/src/libsyntax_ext/concat_idents.rs +++ b/src/libsyntax_ext/concat_idents.rs @@ -31,6 +31,11 @@ pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt, return base::DummyResult::expr(sp); } + if tts.is_empty() { + cx.span_err(sp, "concat_idents! takes 1 or more arguments."); + return DummyResult::expr(sp); + } + let mut res_str = String::new(); for (i, e) in tts.iter().enumerate() { if i & 1 == 1 { diff --git a/src/libsyntax_ext/deriving/custom.rs b/src/libsyntax_ext/deriving/custom.rs index 5fd5e299488..76da1746a03 100644 --- a/src/libsyntax_ext/deriving/custom.rs +++ b/src/libsyntax_ext/deriving/custom.rs @@ -22,11 +22,9 @@ struct MarkAttrs<'a>(&'a [ast::Name]); impl<'a> Visitor<'a> for MarkAttrs<'a> { fn visit_attribute(&mut self, attr: &Attribute) { - if let Some(name) = attr.name() { - if self.0.contains(&name) { - mark_used(attr); - mark_known(attr); - } + if self.0.contains(&attr.name()) { + mark_used(attr); + mark_known(attr); } } diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index becd70149fd..80f65957c39 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -472,7 +472,7 @@ impl<'a> TraitDef<'a> { attrs.extend(item.attrs .iter() .filter(|a| { - a.name().is_some() && match &*a.name().unwrap().as_str() { + match &*a.name().as_str() { "allow" | "warn" | "deny" | "forbid" | "stable" | "unstable" => true, _ => false, } diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 5e96b5ce673..658408519b9 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -21,6 +21,7 @@ use symbol::{Ident, Symbol}; use serialize::{Encodable, Decodable, Encoder, Decoder}; use std::collections::HashMap; +use rustc_data_structures::fx::FxHashSet; use std::fmt; /// A SyntaxContext represents a chain of macro expansions (represented by marks). @@ -117,6 +118,32 @@ impl Mark { true }) } + + /// Computes a mark such that both input marks are descendants of (or equal to) the returned + /// mark. That is, the following holds: + /// + /// ```rust + /// let la = least_ancestor(a, b); + /// assert!(a.is_descendant_of(la)) + /// assert!(b.is_descendant_of(la)) + /// ``` + pub fn least_ancestor(mut a: Mark, mut b: Mark) -> Mark { + HygieneData::with(|data| { + // Compute the path from a to the root + let mut a_path = FxHashSet::<Mark>(); + while a != Mark::root() { + a_path.insert(a); + a = data.marks[a.0 as usize].parent; + } + + // While the path from b to the root hasn't intersected, move up the tree + while !a_path.contains(&b) { + b = data.marks[b.0 as usize].parent; + } + + b + }) + } } pub struct HygieneData { @@ -238,6 +265,22 @@ impl SyntaxContext { }) } + /// Pulls a single mark off of the syntax context. This effectively moves the + /// context up one macro definition level. That is, if we have a nested macro + /// definition as follows: + /// + /// ```rust + /// macro_rules! f { + /// macro_rules! g { + /// ... + /// } + /// } + /// ``` + /// + /// and we have a SyntaxContext that is referring to something declared by an invocation + /// of g (call it g1), calling remove_mark will result in the SyntaxContext for the + /// invocation of f that created g1. + /// Returns the mark that was removed. pub fn remove_mark(&mut self) -> Mark { HygieneData::with(|data| { let outer_mark = data.syntax_contexts[self.0 as usize].outer_mark; diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 9a7d1fd8ee6..8b4a3ea26a1 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -291,6 +291,12 @@ impl Span { self.ctxt().outer().expn_info().map(|info| info.call_site.source_callsite()).unwrap_or(self) } + /// The `Span` for the tokens in the previous macro expansion from which `self` was generated, + /// if any + pub fn parent(self) -> Option<Span> { + self.ctxt().outer().expn_info().map(|i| i.call_site) + } + /// Return the source callee. /// /// Returns None if the supplied span has no expansion trace, @@ -1144,13 +1150,17 @@ pub struct CharPos(pub usize); // have been unsuccessful impl Pos for BytePos { + #[inline(always)] fn from_usize(n: usize) -> BytePos { BytePos(n as u32) } + + #[inline(always)] fn to_usize(&self) -> usize { let BytePos(n) = *self; n as usize } } impl Add for BytePos { type Output = BytePos; + #[inline(always)] fn add(self, rhs: BytePos) -> BytePos { BytePos((self.to_usize() + rhs.to_usize()) as u32) } @@ -1159,6 +1169,7 @@ impl Add for BytePos { impl Sub for BytePos { type Output = BytePos; + #[inline(always)] fn sub(self, rhs: BytePos) -> BytePos { BytePos((self.to_usize() - rhs.to_usize()) as u32) } @@ -1177,13 +1188,17 @@ impl Decodable for BytePos { } impl Pos for CharPos { + #[inline(always)] fn from_usize(n: usize) -> CharPos { CharPos(n) } + + #[inline(always)] fn to_usize(&self) -> usize { let CharPos(n) = *self; n } } impl Add for CharPos { type Output = CharPos; + #[inline(always)] fn add(self, rhs: CharPos) -> CharPos { CharPos(self.to_usize() + rhs.to_usize()) } @@ -1192,6 +1207,7 @@ impl Add for CharPos { impl Sub for CharPos { type Output = CharPos; + #[inline(always)] fn sub(self, rhs: CharPos) -> CharPos { CharPos(self.to_usize() - rhs.to_usize()) } diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 556ee162c6e..4a8b1e8b1c1 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -18,6 +18,7 @@ use {Span, DUMMY_SP, GLOBALS}; use rustc_data_structures::fx::FxHashMap; use serialize::{Decodable, Decoder, Encodable, Encoder}; use std::fmt; +use std::cmp::{PartialEq, Ordering, PartialOrd, Ord}; use std::hash::{Hash, Hasher}; #[derive(Copy, Clone, Eq)] @@ -36,6 +37,11 @@ impl Ident { Ident::new(name, DUMMY_SP) } + /// Maps an interned string to an identifier with an empty syntax context. + pub fn from_interned_str(string: InternedString) -> Ident { + Ident::with_empty_ctxt(string.as_symbol()) + } + /// Maps a string to an identifier with an empty syntax context. pub fn from_str(string: &str) -> Ident { Ident::with_empty_ctxt(Symbol::intern(string)) @@ -138,14 +144,20 @@ impl Symbol { with_interner(|interner| interner.gensymed(self)) } - pub fn as_str(self) -> InternedString { + pub fn as_str(self) -> LocalInternedString { with_interner(|interner| unsafe { - InternedString { + LocalInternedString { string: ::std::mem::transmute::<&str, &str>(interner.get(self)) } }) } + pub fn as_interned_str(self) -> InternedString { + with_interner(|interner| InternedString { + symbol: interner.interned(self) + }) + } + pub fn as_u32(self) -> u32 { self.0 } @@ -365,84 +377,208 @@ fn with_interner<T, F: FnOnce(&mut Interner) -> T>(f: F) -> T { GLOBALS.with(|globals| f(&mut *globals.symbol_interner.lock())) } -/// Represents a string stored in the thread-local interner. Because the -/// interner lives for the life of the thread, this can be safely treated as an -/// immortal string, as long as it never crosses between threads. -/// -/// FIXME(pcwalton): You must be careful about what you do in the destructors -/// of objects stored in TLS, because they may run after the interner is -/// destroyed. In particular, they must not access string contents. This can -/// be fixed in the future by just leaking all strings until thread death -/// somehow. +/// Represents a string stored in the interner. Because the interner outlives any thread +/// which uses this type, we can safely treat `string` which points to interner data, +/// as an immortal string, as long as this type never crosses between threads. +// FIXME: Ensure that the interner outlives any thread which uses LocalInternedString, +// by creating a new thread right after constructing the interner #[derive(Clone, Copy, Hash, PartialOrd, Eq, Ord)] -pub struct InternedString { +pub struct LocalInternedString { string: &'static str, } -impl<U: ?Sized> ::std::convert::AsRef<U> for InternedString where str: ::std::convert::AsRef<U> { +impl LocalInternedString { + pub fn as_interned_str(self) -> InternedString { + InternedString { + symbol: Symbol::intern(self.string) + } + } +} + +impl<U: ?Sized> ::std::convert::AsRef<U> for LocalInternedString +where + str: ::std::convert::AsRef<U> +{ fn as_ref(&self) -> &U { self.string.as_ref() } } -impl<T: ::std::ops::Deref<Target = str>> ::std::cmp::PartialEq<T> for InternedString { +impl<T: ::std::ops::Deref<Target = str>> ::std::cmp::PartialEq<T> for LocalInternedString { fn eq(&self, other: &T) -> bool { self.string == other.deref() } } -impl ::std::cmp::PartialEq<InternedString> for str { - fn eq(&self, other: &InternedString) -> bool { +impl ::std::cmp::PartialEq<LocalInternedString> for str { + fn eq(&self, other: &LocalInternedString) -> bool { self == other.string } } -impl<'a> ::std::cmp::PartialEq<InternedString> for &'a str { - fn eq(&self, other: &InternedString) -> bool { +impl<'a> ::std::cmp::PartialEq<LocalInternedString> for &'a str { + fn eq(&self, other: &LocalInternedString) -> bool { *self == other.string } } -impl ::std::cmp::PartialEq<InternedString> for String { - fn eq(&self, other: &InternedString) -> bool { +impl ::std::cmp::PartialEq<LocalInternedString> for String { + fn eq(&self, other: &LocalInternedString) -> bool { self == other.string } } -impl<'a> ::std::cmp::PartialEq<InternedString> for &'a String { - fn eq(&self, other: &InternedString) -> bool { +impl<'a> ::std::cmp::PartialEq<LocalInternedString> for &'a String { + fn eq(&self, other: &LocalInternedString) -> bool { *self == other.string } } -impl !Send for InternedString { } +impl !Send for LocalInternedString {} +impl !Sync for LocalInternedString {} -impl ::std::ops::Deref for InternedString { +impl ::std::ops::Deref for LocalInternedString { type Target = str; fn deref(&self) -> &str { self.string } } -impl fmt::Debug for InternedString { +impl fmt::Debug for LocalInternedString { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(self.string, f) } } -impl fmt::Display for InternedString { +impl fmt::Display for LocalInternedString { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(self.string, f) } } +impl Decodable for LocalInternedString { + fn decode<D: Decoder>(d: &mut D) -> Result<LocalInternedString, D::Error> { + Ok(Symbol::intern(&d.read_str()?).as_str()) + } +} + +impl Encodable for LocalInternedString { + fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_str(self.string) + } +} + +/// Represents a string stored in the string interner +#[derive(Clone, Copy, Eq)] +pub struct InternedString { + symbol: Symbol, +} + +impl InternedString { + pub fn with<F: FnOnce(&str) -> R, R>(self, f: F) -> R { + let str = with_interner(|interner| { + interner.get(self.symbol) as *const str + }); + // This is safe because the interner keeps string alive until it is dropped. + // We can access it because we know the interner is still alive since we use a + // scoped thread local to access it, and it was alive at the begining of this scope + unsafe { f(&*str) } + } + + pub fn as_symbol(self) -> Symbol { + self.symbol + } + + pub fn as_str(self) -> LocalInternedString { + self.symbol.as_str() + } +} + +impl Hash for InternedString { + fn hash<H: Hasher>(&self, state: &mut H) { + self.with(|str| str.hash(state)) + } +} + +impl PartialOrd<InternedString> for InternedString { + fn partial_cmp(&self, other: &InternedString) -> Option<Ordering> { + if self.symbol == other.symbol { + return Some(Ordering::Equal); + } + self.with(|self_str| other.with(|other_str| self_str.partial_cmp(&other_str))) + } +} + +impl Ord for InternedString { + fn cmp(&self, other: &InternedString) -> Ordering { + if self.symbol == other.symbol { + return Ordering::Equal; + } + self.with(|self_str| other.with(|other_str| self_str.cmp(&other_str))) + } +} + +impl<T: ::std::ops::Deref<Target = str>> PartialEq<T> for InternedString { + fn eq(&self, other: &T) -> bool { + self.with(|string| string == other.deref()) + } +} + +impl PartialEq<InternedString> for InternedString { + fn eq(&self, other: &InternedString) -> bool { + self.symbol == other.symbol + } +} + +impl PartialEq<InternedString> for str { + fn eq(&self, other: &InternedString) -> bool { + other.with(|string| self == string) + } +} + +impl<'a> PartialEq<InternedString> for &'a str { + fn eq(&self, other: &InternedString) -> bool { + other.with(|string| *self == string) + } +} + +impl PartialEq<InternedString> for String { + fn eq(&self, other: &InternedString) -> bool { + other.with(|string| self == string) + } +} + +impl<'a> PartialEq<InternedString> for &'a String { + fn eq(&self, other: &InternedString) -> bool { + other.with(|string| *self == string) + } +} + +impl ::std::convert::From<InternedString> for String { + fn from(val: InternedString) -> String { + val.as_symbol().to_string() + } +} + +impl fmt::Debug for InternedString { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.with(|str| fmt::Debug::fmt(&str, f)) + } +} + +impl fmt::Display for InternedString { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.with(|str| fmt::Display::fmt(&str, f)) + } +} + impl Decodable for InternedString { fn decode<D: Decoder>(d: &mut D) -> Result<InternedString, D::Error> { - Ok(Symbol::intern(&d.read_str()?).as_str()) + Ok(Symbol::intern(&d.read_str()?).as_interned_str()) } } impl Encodable for InternedString { fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_str(self.string) + self.with(|string| s.emit_str(string)) } } diff --git a/src/stage0.txt b/src/stage0.txt index e8db3358cf0..a5ad2b315a1 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -12,7 +12,7 @@ # source tarball for a stable release you'll likely see `1.x.0` for rustc and # `0.x.0` for Cargo where they were released on `date`. -date: 2018-04-04 +date: 2018-04-24 rustc: beta cargo: beta diff --git a/src/test/codegen/align-struct.rs b/src/test/codegen/align-struct.rs index 155319cb154..f306608f432 100644 --- a/src/test/codegen/align-struct.rs +++ b/src/test/codegen/align-struct.rs @@ -29,7 +29,6 @@ pub enum Enum4 { A(i32), B(i32), } -// CHECK: %Enum4 = type { [0 x i32], i32, [1 x i32] } // CHECK: %"Enum4::A" = type { [1 x i32], i32, [0 x i32] } pub enum Enum64 { @@ -59,7 +58,7 @@ pub fn nested64(a: Align64, b: i32, c: i32, d: i8) -> Nested64 { // CHECK-LABEL: @enum4 #[no_mangle] pub fn enum4(a: i32) -> Enum4 { -// CHECK: %e4 = alloca %Enum4, align 4 +// CHECK: %e4 = alloca { i32, i32 }, align 4 let e4 = Enum4::A(a); e4 } diff --git a/src/test/codegen/call-metadata.rs b/src/test/codegen/call-metadata.rs new file mode 100644 index 00000000000..20d42ed852d --- /dev/null +++ b/src/test/codegen/call-metadata.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. + +// Checks that range metadata gets emitted on calls to functions returning a +// scalar value. + +// compile-flags: -C no-prepopulate-passes +// min-llvm-version 4.0 + + +#![crate_type = "lib"] + +pub fn test() { + // CHECK: call i8 @some_true(), !range [[R0:![0-9]+]] + // CHECK: [[R0]] = !{i8 0, i8 3} + some_true(); +} + +#[no_mangle] +fn some_true() -> Option<bool> { + Some(true) +} diff --git a/src/test/compile-fail/macro-reexport-malformed-2.rs b/src/test/codegen/force-frame-pointers.rs index 5f741d010de..f70e3667198 100644 --- a/src/test/compile-fail/macro-reexport-malformed-2.rs +++ b/src/test/codegen/force-frame-pointers.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -7,10 +7,10 @@ // <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 -C force-frame-pointers=y -#![no_std] -#![feature(macro_reexport)] +#![crate_type="lib"] -#[allow(unused_extern_crates)] -#[macro_reexport="foo"] //~ ERROR bad macro re-export -extern crate std; +// CHECK: attributes #{{.*}} "no-frame-pointer-elim"="true" +pub fn foo() {} diff --git a/src/test/codegen/function-arguments.rs b/src/test/codegen/function-arguments.rs index de302c69056..40a9ea5a181 100644 --- a/src/test/codegen/function-arguments.rs +++ b/src/test/codegen/function-arguments.rs @@ -145,6 +145,18 @@ pub fn return_slice(x: &[u16]) -> &[u16] { x } +// CHECK: { i16, i16 } @enum_id_1(i16 %x.0, i16 %x.1) +#[no_mangle] +pub fn enum_id_1(x: Option<Result<u16, u16>>) -> Option<Result<u16, u16>> { + x +} + +// CHECK: i16 @enum_id_2(i16) +#[no_mangle] +pub fn enum_id_2(x: Option<u8>) -> Option<u8> { + x +} + // CHECK: noalias i8* @allocator() #[no_mangle] #[allocator] diff --git a/src/test/codegen/lifetime_start_end.rs b/src/test/codegen/lifetime_start_end.rs index 62aa93398ac..ea3f0de5d08 100644 --- a/src/test/codegen/lifetime_start_end.rs +++ b/src/test/codegen/lifetime_start_end.rs @@ -25,16 +25,16 @@ pub fn test() { let b = &Some(a); &b; // keep variable in an alloca -// CHECK: [[S_b:%[0-9]+]] = bitcast %"core::option::Option<i32>"** %b to i8* +// CHECK: [[S_b:%[0-9]+]] = bitcast { i32, i32 }** %b to i8* // CHECK: call void @llvm.lifetime.start{{.*}}(i{{[0-9 ]+}}, i8* [[S_b]]) -// CHECK: [[S__4:%[0-9]+]] = bitcast %"core::option::Option<i32>"* %_4 to i8* +// CHECK: [[S__4:%[0-9]+]] = bitcast { i32, i32 }* %_4 to i8* // CHECK: call void @llvm.lifetime.start{{.*}}(i{{[0-9 ]+}}, i8* [[S__4]]) -// CHECK: [[E_b:%[0-9]+]] = bitcast %"core::option::Option<i32>"** %b to i8* +// CHECK: [[E_b:%[0-9]+]] = bitcast { i32, i32 }** %b to i8* // CHECK: call void @llvm.lifetime.end{{.*}}(i{{[0-9 ]+}}, i8* [[E_b]]) -// CHECK: [[E__4:%[0-9]+]] = bitcast %"core::option::Option<i32>"* %_4 to i8* +// CHECK: [[E__4:%[0-9]+]] = bitcast { i32, i32 }* %_4 to i8* // CHECK: call void @llvm.lifetime.end{{.*}}(i{{[0-9 ]+}}, i8* [[E__4]]) } diff --git a/src/test/codegen/noreturnflag.rs b/src/test/codegen/noreturnflag.rs index 24a5a4e44cb..7239223ca20 100644 --- a/src/test/codegen/noreturnflag.rs +++ b/src/test/codegen/noreturnflag.rs @@ -8,17 +8,27 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -g -C no-prepopulate-passes // ignore-tidy-linelength // min-llvm-version 4.0 -// compile-flags: -g -C no-prepopulate-passes - -// CHECK: {{.*}}DISubprogram{{.*}}name: "foo"{{.*}}DIFlagNoReturn +#![crate_type = "lib"] -fn foo() -> ! { +#[no_mangle] +pub fn foo() -> ! { +// CHECK: @foo() unnamed_addr #0 loop {} } -pub fn main() { - foo(); +pub enum EmptyEnum {} + +#[no_mangle] +pub fn bar() -> EmptyEnum { +// CHECK: @bar() unnamed_addr #0 + loop {} } + +// CHECK: attributes #0 = {{{.*}} noreturn {{.*}}} + +// CHECK: DISubprogram(name: "foo", {{.*}} DIFlagNoReturn +// CHECK: DISubprogram(name: "bar", {{.*}} DIFlagNoReturn diff --git a/src/test/codegen/target-feature-on-functions.rs b/src/test/codegen/target-feature-on-functions.rs new file mode 100644 index 00000000000..e3cc2c753e5 --- /dev/null +++ b/src/test/codegen/target-feature-on-functions.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. + +// only-x86_64 +// compile-flags: -C target-feature=+avx + +#![crate_type = "lib"] + +#[no_mangle] +pub fn foo() { + // CHECK: attributes #0 = { {{.*}}"target-features"="+avx"{{.*}} } +} diff --git a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs b/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs index 040f0b661be..fb0f9105b0d 100644 --- a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs +++ b/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs @@ -117,7 +117,7 @@ fn expand_duplicate(cx: &mut ExtCtxt, let copy_name = match mi.node { ast::MetaItemKind::List(ref xs) => { if let Some(word) = xs[0].word() { - word.ident + word.ident.segments.last().unwrap().ident } else { cx.span_err(mi.span, "Expected word"); return; diff --git a/src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates.rs b/src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates.rs index 0dc1c2ab2da..fff433b90ce 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates.rs @@ -24,9 +24,17 @@ use foo::*; #[foo::a] //~ ERROR: paths of length greater than one fn _test() {} +fn _test_inner() { + #![a] // OK +} + #[a] //~ ERROR: custom attributes cannot be applied to modules mod _test2 {} +mod _test2_inner { + #![a] //~ ERROR: custom attributes cannot be applied to modules +} + #[a = y] //~ ERROR: must only be followed by a delimiter token fn _test3() {} @@ -36,19 +44,40 @@ fn _test4() {} #[a () = ] //~ ERROR: must only be followed by a delimiter token fn _test5() {} -fn main() { +fn attrs() { + // Statement, item + #[a] // OK + struct S; + + // Statement, macro + #[a] //~ ERROR: custom attributes cannot be applied to statements + println!(); + + // Statement, semi + #[a] //~ ERROR: custom attributes cannot be applied to statements + S; + + // Statement, local #[a] //~ ERROR: custom attributes cannot be applied to statements let _x = 2; - let _x = #[a] 2; - //~^ ERROR: custom attributes cannot be applied to expressions - - let _x: m!(u32) = 3; - //~^ ERROR: procedural macros cannot be expanded to types - if let m!(Some(_x)) = Some(3) { - //~^ ERROR: procedural macros cannot be expanded to patterns - } - let _x = m!(3); - //~^ ERROR: procedural macros cannot be expanded to expressions - m!(let _x = 3;); - //~^ ERROR: procedural macros cannot be expanded to statements + + // Expr + let _x = #[a] 2; //~ ERROR: custom attributes cannot be applied to expressions + + // Opt expr + let _x = [#[a] 2]; //~ ERROR: custom attributes cannot be applied to expressions + + // Expr macro + let _x = #[a] println!(); //~ ERROR: custom attributes cannot be applied to expressions +} + +fn main() { + let _x: m!(u32) = 3; //~ ERROR: procedural macros cannot be expanded to types + if let m!(Some(_x)) = Some(3) {} //~ ERROR: procedural macros cannot be expanded to patterns + + m!(struct S;); //~ ERROR: procedural macros cannot be expanded to statements + m!(let _x = 3;); //~ ERROR: procedural macros cannot be expanded to statements + + let _x = m!(3); //~ ERROR: procedural macros cannot be expanded to expressions + let _x = [m!(3)]; //~ ERROR: procedural macros cannot be expanded to expressions } diff --git a/src/test/compile-fail/attr-usage-inline.rs b/src/test/compile-fail/attr-usage-inline.rs index c6b9b016331..250905dbdcd 100644 --- a/src/test/compile-fail/attr-usage-inline.rs +++ b/src/test/compile-fail/attr-usage-inline.rs @@ -13,7 +13,7 @@ #[inline] fn f() {} -#[inline] //~ ERROR: attribute should be applied to function +#[inline] //~ ERROR: attribute should be applied to function or closure struct S; fn main() {} diff --git a/src/test/compile-fail/auxiliary/macro_non_reexport_2.rs b/src/test/compile-fail/auxiliary/macro_non_reexport_2.rs deleted file mode 100644 index 910fcd2e367..00000000000 --- a/src/test/compile-fail/auxiliary/macro_non_reexport_2.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![crate_type = "dylib"] - -// Since we load a serialized macro with all its attributes, accidentally -// re-exporting a `#[macro_export] macro_rules!` is something of a concern! -// -// We avoid it at the moment only because of the order in which we do things. - -#[macro_use] #[no_link] -extern crate macro_reexport_1; diff --git a/src/test/compile-fail/borrowck/two-phase-reservation-sharing-interference.rs b/src/test/compile-fail/borrowck/two-phase-reservation-sharing-interference.rs index 1333167b780..1e86603c19e 100644 --- a/src/test/compile-fail/borrowck/two-phase-reservation-sharing-interference.rs +++ b/src/test/compile-fail/borrowck/two-phase-reservation-sharing-interference.rs @@ -10,7 +10,7 @@ // ignore-tidy-linelength -// revisions: nll_beyond nll_target +// revisions: nll_target // The following revisions are disabled due to missing support from two-phase beyond autorefs //[nll_beyond]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z two-phase-beyond-autoref diff --git a/src/test/compile-fail/extern-macro.rs b/src/test/compile-fail/extern-macro.rs index 08269ce5c7e..4267103ab9a 100644 --- a/src/test/compile-fail/extern-macro.rs +++ b/src/test/compile-fail/extern-macro.rs @@ -10,7 +10,7 @@ // #41719 -#![feature(use_extern_macros, proc_macro_path_invoc)] +#![feature(use_extern_macros)] fn main() { enum Foo {} diff --git a/src/test/compile-fail/feature-gate-tool_attributes.rs b/src/test/compile-fail/feature-gate-tool_attributes.rs new file mode 100644 index 00000000000..5a7536ca330 --- /dev/null +++ b/src/test/compile-fail/feature-gate-tool_attributes.rs @@ -0,0 +1,15 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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() { + #[rustfmt::skip] //~ ERROR scoped attribute `rustfmt::skip` is experimental + let x = + 3; +} diff --git a/src/test/compile-fail/impl-trait/impl-generic-mismatch.rs b/src/test/compile-fail/impl-trait/impl-generic-mismatch.rs index eea7ca20957..d6707f59011 100644 --- a/src/test/compile-fail/impl-trait/impl-generic-mismatch.rs +++ b/src/test/compile-fail/impl-trait/impl-generic-mismatch.rs @@ -28,4 +28,15 @@ impl Bar for () { //~^ Error method `bar` has incompatible signature for trait } +// With non-local trait (#49841): + +use std::hash::{Hash, Hasher}; + +struct X; + +impl Hash for X { + fn hash(&self, hasher: &mut impl Hasher) {} + //~^ Error method `hash` has incompatible signature for trait +} + fn main() {} diff --git a/src/test/compile-fail/impl-trait/where-allowed.rs b/src/test/compile-fail/impl-trait/where-allowed.rs index 038eacaf110..2891cd59e3e 100644 --- a/src/test/compile-fail/impl-trait/where-allowed.rs +++ b/src/test/compile-fail/impl-trait/where-allowed.rs @@ -10,7 +10,6 @@ //! A simple test for testing many permutations of allowedness of //! impl Trait -#![feature(dyn_trait)] use std::fmt::Debug; // Allowed diff --git a/src/test/compile-fail/issue-23080-2.rs b/src/test/compile-fail/issue-23080-2.rs index 2aa87f8424b..fc365a4b9aa 100644 --- a/src/test/compile-fail/issue-23080-2.rs +++ b/src/test/compile-fail/issue-23080-2.rs @@ -10,6 +10,8 @@ // ignore-tidy-linelength +//~^^^^^^^^^^^^ ERROR + #![feature(optin_builtin_traits)] unsafe auto trait Trait { @@ -22,5 +24,4 @@ fn call_method<T: Trait>(x: T) {} fn main() { // ICE call_method(()); - //~^ ERROR } diff --git a/src/test/compile-fail/issue-31769.rs b/src/test/compile-fail/issue-31769.rs index 7f73d9076ec..2bd45deeab4 100644 --- a/src/test/compile-fail/issue-31769.rs +++ b/src/test/compile-fail/issue-31769.rs @@ -9,6 +9,6 @@ // except according to those terms. fn main() { - #[inline] struct Foo; //~ ERROR attribute should be applied to function + #[inline] struct Foo; //~ ERROR attribute should be applied to function or closure #[repr(C)] fn foo() {} //~ ERROR attribute should be applied to struct, enum or union } diff --git a/src/test/compile-fail/issue-43988.rs b/src/test/compile-fail/issue-43988.rs index ff1fdaef416..0dfa9f6f0d3 100644 --- a/src/test/compile-fail/issue-43988.rs +++ b/src/test/compile-fail/issue-43988.rs @@ -14,12 +14,12 @@ fn main() { #[inline] let _a = 4; - //~^^ ERROR attribute should be applied to function + //~^^ ERROR attribute should be applied to function or closure #[inline(XYZ)] let _b = 4; - //~^^ ERROR attribute should be applied to function + //~^^ ERROR attribute should be applied to function or closure #[repr(nothing)] let _x = 0; @@ -40,7 +40,7 @@ fn main() { #[inline(ABC)] foo(); - //~^^ ERROR attribute should be applied to function + //~^^ ERROR attribute should be applied to function or closure let _z = #[repr] 1; //~^ ERROR attribute should not be applied to an expression diff --git a/src/test/compile-fail/lint-unused-mut-variables.rs b/src/test/compile-fail/lint-unused-mut-variables.rs index 3c76740d2b5..14d836074dc 100644 --- a/src/test/compile-fail/lint-unused-mut-variables.rs +++ b/src/test/compile-fail/lint-unused-mut-variables.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// revisions: lexical nll +#![cfg_attr(nll, feature(nll))] + // Exercise the unused_mut attribute in some positive and negative cases #![allow(unused_assignments)] @@ -18,15 +21,22 @@ fn main() { // negative cases - let mut a = 3; //~ ERROR: variable does not need to be mutable - let mut a = 2; //~ ERROR: variable does not need to be mutable - let mut b = 3; //~ ERROR: variable does not need to be mutable - let mut a = vec![3]; //~ ERROR: variable does not need to be mutable - let (mut a, b) = (1, 2); //~ ERROR: variable does not need to be mutable - let mut a; //~ ERROR: variable does not need to be mutable + let mut a = 3; //[lexical]~ ERROR: variable does not need to be mutable + //[nll]~^ ERROR: variable does not need to be mutable + let mut a = 2; //[lexical]~ ERROR: variable does not need to be mutable + //[nll]~^ ERROR: variable does not need to be mutable + let mut b = 3; //[lexical]~ ERROR: variable does not need to be mutable + //[nll]~^ ERROR: variable does not need to be mutable + let mut a = vec![3]; //[lexical]~ ERROR: variable does not need to be mutable + //[nll]~^ ERROR: variable does not need to be mutable + let (mut a, b) = (1, 2); //[lexical]~ ERROR: variable does not need to be mutable + //[nll]~^ ERROR: variable does not need to be mutable + let mut a; //[lexical]~ ERROR: variable does not need to be mutable + //[nll]~^ ERROR: variable does not need to be mutable a = 3; - let mut b; //~ ERROR: variable does not need to be mutable + let mut b; //[lexical]~ ERROR: variable does not need to be mutable + //[nll]~^ ERROR: variable does not need to be mutable if true { b = 3; } else { @@ -34,37 +44,45 @@ fn main() { } match 30 { - mut x => {} //~ ERROR: variable does not need to be mutable + mut x => {} //[lexical]~ ERROR: variable does not need to be mutable + //[nll]~^ ERROR: variable does not need to be mutable } match (30, 2) { - (mut x, 1) | //~ ERROR: variable does not need to be mutable + (mut x, 1) | //[lexical]~ ERROR: variable does not need to be mutable + //[nll]~^ ERROR: variable does not need to be mutable (mut x, 2) | (mut x, 3) => { } _ => {} } - let x = |mut y: isize| 10; //~ ERROR: variable does not need to be mutable - fn what(mut foo: isize) {} //~ ERROR: variable does not need to be mutable + let x = |mut y: isize| 10; //[lexical]~ ERROR: variable does not need to be mutable + //[nll]~^ ERROR: variable does not need to be mutable + fn what(mut foo: isize) {} //[lexical]~ ERROR: variable does not need to be mutable + //[nll]~^ ERROR: variable does not need to be mutable - let mut a = &mut 5; //~ ERROR: variable does not need to be mutable + let mut a = &mut 5; //[lexical]~ ERROR: variable does not need to be mutable + //[nll]~^ ERROR: variable does not need to be mutable *a = 4; let mut a = 5; - let mut b = (&mut a,); - *b.0 = 4; //~^ ERROR: variable does not need to be mutable + let mut b = (&mut a,); //[lexical]~ ERROR: variable does not need to be mutable + *b.0 = 4; //[nll]~^ ERROR: variable does not need to be mutable - let mut x = &mut 1; //~ ERROR: variable does not need to be mutable + let mut x = &mut 1; //[lexical]~ ERROR: variable does not need to be mutable + //[nll]~^ ERROR: variable does not need to be mutable let mut f = || { *x += 1; }; f(); fn mut_ref_arg(mut arg : &mut [u8]) -> &mut [u8] { - &mut arg[..] //~^ ERROR: variable does not need to be mutable + &mut arg[..] //[lexical]~^ ERROR: variable does not need to be mutable + //[nll]~^^ ERROR: variable does not need to be mutable } - let mut v : &mut Vec<()> = &mut vec![]; //~ ERROR: variable does not need to be mutable + let mut v : &mut Vec<()> = &mut vec![]; //[lexical]~ ERROR: variable does not need to be mutable + //[nll]~^ ERROR: variable does not need to be mutable v.push(()); // positive cases @@ -76,6 +94,12 @@ fn main() { callback(|| { a.push(3); }); + let mut a = Vec::new(); + callback(|| { + callback(|| { + a.push(3); + }); + }); let (mut a, b) = (1, 2); a = 34; @@ -116,5 +140,6 @@ fn foo(mut a: isize) { fn bar() { #[allow(unused_mut)] let mut a = 3; - let mut b = vec![2]; //~ ERROR: variable does not need to be mutable + let mut b = vec![2]; //[lexical]~ ERROR: variable does not need to be mutable + //[nll]~^ ERROR: variable does not need to be mutable } diff --git a/src/test/compile-fail/macro-reexport-not-locally-visible.rs b/src/test/compile-fail/macro-non-lifetime.rs index 54a74b0e134..a2706e83229 100644 --- a/src/test/compile-fail/macro-reexport-not-locally-visible.rs +++ b/src/test/compile-fail/macro-non-lifetime.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,15 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// aux-build:macro_reexport_1.rs +// Test for issue #50381: non-lifetime passed to :lifetime. -#![feature(macro_reexport)] +#![feature(macro_lifetime_matcher)] -#[macro_reexport(reexported)] -#[no_link] -extern crate macro_reexport_1; +macro_rules! m { ($x:lifetime) => { } } fn main() { - assert_eq!(reexported!(), 3); - //~^ ERROR cannot find macro + m!(a); + //~^ ERROR expected a lifetime, found `a` } diff --git a/src/test/compile-fail/macros-nonfatal-errors.rs b/src/test/compile-fail/macros-nonfatal-errors.rs index 40412087cef..7046ee12b50 100644 --- a/src/test/compile-fail/macros-nonfatal-errors.rs +++ b/src/test/compile-fail/macros-nonfatal-errors.rs @@ -13,7 +13,6 @@ #![feature(asm)] #![feature(trace_macros, concat_idents)] -#![feature(proc_macro_path_invoc)] #[derive(Default)] //~ ERROR enum OrDeriveThis {} diff --git a/src/test/compile-fail/mir_check_cast_unsize.rs b/src/test/compile-fail/mir_check_cast_unsize.rs index e30bed61058..a2c840a7098 100644 --- a/src/test/compile-fail/mir_check_cast_unsize.rs +++ b/src/test/compile-fail/mir_check_cast_unsize.rs @@ -11,7 +11,6 @@ // compile-flags: -Z borrowck=mir #![allow(dead_code)] -#![feature(dyn_trait)] use std::fmt::Debug; diff --git a/src/test/compile-fail/nll/match-guards-always-borrow.rs b/src/test/compile-fail/nll/match-guards-always-borrow.rs new file mode 100644 index 00000000000..98553144627 --- /dev/null +++ b/src/test/compile-fail/nll/match-guards-always-borrow.rs @@ -0,0 +1,61 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//revisions: ast mir +//[mir] compile-flags: -Z borrowck=mir + +#![feature(rustc_attrs)] + +// Here is arielb1's basic example from rust-lang/rust#27282 +// that AST borrowck is flummoxed by: + +fn should_reject_destructive_mutate_in_guard() { + match Some(&4) { + None => {}, + ref mut foo if { + (|| { let bar = foo; bar.take() })(); + //[mir]~^ ERROR cannot move out of borrowed content [E0507] + false } => { }, + Some(s) => std::process::exit(*s), + } +} + +// Here below is a case that needs to keep working: we only use the +// binding via immutable-borrow in the guard, and we mutate in the arm +// body. +fn allow_mutate_in_arm_body() { + match Some(&4) { + None => {}, + ref mut foo if foo.is_some() && false => { foo.take(); () } + Some(s) => std::process::exit(*s), + } +} + +// Here below is a case that needs to keep working: we only use the +// binding via immutable-borrow in the guard, and we move into the arm +// body. +fn allow_move_into_arm_body() { + match Some(&4) { + None => {}, + mut foo if foo.is_some() && false => { foo.take(); () } + Some(s) => std::process::exit(*s), + } +} + +// Since this is a compile-fail test that is explicitly encoding the +// different behavior of AST- vs MIR-borrowck where AST-borrowck does +// not error, we need to use rustc_error to placate the test harness +// that wants *some* error to occur. +#[rustc_error] +fn main() { //[ast]~ ERROR compilation successful + should_reject_destructive_mutate_in_guard(); + allow_mutate_in_arm_body(); + allow_move_into_arm_body(); +} diff --git a/src/test/compile-fail/nll/unused-mut-issue-50343.rs b/src/test/compile-fail/nll/unused-mut-issue-50343.rs new file mode 100644 index 00000000000..e9110b8114b --- /dev/null +++ b/src/test/compile-fail/nll/unused-mut-issue-50343.rs @@ -0,0 +1,17 @@ +// 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(nll)] +#![deny(unused_mut)] + +fn main() { + vec![(42, 22)].iter().map(|(mut x, _y)| ()).count(); + //~^ ERROR: variable does not need to be mutable +} diff --git a/src/test/compile-fail/privacy/associated-item-privacy-inherent.rs b/src/test/compile-fail/privacy/associated-item-privacy-inherent.rs index b64829edaa2..63cb6e82c25 100644 --- a/src/test/compile-fail/privacy/associated-item-privacy-inherent.rs +++ b/src/test/compile-fail/privacy/associated-item-privacy-inherent.rs @@ -10,7 +10,6 @@ #![feature(decl_macro, associated_type_defaults)] #![allow(unused, private_in_public)] -#![feature(proc_macro_path_invoc)] mod priv_nominal { pub struct Pub; diff --git a/src/test/compile-fail/privacy/associated-item-privacy-trait.rs b/src/test/compile-fail/privacy/associated-item-privacy-trait.rs index 062dc533617..bdc0c680a92 100644 --- a/src/test/compile-fail/privacy/associated-item-privacy-trait.rs +++ b/src/test/compile-fail/privacy/associated-item-privacy-trait.rs @@ -10,7 +10,6 @@ // ignore-tidy-linelength -#![feature(proc_macro_path_invoc)] #![feature(decl_macro, associated_type_defaults)] #![allow(unused, private_in_public)] diff --git a/src/test/compile-fail/privacy/associated-item-privacy-type-binding.rs b/src/test/compile-fail/privacy/associated-item-privacy-type-binding.rs index 0dfa61a18ab..c25616c5435 100644 --- a/src/test/compile-fail/privacy/associated-item-privacy-type-binding.rs +++ b/src/test/compile-fail/privacy/associated-item-privacy-type-binding.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(proc_macro_path_invoc)] #![feature(decl_macro, associated_type_defaults)] #![allow(unused, private_in_public)] diff --git a/src/test/compile-fail/private-inferred-type-3.rs b/src/test/compile-fail/private-inferred-type-3.rs index 97d6b470d33..0c393f02323 100644 --- a/src/test/compile-fail/private-inferred-type-3.rs +++ b/src/test/compile-fail/private-inferred-type-3.rs @@ -18,7 +18,6 @@ // error-pattern:type `fn(u8) -> ext::PubTupleStruct {ext::PubTupleStruct::{{constructor}}}` is priv // error-pattern:type `for<'r> fn(&'r ext::Pub<u8>) {<ext::Pub<u8>>::priv_method}` is private -#![feature(proc_macro_path_invoc)] #![feature(decl_macro)] extern crate private_inferred_type as ext; diff --git a/src/test/compile-fail/private-inferred-type.rs b/src/test/compile-fail/private-inferred-type.rs index dfc0107e075..5af8b063c16 100644 --- a/src/test/compile-fail/private-inferred-type.rs +++ b/src/test/compile-fail/private-inferred-type.rs @@ -11,7 +11,6 @@ #![feature(associated_consts)] #![feature(decl_macro)] #![allow(private_in_public)] -#![feature(proc_macro_path_invoc)] mod m { fn priv_fn() {} diff --git a/src/test/compile-fail/repr-align.rs b/src/test/compile-fail/repr-align.rs index 7c8eb6a2de9..9b0408de2a4 100644 --- a/src/test/compile-fail/repr-align.rs +++ b/src/test/compile-fail/repr-align.rs @@ -15,7 +15,10 @@ struct A(i32); #[repr(align(15))] //~ ERROR: invalid `repr(align)` attribute: not a power of two struct B(i32); -#[repr(align(4294967296))] //~ ERROR: invalid `repr(align)` attribute: larger than 2147483647 +#[repr(align(4294967296))] //~ ERROR: invalid `repr(align)` attribute: larger than 2^29 struct C(i32); +#[repr(align(536870912))] // ok: this is the largest accepted alignment +struct D(i32); + fn main() {} diff --git a/src/test/compile-fail/trait-bounds-not-on-struct.rs b/src/test/compile-fail/trait-bounds-not-on-struct.rs index 0dd1a4e7d73..1b1a238a941 100644 --- a/src/test/compile-fail/trait-bounds-not-on-struct.rs +++ b/src/test/compile-fail/trait-bounds-not-on-struct.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(dyn_trait)] #![allow(bare_trait_object)] struct Foo; diff --git a/src/test/compile-fail/unknown-tool-name.rs b/src/test/compile-fail/unknown-tool-name.rs new file mode 100644 index 00000000000..c2192a21d90 --- /dev/null +++ b/src/test/compile-fail/unknown-tool-name.rs @@ -0,0 +1,16 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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(tool_attributes)] + +#![foo::bar] //~ ERROR an unknown tool name found in scoped attribute: `foo::bar`. [E0694] + +#[foo::bar] //~ ERROR an unknown tool name found in scoped attribute: `foo::bar`. [E0694] +fn main() {} diff --git a/src/test/compile-fail/unknown_tool_attributes-1.rs b/src/test/compile-fail/unknown_tool_attributes-1.rs new file mode 100644 index 00000000000..ba38c297a11 --- /dev/null +++ b/src/test/compile-fail/unknown_tool_attributes-1.rs @@ -0,0 +1,18 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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. + +// Make sure that 'custom_attributes' feature does not allow scoped attributes. + +#![feature(custom_attributes)] + +#[foo::bar] +//~^ ERROR scoped attribute `foo::bar` is experimental (see issue #44690) [E0658] +//~^^ ERROR an unknown tool name found in scoped attribute: `foo::bar`. [E0694] +fn main() {} diff --git a/src/test/compile-fail/used.rs b/src/test/compile-fail/used.rs new file mode 100644 index 00000000000..f170d9c25f5 --- /dev/null +++ b/src/test/compile-fail/used.rs @@ -0,0 +1,28 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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(used)] + +#[used] +static FOO: u32 = 0; // OK + +#[used] //~ ERROR attribute must be applied to a `static` variable +fn foo() {} + +#[used] //~ ERROR attribute must be applied to a `static` variable +struct Foo {} + +#[used] //~ ERROR attribute must be applied to a `static` variable +trait Bar {} + +#[used] //~ ERROR attribute must be applied to a `static` variable +impl Bar for Foo {} + +fn main() {} diff --git a/src/test/mir-opt/match_false_edges.rs b/src/test/mir-opt/match_false_edges.rs index 53f17861997..a31298a0f51 100644 --- a/src/test/mir-opt/match_false_edges.rs +++ b/src/test/mir-opt/match_false_edges.rs @@ -54,17 +54,17 @@ fn main() { // ... // _2 = std::option::Option<i32>::Some(const 42i32,); // _3 = discriminant(_2); -// _6 = discriminant(_2); -// switchInt(move _6) -> [0isize: bb6, 1isize: bb4, otherwise: bb8]; +// _7 = discriminant(_2); +// switchInt(move _7) -> [0isize: bb6, 1isize: bb4, otherwise: bb8]; // } // bb1: { // resume; // } // bb2: { // arm1 -// StorageLive(_8); -// _8 = _4; -// _1 = (const 1i32, move _8); -// StorageDead(_8); +// StorageLive(_9); +// _9 = _4; +// _1 = (const 1i32, move _9); +// StorageDead(_9); // goto -> bb13; // } // bb3: { // binding3(empty) and arm3 @@ -87,24 +87,26 @@ fn main() { // unreachable; // } // bb9: { // binding1 and guard -// StorageLive(_4); -// _4 = ((_2 as Some).0: i32); -// StorageLive(_7); -// _7 = const guard() -> [return: bb10, unwind: bb1]; +// StorageLive(_5); +// _5 = &((_2 as Some).0: i32); +// StorageLive(_8); +// _8 = const guard() -> [return: bb10, unwind: bb1]; // } // bb10: { // end of guard -// switchInt(move _7) -> [false: bb11, otherwise: bb2]; +// StorageLive(_4); +// _4 = ((_2 as Some).0: i32); +// switchInt(move _8) -> [false: bb11, otherwise: bb2]; // } // bb11: { // to pre_binding2 // falseEdges -> [real: bb5, imaginary: bb5]; // } // bb12: { // bindingNoLandingPads.before.mir2 and arm2 -// StorageLive(_5); -// _5 = ((_2 as Some).0: i32); -// StorageLive(_9); -// _9 = _5; -// _1 = (const 2i32, move _9); -// StorageDead(_9); +// StorageLive(_6); +// _6 = ((_2 as Some).0: i32); +// StorageLive(_10); +// _10 = _6; +// _1 = (const 2i32, move _10); +// StorageDead(_10); // goto -> bb13; // } // bb13: { @@ -118,17 +120,17 @@ fn main() { // ... // _2 = std::option::Option<i32>::Some(const 42i32,); // _3 = discriminant(_2); -// _6 = discriminant(_2); -// switchInt(move _6) -> [0isize: bb5, 1isize: bb4, otherwise: bb8]; +// _7 = discriminant(_2); +// switchInt(move _7) -> [0isize: bb5, 1isize: bb4, otherwise: bb8]; // } // bb1: { // resume; // } // bb2: { // arm1 -// StorageLive(_8); -// _8 = _4; -// _1 = (const 1i32, move _8); -// StorageDead(_8); +// StorageLive(_9); +// _9 = _4; +// _1 = (const 1i32, move _9); +// StorageDead(_9); // goto -> bb13; // } // bb3: { // binding3(empty) and arm3 @@ -151,24 +153,26 @@ fn main() { // unreachable; // } // bb9: { // binding1 and guard -// StorageLive(_4); -// _4 = ((_2 as Some).0: i32); -// StorageLive(_7); -// _7 = const guard() -> [return: bb10, unwind: bb1]; +// StorageLive(_5); +// _5 = &((_2 as Some).0: i32); +// StorageLive(_8); +// _8 = const guard() -> [return: bb10, unwind: bb1]; // } // bb10: { // end of guard -// switchInt(move _7) -> [false: bb11, otherwise: bb2]; +// StorageLive(_4); +// _4 = ((_2 as Some).0: i32); +// switchInt(move _8) -> [false: bb11, otherwise: bb2]; // } // bb11: { // to pre_binding2 // falseEdges -> [real: bb6, imaginary: bb5]; // } // bb12: { // binding2 and arm2 -// StorageLive(_5); -// _5 = ((_2 as Some).0: i32); -// StorageLive(_9); -// _9 = _5; -// _1 = (const 2i32, move _9); -// StorageDead(_9); +// StorageLive(_6); +// _6 = ((_2 as Some).0: i32); +// StorageLive(_10); +// _10 = _6; +// _1 = (const 2i32, move _10); +// StorageDead(_10); // goto -> bb13; // } // bb13: { @@ -182,8 +186,8 @@ fn main() { // ... // _2 = std::option::Option<i32>::Some(const 1i32,); // _3 = discriminant(_2); -// _8 = discriminant(_2); -// switchInt(move _8) -> [1isize: bb4, otherwise: bb5]; +// _10 = discriminant(_2); +// switchInt(move _10) -> [1isize: bb4, otherwise: bb5]; // } // bb1: { // resume; @@ -213,41 +217,45 @@ fn main() { // unreachable; // } // bb9: { // binding1: Some(w) if guard() -// StorageLive(_4); -// _4 = ((_2 as Some).0: i32); -// StorageLive(_9); -// _9 = const guard() -> [return: bb10, unwind: bb1]; +// StorageLive(_5); +// _5 = &((_2 as Some).0: i32); +// StorageLive(_11); +// _11 = const guard() -> [return: bb10, unwind: bb1]; // } // bb10: { //end of guard -// switchInt(move _9) -> [false: bb11, otherwise: bb2]; +// StorageLive(_4); +// _4 = ((_2 as Some).0: i32); +// switchInt(move _11) -> [false: bb11, otherwise: bb2]; // } // bb11: { // to pre_binding2 // falseEdges -> [real: bb5, imaginary: bb5]; // } // bb12: { // binding2 & arm2 -// StorageLive(_5); -// _5 = _2; +// StorageLive(_6); +// _6 = _2; // _1 = const 2i32; // goto -> bb17; // } // bb13: { // binding3: Some(y) if guard2(y) -// StorageLive(_6); -// _6 = ((_2 as Some).0: i32); -// StorageLive(_11); -// StorageLive(_12); -// _12 = _6; -// _11 = const guard2(move _12) -> [return: bb14, unwind: bb1]; +// StorageLive(_8); +// _8 = &((_2 as Some).0: i32); +// StorageLive(_13); +// StorageLive(_14); +// _14 = (*_8); +// _13 = const guard2(move _14) -> [return: bb14, unwind: bb1]; // } // bb14: { // end of guard2 -// StorageDead(_12); -// switchInt(move _11) -> [false: bb15, otherwise: bb3]; +// StorageDead(_14); +// StorageLive(_7); +// _7 = ((_2 as Some).0: i32); +// switchInt(move _13) -> [false: bb15, otherwise: bb3]; // } // bb15: { // to pre_binding4 // falseEdges -> [real: bb7, imaginary: bb7]; // } // bb16: { // binding4 & arm4 -// StorageLive(_7); -// _7 = _2; +// StorageLive(_9); +// _9 = _2; // _1 = const 4i32; // goto -> bb17; // } diff --git a/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-box-dyn-error.rs b/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-box-dyn-error.rs index 219eca6fd21..66a6e6afed3 100644 --- a/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-box-dyn-error.rs +++ b/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-box-dyn-error.rs @@ -11,8 +11,6 @@ // compile-pass // failure-status: 1 -#![feature(dyn_trait)] - use std::error::Error; use std::io; diff --git a/src/test/run-make-fulldeps/extern-prelude/Makefile b/src/test/run-make-fulldeps/extern-prelude/Makefile new file mode 100644 index 00000000000..aa8158c6eb3 --- /dev/null +++ b/src/test/run-make-fulldeps/extern-prelude/Makefile @@ -0,0 +1,12 @@ +-include ../tools.mk + +all: + $(RUSTC) ep-lib.rs + $(RUSTC) ep-vec.rs + + $(RUSTC) basic.rs --extern ep_lib=$(TMPDIR)/libep_lib.rlib + $(RUSTC) shadow-mod.rs --extern ep_lib=$(TMPDIR)/libep_lib.rlib + $(RUSTC) shadow-prelude.rs --extern Vec=$(TMPDIR)/libep_vec.rlib + $(RUSTC) feature-gate.rs --extern ep_lib=$(TMPDIR)/libep_lib.rlib 2>&1 | $(CGREP) "access to extern crates through prelude is experimental" + $(RUSTC) relative-only.rs --extern ep_lib=$(TMPDIR)/libep_lib.rlib 2>&1 | $(CGREP) "unresolved import" + $(RUSTC) relative-only.rs --extern ep_lib=$(TMPDIR)/libep_lib.rlib 2>&1 | $(CGREP) "failed to resolve" diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-reexport.rs b/src/test/run-make-fulldeps/extern-prelude/basic.rs index cfaf913216a..b8d6a772e2a 100644 --- a/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-reexport.rs +++ b/src/test/run-make-fulldeps/extern-prelude/basic.rs @@ -1,4 +1,4 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-test not a test, auxiliary +#![feature(extern_prelude)] -#![feature(macro_reexport)] - -#[macro_reexport(A)] -extern crate derive_a; +fn main() { + let s = ep_lib::S; // It works + s.external(); +} diff --git a/src/test/compile-fail/auxiliary/macro_reexport_1.rs b/src/test/run-make-fulldeps/extern-prelude/ep-lib.rs index aaeccc6e898..dac0a3ce760 100644 --- a/src/test/compile-fail/auxiliary/macro_reexport_1.rs +++ b/src/test/run-make-fulldeps/extern-prelude/ep-lib.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,8 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![crate_type = "dylib"] -#[macro_export] -macro_rules! reexported { - () => ( 3 ) +#![crate_type = "rlib"] + +pub struct S; + +impl S { + pub fn external(&self) {} } diff --git a/src/test/run-make-fulldeps/extern-prelude/ep-vec.rs b/src/test/run-make-fulldeps/extern-prelude/ep-vec.rs new file mode 100644 index 00000000000..f750a26f9e6 --- /dev/null +++ b/src/test/run-make-fulldeps/extern-prelude/ep-vec.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. + +#![crate_type = "rlib"] + +pub fn new(arg1: f32, arg2: ()) {} diff --git a/src/test/run-pass/auxiliary/macro_reexport_1.rs b/src/test/run-make-fulldeps/extern-prelude/feature-gate.rs index aaeccc6e898..49763f3ba6a 100644 --- a/src/test/run-pass/auxiliary/macro_reexport_1.rs +++ b/src/test/run-make-fulldeps/extern-prelude/feature-gate.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![crate_type = "dylib"] -#[macro_export] -macro_rules! reexported { - () => ( 3 ) +fn main() { + let s = ep_lib::S; // Feature error } diff --git a/src/test/compile-fail/macro-reexport-malformed-1.rs b/src/test/run-make-fulldeps/extern-prelude/relative-only.rs index 36a6fce00a1..0cd56b93de6 100644 --- a/src/test/compile-fail/macro-reexport-malformed-1.rs +++ b/src/test/run-make-fulldeps/extern-prelude/relative-only.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,9 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![no_std] -#![feature(macro_reexport)] +// Extern prelude names are not available by absolute paths -#[allow(unused_extern_crates)] -#[macro_reexport] //~ ERROR bad macro re-export -extern crate std; +#![feature(extern_prelude)] + +use ep_lib::S; + +fn main() { + let s = ::ep_lib::S; +} diff --git a/src/test/run-make-fulldeps/extern-prelude/shadow-mod.rs b/src/test/run-make-fulldeps/extern-prelude/shadow-mod.rs new file mode 100644 index 00000000000..52213c8d4f9 --- /dev/null +++ b/src/test/run-make-fulldeps/extern-prelude/shadow-mod.rs @@ -0,0 +1,24 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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. + +// Local module shadows `ep_lib` from extern prelude + +mod ep_lib { + pub struct S; + + impl S { + pub fn internal(&self) {} + } +} + +fn main() { + let s = ep_lib::S; + s.internal(); // OK +} diff --git a/src/test/run-make-fulldeps/extern-prelude/shadow-prelude.rs b/src/test/run-make-fulldeps/extern-prelude/shadow-prelude.rs new file mode 100644 index 00000000000..de1c4d16d39 --- /dev/null +++ b/src/test/run-make-fulldeps/extern-prelude/shadow-prelude.rs @@ -0,0 +1,17 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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. + +// Extern prelude shadows standard library prelude + +#![feature(extern_prelude)] + +fn main() { + let x = Vec::new(0f32, ()); // OK +} diff --git a/src/test/run-make-fulldeps/libtest-json/Makefile b/src/test/run-make-fulldeps/libtest-json/Makefile index ec91ddfb9f9..a0bc8cf6688 100644 --- a/src/test/run-make-fulldeps/libtest-json/Makefile +++ b/src/test/run-make-fulldeps/libtest-json/Makefile @@ -6,7 +6,7 @@ OUTPUT_FILE := $(TMPDIR)/libtest-json-output.json all: $(RUSTC) --test f.rs - $(call RUN,f) -Z unstable-options --test-threads=1 --format=json > $(OUTPUT_FILE) || true + RUST_BACKTRACE=0 $(call RUN,f) -Z unstable-options --test-threads=1 --format=json > $(OUTPUT_FILE) || true cat $(OUTPUT_FILE) | "$(PYTHON)" validate_json.py diff --git a/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs b/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs index 2f80408ac1c..d698af50579 100644 --- a/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs +++ b/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs @@ -112,7 +112,7 @@ fn expand_duplicate(cx: &mut ExtCtxt, let copy_name = match mi.node { ast::MetaItemKind::List(ref xs) => { if let Some(word) = xs[0].word() { - word.ident + word.ident.segments.last().unwrap().ident } else { cx.span_err(mi.span, "Expected word"); return; diff --git a/src/test/run-pass-fulldeps/macro-quote-test.rs b/src/test/run-pass-fulldeps/macro-quote-test.rs index 9bb8f691915..f359735d2f7 100644 --- a/src/test/run-pass-fulldeps/macro-quote-test.rs +++ b/src/test/run-pass-fulldeps/macro-quote-test.rs @@ -13,7 +13,7 @@ // aux-build:hello_macro.rs // ignore-stage1 -#![feature(proc_macro, proc_macro_path_invoc, proc_macro_non_items)] +#![feature(proc_macro, proc_macro_non_items)] extern crate hello_macro; diff --git a/src/test/run-pass/auxiliary/issue-48984-aux.rs b/src/test/run-pass/auxiliary/issue-48984-aux.rs new file mode 100644 index 00000000000..6290279701e --- /dev/null +++ b/src/test/run-pass/auxiliary/issue-48984-aux.rs @@ -0,0 +1,16 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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 = "lib"] +#![crate_name = "issue48984aux"] + +pub trait Foo { type Item; } + +pub trait Bar: Foo<Item=[u8;1]> { } diff --git a/src/test/run-pass/auxiliary/macro_reexport_2.rs b/src/test/run-pass/auxiliary/macro_reexport_2.rs deleted file mode 100644 index 3918be88d86..00000000000 --- a/src/test/run-pass/auxiliary/macro_reexport_2.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![crate_type = "dylib"] -#![feature(macro_reexport)] - -#[macro_reexport(reexported)] -#[macro_use] #[no_link] -extern crate macro_reexport_1; diff --git a/src/test/run-pass/backtrace-debuginfo.rs b/src/test/run-pass/backtrace-debuginfo.rs index 2b82a894363..7bcb4e5ec2d 100644 --- a/src/test/run-pass/backtrace-debuginfo.rs +++ b/src/test/run-pass/backtrace-debuginfo.rs @@ -16,6 +16,7 @@ // "enable" to 0 instead. // compile-flags:-g -Cllvm-args=-enable-tail-merge=0 -Cllvm-args=-opt-bisect-limit=0 +// compile-flags:-Cforce-frame-pointers=yes // ignore-pretty issue #37195 // ignore-cloudabi spawning processes is not supported // ignore-emscripten spawning processes is not supported diff --git a/src/test/run-pass/borrowck/borrowck-unused-mut-locals.rs b/src/test/run-pass/borrowck/borrowck-unused-mut-locals.rs new file mode 100644 index 00000000000..7f1b6ed1701 --- /dev/null +++ b/src/test/run-pass/borrowck/borrowck-unused-mut-locals.rs @@ -0,0 +1,56 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <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(nll)] +#![deny(unused_mut)] + +#[derive(Debug)] +struct A {} + +fn init_a() -> A { + A {} +} + +#[derive(Debug)] +struct B<'a> { + ed: &'a mut A, +} + +fn init_b<'a>(ed: &'a mut A) -> B<'a> { + B { ed } +} + +#[derive(Debug)] +struct C<'a> { + pd: &'a mut B<'a>, +} + +fn init_c<'a>(pd: &'a mut B<'a>) -> C<'a> { + C { pd } +} + +#[derive(Debug)] +struct D<'a> { + sd: &'a mut C<'a>, +} + +fn init_d<'a>(sd: &'a mut C<'a>) -> D<'a> { + D { sd } +} + +fn main() { + let mut a = init_a(); + let mut b = init_b(&mut a); + let mut c = init_c(&mut b); + + let d = init_d(&mut c); + + println!("{:?}", d) +} diff --git a/src/test/run-pass/dyn-trait.rs b/src/test/run-pass/dyn-trait.rs index 399823ec92d..01066794242 100644 --- a/src/test/run-pass/dyn-trait.rs +++ b/src/test/run-pass/dyn-trait.rs @@ -10,8 +10,6 @@ // ignore-pretty `dyn ::foo` parses differently in the current edition -#![feature(dyn_trait)] - use std::fmt::Display; static BYTE: u8 = 33; diff --git a/src/test/run-pass/extern-prelude-no-speculative.rs b/src/test/run-pass/extern-prelude-no-speculative.rs new file mode 100644 index 00000000000..ff3aec439aa --- /dev/null +++ b/src/test/run-pass/extern-prelude-no-speculative.rs @@ -0,0 +1,21 @@ +// 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: --extern LooksLikeExternCrate=/path/to/nowhere + +mod m { + pub struct LooksLikeExternCrate; +} + +fn main() { + // OK, speculative resolution for `unused_qualifications` doesn't try + // to resolve this as an extern crate and load that crate + let s = m::LooksLikeExternCrate {}; +} diff --git a/src/test/run-pass/hygiene/issue-47311.rs b/src/test/run-pass/hygiene/issue-47311.rs index c4391ad0577..3b6890cdce6 100644 --- a/src/test/run-pass/hygiene/issue-47311.rs +++ b/src/test/run-pass/hygiene/issue-47311.rs @@ -10,7 +10,7 @@ // ignore-pretty pretty-printing is unhygienic -#![feature(decl_macro, proc_macro_path_invoc)] +#![feature(decl_macro)] #![allow(unused)] macro m($S:ident, $x:ident) { diff --git a/src/test/run-pass/hygiene/issue-47312.rs b/src/test/run-pass/hygiene/issue-47312.rs index 0cda0e7c7cc..5e83f3808d8 100644 --- a/src/test/run-pass/hygiene/issue-47312.rs +++ b/src/test/run-pass/hygiene/issue-47312.rs @@ -10,7 +10,7 @@ // ignore-pretty pretty-printing is unhygienic -#![feature(decl_macro, proc_macro_path_invoc)] +#![feature(decl_macro)] #![allow(unused)] mod foo { diff --git a/src/test/run-pass/hygiene/legacy_interaction.rs b/src/test/run-pass/hygiene/legacy_interaction.rs index 5395ef35882..683a15b99ae 100644 --- a/src/test/run-pass/hygiene/legacy_interaction.rs +++ b/src/test/run-pass/hygiene/legacy_interaction.rs @@ -12,7 +12,7 @@ // aux-build:legacy_interaction.rs -#![feature(decl_macro, proc_macro_path_invoc)] +#![feature(decl_macro)] #[allow(unused)] extern crate legacy_interaction; diff --git a/src/test/run-pass/hygiene/lexical.rs b/src/test/run-pass/hygiene/lexical.rs index 73deda0777e..cb02a17fec3 100644 --- a/src/test/run-pass/hygiene/lexical.rs +++ b/src/test/run-pass/hygiene/lexical.rs @@ -10,7 +10,7 @@ // ignore-pretty pretty-printing is unhygienic -#![feature(decl_macro, proc_macro_path_invoc)] +#![feature(decl_macro)] mod bar { mod baz { diff --git a/src/test/run-pass/hygiene/wrap_unhygienic_example.rs b/src/test/run-pass/hygiene/wrap_unhygienic_example.rs index 66e83eb7cac..55206950214 100644 --- a/src/test/run-pass/hygiene/wrap_unhygienic_example.rs +++ b/src/test/run-pass/hygiene/wrap_unhygienic_example.rs @@ -13,7 +13,7 @@ // aux-build:my_crate.rs // aux-build:unhygienic_example.rs -#![feature(decl_macro, proc_macro_path_invoc)] +#![feature(decl_macro)] extern crate unhygienic_example; extern crate my_crate; // (b) diff --git a/src/test/run-pass/hygiene/xcrate.rs b/src/test/run-pass/hygiene/xcrate.rs index 95d7ae6db60..6df3a34d3c8 100644 --- a/src/test/run-pass/hygiene/xcrate.rs +++ b/src/test/run-pass/hygiene/xcrate.rs @@ -12,7 +12,7 @@ // aux-build:xcrate.rs -#![feature(decl_macro, proc_macro_path_invoc)] +#![feature(decl_macro)] extern crate xcrate; diff --git a/src/test/run-pass/issue-47703-tuple.rs b/src/test/run-pass/issue-47703-tuple.rs new file mode 100644 index 00000000000..4fec3efc0a0 --- /dev/null +++ b/src/test/run-pass/issue-47703-tuple.rs @@ -0,0 +1,21 @@ +// 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(nll)] + +struct WithDrop; + +impl Drop for WithDrop { + fn drop(&mut self) {} +} + +fn consume(x: (&mut (), WithDrop)) -> &mut () { x.0 } + +fn main() {} diff --git a/src/test/run-pass/auxiliary/macro_reexport_2_no_use.rs b/src/test/run-pass/issue-48984.rs index 1d3dc26b0b4..227ad4e58f1 100644 --- a/src/test/run-pass/auxiliary/macro_reexport_2_no_use.rs +++ b/src/test/run-pass/issue-48984.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,9 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![crate_type = "dylib"] -#![feature(macro_reexport)] +// aux-build:issue-48984-aux.rs +extern crate issue48984aux; +use issue48984aux::Bar; -#[macro_reexport(reexported)] -#[no_link] -extern crate macro_reexport_1; +fn do_thing<T: Bar>() { } + +fn main() { } diff --git a/src/test/compile-fail/macro-reexport-malformed-3.rs b/src/test/run-pass/issue-49632.rs index 1a7e3b918cd..8cbb7d21af7 100644 --- a/src/test/compile-fail/macro-reexport-malformed-3.rs +++ b/src/test/run-pass/issue-49632.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,9 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![no_std] -#![feature(macro_reexport)] +#![feature(stmt_expr_attributes)] -#[allow(unused_extern_crates)] -#[macro_reexport(foo="bar")] //~ ERROR bad macro re-export -extern crate std; +pub fn main() { + let _x = #[inline(always)] || {}; + let _y = #[inline(never)] || {}; + let _z = #[inline] || {}; +} diff --git a/src/test/compile-fail-fulldeps/gated-macro-reexports.rs b/src/test/run-pass/issue-49685.rs index 8b448e401bd..1e4e7955323 100644 --- a/src/test/compile-fail-fulldeps/gated-macro-reexports.rs +++ b/src/test/run-pass/issue-49685.rs @@ -8,14 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test that macro re-exports item are gated by `macro_reexport` feature gate. +// Regression test for #49685: drop elaboration was not revealing the +// value of `impl Trait` returns, leading to an ICE. -// aux-build:macro_reexport_1.rs -// gate-test-macro_reexport +fn main() { + let _ = Some(()) + .into_iter() + .flat_map(|_| Some(()).into_iter().flat_map(func)); +} -#![crate_type = "dylib"] - -#[macro_reexport(reexported)] -//~^ ERROR macros re-exports are experimental and possibly buggy -#[macro_use] #[no_link] -extern crate macro_reexport_1; +fn func(_: ()) -> impl Iterator<Item = ()> { + Some(()).into_iter().flat_map(|_| vec![]) +} diff --git a/src/test/run-pass/issue-50415.rs b/src/test/run-pass/issue-50415.rs new file mode 100644 index 00000000000..aa493ce0321 --- /dev/null +++ b/src/test/run-pass/issue-50415.rs @@ -0,0 +1,27 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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() { + // -------- Simplified test case -------- + + let _ = || 0..=1; + + // -------- Original test case -------- + + let full_length = 1024; + let range = { + // do some stuff, omit here + None + }; + + let range = range.map(|(s, t)| s..=t).unwrap_or(0..=(full_length-1)); + + assert_eq!(range, 0..=1023); +} diff --git a/src/test/run-pass/nll/issue-48623-closure.rs b/src/test/run-pass/nll/issue-48623-closure.rs new file mode 100644 index 00000000000..08ff54a428e --- /dev/null +++ b/src/test/run-pass/nll/issue-48623-closure.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. + +#![feature(nll)] + +struct WithDrop; + +impl Drop for WithDrop { + fn drop(&mut self) {} +} + +fn reborrow_from_closure(r: &mut ()) -> &mut () { + let d = WithDrop; + (move || { d; &mut *r })() +} + +fn main() {} diff --git a/src/test/run-pass/nll/issue-48623-generator.rs b/src/test/run-pass/nll/issue-48623-generator.rs new file mode 100644 index 00000000000..524837c4ba9 --- /dev/null +++ b/src/test/run-pass/nll/issue-48623-generator.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. + +#![feature(nll)] +#![feature(generators, generator_trait)] + +struct WithDrop; + +impl Drop for WithDrop { + fn drop(&mut self) {} +} + +fn reborrow_from_generator(r: &mut ()) { + let d = WithDrop; + move || { d; yield; &mut *r }; +} + +fn main() {} diff --git a/src/test/run-pass/nll/issue-50343.rs b/src/test/run-pass/nll/issue-50343.rs new file mode 100644 index 00000000000..f01d99c68cc --- /dev/null +++ b/src/test/run-pass/nll/issue-50343.rs @@ -0,0 +1,17 @@ +// 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(nll)] +#![deny(unused_mut)] + +fn main() { + vec![42].iter().map(|_| ()).count(); + vec![(42, 22)].iter().map(|(_x, _y)| ()).count(); +} diff --git a/src/test/run-pass/paths-in-macro-invocations.rs b/src/test/run-pass/paths-in-macro-invocations.rs index 2e87809a84e..69f8906778a 100644 --- a/src/test/run-pass/paths-in-macro-invocations.rs +++ b/src/test/run-pass/paths-in-macro-invocations.rs @@ -10,7 +10,7 @@ // aux-build:two_macros.rs -#![feature(use_extern_macros, proc_macro_path_invoc)] +#![feature(use_extern_macros)] extern crate two_macros; diff --git a/src/test/run-pass/repr_c_int_align.rs b/src/test/run-pass/repr_c_int_align.rs new file mode 100644 index 00000000000..af4eb615302 --- /dev/null +++ b/src/test/run-pass/repr_c_int_align.rs @@ -0,0 +1,55 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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: -O + +#![allow(dead_code)] + +#[repr(C, u8)] +enum ReprCu8 { + A(u16), + B, +} + +#[repr(u8)] +enum Repru8 { + A(u16), + B, +} + +#[repr(C)] +struct ReprC { + tag: u8, + padding: u8, + payload: u16, +} + +fn main() { + // Test `repr(C, u8)`. + let r1 = ReprC { tag: 0, padding: 0, payload: 0 }; + let r2 = ReprC { tag: 0, padding: 1, payload: 1 }; + + let t1: &ReprCu8 = unsafe { std::mem::transmute(&r1) }; + let t2: &ReprCu8 = unsafe { std::mem::transmute(&r2) }; + + match (t1, t2) { + (ReprCu8::A(_), ReprCu8::A(_)) => (), + _ => assert!(false) + }; + + // Test `repr(u8)`. + let t1: &Repru8 = unsafe { std::mem::transmute(&r1) }; + let t2: &Repru8 = unsafe { std::mem::transmute(&r2) }; + + match (t1, t2) { + (Repru8::A(_), Repru8::A(_)) => (), + _ => assert!(false) + }; +} diff --git a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-box-dyn-error.rs b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-box-dyn-error.rs index 24c30a5abc2..183bb553530 100644 --- a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-box-dyn-error.rs +++ b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-box-dyn-error.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(dyn_trait)] - use std::error::Error; fn main() -> Result<(), Box<dyn Error>> { diff --git a/src/test/run-pass/sync-send-in-std.rs b/src/test/run-pass/sync-send-in-std.rs index f03387957bc..335a9c0d8be 100644 --- a/src/test/run-pass/sync-send-in-std.rs +++ b/src/test/run-pass/sync-send-in-std.rs @@ -11,9 +11,7 @@ // ignore-cloudabi networking not available // ignore-wasm32-bare networking not available -#![feature(lookup_host)] - -use std::net::lookup_host; +use std::net::ToSocketAddrs; fn is_sync<T>(_: T) where T: Sync {} fn is_send<T>(_: T) where T: Send {} @@ -30,5 +28,5 @@ macro_rules! all_sync_send { } fn main() { - all_sync_send!(lookup_host("localhost").unwrap(), next); + all_sync_send!("localhost:80".to_socket_addrs().unwrap(), next); } diff --git a/src/test/run-pass/tool_attributes.rs b/src/test/run-pass/tool_attributes.rs new file mode 100644 index 00000000000..eb13930de40 --- /dev/null +++ b/src/test/run-pass/tool_attributes.rs @@ -0,0 +1,23 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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. + +// Scoped attributes should not trigger an unused attributes lint. + +#![feature(tool_attributes)] +#![deny(unused_attributes)] + +fn main() { + #[rustfmt::skip] + foo (); +} + +fn foo() { + assert!(true); +} diff --git a/src/test/run-pass/vec-const-new.rs b/src/test/run-pass/vec-const-new.rs new file mode 100644 index 00000000000..62e2a36d7cc --- /dev/null +++ b/src/test/run-pass/vec-const-new.rs @@ -0,0 +1,17 @@ +// 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. + +// Test that Vec::new() can be used for constants + +#![feature(const_vec_new)] + +const MY_VEC: Vec<usize> = Vec::new(); + +pub fn main() {} diff --git a/src/test/rustdoc-js/alias-2.js b/src/test/rustdoc-js/alias-2.js index f31786df67c..0c5ec4fccbc 100644 --- a/src/test/rustdoc-js/alias-2.js +++ b/src/test/rustdoc-js/alias-2.js @@ -8,11 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-order + const QUERY = '+'; const EXPECTED = { 'others': [ - { 'path': 'std::ops::AddAssign', 'name': 'AddAssign' }, - { 'path': 'std::ops::Add', 'name': 'Add' }, + { 'path': 'std::ops', 'name': 'AddAssign' }, + { 'path': 'std::ops', 'name': 'Add' }, ], }; diff --git a/src/test/rustdoc-js/alias.js b/src/test/rustdoc-js/alias.js index a0500f24c17..e7aafe3b9e2 100644 --- a/src/test/rustdoc-js/alias.js +++ b/src/test/rustdoc-js/alias.js @@ -8,12 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-order + const QUERY = '['; const EXPECTED = { 'others': [ { 'path': 'std', 'name': 'slice' }, - { 'path': 'std::ops::IndexMut', 'name': 'IndexMut' }, - { 'path': 'std::ops::Index', 'name': 'Index' }, + { 'path': 'std::ops', 'name': 'IndexMut' }, + { 'path': 'std::ops', 'name': 'Index' }, ], }; diff --git a/src/test/rustdoc-js/basic.js b/src/test/rustdoc-js/basic.js index 863437cac91..d7ba1253eab 100644 --- a/src/test/rustdoc-js/basic.js +++ b/src/test/rustdoc-js/basic.js @@ -13,8 +13,8 @@ const QUERY = 'String'; const EXPECTED = { 'others': [ { 'path': 'std::string', 'name': 'String' }, - { 'path': 'std::ffi', 'name': 'OsString' }, { 'path': 'std::ffi', 'name': 'CString' }, + { 'path': 'std::ffi', 'name': 'OsString' }, ], 'in_args': [ { 'path': 'std::str', 'name': 'eq' }, diff --git a/src/test/rustdoc/auxiliary/all-item-types.rs b/src/test/rustdoc/auxiliary/all-item-types.rs new file mode 100644 index 00000000000..19a0b88ce7d --- /dev/null +++ b/src/test/rustdoc/auxiliary/all-item-types.rs @@ -0,0 +1,32 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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(extern_types)] + +pub mod foo_mod {} +extern "C" { + pub fn foo_ffn(); + pub static FOO_FSTATIC: FooStruct; + pub type FooFType; +} +pub fn foo_fn() {} +pub trait FooTrait {} +pub struct FooStruct; +pub enum FooEnum {} +pub union FooUnion { + x: (), +} +pub type FooType = FooStruct; +pub static FOO_STATIC: FooStruct = FooStruct; +pub const FOO_CONSTANT: FooStruct = FooStruct; +#[macro_export] +macro_rules! foo_macro { + () => (); +} diff --git a/src/test/rustdoc/cross-crate-links.rs b/src/test/rustdoc/cross-crate-links.rs new file mode 100644 index 00000000000..6078352fc0e --- /dev/null +++ b/src/test/rustdoc/cross-crate-links.rs @@ -0,0 +1,71 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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:all-item-types.rs +// build-aux-docs + +#![feature(use_extern_macros)] + +#![crate_name = "foo"] + +#[macro_use] +extern crate all_item_types; + +// @has 'foo/index.html' '//a[@href="../all_item_types/foo_mod/index.html"]' 'foo_mod' +#[doc(no_inline)] +pub use all_item_types::foo_mod; + +// @has 'foo/index.html' '//a[@href="../all_item_types/fn.foo_ffn.html"]' 'foo_ffn' +#[doc(no_inline)] +pub use all_item_types::foo_ffn; + +// @has 'foo/index.html' '//a[@href="../all_item_types/static.FOO_FSTATIC.html"]' 'FOO_FSTATIC' +#[doc(no_inline)] +pub use all_item_types::FOO_FSTATIC; + +// @has 'foo/index.html' '//a[@href="../all_item_types/foreigntype.FooFType.html"]' 'FooFType' +#[doc(no_inline)] +pub use all_item_types::FooFType; + +// @has 'foo/index.html' '//a[@href="../all_item_types/fn.foo_fn.html"]' 'foo_fn' +#[doc(no_inline)] +pub use all_item_types::foo_fn; + +// @has 'foo/index.html' '//a[@href="../all_item_types/trait.FooTrait.html"]' 'FooTrait' +#[doc(no_inline)] +pub use all_item_types::FooTrait; + +// @has 'foo/index.html' '//a[@href="../all_item_types/struct.FooStruct.html"]' 'FooStruct' +#[doc(no_inline)] +pub use all_item_types::FooStruct; + +// @has 'foo/index.html' '//a[@href="../all_item_types/enum.FooEnum.html"]' 'FooEnum' +#[doc(no_inline)] +pub use all_item_types::FooEnum; + +// @has 'foo/index.html' '//a[@href="../all_item_types/union.FooUnion.html"]' 'FooUnion' +#[doc(no_inline)] +pub use all_item_types::FooUnion; + +// @has 'foo/index.html' '//a[@href="../all_item_types/type.FooType.html"]' 'FooType' +#[doc(no_inline)] +pub use all_item_types::FooType; + +// @has 'foo/index.html' '//a[@href="../all_item_types/static.FOO_STATIC.html"]' 'FOO_STATIC' +#[doc(no_inline)] +pub use all_item_types::FOO_STATIC; + +// @has 'foo/index.html' '//a[@href="../all_item_types/constant.FOO_CONSTANT.html"]' 'FOO_CONSTANT' +#[doc(no_inline)] +pub use all_item_types::FOO_CONSTANT; + +// @has 'foo/index.html' '//a[@href="../foo/macro.foo_macro.html"]' 'foo_macro' +#[doc(no_inline)] +pub use all_item_types::foo_macro; diff --git a/src/test/rustdoc/pub-use-extern-macros.rs b/src/test/rustdoc/pub-use-extern-macros.rs index 3f8f6f9544e..57d54585d84 100644 --- a/src/test/rustdoc/pub-use-extern-macros.rs +++ b/src/test/rustdoc/pub-use-extern-macros.rs @@ -10,14 +10,11 @@ // aux-build:pub-use-extern-macros.rs -#![feature(use_extern_macros, macro_reexport)] +#![feature(use_extern_macros)] -// @has pub_use_extern_macros/macro.foo.html -// @!has pub_use_extern_macros/index.html 'pub use macros::foo;' -#[macro_reexport(foo)] extern crate macros; +extern crate macros; -// @has pub_use_extern_macros/index.html 'pub use macros::bar;' -// @!has pub_use_extern_macros/macro.bar.html +// @has pub_use_extern_macros/macro.bar.html pub use macros::bar; // @has pub_use_extern_macros/macro.baz.html @@ -25,7 +22,7 @@ pub use macros::bar; #[doc(inline)] pub use macros::baz; -// @!has pub_use_extern_macros/macro.quux.html +// @has pub_use_extern_macros/macro.quux.html // @!has pub_use_extern_macros/index.html 'pub use macros::quux;' #[doc(hidden)] pub use macros::quux; diff --git a/src/test/rustdoc/universal-impl-trait.rs b/src/test/rustdoc/universal-impl-trait.rs index 4cf99562c52..af51ff3d941 100644 --- a/src/test/rustdoc/universal-impl-trait.rs +++ b/src/test/rustdoc/universal-impl-trait.rs @@ -11,6 +11,8 @@ #![feature(universal_impl_trait)] #![crate_name = "foo"] +use std::io::Read; + // @has foo/fn.foo.html // @has - //pre 'foo(' // @matches - '_x: impl <a class="trait" href="[^"]+/trait\.Clone\.html"' @@ -39,6 +41,11 @@ impl<T> S<T> { // @matches - '_baz:.+struct\.S\.html.+impl .+trait\.Clone\.html' pub fn baz(_baz: S<impl Clone>) { } + + // @has - 'qux</a>(' + // @matches - 'trait\.Read\.html' + pub fn qux(_qux: impl IntoIterator<Item = S<impl Read>>) { + } } // @has - 'method</a>(' diff --git a/src/test/run-pass/macro-reexport.rs b/src/test/rustfix/closure-immutable-outer-variable.fixed index b8926eca9e9..bddc2eab16d 100644 --- a/src/test/run-pass/macro-reexport.rs +++ b/src/test/rustfix/closure-immutable-outer-variable.fixed @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,12 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// aux-build:macro_reexport_1.rs -// aux-build:macro_reexport_2.rs +// Point at the captured immutable outer variable -#[macro_use] #[no_link] -extern crate macro_reexport_2; +fn foo(mut f: Box<FnMut()>) { + f(); +} fn main() { - assert_eq!(reexported!(), 3_usize); + let mut y = true; + foo(Box::new(move || y = false) as Box<_>); } diff --git a/src/test/run-pass/macro-reexport-no-intermediate-use.rs b/src/test/rustfix/closure-immutable-outer-variable.rs index de7df1ec021..fe8e2bc6c8e 100644 --- a/src/test/run-pass/macro-reexport-no-intermediate-use.rs +++ b/src/test/rustfix/closure-immutable-outer-variable.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,12 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// aux-build:macro_reexport_1.rs -// aux-build:macro_reexport_2_no_use.rs +// Point at the captured immutable outer variable -#[macro_use] #[no_link] -extern crate macro_reexport_2_no_use; +fn foo(mut f: Box<FnMut()>) { + f(); +} fn main() { - assert_eq!(reexported!(), 3_usize); + let y = true; + foo(Box::new(move || y = false) as Box<_>); } diff --git a/src/test/rustfix/empty-no-fixes.fixed b/src/test/rustfix/empty-no-fixes.fixed new file mode 100644 index 00000000000..39e19566d76 --- /dev/null +++ b/src/test/rustfix/empty-no-fixes.fixed @@ -0,0 +1,11 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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:--crate-type lib diff --git a/src/test/rustfix/empty-no-fixes.rs b/src/test/rustfix/empty-no-fixes.rs new file mode 100644 index 00000000000..39e19566d76 --- /dev/null +++ b/src/test/rustfix/empty-no-fixes.rs @@ -0,0 +1,11 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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:--crate-type lib diff --git a/src/test/rustfix/empty-no-fixes.rs.fixed b/src/test/rustfix/empty-no-fixes.rs.fixed new file mode 100644 index 00000000000..ee58e778253 --- /dev/null +++ b/src/test/rustfix/empty-no-fixes.rs.fixed @@ -0,0 +1,12 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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:--crate-type lib +fn foo() {} diff --git a/src/test/rustfix/issue-45562.fixed b/src/test/rustfix/issue-45562.fixed new file mode 100644 index 00000000000..d7a27a11fc0 --- /dev/null +++ b/src/test/rustfix/issue-45562.fixed @@ -0,0 +1,13 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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. + +#[no_mangle] pub static RAH: usize = 5; + +fn main() {} diff --git a/src/test/rustfix/issue-45562.rs b/src/test/rustfix/issue-45562.rs new file mode 100644 index 00000000000..39576e9c845 --- /dev/null +++ b/src/test/rustfix/issue-45562.rs @@ -0,0 +1,13 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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. + +#[no_mangle] pub const RAH: usize = 5; + +fn main() {} diff --git a/src/test/rustfix/issue-45799-bad-extern-crate-rename-suggestion-formatting.fixed b/src/test/rustfix/issue-45799-bad-extern-crate-rename-suggestion-formatting.fixed new file mode 100644 index 00000000000..d931f90cd04 --- /dev/null +++ b/src/test/rustfix/issue-45799-bad-extern-crate-rename-suggestion-formatting.fixed @@ -0,0 +1,12 @@ +// 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. + +extern crate std as other_std; +fn main() {} diff --git a/src/test/rustfix/issue-45799-bad-extern-crate-rename-suggestion-formatting.rs b/src/test/rustfix/issue-45799-bad-extern-crate-rename-suggestion-formatting.rs new file mode 100644 index 00000000000..7c55f9c4eb9 --- /dev/null +++ b/src/test/rustfix/issue-45799-bad-extern-crate-rename-suggestion-formatting.rs @@ -0,0 +1,12 @@ +// 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. + +extern crate std; +fn main() {} diff --git a/src/test/ui/feature-gate-fn_must_use-cap-lints-allow.rs b/src/test/rustfix/issue-46756-consider-borrowing-cast-or-binexpr.fixed index 1c04199c05f..aaa04ef4004 100644 --- a/src/test/ui/feature-gate-fn_must_use-cap-lints-allow.rs +++ b/src/test/rustfix/issue-46756-consider-borrowing-cast-or-binexpr.fixed @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: --cap-lints allow +#![allow(unused)] -// This tests that the fn_must_use feature-gate warning respects the lint -// cap. (See discussion in Issue #44213.) +fn light_flows_our_war_of_mocking_words(and_yet: &usize) -> usize { + and_yet + 1 +} -#![feature(rustc_attrs)] - -#[must_use] // (no feature-gate warning because of the lint cap!) -fn need_to_use_it() -> bool { true } - -#[rustc_error] -fn main() {} //~ ERROR compilation successful +fn main() { + let behold: isize = 2; + let with_tears: usize = 3; + light_flows_our_war_of_mocking_words(&(behold as usize)); + light_flows_our_war_of_mocking_words(&(with_tears + 4)); +} diff --git a/src/test/rustfix/issue-46756-consider-borrowing-cast-or-binexpr.rs b/src/test/rustfix/issue-46756-consider-borrowing-cast-or-binexpr.rs new file mode 100644 index 00000000000..d21681747e9 --- /dev/null +++ b/src/test/rustfix/issue-46756-consider-borrowing-cast-or-binexpr.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. + +#![allow(unused)] + +fn light_flows_our_war_of_mocking_words(and_yet: &usize) -> usize { + and_yet + 1 +} + +fn main() { + let behold: isize = 2; + let with_tears: usize = 3; + light_flows_our_war_of_mocking_words(behold as usize); + light_flows_our_war_of_mocking_words(with_tears + 4); +} diff --git a/src/test/rustfix/main-no-fixes.fixed b/src/test/rustfix/main-no-fixes.fixed new file mode 100644 index 00000000000..3f07b46791d --- /dev/null +++ b/src/test/rustfix/main-no-fixes.fixed @@ -0,0 +1,11 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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() {} diff --git a/src/test/rustfix/main-no-fixes.rs b/src/test/rustfix/main-no-fixes.rs new file mode 100644 index 00000000000..3f07b46791d --- /dev/null +++ b/src/test/rustfix/main-no-fixes.rs @@ -0,0 +1,11 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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() {} diff --git a/src/test/rustfix/main-no-fixes.rs.fixed b/src/test/rustfix/main-no-fixes.rs.fixed new file mode 100644 index 00000000000..3f07b46791d --- /dev/null +++ b/src/test/rustfix/main-no-fixes.rs.fixed @@ -0,0 +1,11 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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() {} diff --git a/src/test/rustfix/missing-comma-in-match.fixed b/src/test/rustfix/missing-comma-in-match.fixed new file mode 100644 index 00000000000..621a4127bc2 --- /dev/null +++ b/src/test/rustfix/missing-comma-in-match.fixed @@ -0,0 +1,17 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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() { + match &Some(3) { + &None => 1, + &Some(2) => { 3 } + _ => 2 + }; +} diff --git a/src/test/rustfix/missing-comma-in-match.rs b/src/test/rustfix/missing-comma-in-match.rs new file mode 100644 index 00000000000..8ccad7b9c94 --- /dev/null +++ b/src/test/rustfix/missing-comma-in-match.rs @@ -0,0 +1,17 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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() { + match &Some(3) { + &None => 1 + &Some(2) => { 3 } + _ => 2 + }; +} diff --git a/src/test/rustfix/str-as-char.fixed b/src/test/rustfix/str-as-char.fixed new file mode 100644 index 00000000000..0ace6d96613 --- /dev/null +++ b/src/test/rustfix/str-as-char.fixed @@ -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() { + println!("●●"); +} diff --git a/src/test/rustfix/str-as-char.rs b/src/test/rustfix/str-as-char.rs new file mode 100644 index 00000000000..fa0e474fc7f --- /dev/null +++ b/src/test/rustfix/str-as-char.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() { + println!('●●'); +} diff --git a/src/test/rustfix/tuple-float-index.fixed b/src/test/rustfix/tuple-float-index.fixed new file mode 100644 index 00000000000..9cb7537b428 --- /dev/null +++ b/src/test/rustfix/tuple-float-index.fixed @@ -0,0 +1,15 @@ +// 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 parse-only + +fn main () { + ((1, (2, 3)).1).1; +} diff --git a/src/test/rustfix/tuple-float-index.rs b/src/test/rustfix/tuple-float-index.rs new file mode 100644 index 00000000000..8bfbd0e74db --- /dev/null +++ b/src/test/rustfix/tuple-float-index.rs @@ -0,0 +1,15 @@ +// 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 parse-only + +fn main () { + (1, (2, 3)).1.1; +} diff --git a/src/test/rustfix/update-all-references.sh b/src/test/rustfix/update-all-references.sh new file mode 100755 index 00000000000..c3f615066bb --- /dev/null +++ b/src/test/rustfix/update-all-references.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +# +# 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. + +# A script to update the references for all tests. The idea is that +# you do a run, which will generate files in the build directory +# containing the (normalized) actual output of the compiler. You then +# run this script, which will copy those files over. If you find +# yourself manually editing a foo.stderr file, you're doing it wrong. +# +# See all `update-references.sh`, if you just want to update a single test. + +if [[ "$1" == "--help" || "$1" == "-h" || "$1" == "" || "$2" != "" ]]; then + echo "usage: $0 <build-directory>" + echo "" + echo "For example:" + echo " $0 ../../../build/x86_64-apple-darwin/test/rustfix" +fi + +BUILD_DIR=$PWD/$1 +MY_DIR=$(dirname $0) +cd $MY_DIR +find . -name '*.rs' | xargs ./update-references.sh $BUILD_DIR diff --git a/src/test/rustfix/update-references.sh b/src/test/rustfix/update-references.sh new file mode 100755 index 00000000000..bcca2fec10d --- /dev/null +++ b/src/test/rustfix/update-references.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +# +# 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. + +# A script to update the references for particular tests. The idea is +# that you do a run, which will generate files in the build directory +# containing the (normalized) actual output of the compiler. This +# script will then copy that output and replace the "expected output" +# files. You can then commit the changes. +# +# If you find yourself manually editing a foo.stderr file, you're +# doing it wrong. + +if [[ "$1" == "--help" || "$1" == "-h" || "$1" == "" || "$2" == "" ]]; then + echo "usage: $0 <build-directory> <relative-path-to-rs-files>" + echo "" + echo "For example:" + echo " $0 ../../../build/x86_64-apple-darwin/test/rustfix *.rs */*.rs" +fi + +MYDIR=$(dirname $0) + +BUILD_DIR="$1" +shift + +shopt -s nullglob + +while [[ "$1" != "" ]]; do + for OUT_NAME in $BUILD_DIR/${1%.rs}.*fixed; do + OUT_BASE=`basename "$OUT_NAME"` + if ! (diff $OUT_NAME $MYDIR/$OUT_BASE >& /dev/null); then + echo updating $MYDIR/$OUT_BASE + cp $OUT_NAME $MYDIR + fi + done + shift +done diff --git a/src/test/ui/const-eval/ice-packed.rs b/src/test/ui/const-eval/ice-packed.rs new file mode 100644 index 00000000000..1db12a06b03 --- /dev/null +++ b/src/test/ui/const-eval/ice-packed.rs @@ -0,0 +1,28 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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-pass +#[derive(Copy, Clone, PartialEq, Eq)] +#[repr(packed)] +pub struct Num(u64); + +impl Num { + pub const ZERO: Self = Num(0); +} + +pub fn decrement(a: Num) -> Num { + match a { + Num::ZERO => Num::ZERO, + a => Num(a.0 - 1) + } +} + +fn main() { +} diff --git a/src/test/ui/const-eval/index_out_of_bound.stderr b/src/test/ui/const-eval/index_out_of_bound.stderr index 793e0a7ace8..d16231c72b9 100644 --- a/src/test/ui/const-eval/index_out_of_bound.stderr +++ b/src/test/ui/const-eval/index_out_of_bound.stderr @@ -2,7 +2,7 @@ error[E0080]: constant evaluation error --> $DIR/index_out_of_bound.rs:11:19 | LL | static FOO: i32 = [][0]; - | ^^^^^ index out of bounds: the len is 0 but the index is 0 at $DIR/index_out_of_bound.rs:11:19: 11:24 + | ^^^^^ index out of bounds: the len is 0 but the index is 0 error: aborting due to previous error diff --git a/src/test/ui/const-eval/promoted_errors.stderr b/src/test/ui/const-eval/promoted_errors.stderr index a5db8cc9083..7761f192fdb 100644 --- a/src/test/ui/const-eval/promoted_errors.stderr +++ b/src/test/ui/const-eval/promoted_errors.stderr @@ -2,7 +2,7 @@ warning: constant evaluation error --> $DIR/promoted_errors.rs:14:20 | LL | println!("{}", 0u32 - 1); - | ^^^^^^^^ attempted to do overflowing math + | ^^^^^^^^ attempt to subtract with overflow | = note: #[warn(const_err)] on by default @@ -10,13 +10,13 @@ warning: constant evaluation error --> $DIR/promoted_errors.rs:14:20 | LL | println!("{}", 0u32 - 1); - | ^^^^^^^^ attempted to do overflowing math + | ^^^^^^^^ attempt to subtract with overflow warning: constant evaluation error --> $DIR/promoted_errors.rs:17:14 | LL | let _x = 0u32 - 1; - | ^^^^^^^^ attempted to do overflowing math + | ^^^^^^^^ attempt to subtract with overflow warning: attempt to divide by zero --> $DIR/promoted_errors.rs:19:20 @@ -28,7 +28,7 @@ warning: constant evaluation error --> $DIR/promoted_errors.rs:19:20 | LL | println!("{}", 1/(1-1)); - | ^^^^^^^ attempted to do overflowing math + | ^^^^^^^ attempt to divide by zero warning: attempt to divide by zero --> $DIR/promoted_errors.rs:22:14 @@ -40,11 +40,11 @@ warning: constant evaluation error --> $DIR/promoted_errors.rs:22:14 | LL | let _x = 1/(1-1); - | ^^^^^^^ attempted to do overflowing math + | ^^^^^^^ attempt to divide by zero warning: constant evaluation error --> $DIR/promoted_errors.rs:25:20 | LL | println!("{}", 1/(false as u32)); - | ^^^^^^^^^^^^^^^^ attempted to do overflowing math + | ^^^^^^^^^^^^^^^^ attempt to divide by zero diff --git a/src/test/ui/error-codes/E0080.rs b/src/test/ui/error-codes/E0080.rs index c8e42571128..7f3e6eaad9b 100644 --- a/src/test/ui/error-codes/E0080.rs +++ b/src/test/ui/error-codes/E0080.rs @@ -15,7 +15,6 @@ enum Enum { //~| const_err //~| const_err //~| const_err - //~| divide by zero } fn main() { diff --git a/src/test/ui/error-codes/E0080.stderr b/src/test/ui/error-codes/E0080.stderr index 500e0e83a55..5e401bd6c79 100644 --- a/src/test/ui/error-codes/E0080.stderr +++ b/src/test/ui/error-codes/E0080.stderr @@ -24,7 +24,7 @@ warning: constant evaluation error --> $DIR/E0080.rs:14:9 | LL | Y = (1 / 0) //~ ERROR E0080 - | ^^^^^^^ attempted to do overflowing math + | ^^^^^^^ attempt to divide by zero error[E0080]: constant evaluation error --> $DIR/E0080.rs:14:9 diff --git a/src/test/ui/error-codes/E0518.stderr b/src/test/ui/error-codes/E0518.stderr index d8feec99140..27d5d3645fd 100644 --- a/src/test/ui/error-codes/E0518.stderr +++ b/src/test/ui/error-codes/E0518.stderr @@ -1,19 +1,19 @@ -error[E0518]: attribute should be applied to function +error[E0518]: attribute should be applied to function or closure --> $DIR/E0518.rs:11:1 | LL | #[inline(always)] //~ ERROR: E0518 | ^^^^^^^^^^^^^^^^^ LL | struct Foo; - | ----------- not a function + | ----------- not a function or closure -error[E0518]: attribute should be applied to function +error[E0518]: attribute should be applied to function or closure --> $DIR/E0518.rs:14:1 | LL | #[inline(never)] //~ ERROR: E0518 | ^^^^^^^^^^^^^^^^ LL | / impl Foo { LL | | } - | |_- not a function + | |_- not a function or closure error: aborting due to 2 previous errors diff --git a/src/test/ui/feature-gate-dyn-trait.stderr b/src/test/ui/feature-gate-dyn-trait.stderr deleted file mode 100644 index 6e6bdf1cbf0..00000000000 --- a/src/test/ui/feature-gate-dyn-trait.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0658]: `dyn Trait` syntax is unstable (see issue #44662) - --> $DIR/feature-gate-dyn-trait.rs:12:14 - | -LL | type A = Box<dyn Trait>; //~ ERROR `dyn Trait` syntax is unstable - | ^^^^^^^^^ - | - = help: add #![feature(dyn_trait)] to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gate-extern_prelude.rs b/src/test/ui/feature-gate-extern_prelude.rs new file mode 100644 index 00000000000..8d3a30305bd --- /dev/null +++ b/src/test/ui/feature-gate-extern_prelude.rs @@ -0,0 +1,11 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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. + +can-only-test-this-in-run-make-fulldeps //~ ERROR expected one of `!` or `::`, found `-` diff --git a/src/test/ui/feature-gate-extern_prelude.stderr b/src/test/ui/feature-gate-extern_prelude.stderr new file mode 100644 index 00000000000..5abf369baf9 --- /dev/null +++ b/src/test/ui/feature-gate-extern_prelude.stderr @@ -0,0 +1,8 @@ +error: expected one of `!` or `::`, found `-` + --> $DIR/feature-gate-extern_prelude.rs:11:4 + | +LL | can-only-test-this-in-run-make-fulldeps //~ ERROR expected one of `!` or `::`, found `-` + | ^ expected one of `!` or `::` here + +error: aborting due to previous error + diff --git a/src/test/ui/feature-gate-fn_must_use-cap-lints-allow.stderr b/src/test/ui/feature-gate-fn_must_use-cap-lints-allow.stderr deleted file mode 100644 index a2c1dedff38..00000000000 --- a/src/test/ui/feature-gate-fn_must_use-cap-lints-allow.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: compilation successful - --> $DIR/feature-gate-fn_must_use-cap-lints-allow.rs:22:1 - | -LL | fn main() {} //~ ERROR compilation successful - | ^^^^^^^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/feature-gate-fn_must_use.rs b/src/test/ui/feature-gate-fn_must_use.rs deleted file mode 100644 index 72fdcc76cf4..00000000000 --- a/src/test/ui/feature-gate-fn_must_use.rs +++ /dev/null @@ -1,31 +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. - -#![feature(rustc_attrs)] - -struct MyStruct; - -impl MyStruct { - #[must_use] //~ WARN `#[must_use]` on methods is experimental - fn need_to_use_method() -> bool { true } -} - -#[must_use] //~ WARN `#[must_use]` on functions is experimental -fn need_to_use_it() -> bool { true } - - -// Feature gates are tidy-required to have a specially named (or -// comment-annotated) compile-fail test (which MUST fail), but for -// backwards-compatibility reasons, we want `#[must_use]` on functions to be -// compilable even if the `fn_must_use` feature is absent, thus necessitating -// the usage of `#[rustc_error]` here, pragmatically if awkwardly solving this -// dilemma until a superior solution can be devised. -#[rustc_error] -fn main() {} //~ ERROR compilation successful diff --git a/src/test/ui/feature-gate-fn_must_use.stderr b/src/test/ui/feature-gate-fn_must_use.stderr deleted file mode 100644 index 431c57abd26..00000000000 --- a/src/test/ui/feature-gate-fn_must_use.stderr +++ /dev/null @@ -1,24 +0,0 @@ -warning: `#[must_use]` on methods is experimental (see issue #43302) - --> $DIR/feature-gate-fn_must_use.rs:16:5 - | -LL | #[must_use] //~ WARN `#[must_use]` on methods is experimental - | ^^^^^^^^^^^ - | - = help: add #![feature(fn_must_use)] to the crate attributes to enable - -warning: `#[must_use]` on functions is experimental (see issue #43302) - --> $DIR/feature-gate-fn_must_use.rs:20:1 - | -LL | #[must_use] //~ WARN `#[must_use]` on functions is experimental - | ^^^^^^^^^^^ - | - = help: add #![feature(fn_must_use)] to the crate attributes to enable - -error: compilation successful - --> $DIR/feature-gate-fn_must_use.rs:31:1 - | -LL | fn main() {} //~ ERROR compilation successful - | ^^^^^^^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/feature-gate-tool_attributes.rs b/src/test/ui/feature-gate-tool_attributes.rs new file mode 100644 index 00000000000..2b7cf56d938 --- /dev/null +++ b/src/test/ui/feature-gate-tool_attributes.rs @@ -0,0 +1,15 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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() { + #[rustfmt::skip] //~ ERROR scoped attribute `rustfmt::skip` is experimental + let x = 3 + ; +} diff --git a/src/test/ui/feature-gate-tool_attributes.stderr b/src/test/ui/feature-gate-tool_attributes.stderr new file mode 100644 index 00000000000..da89c4a5ef6 --- /dev/null +++ b/src/test/ui/feature-gate-tool_attributes.stderr @@ -0,0 +1,11 @@ +error[E0658]: scoped attribute `rustfmt::skip` is experimental (see issue #44690) + --> $DIR/feature-gate-tool_attributes.rs:12:5 + | +LL | #[rustfmt::skip] //~ ERROR scoped attribute `rustfmt::skip` is experimental + | ^^^^^^^^^^^^^^^^ + | + = help: add #![feature(tool_attributes)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs index 21950402c8c..76fb09f27be 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs @@ -50,7 +50,6 @@ #![allow (x5300)] //~ WARN unknown lint: `x5300` #![forbid (x5200)] //~ WARN unknown lint: `x5200` #![deny (x5100)] //~ WARN unknown lint: `x5100` -#![macro_reexport = "5000"] //~ WARN unused attribute #![macro_use] // (allowed if no argument; see issue-43160-gating-of-macro_use.rs) #![macro_export = "4800"] //~ WARN unused attribute #![plugin_registrar = "4700"] //~ WARN unused attribute @@ -186,25 +185,6 @@ mod deny { //~^ WARN unknown lint: `x5100` } -#[macro_reexport = "5000"] -//~^ WARN unused attribute -mod macro_reexport { - mod inner { #![macro_reexport="5000"] } - //~^ WARN unused attribute - - #[macro_reexport = "5000"] fn f() { } - //~^ WARN unused attribute - - #[macro_reexport = "5000"] struct S; - //~^ WARN unused attribute - - #[macro_reexport = "5000"] type T = S; - //~^ WARN unused attribute - - #[macro_reexport = "5000"] impl S { } - //~^ WARN unused attribute -} - #[macro_use] mod macro_use { mod inner { #![macro_use] } @@ -661,7 +641,6 @@ mod must_use { mod inner { #![must_use="1400"] } #[must_use = "1400"] fn f() { } - //~^ WARN `#[must_use]` on functions is experimental #[must_use = "1400"] struct S; diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr index 0beed627987..f8e5f58ca0e 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr @@ -1,25 +1,17 @@ warning: macro_escape is a deprecated synonym for macro_use - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:513:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:493:1 | LL | #[macro_escape] | ^^^^^^^^^^^^^^^ warning: macro_escape is a deprecated synonym for macro_use - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:516:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:496:17 | LL | mod inner { #![macro_escape] } | ^^^^^^^^^^^^^^^^ | = help: consider an outer attribute, #[macro_use] mod ... -warning: `#[must_use]` on functions is experimental (see issue #43302) - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:663:5 - | -LL | #[must_use = "1400"] fn f() { } - | ^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(fn_must_use)] to the crate attributes to enable - warning: unknown lint: `x5400` --> $DIR/issue-43106-gating-of-builtin-attrs.rs:49:33 | @@ -51,154 +43,154 @@ LL | #![deny (x5100)] //~ WARN unknown lint: `x5100` | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:113:8 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:112:8 | LL | #[warn(x5400)] | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:116:25 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:115:25 | LL | mod inner { #![warn(x5400)] } | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:119:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:118:12 | LL | #[warn(x5400)] fn f() { } | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:122:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:121:12 | LL | #[warn(x5400)] struct S; | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:125:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:124:12 | LL | #[warn(x5400)] type T = S; | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:128:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:127:12 | LL | #[warn(x5400)] impl S { } | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:132:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:131:9 | LL | #[allow(x5300)] | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:135:26 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:134:26 | LL | mod inner { #![allow(x5300)] } | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:138:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:137:13 | LL | #[allow(x5300)] fn f() { } | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:141:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:140:13 | LL | #[allow(x5300)] struct S; | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:144:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:143:13 | LL | #[allow(x5300)] type T = S; | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:147:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:146:13 | LL | #[allow(x5300)] impl S { } | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:151:10 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:150:10 | LL | #[forbid(x5200)] | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:154:27 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:153:27 | LL | mod inner { #![forbid(x5200)] } | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:157:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:156:14 | LL | #[forbid(x5200)] fn f() { } | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:160:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:159:14 | LL | #[forbid(x5200)] struct S; | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:163:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:162:14 | LL | #[forbid(x5200)] type T = S; | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:166:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:165:14 | LL | #[forbid(x5200)] impl S { } | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:170:8 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:169:8 | LL | #[deny(x5100)] | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:173:25 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:172:25 | LL | mod inner { #![deny(x5100)] } | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:176:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:175:12 | LL | #[deny(x5100)] fn f() { } | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:179:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:178:12 | LL | #[deny(x5100)] struct S; | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:182:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:181:12 | LL | #[deny(x5100)] type T = S; | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:185:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:184:12 | LL | #[deny(x5100)] impl S { } | ^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:192:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:192:5 | -LL | mod inner { #![macro_reexport="5000"] } - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[macro_use] fn f() { } + | ^^^^^^^^^^^^ | note: lint level defined here --> $DIR/issue-43106-gating-of-builtin-attrs.rs:44:9 @@ -209,311 +201,275 @@ LL | #![warn(unused_attributes, unknown_lints)] warning: unused attribute --> $DIR/issue-43106-gating-of-builtin-attrs.rs:195:5 | -LL | #[macro_reexport = "5000"] fn f() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:198:5 - | -LL | #[macro_reexport = "5000"] struct S; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:201:5 - | -LL | #[macro_reexport = "5000"] type T = S; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:204:5 - | -LL | #[macro_reexport = "5000"] impl S { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:189:1 - | -LL | #[macro_reexport = "5000"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:212:5 - | -LL | #[macro_use] fn f() { } - | ^^^^^^^^^^^^ - -warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:215:5 - | LL | #[macro_use] struct S; | ^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:218:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:198:5 | LL | #[macro_use] type T = S; | ^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:221:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:201:5 | LL | #[macro_use] impl S { } | ^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:228:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:208:17 | LL | mod inner { #![macro_export="4800"] } | ^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:231:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:211:5 | LL | #[macro_export = "4800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:234:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:214:5 | LL | #[macro_export = "4800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:237:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:217:5 | LL | #[macro_export = "4800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:240:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:220:5 | LL | #[macro_export = "4800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:225:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:205:1 | LL | #[macro_export = "4800"] | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:247:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:227:17 | LL | mod inner { #![plugin_registrar="4700"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:252:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:232:5 | LL | #[plugin_registrar = "4700"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:255:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:235:5 | LL | #[plugin_registrar = "4700"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:258:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:238:5 | LL | #[plugin_registrar = "4700"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:244:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:224:1 | LL | #[plugin_registrar = "4700"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:265:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:245:17 | LL | mod inner { #![main="4300"] } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:270:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:250:5 | LL | #[main = "4400"] struct S; | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:273:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:253:5 | LL | #[main = "4400"] type T = S; | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:276:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:256:5 | LL | #[main = "4400"] impl S { } | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:262:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:242:1 | LL | #[main = "4400"] | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:283:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:263:17 | LL | mod inner { #![start="4300"] } | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:288:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:268:5 | LL | #[start = "4300"] struct S; | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:291:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:271:5 | LL | #[start = "4300"] type T = S; | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:294:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:274:5 | LL | #[start = "4300"] impl S { } | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:280:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:260:1 | LL | #[start = "4300"] | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:333:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:313:17 | LL | mod inner { #![repr="3900"] } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:336:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:316:5 | LL | #[repr = "3900"] fn f() { } | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:341:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:321:5 | LL | #[repr = "3900"] type T = S; | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:344:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:324:5 | LL | #[repr = "3900"] impl S { } | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:330:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:310:1 | LL | #[repr = "3900"] | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:352:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:332:5 | LL | #[path = "3800"] fn f() { } | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:355:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:335:5 | LL | #[path = "3800"] struct S; | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:358:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:338:5 | LL | #[path = "3800"] type T = S; | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:361:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:341:5 | LL | #[path = "3800"] impl S { } | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:368:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:348:17 | LL | mod inner { #![abi="3700"] } | ^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:371:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:351:5 | LL | #[abi = "3700"] fn f() { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:374:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:354:5 | LL | #[abi = "3700"] struct S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:377:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:357:5 | LL | #[abi = "3700"] type T = S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:380:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:360:5 | LL | #[abi = "3700"] impl S { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:365:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:345:1 | LL | #[abi = "3700"] | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:387:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:367:17 | LL | mod inner { #![automatically_derived="3600"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:390:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:370:5 | LL | #[automatically_derived = "3600"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:393:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:373:5 | LL | #[automatically_derived = "3600"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:396:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:376:5 | LL | #[automatically_derived = "3600"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:399:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:379:5 | LL | #[automatically_derived = "3600"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:384:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:364:1 | LL | #[automatically_derived = "3600"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: function is marked #[no_mangle], but not exported - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:407:27 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:387:27 | LL | #[no_mangle = "3500"] fn f() { } | -^^^^^^^^^ @@ -523,793 +479,787 @@ LL | #[no_mangle = "3500"] fn f() { } = note: #[warn(private_no_mangle_fns)] on by default warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:420:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:400:17 | LL | mod inner { #![no_link="3400"] } | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:423:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:403:5 | LL | #[no_link = "3400"] fn f() { } | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:426:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:406:5 | LL | #[no_link = "3400"] struct S; | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:429:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:409:5 | LL | #[no_link = "3400"]type T = S; | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:432:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:412:5 | LL | #[no_link = "3400"] impl S { } | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:417:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:397:1 | LL | #[no_link = "3400"] | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:439:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:419:17 | LL | mod inner { #![should_panic="3200"] } | ^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:442:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:422:5 | LL | #[should_panic = "3200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:445:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:425:5 | LL | #[should_panic = "3200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:448:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:428:5 | LL | #[should_panic = "3200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:451:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:431:5 | LL | #[should_panic = "3200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:436:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:416:1 | LL | #[should_panic = "3200"] | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:458:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:438:17 | LL | mod inner { #![ignore="3100"] } | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:461:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:441:5 | LL | #[ignore = "3100"] fn f() { } | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:464:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:444:5 | LL | #[ignore = "3100"] struct S; | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:467:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:447:5 | LL | #[ignore = "3100"] type T = S; | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:470:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:450:5 | LL | #[ignore = "3100"] impl S { } | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:455:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:435:1 | LL | #[ignore = "3100"] | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:477:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:457:17 | LL | mod inner { #![no_implicit_prelude="3000"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:480:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:460:5 | LL | #[no_implicit_prelude = "3000"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:483:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:463:5 | LL | #[no_implicit_prelude = "3000"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:486:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:466:5 | LL | #[no_implicit_prelude = "3000"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:489:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:469:5 | LL | #[no_implicit_prelude = "3000"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:474:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:454:1 | LL | #[no_implicit_prelude = "3000"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:496:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:476:17 | LL | mod inner { #![reexport_test_harness_main="2900"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:499:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:479:5 | LL | #[reexport_test_harness_main = "2900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:502:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:482:5 | LL | #[reexport_test_harness_main = "2900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:505:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:485:5 | LL | #[reexport_test_harness_main = "2900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:508:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:488:5 | LL | #[reexport_test_harness_main = "2900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:493:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:473:1 | LL | #[reexport_test_harness_main = "2900"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:519:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:499:5 | LL | #[macro_escape] fn f() { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:522:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:502:5 | LL | #[macro_escape] struct S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:525:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:505:5 | LL | #[macro_escape] type T = S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:528:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:508:5 | LL | #[macro_escape] impl S { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:536:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:516:17 | LL | mod inner { #![no_std="2600"] } | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:536:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:516:17 | LL | mod inner { #![no_std="2600"] } | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:540:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:520:5 | LL | #[no_std = "2600"] fn f() { } | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:540:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:520:5 | LL | #[no_std = "2600"] fn f() { } | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:544:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:524:5 | LL | #[no_std = "2600"] struct S; | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:544:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:524:5 | LL | #[no_std = "2600"] struct S; | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:548:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:528:5 | LL | #[no_std = "2600"] type T = S; | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:548:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:528:5 | LL | #[no_std = "2600"] type T = S; | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:552:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:532:5 | LL | #[no_std = "2600"] impl S { } | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:552:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:532:5 | LL | #[no_std = "2600"] impl S { } | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:532:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:512:1 | LL | #[no_std = "2600"] | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:532:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:512:1 | LL | #[no_std = "2600"] | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:692:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:671:17 | LL | mod inner { #![crate_name="0900"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:692:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:671:17 | LL | mod inner { #![crate_name="0900"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:675:5 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:675:5 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:700:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:679:5 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:700:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:679:5 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:704:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:683:5 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:704:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:683:5 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:708:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:687:5 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:708:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:687:5 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:688:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:667:1 | LL | #[crate_name = "0900"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:688:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:667:1 | LL | #[crate_name = "0900"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:717:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:17 | LL | mod inner { #![crate_type="0800"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:717:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:17 | LL | mod inner { #![crate_type="0800"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:721:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:700:5 | LL | #[crate_type = "0800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:721:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:700:5 | LL | #[crate_type = "0800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:725:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:704:5 | LL | #[crate_type = "0800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:725:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:704:5 | LL | #[crate_type = "0800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:729:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:708:5 | LL | #[crate_type = "0800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:729:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:708:5 | LL | #[crate_type = "0800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:733:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:5 | LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:733:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:5 | LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:713:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:692:1 | LL | #[crate_type = "0800"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:713:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:692:1 | LL | #[crate_type = "0800"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:742:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:721:17 | LL | mod inner { #![feature(x0600)] } | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:742:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:721:17 | LL | mod inner { #![feature(x0600)] } | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:746:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:725:5 | LL | #[feature(x0600)] fn f() { } | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:746:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:725:5 | LL | #[feature(x0600)] fn f() { } | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:750:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:729:5 | LL | #[feature(x0600)] struct S; | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:750:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:729:5 | LL | #[feature(x0600)] struct S; | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:754:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:733:5 | LL | #[feature(x0600)] type T = S; | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:754:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:733:5 | LL | #[feature(x0600)] type T = S; | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:758:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:737:5 | LL | #[feature(x0600)] impl S { } | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:758:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:737:5 | LL | #[feature(x0600)] impl S { } | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:738:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:717:1 | LL | #[feature(x0600)] | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:738:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:717:1 | LL | #[feature(x0600)] | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:768:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:747:17 | LL | mod inner { #![no_main="0400"] } | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:768:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:747:17 | LL | mod inner { #![no_main="0400"] } | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:772:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:751:5 | LL | #[no_main = "0400"] fn f() { } | ^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:772:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:751:5 | LL | #[no_main = "0400"] fn f() { } | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:776:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:755:5 | LL | #[no_main = "0400"] struct S; | ^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:776:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:755:5 | LL | #[no_main = "0400"] struct S; | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:780:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:759:5 | LL | #[no_main = "0400"] type T = S; | ^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:780:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:759:5 | LL | #[no_main = "0400"] type T = S; | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:784:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:763:5 | LL | #[no_main = "0400"] impl S { } | ^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:784:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:763:5 | LL | #[no_main = "0400"] impl S { } | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:764:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:743:1 | LL | #[no_main = "0400"] | ^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:764:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:743:1 | LL | #[no_main = "0400"] | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:806:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:785:17 | LL | mod inner { #![recursion_limit="0200"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:806:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:785:17 | LL | mod inner { #![recursion_limit="0200"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:810:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:789:5 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:810:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:789:5 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:814:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:793:5 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:814:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:793:5 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:818:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:797:5 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:818:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:797:5 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:822:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:801:5 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:822:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:801:5 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:802:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:781:1 | LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:802:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:781:1 | LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:831:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:810:17 | LL | mod inner { #![type_length_limit="0100"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:831:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:810:17 | LL | mod inner { #![type_length_limit="0100"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:835:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:814:5 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:835:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:814:5 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:839:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:818:5 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:839:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:818:5 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:843:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:822:5 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:843:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:822:5 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:847:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:826:5 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:847:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:826:5 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:827:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:806:1 | LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:827:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:806:1 | LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:53:1 - | -LL | #![macro_reexport = "5000"] //~ WARN unused attribute - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:55:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:54:1 | LL | #![macro_export = "4800"] //~ WARN unused attribute | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:56:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:55:1 | LL | #![plugin_registrar = "4700"] //~ WARN unused attribute | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:59:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:58:1 | LL | #![main = "x4400"] //~ WARN unused attribute | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:60:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:59:1 | LL | #![start = "x4300"] //~ WARN unused attribute | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:63:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:62:1 | LL | #![repr = "3900"] //~ WARN unused attribute | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:64:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:63:1 | LL | #![path = "3800"] //~ WARN unused attribute | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:65:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:64:1 | LL | #![abi = "3700"] //~ WARN unused attribute | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:66:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:65:1 | LL | #![automatically_derived = "3600"] //~ WARN unused attribute | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:68:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:67:1 | LL | #![no_link = "3400"] //~ WARN unused attribute | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:70:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:69:1 | LL | #![should_panic = "3200"] //~ WARN unused attribute | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:71:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:70:1 | LL | #![ignore = "3100"] //~ WARN unused attribute | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:77:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:76:1 | LL | #![proc_macro_derive = "2500"] //~ WARN unused attribute | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: compilation successful - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:858:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:837:1 | LL | / fn main() { //~ ERROR compilation successful LL | | println!("Hello World"); diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-inline.rs b/src/test/ui/feature-gate/issue-43106-gating-of-inline.rs index 410f960e655..b03faad988e 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-inline.rs +++ b/src/test/ui/feature-gate/issue-43106-gating-of-inline.rs @@ -19,21 +19,21 @@ #![inline = "2100"] #[inline = "2100"] -//~^ ERROR attribute should be applied to function +//~^ ERROR attribute should be applied to function or closure mod inline { mod inner { #![inline="2100"] } - //~^ ERROR attribute should be applied to function + //~^ ERROR attribute should be applied to function or closure #[inline = "2100"] fn f() { } #[inline = "2100"] struct S; - //~^ ERROR attribute should be applied to function + //~^ ERROR attribute should be applied to function or closure #[inline = "2100"] type T = S; - //~^ ERROR attribute should be applied to function + //~^ ERROR attribute should be applied to function or closure #[inline = "2100"] impl S { } - //~^ ERROR attribute should be applied to function + //~^ ERROR attribute should be applied to function or closure } fn main() {} diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-inline.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-inline.stderr index d67d78e31a9..4d63c3f5012 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-inline.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-inline.stderr @@ -1,41 +1,41 @@ -error[E0518]: attribute should be applied to function +error[E0518]: attribute should be applied to function or closure --> $DIR/issue-43106-gating-of-inline.rs:21:1 | LL | #[inline = "2100"] | ^^^^^^^^^^^^^^^^^^ -LL | //~^ ERROR attribute should be applied to function +LL | //~^ ERROR attribute should be applied to function or closure LL | / mod inline { LL | | mod inner { #![inline="2100"] } -LL | | //~^ ERROR attribute should be applied to function +LL | | //~^ ERROR attribute should be applied to function or closure LL | | ... | -LL | | //~^ ERROR attribute should be applied to function +LL | | //~^ ERROR attribute should be applied to function or closure LL | | } - | |_- not a function + | |_- not a function or closure -error[E0518]: attribute should be applied to function +error[E0518]: attribute should be applied to function or closure --> $DIR/issue-43106-gating-of-inline.rs:24:17 | LL | mod inner { #![inline="2100"] } - | ------------^^^^^^^^^^^^^^^^^-- not a function + | ------------^^^^^^^^^^^^^^^^^-- not a function or closure -error[E0518]: attribute should be applied to function +error[E0518]: attribute should be applied to function or closure --> $DIR/issue-43106-gating-of-inline.rs:29:5 | LL | #[inline = "2100"] struct S; - | ^^^^^^^^^^^^^^^^^^ --------- not a function + | ^^^^^^^^^^^^^^^^^^ --------- not a function or closure -error[E0518]: attribute should be applied to function +error[E0518]: attribute should be applied to function or closure --> $DIR/issue-43106-gating-of-inline.rs:32:5 | LL | #[inline = "2100"] type T = S; - | ^^^^^^^^^^^^^^^^^^ ----------- not a function + | ^^^^^^^^^^^^^^^^^^ ----------- not a function or closure -error[E0518]: attribute should be applied to function +error[E0518]: attribute should be applied to function or closure --> $DIR/issue-43106-gating-of-inline.rs:35:5 | LL | #[inline = "2100"] impl S { } - | ^^^^^^^^^^^^^^^^^^ ---------- not a function + | ^^^^^^^^^^^^^^^^^^ ---------- not a function or closure error: aborting due to 5 previous errors diff --git a/src/test/ui/rfc_1940-must_use_on_functions/fn_must_use.rs b/src/test/ui/fn_must_use.rs index d20ebf0b740..def23046db2 100644 --- a/src/test/ui/rfc_1940-must_use_on_functions/fn_must_use.rs +++ b/src/test/ui/fn_must_use.rs @@ -10,7 +10,6 @@ // compile-pass -#![feature(fn_must_use)] #![warn(unused_must_use)] #[derive(PartialEq, Eq)] diff --git a/src/test/ui/rfc_1940-must_use_on_functions/fn_must_use.stderr b/src/test/ui/fn_must_use.stderr index d0a8bb525b6..5026dac0a94 100644 --- a/src/test/ui/rfc_1940-must_use_on_functions/fn_must_use.stderr +++ b/src/test/ui/fn_must_use.stderr @@ -1,47 +1,47 @@ warning: unused return value of `need_to_use_this_value` which must be used: it's important - --> $DIR/fn_must_use.rs:61:5 + --> $DIR/fn_must_use.rs:60:5 | LL | need_to_use_this_value(); //~ WARN unused return value | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: lint level defined here - --> $DIR/fn_must_use.rs:14:9 + --> $DIR/fn_must_use.rs:13:9 | LL | #![warn(unused_must_use)] | ^^^^^^^^^^^^^^^ warning: unused return value of `MyStruct::need_to_use_this_method_value` which must be used - --> $DIR/fn_must_use.rs:66:5 + --> $DIR/fn_must_use.rs:65:5 | LL | m.need_to_use_this_method_value(); //~ WARN unused return value | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused return value of `EvenNature::is_even` which must be used: no side effects - --> $DIR/fn_must_use.rs:67:5 + --> $DIR/fn_must_use.rs:66:5 | LL | m.is_even(); // trait method! | ^^^^^^^^^^^^ warning: unused return value of `std::cmp::PartialEq::eq` which must be used - --> $DIR/fn_must_use.rs:73:5 + --> $DIR/fn_must_use.rs:72:5 | LL | 2.eq(&3); //~ WARN unused return value | ^^^^^^^^^ warning: unused return value of `std::cmp::PartialEq::eq` which must be used - --> $DIR/fn_must_use.rs:74:5 + --> $DIR/fn_must_use.rs:73:5 | LL | m.eq(&n); //~ WARN unused return value | ^^^^^^^^^ warning: unused comparison which must be used - --> $DIR/fn_must_use.rs:77:5 + --> $DIR/fn_must_use.rs:76:5 | LL | 2 == 3; //~ WARN unused comparison | ^^^^^^ warning: unused comparison which must be used - --> $DIR/fn_must_use.rs:78:5 + --> $DIR/fn_must_use.rs:77:5 | LL | m == n; //~ WARN unused comparison | ^^^^^^ diff --git a/src/test/ui/generator/borrowing.nll.stderr b/src/test/ui/generator/borrowing.nll.stderr index 1801da6c8b2..243e9018585 100644 --- a/src/test/ui/generator/borrowing.nll.stderr +++ b/src/test/ui/generator/borrowing.nll.stderr @@ -1,14 +1,30 @@ -error: compilation successful - --> $DIR/borrowing.rs:15:1 +error[E0597]: `a` does not live long enough + --> $DIR/borrowing.rs:18:18 | -LL | / fn main() { #![rustc_error] // rust-lang/rust#49855 -LL | | let _b = { -LL | | let a = 3; -LL | | unsafe { (|| yield &a).resume() } -... | -LL | | }; -LL | | } - | |_^ +LL | unsafe { (|| yield &a).resume() } + | ^^^^^^^^^^^^^ + | | + | borrowed value does not live long enough + | borrow may end up in a temporary, created here +LL | //~^ ERROR: `a` does not live long enough +LL | }; + | -- temporary later dropped here, potentially using the reference + | | + | borrowed value only lives until here -error: aborting due to previous error +error[E0597]: `a` does not live long enough + --> $DIR/borrowing.rs:24:9 + | +LL | / || { +LL | | yield &a +LL | | //~^ ERROR: `a` does not live long enough +LL | | } + | |_________^ borrowed value does not live long enough +LL | }; + | - borrowed value only lives until here +LL | } + | - borrow later used here, when `_b` is dropped + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/generator/borrowing.rs b/src/test/ui/generator/borrowing.rs index f80aca9fb00..e56927d8182 100644 --- a/src/test/ui/generator/borrowing.rs +++ b/src/test/ui/generator/borrowing.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(generators, generator_trait, rustc_attrs)] +#![feature(generators, generator_trait)] use std::ops::Generator; -fn main() { #![rustc_error] // rust-lang/rust#49855 +fn main() { let _b = { let a = 3; unsafe { (|| yield &a).resume() } diff --git a/src/test/ui/generator/dropck.nll.stderr b/src/test/ui/generator/dropck.nll.stderr index 72ebaab3278..c352fd6a62f 100644 --- a/src/test/ui/generator/dropck.nll.stderr +++ b/src/test/ui/generator/dropck.nll.stderr @@ -1,14 +1,20 @@ -error: compilation successful - --> $DIR/dropck.rs:16:1 +error[E0597]: `ref_` does not live long enough + --> $DIR/dropck.rs:22:11 | -LL | / fn main() { #![rustc_error] // rust-lang/rust#49855 -LL | | let (cell, mut gen); -LL | | cell = Box::new(RefCell::new(0)); -LL | | let ref_ = Box::leak(Box::new(Some(cell.borrow_mut()))); -... | -LL | | // drops the RefCell and then the Ref, leading to use-after-free -LL | | } - | |_^ +LL | gen = || { + | ___________^ +LL | | // but the generator can use it to drop a `Ref<'a, i32>`. +LL | | let _d = ref_.take(); //~ ERROR `ref_` does not live long enough +LL | | yield; +LL | | }; + | |_____^ borrowed value does not live long enough +... +LL | } + | - + | | + | borrowed value only lives until here + | borrow later used here, when `gen` is dropped error: aborting due to previous error +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/generator/dropck.rs b/src/test/ui/generator/dropck.rs index 8f4ba64fd57..857288818c6 100644 --- a/src/test/ui/generator/dropck.rs +++ b/src/test/ui/generator/dropck.rs @@ -8,15 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(generators, generator_trait, box_leak, rustc_attrs)] +#![feature(generators, generator_trait, box_leak)] use std::cell::RefCell; use std::ops::Generator; -fn main() { #![rustc_error] // rust-lang/rust#49855 +fn main() { let (cell, mut gen); cell = Box::new(RefCell::new(0)); let ref_ = Box::leak(Box::new(Some(cell.borrow_mut()))); + //~^ ERROR `*cell` does not live long enough [E0597] // the upvar is the non-dropck `&mut Option<Ref<'a, i32>>`. gen = || { // but the generator can use it to drop a `Ref<'a, i32>`. diff --git a/src/test/ui/generator/dropck.stderr b/src/test/ui/generator/dropck.stderr index 4a22d299701..1a6fed2dd35 100644 --- a/src/test/ui/generator/dropck.stderr +++ b/src/test/ui/generator/dropck.stderr @@ -1,5 +1,16 @@ +error[E0597]: `*cell` does not live long enough + --> $DIR/dropck.rs:19:40 + | +LL | let ref_ = Box::leak(Box::new(Some(cell.borrow_mut()))); + | ^^^^ borrowed value does not live long enough +... +LL | } + | - `*cell` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + error[E0597]: `ref_` does not live long enough - --> $DIR/dropck.rs:23:18 + --> $DIR/dropck.rs:24:18 | LL | gen = || { | -- capture occurs here @@ -12,6 +23,6 @@ LL | } | = note: values in a scope are dropped in the opposite order they are created -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/generator/ref-escapes-but-not-over-yield.nll.stderr b/src/test/ui/generator/ref-escapes-but-not-over-yield.nll.stderr index 08839c23c37..70870b98365 100644 --- a/src/test/ui/generator/ref-escapes-but-not-over-yield.nll.stderr +++ b/src/test/ui/generator/ref-escapes-but-not-over-yield.nll.stderr @@ -1,11 +1,19 @@ error[E0597]: `b` does not live long enough --> $DIR/ref-escapes-but-not-over-yield.rs:24:13 | -LL | a = &b; - | ^^ borrowed value does not live long enough -LL | //~^ ERROR `b` does not live long enough -LL | }; - | - borrowed value only lives until here +LL | let mut b = move || { + | _________________- +LL | | yield(); +LL | | let b = 5; +LL | | a = &b; + | | ^^ borrowed value does not live long enough +LL | | //~^ ERROR `b` does not live long enough +LL | | }; + | | - + | | | + | | borrowed value only lives until here + | |_____temporary later dropped here, potentially using the reference + | borrow may end up in a temporary, created here error: aborting due to previous error diff --git a/src/test/ui/generator/yield-while-iterating.nll.stderr b/src/test/ui/generator/yield-while-iterating.nll.stderr index be4852aaf06..af79eb7ac05 100644 --- a/src/test/ui/generator/yield-while-iterating.nll.stderr +++ b/src/test/ui/generator/yield-while-iterating.nll.stderr @@ -6,20 +6,6 @@ LL | for p in &x { //~ ERROR LL | yield(); | ------- possible yield occurs here -error[E0597]: borrowed value does not live long enough - --> $DIR/yield-while-iterating.rs:50:17 - | -LL | let mut b = || { - | _________________^ -LL | | for p in &mut x { -LL | | yield p; -LL | | } -LL | | }; - | | ^ - | | | - | |_____temporary value only lives until here - | temporary value does not live long enough - error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable --> $DIR/yield-while-iterating.rs:67:20 | @@ -35,21 +21,7 @@ LL | println!("{}", x[0]); //~ ERROR LL | b.resume(); | - borrow later used here -error[E0597]: borrowed value does not live long enough - --> $DIR/yield-while-iterating.rs:62:17 - | -LL | let mut b = || { - | _________________^ -LL | | for p in &mut x { -LL | | yield p; -LL | | } -LL | | }; - | | ^ - | | | - | |_____temporary value only lives until here - | temporary value does not live long enough - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors -Some errors occurred: E0502, E0597, E0626. +Some errors occurred: E0502, E0626. For more information about an error, try `rustc --explain E0502`. diff --git a/src/test/ui/hygiene/fields.rs b/src/test/ui/hygiene/fields.rs index ed155b28037..64217770b13 100644 --- a/src/test/ui/hygiene/fields.rs +++ b/src/test/ui/hygiene/fields.rs @@ -10,7 +10,7 @@ // ignore-pretty pretty-printing is unhygienic -#![feature(decl_macro, proc_macro_path_invoc)] +#![feature(decl_macro)] mod foo { struct S { x: u32 } diff --git a/src/test/ui/hygiene/globs.rs b/src/test/ui/hygiene/globs.rs index f3f400aafeb..7ba217061c6 100644 --- a/src/test/ui/hygiene/globs.rs +++ b/src/test/ui/hygiene/globs.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(decl_macro, proc_macro_path_invoc)] +#![feature(decl_macro)] mod foo { pub fn f() {} diff --git a/src/test/ui/hygiene/impl_items.rs b/src/test/ui/hygiene/impl_items.rs index 4f997a790e6..cdba559445d 100644 --- a/src/test/ui/hygiene/impl_items.rs +++ b/src/test/ui/hygiene/impl_items.rs @@ -10,7 +10,7 @@ // ignore-pretty pretty-printing is unhygienic -#![feature(decl_macro, proc_macro_path_invoc)] +#![feature(decl_macro)] mod foo { struct S; diff --git a/src/test/ui/hygiene/intercrate.rs b/src/test/ui/hygiene/intercrate.rs index 20ca918f026..50fc985ba34 100644 --- a/src/test/ui/hygiene/intercrate.rs +++ b/src/test/ui/hygiene/intercrate.rs @@ -14,7 +14,7 @@ // error-pattern:type `fn() -> u32 {intercrate::foo::bar::f}` is private -#![feature(decl_macro, proc_macro_path_invoc)] +#![feature(decl_macro)] extern crate intercrate; diff --git a/src/test/ui/hygiene/no_implicit_prelude.rs b/src/test/ui/hygiene/no_implicit_prelude.rs index ea6a45fba6a..c90c7b3093c 100644 --- a/src/test/ui/hygiene/no_implicit_prelude.rs +++ b/src/test/ui/hygiene/no_implicit_prelude.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(decl_macro, proc_macro_path_invoc)] +#![feature(decl_macro)] mod foo { pub macro m() { Vec::new(); ().clone() } diff --git a/src/test/ui/hygiene/privacy.rs b/src/test/ui/hygiene/privacy.rs index 8a392db92f9..987cad187d4 100644 --- a/src/test/ui/hygiene/privacy.rs +++ b/src/test/ui/hygiene/privacy.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(decl_macro, proc_macro_path_invoc)] +#![feature(decl_macro)] mod foo { fn f() {} diff --git a/src/test/ui/hygiene/trait_items.rs b/src/test/ui/hygiene/trait_items.rs index d0da6254b9b..3bd19cbc0ac 100644 --- a/src/test/ui/hygiene/trait_items.rs +++ b/src/test/ui/hygiene/trait_items.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(decl_macro, proc_macro_path_invoc)] +#![feature(decl_macro)] mod foo { pub trait T { diff --git a/src/test/ui/impl-trait/auto-trait-leak.stderr b/src/test/ui/impl-trait/auto-trait-leak.stderr index 3b20451b102..efa9a58d633 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak.stderr @@ -34,6 +34,7 @@ error[E0391]: cycle detected when processing `cycle1` LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ | +note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... note: ...which requires processing `cycle2::{{impl-Trait}}`... --> $DIR/auto-trait-leak.rs:49:16 | @@ -44,6 +45,7 @@ note: ...which requires processing `cycle2`... | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... note: ...which requires processing `cycle1::{{impl-Trait}}`... --> $DIR/auto-trait-leak.rs:42:16 | diff --git a/src/test/ui/impl_trait_projections.rs b/src/test/ui/impl_trait_projections.rs index 6a727942271..57a0040600a 100644 --- a/src/test/ui/impl_trait_projections.rs +++ b/src/test/ui/impl_trait_projections.rs @@ -7,8 +7,6 @@ // <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(dyn_trait)] - use std::fmt::Debug; use std::option; diff --git a/src/test/ui/impl_trait_projections.stderr b/src/test/ui/impl_trait_projections.stderr index 9b38de614fc..f6d58984ece 100644 --- a/src/test/ui/impl_trait_projections.stderr +++ b/src/test/ui/impl_trait_projections.stderr @@ -1,29 +1,29 @@ error[E0667]: `impl Trait` is not allowed in path parameters - --> $DIR/impl_trait_projections.rs:23:51 + --> $DIR/impl_trait_projections.rs:21:51 | LL | fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item { | ^^^^^^^^^^^^^ error[E0667]: `impl Trait` is not allowed in path parameters - --> $DIR/impl_trait_projections.rs:30:9 + --> $DIR/impl_trait_projections.rs:28:9 | LL | -> <impl Iterator as Iterator>::Item | ^^^^^^^^^^^^^ error[E0667]: `impl Trait` is not allowed in path parameters - --> $DIR/impl_trait_projections.rs:37:27 + --> $DIR/impl_trait_projections.rs:35:27 | LL | -> <::std::ops::Range<impl Debug> as Iterator>::Item | ^^^^^^^^^^ error[E0667]: `impl Trait` is not allowed in path parameters - --> $DIR/impl_trait_projections.rs:44:29 + --> $DIR/impl_trait_projections.rs:42:29 | LL | -> <dyn Iterator<Item = impl Debug> as Iterator>::Item | ^^^^^^^^^^ error[E0223]: ambiguous associated type - --> $DIR/impl_trait_projections.rs:23:50 + --> $DIR/impl_trait_projections.rs:21:50 | LL | fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item { | ^^^^^^^^^^^^^^^^^^^^^ ambiguous associated type diff --git a/src/test/ui/imports/macro-paths.rs b/src/test/ui/imports/macro-paths.rs index 51e5257be1b..e709eeee14a 100644 --- a/src/test/ui/imports/macro-paths.rs +++ b/src/test/ui/imports/macro-paths.rs @@ -10,7 +10,7 @@ // aux-build:two_macros.rs -#![feature(use_extern_macros, proc_macro_path_invoc)] +#![feature(use_extern_macros)] extern crate two_macros; diff --git a/src/test/ui/imports/shadow_builtin_macros.rs b/src/test/ui/imports/shadow_builtin_macros.rs index aad0a43be26..93de136c405 100644 --- a/src/test/ui/imports/shadow_builtin_macros.rs +++ b/src/test/ui/imports/shadow_builtin_macros.rs @@ -10,7 +10,7 @@ // aux-build:two_macros.rs -#![feature(use_extern_macros, proc_macro_path_invoc)] +#![feature(use_extern_macros)] mod foo { extern crate two_macros; diff --git a/src/test/ui/in-band-lifetimes/impl/dyn-trait.nll.stderr b/src/test/ui/in-band-lifetimes/impl/dyn-trait.nll.stderr index ec8c4ecf102..4cf7feddd46 100644 --- a/src/test/ui/in-band-lifetimes/impl/dyn-trait.nll.stderr +++ b/src/test/ui/in-band-lifetimes/impl/dyn-trait.nll.stderr @@ -1,11 +1,11 @@ warning: not reporting region error due to nll - --> $DIR/dyn-trait.rs:33:16 + --> $DIR/dyn-trait.rs:32:16 | LL | static_val(x); //~ ERROR cannot infer | ^ error: free region `'a` does not outlive free region `'static` - --> $DIR/dyn-trait.rs:33:5 + --> $DIR/dyn-trait.rs:32:5 | LL | static_val(x); //~ ERROR cannot infer | ^^^^^^^^^^^^^ diff --git a/src/test/ui/in-band-lifetimes/impl/dyn-trait.rs b/src/test/ui/in-band-lifetimes/impl/dyn-trait.rs index a504bae2e60..c27bbe77fbf 100644 --- a/src/test/ui/in-band-lifetimes/impl/dyn-trait.rs +++ b/src/test/ui/in-band-lifetimes/impl/dyn-trait.rs @@ -13,7 +13,6 @@ #![allow(warnings)] -#![feature(dyn_trait)] #![feature(in_band_lifetimes)] use std::fmt::Debug; diff --git a/src/test/ui/in-band-lifetimes/impl/dyn-trait.stderr b/src/test/ui/in-band-lifetimes/impl/dyn-trait.stderr index 9d6a318c075..201470abe67 100644 --- a/src/test/ui/in-band-lifetimes/impl/dyn-trait.stderr +++ b/src/test/ui/in-band-lifetimes/impl/dyn-trait.stderr @@ -1,11 +1,11 @@ error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements - --> $DIR/dyn-trait.rs:33:16 + --> $DIR/dyn-trait.rs:32:16 | LL | static_val(x); //~ ERROR cannot infer | ^ | -note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 32:1... - --> $DIR/dyn-trait.rs:32:1 +note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 31:1... + --> $DIR/dyn-trait.rs:31:1 | LL | fn with_dyn_debug_static<'a>(x: Box<dyn Debug + 'a>) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/inference_unstable.rs b/src/test/ui/inference_unstable.rs index 816c443a06c..5a70dffd4c8 100644 --- a/src/test/ui/inference_unstable.rs +++ b/src/test/ui/inference_unstable.rs @@ -25,5 +25,5 @@ use inference_unstable_itertools::IpuItertools; fn main() { assert_eq!('x'.ipu_flatten(), 1); //~^ WARN a method with this name may be added to the standard library in the future - //~^^ WARN once this method is added to the standard library, there will be ambiguity here + //~^^ WARN once this method is added to the standard library, the ambiguity may cause an error } diff --git a/src/test/ui/inference_unstable.stderr b/src/test/ui/inference_unstable.stderr index 9c614d659d3..a217bc57b36 100644 --- a/src/test/ui/inference_unstable.stderr +++ b/src/test/ui/inference_unstable.stderr @@ -5,7 +5,7 @@ LL | assert_eq!('x'.ipu_flatten(), 1); | ^^^^^^^^^^^ | = note: #[warn(unstable_name_collision)] on by default - = warning: once this method is added to the standard library, there will be ambiguity here, which will cause a hard error! + = warning: once this method is added to the standard library, the ambiguity may cause an error or change in behavior! = note: for more information, see issue #48919 <https://github.com/rust-lang/rust/issues/48919> = help: call with fully qualified syntax `inference_unstable_itertools::IpuItertools::ipu_flatten(...)` to keep using the current method = note: add #![feature(ipu_flatten)] to the crate attributes to enable `inference_unstable_iterator::IpuIterator::ipu_flatten` diff --git a/src/test/ui/issue-49934.rs b/src/test/ui/issue-49934.rs new file mode 100644 index 00000000000..3e30e7a6450 --- /dev/null +++ b/src/test/ui/issue-49934.rs @@ -0,0 +1,52 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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-pass + +#![feature(stmt_expr_attributes)] +#![warn(unused_attributes)] //~ NOTE lint level defined here + +fn foo<#[derive(Debug)] T>() { //~ WARN unused attribute + match 0 { + #[derive(Debug)] //~ WARN unused attribute + _ => (), + } +} + +fn main() { + // fold_stmt (Item) + #[allow(dead_code)] + #[derive(Debug)] // should not warn + struct Foo; + + // fold_stmt (Mac) + #[derive(Debug)] + //~^ WARN `#[derive]` does nothing on macro invocations + //~| NOTE this may become a hard error in a future release + println!("Hello, world!"); + + // fold_stmt (Semi) + #[derive(Debug)] //~ WARN unused attribute + "Hello, world!"; + + // fold_stmt (Local) + #[derive(Debug)] //~ WARN unused attribute + let _ = "Hello, world!"; + + // fold_expr + let _ = #[derive(Debug)] "Hello, world!"; + //~^ WARN unused attribute + + let _ = [ + // fold_opt_expr + #[derive(Debug)] //~ WARN unused attribute + "Hello, world!" + ]; +} diff --git a/src/test/ui/issue-49934.stderr b/src/test/ui/issue-49934.stderr new file mode 100644 index 00000000000..298230b8b29 --- /dev/null +++ b/src/test/ui/issue-49934.stderr @@ -0,0 +1,50 @@ +warning: `#[derive]` does nothing on macro invocations + --> $DIR/issue-49934.rs:30:5 + | +LL | #[derive(Debug)] + | ^^^^^^^^^^^^^^^^ + | + = note: this may become a hard error in a future release + +warning: unused attribute + --> $DIR/issue-49934.rs:16:8 + | +LL | fn foo<#[derive(Debug)] T>() { //~ WARN unused attribute + | ^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/issue-49934.rs:14:9 + | +LL | #![warn(unused_attributes)] //~ NOTE lint level defined here + | ^^^^^^^^^^^^^^^^^ + +warning: unused attribute + --> $DIR/issue-49934.rs:18:9 + | +LL | #[derive(Debug)] //~ WARN unused attribute + | ^^^^^^^^^^^^^^^^ + +warning: unused attribute + --> $DIR/issue-49934.rs:36:5 + | +LL | #[derive(Debug)] //~ WARN unused attribute + | ^^^^^^^^^^^^^^^^ + +warning: unused attribute + --> $DIR/issue-49934.rs:40:5 + | +LL | #[derive(Debug)] //~ WARN unused attribute + | ^^^^^^^^^^^^^^^^ + +warning: unused attribute + --> $DIR/issue-49934.rs:44:13 + | +LL | let _ = #[derive(Debug)] "Hello, world!"; + | ^^^^^^^^^^^^^^^^ + +warning: unused attribute + --> $DIR/issue-49934.rs:49:9 + | +LL | #[derive(Debug)] //~ WARN unused attribute + | ^^^^^^^^^^^^^^^^ + diff --git a/src/test/ui/issue-50187.rs b/src/test/ui/issue-50187.rs new file mode 100644 index 00000000000..87acf106393 --- /dev/null +++ b/src/test/ui/issue-50187.rs @@ -0,0 +1,49 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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-pass + +#![feature(use_extern_macros, decl_macro)] + +mod type_ns { + pub type A = u8; +} +mod value_ns { + pub const A: u8 = 0; +} +mod macro_ns { + pub macro A() {} +} + +mod merge2 { + pub use type_ns::A; + pub use value_ns::A; +} +mod merge3 { + pub use type_ns::A; + pub use value_ns::A; + pub use macro_ns::A; +} + +mod use2 { + pub use merge2::A; +} +mod use3 { + pub use merge3::A; +} + +fn main() { + type B2 = use2::A; + let a2 = use2::A; + + type B3 = use3::A; + let a3 = use3::A; + use3::A!(); +} diff --git a/src/test/ui/feature-gate-dyn-trait.rs b/src/test/ui/issue-50403.rs index 4b3803d019b..8d4c6c5140f 100644 --- a/src/test/ui/feature-gate-dyn-trait.rs +++ b/src/test/ui/issue-50403.rs @@ -8,7 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -trait Trait {} -type A = Box<dyn Trait>; //~ ERROR `dyn Trait` syntax is unstable +#![feature(concat_idents)] -fn main() {} +fn main() { + let x = concat_idents!(); //~ ERROR concat_idents! takes 1 or more arguments +} diff --git a/src/test/ui/issue-50403.stderr b/src/test/ui/issue-50403.stderr new file mode 100644 index 00000000000..f2871c72e25 --- /dev/null +++ b/src/test/ui/issue-50403.stderr @@ -0,0 +1,8 @@ +error: concat_idents! takes 1 or more arguments. + --> $DIR/issue-50403.rs:14:13 + | +LL | let x = concat_idents!(); //~ ERROR concat_idents! takes 1 or more arguments + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/lifetime_starts_expressions.rs b/src/test/ui/lifetime_starts_expressions.rs new file mode 100644 index 00000000000..ffe1d7c353b --- /dev/null +++ b/src/test/ui/lifetime_starts_expressions.rs @@ -0,0 +1,23 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn foo() -> u32 { + return 'label: loop { break 'label 42; }; +} + +fn bar() -> u32 { + loop { break 'label: loop { break 'label 42; }; } + //~^ ERROR expected identifier, found keyword `loop` + //~| ERROR expected type, found keyword `loop` +} + +pub fn main() { + foo(); +} diff --git a/src/test/ui/lifetime_starts_expressions.stderr b/src/test/ui/lifetime_starts_expressions.stderr new file mode 100644 index 00000000000..de42f1daa1e --- /dev/null +++ b/src/test/ui/lifetime_starts_expressions.stderr @@ -0,0 +1,14 @@ +error: expected identifier, found keyword `loop` + --> $DIR/lifetime_starts_expressions.rs:16:26 + | +LL | loop { break 'label: loop { break 'label 42; }; } + | ^^^^ expected identifier, found keyword + +error: expected type, found keyword `loop` + --> $DIR/lifetime_starts_expressions.rs:16:26 + | +LL | loop { break 'label: loop { break 'label 42; }; } + | ^^^^ expecting a type here because of type ascription + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.rs b/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.rs index 18b83370355..6994a377a06 100644 --- a/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.rs +++ b/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.rs @@ -10,6 +10,8 @@ // compile-pass +#![feature(box_syntax)] +#![feature(box_patterns)] #![warn(unused)] // UI tests pass `-A unused` (#43896) struct SoulHistory { @@ -18,6 +20,13 @@ struct SoulHistory { endless_and_singing: bool } +#[derive(Clone, Copy)] +enum Large { + Suit { case: () } +} + +struct Tuple(Large, ()); + fn main() { let i_think_continually = 2; let who_from_the_womb_remembered = SoulHistory { @@ -31,4 +40,38 @@ fn main() { endless_and_singing: true } = who_from_the_womb_remembered { hours_are_suns = false; } + + let bag = Large::Suit { + case: () + }; + + // Plain struct + match bag { + Large::Suit { case } => {} + }; + + // Referenced struct + match &bag { + &Large::Suit { case } => {} + }; + + // Boxed struct + match box bag { + box Large::Suit { case } => {} + }; + + // Tuple with struct + match (bag,) { + (Large::Suit { case },) => {} + }; + + // Slice with struct + match [bag] { + [Large::Suit { case }] => {} + }; + + // Tuple struct with struct + match Tuple(bag, ()) { + Tuple(Large::Suit { case }, ()) => {} + }; } diff --git a/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr b/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr index 35fe5479406..7bfe2c9162e 100644 --- a/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr +++ b/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr @@ -1,24 +1,24 @@ warning: unused variable: `i_think_continually` - --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:22:9 + --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:31:9 | LL | let i_think_continually = 2; | ^^^^^^^^^^^^^^^^^^^ help: consider using `_i_think_continually` instead | note: lint level defined here - --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:13:9 + --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:15:9 | LL | #![warn(unused)] // UI tests pass `-A unused` (#43896) | ^^^^^^ = note: #[warn(unused_variables)] implied by #[warn(unused)] warning: unused variable: `corridors_of_light` - --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:29:26 + --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:38:26 | LL | if let SoulHistory { corridors_of_light, | ^^^^^^^^^^^^^^^^^^ help: try ignoring the field: `corridors_of_light: _` warning: variable `hours_are_suns` is assigned to, but never used - --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:30:26 + --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:39:26 | LL | mut hours_are_suns, | ^^^^^^^^^^^^^^^^^^ @@ -26,15 +26,51 @@ LL | mut hours_are_suns, = note: consider using `_hours_are_suns` instead warning: value assigned to `hours_are_suns` is never read - --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:32:9 + --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:41:9 | LL | hours_are_suns = false; | ^^^^^^^^^^^^^^ | note: lint level defined here - --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:13:9 + --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:15:9 | LL | #![warn(unused)] // UI tests pass `-A unused` (#43896) | ^^^^^^ = note: #[warn(unused_assignments)] implied by #[warn(unused)] +warning: unused variable: `case` + --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:50:23 + | +LL | Large::Suit { case } => {} + | ^^^^ help: try ignoring the field: `case: _` + +warning: unused variable: `case` + --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:55:24 + | +LL | &Large::Suit { case } => {} + | ^^^^ help: try ignoring the field: `case: _` + +warning: unused variable: `case` + --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:60:27 + | +LL | box Large::Suit { case } => {} + | ^^^^ help: try ignoring the field: `case: _` + +warning: unused variable: `case` + --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:65:24 + | +LL | (Large::Suit { case },) => {} + | ^^^^ help: try ignoring the field: `case: _` + +warning: unused variable: `case` + --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:70:24 + | +LL | [Large::Suit { case }] => {} + | ^^^^ help: try ignoring the field: `case: _` + +warning: unused variable: `case` + --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:75:29 + | +LL | Tuple(Large::Suit { case }, ()) => {} + | ^^^^ help: try ignoring the field: `case: _` + diff --git a/src/test/ui/lint/must-use-ops.rs b/src/test/ui/lint/must-use-ops.rs new file mode 100644 index 00000000000..c0575f817c8 --- /dev/null +++ b/src/test/ui/lint/must-use-ops.rs @@ -0,0 +1,51 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Issue #50124 - Test warning for unused operator expressions + +// compile-pass + +#![warn(unused_must_use)] + +fn main() { + let val = 1; + let val_pointer = &val; + +// Comparison Operators + val == 1; + val < 1; + val <= 1; + val != 1; + val >= 1; + val > 1; + +// Arithmetic Operators + val + 2; + val - 2; + val / 2; + val * 2; + val % 2; + +// Logical Operators + true && true; + false || true; + +// Bitwise Operators + 5 ^ val; + 5 & val; + 5 | val; + 5 << val; + 5 >> val; + +// Unary Operators + !val; + -val; + *val_pointer; +} diff --git a/src/test/ui/lint/must-use-ops.stderr b/src/test/ui/lint/must-use-ops.stderr new file mode 100644 index 00000000000..5703536ef48 --- /dev/null +++ b/src/test/ui/lint/must-use-ops.stderr @@ -0,0 +1,132 @@ +warning: unused comparison which must be used + --> $DIR/must-use-ops.rs:22:5 + | +LL | val == 1; + | ^^^^^^^^ + | +note: lint level defined here + --> $DIR/must-use-ops.rs:15:9 + | +LL | #![warn(unused_must_use)] + | ^^^^^^^^^^^^^^^ + +warning: unused comparison which must be used + --> $DIR/must-use-ops.rs:23:5 + | +LL | val < 1; + | ^^^^^^^ + +warning: unused comparison which must be used + --> $DIR/must-use-ops.rs:24:5 + | +LL | val <= 1; + | ^^^^^^^^ + +warning: unused comparison which must be used + --> $DIR/must-use-ops.rs:25:5 + | +LL | val != 1; + | ^^^^^^^^ + +warning: unused comparison which must be used + --> $DIR/must-use-ops.rs:26:5 + | +LL | val >= 1; + | ^^^^^^^^ + +warning: unused comparison which must be used + --> $DIR/must-use-ops.rs:27:5 + | +LL | val > 1; + | ^^^^^^^ + +warning: unused arithmetic operation which must be used + --> $DIR/must-use-ops.rs:30:5 + | +LL | val + 2; + | ^^^^^^^ + +warning: unused arithmetic operation which must be used + --> $DIR/must-use-ops.rs:31:5 + | +LL | val - 2; + | ^^^^^^^ + +warning: unused arithmetic operation which must be used + --> $DIR/must-use-ops.rs:32:5 + | +LL | val / 2; + | ^^^^^^^ + +warning: unused arithmetic operation which must be used + --> $DIR/must-use-ops.rs:33:5 + | +LL | val * 2; + | ^^^^^^^ + +warning: unused arithmetic operation which must be used + --> $DIR/must-use-ops.rs:34:5 + | +LL | val % 2; + | ^^^^^^^ + +warning: unused logical operation which must be used + --> $DIR/must-use-ops.rs:37:5 + | +LL | true && true; + | ^^^^^^^^^^^^ + +warning: unused logical operation which must be used + --> $DIR/must-use-ops.rs:38:5 + | +LL | false || true; + | ^^^^^^^^^^^^^ + +warning: unused bitwise operation which must be used + --> $DIR/must-use-ops.rs:41:5 + | +LL | 5 ^ val; + | ^^^^^^^ + +warning: unused bitwise operation which must be used + --> $DIR/must-use-ops.rs:42:5 + | +LL | 5 & val; + | ^^^^^^^ + +warning: unused bitwise operation which must be used + --> $DIR/must-use-ops.rs:43:5 + | +LL | 5 | val; + | ^^^^^^^ + +warning: unused bitwise operation which must be used + --> $DIR/must-use-ops.rs:44:5 + | +LL | 5 << val; + | ^^^^^^^^ + +warning: unused bitwise operation which must be used + --> $DIR/must-use-ops.rs:45:5 + | +LL | 5 >> val; + | ^^^^^^^^ + +warning: unused unary operation which must be used + --> $DIR/must-use-ops.rs:48:5 + | +LL | !val; + | ^^^^ + +warning: unused unary operation which must be used + --> $DIR/must-use-ops.rs:49:5 + | +LL | -val; + | ^^^^ + +warning: unused unary operation which must be used + --> $DIR/must-use-ops.rs:50:5 + | +LL | *val_pointer; + | ^^^^^^^^^^^^ + diff --git a/src/test/compile-fail/macro-reexport-undef.rs b/src/test/ui/macro-reexport-removed.rs index 50ac89e49e0..bab583da37b 100644 --- a/src/test/compile-fail/macro-reexport-undef.rs +++ b/src/test/ui/macro-reexport-removed.rs @@ -10,12 +10,9 @@ // aux-build:two_macros.rs -#![feature(macro_reexport)] +#![feature(macro_reexport)] //~ ERROR feature has been removed -#[macro_use(macro_two)] -#[macro_reexport(no_way)] //~ ERROR re-exported macro not found +#[macro_reexport(macro_one)] //~ ERROR attribute `macro_reexport` is currently unknown extern crate two_macros; -pub fn main() { - macro_two!(); -} +fn main() {} diff --git a/src/test/ui/macro-reexport-removed.stderr b/src/test/ui/macro-reexport-removed.stderr new file mode 100644 index 00000000000..ba0ab232e86 --- /dev/null +++ b/src/test/ui/macro-reexport-removed.stderr @@ -0,0 +1,24 @@ +error[E0557]: feature has been removed + --> $DIR/macro-reexport-removed.rs:13:12 + | +LL | #![feature(macro_reexport)] //~ ERROR feature has been removed + | ^^^^^^^^^^^^^^ + | +note: subsumed by `#![feature(use_extern_macros)]` and `pub use` + --> $DIR/macro-reexport-removed.rs:13:12 + | +LL | #![feature(macro_reexport)] //~ ERROR feature has been removed + | ^^^^^^^^^^^^^^ + +error[E0658]: The attribute `macro_reexport` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) + --> $DIR/macro-reexport-removed.rs:15:1 + | +LL | #[macro_reexport(macro_one)] //~ ERROR attribute `macro_reexport` is currently unknown + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(custom_attribute)] to the crate attributes to enable + +error: aborting due to 2 previous errors + +Some errors occurred: E0557, E0658. +For more information about an error, try `rustc --explain E0557`. diff --git a/src/test/ui/mismatched_types/closure-arg-count.rs b/src/test/ui/mismatched_types/closure-arg-count.rs index 34232e81cbd..9eb11148a8b 100644 --- a/src/test/ui/mismatched_types/closure-arg-count.rs +++ b/src/test/ui/mismatched_types/closure-arg-count.rs @@ -39,7 +39,13 @@ fn main() { let _it = vec![1, 2, 3].into_iter().map(usize::checked_add); //~^ ERROR function is expected to take + + call(Foo); + //~^ ERROR function is expected to take } fn foo() {} fn qux(x: usize, y: usize) {} + +fn call<F, R>(_: F) where F: FnOnce() -> R {} +struct Foo(u8); diff --git a/src/test/ui/mismatched_types/closure-arg-count.stderr b/src/test/ui/mismatched_types/closure-arg-count.stderr index 6451c0d06fa..6270e794498 100644 --- a/src/test/ui/mismatched_types/closure-arg-count.stderr +++ b/src/test/ui/mismatched_types/closure-arg-count.stderr @@ -116,6 +116,21 @@ error[E0593]: function is expected to take 1 argument, but it takes 2 arguments LL | let _it = vec![1, 2, 3].into_iter().map(usize::checked_add); | ^^^ expected function that takes 1 argument -error: aborting due to 12 previous errors +error[E0593]: function is expected to take 0 arguments, but it takes 1 argument + --> $DIR/closure-arg-count.rs:43:5 + | +LL | call(Foo); + | ^^^^ expected function that takes 0 arguments +... +LL | struct Foo(u8); + | --------------- takes 1 argument + | +note: required by `call` + --> $DIR/closure-arg-count.rs:50:1 + | +LL | fn call<F, R>(_: F) where F: FnOnce() -> R {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 13 previous errors For more information about this error, try `rustc --explain E0593`. diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.rs b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.rs index 7b3ed6a94fc..4767b75d89c 100644 --- a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.rs +++ b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.rs @@ -15,7 +15,6 @@ // Iterator>::Item`, to be exact). #![allow(warnings)] -#![feature(dyn_trait)] #![feature(rustc_attrs)] trait Anything { } diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr index 0efbbdff12a..3689ca74adb 100644 --- a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr @@ -1,17 +1,17 @@ warning: not reporting region error due to nll - --> $DIR/projection-no-regions-closure.rs:36:31 + --> $DIR/projection-no-regions-closure.rs:35:31 | LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^ warning: not reporting region error due to nll - --> $DIR/projection-no-regions-closure.rs:54:31 + --> $DIR/projection-no-regions-closure.rs:53:31 | LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^ note: External requirements - --> $DIR/projection-no-regions-closure.rs:36:23 + --> $DIR/projection-no-regions-closure.rs:35:23 | LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -26,7 +26,7 @@ LL | with_signature(x, |mut y| Box::new(y.next())) = note: where <T as std::iter::Iterator>::Item: '_#2r error[E0309]: the associated type `<T as std::iter::Iterator>::Item` may not live long enough - --> $DIR/projection-no-regions-closure.rs:36:23 + --> $DIR/projection-no-regions-closure.rs:35:23 | LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -34,7 +34,7 @@ LL | with_signature(x, |mut y| Box::new(y.next())) = help: consider adding an explicit lifetime bound `<T as std::iter::Iterator>::Item: ReEarlyBound(0, 'a)`... note: No external requirements - --> $DIR/projection-no-regions-closure.rs:32:1 + --> $DIR/projection-no-regions-closure.rs:31:1 | LL | / fn no_region<'a, T>(x: Box<T>) -> Box<dyn Anything + 'a> LL | | where @@ -51,7 +51,7 @@ LL | | } ] note: External requirements - --> $DIR/projection-no-regions-closure.rs:46:23 + --> $DIR/projection-no-regions-closure.rs:45:23 | LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -66,7 +66,7 @@ LL | with_signature(x, |mut y| Box::new(y.next())) = note: where <T as std::iter::Iterator>::Item: '_#2r note: No external requirements - --> $DIR/projection-no-regions-closure.rs:42:1 + --> $DIR/projection-no-regions-closure.rs:41:1 | LL | / fn correct_region<'a, T>(x: Box<T>) -> Box<dyn Anything + 'a> LL | | where @@ -82,7 +82,7 @@ LL | | } ] note: External requirements - --> $DIR/projection-no-regions-closure.rs:54:23 + --> $DIR/projection-no-regions-closure.rs:53:23 | LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -98,7 +98,7 @@ LL | with_signature(x, |mut y| Box::new(y.next())) = note: where <T as std::iter::Iterator>::Item: '_#3r error[E0309]: the associated type `<T as std::iter::Iterator>::Item` may not live long enough - --> $DIR/projection-no-regions-closure.rs:54:23 + --> $DIR/projection-no-regions-closure.rs:53:23 | LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -106,7 +106,7 @@ LL | with_signature(x, |mut y| Box::new(y.next())) = help: consider adding an explicit lifetime bound `<T as std::iter::Iterator>::Item: ReEarlyBound(0, 'a)`... note: No external requirements - --> $DIR/projection-no-regions-closure.rs:50:1 + --> $DIR/projection-no-regions-closure.rs:49:1 | LL | / fn wrong_region<'a, 'b, T>(x: Box<T>) -> Box<dyn Anything + 'a> LL | | where @@ -124,7 +124,7 @@ LL | | } ] note: External requirements - --> $DIR/projection-no-regions-closure.rs:65:23 + --> $DIR/projection-no-regions-closure.rs:64:23 | LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -140,7 +140,7 @@ LL | with_signature(x, |mut y| Box::new(y.next())) = note: where <T as std::iter::Iterator>::Item: '_#3r note: No external requirements - --> $DIR/projection-no-regions-closure.rs:60:1 + --> $DIR/projection-no-regions-closure.rs:59:1 | LL | / fn outlives_region<'a, 'b, T>(x: Box<T>) -> Box<dyn Anything + 'a> LL | | where diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-fn.rs b/src/test/ui/nll/ty-outlives/projection-no-regions-fn.rs index 32b73a51e11..dea2daf7e8e 100644 --- a/src/test/ui/nll/ty-outlives/projection-no-regions-fn.rs +++ b/src/test/ui/nll/ty-outlives/projection-no-regions-fn.rs @@ -11,7 +11,6 @@ // compile-flags:-Zborrowck=mir -Zverbose #![allow(warnings)] -#![feature(dyn_trait)] trait Anything { } diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-fn.stderr b/src/test/ui/nll/ty-outlives/projection-no-regions-fn.stderr index b2c5f28268d..3199ec15133 100644 --- a/src/test/ui/nll/ty-outlives/projection-no-regions-fn.stderr +++ b/src/test/ui/nll/ty-outlives/projection-no-regions-fn.stderr @@ -1,17 +1,17 @@ warning: not reporting region error due to nll - --> $DIR/projection-no-regions-fn.rs:24:5 + --> $DIR/projection-no-regions-fn.rs:23:5 | LL | Box::new(x.next()) | ^^^^^^^^^^^^^^^^^^ warning: not reporting region error due to nll - --> $DIR/projection-no-regions-fn.rs:40:5 + --> $DIR/projection-no-regions-fn.rs:39:5 | LL | Box::new(x.next()) | ^^^^^^^^^^^^^^^^^^ error[E0309]: the associated type `<T as std::iter::Iterator>::Item` may not live long enough - --> $DIR/projection-no-regions-fn.rs:24:5 + --> $DIR/projection-no-regions-fn.rs:23:5 | LL | Box::new(x.next()) | ^^^^^^^^^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | Box::new(x.next()) = help: consider adding an explicit lifetime bound `<T as std::iter::Iterator>::Item: ReEarlyBound(0, 'a)`... error[E0309]: the associated type `<T as std::iter::Iterator>::Item` may not live long enough - --> $DIR/projection-no-regions-fn.rs:40:5 + --> $DIR/projection-no-regions-fn.rs:39:5 | LL | Box::new(x.next()) | ^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs b/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs index cfe2880bfed..77024c4119f 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs +++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs @@ -25,7 +25,6 @@ // compile-flags:-Zborrowck=mir -Zverbose #![allow(warnings)] -#![feature(dyn_trait)] #![feature(rustc_attrs)] use std::cell::Cell; diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr index 0d5a2dc7c55..e1218830dbb 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr @@ -1,23 +1,23 @@ warning: not reporting region error due to nll - --> $DIR/projection-one-region-closure.rs:56:39 + --> $DIR/projection-one-region-closure.rs:55:39 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^ warning: not reporting region error due to nll - --> $DIR/projection-one-region-closure.rs:68:39 + --> $DIR/projection-one-region-closure.rs:67:39 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^ warning: not reporting region error due to nll - --> $DIR/projection-one-region-closure.rs:90:39 + --> $DIR/projection-one-region-closure.rs:89:39 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^ note: External requirements - --> $DIR/projection-one-region-closure.rs:56:29 + --> $DIR/projection-one-region-closure.rs:55:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: where '_#1r: '_#2r error[E0309]: the parameter type `T` may not live long enough - --> $DIR/projection-one-region-closure.rs:56:29 + --> $DIR/projection-one-region-closure.rs:55:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -41,13 +41,13 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))`... error: free region `ReEarlyBound(0, 'b)` does not outlive free region `ReFree(DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))` - --> $DIR/projection-one-region-closure.rs:56:20 + --> $DIR/projection-one-region-closure.rs:55:20 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^ note: No external requirements - --> $DIR/projection-one-region-closure.rs:52:1 + --> $DIR/projection-one-region-closure.rs:51:1 | LL | / fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -64,7 +64,7 @@ LL | | } ] note: External requirements - --> $DIR/projection-one-region-closure.rs:68:29 + --> $DIR/projection-one-region-closure.rs:67:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -81,7 +81,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: where '_#2r: '_#3r error[E0309]: the parameter type `T` may not live long enough - --> $DIR/projection-one-region-closure.rs:68:29 + --> $DIR/projection-one-region-closure.rs:67:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -89,13 +89,13 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`... error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)` - --> $DIR/projection-one-region-closure.rs:68:20 + --> $DIR/projection-one-region-closure.rs:67:20 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^ note: No external requirements - --> $DIR/projection-one-region-closure.rs:63:1 + --> $DIR/projection-one-region-closure.rs:62:1 | LL | / fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -113,7 +113,7 @@ LL | | } ] note: External requirements - --> $DIR/projection-one-region-closure.rs:90:29 + --> $DIR/projection-one-region-closure.rs:89:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -130,7 +130,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: where '_#2r: '_#3r error[E0309]: the parameter type `T` may not live long enough - --> $DIR/projection-one-region-closure.rs:90:29 + --> $DIR/projection-one-region-closure.rs:89:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -138,13 +138,13 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`... error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)` - --> $DIR/projection-one-region-closure.rs:90:20 + --> $DIR/projection-one-region-closure.rs:89:20 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^ note: No external requirements - --> $DIR/projection-one-region-closure.rs:75:1 + --> $DIR/projection-one-region-closure.rs:74:1 | LL | / fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -162,7 +162,7 @@ LL | | } ] note: External requirements - --> $DIR/projection-one-region-closure.rs:103:29 + --> $DIR/projection-one-region-closure.rs:102:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -179,7 +179,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: where '_#2r: '_#3r note: No external requirements - --> $DIR/projection-one-region-closure.rs:97:1 + --> $DIR/projection-one-region-closure.rs:96:1 | LL | / fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T) LL | | where diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs index 16e91f2708f..fb1009c9cc8 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs @@ -17,7 +17,6 @@ // compile-flags:-Zborrowck=mir -Zverbose #![allow(warnings)] -#![feature(dyn_trait)] #![feature(rustc_attrs)] use std::cell::Cell; diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr index d4aca8380b4..76554e29f62 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr @@ -1,23 +1,23 @@ warning: not reporting region error due to nll - --> $DIR/projection-one-region-trait-bound-closure.rs:48:39 + --> $DIR/projection-one-region-trait-bound-closure.rs:47:39 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^ warning: not reporting region error due to nll - --> $DIR/projection-one-region-trait-bound-closure.rs:59:39 + --> $DIR/projection-one-region-trait-bound-closure.rs:58:39 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^ warning: not reporting region error due to nll - --> $DIR/projection-one-region-trait-bound-closure.rs:80:39 + --> $DIR/projection-one-region-trait-bound-closure.rs:79:39 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^ note: External requirements - --> $DIR/projection-one-region-trait-bound-closure.rs:48:29 + --> $DIR/projection-one-region-trait-bound-closure.rs:47:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -32,13 +32,13 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: where '_#1r: '_#2r error: free region `ReEarlyBound(0, 'b)` does not outlive free region `ReFree(DefId(0/0:8 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))` - --> $DIR/projection-one-region-trait-bound-closure.rs:48:20 + --> $DIR/projection-one-region-trait-bound-closure.rs:47:20 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^ note: No external requirements - --> $DIR/projection-one-region-trait-bound-closure.rs:44:1 + --> $DIR/projection-one-region-trait-bound-closure.rs:43:1 | LL | / fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -55,7 +55,7 @@ LL | | } ] note: External requirements - --> $DIR/projection-one-region-trait-bound-closure.rs:59:29 + --> $DIR/projection-one-region-trait-bound-closure.rs:58:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,13 +71,13 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: where '_#2r: '_#3r error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)` - --> $DIR/projection-one-region-trait-bound-closure.rs:59:20 + --> $DIR/projection-one-region-trait-bound-closure.rs:58:20 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^ note: No external requirements - --> $DIR/projection-one-region-trait-bound-closure.rs:54:1 + --> $DIR/projection-one-region-trait-bound-closure.rs:53:1 | LL | / fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -95,7 +95,7 @@ LL | | } ] note: External requirements - --> $DIR/projection-one-region-trait-bound-closure.rs:80:29 + --> $DIR/projection-one-region-trait-bound-closure.rs:79:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -111,13 +111,13 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: where '_#2r: '_#3r error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)` - --> $DIR/projection-one-region-trait-bound-closure.rs:80:20 + --> $DIR/projection-one-region-trait-bound-closure.rs:79:20 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^ note: No external requirements - --> $DIR/projection-one-region-trait-bound-closure.rs:65:1 + --> $DIR/projection-one-region-trait-bound-closure.rs:64:1 | LL | / fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -135,7 +135,7 @@ LL | | } ] note: External requirements - --> $DIR/projection-one-region-trait-bound-closure.rs:91:29 + --> $DIR/projection-one-region-trait-bound-closure.rs:90:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -151,7 +151,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: where '_#2r: '_#3r note: No external requirements - --> $DIR/projection-one-region-trait-bound-closure.rs:86:1 + --> $DIR/projection-one-region-trait-bound-closure.rs:85:1 | LL | / fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -169,7 +169,7 @@ LL | | } ] note: External requirements - --> $DIR/projection-one-region-trait-bound-closure.rs:103:29 + --> $DIR/projection-one-region-trait-bound-closure.rs:102:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -184,7 +184,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: where '_#1r: '_#2r note: No external requirements - --> $DIR/projection-one-region-trait-bound-closure.rs:95:1 + --> $DIR/projection-one-region-trait-bound-closure.rs:94:1 | LL | / fn one_region<'a, T>(cell: Cell<&'a ()>, t: T) LL | | where diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.rs b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.rs index 0d42636c844..1f2f40196f8 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.rs +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.rs @@ -16,7 +16,6 @@ // compile-pass #![allow(warnings)] -#![feature(dyn_trait)] #![feature(rustc_attrs)] use std::cell::Cell; diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr index 875907e6b39..136e143e80e 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr @@ -1,5 +1,5 @@ note: No external requirements - --> $DIR/projection-one-region-trait-bound-static-closure.rs:47:29 + --> $DIR/projection-one-region-trait-bound-static-closure.rs:46:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -12,7 +12,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); ] note: No external requirements - --> $DIR/projection-one-region-trait-bound-static-closure.rs:43:1 + --> $DIR/projection-one-region-trait-bound-static-closure.rs:42:1 | LL | / fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -28,7 +28,7 @@ LL | | } ] note: No external requirements - --> $DIR/projection-one-region-trait-bound-static-closure.rs:56:29 + --> $DIR/projection-one-region-trait-bound-static-closure.rs:55:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -42,7 +42,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); ] note: No external requirements - --> $DIR/projection-one-region-trait-bound-static-closure.rs:51:1 + --> $DIR/projection-one-region-trait-bound-static-closure.rs:50:1 | LL | / fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -60,7 +60,7 @@ LL | | } ] note: No external requirements - --> $DIR/projection-one-region-trait-bound-static-closure.rs:75:29 + --> $DIR/projection-one-region-trait-bound-static-closure.rs:74:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -74,7 +74,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); ] note: No external requirements - --> $DIR/projection-one-region-trait-bound-static-closure.rs:60:1 + --> $DIR/projection-one-region-trait-bound-static-closure.rs:59:1 | LL | / fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -92,7 +92,7 @@ LL | | } ] note: No external requirements - --> $DIR/projection-one-region-trait-bound-static-closure.rs:84:29 + --> $DIR/projection-one-region-trait-bound-static-closure.rs:83:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -106,7 +106,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); ] note: No external requirements - --> $DIR/projection-one-region-trait-bound-static-closure.rs:79:1 + --> $DIR/projection-one-region-trait-bound-static-closure.rs:78:1 | LL | / fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -124,7 +124,7 @@ LL | | } ] note: No external requirements - --> $DIR/projection-one-region-trait-bound-static-closure.rs:96:29 + --> $DIR/projection-one-region-trait-bound-static-closure.rs:95:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -137,7 +137,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); ] note: No external requirements - --> $DIR/projection-one-region-trait-bound-static-closure.rs:88:1 + --> $DIR/projection-one-region-trait-bound-static-closure.rs:87:1 | LL | / fn one_region<'a, T>(cell: Cell<&'a ()>, t: T) LL | | where diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs index 7c8ef140a29..5307d0880d4 100644 --- a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs +++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs @@ -18,7 +18,6 @@ // compile-flags:-Zborrowck=mir -Zverbose #![allow(warnings)] -#![feature(dyn_trait)] #![feature(rustc_attrs)] use std::cell::Cell; diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr index 7e36e467e4e..c7f45692960 100644 --- a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr @@ -1,29 +1,29 @@ warning: not reporting region error due to nll - --> $DIR/projection-two-region-trait-bound-closure.rs:49:39 + --> $DIR/projection-two-region-trait-bound-closure.rs:48:39 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^ warning: not reporting region error due to nll - --> $DIR/projection-two-region-trait-bound-closure.rs:60:39 + --> $DIR/projection-two-region-trait-bound-closure.rs:59:39 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^ warning: not reporting region error due to nll - --> $DIR/projection-two-region-trait-bound-closure.rs:81:39 + --> $DIR/projection-two-region-trait-bound-closure.rs:80:39 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^ warning: not reporting region error due to nll - --> $DIR/projection-two-region-trait-bound-closure.rs:109:39 + --> $DIR/projection-two-region-trait-bound-closure.rs:108:39 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^ note: External requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:49:29 + --> $DIR/projection-two-region-trait-bound-closure.rs:48:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -39,7 +39,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#2r)>>::AssocType: '_#3r error[E0309]: the associated type `<T as Anything<'_#5r, '_#6r>>::AssocType` may not live long enough - --> $DIR/projection-two-region-trait-bound-closure.rs:49:29 + --> $DIR/projection-two-region-trait-bound-closure.rs:48:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -47,7 +47,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = help: consider adding an explicit lifetime bound `<T as Anything<'_#5r, '_#6r>>::AssocType: ReFree(DefId(0/0:8 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:18), 'a))`... note: No external requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:45:1 + --> $DIR/projection-two-region-trait-bound-closure.rs:44:1 | LL | / fn no_relationships_late<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -65,7 +65,7 @@ LL | | } ] note: External requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:60:29 + --> $DIR/projection-two-region-trait-bound-closure.rs:59:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -82,7 +82,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r error[E0309]: the associated type `<T as Anything<'_#6r, '_#7r>>::AssocType` may not live long enough - --> $DIR/projection-two-region-trait-bound-closure.rs:60:29 + --> $DIR/projection-two-region-trait-bound-closure.rs:59:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -90,7 +90,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = help: consider adding an explicit lifetime bound `<T as Anything<'_#6r, '_#7r>>::AssocType: ReEarlyBound(0, 'a)`... note: No external requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:55:1 + --> $DIR/projection-two-region-trait-bound-closure.rs:54:1 | LL | / fn no_relationships_early<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -109,7 +109,7 @@ LL | | } ] note: External requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:81:29 + --> $DIR/projection-two-region-trait-bound-closure.rs:80:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -126,7 +126,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r error[E0309]: the associated type `<T as Anything<'_#6r, '_#7r>>::AssocType` may not live long enough - --> $DIR/projection-two-region-trait-bound-closure.rs:81:29 + --> $DIR/projection-two-region-trait-bound-closure.rs:80:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -134,7 +134,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = help: consider adding an explicit lifetime bound `<T as Anything<'_#6r, '_#7r>>::AssocType: ReEarlyBound(0, 'a)`... note: No external requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:66:1 + --> $DIR/projection-two-region-trait-bound-closure.rs:65:1 | LL | / fn projection_outlives<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -153,7 +153,7 @@ LL | | } ] note: External requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:92:29 + --> $DIR/projection-two-region-trait-bound-closure.rs:91:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -170,7 +170,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r note: No external requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:87:1 + --> $DIR/projection-two-region-trait-bound-closure.rs:86:1 | LL | / fn elements_outlive1<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -189,7 +189,7 @@ LL | | } ] note: External requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:101:29 + --> $DIR/projection-two-region-trait-bound-closure.rs:100:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -206,7 +206,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r note: No external requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:96:1 + --> $DIR/projection-two-region-trait-bound-closure.rs:95:1 | LL | / fn elements_outlive2<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -225,7 +225,7 @@ LL | | } ] note: External requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:109:29 + --> $DIR/projection-two-region-trait-bound-closure.rs:108:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -240,13 +240,13 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#1r)>>::AssocType: '_#2r error: free region `ReEarlyBound(0, 'b)` does not outlive free region `ReFree(DefId(0/0:13 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]), BrNamed(crate0:DefIndex(1:43), 'a))` - --> $DIR/projection-two-region-trait-bound-closure.rs:109:20 + --> $DIR/projection-two-region-trait-bound-closure.rs:108:20 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^ note: No external requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:105:1 + --> $DIR/projection-two-region-trait-bound-closure.rs:104:1 | LL | / fn two_regions<'a, 'b, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -263,7 +263,7 @@ LL | | } ] note: External requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:120:29 + --> $DIR/projection-two-region-trait-bound-closure.rs:119:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -279,7 +279,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#2r)>>::AssocType: '_#3r note: No external requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:115:1 + --> $DIR/projection-two-region-trait-bound-closure.rs:114:1 | LL | / fn two_regions_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -297,7 +297,7 @@ LL | | } ] note: External requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:132:29 + --> $DIR/projection-two-region-trait-bound-closure.rs:131:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -312,7 +312,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#1r)>>::AssocType: '_#2r note: No external requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:124:1 + --> $DIR/projection-two-region-trait-bound-closure.rs:123:1 | LL | / fn one_region<'a, T>(cell: Cell<&'a ()>, t: T) LL | | where diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.rs b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.rs index 80b42c29563..7ff4b484af1 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.rs +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.rs @@ -11,7 +11,6 @@ // compile-flags:-Zborrowck=mir -Zverbose #![allow(warnings)] -#![feature(dyn_trait)] #![feature(rustc_attrs)] use std::cell::Cell; diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr index c8feaddff93..b4f51401a90 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr @@ -1,23 +1,23 @@ warning: not reporting region error due to nll - --> $DIR/ty-param-closure-approximate-lower-bound.rs:35:31 + --> $DIR/ty-param-closure-approximate-lower-bound.rs:34:31 | LL | twice(cell, value, |a, b| invoke(a, b)); | ^^^^^^^^^^^^ warning: not reporting region error due to nll - --> $DIR/ty-param-closure-approximate-lower-bound.rs:43:31 + --> $DIR/ty-param-closure-approximate-lower-bound.rs:42:31 | LL | twice(cell, value, |a, b| invoke(a, b)); | ^^^^^^ warning: not reporting region error due to nll - --> $DIR/ty-param-closure-approximate-lower-bound.rs:43:31 + --> $DIR/ty-param-closure-approximate-lower-bound.rs:42:31 | LL | twice(cell, value, |a, b| invoke(a, b)); | ^^^^^^^^^^^^ note: External requirements - --> $DIR/ty-param-closure-approximate-lower-bound.rs:35:24 + --> $DIR/ty-param-closure-approximate-lower-bound.rs:34:24 | LL | twice(cell, value, |a, b| invoke(a, b)); | ^^^^^^^^^^^^^^^^^^^ @@ -31,7 +31,7 @@ LL | twice(cell, value, |a, b| invoke(a, b)); = note: where T: '_#1r note: No external requirements - --> $DIR/ty-param-closure-approximate-lower-bound.rs:33:1 + --> $DIR/ty-param-closure-approximate-lower-bound.rs:32:1 | LL | / fn generic<T>(value: T) { LL | | let cell = Cell::new(&()); @@ -47,7 +47,7 @@ LL | | } ] note: External requirements - --> $DIR/ty-param-closure-approximate-lower-bound.rs:43:24 + --> $DIR/ty-param-closure-approximate-lower-bound.rs:42:24 | LL | twice(cell, value, |a, b| invoke(a, b)); | ^^^^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL | twice(cell, value, |a, b| invoke(a, b)); = note: where T: '_#1r error[E0309]: the parameter type `T` may not live long enough - --> $DIR/ty-param-closure-approximate-lower-bound.rs:43:24 + --> $DIR/ty-param-closure-approximate-lower-bound.rs:42:24 | LL | twice(cell, value, |a, b| invoke(a, b)); | ^^^^^^^^^^^^^^^^^^^ @@ -69,7 +69,7 @@ LL | twice(cell, value, |a, b| invoke(a, b)); = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:6 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]), BrNamed(crate0:DefIndex(1:15), 'a))`... note: No external requirements - --> $DIR/ty-param-closure-approximate-lower-bound.rs:42:1 + --> $DIR/ty-param-closure-approximate-lower-bound.rs:41:1 | LL | / fn generic_fail<'a, T>(cell: Cell<&'a ()>, value: T) { LL | | twice(cell, value, |a, b| invoke(a, b)); diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.rs b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.rs index 50763a1d508..b5cbd07b99c 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.rs +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.rs @@ -11,7 +11,6 @@ // compile-flags:-Zborrowck=mir -Zverbose #![allow(warnings)] -#![feature(dyn_trait)] #![feature(rustc_attrs)] use std::fmt::Debug; diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr index 500595e0c5d..59a8a39a7b0 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr @@ -1,17 +1,17 @@ warning: not reporting region error due to nll - --> $DIR/ty-param-closure-outlives-from-return-type.rs:37:27 + --> $DIR/ty-param-closure-outlives-from-return-type.rs:36:27 | LL | with_signature(x, |y| y) | ^ warning: not reporting region error due to nll - --> $DIR/ty-param-closure-outlives-from-return-type.rs:53:5 + --> $DIR/ty-param-closure-outlives-from-return-type.rs:52:5 | LL | x | ^ note: External requirements - --> $DIR/ty-param-closure-outlives-from-return-type.rs:37:23 + --> $DIR/ty-param-closure-outlives-from-return-type.rs:36:23 | LL | with_signature(x, |y| y) | ^^^^^ @@ -26,7 +26,7 @@ LL | with_signature(x, |y| y) = note: where T: '_#2r error[E0309]: the parameter type `T` may not live long enough - --> $DIR/ty-param-closure-outlives-from-return-type.rs:37:23 + --> $DIR/ty-param-closure-outlives-from-return-type.rs:36:23 | LL | with_signature(x, |y| y) | ^^^^^ @@ -34,7 +34,7 @@ LL | with_signature(x, |y| y) = help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`... note: No external requirements - --> $DIR/ty-param-closure-outlives-from-return-type.rs:26:1 + --> $DIR/ty-param-closure-outlives-from-return-type.rs:25:1 | LL | / fn no_region<'a, T>(x: Box<T>) -> Box<dyn Debug + 'a> LL | | where @@ -51,7 +51,7 @@ LL | | } ] error[E0309]: the parameter type `T` may not live long enough - --> $DIR/ty-param-closure-outlives-from-return-type.rs:53:5 + --> $DIR/ty-param-closure-outlives-from-return-type.rs:52:5 | LL | x | ^ diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.rs b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.rs index b70fc2b2ec4..edaaeac080d 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.rs +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.rs @@ -15,7 +15,6 @@ // compile-flags:-Zborrowck=mir -Zverbose #![allow(warnings)] -#![feature(dyn_trait)] #![feature(rustc_attrs)] use std::cell::Cell; diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr index 4d8a66ba8e1..a53ce21b7e6 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr @@ -1,17 +1,17 @@ warning: not reporting region error due to nll - --> $DIR/ty-param-closure-outlives-from-where-clause.rs:45:9 + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:44:9 | LL | require(&x, &y) | ^^^^^^^ warning: not reporting region error due to nll - --> $DIR/ty-param-closure-outlives-from-where-clause.rs:79:9 + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:78:9 | LL | require(&x, &y) | ^^^^^^^ note: External requirements - --> $DIR/ty-param-closure-outlives-from-where-clause.rs:38:26 + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:37:26 | LL | with_signature(a, b, |x, y| { | __________________________^ @@ -32,7 +32,7 @@ LL | | }) = note: where T: '_#1r error[E0309]: the parameter type `T` may not live long enough - --> $DIR/ty-param-closure-outlives-from-where-clause.rs:38:26 + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:37:26 | LL | with_signature(a, b, |x, y| { | __________________________^ @@ -47,7 +47,7 @@ LL | | }) = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:6 ~ ty_param_closure_outlives_from_where_clause[317d]::no_region[0]), BrNamed(crate0:DefIndex(1:14), 'a))`... note: No external requirements - --> $DIR/ty-param-closure-outlives-from-where-clause.rs:37:1 + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:36:1 | LL | / fn no_region<'a, T>(a: Cell<&'a ()>, b: T) { LL | | with_signature(a, b, |x, y| { @@ -63,7 +63,7 @@ LL | | } ] note: External requirements - --> $DIR/ty-param-closure-outlives-from-where-clause.rs:55:26 + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:54:26 | LL | with_signature(a, b, |x, y| { | __________________________^ @@ -85,7 +85,7 @@ LL | | }) = note: where T: '_#2r note: No external requirements - --> $DIR/ty-param-closure-outlives-from-where-clause.rs:51:1 + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:50:1 | LL | / fn correct_region<'a, T>(a: Cell<&'a ()>, b: T) LL | | where @@ -102,7 +102,7 @@ LL | | } ] note: External requirements - --> $DIR/ty-param-closure-outlives-from-where-clause.rs:76:26 + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:75:26 | LL | with_signature(a, b, |x, y| { | __________________________^ @@ -123,7 +123,7 @@ LL | | }) = note: where T: '_#2r error[E0309]: the parameter type `T` may not live long enough - --> $DIR/ty-param-closure-outlives-from-where-clause.rs:76:26 + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:75:26 | LL | with_signature(a, b, |x, y| { | __________________________^ @@ -137,7 +137,7 @@ LL | | }) = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:8 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]), BrNamed(crate0:DefIndex(1:20), 'a))`... note: No external requirements - --> $DIR/ty-param-closure-outlives-from-where-clause.rs:72:1 + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:71:1 | LL | / fn wrong_region<'a, 'b, T>(a: Cell<&'a ()>, b: T) LL | | where @@ -154,7 +154,7 @@ LL | | } ] note: External requirements - --> $DIR/ty-param-closure-outlives-from-where-clause.rs:90:26 + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:89:26 | LL | with_signature(a, b, |x, y| { | __________________________^ @@ -174,7 +174,7 @@ LL | | }) = note: where T: '_#3r note: No external requirements - --> $DIR/ty-param-closure-outlives-from-where-clause.rs:85:1 + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:84:1 | LL | / fn outlives_region<'a, 'b, T>(a: Cell<&'a ()>, b: T) LL | | where diff --git a/src/test/ui/nll/ty-outlives/ty-param-fn-body-nll-feature.rs b/src/test/ui/nll/ty-outlives/ty-param-fn-body-nll-feature.rs index babe608354f..c0c483b3957 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-fn-body-nll-feature.rs +++ b/src/test/ui/nll/ty-outlives/ty-param-fn-body-nll-feature.rs @@ -15,7 +15,6 @@ #![feature(nll)] #![allow(warnings)] -#![feature(dyn_trait)] use std::cell::Cell; diff --git a/src/test/ui/nll/ty-outlives/ty-param-fn-body-nll-feature.stderr b/src/test/ui/nll/ty-outlives/ty-param-fn-body-nll-feature.stderr index 1510ca61e5c..dec15f47a03 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-fn-body-nll-feature.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-fn-body-nll-feature.stderr @@ -1,5 +1,5 @@ error[E0309]: the parameter type `T` may not live long enough - --> $DIR/ty-param-fn-body-nll-feature.rs:31:5 + --> $DIR/ty-param-fn-body-nll-feature.rs:30:5 | LL | outlives(cell, t) | ^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/nll/ty-outlives/ty-param-fn-body.rs b/src/test/ui/nll/ty-outlives/ty-param-fn-body.rs index fb4ea63f853..6226108ef19 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-fn-body.rs +++ b/src/test/ui/nll/ty-outlives/ty-param-fn-body.rs @@ -14,7 +14,6 @@ // function body. #![allow(warnings)] -#![feature(dyn_trait)] use std::cell::Cell; diff --git a/src/test/ui/nll/ty-outlives/ty-param-fn-body.stderr b/src/test/ui/nll/ty-outlives/ty-param-fn-body.stderr index 0596861e67b..537f1223470 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-fn-body.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-fn-body.stderr @@ -1,11 +1,11 @@ warning: not reporting region error due to nll - --> $DIR/ty-param-fn-body.rs:30:5 + --> $DIR/ty-param-fn-body.rs:29:5 | LL | outlives(cell, t) | ^^^^^^^^ error[E0309]: the parameter type `T` may not live long enough - --> $DIR/ty-param-fn-body.rs:30:5 + --> $DIR/ty-param-fn-body.rs:29:5 | LL | outlives(cell, t) | ^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/nll/ty-outlives/ty-param-fn.rs b/src/test/ui/nll/ty-outlives/ty-param-fn.rs index 42d662e1419..258d77eb2b0 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-fn.rs +++ b/src/test/ui/nll/ty-outlives/ty-param-fn.rs @@ -11,7 +11,6 @@ // compile-flags:-Zborrowck=mir #![allow(warnings)] -#![feature(dyn_trait)] use std::fmt::Debug; diff --git a/src/test/ui/nll/ty-outlives/ty-param-fn.stderr b/src/test/ui/nll/ty-outlives/ty-param-fn.stderr index 0d09cac8c38..5ce50d81185 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-fn.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-fn.stderr @@ -1,17 +1,17 @@ warning: not reporting region error due to nll - --> $DIR/ty-param-fn.rs:22:5 + --> $DIR/ty-param-fn.rs:21:5 | LL | x | ^ warning: not reporting region error due to nll - --> $DIR/ty-param-fn.rs:38:5 + --> $DIR/ty-param-fn.rs:37:5 | LL | x | ^ error[E0309]: the parameter type `T` may not live long enough - --> $DIR/ty-param-fn.rs:22:5 + --> $DIR/ty-param-fn.rs:21:5 | LL | x | ^ @@ -19,7 +19,7 @@ LL | x = help: consider adding an explicit lifetime bound `T: 'a`... error[E0309]: the parameter type `T` may not live long enough - --> $DIR/ty-param-fn.rs:38:5 + --> $DIR/ty-param-fn.rs:37:5 | LL | x | ^ diff --git a/src/test/ui/on-unimplemented/no-debug.stderr b/src/test/ui/on-unimplemented/no-debug.stderr index 5d8f80e57b0..275cd91a435 100644 --- a/src/test/ui/on-unimplemented/no-debug.stderr +++ b/src/test/ui/on-unimplemented/no-debug.stderr @@ -2,16 +2,17 @@ error[E0277]: `Foo` doesn't implement `std::fmt::Debug` --> $DIR/no-debug.rs:20:27 | LL | println!("{:?} {:?}", Foo, Bar); - | ^^^ `Foo` cannot be formatted using `:?`; add `#[derive(Debug)]` or manually implement `std::fmt::Debug` + | ^^^ `Foo` cannot be formatted using `{:?}` | = help: the trait `std::fmt::Debug` is not implemented for `Foo` + = note: add `#[derive(Debug)]` or manually implement `std::fmt::Debug` = note: required by `std::fmt::Debug::fmt` error[E0277]: `no_debug::Bar` doesn't implement `std::fmt::Debug` --> $DIR/no-debug.rs:20:32 | LL | println!("{:?} {:?}", Foo, Bar); - | ^^^ `no_debug::Bar` cannot be formatted using `:?` because it doesn't implement `std::fmt::Debug` + | ^^^ `no_debug::Bar` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` | = help: the trait `std::fmt::Debug` is not implemented for `no_debug::Bar` = note: required by `std::fmt::Debug::fmt` @@ -20,18 +21,20 @@ error[E0277]: `Foo` doesn't implement `std::fmt::Display` --> $DIR/no-debug.rs:21:23 | LL | println!("{} {}", Foo, Bar); - | ^^^ `Foo` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string + | ^^^ `Foo` cannot be formatted with the default formatter | = help: the trait `std::fmt::Display` is not implemented for `Foo` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead = note: required by `std::fmt::Display::fmt` error[E0277]: `no_debug::Bar` doesn't implement `std::fmt::Display` --> $DIR/no-debug.rs:21:28 | LL | println!("{} {}", Foo, Bar); - | ^^^ `no_debug::Bar` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string + | ^^^ `no_debug::Bar` cannot be formatted with the default formatter | = help: the trait `std::fmt::Display` is not implemented for `no_debug::Bar` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead = note: required by `std::fmt::Display::fmt` error: aborting due to 4 previous errors diff --git a/src/test/ui/print_type_sizes/repr_int_c.rs b/src/test/ui/print_type_sizes/repr_int_c.rs new file mode 100644 index 00000000000..04bb2ab26f3 --- /dev/null +++ b/src/test/ui/print_type_sizes/repr_int_c.rs @@ -0,0 +1,35 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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 print-type-sizes +// compile-pass + +// This test makes sure that the tag is not grown for `repr(C)` or `repr(u8)` +// variants (see https://github.com/rust-lang/rust/issues/50098 for the original bug). + +#![feature(start)] +#![allow(dead_code)] + +#[repr(C, u8)] +enum ReprCu8 { + A(u16), + B, +} + +#[repr(u8)] +enum Repru8 { + A(u16), + B, +} + +#[start] +fn start(_: isize, _: *const *const u8) -> isize { + 0 +} diff --git a/src/test/ui/print_type_sizes/repr_int_c.stdout b/src/test/ui/print_type_sizes/repr_int_c.stdout new file mode 100644 index 00000000000..254b3c7a853 --- /dev/null +++ b/src/test/ui/print_type_sizes/repr_int_c.stdout @@ -0,0 +1,12 @@ +print-type-size type: `ReprCu8`: 4 bytes, alignment: 2 bytes +print-type-size discriminant: 1 bytes +print-type-size variant `A`: 3 bytes +print-type-size padding: 1 bytes +print-type-size field `.0`: 2 bytes, alignment: 2 bytes +print-type-size variant `B`: 1 bytes +print-type-size type: `Repru8`: 4 bytes, alignment: 2 bytes +print-type-size discriminant: 1 bytes +print-type-size variant `A`: 3 bytes +print-type-size padding: 1 bytes +print-type-size field `.0`: 2 bytes, alignment: 2 bytes +print-type-size variant `B`: 0 bytes diff --git a/src/test/ui/raw-literal-keywords.rs b/src/test/ui/raw-literal-keywords.rs index 9b28aa0b151..9bb6653d770 100644 --- a/src/test/ui/raw-literal-keywords.rs +++ b/src/test/ui/raw-literal-keywords.rs @@ -10,7 +10,6 @@ // compile-flags: -Z parse-only -#![feature(dyn_trait)] #![feature(raw_identifiers)] fn test_if() { diff --git a/src/test/ui/raw-literal-keywords.stderr b/src/test/ui/raw-literal-keywords.stderr index 3758568323c..022f80ae8a4 100644 --- a/src/test/ui/raw-literal-keywords.stderr +++ b/src/test/ui/raw-literal-keywords.stderr @@ -1,17 +1,17 @@ error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `true` - --> $DIR/raw-literal-keywords.rs:17:10 + --> $DIR/raw-literal-keywords.rs:16:10 | LL | r#if true { } //~ ERROR found `true` | ^^^^ expected one of 8 possible tokens here error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `Test` - --> $DIR/raw-literal-keywords.rs:21:14 + --> $DIR/raw-literal-keywords.rs:20:14 | LL | r#struct Test; //~ ERROR found `Test` | ^^^^ expected one of 8 possible tokens here error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `Test` - --> $DIR/raw-literal-keywords.rs:25:13 + --> $DIR/raw-literal-keywords.rs:24:13 | LL | r#union Test; //~ ERROR found `Test` | ^^^^ expected one of 8 possible tokens here diff --git a/src/test/run-pass-fulldeps/proc-macro/use-reexport.rs b/src/test/ui/repr-align-assign.rs index 03dfeb1f5c9..c9780dde235 100644 --- a/src/test/run-pass-fulldeps/proc-macro/use-reexport.rs +++ b/src/test/ui/repr-align-assign.rs @@ -1,4 +1,4 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,14 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// aux-build:derive-a.rs -// aux-build:derive-reexport.rs -// ignore-stage1 +#[repr(align=8)] //~ ERROR incorrect `repr(align)` attribute format +struct A(u64); -#[macro_use] -extern crate derive_reexport; - -#[derive(Debug, PartialEq, A, Eq, Copy, Clone)] -struct A; +#[repr(align="8")] //~ ERROR incorrect `repr(align)` attribute format +struct B(u64); fn main() {} diff --git a/src/test/ui/repr-align-assign.stderr b/src/test/ui/repr-align-assign.stderr new file mode 100644 index 00000000000..1fa1263b946 --- /dev/null +++ b/src/test/ui/repr-align-assign.stderr @@ -0,0 +1,15 @@ +error[E0693]: incorrect `repr(align)` attribute format + --> $DIR/repr-align-assign.rs:11:8 + | +LL | #[repr(align=8)] //~ ERROR incorrect `repr(align)` attribute format + | ^^^^^^^ help: use parentheses instead: `align(8)` + +error[E0693]: incorrect `repr(align)` attribute format + --> $DIR/repr-align-assign.rs:14:8 + | +LL | #[repr(align="8")] //~ ERROR incorrect `repr(align)` attribute format + | ^^^^^^^^^ help: use parentheses instead: `align(8)` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0693`. diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.rs b/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.rs new file mode 100644 index 00000000000..1c00edee770 --- /dev/null +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.rs @@ -0,0 +1,20 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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 + +#![feature(termination_trait_test)] + +use std::num::ParseIntError; + +#[test] +fn can_parse_zero_as_f32() -> Result<f32, ParseIntError> { //~ ERROR + "0".parse() +} diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr b/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr new file mode 100644 index 00000000000..8efd8a216f1 --- /dev/null +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr @@ -0,0 +1,14 @@ +error[E0277]: `main` has invalid return type `std::result::Result<f32, std::num::ParseIntError>` + --> $DIR/termination-trait-test-wrong-type.rs:18:1 + | +LL | / fn can_parse_zero_as_f32() -> Result<f32, ParseIntError> { //~ ERROR +LL | | "0".parse() +LL | | } + | |_^ `main` can only return types that implement `std::process::Termination` + | + = help: the trait `std::process::Termination` is not implemented for `std::result::Result<f32, std::num::ParseIntError>` + = note: required by `__test::test::assert_test_result` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/span/gated-features-attr-spans.rs b/src/test/ui/span/gated-features-attr-spans.rs index 83a4c5d5dd2..eff1f98eb71 100644 --- a/src/test/ui/span/gated-features-attr-spans.rs +++ b/src/test/ui/span/gated-features-attr-spans.rs @@ -8,33 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(attr_literals)] - -#[repr(align(16))] -struct Gem { - mohs_hardness: u8, - poofed: bool, - weapon: Weapon, -} - #[repr(simd)] //~ ERROR are experimental struct Weapon { name: String, damage: u32 } -impl Gem { - #[must_use] fn summon_weapon(&self) -> Weapon { self.weapon } - //~^ WARN is experimental -} - -#[must_use] //~ WARN is experimental -fn bubble(gem: Gem) -> Result<Gem, ()> { - if gem.poofed { - Ok(gem) - } else { - Err(()) - } -} - fn main() {} diff --git a/src/test/ui/span/gated-features-attr-spans.stderr b/src/test/ui/span/gated-features-attr-spans.stderr index 179daf83c3c..a99530529fc 100644 --- a/src/test/ui/span/gated-features-attr-spans.stderr +++ b/src/test/ui/span/gated-features-attr-spans.stderr @@ -1,27 +1,11 @@ error[E0658]: SIMD types are experimental and possibly buggy (see issue #27731) - --> $DIR/gated-features-attr-spans.rs:20:1 + --> $DIR/gated-features-attr-spans.rs:11:1 | LL | #[repr(simd)] //~ ERROR are experimental | ^^^^^^^^^^^^^ | = help: add #![feature(repr_simd)] to the crate attributes to enable -warning: `#[must_use]` on methods is experimental (see issue #43302) - --> $DIR/gated-features-attr-spans.rs:27:5 - | -LL | #[must_use] fn summon_weapon(&self) -> Weapon { self.weapon } - | ^^^^^^^^^^^ - | - = help: add #![feature(fn_must_use)] to the crate attributes to enable - -warning: `#[must_use]` on functions is experimental (see issue #43302) - --> $DIR/gated-features-attr-spans.rs:31:1 - | -LL | #[must_use] //~ WARN is experimental - | ^^^^^^^^^^^ - | - = help: add #![feature(fn_must_use)] to the crate attributes to enable - error: aborting due to previous error For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/suggestions/closure-immutable-outer-variable.fixed b/src/test/ui/suggestions/closure-immutable-outer-variable.fixed new file mode 100644 index 00000000000..b3a0d592f76 --- /dev/null +++ b/src/test/ui/suggestions/closure-immutable-outer-variable.fixed @@ -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. + +// run-rustfix + +// Point at the captured immutable outer variable + +fn foo(mut f: Box<FnMut()>) { + f(); +} + +fn main() { + let mut y = true; + foo(Box::new(move || y = false) as Box<_>); //~ ERROR cannot assign to captured outer variable +} diff --git a/src/test/compile-fail/macro-no-implicit-reexport.rs b/src/test/ui/suggestions/closure-immutable-outer-variable.nll.fixed index 07467e06eb2..e162678460c 100644 --- a/src/test/compile-fail/macro-no-implicit-reexport.rs +++ b/src/test/ui/suggestions/closure-immutable-outer-variable.nll.fixed @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,13 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// aux-build:macro_reexport_1.rs -// aux-build:macro_non_reexport_2.rs +// run-rustfix -#[macro_use] #[no_link] -extern crate macro_non_reexport_2; +// Point at the captured immutable outer variable + +fn foo(mut f: Box<FnMut()>) { + f(); +} fn main() { - assert_eq!(reexported!(), 3); - //~^ ERROR cannot find macro `reexported!` in this scope + let y = true; + foo(Box::new(move || y = false) as Box<_>); //~ ERROR cannot assign to captured outer variable } diff --git a/src/test/ui/suggestions/closure-immutable-outer-variable.nll.stderr b/src/test/ui/suggestions/closure-immutable-outer-variable.nll.stderr index e4e93ecac8e..bc655114c2b 100644 --- a/src/test/ui/suggestions/closure-immutable-outer-variable.nll.stderr +++ b/src/test/ui/suggestions/closure-immutable-outer-variable.nll.stderr @@ -1,5 +1,5 @@ error[E0594]: cannot assign to immutable item `y` - --> $DIR/closure-immutable-outer-variable.rs:19:26 + --> $DIR/closure-immutable-outer-variable.rs:21:26 | LL | foo(Box::new(move || y = false) as Box<_>); //~ ERROR cannot assign to captured outer variable | ^^^^^^^^^ cannot mutate diff --git a/src/test/ui/suggestions/closure-immutable-outer-variable.rs b/src/test/ui/suggestions/closure-immutable-outer-variable.rs index 1d14afd6a01..e162678460c 100644 --- a/src/test/ui/suggestions/closure-immutable-outer-variable.rs +++ b/src/test/ui/suggestions/closure-immutable-outer-variable.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// run-rustfix + // Point at the captured immutable outer variable fn foo(mut f: Box<FnMut()>) { diff --git a/src/test/ui/suggestions/closure-immutable-outer-variable.rs.fixed b/src/test/ui/suggestions/closure-immutable-outer-variable.rs.fixed new file mode 100644 index 00000000000..80a5a45a305 --- /dev/null +++ b/src/test/ui/suggestions/closure-immutable-outer-variable.rs.fixed @@ -0,0 +1,20 @@ +// 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. + +// Point at the captured immutable outer variable + +fn foo(mut f: Box<FnMut()>) { + f(); +} + +fn main() { + let mut y = true; + foo(Box::new(move || y = false) as Box<_>); //~ ERROR cannot assign to captured outer variable +} diff --git a/src/test/ui/suggestions/closure-immutable-outer-variable.stderr b/src/test/ui/suggestions/closure-immutable-outer-variable.stderr index 3353e2c7291..0ee11d8cf15 100644 --- a/src/test/ui/suggestions/closure-immutable-outer-variable.stderr +++ b/src/test/ui/suggestions/closure-immutable-outer-variable.stderr @@ -1,5 +1,5 @@ error[E0594]: cannot assign to captured outer variable in an `FnMut` closure - --> $DIR/closure-immutable-outer-variable.rs:19:26 + --> $DIR/closure-immutable-outer-variable.rs:21:26 | LL | let y = true; | - help: consider making `y` mutable: `mut y` diff --git a/src/test/ui/suggestions/issue-45562.fixed b/src/test/ui/suggestions/issue-45562.fixed new file mode 100644 index 00000000000..7c01f0d1ee5 --- /dev/null +++ b/src/test/ui/suggestions/issue-45562.fixed @@ -0,0 +1,16 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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. + +// run-rustfix + +#[no_mangle] pub static RAH: usize = 5; +//~^ ERROR const items should never be #[no_mangle] + +fn main() {} diff --git a/src/test/ui/suggestions/issue-45562.rs b/src/test/ui/suggestions/issue-45562.rs index f493df56f94..c27d52fcdd3 100644 --- a/src/test/ui/suggestions/issue-45562.rs +++ b/src/test/ui/suggestions/issue-45562.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// run-rustfix + #[no_mangle] pub const RAH: usize = 5; //~^ ERROR const items should never be #[no_mangle] diff --git a/src/test/ui/suggestions/issue-45562.stderr b/src/test/ui/suggestions/issue-45562.stderr index d6960dca054..d9e624cadc7 100644 --- a/src/test/ui/suggestions/issue-45562.stderr +++ b/src/test/ui/suggestions/issue-45562.stderr @@ -1,5 +1,5 @@ error: const items should never be #[no_mangle] - --> $DIR/issue-45562.rs:11:14 + --> $DIR/issue-45562.rs:13:14 | LL | #[no_mangle] pub const RAH: usize = 5; | ---------^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/suggestions/issue-45799-bad-extern-crate-rename-suggestion-formatting.fixed b/src/test/ui/suggestions/issue-45799-bad-extern-crate-rename-suggestion-formatting.fixed new file mode 100644 index 00000000000..e3287030408 --- /dev/null +++ b/src/test/ui/suggestions/issue-45799-bad-extern-crate-rename-suggestion-formatting.fixed @@ -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. + +// run-rustfix + +extern crate std as other_std; +fn main() {} +//~^^ ERROR the name `std` is defined multiple times [E0259] diff --git a/src/test/ui/suggestions/issue-45799-bad-extern-crate-rename-suggestion-formatting.rs b/src/test/ui/suggestions/issue-45799-bad-extern-crate-rename-suggestion-formatting.rs index 4d75127b645..f47ea474d51 100644 --- a/src/test/ui/suggestions/issue-45799-bad-extern-crate-rename-suggestion-formatting.rs +++ b/src/test/ui/suggestions/issue-45799-bad-extern-crate-rename-suggestion-formatting.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// run-rustfix + extern crate std; fn main() {} //~^^ ERROR the name `std` is defined multiple times [E0259] diff --git a/src/test/ui/suggestions/issue-45799-bad-extern-crate-rename-suggestion-formatting.stderr b/src/test/ui/suggestions/issue-45799-bad-extern-crate-rename-suggestion-formatting.stderr index 8e2b2d845e9..ecdfec2b3bf 100644 --- a/src/test/ui/suggestions/issue-45799-bad-extern-crate-rename-suggestion-formatting.stderr +++ b/src/test/ui/suggestions/issue-45799-bad-extern-crate-rename-suggestion-formatting.stderr @@ -1,5 +1,5 @@ error[E0259]: the name `std` is defined multiple times - --> $DIR/issue-45799-bad-extern-crate-rename-suggestion-formatting.rs:11:1 + --> $DIR/issue-45799-bad-extern-crate-rename-suggestion-formatting.rs:13:1 | LL | extern crate std; | ^^^^^^^^^^^^^^^^^ `std` reimported here diff --git a/src/test/ui/suggestions/issue-46756-consider-borrowing-cast-or-binexpr.fixed b/src/test/ui/suggestions/issue-46756-consider-borrowing-cast-or-binexpr.fixed new file mode 100644 index 00000000000..77171cad6e7 --- /dev/null +++ b/src/test/ui/suggestions/issue-46756-consider-borrowing-cast-or-binexpr.fixed @@ -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. + +// run-rustfix + +#![allow(unused)] + +fn light_flows_our_war_of_mocking_words(and_yet: &usize) -> usize { + and_yet + 1 +} + +fn main() { + let behold: isize = 2; + let with_tears: usize = 3; + light_flows_our_war_of_mocking_words(&(behold as usize)); + //~^ ERROR mismatched types [E0308] + light_flows_our_war_of_mocking_words(&(with_tears + 4)); + //~^ ERROR mismatched types [E0308] +} diff --git a/src/test/ui/suggestions/issue-46756-consider-borrowing-cast-or-binexpr.rs b/src/test/ui/suggestions/issue-46756-consider-borrowing-cast-or-binexpr.rs index 5617c46afa9..e5ea9b5ed09 100644 --- a/src/test/ui/suggestions/issue-46756-consider-borrowing-cast-or-binexpr.rs +++ b/src/test/ui/suggestions/issue-46756-consider-borrowing-cast-or-binexpr.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// run-rustfix + #![allow(unused)] fn light_flows_our_war_of_mocking_words(and_yet: &usize) -> usize { diff --git a/src/test/ui/suggestions/issue-46756-consider-borrowing-cast-or-binexpr.stderr b/src/test/ui/suggestions/issue-46756-consider-borrowing-cast-or-binexpr.stderr index e89e9dce94d..9c492751ca1 100644 --- a/src/test/ui/suggestions/issue-46756-consider-borrowing-cast-or-binexpr.stderr +++ b/src/test/ui/suggestions/issue-46756-consider-borrowing-cast-or-binexpr.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-46756-consider-borrowing-cast-or-binexpr.rs:20:42 + --> $DIR/issue-46756-consider-borrowing-cast-or-binexpr.rs:22:42 | LL | light_flows_our_war_of_mocking_words(behold as usize); | ^^^^^^^^^^^^^^^ @@ -11,7 +11,7 @@ LL | light_flows_our_war_of_mocking_words(behold as usize); found type `usize` error[E0308]: mismatched types - --> $DIR/issue-46756-consider-borrowing-cast-or-binexpr.rs:22:42 + --> $DIR/issue-46756-consider-borrowing-cast-or-binexpr.rs:24:42 | LL | light_flows_our_war_of_mocking_words(with_tears + 4); | ^^^^^^^^^^^^^^ diff --git a/src/test/ui/suggestions/missing-comma-in-match.fixed b/src/test/ui/suggestions/missing-comma-in-match.fixed new file mode 100644 index 00000000000..4832f35f42d --- /dev/null +++ b/src/test/ui/suggestions/missing-comma-in-match.fixed @@ -0,0 +1,21 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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. + +// run-rustfix + +fn main() { + match &Some(3) { + &None => 1, + &Some(2) => { 3 } + //~^ ERROR expected one of `,`, `.`, `?`, `}`, or an operator, found `=>` + //~| NOTE expected one of `,`, `.`, `?`, `}`, or an operator here + _ => 2 + }; +} diff --git a/src/test/ui/suggestions/missing-comma-in-match.rs b/src/test/ui/suggestions/missing-comma-in-match.rs index 6f86cdea3cf..e39b20e77ea 100644 --- a/src/test/ui/suggestions/missing-comma-in-match.rs +++ b/src/test/ui/suggestions/missing-comma-in-match.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// run-rustfix + fn main() { match &Some(3) { &None => 1 diff --git a/src/test/ui/suggestions/missing-comma-in-match.stderr b/src/test/ui/suggestions/missing-comma-in-match.stderr index b71a50b6631..77935934107 100644 --- a/src/test/ui/suggestions/missing-comma-in-match.stderr +++ b/src/test/ui/suggestions/missing-comma-in-match.stderr @@ -1,5 +1,5 @@ error: expected one of `,`, `.`, `?`, `}`, or an operator, found `=>` - --> $DIR/missing-comma-in-match.rs:14:18 + --> $DIR/missing-comma-in-match.rs:16:18 | LL | &None => 1 | - help: missing a comma here to end this `match` arm diff --git a/src/test/ui/suggestions/str-as-char.fixed b/src/test/ui/suggestions/str-as-char.fixed new file mode 100644 index 00000000000..c0dad38e436 --- /dev/null +++ b/src/test/ui/suggestions/str-as-char.fixed @@ -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. + +// run-rustfix + +fn main() { + println!("●●"); + //~^ ERROR character literal may only contain one codepoint +} diff --git a/src/test/ui/suggestions/str-as-char.rs b/src/test/ui/suggestions/str-as-char.rs index 09aca61147d..b5a5df0af7f 100644 --- a/src/test/ui/suggestions/str-as-char.rs +++ b/src/test/ui/suggestions/str-as-char.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// run-rustfix + fn main() { println!('●●'); //~^ ERROR character literal may only contain one codepoint diff --git a/src/test/ui/suggestions/str-as-char.stderr b/src/test/ui/suggestions/str-as-char.stderr index d881becf00c..60eb182adf1 100644 --- a/src/test/ui/suggestions/str-as-char.stderr +++ b/src/test/ui/suggestions/str-as-char.stderr @@ -1,5 +1,5 @@ error: character literal may only contain one codepoint - --> $DIR/str-as-char.rs:12:14 + --> $DIR/str-as-char.rs:14:14 | LL | println!('●●'); | ^^^^ diff --git a/src/test/ui/suggestions/tuple-float-index.fixed b/src/test/ui/suggestions/tuple-float-index.fixed new file mode 100644 index 00000000000..55bc2f77dad --- /dev/null +++ b/src/test/ui/suggestions/tuple-float-index.fixed @@ -0,0 +1,16 @@ +// 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. + +// run-rustfix +// compile-flags: -Z parse-only + +fn main () { + ((1, (2, 3)).1).1; //~ ERROR unexpected token: `1.1` +} diff --git a/src/test/ui/suggestions/tuple-float-index.rs b/src/test/ui/suggestions/tuple-float-index.rs index 0a188305a92..d569ca4cb86 100644 --- a/src/test/ui/suggestions/tuple-float-index.rs +++ b/src/test/ui/suggestions/tuple-float-index.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// run-rustfix // compile-flags: -Z parse-only fn main () { diff --git a/src/test/ui/suggestions/tuple-float-index.stderr b/src/test/ui/suggestions/tuple-float-index.stderr index 4a1e34890f4..15af0834f03 100644 --- a/src/test/ui/suggestions/tuple-float-index.stderr +++ b/src/test/ui/suggestions/tuple-float-index.stderr @@ -1,5 +1,5 @@ error: unexpected token: `1.1` - --> $DIR/tuple-float-index.rs:14:17 + --> $DIR/tuple-float-index.rs:15:17 | LL | (1, (2, 3)).1.1; //~ ERROR unexpected token: `1.1` | ------------^^^ diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.rs b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.rs index e573ad8fc1f..6c83205d050 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.rs +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.rs @@ -13,8 +13,6 @@ // // cc #48468 -#![feature(dyn_trait)] - use std::fmt::Debug; struct Foo { diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr index 6d777841f03..1017217828a 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr @@ -1,11 +1,11 @@ error[E0106]: missing lifetime specifier - --> $DIR/dyn-trait-underscore-in-struct.rs:21:24 + --> $DIR/dyn-trait-underscore-in-struct.rs:19:24 | LL | x: Box<dyn Debug + '_>, //~ ERROR missing lifetime specifier | ^^ expected lifetime parameter error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound - --> $DIR/dyn-trait-underscore-in-struct.rs:21:12 + --> $DIR/dyn-trait-underscore-in-struct.rs:19:12 | LL | x: Box<dyn Debug + '_>, //~ ERROR missing lifetime specifier | ^^^^^^^^^^^^^^ diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr index 10a03786d7b..cdc0c78e694 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr @@ -1,29 +1,29 @@ warning: not reporting region error due to nll - --> $DIR/dyn-trait-underscore.rs:20:14 + --> $DIR/dyn-trait-underscore.rs:18:14 | LL | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime | ^^^^^ warning: not reporting region error due to nll - --> $DIR/dyn-trait-underscore.rs:20:20 + --> $DIR/dyn-trait-underscore.rs:18:20 | LL | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime | ^^^^ warning: not reporting region error due to nll - --> $DIR/dyn-trait-underscore.rs:20:5 + --> $DIR/dyn-trait-underscore.rs:18:5 | LL | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime | ^^^^^^^^ warning: not reporting region error due to nll - --> $DIR/dyn-trait-underscore.rs:20:5 + --> $DIR/dyn-trait-underscore.rs:18:5 | LL | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime | ^^^^^^^^^^^^^^^^^^^^^^ error: free region `` does not outlive free region `'static` - --> $DIR/dyn-trait-underscore.rs:18:52 + --> $DIR/dyn-trait-underscore.rs:16:52 | LL | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> { | ____________________________________________________^ diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.rs b/src/test/ui/underscore-lifetime/dyn-trait-underscore.rs index 9640d346597..247492fb7b7 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.rs +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.rs @@ -13,8 +13,6 @@ // // cc #48468 -#![feature(dyn_trait)] - fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> { // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static` Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr index f1e59aed54a..98249d3f2b5 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr @@ -1,11 +1,11 @@ error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements - --> $DIR/dyn-trait-underscore.rs:20:20 + --> $DIR/dyn-trait-underscore.rs:18:20 | LL | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime | ^^^^ | -note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the function body at 18:1... - --> $DIR/dyn-trait-underscore.rs:18:1 +note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the function body at 16:1... + --> $DIR/dyn-trait-underscore.rs:16:1 | LL | / fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> { LL | | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static` @@ -13,7 +13,7 @@ LL | | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime LL | | } | |_^ note: ...so that reference does not outlive borrowed content - --> $DIR/dyn-trait-underscore.rs:20:14 + --> $DIR/dyn-trait-underscore.rs:18:14 | LL | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime | ^^^^^ diff --git a/src/test/ui/update-references.sh b/src/test/ui/update-references.sh index 4fc11daaa3a..47a85352b00 100755 --- a/src/test/ui/update-references.sh +++ b/src/test/ui/update-references.sh @@ -26,7 +26,6 @@ if [[ "$1" == "--help" || "$1" == "-h" || "$1" == "" || "$2" == "" ]]; then echo " $0 ../../../build/x86_64-apple-darwin/test/ui *.rs */*.rs" fi -MYDIR=$(dirname $0) BUILD_DIR="$1" shift @@ -34,7 +33,8 @@ shift shopt -s nullglob while [[ "$1" != "" ]]; do - for EXT in "stderr" "stdout"; do + MYDIR=$(dirname $1) + for EXT in "stderr" "stdout" "fixed"; do for OUT_NAME in $BUILD_DIR/${1%.rs}.*$EXT; do OUT_BASE=`basename "$OUT_NAME"` if ! (diff $OUT_NAME $MYDIR/$OUT_BASE >& /dev/null); then diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 9f238929215..6b548742fb3 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -57,6 +57,7 @@ static TARGETS: &'static [&'static str] = &[ "arm-unknown-linux-musleabi", "arm-unknown-linux-musleabihf", "armv5te-unknown-linux-gnueabi", + "armv5te-unknown-linux-musleabi", "armv7-apple-ios", "armv7-linux-androideabi", "armv7-unknown-cloudabi-eabihf", diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 0a1add2d8689ad12a86f6c32d0a5cd0393dc5d8 +Subproject af3f1cd29bc872b932a13083e531255aab233a7 diff --git a/src/tools/clippy b/src/tools/clippy -Subproject c5b39a5917ffc0f1349b6e414fa3b874fdcf842 +Subproject 1742229ebb7843a65c05ee495d8de5366fcc556 diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 7d02f0b746d..45cb147fbbc 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -13,10 +13,12 @@ regex = "0.2" serde = "1.0" serde_json = "1.0" serde_derive = "1.0" +rustfix = "0.2" [target.'cfg(unix)'.dependencies] libc = "0.2" [target.'cfg(windows)'.dependencies] +lazy_static = "1.0" miow = "0.3" winapi = { version = "0.3", features = ["winerror"] } diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 365b47447f2..2df52816599 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -74,30 +74,30 @@ impl FromStr for Mode { impl fmt::Display for Mode { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(match *self { - CompileFail => "compile-fail", - ParseFail => "parse-fail", - RunFail => "run-fail", - RunPass => "run-pass", - RunPassValgrind => "run-pass-valgrind", - Pretty => "pretty", - DebugInfoGdb => "debuginfo-gdb", - DebugInfoLldb => "debuginfo-lldb", - Codegen => "codegen", - Rustdoc => "rustdoc", - CodegenUnits => "codegen-units", - Incremental => "incremental", - RunMake => "run-make", - Ui => "ui", - MirOpt => "mir-opt", - }, - f) + let s = match *self { + CompileFail => "compile-fail", + ParseFail => "parse-fail", + RunFail => "run-fail", + RunPass => "run-pass", + RunPassValgrind => "run-pass-valgrind", + Pretty => "pretty", + DebugInfoGdb => "debuginfo-gdb", + DebugInfoLldb => "debuginfo-lldb", + Codegen => "codegen", + Rustdoc => "rustdoc", + CodegenUnits => "codegen-units", + Incremental => "incremental", + RunMake => "run-make", + Ui => "ui", + MirOpt => "mir-opt", + }; + fmt::Display::fmt(s, f) } } -#[derive(Clone)] +#[derive(Clone, PartialEq)] pub enum CompareMode { - Nll + Nll, } impl CompareMode { @@ -269,6 +269,7 @@ pub fn expected_output_path(testpaths: &TestPaths, testpaths.file.with_extension(extension) } -pub const UI_EXTENSIONS: &[&str] = &[UI_STDERR, UI_STDOUT]; +pub const UI_EXTENSIONS: &[&str] = &[UI_STDERR, UI_STDOUT, UI_FIXED]; pub const UI_STDERR: &str = "stderr"; pub const UI_STDOUT: &str = "stdout"; +pub const UI_FIXED: &str = "fixed"; diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 73dd079cf0c..7ac3f5b5b25 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -236,6 +236,7 @@ pub struct TestProps { pub normalize_stdout: Vec<(String, String)>, pub normalize_stderr: Vec<(String, String)>, pub failure_status: i32, + pub run_rustfix: bool, } impl TestProps { @@ -267,6 +268,7 @@ impl TestProps { normalize_stdout: vec![], normalize_stderr: vec![], failure_status: 101, + run_rustfix: false, } } @@ -403,6 +405,10 @@ impl TestProps { if let Some(code) = config.parse_failure_status(ln) { self.failure_status = code; } + + if !self.run_rustfix { + self.run_rustfix = config.parse_run_rustfix(ln); + } }); for key in &["RUST_TEST_NOCAPTURE", "RUST_TEST_THREADS"] { @@ -642,6 +648,10 @@ impl Config { None } + + fn parse_run_rustfix(&self, line: &str) -> bool { + self.parse_name_directive(line, "run-rustfix") + } } pub fn lldb_version_to_int(version_string: &str) -> isize { diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 37f7af0abe8..e2b446c99dc 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -23,9 +23,13 @@ extern crate libc; extern crate log; extern crate regex; #[macro_use] +#[cfg(windows)] +extern crate lazy_static; +#[macro_use] extern crate serde_derive; extern crate serde_json; extern crate test; +extern crate rustfix; use std::env; use std::ffi::OsString; diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 85434bb8a69..1bac9ef66bb 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -12,7 +12,7 @@ use common::{Config, TestPaths}; use common::{CompileFail, ParseFail, Pretty, RunFail, RunPass, RunPassValgrind}; use common::{Codegen, CodegenUnits, DebugInfoGdb, DebugInfoLldb, Rustdoc}; use common::{Incremental, MirOpt, RunMake, Ui}; -use common::{expected_output_path, UI_STDERR, UI_STDOUT}; +use common::{expected_output_path, UI_STDERR, UI_STDOUT, UI_FIXED}; use common::CompareMode; use diff; use errors::{self, Error, ErrorKind}; @@ -21,6 +21,7 @@ use json; use header::TestProps; use util::logv; use regex::Regex; +use rustfix::{apply_suggestions, get_suggestions_from_json}; use std::collections::VecDeque; use std::collections::HashMap; @@ -37,6 +38,39 @@ use std::str; use extract_gdb_version; +#[cfg(windows)] +fn disable_error_reporting<F: FnOnce() -> R, R>(f: F) -> R { + use std::sync::Mutex; + const SEM_NOGPFAULTERRORBOX: u32 = 0x0002; + extern "system" { + fn SetErrorMode(mode: u32) -> u32; + } + + lazy_static! { + static ref LOCK: Mutex<()> = { + Mutex::new(()) + }; + } + // Error mode is a global variable, so lock it so only one thread will change it + let _lock = LOCK.lock().unwrap(); + + // Tell Windows to not show any UI on errors (such as terminating abnormally). + // This is important for running tests, since some of them use abnormal + // termination by design. This mode is inherited by all child processes. + unsafe { + let old_mode = SetErrorMode(SEM_NOGPFAULTERRORBOX); // read inherited flags + SetErrorMode(old_mode | SEM_NOGPFAULTERRORBOX); + let r = f(); + SetErrorMode(old_mode); + r + } +} + +#[cfg(not(windows))] +fn disable_error_reporting<F: FnOnce() -> R, R>(f: F) -> R { + f() +} + /// The name of the environment variable that holds dynamic library locations. pub fn dylib_env_var() -> &'static str { if cfg!(windows) { @@ -1168,6 +1202,8 @@ impl<'test> TestCx<'test> { for line in proc_res.stderr.lines() { if line.contains("error: internal compiler error") { self.fatal_proc_rec("compiler encountered internal error", proc_res); + } else if line.contains(" panicked at ") { + self.fatal_proc_rec("compiler panicked", proc_res); } } } @@ -1575,8 +1611,7 @@ impl<'test> TestCx<'test> { let newpath = env::join_paths(&path).unwrap(); command.env(dylib_env_var(), newpath); - let mut child = command - .spawn() + let mut child = disable_error_reporting(|| command.spawn()) .expect(&format!("failed to exec `{:?}`", &command)); if let Some(input) = input { child @@ -2550,6 +2585,7 @@ impl<'test> TestCx<'test> { let expected_stderr = self.load_expected_output(UI_STDERR); let expected_stdout = self.load_expected_output(UI_STDOUT); + let expected_fixed = self.load_expected_output(UI_FIXED); let normalized_stdout = self.normalize_output(&proc_res.stdout, &self.props.normalize_stdout); @@ -2566,6 +2602,21 @@ impl<'test> TestCx<'test> { errors += self.compare_output("stdout", &normalized_stdout, &expected_stdout); errors += self.compare_output("stderr", &normalized_stderr, &expected_stderr); + if self.config.compare_mode.is_some() { + // don't test rustfix with nll right now + } else if self.props.run_rustfix { + // Apply suggestions from rustc to the code itself + let unfixed_code = self.load_expected_output_from_path(&self.testpaths.file) + .unwrap(); + let suggestions = get_suggestions_from_json(&proc_res.stderr, &HashSet::new()).unwrap(); + let fixed_code = apply_suggestions(&unfixed_code, &suggestions); + + errors += self.compare_output("fixed", &fixed_code, &expected_fixed); + } else if !expected_fixed.is_empty() { + panic!("the `// run-rustfix` directive wasn't found but a `*.fixed` \ + file was found"); + } + if errors > 0 { println!("To update references, run this command from build directory:"); let relative_path_to_file = self.testpaths @@ -2601,6 +2652,23 @@ impl<'test> TestCx<'test> { self.check_error_patterns(&proc_res.stderr, &proc_res); } } + + if self.props.run_rustfix && self.config.compare_mode.is_none() { + // And finally, compile the fixed code and make sure it both + // succeeds and has no diagnostics. + let mut rustc = self.make_compile_args( + &self.testpaths.file.with_extension(UI_FIXED), + TargetLocation::ThisFile(self.make_exe_name()), + ); + rustc.arg("-L").arg(&self.aux_output_dir_name()); + let res = self.compose_and_run_compiler(rustc, None); + if !res.status.success() { + self.fatal_proc_rec("failed to compile fixed code", &res); + } + if !res.stderr.is_empty() { + self.fatal_proc_rec("fixed code is still producing diagnostics", &res); + } + } } fn run_mir_opt_test(&self) { @@ -2733,10 +2801,12 @@ impl<'test> TestCx<'test> { panic!( "Did not find expected line, error: {}\n\ Expected Line: {:?}\n\ + Test Name: {}\n\ Expected:\n{}\n\ Actual:\n{}", extra_msg, expected_line, + test_name, expected_content, normalize_all ); diff --git a/src/tools/rls b/src/tools/rls -Subproject 9144e223a5b90e078366275ff3dcdd406e62eae +Subproject d2f44357fef6d61f316abc403e0a5d917f2771c diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js index 6992f2ba123..1c79443dedf 100644 --- a/src/tools/rustdoc-js/tester.js +++ b/src/tools/rustdoc-js/tester.js @@ -87,6 +87,7 @@ function loadContent(content) { var Module = module.constructor; var m = new Module(); m._compile(content, "tmp.js"); + m.exports.ignore_order = content.indexOf("\n// ignore-order\n") !== -1; return m.exports; } @@ -130,10 +131,10 @@ function lookForEntry(entry, data) { } } if (allGood === true) { - return true; + return i; } } - return false; + return null; } function main(argv) { @@ -177,6 +178,7 @@ function main(argv) { 'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;'); const expected = loadedFile.EXPECTED; const query = loadedFile.QUERY; + const ignore_order = loadedFile.ignore_order; var results = loaded.execSearch(loaded.getQuery(query), index); process.stdout.write('Checking "' + file + '" ... '); var error_text = []; @@ -189,13 +191,17 @@ function main(argv) { break; } var entry = expected[key]; - var found = false; + var prev_pos = 0; for (var i = 0; i < entry.length; ++i) { - if (lookForEntry(entry[i], results[key]) === true) { - found = true; - } else { + var entry_pos = lookForEntry(entry[i], results[key]); + if (entry_pos === null) { error_text.push("==> Result not found in '" + key + "': '" + JSON.stringify(entry[i]) + "'"); + } else if (entry_pos < prev_pos && ignore_order === false) { + error_text.push("==> '" + JSON.stringify(entry[i]) + "' was supposed to be " + + " before '" + JSON.stringify(results[key][entry_pos]) + "'"); + } else { + prev_pos = entry_pos; } } } diff --git a/src/tools/rustfmt b/src/tools/rustfmt -Subproject ac8ae0062544743aaea1719a34f299b66f2b7dc +Subproject b6cd17f28ae314f2484ff05d3ce57652d51c5e8 diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 8caf39fc27b..9a87fcb00d5 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -73,6 +73,7 @@ static WHITELIST: &'static [Crate] = &[ Crate("flate2"), Crate("fuchsia-zircon"), Crate("fuchsia-zircon-sys"), + Crate("getopts"), Crate("humantime"), Crate("jobserver"), Crate("kernel32-sys"), diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index fa227436640..022ef57503a 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -51,6 +51,7 @@ pub mod pal; pub mod deps; pub mod ui_tests; pub mod unstable_book; +pub mod libcoretest; fn filter_dirs(path: &Path) -> bool { let skip = [ diff --git a/src/tools/tidy/src/libcoretest.rs b/src/tools/tidy/src/libcoretest.rs new file mode 100644 index 00000000000..ef8b55186b1 --- /dev/null +++ b/src/tools/tidy/src/libcoretest.rs @@ -0,0 +1,34 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// 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. + +//! Tidy check to ensure `#[test]` is not used directly inside `libcore`. +//! +//! `#![no_core]` libraries cannot be tested directly due to duplicating lang +//! item. All tests must be written externally in `libcore/tests`. + +use std::path::Path; +use std::fs::read_to_string; + +pub fn check(path: &Path, bad: &mut bool) { + let libcore_path = path.join("libcore"); + super::walk( + &libcore_path, + &mut |subpath| t!(subpath.strip_prefix(&libcore_path)).starts_with("tests"), + &mut |subpath| { + if t!(read_to_string(subpath)).contains("#[test]") { + tidy_error!( + bad, + "{} contains #[test]; libcore tests must be placed inside `src/libcore/tests/`", + subpath.display() + ); + } + }, + ); +} diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 24974192795..7b86650823a 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -41,6 +41,7 @@ fn main() { features::check(&path, &mut bad, quiet); pal::check(&path, &mut bad); unstable_book::check(&path, &mut bad); + libcoretest::check(&path, &mut bad); if !args.iter().any(|s| *s == "--no-vendor") { deps::check(&path, &mut bad); } |
