From bee92b5327c437a4fbc471ee15627850264d5428 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 12 Apr 2019 22:03:41 +0300 Subject: [PATCH 01/33] Make deprecation lint `ambiguous_associated_items` deny-by-default --- src/librustc/lint/builtin.rs | 2 +- src/test/ui/type-alias-enum-variants-priority.rs | 1 - src/test/ui/type-alias-enum-variants-priority.stderr | 12 ++++-------- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index cbdeda7b90206..79c11c444da57 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -382,7 +382,7 @@ declare_lint! { declare_lint! { pub AMBIGUOUS_ASSOCIATED_ITEMS, - Warn, + Deny, "ambiguous associated items" } diff --git a/src/test/ui/type-alias-enum-variants-priority.rs b/src/test/ui/type-alias-enum-variants-priority.rs index db1da2b12e256..82cd21b09d3e7 100644 --- a/src/test/ui/type-alias-enum-variants-priority.rs +++ b/src/test/ui/type-alias-enum-variants-priority.rs @@ -1,5 +1,4 @@ #![feature(type_alias_enum_variants)] -#![deny(ambiguous_associated_items)] enum E { V diff --git a/src/test/ui/type-alias-enum-variants-priority.stderr b/src/test/ui/type-alias-enum-variants-priority.stderr index dcf7dc77ed5ea..b8271807b835d 100644 --- a/src/test/ui/type-alias-enum-variants-priority.stderr +++ b/src/test/ui/type-alias-enum-variants-priority.stderr @@ -1,23 +1,19 @@ error: ambiguous associated item - --> $DIR/type-alias-enum-variants-priority.rs:15:15 + --> $DIR/type-alias-enum-variants-priority.rs:14:15 | LL | fn f() -> Self::V { 0 } | ^^^^^^^ help: use fully-qualified syntax: `::V` | -note: lint level defined here - --> $DIR/type-alias-enum-variants-priority.rs:2:9 - | -LL | #![deny(ambiguous_associated_items)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: #[deny(ambiguous_associated_items)] 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 #57644 note: `V` could refer to variant defined here - --> $DIR/type-alias-enum-variants-priority.rs:5:5 + --> $DIR/type-alias-enum-variants-priority.rs:4:5 | LL | V | ^ note: `V` could also refer to associated type defined here - --> $DIR/type-alias-enum-variants-priority.rs:9:5 + --> $DIR/type-alias-enum-variants-priority.rs:8:5 | LL | type V; | ^^^^^^^ From be337381393c733bbd8f1469fecfdfc85d5f3bd7 Mon Sep 17 00:00:00 2001 From: Gilad Naaman Date: Sat, 20 Apr 2019 18:24:29 +0300 Subject: [PATCH 02/33] Added arm-none-eabi target --- src/ci/docker/dist-various-1/Dockerfile | 2 ++ src/librustc_target/spec/arm_none_eabi.rs | 34 +++++++++++++++++++++++ src/librustc_target/spec/mod.rs | 1 + src/tools/build-manifest/src/main.rs | 1 + 4 files changed, 38 insertions(+) create mode 100644 src/librustc_target/spec/arm_none_eabi.rs diff --git a/src/ci/docker/dist-various-1/Dockerfile b/src/ci/docker/dist-various-1/Dockerfile index a722a4183912e..f5ce2b1fbd49d 100644 --- a/src/ci/docker/dist-various-1/Dockerfile +++ b/src/ci/docker/dist-various-1/Dockerfile @@ -120,6 +120,7 @@ ENV TARGETS=$TARGETS,armebv7r-none-eabi ENV TARGETS=$TARGETS,armebv7r-none-eabihf ENV TARGETS=$TARGETS,armv7r-none-eabi ENV TARGETS=$TARGETS,armv7r-none-eabihf +ENV TARGETS=$TARGETS,arm-none-eabi ENV TARGETS=$TARGETS,thumbv7neon-unknown-linux-gnueabihf ENV CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \ @@ -127,6 +128,7 @@ 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_armebv7r_none_eabi=arm-none-eabi-gcc \ + CC_arm_none_eabi=arm-none-eabi-gcc \ CC_thumbv7neon_unknown_linux_gnueabihf=arm-linux-gnueabihf-gcc \ AR_thumbv7neon_unknown_linux_gnueabihf=arm-linux-gnueabihf-ar \ CXX_thumbv7neon_unknown_linux_gnueabihf=arm-linux-gnueabihf-g++ diff --git a/src/librustc_target/spec/arm_none_eabi.rs b/src/librustc_target/spec/arm_none_eabi.rs new file mode 100644 index 0000000000000..e505f37017308 --- /dev/null +++ b/src/librustc_target/spec/arm_none_eabi.rs @@ -0,0 +1,34 @@ +// Generic arm target for bare-metal code +// +// Can be used in conjunction with the `target-feature` and +// `target-cpu` compiler flags to opt-in more hardware-specific +// features. +// +// For example, `-C target-cpu=cortex-a7`. + +use super::{LinkerFlavor, Target, TargetOptions, PanicStrategy}; + +pub fn target() -> Result { + Ok(Target { + llvm_target: "arm-none-eabi".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: "none".to_string(), + target_env: String::new(), + target_vendor: String::new(), + linker_flavor: LinkerFlavor::Gcc, + + options: TargetOptions { + features: "+strict-align,+v6".to_string(), + executables: true, + relocation_model: "static".to_string(), + max_atomic_width: Some(64), + panic_strategy: PanicStrategy::Abort, + abi_blacklist: super::arm_base::abi_blacklist(), + .. Default::default() + }, + }) +} diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index 46fefd78f4519..ff318e7fb0254 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -351,6 +351,7 @@ supported_targets! { ("s390x-unknown-linux-gnu", s390x_unknown_linux_gnu), ("sparc-unknown-linux-gnu", sparc_unknown_linux_gnu), ("sparc64-unknown-linux-gnu", sparc64_unknown_linux_gnu), + ("arm-none-eabi", arm_none_eabi), ("arm-unknown-linux-gnueabi", arm_unknown_linux_gnueabi), ("arm-unknown-linux-gnueabihf", arm_unknown_linux_gnueabihf), ("arm-unknown-linux-musleabi", arm_unknown_linux_musleabi), diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 61cc78ad807af..31d3a058bfe5b 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -49,6 +49,7 @@ static TARGETS: &[&str] = &[ "aarch64-unknown-linux-gnu", "aarch64-unknown-linux-musl", "arm-linux-androideabi", + "arm-none-eabi", "arm-unknown-linux-gnueabi", "arm-unknown-linux-gnueabihf", "arm-unknown-linux-musleabi", From d8cc8dcbcfc7826d7d9e2ccb426d9d447268aa19 Mon Sep 17 00:00:00 2001 From: Gilad Naaman Date: Tue, 23 Apr 2019 11:20:04 +0300 Subject: [PATCH 03/33] Added armv7-none target instead of arm-none --- src/ci/docker/dist-various-1/Dockerfile | 4 ++-- .../spec/{arm_none_eabi.rs => armv7_none_eabihf.rs} | 11 ++++++----- src/librustc_target/spec/mod.rs | 2 +- src/tools/build-manifest/src/main.rs | 2 +- 4 files changed, 10 insertions(+), 9 deletions(-) rename src/librustc_target/spec/{arm_none_eabi.rs => armv7_none_eabihf.rs} (72%) diff --git a/src/ci/docker/dist-various-1/Dockerfile b/src/ci/docker/dist-various-1/Dockerfile index f5ce2b1fbd49d..4623c5847cc11 100644 --- a/src/ci/docker/dist-various-1/Dockerfile +++ b/src/ci/docker/dist-various-1/Dockerfile @@ -120,7 +120,7 @@ ENV TARGETS=$TARGETS,armebv7r-none-eabi ENV TARGETS=$TARGETS,armebv7r-none-eabihf ENV TARGETS=$TARGETS,armv7r-none-eabi ENV TARGETS=$TARGETS,armv7r-none-eabihf -ENV TARGETS=$TARGETS,arm-none-eabi +ENV TARGETS=$TARGETS,armv7-none-eabihf ENV TARGETS=$TARGETS,thumbv7neon-unknown-linux-gnueabihf ENV CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \ @@ -128,7 +128,7 @@ 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_armebv7r_none_eabi=arm-none-eabi-gcc \ - CC_arm_none_eabi=arm-none-eabi-gcc \ + CC_armv7_none_eabihf=arm-none-eabi-gcc \ CC_thumbv7neon_unknown_linux_gnueabihf=arm-linux-gnueabihf-gcc \ AR_thumbv7neon_unknown_linux_gnueabihf=arm-linux-gnueabihf-ar \ CXX_thumbv7neon_unknown_linux_gnueabihf=arm-linux-gnueabihf-g++ diff --git a/src/librustc_target/spec/arm_none_eabi.rs b/src/librustc_target/spec/armv7_none_eabihf.rs similarity index 72% rename from src/librustc_target/spec/arm_none_eabi.rs rename to src/librustc_target/spec/armv7_none_eabihf.rs index e505f37017308..61b47dfdbb9dd 100644 --- a/src/librustc_target/spec/arm_none_eabi.rs +++ b/src/librustc_target/spec/armv7_none_eabihf.rs @@ -6,11 +6,11 @@ // // For example, `-C target-cpu=cortex-a7`. -use super::{LinkerFlavor, Target, TargetOptions, PanicStrategy}; +use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions, TargetResult}; -pub fn target() -> Result { +pub fn target() -> TargetResult { Ok(Target { - llvm_target: "arm-none-eabi".to_string(), + llvm_target: "armv7-none-eabihf".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), target_c_int_width: "32".to_string(), @@ -19,10 +19,11 @@ pub fn target() -> Result { target_os: "none".to_string(), target_env: String::new(), target_vendor: String::new(), - linker_flavor: LinkerFlavor::Gcc, + linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), options: TargetOptions { - features: "+strict-align,+v6".to_string(), + features: "+v7,+vfp3,+d16,+thumb2,-neon".to_string(), + linker: Some("rust-lld".to_owned()), executables: true, relocation_model: "static".to_string(), max_atomic_width: Some(64), diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index ff318e7fb0254..f4d5bfd274304 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -351,7 +351,7 @@ supported_targets! { ("s390x-unknown-linux-gnu", s390x_unknown_linux_gnu), ("sparc-unknown-linux-gnu", sparc_unknown_linux_gnu), ("sparc64-unknown-linux-gnu", sparc64_unknown_linux_gnu), - ("arm-none-eabi", arm_none_eabi), + ("armv7-none-eabihf", armv7_none_eabihf), ("arm-unknown-linux-gnueabi", arm_unknown_linux_gnueabi), ("arm-unknown-linux-gnueabihf", arm_unknown_linux_gnueabihf), ("arm-unknown-linux-musleabi", arm_unknown_linux_musleabi), diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 31d3a058bfe5b..2d9ec6eb442c3 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -49,7 +49,6 @@ static TARGETS: &[&str] = &[ "aarch64-unknown-linux-gnu", "aarch64-unknown-linux-musl", "arm-linux-androideabi", - "arm-none-eabi", "arm-unknown-linux-gnueabi", "arm-unknown-linux-gnueabihf", "arm-unknown-linux-musleabi", @@ -67,6 +66,7 @@ static TARGETS: &[&str] = &[ "armv7r-none-eabi", "armv7r-none-eabihf", "armv7s-apple-ios", + "armv7-none-eabihf", "asmjs-unknown-emscripten", "i386-apple-ios", "i586-pc-windows-msvc", From bd42e124688b952ce9e47de53731313ae0d04ff4 Mon Sep 17 00:00:00 2001 From: Gilad Naaman Date: Tue, 23 Apr 2019 14:39:26 +0300 Subject: [PATCH 04/33] Set armv7-none to use strict alignment --- src/librustc_target/spec/armv7_none_eabihf.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_target/spec/armv7_none_eabihf.rs b/src/librustc_target/spec/armv7_none_eabihf.rs index 61b47dfdbb9dd..708f888933e3a 100644 --- a/src/librustc_target/spec/armv7_none_eabihf.rs +++ b/src/librustc_target/spec/armv7_none_eabihf.rs @@ -22,7 +22,7 @@ pub fn target() -> TargetResult { linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), options: TargetOptions { - features: "+v7,+vfp3,+d16,+thumb2,-neon".to_string(), + features: "+strict-align,+v7,+vfp3,+d16,+thumb2,-neon".to_string(), linker: Some("rust-lld".to_owned()), executables: true, relocation_model: "static".to_string(), From a912664113394fdf3a7c26a93504ebfe54a66e5c Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Tue, 23 Apr 2019 17:39:26 -0400 Subject: [PATCH 05/33] report fatal errors during doctest parsing --- src/librustdoc/test.rs | 23 ++++++++++++++---- .../rustdoc-ui/failed-doctest-output.stdout | 4 ++-- src/test/rustdoc-ui/unparseable-doc-test.rs | 10 ++++++++ .../rustdoc-ui/unparseable-doc-test.stdout | 24 +++++++++++++++++++ 4 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 src/test/rustdoc-ui/unparseable-doc-test.rs create mode 100644 src/test/rustdoc-ui/unparseable-doc-test.stdout diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index abf74158c938e..8064c3ebb8a52 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -166,9 +166,18 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize, compile_fail: bool, mut error_codes: Vec, opts: &TestOptions, maybe_sysroot: Option, linker: Option, edition: Edition, persist_doctests: Option) { - // The test harness wants its own `main` and top-level functions, so - // never wrap the test in `fn main() { ... }`. - let (test, line_offset) = make_test(test, Some(cratename), as_test_harness, opts); + let (test, line_offset) = match panic::catch_unwind(|| { + make_test(test, Some(cratename), as_test_harness, opts) + }) { + Ok((test, line_offset)) => (test, line_offset), + Err(cause) if cause.is::() => { + // If the parser used by `make_test` panicked due to a fatal error, pass the test code + // through unchanged. The error will be reported during compilation. + (test.to_owned(), 0) + }, + Err(cause) => panic::resume_unwind(cause), + }; + // FIXME(#44940): if doctests ever support path remapping, then this filename // needs to be the result of `SourceMap::span_to_unmapped_path`. let path = match filename { @@ -337,7 +346,13 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize, } } -/// Makes the test file. Also returns the number of lines before the code begins +/// Transforms a test into code that can be compiled into a Rust binary, and returns the number of +/// lines before the test code begins. +/// +/// # Panics +/// +/// This function uses the compiler's parser internally. The parser will panic if it encounters a +/// fatal error while parsing the test. pub fn make_test(s: &str, cratename: Option<&str>, dont_insert_main: bool, diff --git a/src/test/rustdoc-ui/failed-doctest-output.stdout b/src/test/rustdoc-ui/failed-doctest-output.stdout index c9f59405ce012..7b1cd70273140 100644 --- a/src/test/rustdoc-ui/failed-doctest-output.stdout +++ b/src/test/rustdoc-ui/failed-doctest-output.stdout @@ -15,7 +15,7 @@ error[E0425]: cannot find value `no` in this scope error: aborting due to previous error For more information about this error, try `rustc --explain E0425`. -thread '$DIR/failed-doctest-output.rs - OtherStruct (line 17)' panicked at 'couldn't compile the test', src/librustdoc/test.rs:310:13 +thread '$DIR/failed-doctest-output.rs - OtherStruct (line 17)' panicked at 'couldn't compile the test', src/librustdoc/test.rs:319:13 note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace. ---- $DIR/failed-doctest-output.rs - SomeStruct (line 11) stdout ---- @@ -24,7 +24,7 @@ thread '$DIR/failed-doctest-output.rs - SomeStruct (line 11)' panicked at 'test thread 'main' panicked at 'oh no', $DIR/failed-doctest-output.rs:3:1 note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace. -', src/librustdoc/test.rs:332:17 +', src/librustdoc/test.rs:341:17 failures: diff --git a/src/test/rustdoc-ui/unparseable-doc-test.rs b/src/test/rustdoc-ui/unparseable-doc-test.rs new file mode 100644 index 0000000000000..18d6b32bf4037 --- /dev/null +++ b/src/test/rustdoc-ui/unparseable-doc-test.rs @@ -0,0 +1,10 @@ +// compile-flags: --test +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// failure-status: 101 +// rustc-env: RUST_BACKTRACE=0 + +/// ```rust +/// let x = 7; +/// "unterminated +/// ``` +pub fn foo() {} diff --git a/src/test/rustdoc-ui/unparseable-doc-test.stdout b/src/test/rustdoc-ui/unparseable-doc-test.stdout new file mode 100644 index 0000000000000..7048ef2c58977 --- /dev/null +++ b/src/test/rustdoc-ui/unparseable-doc-test.stdout @@ -0,0 +1,24 @@ + +running 1 test +test $DIR/unparseable-doc-test.rs - foo (line 6) ... FAILED + +failures: + +---- $DIR/unparseable-doc-test.rs - foo (line 6) stdout ---- +error: unterminated double quote string + --> $DIR/unparseable-doc-test.rs:8:1 + | +2 | "unterminated + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + +thread '$DIR/unparseable-doc-test.rs - foo (line 6)' panicked at 'couldn't compile the test', src/librustdoc/test.rs:319:13 +note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace. + + +failures: + $DIR/unparseable-doc-test.rs - foo (line 6) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out + From c8baec9cd08a984c8d5438d6dc6017cded9e5369 Mon Sep 17 00:00:00 2001 From: Gilad Naaman Date: Wed, 24 Apr 2019 08:59:27 +0300 Subject: [PATCH 06/33] Added non hf armv7a target --- src/ci/docker/dist-various-1/Dockerfile | 6 ++-- src/librustc_target/spec/armv7a_none_eabi.rs | 35 +++++++++++++++++++ ...7_none_eabihf.rs => armv7a_none_eabihf.rs} | 4 +-- src/librustc_target/spec/mod.rs | 3 +- src/tools/build-manifest/src/main.rs | 3 +- 5 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 src/librustc_target/spec/armv7a_none_eabi.rs rename src/librustc_target/spec/{armv7_none_eabihf.rs => armv7a_none_eabihf.rs} (90%) diff --git a/src/ci/docker/dist-various-1/Dockerfile b/src/ci/docker/dist-various-1/Dockerfile index 4623c5847cc11..0c8d08ffa1d7a 100644 --- a/src/ci/docker/dist-various-1/Dockerfile +++ b/src/ci/docker/dist-various-1/Dockerfile @@ -120,7 +120,8 @@ ENV TARGETS=$TARGETS,armebv7r-none-eabi ENV TARGETS=$TARGETS,armebv7r-none-eabihf ENV TARGETS=$TARGETS,armv7r-none-eabi ENV TARGETS=$TARGETS,armv7r-none-eabihf -ENV TARGETS=$TARGETS,armv7-none-eabihf +ENV TARGETS=$TARGETS,armv7a-none-eabi +ENV TARGETS=$TARGETS,armv7a-none-eabihf ENV TARGETS=$TARGETS,thumbv7neon-unknown-linux-gnueabihf ENV CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \ @@ -128,7 +129,8 @@ 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_armebv7r_none_eabi=arm-none-eabi-gcc \ - CC_armv7_none_eabihf=arm-none-eabi-gcc \ + CC_armv7a_none_eabi=arm-none-eabi-gcc \ + CC_armv7a_none_eabihf=arm-none-eabi-gcc \ CC_thumbv7neon_unknown_linux_gnueabihf=arm-linux-gnueabihf-gcc \ AR_thumbv7neon_unknown_linux_gnueabihf=arm-linux-gnueabihf-ar \ CXX_thumbv7neon_unknown_linux_gnueabihf=arm-linux-gnueabihf-g++ diff --git a/src/librustc_target/spec/armv7a_none_eabi.rs b/src/librustc_target/spec/armv7a_none_eabi.rs new file mode 100644 index 0000000000000..78eedb88bfd06 --- /dev/null +++ b/src/librustc_target/spec/armv7a_none_eabi.rs @@ -0,0 +1,35 @@ +// Generic ARM-v7 Cortex-A target, with software floating-point emulation. +// +// Can be used in conjunction with the `target-feature` and +// `target-cpu` compiler flags to opt-in more hardware-specific +// features. +// +// For example, `-C target-cpu=cortex-a7`. + +use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions, TargetResult}; + +pub fn target() -> TargetResult { + Ok(Target { + llvm_target: "armv7a-none-eabi".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: "none".to_string(), + target_env: String::new(), + target_vendor: String::new(), + linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), + + options: TargetOptions { + features: "+strict-align,+v7,+thumb2,-neon".to_string(), + linker: Some("rust-lld".to_owned()), + executables: true, + relocation_model: "static".to_string(), + max_atomic_width: Some(64), + panic_strategy: PanicStrategy::Abort, + abi_blacklist: super::arm_base::abi_blacklist(), + .. Default::default() + }, + }) +} diff --git a/src/librustc_target/spec/armv7_none_eabihf.rs b/src/librustc_target/spec/armv7a_none_eabihf.rs similarity index 90% rename from src/librustc_target/spec/armv7_none_eabihf.rs rename to src/librustc_target/spec/armv7a_none_eabihf.rs index 708f888933e3a..dc42080e85b35 100644 --- a/src/librustc_target/spec/armv7_none_eabihf.rs +++ b/src/librustc_target/spec/armv7a_none_eabihf.rs @@ -1,4 +1,4 @@ -// Generic arm target for bare-metal code +// Generic ARM-v7 Cortex-A target, with hardware floating-point. // // Can be used in conjunction with the `target-feature` and // `target-cpu` compiler flags to opt-in more hardware-specific @@ -10,7 +10,7 @@ use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions, pub fn target() -> TargetResult { Ok(Target { - llvm_target: "armv7-none-eabihf".to_string(), + llvm_target: "armv7a-none-eabihf".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), target_c_int_width: "32".to_string(), diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index f4d5bfd274304..70c77e7e6c347 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -351,7 +351,8 @@ supported_targets! { ("s390x-unknown-linux-gnu", s390x_unknown_linux_gnu), ("sparc-unknown-linux-gnu", sparc_unknown_linux_gnu), ("sparc64-unknown-linux-gnu", sparc64_unknown_linux_gnu), - ("armv7-none-eabihf", armv7_none_eabihf), + ("armv7a-none-eabi", armv7a_none_eabi), + ("armv7a-none-eabihf", armv7a_none_eabihf), ("arm-unknown-linux-gnueabi", arm_unknown_linux_gnueabi), ("arm-unknown-linux-gnueabihf", arm_unknown_linux_gnueabihf), ("arm-unknown-linux-musleabi", arm_unknown_linux_musleabi), diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 2d9ec6eb442c3..e9da8940573de 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -66,7 +66,8 @@ static TARGETS: &[&str] = &[ "armv7r-none-eabi", "armv7r-none-eabihf", "armv7s-apple-ios", - "armv7-none-eabihf", + "armv7a-none-eabi", + "armv7a-none-eabihf", "asmjs-unknown-emscripten", "i386-apple-ios", "i586-pc-windows-msvc", From 0e7e9382fa1a6e50c976cd74ca420d7cb10591fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 29 Apr 2019 18:12:57 -0700 Subject: [PATCH 07/33] Do not suggest incorrect syntax on pattern borrow error --- src/librustc_typeck/check/_match.rs | 25 ++++++++++++++----- src/test/ui/destructure-trait-ref.stderr | 2 -- .../ui/mismatched_types/issue-38371.stderr | 1 - 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index f3cabced34dfc..715b82183a761 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -378,12 +378,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // `fn foo(foo: &u32)` if let Some(mut err) = err { if let PatKind::Binding(..) = inner.node { - if let Ok(snippet) = tcx.sess.source_map() - .span_to_snippet(pat.span) - { - err.help(&format!("did you mean `{}: &{}`?", - &snippet[1..], - expected)); + let parent_id = tcx.hir().get_parent_node_by_hir_id(pat.hir_id); + let parent = tcx.hir().get_by_hir_id(parent_id); + match parent { + hir::Node::Item(_) | + hir::Node::ForeignItem(_) | + hir::Node::TraitItem(_) | + hir::Node::ImplItem(_) => { // this pat is an argument + if let Ok(snippet) = tcx.sess.source_map() + .span_to_snippet(pat.span) + { // FIXME: turn into structured suggestion, will need + // a span that also includes the the type. + err.help(&format!( + "did you mean `{}: &{}`?", + &snippet[1..], + expected, + )); + } + } + _ => {} // don't provide the suggestion from above #55175 } } err.emit(); diff --git a/src/test/ui/destructure-trait-ref.stderr b/src/test/ui/destructure-trait-ref.stderr index 34dd213e2b390..7f389299afba8 100644 --- a/src/test/ui/destructure-trait-ref.stderr +++ b/src/test/ui/destructure-trait-ref.stderr @@ -24,7 +24,6 @@ LL | let &&x = &1isize as &T; | = note: expected type `dyn T` found type `&_` - = help: did you mean `x: &dyn T`? error[E0308]: mismatched types --> $DIR/destructure-trait-ref.rs:36:11 @@ -34,7 +33,6 @@ LL | let &&&x = &(&1isize as &T); | = note: expected type `dyn T` found type `&_` - = help: did you mean `x: &dyn T`? error[E0308]: mismatched types --> $DIR/destructure-trait-ref.rs:41:13 diff --git a/src/test/ui/mismatched_types/issue-38371.stderr b/src/test/ui/mismatched_types/issue-38371.stderr index 236f742db3f71..30da48ba4a8ad 100644 --- a/src/test/ui/mismatched_types/issue-38371.stderr +++ b/src/test/ui/mismatched_types/issue-38371.stderr @@ -16,7 +16,6 @@ LL | fn agh(&&bar: &u32) { | = note: expected type `u32` found type `&_` - = help: did you mean `bar: &u32`? error[E0308]: mismatched types --> $DIR/issue-38371.rs:21:8 From 742b48dc39768fbafd5a072b4ee1dbcd207d12f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 29 Apr 2019 19:02:54 -0700 Subject: [PATCH 08/33] Be more specific in the suggestion filtering --- src/librustc_typeck/check/_match.rs | 52 ++++++++++++++++--- src/test/ui/destructure-trait-ref.stderr | 10 +++- .../ui/mismatched_types/issue-38371.stderr | 5 +- 3 files changed, 56 insertions(+), 11 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 715b82183a761..53d1ac7b02496 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -380,23 +380,59 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let PatKind::Binding(..) = inner.node { let parent_id = tcx.hir().get_parent_node_by_hir_id(pat.hir_id); let parent = tcx.hir().get_by_hir_id(parent_id); + debug!("inner {:?} pat {:?} parent {:?}", inner, pat, parent); match parent { - hir::Node::Item(_) | - hir::Node::ForeignItem(_) | - hir::Node::TraitItem(_) | - hir::Node::ImplItem(_) => { // this pat is an argument + hir::Node::Item(hir::Item { + node: hir::ItemKind::Fn(..), .. + }) | + hir::Node::ForeignItem(hir::ForeignItem { + node: hir::ForeignItemKind::Fn(..), .. + }) | + hir::Node::TraitItem(hir::TraitItem { + node: hir::TraitItemKind::Method(..), .. + }) | + hir::Node::ImplItem(hir::ImplItem { + node: hir::ImplItemKind::Method(..), .. + }) => { // this pat is likely an argument if let Ok(snippet) = tcx.sess.source_map() - .span_to_snippet(pat.span) + .span_to_snippet(inner.span) { // FIXME: turn into structured suggestion, will need - // a span that also includes the the type. + // a span that also includes the the arg's type. err.help(&format!( "did you mean `{}: &{}`?", - &snippet[1..], + snippet, expected, )); } } - _ => {} // don't provide the suggestion from above #55175 + hir::Node::Expr(hir::Expr { + node: hir::ExprKind::Match(..), .. + }) => { // rely on match ergonomics + if let Ok(snippet) = tcx.sess.source_map() + .span_to_snippet(inner.span) + { + err.span_suggestion( + pat.span, + "you can rely on match ergonomics and remove \ + the explicit borrow", + snippet, + Applicability::MaybeIncorrect, + ); + } + } + hir::Node::Pat(_) => { // nested `&&pat` + if let Ok(snippet) = tcx.sess.source_map() + .span_to_snippet(inner.span) + { + err.span_suggestion( + pat.span, + "you can probaly remove the explicit borrow", + snippet, + Applicability::MaybeIncorrect, + ); + } + } + _ => {} // don't provide suggestions in other cases #55175 } } err.emit(); diff --git a/src/test/ui/destructure-trait-ref.stderr b/src/test/ui/destructure-trait-ref.stderr index 7f389299afba8..47ecadfd01afb 100644 --- a/src/test/ui/destructure-trait-ref.stderr +++ b/src/test/ui/destructure-trait-ref.stderr @@ -20,7 +20,10 @@ error[E0308]: mismatched types --> $DIR/destructure-trait-ref.rs:31:10 | LL | let &&x = &1isize as &T; - | ^^ expected trait T, found reference + | ^^ + | | + | expected trait T, found reference + | help: you can probaly remove the explicit borrow: `x` | = note: expected type `dyn T` found type `&_` @@ -29,7 +32,10 @@ error[E0308]: mismatched types --> $DIR/destructure-trait-ref.rs:36:11 | LL | let &&&x = &(&1isize as &T); - | ^^ expected trait T, found reference + | ^^ + | | + | expected trait T, found reference + | help: you can probaly remove the explicit borrow: `x` | = note: expected type `dyn T` found type `&_` diff --git a/src/test/ui/mismatched_types/issue-38371.stderr b/src/test/ui/mismatched_types/issue-38371.stderr index 30da48ba4a8ad..833b8998c338a 100644 --- a/src/test/ui/mismatched_types/issue-38371.stderr +++ b/src/test/ui/mismatched_types/issue-38371.stderr @@ -12,7 +12,10 @@ error[E0308]: mismatched types --> $DIR/issue-38371.rs:18:9 | LL | fn agh(&&bar: &u32) { - | ^^^^ expected u32, found reference + | ^^^^ + | | + | expected u32, found reference + | help: you can probaly remove the explicit borrow: `bar` | = note: expected type `u32` found type `&_` From ff6867338792042b13d401d7c2c3f0aee8d04e62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 29 Apr 2019 19:16:35 -0700 Subject: [PATCH 09/33] add tests --- src/test/ui/suggestions/match-ergonomics.rs | 40 ++++++++++++++++++ .../ui/suggestions/match-ergonomics.stderr | 41 +++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 src/test/ui/suggestions/match-ergonomics.rs create mode 100644 src/test/ui/suggestions/match-ergonomics.stderr diff --git a/src/test/ui/suggestions/match-ergonomics.rs b/src/test/ui/suggestions/match-ergonomics.rs new file mode 100644 index 0000000000000..d75f8363cd221 --- /dev/null +++ b/src/test/ui/suggestions/match-ergonomics.rs @@ -0,0 +1,40 @@ +fn main() { + let x = vec![1i32]; + match &x[..] { + [&v] => {}, //~ ERROR mismatched types + _ => {}, + } + match x { + [&v] => {}, //~ ERROR expected an array or slice + _ => {}, + } + match &x[..] { + [v] => {}, + _ => {}, + } + match &x[..] { + &[v] => {}, + _ => {}, + } + match x { + [v] => {}, //~ ERROR expected an array or slice + _ => {}, + } + let y = 1i32; + match &y { + &v => {}, + _ => {}, + } + match y { + &v => {}, //~ ERROR mismatched types + _ => {}, + } + match &y { + v => {}, + _ => {}, + } + match y { + v => {}, + _ => {}, + } +} diff --git a/src/test/ui/suggestions/match-ergonomics.stderr b/src/test/ui/suggestions/match-ergonomics.stderr new file mode 100644 index 0000000000000..4239089b7cec7 --- /dev/null +++ b/src/test/ui/suggestions/match-ergonomics.stderr @@ -0,0 +1,41 @@ +error[E0308]: mismatched types + --> $DIR/match-ergonomics.rs:4:10 + | +LL | [&v] => {}, + | ^^ + | | + | expected i32, found reference + | help: you can probaly remove the explicit borrow: `v` + | + = note: expected type `i32` + found type `&_` + +error[E0529]: expected an array or slice, found `std::vec::Vec` + --> $DIR/match-ergonomics.rs:8:9 + | +LL | [&v] => {}, + | ^^^^ pattern cannot match with input type `std::vec::Vec` + +error[E0529]: expected an array or slice, found `std::vec::Vec` + --> $DIR/match-ergonomics.rs:20:9 + | +LL | [v] => {}, + | ^^^ pattern cannot match with input type `std::vec::Vec` + +error[E0308]: mismatched types + --> $DIR/match-ergonomics.rs:29:9 + | +LL | &v => {}, + | ^^ expected i32, found reference + | + = note: expected type `i32` + found type `&_` +help: you can rely on match ergonomics and remove the explicit borrow + | +LL | v => {}, + | ^ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0308, E0529. +For more information about an error, try `rustc --explain E0308`. From 693eea5784fc58e9d9a8cade7a5b2afa2f3dbd3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 29 Apr 2019 19:56:50 -0700 Subject: [PATCH 10/33] review comments --- src/librustc_typeck/check/_match.rs | 116 +++++++++--------- src/test/ui/destructure-trait-ref.stderr | 4 +- .../ui/mismatched_types/issue-38371.stderr | 2 +- .../ui/suggestions/match-ergonomics.stderr | 2 +- 4 files changed, 60 insertions(+), 64 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 53d1ac7b02496..124afc5491e89 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -1,8 +1,8 @@ use crate::check::{FnCtxt, Expectation, Diverges, Needs}; use crate::check::coercion::CoerceMany; use crate::util::nodemap::FxHashMap; -use errors::Applicability; -use rustc::hir::{self, PatKind}; +use errors::{Applicability, DiagnosticBuilder}; +use rustc::hir::{self, PatKind, Pat}; use rustc::hir::def::{Def, CtorKind}; use rustc::hir::pat_util::EnumerateAndAdjustIterator; use rustc::infer; @@ -377,64 +377,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Look for a case like `fn foo(&foo: u32)` and suggest // `fn foo(foo: &u32)` if let Some(mut err) = err { - if let PatKind::Binding(..) = inner.node { - let parent_id = tcx.hir().get_parent_node_by_hir_id(pat.hir_id); - let parent = tcx.hir().get_by_hir_id(parent_id); - debug!("inner {:?} pat {:?} parent {:?}", inner, pat, parent); - match parent { - hir::Node::Item(hir::Item { - node: hir::ItemKind::Fn(..), .. - }) | - hir::Node::ForeignItem(hir::ForeignItem { - node: hir::ForeignItemKind::Fn(..), .. - }) | - hir::Node::TraitItem(hir::TraitItem { - node: hir::TraitItemKind::Method(..), .. - }) | - hir::Node::ImplItem(hir::ImplItem { - node: hir::ImplItemKind::Method(..), .. - }) => { // this pat is likely an argument - if let Ok(snippet) = tcx.sess.source_map() - .span_to_snippet(inner.span) - { // FIXME: turn into structured suggestion, will need - // a span that also includes the the arg's type. - err.help(&format!( - "did you mean `{}: &{}`?", - snippet, - expected, - )); - } - } - hir::Node::Expr(hir::Expr { - node: hir::ExprKind::Match(..), .. - }) => { // rely on match ergonomics - if let Ok(snippet) = tcx.sess.source_map() - .span_to_snippet(inner.span) - { - err.span_suggestion( - pat.span, - "you can rely on match ergonomics and remove \ - the explicit borrow", - snippet, - Applicability::MaybeIncorrect, - ); - } - } - hir::Node::Pat(_) => { // nested `&&pat` - if let Ok(snippet) = tcx.sess.source_map() - .span_to_snippet(inner.span) - { - err.span_suggestion( - pat.span, - "you can probaly remove the explicit borrow", - snippet, - Applicability::MaybeIncorrect, - ); - } - } - _ => {} // don't provide suggestions in other cases #55175 - } - } + self.borrow_pat_suggestion(&mut err, &pat, &inner, &expected); err.emit(); } (rptr_ty, inner_ty) @@ -566,6 +509,59 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // subtyping. } + fn borrow_pat_suggestion( + &self, + err: &mut DiagnosticBuilder<'_>, + pat: &Pat, + inner: &Pat, + expected: &Ty<'tcx>, + ) { + let tcx = self.tcx; + if let PatKind::Binding(..) = inner.node { + let parent_id = tcx.hir().get_parent_node_by_hir_id(pat.hir_id); + let parent = tcx.hir().get_by_hir_id(parent_id); + debug!("inner {:?} pat {:?} parent {:?}", inner, pat, parent); + match parent { + hir::Node::Item(hir::Item { node: hir::ItemKind::Fn(..), .. }) | + hir::Node::ForeignItem(hir::ForeignItem { + node: hir::ForeignItemKind::Fn(..), .. + }) | + hir::Node::TraitItem(hir::TraitItem { node: hir::TraitItemKind::Method(..), .. }) | + hir::Node::ImplItem(hir::ImplItem { node: hir::ImplItemKind::Method(..), .. }) => { + // this pat is likely an argument + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(inner.span) { + // FIXME: turn into structured suggestion, will need a span that also + // includes the the arg's type. + err.help(&format!("did you mean `{}: &{}`?", snippet, expected)); + } + } + hir::Node::Expr(hir::Expr { node: hir::ExprKind::Match(..), .. }) => { + // rely on match ergonomics + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(inner.span) { + err.span_suggestion( + pat.span, + "you can rely on match ergonomics and remove the explicit borrow", + snippet, + Applicability::MaybeIncorrect, + ); + } + } + hir::Node::Pat(_) => { + // nested `&&pat` + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(inner.span) { + err.span_suggestion( + pat.span, + "you can probably remove the explicit borrow", + snippet, + Applicability::MaybeIncorrect, + ); + } + } + _ => {} // don't provide suggestions in other cases #55175 + } + } + } + pub fn check_dereferencable(&self, span: Span, expected: Ty<'tcx>, inner: &hir::Pat) -> bool { if let PatKind::Binding(..) = inner.node { if let Some(mt) = self.shallow_resolve(expected).builtin_deref(true) { diff --git a/src/test/ui/destructure-trait-ref.stderr b/src/test/ui/destructure-trait-ref.stderr index 47ecadfd01afb..bc3013b78b38c 100644 --- a/src/test/ui/destructure-trait-ref.stderr +++ b/src/test/ui/destructure-trait-ref.stderr @@ -23,7 +23,7 @@ LL | let &&x = &1isize as &T; | ^^ | | | expected trait T, found reference - | help: you can probaly remove the explicit borrow: `x` + | help: you can probably remove the explicit borrow: `x` | = note: expected type `dyn T` found type `&_` @@ -35,7 +35,7 @@ LL | let &&&x = &(&1isize as &T); | ^^ | | | expected trait T, found reference - | help: you can probaly remove the explicit borrow: `x` + | help: you can probably remove the explicit borrow: `x` | = note: expected type `dyn T` found type `&_` diff --git a/src/test/ui/mismatched_types/issue-38371.stderr b/src/test/ui/mismatched_types/issue-38371.stderr index 833b8998c338a..a9347926bda0a 100644 --- a/src/test/ui/mismatched_types/issue-38371.stderr +++ b/src/test/ui/mismatched_types/issue-38371.stderr @@ -15,7 +15,7 @@ LL | fn agh(&&bar: &u32) { | ^^^^ | | | expected u32, found reference - | help: you can probaly remove the explicit borrow: `bar` + | help: you can probably remove the explicit borrow: `bar` | = note: expected type `u32` found type `&_` diff --git a/src/test/ui/suggestions/match-ergonomics.stderr b/src/test/ui/suggestions/match-ergonomics.stderr index 4239089b7cec7..a064e2485ffe8 100644 --- a/src/test/ui/suggestions/match-ergonomics.stderr +++ b/src/test/ui/suggestions/match-ergonomics.stderr @@ -5,7 +5,7 @@ LL | [&v] => {}, | ^^ | | | expected i32, found reference - | help: you can probaly remove the explicit borrow: `v` + | help: you can probably remove the explicit borrow: `v` | = note: expected type `i32` found type `&_` From 14ca95066579f4ec3761fa171e9c9c6d7bd80ccb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 29 Apr 2019 20:50:04 -0700 Subject: [PATCH 11/33] Fix style --- src/librustc_typeck/check/_match.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 124afc5491e89..88168a6950be4 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -514,7 +514,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { err: &mut DiagnosticBuilder<'_>, pat: &Pat, inner: &Pat, - expected: &Ty<'tcx>, + expected: Ty<'tcx>, ) { let tcx = self.tcx; if let PatKind::Binding(..) = inner.node { From 6068478d56a05ab1aa4d9ad87046e1d5d47afd7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 29 Apr 2019 20:58:29 -0700 Subject: [PATCH 12/33] Add if let test --- src/test/ui/suggestions/match-ergonomics.rs | 1 + src/test/ui/suggestions/match-ergonomics.stderr | 14 +++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/test/ui/suggestions/match-ergonomics.rs b/src/test/ui/suggestions/match-ergonomics.rs index d75f8363cd221..c4fc01469bf65 100644 --- a/src/test/ui/suggestions/match-ergonomics.rs +++ b/src/test/ui/suggestions/match-ergonomics.rs @@ -37,4 +37,5 @@ fn main() { v => {}, _ => {}, } + if let [&v] = &x[..] {} //~ ERROR mismatched types } diff --git a/src/test/ui/suggestions/match-ergonomics.stderr b/src/test/ui/suggestions/match-ergonomics.stderr index a064e2485ffe8..9915eeb34fac1 100644 --- a/src/test/ui/suggestions/match-ergonomics.stderr +++ b/src/test/ui/suggestions/match-ergonomics.stderr @@ -35,7 +35,19 @@ help: you can rely on match ergonomics and remove the explicit borrow LL | v => {}, | ^ -error: aborting due to 4 previous errors +error[E0308]: mismatched types + --> $DIR/match-ergonomics.rs:40:13 + | +LL | if let [&v] = &x[..] {} + | ^^ + | | + | expected i32, found reference + | help: you can probably remove the explicit borrow: `v` + | + = note: expected type `i32` + found type `&_` + +error: aborting due to 5 previous errors Some errors have detailed explanations: E0308, E0529. For more information about an error, try `rustc --explain E0308`. From bf4d0adf2395a260b024586e105f2e109222201c Mon Sep 17 00:00:00 2001 From: Yuki OKUSHI Date: Tue, 30 Apr 2019 17:27:53 +0900 Subject: [PATCH 13/33] Rename to RUSTC_LOG --- src/bootstrap/native.rs | 2 +- src/librustc/infer/mod.rs | 2 +- src/librustc_driver/lib.rs | 2 +- src/test/run-make-fulldeps/libs-through-symlinks/Makefile | 2 +- src/test/run-pass/issues/issue-18075.rs | 2 +- src/test/run-pass/logging-only-prints-once.rs | 2 +- src/test/run-pass/logging_before_rt_started.rs | 2 +- src/test/run-pass/rustc-rust-log.rs | 2 +- src/test/run-pass/threads-sendsync/spawning-with-debug.rs | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 96aed7293450c..285f9458c44b6 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -436,7 +436,7 @@ fn configure_cmake(builder: &Builder<'_>, } if env::var_os("SCCACHE_ERROR_LOG").is_some() { - cfg.env("RUST_LOG", "sccache=warn"); + cfg.env("RUSTC_LOG", "sccache=warn"); } } diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index e9b80c56e0c5c..3e5d6247e2b10 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -694,7 +694,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// potentially leaving "dangling type variables" behind. /// In such cases, an assertion will fail when attempting to /// register obligations, within a snapshot. Very useful, much - /// better than grovelling through megabytes of `RUST_LOG` output. + /// better than grovelling through megabytes of `RUSTC_LOG` output. /// /// HOWEVER, in some cases the flag is unhelpful. In particular, we /// sometimes create a "mini-fulfilment-cx" in which we enroll diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 6a5accc8d7f05..5b42b049b5b18 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -1163,7 +1163,7 @@ pub fn report_ices_to_stderr_if_any R, R>(f: F) -> Result Date: Tue, 30 Apr 2019 20:43:03 +0900 Subject: [PATCH 14/33] Add error for existential types --- src/librustc_passes/ast_validation.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 9dd8a7050fd28..a482f60897bed 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -679,6 +679,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> { "unions cannot have zero fields"); } } + ItemKind::Existential(ref bounds, _) => { + if !bounds.iter() + .any(|b| if let GenericBound::Trait(..) = *b { true } else { false }) { + self.err_handler().span_err(item.span, "at least one trait must be specified"); + } + } _ => {} } From bb3549fce26355c79437d516b7afa4d4ddad924f Mon Sep 17 00:00:00 2001 From: Yuki OKUSHI Date: Tue, 30 Apr 2019 20:43:10 +0900 Subject: [PATCH 15/33] Fix tests --- .../existential-types-with-no-traits.rs | 14 ++++++++++++++ .../existential-types-with-no-traits.stderr | 14 ++++++++++++++ .../existential_types/generic_nondefining_use.rs | 2 ++ .../generic_nondefining_use.stderr | 10 ++++++++-- .../ui/existential_types/generic_not_used.rs | 1 + .../ui/existential_types/generic_not_used.stderr | 10 ++++++++-- .../generic_type_does_not_live_long_enough.rs | 1 + ...generic_type_does_not_live_long_enough.stderr | 8 +++++++- .../generic_underconstrained.rs | 1 + .../generic_underconstrained.stderr | 8 +++++++- .../generic_underconstrained2.rs | 2 ++ .../generic_underconstrained2.stderr | 16 ++++++++++++++-- .../ui/existential_types/unused_generic_param.rs | 5 ++--- .../unused_generic_param.stderr | 14 ++++++++++++++ 14 files changed, 95 insertions(+), 11 deletions(-) create mode 100644 src/test/ui/existential_types/existential-types-with-no-traits.rs create mode 100644 src/test/ui/existential_types/existential-types-with-no-traits.stderr create mode 100644 src/test/ui/existential_types/unused_generic_param.stderr diff --git a/src/test/ui/existential_types/existential-types-with-no-traits.rs b/src/test/ui/existential_types/existential-types-with-no-traits.rs new file mode 100644 index 0000000000000..46339c73b1f1d --- /dev/null +++ b/src/test/ui/existential_types/existential-types-with-no-traits.rs @@ -0,0 +1,14 @@ +#![feature(existential_type)] + +existential type Foo: 'static; +//~^ ERROR: at least one trait must be specified + +fn foo() -> Foo { + "foo" +} + +fn bar() -> impl 'static { //~ ERROR: at least one trait must be specified + "foo" +} + +fn main() {} diff --git a/src/test/ui/existential_types/existential-types-with-no-traits.stderr b/src/test/ui/existential_types/existential-types-with-no-traits.stderr new file mode 100644 index 0000000000000..1464e8b48ebda --- /dev/null +++ b/src/test/ui/existential_types/existential-types-with-no-traits.stderr @@ -0,0 +1,14 @@ +error: at least one trait must be specified + --> $DIR/existential-types-with-no-traits.rs:3:1 + | +LL | existential type Foo: 'static; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: at least one trait must be specified + --> $DIR/existential-types-with-no-traits.rs:10:13 + | +LL | fn bar() -> impl 'static { + | ^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/existential_types/generic_nondefining_use.rs b/src/test/ui/existential_types/generic_nondefining_use.rs index 75af5d9570ff2..ffc965aca47c9 100644 --- a/src/test/ui/existential_types/generic_nondefining_use.rs +++ b/src/test/ui/existential_types/generic_nondefining_use.rs @@ -4,6 +4,8 @@ fn main() {} existential type Cmp: 'static; //~^ ERROR could not find defining uses +//~^^ ERROR: at least one trait must be specified + // not a defining use, because it doesn't define *all* possible generics fn cmp() -> Cmp { //~ ERROR defining existential type use does not fully define diff --git a/src/test/ui/existential_types/generic_nondefining_use.stderr b/src/test/ui/existential_types/generic_nondefining_use.stderr index ef579260f061c..7bde5f3ee5e69 100644 --- a/src/test/ui/existential_types/generic_nondefining_use.stderr +++ b/src/test/ui/existential_types/generic_nondefining_use.stderr @@ -1,5 +1,11 @@ +error: at least one trait must be specified + --> $DIR/generic_nondefining_use.rs:5:1 + | +LL | existential type Cmp: 'static; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: defining existential type use does not fully define existential type - --> $DIR/generic_nondefining_use.rs:9:1 + --> $DIR/generic_nondefining_use.rs:11:1 | LL | / fn cmp() -> Cmp { LL | | 5u32 @@ -12,5 +18,5 @@ error: could not find defining uses LL | existential type Cmp: 'static; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors diff --git a/src/test/ui/existential_types/generic_not_used.rs b/src/test/ui/existential_types/generic_not_used.rs index bfe7b8c4a1d53..054e6f5f2ade9 100644 --- a/src/test/ui/existential_types/generic_not_used.rs +++ b/src/test/ui/existential_types/generic_not_used.rs @@ -3,6 +3,7 @@ fn main() {} existential type WrongGeneric: 'static; +//~^ ERROR: at least one trait must be specified fn wrong_generic(_: U, v: V) -> WrongGeneric { //~^ ERROR type parameter `V` is part of concrete type but not used in parameter list diff --git a/src/test/ui/existential_types/generic_not_used.stderr b/src/test/ui/existential_types/generic_not_used.stderr index 1ae4ab65929f0..4bce35ea09dc3 100644 --- a/src/test/ui/existential_types/generic_not_used.stderr +++ b/src/test/ui/existential_types/generic_not_used.stderr @@ -1,5 +1,11 @@ +error: at least one trait must be specified + --> $DIR/generic_not_used.rs:5:1 + | +LL | existential type WrongGeneric: 'static; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: type parameter `V` is part of concrete type but not used in parameter list for existential type - --> $DIR/generic_not_used.rs:7:73 + --> $DIR/generic_not_used.rs:8:73 | LL | fn wrong_generic(_: U, v: V) -> WrongGeneric { | _________________________________________________________________________^ @@ -8,5 +14,5 @@ LL | | v LL | | } | |_^ -error: aborting due to previous error +error: aborting due to 2 previous errors diff --git a/src/test/ui/existential_types/generic_type_does_not_live_long_enough.rs b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.rs index 02bb151ccb618..d9eedd6dca7c1 100644 --- a/src/test/ui/existential_types/generic_type_does_not_live_long_enough.rs +++ b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.rs @@ -8,6 +8,7 @@ fn main() { existential type WrongGeneric: 'static; //~^ ERROR the parameter type `T` may not live long enough +//~^^ ERROR: at least one trait must be specified fn wrong_generic(t: T) -> WrongGeneric { t diff --git a/src/test/ui/existential_types/generic_type_does_not_live_long_enough.stderr b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.stderr index 002acc41553b6..1e4c49f3f316b 100644 --- a/src/test/ui/existential_types/generic_type_does_not_live_long_enough.stderr +++ b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.stderr @@ -1,3 +1,9 @@ +error: at least one trait must be specified + --> $DIR/generic_type_does_not_live_long_enough.rs:9:1 + | +LL | existential type WrongGeneric: 'static; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0308]: mismatched types --> $DIR/generic_type_does_not_live_long_enough.rs:6:18 | @@ -22,7 +28,7 @@ note: ...so that the type `T` will meet its required lifetime bounds LL | existential type WrongGeneric: 'static; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0308, E0310. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/existential_types/generic_underconstrained.rs b/src/test/ui/existential_types/generic_underconstrained.rs index 967faca067c1e..cc0db893c6aa7 100644 --- a/src/test/ui/existential_types/generic_underconstrained.rs +++ b/src/test/ui/existential_types/generic_underconstrained.rs @@ -4,6 +4,7 @@ fn main() {} trait Trait {} existential type Underconstrained: 'static; //~ ERROR the trait bound `T: Trait` +//~^ ERROR: at least one trait must be specified // no `Trait` bound fn underconstrain(_: T) -> Underconstrained { diff --git a/src/test/ui/existential_types/generic_underconstrained.stderr b/src/test/ui/existential_types/generic_underconstrained.stderr index 8551a939e8ed8..d5e9ecc1abe77 100644 --- a/src/test/ui/existential_types/generic_underconstrained.stderr +++ b/src/test/ui/existential_types/generic_underconstrained.stderr @@ -1,3 +1,9 @@ +error: at least one trait must be specified + --> $DIR/generic_underconstrained.rs:6:1 + | +LL | existential type Underconstrained: 'static; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0277]: the trait bound `T: Trait` is not satisfied --> $DIR/generic_underconstrained.rs:6:1 | @@ -7,6 +13,6 @@ LL | existential type Underconstrained: 'static; = help: consider adding a `where T: Trait` bound = note: the return type of a function must have a statically known size -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/existential_types/generic_underconstrained2.rs b/src/test/ui/existential_types/generic_underconstrained2.rs index 98d9da832cfd3..c6263eacd53e3 100644 --- a/src/test/ui/existential_types/generic_underconstrained2.rs +++ b/src/test/ui/existential_types/generic_underconstrained2.rs @@ -4,6 +4,7 @@ fn main() {} existential type Underconstrained: 'static; //~^ ERROR `U` doesn't implement `std::fmt::Debug` +//~^^ ERROR: at least one trait must be specified // not a defining use, because it doesn't define *all* possible generics fn underconstrained(_: U) -> Underconstrained { @@ -12,6 +13,7 @@ fn underconstrained(_: U) -> Underconstrained { existential type Underconstrained2: 'static; //~^ ERROR `V` doesn't implement `std::fmt::Debug` +//~^^ ERROR: at least one trait must be specified // not a defining use, because it doesn't define *all* possible generics fn underconstrained2(_: U, _: V) -> Underconstrained2 { diff --git a/src/test/ui/existential_types/generic_underconstrained2.stderr b/src/test/ui/existential_types/generic_underconstrained2.stderr index c7b6d6ade557c..df726dde42966 100644 --- a/src/test/ui/existential_types/generic_underconstrained2.stderr +++ b/src/test/ui/existential_types/generic_underconstrained2.stderr @@ -1,3 +1,15 @@ +error: at least one trait must be specified + --> $DIR/generic_underconstrained2.rs:5:1 + | +LL | existential type Underconstrained: 'static; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: at least one trait must be specified + --> $DIR/generic_underconstrained2.rs:14:1 + | +LL | existential type Underconstrained2: 'static; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0277]: `U` doesn't implement `std::fmt::Debug` --> $DIR/generic_underconstrained2.rs:5:1 | @@ -9,7 +21,7 @@ LL | existential type Underconstrained: 'static; = note: the return type of a function must have a statically known size error[E0277]: `V` doesn't implement `std::fmt::Debug` - --> $DIR/generic_underconstrained2.rs:13:1 + --> $DIR/generic_underconstrained2.rs:14:1 | LL | existential type Underconstrained2: 'static; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` @@ -18,6 +30,6 @@ LL | existential type Underconstrained2: 'static; = help: consider adding a `where V: std::fmt::Debug` bound = note: the return type of a function must have a statically known size -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/existential_types/unused_generic_param.rs b/src/test/ui/existential_types/unused_generic_param.rs index 7af6508788129..5455b39f4cbe2 100644 --- a/src/test/ui/existential_types/unused_generic_param.rs +++ b/src/test/ui/existential_types/unused_generic_param.rs @@ -1,18 +1,17 @@ -// compile-pass #![feature(existential_type)] fn main() { } -// test that unused generic parameters are ok existential type PartiallyDefined: 'static; +//~^ ERROR: at least one trait must be specified fn partially_defined(_: T) -> PartiallyDefined { 4u32 } -// test that unused generic parameters are ok existential type PartiallyDefined2: 'static; +//~^ ERROR: at least one trait must be specified fn partially_defined2(_: T) -> PartiallyDefined2 { 4u32 diff --git a/src/test/ui/existential_types/unused_generic_param.stderr b/src/test/ui/existential_types/unused_generic_param.stderr new file mode 100644 index 0000000000000..8c563e93ae55c --- /dev/null +++ b/src/test/ui/existential_types/unused_generic_param.stderr @@ -0,0 +1,14 @@ +error: at least one trait must be specified + --> $DIR/unused_generic_param.rs:6:1 + | +LL | existential type PartiallyDefined: 'static; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: at least one trait must be specified + --> $DIR/unused_generic_param.rs:13:1 + | +LL | existential type PartiallyDefined2: 'static; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + From f56d2854436de7f0e00f5a76bf9dba4364ca4d31 Mon Sep 17 00:00:00 2001 From: Yuki OKUSHI Date: Tue, 30 Apr 2019 21:28:13 +0900 Subject: [PATCH 16/33] Use multispan --- src/librustc_passes/ast_validation.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index a482f60897bed..1f5a6d7914125 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -20,7 +20,7 @@ use syntax::ptr::P; use syntax::visit::{self, Visitor}; use syntax::{span_err, struct_span_err, walk_list}; use syntax_ext::proc_macro_decls::is_proc_macro_attr; -use syntax_pos::Span; +use syntax_pos::{Span, MultiSpan}; use errors::Applicability; use log::debug; @@ -682,7 +682,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { ItemKind::Existential(ref bounds, _) => { if !bounds.iter() .any(|b| if let GenericBound::Trait(..) = *b { true } else { false }) { - self.err_handler().span_err(item.span, "at least one trait must be specified"); + let msp = MultiSpan::from_spans(bounds.iter() + .map(|bound| bound.span()).collect()); + self.err_handler().span_err(msp, "at least one trait must be specified"); } } _ => {} From db7f26566062b5444704aec669bbebbc2ff3a8d6 Mon Sep 17 00:00:00 2001 From: Yuki OKUSHI Date: Tue, 30 Apr 2019 21:28:34 +0900 Subject: [PATCH 17/33] Fix spans --- .../existential-types-with-no-traits.stderr | 4 ++-- .../ui/existential_types/generic_nondefining_use.stderr | 4 ++-- src/test/ui/existential_types/generic_not_used.stderr | 4 ++-- .../generic_type_does_not_live_long_enough.stderr | 4 ++-- .../ui/existential_types/generic_underconstrained.stderr | 4 ++-- .../ui/existential_types/generic_underconstrained2.stderr | 8 ++++---- src/test/ui/existential_types/unused_generic_param.stderr | 8 ++++---- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/test/ui/existential_types/existential-types-with-no-traits.stderr b/src/test/ui/existential_types/existential-types-with-no-traits.stderr index 1464e8b48ebda..4b2fbc79d3bc2 100644 --- a/src/test/ui/existential_types/existential-types-with-no-traits.stderr +++ b/src/test/ui/existential_types/existential-types-with-no-traits.stderr @@ -1,8 +1,8 @@ error: at least one trait must be specified - --> $DIR/existential-types-with-no-traits.rs:3:1 + --> $DIR/existential-types-with-no-traits.rs:3:23 | LL | existential type Foo: 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ error: at least one trait must be specified --> $DIR/existential-types-with-no-traits.rs:10:13 diff --git a/src/test/ui/existential_types/generic_nondefining_use.stderr b/src/test/ui/existential_types/generic_nondefining_use.stderr index 7bde5f3ee5e69..d205d44c68c71 100644 --- a/src/test/ui/existential_types/generic_nondefining_use.stderr +++ b/src/test/ui/existential_types/generic_nondefining_use.stderr @@ -1,8 +1,8 @@ error: at least one trait must be specified - --> $DIR/generic_nondefining_use.rs:5:1 + --> $DIR/generic_nondefining_use.rs:5:26 | LL | existential type Cmp: 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ error: defining existential type use does not fully define existential type --> $DIR/generic_nondefining_use.rs:11:1 diff --git a/src/test/ui/existential_types/generic_not_used.stderr b/src/test/ui/existential_types/generic_not_used.stderr index 4bce35ea09dc3..d243233992b02 100644 --- a/src/test/ui/existential_types/generic_not_used.stderr +++ b/src/test/ui/existential_types/generic_not_used.stderr @@ -1,8 +1,8 @@ error: at least one trait must be specified - --> $DIR/generic_not_used.rs:5:1 + --> $DIR/generic_not_used.rs:5:44 | LL | existential type WrongGeneric: 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ error: type parameter `V` is part of concrete type but not used in parameter list for existential type --> $DIR/generic_not_used.rs:8:73 diff --git a/src/test/ui/existential_types/generic_type_does_not_live_long_enough.stderr b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.stderr index 1e4c49f3f316b..2f76eea4460bd 100644 --- a/src/test/ui/existential_types/generic_type_does_not_live_long_enough.stderr +++ b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.stderr @@ -1,8 +1,8 @@ error: at least one trait must be specified - --> $DIR/generic_type_does_not_live_long_enough.rs:9:1 + --> $DIR/generic_type_does_not_live_long_enough.rs:9:35 | LL | existential type WrongGeneric: 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ error[E0308]: mismatched types --> $DIR/generic_type_does_not_live_long_enough.rs:6:18 diff --git a/src/test/ui/existential_types/generic_underconstrained.stderr b/src/test/ui/existential_types/generic_underconstrained.stderr index d5e9ecc1abe77..35083a53eb343 100644 --- a/src/test/ui/existential_types/generic_underconstrained.stderr +++ b/src/test/ui/existential_types/generic_underconstrained.stderr @@ -1,8 +1,8 @@ error: at least one trait must be specified - --> $DIR/generic_underconstrained.rs:6:1 + --> $DIR/generic_underconstrained.rs:6:46 | LL | existential type Underconstrained: 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ error[E0277]: the trait bound `T: Trait` is not satisfied --> $DIR/generic_underconstrained.rs:6:1 diff --git a/src/test/ui/existential_types/generic_underconstrained2.stderr b/src/test/ui/existential_types/generic_underconstrained2.stderr index df726dde42966..6ff783f33b96f 100644 --- a/src/test/ui/existential_types/generic_underconstrained2.stderr +++ b/src/test/ui/existential_types/generic_underconstrained2.stderr @@ -1,14 +1,14 @@ error: at least one trait must be specified - --> $DIR/generic_underconstrained2.rs:5:1 + --> $DIR/generic_underconstrained2.rs:5:56 | LL | existential type Underconstrained: 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ error: at least one trait must be specified - --> $DIR/generic_underconstrained2.rs:14:1 + --> $DIR/generic_underconstrained2.rs:14:57 | LL | existential type Underconstrained2: 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ error[E0277]: `U` doesn't implement `std::fmt::Debug` --> $DIR/generic_underconstrained2.rs:5:1 diff --git a/src/test/ui/existential_types/unused_generic_param.stderr b/src/test/ui/existential_types/unused_generic_param.stderr index 8c563e93ae55c..9d628d069d36c 100644 --- a/src/test/ui/existential_types/unused_generic_param.stderr +++ b/src/test/ui/existential_types/unused_generic_param.stderr @@ -1,14 +1,14 @@ error: at least one trait must be specified - --> $DIR/unused_generic_param.rs:6:1 + --> $DIR/unused_generic_param.rs:6:39 | LL | existential type PartiallyDefined: 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ error: at least one trait must be specified - --> $DIR/unused_generic_param.rs:13:1 + --> $DIR/unused_generic_param.rs:13:40 | LL | existential type PartiallyDefined2: 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ error: aborting due to 2 previous errors From 748d978c648711d04cd3f3f06722e13c488e017a Mon Sep 17 00:00:00 2001 From: Yuki OKUSHI Date: Wed, 1 May 2019 00:36:51 +0900 Subject: [PATCH 18/33] Fix run-pass test --- src/test/run-pass/existential_type.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/run-pass/existential_type.rs b/src/test/run-pass/existential_type.rs index dfb195ec83062..b36435cf113f1 100644 --- a/src/test/run-pass/existential_type.rs +++ b/src/test/run-pass/existential_type.rs @@ -68,14 +68,14 @@ fn my_other_iter(u: U) -> MyOtherIter { } trait Trait {} -existential type GenericBound<'a, T: Trait>: 'a; +existential type GenericBound<'a, T: Trait>: Sized + 'a; fn generic_bound<'a, T: Trait + 'a>(t: T) -> GenericBound<'a, T> { t } mod pass_through { - pub existential type Passthrough: 'static; + pub existential type Passthrough: Sized + 'static; fn define_passthrough(t: T) -> Passthrough { t From ed08c6a985d0f69d2eac33e09440112c880c9fd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 30 Apr 2019 10:59:30 -0700 Subject: [PATCH 19/33] review comments: change wording --- src/librustc_typeck/check/_match.rs | 14 ++------------ src/test/ui/suggestions/match-ergonomics.stderr | 9 ++++----- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 88168a6950be4..f5aa2e6ea5cea 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -535,19 +535,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { err.help(&format!("did you mean `{}: &{}`?", snippet, expected)); } } - hir::Node::Expr(hir::Expr { node: hir::ExprKind::Match(..), .. }) => { - // rely on match ergonomics - if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(inner.span) { - err.span_suggestion( - pat.span, - "you can rely on match ergonomics and remove the explicit borrow", - snippet, - Applicability::MaybeIncorrect, - ); - } - } + hir::Node::Expr(hir::Expr { node: hir::ExprKind::Match(..), .. }) | hir::Node::Pat(_) => { - // nested `&&pat` + // rely on match ergonomics or it might be nested `&&pat` if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(inner.span) { err.span_suggestion( pat.span, diff --git a/src/test/ui/suggestions/match-ergonomics.stderr b/src/test/ui/suggestions/match-ergonomics.stderr index 9915eeb34fac1..b7497be6ceb36 100644 --- a/src/test/ui/suggestions/match-ergonomics.stderr +++ b/src/test/ui/suggestions/match-ergonomics.stderr @@ -26,14 +26,13 @@ error[E0308]: mismatched types --> $DIR/match-ergonomics.rs:29:9 | LL | &v => {}, - | ^^ expected i32, found reference + | ^^ + | | + | expected i32, found reference + | help: you can probably remove the explicit borrow: `v` | = note: expected type `i32` found type `&_` -help: you can rely on match ergonomics and remove the explicit borrow - | -LL | v => {}, - | ^ error[E0308]: mismatched types --> $DIR/match-ergonomics.rs:40:13 From 24fddb15e86a46e6057c8c0f2f0fb18844f50049 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 1 May 2019 14:57:24 -0700 Subject: [PATCH 20/33] Resolve match arm ty when arms diverge --- src/librustc/infer/error_reporting/mod.rs | 2 +- src/test/ui/match/match-type-err-first-arm.rs | 24 ++++++++----- .../ui/match/match-type-err-first-arm.stderr | 35 ++++++++++++++----- 3 files changed, 43 insertions(+), 18 deletions(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index c20a08fc5aea6..95b566d4a1b69 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -644,7 +644,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { for sp in prior_arms { err.span_label(*sp, format!( "this is found to be of type `{}`", - last_ty, + self.resolve_type_vars_if_possible(&last_ty), )); } } else if let Some(sp) = prior_arms.last() { diff --git a/src/test/ui/match/match-type-err-first-arm.rs b/src/test/ui/match/match-type-err-first-arm.rs index b4b84ef8f1cec..8dfbf1019e9a4 100644 --- a/src/test/ui/match/match-type-err-first-arm.rs +++ b/src/test/ui/match/match-type-err-first-arm.rs @@ -3,8 +3,7 @@ fn main() { let _ = test_func2(1); } -fn test_func1(n: i32) -> i32 { - //~^ NOTE expected `i32` because of return type +fn test_func1(n: i32) -> i32 { //~ NOTE expected `i32` because of return type match n { 12 => 'b', //~^ ERROR mismatched types @@ -14,10 +13,8 @@ fn test_func1(n: i32) -> i32 { } fn test_func2(n: i32) -> i32 { - let x = match n { - //~^ NOTE `match` arms have incompatible types - 12 => 'b', - //~^ NOTE this is found to be of type `char` + let x = match n { //~ NOTE `match` arms have incompatible types + 12 => 'b', //~ NOTE this is found to be of type `char` _ => 42, //~^ ERROR match arms have incompatible types //~| NOTE expected char, found integer @@ -27,8 +24,7 @@ fn test_func2(n: i32) -> i32 { } fn test_func3(n: i32) -> i32 { - let x = match n { - //~^ NOTE `match` arms have incompatible types + let x = match n { //~ NOTE `match` arms have incompatible types 1 => 'b', 2 => 'b', 3 => 'b', @@ -43,3 +39,15 @@ fn test_func3(n: i32) -> i32 { }; x } + +fn test_func4() { + match Some(0u32) { //~ NOTE `match` arms have incompatible types + Some(x) => { + x //~ NOTE this is found to be of type `u32` + }, + None => {} + //~^ ERROR match arms have incompatible types + //~| NOTE expected u32, found () + //~| NOTE expected type `u32` + }; +} diff --git a/src/test/ui/match/match-type-err-first-arm.stderr b/src/test/ui/match/match-type-err-first-arm.stderr index a318e6cffb937..e0553fca683a5 100644 --- a/src/test/ui/match/match-type-err-first-arm.stderr +++ b/src/test/ui/match/match-type-err-first-arm.stderr @@ -1,24 +1,23 @@ error[E0308]: mismatched types - --> $DIR/match-type-err-first-arm.rs:9:15 + --> $DIR/match-type-err-first-arm.rs:8:15 | LL | fn test_func1(n: i32) -> i32 { | --- expected `i32` because of return type -... +LL | match n { LL | 12 => 'b', | ^^^ expected i32, found char error[E0308]: match arms have incompatible types - --> $DIR/match-type-err-first-arm.rs:21:14 + --> $DIR/match-type-err-first-arm.rs:18:14 | LL | let x = match n { | _____________- -LL | | LL | | 12 => 'b', | | --- this is found to be of type `char` -LL | | LL | | _ => 42, | | ^^ expected char, found integer -... | +LL | | +LL | | LL | | LL | | }; | |_____- `match` arms have incompatible types @@ -27,13 +26,13 @@ LL | | }; found type `{integer}` error[E0308]: match arms have incompatible types - --> $DIR/match-type-err-first-arm.rs:39:14 + --> $DIR/match-type-err-first-arm.rs:35:14 | LL | let x = match n { | _____________- -LL | | LL | | 1 => 'b', LL | | 2 => 'b', +LL | | 3 => 'b', ... | LL | | 6 => 'b', | | --- this and all prior arms are found to be of type `char` @@ -48,6 +47,24 @@ LL | | }; = note: expected type `char` found type `{integer}` -error: aborting due to 3 previous errors +error[E0308]: match arms have incompatible types + --> $DIR/match-type-err-first-arm.rs:48:17 + | +LL | / match Some(0u32) { +LL | | Some(x) => { +LL | | x + | | - this is found to be of type `u32` +LL | | }, +LL | | None => {} + | | ^^ expected u32, found () +... | +LL | | +LL | | }; + | |_____- `match` arms have incompatible types + | + = note: expected type `u32` + found type `()` + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0308`. From 6ef39e69eac42e1cc86ec8eeb1b85c6b3a8784fa Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 2 May 2019 20:34:26 +1000 Subject: [PATCH 21/33] Avoid repeated interning of static strings. `file_metadata_raw` interns the strings `""` and `""` very frequently. This commit avoids that, which reduces the number of symbols interned significantly and reduces instruction counts by up to 0.5% on some workloads. --- .../debuginfo/metadata.rs | 22 +++++++++++-------- src/librustc_codegen_llvm/debuginfo/mod.rs | 2 +- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs index 765992fd2b70e..0d67865d71708 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -784,26 +784,30 @@ pub fn file_metadata(cx: &CodegenCx<'ll, '_>, file_name, defining_crate); - let directory = if defining_crate == LOCAL_CRATE { - &cx.sess().working_dir.0 + let file_name = &file_name.to_string(); + let file_name_symbol = Symbol::intern(file_name); + if defining_crate == LOCAL_CRATE { + let directory = &cx.sess().working_dir.0.to_string_lossy(); + file_metadata_raw(cx, file_name, Some(file_name_symbol), + directory, Some(Symbol::intern(directory))) } else { // If the path comes from an upstream crate we assume it has been made // independent of the compiler's working directory one way or another. - Path::new("") - }; - - file_metadata_raw(cx, &file_name.to_string(), &directory.to_string_lossy()) + file_metadata_raw(cx, file_name, Some(file_name_symbol), "", None) + } } pub fn unknown_file_metadata(cx: &CodegenCx<'ll, '_>) -> &'ll DIFile { - file_metadata_raw(cx, "", "") + file_metadata_raw(cx, "", None, "", None) } fn file_metadata_raw(cx: &CodegenCx<'ll, '_>, file_name: &str, - directory: &str) + file_name_symbol: Option, + directory: &str, + directory_symbol: Option) -> &'ll DIFile { - let key = (Symbol::intern(file_name), Symbol::intern(directory)); + let key = (file_name_symbol, directory_symbol); if let Some(file_metadata) = debug_context(cx).created_files.borrow().get(&key) { return *file_metadata; diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs index 2154ac9b1d259..f3070a03b4ed5 100644 --- a/src/librustc_codegen_llvm/debuginfo/mod.rs +++ b/src/librustc_codegen_llvm/debuginfo/mod.rs @@ -63,7 +63,7 @@ pub struct CrateDebugContext<'a, 'tcx> { llcontext: &'a llvm::Context, llmod: &'a llvm::Module, builder: &'a mut DIBuilder<'a>, - created_files: RefCell>, + created_files: RefCell, Option), &'a DIFile>>, created_enum_disr_types: RefCell>, type_map: RefCell>, From 16fe8ccce95a9df185404c881c029fb0507e4821 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Mon, 29 Apr 2019 18:32:35 -0400 Subject: [PATCH 22/33] Remove the `self.mir` field from `ConstPropagator` --- src/librustc_mir/transform/const_prop.rs | 124 +++++++++++++---------- src/test/ui/consts/const-err.stderr | 12 ++- 2 files changed, 80 insertions(+), 56 deletions(-) diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 2465adf46cdf4..2d89f73a95f69 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -1,18 +1,19 @@ //! Propagates constants for early reporting of statically known //! assertion failures - use rustc::hir::def::Def; -use rustc::mir::{Constant, Location, Place, PlaceBase, Mir, Operand, Rvalue, Local}; -use rustc::mir::{NullOp, UnOp, StatementKind, Statement, LocalKind, Static, StaticKind}; -use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp, ProjectionElem}; +use rustc::mir::{ + Constant, Location, Place, PlaceBase, Mir, Operand, Rvalue, Local, + NullOp, UnOp, StatementKind, Statement, LocalKind, Static, StaticKind, + TerminatorKind, Terminator, ClearCrossCrate, SourceInfo, BinOp, ProjectionElem, + SourceScope, SourceScopeLocalData, LocalDecl, Promoted, +}; use rustc::mir::visit::{Visitor, PlaceContext, MutatingUseContext, NonMutatingUseContext}; use rustc::mir::interpret::{InterpError, Scalar, GlobalId, EvalResult}; -use rustc::ty::{self, Instance, Ty, TyCtxt}; -use syntax::source_map::{Span, DUMMY_SP}; +use rustc::ty::{self, Instance, ParamEnv, Ty, TyCtxt}; +use syntax::source_map::DUMMY_SP; use rustc::ty::subst::InternalSubsts; use rustc_data_structures::indexed_vec::IndexVec; -use rustc::ty::ParamEnv; use rustc::ty::layout::{ LayoutOf, TyLayout, LayoutError, HasTyCtxt, TargetDataLayout, HasDataLayout, @@ -62,21 +63,33 @@ impl MirPass for ConstProp { let mut optimization_finder = ConstPropagator::new(mir, tcx, source); optimization_finder.visit_mir(mir); + // put back the data we stole from `mir` + std::mem::replace( + &mut mir.source_scope_local_data, + optimization_finder.source_scope_local_data + ); + std::mem::replace( + &mut mir.promoted, + optimization_finder.promoted + ); + trace!("ConstProp done for {:?}", source.def_id()); } } -type Const<'tcx> = (OpTy<'tcx>, Span); +type Const<'tcx> = OpTy<'tcx>; /// Finds optimization opportunities on the MIR. struct ConstPropagator<'a, 'mir, 'tcx:'a+'mir> { ecx: InterpretCx<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>, - mir: &'mir Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>, source: MirSource<'tcx>, places: IndexVec>>, can_const_prop: IndexVec, param_env: ParamEnv<'tcx>, + source_scope_local_data: ClearCrossCrate>, + local_decls: IndexVec>, + promoted: IndexVec>, } impl<'a, 'b, 'tcx> LayoutOf for ConstPropagator<'a, 'b, 'tcx> { @@ -104,20 +117,33 @@ impl<'a, 'b, 'tcx> HasTyCtxt<'tcx> for ConstPropagator<'a, 'b, 'tcx> { impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { fn new( - mir: &'mir Mir<'tcx>, + mir: &mut Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>, source: MirSource<'tcx>, ) -> ConstPropagator<'a, 'mir, 'tcx> { let param_env = tcx.param_env(source.def_id()); let ecx = mk_eval_cx(tcx, tcx.def_span(source.def_id()), param_env); + let can_const_prop = CanConstProp::check(mir); + let source_scope_local_data = std::mem::replace( + &mut mir.source_scope_local_data, + ClearCrossCrate::Clear + ); + let promoted = std::mem::replace( + &mut mir.promoted, + IndexVec::new() + ); + ConstPropagator { ecx, - mir, tcx, source, param_env, - can_const_prop: CanConstProp::check(mir), + can_const_prop, places: IndexVec::from_elem(None, &mir.local_decls), + source_scope_local_data, + //FIXME(wesleywiser) we can't steal this because `Visitor::super_visit_mir()` needs it + local_decls: mir.local_decls.clone(), + promoted, } } @@ -130,7 +156,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { F: FnOnce(&mut Self) -> EvalResult<'tcx, T>, { self.ecx.tcx.span = source_info.span; - let lint_root = match self.mir.source_scope_local_data { + let lint_root = match self.source_scope_local_data { ClearCrossCrate::Set(ref ivs) => { //FIXME(#51314): remove this check if source_info.scope.index() >= ivs.len() { @@ -252,12 +278,11 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { fn eval_constant( &mut self, c: &Constant<'tcx>, - source_info: SourceInfo, ) -> Option> { - self.ecx.tcx.span = source_info.span; + self.ecx.tcx.span = c.span; match self.ecx.eval_const_to_op(*c.literal, None) { Ok(op) => { - Some((op, c.span)) + Some(op) }, Err(error) => { let err = error_to_const_error(&self.ecx, error); @@ -273,11 +298,11 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { Place::Projection(ref proj) => match proj.elem { ProjectionElem::Field(field, _) => { trace!("field proj on {:?}", proj.base); - let (base, span) = self.eval_place(&proj.base, source_info)?; + let base = self.eval_place(&proj.base, source_info)?; let res = self.use_ecx(source_info, |this| { this.ecx.operand_field(base, field.index() as u64) })?; - Some((res, span)) + Some(res) }, // We could get more projections by using e.g., `operand_projection`, // but we do not even have the stack frame set up properly so @@ -301,11 +326,11 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { // cannot use `const_eval` here, because that would require having the MIR // for the current function available, but we're producing said MIR right now let res = self.use_ecx(source_info, |this| { - let mir = &this.mir.promoted[promoted]; + let mir = &this.promoted[promoted]; eval_promoted(this.tcx, cid, mir, this.param_env) })?; trace!("evaluated promoted {:?} to {:?}", promoted, res); - Some((res.into(), source_info.span)) + Some(res.into()) }, _ => None, } @@ -313,7 +338,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { fn eval_operand(&mut self, op: &Operand<'tcx>, source_info: SourceInfo) -> Option> { match *op { - Operand::Constant(ref c) => self.eval_constant(c, source_info), + Operand::Constant(ref c) => self.eval_constant(c), | Operand::Move(ref place) | Operand::Copy(ref place) => self.eval_place(place, source_info), } @@ -337,18 +362,18 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { Rvalue::Discriminant(..) => None, Rvalue::Cast(kind, ref operand, _) => { - let (op, span) = self.eval_operand(operand, source_info)?; + let op = self.eval_operand(operand, source_info)?; self.use_ecx(source_info, |this| { let dest = this.ecx.allocate(place_layout, MemoryKind::Stack); this.ecx.cast(op, kind, dest.into())?; - Ok((dest.into(), span)) + Ok(dest.into()) }) } // FIXME(oli-obk): evaluate static/constant slice lengths Rvalue::Len(_) => None, Rvalue::NullaryOp(NullOp::SizeOf, ty) => { - type_size_of(self.tcx, self.param_env, ty).and_then(|n| Some(( + type_size_of(self.tcx, self.param_env, ty).and_then(|n| Some( ImmTy { imm: Immediate::Scalar( Scalar::Bits { @@ -357,9 +382,8 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { }.into() ), layout: self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).ok()?, - }.into(), - span, - ))) + }.into() + )) } Rvalue::UnaryOp(op, ref arg) => { let def_id = if self.tcx.is_closure(self.source.def_id()) { @@ -373,7 +397,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { return None; } - let (arg, _) = self.eval_operand(arg, source_info)?; + let arg = self.eval_operand(arg, source_info)?; let val = self.use_ecx(source_info, |this| { let prim = this.ecx.read_immediate(arg)?; match op { @@ -395,7 +419,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { imm: Immediate::Scalar(val.into()), layout: place_layout, }; - Some((res.into(), span)) + Some(res.into()) } Rvalue::CheckedBinaryOp(op, ref left, ref right) | Rvalue::BinaryOp(op, ref left, ref right) => { @@ -413,20 +437,20 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { } let r = self.use_ecx(source_info, |this| { - this.ecx.read_immediate(right.0) + this.ecx.read_immediate(right) })?; if op == BinOp::Shr || op == BinOp::Shl { - let left_ty = left.ty(self.mir, self.tcx); + let left_ty = left.ty(&self.local_decls, self.tcx); let left_bits = self .tcx .layout_of(self.param_env.and(left_ty)) .unwrap() .size .bits(); - let right_size = right.0.layout.size; + let right_size = right.layout.size; let r_bits = r.to_scalar().and_then(|r| r.to_bits(right_size)); if r_bits.ok().map_or(false, |b| b >= left_bits as u128) { - let source_scope_local_data = match self.mir.source_scope_local_data { + let source_scope_local_data = match self.source_scope_local_data { ClearCrossCrate::Set(ref data) => data, ClearCrossCrate::Clear => return None, }; @@ -446,7 +470,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { } let left = self.eval_operand(left, source_info)?; let l = self.use_ecx(source_info, |this| { - this.ecx.read_immediate(left.0) + this.ecx.read_immediate(left) })?; trace!("const evaluating {:?} for {:?} and {:?}", op, left, right); let (val, overflow) = self.use_ecx(source_info, |this| { @@ -469,7 +493,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { imm: val, layout: place_layout, }; - Some((res.into(), span)) + Some(res.into()) }, } } @@ -544,8 +568,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> { ) { trace!("visit_constant: {:?}", constant); self.super_constant(constant, location); - let source_info = *self.mir.source_info(location); - self.eval_constant(constant, source_info); + self.eval_constant(constant); } fn visit_statement( @@ -556,7 +579,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> { trace!("visit_statement: {:?}", statement); if let StatementKind::Assign(ref place, ref rval) = statement.kind { let place_ty: Ty<'tcx> = place - .ty(&self.mir.local_decls, self.tcx) + .ty(&self.local_decls, self.tcx) .ty; if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) { if let Some(value) = self.const_prop(rval, place_layout, statement.source_info) { @@ -574,18 +597,18 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> { self.super_statement(statement, location); } - fn visit_terminator_kind( + fn visit_terminator( &mut self, - kind: &TerminatorKind<'tcx>, + terminator: &Terminator<'tcx>, location: Location, ) { - self.super_terminator_kind(kind, location); - let source_info = *self.mir.source_info(location); - if let TerminatorKind::Assert { expected, msg, cond, .. } = kind { - if let Some(value) = self.eval_operand(cond, source_info) { + self.super_terminator(terminator, location); + let source_info = terminator.source_info;; + if let TerminatorKind::Assert { expected, msg, cond, .. } = &terminator.kind { + if let Some(value) = self.eval_operand(&cond, source_info) { trace!("assertion on {:?} should be {:?}", value, expected); let expected = ScalarMaybeUndef::from(Scalar::from_bool(*expected)); - if expected != self.ecx.read_scalar(value.0).unwrap() { + if expected != self.ecx.read_scalar(value).unwrap() { // poison all places this operand references so that further code // doesn't use the invalid value match cond { @@ -600,12 +623,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> { }, Operand::Constant(_) => {} } - let span = self.mir[location.block] - .terminator - .as_ref() - .unwrap() - .source_info - .span; + let span = terminator.source_info.span; let hir_id = self .tcx .hir() @@ -621,7 +639,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> { let len = self .eval_operand(len, source_info) .expect("len must be const"); - let len = match self.ecx.read_scalar(len.0) { + let len = match self.ecx.read_scalar(len) { Ok(ScalarMaybeUndef::Scalar(Scalar::Bits { bits, .. })) => bits, @@ -630,7 +648,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> { let index = self .eval_operand(index, source_info) .expect("index must be const"); - let index = match self.ecx.read_scalar(index.0) { + let index = match self.ecx.read_scalar(index) { Ok(ScalarMaybeUndef::Scalar(Scalar::Bits { bits, .. })) => bits, diff --git a/src/test/ui/consts/const-err.stderr b/src/test/ui/consts/const-err.stderr index 0ee9ecdef451d..429e2ae7600d6 100644 --- a/src/test/ui/consts/const-err.stderr +++ b/src/test/ui/consts/const-err.stderr @@ -13,11 +13,17 @@ LL | #![warn(const_err)] | ^^^^^^^^^ error[E0080]: erroneous constant used - --> $DIR/const-err.rs:14:15 + --> $DIR/const-err.rs:14:16 | LL | black_box((FOO, FOO)); - | ^^^^^^^^^^ referenced constant has errors + | ^^^ referenced constant has errors -error: aborting due to previous error +error[E0080]: erroneous constant used + --> $DIR/const-err.rs:14:21 + | +LL | black_box((FOO, FOO)); + | ^^^ referenced constant has errors + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0080`. From cac07eba5355a4c29532b180e394333167e10c63 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Thu, 2 May 2019 08:48:08 -0400 Subject: [PATCH 23/33] Fix failing test --- src/test/ui/consts/const-err.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/ui/consts/const-err.rs b/src/test/ui/consts/const-err.rs index 8cc3dc7f58744..7dfcda69058ac 100644 --- a/src/test/ui/consts/const-err.rs +++ b/src/test/ui/consts/const-err.rs @@ -13,4 +13,5 @@ const FOO: u8 = [5u8][1]; fn main() { black_box((FOO, FOO)); //~^ ERROR erroneous constant used + //~| ERROR erroneous constant } From 8b82f685a57d6a1a3567c2ca6e77efedbedefac2 Mon Sep 17 00:00:00 2001 From: Alexey Shmalko Date: Mon, 29 Apr 2019 20:01:46 +0300 Subject: [PATCH 24/33] Make find_attr_val a little bit more precise `find_attr_val(&line, "since")` returns `Some(", issue = ")` when `line` is set to the following line: ``` [unstable(feature = "checked_duration_since", issue = "58402")] ``` Make `find_attr_val` use regex that is a little bit more precise (requires `=` after key name). It still does not handle all cases (e.g., extra leading chars in key name, or escaped quotes in value), but is good enough for now. --- Cargo.lock | 1 + src/tools/tidy/Cargo.toml | 1 + src/tools/tidy/src/features.rs | 19 +++++++++++++++---- src/tools/tidy/src/lib.rs | 1 + 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fd6a7a5604edf..79ef359bdac5f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3565,6 +3565,7 @@ dependencies = [ name = "tidy" version = "0.1.0" dependencies = [ + "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml index f7b491823f838..f5db2487618d6 100644 --- a/src/tools/tidy/Cargo.toml +++ b/src/tools/tidy/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors = ["Alex Crichton "] [dependencies] +regex = "1" serde = "1.0.8" serde_derive = "1.0.8" serde_json = "1.0.2" diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index 8239fd9dce0c1..f2b17c7471109 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -14,6 +14,8 @@ use std::fs::{self, File}; use std::io::prelude::*; use std::path::Path; +use regex::{Regex, escape}; + #[derive(Debug, PartialEq, Clone)] pub enum Status { Stable, @@ -151,10 +153,19 @@ pub fn check(path: &Path, bad: &mut bool, quiet: bool) { } fn find_attr_val<'a>(line: &'a str, attr: &str) -> Option<&'a str> { - line.find(attr) - .and_then(|i| line[i..].find('"').map(|j| i + j + 1)) - .and_then(|i| line[i..].find('"').map(|j| (i, i + j))) - .map(|(i, j)| &line[i..j]) + let r = Regex::new(&format!(r#"{} *= *"([^"]*)""#, escape(attr))) + .expect("malformed regex for find_attr_val"); + r.captures(line) + .and_then(|c| c.get(1)) + .map(|m| m.as_str()) +} + +#[test] +fn test_find_attr_val() { + let s = r#"#[unstable(feature = "checked_duration_since", issue = "58402")]"#; + assert_eq!(find_attr_val(s, "feature"), Some("checked_duration_since")); + assert_eq!(find_attr_val(s, "issue"), Some("58402")); + assert_eq!(find_attr_val(s, "since"), None); } fn test_filen_gate(filen_underscore: &str, features: &mut Features) -> bool { diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index c4a1246ffdf55..30080452edc01 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -5,6 +5,7 @@ #![deny(rust_2018_idioms)] +extern crate regex; extern crate serde_json; #[macro_use] extern crate serde_derive; From b7f55ca238a70f6738b14f1fded0fb9a47957343 Mon Sep 17 00:00:00 2001 From: Alexey Shmalko Date: Mon, 29 Apr 2019 20:39:55 +0300 Subject: [PATCH 25/33] Assign group and parse since for Feature --- src/tools/tidy/src/features.rs | 62 +++++++++++++++++++----- src/tools/tidy/src/features/version.rs | 66 ++++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 11 deletions(-) create mode 100644 src/tools/tidy/src/features/version.rs diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index f2b17c7471109..fe2aa0fd70fe3 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -16,6 +16,12 @@ use std::path::Path; use regex::{Regex, escape}; +mod version; +use self::version::Version; + +const FEATURE_GROUP_START_PREFIX: &str = "// feature group start:"; +const FEATURE_GROUP_END_PREFIX: &str = "// feature group end"; + #[derive(Debug, PartialEq, Clone)] pub enum Status { Stable, @@ -37,9 +43,10 @@ impl fmt::Display for Status { #[derive(Debug, Clone)] pub struct Feature { pub level: Status, - pub since: String, + pub since: Option, pub has_gate_test: bool, pub tracking_issue: Option, + pub group: Option, } pub type Features = HashMap; @@ -136,14 +143,16 @@ pub fn check(path: &Path, bad: &mut bool, quiet: bool) { name, "lang", feature.level, - feature.since)); + feature.since.as_ref().map_or("None".to_owned(), + |since| since.to_string()))); } for (name, feature) in lib_features { lines.push(format!("{:<32} {:<8} {:<12} {:<8}", name, "lib", feature.level, - feature.since)); + feature.since.as_ref().map_or("None".to_owned(), + |since| since.to_string()))); } lines.sort(); @@ -188,6 +197,8 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { // without one inside `// no tracking issue START` and `// no tracking issue END`. let mut next_feature_omits_tracking_issue = false; + let mut next_feature_group = None; + contents.lines().zip(1..) .filter_map(|(line, line_number)| { let line = line.trim(); @@ -205,6 +216,15 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { _ => {} } + if line.starts_with(FEATURE_GROUP_START_PREFIX) { + let group = line.trim_start_matches(FEATURE_GROUP_START_PREFIX).trim(); + next_feature_group = Some(group.to_owned()); + return None; + } else if line.starts_with(FEATURE_GROUP_END_PREFIX) { + next_feature_group = None; + return None; + } + let mut parts = line.split(','); let level = match parts.next().map(|l| l.trim().trim_start_matches('(')) { Some("active") => Status::Unstable, @@ -213,7 +233,20 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { _ => return None, }; let name = parts.next().unwrap().trim(); - let since = parts.next().unwrap().trim().trim_matches('"'); + let since_str = parts.next().unwrap().trim().trim_matches('"'); + let since = match since_str.parse() { + Ok(since) => Some(since), + Err(err) => { + tidy_error!( + bad, + "libsyntax/feature_gate.rs:{}: failed to parse since: {} ({})", + line_number, + since_str, + err, + ); + None + } + }; let issue_str = parts.next().unwrap().trim(); let tracking_issue = if issue_str.starts_with("None") { if level == Status::Unstable && !next_feature_omits_tracking_issue { @@ -233,9 +266,10 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { Some((name.to_owned(), Feature { level, - since: since.to_owned(), + since, has_gate_test: false, tracking_issue, + group: next_feature_group.clone(), })) }) .collect() @@ -250,9 +284,10 @@ pub fn collect_lib_features(base_src_path: &Path) -> Features { // add it to the set of known library features so we can still generate docs. lib_features.insert("compiler_builtins_lib".to_owned(), Feature { level: Status::Unstable, - since: String::new(), + since: None, has_gate_test: false, tracking_issue: None, + group: None, }); map_lib_features(base_src_path, @@ -351,12 +386,13 @@ fn map_lib_features(base_src_path: &Path, }; let feature = Feature { level: Status::Unstable, - since: "None".to_owned(), + since: None, has_gate_test: false, // FIXME(#57563): #57563 is now used as a common tracking issue, // although we would like to have specific tracking issues for each // `rustc_const_unstable` in the future. tracking_issue: Some(57563), + group: None, }; mf(Ok((feature_name, feature)), file, i + 1); continue; @@ -372,20 +408,24 @@ fn map_lib_features(base_src_path: &Path, Some(name) => name, None => err!("malformed stability attribute"), }; - let since = match find_attr_val(line, "since") { - Some(name) => name, + let since = match find_attr_val(line, "since").map(|x| x.parse()) { + Some(Ok(since)) => Some(since), + Some(Err(_err)) => { + err!("malformed since attribute"); + }, None if level == Status::Stable => { err!("malformed stability attribute"); } - None => "None", + None => None, }; let tracking_issue = find_attr_val(line, "issue").map(|s| s.parse().unwrap()); let feature = Feature { level, - since: since.to_owned(), + since, has_gate_test: false, tracking_issue, + group: None, }; if line.contains(']') { mf(Ok((feature_name, feature)), file, i + 1); diff --git a/src/tools/tidy/src/features/version.rs b/src/tools/tidy/src/features/version.rs new file mode 100644 index 0000000000000..0bab1427be849 --- /dev/null +++ b/src/tools/tidy/src/features/version.rs @@ -0,0 +1,66 @@ +use std::str::FromStr; +use std::num::ParseIntError; +use std::fmt; + +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct Version { + parts: Vec, +} + +impl fmt::Display for Version { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let x = self.parts.iter().map(|x| x.to_string()).collect::>().join("."); + f.pad(&x) + } +} + +impl FromStr for Version { + type Err = ParseIntError; + + fn from_str(s: &str) -> Result { + let parts = s.split('.').map(|part| part.parse()).collect::>()?; + Ok(Version { parts }) + } +} + +#[cfg(test)] +mod test { + use super::Version; + + #[test] + fn test_try_from_invalid_version() { + assert!("".parse::().is_err()); + assert!("hello".parse::().is_err()); + assert!("1.32.hi".parse::().is_err()); + assert!("1.32..1".parse::().is_err()); + } + + #[test] + fn test_try_from_single() { + assert_eq!("1.32.0".parse(), Ok(Version { parts: vec![1, 32, 0] })); + assert_eq!("1.0.0".parse(), Ok(Version { parts: vec![1, 0, 0] })); + } + + #[test] + fn test_compare() { + let v_1_0_0 = "1.0.0".parse::().unwrap(); + let v_1_32 = "1.32".parse::().unwrap(); + let v_1_32_1 = "1.32.1".parse::().unwrap(); + assert!(v_1_0_0 < v_1_32_1); + assert!(v_1_0_0 < v_1_32); + assert!(v_1_32 < v_1_32_1); + } + + #[test] + fn test_to_string() { + let v_1_0_0 = "1.0.0".parse::().unwrap(); + let v_1_32 = "1.32".parse::().unwrap(); + let v_1_32_1 = "1.32.1".parse::().unwrap(); + + assert_eq!(v_1_0_0.to_string(), "1.0.0"); + assert_eq!(v_1_32.to_string(), "1.32"); + assert_eq!(v_1_32_1.to_string(), "1.32.1"); + assert_eq!(format!("{:<8}", v_1_32_1), "1.32.1 "); + assert_eq!(format!("{:>8}", v_1_32_1), " 1.32.1"); + } +} From d5ba6d4b3cef4f7f54295d3a475411cedf1254fb Mon Sep 17 00:00:00 2001 From: Alexey Shmalko Date: Mon, 29 Apr 2019 20:51:19 +0300 Subject: [PATCH 26/33] Ensure language features in group are sorted by since --- src/tools/tidy/src/features.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index fe2aa0fd70fe3..d014c43f3b3f2 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -7,6 +7,7 @@ //! * Library features have at most one stability level. //! * Library features have at most one `since` value. //! * All unstable lang features have tests to ensure they are actually unstable. +//! * Language features in a group are sorted by `since` value. use std::collections::HashMap; use std::fmt; @@ -198,6 +199,7 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { let mut next_feature_omits_tracking_issue = false; let mut next_feature_group = None; + let mut prev_since = None; contents.lines().zip(1..) .filter_map(|(line, line_number)| { @@ -219,9 +221,11 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { if line.starts_with(FEATURE_GROUP_START_PREFIX) { let group = line.trim_start_matches(FEATURE_GROUP_START_PREFIX).trim(); next_feature_group = Some(group.to_owned()); + prev_since = None; return None; } else if line.starts_with(FEATURE_GROUP_END_PREFIX) { next_feature_group = None; + prev_since = None; return None; } @@ -233,6 +237,7 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { _ => return None, }; let name = parts.next().unwrap().trim(); + let since_str = parts.next().unwrap().trim().trim_matches('"'); let since = match since_str.parse() { Ok(since) => Some(since), @@ -247,6 +252,18 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { None } }; + if next_feature_group.is_some() { + if prev_since > since { + tidy_error!( + bad, + "libsyntax/feature_gate.rs:{}: feature {} is not sorted by since", + line_number, + name, + ); + } + prev_since = since.clone(); + } + let issue_str = parts.next().unwrap().trim(); let tracking_issue = if issue_str.starts_with("None") { if level == Status::Unstable && !next_feature_omits_tracking_issue { From d54477e97415c8c4931533f98ebf2704cd60e9b4 Mon Sep 17 00:00:00 2001 From: Alexey Shmalko Date: Wed, 1 May 2019 22:01:01 +0300 Subject: [PATCH 27/33] Address review comments --- src/tools/tidy/src/features.rs | 57 +++++++++++++++++----------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index d014c43f3b3f2..c7a109e050987 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -20,8 +20,8 @@ use regex::{Regex, escape}; mod version; use self::version::Version; -const FEATURE_GROUP_START_PREFIX: &str = "// feature group start:"; -const FEATURE_GROUP_END_PREFIX: &str = "// feature group end"; +const FEATURE_GROUP_START_PREFIX: &str = "// feature-group-start:"; +const FEATURE_GROUP_END_PREFIX: &str = "// feature-group-end"; #[derive(Debug, PartialEq, Clone)] pub enum Status { @@ -47,7 +47,6 @@ pub struct Feature { pub since: Option, pub has_gate_test: bool, pub tracking_issue: Option, - pub group: Option, } pub type Features = HashMap; @@ -139,22 +138,8 @@ pub fn check(path: &Path, bad: &mut bool, quiet: bool) { } let mut lines = Vec::new(); - for (name, feature) in features.iter() { - lines.push(format!("{:<32} {:<8} {:<12} {:<8}", - name, - "lang", - feature.level, - feature.since.as_ref().map_or("None".to_owned(), - |since| since.to_string()))); - } - for (name, feature) in lib_features { - lines.push(format!("{:<32} {:<8} {:<12} {:<8}", - name, - "lib", - feature.level, - feature.since.as_ref().map_or("None".to_owned(), - |since| since.to_string()))); - } + lines.extend(format_features(&features, "lang")); + lines.extend(format_features(&lib_features, "lib")); lines.sort(); for line in lines { @@ -162,8 +147,19 @@ pub fn check(path: &Path, bad: &mut bool, quiet: bool) { } } +fn format_features<'a>(features: &'a Features, family: &'a str) -> impl Iterator + 'a { + features.iter().map(move |(name, feature)| { + format!("{:<32} {:<8} {:<12} {:<8}", + name, + family, + feature.level, + feature.since.as_ref().map_or("None".to_owned(), + |since| since.to_string())) + }) +} + fn find_attr_val<'a>(line: &'a str, attr: &str) -> Option<&'a str> { - let r = Regex::new(&format!(r#"{} *= *"([^"]*)""#, escape(attr))) + let r = Regex::new(&format!(r#"{}\s*=\s*"([^"]*)""#, escape(attr))) .expect("malformed regex for find_attr_val"); r.captures(line) .and_then(|c| c.get(1)) @@ -219,6 +215,15 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { } if line.starts_with(FEATURE_GROUP_START_PREFIX) { + if next_feature_group.is_some() { + tidy_error!( + bad, + // ignore-tidy-linelength + "libsyntax/feature_gate.rs:{}: new feature group is started without ending the previous one", + line_number, + ); + } + let group = line.trim_start_matches(FEATURE_GROUP_START_PREFIX).trim(); next_feature_group = Some(group.to_owned()); prev_since = None; @@ -286,7 +291,6 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { since, has_gate_test: false, tracking_issue, - group: next_feature_group.clone(), })) }) .collect() @@ -304,7 +308,6 @@ pub fn collect_lib_features(base_src_path: &Path) -> Features { since: None, has_gate_test: false, tracking_issue: None, - group: None, }); map_lib_features(base_src_path, @@ -399,7 +402,7 @@ fn map_lib_features(base_src_path: &Path, // `const fn` features are handled specially. let feature_name = match find_attr_val(line, "feature") { Some(name) => name, - None => err!("malformed stability attribute"), + None => err!("malformed stability attribute: missing `feature` key"), }; let feature = Feature { level: Status::Unstable, @@ -409,7 +412,6 @@ fn map_lib_features(base_src_path: &Path, // although we would like to have specific tracking issues for each // `rustc_const_unstable` in the future. tracking_issue: Some(57563), - group: None, }; mf(Ok((feature_name, feature)), file, i + 1); continue; @@ -423,15 +425,15 @@ fn map_lib_features(base_src_path: &Path, }; let feature_name = match find_attr_val(line, "feature") { Some(name) => name, - None => err!("malformed stability attribute"), + None => err!("malformed stability attribute: missing `feature` key"), }; let since = match find_attr_val(line, "since").map(|x| x.parse()) { Some(Ok(since)) => Some(since), Some(Err(_err)) => { - err!("malformed since attribute"); + err!("malformed stability attribute: can't parse `since` key"); }, None if level == Status::Stable => { - err!("malformed stability attribute"); + err!("malformed stability attribute: missing the `since` key"); } None => None, }; @@ -442,7 +444,6 @@ fn map_lib_features(base_src_path: &Path, since, has_gate_test: false, tracking_issue, - group: None, }; if line.contains(']') { mf(Ok((feature_name, feature)), file, i + 1); From 90d3fa223d82cee5430c71d117b6be2922a256b3 Mon Sep 17 00:00:00 2001 From: Alexey Shmalko Date: Wed, 1 May 2019 22:15:00 +0300 Subject: [PATCH 28/33] Make tidy::version::Version a [u32; 3] --- src/libstd/sys/redox/ext/net.rs | 82 +++++++++++++------------- src/tools/tidy/src/features.rs | 2 +- src/tools/tidy/src/features/version.rs | 38 ++++++++---- 3 files changed, 69 insertions(+), 53 deletions(-) diff --git a/src/libstd/sys/redox/ext/net.rs b/src/libstd/sys/redox/ext/net.rs index 096d0681959cd..b3ef5f3064c16 100644 --- a/src/libstd/sys/redox/ext/net.rs +++ b/src/libstd/sys/redox/ext/net.rs @@ -1,4 +1,4 @@ -#![stable(feature = "unix_socket_redox", since = "1.29")] +#![stable(feature = "unix_socket_redox", since = "1.29.0")] //! Unix-specific networking functionality @@ -27,7 +27,7 @@ use crate::sys::{cvt, fd::FileDesc, syscall}; /// let addr = socket.local_addr().expect("Couldn't get local address"); /// ``` #[derive(Clone)] -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] pub struct SocketAddr(()); impl SocketAddr { @@ -55,7 +55,7 @@ impl SocketAddr { /// let addr = socket.local_addr().expect("Couldn't get local address"); /// assert_eq!(addr.as_pathname(), None); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn as_pathname(&self) -> Option<&Path> { None } @@ -83,12 +83,12 @@ impl SocketAddr { /// let addr = socket.local_addr().expect("Couldn't get local address"); /// assert_eq!(addr.is_unnamed(), true); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn is_unnamed(&self) -> bool { false } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl fmt::Debug for SocketAddr { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { write!(fmt, "SocketAddr") @@ -109,10 +109,10 @@ impl fmt::Debug for SocketAddr { /// stream.read_to_string(&mut response).unwrap(); /// println!("{}", response); /// ``` -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] pub struct UnixStream(FileDesc); -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl fmt::Debug for UnixStream { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { let mut builder = fmt.debug_struct("UnixStream"); @@ -143,7 +143,7 @@ impl UnixStream { /// } /// }; /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn connect>(path: P) -> io::Result { if let Some(s) = path.as_ref().to_str() { cvt(syscall::open(format!("chan:{}", s), syscall::O_CLOEXEC)) @@ -174,7 +174,7 @@ impl UnixStream { /// } /// }; /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn pair() -> io::Result<(UnixStream, UnixStream)> { let server = cvt(syscall::open("chan:", syscall::O_CREAT | syscall::O_CLOEXEC)) .map(FileDesc::new)?; @@ -198,7 +198,7 @@ impl UnixStream { /// let socket = UnixStream::connect("/tmp/sock").unwrap(); /// let sock_copy = socket.try_clone().expect("Couldn't clone socket"); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn try_clone(&self) -> io::Result { self.0.duplicate().map(UnixStream) } @@ -213,7 +213,7 @@ impl UnixStream { /// let socket = UnixStream::connect("/tmp/sock").unwrap(); /// let addr = socket.local_addr().expect("Couldn't get local address"); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn local_addr(&self) -> io::Result { Err(Error::new(ErrorKind::Other, "UnixStream::local_addr unimplemented on redox")) } @@ -228,7 +228,7 @@ impl UnixStream { /// let socket = UnixStream::connect("/tmp/sock").unwrap(); /// let addr = socket.peer_addr().expect("Couldn't get peer address"); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn peer_addr(&self) -> io::Result { Err(Error::new(ErrorKind::Other, "UnixStream::peer_addr unimplemented on redox")) } @@ -267,7 +267,7 @@ impl UnixStream { /// let err = result.unwrap_err(); /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn set_read_timeout(&self, _timeout: Option) -> io::Result<()> { Err(Error::new(ErrorKind::Other, "UnixStream::set_read_timeout unimplemented on redox")) } @@ -306,7 +306,7 @@ impl UnixStream { /// let err = result.unwrap_err(); /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn set_write_timeout(&self, _timeout: Option) -> io::Result<()> { Err(Error::new(ErrorKind::Other, "UnixStream::set_write_timeout unimplemented on redox")) } @@ -323,7 +323,7 @@ impl UnixStream { /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); /// assert_eq!(socket.read_timeout().unwrap(), Some(Duration::new(1, 0))); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn read_timeout(&self) -> io::Result> { Err(Error::new(ErrorKind::Other, "UnixStream::read_timeout unimplemented on redox")) } @@ -340,7 +340,7 @@ impl UnixStream { /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); /// assert_eq!(socket.write_timeout().unwrap(), Some(Duration::new(1, 0))); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn write_timeout(&self) -> io::Result> { Err(Error::new(ErrorKind::Other, "UnixStream::write_timeout unimplemented on redox")) } @@ -355,7 +355,7 @@ impl UnixStream { /// let socket = UnixStream::connect("/tmp/sock").unwrap(); /// socket.set_nonblocking(true).expect("Couldn't set nonblocking"); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { self.0.set_nonblocking(nonblocking) } @@ -375,7 +375,7 @@ impl UnixStream { /// /// # Platform specific /// On Redox this always returns `None`. - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn take_error(&self) -> io::Result> { Ok(None) } @@ -397,13 +397,13 @@ impl UnixStream { /// let socket = UnixStream::connect("/tmp/sock").unwrap(); /// socket.shutdown(Shutdown::Both).expect("shutdown function failed"); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn shutdown(&self, _how: Shutdown) -> io::Result<()> { Err(Error::new(ErrorKind::Other, "UnixStream::shutdown unimplemented on redox")) } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl io::Read for UnixStream { fn read(&mut self, buf: &mut [u8]) -> io::Result { io::Read::read(&mut &*self, buf) @@ -415,7 +415,7 @@ impl io::Read for UnixStream { } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl<'a> io::Read for &'a UnixStream { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) @@ -427,7 +427,7 @@ impl<'a> io::Read for &'a UnixStream { } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl io::Write for UnixStream { fn write(&mut self, buf: &[u8]) -> io::Result { io::Write::write(&mut &*self, buf) @@ -438,7 +438,7 @@ impl io::Write for UnixStream { } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl<'a> io::Write for &'a UnixStream { fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) @@ -449,21 +449,21 @@ impl<'a> io::Write for &'a UnixStream { } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl AsRawFd for UnixStream { fn as_raw_fd(&self) -> RawFd { self.0.raw() } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl FromRawFd for UnixStream { unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { UnixStream(FileDesc::new(fd)) } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl IntoRawFd for UnixStream { fn into_raw_fd(self) -> RawFd { self.0.into_raw() @@ -498,10 +498,10 @@ impl IntoRawFd for UnixStream { /// } /// } /// ``` -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] pub struct UnixListener(FileDesc); -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl fmt::Debug for UnixListener { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { let mut builder = fmt.debug_struct("UnixListener"); @@ -529,7 +529,7 @@ impl UnixListener { /// } /// }; /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn bind>(path: P) -> io::Result { if let Some(s) = path.as_ref().to_str() { cvt(syscall::open(format!("chan:{}", s), syscall::O_CREAT | syscall::O_CLOEXEC)) @@ -563,7 +563,7 @@ impl UnixListener { /// Err(e) => println!("accept function failed: {:?}", e), /// } /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { self.0.duplicate_path(b"listen").map(|fd| (UnixStream(fd), SocketAddr(()))) } @@ -583,7 +583,7 @@ impl UnixListener { /// /// let listener_copy = listener.try_clone().expect("try_clone failed"); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn try_clone(&self) -> io::Result { self.0.duplicate().map(UnixListener) } @@ -599,7 +599,7 @@ impl UnixListener { /// /// let addr = listener.local_addr().expect("Couldn't get local address"); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn local_addr(&self) -> io::Result { Err(Error::new(ErrorKind::Other, "UnixListener::local_addr unimplemented on redox")) } @@ -615,7 +615,7 @@ impl UnixListener { /// /// listener.set_nonblocking(true).expect("Couldn't set non blocking"); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { self.0.set_nonblocking(nonblocking) } @@ -636,7 +636,7 @@ impl UnixListener { /// /// # Platform specific /// On Redox this always returns `None`. - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn take_error(&self) -> io::Result> { Ok(None) } @@ -672,34 +672,34 @@ impl UnixListener { /// } /// } /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn incoming<'a>(&'a self) -> Incoming<'a> { Incoming { listener: self } } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl AsRawFd for UnixListener { fn as_raw_fd(&self) -> RawFd { self.0.raw() } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl FromRawFd for UnixListener { unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { UnixListener(FileDesc::new(fd)) } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl IntoRawFd for UnixListener { fn into_raw_fd(self) -> RawFd { self.0.into_raw() } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl<'a> IntoIterator for &'a UnixListener { type Item = io::Result; type IntoIter = Incoming<'a>; @@ -740,12 +740,12 @@ impl<'a> IntoIterator for &'a UnixListener { /// } /// ``` #[derive(Debug)] -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] pub struct Incoming<'a> { listener: &'a UnixListener, } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl<'a> Iterator for Incoming<'a> { type Item = io::Result; diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index c7a109e050987..afadedd8b6bbb 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -249,7 +249,7 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { Err(err) => { tidy_error!( bad, - "libsyntax/feature_gate.rs:{}: failed to parse since: {} ({})", + "libsyntax/feature_gate.rs:{}: failed to parse since: {} ({:?})", line_number, since_str, err, diff --git a/src/tools/tidy/src/features/version.rs b/src/tools/tidy/src/features/version.rs index 0bab1427be849..7ea788a85180b 100644 --- a/src/tools/tidy/src/features/version.rs +++ b/src/tools/tidy/src/features/version.rs @@ -1,10 +1,11 @@ use std::str::FromStr; use std::num::ParseIntError; use std::fmt; +use std::convert::TryInto; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct Version { - parts: Vec, + parts: [u32; 3], } impl fmt::Display for Version { @@ -14,12 +15,27 @@ impl fmt::Display for Version { } } +#[derive(Debug, PartialEq, Eq)] +pub enum ParseVersionError { + ParseIntError(ParseIntError), + // core::array::TryFromSlice is not exported from std, so we invent our own variant + WrongNumberOfParts +} + +impl From for ParseVersionError { + fn from(err: ParseIntError) -> Self { + ParseVersionError::ParseIntError(err) + } +} + impl FromStr for Version { - type Err = ParseIntError; + type Err = ParseVersionError; fn from_str(s: &str) -> Result { - let parts = s.split('.').map(|part| part.parse()).collect::>()?; - Ok(Version { parts }) + let parts: Vec<_> = s.split('.').map(|part| part.parse()).collect::>()?; + Ok(Self { + parts: parts.as_slice().try_into() .or(Err(ParseVersionError::WrongNumberOfParts))?, + }) } } @@ -33,32 +49,32 @@ mod test { assert!("hello".parse::().is_err()); assert!("1.32.hi".parse::().is_err()); assert!("1.32..1".parse::().is_err()); + assert!("1.32".parse::().is_err()); + assert!("1.32.0.1".parse::().is_err()); } #[test] fn test_try_from_single() { - assert_eq!("1.32.0".parse(), Ok(Version { parts: vec![1, 32, 0] })); - assert_eq!("1.0.0".parse(), Ok(Version { parts: vec![1, 0, 0] })); + assert_eq!("1.32.0".parse(), Ok(Version { parts: [1, 32, 0] })); + assert_eq!("1.0.0".parse(), Ok(Version { parts: [1, 0, 0] })); } #[test] fn test_compare() { let v_1_0_0 = "1.0.0".parse::().unwrap(); - let v_1_32 = "1.32".parse::().unwrap(); + let v_1_32_0 = "1.32.0".parse::().unwrap(); let v_1_32_1 = "1.32.1".parse::().unwrap(); assert!(v_1_0_0 < v_1_32_1); - assert!(v_1_0_0 < v_1_32); - assert!(v_1_32 < v_1_32_1); + assert!(v_1_0_0 < v_1_32_0); + assert!(v_1_32_0 < v_1_32_1); } #[test] fn test_to_string() { let v_1_0_0 = "1.0.0".parse::().unwrap(); - let v_1_32 = "1.32".parse::().unwrap(); let v_1_32_1 = "1.32.1".parse::().unwrap(); assert_eq!(v_1_0_0.to_string(), "1.0.0"); - assert_eq!(v_1_32.to_string(), "1.32"); assert_eq!(v_1_32_1.to_string(), "1.32.1"); assert_eq!(format!("{:<8}", v_1_32_1), "1.32.1 "); assert_eq!(format!("{:>8}", v_1_32_1), " 1.32.1"); From 3b4fe7ef37c3ff2afcfda8577f010d3fe926bde5 Mon Sep 17 00:00:00 2001 From: Alexey Shmalko Date: Wed, 1 May 2019 22:42:57 +0300 Subject: [PATCH 29/33] Group and sort feature_gate.rs --- src/libsyntax/feature_gate.rs | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 012fcbdd8c8e2..2a1f3c4801406 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -109,15 +109,14 @@ macro_rules! declare_features { // stable (active). // // Note that the features should be grouped into internal/user-facing -// and then sorted by version inside those groups. -// FIXME(60361): Enforce ^-- with tidy. +// and then sorted by version inside those groups. This is inforced with tidy. // // N.B., `tools/tidy/src/features.rs` parses this information directly out of the // source, so take care when modifying it. declare_features! ( // ------------------------------------------------------------------------- - // Internal feature gates. + // feature-group-start: internal feature gates // ------------------------------------------------------------------------- // no tracking issue START @@ -211,12 +210,12 @@ declare_features! ( // no tracking issue END - // Allows using the `may_dangle` attribute (RFC 1327). - (active, dropck_eyepatch, "1.10.0", Some(34761), None), - // Allows using `#[structural_match]` which indicates that a type is structurally matchable. (active, structural_match, "1.8.0", Some(31434), None), + // Allows using the `may_dangle` attribute (RFC 1327). + (active, dropck_eyepatch, "1.10.0", Some(34761), None), + // Allows using the `#![panic_runtime]` attribute. (active, panic_runtime, "1.10.0", Some(32837), None), @@ -252,7 +251,11 @@ declare_features! ( (active, test_2018_feature, "1.31.0", Some(0), Some(Edition::Edition2018)), // ------------------------------------------------------------------------- - // Actual feature gates (target features). + // feature-group-end: internal feature gates + // ------------------------------------------------------------------------- + + // ------------------------------------------------------------------------- + // feature-group-start: actual feature gates (target features) // ------------------------------------------------------------------------- // FIXME: Document these and merge with the list below. @@ -275,7 +278,11 @@ declare_features! ( (active, f16c_target_feature, "1.36.0", Some(44839), None), // ------------------------------------------------------------------------- - // Actual feature gates. + // feature-group-end: actual feature gates (target features) + // ------------------------------------------------------------------------- + + // ------------------------------------------------------------------------- + // feature-group-start: actual feature gates // ------------------------------------------------------------------------- // Allows using `asm!` macro with which inline assembly can be embedded. @@ -340,9 +347,6 @@ declare_features! ( // Permits specifying whether a function should permit unwinding or abort on unwind. (active, unwind_attributes, "1.4.0", Some(58760), None), - // Allows using `#[naked]` on functions. - (active, naked_functions, "1.9.0", Some(32408), None), - // Allows `#[no_debug]`. (active, no_debug, "1.5.0", Some(29721), None), @@ -358,6 +362,9 @@ declare_features! ( // Allows specialization of implementations (RFC 1210). (active, specialization, "1.7.0", Some(31844), None), + // Allows using `#[naked]` on functions. + (active, naked_functions, "1.9.0", Some(32408), None), + // Allows `cfg(target_has_atomic = "...")`. (active, cfg_target_has_atomic, "1.9.0", Some(32976), None), @@ -545,6 +552,10 @@ declare_features! ( // Allows using C-variadics. (active, c_variadic, "1.34.0", Some(44930), None), + + // ------------------------------------------------------------------------- + // feature-group-end: actual feature gates + // ------------------------------------------------------------------------- ); // Some features are known to be incomplete and using them is likely to have From c120fd823ba1cbd78167f0f3dca32b68d9f2308a Mon Sep 17 00:00:00 2001 From: Alexey Shmalko Date: Thu, 2 May 2019 00:52:44 +0300 Subject: [PATCH 30/33] Rework Version::parse to avoid extra allocations --- src/tools/tidy/src/features.rs | 2 +- src/tools/tidy/src/features/version.rs | 28 +++++++++++++++++--------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index afadedd8b6bbb..48ecbe3380745 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -147,7 +147,7 @@ pub fn check(path: &Path, bad: &mut bool, quiet: bool) { } } -fn format_features<'a>(features: &'a Features, family: &'a str) -> impl Iterator + 'a { +fn format_features<'a>(features: &'a Features, family: &'a str) -> impl Iterator + 'a { features.iter().map(move |(name, feature)| { format!("{:<32} {:<8} {:<12} {:<8}", name, diff --git a/src/tools/tidy/src/features/version.rs b/src/tools/tidy/src/features/version.rs index 7ea788a85180b..8d1ebccbff670 100644 --- a/src/tools/tidy/src/features/version.rs +++ b/src/tools/tidy/src/features/version.rs @@ -1,7 +1,6 @@ use std::str::FromStr; use std::num::ParseIntError; use std::fmt; -use std::convert::TryInto; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct Version { @@ -10,16 +9,14 @@ pub struct Version { impl fmt::Display for Version { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let x = self.parts.iter().map(|x| x.to_string()).collect::>().join("."); - f.pad(&x) + f.pad(&format!("{}.{}.{}", self.parts[0], self.parts[1], self.parts[2])) } } #[derive(Debug, PartialEq, Eq)] pub enum ParseVersionError { ParseIntError(ParseIntError), - // core::array::TryFromSlice is not exported from std, so we invent our own variant - WrongNumberOfParts + WrongNumberOfParts, } impl From for ParseVersionError { @@ -32,10 +29,23 @@ impl FromStr for Version { type Err = ParseVersionError; fn from_str(s: &str) -> Result { - let parts: Vec<_> = s.split('.').map(|part| part.parse()).collect::>()?; - Ok(Self { - parts: parts.as_slice().try_into() .or(Err(ParseVersionError::WrongNumberOfParts))?, - }) + let mut iter = s.split('.').map(|part| Ok(part.parse()?)); + + let parts = { + let mut part = || { + iter.next() + .unwrap_or(Err(ParseVersionError::WrongNumberOfParts)) + }; + + [part()?, part()?, part()?] + }; + + if let Some(_) = iter.next() { + // Ensure we don't have more than 3 parts. + return Err(ParseVersionError::WrongNumberOfParts); + } + + Ok(Self { parts }) } } From 4bcc828b9ca7611ecb1200056bab5fc6d805fd99 Mon Sep 17 00:00:00 2001 From: Alexey Shmalko Date: Thu, 2 May 2019 14:30:30 +0300 Subject: [PATCH 31/33] Make in_feature_group a simple bool flag --- src/tools/tidy/src/features.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index 48ecbe3380745..63731a0cb056b 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -20,7 +20,7 @@ use regex::{Regex, escape}; mod version; use self::version::Version; -const FEATURE_GROUP_START_PREFIX: &str = "// feature-group-start:"; +const FEATURE_GROUP_START_PREFIX: &str = "// feature-group-start"; const FEATURE_GROUP_END_PREFIX: &str = "// feature-group-end"; #[derive(Debug, PartialEq, Clone)] @@ -194,7 +194,7 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { // without one inside `// no tracking issue START` and `// no tracking issue END`. let mut next_feature_omits_tracking_issue = false; - let mut next_feature_group = None; + let mut in_feature_group = false; let mut prev_since = None; contents.lines().zip(1..) @@ -215,7 +215,7 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { } if line.starts_with(FEATURE_GROUP_START_PREFIX) { - if next_feature_group.is_some() { + if in_feature_group { tidy_error!( bad, // ignore-tidy-linelength @@ -224,12 +224,11 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { ); } - let group = line.trim_start_matches(FEATURE_GROUP_START_PREFIX).trim(); - next_feature_group = Some(group.to_owned()); + in_feature_group = true; prev_since = None; return None; } else if line.starts_with(FEATURE_GROUP_END_PREFIX) { - next_feature_group = None; + in_feature_group = false; prev_since = None; return None; } @@ -257,7 +256,7 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { None } }; - if next_feature_group.is_some() { + if in_feature_group { if prev_since > since { tidy_error!( bad, From 201f14b88b19d43615845bfc2a6de9bc31985b13 Mon Sep 17 00:00:00 2001 From: Alexey Shmalko Date: Thu, 2 May 2019 14:38:16 +0300 Subject: [PATCH 32/33] Make tidy::version::Version copy --- src/tools/tidy/src/features.rs | 6 +++--- src/tools/tidy/src/features/version.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index 63731a0cb056b..3144df6dd4cdf 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -153,8 +153,8 @@ fn format_features<'a>(features: &'a Features, family: &'a str) -> impl Iterator name, family, feature.level, - feature.since.as_ref().map_or("None".to_owned(), - |since| since.to_string())) + feature.since.map_or("None".to_owned(), + |since| since.to_string())) }) } @@ -265,7 +265,7 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { name, ); } - prev_since = since.clone(); + prev_since = since; } let issue_str = parts.next().unwrap().trim(); diff --git a/src/tools/tidy/src/features/version.rs b/src/tools/tidy/src/features/version.rs index 8d1ebccbff670..6027e7d35e28c 100644 --- a/src/tools/tidy/src/features/version.rs +++ b/src/tools/tidy/src/features/version.rs @@ -2,7 +2,7 @@ use std::str::FromStr; use std::num::ParseIntError; use std::fmt; -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct Version { parts: [u32; 3], } From d72f4de659341c281021ddd42c15705a63370bda Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Wed, 1 May 2019 21:15:01 +0100 Subject: [PATCH 33/33] Constrain all regions in the concrete type for an opaque type --- src/librustc/infer/opaque_types/mod.rs | 141 +++++++++++------- .../can-return-unconstrained-closure.rs | 19 +++ .../issue-55608-captures-empty-region.rs | 4 +- .../issue-55608-captures-empty-region.stderr | 11 -- .../issue-57464-unexpected-regions.rs | 22 +++ src/test/ui/issues/issue-49556.rs | 4 +- 6 files changed, 129 insertions(+), 72 deletions(-) create mode 100644 src/test/ui/impl-trait/can-return-unconstrained-closure.rs delete mode 100644 src/test/ui/impl-trait/issue-55608-captures-empty-region.stderr create mode 100644 src/test/ui/impl-trait/issue-57464-unexpected-regions.rs diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index b1d009146473f..072de3dd01316 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -1,13 +1,14 @@ +use rustc_data_structures::fx::FxHashMap; +use syntax_pos::Span; + use crate::hir::def_id::DefId; use crate::hir; use crate::hir::Node; use crate::infer::{self, InferCtxt, InferOk, TypeVariableOrigin}; use crate::infer::outlives::free_region_map::FreeRegionRelations; -use rustc_data_structures::fx::FxHashMap; use crate::traits::{self, PredicateObligation}; use crate::ty::{self, Ty, TyCtxt, GenericParamDefKind}; -use crate::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder}; -use crate::ty::outlives::Component; +use crate::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor}; use crate::ty::subst::{Kind, InternalSubsts, SubstsRef, UnpackedKind}; use crate::util::nodemap::DefIdMap; @@ -373,58 +374,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let least_region = least_region.unwrap_or(self.tcx.lifetimes.re_static); debug!("constrain_opaque_types: least_region={:?}", least_region); - // Require that the type `concrete_ty` outlives - // `least_region`, modulo any type parameters that appear - // in the type, which we ignore. This is because impl - // trait values are assumed to capture all the in-scope - // type parameters. This little loop here just invokes - // `outlives` repeatedly, draining all the nested - // obligations that result. - let mut types = vec![concrete_ty]; - let bound_region = |r| self.sub_regions(infer::CallReturn(span), least_region, r); - while let Some(ty) = types.pop() { - let mut components = smallvec![]; - self.tcx.push_outlives_components(ty, &mut components); - while let Some(component) = components.pop() { - match component { - Component::Region(r) => { - bound_region(r); - } - - Component::Param(_) => { - // ignore type parameters like `T`, they are captured - // implicitly by the `impl Trait` - } - - Component::UnresolvedInferenceVariable(_) => { - // we should get an error that more type - // annotations are needed in this case - self.tcx - .sess - .delay_span_bug(span, "unresolved inf var in opaque"); - } - - Component::Projection(ty::ProjectionTy { - substs, - item_def_id: _, - }) => { - for k in substs { - match k.unpack() { - UnpackedKind::Lifetime(lt) => bound_region(lt), - UnpackedKind::Type(ty) => types.push(ty), - UnpackedKind::Const(_) => { - // Const parameters don't impose constraints. - } - } - } - } - - Component::EscapingProjection(more_components) => { - components.extend(more_components); - } - } - } - } + concrete_ty.visit_with(&mut OpaqueTypeOutlivesVisitor { + infcx: self, + least_region, + span, + }); } /// Given the fully resolved, instantiated type for an opaque @@ -502,6 +456,80 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } +// Visitor that requires that (almost) all regions in the type visited outlive +// `least_region`. We cannot use `push_outlives_components` because regions in +// closure signatures are not included in their outlives components. We need to +// ensure all regions outlive the given bound so that we don't end up with, +// say, `ReScope` appearing in a return type and causing ICEs when other +// functions end up with region constraints involving regions from other +// functions. +// +// We also cannot use `for_each_free_region` because for closures it includes +// the regions parameters from the enclosing item. +// +// We ignore any type parameters because impl trait values are assumed to +// capture all the in-scope type parameters. +struct OpaqueTypeOutlivesVisitor<'a, 'gcx, 'tcx> { + infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + least_region: ty::Region<'tcx>, + span: Span, +} + +impl<'tcx> TypeVisitor<'tcx> for OpaqueTypeOutlivesVisitor<'_, '_, 'tcx> +{ + fn visit_binder>(&mut self, t: &ty::Binder) -> bool { + t.skip_binder().visit_with(self); + false // keep visiting + } + + fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { + match *r { + // ignore bound regions, keep visiting + ty::ReLateBound(_, _) => false, + _ => { + self.infcx.sub_regions(infer::CallReturn(self.span), self.least_region, r); + false + } + } + } + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { + // We're only interested in types involving regions + if !ty.flags.intersects(ty::TypeFlags::HAS_FREE_REGIONS) { + return false; // keep visiting + } + + match ty.sty { + ty::Closure(def_id, ref substs) => { + // Skip lifetime parameters of the enclosing item(s) + + for upvar_ty in substs.upvar_tys(def_id, self.infcx.tcx) { + upvar_ty.visit_with(self); + } + + substs.closure_sig_ty(def_id, self.infcx.tcx).visit_with(self); + } + + ty::Generator(def_id, ref substs, _) => { + // Skip lifetime parameters of the enclosing item(s) + // Also skip the witness type, because that has no free regions. + + for upvar_ty in substs.upvar_tys(def_id, self.infcx.tcx) { + upvar_ty.visit_with(self); + } + + substs.return_ty(def_id, self.infcx.tcx).visit_with(self); + substs.yield_ty(def_id, self.infcx.tcx).visit_with(self); + } + _ => { + ty.super_visit_with(self); + } + } + + false + } +} + struct ReverseMapper<'cx, 'gcx: 'tcx, 'tcx: 'cx> { tcx: TyCtxt<'cx, 'gcx, 'tcx>, @@ -563,8 +591,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for ReverseMapper<'cx, 'gcx, 'tcx> // ignore `'static`, as that can appear anywhere ty::ReStatic | - // ignore `ReScope`, as that can appear anywhere - // See `src/test/run-pass/issue-49556.rs` for example. + // ignore `ReScope`, which may appear in impl Trait in bindings. ty::ReScope(..) => return r, _ => { } diff --git a/src/test/ui/impl-trait/can-return-unconstrained-closure.rs b/src/test/ui/impl-trait/can-return-unconstrained-closure.rs new file mode 100644 index 0000000000000..a982b176ecda1 --- /dev/null +++ b/src/test/ui/impl-trait/can-return-unconstrained-closure.rs @@ -0,0 +1,19 @@ +// Test that we are special casing "outlives" for opaque types. +// +// The return type of a closure is not required to outlive the closure. As such +// the following code would not compile if we used a standard outlives check +// when checking the return type, because the return type of the closure would +// be `&ReEmpty i32`, and we don't allow `ReEmpty` to occur in the concrete +// type used for an opaque type. +// +// However, opaque types are special cased to include check all regions in the +// concrete type against the bound, which forces the return type to be +// `&'static i32` here. + +// compile-pass + +fn make_identity() -> impl Sized { + |x: &'static i32| x +} + +fn main() {} diff --git a/src/test/ui/impl-trait/issue-55608-captures-empty-region.rs b/src/test/ui/impl-trait/issue-55608-captures-empty-region.rs index 7ebc348996f5e..50646edd61a85 100644 --- a/src/test/ui/impl-trait/issue-55608-captures-empty-region.rs +++ b/src/test/ui/impl-trait/issue-55608-captures-empty-region.rs @@ -1,9 +1,9 @@ // This used to ICE because it creates an `impl Trait` that captures a // hidden empty region. -#![feature(conservative_impl_trait)] +// compile-pass -fn server() -> impl FilterBase2 { //~ ERROR [E0700] +fn server() -> impl FilterBase2 { segment2(|| { loop { } }).map2(|| "") } diff --git a/src/test/ui/impl-trait/issue-55608-captures-empty-region.stderr b/src/test/ui/impl-trait/issue-55608-captures-empty-region.stderr deleted file mode 100644 index 6311a7f00674f..0000000000000 --- a/src/test/ui/impl-trait/issue-55608-captures-empty-region.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/issue-55608-captures-empty-region.rs:6:16 - | -LL | fn server() -> impl FilterBase2 { - | ^^^^^^^^^^^^^^^^ - | - = note: hidden type `Map2<[closure@$DIR/issue-55608-captures-empty-region.rs:7:36: 7:41]>` captures an empty lifetime - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0700`. diff --git a/src/test/ui/impl-trait/issue-57464-unexpected-regions.rs b/src/test/ui/impl-trait/issue-57464-unexpected-regions.rs new file mode 100644 index 0000000000000..29e271c68ec90 --- /dev/null +++ b/src/test/ui/impl-trait/issue-57464-unexpected-regions.rs @@ -0,0 +1,22 @@ +// Regression test for issue 57464. +// +// Closure are (surprisingly) allowed to outlive their signature. As such it +// was possible to end up with `ReScope`s appearing in the concrete type of an +// opaque type. As all regions are now required to outlive the bound in an +// opaque type we avoid the issue here. + +// compile-pass + +struct A(F); + +unsafe impl <'a, 'b, F: Fn(&'a i32) -> &'b i32> Send for A {} + +fn wrapped_closure() -> impl Sized { + let f = |x| x; + f(&0); + A(f) +} + +fn main() { + let x: Box = Box::new(wrapped_closure()); +} diff --git a/src/test/ui/issues/issue-49556.rs b/src/test/ui/issues/issue-49556.rs index b8fcc645a59d3..46d9e749aae23 100644 --- a/src/test/ui/issues/issue-49556.rs +++ b/src/test/ui/issues/issue-49556.rs @@ -2,10 +2,10 @@ fn iter<'a>(data: &'a [usize]) -> impl Iterator + 'a { data.iter() .map( - |x| x // fn(&'a usize) -> &'(ReScope) usize + |x| x // fn(&'a usize) -> &'a usize ) .map( - |x| *x // fn(&'(ReScope) usize) -> usize + |x| *x // fn(&'a usize) -> usize ) }