From cf23dae2ee5a5c8c00efaec245b8aa470dac2ccc Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Tue, 29 Dec 2015 17:44:02 -0500 Subject: [PATCH 01/22] We actually require python 2.7 Fixes #30618 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6e5e1ca0c3282..cd76de541b7fa 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Read ["Installing Rust"] from [The Book]. 1. Make sure you have installed the dependencies: * `g++` 4.7 or `clang++` 3.x - * `python` 2.6 or later (but not 3.x) + * `python` 2.7 or later (but not 3.x) * GNU `make` 3.81 or later * `curl` * `git` From 416267fb19f1e9d78de6a39ac3753488efb81f14 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 10 Jan 2016 20:01:07 -0800 Subject: [PATCH 02/22] Derive Hash for Duration --- src/libstd/time/duration.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index ad1be82d6d842..7ecb3920cc86c 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -40,7 +40,7 @@ const MILLIS_PER_SEC: u64 = 1_000; /// let ten_millis = Duration::from_millis(10); /// ``` #[stable(feature = "duration", since = "1.3.0")] -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] pub struct Duration { secs: u64, nanos: u32, // Always 0 <= nanos < NANOS_PER_SEC From 30779d455d142c7aa75ace6e4611009cd057f52f Mon Sep 17 00:00:00 2001 From: Shmuale Mark Date: Mon, 11 Jan 2016 14:38:40 -0500 Subject: [PATCH 03/22] rustdoc: remove dead link from issue-less unstable entries. --- src/librustdoc/html/render.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index b9ebe977b7bd7..8bc1c184d2038 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1819,10 +1819,10 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Optio } else if stab.level == stability::Unstable { let unstable_extra = if show_reason { match (!stab.feature.is_empty(), &cx.issue_tracker_base_url, stab.issue) { - (true, &Some(ref tracker_url), Some(issue_no)) => + (true, &Some(ref tracker_url), Some(issue_no)) if issue_no > 0 => format!(" ({} #{})", Escape(&stab.feature), tracker_url, issue_no, issue_no), - (false, &Some(ref tracker_url), Some(issue_no)) => + (false, &Some(ref tracker_url), Some(issue_no)) if issue_no > 0 => format!(" (#{})", Escape(&tracker_url), issue_no, issue_no), (true, _, _) => From 757f57bb1eef755474cbb71945ed6370890dd936 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 9 Jan 2016 18:20:33 +0000 Subject: [PATCH 04/22] Add set_oom_handler and use it print a message when out of memory --- src/liballoc/lib.rs | 14 +++--------- src/liballoc/oom.rs | 42 +++++++++++++++++++++++++++++++++++ src/libstd/sys/unix/mod.rs | 23 ++++++++++++++++++- src/libstd/sys/windows/mod.rs | 22 +++++++++++++++++- 4 files changed, 88 insertions(+), 13 deletions(-) create mode 100644 src/liballoc/oom.rs diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 93b84cdedd4cd..dd4bf5174ee2c 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -92,6 +92,7 @@ #![feature(unsize)] #![feature(drop_in_place)] #![feature(fn_traits)] +#![feature(const_fn)] #![feature(needs_allocator)] @@ -127,15 +128,6 @@ mod boxed_test; pub mod arc; pub mod rc; pub mod raw_vec; +pub mod oom; -/// Common out-of-memory routine -#[cold] -#[inline(never)] -#[unstable(feature = "oom", reason = "not a scrutinized interface", - issue = "27700")] -pub fn oom() -> ! { - // FIXME(#14674): This really needs to do something other than just abort - // here, but any printing done must be *guaranteed* to not - // allocate. - unsafe { core::intrinsics::abort() } -} +pub use oom::oom; diff --git a/src/liballoc/oom.rs b/src/liballoc/oom.rs new file mode 100644 index 0000000000000..d355d59185eb4 --- /dev/null +++ b/src/liballoc/oom.rs @@ -0,0 +1,42 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core::sync::atomic::{AtomicPtr, Ordering}; +use core::mem; +use core::intrinsics; + +static OOM_HANDLER: AtomicPtr<()> = AtomicPtr::new(default_oom_handler as *mut ()); + +fn default_oom_handler() -> ! { + // The default handler can't do much more since we can't assume the presence + // of libc or any way of printing an error message. + unsafe { intrinsics::abort() } +} + +/// Common out-of-memory routine +#[cold] +#[inline(never)] +#[unstable(feature = "oom", reason = "not a scrutinized interface", + issue = "27700")] +pub fn oom() -> ! { + let value = OOM_HANDLER.load(Ordering::SeqCst); + let handler: fn() -> ! = unsafe { mem::transmute(value) }; + handler(); +} + +/// Set a custom handler for out-of-memory conditions +/// +/// To avoid recursive OOM failures, it is critical that the OOM handler does +/// not allocate any memory itself. +#[unstable(feature = "oom", reason = "not a scrutinized interface", + issue = "27700")] +pub fn set_oom_handler(handler: fn() -> !) { + OOM_HANDLER.store(handler as *mut (), Ordering::SeqCst); +} diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index 929fd2fb0c38b..9771b057d8d21 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -15,6 +15,7 @@ use io::{self, ErrorKind}; use libc; use num::One; use ops::Neg; +use alloc::oom; #[cfg(target_os = "android")] pub use os::android as platform; #[cfg(target_os = "bitrig")] pub use os::bitrig as platform; @@ -45,6 +46,22 @@ pub mod thread_local; pub mod time; pub mod stdio; +// A nicer handler for out-of-memory situations than the default one. This one +// prints a message to stderr before aborting. It is critical that this code +// does not allocate any memory since we are in an OOM situation. Any errors are +// ignored while printing since there's nothing we can do about them and we are +// about to exit anyways. +fn oom_handler() -> ! { + use intrinsics; + let msg = "fatal runtime error: out of memory\n"; + unsafe { + libc::write(libc::STDERR_FILENO, + msg.as_ptr() as *const libc::c_void, + msg.len() as libc::size_t); + intrinsics::abort(); + } +} + #[cfg(not(any(target_os = "nacl", test)))] pub fn init() { use libc::signal; @@ -58,10 +75,14 @@ pub fn init() { unsafe { assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != !0); } + + oom::set_oom_handler(oom_handler); } #[cfg(all(target_os = "nacl", not(test)))] -pub fn init() { } +pub fn init() { + oom::set_oom_handler(oom_handler); +} pub fn decode_error_kind(errno: i32) -> ErrorKind { match errno as libc::c_int { diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 7e5342a3fd473..7e4db3d89a3f7 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -20,6 +20,7 @@ use num::Zero; use os::windows::ffi::{OsStrExt, OsStringExt}; use path::PathBuf; use time::Duration; +use alloc::oom; #[macro_use] pub mod compat; @@ -42,7 +43,26 @@ pub mod thread_local; pub mod time; pub mod stdio; -pub fn init() {} +// See comment in sys/unix/mod.rs +fn oom_handler() -> ! { + use intrinsics; + use ptr; + let msg = "fatal runtime error: out of memory\n"; + unsafe { + // WriteFile silently fails if it is passed an invalid handle, so there + // is no need to check the result of GetStdHandle. + c::WriteFile(c::GetStdHandle(c::STD_ERROR_HANDLE), + msg.as_ptr() as c::LPVOID, + msg.len() as DWORD, + ptr::null_mut(), + ptr::null_mut()); + intrinsics::abort(); + } +} + +pub fn init() { + oom::set_oom_handler(oom_handler); +} pub fn decode_error_kind(errno: i32) -> ErrorKind { match errno as c::DWORD { From 5fb15d02379b2d18176bd5a920a94157a3344e51 Mon Sep 17 00:00:00 2001 From: Matt Kraai Date: Mon, 11 Jan 2016 20:44:24 -0800 Subject: [PATCH 05/22] Replace --show-span with -Z show-span --- src/librustc/session/config.rs | 6 ++---- src/librustc_driver/driver.rs | 2 +- src/librustc_driver/lib.rs | 7 ++----- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 0134bcdf1757b..80bfbe4edda88 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -132,7 +132,6 @@ pub struct Options { pub prints: Vec, pub cg: CodegenOptions, pub color: ColorConfig, - pub show_span: Option, pub externs: HashMap>, pub crate_name: Option, /// An optional name to use as the crate for std during std injection, @@ -243,7 +242,6 @@ pub fn basic_options() -> Options { prints: Vec::new(), cg: basic_codegen_options(), color: ColorConfig::Auto, - show_span: None, externs: HashMap::new(), crate_name: None, alt_std_name: None, @@ -634,6 +632,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "don't clear the resolution tables after analysis"), keep_ast: bool = (false, parse_bool, "keep the AST after lowering it to HIR"), + show_span: Option = (None, parse_opt_string, + "show spans for compiler debugging (expr|pat|ty)"), } pub fn default_lib_output() -> CrateType { @@ -882,7 +882,6 @@ pub fn rustc_optgroups() -> Vec { `hir` (the HIR), `hir,identified`, or `hir,typed` (HIR with types for each node).", "TYPE"), - opt::opt_u("", "show-span", "Show spans for compiler debugging", "expr|pat|ty"), ]); opts } @@ -1123,7 +1122,6 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { prints: prints, cg: cg, color: color, - show_span: None, externs: externs, crate_name: crate_name, alt_std_name: None, diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index d172bfb441358..840260da33086 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -428,7 +428,7 @@ pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input) println!("Pre-expansion node count: {}", count_nodes(&krate)); } - if let Some(ref s) = sess.opts.show_span { + if let Some(ref s) = sess.opts.debugging_opts.show_span { syntax::show_span::run(sess.diagnostic(), s, &krate); } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 7b8970876f6e3..cdac3de3682e5 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -138,12 +138,9 @@ pub fn run_compiler<'a>(args: &[String], callbacks: &mut CompilerCalls<'a>) { }; let cstore = Rc::new(CStore::new(token::get_ident_interner())); - let mut sess = build_session(sopts, input_file_path, descriptions, + let sess = build_session(sopts, input_file_path, descriptions, cstore.clone()); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); - if sess.unstable_options() { - sess.opts.show_span = matches.opt_str("show-span"); - } let mut cfg = config::build_configuration(&sess); target_features::add_configuration(&mut cfg, &sess); @@ -387,7 +384,7 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { fn build_controller(&mut self, sess: &Session) -> CompileController<'a> { let mut control = CompileController::basic(); - if sess.opts.parse_only || sess.opts.show_span.is_some() || + if sess.opts.parse_only || sess.opts.debugging_opts.show_span.is_some() || sess.opts.debugging_opts.ast_json_noexpand { control.after_parse.stop = Compilation::Stop; } From cb3999cd83a3fbfbd79aaeef3a295aff46c9ea14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Wed, 23 Dec 2015 11:24:11 +0100 Subject: [PATCH 06/22] switch from syscall(2) to getentropy(2) use the `getentropy()` function instead of `syscall()` and syscall-numbers. --- src/libstd/rand/os.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/rand/os.rs b/src/libstd/rand/os.rs index 0ba0e01ce2910..23a368a30a52b 100644 --- a/src/libstd/rand/os.rs +++ b/src/libstd/rand/os.rs @@ -222,7 +222,7 @@ mod imp { // getentropy(2) permits a maximum buffer size of 256 bytes for s in v.chunks_mut(256) { let ret = unsafe { - libc::syscall(libc::NR_GETENTROPY, s.as_mut_ptr(), s.len()) + libc::getentropy(s.as_mut_ptr() as *mut libc::c_void, s.len()) }; if ret == -1 { panic!("unexpected getentropy error: {}", errno()); From 468959580ae9bef5996ae1d43fc9d730e4977999 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Wed, 23 Dec 2015 11:28:24 +0100 Subject: [PATCH 07/22] HW_AVAILCPU is unavailable under openbsd define `num_cpus()` function for openbsd that use `HW_NCPU` for grabbing the current number of cpus that could be used. --- src/libtest/lib.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 2945d20ceb1b8..dcc344c4ffd21 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -919,7 +919,6 @@ fn get_concurrency() -> usize { #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", - target_os = "openbsd", target_os = "netbsd"))] fn num_cpus() -> usize { let mut cpus: libc::c_uint = 0; @@ -946,6 +945,24 @@ fn get_concurrency() -> usize { } cpus as usize } + + #[cfg(target_os = "openbsd")] + fn num_cpus() -> usize { + let mut cpus: libc::c_uint = 0; + let mut cpus_size = std::mem::size_of_val(&cpus); + let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0]; + + unsafe { + libc::sysctl(mib.as_mut_ptr(), 2, + &mut cpus as *mut _ as *mut _, + &mut cpus_size as *mut _ as *mut _, + 0 as *mut _, 0); + } + if cpus < 1 { + cpus = 1; + } + cpus as usize + } } pub fn filter_tests(opts: &TestOpts, tests: Vec) -> Vec { From a545eac593b0ff3a6ad6c2d8390de51c30712089 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Wed, 23 Dec 2015 11:32:02 +0100 Subject: [PATCH 08/22] make siginfo_si_addr() returns a usize `siginfo_si_addr()` function is used once, and the returned value is casted to `usize`. So make the function returns a `usize`. it simplifies OpenBSD case, where the return type wouldn't be a `*mut libc::c_void` but a `*mut libc::c_char`. --- src/libstd/sys/unix/stack_overflow.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libstd/sys/unix/stack_overflow.rs b/src/libstd/sys/unix/stack_overflow.rs index 776acd20b069b..fc49f4257be2a 100644 --- a/src/libstd/sys/unix/stack_overflow.rs +++ b/src/libstd/sys/unix/stack_overflow.rs @@ -59,19 +59,19 @@ mod imp { static mut PAGE_SIZE: usize = 0; #[cfg(any(target_os = "linux", target_os = "android"))] - unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> *mut libc::c_void { + unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize { #[repr(C)] struct siginfo_t { a: [libc::c_int; 3], // si_signo, si_code, si_errno, si_addr: *mut libc::c_void, } - (*(info as *const siginfo_t)).si_addr + (*(info as *const siginfo_t)).si_addr as usize } #[cfg(not(any(target_os = "linux", target_os = "android")))] - unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> *mut libc::c_void { - (*info).si_addr + unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize { + (*info).si_addr as usize } // Signal handler for the SIGSEGV and SIGBUS handlers. We've got guard pages @@ -98,7 +98,7 @@ mod imp { use sys_common::util::report_overflow; let guard = thread_info::stack_guard().unwrap_or(0); - let addr = siginfo_si_addr(info) as usize; + let addr = siginfo_si_addr(info); // If the faulting address is within the guard page, then we print a // message saying so. From 667ee8a57b86f5f3e12ff9bd780d6f16dc4129d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Wed, 23 Dec 2015 18:56:42 +0100 Subject: [PATCH 09/22] openbsd has dirent d_namlen field now --- src/libstd/sys/unix/fs.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index e8575a6c21cf1..10fda3fcd7fa5 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -204,7 +204,8 @@ impl DirEntry { #[cfg(any(target_os = "macos", target_os = "ios", - target_os = "netbsd"))] + target_os = "netbsd", + target_os = "openbsd"))] fn name_bytes(&self) -> &[u8] { unsafe { ::slice::from_raw_parts(self.entry.d_name.as_ptr() as *const u8, @@ -213,8 +214,7 @@ impl DirEntry { } #[cfg(any(target_os = "freebsd", target_os = "dragonfly", - target_os = "bitrig", - target_os = "openbsd"))] + target_os = "bitrig"))] fn name_bytes(&self) -> &[u8] { unsafe { ::slice::from_raw_parts(self.entry.d_name.as_ptr() as *const u8, From 59df1d80f20c2e720dbcc452f063cd39c1bd287d Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 12 Jan 2016 11:23:18 +0100 Subject: [PATCH 10/22] Fix the Debug impl of PhantomData requiring Sized on T --- src/libcore/fmt/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 628bf654873c7..4033fea1f8e5d 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1569,7 +1569,7 @@ impl Debug for () { } } #[stable(feature = "rust1", since = "1.0.0")] -impl Debug for PhantomData { +impl Debug for PhantomData { fn fmt(&self, f: &mut Formatter) -> Result { f.pad("PhantomData") } From 965b0bfefe27b0a487b7243cb1a0a6f36a2be70b Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 8 Jan 2016 20:40:52 +0100 Subject: [PATCH 11/22] Issue 30530: initialize allocas for `Datum::to_lvalue_datum_in_scope`. In particular, bring back the `zero` flag for `lvalue_scratch_datum`, which controls whether the alloca's created immediately at function start are uninitialized at that point or have their embedded drop-flags initialized to "dropped". Then made `to_lvalue_datum_in_scope` pass "dropped" as `zero` flag. --- src/librustc_trans/trans/adt.rs | 2 ++ src/librustc_trans/trans/base.rs | 59 +++++++++++++++++++++++++++++-- src/librustc_trans/trans/datum.rs | 15 ++++++-- 3 files changed, 70 insertions(+), 6 deletions(-) diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index c744ef321278d..e152e11a6a657 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -55,6 +55,7 @@ use syntax::ast; use syntax::attr; use syntax::attr::IntType; use trans::_match; +use trans::base::InitAlloca; use trans::build::*; use trans::cleanup; use trans::cleanup::CleanupMethods; @@ -1279,6 +1280,7 @@ pub fn trans_drop_flag_ptr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let custom_cleanup_scope = fcx.push_custom_cleanup_scope(); let scratch = unpack_datum!(bcx, datum::lvalue_scratch_datum( bcx, tcx.dtor_type(), "drop_flag", + InitAlloca::Uninit("drop flag itself has no dtor"), cleanup::CustomScope(custom_cleanup_scope), (), |_, bcx, _| bcx )); bcx = fold_variants(bcx, r, val, |variant_cx, st, value| { diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index d694374acc927..b2bc7c2af933b 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -1285,12 +1285,62 @@ fn memfill<'a, 'tcx>(b: &Builder<'a, 'tcx>, llptr: ValueRef, ty: Ty<'tcx>, byte: None); } -pub fn alloc_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, name: &str) -> ValueRef { +/// In general, when we create an scratch value in an alloca, the +/// creator may not know if the block (that initializes the scratch +/// with the desired value) actually dominates the cleanup associated +/// with the scratch value. +/// +/// To deal with this, when we do an alloca (at the *start* of whole +/// function body), we optionally can also set the associated +/// dropped-flag state of the alloca to "dropped." +#[derive(Copy, Clone, Debug)] +pub enum InitAlloca { + /// Indicates that the state should have its associated drop flag + /// set to "dropped" at the point of allocation. + Dropped, + /// Indicates the value of the associated drop flag is irrelevant. + /// The embedded string literal is a programmer provided argument + /// for why. This is a safeguard forcing compiler devs to + /// document; it might be a good idea to also emit this as a + /// comment with the alloca itself when emitting LLVM output.ll. + Uninit(&'static str), +} + + +pub fn alloc_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + t: Ty<'tcx>, + name: &str) -> ValueRef { + // pnkfelix: I do not know why alloc_ty meets the assumptions for + // passing Uninit, but it was never needed (even back when we had + // the original boolean `zero` flag on `lvalue_scratch_datum`). + alloc_ty_init(bcx, t, InitAlloca::Uninit("all alloc_ty are uninit"), name) +} + +pub fn alloc_ty_init<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + t: Ty<'tcx>, + init: InitAlloca, + name: &str) -> ValueRef { let _icx = push_ctxt("alloc_ty"); let ccx = bcx.ccx(); let ty = type_of::type_of(ccx, t); assert!(!t.has_param_types()); - alloca(bcx, ty, name) + match init { + InitAlloca::Dropped => alloca_dropped(bcx, t, name), + InitAlloca::Uninit(_) => alloca(bcx, ty, name), + } +} + +pub fn alloca_dropped<'blk, 'tcx>(cx: Block<'blk, 'tcx>, ty: Ty<'tcx>, name: &str) -> ValueRef { + let _icx = push_ctxt("alloca_dropped"); + let llty = type_of::type_of(cx.ccx(), ty); + if cx.unreachable.get() { + unsafe { return llvm::LLVMGetUndef(llty.ptr_to().to_ref()); } + } + let p = alloca(cx, llty, name); + let b = cx.fcx.ccx.builder(); + b.position_before(cx.fcx.alloca_insert_pt.get().unwrap()); + memfill(&b, p, ty, adt::DTOR_DONE); + p } pub fn alloca(cx: Block, ty: Type, name: &str) -> ValueRef { @@ -1650,6 +1700,7 @@ pub fn create_datums_for_fn_args<'a, 'tcx>(mut bcx: Block<'a, 'tcx>, // This alloca should be optimized away by LLVM's mem-to-reg pass in // the event it's not truly needed. let mut idx = fcx.arg_offset() as c_uint; + let uninit_reason = InitAlloca::Uninit("fn_arg populate dominates dtor"); for (i, &arg_ty) in arg_tys.iter().enumerate() { let arg_datum = if !has_tupled_arg || i < arg_tys.len() - 1 { if type_of::arg_is_indirect(bcx.ccx(), arg_ty) && @@ -1669,7 +1720,7 @@ pub fn create_datums_for_fn_args<'a, 'tcx>(mut bcx: Block<'a, 'tcx>, let data = get_param(fcx.llfn, idx); let extra = get_param(fcx.llfn, idx + 1); idx += 2; - unpack_datum!(bcx, datum::lvalue_scratch_datum(bcx, arg_ty, "", + unpack_datum!(bcx, datum::lvalue_scratch_datum(bcx, arg_ty, "", uninit_reason, arg_scope_id, (data, extra), |(data, extra), bcx, dst| { Store(bcx, data, expr::get_dataptr(bcx, dst)); @@ -1684,6 +1735,7 @@ pub fn create_datums_for_fn_args<'a, 'tcx>(mut bcx: Block<'a, 'tcx>, datum::lvalue_scratch_datum(bcx, arg_ty, "", + uninit_reason, arg_scope_id, tmp, |tmp, bcx, dst| tmp.store_to(bcx, dst))) @@ -1696,6 +1748,7 @@ pub fn create_datums_for_fn_args<'a, 'tcx>(mut bcx: Block<'a, 'tcx>, datum::lvalue_scratch_datum(bcx, arg_ty, "tupled_args", + uninit_reason, arg_scope_id, (), |(), diff --git a/src/librustc_trans/trans/datum.rs b/src/librustc_trans/trans/datum.rs index 418ff4c8337e7..339b3f0f920d7 100644 --- a/src/librustc_trans/trans/datum.rs +++ b/src/librustc_trans/trans/datum.rs @@ -288,20 +288,29 @@ pub fn immediate_rvalue_bcx<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, return DatumBlock::new(bcx, immediate_rvalue(val, ty)) } - /// Allocates temporary space on the stack using alloca() and returns a by-ref Datum pointing to /// it. The memory will be dropped upon exit from `scope`. The callback `populate` should /// initialize the memory. +/// +/// The flag `zero` indicates how the temporary space itself should be +/// initialized at the outset of the function; the only time that +/// `InitAlloca::Uninit` is a valid value for `zero` is when the +/// caller can prove that either (1.) the code injected by `populate` +/// onto `bcx` always dominates the end of `scope`, or (2.) the data +/// being allocated has no associated destructor. pub fn lvalue_scratch_datum<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>, ty: Ty<'tcx>, name: &str, + zero: InitAlloca, scope: cleanup::ScopeId, arg: A, populate: F) -> DatumBlock<'blk, 'tcx, Lvalue> where F: FnOnce(A, Block<'blk, 'tcx>, ValueRef) -> Block<'blk, 'tcx>, { - let scratch = alloc_ty(bcx, ty, name); + // Very subtle: potentially initialize the scratch memory at point where it is alloca'ed. + // (See discussion at Issue 30530.) + let scratch = alloc_ty_init(bcx, ty, zero, name); // Subtle. Populate the scratch memory *before* scheduling cleanup. let bcx = populate(arg, bcx, scratch); @@ -496,7 +505,7 @@ impl<'tcx> Datum<'tcx, Rvalue> { ByValue => { lvalue_scratch_datum( - bcx, self.ty, name, scope, self, + bcx, self.ty, name, InitAlloca::Dropped, scope, self, |this, bcx, llval| { call_lifetime_start(bcx, llval); let bcx = this.store_to(bcx, llval); From cec7280bf367be9da472e02eba59b5440b5336c9 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 8 Jan 2016 20:40:13 +0100 Subject: [PATCH 12/22] debug instrumentation (can remove) --- src/librustc_trans/trans/_match.rs | 3 +++ src/librustc_trans/trans/adt.rs | 6 +++++- src/librustc_trans/trans/base.rs | 17 +++++++++++++++-- src/librustc_trans/trans/datum.rs | 6 ++++++ src/librustc_trans/trans/expr.rs | 2 ++ 5 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index 0ad780fb0e4d3..f46a7ea67b5f2 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -1760,6 +1760,9 @@ fn mk_binding_alloca<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>, let lvalue = Lvalue::new_with_hint(caller_name, bcx, p_id, HintKind::DontZeroJustUse); let datum = Datum::new(llval, var_ty, lvalue); + debug!("mk_binding_alloca cleanup_scope={:?} llval={} var_ty={:?}", + cleanup_scope, bcx.ccx().tn().val_to_string(llval), var_ty); + // Subtle: be sure that we *populate* the memory *before* // we schedule the cleanup. call_lifetime_start(bcx, llval); diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index e152e11a6a657..d22d619b96227 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -1281,7 +1281,11 @@ pub fn trans_drop_flag_ptr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let scratch = unpack_datum!(bcx, datum::lvalue_scratch_datum( bcx, tcx.dtor_type(), "drop_flag", InitAlloca::Uninit("drop flag itself has no dtor"), - cleanup::CustomScope(custom_cleanup_scope), (), |_, bcx, _| bcx + cleanup::CustomScope(custom_cleanup_scope), (), |_, bcx, _| { + debug!("no-op populate call for trans_drop_flag_ptr on dtor_type={:?}", + tcx.dtor_type()); + bcx + } )); bcx = fold_variants(bcx, r, val, |variant_cx, st, value| { let ptr = struct_field_ptr(variant_cx, st, MaybeSizedValue::sized(value), diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index b2bc7c2af933b..1e5c60609b0b8 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -1689,6 +1689,8 @@ pub fn create_datums_for_fn_args<'a, 'tcx>(mut bcx: Block<'a, 'tcx>, let fcx = bcx.fcx; let arg_scope_id = cleanup::CustomScope(arg_scope); + debug!("create_datums_for_fn_args"); + // Return an array wrapping the ValueRefs that we get from `get_param` for // each argument into datums. // @@ -1723,6 +1725,9 @@ pub fn create_datums_for_fn_args<'a, 'tcx>(mut bcx: Block<'a, 'tcx>, unpack_datum!(bcx, datum::lvalue_scratch_datum(bcx, arg_ty, "", uninit_reason, arg_scope_id, (data, extra), |(data, extra), bcx, dst| { + debug!("populate call for create_datum_for_fn_args \ + early fat arg, on arg[{}] ty={:?}", i, arg_ty); + Store(bcx, data, expr::get_dataptr(bcx, dst)); Store(bcx, extra, expr::get_meta(bcx, dst)); bcx @@ -1738,7 +1743,13 @@ pub fn create_datums_for_fn_args<'a, 'tcx>(mut bcx: Block<'a, 'tcx>, uninit_reason, arg_scope_id, tmp, - |tmp, bcx, dst| tmp.store_to(bcx, dst))) + |tmp, bcx, dst| { + + debug!("populate call for create_datum_for_fn_args \ + early thin arg, on arg[{}] ty={:?}", i, arg_ty); + + tmp.store_to(bcx, dst) + })) } } else { // FIXME(pcwalton): Reduce the amount of code bloat this is responsible for. @@ -1753,7 +1764,9 @@ pub fn create_datums_for_fn_args<'a, 'tcx>(mut bcx: Block<'a, 'tcx>, (), |(), mut bcx, - llval| { + llval| { + debug!("populate call for create_datum_for_fn_args \ + tupled_args, on arg[{}] ty={:?}", i, arg_ty); for (j, &tupled_arg_ty) in tupled_arg_tys.iter().enumerate() { let lldest = StructGEP(bcx, llval, j); diff --git a/src/librustc_trans/trans/datum.rs b/src/librustc_trans/trans/datum.rs index 339b3f0f920d7..6a033602adaba 100644 --- a/src/librustc_trans/trans/datum.rs +++ b/src/librustc_trans/trans/datum.rs @@ -311,6 +311,8 @@ pub fn lvalue_scratch_datum<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>, // Very subtle: potentially initialize the scratch memory at point where it is alloca'ed. // (See discussion at Issue 30530.) let scratch = alloc_ty_init(bcx, ty, zero, name); + debug!("lvalue_scratch_datum scope={:?} scratch={} ty={:?}", + scope, bcx.ccx().tn().val_to_string(scratch), ty); // Subtle. Populate the scratch memory *before* scheduling cleanup. let bcx = populate(arg, bcx, scratch); @@ -349,6 +351,8 @@ fn add_rvalue_clean<'a, 'tcx>(mode: RvalueMode, scope: cleanup::ScopeId, val: ValueRef, ty: Ty<'tcx>) { + debug!("add_rvalue_clean scope={:?} val={} ty={:?}", + scope, fcx.ccx.tn().val_to_string(val), ty); match mode { ByValue => { fcx.schedule_drop_immediate(scope, val, ty); } ByRef => { @@ -507,6 +511,8 @@ impl<'tcx> Datum<'tcx, Rvalue> { lvalue_scratch_datum( bcx, self.ty, name, InitAlloca::Dropped, scope, self, |this, bcx, llval| { + debug!("populate call for Datum::to_lvalue_datum_in_scope \ + self.ty={:?}", this.ty); call_lifetime_start(bcx, llval); let bcx = this.store_to(bcx, llval); bcx.fcx.schedule_lifetime_end(scope, llval); diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index fb6f2190207ee..57afd0b580f17 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -1487,6 +1487,8 @@ pub fn trans_adt<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } }; + debug!("trans_adt"); + // This scope holds intermediates that must be cleaned should // panic occur before the ADT as a whole is ready. let custom_cleanup_scope = fcx.push_custom_cleanup_scope(); From e3abc3cfe746c0ab078f33bc4566f6fb9773f489 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 12 Jan 2016 18:04:21 +0100 Subject: [PATCH 13/22] Don't use dropflag hints when the type is dropless --- src/librustc_trans/trans/base.rs | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index d694374acc927..daac6bae677c3 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -1565,6 +1565,7 @@ pub fn init_function<'a, 'tcx>(fcx: &'a FunctionContext<'a, 'tcx>, // Create the drop-flag hints for every unfragmented path in the function. let tcx = fcx.ccx.tcx(); let fn_did = tcx.map.local_def_id(fcx.id); + let tables = tcx.tables.borrow(); let mut hints = fcx.lldropflag_hints.borrow_mut(); let fragment_infos = tcx.fragment_infos.borrow(); @@ -1588,12 +1589,22 @@ pub fn init_function<'a, 'tcx>(fcx: &'a FunctionContext<'a, 'tcx>, let (var, datum) = match info { ty::FragmentInfo::Moved { var, .. } | ty::FragmentInfo::Assigned { var, .. } => { - let datum = seen.get(&var).cloned().unwrap_or_else(|| { - let datum = make_datum(var); - seen.insert(var, datum.clone()); - datum + let opt_datum = seen.get(&var).cloned().unwrap_or_else(|| { + let ty = tables.node_types[&var]; + if fcx.type_needs_drop(ty) { + let datum = make_datum(var); + seen.insert(var, Some(datum.clone())); + Some(datum) + } else { + // No drop call needed, so we don't need a dropflag hint + None + } }); - (var, datum) + if let Some(datum) = opt_datum { + (var, datum) + } else { + continue + } } }; match info { From fb82398b2a382649377b7e86407deff1aee4a229 Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Tue, 12 Jan 2016 11:58:52 +0100 Subject: [PATCH 14/22] Remove dead `InternalBufWriter` implementation In 8d90d3f36871a00023cc1f313f91e351c287ca15 `BufStream`, the only consumer of `InternalBufWriter`, was removed. As implied by the name, this type is private, hence it is currently dead code. --- src/libstd/io/buffered.rs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 16ce05ef2dcaf..a9a79fe2c7733 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -772,21 +772,6 @@ impl fmt::Debug for LineWriter where W: fmt::Debug { } } -struct InternalBufWriter(BufWriter); - -impl InternalBufWriter { - fn get_mut(&mut self) -> &mut BufWriter { - let InternalBufWriter(ref mut w) = *self; - return w; - } -} - -impl Read for InternalBufWriter { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.get_mut().inner.as_mut().unwrap().read(buf) - } -} - #[cfg(test)] mod tests { use prelude::v1::*; From b6cc0995b0bae79a5c4c3823fb462dd697d9a2e9 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Thu, 7 Jan 2016 14:54:17 -0500 Subject: [PATCH 15/22] Add some examples to std::string Fixes #30345 --- src/libcollections/string.rs | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index d2cbcad875f34..d9cafd53a851e 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -16,6 +16,42 @@ //! //! [`String`]: struct.String.html //! [`ToString`]: trait.ToString.html +//! +//! # Examples +//! +//! There are multiple ways to create a new `String` from a string literal: +//! +//! ```rust +//! let s = "Hello".to_string(); +//! +//! let s = String::from("world"); +//! let s: String = "also this".into(); +//! ``` +//! +//! You can create a new `String` from an existing one by concatenating with +//! `+`: +//! +//! ```rust +//! let s = "Hello".to_string(); +//! +//! let message = s + " world!"; +//! ``` +//! +//! If you have a vector of valid UTF-8 bytes, you can make a `String` out of +//! it. You can do the reverse too. +//! +//! ```rust +//! let sparkle_heart = vec![240, 159, 146, 150]; +//! +//! // We know these bytes are valid, so we'll use `unwrap()`. +//! let sparkle_heart = String::from_utf8(sparkle_heart).unwrap(); +//! +//! assert_eq!("💖", sparkle_heart); +//! +//! let bytes = sparkle_heart.into_bytes(); +//! +//! assert_eq!(bytes, [240, 159, 146, 150]); +//! ``` #![stable(feature = "rust1", since = "1.0.0")] From a8514d3ecca6bd404e2d7eff4deef31e3d00dad8 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 11 Jan 2016 21:19:29 +0000 Subject: [PATCH 16/22] resolve: use arena allocation instead of reference counting for `Module`s to fix memory leaks from Rc cycles --- mk/crates.mk | 2 +- src/librustc_resolve/build_reduced_graph.rs | 112 ++++---- src/librustc_resolve/lib.rs | 268 +++++++++++--------- src/librustc_resolve/record_exports.rs | 19 +- src/librustc_resolve/resolve_imports.rs | 104 ++++---- 5 files changed, 260 insertions(+), 245 deletions(-) diff --git a/mk/crates.mk b/mk/crates.mk index 2597c724da96f..9d6215a51cc88 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -103,7 +103,7 @@ DEPS_rustc_lint := rustc log syntax DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags DEPS_rustc_metadata := rustc rustc_front syntax rbml DEPS_rustc_mir := rustc rustc_front syntax -DEPS_rustc_resolve := rustc rustc_front log syntax +DEPS_rustc_resolve := arena rustc rustc_front log syntax DEPS_rustc_platform_intrinsics := rustc rustc_llvm DEPS_rustc_plugin := rustc rustc_metadata syntax DEPS_rustc_privacy := rustc rustc_front log syntax diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 8ed47300a1708..2e713a2f50e0f 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -21,7 +21,7 @@ use Module; use Namespace::{TypeNS, ValueNS}; use NameBindings; use {names_to_string, module_to_string}; -use ParentLink::{self, ModuleParentLink, BlockParentLink}; +use ParentLink::{ModuleParentLink, BlockParentLink}; use Resolver; use resolve_imports::Shadowable; use {resolve_error, resolve_struct_error, ResolutionError}; @@ -52,7 +52,6 @@ use rustc_front::intravisit::{self, Visitor}; use std::mem::replace; use std::ops::{Deref, DerefMut}; -use std::rc::Rc; // Specifies how duplicates should be handled when adding a child item if // another item exists with the same name in some namespace. @@ -86,7 +85,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { /// Constructs the reduced graph for the entire crate. fn build_reduced_graph(self, krate: &hir::Crate) { let mut visitor = BuildReducedGraphVisitor { - parent: self.graph_root.clone(), + parent: self.graph_root, builder: self, }; intravisit::walk_crate(&mut visitor, krate); @@ -97,12 +96,12 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { /// Returns the child's corresponding name bindings. fn add_child(&self, name: Name, - parent: &Rc, + parent: Module<'b>, duplicate_checking_mode: DuplicateCheckingMode, // For printing errors sp: Span) - -> NameBindings { - self.check_for_conflicts_between_external_crates_and_items(&**parent, name, sp); + -> NameBindings<'b> { + self.check_for_conflicts_between_external_crates_and_items(parent, name, sp); // Add or reuse the child. let child = parent.children.borrow().get(&name).cloned(); @@ -178,12 +177,8 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { return false; } - fn get_parent_link(&mut self, parent: &Rc, name: Name) -> ParentLink { - ModuleParentLink(Rc::downgrade(parent), name) - } - /// Constructs the reduced graph for one item. - fn build_reduced_graph_for_item(&mut self, item: &Item, parent: &Rc) -> Rc { + fn build_reduced_graph_for_item(&mut self, item: &Item, parent: Module<'b>) -> Module<'b> { let name = item.name; let sp = item.span; let is_public = item.vis == hir::Public; @@ -238,7 +233,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { } let subclass = SingleImport(binding, source_name); - self.build_import_directive(&**parent, + self.build_import_directive(parent, module_path, subclass, view_path.span, @@ -288,7 +283,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { (module_path.to_vec(), name, rename) } }; - self.build_import_directive(&**parent, + self.build_import_directive(parent, module_path, SingleImport(rename, name), source_item.span, @@ -298,7 +293,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { } } ViewPathGlob(_) => { - self.build_import_directive(&**parent, + self.build_import_directive(parent, module_path, GlobImport, view_path.span, @@ -307,7 +302,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { shadowable); } } - parent.clone() + parent } ItemExternCrate(_) => { @@ -319,32 +314,32 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { index: CRATE_DEF_INDEX, }; self.external_exports.insert(def_id); - let parent_link = ModuleParentLink(Rc::downgrade(parent), name); + let parent_link = ModuleParentLink(parent, name); let def = DefMod(def_id); - let external_module = Module::new(parent_link, Some(def), false, true); + let external_module = self.new_module(parent_link, Some(def), false, true); debug!("(build reduced graph for item) found extern `{}`", module_to_string(&*external_module)); - self.check_for_conflicts_for_external_crate(&parent, name, sp); + self.check_for_conflicts_for_external_crate(parent, name, sp); parent.external_module_children .borrow_mut() - .insert(name, external_module.clone()); + .insert(name, external_module); self.build_reduced_graph_for_external_crate(&external_module); } - parent.clone() + parent } ItemMod(..) => { let name_bindings = self.add_child(name, parent, ForbidDuplicateTypes, sp); - let parent_link = self.get_parent_link(parent, name); + let parent_link = ModuleParentLink(parent, name); let def = DefMod(self.ast_map.local_def_id(item.id)); - let module = Module::new(parent_link, Some(def), false, is_public); + let module = self.new_module(parent_link, Some(def), false, is_public); name_bindings.define_module(module.clone(), sp); module } - ItemForeignMod(..) => parent.clone(), + ItemForeignMod(..) => parent, // These items live in the value namespace. ItemStatic(_, m, _) => { @@ -354,19 +349,19 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { name_bindings.define_value(DefStatic(self.ast_map.local_def_id(item.id), mutbl), sp, modifiers); - parent.clone() + parent } ItemConst(_, _) => { self.add_child(name, parent, ForbidDuplicateValues, sp) .define_value(DefConst(self.ast_map.local_def_id(item.id)), sp, modifiers); - parent.clone() + parent } ItemFn(_, _, _, _, _, _) => { let name_bindings = self.add_child(name, parent, ForbidDuplicateValues, sp); let def = DefFn(self.ast_map.local_def_id(item.id), false); name_bindings.define_value(def, sp, modifiers); - parent.clone() + parent } // These items live in the type namespace. @@ -376,11 +371,11 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { ForbidDuplicateTypes, sp); - let parent_link = self.get_parent_link(parent, name); + let parent_link = ModuleParentLink(parent, name); let def = DefTy(self.ast_map.local_def_id(item.id), false); - let module = Module::new(parent_link, Some(def), false, is_public); + let module = self.new_module(parent_link, Some(def), false, is_public); name_bindings.define_module(module, sp); - parent.clone() + parent } ItemEnum(ref enum_definition, _) => { @@ -389,9 +384,9 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { ForbidDuplicateTypes, sp); - let parent_link = self.get_parent_link(parent, name); + let parent_link = ModuleParentLink(parent, name); let def = DefTy(self.ast_map.local_def_id(item.id), true); - let module = Module::new(parent_link, Some(def), false, is_public); + let module = self.new_module(parent_link, Some(def), false, is_public); name_bindings.define_module(module.clone(), sp); let variant_modifiers = if is_public { @@ -404,7 +399,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { self.build_reduced_graph_for_variant(variant, item_def_id, &module, variant_modifiers); } - parent.clone() + parent } // These items live in both the type and value namespaces. @@ -444,11 +439,11 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { let item_def_id = self.ast_map.local_def_id(item.id); self.structs.insert(item_def_id, named_fields); - parent.clone() + parent } ItemDefaultImpl(_, _) | - ItemImpl(..) => parent.clone(), + ItemImpl(..) => parent, ItemTrait(_, _, _, ref items) => { let name_bindings = self.add_child(name, @@ -459,9 +454,9 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { let def_id = self.ast_map.local_def_id(item.id); // Add all the items within to a new module. - let parent_link = self.get_parent_link(parent, name); + let parent_link = ModuleParentLink(parent, name); let def = DefTrait(def_id); - let module_parent = Module::new(parent_link, Some(def), false, is_public); + let module_parent = self.new_module(parent_link, Some(def), false, is_public); name_bindings.define_module(module_parent.clone(), sp); // Add the names of all the items to the trait info. @@ -494,7 +489,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { self.trait_item_map.insert((trait_item.name, def_id), trait_item_def_id); } - parent.clone() + parent } } } @@ -504,7 +499,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { fn build_reduced_graph_for_variant(&mut self, variant: &Variant, item_id: DefId, - parent: &Rc, + parent: Module<'b>, variant_modifiers: DefModifiers) { let name = variant.node.name; let is_exported = if variant.node.data.is_struct() { @@ -534,7 +529,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { /// Constructs the reduced graph for one foreign item. fn build_reduced_graph_for_foreign_item(&mut self, foreign_item: &ForeignItem, - parent: &Rc) { + parent: Module<'b>) { let name = foreign_item.name; let is_public = foreign_item.vis == hir::Public; let modifiers = if is_public { @@ -555,7 +550,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { name_bindings.define_value(def, foreign_item.span, modifiers); } - fn build_reduced_graph_for_block(&mut self, block: &Block, parent: &Rc) -> Rc { + fn build_reduced_graph_for_block(&mut self, block: &Block, parent: Module<'b>) -> Module<'b> { if self.block_needs_anonymous_module(block) { let block_id = block.id; @@ -563,22 +558,22 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { {}", block_id); - let parent_link = BlockParentLink(Rc::downgrade(parent), block_id); - let new_module = Module::new(parent_link, None, false, false); - parent.anonymous_children.borrow_mut().insert(block_id, new_module.clone()); + let parent_link = BlockParentLink(parent, block_id); + let new_module = self.new_module(parent_link, None, false, false); + parent.anonymous_children.borrow_mut().insert(block_id, new_module); new_module } else { - parent.clone() + parent } } fn handle_external_def(&mut self, def: Def, vis: Visibility, - child_name_bindings: &NameBindings, + child_name_bindings: &NameBindings<'b>, final_ident: &str, name: Name, - new_parent: &Rc) { + new_parent: Module<'b>) { debug!("(building reduced graph for external crate) building external def {}, priv {:?}", final_ident, vis); @@ -609,8 +604,8 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { debug!("(building reduced graph for external crate) building module {} {}", final_ident, is_public); - let parent_link = self.get_parent_link(new_parent, name); - let module = Module::new(parent_link, Some(def), true, is_public); + let parent_link = ModuleParentLink(new_parent, name); + let module = self.new_module(parent_link, Some(def), true, is_public); child_name_bindings.define_module(module, DUMMY_SP); } } @@ -681,8 +676,8 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { } // Define a module if necessary. - let parent_link = self.get_parent_link(new_parent, name); - let module = Module::new(parent_link, Some(def), true, is_public); + let parent_link = ModuleParentLink(new_parent, name); + let module = self.new_module(parent_link, Some(def), true, is_public); child_name_bindings.define_module(module, DUMMY_SP); } DefTy(..) | DefAssociatedTy(..) => { @@ -728,7 +723,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { /// Builds the reduced graph for a single item in an external crate. fn build_reduced_graph_for_external_crate_def(&mut self, - root: &Rc, + root: Module<'b>, xcdef: ChildItem) { match xcdef.def { DlDef(def) => { @@ -766,9 +761,9 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { } /// Builds the reduced graph rooted at the given external module. - fn populate_external_module(&mut self, module: &Rc) { + fn populate_external_module(&mut self, module: Module<'b>) { debug!("(populating external module) attempting to populate {}", - module_to_string(&**module)); + module_to_string(module)); let def_id = match module.def_id() { None => { @@ -788,7 +783,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { /// Ensures that the reduced graph rooted at the given external module /// is built, building it if it is not. - fn populate_module_if_necessary(&mut self, module: &Rc) { + fn populate_module_if_necessary(&mut self, module: Module<'b>) { if !module.populated.get() { self.populate_external_module(module) } @@ -797,7 +792,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { /// Builds the reduced graph rooted at the 'use' directive for an external /// crate. - fn build_reduced_graph_for_external_crate(&mut self, root: &Rc) { + fn build_reduced_graph_for_external_crate(&mut self, root: Module<'b>) { let root_cnum = root.def_id().unwrap().krate; for child in self.session.cstore.crate_top_level_items(root_cnum) { self.build_reduced_graph_for_external_crate_def(root, child); @@ -806,7 +801,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { /// Creates and adds an import directive to the given module. fn build_import_directive(&mut self, - module_: &Module, + module_: Module<'b>, module_path: Vec, subclass: ImportDirectiveSubclass, span: Span, @@ -866,7 +861,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { struct BuildReducedGraphVisitor<'a, 'b: 'a, 'tcx: 'b> { builder: GraphBuilder<'a, 'b, 'tcx>, - parent: Rc, + parent: Module<'b>, } impl<'a, 'b, 'v, 'tcx> Visitor<'v> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { @@ -897,6 +892,7 @@ pub fn build_reduced_graph(resolver: &mut Resolver, krate: &hir::Crate) { GraphBuilder { resolver: resolver }.build_reduced_graph(krate); } -pub fn populate_module_if_necessary(resolver: &mut Resolver, module: &Rc) { +pub fn populate_module_if_necessary<'a, 'tcx>(resolver: &mut Resolver<'a, 'tcx>, + module: Module<'a>) { GraphBuilder { resolver: resolver }.populate_module_if_necessary(module); } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index c7031f72af463..9857e83bd621a 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -26,6 +26,7 @@ extern crate log; #[macro_use] extern crate syntax; +extern crate arena; #[macro_use] #[no_link] extern crate rustc_bitflags; @@ -90,7 +91,7 @@ use std::collections::{HashMap, HashSet}; use std::cell::{Cell, RefCell}; use std::fmt; use std::mem::replace; -use std::rc::{Rc, Weak}; +use std::rc::Rc; use resolve_imports::{Target, ImportDirective, ImportResolutionPerNamespace}; use resolve_imports::Shadowable; @@ -576,7 +577,7 @@ pub enum Namespace { /// a particular namespace. The result is either definitely-resolved, /// definitely- unresolved, or unknown. #[derive(Clone)] -enum NamespaceResult { +enum NamespaceResult<'a> { /// Means that resolve hasn't gathered enough information yet to determine /// whether the name is bound in this namespace. (That is, it hasn't /// resolved all `use` directives yet.) @@ -586,10 +587,10 @@ enum NamespaceResult { UnboundResult, /// Means that resolve has determined that the name is bound in the Module /// argument, and specified by the NameBinding argument. - BoundResult(Rc, NameBinding), + BoundResult(Module<'a>, NameBinding<'a>), } -impl NamespaceResult { +impl<'a> NamespaceResult<'a> { fn is_unknown(&self) -> bool { match *self { UnknownResult => true, @@ -766,9 +767,9 @@ enum UseLexicalScopeFlag { UseLexicalScope, } -enum ModulePrefixResult { +enum ModulePrefixResult<'a> { NoPrefixFound, - PrefixFound(Rc, usize), + PrefixFound(Module<'a>, usize), } #[derive(Copy, Clone)] @@ -830,24 +831,24 @@ impl LocalDef { /// The link from a module up to its nearest parent node. #[derive(Clone,Debug)] -enum ParentLink { +enum ParentLink<'a> { NoParentLink, - ModuleParentLink(Weak, Name), - BlockParentLink(Weak, NodeId), + ModuleParentLink(Module<'a>, Name), + BlockParentLink(Module<'a>, NodeId), } /// One node in the tree of modules. -pub struct Module { - parent_link: ParentLink, +pub struct ModuleS<'a> { + parent_link: ParentLink<'a>, def: Cell>, is_public: bool, - children: RefCell>, + children: RefCell>>, imports: RefCell>, // The external module children of this node that were declared with // `extern crate`. - external_module_children: RefCell>>, + external_module_children: RefCell>>, // The anonymous children of this node. Anonymous children are pseudo- // modules that are implicitly created around items contained within @@ -863,10 +864,10 @@ pub struct Module { // // There will be an anonymous module created around `g` with the ID of the // entry block for `f`. - anonymous_children: RefCell>>, + anonymous_children: RefCell>>, // The status of resolving each import in this module. - import_resolutions: RefCell>, + import_resolutions: RefCell>>, // The number of unresolved globs that this module exports. glob_count: Cell, @@ -886,13 +887,11 @@ pub struct Module { populated: Cell, } -impl Module { - fn new(parent_link: ParentLink, - def: Option, - external: bool, - is_public: bool) - -> Rc { - Rc::new(Module { +pub type Module<'a> = &'a ModuleS<'a>; + +impl<'a> ModuleS<'a> { + fn new(parent_link: ParentLink<'a>, def: Option, external: bool, is_public: bool) -> Self { + ModuleS { parent_link: parent_link, def: Cell::new(def), is_public: is_public, @@ -906,7 +905,7 @@ impl Module { pub_glob_count: Cell::new(0), resolved_import_count: Cell::new(0), populated: Cell::new(!external), - }) + } } fn def_id(&self) -> Option { @@ -935,9 +934,7 @@ impl Module { self.imports.borrow().len() == self.resolved_import_count.get() } } -} -impl Module { pub fn inc_glob_count(&self) { self.glob_count.set(self.glob_count.get() + 1); } @@ -961,7 +958,7 @@ impl Module { } } -impl fmt::Debug for Module { +impl<'a> fmt::Debug for ModuleS<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:?}, {}", @@ -989,20 +986,20 @@ bitflags! { // Records a possibly-private value, type, or module definition. #[derive(Debug)] -struct NsDef { +struct NsDef<'a> { modifiers: DefModifiers, // see note in ImportResolutionPerNamespace about how to use this - def_or_module: DefOrModule, + def_or_module: DefOrModule<'a>, span: Option, } #[derive(Debug)] -enum DefOrModule { +enum DefOrModule<'a> { Def(Def), - Module(Rc), + Module(Module<'a>), } -impl NsDef { - fn create_from_module(module: Rc, span: Option) -> Self { +impl<'a> NsDef<'a> { + fn create_from_module(module: Module<'a>, span: Option) -> Self { let modifiers = if module.is_public { DefModifiers::PUBLIC } else { @@ -1016,9 +1013,9 @@ impl NsDef { NsDef { modifiers: modifiers, def_or_module: DefOrModule::Def(def), span: span } } - fn module(&self) -> Option> { + fn module(&self) -> Option> { match self.def_or_module { - DefOrModule::Module(ref module) => Some(module.clone()), + DefOrModule::Module(ref module) => Some(module), DefOrModule::Def(_) => None, } } @@ -1033,18 +1030,18 @@ impl NsDef { // Records at most one definition that a name in a namespace is bound to #[derive(Clone,Debug)] -pub struct NameBinding(Rc>>); +pub struct NameBinding<'a>(Rc>>>); -impl NameBinding { +impl<'a> NameBinding<'a> { fn new() -> Self { NameBinding(Rc::new(RefCell::new(None))) } - fn create_from_module(module: Rc) -> Self { + fn create_from_module(module: Module<'a>) -> Self { NameBinding(Rc::new(RefCell::new(Some(NsDef::create_from_module(module, None))))) } - fn set(&self, ns_def: NsDef) { + fn set(&self, ns_def: NsDef<'a>) { *self.0.borrow_mut() = Some(ns_def); } @@ -1054,7 +1051,7 @@ impl NameBinding { } } - fn borrow(&self) -> ::std::cell::Ref> { + fn borrow(&self) -> ::std::cell::Ref>> { self.0.borrow() } @@ -1062,7 +1059,7 @@ impl NameBinding { fn def(&self) -> Option { self.borrow().as_ref().and_then(NsDef::def) } - fn module(&self) -> Option> { + fn module(&self) -> Option> { self.borrow().as_ref().and_then(NsDef::module) } fn span(&self) -> Option { @@ -1093,20 +1090,20 @@ impl NameBinding { // Records the definitions (at most one for each namespace) that a name is // bound to. #[derive(Clone,Debug)] -pub struct NameBindings { - type_ns: NameBinding, // < Meaning in type namespace. - value_ns: NameBinding, // < Meaning in value namespace. +pub struct NameBindings<'a> { + type_ns: NameBinding<'a>, // < Meaning in type namespace. + value_ns: NameBinding<'a>, // < Meaning in value namespace. } -impl ::std::ops::Index for NameBindings { - type Output = NameBinding; - fn index(&self, namespace: Namespace) -> &NameBinding { +impl<'a> ::std::ops::Index for NameBindings<'a> { + type Output = NameBinding<'a>; + fn index(&self, namespace: Namespace) -> &NameBinding<'a> { match namespace { TypeNS => &self.type_ns, ValueNS => &self.value_ns } } } -impl NameBindings { - fn new() -> NameBindings { +impl<'a> NameBindings<'a> { + fn new() -> Self { NameBindings { type_ns: NameBinding::new(), value_ns: NameBinding::new(), @@ -1114,7 +1111,7 @@ impl NameBindings { } /// Creates a new module in this set of name bindings. - fn define_module(&self, module: Rc, sp: Span) { + fn define_module(&self, module: Module<'a>, sp: Span) { self.type_ns.set(NsDef::create_from_module(module, Some(sp))); } @@ -1170,7 +1167,7 @@ pub struct Resolver<'a, 'tcx: 'a> { ast_map: &'a hir_map::Map<'tcx>, - graph_root: Rc, + graph_root: Module<'a>, trait_item_map: FnvHashMap<(Name, DefId), DefId>, @@ -1180,7 +1177,7 @@ pub struct Resolver<'a, 'tcx: 'a> { unresolved_imports: usize, // The module that represents the current item scope. - current_module: Rc, + current_module: Module<'a>, // The current set of local scopes, for values. // FIXME #4948: Reuse ribs to avoid allocation. @@ -1226,6 +1223,12 @@ pub struct Resolver<'a, 'tcx: 'a> { // The intention is that the callback modifies this flag. // Once set, the resolver falls out of the walk, preserving the ribs. resolved: bool, + + arenas: &'a ResolverArenas<'a>, +} + +pub struct ResolverArenas<'a> { + modules: arena::TypedArena>, } #[derive(PartialEq)] @@ -1237,10 +1240,12 @@ enum FallbackChecks { impl<'a, 'tcx> Resolver<'a, 'tcx> { fn new(session: &'a Session, ast_map: &'a hir_map::Map<'tcx>, - make_glob_map: MakeGlobMap) + make_glob_map: MakeGlobMap, + arenas: &'a ResolverArenas<'a>) -> Resolver<'a, 'tcx> { let root_def_id = ast_map.local_def_id(CRATE_NODE_ID); - let graph_root = Module::new(NoParentLink, Some(DefMod(root_def_id)), false, true); + let graph_root = ModuleS::new(NoParentLink, Some(DefMod(root_def_id)), false, true); + let graph_root = arenas.modules.alloc(graph_root); Resolver { session: session, @@ -1249,7 +1254,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // The outermost module has def ID 0; this is not reflected in the // AST. - graph_root: graph_root.clone(), + graph_root: graph_root, trait_item_map: FnvHashMap(), structs: FnvHashMap(), @@ -1281,9 +1286,25 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { callback: None, resolved: false, + + arenas: arenas, + } + } + + fn arenas() -> ResolverArenas<'a> { + ResolverArenas { + modules: arena::TypedArena::new(), } } + fn new_module(&self, + parent_link: ParentLink<'a>, + def: Option, + external: bool, + is_public: bool) -> Module<'a> { + self.arenas.modules.alloc(ModuleS::new(parent_link, def, external, is_public)) + } + #[inline] fn record_import_use(&mut self, import_id: NodeId, name: Name) { if !self.make_glob_map { @@ -1308,7 +1329,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } /// Check that an external crate doesn't collide with items or other external crates. - fn check_for_conflicts_for_external_crate(&self, module: &Module, name: Name, span: Span) { + fn check_for_conflicts_for_external_crate(&self, module: Module<'a>, name: Name, span: Span) { if module.external_module_children.borrow().contains_key(&name) { span_err!(self.session, span, @@ -1328,7 +1349,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { /// Checks that the names of items don't collide with external crates. fn check_for_conflicts_between_external_crates_and_items(&self, - module: &Module, + module: Module<'a>, name: Name, span: Span) { if module.external_module_children.borrow().contains_key(&name) { @@ -1338,19 +1359,20 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { /// Resolves the given module path from the given root `module_`. fn resolve_module_path_from_root(&mut self, - module_: Rc, + module_: Module<'a>, module_path: &[Name], index: usize, span: Span, name_search_type: NameSearchType, lp: LastPrivate) - -> ResolveResult<(Rc, LastPrivate)> { - fn search_parent_externals(needle: Name, module: &Rc) -> Option> { + -> ResolveResult<(Module<'a>, LastPrivate)> { + fn search_parent_externals<'a>(needle: Name, module: Module<'a>) + -> Option> { match module.external_module_children.borrow().get(&needle) { - Some(_) => Some(module.clone()), + Some(_) => Some(module), None => match module.parent_link { ModuleParentLink(ref parent, _) => { - search_parent_externals(needle, &parent.upgrade().unwrap()) + search_parent_externals(needle, parent) } _ => None, }, @@ -1367,14 +1389,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // modules as we go. while index < module_path_len { let name = module_path[index]; - match self.resolve_name_in_module(search_module.clone(), + match self.resolve_name_in_module(search_module, name, TypeNS, name_search_type, false) { Failed(None) => { let segment_name = name.as_str(); - let module_name = module_to_string(&*search_module); + let module_name = module_to_string(search_module); let mut span = span; let msg = if "???" == &module_name[..] { span.hi = span.lo + Pos::from_usize(segment_name.len()); @@ -1445,12 +1467,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { /// On success, returns the resolved module, and the closest *private* /// module found to the destination when resolving this path. fn resolve_module_path(&mut self, - module_: Rc, + module_: Module<'a>, module_path: &[Name], use_lexical_scope: UseLexicalScopeFlag, span: Span, name_search_type: NameSearchType) - -> ResolveResult<(Rc, LastPrivate)> { + -> ResolveResult<(Module<'a>, LastPrivate)> { let module_path_len = module_path.len(); assert!(module_path_len > 0); @@ -1459,7 +1481,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { module_to_string(&*module_)); // Resolve the module prefix, if any. - let module_prefix_result = self.resolve_module_prefix(module_.clone(), module_path); + let module_prefix_result = self.resolve_module_prefix(module_, module_path); let search_module; let start_index; @@ -1495,7 +1517,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { DontUseLexicalScope => { // This is a crate-relative path. We will start the // resolution process at index zero. - search_module = self.graph_root.clone(); + search_module = self.graph_root; start_index = 0; last_private = LastMod(AllPublic); } @@ -1519,7 +1541,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } Success(PrefixFound(ref containing_module, index)) => { - search_module = containing_module.clone(); + search_module = containing_module; start_index = index; last_private = LastMod(DependsOn(containing_module.def_id() .unwrap())); @@ -1537,11 +1559,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { /// Invariant: This must only be called during main resolution, not during /// import resolution. fn resolve_item_in_lexical_scope(&mut self, - module_: Rc, + module_: Module<'a>, name: Name, namespace: Namespace, record_used: bool) - -> ResolveResult<(Target, bool)> { + -> ResolveResult<(Target<'a>, bool)> { debug!("(resolving item in lexical scope) resolving `{}` in namespace {:?} in `{}`", name, namespace, @@ -1554,7 +1576,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { match module_.children.borrow().get(&name) { Some(name_bindings) if name_bindings[namespace].defined() => { debug!("top name bindings succeeded"); - return Success((Target::new(module_.clone(), + return Success((Target::new(module_, name_bindings[namespace].clone(), Shadowable::Never), false)); @@ -1594,9 +1616,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // Search for external modules. if namespace == TypeNS { - // FIXME (21114): In principle unclear `child` *has* to be lifted. - let child = module_.external_module_children.borrow().get(&name).cloned(); - if let Some(module) = child { + let children = module_.external_module_children.borrow(); + if let Some(module) = children.get(&name) { let name_binding = NameBinding::create_from_module(module); debug!("lower name bindings succeeded"); return Success((Target::new(module_, name_binding, Shadowable::Never), @@ -1608,7 +1629,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let mut search_module = module_; loop { // Go to the next parent. - match search_module.parent_link.clone() { + match search_module.parent_link { NoParentLink => { // No more parents. This module was unresolved. debug!("(resolving item in lexical scope) unresolved module"); @@ -1621,16 +1642,16 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { searching through module parents"); return Failed(None); } else { - search_module = parent_module_node.upgrade().unwrap(); + search_module = parent_module_node; } } - BlockParentLink(ref parent_module_node, _) => { - search_module = parent_module_node.upgrade().unwrap(); + BlockParentLink(parent_module_node, _) => { + search_module = parent_module_node; } } // Resolve the name in the parent module. - match self.resolve_name_in_module(search_module.clone(), + match self.resolve_name_in_module(search_module, name, namespace, PathSearch, @@ -1657,9 +1678,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { /// Resolves a module name in the current lexical scope. fn resolve_module_in_lexical_scope(&mut self, - module_: Rc, + module_: Module<'a>, name: Name) - -> ResolveResult> { + -> ResolveResult> { // If this module is an anonymous module, resolve the item in the // lexical scope. Otherwise, resolve the item from the crate root. let resolve_result = self.resolve_item_in_lexical_scope(module_, name, TypeNS, true); @@ -1685,14 +1706,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } /// Returns the nearest normal module parent of the given module. - fn get_nearest_normal_module_parent(&mut self, module_: Rc) -> Option> { + fn get_nearest_normal_module_parent(&mut self, module_: Module<'a>) -> Option> { let mut module_ = module_; loop { - match module_.parent_link.clone() { + match module_.parent_link { NoParentLink => return None, ModuleParentLink(new_module, _) | BlockParentLink(new_module, _) => { - let new_module = new_module.upgrade().unwrap(); + let new_module = new_module; if new_module.is_normal() { return Some(new_module); } @@ -1704,11 +1725,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { /// Returns the nearest normal module parent of the given module, or the /// module itself if it is a normal module. - fn get_nearest_normal_module_parent_or_self(&mut self, module_: Rc) -> Rc { + fn get_nearest_normal_module_parent_or_self(&mut self, module_: Module<'a>) -> Module<'a> { if module_.is_normal() { return module_; } - match self.get_nearest_normal_module_parent(module_.clone()) { + match self.get_nearest_normal_module_parent(module_) { None => module_, Some(new_module) => new_module, } @@ -1718,9 +1739,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { /// (b) some chain of `super::`. /// grammar: (SELF MOD_SEP ) ? (SUPER MOD_SEP) * fn resolve_module_prefix(&mut self, - module_: Rc, + module_: Module<'a>, module_path: &[Name]) - -> ResolveResult { + -> ResolveResult> { // Start at the current module if we see `self` or `super`, or at the // top of the crate otherwise. let mut i = match &*module_path[0].as_str() { @@ -1756,12 +1777,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { /// The boolean returned on success is an indicator of whether this lookup /// passed through a public re-export proxy. fn resolve_name_in_module(&mut self, - module_: Rc, + module_: Module<'a>, name: Name, namespace: Namespace, name_search_type: NameSearchType, allow_private_imports: bool) - -> ResolveResult<(Target, bool)> { + -> ResolveResult<(Target<'a>, bool)> { debug!("(resolving name in module) resolving `{}` in `{}`", name, module_to_string(&*module_)); @@ -1769,10 +1790,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // First, check the direct children of the module. build_reduced_graph::populate_module_if_necessary(self, &module_); - match module_.children.borrow().get(&name) { + let children = module_.children.borrow(); + match children.get(&name) { Some(name_bindings) if name_bindings[namespace].defined() => { debug!("(resolving name in module) found node as child"); - return Success((Target::new(module_.clone(), + return Success((Target::new(module_, name_bindings[namespace].clone(), Shadowable::Never), false)); @@ -1791,7 +1813,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } // Check the list of resolved imports. - match module_.import_resolutions.borrow().get(&name) { + let children = module_.import_resolutions.borrow(); + match children.get(&name) { Some(import_resolution) if allow_private_imports || import_resolution[namespace].is_public => { @@ -1823,9 +1846,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // Finally, search through external children. if namespace == TypeNS { - // FIXME (21114): In principle unclear `child` *has* to be lifted. - let child = module_.external_module_children.borrow().get(&name).cloned(); - if let Some(module) = child { + let children = module_.external_module_children.borrow(); + if let Some(module) = children.get(&name) { let name_binding = NameBinding::create_from_module(module); return Success((Target::new(module_, name_binding, Shadowable::Never), false)); @@ -1837,7 +1859,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { return Failed(None); } - fn report_unresolved_imports(&mut self, module_: Rc) { + fn report_unresolved_imports(&mut self, module_: Module<'a>) { let index = module_.resolved_import_count.get(); let imports = module_.imports.borrow(); let import_count = imports.len(); @@ -1862,7 +1884,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } for (_, module_) in module_.anonymous_children.borrow().iter() { - self.report_unresolved_imports(module_.clone()); + self.report_unresolved_imports(module_); } } @@ -1887,7 +1909,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn with_scope(&mut self, name: Option, f: F) where F: FnOnce(&mut Resolver) { - let orig_module = self.current_module.clone(); + let orig_module = self.current_module; // Move down in the graph. match name { @@ -2475,14 +2497,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { self.value_ribs.push(Rib::new(NormalRibKind)); // Move down in the graph, if there's an anonymous module rooted here. - let orig_module = self.current_module.clone(); + let orig_module = self.current_module; match orig_module.anonymous_children.borrow().get(&block.id) { None => { // Nothing to do. } Some(anonymous_module) => { debug!("(resolving block) found anonymous module, moving down"); - self.current_module = anonymous_module.clone(); + self.current_module = anonymous_module; } } @@ -2871,7 +2893,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { name: Name, span: Span) -> BareIdentifierPatternResolution { - let module = self.current_module.clone(); + let module = self.current_module; match self.resolve_item_in_lexical_scope(module, name, ValueNS, true) { Success((target, _)) => { debug!("(resolve bare identifier pattern) succeeded in finding {} at {:?}", @@ -3135,7 +3157,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let containing_module; let last_private; - let current_module = self.current_module.clone(); + let current_module = self.current_module; match self.resolve_module_path(current_module, &module_path[..], UseLexicalScope, @@ -3162,7 +3184,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } let name = segments.last().unwrap().identifier.name; - let def = match self.resolve_name_in_module(containing_module.clone(), + let def = match self.resolve_name_in_module(containing_module, name, namespace, NameSearchType::PathSearch, @@ -3193,7 +3215,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { .map(|ps| ps.identifier.name) .collect::>(); - let root_module = self.graph_root.clone(); + let root_module = self.graph_root; let containing_module; let last_private; @@ -3283,7 +3305,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { record_used: bool) -> Option { // Check the items. - let module = self.current_module.clone(); + let module = self.current_module; match self.resolve_item_in_lexical_scope(module, name, namespace, record_used) { Success((target, _)) => { match target.binding.def() { @@ -3345,11 +3367,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - fn get_module(this: &mut Resolver, - span: Span, - name_path: &[ast::Name]) - -> Option> { - let root = this.current_module.clone(); + fn get_module<'a, 'tcx>(this: &mut Resolver<'a, 'tcx>, + span: Span, + name_path: &[ast::Name]) + -> Option> { + let root = this.current_module; let last_name = name_path.last().unwrap(); if name_path.len() == 1 { @@ -3603,7 +3625,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let name_path = path.segments.iter() .map(|seg| seg.identifier.name) .collect::>(); - let current_module = self.current_module.clone(); + let current_module = self.current_module; match self.resolve_module_path(current_module, &name_path[..], @@ -3725,7 +3747,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } let mut found_traits = Vec::new(); - let mut search_module = self.current_module.clone(); + let mut search_module = self.current_module; loop { // Look for the current trait. match self.current_trait_ref { @@ -3778,10 +3800,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - match search_module.parent_link.clone() { + match search_module.parent_link { NoParentLink | ModuleParentLink(..) => break, BlockParentLink(parent_module, _) => { - search_module = parent_module.upgrade().unwrap(); + search_module = parent_module; } } } @@ -3828,7 +3850,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // #[allow(dead_code)] // useful for debugging - fn dump_module(&mut self, module_: Rc) { + fn dump_module(&mut self, module_: Module<'a>) { debug!("Dump of module `{}`:", module_to_string(&*module_)); debug!("Children:"); @@ -3891,20 +3913,20 @@ fn path_names_to_string(path: &Path, depth: usize) -> String { } /// A somewhat inefficient routine to obtain the name of a module. -fn module_to_string(module: &Module) -> String { +fn module_to_string<'a>(module: Module<'a>) -> String { let mut names = Vec::new(); - fn collect_mod(names: &mut Vec, module: &Module) { + fn collect_mod<'a>(names: &mut Vec, module: Module<'a>) { match module.parent_link { NoParentLink => {} ModuleParentLink(ref module, name) => { names.push(name); - collect_mod(names, &*module.upgrade().unwrap()); + collect_mod(names, module); } BlockParentLink(ref module, _) => { // danger, shouldn't be ident? names.push(special_idents::opaque.name); - collect_mod(names, &*module.upgrade().unwrap()); + collect_mod(names, module); } } } @@ -3946,7 +3968,8 @@ pub fn resolve_crate<'a, 'tcx>(session: &'a Session, make_glob_map: MakeGlobMap) -> CrateMap { let krate = ast_map.krate(); - let mut resolver = create_resolver(session, ast_map, krate, make_glob_map, None); + let arenas = Resolver::arenas(); + let mut resolver = create_resolver(session, ast_map, krate, make_glob_map, &arenas, None); resolver.resolve_crate(krate); @@ -3978,9 +4001,10 @@ pub fn create_resolver<'a, 'tcx>(session: &'a Session, ast_map: &'a hir_map::Map<'tcx>, krate: &'a Crate, make_glob_map: MakeGlobMap, + arenas: &'a ResolverArenas<'a>, callback: Option bool>>) -> Resolver<'a, 'tcx> { - let mut resolver = Resolver::new(session, ast_map, make_glob_map); + let mut resolver = Resolver::new(session, ast_map, make_glob_map, arenas); resolver.callback = callback; diff --git a/src/librustc_resolve/record_exports.rs b/src/librustc_resolve/record_exports.rs index 59cf83e91d2da..13f4348f79522 100644 --- a/src/librustc_resolve/record_exports.rs +++ b/src/librustc_resolve/record_exports.rs @@ -28,7 +28,6 @@ use rustc::middle::def::Export; use syntax::ast; use std::ops::{Deref, DerefMut}; -use std::rc::Rc; struct ExportRecorder<'a, 'b: 'a, 'tcx: 'b> { resolver: &'a mut Resolver<'b, 'tcx>, @@ -50,7 +49,7 @@ impl<'a, 'b, 'tcx:'b> DerefMut for ExportRecorder<'a, 'b, 'tcx> { } impl<'a, 'b, 'tcx> ExportRecorder<'a, 'b, 'tcx> { - fn record_exports_for_module_subtree(&mut self, module_: Rc) { + fn record_exports_for_module_subtree(&mut self, module_: Module<'b>) { // If this isn't a local krate, then bail out. We don't need to record // exports for nonlocal crates. @@ -59,23 +58,23 @@ impl<'a, 'b, 'tcx> ExportRecorder<'a, 'b, 'tcx> { // OK. Continue. debug!("(recording exports for module subtree) recording exports for local \ module `{}`", - module_to_string(&*module_)); + module_to_string(module_)); } None => { // Record exports for the root module. debug!("(recording exports for module subtree) recording exports for root module \ `{}`", - module_to_string(&*module_)); + module_to_string(module_)); } Some(_) => { // Bail out. debug!("(recording exports for module subtree) not recording exports for `{}`", - module_to_string(&*module_)); + module_to_string(module_)); return; } } - self.record_exports_for_module(&*module_); + self.record_exports_for_module(module_); build_reduced_graph::populate_module_if_necessary(self.resolver, &module_); for (_, child_name_bindings) in module_.children.borrow().iter() { @@ -90,11 +89,11 @@ impl<'a, 'b, 'tcx> ExportRecorder<'a, 'b, 'tcx> { } for (_, child_module) in module_.anonymous_children.borrow().iter() { - self.record_exports_for_module_subtree(child_module.clone()); + self.record_exports_for_module_subtree(child_module); } } - fn record_exports_for_module(&mut self, module_: &Module) { + fn record_exports_for_module(&mut self, module_: Module<'b>) { let mut exports = Vec::new(); self.add_exports_for_module(&mut exports, module_); @@ -128,7 +127,7 @@ impl<'a, 'b, 'tcx> ExportRecorder<'a, 'b, 'tcx> { } } - fn add_exports_for_module(&mut self, exports: &mut Vec, module_: &Module) { + fn add_exports_for_module(&mut self, exports: &mut Vec, module_: Module<'b>) { for (name, import_resolution) in module_.import_resolutions.borrow().iter() { let xs = [TypeNS, ValueNS]; for &ns in &xs { @@ -150,6 +149,6 @@ impl<'a, 'b, 'tcx> ExportRecorder<'a, 'b, 'tcx> { pub fn record(resolver: &mut Resolver) { let mut recorder = ExportRecorder { resolver: resolver }; - let root_module = recorder.graph_root.clone(); + let root_module = recorder.graph_root; recorder.record_exports_for_module_subtree(root_module); } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 40bf55efde645..53d1b888d8e87 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -36,7 +36,6 @@ use syntax::codemap::Span; use syntax::util::lev_distance::find_best_match_for_name; use std::mem::replace; -use std::rc::Rc; /// Contains data for specific types of import directives. #[derive(Copy, Clone,Debug)] @@ -84,17 +83,15 @@ impl ImportDirective { /// The item that an import resolves to. #[derive(Clone,Debug)] -pub struct Target { - pub target_module: Rc, - pub binding: NameBinding, +pub struct Target<'a> { + pub target_module: Module<'a>, + pub binding: NameBinding<'a>, pub shadowable: Shadowable, } -impl Target { - pub fn new(target_module: Rc, - binding: NameBinding, - shadowable: Shadowable) - -> Target { +impl<'a> Target<'a> { + pub fn new(target_module: Module<'a>, binding: NameBinding<'a>, shadowable: Shadowable) + -> Self { Target { target_module: target_module, binding: binding, @@ -109,44 +106,44 @@ impl Target { /// and for each namespace, it records the `use` directive importing the name in the namespace /// and the `Target` to which the name in the namespace resolves (if applicable). /// Different `use` directives may import the same name in different namespaces. -pub struct ImportResolutionPerNamespace { +pub struct ImportResolutionPerNamespace<'a> { // When outstanding_references reaches zero, outside modules can count on the targets being // correct. Before then, all bets are off; future `use` directives could override the name. // Since shadowing is forbidden, the only way outstanding_references > 1 in a legal program // is if the name is imported by exactly two `use` directives, one of which resolves to a // value and the other of which resolves to a type. pub outstanding_references: usize, - pub type_ns: ImportResolution, - pub value_ns: ImportResolution, + pub type_ns: ImportResolution<'a>, + pub value_ns: ImportResolution<'a>, } /// Records what we know about an imported name in a namespace (see `ImportResolutionPerNamespace`). #[derive(Clone,Debug)] -pub struct ImportResolution { +pub struct ImportResolution<'a> { /// Whether the name in the namespace was imported with a `use` or a `pub use`. pub is_public: bool, /// Resolution of the name in the namespace - pub target: Option, + pub target: Option>, /// The source node of the `use` directive pub id: NodeId, } -impl ::std::ops::Index for ImportResolutionPerNamespace { - type Output = ImportResolution; - fn index(&self, ns: Namespace) -> &ImportResolution { +impl<'a> ::std::ops::Index for ImportResolutionPerNamespace<'a> { + type Output = ImportResolution<'a>; + fn index(&self, ns: Namespace) -> &ImportResolution<'a> { match ns { TypeNS => &self.type_ns, ValueNS => &self.value_ns } } } -impl ::std::ops::IndexMut for ImportResolutionPerNamespace { - fn index_mut(&mut self, ns: Namespace) -> &mut ImportResolution { +impl<'a> ::std::ops::IndexMut for ImportResolutionPerNamespace<'a> { + fn index_mut(&mut self, ns: Namespace) -> &mut ImportResolution<'a> { match ns { TypeNS => &mut self.type_ns, ValueNS => &mut self.value_ns } } } -impl ImportResolutionPerNamespace { +impl<'a> ImportResolutionPerNamespace<'a> { pub fn new(id: NodeId, is_public: bool) -> Self { let resolution = ImportResolution { id: id, is_public: is_public, target: None }; ImportResolutionPerNamespace { @@ -191,8 +188,8 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { i, self.resolver.unresolved_imports); - let module_root = self.resolver.graph_root.clone(); - let errors = self.resolve_imports_for_module_subtree(module_root.clone()); + let module_root = self.resolver.graph_root; + let errors = self.resolve_imports_for_module_subtree(module_root); if self.resolver.unresolved_imports == 0 { debug!("(resolving imports) success"); @@ -225,13 +222,13 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { /// Attempts to resolve imports for the given module and all of its /// submodules. fn resolve_imports_for_module_subtree(&mut self, - module_: Rc) + module_: Module<'b>) -> Vec { let mut errors = Vec::new(); debug!("(resolving imports for module subtree) resolving {}", module_to_string(&*module_)); - let orig_module = replace(&mut self.resolver.current_module, module_.clone()); - errors.extend(self.resolve_imports_for_module(module_.clone())); + let orig_module = replace(&mut self.resolver.current_module, module_); + errors.extend(self.resolve_imports_for_module(module_)); self.resolver.current_module = orig_module; build_reduced_graph::populate_module_if_necessary(self.resolver, &module_); @@ -247,14 +244,14 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { } for (_, child_module) in module_.anonymous_children.borrow().iter() { - errors.extend(self.resolve_imports_for_module_subtree(child_module.clone())); + errors.extend(self.resolve_imports_for_module_subtree(child_module)); } errors } /// Attempts to resolve imports for the given module only. - fn resolve_imports_for_module(&mut self, module: Rc) -> Vec { + fn resolve_imports_for_module(&mut self, module: Module<'b>) -> Vec { let mut errors = Vec::new(); if module.all_imports_resolved() { @@ -268,7 +265,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { let mut indeterminate_imports = Vec::new(); while module.resolved_import_count.get() + indeterminate_imports.len() < import_count { let import_index = module.resolved_import_count.get(); - match self.resolve_import_for_module(module.clone(), &imports[import_index]) { + match self.resolve_import_for_module(module, &imports[import_index]) { ResolveResult::Failed(err) => { let import_directive = &imports[import_index]; let (span, help) = match err { @@ -306,7 +303,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { /// currently-unresolved imports, or success if we know the name exists. /// If successful, the resolved bindings are written into the module. fn resolve_import_for_module(&mut self, - module_: Rc, + module_: Module<'b>, import_directive: &ImportDirective) -> ResolveResult<()> { let mut resolution_result = ResolveResult::Failed(None); @@ -319,9 +316,9 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { // First, resolve the module path for the directive, if necessary. let container = if module_path.is_empty() { // Use the crate root. - Some((self.resolver.graph_root.clone(), LastMod(AllPublic))) + Some((self.resolver.graph_root, LastMod(AllPublic))) } else { - match self.resolver.resolve_module_path(module_.clone(), + match self.resolver.resolve_module_path(module_, &module_path[..], UseLexicalScopeFlag::DontUseLexicalScope, import_directive.span, @@ -399,8 +396,8 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { } fn resolve_single_import(&mut self, - module_: &Module, - target_module: Rc, + module_: Module<'b>, + target_module: Module<'b>, target: Name, source: Name, directive: &ImportDirective, @@ -447,7 +444,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { let mut pub_err = false; if child_name_bindings.value_ns.defined() { debug!("(resolving single import) found value binding"); - value_result = BoundResult(target_module.clone(), + value_result = BoundResult(target_module, child_name_bindings.value_ns.clone()); if directive.is_public && !child_name_bindings.value_ns.is_public() { let msg = format!("`{}` is private, and cannot be reexported", source); @@ -473,7 +470,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { } if child_name_bindings.type_ns.defined() { debug!("(resolving single import) found type binding"); - type_result = BoundResult(target_module.clone(), + type_result = BoundResult(target_module, child_name_bindings.type_ns.clone()); if !pub_err && directive.is_public && !child_name_bindings.type_ns.is_public() { @@ -543,11 +540,11 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { } Some(import_resolution) if import_resolution.outstanding_references == 0 => { - fn get_binding(this: &mut Resolver, - import_resolution: &ImportResolutionPerNamespace, - namespace: Namespace, - source: Name) - -> NamespaceResult { + fn get_binding<'a>(this: &mut Resolver, + import_resolution: &ImportResolutionPerNamespace<'a>, + namespace: Namespace, + source: Name) + -> NamespaceResult<'a> { // Import resolutions must be declared with "pub" // in order to be exported. @@ -640,7 +637,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { match type_result { BoundResult(..) => {} _ => { - match target_module.external_module_children.borrow_mut().get(&source).cloned() { + match target_module.external_module_children.borrow_mut().get(&source) { None => {} // Continue. Some(module) => { debug!("(resolving single import) found external module"); @@ -652,7 +649,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { _ => {} } let name_binding = NameBinding::create_from_module(module); - type_result = BoundResult(target_module.clone(), name_binding); + type_result = BoundResult(target_module, name_binding); type_used_public = true; } } @@ -685,7 +682,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { target); import_resolution[namespace] = ImportResolution { - target: Some(Target::new(target_module.clone(), + target: Some(Target::new(target_module, name_binding.clone(), directive.shadowable)), id: directive.id, @@ -777,8 +774,8 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { // that exports nothing is valid). target_module is the module we are // actually importing, i.e., `foo` in `use foo::*`. fn resolve_glob_import(&mut self, - module_: &Module, - target_module: Rc, + module_: Module<'b>, + target_module: Module<'b>, import_directive: &ImportDirective, lp: LastPrivate) -> ResolveResult<()> { @@ -841,7 +838,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { for (&name, name_bindings) in target_module.children.borrow().iter() { self.merge_import_resolution(module_, - target_module.clone(), + target_module, import_directive, name, name_bindings.clone()); @@ -863,11 +860,11 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { } fn merge_import_resolution(&mut self, - module_: &Module, - containing_module: Rc, + module_: Module<'b>, + containing_module: Module<'b>, import_directive: &ImportDirective, name: Name, - name_bindings: NameBindings) { + name_bindings: NameBindings<'b>) { let id = import_directive.id; let is_public = import_directive.is_public; @@ -916,7 +913,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { msg); } else { dest_import_resolution[namespace] = ImportResolution { - target: Some(Target::new(containing_module.clone(), + target: Some(Target::new(containing_module, name_bindings[namespace].clone(), import_directive.shadowable)), id: id, @@ -993,8 +990,8 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { /// Checks that imported names and items don't have the same name. fn check_for_conflicts_between_imports_and_items(&mut self, - module: &Module, - import: &ImportResolutionPerNamespace, + module: Module<'b>, + import: &ImportResolutionPerNamespace<'b>, import_span: Span, name: Name) { // First, check for conflicts between imports and `extern crate`s. @@ -1013,8 +1010,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { } // Check for item conflicts. - let children = module.children.borrow(); - let name_bindings = match children.get(&name) { + let name_bindings = match module.children.borrow().get(&name) { None => { // There can't be any conflicts. return; From f251ff4081dc89b984000547ec0903e845f14201 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 11 Jan 2016 18:23:22 +0100 Subject: [PATCH 17/22] bug fixes for issues 30018 and 30822. includes bugfixes pointed out during review: * Only `call_lifetime_start` for an alloca if the function entry does not itself initialize it to "dropped." * Remove `schedule_lifetime_end` after writing an *element* into a borrowed slice. (As explained by [dotdash][irc], "the lifetime end that is being removed was for an element in the slice, which is not an alloca of its own and has no lifetime start of its own") [irc]: https://botbot.me/mozilla/rust-internals/2016-01-13/?msg=57844504&page=3 --- src/librustc_trans/trans/tvec.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/librustc_trans/trans/tvec.rs b/src/librustc_trans/trans/tvec.rs index c7e1af5853d11..3a1568a70c992 100644 --- a/src/librustc_trans/trans/tvec.rs +++ b/src/librustc_trans/trans/tvec.rs @@ -111,8 +111,15 @@ pub fn trans_slice_vec<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // Always create an alloca even if zero-sized, to preserve // the non-null invariant of the inner slice ptr - let llfixed = base::alloc_ty(bcx, fixed_ty, ""); - call_lifetime_start(bcx, llfixed); + let llfixed; + // Issue 30018: ensure state is initialized as dropped if necessary. + if fcx.type_needs_drop(vt.unit_ty) { + llfixed = base::alloc_ty_init(bcx, fixed_ty, InitAlloca::Dropped, ""); + } else { + let uninit = InitAlloca::Uninit("fcx says vt.unit_ty is non-drop"); + llfixed = base::alloc_ty_init(bcx, fixed_ty, uninit, ""); + call_lifetime_start(bcx, llfixed); + }; if count > 0 { // Arrange for the backing array to be cleaned up. @@ -212,8 +219,8 @@ fn write_content<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, bcx = expr::trans_into(bcx, &**element, SaveIn(lleltptr)); let scope = cleanup::CustomScope(temp_scope); - fcx.schedule_lifetime_end(scope, lleltptr); - fcx.schedule_drop_mem(scope, lleltptr, vt.unit_ty, None); + // Issue #30822: mark memory as dropped after running destructor + fcx.schedule_drop_and_fill_mem(scope, lleltptr, vt.unit_ty, None); } fcx.pop_custom_cleanup_scope(temp_scope); } From df1283cd1a6902bad5c869b124519814cd482064 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 11 Jan 2016 18:32:28 +0100 Subject: [PATCH 18/22] Unit/regression tests for issues #29092, #30018, #30530, #30822. Note that the test for #30822 is folded into the test for #30530 (but the file name mentions only 30530). --- src/test/run-pass/issue-29092.rs | 35 +++++++ src/test/run-pass/issue-30018-nopanic.rs | 111 +++++++++++++++++++++++ src/test/run-pass/issue-30018-panic.rs | 32 +++++++ src/test/run-pass/issue-30530.rs | 35 +++++++ 4 files changed, 213 insertions(+) create mode 100644 src/test/run-pass/issue-29092.rs create mode 100644 src/test/run-pass/issue-30018-nopanic.rs create mode 100644 src/test/run-pass/issue-30018-panic.rs create mode 100644 src/test/run-pass/issue-30530.rs diff --git a/src/test/run-pass/issue-29092.rs b/src/test/run-pass/issue-29092.rs new file mode 100644 index 0000000000000..c55cc91cc928f --- /dev/null +++ b/src/test/run-pass/issue-29092.rs @@ -0,0 +1,35 @@ +// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Regression test for Issue #29092. +// +// (Possibly redundant with regression test run-pass/issue-30530.rs) + +use self::Term::*; + +#[derive(Clone)] +pub enum Term { + Dummy, + A(Box), + B(Box), +} + +// a small-step evaluator +pub fn small_eval(v: Term) -> Term { + match v { + A(t) => *t.clone(), + B(t) => *t.clone(), + _ => Dummy, + } +} + +fn main() { + small_eval(Dummy); +} diff --git a/src/test/run-pass/issue-30018-nopanic.rs b/src/test/run-pass/issue-30018-nopanic.rs new file mode 100644 index 0000000000000..25eff9def9dfc --- /dev/null +++ b/src/test/run-pass/issue-30018-nopanic.rs @@ -0,0 +1,111 @@ +// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// More thorough regression test for Issues #30018 and #30822. This +// attempts to explore different ways that array element construction +// (for both scratch arrays and non-scratch ones) interacts with +// breaks in the control-flow, in terms of the order of evaluation of +// the destructors (which may change; see RFC Issue 744) and the +// number of times that the destructor evaluates for each value (which +// should never exceed 1; this latter case is what #30822 is about). + +use std::cell::RefCell; + +struct D<'a>(&'a RefCell>, i32); + +impl<'a> Drop for D<'a> { + fn drop(&mut self) { + println!("Dropping D({})", self.1); + (self.0).borrow_mut().push(self.1); + } +} + +fn main() { + println!("Start"); + break_during_elem(); + break_after_whole(); + println!("Finis"); +} + +fn break_during_elem() { + let log = &RefCell::new(Vec::new()); + + // CASE 1: Fixed-size array itself is stored in _r slot. + loop { + let _r = [D(log, 10), + D(log, 11), + { D(log, 12); break; }, + D(log, 13)]; + } + assert_eq!(&log.borrow()[..], &[12, 11, 10]); + log.borrow_mut().clear(); + + // CASE 2: Slice (borrow of array) is stored in _r slot. + // This is the case that is actually being reported in #30018. + loop { + let _r = &[D(log, 20), + D(log, 21), + { D(log, 22); break; }, + D(log, 23)]; + } + assert_eq!(&log.borrow()[..], &[22, 21, 20]); + log.borrow_mut().clear(); + + // CASE 3: (Borrow of) slice-index of array is stored in _r slot. + loop { + let _r = &[D(log, 30), + D(log, 31), + { D(log, 32); break; }, + D(log, 33)][..]; + } + assert_eq!(&log.borrow()[..], &[32, 31, 30]); + log.borrow_mut().clear(); +} + +// The purpose of these functions is to test what happens when we +// panic after an array has been constructed in its entirety. +// +// It is meant to act as proof that we still need to continue +// scheduling the destruction of an array even after we've scheduling +// drop for its elements during construction; the latter is tested by +// `fn break_during_elem()`. +fn break_after_whole() { + let log = &RefCell::new(Vec::new()); + + // CASE 1: Fixed-size array itself is stored in _r slot. + loop { + let _r = [D(log, 10), + D(log, 11), + D(log, 12)]; + break; + } + assert_eq!(&log.borrow()[..], &[10, 11, 12]); + log.borrow_mut().clear(); + + // CASE 2: Slice (borrow of array) is stored in _r slot. + loop { + let _r = &[D(log, 20), + D(log, 21), + D(log, 22)]; + break; + } + assert_eq!(&log.borrow()[..], &[20, 21, 22]); + log.borrow_mut().clear(); + + // CASE 3: (Borrow of) slice-index of array is stored in _r slot. + loop { + let _r = &[D(log, 30), + D(log, 31), + D(log, 32)][..]; + break; + } + assert_eq!(&log.borrow()[..], &[30, 31, 32]); + log.borrow_mut().clear(); +} diff --git a/src/test/run-pass/issue-30018-panic.rs b/src/test/run-pass/issue-30018-panic.rs new file mode 100644 index 0000000000000..da4d5f19d4a2e --- /dev/null +++ b/src/test/run-pass/issue-30018-panic.rs @@ -0,0 +1,32 @@ +// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Regression test for Issue #30018. This is very similar to the +// original reported test, except that the panic is wrapped in a +// spawned thread to isolate the expected error result from the +// SIGTRAP injected by the drop-flag consistency checking. + +struct Foo; + +impl Drop for Foo { + fn drop(&mut self) {} +} + +fn foo() -> Foo { + panic!(); +} + +fn main() { + use std::thread; + let handle = thread::spawn(|| { + let _ = &[foo()]; + }); + let _ = handle.join(); +} diff --git a/src/test/run-pass/issue-30530.rs b/src/test/run-pass/issue-30530.rs new file mode 100644 index 0000000000000..d5139c908bdac --- /dev/null +++ b/src/test/run-pass/issue-30530.rs @@ -0,0 +1,35 @@ +// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Regression test for Issue #30530: alloca's created for storing +// intermediate scratch values during brace-less match arms need to be +// initialized with their drop-flag set to "dropped" (or else we end +// up running the destructors on garbage data at the end of the +// function). + +pub enum Handler { + Default, + #[allow(dead_code)] + Custom(*mut Box), +} + +fn main() { + take(Handler::Default, Box::new(main)); +} + +#[inline(never)] +pub fn take(h: Handler, f: Box) -> Box { + unsafe { + match h { + Handler::Custom(ptr) => *Box::from_raw(ptr), + Handler::Default => f, + } + } +} From 8168765d43937d1def40f13bcfe9be5748a180b3 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 12 Jan 2016 17:17:50 +0100 Subject: [PATCH 19/22] Factored out private routine for emitting LLVM lifetime intrinsic calls. (The reason this is not factored as far as possible because a subsequent commit is going to need to do construction without having access to a `cx`.) --- src/librustc_trans/trans/base.rs | 75 +++++++++++++++++++------------- 1 file changed, 45 insertions(+), 30 deletions(-) diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 1e5c60609b0b8..636db8fecdf7f 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -1147,48 +1147,63 @@ pub fn with_cond<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, val: ValueRef, f: F) -> next_cx } -pub fn call_lifetime_start(cx: Block, ptr: ValueRef) { - if cx.sess().opts.optimize == config::No { +enum Lifetime { Start, End } + +// If LLVM lifetime intrinsic support is enabled (i.e. optimizations +// on), and `ptr` is nonzero-sized, then extracts the size of `ptr` +// and the intrinsic for `lt` and passes them to `emit`, which is in +// charge of generating code to call the passed intrinsic on whatever +// block of generated code is targetted for the intrinsic. +// +// If LLVM lifetime intrinsic support is disabled (i.e. optimizations +// off) or `ptr` is zero-sized, then no-op (does not call `emit`). +fn core_lifetime_emit<'blk, 'tcx, F>(ccx: &'blk CrateContext<'blk, 'tcx>, + ptr: ValueRef, + lt: Lifetime, + emit: F) + where F: FnOnce(&'blk CrateContext<'blk, 'tcx>, machine::llsize, ValueRef) +{ + if ccx.sess().opts.optimize == config::No { return; } - let _icx = push_ctxt("lifetime_start"); - let ccx = cx.ccx(); + let _icx = push_ctxt(match lt { + Lifetime::Start => "lifetime_start", + Lifetime::End => "lifetime_end" + }); let size = machine::llsize_of_alloc(ccx, val_ty(ptr).element_type()); if size == 0 { return; } - let ptr = PointerCast(cx, ptr, Type::i8p(ccx)); - let lifetime_start = ccx.get_intrinsic(&"llvm.lifetime.start"); - Call(cx, - lifetime_start, - &[C_u64(ccx, size), ptr], - None, - DebugLoc::None); + let lifetime_intrinsic = ccx.get_intrinsic(match lt { + Lifetime::Start => "llvm.lifetime.start", + Lifetime::End => "llvm.lifetime.end" + }); + emit(ccx, size, lifetime_intrinsic) } -pub fn call_lifetime_end(cx: Block, ptr: ValueRef) { - if cx.sess().opts.optimize == config::No { - return; - } - - let _icx = push_ctxt("lifetime_end"); - let ccx = cx.ccx(); - - let size = machine::llsize_of_alloc(ccx, val_ty(ptr).element_type()); - if size == 0 { - return; - } +pub fn call_lifetime_start(cx: Block, ptr: ValueRef) { + core_lifetime_emit(cx.ccx(), ptr, Lifetime::Start, |ccx, size, lifetime_start| { + let ptr = PointerCast(cx, ptr, Type::i8p(ccx)); + Call(cx, + lifetime_start, + &[C_u64(ccx, size), ptr], + None, + DebugLoc::None); + }) +} - let ptr = PointerCast(cx, ptr, Type::i8p(ccx)); - let lifetime_end = ccx.get_intrinsic(&"llvm.lifetime.end"); - Call(cx, - lifetime_end, - &[C_u64(ccx, size), ptr], - None, - DebugLoc::None); +pub fn call_lifetime_end(cx: Block, ptr: ValueRef) { + core_lifetime_emit(cx.ccx(), ptr, Lifetime::End, |ccx, size, lifetime_end| { + let ptr = PointerCast(cx, ptr, Type::i8p(ccx)); + Call(cx, + lifetime_end, + &[C_u64(ccx, size), ptr], + None, + DebugLoc::None); + }) } // Generates code for resumption of unwind at the end of a landing pad. From 7706e2333eacbbdf943164cec583a51b216bbde1 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 12 Jan 2016 17:21:11 +0100 Subject: [PATCH 20/22] revise lifetime handling for alloca's that are initialized as "dropped." (This can/should be revisited when drop flags are stored out of band.) --- src/librustc_trans/trans/base.rs | 7 +++++++ src/librustc_trans/trans/datum.rs | 4 +++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 636db8fecdf7f..375b3e3f0d2d5 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -1354,6 +1354,13 @@ pub fn alloca_dropped<'blk, 'tcx>(cx: Block<'blk, 'tcx>, ty: Ty<'tcx>, name: &st let p = alloca(cx, llty, name); let b = cx.fcx.ccx.builder(); b.position_before(cx.fcx.alloca_insert_pt.get().unwrap()); + + // This is just like `call_lifetime_start` (but latter expects a + // Block, which we do not have for `alloca_insert_pt`). + core_lifetime_emit(cx.ccx(), p, Lifetime::Start, |ccx, size, lifetime_start| { + let ptr = b.pointercast(p, Type::i8p(ccx)); + b.call(lifetime_start, &[C_u64(ccx, size), ptr], None); + }); memfill(&b, p, ty, adt::DTOR_DONE); p } diff --git a/src/librustc_trans/trans/datum.rs b/src/librustc_trans/trans/datum.rs index 6a033602adaba..32f263746d31e 100644 --- a/src/librustc_trans/trans/datum.rs +++ b/src/librustc_trans/trans/datum.rs @@ -513,7 +513,9 @@ impl<'tcx> Datum<'tcx, Rvalue> { |this, bcx, llval| { debug!("populate call for Datum::to_lvalue_datum_in_scope \ self.ty={:?}", this.ty); - call_lifetime_start(bcx, llval); + // do not call_lifetime_start here; the + // `InitAlloc::Dropped` will start scratch + // value's lifetime at open of function body. let bcx = this.store_to(bcx, llval); bcx.fcx.schedule_lifetime_end(scope, llval); bcx From decc2867577c65682c6a73c89c550d34b5b270ad Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 12 Jan 2016 17:24:00 +0100 Subject: [PATCH 21/22] add doc for new `fn alloc_ty_init`. (Note that it might be a good idea to replace *all* calls of `alloc_ty` with calls to `alloc_ty_init`, to encourage programmers to consider the appropriate value for the `init` flag when creating temporary values.) --- src/librustc_trans/trans/base.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 375b3e3f0d2d5..5f2fe98727fa1 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -1331,6 +1331,18 @@ pub fn alloc_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, alloc_ty_init(bcx, t, InitAlloca::Uninit("all alloc_ty are uninit"), name) } +/// This variant of `fn alloc_ty` does not necessarily assume that the +/// alloca should be created with no initial value. Instead the caller +/// controls that assumption via the `init` flag. +/// +/// Note that if the alloca *is* initialized via `init`, then we will +/// also inject an `llvm.lifetime.start` before that initialization +/// occurs, and thus callers should not call_lifetime_start +/// themselves. But if `init` says "uninitialized", then callers are +/// in charge of choosing where to call_lifetime_start and +/// subsequently populate the alloca. +/// +/// (See related discussion on PR #30823.) pub fn alloc_ty_init<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, init: InitAlloca, From 98bef2b81823483a23beef48c7999a67206d261d Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 9 Jan 2016 19:19:56 +0000 Subject: [PATCH 22/22] Add missing newline character to callers of dumb_print --- src/libstd/panicking.rs | 4 ++-- src/libstd/sys/common/util.rs | 4 ++-- src/libstd/sys/windows/mod.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 3f9a1c30ef493..8561ecd9c4cb9 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -206,7 +206,7 @@ pub fn on_panic(obj: &(Any+Send), file: &'static str, line: u32) { // debugger provides a useable stacktrace. if panics >= 3 { util::dumb_print(format_args!("thread panicked while processing \ - panic. aborting.")); + panic. aborting.\n")); unsafe { intrinsics::abort() } } @@ -232,7 +232,7 @@ pub fn on_panic(obj: &(Any+Send), file: &'static str, line: u32) { // just abort. In the future we may consider resuming // unwinding or otherwise exiting the thread cleanly. util::dumb_print(format_args!("thread panicked while panicking. \ - aborting.")); + aborting.\n")); unsafe { intrinsics::abort() } } } diff --git a/src/libstd/sys/common/util.rs b/src/libstd/sys/common/util.rs index 979f1f4866983..b7a6b7650d540 100644 --- a/src/libstd/sys/common/util.rs +++ b/src/libstd/sys/common/util.rs @@ -35,12 +35,12 @@ pub fn dumb_print(args: fmt::Arguments) { } pub fn abort(args: fmt::Arguments) -> ! { - dumb_print(format_args!("fatal runtime error: {}", args)); + dumb_print(format_args!("fatal runtime error: {}\n", args)); unsafe { intrinsics::abort(); } } #[allow(dead_code)] // stack overflow detection not enabled on all platforms pub unsafe fn report_overflow() { - dumb_print(format_args!("\nthread '{}' has overflowed its stack", + dumb_print(format_args!("\nthread '{}' has overflowed its stack\n", thread::current().name().unwrap_or(""))); } diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 7e4db3d89a3f7..16c4ae8257c13 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -53,7 +53,7 @@ fn oom_handler() -> ! { // is no need to check the result of GetStdHandle. c::WriteFile(c::GetStdHandle(c::STD_ERROR_HANDLE), msg.as_ptr() as c::LPVOID, - msg.len() as DWORD, + msg.len() as c::DWORD, ptr::null_mut(), ptr::null_mut()); intrinsics::abort();