From b78457f0fbe15c21dc28efaef8146a0ff9d58059 Mon Sep 17 00:00:00 2001 From: dylan_DPC Date: Sat, 2 Jun 2018 17:27:37 +0530 Subject: [PATCH 01/16] Stabilize unit tests with non-`()` return type --- src/libsyntax/feature_gate.rs | 6 +-- src/libsyntax/test.rs | 38 ++++--------------- .../feature-gate-termination_trait_test.rs | 22 ----------- .../termination-trait-in-test-should-panic.rs | 1 - .../termination-trait-in-test.rs | 1 - .../termination-trait-test-wrong-type.rs | 2 - 6 files changed, 10 insertions(+), 60 deletions(-) delete mode 100644 src/test/compile-fail/feature-gate-termination_trait_test.rs diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 9b84713b0f90f..ecda2b077e1f9 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -398,9 +398,6 @@ declare_features! ( // `foo.rs` as an alternative to `foo/mod.rs` (active, non_modrs_mods, "1.24.0", Some(44660), Some(Edition::Edition2018)), - // Termination trait in tests (RFC 1937) - (active, termination_trait_test, "1.24.0", Some(48854), Some(Edition::Edition2018)), - // `extern` in paths (active, extern_in_paths, "1.23.0", Some(44660), None), @@ -475,6 +472,9 @@ declare_features! ( // 'a: { break 'a; } (active, label_break_value, "1.28.0", Some(48594), None), + + // Termination trait in tests (RFC 1937) + (accepted, termination_trait_test, "1.28.0", Some(48854), Some(Edition::Edition2018)), ); declare_features! ( diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index e63a3d47a828f..5506f408cd269 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -351,15 +351,15 @@ fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool { return No(BadTestSignature::NoArgumentsAllowed); } - match (has_output, cx.features.termination_trait_test, has_should_panic_attr) { - (true, true, true) => No(BadTestSignature::ShouldPanicOnlyWithNoArgs), - (true, true, false) => if generics.is_parameterized() { + match (has_output, has_should_panic_attr) { + (true, true) => No(BadTestSignature::ShouldPanicOnlyWithNoArgs), + (true, false) => if generics.is_parameterized() { No(BadTestSignature::WrongTypeSignature) } else { Yes }, - (true, false, _) => No(BadTestSignature::WrongTypeSignature), - (false, _, _) => Yes + (true, _) => No(BadTestSignature::WrongTypeSignature), + (false, _) => Yes } } _ => No(BadTestSignature::NotEvenAFunction), @@ -398,28 +398,9 @@ fn is_bench_fn(cx: &TestCtxt, i: &ast::Item) -> bool { fn has_bench_signature(cx: &TestCtxt, i: &ast::Item) -> bool { match i.node { ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => { - let input_cnt = decl.inputs.len(); - - // If the termination trait is active, the compiler will check that the output - // type implements the `Termination` trait as `libtest` enforces that. - let output_matches = if cx.features.termination_trait_test { - true - } else { - let no_output = match decl.output { - ast::FunctionRetTy::Default(..) => true, - ast::FunctionRetTy::Ty(ref t) if t.node == ast::TyKind::Tup(vec![]) => true, - _ => false - }; - let tparm_cnt = generics.params.iter() - .filter(|param| param.is_type_param()) - .count(); - - no_output && tparm_cnt == 0 - }; - // NB: inadequate check, but we're running // well before resolve, can't get too deep. - input_cnt == 1 && output_matches + decl.inputs.len() == 1 } _ => false } @@ -430,13 +411,8 @@ fn is_bench_fn(cx: &TestCtxt, i: &ast::Item) -> bool { if has_bench_attr && !has_bench_signature { let diag = cx.span_diagnostic; - if cx.features.termination_trait_test { - diag.span_err(i.span, "functions used as benches must have signature \ + diag.span_err(i.span, "functions used as benches must have signature \ `fn(&mut Bencher) -> impl Termination`"); - } else { - diag.span_err(i.span, "functions used as benches must have signature \ - `fn(&mut Bencher) -> ()`"); - } } has_bench_attr && has_bench_signature diff --git a/src/test/compile-fail/feature-gate-termination_trait_test.rs b/src/test/compile-fail/feature-gate-termination_trait_test.rs deleted file mode 100644 index 4af7e94671627..0000000000000 --- a/src/test/compile-fail/feature-gate-termination_trait_test.rs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// compile-flags: --test - -fn main() {} - -#[cfg(test)] -mod tests { - #[test] - fn it_works() -> Result<(), ()> { - //~^ ERROR functions used as tests must have signature fn() -> () - Ok(()) - } -} diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-in-test-should-panic.rs b/src/test/ui/rfc-1937-termination-trait/termination-trait-in-test-should-panic.rs index 73a0150c0bb3f..a0b2784214ae9 100644 --- a/src/test/ui/rfc-1937-termination-trait/termination-trait-in-test-should-panic.rs +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-in-test-should-panic.rs @@ -10,7 +10,6 @@ // compile-flags: --test -#![feature(termination_trait_test)] #![feature(test)] extern crate test; diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-in-test.rs b/src/test/ui/rfc-1937-termination-trait/termination-trait-in-test.rs index 2cb4552a4b29e..0561b12221d1a 100644 --- a/src/test/ui/rfc-1937-termination-trait/termination-trait-in-test.rs +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-in-test.rs @@ -11,7 +11,6 @@ // compile-flags: --test // run-pass -#![feature(termination_trait_test)] #![feature(test)] extern crate test; diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.rs b/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.rs index 1c00edee770f2..6153d840c8a7d 100644 --- a/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.rs +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.rs @@ -10,8 +10,6 @@ // compile-flags: --test -#![feature(termination_trait_test)] - use std::num::ParseIntError; #[test] From bc7416213c20e165ebe723c4328667e8008c0794 Mon Sep 17 00:00:00 2001 From: dylan_DPC Date: Sat, 2 Jun 2018 17:58:06 +0530 Subject: [PATCH 02/16] fixed feature gate to right place --- src/libsyntax/feature_gate.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index ecda2b077e1f9..9adfb61d92d32 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -473,8 +473,6 @@ declare_features! ( // 'a: { break 'a; } (active, label_break_value, "1.28.0", Some(48594), None), - // Termination trait in tests (RFC 1937) - (accepted, termination_trait_test, "1.28.0", Some(48854), Some(Edition::Edition2018)), ); declare_features! ( @@ -609,6 +607,8 @@ declare_features! ( (accepted, fn_must_use, "1.27.0", Some(43302), None), // Allows use of the :lifetime macro fragment specifier (accepted, macro_lifetime_matcher, "1.27.0", Some(34303), None), + // Termination trait in tests (RFC 1937) + (accepted, termination_trait_test, "1.27.0", Some(48854), Some(Edition::Edition2018)), ); // If you change this, please modify src/doc/unstable-book as well. You must From f37557764d0f1ca32d6b0c2525c88e49319e13d3 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 5 Jun 2018 14:36:36 +0100 Subject: [PATCH 03/16] Fix the use of closures within #[panic_implementation] --- src/librustc_typeck/check/mod.rs | 2 +- .../panic_implementation-closures.rs | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 src/test/compile-fail/panic_implementation-closures.rs diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c2c71d90f0674..0c1c2ab481714 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1131,7 +1131,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, // Check that a function marked as `#[panic_implementation]` has signature `fn(&PanicInfo) -> !` if let Some(panic_impl_did) = fcx.tcx.lang_items().panic_impl() { - if panic_impl_did == fn_hir_id.owner_def_id() { + if panic_impl_did == fcx.tcx.hir.local_def_id(fn_id) { if let Some(panic_info_did) = fcx.tcx.lang_items().panic_info() { if declared_ret_ty.sty != ty::TyNever { fcx.tcx.sess.span_err( diff --git a/src/test/compile-fail/panic_implementation-closures.rs b/src/test/compile-fail/panic_implementation-closures.rs new file mode 100644 index 0000000000000..4fa9a639928f9 --- /dev/null +++ b/src/test/compile-fail/panic_implementation-closures.rs @@ -0,0 +1,21 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-pass + +#![crate_type = "rlib"] +#![no_std] +#![feature(panic_implementation)] + +#[panic_implementation] +pub fn panic_fmt(_: &::core::panic::PanicInfo) -> ! { + |x: u8| x; + loop {} +} From aa23aba55f32e2239722f6c3b7bc358607ff3020 Mon Sep 17 00:00:00 2001 From: Adam Barth Date: Fri, 1 Jun 2018 12:58:30 -0700 Subject: [PATCH 04/16] [fuchsia] Migrate from launchpad to fdio_spawn_etc fdio_spawn_etc is the preferred way of creating processes on Fuchsia now. --- src/libstd/build.rs | 1 - .../sys/unix/process/process_fuchsia.rs | 75 ++++++---------- src/libstd/sys/unix/process/zircon.rs | 85 +++++-------------- 3 files changed, 51 insertions(+), 110 deletions(-) diff --git a/src/libstd/build.rs b/src/libstd/build.rs index c34877d369c93..c001e4e8cebf9 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -74,7 +74,6 @@ fn main() { } println!("cargo:rustc-link-lib=zircon"); println!("cargo:rustc-link-lib=fdio"); - println!("cargo:rustc-link-lib=launchpad"); // for std::process } else if target.contains("cloudabi") { if cfg!(feature = "backtrace") { println!("cargo:rustc-link-lib=unwind"); diff --git a/src/libstd/sys/unix/process/process_fuchsia.rs b/src/libstd/sys/unix/process/process_fuchsia.rs index 06c0540fec0d7..0fbeb8603a99b 100644 --- a/src/libstd/sys/unix/process/process_fuchsia.rs +++ b/src/libstd/sys/unix/process/process_fuchsia.rs @@ -56,68 +56,49 @@ impl Command { -> io::Result { use sys::process::zircon::*; - let job_handle = zx_job_default(); let envp = match maybe_envp { Some(envp) => envp.as_ptr(), None => ptr::null(), }; - // To make sure launchpad_destroy gets called on the launchpad if this function fails - struct LaunchpadDestructor(*mut launchpad_t); - impl Drop for LaunchpadDestructor { - fn drop(&mut self) { unsafe { launchpad_destroy(self.0); } } - } - - // Duplicate the job handle - let mut job_copy: zx_handle_t = ZX_HANDLE_INVALID; - zx_cvt(zx_handle_duplicate(job_handle, ZX_RIGHT_SAME_RIGHTS, &mut job_copy))?; - // Create a launchpad - let mut launchpad: *mut launchpad_t = ptr::null_mut(); - zx_cvt(launchpad_create(job_copy, self.get_argv()[0], &mut launchpad))?; - let launchpad_destructor = LaunchpadDestructor(launchpad); - - // Set the process argv - zx_cvt(launchpad_set_args(launchpad, self.get_argv().len() as i32 - 1, - self.get_argv().as_ptr()))?; - // Setup the environment vars - zx_cvt(launchpad_set_environ(launchpad, envp))?; - zx_cvt(launchpad_add_vdso_vmo(launchpad))?; - // Load the executable - zx_cvt(launchpad_elf_load(launchpad, launchpad_vmo_from_file(self.get_argv()[0])))?; - zx_cvt(launchpad_load_vdso(launchpad, ZX_HANDLE_INVALID))?; - zx_cvt(launchpad_clone(launchpad, LP_CLONE_FDIO_NAMESPACE | LP_CLONE_FDIO_CWD))?; + let transfer_or_clone = |opt_fd, target_fd| if let Some(local_fd) = opt_fd { + fdio_spawn_action_t { + action: FDIO_SPAWN_ACTION_TRANSFER_FD, + local_fd, + target_fd, + ..Default::default() + } + } else { + fdio_spawn_action_t { + action: FDIO_SPAWN_ACTION_CLONE_FD, + local_fd: target_fd, + target_fd, + ..Default::default() + } + }; // Clone stdin, stdout, and stderr - if let Some(fd) = stdio.stdin.fd() { - zx_cvt(launchpad_transfer_fd(launchpad, fd, 0))?; - } else { - zx_cvt(launchpad_clone_fd(launchpad, 0, 0))?; - } - if let Some(fd) = stdio.stdout.fd() { - zx_cvt(launchpad_transfer_fd(launchpad, fd, 1))?; - } else { - zx_cvt(launchpad_clone_fd(launchpad, 1, 1))?; - } - if let Some(fd) = stdio.stderr.fd() { - zx_cvt(launchpad_transfer_fd(launchpad, fd, 2))?; - } else { - zx_cvt(launchpad_clone_fd(launchpad, 2, 2))?; - } + let action1 = transfer_or_clone(stdio.stdin.fd(), 0); + let action2 = transfer_or_clone(stdio.stdout.fd(), 1); + let action3 = transfer_or_clone(stdio.stderr.fd(), 2); + let actions = [action1, action2, action3]; - // We don't want FileDesc::drop to be called on any stdio. It would close their fds. The - // fds will be closed once the child process finishes. + // We don't want FileDesc::drop to be called on any stdio. fdio_spawn_etc + // always consumes transferred file descriptors. mem::forget(stdio); for callback in self.get_closures().iter_mut() { callback()?; } - // `launchpad_go` destroys the launchpad, so we must not - mem::forget(launchpad_destructor); - let mut process_handle: zx_handle_t = 0; - let mut err_msg: *const libc::c_char = ptr::null(); - zx_cvt(launchpad_go(launchpad, &mut process_handle, &mut err_msg))?; + zx_cvt(fdio_spawn_etc( + 0, + FDIO_SPAWN_SHARE_JOB | FDIO_SPAWN_CLONE_LDSVC | FDIO_SPAWN_CLONE_NAMESPACE, + self.get_argv()[0], self.get_argv().as_ptr(), envp, 3, actions.as_ptr(), + &mut process_handle, + ptr::null_mut(), + ))?; // FIXME: See if we want to do something with that err_msg Ok(process_handle) diff --git a/src/libstd/sys/unix/process/zircon.rs b/src/libstd/sys/unix/process/zircon.rs index 90864e6ef3ff2..a06c73ee263c2 100644 --- a/src/libstd/sys/unix/process/zircon.rs +++ b/src/libstd/sys/unix/process/zircon.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(non_camel_case_types)] +#![allow(non_camel_case_types, unused)] use convert::TryInto; use io; @@ -117,75 +117,36 @@ extern { avail: *mut size_t) -> zx_status_t; } -// From `enum special_handles` in system/ulib/launchpad/launchpad.c -// HND_LOADER_SVC = 0 -// HND_EXEC_VMO = 1 -// HND_SEGMENTS_VMAR = 2 -const HND_SPECIAL_COUNT: c_int = 3; - +#[derive(Default)] #[repr(C)] -pub struct launchpad_t { - argc: u32, - envc: u32, - args: *const c_char, - args_len: size_t, - env: *const c_char, - env_len: size_t, - - handles: *mut zx_handle_t, - handles_info: *mut u32, - handle_count: size_t, - handle_alloc: size_t, - - entry: zx_vaddr_t, - base: zx_vaddr_t, - vdso_base: zx_vaddr_t, - - stack_size: size_t, - - special_handles: [zx_handle_t; HND_SPECIAL_COUNT as usize], - loader_message: bool, +pub struct fdio_spawn_action_t { + pub action: u32, + pub reserved0: u32, + pub local_fd: i32, + pub target_fd: i32, + pub reserved1: u64, } extern { - pub fn launchpad_create(job: zx_handle_t, name: *const c_char, - lp: *mut *mut launchpad_t) -> zx_status_t; - - pub fn launchpad_go(lp: *mut launchpad_t, - proc_handle: *mut zx_handle_t, - err_msg: *mut *const c_char) -> zx_status_t; - - pub fn launchpad_destroy(lp: *mut launchpad_t); - - pub fn launchpad_set_args(lp: *mut launchpad_t, argc: c_int, - argv: *const *const c_char) -> zx_status_t; - - pub fn launchpad_set_environ(lp: *mut launchpad_t, envp: *const *const c_char) -> zx_status_t; - - pub fn launchpad_clone(lp: *mut launchpad_t, what: u32) -> zx_status_t; - - pub fn launchpad_clone_fd(lp: *mut launchpad_t, fd: c_int, target_fd: c_int) -> zx_status_t; - - pub fn launchpad_transfer_fd(lp: *mut launchpad_t, fd: c_int, target_fd: c_int) -> zx_status_t; - - pub fn launchpad_elf_load(lp: *mut launchpad_t, vmo: zx_handle_t) -> zx_status_t; - - pub fn launchpad_add_vdso_vmo(lp: *mut launchpad_t) -> zx_status_t; + pub fn fdio_spawn_etc(job: zx_handle_t, flags: u32, path: *const c_char, + argv: *const *const c_char, envp: *const *const c_char, + action_count: u64, actions: *const fdio_spawn_action_t, + process: *mut zx_handle_t, err_msg: *mut c_char) -> zx_status_t; +} - pub fn launchpad_load_vdso(lp: *mut launchpad_t, vmo: zx_handle_t) -> zx_status_t; +// fdio_spawn_etc flags - pub fn launchpad_vmo_from_file(filename: *const c_char) -> zx_handle_t; -} +pub const FDIO_SPAWN_CLONE_JOB: u32 = 0x0001; +pub const FDIO_SPAWN_CLONE_LDSVC: u32 = 0x0002; +pub const FDIO_SPAWN_CLONE_NAMESPACE: u32 = 0x0004; +pub const FDIO_SPAWN_CLONE_STDIO: u32 = 0x0008; +pub const FDIO_SPAWN_CLONE_ENVIRON: u32 = 0x0010; +pub const FDIO_SPAWN_CLONE_ALL: u32 = 0xFFFF; -// Launchpad clone constants +// fdio_spawn_etc actions -pub const LP_CLONE_FDIO_NAMESPACE: u32 = 0x0001; -pub const LP_CLONE_FDIO_CWD: u32 = 0x0002; -// LP_CLONE_FDIO_STDIO = 0x0004 -// LP_CLONE_FDIO_ALL = 0x00FF -// LP_CLONE_ENVIRON = 0x0100 -// LP_CLONE_DEFAULT_JOB = 0x0200 -// LP_CLONE_ALL = 0xFFFF +pub const FDIO_SPAWN_ACTION_CLONE_FD: u32 = 0x0001; +pub const FDIO_SPAWN_ACTION_TRANSFER_FD: u32 = 0x0002; // Errors From 4cbf400366bb7d635cf4be31568b41992115220a Mon Sep 17 00:00:00 2001 From: dylan_DPC Date: Tue, 5 Jun 2018 23:28:32 +0530 Subject: [PATCH 05/16] flag changed to none --- src/libsyntax/feature_gate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 17118e4dff2ee..4873062d659d9 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -610,7 +610,7 @@ declare_features! ( // Allows use of the :lifetime macro fragment specifier (accepted, macro_lifetime_matcher, "1.27.0", Some(34303), None), // Termination trait in tests (RFC 1937) - (accepted, termination_trait_test, "1.27.0", Some(48854), Some(Edition::Edition2018)), + (accepted, termination_trait_test, "1.27.0", Some(48854), None), ); // If you change this, please modify src/doc/unstable-book as well. You must From e8fd74a11d66849c0b5b737d3bbe0cf121f8908e Mon Sep 17 00:00:00 2001 From: dylan_DPC Date: Tue, 5 Jun 2018 23:44:42 +0530 Subject: [PATCH 06/16] remove redundant match branch --- src/libsyntax/test.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 5506f408cd269..2d5606b2edeb9 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -358,7 +358,6 @@ fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool { } else { Yes }, - (true, _) => No(BadTestSignature::WrongTypeSignature), (false, _) => Yes } } From b1a8088fdb879917a5a47de9ad146c1e9958dcb8 Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Tue, 5 Jun 2018 15:55:07 -0600 Subject: [PATCH 07/16] Remove fmt_macros dependency --- src/Cargo.lock | 1 - src/librustc_typeck/Cargo.toml | 1 - 2 files changed, 2 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index d17faef82b563..78922a858528c 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -2307,7 +2307,6 @@ name = "rustc_typeck" version = "0.0.0" dependencies = [ "arena 0.0.0", - "fmt_macros 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_data_structures 0.0.0", diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml index c426533779c9b..184cb9826ba68 100644 --- a/src/librustc_typeck/Cargo.toml +++ b/src/librustc_typeck/Cargo.toml @@ -13,7 +13,6 @@ test = false log = "0.4" syntax = { path = "../libsyntax" } arena = { path = "../libarena" } -fmt_macros = { path = "../libfmt_macros" } rustc = { path = "../librustc" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" } From e73941a06b8a12d45407395a82589aaabcab1354 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Wed, 6 Jun 2018 04:13:55 +0100 Subject: [PATCH 08/16] rustdoc: Fix missing stability and src links for inlined external macros --- src/librustdoc/visit_ast.rs | 6 ++-- .../rustdoc/inline_cross/auxiliary/macros.rs | 21 ++++++++++++++ src/test/rustdoc/inline_cross/macros.rs | 28 +++++++++++++++++++ 3 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 src/test/rustdoc/inline_cross/auxiliary/macros.rs create mode 100644 src/test/rustdoc/inline_cross/macros.rs diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 8c2555c4b3de2..f05cbbfd7a2b6 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -244,10 +244,10 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { def_id, attrs: def.attrs.clone().into(), name: def.ident.name, - whence: def.span, + whence: self.cx.tcx.def_span(def_id), matchers, - stab: self.stability(def.id), - depr: self.deprecation(def.id), + stab: self.cx.tcx.lookup_stability(def_id).cloned(), + depr: self.cx.tcx.lookup_deprecation(def_id), imported_from: Some(imported_from), }) } diff --git a/src/test/rustdoc/inline_cross/auxiliary/macros.rs b/src/test/rustdoc/inline_cross/auxiliary/macros.rs new file mode 100644 index 0000000000000..39b52d68bf1c2 --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/macros.rs @@ -0,0 +1,21 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(staged_api)] + +#![stable(feature = "rust1", since = "1.0.0")] + +/// docs for my_macro +#[unstable(feature = "macro_test", issue = "0")] +#[rustc_deprecated(since = "1.2.3", reason = "text")] +#[macro_export] +macro_rules! my_macro { + () => () +} diff --git a/src/test/rustdoc/inline_cross/macros.rs b/src/test/rustdoc/inline_cross/macros.rs new file mode 100644 index 0000000000000..8d2f7d15d7d7f --- /dev/null +++ b/src/test/rustdoc/inline_cross/macros.rs @@ -0,0 +1,28 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:macros.rs +// build-aux-docs + +#![feature(macro_test)] +#![feature(use_extern_macros)] + +#![crate_name = "foo"] + +extern crate macros; + +// @has foo/index.html '//*[@class="docblock-short"]' '[Deprecated] [Experimental]' + +// @has foo/macro.my_macro.html +// @has - '//*[@class="docblock"]' 'docs for my_macro' +// @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.2.3: text' +// @has - '//*[@class="stab unstable"]' 'macro_test' +// @has - '//a/@href' '../src/macros/macros.rs.html#19-21' +pub use macros::my_macro; From 1048ae29a11f5e4ee188dde0d3ba39be2b05d8ed Mon Sep 17 00:00:00 2001 From: dylan_DPC Date: Wed, 6 Jun 2018 12:22:38 +0530 Subject: [PATCH 09/16] append unused variables with _ --- src/libsyntax/test.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 2d5606b2edeb9..0c7f70a578a26 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -335,7 +335,7 @@ enum BadTestSignature { fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool { let has_test_attr = attr::contains_name(&i.attrs, "test"); - fn has_test_signature(cx: &TestCtxt, i: &ast::Item) -> HasTestSignature { + fn has_test_signature(_cx: &TestCtxt, i: &ast::Item) -> HasTestSignature { let has_should_panic_attr = attr::contains_name(&i.attrs, "should_panic"); match i.node { ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => { @@ -394,9 +394,9 @@ fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool { fn is_bench_fn(cx: &TestCtxt, i: &ast::Item) -> bool { let has_bench_attr = attr::contains_name(&i.attrs, "bench"); - fn has_bench_signature(cx: &TestCtxt, i: &ast::Item) -> bool { + fn has_bench_signature(_cx: &TestCtxt, i: &ast::Item) -> bool { match i.node { - ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => { + ast::ItemKind::Fn(ref decl, _, _, _, _, _) => { // NB: inadequate check, but we're running // well before resolve, can't get too deep. decl.inputs.len() == 1 From 5c36e01f35c1e0290afd654367c2ba1e2353ca36 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 6 Jun 2018 12:44:05 +1000 Subject: [PATCH 10/16] Use scope tree depths to speed up `nearest_common_ancestor`. This patch adds depth markings to all entries in the `ScopeTree`'s `parent_map`. This change increases memory usage somewhat, but permits a much faster algorithm to be used: - If one scope has a greater depth than the other, the deeper scope is moved upward until they are at equal depths. - Then we move the two scopes upward in lockstep until they match. This avoids the need to keep track of which scopes have already been seen, which was the major part of the cost of the old algorithm. It also reduces the number of child-to-parent moves (which are hash table lookups) when the scopes start at different levels, because it never goes past the nearest common ancestor the way the old algorithm did. Finally, the case where one of the scopes is the root is now handled in advance, because that is moderately common and lets us skip everything. This change speeds up runs of several rust-perf benchmarks, the best by 6%. --- src/librustc/middle/region.rs | 130 ++++++++++++++++++---------------- src/librustc_driver/test.rs | 7 +- 2 files changed, 74 insertions(+), 63 deletions(-) diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 42a08afe305a5..0ba204dc20606 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -22,7 +22,6 @@ use ty; use std::fmt; use std::mem; -use rustc_data_structures::small_vec::SmallVec; use rustc_data_structures::sync::Lrc; use syntax::codemap; use syntax::ast; @@ -280,6 +279,8 @@ impl Scope { } } +pub type ScopeDepth = u32; + /// The region scope tree encodes information about region relationships. #[derive(Default, Debug)] pub struct ScopeTree { @@ -297,7 +298,7 @@ pub struct ScopeTree { /// conditional expression or repeating block. (Note that the /// enclosing scope id for the block associated with a closure is /// the closure itself.) - parent_map: FxHashMap, + parent_map: FxHashMap, /// `var_map` maps from a variable or binding id to the block in /// which that variable is declared. @@ -415,11 +416,12 @@ pub struct Context { /// details. root_id: Option, - /// the scope that contains any new variables declared - var_parent: Option, + /// The scope that contains any new variables declared, plus its depth in + /// the scope tree. + var_parent: Option<(Scope, ScopeDepth)>, - /// region parent of expressions etc - parent: Option, + /// Region parent of expressions, etc., plus its depth in the scope tree. + parent: Option<(Scope, ScopeDepth)>, } struct RegionResolutionVisitor<'a, 'tcx: 'a> { @@ -499,7 +501,7 @@ impl<'tcx> Visitor<'tcx> for ExprLocatorVisitor { } impl<'tcx> ScopeTree { - pub fn record_scope_parent(&mut self, child: Scope, parent: Option) { + pub fn record_scope_parent(&mut self, child: Scope, parent: Option<(Scope, ScopeDepth)>) { debug!("{:?}.parent = {:?}", child, parent); if let Some(p) = parent { @@ -515,7 +517,7 @@ impl<'tcx> ScopeTree { pub fn each_encl_scope(&self, mut e:E) where E: FnMut(Scope, Scope) { for (&child, &parent) in &self.parent_map { - e(child, parent) + e(child, parent.0) } } @@ -558,7 +560,7 @@ impl<'tcx> ScopeTree { pub fn opt_encl_scope(&self, id: Scope) -> Option { //! Returns the narrowest scope that encloses `id`, if any. - self.parent_map.get(&id).cloned() + self.parent_map.get(&id).cloned().map(|(p, _)| p) } #[allow(dead_code)] // used in cfg @@ -590,7 +592,7 @@ impl<'tcx> ScopeTree { // returned. let mut id = Scope::Node(expr_id); - while let Some(&p) = self.parent_map.get(&id) { + while let Some(&(p, _)) = self.parent_map.get(&id) { match p.data() { ScopeData::Destruction(..) => { debug!("temporary_scope({:?}) = {:?} [enclosing]", @@ -658,57 +660,61 @@ impl<'tcx> ScopeTree { } } - /// Finds the nearest common ancestor (if any) of two scopes. That is, finds the smallest - /// scope which is greater than or equal to both `scope_a` and `scope_b`. - pub fn nearest_common_ancestor(&self, - scope_a: Scope, - scope_b: Scope) - -> Scope { + /// Finds the nearest common ancestor of two scopes. That is, finds the + /// smallest scope which is greater than or equal to both `scope_a` and + /// `scope_b`. + pub fn nearest_common_ancestor(&self, scope_a: Scope, scope_b: Scope) -> Scope { if scope_a == scope_b { return scope_a; } - // Process the lists in tandem from the innermost scope, recording the - // scopes seen so far. The first scope that comes up for a second time - // is the nearest common ancestor. - // - // Note: another way to compute the nearest common ancestor is to get - // the full scope chain for both scopes and then compare the chains to - // find the first scope in a common tail. But getting a parent scope - // requires a hash table lookup, and we often have very long scope - // chains (10s or 100s of scopes) that only differ by a few elements at - // the start. So this algorithm is faster. - - let mut ma = Some(&scope_a); - let mut mb = Some(&scope_b); - - // A HashSet is a more obvious choice for these, but SmallVec is - // faster because the set size is normally small so linear search is - // as good or better than a hash table lookup, plus the size is usually - // small enough to avoid a heap allocation. - let mut seen_a: SmallVec<[&Scope; 32]> = SmallVec::new(); - let mut seen_b: SmallVec<[&Scope; 32]> = SmallVec::new(); + let mut a = scope_a; + let mut b = scope_b; - loop { - if let Some(a) = ma { - if seen_b.iter().any(|s| *s == a) { - return *a; - } - seen_a.push(a); - ma = self.parent_map.get(&a); - } + // Get the depth of each scope's parent. If either scope has no parent, + // it must be the root, which means we can stop immediately because the + // root must be the nearest common ancestor. (In practice, this is + // moderately common.) + let (parent_a, parent_a_depth) = match self.parent_map.get(&a) { + Some(pd) => *pd, + None => return a, + }; + let (parent_b, parent_b_depth) = match self.parent_map.get(&b) { + Some(pd) => *pd, + None => return b, + }; - if let Some(b) = mb { - if seen_a.iter().any(|s| *s == b) { - return *b; - } - seen_b.push(b); - mb = self.parent_map.get(&b); + if parent_a_depth > parent_b_depth { + // `a` is lower than `b`. Move `a` up until it's at the same depth + // as `b`. The first move up is trivial because we already found + // `parent_a` above; the loop does the remaining N-1 moves. + a = parent_a; + for _ in 0..(parent_a_depth - parent_b_depth - 1) { + a = self.parent_map.get(&a).unwrap().0; } - - if ma.is_none() && mb.is_none() { - // No nearest common ancestor found. - bug!(); + } else if parent_b_depth > parent_a_depth { + // `b` is lower than `a`. + b = parent_b; + for _ in 0..(parent_b_depth - parent_a_depth - 1) { + b = self.parent_map.get(&b).unwrap().0; } + } else { + // Both scopes are at the same depth, and we know they're not equal + // because that case was tested for at the top of this function. So + // we can trivially move them both up one level now. + assert!(parent_a_depth != 0); + a = parent_a; + b = parent_b; } + + // Now both scopes are at the same level. We move upwards in lockstep + // until they match. In practice, this loop is almost always executed + // zero times because `a` is almost always a direct ancestor of `b` or + // vice versa. + while a != b { + a = self.parent_map.get(&a).unwrap().0; + b = self.parent_map.get(&b).unwrap().0; + }; + + a } /// Assuming that the provided region was defined within this `ScopeTree`, @@ -807,7 +813,7 @@ fn record_var_lifetime(visitor: &mut RegionResolutionVisitor, // // extern fn isalnum(c: c_int) -> c_int } - Some(parent_scope) => + Some((parent_scope, _)) => visitor.scope_tree.record_var_scope(var_id, parent_scope), } } @@ -1019,7 +1025,7 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr: // Keep traversing up while we can. match visitor.scope_tree.parent_map.get(&scope) { // Don't cross from closure bodies to their parent. - Some(&superscope) => match superscope.data() { + Some(&(superscope, _)) => match superscope.data() { ScopeData::CallSite(_) => break, _ => scope = superscope }, @@ -1036,7 +1042,7 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, init: Option<&'tcx hir::Expr>) { debug!("resolve_local(pat={:?}, init={:?})", pat, init); - let blk_scope = visitor.cx.var_parent; + let blk_scope = visitor.cx.var_parent.map(|(p, _)| p); // As an exception to the normal rules governing temporary // lifetimes, initializers in a let have a temporary lifetime @@ -1261,16 +1267,20 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, impl<'a, 'tcx> RegionResolutionVisitor<'a, 'tcx> { /// Records the current parent (if any) as the parent of `child_scope`. - fn record_child_scope(&mut self, child_scope: Scope) { + /// Returns the depth of `child_scope`. + fn record_child_scope(&mut self, child_scope: Scope) -> ScopeDepth { let parent = self.cx.parent; self.scope_tree.record_scope_parent(child_scope, parent); + // If `child_scope` has no parent, it must be the root node, and so has + // a depth of 1. Otherwise, its depth is one more than its parent's. + parent.map_or(1, |(_p, d)| d + 1) } /// Records the current parent (if any) as the parent of `child_scope`, /// and sets `child_scope` as the new current parent. fn enter_scope(&mut self, child_scope: Scope) { - self.record_child_scope(child_scope); - self.cx.parent = Some(child_scope); + let child_depth = self.record_child_scope(child_scope); + self.cx.parent = Some((child_scope, child_depth)); } fn enter_node_scope_with_dtor(&mut self, id: hir::ItemLocalId) { diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index b22817a066c43..206e58b3e2e27 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -191,11 +191,12 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { self.infcx.tcx } - pub fn create_region_hierarchy(&mut self, rh: &RH, parent: region::Scope) { + pub fn create_region_hierarchy(&mut self, rh: &RH, + parent: (region::Scope, region::ScopeDepth)) { let me = region::Scope::Node(rh.id); self.region_scope_tree.record_scope_parent(me, Some(parent)); for child_rh in rh.sub { - self.create_region_hierarchy(child_rh, me); + self.create_region_hierarchy(child_rh, (me, parent.1 + 1)); } } @@ -215,7 +216,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { id: hir::ItemLocalId(11), sub: &[], }], - }, dscope); + }, (dscope, 1)); } #[allow(dead_code)] // this seems like it could be useful, even if we don't use it now From 8ecbd351bb80f03a76110ba9f7b9e6a68b3d2798 Mon Sep 17 00:00:00 2001 From: dylan_DPC Date: Wed, 6 Jun 2018 20:51:57 +0530 Subject: [PATCH 11/16] fix stderrs --- .../termination-trait-in-test-should-panic.stderr | 2 +- .../termination-trait-test-wrong-type.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-in-test-should-panic.stderr b/src/test/ui/rfc-1937-termination-trait/termination-trait-in-test-should-panic.stderr index e3dab82df41b9..bfdcf01c325f7 100644 --- a/src/test/ui/rfc-1937-termination-trait/termination-trait-in-test-should-panic.stderr +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-in-test-should-panic.stderr @@ -1,5 +1,5 @@ error: functions using `#[should_panic]` must return `()` - --> $DIR/termination-trait-in-test-should-panic.rs:22:1 + --> $DIR/termination-trait-in-test-should-panic.rs:21:1 | LL | / fn not_a_num() -> Result<(), ParseIntError> { LL | | //~^ ERROR functions using `#[should_panic]` must return `()` diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr b/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr index 8efd8a216f10f..0972a0994fc0d 100644 --- a/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr @@ -1,5 +1,5 @@ error[E0277]: `main` has invalid return type `std::result::Result` - --> $DIR/termination-trait-test-wrong-type.rs:18:1 + --> $DIR/termination-trait-test-wrong-type.rs:16:1 | LL | / fn can_parse_zero_as_f32() -> Result { //~ ERROR LL | | "0".parse() From f1c92476634485c6a2fb17d33046cedddaa150a2 Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Wed, 6 Jun 2018 17:31:22 +0200 Subject: [PATCH 12/16] NLL performance boost --- .../borrow_check/nll/type_check/liveness.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness.rs index d19fd2bb5969d..76320c6a2eacc 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness.rs @@ -104,13 +104,15 @@ impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flo location, live_local ); - self.flow_inits.each_state_bit(|mpi_init| { - debug!( - "add_liveness_constraints: location={:?} initialized={:?}", - location, - &self.flow_inits.operator().move_data().move_paths[mpi_init] - ); - }); + if log_enabled!(::log::Level::Debug) { + self.flow_inits.each_state_bit(|mpi_init| { + debug!( + "add_liveness_constraints: location={:?} initialized={:?}", + location, + &self.flow_inits.operator().move_data().move_paths[mpi_init] + ); + }); + } let mpi = self.move_data.rev_lookup.find_local(live_local); if let Some(initialized_child) = self.flow_inits.has_any_child_of(mpi) { From 50224ec1a90eff7a3c475fcd1a19c99e10ee5b26 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 29 May 2018 23:25:53 +0200 Subject: [PATCH 13/16] It turns out that the diagnostics generated from NLL for these cases are now exactly the same as that produced by AST borrowck. Bravo! --- .../ui/generator/pattern-borrow.nll.stderr | 11 ------ src/test/ui/issue-45697.nll.stderr | 34 ------------------- 2 files changed, 45 deletions(-) delete mode 100644 src/test/ui/generator/pattern-borrow.nll.stderr delete mode 100644 src/test/ui/issue-45697.nll.stderr diff --git a/src/test/ui/generator/pattern-borrow.nll.stderr b/src/test/ui/generator/pattern-borrow.nll.stderr deleted file mode 100644 index 48f23486a317c..0000000000000 --- a/src/test/ui/generator/pattern-borrow.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0626]: borrow may still be in use when generator yields - --> $DIR/pattern-borrow.rs:19:24 - | -LL | if let Test::A(ref _a) = test { //~ ERROR borrow may still be in use when generator yields - | ^^^^^^ -LL | yield (); - | -------- possible yield occurs here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0626`. diff --git a/src/test/ui/issue-45697.nll.stderr b/src/test/ui/issue-45697.nll.stderr deleted file mode 100644 index a85972fcd7a1c..0000000000000 --- a/src/test/ui/issue-45697.nll.stderr +++ /dev/null @@ -1,34 +0,0 @@ -error[E0506]: cannot assign to `*y.pointer` because it is borrowed (Ast) - --> $DIR/issue-45697.rs:30:9 - | -LL | let z = copy_borrowed_ptr(&mut y); - | - borrow of `*y.pointer` occurs here -LL | *y.pointer += 1; - | ^^^^^^^^^^^^^^^ assignment to borrowed `*y.pointer` occurs here - -error[E0503]: cannot use `*y.pointer` because it was mutably borrowed (Mir) - --> $DIR/issue-45697.rs:30:9 - | -LL | let z = copy_borrowed_ptr(&mut y); - | ------ borrow of `y` occurs here -LL | *y.pointer += 1; - | ^^^^^^^^^^^^^^^ use of borrowed `y` -... -LL | *z.pointer += 1; - | --------------- borrow later used here - -error[E0506]: cannot assign to `*y.pointer` because it is borrowed (Mir) - --> $DIR/issue-45697.rs:30:9 - | -LL | let z = copy_borrowed_ptr(&mut y); - | ------ borrow of `*y.pointer` occurs here -LL | *y.pointer += 1; - | ^^^^^^^^^^^^^^^ assignment to borrowed `*y.pointer` occurs here -... -LL | *z.pointer += 1; - | --------------- borrow later used here - -error: aborting due to 3 previous errors - -Some errors occurred: E0503, E0506. -For more information about an error, try `rustc --explain E0503`. From fbe7d5bce8f618ce0fc8d78d4153c05dc85e62bb Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 31 May 2018 12:46:43 +0200 Subject: [PATCH 14/16] When NLL has illegal move due to borrowed content, provide feedback about why the move wasn't a copy. This should address #51190. --- .../borrowck/gather_loans/move_error.rs | 2 +- src/librustc_mir/borrow_check/mod.rs | 13 ++++++++++--- src/librustc_mir/dataflow/move_paths/builder.rs | 9 +++++---- src/librustc_mir/dataflow/move_paths/mod.rs | 16 +++++++++++++++- src/librustc_mir/util/borrowck_errors.rs | 8 ++++++-- 5 files changed, 37 insertions(+), 11 deletions(-) diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index 18026a14259de..8493190796435 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -147,7 +147,7 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &'a BorrowckCtxt<'a, 'tcx>, } Categorization::Interior(ref b, mc::InteriorElement(ik)) => { bccx.cannot_move_out_of_interior_noncopy( - move_from.span, b.ty, ik == Kind::Index, Origin::Ast) + move_from.span, b.ty, Some(ik == Kind::Index), Origin::Ast) } Categorization::Downcast(ref b, _) | diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 5efbdeafd1bbf..ba0557d062f24 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -132,14 +132,21 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( IllegalMoveOriginKind::Static => { tcx.cannot_move_out_of(span, "static item", origin) } - IllegalMoveOriginKind::BorrowedContent => { - tcx.cannot_move_out_of(span, "borrowed content", origin) + IllegalMoveOriginKind::BorrowedContent { target_ty: ty } => { + // Inspect the type of the content behind the + // borrow to provide feedback about why this + // was a move rather than a copy. + match ty.sty { + ty::TyArray(..) | ty::TySlice(..) => + tcx.cannot_move_out_of_interior_noncopy(span, ty, None, origin), + _ => tcx.cannot_move_out_of(span, "borrowed content", origin) + } } IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => { tcx.cannot_move_out_of_interior_of_drop(span, ty, origin) } IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } => { - tcx.cannot_move_out_of_interior_noncopy(span, ty, is_index, origin) + tcx.cannot_move_out_of_interior_noncopy(span, ty, Some(is_index), origin) } }; err.emit(); diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index 2ff22842141d9..590f9917015dc 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -119,8 +119,8 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> { } fn create_move_path(&mut self, place: &Place<'tcx>) { - // This is an assignment, not a move, so this not being a valid - // move path is OK. + // This is an non-moving access (such as an overwrite or + // drop), so this not being a valid move path is OK. let _ = self.move_path_for(place); } @@ -135,8 +135,9 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> { let place_ty = proj.base.ty(mir, tcx).to_ty(tcx); match place_ty.sty { ty::TyRef(..) | ty::TyRawPtr(..) => - return Err(MoveError::cannot_move_out_of(mir.source_info(self.loc).span, - BorrowedContent)), + return Err(MoveError::cannot_move_out_of( + mir.source_info(self.loc).span, + BorrowedContent { target_ty: place.ty(mir, tcx).to_ty(tcx) })), ty::TyAdt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => return Err(MoveError::cannot_move_out_of(mir.source_info(self.loc).span, InteriorOfTypeWithDestructor { diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs index 610963af9e13c..a73e47bc16ab2 100644 --- a/src/librustc_mir/dataflow/move_paths/mod.rs +++ b/src/librustc_mir/dataflow/move_paths/mod.rs @@ -277,9 +277,23 @@ pub struct IllegalMoveOrigin<'tcx> { #[derive(Debug)] pub(crate) enum IllegalMoveOriginKind<'tcx> { + /// Illegal move due to attempt to move from `static` variable. Static, - BorrowedContent, + + /// Illegal move due to attempt to move from behind a reference. + BorrowedContent { + /// The content's type: if erroneous code was trying to move + /// from `*x` where `x: &T`, then this will be `T`. + target_ty: ty::Ty<'tcx>, + }, + + /// Illegal move due to attempt to move from field of an ADT that + /// implements `Drop`. Rust maintains invariant that all `Drop` + /// ADT's remain fully-initialized so that user-defined destructor + /// can safely read from all of the ADT's fields. InteriorOfTypeWithDestructor { container_ty: ty::Ty<'tcx> }, + + /// Illegal move due to attempt to move out of a slice or array. InteriorOfSliceOrArray { ty: ty::Ty<'tcx>, is_index: bool, }, } diff --git a/src/librustc_mir/util/borrowck_errors.rs b/src/librustc_mir/util/borrowck_errors.rs index d6b3e674f8f80..d01b90ad2628e 100644 --- a/src/librustc_mir/util/borrowck_errors.rs +++ b/src/librustc_mir/util/borrowck_errors.rs @@ -312,15 +312,19 @@ pub trait BorrowckErrors<'cx>: Sized + Copy { self.cancel_if_wrong_origin(err, o) } + /// Signal an error due to an attempt to move out of the interior + /// of an array or slice. `is_index` is None when error origin + /// didn't capture whether there was an indexing operation or not. fn cannot_move_out_of_interior_noncopy(self, move_from_span: Span, ty: ty::Ty, - is_index: bool, + is_index: Option, o: Origin) -> DiagnosticBuilder<'cx> { let type_name = match (&ty.sty, is_index) { - (&ty::TyArray(_, _), true) => "array", + (&ty::TyArray(_, _), Some(true)) | + (&ty::TyArray(_, _), None) => "array", (&ty::TySlice(_), _) => "slice", _ => span_bug!(move_from_span, "this path should not cause illegal move"), }; From 9b24595226f3290e09aada4d3d370331d71e6241 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 31 May 2018 12:58:10 +0200 Subject: [PATCH 15/16] Drive-by: Make assignment conflict tests in borrowck-vec-pattern-nesting.rs robust for NLL. --- src/test/ui/borrowck/borrowck-vec-pattern-nesting.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.rs b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.rs index 111968e9c9313..63dac0a83004a 100644 --- a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.rs +++ b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.rs @@ -19,6 +19,7 @@ fn a() { //~^ borrow of `vec[..]` occurs here vec[0] = box 4; //~ ERROR cannot assign //~^ assignment to borrowed `vec[..]` occurs here + _a.use_ref(); } } } @@ -31,6 +32,7 @@ fn b() { //~^ borrow of `vec[..]` occurs here vec[0] = box 4; //~ ERROR cannot assign //~^ assignment to borrowed `vec[..]` occurs here + _b.use_ref(); } } } @@ -82,3 +84,6 @@ fn e() { } fn main() {} + +trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { } } +impl Fake for T { } From e5b378b18df428e296243a82e4a2c5856ef0cb75 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 31 May 2018 12:58:34 +0200 Subject: [PATCH 16/16] Update the expected error output to reflect changes in this PR. --- .../borrowck-move-out-of-vec-tail.nll.stderr | 10 +-- .../borrowck-vec-pattern-nesting.nll.stderr | 77 ++++++++++++------- .../borrowck-vec-pattern-nesting.stderr | 14 ++-- 3 files changed, 63 insertions(+), 38 deletions(-) diff --git a/src/test/ui/borrowck/borrowck-move-out-of-vec-tail.nll.stderr b/src/test/ui/borrowck/borrowck-move-out-of-vec-tail.nll.stderr index a430c97158a48..96b376ea7ae40 100644 --- a/src/test/ui/borrowck/borrowck-move-out-of-vec-tail.nll.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-of-vec-tail.nll.stderr @@ -1,15 +1,15 @@ -error[E0507]: cannot move out of borrowed content +error[E0508]: cannot move out of type `[Foo]`, a non-copy slice --> $DIR/borrowck-move-out-of-vec-tail.rs:30:33 | LL | &[Foo { string: a }, - | ^ cannot move out of borrowed content + | ^ cannot move out of here -error[E0507]: cannot move out of borrowed content +error[E0508]: cannot move out of type `[Foo]`, a non-copy slice --> $DIR/borrowck-move-out-of-vec-tail.rs:34:33 | LL | Foo { string: b }] => { - | ^ cannot move out of borrowed content + | ^ cannot move out of here error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0507`. +For more information about this error, try `rustc --explain E0508`. diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.nll.stderr b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.nll.stderr index d5a66a6c70635..6d28a37463b92 100644 --- a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.nll.stderr +++ b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.nll.stderr @@ -1,51 +1,76 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-vec-pattern-nesting.rs:42:15 +error[E0506]: cannot assign to `vec[..]` because it is borrowed + --> $DIR/borrowck-vec-pattern-nesting.rs:20:13 + | +LL | [box ref _a, _, _] => { + | ------ borrow of `vec[..]` occurs here +LL | //~^ borrow of `vec[..]` occurs here +LL | vec[0] = box 4; //~ ERROR cannot assign + | ^^^^^^ assignment to borrowed `vec[..]` occurs here +LL | //~^ assignment to borrowed `vec[..]` occurs here +LL | _a.use_ref(); + | -- borrow later used here + +error[E0506]: cannot assign to `vec[..]` because it is borrowed + --> $DIR/borrowck-vec-pattern-nesting.rs:33:13 + | +LL | &mut [ref _b..] => { + | ------ borrow of `vec[..]` occurs here +LL | //~^ borrow of `vec[..]` occurs here +LL | vec[0] = box 4; //~ ERROR cannot assign + | ^^^^^^ assignment to borrowed `vec[..]` occurs here +LL | //~^ assignment to borrowed `vec[..]` occurs here +LL | _b.use_ref(); + | -- borrow later used here + +error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice + --> $DIR/borrowck-vec-pattern-nesting.rs:44:15 | LL | &mut [_a, //~ ERROR cannot move out - | ^^ cannot move out of borrowed content + | ^^ cannot move out of here -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-vec-pattern-nesting.rs:55:13 +error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice + --> $DIR/borrowck-vec-pattern-nesting.rs:57:13 | LL | let a = vec[0]; //~ ERROR cannot move out - | ^^^^^^ cannot move out of borrowed content + | ^^^^^^ cannot move out of here -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-vec-pattern-nesting.rs:65:10 +error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice + --> $DIR/borrowck-vec-pattern-nesting.rs:67:10 | LL | _b] => {} - | ^^ cannot move out of borrowed content + | ^^ cannot move out of here -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-vec-pattern-nesting.rs:68:13 +error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice + --> $DIR/borrowck-vec-pattern-nesting.rs:70:13 | LL | let a = vec[0]; //~ ERROR cannot move out - | ^^^^^^ cannot move out of borrowed content + | ^^^^^^ cannot move out of here -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-vec-pattern-nesting.rs:76:15 +error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice + --> $DIR/borrowck-vec-pattern-nesting.rs:78:15 | LL | &mut [_a, _b, _c] => {} //~ ERROR cannot move out - | ^^ cannot move out of borrowed content + | ^^ cannot move out of here -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-vec-pattern-nesting.rs:76:19 +error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice + --> $DIR/borrowck-vec-pattern-nesting.rs:78:19 | LL | &mut [_a, _b, _c] => {} //~ ERROR cannot move out - | ^^ cannot move out of borrowed content + | ^^ cannot move out of here -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-vec-pattern-nesting.rs:76:23 +error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice + --> $DIR/borrowck-vec-pattern-nesting.rs:78:23 | LL | &mut [_a, _b, _c] => {} //~ ERROR cannot move out - | ^^ cannot move out of borrowed content + | ^^ cannot move out of here -error[E0507]: cannot move out of borrowed content - --> $DIR/borrowck-vec-pattern-nesting.rs:80:13 +error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice + --> $DIR/borrowck-vec-pattern-nesting.rs:82:13 | LL | let a = vec[0]; //~ ERROR cannot move out - | ^^^^^^ cannot move out of borrowed content + | ^^^^^^ cannot move out of here -error: aborting due to 8 previous errors +error: aborting due to 10 previous errors -For more information about this error, try `rustc --explain E0507`. +Some errors occurred: E0506, E0508. +For more information about an error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr index 6673549e23903..a03e1eab7ad06 100644 --- a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr +++ b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr @@ -8,7 +8,7 @@ LL | vec[0] = box 4; //~ ERROR cannot assign | ^^^^^^^^^^^^^^ assignment to borrowed `vec[..]` occurs here error[E0506]: cannot assign to `vec[..]` because it is borrowed - --> $DIR/borrowck-vec-pattern-nesting.rs:32:13 + --> $DIR/borrowck-vec-pattern-nesting.rs:33:13 | LL | &mut [ref _b..] => { | ------ borrow of `vec[..]` occurs here @@ -17,7 +17,7 @@ LL | vec[0] = box 4; //~ ERROR cannot assign | ^^^^^^^^^^^^^^ assignment to borrowed `vec[..]` occurs here error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:42:14 + --> $DIR/borrowck-vec-pattern-nesting.rs:44:14 | LL | &mut [_a, //~ ERROR cannot move out | ^-- hint: to prevent move, use `ref _a` or `ref mut _a` @@ -30,7 +30,7 @@ LL | | ] => { | |_________^ cannot move out of here error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:55:13 + --> $DIR/borrowck-vec-pattern-nesting.rs:57:13 | LL | let a = vec[0]; //~ ERROR cannot move out | ^^^^^^ @@ -39,7 +39,7 @@ LL | let a = vec[0]; //~ ERROR cannot move out | help: consider using a reference instead: `&vec[0]` error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:63:14 + --> $DIR/borrowck-vec-pattern-nesting.rs:65:14 | LL | &mut [ //~ ERROR cannot move out | ______________^ @@ -50,7 +50,7 @@ LL | | _b] => {} | hint: to prevent move, use `ref _b` or `ref mut _b` error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:68:13 + --> $DIR/borrowck-vec-pattern-nesting.rs:70:13 | LL | let a = vec[0]; //~ ERROR cannot move out | ^^^^^^ @@ -59,7 +59,7 @@ LL | let a = vec[0]; //~ ERROR cannot move out | help: consider using a reference instead: `&vec[0]` error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:76:14 + --> $DIR/borrowck-vec-pattern-nesting.rs:78:14 | LL | &mut [_a, _b, _c] => {} //~ ERROR cannot move out | ^--^^--^^--^ @@ -70,7 +70,7 @@ LL | &mut [_a, _b, _c] => {} //~ ERROR cannot move out | cannot move out of here error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:80:13 + --> $DIR/borrowck-vec-pattern-nesting.rs:82:13 | LL | let a = vec[0]; //~ ERROR cannot move out | ^^^^^^