From 907d2a1aeb26151cc81dfa148e874e4fe50d1a14 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 30 Oct 2016 22:14:05 -0500 Subject: [PATCH 001/293] make `alloc` and `collections` compilable for thumbv6m-none-eabi by cfging away `alloc::Arc` and changing OOM to abort for this target --- src/liballoc/lib.rs | 2 ++ src/liballoc/oom.rs | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 31491106d97..dd22894ea95 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -74,6 +74,7 @@ #![feature(allocator)] #![feature(box_syntax)] +#![feature(cfg_target_has_atomic)] #![feature(coerce_unsized)] #![feature(const_fn)] #![feature(core_intrinsics)] @@ -117,6 +118,7 @@ mod boxed { } #[cfg(test)] mod boxed_test; +#[cfg(target_has_atomic = "ptr")] pub mod arc; pub mod rc; pub mod raw_vec; diff --git a/src/liballoc/oom.rs b/src/liballoc/oom.rs index d355d59185e..afdc19678dc 100644 --- a/src/liballoc/oom.rs +++ b/src/liballoc/oom.rs @@ -8,10 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#[cfg(target_has_atomic = "ptr")] use core::sync::atomic::{AtomicPtr, Ordering}; +#[cfg(target_has_atomic = "ptr")] use core::mem; use core::intrinsics; +#[cfg(target_has_atomic = "ptr")] static OOM_HANDLER: AtomicPtr<()> = AtomicPtr::new(default_oom_handler as *mut ()); fn default_oom_handler() -> ! { @@ -21,6 +24,7 @@ fn default_oom_handler() -> ! { } /// Common out-of-memory routine +#[cfg(target_has_atomic = "ptr")] #[cold] #[inline(never)] #[unstable(feature = "oom", reason = "not a scrutinized interface", @@ -31,10 +35,21 @@ pub fn oom() -> ! { handler(); } +/// Common out-of-memory routine +#[cfg(not(target_has_atomic = "ptr"))] +#[cold] +#[inline(never)] +#[unstable(feature = "oom", reason = "not a scrutinized interface", + issue = "27700")] +pub fn oom() -> ! { + default_oom_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. +#[cfg(target_has_atomic = "ptr")] #[unstable(feature = "oom", reason = "not a scrutinized interface", issue = "27700")] pub fn set_oom_handler(handler: fn() -> !) { From 24dc2bc3f5946927784bf1924041035be07474b2 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 10 Nov 2016 23:42:59 -0500 Subject: [PATCH 002/293] use an 'imp' module to reduce the amount of cfgs --- src/liballoc/oom.rs | 61 ++++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/src/liballoc/oom.rs b/src/liballoc/oom.rs index afdc19678dc..87ae16f6c53 100644 --- a/src/liballoc/oom.rs +++ b/src/liballoc/oom.rs @@ -9,14 +9,9 @@ // except according to those terms. #[cfg(target_has_atomic = "ptr")] -use core::sync::atomic::{AtomicPtr, Ordering}; -#[cfg(target_has_atomic = "ptr")] -use core::mem; +pub use self::imp::set_oom_handler; use core::intrinsics; -#[cfg(target_has_atomic = "ptr")] -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. @@ -24,34 +19,44 @@ fn default_oom_handler() -> ! { } /// Common out-of-memory routine -#[cfg(target_has_atomic = "ptr")] #[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(); + self::imp::oom() +} + +#[cfg(target_has_atomic = "ptr")] +mod imp { + use core::mem; + use core::sync::atomic::{AtomicPtr, Ordering}; + + static OOM_HANDLER: AtomicPtr<()> = AtomicPtr::new(super::default_oom_handler as *mut ()); + + #[inline(always)] + 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); + } + } -/// Common out-of-memory routine #[cfg(not(target_has_atomic = "ptr"))] -#[cold] -#[inline(never)] -#[unstable(feature = "oom", reason = "not a scrutinized interface", - issue = "27700")] -pub fn oom() -> ! { - default_oom_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. -#[cfg(target_has_atomic = "ptr")] -#[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); +mod imp { + #[inline(always)] + pub fn oom() -> ! { + super::default_oom_handler() + } } From abe6fc73e0d5d58d12b069a8b27514086ebbefa1 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 10 Nov 2016 23:44:15 -0500 Subject: [PATCH 003/293] drop an unnecessary newline --- src/liballoc/oom.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/liballoc/oom.rs b/src/liballoc/oom.rs index 87ae16f6c53..3640156fec2 100644 --- a/src/liballoc/oom.rs +++ b/src/liballoc/oom.rs @@ -50,7 +50,6 @@ mod imp { pub fn set_oom_handler(handler: fn() -> !) { OOM_HANDLER.store(handler as *mut (), Ordering::SeqCst); } - } #[cfg(not(target_has_atomic = "ptr"))] From c5e6dfc4f9ba04b906ceef2a4512d19bf079d8d0 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Thu, 17 Nov 2016 13:16:27 -0500 Subject: [PATCH 004/293] Clarify the reference's status. The former wording only gave part of the picture, we want to be crystal clear about this. --- src/doc/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/index.md b/src/doc/index.md index f8a1ec134d9..71dfcf0b067 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -17,7 +17,7 @@ the language. [**The Rust Reference**][ref]. While Rust does not have a specification, the reference tries to describe its working in -detail. It tends to be out of date. +detail. It is accurate, but not necessarily complete. [**Standard Library API Reference**][api]. Documentation for the standard library. From ec24442e60bce2605a64ac3aef5784510e4a5fd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 27 Oct 2016 19:02:27 -0700 Subject: [PATCH 005/293] Provide hint when cast needs a dereference For a given code: ```rust vec![0.0].iter().map(|s| s as i16).collect::>(); ``` display: ```nocode error: casting `&f64` as `i16` is invalid --> foo.rs:2:35 | 2 | vec![0.0].iter().map(|s| s as i16).collect::>(); | - ^^^ cannot cast `&f64` as `i16` | | | did you mean `*s`? ``` instead of: ```nocode error: casting `&f64` as `i16` is invalid --> :2:30 | 2 | vec![0.0].iter().map(|s| s as i16).collect(); | ^^^^^^^^ | = help: cast through a raw pointer first ``` --- src/librustc_typeck/check/cast.rs | 44 +++++++++++++++++++++++++-- src/test/compile-fail/cast-rfc0401.rs | 5 +++ 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 4edf0011cb3..5839c606566 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -102,6 +102,7 @@ enum CastError { /// Cast of thin to fat raw ptr (eg. `*const () as *const [u8]`) SizedUnsizedCast, IllegalCast, + NeedDeref, NeedViaPtr, NeedViaThinPtr, NeedViaInt, @@ -138,6 +139,25 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { fn report_cast_error(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, e: CastError) { match e { + CastError::NeedDeref => { + let cast_ty = fcx.ty_to_string(self.cast_ty); + let mut err = fcx.type_error_struct(self.cast_span, + |actual| { + format!("casting `{}` as `{}` is invalid", + actual, + cast_ty) + }, + self.expr_ty); + err.span_label(self.expr.span, + &format!("cannot cast `{}` as `{}`", + fcx.ty_to_string(self.expr_ty), + cast_ty)); + if let Ok(snippet) = fcx.sess().codemap().span_to_snippet(self.expr.span) { + err.span_label(self.expr.span, + &format!("did you mean `*{}`?", snippet)); + } + err.emit(); + } CastError::NeedViaThinPtr | CastError::NeedViaPtr => { let mut err = fcx.type_error_struct(self.span, @@ -390,8 +410,28 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { (Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast (Ptr(m_expr), Int(_)) => self.check_ptr_addr_cast(fcx, m_expr), // ptr-addr-cast (FnPtr, Int(_)) => Ok(CastKind::FnPtrAddrCast), - (RPtr(_), Int(_)) | - (RPtr(_), Float) => Err(CastError::NeedViaPtr), + (RPtr(p), Int(_)) | + (RPtr(p), Float) => { + match p.ty.sty { + ty::TypeVariants::TyInt(_) | + ty::TypeVariants::TyUint(_) | + ty::TypeVariants::TyFloat(_) => { + Err(CastError::NeedDeref) + } + ty::TypeVariants::TyInfer(t) => { + match t { + ty::InferTy::IntVar(_) | + ty::InferTy::FloatVar(_) | + ty::InferTy::FreshIntTy(_) | + ty::InferTy::FreshFloatTy(_) => { + Err(CastError::NeedDeref) + } + _ => Err(CastError::NeedViaPtr), + } + } + _ => Err(CastError::NeedViaPtr), + } + } // * -> ptr (Int(_), Ptr(mt)) => self.check_addr_ptr_cast(fcx, mt), // addr-ptr-cast (FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt), diff --git a/src/test/compile-fail/cast-rfc0401.rs b/src/test/compile-fail/cast-rfc0401.rs index 1dbad9e30e3..b98f464c902 100644 --- a/src/test/compile-fail/cast-rfc0401.rs +++ b/src/test/compile-fail/cast-rfc0401.rs @@ -115,4 +115,9 @@ fn main() let _ = cf as *const Bar; //~^ ERROR casting //~^^ NOTE vtable kinds + + vec![0.0].iter().map(|s| s as f32).collect::>(); + //~^ ERROR casting `&{float}` as `f32` is invalid + //~| NOTE cannot cast `&{float}` as `f32` + //~| NOTE did you mean `*s`? } From d37c02525405261527675fd051b94a23b9330f0c Mon Sep 17 00:00:00 2001 From: Wang Xuerui Date: Fri, 18 Nov 2016 13:25:19 +0800 Subject: [PATCH 006/293] Update compiler-rt to fix MIPS64 infinite recursion Fixes #37823. --- src/compiler-rt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler-rt b/src/compiler-rt index 3bc0272cab9..a8fc4c169fa 160000 --- a/src/compiler-rt +++ b/src/compiler-rt @@ -1 +1 @@ -Subproject commit 3bc0272cab9fdcfc2ef4df9625ec3c9d5909db79 +Subproject commit a8fc4c169fac43a5dc204d4fd56ddb1739f8c178 From ff433da52695df69e7cdffca859d832ecabf2079 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 21 Nov 2016 14:07:58 +0100 Subject: [PATCH 007/293] Add missing examples for SocketAddrV4 --- src/libstd/net/addr.rs | 46 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index 1c016015b79..0328012ee57 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -194,6 +194,14 @@ impl SocketAddr { impl SocketAddrV4 { /// Creates a new socket address from the (ip, port) pair. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV4, Ipv4Addr}; + /// + /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 { SocketAddrV4 { @@ -207,6 +215,15 @@ impl SocketAddrV4 { } /// Returns the IP address associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV4, Ipv4Addr}; + /// + /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); + /// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1)); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn ip(&self) -> &Ipv4Addr { unsafe { @@ -215,18 +232,47 @@ impl SocketAddrV4 { } /// Change the IP address associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV4, Ipv4Addr}; + /// + /// let mut socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); + /// socket.set_ip(Ipv4Addr::new(192, 168, 0, 1)); + /// assert_eq!(socket.ip(), &Ipv4Addr::new(192, 168, 0, 1)); + /// ``` #[stable(feature = "sockaddr_setters", since = "1.9.0")] pub fn set_ip(&mut self, new_ip: Ipv4Addr) { self.inner.sin_addr = *new_ip.as_inner() } /// Returns the port number associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV4, Ipv4Addr}; + /// + /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); + /// assert_eq!(socket.port(), 8080); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn port(&self) -> u16 { ntoh(self.inner.sin_port) } /// Change the port number associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV4, Ipv4Addr}; + /// + /// let mut socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); + /// socket.set_port(4242); + /// assert_eq!(socket.port(), 4242); + /// ``` #[stable(feature = "sockaddr_setters", since = "1.9.0")] pub fn set_port(&mut self, new_port: u16) { self.inner.sin_port = hton(new_port); From dac987e355deb903493d22c0ae8a8a4fd072d1c5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 21 Nov 2016 13:22:21 -0500 Subject: [PATCH 008/293] add regression test for #36168 Fixes #36168 --- .../auxiliary/point.rs | 35 ++++++++ .../struct_point.rs | 84 +++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 src/test/incremental/add_private_fn_at_krate_root_cc/auxiliary/point.rs create mode 100644 src/test/incremental/add_private_fn_at_krate_root_cc/struct_point.rs diff --git a/src/test/incremental/add_private_fn_at_krate_root_cc/auxiliary/point.rs b/src/test/incremental/add_private_fn_at_krate_root_cc/auxiliary/point.rs new file mode 100644 index 00000000000..99ba576a137 --- /dev/null +++ b/src/test/incremental/add_private_fn_at_krate_root_cc/auxiliary/point.rs @@ -0,0 +1,35 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub struct Point { + pub x: f32, + pub y: f32, +} + +#[cfg(rpass2)] +fn unused_helper() { +} + +fn distance_squared(this: &Point) -> f32 { + return this.x * this.x + this.y * this.y; +} + +impl Point { + pub fn distance_from_origin(&self) -> f32 { + distance_squared(self).sqrt() + } +} + +impl Point { + pub fn translate(&mut self, x: f32, y: f32) { + self.x += x; + self.y += y; + } +} diff --git a/src/test/incremental/add_private_fn_at_krate_root_cc/struct_point.rs b/src/test/incremental/add_private_fn_at_krate_root_cc/struct_point.rs new file mode 100644 index 00000000000..dba7f147619 --- /dev/null +++ b/src/test/incremental/add_private_fn_at_krate_root_cc/struct_point.rs @@ -0,0 +1,84 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test where we add a private item into the root of an external. +// crate. This should not cause anything we use to be invalidated. +// Regression test for #36168. + +// revisions:rpass1 rpass2 +// compile-flags: -Z query-dep-graph +// aux-build:point.rs + +#![feature(rustc_attrs)] +#![feature(stmt_expr_attributes)] +#![allow(dead_code)] + +#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_same_impl", cfg="rpass2")] +#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_another_impl", cfg="rpass2")] +#![rustc_partition_reused(module="struct_point-fn_read_field", cfg="rpass2")] +#![rustc_partition_reused(module="struct_point-fn_write_field", cfg="rpass2")] +#![rustc_partition_reused(module="struct_point-fn_make_struct", cfg="rpass2")] + +extern crate point; + +/// A fn item that calls (public) methods on `Point` from the same impl which changed +mod fn_calls_methods_in_same_impl { + use point::Point; + + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] + pub fn check() { + let x = Point { x: 2.0, y: 2.0 }; + x.distance_from_origin(); + } +} + +/// A fn item that calls (public) methods on `Point` from another impl +mod fn_calls_methods_in_another_impl { + use point::Point; + + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] + pub fn check() { + let mut x = Point { x: 2.0, y: 2.0 }; + x.translate(3.0, 3.0); + } +} + +/// A fn item that makes an instance of `Point` but does not invoke methods +mod fn_make_struct { + use point::Point; + + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] + pub fn make_origin() -> Point { + Point { x: 2.0, y: 2.0 } + } +} + +/// A fn item that reads fields from `Point` but does not invoke methods +mod fn_read_field { + use point::Point; + + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] + pub fn get_x(p: Point) -> f32 { + p.x + } +} + +/// A fn item that writes to a field of `Point` but does not invoke methods +mod fn_write_field { + use point::Point; + + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] + pub fn inc_x(p: &mut Point) { + p.x += 1.0; + } +} + +fn main() { +} From e795d38270fe11195be761efb52f4acef0ad197d Mon Sep 17 00:00:00 2001 From: Joe Neeman Date: Mon, 21 Nov 2016 22:02:03 +0100 Subject: [PATCH 009/293] Add regression test for issue 23699. --- src/test/run-pass/issue-23699.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/test/run-pass/issue-23699.rs diff --git a/src/test/run-pass/issue-23699.rs b/src/test/run-pass/issue-23699.rs new file mode 100644 index 00000000000..1909be4df7b --- /dev/null +++ b/src/test/run-pass/issue-23699.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn gimme_a_raw_pointer(_: *const T) { } + +fn test(t: T) { } + +fn main() { + // Clearly `pointer` must be of type `*const ()`. + let pointer = &() as *const _; + gimme_a_raw_pointer(pointer); + + let t = test as fn (i32); + t(0i32); +} + From 9170ddf1e4b71d03069acf266d30f7b6af68cc83 Mon Sep 17 00:00:00 2001 From: John Downey Date: Mon, 21 Nov 2016 16:12:14 -0600 Subject: [PATCH 010/293] Add some internal docs links for Args/ArgsOs --- src/libstd/env.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/libstd/env.rs b/src/libstd/env.rs index e29dbe35c5a..baa2b5d2846 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -546,17 +546,23 @@ pub fn current_exe() -> io::Result { os_imp::current_exe() } -/// An iterator over the arguments of a process, yielding a `String` value +/// An iterator over the arguments of a process, yielding a [`String`] value /// for each argument. /// -/// This structure is created through the `std::env::args` method. +/// This structure is created through the [`std::env::args`] method. +/// +/// [`String`]: ../string/struct.String.html +/// [`std::env::args`]: ./fn.args.html #[stable(feature = "env", since = "1.0.0")] pub struct Args { inner: ArgsOs } -/// An iterator over the arguments of a process, yielding an `OsString` value +/// An iterator over the arguments of a process, yielding an [`OsString`] value /// for each argument. /// -/// This structure is created through the `std::env::args_os` method. +/// This structure is created through the [`std::env::args_os`] method. +/// +/// [`OsString`]: ../ffi/struct.OsString.html +/// [`std::env::args_os`]: ./fn.args_os.html #[stable(feature = "env", since = "1.0.0")] pub struct ArgsOs { inner: sys::args::Args } @@ -571,7 +577,7 @@ pub struct ArgsOs { inner: sys::args::Args } /// /// The returned iterator will panic during iteration if any argument to the /// process is not valid unicode. If this is not desired, -/// use the `args_os` function instead. +/// use the [`args_os`] function instead. /// /// # Examples /// @@ -583,6 +589,8 @@ pub struct ArgsOs { inner: sys::args::Args } /// println!("{}", argument); /// } /// ``` +/// +/// [`args_os`]: ./fn.args_os.html #[stable(feature = "env", since = "1.0.0")] pub fn args() -> Args { Args { inner: args_os() } From f72685f2ffd1e79c2d4e099770490d4cf00795fa Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 18 Oct 2016 08:23:09 +1100 Subject: [PATCH 011/293] Use SmallVec for TypeWalker's stack. The change also adds the missing `SmallVec::truncate` method. --- src/librustc/ty/mod.rs | 3 ++- src/librustc/ty/walk.rs | 21 +++++++++++++-------- src/librustc_data_structures/small_vec.rs | 12 ++++++++++++ 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index e94e93158c4..ebf8c96def7 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -48,6 +48,7 @@ use syntax::symbol::{Symbol, InternedString}; use syntax_pos::{DUMMY_SP, Span}; use rustc_const_math::ConstInt; +use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter; use hir; use hir::itemlikevisit::ItemLikeVisitor; @@ -1887,7 +1888,7 @@ impl<'tcx> TyS<'tcx> { /// Iterator that walks the immediate children of `self`. Hence /// `Foo, u32>` yields the sequence `[Bar, u32]` /// (but not `i32`, like `walk`). - pub fn walk_shallow(&'tcx self) -> IntoIter> { + pub fn walk_shallow(&'tcx self) -> AccIntoIter> { walk::walk_shallow(self) } diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index a6ecfd2fb70..2f9468dbe58 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -12,17 +12,22 @@ //! WARNING: this does not keep track of the region depth. use ty::{self, Ty}; -use std::iter::Iterator; -use std::vec::IntoIter; +use rustc_data_structures::small_vec::SmallVec; +use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter; + +// The TypeWalker's stack is hot enough that it's worth going to some effort to +// avoid heap allocations. +pub type TypeWalkerArray<'tcx> = [Ty<'tcx>; 8]; +pub type TypeWalkerStack<'tcx> = SmallVec>; pub struct TypeWalker<'tcx> { - stack: Vec>, + stack: TypeWalkerStack<'tcx>, last_subtree: usize, } impl<'tcx> TypeWalker<'tcx> { pub fn new(ty: Ty<'tcx>) -> TypeWalker<'tcx> { - TypeWalker { stack: vec![ty], last_subtree: 1, } + TypeWalker { stack: SmallVec::one(ty), last_subtree: 1, } } /// Skips the subtree of types corresponding to the last type @@ -61,8 +66,8 @@ impl<'tcx> Iterator for TypeWalker<'tcx> { } } -pub fn walk_shallow<'tcx>(ty: Ty<'tcx>) -> IntoIter> { - let mut stack = vec![]; +pub fn walk_shallow<'tcx>(ty: Ty<'tcx>) -> AccIntoIter> { + let mut stack = SmallVec::new(); push_subtypes(&mut stack, ty); stack.into_iter() } @@ -73,7 +78,7 @@ pub fn walk_shallow<'tcx>(ty: Ty<'tcx>) -> IntoIter> { // known to be significant to any code, but it seems like the // natural order one would expect (basically, the order of the // types as they are written). -fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { +fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) { match parent_ty.sty { ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyStr | ty::TyInfer(_) | ty::TyParam(_) | ty::TyNever | ty::TyError => { @@ -112,7 +117,7 @@ fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { } } -fn push_sig_subtypes<'tcx>(stack: &mut Vec>, sig: &ty::PolyFnSig<'tcx>) { +fn push_sig_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, sig: &ty::PolyFnSig<'tcx>) { stack.push(sig.0.output); stack.extend(sig.0.inputs.iter().cloned().rev()); } diff --git a/src/librustc_data_structures/small_vec.rs b/src/librustc_data_structures/small_vec.rs index 565a3c443a3..4e2b3786021 100644 --- a/src/librustc_data_structures/small_vec.rs +++ b/src/librustc_data_structures/small_vec.rs @@ -130,6 +130,18 @@ impl SmallVec { self.set_len(len + 1); } } + + pub fn truncate(&mut self, len: usize) { + unsafe { + while len < self.len() { + // Decrement len before the drop_in_place(), so a panic on Drop + // doesn't re-drop the just-failed value. + let newlen = self.len() - 1; + self.set_len(newlen); + ::std::ptr::drop_in_place(self.get_unchecked_mut(newlen)); + } + } + } } impl Deref for SmallVec { From 69bb5fa85203e264387806bbb05acaffb1e95559 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Tue, 13 Sep 2016 16:30:57 +0800 Subject: [PATCH 012/293] Expand is_uninhabited for ! and tuples --- src/librustc/ty/sty.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 81896ecfb53..af45a323eee 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -929,16 +929,14 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } - pub fn is_uninhabited(&self, _cx: TyCtxt) -> bool { + pub fn is_uninhabited(&self, cx: TyCtxt) -> bool { // FIXME(#24885): be smarter here, the AdtDefData::is_empty method could easily be made // more complete. match self.sty { TyAdt(def, _) => def.is_empty(), - // FIXME(canndrew): There's no reason why these can't be uncommented, they're tested - // and they don't break anything. But I'm keeping my changes small for now. - //TyNever => true, - //TyTuple(ref tys) => tys.iter().any(|ty| ty.is_uninhabited(cx)), + TyNever => true, + TyTuple(ref tys) => tys.iter().any(|ty| ty.is_uninhabited(cx)), // FIXME(canndrew): this line breaks core::fmt //TyRef(_, ref tm) => tm.ty.is_uninhabited(cx), From d6482510f4ac179506370f421b2c3a3802f574f9 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Wed, 14 Sep 2016 23:58:58 +0800 Subject: [PATCH 013/293] Expand `is_uninhabited` to recurse into datatypes --- src/librustc/ty/mod.rs | 45 +++++++++++++++++++++++++++++++++++++----- src/librustc/ty/sty.rs | 15 ++++++++++++-- 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index e94e93158c4..5737f776422 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -16,6 +16,7 @@ pub use self::IntVarValue::*; pub use self::LvaluePreference::*; pub use self::fold::TypeFoldable; +use std::collections::{hash_map, HashMap}; use dep_graph::{self, DepNode}; use hir::map as ast_map; use middle; @@ -1389,6 +1390,20 @@ impl<'tcx> serialize::UseSpecializedEncodable for AdtDef<'tcx> { impl<'tcx> serialize::UseSpecializedDecodable for AdtDef<'tcx> {} +impl<'a, 'gcx, 'tcx> AdtDefData<'tcx, 'static> { + #[inline] + pub fn is_uninhabited_recurse(&'tcx self, + visited: &mut HashMap<(DefId, &'tcx Substs<'tcx>), ()>, + cx: TyCtxt<'a, 'gcx, 'tcx>, + substs: &'tcx Substs<'tcx>) -> bool { + match visited.entry((self.did, substs)) { + hash_map::Entry::Occupied(_) => return true, + hash_map::Entry::Vacant(ve) => ve.insert(()), + }; + self.variants.iter().all(|v| v.is_uninhabited_recurse(visited, cx, substs, self.is_union())) + } +} + #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum AdtKind { Struct, Union, Enum } @@ -1531,11 +1546,6 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> { self.variants.iter().flat_map(VariantDefData::fields_iter) } - #[inline] - pub fn is_empty(&self) -> bool { - self.variants.is_empty() - } - #[inline] pub fn is_univariant(&self) -> bool { self.variants.len() == 1 @@ -1795,6 +1805,21 @@ impl<'tcx, 'container> VariantDefData<'tcx, 'container> { } } +impl<'a, 'gcx, 'tcx> VariantDefData<'tcx, 'static> { + #[inline] + pub fn is_uninhabited_recurse(&'tcx self, + visited: &mut HashMap<(DefId, &'tcx Substs<'tcx>), ()>, + cx: TyCtxt<'a, 'gcx, 'tcx>, + substs: &'tcx Substs<'tcx>, + is_union: bool) -> bool { + if is_union { + self.fields.iter().all(|f| f.is_uninhabited_recurse(visited, cx, substs)) + } else { + self.fields.iter().any(|f| f.is_uninhabited_recurse(visited, cx, substs)) + } + } +} + impl<'a, 'gcx, 'tcx, 'container> FieldDefData<'tcx, 'container> { pub fn new(did: DefId, name: Name, @@ -1820,6 +1845,16 @@ impl<'a, 'gcx, 'tcx, 'container> FieldDefData<'tcx, 'container> { } } +impl<'a, 'gcx, 'tcx> FieldDefData<'tcx, 'static> { + #[inline] + pub fn is_uninhabited_recurse(&'tcx self, + visited: &mut HashMap<(DefId, &'tcx Substs<'tcx>), ()>, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + substs: &'tcx Substs<'tcx>) -> bool { + self.ty(tcx, substs).is_uninhabited_recurse(visited, tcx) + } +} + /// Records the substitutions used to translate the polytype for an /// item into the monotype of an item reference. #[derive(Clone, RustcEncodable, RustcDecodable)] diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index af45a323eee..53230eaf59d 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -21,6 +21,7 @@ use util::common::ErrorReported; use collections::enum_set::{self, EnumSet, CLike}; use std::fmt; use std::ops; +use std::collections::HashMap; use syntax::abi; use syntax::ast::{self, Name}; use syntax::symbol::{keywords, InternedString}; @@ -929,14 +930,24 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } - pub fn is_uninhabited(&self, cx: TyCtxt) -> bool { + pub fn is_uninhabited(&self, cx: TyCtxt<'a, 'gcx, 'tcx>) -> bool { + let mut visited = HashMap::new(); + self.is_uninhabited_recurse(&mut visited, cx) + } + + pub fn is_uninhabited_recurse(&self, + visited: &mut HashMap<(DefId, &'tcx Substs<'tcx>), ()>, + cx: TyCtxt<'a, 'gcx, 'tcx>) -> bool { // FIXME(#24885): be smarter here, the AdtDefData::is_empty method could easily be made // more complete. match self.sty { - TyAdt(def, _) => def.is_empty(), + TyAdt(def, substs) => { + def.is_uninhabited_recurse(visited, cx, substs) + }, TyNever => true, TyTuple(ref tys) => tys.iter().any(|ty| ty.is_uninhabited(cx)), + TyArray(ty, len) => len > 0 && ty.is_uninhabited(cx), // FIXME(canndrew): this line breaks core::fmt //TyRef(_, ref tm) => tm.ty.is_uninhabited(cx), From 75140512ebe0138d630e4af52216352300d12d08 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Thu, 15 Sep 2016 01:10:53 +0800 Subject: [PATCH 014/293] Fix previous commit --- src/librustc/ty/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 5737f776422..68440a2c8d8 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1393,7 +1393,7 @@ impl<'tcx> serialize::UseSpecializedDecodable for AdtDef<'tcx> {} impl<'a, 'gcx, 'tcx> AdtDefData<'tcx, 'static> { #[inline] pub fn is_uninhabited_recurse(&'tcx self, - visited: &mut HashMap<(DefId, &'tcx Substs<'tcx>), ()>, + visited: &mut HashMap<(DefId, &'tcx Substs<'tcx>), ()>, cx: TyCtxt<'a, 'gcx, 'tcx>, substs: &'tcx Substs<'tcx>) -> bool { match visited.entry((self.did, substs)) { From f1bdd4fae21e3053cedaa850691edd7a25a62dd2 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Thu, 15 Sep 2016 01:11:11 +0800 Subject: [PATCH 015/293] Expand is_uninhabited for references --- src/libcore/fmt/mod.rs | 8 +++++--- src/librustc/ty/sty.rs | 7 +++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 2d75a8ec420..9fcccacdbe1 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -178,8 +178,9 @@ enum Void {} issue = "0")] #[doc(hidden)] pub struct ArgumentV1<'a> { - value: &'a Void, - formatter: fn(&Void, &mut Formatter) -> Result, + _ph: PhantomData<&'a ()>, + value: *const Void, + formatter: fn(*const Void, &mut Formatter) -> Result, } #[unstable(feature = "fmt_internals", reason = "internal to format_args!", @@ -203,6 +204,7 @@ impl<'a> ArgumentV1<'a> { f: fn(&T, &mut Formatter) -> Result) -> ArgumentV1<'b> { unsafe { ArgumentV1 { + _ph: PhantomData, formatter: mem::transmute(f), value: mem::transmute(x) } @@ -218,7 +220,7 @@ impl<'a> ArgumentV1<'a> { fn as_usize(&self) -> Option { if self.formatter as usize == ArgumentV1::show_usize as usize { - Some(unsafe { *(self.value as *const _ as *const usize) }) + Some(unsafe { *(self.value as *const usize) }) } else { None } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 53230eaf59d..39461dc4f74 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -946,11 +946,10 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { }, TyNever => true, - TyTuple(ref tys) => tys.iter().any(|ty| ty.is_uninhabited(cx)), - TyArray(ty, len) => len > 0 && ty.is_uninhabited(cx), + TyTuple(ref tys) => tys.iter().any(|ty| ty.is_uninhabited_recurse(visited, cx)), + TyArray(ty, len) => len > 0 && ty.is_uninhabited_recurse(visited, cx), + TyRef(_, ref tm) => tm.ty.is_uninhabited_recurse(visited, cx), - // FIXME(canndrew): this line breaks core::fmt - //TyRef(_, ref tm) => tm.ty.is_uninhabited(cx), _ => false, } } From 5b20c6aec716abd1b1e8cd8750ae0d106db5f616 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Thu, 15 Sep 2016 01:41:45 +0800 Subject: [PATCH 016/293] Recursive types are always non-empty --- src/librustc/ty/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 68440a2c8d8..f4a90876418 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1397,7 +1397,7 @@ impl<'a, 'gcx, 'tcx> AdtDefData<'tcx, 'static> { cx: TyCtxt<'a, 'gcx, 'tcx>, substs: &'tcx Substs<'tcx>) -> bool { match visited.entry((self.did, substs)) { - hash_map::Entry::Occupied(_) => return true, + hash_map::Entry::Occupied(_) => return false, hash_map::Entry::Vacant(ve) => ve.insert(()), }; self.variants.iter().all(|v| v.is_uninhabited_recurse(visited, cx, substs, self.is_union())) From a6cc398207009884a2885855e79ba424c2f4c303 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Wed, 9 Nov 2016 17:55:11 +0800 Subject: [PATCH 017/293] Revert libcore changes, redefine Void instead --- src/libcore/fmt/mod.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 9fcccacdbe1..c5116b996dd 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -166,7 +166,9 @@ pub struct Formatter<'a> { // NB. Argument is essentially an optimized partially applied formatting function, // equivalent to `exists T.(&T, fn(&T, &mut Formatter) -> Result`. -enum Void {} +struct Void { + _private: (), +} /// This struct represents the generic "argument" which is taken by the Xprintf /// family of functions. It contains a function to format the given value. At @@ -178,9 +180,8 @@ enum Void {} issue = "0")] #[doc(hidden)] pub struct ArgumentV1<'a> { - _ph: PhantomData<&'a ()>, - value: *const Void, - formatter: fn(*const Void, &mut Formatter) -> Result, + value: &'a Void, + formatter: fn(&Void, &mut Formatter) -> Result, } #[unstable(feature = "fmt_internals", reason = "internal to format_args!", @@ -204,7 +205,6 @@ impl<'a> ArgumentV1<'a> { f: fn(&T, &mut Formatter) -> Result) -> ArgumentV1<'b> { unsafe { ArgumentV1 { - _ph: PhantomData, formatter: mem::transmute(f), value: mem::transmute(x) } @@ -220,7 +220,7 @@ impl<'a> ArgumentV1<'a> { fn as_usize(&self) -> Option { if self.formatter as usize == ArgumentV1::show_usize as usize { - Some(unsafe { *(self.value as *const usize) }) + Some(unsafe { *(self.value as *const _ as *const usize) }) } else { None } From d756f61a5a7ab84d58fdaa9d53d84f6dad29f8db Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Wed, 9 Nov 2016 17:55:57 +0800 Subject: [PATCH 018/293] Make is_uninhabited respect privacy --- src/librustc/ty/mod.rs | 14 ++++++++++---- src/librustc/ty/sty.rs | 19 ++++++++++--------- src/librustc_const_eval/check_match.rs | 2 +- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index f4a90876418..88eb4ec1014 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1394,13 +1394,16 @@ impl<'a, 'gcx, 'tcx> AdtDefData<'tcx, 'static> { #[inline] pub fn is_uninhabited_recurse(&'tcx self, visited: &mut HashMap<(DefId, &'tcx Substs<'tcx>), ()>, + block: Option, cx: TyCtxt<'a, 'gcx, 'tcx>, substs: &'tcx Substs<'tcx>) -> bool { match visited.entry((self.did, substs)) { hash_map::Entry::Occupied(_) => return false, hash_map::Entry::Vacant(ve) => ve.insert(()), }; - self.variants.iter().all(|v| v.is_uninhabited_recurse(visited, cx, substs, self.is_union())) + self.variants.iter().all(|v| { + v.is_uninhabited_recurse(visited, block, cx, substs, self.is_union()) + }) } } @@ -1809,13 +1812,14 @@ impl<'a, 'gcx, 'tcx> VariantDefData<'tcx, 'static> { #[inline] pub fn is_uninhabited_recurse(&'tcx self, visited: &mut HashMap<(DefId, &'tcx Substs<'tcx>), ()>, + block: Option, cx: TyCtxt<'a, 'gcx, 'tcx>, substs: &'tcx Substs<'tcx>, is_union: bool) -> bool { if is_union { - self.fields.iter().all(|f| f.is_uninhabited_recurse(visited, cx, substs)) + self.fields.iter().all(|f| f.is_uninhabited_recurse(visited, block, cx, substs)) } else { - self.fields.iter().any(|f| f.is_uninhabited_recurse(visited, cx, substs)) + self.fields.iter().any(|f| f.is_uninhabited_recurse(visited, block, cx, substs)) } } } @@ -1849,9 +1853,11 @@ impl<'a, 'gcx, 'tcx> FieldDefData<'tcx, 'static> { #[inline] pub fn is_uninhabited_recurse(&'tcx self, visited: &mut HashMap<(DefId, &'tcx Substs<'tcx>), ()>, + block: Option, tcx: TyCtxt<'a, 'gcx, 'tcx>, substs: &'tcx Substs<'tcx>) -> bool { - self.ty(tcx, substs).is_uninhabited_recurse(visited, tcx) + block.map_or(true, |b| self.vis.is_accessible_from(b, &tcx.map)) && + self.ty(tcx, substs).is_uninhabited_recurse(visited, block, tcx) } } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 39461dc4f74..4e54e3a3630 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -23,7 +23,7 @@ use std::fmt; use std::ops; use std::collections::HashMap; use syntax::abi; -use syntax::ast::{self, Name}; +use syntax::ast::{self, Name, NodeId}; use syntax::symbol::{keywords, InternedString}; use serialize; @@ -930,25 +930,26 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } - pub fn is_uninhabited(&self, cx: TyCtxt<'a, 'gcx, 'tcx>) -> bool { + /// Checks whether a type is uninhabited. + /// If `block` is `Some(id)` it also checks that the uninhabited-ness is visible from `id`. + pub fn is_uninhabited(&self, block: Option, cx: TyCtxt<'a, 'gcx, 'tcx>) -> bool { let mut visited = HashMap::new(); - self.is_uninhabited_recurse(&mut visited, cx) + self.is_uninhabited_recurse(&mut visited, block, cx) } pub fn is_uninhabited_recurse(&self, visited: &mut HashMap<(DefId, &'tcx Substs<'tcx>), ()>, + block: Option, cx: TyCtxt<'a, 'gcx, 'tcx>) -> bool { - // FIXME(#24885): be smarter here, the AdtDefData::is_empty method could easily be made - // more complete. match self.sty { TyAdt(def, substs) => { - def.is_uninhabited_recurse(visited, cx, substs) + def.is_uninhabited_recurse(visited, block, cx, substs) }, TyNever => true, - TyTuple(ref tys) => tys.iter().any(|ty| ty.is_uninhabited_recurse(visited, cx)), - TyArray(ty, len) => len > 0 && ty.is_uninhabited_recurse(visited, cx), - TyRef(_, ref tm) => tm.ty.is_uninhabited_recurse(visited, cx), + TyTuple(ref tys) => tys.iter().any(|ty| ty.is_uninhabited_recurse(visited, block, cx)), + TyArray(ty, len) => len > 0 && ty.is_uninhabited_recurse(visited, block, cx), + TyRef(_, ref tm) => tm.ty.is_uninhabited_recurse(visited, block, cx), _ => false, } diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index f63a27e0d75..3c94d7d6fd5 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -204,7 +204,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { // Check for empty enum, because is_useful only works on inhabited types. let pat_ty = self.tcx.tables().node_id_to_type(scrut.id); if inlined_arms.is_empty() { - if !pat_ty.is_uninhabited(self.tcx) { + if !pat_ty.is_uninhabited(Some(scrut.id), self.tcx) { // We know the type is inhabited, so this must be wrong let mut err = create_e0004(self.tcx.sess, span, format!("non-exhaustive patterns: type {} \ From 2afec4dad1e80b3e53256306822f7849b7b9d128 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Tue, 22 Nov 2016 14:39:56 +0800 Subject: [PATCH 019/293] Use FxHashSet instead of HashMap --- src/librustc/ty/mod.rs | 14 ++++++-------- src/librustc/ty/sty.rs | 6 +++--- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 88eb4ec1014..d3864539c75 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -16,7 +16,6 @@ pub use self::IntVarValue::*; pub use self::LvaluePreference::*; pub use self::fold::TypeFoldable; -use std::collections::{hash_map, HashMap}; use dep_graph::{self, DepNode}; use hir::map as ast_map; use middle; @@ -31,7 +30,7 @@ use ty::subst::{Subst, Substs}; use ty::walk::TypeWalker; use util::common::MemoizationMap; use util::nodemap::NodeSet; -use util::nodemap::FxHashMap; +use util::nodemap::{FxHashMap, FxHashSet}; use serialize::{self, Encodable, Encoder}; use std::borrow::Cow; @@ -1393,13 +1392,12 @@ impl<'tcx> serialize::UseSpecializedDecodable for AdtDef<'tcx> {} impl<'a, 'gcx, 'tcx> AdtDefData<'tcx, 'static> { #[inline] pub fn is_uninhabited_recurse(&'tcx self, - visited: &mut HashMap<(DefId, &'tcx Substs<'tcx>), ()>, + visited: &mut FxHashSet<(DefId, &'tcx Substs<'tcx>)>, block: Option, cx: TyCtxt<'a, 'gcx, 'tcx>, substs: &'tcx Substs<'tcx>) -> bool { - match visited.entry((self.did, substs)) { - hash_map::Entry::Occupied(_) => return false, - hash_map::Entry::Vacant(ve) => ve.insert(()), + if !visited.insert((self.did, substs)) { + return false; }; self.variants.iter().all(|v| { v.is_uninhabited_recurse(visited, block, cx, substs, self.is_union()) @@ -1811,7 +1809,7 @@ impl<'tcx, 'container> VariantDefData<'tcx, 'container> { impl<'a, 'gcx, 'tcx> VariantDefData<'tcx, 'static> { #[inline] pub fn is_uninhabited_recurse(&'tcx self, - visited: &mut HashMap<(DefId, &'tcx Substs<'tcx>), ()>, + visited: &mut FxHashSet<(DefId, &'tcx Substs<'tcx>)>, block: Option, cx: TyCtxt<'a, 'gcx, 'tcx>, substs: &'tcx Substs<'tcx>, @@ -1852,7 +1850,7 @@ impl<'a, 'gcx, 'tcx, 'container> FieldDefData<'tcx, 'container> { impl<'a, 'gcx, 'tcx> FieldDefData<'tcx, 'static> { #[inline] pub fn is_uninhabited_recurse(&'tcx self, - visited: &mut HashMap<(DefId, &'tcx Substs<'tcx>), ()>, + visited: &mut FxHashSet<(DefId, &'tcx Substs<'tcx>)>, block: Option, tcx: TyCtxt<'a, 'gcx, 'tcx>, substs: &'tcx Substs<'tcx>) -> bool { diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 4e54e3a3630..cb3176cce10 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -21,10 +21,10 @@ use util::common::ErrorReported; use collections::enum_set::{self, EnumSet, CLike}; use std::fmt; use std::ops; -use std::collections::HashMap; use syntax::abi; use syntax::ast::{self, Name, NodeId}; use syntax::symbol::{keywords, InternedString}; +use util::nodemap::FxHashSet; use serialize; @@ -933,12 +933,12 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { /// Checks whether a type is uninhabited. /// If `block` is `Some(id)` it also checks that the uninhabited-ness is visible from `id`. pub fn is_uninhabited(&self, block: Option, cx: TyCtxt<'a, 'gcx, 'tcx>) -> bool { - let mut visited = HashMap::new(); + let mut visited = FxHashSet::default(); self.is_uninhabited_recurse(&mut visited, block, cx) } pub fn is_uninhabited_recurse(&self, - visited: &mut HashMap<(DefId, &'tcx Substs<'tcx>), ()>, + visited: &mut FxHashSet<(DefId, &'tcx Substs<'tcx>)>, block: Option, cx: TyCtxt<'a, 'gcx, 'tcx>) -> bool { match self.sty { From f4c68d2825535cbef847d0ac874ceced81cf2980 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 22 Nov 2016 14:51:55 +0200 Subject: [PATCH 020/293] rustc_metadata: don't break the version check when CrateRoot changes. --- src/librustc_metadata/decoder.rs | 4 ++++ src/librustc_metadata/encoder.rs | 15 +++++++++++---- src/librustc_metadata/locator.rs | 25 +++++++++++++------------ src/librustc_metadata/schema.rs | 9 +++++---- 4 files changed, 33 insertions(+), 20 deletions(-) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index fb1314992c0..25045679e71 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -420,6 +420,10 @@ impl<'a, 'tcx> MetadataBlob { self.raw_bytes().starts_with(METADATA_HEADER) } + pub fn get_rustc_version(&self) -> String { + Lazy::with_position(METADATA_HEADER.len() + 4).decode(self) + } + pub fn get_root(&self) -> CrateRoot { let slice = self.raw_bytes(); let offset = METADATA_HEADER.len(); diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 2f4b0d5c87b..665f3de0a3b 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1278,7 +1278,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let link_meta = self.link_meta; let is_proc_macro = tcx.sess.crate_types.borrow().contains(&CrateTypeProcMacro); let root = self.lazy(&CrateRoot { - rustc_version: rustc_version(), name: link_meta.crate_name, triple: tcx.sess.opts.target_triple.clone(), hash: link_meta.crate_hash, @@ -1368,7 +1367,8 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Will be filed with the root position after encoding everything. cursor.write_all(&[0, 0, 0, 0]).unwrap(); - let root = EncodeContext { + let root = { + let mut ecx = EncodeContext { opaque: opaque::Encoder::new(&mut cursor), tcx: tcx, reexports: reexports, @@ -1378,8 +1378,15 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, lazy_state: LazyState::NoNode, type_shorthands: Default::default(), predicate_shorthands: Default::default(), - } - .encode_crate_root(); + }; + + // Encode the rustc version string in a predictable location. + rustc_version().encode(&mut ecx).unwrap(); + + // Encode all the entries and extra information in the crate, + // culminating in the `CrateRoot` which points to all of it. + ecx.encode_crate_root() + }; let mut result = cursor.into_inner(); // Encode the root position. diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs index f5196f7ea84..106d479c12c 100644 --- a/src/librustc_metadata/locator.rs +++ b/src/librustc_metadata/locator.rs @@ -629,6 +629,19 @@ impl<'a> Context<'a> { } fn crate_matches(&mut self, metadata: &MetadataBlob, libpath: &Path) -> Option { + let rustc_version = rustc_version(); + let found_version = metadata.get_rustc_version(); + if found_version != rustc_version { + info!("Rejecting via version: expected {} got {}", + rustc_version, + found_version); + self.rejected_via_version.push(CrateMismatch { + path: libpath.to_path_buf(), + got: found_version, + }); + return None; + } + let root = metadata.get_root(); if let Some(is_proc_macro) = self.is_proc_macro { if root.macro_derive_registrar.is_some() != is_proc_macro { @@ -636,18 +649,6 @@ impl<'a> Context<'a> { } } - let rustc_version = rustc_version(); - if root.rustc_version != rustc_version { - info!("Rejecting via version: expected {} got {}", - rustc_version, - root.rustc_version); - self.rejected_via_version.push(CrateMismatch { - path: libpath.to_path_buf(), - got: root.rustc_version, - }); - return None; - } - if self.should_match_name { if self.crate_name != root.name { info!("Rejecting via crate name"); diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index e11719dc40f..32e89f64f0e 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -34,15 +34,17 @@ pub fn rustc_version() -> String { /// Metadata encoding version. /// NB: increment this if you change the format of metadata such that -/// the rustc version can't be found to compare with `RUSTC_VERSION`. -pub const METADATA_VERSION: u8 = 3; +/// the rustc version can't be found to compare with `rustc_version()`. +pub const METADATA_VERSION: u8 = 4; /// Metadata header which includes `METADATA_VERSION`. /// To get older versions of rustc to ignore this metadata, /// there are 4 zero bytes at the start, which are treated /// as a length of 0 by old compilers. /// -/// This header is followed by the position of the `CrateRoot`. +/// This header is followed by the position of the `CrateRoot`, +/// which is encoded as a 32-bit big-endian unsigned integer, +/// and further followed by the rustc version string. pub const METADATA_HEADER: &'static [u8; 12] = &[0, 0, 0, 0, b'r', b'u', b's', b't', 0, 0, 0, METADATA_VERSION]; @@ -163,7 +165,6 @@ pub enum LazyState { #[derive(RustcEncodable, RustcDecodable)] pub struct CrateRoot { - pub rustc_version: String, pub name: Symbol, pub triple: String, pub hash: hir::svh::Svh, From 1a91fc62d3f5bf91c13f13a6620cb529dbcad518 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 18 Nov 2016 17:19:39 +0100 Subject: [PATCH 021/293] Add missing examples for Ipv6Addr --- src/libstd/net/ip.rs | 129 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 7b7be6e2eee..4df7eeae192 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -522,6 +522,14 @@ impl Ipv6Addr { /// Creates a new IPv6 address from eight 16-bit segments. /// /// The result will represent the IP address a:b:c:d:e:f:g:h. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr { @@ -538,6 +546,15 @@ impl Ipv6Addr { } /// Returns the eight 16-bit segments that make up this address. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).segments(), + /// [0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff]); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn segments(&self) -> [u16; 8] { let arr = &self.inner.s6_addr; @@ -558,6 +575,15 @@ impl Ipv6Addr { /// This property is defined in [RFC 4291]. /// /// [RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unspecified(), false); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).is_unspecified(), true); + /// ``` #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_unspecified(&self) -> bool { self.segments() == [0, 0, 0, 0, 0, 0, 0, 0] @@ -568,6 +594,15 @@ impl Ipv6Addr { /// This property is defined in [RFC 4291]. /// /// [RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_loopback(), false); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_loopback(), true); + /// ``` #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_loopback(&self) -> bool { self.segments() == [0, 0, 0, 0, 0, 0, 0, 1] @@ -580,6 +615,20 @@ impl Ipv6Addr { /// - the loopback address /// - link-local, site-local, and unique local unicast addresses /// - interface-, link-, realm-, admin- and site-local multicast addresses + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv6Addr; + /// + /// fn main() { + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), true); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_global(), false); + /// assert_eq!(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1).is_global(), true); + /// } + /// ``` pub fn is_global(&self) -> bool { match self.multicast_scope() { Some(Ipv6MulticastScope::Global) => true, @@ -593,6 +642,15 @@ impl Ipv6Addr { /// This property is defined in [RFC 4193]. /// /// [RFC 4193]: https://tools.ietf.org/html/rfc4193 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unique_local(), false); + /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true); + /// ``` pub fn is_unique_local(&self) -> bool { (self.segments()[0] & 0xfe00) == 0xfc00 } @@ -602,12 +660,32 @@ impl Ipv6Addr { /// This property is defined in [RFC 4291]. /// /// [RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_link_local(), + /// false); + /// assert_eq!(Ipv6Addr::new(0xfe8a, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true); + /// ``` pub fn is_unicast_link_local(&self) -> bool { (self.segments()[0] & 0xffc0) == 0xfe80 } /// Returns true if this is a deprecated unicast site-local address /// (fec0::/10). + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_site_local(), + /// false); + /// assert_eq!(Ipv6Addr::new(0xfec2, 0, 0, 0, 0, 0, 0, 0).is_unicast_site_local(), true); + /// ``` pub fn is_unicast_site_local(&self) -> bool { (self.segments()[0] & 0xffc0) == 0xfec0 } @@ -618,6 +696,15 @@ impl Ipv6Addr { /// This property is defined in [RFC 3849]. /// /// [RFC 3849]: https://tools.ietf.org/html/rfc3849 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(), false); + /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true); + /// ``` pub fn is_documentation(&self) -> bool { (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) } @@ -632,6 +719,15 @@ impl Ipv6Addr { /// - unique local addresses /// - the unspecified address /// - the address range reserved for documentation + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_global(), false); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(), true); + /// ``` pub fn is_unicast_global(&self) -> bool { !self.is_multicast() && !self.is_loopback() && !self.is_unicast_link_local() @@ -640,6 +736,16 @@ impl Ipv6Addr { } /// Returns the address's multicast scope if the address is multicast. + /// + /// # Examples + /// + /// ``` + /// use std::net::{Ipv6Addr, Ipv6MulticastScope}; + /// + /// assert_eq!(Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0).multicast_scope(), + /// Some(Ipv6MulticastScope::Global)); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None); + /// ``` pub fn multicast_scope(&self) -> Option { if self.is_multicast() { match self.segments()[0] & 0x000f { @@ -662,6 +768,14 @@ impl Ipv6Addr { /// This property is defined by [RFC 4291]. /// /// [RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_multicast(), true); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_multicast(), false); + /// ``` #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_multicast(&self) -> bool { (self.segments()[0] & 0xff00) == 0xff00 @@ -671,6 +785,14 @@ impl Ipv6Addr { /// neither IPv4-compatible or IPv4-mapped. /// /// ::a.b.c.d and ::ffff:a.b.c.d become a.b.c.d + /// + /// ``` + /// use std::net::{Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4(), None); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4(), + /// Some(Ipv4Addr::new(192, 10, 2, 255))); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn to_ipv4(&self) -> Option { match self.segments() { @@ -683,6 +805,13 @@ impl Ipv6Addr { } /// Returns the sixteen eight-bit integers the IPv6 address consists of. + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).octets(), + /// [255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + /// ``` #[stable(feature = "ipv6_to_octets", since = "1.12.0")] pub fn octets(&self) -> [u8; 16] { self.inner.s6_addr From 5c23f2e3c88275cee37acbd36c12baba57c4de2b Mon Sep 17 00:00:00 2001 From: Theodore DeRego Date: Fri, 11 Nov 2016 18:21:03 -0800 Subject: [PATCH 022/293] Fuchsia support for std::process via liblaunchpad. --- src/libstd/build.rs | 2 + src/libstd/process.rs | 13 +- src/libstd/sys/unix/fd.rs | 2 + src/libstd/sys/unix/magenta.rs | 157 ++++++++++++++++++++++ src/libstd/sys/unix/mod.rs | 20 +++ src/libstd/sys/unix/pipe.rs | 1 + src/libstd/sys/unix/process.rs | 236 ++++++++++++++++++++++++++++++++- 7 files changed, 426 insertions(+), 5 deletions(-) create mode 100644 src/libstd/sys/unix/magenta.rs diff --git a/src/libstd/build.rs b/src/libstd/build.rs index 72cd6e4830b..1087d1f2447 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -60,6 +60,8 @@ fn main() { println!("cargo:rustc-link-lib=shell32"); } else if target.contains("fuchsia") { println!("cargo:rustc-link-lib=magenta"); + println!("cargo:rustc-link-lib=mxio"); + println!("cargo:rustc-link-lib=launchpad"); // for std::process } } diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 9d21a76e81b..a9c68e82175 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -780,6 +780,8 @@ impl Child { /// #[stable(feature = "process", since = "1.0.0")] pub fn wait_with_output(mut self) -> io::Result { + //use io::ErrorKind; + drop(self.stdin.take()); let (mut stdout, mut stderr) = (Vec::new(), Vec::new()); @@ -794,8 +796,15 @@ impl Child { res.unwrap(); } (Some(out), Some(err)) => { - let res = read2(out.inner, &mut stdout, err.inner, &mut stderr); - res.unwrap(); + match read2(out.inner, &mut stdout, err.inner, &mut stderr) { + Ok(()) => { }, + #[cfg(not(target_os = "fuchsia"))] + Err(ref e) => { panic!("Failed to read child's stdout and stderr: {:?}", e); }, + #[cfg(target_os = "fuchsia")] + Err(_) => { + // FIXME: Right now there's a bug in magenta's pipes implementation + }, + } } } diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs index 41bb96fed16..61eb60da486 100644 --- a/src/libstd/sys/unix/fd.rs +++ b/src/libstd/sys/unix/fd.rs @@ -110,6 +110,7 @@ impl FileDesc { #[cfg(not(any(target_env = "newlib", target_os = "solaris", target_os = "emscripten", + target_os = "fuchsia", target_os = "haiku")))] pub fn set_cloexec(&self) -> io::Result<()> { unsafe { @@ -120,6 +121,7 @@ impl FileDesc { #[cfg(any(target_env = "newlib", target_os = "solaris", target_os = "emscripten", + target_os = "fuchsia", target_os = "haiku"))] pub fn set_cloexec(&self) -> io::Result<()> { unsafe { diff --git a/src/libstd/sys/unix/magenta.rs b/src/libstd/sys/unix/magenta.rs new file mode 100644 index 00000000000..ae3b7789b10 --- /dev/null +++ b/src/libstd/sys/unix/magenta.rs @@ -0,0 +1,157 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(non_camel_case_types)] + +use os::raw::c_char; +use u64; + +use libc::{c_int, c_void}; + +pub type mx_handle_t = i32; +pub type mx_vaddr_t = usize; +pub type mx_rights_t = u32; +pub type mx_status_t = i32; + +pub type mx_size_t = usize; +pub type mx_ssize_t = isize; + +pub const MX_HANDLE_INVALID: mx_handle_t = 0; + +pub type mx_time_t = u64; +pub const MX_TIME_INFINITE : mx_time_t = u64::MAX; + +pub const NO_ERROR : mx_status_t = 0; + +pub type mx_signals_t = u32; + +pub const MX_OBJECT_SIGNAL_3 : mx_signals_t = 1 << 3; + +pub const MX_TASK_TERMINATED : mx_signals_t = MX_OBJECT_SIGNAL_3; + +pub const MX_RIGHT_SAME_RIGHTS : mx_rights_t = 1 << 31; + +pub type mx_object_info_topic_t = u32; + +pub const MX_INFO_PROCESS : mx_object_info_topic_t = 3; + +pub const MX_HND_TYPE_JOB: u32 = 6; + +// Common MX_INFO header +#[derive(Default)] +#[repr(C)] +pub struct mx_info_header_t { + pub topic: u32, // identifies the info struct + pub avail_topic_size: u16, // “native” size of the struct + pub topic_size: u16, // size of the returned struct (<=topic_size) + pub avail_count: u32, // number of records the kernel has + pub count: u32, // number of records returned (limited by buffer size) +} + +#[derive(Default)] +#[repr(C)] +pub struct mx_record_process_t { + pub return_code: c_int, +} + +// Returned for topic MX_INFO_PROCESS +#[derive(Default)] +#[repr(C)] +pub struct mx_info_process_t { + pub hdr: mx_info_header_t, + pub rec: mx_record_process_t, +} + +#[link(name = "magenta")] +extern { + pub fn mx_handle_close(handle: mx_handle_t) -> mx_status_t; + + pub fn mx_handle_duplicate(handle: mx_handle_t, rights: mx_rights_t, + out: *const mx_handle_t) -> mx_handle_t; + + pub fn mx_handle_wait_one(handle: mx_handle_t, signals: mx_signals_t, timeout: mx_time_t, + pending: *mut mx_signals_t) -> mx_status_t; + + pub fn mx_object_get_info(handle: mx_handle_t, topic: u32, buffer: *mut c_void, + buffer_size: mx_size_t, actual_size: *mut mx_size_t, + avail: *mut mx_size_t) -> mx_status_t; +} + +// Handle Info entries associate a type and optional +// argument with each handle included in the process +// arguments message. +pub fn mx_hnd_info(hnd_type: u32, arg: u32) -> u32 { + (hnd_type & 0xFFFF) | ((arg & 0xFFFF) << 16) +} + +#[link(name="mxio")] +extern { + pub fn mxio_get_startup_handle(id: u32) -> mx_handle_t; +} + +// From `enum special_handles` in system/ulib/launchpad/launchpad.c +#[allow(unused)] pub const HND_LOADER_SVC: usize = 0; +// HND_EXEC_VMO = 1 +#[allow(unused)] pub const HND_SPECIAL_COUNT: usize = 2; + +#[repr(C)] +pub struct launchpad_t { + argc: u32, + envc: u32, + args: *const c_char, + args_len: usize, + env: *const c_char, + env_len: usize, + + handles: *mut mx_handle_t, + handles_info: *mut u32, + handle_count: usize, + handle_alloc: usize, + + entry: mx_vaddr_t, + base: mx_vaddr_t, + vdso_base: mx_vaddr_t, + + stack_size: usize, + + special_handles: [mx_handle_t; HND_SPECIAL_COUNT], + loader_message: bool, +} + +#[link(name="launchpad")] +extern { + pub fn launchpad_create(job: mx_handle_t, name: *const c_char, + lp: *mut *mut launchpad_t) -> mx_status_t; + + pub fn launchpad_start(lp: *mut launchpad_t) -> mx_status_t; + + pub fn launchpad_destroy(lp: *mut launchpad_t); + + pub fn launchpad_arguments(lp: *mut launchpad_t, argc: c_int, + argv: *const *const c_char) -> mx_status_t; + + pub fn launchpad_environ(lp: *mut launchpad_t, envp: *const *const c_char) -> mx_status_t; + + pub fn launchpad_clone_mxio_root(lp: *mut launchpad_t) -> mx_status_t; + + pub fn launchpad_clone_mxio_cwd(lp: *mut launchpad_t) -> mx_status_t; + + pub fn launchpad_clone_fd(lp: *mut launchpad_t, fd: c_int, target_fd: c_int) -> mx_status_t; + + pub fn launchpad_transfer_fd(lp: *mut launchpad_t, fd: c_int, target_fd: c_int) -> mx_status_t; + + pub fn launchpad_elf_load(lp: *mut launchpad_t, vmo: mx_handle_t) -> mx_status_t; + + pub fn launchpad_add_vdso_vmo(lp: *mut launchpad_t) -> mx_status_t; + + pub fn launchpad_load_vdso(lp: *mut launchpad_t, vmo: mx_handle_t) -> mx_status_t; + + pub fn launchpad_vmo_from_file(filename: *const c_char) -> mx_handle_t; +} diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index fd7dc17cccd..8fe55af51d5 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -13,6 +13,11 @@ use io::{self, ErrorKind}; use libc; +#[cfg(target_os = "fuchsia")] +use convert::TryInto; +#[cfg(target_os = "fuchsia")] +pub use self::magenta::mx_status_t; + #[cfg(target_os = "android")] pub use os::android as platform; #[cfg(target_os = "bitrig")] pub use os::bitrig as platform; #[cfg(target_os = "dragonfly")] pub use os::dragonfly as platform; @@ -41,6 +46,8 @@ pub mod ext; pub mod fast_thread_local; pub mod fd; pub mod fs; +#[cfg(target_os = "fuchsia")] +pub mod magenta; pub mod memchr; pub mod mutex; pub mod net; @@ -164,6 +171,19 @@ pub fn cvt_r(mut f: F) -> io::Result } } +#[cfg(target_os = "fuchsia")] +pub fn mx_cvt(t: T) -> io::Result where T: TryInto+Copy { + if let Ok(status) = TryInto::try_into(t) { + if status < 0 { + Err(io::Error::from_raw_os_error(status)) + } else { + Ok(t) + } + } else { + Err(io::Error::last_os_error()) + } +} + // On Unix-like platforms, libc::abort will unregister signal handlers // including the SIGABRT handler, preventing the abort from being blocked, and // fclose streams, with the side effect of flushing them so libc bufferred diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index ffe8032e460..a8ed415b7f4 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -77,6 +77,7 @@ pub fn read2(p1: AnonPipe, v1: &mut Vec, p2: AnonPipe, v2: &mut Vec) -> io::Result<()> { + // Set both pipes into nonblocking mode as we're gonna be reading from both // in the `select` loop below, and we wouldn't want one to block the other! let p1 = p1.into_fd(); diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs index dafc11d9cc8..aa203dc6215 100644 --- a/src/libstd/sys/unix/process.rs +++ b/src/libstd/sys/unix/process.rs @@ -15,13 +15,23 @@ use env; use ffi::{OsString, OsStr, CString, CStr}; use fmt; use io::{self, Error, ErrorKind}; -use libc::{self, pid_t, c_int, gid_t, uid_t, c_char}; +use libc::{self, c_int, gid_t, uid_t, c_char}; use mem; use ptr; use sys::fd::FileDesc; use sys::fs::{File, OpenOptions}; use sys::pipe::{self, AnonPipe}; -use sys::{self, cvt, cvt_r}; + +#[cfg(not(target_os = "fuchsia"))] +use sys::cvt; +#[cfg(target_os = "fuchsia")] +use sys::mx_cvt; + +#[cfg(target_os = "fuchsia")] +use sys::magenta::{launchpad_t, mx_handle_t}; + +#[cfg(not(target_os = "fuchsia"))] +use libc::pid_t; //////////////////////////////////////////////////////////////////////////////// // Command @@ -210,8 +220,11 @@ impl Command { self.stderr = Some(stderr); } + #[cfg(not(target_os = "fuchsia"))] pub fn spawn(&mut self, default: Stdio, needs_stdin: bool) -> io::Result<(Process, StdioPipes)> { + use sys; + const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX"; if self.saw_nul { @@ -286,6 +299,31 @@ impl Command { } } + #[cfg(target_os = "fuchsia")] + pub fn spawn(&mut self, default: Stdio, needs_stdin: bool) + -> io::Result<(Process, StdioPipes)> { + if self.saw_nul { + return Err(io::Error::new(ErrorKind::InvalidInput, + "nul byte found in provided data")); + } + + let (ours, theirs) = self.setup_io(default, needs_stdin)?; + + let (maybe_process, err) = unsafe { self.do_exec(&theirs) }; + // We don't want FileDesc::drop to be called on any stdio. It would close their handles. + let ChildPipes { stdin: their_stdin, stdout: their_stdout, stderr: their_stderr } = theirs; + their_stdin.fd(); + their_stdout.fd(); + their_stderr.fd(); + + if let Some((launchpad, process_handle)) = maybe_process { + Ok((Process { launchpad: launchpad, handle: process_handle, status: None }, ours)) + } else { + Err(err) + } + } + + #[cfg(not(target_os = "fuchsia"))] pub fn exec(&mut self, default: Stdio) -> io::Error { if self.saw_nul { return io::Error::new(ErrorKind::InvalidInput, @@ -298,6 +336,22 @@ impl Command { } } + #[cfg(target_os = "fuchsia")] + pub fn exec(&mut self, default: Stdio) -> io::Error { + if self.saw_nul { + return io::Error::new(ErrorKind::InvalidInput, + "nul byte found in provided data") + } + + match self.setup_io(default, true) { + Ok((_, _)) => { + // FIXME: This is tough because we don't support the exec syscalls + unimplemented!(); + }, + Err(e) => e, + } + } + // And at this point we've reached a special time in the life of the // child. The child must now be considered hamstrung and unable to // do anything other than syscalls really. Consider the following @@ -328,7 +382,10 @@ impl Command { // allocation). Instead we just close it manually. This will never // have the drop glue anyway because this code never returns (the // child will either exec() or invoke libc::exit) + #[cfg(not(target_os = "fuchsia"))] unsafe fn do_exec(&mut self, stdio: ChildPipes) -> io::Error { + use sys::{self, cvt_r}; + macro_rules! t { ($e:expr) => (match $e { Ok(e) => e, @@ -395,6 +452,108 @@ impl Command { io::Error::last_os_error() } + #[cfg(target_os = "fuchsia")] + unsafe fn do_exec(&mut self, stdio: &ChildPipes) + -> (Option<(*mut launchpad_t, mx_handle_t)>, io::Error) { + use sys::magenta::*; + + macro_rules! t { + ($e:expr) => (match $e { + Ok(e) => e, + Err(e) => return (None, e), + }) + } + + macro_rules! tlp { + ($lp:expr, $e:expr) => (match $e { + Ok(e) => e, + Err(e) => { + launchpad_destroy($lp); + return (None, e); + }, + }) + } + + let job_handle = mxio_get_startup_handle(mx_hnd_info(MX_HND_TYPE_JOB, 0)); + let envp = match self.envp { + Some(ref envp) => envp.as_ptr(), + None => ptr::null(), + }; + + let mut launchpad: *mut launchpad_t = ptr::null_mut(); + let mut job_copy: mx_handle_t = MX_HANDLE_INVALID; + + // Duplicate the job handle + t!(mx_cvt(mx_handle_duplicate(job_handle, MX_RIGHT_SAME_RIGHTS, + &mut job_copy as *mut mx_handle_t))); + // Create a launchpad + t!(mx_cvt(launchpad_create(job_copy, self.argv[0], + &mut launchpad as *mut *mut launchpad_t))); + // Set the process argv + tlp!(launchpad, mx_cvt(launchpad_arguments(launchpad, self.argv.len() as i32 - 1, + self.argv.as_ptr()))); + // Setup the environment vars + let status = launchpad_environ(launchpad, envp); + if status != NO_ERROR { + launchpad_destroy(launchpad); + return (None, io::Error::last_os_error()); + } + let status = launchpad_add_vdso_vmo(launchpad); + if status != NO_ERROR { + launchpad_destroy(launchpad); + return (None, io::Error::last_os_error()); + } + let status = launchpad_clone_mxio_root(launchpad); + if status != NO_ERROR { + launchpad_destroy(launchpad); + return (None, io::Error::last_os_error()); + } + // Load the executable + let status = launchpad_elf_load(launchpad, launchpad_vmo_from_file(self.argv[0])); + if status != NO_ERROR { + launchpad_destroy(launchpad); + return (None, io::Error::last_os_error()); + } + let status = launchpad_load_vdso(launchpad, MX_HANDLE_INVALID); + if status != NO_ERROR { + launchpad_destroy(launchpad); + return (None, io::Error::last_os_error()); + } + let status = launchpad_clone_mxio_cwd(launchpad); + if status != NO_ERROR { + launchpad_destroy(launchpad); + return (None, io::Error::last_os_error()); + } + + // Clone stdin, stdout, and stderr + if let Some(fd) = stdio.stdin.fd() { + launchpad_transfer_fd(launchpad, fd, 0); + } else { + launchpad_clone_fd(launchpad, 0, 0); + } + if let Some(fd) = stdio.stdout.fd() { + launchpad_transfer_fd(launchpad, fd, 1); + } else { + launchpad_clone_fd(launchpad, 1, 1); + } + if let Some(fd) = stdio.stderr.fd() { + launchpad_transfer_fd(launchpad, fd, 2); + } else { + launchpad_clone_fd(launchpad, 2, 2); + } + + for callback in self.closures.iter_mut() { + t!(callback()); + } + + let process_handle = launchpad_start(launchpad); + if process_handle < 0 { + launchpad_destroy(launchpad); + return (None, io::Error::last_os_error()); + } + + (Some((launchpad, process_handle)), io::Error::last_os_error()) + } fn setup_io(&self, default: Stdio, needs_stdin: bool) -> io::Result<(StdioPipes, ChildPipes)> { @@ -431,7 +590,9 @@ impl Stdio { fn to_child_stdio(&self, readable: bool) -> io::Result<(ChildStdio, Option)> { match *self { - Stdio::Inherit => Ok((ChildStdio::Inherit, None)), + Stdio::Inherit => { + Ok((ChildStdio::Inherit, None)) + }, // Make sure that the source descriptors are not an stdio // descriptor, otherwise the order which we set the child's @@ -556,16 +717,31 @@ impl fmt::Display for ExitStatus { } /// The unique id of the process (this should never be negative). +#[cfg(not(target_os = "fuchsia"))] pub struct Process { pid: pid_t, status: Option, } +#[cfg(target_os = "fuchsia")] +pub struct Process { + launchpad: *mut launchpad_t, + handle: mx_handle_t, + status: Option, +} + impl Process { + #[cfg(not(target_os = "fuchsia"))] pub fn id(&self) -> u32 { self.pid as u32 } + #[cfg(target_os = "fuchsia")] + pub fn id(&self) -> u32 { + 0 + } + + #[cfg(not(target_os = "fuchsia"))] pub fn kill(&mut self) -> io::Result<()> { // If we've already waited on this process then the pid can be recycled // and used for another process, and we probably shouldn't be killing @@ -578,7 +754,28 @@ impl Process { } } + #[cfg(target_os = "fuchsia")] + pub fn kill(&mut self) -> io::Result<()> { + use sys::magenta::*; + + // If we've already waited on this process then the pid can be recycled + // and used for another process, and we probably shouldn't be killing + // random processes, so just return an error. + if self.status.is_some() { + Err(Error::new(ErrorKind::InvalidInput, + "invalid argument: can't kill an exited process")) + } else { + unsafe { + mx_cvt(mx_handle_close(self.handle))?; + launchpad_destroy(self.launchpad); + } + Ok(()) + } + } + + #[cfg(not(target_os = "fuchsia"))] pub fn wait(&mut self) -> io::Result { + use sys::cvt_r; if let Some(status) = self.status { return Ok(status) } @@ -587,6 +784,39 @@ impl Process { self.status = Some(ExitStatus(status)); Ok(ExitStatus(status)) } + + #[cfg(target_os = "fuchsia")] + pub fn wait(&mut self) -> io::Result { + use default::Default; + use sys::magenta::*; + + if let Some(status) = self.status { + return Ok(status) + } + + let mut proc_info: mx_info_process_t = Default::default(); + let mut actual: mx_size_t = 0; + let mut avail: mx_size_t = 0; + + unsafe { + mx_cvt(mx_handle_wait_one(self.handle, MX_TASK_TERMINATED, + MX_TIME_INFINITE, ptr::null_mut()))?; + mx_cvt(mx_object_get_info(self.handle, MX_INFO_PROCESS, + &mut proc_info as *mut _ as *mut libc::c_void, + mem::size_of::(), &mut actual, + &mut avail))?; + } + if actual != 1 { + return Err(Error::new(ErrorKind::InvalidInput, + "Failed to get exit status of process")); + } + self.status = Some(ExitStatus(proc_info.rec.return_code)); + unsafe { + mx_cvt(mx_handle_close(self.handle))?; + launchpad_destroy(self.launchpad); + } + Ok(ExitStatus(proc_info.rec.return_code)) + } } #[cfg(all(test, not(target_os = "emscripten")))] From c0464eef175b81073052a173534f17d04e061a30 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 22 Nov 2016 15:16:54 -0500 Subject: [PATCH 023/293] Move the myriad-closures.rs test case to run-pass-full test suite. --- .../{run-pass => run-pass-fulldeps}/myriad-closures.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) rename src/test/{run-pass => run-pass-fulldeps}/myriad-closures.rs (91%) diff --git a/src/test/run-pass/myriad-closures.rs b/src/test/run-pass-fulldeps/myriad-closures.rs similarity index 91% rename from src/test/run-pass/myriad-closures.rs rename to src/test/run-pass-fulldeps/myriad-closures.rs index d2c9a5d562b..a946ec635b2 100644 --- a/src/test/run-pass/myriad-closures.rs +++ b/src/test/run-pass-fulldeps/myriad-closures.rs @@ -13,6 +13,9 @@ // toolchain. // See https://github.com/rust-lang/rust/issues/34793 for more information. +// Make sure we don't optimize anything away: +// compile-flags: -C no-prepopulate-passes + // Expand something exponentially macro_rules! go_bacterial { ($mac:ident) => ($mac!()); @@ -23,10 +26,7 @@ macro_rules! go_bacterial { } macro_rules! mk_closure { - () => ({ - let c = |a: u32| a + 4; - let _ = c(2); - }) + () => ((move || {})()) } macro_rules! mk_fn { From 12f3caf6a8104c208002b04c815e300d28436719 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 22 Nov 2016 15:49:58 -0500 Subject: [PATCH 024/293] ICH: Add test case for struct constructor expressions. --- .../incremental/hashes/struct_constructors.rs | 254 ++++++++++++++++++ 1 file changed, 254 insertions(+) create mode 100644 src/test/incremental/hashes/struct_constructors.rs diff --git a/src/test/incremental/hashes/struct_constructors.rs b/src/test/incremental/hashes/struct_constructors.rs new file mode 100644 index 00000000000..c4366ea11e3 --- /dev/null +++ b/src/test/incremental/hashes/struct_constructors.rs @@ -0,0 +1,254 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +// This test case tests the incremental compilation hash (ICH) implementation +// for struct constructor expressions. + +// The general pattern followed here is: Change one thing between rev1 and rev2 +// and make sure that the hash has changed, then change nothing between rev2 and +// rev3 and make sure that the hash has not changed. + +// must-compile-successfully +// revisions: cfail1 cfail2 cfail3 +// compile-flags: -Z query-dep-graph + +#![allow(warnings)] +#![feature(rustc_attrs)] +#![crate_type="rlib"] + + +struct RegularStruct { + x: i32, + y: i64, + z: i16, +} + +// Change field value (regular struct) ----------------------------------------- +#[cfg(cfail1)] +fn change_field_value_regular_struct() -> RegularStruct { + RegularStruct { + x: 0, + y: 1, + z: 2, + } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +fn change_field_value_regular_struct() -> RegularStruct { + RegularStruct { + x: 0, + y: 2, + z: 2, + } +} + + + +// Change field order (regular struct) ----------------------------------------- +#[cfg(cfail1)] +fn change_field_order_regular_struct() -> RegularStruct { + RegularStruct { + x: 3, + y: 4, + z: 5, + } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +fn change_field_order_regular_struct() -> RegularStruct { + RegularStruct { + y: 4, + x: 3, + z: 5, + } +} + + + +// Add field (regular struct) -------------------------------------------------- +#[cfg(cfail1)] +fn add_field_regular_struct() -> RegularStruct { + let struct1 = RegularStruct { + x: 3, + y: 4, + z: 5, + }; + + RegularStruct { + x: 7, + .. struct1 + } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +fn add_field_regular_struct() -> RegularStruct { + let struct1 = RegularStruct { + x: 3, + y: 4, + z: 5, + }; + + RegularStruct { + x: 7, + y: 8, + .. struct1 + } +} + + + +// Change field label (regular struct) ----------------------------------------- +#[cfg(cfail1)] +fn change_field_label_regular_struct() -> RegularStruct { + let struct1 = RegularStruct { + x: 3, + y: 4, + z: 5, + }; + + RegularStruct { + x: 7, + y: 9, + .. struct1 + } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +fn change_field_label_regular_struct() -> RegularStruct { + let struct1 = RegularStruct { + x: 3, + y: 4, + z: 5, + }; + + RegularStruct { + x: 7, + z: 9, + .. struct1 + } +} + + + +struct RegularStruct2 { + x: i8, + y: i8, + z: i8, +} + +// Change constructor path (regular struct) ------------------------------------ +#[cfg(cfail1)] +fn change_constructor_path_regular_struct() { + let _ = RegularStruct { + x: 0, + y: 1, + z: 2, + }; +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +fn change_constructor_path_regular_struct() { + let _ = RegularStruct2 { + x: 0, + y: 1, + z: 2, + }; +} + + + +// Change constructor path indirectly (regular struct) ------------------------- +mod change_constructor_path_indirectly_regular_struct { + #[cfg(cfail1)] + use super::RegularStruct as Struct; + #[cfg(not(cfail1))] + use super::RegularStruct2 as Struct; + + fn function() -> Struct { + Struct { + x: 0, + y: 1, + z: 2, + } + } +} + + + +struct TupleStruct(i32, i64, i16); + +// Change field value (tuple struct) ------------------------------------------- +#[cfg(cfail1)] +fn change_field_value_tuple_struct() -> TupleStruct { + TupleStruct(0, 1, 2) +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +fn change_field_value_tuple_struct() -> TupleStruct { + TupleStruct(0, 1, 3) +} + + + +struct TupleStruct2(u16, u16, u16); + +// Change constructor path (tuple struct) -------------------------------------- +#[cfg(cfail1)] +fn change_constructor_path_tuple_struct() { + let _ = TupleStruct(0, 1, 2); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +fn change_constructor_path_tuple_struct() { + let _ = TupleStruct2(0, 1, 2); +} + + + +// Change constructor path indirectly (tuple struct) --------------------------- +mod change_constructor_path_indirectly_tuple_struct { + #[cfg(cfail1)] + use super::TupleStruct as Struct; + #[cfg(not(cfail1))] + use super::TupleStruct2 as Struct; + + fn function() -> Struct { + Struct(0, 1, 2) + } +} From eb53ca3aad616069cb8f6f8fff71c27e9ba9640c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 23 Oct 2016 17:22:06 -0700 Subject: [PATCH 025/293] Show multiline spans in full if short enough When dealing with multiline spans that span few lines, show the complete span instead of restricting to the first character of the first line. For example, instead of: ``` % ./rustc foo.rs error[E0277]: the trait bound `{integer}: std::ops::Add<()>` is not satisfied --> foo.rs:13:9 | 13 | foo(1 + bar(x, | ^ trait `{integer}: std::ops::Add<()>` not satisfied | ``` show ``` % ./rustc foo.rs error[E0277]: the trait bound `{integer}: std::ops::Add<()>` is not satisfied --> foo.rs:13:9 | 13 | foo(1 + bar(x, | ________^ starting here... 14 | | y), | |_____________^ ...ending here: trait `{integer}: std::ops::Add<()>` not satisfied | ``` --- src/librustc_errors/emitter.rs | 494 ++++++++++++++---- src/librustc_errors/snippet.rs | 103 +++- src/libsyntax/lib.rs | 3 + src/libsyntax/test_snippet.rs | 446 ++++++++++++++++ .../ui/compare-method/region-extra-2.stderr | 12 +- .../traits-misc-mismatch-2.stderr | 12 +- ...dropck-eyepatch-implies-unsafe-impl.stderr | 20 +- .../consider-using-explicit-lifetime.stderr | 7 +- src/test/ui/mismatched_types/main.stderr | 6 +- src/test/ui/missing-items/m2.stderr | 6 +- .../ui/span/impl-wrong-item-for-trait.stderr | 54 +- src/test/ui/span/issue-23827.stderr | 12 +- src/test/ui/span/issue-24356.stderr | 10 +- src/test/ui/span/multiline-span-simple.rs | 30 ++ src/test/ui/span/multiline-span-simple.stderr | 20 + 15 files changed, 1086 insertions(+), 149 deletions(-) create mode 100644 src/libsyntax/test_snippet.rs create mode 100644 src/test/ui/span/multiline-span-simple.rs create mode 100644 src/test/ui/span/multiline-span-simple.stderr diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index a307e9b696d..808a1683b84 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -14,7 +14,7 @@ use syntax_pos::{COMMAND_LINE_SP, DUMMY_SP, FileMap, Span, MultiSpan, CharPos}; use {Level, CodeSuggestion, DiagnosticBuilder, SubDiagnostic, CodeMapper}; use RenderSpan::*; -use snippet::{StyledString, Style, Annotation, Line}; +use snippet::{Annotation, AnnotationType, Line, StyledString, Style}; use styled_buffer::StyledBuffer; use std::io::prelude::*; @@ -65,6 +65,7 @@ pub struct EmitterWriter { struct FileWithAnnotatedLines { file: Rc, lines: Vec, + multiline_depth: usize, } @@ -137,10 +138,12 @@ impl EmitterWriter { line_index: line_index, annotations: vec![ann], }], + multiline_depth: 0, }); } let mut output = vec![]; + let mut multiline_annotations = vec![]; if let Some(ref cm) = self.cm { for span_label in msp.span_labels() { @@ -151,8 +154,9 @@ impl EmitterWriter { let mut hi = cm.lookup_char_pos(span_label.span.hi); let mut is_minimized = false; - // If the span is multi-line, simplify down to the span of one character - if lo.line != hi.line { + // If the span is long multi-line, simplify down to the span of one character + let max_multiline_span_length = 8; + if lo.line != hi.line && (hi.line - lo.line) > max_multiline_span_length { hi.line = lo.line; hi.col = CharPos(lo.col.0 + 1); is_minimized = true; @@ -163,22 +167,102 @@ impl EmitterWriter { // 6..7. This is degenerate input, but it's best to degrade // gracefully -- and the parser likes to supply a span like // that for EOF, in particular. - if lo.col == hi.col { + if lo.col == hi.col && lo.line == hi.line { hi.col = CharPos(lo.col.0 + 1); } - add_annotation_to_file(&mut output, - lo.file, - lo.line, - Annotation { - start_col: lo.col.0, - end_col: hi.col.0, - is_primary: span_label.is_primary, - is_minimized: is_minimized, - label: span_label.label.clone(), - }); + let mut ann = Annotation { + start_col: lo.col.0, + end_col: hi.col.0, + is_primary: span_label.is_primary, + label: span_label.label.clone(), + annotation_type: AnnotationType::Singleline, + }; + if is_minimized { + ann.annotation_type = AnnotationType::Minimized; + } else if lo.line != hi.line { + ann.annotation_type = AnnotationType::Multiline { + depth: 1, + line_start: lo.line, + line_end: hi.line, + }; + multiline_annotations.push((lo.file.clone(), ann.clone())); + }; + + if !ann.is_multiline() { + add_annotation_to_file(&mut output, + lo.file, + lo.line, + ann); + } } } + + // Find overlapping multiline annotations, put them at different depths + multiline_annotations.sort_by(|a, b| { + if let AnnotationType::Multiline { + line_start: a_start, + line_end: a_end, + .. + } = a.1.annotation_type { + if let AnnotationType::Multiline { + line_start: b_start, + line_end: b_end, + .. + } = b.1.annotation_type { + (a_start, a_end).cmp(&(b_start, b_end)) + } else { + panic!("tried to sort multiline annotations, but found `{:?}`", b) + } + } else { + panic!("tried to sort multiline annotations, but found `{:?}`", a) + } + }); + for item in multiline_annotations.clone() { + let ann = item.1; + if let AnnotationType::Multiline {line_start, line_end, ..} = ann.annotation_type { + for item in multiline_annotations.iter_mut() { + let ref mut a = item.1; + if let AnnotationType::Multiline { + line_start: start, + line_end: end, + .. + } = a.annotation_type { + // Move all other multiline annotations overlapping with this one + // one level to the right. + if &ann != a && num_overlap(line_start, line_end, start, end, true) { + a.annotation_type.increase_depth(); + } else { + break; + } + } else { + panic!("tried to find depth for multiline annotation, but found `{:?}`", + ann) + }; + } + } else { + panic!("tried to find depth for multiline annotation, but found `{:?}`", ann) + }; + } + + let mut max_depth = 0; // max overlapping multiline spans + for (file, ann) in multiline_annotations { + if let AnnotationType::Multiline {line_start, line_end, depth} = ann.annotation_type { + if depth > max_depth { + max_depth = depth; + } + add_annotation_to_file(&mut output, file.clone(), line_start, ann.as_start()); + for line in line_start + 1..line_end { + add_annotation_to_file(&mut output, file.clone(), line, ann.as_line()); + } + add_annotation_to_file(&mut output, file, line_end, ann.as_end()); + } else { + panic!("non-multiline annotation `{:?}` in `multiline_annotations`!", ann); + } + } + for file_vec in output.iter_mut() { + file_vec.multiline_depth = max_depth; + } output } @@ -186,14 +270,20 @@ impl EmitterWriter { buffer: &mut StyledBuffer, file: Rc, line: &Line, - width_offset: usize) { + width_offset: usize, + multiline_depth: usize) { let source_string = file.get_line(line.line_index - 1) .unwrap_or(""); let line_offset = buffer.num_lines(); + let code_offset = if multiline_depth == 0 { + width_offset + } else { + width_offset + multiline_depth + 1 + }; // First create the source line we will highlight. - buffer.puts(line_offset, width_offset, &source_string, Style::Quotation); + buffer.puts(line_offset, code_offset, &source_string, Style::Quotation); buffer.puts(line_offset, 0, &(line.line_index.to_string()), @@ -201,14 +291,10 @@ impl EmitterWriter { draw_col_separator(buffer, line_offset, width_offset - 2); - if line.annotations.is_empty() { - return; - } - // We want to display like this: // // vec.push(vec.pop().unwrap()); - // --- ^^^ _ previous borrow ends here + // --- ^^^ - previous borrow ends here // | | // | error occurs here // previous borrow of `vec` occurs here @@ -227,42 +313,22 @@ impl EmitterWriter { // Sort the annotations by (start, end col) let mut annotations = line.annotations.clone(); annotations.sort(); + annotations.reverse(); - // Next, create the highlight line. - for annotation in &annotations { - for p in annotation.start_col..annotation.end_col { - if annotation.is_primary { - buffer.putc(line_offset + 1, - width_offset + p, - '^', - Style::UnderlinePrimary); - if !annotation.is_minimized { - buffer.set_style(line_offset, width_offset + p, Style::UnderlinePrimary); - } - } else { - buffer.putc(line_offset + 1, - width_offset + p, - '-', - Style::UnderlineSecondary); - if !annotation.is_minimized { - buffer.set_style(line_offset, width_offset + p, Style::UnderlineSecondary); - } - } - } - } - draw_col_separator(buffer, line_offset + 1, width_offset - 2); - - // Now we are going to write labels in. To start, we'll exclude - // the annotations with no labels. - let (labeled_annotations, unlabeled_annotations): (Vec<_>, _) = annotations.into_iter() - .partition(|a| a.label.is_some()); - - // If there are no annotations that need text, we're done. - if labeled_annotations.is_empty() { - return; - } - // Now add the text labels. We try, when possible, to stick the rightmost - // annotation at the end of the highlight line: + // First, figure out where each label will be positioned. + // + // In the case where you have the following annotations: + // + // vec.push(vec.pop().unwrap()); + // -------- - previous borrow ends here [C] + // || + // |this makes no sense [B] + // previous borrow of `vec` occurs here [A] + // + // `annotations_position` will hold [(2, A), (1, B), (0, C)]. + // + // We try, when possible, to stick the rightmost annotation at the end + // of the highlight line: // // vec.push(vec.pop().unwrap()); // --- --- - previous borrow ends here @@ -296,66 +362,251 @@ impl EmitterWriter { // the rightmost span overlaps with any other span, we should // use the "hang below" version, so we can at least make it // clear where the span *starts*. - let mut labeled_annotations = &labeled_annotations[..]; - match labeled_annotations.split_last().unwrap() { - (last, previous) => { - if previous.iter() - .chain(&unlabeled_annotations) - .all(|a| !overlaps(a, last)) { - // append the label afterwards; we keep it in a separate - // string - let highlight_label: String = format!(" {}", last.label.as_ref().unwrap()); - if last.is_primary { - buffer.append(line_offset + 1, &highlight_label, Style::LabelPrimary); - } else { - buffer.append(line_offset + 1, &highlight_label, Style::LabelSecondary); - } - labeled_annotations = previous; + let mut annotations_position = vec![]; + let mut line_len = 0; + let mut p = 0; + let mut ann_iter = annotations.iter().peekable(); + while let Some(annotation) = ann_iter.next() { + let is_line = if let AnnotationType::MultilineLine(_) = annotation.annotation_type { + true + } else { + false + }; + let peek = ann_iter.peek(); + if let Some(next) = peek { + let next_is_line = if let AnnotationType::MultilineLine(_) = next.annotation_type { + true + } else { + false + }; + + if overlaps(next, annotation) && !is_line && !next_is_line { + p += 1; } } + annotations_position.push((p, annotation)); + if let Some(next) = peek { + let next_is_line = if let AnnotationType::MultilineLine(_) = next.annotation_type { + true + } else { + false + }; + let l = if let Some(ref label) = next.label { + label.len() + 2 + } else { + 0 + }; + if (overlaps(next, annotation) || next.end_col + l > annotation.start_col) + && !is_line && !next_is_line + { + p += 1; + } + } + if line_len < p { + line_len = p; + } + } + if line_len != 0 { + line_len += 1; } - // If that's the last annotation, we're done - if labeled_annotations.is_empty() { + // If there are no annotations or the only annotations on this line are + // MultilineLine, then there's only code being shown, stop processing. + if line.annotations.is_empty() || line.annotations.iter() + .filter(|a| { + // Set the multiline annotation vertical lines to the left of + // the code in this line. + if let AnnotationType::MultilineLine(depth) = a.annotation_type { + buffer.putc(line_offset, + width_offset + depth - 1, + '|', + if a.is_primary { + Style::UnderlinePrimary + } else { + Style::UnderlineSecondary + }); + false + } else { + true + } + }).collect::>().len() == 0 + { return; } - for (index, annotation) in labeled_annotations.iter().enumerate() { - // Leave: - // - 1 extra line - // - One line for each thing that comes after - let comes_after = labeled_annotations.len() - index - 1; - let blank_lines = 3 + comes_after; + for pos in 0..line_len + 1 { + draw_col_separator(buffer, line_offset + pos + 1, width_offset - 2); + buffer.putc(line_offset + pos + 1, + width_offset - 2, + '|', + Style::LineNumber); + } - // For each blank line, draw a `|` at our column. The - // text ought to be long enough for this. - for index in 2..blank_lines { - if annotation.is_primary { - buffer.putc(line_offset + index, - width_offset + annotation.start_col, - '|', - Style::UnderlinePrimary); - } else { - buffer.putc(line_offset + index, - width_offset + annotation.start_col, - '|', - Style::UnderlineSecondary); - } - draw_col_separator(buffer, line_offset + index, width_offset - 2); - } - - if annotation.is_primary { - buffer.puts(line_offset + blank_lines, - width_offset + annotation.start_col, - annotation.label.as_ref().unwrap(), - Style::LabelPrimary); + // Write the horizontal lines for multiline annotations + // (only the first and last lines need this). + // + // After this we will have: + // + // 2 | fn foo() { + // | __________ + // | + // | + // 3 | + // 4 | } + // | _ + for &(pos, annotation) in &annotations_position { + let style = if annotation.is_primary { + Style::UnderlinePrimary } else { - buffer.puts(line_offset + blank_lines, - width_offset + annotation.start_col, - annotation.label.as_ref().unwrap(), - Style::LabelSecondary); + Style::UnderlineSecondary + }; + let pos = pos + 1; + match annotation.annotation_type { + AnnotationType::MultilineStart(depth) | + AnnotationType::MultilineEnd(depth) => { + draw_range(buffer, + '_', + line_offset + pos, + width_offset + depth, + code_offset + annotation.start_col, + style); + } + _ => (), + } + } + + // Write the vertical lines for multiline spans and for labels that are + // on a different line as the underline. + // + // After this we will have: + // + // 2 | fn foo() { + // | __________ + // | | | + // | | + // 3 | | + // 4 | | } + // | |_ + for &(pos, annotation) in &annotations_position { + let style = if annotation.is_primary { + Style::UnderlinePrimary + } else { + Style::UnderlineSecondary + }; + let pos = pos + 1; + if pos > 1 { + for p in line_offset + 1..line_offset + pos + 1 { + buffer.putc(p, + code_offset + annotation.start_col, + '|', + style); + } + } + match annotation.annotation_type { + AnnotationType::MultilineStart(depth) => { + for p in line_offset + pos + 1..line_offset + line_len + 2 { + buffer.putc(p, + width_offset + depth - 1, + '|', + style); + } + } + AnnotationType::MultilineEnd(depth) => { + for p in line_offset..line_offset + pos + 1 { + buffer.putc(p, + width_offset + depth - 1, + '|', + style); + } + } + AnnotationType::MultilineLine(depth) => { + // the first line will have already be filled when we checked + // wether there were any annotations for this line. + for p in line_offset + 1..line_offset + line_len + 2 { + buffer.putc(p, + width_offset + depth - 1, + '|', + style); + } + } + _ => (), + } + } + + // Write the labels on the annotations that actually have a label. + // + // After this we will have: + // + // 2 | fn foo() { + // | __________ starting here... + // | | | + // | | something about `foo` + // 3 | | + // 4 | | } + // | |_ ...ending here: test + for &(pos, annotation) in &annotations_position { + let style = if annotation.is_primary { + Style::LabelPrimary + } else { + Style::LabelSecondary + }; + let (pos, col) = if pos == 0 { + (pos + 1, annotation.end_col + 1) + } else { + (pos + 2, annotation.start_col) + }; + if let Some(ref label) = annotation.label { + buffer.puts(line_offset + pos, + code_offset + col, + &label, + style); + } + } + + // Sort from biggest span to smallest span so that smaller spans are + // represented in the output: + // + // x | fn foo() + // | ^^^---^^ + // | | | + // | | something about `foo` + // | something about `fn foo()` + annotations_position.sort_by(|a, b| { + fn len(a: Annotation) -> usize { + // Account for usize underflows + if a.end_col > a.start_col { + a.end_col - a.start_col + } else { + a.start_col - a.end_col + } + } + // Decreasing order + len(a.1).cmp(&len(b.1)).reverse() + }); + + // Write the underlines. + // + // After this we will have: + // + // 2 | fn foo() { + // | ____-_____^ starting here... + // | | | + // | | something about `foo` + // 3 | | + // 4 | | } + // | |_^ ...ending here: test + for &(_, annotation) in &annotations_position { + let (underline, style) = if annotation.is_primary { + ('^', Style::UnderlinePrimary) + } else { + ('-', Style::UnderlineSecondary) + }; + for p in annotation.start_col..annotation.end_col { + buffer.putc(line_offset + 1, + code_offset + p, + underline, + style); } - draw_col_separator(buffer, line_offset + blank_lines, width_offset - 2); } } @@ -577,7 +828,8 @@ impl EmitterWriter { self.render_source_line(&mut buffer, annotated_file.file.clone(), &annotated_file.lines[line_idx], - 3 + max_line_num_len); + 3 + max_line_num_len, + annotated_file.multiline_depth); // check to see if we need to print out or elide lines that come between // this annotated line and the next one @@ -729,16 +981,38 @@ fn draw_col_separator(buffer: &mut StyledBuffer, line: usize, col: usize) { } fn draw_col_separator_no_space(buffer: &mut StyledBuffer, line: usize, col: usize) { - buffer.puts(line, col, "|", Style::LineNumber); + draw_col_separator_no_space_with_style(buffer, line, col, Style::LineNumber); +} + +fn draw_col_separator_no_space_with_style(buffer: &mut StyledBuffer, + line: usize, + col: usize, + style: Style) { + buffer.putc(line, col, '|', style); +} + +fn draw_range(buffer: &mut StyledBuffer, symbol: char, line: usize, + col_from: usize, col_to: usize, style: Style) { + for col in col_from..col_to { + buffer.putc(line, col, symbol, style); + } } fn draw_note_separator(buffer: &mut StyledBuffer, line: usize, col: usize) { buffer.puts(line, col, "= ", Style::LineNumber); } +fn num_overlap(a_start: usize, a_end: usize, b_start: usize, b_end:usize, inclusive: bool) -> bool { + let extra = if inclusive { + 1 + } else { + 0 + }; + (b_start..b_end + extra).contains(a_start) || + (a_start..a_end + extra).contains(b_start) +} fn overlaps(a1: &Annotation, a2: &Annotation) -> bool { - (a2.start_col..a2.end_col).contains(a1.start_col) || - (a1.start_col..a1.end_col).contains(a2.start_col) + num_overlap(a1.start_col, a1.end_col, a2.start_col, a2.end_col, false) } fn emit_to_destination(rendered_buffer: &Vec>, diff --git a/src/librustc_errors/snippet.rs b/src/librustc_errors/snippet.rs index abfb71c861b..3bf428af994 100644 --- a/src/librustc_errors/snippet.rs +++ b/src/librustc_errors/snippet.rs @@ -41,6 +41,57 @@ pub struct Line { pub annotations: Vec, } +#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] +pub enum AnnotationType { + /// Annotation under a single line of code + Singleline, + + /// Annotation under the first character of a multiline span + Minimized, + + /// Annotation enclosing the first and last character of a multiline span + Multiline { + depth: usize, + line_start: usize, + line_end: usize, + }, + + // The Multiline type above is replaced with the following three in order + // to reuse the current label drawing code. + // + // Each of these corresponds to one part of the following diagram: + // + // x | foo(1 + bar(x, + // | _________^ starting here... < MultilineStart + // x | | y), < MultilineLine + // | |______________^ ...ending here: label < MultilineEnd + // x | z); + /// Annotation marking the first character of a fully shown multiline span + MultilineStart(usize), + /// Annotation marking the last character of a fully shown multiline span + MultilineEnd(usize), + /// Line at the left enclosing the lines of a fully shown multiline span + MultilineLine(usize), +} + +impl AnnotationType { + pub fn depth(&self) -> usize { + match self { + &AnnotationType::Multiline {depth, ..} | + &AnnotationType::MultilineStart(depth) | + &AnnotationType::MultilineLine(depth) | + &AnnotationType::MultilineEnd(depth) => depth, + _ => 0, + } + } + + pub fn increase_depth(&mut self) { + if let AnnotationType::Multiline {ref mut depth, ..} = *self { + *depth += 1; + } + } +} + #[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] pub struct Annotation { /// Start column, 0-based indexing -- counting *characters*, not @@ -55,11 +106,57 @@ pub struct Annotation { /// Is this annotation derived from primary span pub is_primary: bool, - /// Is this a large span minimized down to a smaller span - pub is_minimized: bool, - /// Optional label to display adjacent to the annotation. pub label: Option, + + /// Is this a single line, multiline or multiline span minimized down to a + /// smaller span. + pub annotation_type: AnnotationType, +} + +impl Annotation { + pub fn is_minimized(&self) -> bool { + match self.annotation_type { + AnnotationType::Minimized => true, + _ => false, + } + } + + pub fn is_multiline(&self) -> bool { + match self.annotation_type { + AnnotationType::Multiline {..} | + AnnotationType::MultilineStart(_) | + AnnotationType::MultilineLine(_) | + AnnotationType::MultilineEnd(_) => true, + _ => false, + } + } + + pub fn as_start(&self) -> Annotation { + let mut a = self.clone(); + a.annotation_type = AnnotationType::MultilineStart(self.annotation_type.depth()); + a.end_col = a.start_col + 1; + a.label = Some("starting here...".to_owned()); + a + } + + pub fn as_end(&self) -> Annotation { + let mut a = self.clone(); + a.annotation_type = AnnotationType::MultilineEnd(self.annotation_type.depth()); + a.start_col = a.end_col - 1; + a.label = match a.label { + Some(l) => Some(format!("...ending here: {}", l)), + None => Some("..ending here".to_owned()), + }; + a + } + + pub fn as_line(&self) -> Annotation { + let mut a = self.clone(); + a.annotation_type = AnnotationType::MultilineLine(self.annotation_type.depth()); + a.label = None; + a + } } #[derive(Debug)] diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 34280812421..0545cccabf7 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -144,4 +144,7 @@ pub mod ext { } } +#[cfg(test)] +mod test_snippet; + // __build_diagnostic_array! { libsyntax, DIAGNOSTICS } diff --git a/src/libsyntax/test_snippet.rs b/src/libsyntax/test_snippet.rs new file mode 100644 index 00000000000..4ce51076adc --- /dev/null +++ b/src/libsyntax/test_snippet.rs @@ -0,0 +1,446 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use codemap::CodeMap; +use errors::Handler; +use errors::emitter::EmitterWriter; +use std::io; +use std::io::prelude::*; +use std::rc::Rc; +use std::str; +use std::sync::{Arc, Mutex}; +use syntax_pos::{BytePos, NO_EXPANSION, Span, MultiSpan}; + +/// Identify a position in the text by the Nth occurrence of a string. +struct Position { + string: &'static str, + count: usize, +} + +struct SpanLabel { + start: Position, + end: Position, + label: &'static str, +} + +struct Shared { + data: Arc>, +} + +impl Write for Shared { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.data.lock().unwrap().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.data.lock().unwrap().flush() + } +} + +fn test_harness(file_text: &str, span_labels: Vec, expected_output: &str) { + let output = Arc::new(Mutex::new(Vec::new())); + + let code_map = Rc::new(CodeMap::new()); + code_map.new_filemap_and_lines("test.rs", None, &file_text); + + let primary_span = make_span(&file_text, &span_labels[0].start, &span_labels[0].end); + let mut msp = MultiSpan::from_span(primary_span); + for span_label in span_labels { + let span = make_span(&file_text, &span_label.start, &span_label.end); + msp.push_span_label(span, span_label.label.to_string()); + println!("span: {:?} label: {:?}", span, span_label.label); + println!("text: {:?}", code_map.span_to_snippet(span)); + } + + let emitter = EmitterWriter::new(Box::new(Shared { data: output.clone() }), + Some(code_map.clone())); + let handler = Handler::with_emitter(true, false, Box::new(emitter)); + handler.span_err(msp, "foo"); + + assert!(expected_output.chars().next() == Some('\n'), + "expected output should begin with newline"); + let expected_output = &expected_output[1..]; + + let bytes = output.lock().unwrap(); + let actual_output = str::from_utf8(&bytes).unwrap(); + println!("expected output:\n------\n{}------", expected_output); + println!("actual output:\n------\n{}------", actual_output); + + assert!(expected_output == actual_output) +} + +fn make_span(file_text: &str, start: &Position, end: &Position) -> Span { + let start = make_pos(file_text, start); + let end = make_pos(file_text, end) + end.string.len(); // just after matching thing ends + assert!(start <= end); + Span { + lo: BytePos(start as u32), + hi: BytePos(end as u32), + expn_id: NO_EXPANSION, + } +} + +fn make_pos(file_text: &str, pos: &Position) -> usize { + let mut remainder = file_text; + let mut offset = 0; + for _ in 0..pos.count { + if let Some(n) = remainder.find(&pos.string) { + offset += n; + remainder = &remainder[n + 1..]; + } else { + panic!("failed to find {} instances of {:?} in {:?}", + pos.count, + pos.string, + file_text); + } + } + offset +} + +#[test] +fn ends_on_col0() { + test_harness(r#" +fn foo() { +} +"#, + vec![ + SpanLabel { + start: Position { + string: "{", + count: 1, + }, + end: Position { + string: "}", + count: 1, + }, + label: "test", + }, + ], + r#" +error: foo + --> test.rs:2:10 + | +2 | fn foo() { + | __________^ starting here... +3 | | } + | |_^ ...ending here: test + +"#); +} + +#[test] +fn ends_on_col2() { + test_harness(r#" +fn foo() { + + + } +"#, + vec![ + SpanLabel { + start: Position { + string: "{", + count: 1, + }, + end: Position { + string: "}", + count: 1, + }, + label: "test", + }, + ], + r#" +error: foo + --> test.rs:2:10 + | +2 | fn foo() { + | __________^ starting here... +3 | | +4 | | +5 | | } + | |___^ ...ending here: test + +"#); +} +#[test] +fn non_nested() { + test_harness(r#" +fn foo() { + X0 Y0 + X1 Y1 + X2 Y2 +} +"#, + vec![ + SpanLabel { + start: Position { + string: "X0", + count: 1, + }, + end: Position { + string: "X2", + count: 1, + }, + label: "`X` is a good letter", + }, + SpanLabel { + start: Position { + string: "Y0", + count: 1, + }, + end: Position { + string: "Y2", + count: 1, + }, + label: "`Y` is a good letter too", + }, + ], + r#" +error: foo + --> test.rs:3:3 + | +3 | X0 Y0 + | ____^__- starting here... + | | ___| + | || starting here... +4 | || X1 Y1 +5 | || X2 Y2 + | ||____^__- ...ending here: `Y` is a good letter too + | |____| + | ...ending here: `X` is a good letter + +"#); +} + +#[test] +fn nested() { + test_harness(r#" +fn foo() { + X0 Y0 + Y1 X1 +} +"#, + vec![ + SpanLabel { + start: Position { + string: "X0", + count: 1, + }, + end: Position { + string: "X1", + count: 1, + }, + label: "`X` is a good letter", + }, + SpanLabel { + start: Position { + string: "Y0", + count: 1, + }, + end: Position { + string: "Y1", + count: 1, + }, + label: "`Y` is a good letter too", + }, + ], +r#" +error: foo + --> test.rs:3:3 + | +3 | X0 Y0 + | ____^__- starting here... + | | ___| + | || starting here... +4 | || Y1 X1 + | ||____-__^ ...ending here: `X` is a good letter + | |_____| + | ...ending here: `Y` is a good letter too + +"#); +} + +#[test] +fn different_overlap() { + test_harness(r#" +fn foo() { + X0 Y0 Z0 + X1 Y1 Z1 + X2 Y2 Z2 + X3 Y3 Z3 +} +"#, + vec![ + SpanLabel { + start: Position { + string: "Y0", + count: 1, + }, + end: Position { + string: "X2", + count: 1, + }, + label: "`X` is a good letter", + }, + SpanLabel { + start: Position { + string: "Z1", + count: 1, + }, + end: Position { + string: "X3", + count: 1, + }, + label: "`Y` is a good letter too", + }, + ], + r#" +error: foo + --> test.rs:3:6 + | +3 | X0 Y0 Z0 + | ______^ starting here... +4 | | X1 Y1 Z1 + | |_________- starting here... +5 | || X2 Y2 Z2 + | ||____^ ...ending here: `X` is a good letter +6 | | X3 Y3 Z3 + | |_____- ...ending here: `Y` is a good letter too + +"#); +} + +#[test] +fn triple_overlap() { + test_harness(r#" +fn foo() { + X0 Y0 Z0 + X1 Y1 Z1 + X2 Y2 Z2 +} +"#, + vec![ + SpanLabel { + start: Position { + string: "X0", + count: 1, + }, + end: Position { + string: "X2", + count: 1, + }, + label: "`X` is a good letter", + }, + SpanLabel { + start: Position { + string: "Y0", + count: 1, + }, + end: Position { + string: "Y2", + count: 1, + }, + label: "`Y` is a good letter too", + }, + SpanLabel { + start: Position { + string: "Z0", + count: 1, + }, + end: Position { + string: "Z2", + count: 1, + }, + label: "`Z` label", + }, + ], + r#" +error: foo + --> test.rs:3:3 + | +3 | X0 Y0 Z0 + | _____^__-__- starting here... + | | ____|__| + | || ___| starting here... + | ||| starting here... +4 | ||| X1 Y1 Z1 +5 | ||| X2 Y2 Z2 + | |||____^__-__- ...ending here: `Z` label + | ||____|__| + | |____| ...ending here: `Y` is a good letter too + | ...ending here: `X` is a good letter + +"#); +} + +#[test] +fn minimum_depth() { + test_harness(r#" +fn foo() { + X0 Y0 Z0 + X1 Y1 Z1 + X2 Y2 Z2 + X3 Y3 Z3 +} +"#, + vec![ + SpanLabel { + start: Position { + string: "Y0", + count: 1, + }, + end: Position { + string: "X1", + count: 1, + }, + label: "`X` is a good letter", + }, + SpanLabel { + start: Position { + string: "Y1", + count: 1, + }, + end: Position { + string: "Z2", + count: 1, + }, + label: "`Y` is a good letter too", + }, + SpanLabel { + start: Position { + string: "X2", + count: 1, + }, + end: Position { + string: "Y3", + count: 1, + }, + label: "`Z`", + }, + ], + r#" +error: foo + --> test.rs:3:6 + | +3 | X0 Y0 Z0 + | ______^ starting here... +4 | | X1 Y1 Z1 + | |____^_- starting here... + | ||____| + | | ...ending here: `X` is a good letter +5 | | X2 Y2 Z2 + | |____-______- ...ending here: `Y` is a good letter too + | ____| + | | starting here... +6 | | X3 Y3 Z3 + | |________- ...ending here: `Z` + +"#); +} diff --git a/src/test/ui/compare-method/region-extra-2.stderr b/src/test/ui/compare-method/region-extra-2.stderr index 54a551bcfed..12b0ecabcc7 100644 --- a/src/test/ui/compare-method/region-extra-2.stderr +++ b/src/test/ui/compare-method/region-extra-2.stderr @@ -1,11 +1,15 @@ error[E0276]: impl has stricter requirements than trait --> $DIR/region-extra-2.rs:19:5 | -15 | fn renew<'b: 'a>(self) -> &'b mut [T]; - | -------------------------------------- definition of `renew` from trait +15 | fn renew<'b: 'a>(self) -> &'b mut [T]; + | -------------------------------------- definition of `renew` from trait ... -19 | fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b { - | ^ impl has extra requirement `'a: 'b` +19 | fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b { + | _____^ starting here... +20 | | //~^ ERROR E0276 +21 | | &mut self[..] +22 | | } + | |_____^ ...ending here: impl has extra requirement `'a: 'b` error: aborting due to previous error diff --git a/src/test/ui/compare-method/traits-misc-mismatch-2.stderr b/src/test/ui/compare-method/traits-misc-mismatch-2.stderr index 5003550fd1e..77b056f6978 100644 --- a/src/test/ui/compare-method/traits-misc-mismatch-2.stderr +++ b/src/test/ui/compare-method/traits-misc-mismatch-2.stderr @@ -1,11 +1,15 @@ error[E0276]: impl has stricter requirements than trait --> $DIR/traits-misc-mismatch-2.rs:23:5 | -19 | fn zip>(self, other: U) -> ZipIterator; - | ------------------------------------------------------------------ definition of `zip` from trait +19 | fn zip>(self, other: U) -> ZipIterator; + | ------------------------------------------------------------------ definition of `zip` from trait ... -23 | fn zip>(self, other: U) -> ZipIterator { - | ^ impl has extra requirement `U: Iterator` +23 | fn zip>(self, other: U) -> ZipIterator { + | _____^ starting here... +24 | | //~^ ERROR E0276 +25 | | ZipIterator{a: self, b: other} +26 | | } + | |_____^ ...ending here: impl has extra requirement `U: Iterator` error: aborting due to previous error diff --git a/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr b/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr index c53cf020a9b..b3e72f28d88 100644 --- a/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr +++ b/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr @@ -1,14 +1,26 @@ error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attribute --> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:32:1 | -32 | impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt { - | ^ +32 | impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt { + | _^ starting here... +33 | | //~^ ERROR requires an `unsafe impl` declaration due to `#[may_dangle]` attribute +34 | | +35 | | // (unsafe to access self.1 due to #[may_dangle] on A) +36 | | fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); } +37 | | } + | |_^ ..ending here error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attribute --> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:38:1 | -38 | impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> { - | ^ +38 | impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> { + | _^ starting here... +39 | | //~^ ERROR requires an `unsafe impl` declaration due to `#[may_dangle]` attribute +40 | | +41 | | // (unsafe to access self.1 due to #[may_dangle] on 'a) +42 | | fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); } +43 | | } + | |_^ ..ending here error: aborting due to 2 previous errors diff --git a/src/test/ui/lifetimes/consider-using-explicit-lifetime.stderr b/src/test/ui/lifetimes/consider-using-explicit-lifetime.stderr index 353e251369a..1d1bc58805a 100644 --- a/src/test/ui/lifetimes/consider-using-explicit-lifetime.stderr +++ b/src/test/ui/lifetimes/consider-using-explicit-lifetime.stderr @@ -15,8 +15,11 @@ error[E0495]: cannot infer an appropriate lifetime due to conflicting requiremen help: consider using an explicit lifetime parameter as shown: fn from_str(path: &'a str) -> Result --> $DIR/consider-using-explicit-lifetime.rs:25:5 | -25 | fn from_str(path: &str) -> Result { - | ^ +25 | fn from_str(path: &str) -> Result { + | _____^ starting here... +26 | | Ok(Foo { field: path }) +27 | | } + | |_____^ ..ending here error: aborting due to 2 previous errors diff --git a/src/test/ui/mismatched_types/main.stderr b/src/test/ui/mismatched_types/main.stderr index 9e26be6fddd..c87b635521e 100644 --- a/src/test/ui/mismatched_types/main.stderr +++ b/src/test/ui/mismatched_types/main.stderr @@ -1,8 +1,10 @@ error[E0308]: mismatched types --> $DIR/main.rs:12:18 | -12 | let x: u32 = ( - | ^ expected u32, found () +12 | let x: u32 = ( + | __________________^ starting here... +13 | | ); + | |_____^ ...ending here: expected u32, found () | = note: expected type `u32` = note: found type `()` diff --git a/src/test/ui/missing-items/m2.stderr b/src/test/ui/missing-items/m2.stderr index caeb9ff415c..33135434544 100644 --- a/src/test/ui/missing-items/m2.stderr +++ b/src/test/ui/missing-items/m2.stderr @@ -3,8 +3,10 @@ error: main function not found error[E0046]: not all trait items implemented, missing: `CONSTANT`, `Type`, `method` --> $DIR/m2.rs:20:1 | -20 | impl m1::X for X { - | ^ missing `CONSTANT`, `Type`, `method` in implementation +20 | impl m1::X for X { + | _^ starting here... +21 | | } + | |_^ ...ending here: missing `CONSTANT`, `Type`, `method` in implementation | = note: `CONSTANT` from trait: `const CONSTANT: u32;` = note: `Type` from trait: `type Type;` diff --git a/src/test/ui/span/impl-wrong-item-for-trait.stderr b/src/test/ui/span/impl-wrong-item-for-trait.stderr index 244285e3584..5c352436c3e 100644 --- a/src/test/ui/span/impl-wrong-item-for-trait.stderr +++ b/src/test/ui/span/impl-wrong-item-for-trait.stderr @@ -10,11 +10,19 @@ error[E0323]: item `bar` is an associated const, which doesn't match its trait ` error[E0046]: not all trait items implemented, missing: `bar` --> $DIR/impl-wrong-item-for-trait.rs:22:1 | -16 | fn bar(&self); - | -------------- `bar` from trait +16 | fn bar(&self); + | -------------- `bar` from trait ... -22 | impl Foo for FooConstForMethod { - | ^ missing `bar` in implementation +22 | impl Foo for FooConstForMethod { + | _^ starting here... +23 | | //~^ ERROR E0046 +24 | | //~| NOTE missing `bar` in implementation +25 | | const bar: u64 = 1; +26 | | //~^ ERROR E0323 +27 | | //~| NOTE does not match trait +28 | | const MY_CONST: u32 = 1; +29 | | } + | |_^ ...ending here: missing `bar` in implementation error[E0324]: item `MY_CONST` is an associated method, which doesn't match its trait `` --> $DIR/impl-wrong-item-for-trait.rs:37:5 @@ -28,11 +36,19 @@ error[E0324]: item `MY_CONST` is an associated method, which doesn't match its t error[E0046]: not all trait items implemented, missing: `MY_CONST` --> $DIR/impl-wrong-item-for-trait.rs:33:1 | -17 | const MY_CONST: u32; - | -------------------- `MY_CONST` from trait +17 | const MY_CONST: u32; + | -------------------- `MY_CONST` from trait ... -33 | impl Foo for FooMethodForConst { - | ^ missing `MY_CONST` in implementation +33 | impl Foo for FooMethodForConst { + | _^ starting here... +34 | | //~^ ERROR E0046 +35 | | //~| NOTE missing `MY_CONST` in implementation +36 | | fn bar(&self) {} +37 | | fn MY_CONST() {} +38 | | //~^ ERROR E0324 +39 | | //~| NOTE does not match trait +40 | | } + | |_^ ...ending here: missing `MY_CONST` in implementation error[E0325]: item `bar` is an associated type, which doesn't match its trait `` --> $DIR/impl-wrong-item-for-trait.rs:47:5 @@ -46,17 +62,27 @@ error[E0325]: item `bar` is an associated type, which doesn't match its trait `< error[E0046]: not all trait items implemented, missing: `bar` --> $DIR/impl-wrong-item-for-trait.rs:44:1 | -16 | fn bar(&self); - | -------------- `bar` from trait +16 | fn bar(&self); + | -------------- `bar` from trait ... -44 | impl Foo for FooTypeForMethod { - | ^ missing `bar` in implementation +44 | impl Foo for FooTypeForMethod { + | _^ starting here... +45 | | //~^ ERROR E0046 +46 | | //~| NOTE missing `bar` in implementation +47 | | type bar = u64; +48 | | //~^ ERROR E0325 +49 | | //~| NOTE does not match trait +50 | | const MY_CONST: u32 = 1; +51 | | } + | |_^ ...ending here: missing `bar` in implementation error[E0046]: not all trait items implemented, missing: `fmt` --> $DIR/impl-wrong-item-for-trait.rs:53:1 | -53 | impl Debug for FooTypeForMethod { - | ^ missing `fmt` in implementation +53 | impl Debug for FooTypeForMethod { + | _^ starting here... +54 | | } + | |_^ ...ending here: missing `fmt` in implementation | = note: `fmt` from trait: `fn(&Self, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>` diff --git a/src/test/ui/span/issue-23827.stderr b/src/test/ui/span/issue-23827.stderr index 5130bb53a19..6c1c2467530 100644 --- a/src/test/ui/span/issue-23827.stderr +++ b/src/test/ui/span/issue-23827.stderr @@ -1,8 +1,16 @@ error[E0046]: not all trait items implemented, missing: `Output` --> $DIR/issue-23827.rs:36:1 | -36 | impl FnOnce<(C,)> for Prototype { - | ^ missing `Output` in implementation +36 | impl FnOnce<(C,)> for Prototype { + | _^ starting here... +37 | | //~^ ERROR E0046 +38 | | //~| NOTE missing `Output` in implementation +39 | | //~| NOTE `Output` from trait: `type Output;` +40 | | extern "rust-call" fn call_once(self, (comp,): (C,)) -> Prototype { +41 | | Fn::call(&self, (comp,)) +42 | | } +43 | | } + | |_^ ...ending here: missing `Output` in implementation | = note: `Output` from trait: `type Output;` diff --git a/src/test/ui/span/issue-24356.stderr b/src/test/ui/span/issue-24356.stderr index 906ef25ca0e..963f4bd9bbc 100644 --- a/src/test/ui/span/issue-24356.stderr +++ b/src/test/ui/span/issue-24356.stderr @@ -1,8 +1,14 @@ error[E0046]: not all trait items implemented, missing: `Target` --> $DIR/issue-24356.rs:30:9 | -30 | impl Deref for Thing { - | ^ missing `Target` in implementation +30 | impl Deref for Thing { + | _________^ starting here... +31 | | //~^ ERROR E0046 +32 | | //~| NOTE missing `Target` in implementation +33 | | //~| NOTE `Target` from trait: `type Target;` +34 | | fn deref(&self) -> i8 { self.0 } +35 | | } + | |_________^ ...ending here: missing `Target` in implementation | = note: `Target` from trait: `type Target;` diff --git a/src/test/ui/span/multiline-span-simple.rs b/src/test/ui/span/multiline-span-simple.rs new file mode 100644 index 00000000000..16414766f39 --- /dev/null +++ b/src/test/ui/span/multiline-span-simple.rs @@ -0,0 +1,30 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn foo(a: u32, b: u32) { + a + b; +} + +fn bar(a: u32, b: u32) { + a + b; +} + +fn main() { + let x = 1; + let y = 2; + let z = 3; + foo(1 + + + bar(x, + + y), + + z) +} diff --git a/src/test/ui/span/multiline-span-simple.stderr b/src/test/ui/span/multiline-span-simple.stderr new file mode 100644 index 00000000000..26acef64c89 --- /dev/null +++ b/src/test/ui/span/multiline-span-simple.stderr @@ -0,0 +1,20 @@ +error[E0277]: the trait bound `{integer}: std::ops::Add<()>` is not satisfied + --> $DIR/multiline-span-simple.rs:23:9 + | +23 | foo(1 + + | _________^ starting here... +24 | | +25 | | bar(x, +26 | | +27 | | y), + | |______________^ ...ending here: the trait `std::ops::Add<()>` is not implemented for `{integer}` + | + = help: the following implementations were found: + = help: + = help: <&'a u32 as std::ops::Add> + = help: > + = help: <&'b u32 as std::ops::Add<&'a u32>> + = help: and 90 others + +error: aborting due to previous error + From 22739a148edb2b0b202a55a365f30b113ae5aea3 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Tue, 22 Nov 2016 23:48:33 +0100 Subject: [PATCH 026/293] core: Forward ExactSizeIterator methods for important iterator adaptors --- src/libcore/iter/mod.rs | 63 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index cd2e0cb11d3..ca718d29952 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -368,7 +368,16 @@ impl DoubleEndedIterator for Rev where I: DoubleEndedIterator { #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Rev - where I: ExactSizeIterator + DoubleEndedIterator {} + where I: ExactSizeIterator + DoubleEndedIterator +{ + fn len(&self) -> usize { + self.iter.len() + } + + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for Rev @@ -425,7 +434,15 @@ impl<'a, I, T: 'a> DoubleEndedIterator for Cloned #[stable(feature = "iter_cloned", since = "1.1.0")] impl<'a, I, T: 'a> ExactSizeIterator for Cloned where I: ExactSizeIterator, T: Clone -{} +{ + fn len(&self) -> usize { + self.it.len() + } + + fn is_empty(&self) -> bool { + self.it.is_empty() + } +} #[unstable(feature = "fused", issue = "35602")] impl<'a, I, T: 'a> FusedIterator for Cloned @@ -1007,7 +1024,16 @@ impl DoubleEndedIterator for Map where #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Map - where F: FnMut(I::Item) -> B {} + where F: FnMut(I::Item) -> B +{ + fn len(&self) -> usize { + self.iter.len() + } + + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for Map @@ -1236,7 +1262,15 @@ impl DoubleEndedIterator for Enumerate where } #[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Enumerate where I: ExactSizeIterator {} +impl ExactSizeIterator for Enumerate where I: ExactSizeIterator { + fn len(&self) -> usize { + self.iter.len() + } + + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} #[doc(hidden)] unsafe impl TrustedRandomAccess for Enumerate @@ -1927,7 +1961,15 @@ impl DoubleEndedIterator for Fuse #[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Fuse where I: ExactSizeIterator {} +impl ExactSizeIterator for Fuse where I: ExactSizeIterator { + fn len(&self) -> usize { + self.iter.len() + } + + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} /// An iterator that calls a function with a reference to each element before /// yielding it. @@ -1994,7 +2036,16 @@ impl DoubleEndedIterator for Inspect #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Inspect - where F: FnMut(&I::Item) {} + where F: FnMut(&I::Item) +{ + fn len(&self) -> usize { + self.iter.len() + } + + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for Inspect From 3295afa6e2dd9d3b50bce0342199a7d448d480aa Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 21 Nov 2016 18:11:36 +1300 Subject: [PATCH 027/293] save-analysis: fix ICE on partially resolved path Occurs when we produce save-analysis before type checking is complete (due to errors). --- src/librustc/hir/def.rs | 11 ++++++++--- src/librustc_save_analysis/lib.rs | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index feefc43f401..ce04a7c897a 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -85,10 +85,15 @@ impl PathResolution { /// Get the definition, if fully resolved, otherwise panic. pub fn full_def(&self) -> Def { - if self.depth != 0 { - bug!("path not fully resolved: {:?}", self); + self.maybe_full_def().unwrap_or_else(|| bug!("path not fully resolved: {:?}", self)) + } + + pub fn maybe_full_def(&self) -> Option { + if self.depth == 0 { + Some(self.base_def) + } else { + None } - self.base_def } pub fn kind_name(&self) -> &'static str { diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 778f0184141..4c59f5e8a83 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -497,7 +497,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } pub fn get_path_data(&self, id: NodeId, path: &ast::Path) -> Option { - let def = self.tcx.expect_def(id); + let def = option_try!(self.tcx.expect_resolution(id).maybe_full_def()); let sub_span = self.span_utils.span_for_last_ident(path.span); filter!(self.span_utils, sub_span, path.span, None); match def { From fae86b92dec2a7439a071270193c3c72b65b7ccd Mon Sep 17 00:00:00 2001 From: Theodore DeRego Date: Tue, 22 Nov 2016 16:08:48 -0800 Subject: [PATCH 028/293] Cleaned up and appeased the linter --- src/libstd/process.rs | 13 +---- src/libstd/sys/unix/magenta.rs | 2 - src/libstd/sys/unix/process.rs | 90 ++++++++++------------------------ 3 files changed, 29 insertions(+), 76 deletions(-) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index a9c68e82175..0b59de55cc6 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -780,8 +780,6 @@ impl Child { /// #[stable(feature = "process", since = "1.0.0")] pub fn wait_with_output(mut self) -> io::Result { - //use io::ErrorKind; - drop(self.stdin.take()); let (mut stdout, mut stderr) = (Vec::new(), Vec::new()); @@ -796,15 +794,8 @@ impl Child { res.unwrap(); } (Some(out), Some(err)) => { - match read2(out.inner, &mut stdout, err.inner, &mut stderr) { - Ok(()) => { }, - #[cfg(not(target_os = "fuchsia"))] - Err(ref e) => { panic!("Failed to read child's stdout and stderr: {:?}", e); }, - #[cfg(target_os = "fuchsia")] - Err(_) => { - // FIXME: Right now there's a bug in magenta's pipes implementation - }, - } + let res = read2(out.inner, &mut stdout, err.inner, &mut stderr); + res.update(); } } diff --git a/src/libstd/sys/unix/magenta.rs b/src/libstd/sys/unix/magenta.rs index ae3b7789b10..9da827c7d31 100644 --- a/src/libstd/sys/unix/magenta.rs +++ b/src/libstd/sys/unix/magenta.rs @@ -28,8 +28,6 @@ pub const MX_HANDLE_INVALID: mx_handle_t = 0; pub type mx_time_t = u64; pub const MX_TIME_INFINITE : mx_time_t = u64::MAX; -pub const NO_ERROR : mx_status_t = 0; - pub type mx_signals_t = u32; pub const MX_OBJECT_SIGNAL_3 : mx_signals_t = 1 << 3; diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs index aa203dc6215..d660514a983 100644 --- a/src/libstd/sys/unix/process.rs +++ b/src/libstd/sys/unix/process.rs @@ -309,18 +309,9 @@ impl Command { let (ours, theirs) = self.setup_io(default, needs_stdin)?; - let (maybe_process, err) = unsafe { self.do_exec(&theirs) }; - // We don't want FileDesc::drop to be called on any stdio. It would close their handles. - let ChildPipes { stdin: their_stdin, stdout: their_stdout, stderr: their_stderr } = theirs; - their_stdin.fd(); - their_stdout.fd(); - their_stderr.fd(); + let (launchpad, process_handle) = unsafe { self.do_exec(theirs)? }; - if let Some((launchpad, process_handle)) = maybe_process { - Ok((Process { launchpad: launchpad, handle: process_handle, status: None }, ours)) - } else { - Err(err) - } + Ok((Process { launchpad: launchpad, handle: process_handle, status: None }, ours)) } #[cfg(not(target_os = "fuchsia"))] @@ -453,23 +444,16 @@ impl Command { } #[cfg(target_os = "fuchsia")] - unsafe fn do_exec(&mut self, stdio: &ChildPipes) - -> (Option<(*mut launchpad_t, mx_handle_t)>, io::Error) { + unsafe fn do_exec(&mut self, stdio: ChildPipes) + -> io::Result<(*mut launchpad_t, mx_handle_t)> { use sys::magenta::*; - macro_rules! t { - ($e:expr) => (match $e { - Ok(e) => e, - Err(e) => return (None, e), - }) - } - macro_rules! tlp { ($lp:expr, $e:expr) => (match $e { Ok(e) => e, Err(e) => { launchpad_destroy($lp); - return (None, e); + return Err(e); }, }) } @@ -484,46 +468,23 @@ impl Command { let mut job_copy: mx_handle_t = MX_HANDLE_INVALID; // Duplicate the job handle - t!(mx_cvt(mx_handle_duplicate(job_handle, MX_RIGHT_SAME_RIGHTS, - &mut job_copy as *mut mx_handle_t))); + mx_cvt(mx_handle_duplicate(job_handle, MX_RIGHT_SAME_RIGHTS, + &mut job_copy as *mut mx_handle_t))?; // Create a launchpad - t!(mx_cvt(launchpad_create(job_copy, self.argv[0], - &mut launchpad as *mut *mut launchpad_t))); + mx_cvt(launchpad_create(job_copy, self.argv[0], + &mut launchpad as *mut *mut launchpad_t))?; // Set the process argv tlp!(launchpad, mx_cvt(launchpad_arguments(launchpad, self.argv.len() as i32 - 1, - self.argv.as_ptr()))); + self.argv.as_ptr()))); // Setup the environment vars - let status = launchpad_environ(launchpad, envp); - if status != NO_ERROR { - launchpad_destroy(launchpad); - return (None, io::Error::last_os_error()); - } - let status = launchpad_add_vdso_vmo(launchpad); - if status != NO_ERROR { - launchpad_destroy(launchpad); - return (None, io::Error::last_os_error()); - } - let status = launchpad_clone_mxio_root(launchpad); - if status != NO_ERROR { - launchpad_destroy(launchpad); - return (None, io::Error::last_os_error()); - } + tlp!(launchpad, mx_cvt(launchpad_environ(launchpad, envp))); + tlp!(launchpad, mx_cvt(launchpad_add_vdso_vmo(launchpad))); + tlp!(launchpad, mx_cvt(launchpad_clone_mxio_root(launchpad))); // Load the executable - let status = launchpad_elf_load(launchpad, launchpad_vmo_from_file(self.argv[0])); - if status != NO_ERROR { - launchpad_destroy(launchpad); - return (None, io::Error::last_os_error()); - } - let status = launchpad_load_vdso(launchpad, MX_HANDLE_INVALID); - if status != NO_ERROR { - launchpad_destroy(launchpad); - return (None, io::Error::last_os_error()); - } - let status = launchpad_clone_mxio_cwd(launchpad); - if status != NO_ERROR { - launchpad_destroy(launchpad); - return (None, io::Error::last_os_error()); - } + tlp!(launchpad, + mx_cvt(launchpad_elf_load(launchpad, launchpad_vmo_from_file(self.argv[0])))); + tlp!(launchpad, mx_cvt(launchpad_load_vdso(launchpad, MX_HANDLE_INVALID))); + tlp!(launchpad, mx_cvt(launchpad_clone_mxio_cwd(launchpad))); // Clone stdin, stdout, and stderr if let Some(fd) = stdio.stdin.fd() { @@ -542,17 +503,20 @@ impl Command { launchpad_clone_fd(launchpad, 2, 2); } + // We don't want FileDesc::drop to be called on any stdio. It would close their fds. The + // fds will be closed once the child process finishes. + let ChildPipes { stdin: child_stdin, stdout: child_stdout, stderr: child_stderr } = stdio; + if let ChildStdio::Owned(fd) = child_stdin { fd.into_raw(); } + if let ChildStdio::Owned(fd) = child_stdout { fd.into_raw(); } + if let ChildStdio::Owned(fd) = child_stderr { fd.into_raw(); } + for callback in self.closures.iter_mut() { - t!(callback()); + callback()?; } - let process_handle = launchpad_start(launchpad); - if process_handle < 0 { - launchpad_destroy(launchpad); - return (None, io::Error::last_os_error()); - } + let process_handle = tlp!(launchpad, mx_cvt(launchpad_start(launchpad))); - (Some((launchpad, process_handle)), io::Error::last_os_error()) + Ok((launchpad, process_handle)) } fn setup_io(&self, default: Stdio, needs_stdin: bool) From ae09957040927a16467c544d3ec8f427e9808d75 Mon Sep 17 00:00:00 2001 From: Theodore DeRego Date: Tue, 22 Nov 2016 16:18:02 -0800 Subject: [PATCH 029/293] Whoops :| s/update/unwrap/ --- src/libstd/process.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 0b59de55cc6..9d21a76e81b 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -795,7 +795,7 @@ impl Child { } (Some(out), Some(err)) => { let res = read2(out.inner, &mut stdout, err.inner, &mut stderr); - res.update(); + res.unwrap(); } } From 9ea1544b804818c8df259de60c0e26a85ac52850 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 23 Nov 2016 13:35:07 +1300 Subject: [PATCH 030/293] Add a test --- src/test/run-make/save-analysis-fail/Makefile | 8 + .../run-make/save-analysis-fail/SameDir.rs | 15 + .../run-make/save-analysis-fail/SameDir3.rs | 13 + .../run-make/save-analysis-fail/SubDir/mod.rs | 37 ++ src/test/run-make/save-analysis-fail/foo.rs | 450 ++++++++++++++++++ .../run-make/save-analysis-fail/krate2.rs | 18 + 6 files changed, 541 insertions(+) create mode 100644 src/test/run-make/save-analysis-fail/Makefile create mode 100644 src/test/run-make/save-analysis-fail/SameDir.rs create mode 100644 src/test/run-make/save-analysis-fail/SameDir3.rs create mode 100644 src/test/run-make/save-analysis-fail/SubDir/mod.rs create mode 100644 src/test/run-make/save-analysis-fail/foo.rs create mode 100644 src/test/run-make/save-analysis-fail/krate2.rs diff --git a/src/test/run-make/save-analysis-fail/Makefile b/src/test/run-make/save-analysis-fail/Makefile new file mode 100644 index 00000000000..3711b6ea895 --- /dev/null +++ b/src/test/run-make/save-analysis-fail/Makefile @@ -0,0 +1,8 @@ +-include ../tools.mk +all: code +krate2: krate2.rs + $(RUSTC) $< +code: foo.rs krate2 + $(RUSTC) foo.rs -Zsave-analysis-csv + $(RUSTC) foo.rs -Zsave-analysis + $(RUSTC) foo.rs -Zsave-analysis-api diff --git a/src/test/run-make/save-analysis-fail/SameDir.rs b/src/test/run-make/save-analysis-fail/SameDir.rs new file mode 100644 index 00000000000..fe70ac1edef --- /dev/null +++ b/src/test/run-make/save-analysis-fail/SameDir.rs @@ -0,0 +1,15 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// sub-module in the same directory as the main crate file + +pub struct SameStruct { + pub name: String +} diff --git a/src/test/run-make/save-analysis-fail/SameDir3.rs b/src/test/run-make/save-analysis-fail/SameDir3.rs new file mode 100644 index 00000000000..315f900868b --- /dev/null +++ b/src/test/run-make/save-analysis-fail/SameDir3.rs @@ -0,0 +1,13 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub fn hello(x: isize) { + println!("macro {} :-(", x); +} diff --git a/src/test/run-make/save-analysis-fail/SubDir/mod.rs b/src/test/run-make/save-analysis-fail/SubDir/mod.rs new file mode 100644 index 00000000000..fe84db08da9 --- /dev/null +++ b/src/test/run-make/save-analysis-fail/SubDir/mod.rs @@ -0,0 +1,37 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// sub-module in a sub-directory + +use sub::sub2 as msalias; +use sub::sub2; + +static yy: usize = 25; + +mod sub { + pub mod sub2 { + pub mod sub3 { + pub fn hello() { + println!("hello from module 3"); + } + } + pub fn hello() { + println!("hello from a module"); + } + + pub struct nested_struct { + pub field2: u32, + } + } +} + +pub struct SubStruct { + pub name: String +} diff --git a/src/test/run-make/save-analysis-fail/foo.rs b/src/test/run-make/save-analysis-fail/foo.rs new file mode 100644 index 00000000000..e331f65abb7 --- /dev/null +++ b/src/test/run-make/save-analysis-fail/foo.rs @@ -0,0 +1,450 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![ crate_name = "test" ] +#![feature(box_syntax)] +#![feature(rustc_private)] + +extern crate graphviz; +// A simple rust project + +extern crate krate2; +extern crate krate2 as krate3; +extern crate flate as myflate; + +use graphviz::RenderOption; +use std::collections::{HashMap,HashSet}; +use std::cell::RefCell; +use std::io::Write; + + +use sub::sub2 as msalias; +use sub::sub2; +use sub::sub2::nested_struct as sub_struct; + +use std::mem::size_of; + +use std::char::from_u32; + +static uni: &'static str = "Les Miséééééééérables"; +static yy: usize = 25; + +static bob: Option = None; + +// buglink test - see issue #1337. + +fn test_alias(i: Option<::Item>) { + let s = sub_struct{ field2: 45u32, }; + + // import tests + fn foo(x: &Write) {} + let _: Option<_> = from_u32(45); + + let x = 42usize; + + krate2::hello(); + krate3::hello(); + myflate::deflate_bytes(&[]); + + let x = (3isize, 4usize); + let y = x.1; +} + +// Issue #37700 +const LUT_BITS: usize = 3; +pub struct HuffmanTable { + ac_lut: Option<[(i16, u8); 1 << LUT_BITS]>, +} + +struct TupStruct(isize, isize, Box); + +fn test_tup_struct(x: TupStruct) -> isize { + x.1 +} + +fn println(s: &str) { + std::io::stdout().write_all(s.as_bytes()); +} + +mod sub { + pub mod sub2 { + use std::io::Write; + pub mod sub3 { + use std::io::Write; + pub fn hello() { + ::println("hello from module 3"); + } + } + pub fn hello() { + ::println("hello from a module"); + } + + pub struct nested_struct { + pub field2: u32, + } + + pub enum nested_enum { + Nest2 = 2, + Nest3 = 3 + } + } +} + +pub mod SameDir; +pub mod SubDir; + +#[path = "SameDir3.rs"] +pub mod SameDir2; + +struct nofields; + +#[derive(Clone)] +struct some_fields { + field1: u32, +} + +type SF = some_fields; + +trait SuperTrait { + fn qux(&self) { panic!(); } +} + +trait SomeTrait: SuperTrait { + fn Method(&self, x: u32) -> u32; + + fn prov(&self, x: u32) -> u32 { + println(&x.to_string()); + 42 + } + fn provided_method(&self) -> u32 { + 42 + } +} + +trait SubTrait: SomeTrait { + fn stat2(x: &Self) -> u32 { + 32 + } +} + +trait SizedTrait: Sized {} + +fn error(s: &SizedTrait) { + let foo = 42; + println!("Hello world! {}", foo); +} + +impl SomeTrait for some_fields { + fn Method(&self, x: u32) -> u32 { + println(&x.to_string()); + self.field1 + } +} + +impl SuperTrait for some_fields { +} + +impl SubTrait for some_fields {} + +impl some_fields { + fn stat(x: u32) -> u32 { + println(&x.to_string()); + 42 + } + fn stat2(x: &some_fields) -> u32 { + 42 + } + + fn align_to(&mut self) { + + } + + fn test(&mut self) { + self.align_to::(); + } +} + +impl SuperTrait for nofields { +} +impl SomeTrait for nofields { + fn Method(&self, x: u32) -> u32 { + self.Method(x); + 43 + } + + fn provided_method(&self) -> u32 { + 21 + } +} + +impl SubTrait for nofields {} + +impl SuperTrait for (Box, Box) {} + +fn f_with_params(x: &T) { + x.Method(41); +} + +type MyType = Box; + +enum SomeEnum<'a> { + Ints(isize, isize), + Floats(f64, f64), + Strings(&'a str, &'a str, &'a str), + MyTypes(MyType, MyType) +} + +#[derive(Copy, Clone)] +enum SomeOtherEnum { + SomeConst1, + SomeConst2, + SomeConst3 +} + +enum SomeStructEnum { + EnumStruct{a:isize, b:isize}, + EnumStruct2{f1:MyType, f2:MyType}, + EnumStruct3{f1:MyType, f2:MyType, f3:SomeEnum<'static>} +} + +fn matchSomeEnum(val: SomeEnum) { + match val { + SomeEnum::Ints(int1, int2) => { println(&(int1+int2).to_string()); } + SomeEnum::Floats(float1, float2) => { println(&(float2*float1).to_string()); } + SomeEnum::Strings(.., s3) => { println(s3); } + SomeEnum::MyTypes(mt1, mt2) => { println(&(mt1.field1 - mt2.field1).to_string()); } + } +} + +fn matchSomeStructEnum(se: SomeStructEnum) { + match se { + SomeStructEnum::EnumStruct{a:a, ..} => println(&a.to_string()), + SomeStructEnum::EnumStruct2{f1:f1, f2:f_2} => println(&f_2.field1.to_string()), + SomeStructEnum::EnumStruct3{f1, ..} => println(&f1.field1.to_string()), + } +} + + +fn matchSomeStructEnum2(se: SomeStructEnum) { + use SomeStructEnum::*; + match se { + EnumStruct{a: ref aaa, ..} => println(&aaa.to_string()), + EnumStruct2{f1, f2: f2} => println(&f1.field1.to_string()), + EnumStruct3{f1, f3: SomeEnum::Ints(..), f2} => println(&f1.field1.to_string()), + _ => {}, + } +} + +fn matchSomeOtherEnum(val: SomeOtherEnum) { + use SomeOtherEnum::{SomeConst2, SomeConst3}; + match val { + SomeOtherEnum::SomeConst1 => { println("I'm const1."); } + SomeConst2 | SomeConst3 => { println("I'm const2 or const3."); } + } +} + +fn hello((z, a) : (u32, String), ex: X) { + SameDir2::hello(43); + + println(&yy.to_string()); + let (x, y): (u32, u32) = (5, 3); + println(&x.to_string()); + println(&z.to_string()); + let x: u32 = x; + println(&x.to_string()); + let x = "hello"; + println(x); + + let x = 32.0f32; + let _ = (x + ((x * x) + 1.0).sqrt()).ln(); + + let s: Box = box some_fields {field1: 43}; + let s2: Box = box some_fields {field1: 43}; + let s3 = box nofields; + + s.Method(43); + s3.Method(43); + s2.Method(43); + + ex.prov(43); + + let y: u32 = 56; + // static method on struct + let r = some_fields::stat(y); + // trait static method, calls default + let r = SubTrait::stat2(&*s3); + + let s4 = s3 as Box; + s4.Method(43); + + s4.provided_method(); + s2.prov(45); + + let closure = |x: u32, s: &SomeTrait| { + s.Method(23); + return x + y; + }; + + let z = closure(10, &*s); +} + +pub struct blah { + used_link_args: RefCell<[&'static str; 0]>, +} + +#[macro_use] +mod macro_use_test { + macro_rules! test_rec { + (q, $src: expr) => {{ + print!("{}", $src); + test_rec!($src); + }}; + ($src: expr) => { + print!("{}", $src); + }; + } + + macro_rules! internal_vars { + ($src: ident) => {{ + let mut x = $src; + x += 100; + }}; + } +} + +fn main() { // foo + let s = box some_fields {field1: 43}; + hello((43, "a".to_string()), *s); + sub::sub2::hello(); + sub2::sub3::hello(); + + let h = sub2::sub3::hello; + h(); + + // utf8 chars + let ut = "Les Miséééééééérables"; + + // For some reason, this pattern of macro_rules foiled our generated code + // avoiding strategy. + macro_rules! variable_str(($name:expr) => ( + some_fields { + field1: $name, + } + )); + let vs = variable_str!(32); + + let mut candidates: RefCell> = RefCell::new(HashMap::new()); + let _ = blah { + used_link_args: RefCell::new([]), + }; + let s1 = nofields; + let s2 = SF { field1: 55}; + let s3: some_fields = some_fields{ field1: 55}; + let s4: msalias::nested_struct = sub::sub2::nested_struct{ field2: 55}; + let s4: msalias::nested_struct = sub2::nested_struct{ field2: 55}; + println(&s2.field1.to_string()); + let s5: MyType = box some_fields{ field1: 55}; + let s = SameDir::SameStruct{name: "Bob".to_string()}; + let s = SubDir::SubStruct{name:"Bob".to_string()}; + let s6: SomeEnum = SomeEnum::MyTypes(box s2.clone(), s5); + let s7: SomeEnum = SomeEnum::Strings("one", "two", "three"); + matchSomeEnum(s6); + matchSomeEnum(s7); + let s8: SomeOtherEnum = SomeOtherEnum::SomeConst2; + matchSomeOtherEnum(s8); + let s9: SomeStructEnum = SomeStructEnum::EnumStruct2{ f1: box some_fields{ field1:10 }, + f2: box s2 }; + matchSomeStructEnum(s9); + + for x in &vec![1, 2, 3] { + let _y = x; + } + + let s7: SomeEnum = SomeEnum::Strings("one", "two", "three"); + if let SomeEnum::Strings(..) = s7 { + println!("hello!"); + } + + for i in 0..5 { + foo_foo(i); + } + + if let Some(x) = None { + foo_foo(x); + } + + if false { + } else if let Some(y) = None { + foo_foo(y); + } + + while let Some(z) = None { + foo_foo(z); + } + + let mut x = 4; + test_rec!(q, "Hello"); + assert_eq!(x, 4); + internal_vars!(x); +} + +fn foo_foo(_: i32) {} + +impl Iterator for nofields { + type Item = (usize, usize); + + fn next(&mut self) -> Option<(usize, usize)> { + panic!() + } + + fn size_hint(&self) -> (usize, Option) { + panic!() + } +} + +trait Pattern<'a> { + type Searcher; +} + +struct CharEqPattern; + +impl<'a> Pattern<'a> for CharEqPattern { + type Searcher = CharEqPattern; +} + +struct CharSearcher<'a>(>::Searcher); + +pub trait Error { +} + +impl Error + 'static { + pub fn is(&self) -> bool { + panic!() + } +} + +impl Error + 'static + Send { + pub fn is(&self) -> bool { + ::is::(self) + } +} +extern crate serialize; +#[derive(Clone, Copy, Hash, Encodable, Decodable, PartialEq, Eq, PartialOrd, Ord, Debug, Default)] +struct AllDerives(i32); + +fn test_format_args() { + let x = 1; + let y = 2; + let name = "Joe Blogg"; + println!("Hello {}", name); + print!("Hello {0}", name); + print!("{0} + {} = {}", x, y); + print!("x is {}, y is {1}, name is {n}", x, y, n = name); +} diff --git a/src/test/run-make/save-analysis-fail/krate2.rs b/src/test/run-make/save-analysis-fail/krate2.rs new file mode 100644 index 00000000000..2c6f517ff38 --- /dev/null +++ b/src/test/run-make/save-analysis-fail/krate2.rs @@ -0,0 +1,18 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![ crate_name = "krate2" ] +#![ crate_type = "lib" ] + +use std::io::Write; + +pub fn hello() { + std::io::stdout().write_all(b"hello world!\n"); +} From 74cde120e5edb8d62fb63e8ab738ba0c67ec4d5c Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Tue, 22 Nov 2016 23:31:31 +0100 Subject: [PATCH 031/293] core, collections: Implement better .is_empty() for slice and vec iterators These iterators can use a pointer comparison instead of computing the length. --- src/libcollections/lib.rs | 1 + src/libcollections/vec.rs | 12 ++++++++++-- src/libcollectionstest/lib.rs | 1 + src/libcollectionstest/slice.rs | 10 ++++++++++ src/libcore/slice.rs | 12 ++++++++++-- 5 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 23d6edd6d79..f6d83b25b0d 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -36,6 +36,7 @@ #![cfg_attr(not(test), feature(char_escape_debug))] #![feature(core_intrinsics)] #![feature(dropck_parametricity)] +#![feature(exact_size_is_empty)] #![feature(fmt_internals)] #![feature(fused)] #![feature(heap_api)] diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 24f8e3a2d91..f2632412700 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1988,7 +1988,11 @@ impl DoubleEndedIterator for IntoIter { } #[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for IntoIter {} +impl ExactSizeIterator for IntoIter { + fn is_empty(&self) -> bool { + self.ptr == self.end + } +} #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for IntoIter {} @@ -2082,7 +2086,11 @@ impl<'a, T> Drop for Drain<'a, T> { #[stable(feature = "drain", since = "1.6.0")] -impl<'a, T> ExactSizeIterator for Drain<'a, T> {} +impl<'a, T> ExactSizeIterator for Drain<'a, T> { + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} #[unstable(feature = "fused", issue = "35602")] impl<'a, T> FusedIterator for Drain<'a, T> {} diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs index 14ec8d58bef..1e08074b14d 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollectionstest/lib.rs @@ -18,6 +18,7 @@ #![feature(const_fn)] #![feature(dedup_by)] #![feature(enumset)] +#![feature(exact_size_is_empty)] #![feature(pattern)] #![feature(rand)] #![feature(repeat_str)] diff --git a/src/libcollectionstest/slice.rs b/src/libcollectionstest/slice.rs index a6230ef471c..0e63e8d4a1e 100644 --- a/src/libcollectionstest/slice.rs +++ b/src/libcollectionstest/slice.rs @@ -633,6 +633,16 @@ fn test_iter_clone() { assert_eq!(it.next(), jt.next()); } +#[test] +fn test_iter_is_empty() { + let xs = [1, 2, 5, 10, 11]; + for i in 0..xs.len() { + for j in i..xs.len() { + assert_eq!(xs[i..j].iter().is_empty(), xs[i..j].is_empty()); + } + } +} + #[test] fn test_mut_iterator() { let mut xs = [1, 2, 3, 4, 5]; diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 871b63145ca..ede45111ebb 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -983,7 +983,11 @@ impl<'a, T> Iter<'a, T> { iterator!{struct Iter -> *const T, &'a T} #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> ExactSizeIterator for Iter<'a, T> {} +impl<'a, T> ExactSizeIterator for Iter<'a, T> { + fn is_empty(&self) -> bool { + self.ptr == self.end + } +} #[unstable(feature = "fused", issue = "35602")] impl<'a, T> FusedIterator for Iter<'a, T> {} @@ -1107,7 +1111,11 @@ impl<'a, T> IterMut<'a, T> { iterator!{struct IterMut -> *mut T, &'a mut T} #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> ExactSizeIterator for IterMut<'a, T> {} +impl<'a, T> ExactSizeIterator for IterMut<'a, T> { + fn is_empty(&self) -> bool { + self.ptr == self.end + } +} #[unstable(feature = "fused", issue = "35602")] impl<'a, T> FusedIterator for IterMut<'a, T> {} From cbe478766cb1cafed8341de2e7fffd3b1f104e70 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 23 Nov 2016 01:51:37 +0000 Subject: [PATCH 032/293] macros: improve performance of legacy name resolution. --- src/librustc_resolve/lib.rs | 4 +-- src/librustc_resolve/macros.rs | 51 +++++++++++++--------------------- 2 files changed, 21 insertions(+), 34 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index c72ba7bb687..f30304f2ea4 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1137,7 +1137,7 @@ pub struct Resolver<'a> { crate_loader: &'a mut CrateLoader, macro_names: FxHashSet, builtin_macros: FxHashMap>, - lexical_macro_resolutions: Vec<(Name, LegacyScope<'a>)>, + lexical_macro_resolutions: Vec<(Name, &'a Cell>)>, macro_map: FxHashMap>, macro_exports: Vec, @@ -3416,7 +3416,7 @@ impl<'a> Resolver<'a> { let mut reported_errors = FxHashSet(); for binding in replace(&mut self.disallowed_shadowing, Vec::new()) { - if self.resolve_legacy_scope(binding.parent, binding.name, false).is_some() && + if self.resolve_legacy_scope(&binding.parent, binding.name, false).is_some() && reported_errors.insert((binding.name, binding.span)) { let msg = format!("`{}` is already in scope", binding.name); self.session.struct_span_err(binding.span, &msg) diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 62adf382a69..cdb51f459e8 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -66,21 +66,8 @@ pub enum LegacyScope<'a> { Binding(&'a LegacyBinding<'a>), } -impl<'a> LegacyScope<'a> { - fn simplify_expansion(mut invoc: &'a InvocationData<'a>) -> Self { - while let LegacyScope::Invocation(_) = invoc.expansion.get() { - match invoc.legacy_scope.get() { - LegacyScope::Expansion(new_invoc) => invoc = new_invoc, - LegacyScope::Binding(_) => break, - scope @ _ => return scope, - } - } - LegacyScope::Expansion(invoc) - } -} - pub struct LegacyBinding<'a> { - pub parent: LegacyScope<'a>, + pub parent: Cell>, pub name: ast::Name, ext: Rc, pub span: Span, @@ -157,7 +144,7 @@ impl<'a> base::Resolver for Resolver<'a> { let invocation = self.invocations[&scope]; let binding = self.arenas.alloc_legacy_binding(LegacyBinding { - parent: invocation.legacy_scope.get(), + parent: Cell::new(invocation.legacy_scope.get()), name: def.ident.name, ext: Rc::new(macro_rules::compile(&self.session.parse_sess, &def)), span: def.span, @@ -228,12 +215,8 @@ impl<'a> base::Resolver for Resolver<'a> { let name = path.segments[0].identifier.name; let invocation = self.invocations[&scope]; - if let LegacyScope::Expansion(parent) = invocation.legacy_scope.get() { - invocation.legacy_scope.set(LegacyScope::simplify_expansion(parent)); - } - self.current_module = invocation.module.get(); - let result = match self.resolve_legacy_scope(invocation.legacy_scope.get(), name, false) { + let result = match self.resolve_legacy_scope(&invocation.legacy_scope, name, false) { Some(MacroBinding::Legacy(binding)) => Ok(binding.ext.clone()), Some(MacroBinding::Modern(binding)) => Ok(self.get_macro(binding)), None => match self.resolve_in_item_lexical_scope(name, MacroNS, None) { @@ -299,7 +282,7 @@ impl<'a> Resolver<'a> { } pub fn resolve_legacy_scope(&mut self, - mut scope: LegacyScope<'a>, + mut scope: &'a Cell>, name: Name, record_used: bool) -> Option> { @@ -307,22 +290,26 @@ impl<'a> Resolver<'a> { let mut relative_depth: u32 = 0; let mut binding = None; loop { - scope = match scope { + match scope.get() { LegacyScope::Empty => break, LegacyScope::Expansion(invocation) => { - if let LegacyScope::Empty = invocation.expansion.get() { - if possible_time_travel.is_none() { - possible_time_travel = Some(scope); + match invocation.expansion.get() { + LegacyScope::Invocation(_) => scope.set(invocation.legacy_scope.get()), + LegacyScope::Empty => { + if possible_time_travel.is_none() { + possible_time_travel = Some(scope); + } + scope = &invocation.legacy_scope; + } + _ => { + relative_depth += 1; + scope = &invocation.expansion; } - invocation.legacy_scope.get() - } else { - relative_depth += 1; - invocation.expansion.get() } } LegacyScope::Invocation(invocation) => { relative_depth = relative_depth.saturating_sub(1); - invocation.legacy_scope.get() + scope = &invocation.legacy_scope; } LegacyScope::Binding(potential_binding) => { if potential_binding.name == name { @@ -332,7 +319,7 @@ impl<'a> Resolver<'a> { binding = Some(potential_binding); break } - potential_binding.parent + scope = &potential_binding.parent; } }; } @@ -358,7 +345,7 @@ impl<'a> Resolver<'a> { pub fn finalize_current_module_macro_resolutions(&mut self) { let module = self.current_module; for &(mark, name, span) in module.legacy_macro_resolutions.borrow().iter() { - let legacy_scope = self.invocations[&mark].legacy_scope.get(); + let legacy_scope = &self.invocations[&mark].legacy_scope; let legacy_resolution = self.resolve_legacy_scope(legacy_scope, name, true); let resolution = self.resolve_in_item_lexical_scope(name, MacroNS, Some(span)); let (legacy_resolution, resolution) = match (legacy_resolution, resolution) { From 68312e3e20a881f2bcde20db0c7ee385c0aa27c1 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 23 Nov 2016 18:47:07 +1300 Subject: [PATCH 033/293] Fix a bunch of bugs shown by the test --- src/librustc_save_analysis/dump_visitor.rs | 31 ++++++++++++++++--- src/test/run-make/save-analysis-fail/Makefile | 4 +-- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index e83c2359979..0476fc621d1 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -275,7 +275,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { fn lookup_def_id(&self, ref_id: NodeId) -> Option { self.tcx.expect_def_or_none(ref_id).and_then(|def| { match def { - Def::PrimTy(..) | Def::SelfTy(..) => None, + Def::Label(..) | Def::PrimTy(..) | Def::SelfTy(..) | Def::Err => None, def => Some(def.def_id()), } }) @@ -357,7 +357,10 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { collector.visit_pat(&arg.pat); let span_utils = self.span.clone(); for &(id, ref p, ..) in &collector.collected_paths { - let typ = self.tcx.tables().node_types.get(&id).unwrap().to_string(); + let typ = match self.tcx.tables().node_types.get(&id) { + Some(s) => s.to_string(), + None => continue, + }; // get the span only for the name of the variable (I hope the path is only ever a // variable name, but who knows?) let sub_span = span_utils.span_for_last_ident(p.span); @@ -987,7 +990,13 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { match p.node { PatKind::Struct(ref path, ref fields, _) => { visit::walk_path(self, path); - let adt = self.tcx.tables().node_id_to_type(p.id).ty_adt_def().unwrap(); + let adt = match self.tcx.tables().node_id_to_type_opt(p.id) { + Some(ty) => ty.ty_adt_def().unwrap(), + None => { + visit::walk_pat(self, p); + return; + } + }; let variant = adt.variant_of_def(self.tcx.expect_def(p.id)); for &Spanned { node: ref field, span } in fields { @@ -1353,7 +1362,13 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> } ast::ExprKind::Struct(ref path, ref fields, ref base) => { let hir_expr = self.save_ctxt.tcx.map.expect_expr(ex.id); - let adt = self.tcx.tables().expr_ty(&hir_expr).ty_adt_def().unwrap(); + let adt = match self.tcx.tables().expr_ty_opt(&hir_expr) { + Some(ty) => ty.ty_adt_def().unwrap(), + None => { + visit::walk_expr(self, ex); + return; + } + }; let def = self.tcx.expect_def(hir_expr.id); self.process_struct_lit(ex, path, fields, adt.variant_of_def(def), base) } @@ -1379,7 +1394,13 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> return; } }; - let ty = &self.tcx.tables().expr_ty_adjusted(&hir_node).sty; + let ty = match self.tcx.tables().expr_ty_adjusted_opt(&hir_node) { + Some(ty) => &ty.sty, + None => { + visit::walk_expr(self, ex); + return; + } + }; match *ty { ty::TyAdt(def, _) => { let sub_span = self.span.sub_span_after_token(ex.span, token::Dot); diff --git a/src/test/run-make/save-analysis-fail/Makefile b/src/test/run-make/save-analysis-fail/Makefile index 3711b6ea895..f29f907cf38 100644 --- a/src/test/run-make/save-analysis-fail/Makefile +++ b/src/test/run-make/save-analysis-fail/Makefile @@ -3,6 +3,4 @@ all: code krate2: krate2.rs $(RUSTC) $< code: foo.rs krate2 - $(RUSTC) foo.rs -Zsave-analysis-csv - $(RUSTC) foo.rs -Zsave-analysis - $(RUSTC) foo.rs -Zsave-analysis-api + $(RUSTC) foo.rs -Zsave-analysis || exit 0 From 2121118f5401d84975f7910e0b71b32e74b990ec Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Wed, 23 Nov 2016 17:13:12 +0800 Subject: [PATCH 034/293] Revert libcore changes --- src/libcore/fmt/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index c5116b996dd..2d75a8ec420 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -166,9 +166,7 @@ pub struct Formatter<'a> { // NB. Argument is essentially an optimized partially applied formatting function, // equivalent to `exists T.(&T, fn(&T, &mut Formatter) -> Result`. -struct Void { - _private: (), -} +enum Void {} /// This struct represents the generic "argument" which is taken by the Xprintf /// family of functions. It contains a function to format the given value. At From 1c6048d0f4b4ad49f608f3ecba7183201d4c0eda Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Wed, 23 Nov 2016 11:33:08 +0100 Subject: [PATCH 035/293] core: Iterator docs, collect is not an adaptor --- src/libcore/iter/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index cd2e0cb11d3..4b93bb73139 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -225,12 +225,12 @@ //! often called 'iterator adapters', as they're a form of the 'adapter //! pattern'. //! -//! Common iterator adapters include [`map()`], [`take()`], and [`collect()`]. +//! Common iterator adapters include [`map()`], [`take()`], and [`filter()`]. //! For more, see their documentation. //! //! [`map()`]: trait.Iterator.html#method.map //! [`take()`]: trait.Iterator.html#method.take -//! [`collect()`]: trait.Iterator.html#method.collect +//! [`filter()`]: trait.Iterator.html#method.filter //! //! # Laziness //! @@ -268,7 +268,7 @@ //! [`map()`]: trait.Iterator.html#method.map //! //! The two most common ways to evaluate an iterator are to use a `for` loop -//! like this, or using the [`collect()`] adapter to produce a new collection. +//! like this, or using the [`collect()`] method to produce a new collection. //! //! [`collect()`]: trait.Iterator.html#method.collect //! From 557369ed2eadc3861ce32c53ef0c207bc112abc0 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Wed, 23 Nov 2016 11:33:39 +0100 Subject: [PATCH 036/293] core: Fix example for .map() Make the example use DoubleEndedIterator for map, like it said it would. --- src/libcore/iter/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 4b93bb73139..11f1cf5591d 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -920,7 +920,7 @@ unsafe impl TrustedLen for Zip /// you can also [`map()`] backwards: /// /// ```rust -/// let v: Vec = vec![1, 2, 3].into_iter().rev().map(|x| x + 1).collect(); +/// let v: Vec = vec![1, 2, 3].into_iter().map(|x| x + 1).rev().collect(); /// /// assert_eq!(v, [4, 3, 2]); /// ``` From a5049f7bba1c56027618a07ffa62c3af5c7da850 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 22 Nov 2016 17:04:24 +0100 Subject: [PATCH 037/293] Add ::1 example in IPv6 to IPv4 conversion --- src/libstd/net/ip.rs | 59 +++++++++++++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 15 deletions(-) diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 4df7eeae192..40563eacf29 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -646,10 +646,15 @@ impl Ipv6Addr { /// # Examples /// /// ``` + /// #![feature(ip)] + /// /// use std::net::Ipv6Addr; /// - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unique_local(), false); - /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true); + /// fn main() { + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unique_local(), + /// false); + /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true); + /// } /// ``` pub fn is_unique_local(&self) -> bool { (self.segments()[0] & 0xfe00) == 0xfc00 @@ -664,11 +669,15 @@ impl Ipv6Addr { /// # Examples /// /// ``` + /// #![feature(ip)] + /// /// use std::net::Ipv6Addr; /// - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_link_local(), - /// false); - /// assert_eq!(Ipv6Addr::new(0xfe8a, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true); + /// fn main() { + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_link_local(), + /// false); + /// assert_eq!(Ipv6Addr::new(0xfe8a, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true); + /// } /// ``` pub fn is_unicast_link_local(&self) -> bool { (self.segments()[0] & 0xffc0) == 0xfe80 @@ -680,11 +689,15 @@ impl Ipv6Addr { /// # Examples /// /// ``` + /// #![feature(ip)] + /// /// use std::net::Ipv6Addr; /// - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_site_local(), - /// false); - /// assert_eq!(Ipv6Addr::new(0xfec2, 0, 0, 0, 0, 0, 0, 0).is_unicast_site_local(), true); + /// fn main() { + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_site_local(), + /// false); + /// assert_eq!(Ipv6Addr::new(0xfec2, 0, 0, 0, 0, 0, 0, 0).is_unicast_site_local(), true); + /// } /// ``` pub fn is_unicast_site_local(&self) -> bool { (self.segments()[0] & 0xffc0) == 0xfec0 @@ -700,10 +713,15 @@ impl Ipv6Addr { /// # Examples /// /// ``` + /// #![feature(ip)] + /// /// use std::net::Ipv6Addr; /// - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(), false); - /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true); + /// fn main() { + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(), + /// false); + /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true); + /// } /// ``` pub fn is_documentation(&self) -> bool { (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) @@ -723,10 +741,15 @@ impl Ipv6Addr { /// # Examples /// /// ``` + /// #![feature(ip)] + /// /// use std::net::Ipv6Addr; /// - /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_global(), false); - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(), true); + /// fn main() { + /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_global(), false); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(), + /// true); + /// } /// ``` pub fn is_unicast_global(&self) -> bool { !self.is_multicast() @@ -740,11 +763,15 @@ impl Ipv6Addr { /// # Examples /// /// ``` + /// #![feature(ip)] + /// /// use std::net::{Ipv6Addr, Ipv6MulticastScope}; /// - /// assert_eq!(Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0).multicast_scope(), - /// Some(Ipv6MulticastScope::Global)); - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None); + /// fn main() { + /// assert_eq!(Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0).multicast_scope(), + /// Some(Ipv6MulticastScope::Global)); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None); + /// } /// ``` pub fn multicast_scope(&self) -> Option { if self.is_multicast() { @@ -792,6 +819,8 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4(), None); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4(), /// Some(Ipv4Addr::new(192, 10, 2, 255))); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4(), + /// Some(Ipv4Addr::new(0, 0, 0, 1))); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn to_ipv4(&self) -> Option { From 49c6b3c23f686448d1ac888739d76b11cbe6355e Mon Sep 17 00:00:00 2001 From: Sam Estep Date: Wed, 23 Nov 2016 08:41:50 -0500 Subject: [PATCH 038/293] Use literal 5 instead of five in book section 4.1 --- src/doc/book/variable-bindings.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book/variable-bindings.md b/src/doc/book/variable-bindings.md index 54316649c71..37b6c0513fc 100644 --- a/src/doc/book/variable-bindings.md +++ b/src/doc/book/variable-bindings.md @@ -47,7 +47,7 @@ let x: i32 = 5; ``` If I asked you to read this out loud to the rest of the class, you’d say “`x` -is a binding with the type `i32` and the value `five`.” +is a binding with the type `i32` and the value `5`.” In this case we chose to represent `x` as a 32-bit signed integer. Rust has many different primitive integer types. They begin with `i` for signed integers From b15e6a6a00242d094116fe9da16efa024cff050c Mon Sep 17 00:00:00 2001 From: Sam Estep Date: Wed, 23 Nov 2016 08:49:35 -0500 Subject: [PATCH 039/293] Use "radices" instead of "radicum" --- src/libcore/char.rs | 2 +- src/librustc_unicode/char.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 26d28049a47..966481e7b32 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -238,7 +238,7 @@ impl fmt::Display for CharTryFromError { /// A 'radix' here is sometimes also called a 'base'. A radix of two /// indicates a binary number, a radix of ten, decimal, and a radix of /// sixteen, hexadecimal, to give some common values. Arbitrary -/// radicum are supported. +/// radices are supported. /// /// `from_digit()` will return `None` if the input is not a digit in /// the given radix. diff --git a/src/librustc_unicode/char.rs b/src/librustc_unicode/char.rs index 702d7d8b4b2..94599216db6 100644 --- a/src/librustc_unicode/char.rs +++ b/src/librustc_unicode/char.rs @@ -138,7 +138,7 @@ impl char { /// A 'radix' here is sometimes also called a 'base'. A radix of two /// indicates a binary number, a radix of ten, decimal, and a radix of /// sixteen, hexadecimal, to give some common values. Arbitrary - /// radicum are supported. + /// radices are supported. /// /// Compared to `is_numeric()`, this function only recognizes the characters /// `0-9`, `a-z` and `A-Z`. @@ -190,7 +190,7 @@ impl char { /// A 'radix' here is sometimes also called a 'base'. A radix of two /// indicates a binary number, a radix of ten, decimal, and a radix of /// sixteen, hexadecimal, to give some common values. Arbitrary - /// radicum are supported. + /// radices are supported. /// /// 'Digit' is defined to be only the following characters: /// From 559141c8279429e90a8b524301c7485d70ecfb4c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 23 Nov 2016 17:14:41 +0100 Subject: [PATCH 040/293] Add missing examples to SocketAddrV6 --- src/libstd/net/addr.rs | 84 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index 1c016015b79..0aac95ac02e 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -236,6 +236,14 @@ impl SocketAddrV4 { impl SocketAddrV6 { /// Creates a new socket address from the ip/port/flowinfo/scope_id /// components. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new(ip: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32) -> SocketAddrV6 { @@ -252,6 +260,15 @@ impl SocketAddrV6 { } /// Returns the IP address associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); + /// assert_eq!(socket.ip(), &Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn ip(&self) -> &Ipv6Addr { unsafe { @@ -260,18 +277,47 @@ impl SocketAddrV6 { } /// Change the IP address associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); + /// socket.set_ip(Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0)); + /// assert_eq!(socket.ip(), &Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0)); + /// ``` #[stable(feature = "sockaddr_setters", since = "1.9.0")] pub fn set_ip(&mut self, new_ip: Ipv6Addr) { self.inner.sin6_addr = *new_ip.as_inner() } /// Returns the port number associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); + /// assert_eq!(socket.port(), 8080); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn port(&self) -> u16 { ntoh(self.inner.sin6_port) } /// Change the port number associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); + /// socket.set_port(4242); + /// assert_eq!(socket.port(), 4242); + /// ``` #[stable(feature = "sockaddr_setters", since = "1.9.0")] pub fn set_port(&mut self, new_port: u16) { self.inner.sin6_port = hton(new_port); @@ -279,12 +325,31 @@ impl SocketAddrV6 { /// Returns the flow information associated with this address, /// corresponding to the `sin6_flowinfo` field in C. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 10, 0); + /// assert_eq!(socket.flowinfo(), 10); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn flowinfo(&self) -> u32 { self.inner.sin6_flowinfo } /// Change the flow information associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 10, 0); + /// socket.set_flowinfo(56); + /// assert_eq!(socket.flowinfo(), 56); + /// ``` #[stable(feature = "sockaddr_setters", since = "1.9.0")] pub fn set_flowinfo(&mut self, new_flowinfo: u32) { self.inner.sin6_flowinfo = new_flowinfo; @@ -292,12 +357,31 @@ impl SocketAddrV6 { /// Returns the scope ID associated with this address, /// corresponding to the `sin6_scope_id` field in C. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 78); + /// assert_eq!(socket.scope_id(), 78); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn scope_id(&self) -> u32 { self.inner.sin6_scope_id } /// Change the scope ID associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV6, Ipv6Addr}; + /// + /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 78); + /// socket.set_scope_id(42); + /// assert_eq!(socket.scope_id(), 42); + /// ``` #[stable(feature = "sockaddr_setters", since = "1.9.0")] pub fn set_scope_id(&mut self, new_scope_id: u32) { self.inner.sin6_scope_id = new_scope_id; From b1f86fb7c30c6296a9c2e07d3a58795bca8c4cf4 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 24 Nov 2016 07:50:22 +1300 Subject: [PATCH 041/293] Inspect def locally instead of using a method --- src/librustc/hir/def.rs | 11 +++-------- src/librustc_save_analysis/lib.rs | 7 ++++++- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index ce04a7c897a..feefc43f401 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -85,15 +85,10 @@ impl PathResolution { /// Get the definition, if fully resolved, otherwise panic. pub fn full_def(&self) -> Def { - self.maybe_full_def().unwrap_or_else(|| bug!("path not fully resolved: {:?}", self)) - } - - pub fn maybe_full_def(&self) -> Option { - if self.depth == 0 { - Some(self.base_def) - } else { - None + if self.depth != 0 { + bug!("path not fully resolved: {:?}", self); } + self.base_def } pub fn kind_name(&self) -> &'static str { diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 4c59f5e8a83..a82a51a2e17 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -497,7 +497,12 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } pub fn get_path_data(&self, id: NodeId, path: &ast::Path) -> Option { - let def = option_try!(self.tcx.expect_resolution(id).maybe_full_def()); + let resolution = self.tcx.expect_resolution(id); + if resolution.depth != 0 { + return None; + } + let def = resolution.base_def; + let sub_span = self.span_utils.span_for_last_ident(path.span); filter!(self.span_utils, sub_span, path.span, None); match def { From 8560991cb04050d068157b100c80c5e864ec5db9 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 23 Nov 2016 10:55:44 -0800 Subject: [PATCH 042/293] Add a tracking issue for enum_set --- src/libcollections/enum_set.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcollections/enum_set.rs b/src/libcollections/enum_set.rs index 2d12b4ccffe..79e0021b148 100644 --- a/src/libcollections/enum_set.rs +++ b/src/libcollections/enum_set.rs @@ -16,7 +16,7 @@ #![unstable(feature = "enumset", reason = "matches collection reform specification, \ waiting for dust to settle", - issue = "0")] + issue = "37966")] use core::marker; use core::fmt; From 5c1c48532f1f5ce726d1704d33366f8fb371cca0 Mon Sep 17 00:00:00 2001 From: Theodore DeRego Date: Wed, 23 Nov 2016 13:58:13 -0800 Subject: [PATCH 043/293] Separated fuchsia-specific process stuff into 'process_fuchsia.rs' and refactored out some now-duplicated code into a 'process_common.rs' --- src/libstd/sys/unix/magenta.rs | 3 - src/libstd/sys/unix/process.rs | 865 ------------------ src/libstd/sys/unix/process/mod.rs | 20 + src/libstd/sys/unix/process/process_common.rs | 480 ++++++++++ .../sys/unix/process/process_fuchsia.rs | 190 ++++ src/libstd/sys/unix/process/process_unix.rs | 250 +++++ 6 files changed, 940 insertions(+), 868 deletions(-) delete mode 100644 src/libstd/sys/unix/process.rs create mode 100644 src/libstd/sys/unix/process/mod.rs create mode 100644 src/libstd/sys/unix/process/process_common.rs create mode 100644 src/libstd/sys/unix/process/process_fuchsia.rs create mode 100644 src/libstd/sys/unix/process/process_unix.rs diff --git a/src/libstd/sys/unix/magenta.rs b/src/libstd/sys/unix/magenta.rs index 9da827c7d31..155259d2645 100644 --- a/src/libstd/sys/unix/magenta.rs +++ b/src/libstd/sys/unix/magenta.rs @@ -67,7 +67,6 @@ pub struct mx_info_process_t { pub rec: mx_record_process_t, } -#[link(name = "magenta")] extern { pub fn mx_handle_close(handle: mx_handle_t) -> mx_status_t; @@ -89,7 +88,6 @@ pub fn mx_hnd_info(hnd_type: u32, arg: u32) -> u32 { (hnd_type & 0xFFFF) | ((arg & 0xFFFF) << 16) } -#[link(name="mxio")] extern { pub fn mxio_get_startup_handle(id: u32) -> mx_handle_t; } @@ -123,7 +121,6 @@ pub struct launchpad_t { loader_message: bool, } -#[link(name="launchpad")] extern { pub fn launchpad_create(job: mx_handle_t, name: *const c_char, lp: *mut *mut launchpad_t) -> mx_status_t; diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs deleted file mode 100644 index d660514a983..00000000000 --- a/src/libstd/sys/unix/process.rs +++ /dev/null @@ -1,865 +0,0 @@ -// 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 os::unix::prelude::*; - -use collections::hash_map::{HashMap, Entry}; -use env; -use ffi::{OsString, OsStr, CString, CStr}; -use fmt; -use io::{self, Error, ErrorKind}; -use libc::{self, c_int, gid_t, uid_t, c_char}; -use mem; -use ptr; -use sys::fd::FileDesc; -use sys::fs::{File, OpenOptions}; -use sys::pipe::{self, AnonPipe}; - -#[cfg(not(target_os = "fuchsia"))] -use sys::cvt; -#[cfg(target_os = "fuchsia")] -use sys::mx_cvt; - -#[cfg(target_os = "fuchsia")] -use sys::magenta::{launchpad_t, mx_handle_t}; - -#[cfg(not(target_os = "fuchsia"))] -use libc::pid_t; - -//////////////////////////////////////////////////////////////////////////////// -// Command -//////////////////////////////////////////////////////////////////////////////// - -pub struct Command { - // Currently we try hard to ensure that the call to `.exec()` doesn't - // actually allocate any memory. While many platforms try to ensure that - // memory allocation works after a fork in a multithreaded process, it's - // been observed to be buggy and somewhat unreliable, so we do our best to - // just not do it at all! - // - // Along those lines, the `argv` and `envp` raw pointers here are exactly - // what's gonna get passed to `execvp`. The `argv` array starts with the - // `program` and ends with a NULL, and the `envp` pointer, if present, is - // also null-terminated. - // - // Right now we don't support removing arguments, so there's no much fancy - // support there, but we support adding and removing environment variables, - // so a side table is used to track where in the `envp` array each key is - // located. Whenever we add a key we update it in place if it's already - // present, and whenever we remove a key we update the locations of all - // other keys. - program: CString, - args: Vec, - env: Option>, - argv: Vec<*const c_char>, - envp: Option>, - - cwd: Option, - uid: Option, - gid: Option, - saw_nul: bool, - closures: Vec io::Result<()> + Send + Sync>>, - stdin: Option, - stdout: Option, - stderr: Option, -} - -// passed back to std::process with the pipes connected to the child, if any -// were requested -pub struct StdioPipes { - pub stdin: Option, - pub stdout: Option, - pub stderr: Option, -} - -// passed to do_exec() with configuration of what the child stdio should look -// like -struct ChildPipes { - stdin: ChildStdio, - stdout: ChildStdio, - stderr: ChildStdio, -} - -enum ChildStdio { - Inherit, - Explicit(c_int), - Owned(FileDesc), -} - -pub enum Stdio { - Inherit, - Null, - MakePipe, - Fd(FileDesc), -} - -impl Command { - pub fn new(program: &OsStr) -> Command { - let mut saw_nul = false; - let program = os2c(program, &mut saw_nul); - Command { - argv: vec![program.as_ptr(), ptr::null()], - program: program, - args: Vec::new(), - env: None, - envp: None, - cwd: None, - uid: None, - gid: None, - saw_nul: saw_nul, - closures: Vec::new(), - stdin: None, - stdout: None, - stderr: None, - } - } - - pub fn arg(&mut self, arg: &OsStr) { - // Overwrite the trailing NULL pointer in `argv` and then add a new null - // pointer. - let arg = os2c(arg, &mut self.saw_nul); - self.argv[self.args.len() + 1] = arg.as_ptr(); - self.argv.push(ptr::null()); - - // Also make sure we keep track of the owned value to schedule a - // destructor for this memory. - self.args.push(arg); - } - - fn init_env_map(&mut self) -> (&mut HashMap, - &mut Vec<*const c_char>) { - if self.env.is_none() { - let mut map = HashMap::new(); - let mut envp = Vec::new(); - for (k, v) in env::vars_os() { - let s = pair_to_key(&k, &v, &mut self.saw_nul); - envp.push(s.as_ptr()); - map.insert(k, (envp.len() - 1, s)); - } - envp.push(ptr::null()); - self.env = Some(map); - self.envp = Some(envp); - } - (self.env.as_mut().unwrap(), self.envp.as_mut().unwrap()) - } - - pub fn env(&mut self, key: &OsStr, val: &OsStr) { - let new_key = pair_to_key(key, val, &mut self.saw_nul); - let (map, envp) = self.init_env_map(); - - // If `key` is already present then we just update `envp` in place - // (and store the owned value), but if it's not there we override the - // trailing NULL pointer, add a new NULL pointer, and store where we - // were located. - match map.entry(key.to_owned()) { - Entry::Occupied(mut e) => { - let (i, ref mut s) = *e.get_mut(); - envp[i] = new_key.as_ptr(); - *s = new_key; - } - Entry::Vacant(e) => { - let len = envp.len(); - envp[len - 1] = new_key.as_ptr(); - envp.push(ptr::null()); - e.insert((len - 1, new_key)); - } - } - } - - pub fn env_remove(&mut self, key: &OsStr) { - let (map, envp) = self.init_env_map(); - - // If we actually ended up removing a key, then we need to update the - // position of all keys that come after us in `envp` because they're all - // one element sooner now. - if let Some((i, _)) = map.remove(key) { - envp.remove(i); - - for (_, &mut (ref mut j, _)) in map.iter_mut() { - if *j >= i { - *j -= 1; - } - } - } - } - - pub fn env_clear(&mut self) { - self.env = Some(HashMap::new()); - self.envp = Some(vec![ptr::null()]); - } - - pub fn cwd(&mut self, dir: &OsStr) { - self.cwd = Some(os2c(dir, &mut self.saw_nul)); - } - pub fn uid(&mut self, id: uid_t) { - self.uid = Some(id); - } - pub fn gid(&mut self, id: gid_t) { - self.gid = Some(id); - } - - pub fn before_exec(&mut self, - f: Box io::Result<()> + Send + Sync>) { - self.closures.push(f); - } - - pub fn stdin(&mut self, stdin: Stdio) { - self.stdin = Some(stdin); - } - pub fn stdout(&mut self, stdout: Stdio) { - self.stdout = Some(stdout); - } - pub fn stderr(&mut self, stderr: Stdio) { - self.stderr = Some(stderr); - } - - #[cfg(not(target_os = "fuchsia"))] - pub fn spawn(&mut self, default: Stdio, needs_stdin: bool) - -> io::Result<(Process, StdioPipes)> { - use sys; - - const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX"; - - if self.saw_nul { - return Err(io::Error::new(ErrorKind::InvalidInput, - "nul byte found in provided data")); - } - - let (ours, theirs) = self.setup_io(default, needs_stdin)?; - let (input, output) = sys::pipe::anon_pipe()?; - - let pid = unsafe { - match cvt(libc::fork())? { - 0 => { - drop(input); - let err = self.do_exec(theirs); - let errno = err.raw_os_error().unwrap_or(libc::EINVAL) as u32; - let bytes = [ - (errno >> 24) as u8, - (errno >> 16) as u8, - (errno >> 8) as u8, - (errno >> 0) as u8, - CLOEXEC_MSG_FOOTER[0], CLOEXEC_MSG_FOOTER[1], - CLOEXEC_MSG_FOOTER[2], CLOEXEC_MSG_FOOTER[3] - ]; - // pipe I/O up to PIPE_BUF bytes should be atomic, and then - // we want to be sure we *don't* run at_exit destructors as - // we're being torn down regardless - assert!(output.write(&bytes).is_ok()); - libc::_exit(1) - } - n => n, - } - }; - - let mut p = Process { pid: pid, status: None }; - drop(output); - let mut bytes = [0; 8]; - - // loop to handle EINTR - loop { - match input.read(&mut bytes) { - Ok(0) => return Ok((p, ours)), - Ok(8) => { - assert!(combine(CLOEXEC_MSG_FOOTER) == combine(&bytes[4.. 8]), - "Validation on the CLOEXEC pipe failed: {:?}", bytes); - let errno = combine(&bytes[0.. 4]); - assert!(p.wait().is_ok(), - "wait() should either return Ok or panic"); - return Err(Error::from_raw_os_error(errno)) - } - Err(ref e) if e.kind() == ErrorKind::Interrupted => {} - Err(e) => { - assert!(p.wait().is_ok(), - "wait() should either return Ok or panic"); - panic!("the CLOEXEC pipe failed: {:?}", e) - }, - Ok(..) => { // pipe I/O up to PIPE_BUF bytes should be atomic - assert!(p.wait().is_ok(), - "wait() should either return Ok or panic"); - panic!("short read on the CLOEXEC pipe") - } - } - } - - fn combine(arr: &[u8]) -> i32 { - let a = arr[0] as u32; - let b = arr[1] as u32; - let c = arr[2] as u32; - let d = arr[3] as u32; - - ((a << 24) | (b << 16) | (c << 8) | (d << 0)) as i32 - } - } - - #[cfg(target_os = "fuchsia")] - pub fn spawn(&mut self, default: Stdio, needs_stdin: bool) - -> io::Result<(Process, StdioPipes)> { - if self.saw_nul { - return Err(io::Error::new(ErrorKind::InvalidInput, - "nul byte found in provided data")); - } - - let (ours, theirs) = self.setup_io(default, needs_stdin)?; - - let (launchpad, process_handle) = unsafe { self.do_exec(theirs)? }; - - Ok((Process { launchpad: launchpad, handle: process_handle, status: None }, ours)) - } - - #[cfg(not(target_os = "fuchsia"))] - pub fn exec(&mut self, default: Stdio) -> io::Error { - if self.saw_nul { - return io::Error::new(ErrorKind::InvalidInput, - "nul byte found in provided data") - } - - match self.setup_io(default, true) { - Ok((_, theirs)) => unsafe { self.do_exec(theirs) }, - Err(e) => e, - } - } - - #[cfg(target_os = "fuchsia")] - pub fn exec(&mut self, default: Stdio) -> io::Error { - if self.saw_nul { - return io::Error::new(ErrorKind::InvalidInput, - "nul byte found in provided data") - } - - match self.setup_io(default, true) { - Ok((_, _)) => { - // FIXME: This is tough because we don't support the exec syscalls - unimplemented!(); - }, - Err(e) => e, - } - } - - // And at this point we've reached a special time in the life of the - // child. The child must now be considered hamstrung and unable to - // do anything other than syscalls really. Consider the following - // scenario: - // - // 1. Thread A of process 1 grabs the malloc() mutex - // 2. Thread B of process 1 forks(), creating thread C - // 3. Thread C of process 2 then attempts to malloc() - // 4. The memory of process 2 is the same as the memory of - // process 1, so the mutex is locked. - // - // This situation looks a lot like deadlock, right? It turns out - // that this is what pthread_atfork() takes care of, which is - // presumably implemented across platforms. The first thing that - // threads to *before* forking is to do things like grab the malloc - // mutex, and then after the fork they unlock it. - // - // Despite this information, libnative's spawn has been witnessed to - // deadlock on both OSX and FreeBSD. I'm not entirely sure why, but - // all collected backtraces point at malloc/free traffic in the - // child spawned process. - // - // For this reason, the block of code below should contain 0 - // invocations of either malloc of free (or their related friends). - // - // As an example of not having malloc/free traffic, we don't close - // this file descriptor by dropping the FileDesc (which contains an - // allocation). Instead we just close it manually. This will never - // have the drop glue anyway because this code never returns (the - // child will either exec() or invoke libc::exit) - #[cfg(not(target_os = "fuchsia"))] - unsafe fn do_exec(&mut self, stdio: ChildPipes) -> io::Error { - use sys::{self, cvt_r}; - - macro_rules! t { - ($e:expr) => (match $e { - Ok(e) => e, - Err(e) => return e, - }) - } - - if let Some(fd) = stdio.stdin.fd() { - t!(cvt_r(|| libc::dup2(fd, libc::STDIN_FILENO))); - } - if let Some(fd) = stdio.stdout.fd() { - t!(cvt_r(|| libc::dup2(fd, libc::STDOUT_FILENO))); - } - if let Some(fd) = stdio.stderr.fd() { - t!(cvt_r(|| libc::dup2(fd, libc::STDERR_FILENO))); - } - - if let Some(u) = self.gid { - t!(cvt(libc::setgid(u as gid_t))); - } - if let Some(u) = self.uid { - // When dropping privileges from root, the `setgroups` call - // will remove any extraneous groups. If we don't call this, - // then even though our uid has dropped, we may still have - // groups that enable us to do super-user things. This will - // fail if we aren't root, so don't bother checking the - // return value, this is just done as an optimistic - // privilege dropping function. - let _ = libc::setgroups(0, ptr::null()); - - t!(cvt(libc::setuid(u as uid_t))); - } - if let Some(ref cwd) = self.cwd { - t!(cvt(libc::chdir(cwd.as_ptr()))); - } - if let Some(ref envp) = self.envp { - *sys::os::environ() = envp.as_ptr(); - } - - // NaCl has no signal support. - if cfg!(not(any(target_os = "nacl", target_os = "emscripten"))) { - // Reset signal handling so the child process starts in a - // standardized state. libstd ignores SIGPIPE, and signal-handling - // libraries often set a mask. Child processes inherit ignored - // signals and the signal mask from their parent, but most - // UNIX programs do not reset these things on their own, so we - // need to clean things up now to avoid confusing the program - // we're about to run. - let mut set: libc::sigset_t = mem::uninitialized(); - t!(cvt(libc::sigemptyset(&mut set))); - t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &set, - ptr::null_mut()))); - let ret = super::signal(libc::SIGPIPE, libc::SIG_DFL); - if ret == libc::SIG_ERR { - return io::Error::last_os_error() - } - } - - for callback in self.closures.iter_mut() { - t!(callback()); - } - - libc::execvp(self.argv[0], self.argv.as_ptr()); - io::Error::last_os_error() - } - - #[cfg(target_os = "fuchsia")] - unsafe fn do_exec(&mut self, stdio: ChildPipes) - -> io::Result<(*mut launchpad_t, mx_handle_t)> { - use sys::magenta::*; - - macro_rules! tlp { - ($lp:expr, $e:expr) => (match $e { - Ok(e) => e, - Err(e) => { - launchpad_destroy($lp); - return Err(e); - }, - }) - } - - let job_handle = mxio_get_startup_handle(mx_hnd_info(MX_HND_TYPE_JOB, 0)); - let envp = match self.envp { - Some(ref envp) => envp.as_ptr(), - None => ptr::null(), - }; - - let mut launchpad: *mut launchpad_t = ptr::null_mut(); - let mut job_copy: mx_handle_t = MX_HANDLE_INVALID; - - // Duplicate the job handle - mx_cvt(mx_handle_duplicate(job_handle, MX_RIGHT_SAME_RIGHTS, - &mut job_copy as *mut mx_handle_t))?; - // Create a launchpad - mx_cvt(launchpad_create(job_copy, self.argv[0], - &mut launchpad as *mut *mut launchpad_t))?; - // Set the process argv - tlp!(launchpad, mx_cvt(launchpad_arguments(launchpad, self.argv.len() as i32 - 1, - self.argv.as_ptr()))); - // Setup the environment vars - tlp!(launchpad, mx_cvt(launchpad_environ(launchpad, envp))); - tlp!(launchpad, mx_cvt(launchpad_add_vdso_vmo(launchpad))); - tlp!(launchpad, mx_cvt(launchpad_clone_mxio_root(launchpad))); - // Load the executable - tlp!(launchpad, - mx_cvt(launchpad_elf_load(launchpad, launchpad_vmo_from_file(self.argv[0])))); - tlp!(launchpad, mx_cvt(launchpad_load_vdso(launchpad, MX_HANDLE_INVALID))); - tlp!(launchpad, mx_cvt(launchpad_clone_mxio_cwd(launchpad))); - - // Clone stdin, stdout, and stderr - if let Some(fd) = stdio.stdin.fd() { - launchpad_transfer_fd(launchpad, fd, 0); - } else { - launchpad_clone_fd(launchpad, 0, 0); - } - if let Some(fd) = stdio.stdout.fd() { - launchpad_transfer_fd(launchpad, fd, 1); - } else { - launchpad_clone_fd(launchpad, 1, 1); - } - if let Some(fd) = stdio.stderr.fd() { - launchpad_transfer_fd(launchpad, fd, 2); - } else { - launchpad_clone_fd(launchpad, 2, 2); - } - - // We don't want FileDesc::drop to be called on any stdio. It would close their fds. The - // fds will be closed once the child process finishes. - let ChildPipes { stdin: child_stdin, stdout: child_stdout, stderr: child_stderr } = stdio; - if let ChildStdio::Owned(fd) = child_stdin { fd.into_raw(); } - if let ChildStdio::Owned(fd) = child_stdout { fd.into_raw(); } - if let ChildStdio::Owned(fd) = child_stderr { fd.into_raw(); } - - for callback in self.closures.iter_mut() { - callback()?; - } - - let process_handle = tlp!(launchpad, mx_cvt(launchpad_start(launchpad))); - - Ok((launchpad, process_handle)) - } - - fn setup_io(&self, default: Stdio, needs_stdin: bool) - -> io::Result<(StdioPipes, ChildPipes)> { - let null = Stdio::Null; - let default_stdin = if needs_stdin {&default} else {&null}; - let stdin = self.stdin.as_ref().unwrap_or(default_stdin); - let stdout = self.stdout.as_ref().unwrap_or(&default); - let stderr = self.stderr.as_ref().unwrap_or(&default); - let (their_stdin, our_stdin) = stdin.to_child_stdio(true)?; - let (their_stdout, our_stdout) = stdout.to_child_stdio(false)?; - let (their_stderr, our_stderr) = stderr.to_child_stdio(false)?; - let ours = StdioPipes { - stdin: our_stdin, - stdout: our_stdout, - stderr: our_stderr, - }; - let theirs = ChildPipes { - stdin: their_stdin, - stdout: their_stdout, - stderr: their_stderr, - }; - Ok((ours, theirs)) - } -} - -fn os2c(s: &OsStr, saw_nul: &mut bool) -> CString { - CString::new(s.as_bytes()).unwrap_or_else(|_e| { - *saw_nul = true; - CString::new("").unwrap() - }) -} - -impl Stdio { - fn to_child_stdio(&self, readable: bool) - -> io::Result<(ChildStdio, Option)> { - match *self { - Stdio::Inherit => { - Ok((ChildStdio::Inherit, None)) - }, - - // Make sure that the source descriptors are not an stdio - // descriptor, otherwise the order which we set the child's - // descriptors may blow away a descriptor which we are hoping to - // save. For example, suppose we want the child's stderr to be the - // parent's stdout, and the child's stdout to be the parent's - // stderr. No matter which we dup first, the second will get - // overwritten prematurely. - Stdio::Fd(ref fd) => { - if fd.raw() >= 0 && fd.raw() <= libc::STDERR_FILENO { - Ok((ChildStdio::Owned(fd.duplicate()?), None)) - } else { - Ok((ChildStdio::Explicit(fd.raw()), None)) - } - } - - Stdio::MakePipe => { - let (reader, writer) = pipe::anon_pipe()?; - let (ours, theirs) = if readable { - (writer, reader) - } else { - (reader, writer) - }; - Ok((ChildStdio::Owned(theirs.into_fd()), Some(ours))) - } - - Stdio::Null => { - let mut opts = OpenOptions::new(); - opts.read(readable); - opts.write(!readable); - let path = unsafe { - CStr::from_ptr("/dev/null\0".as_ptr() as *const _) - }; - let fd = File::open_c(&path, &opts)?; - Ok((ChildStdio::Owned(fd.into_fd()), None)) - } - } - } -} - -impl ChildStdio { - fn fd(&self) -> Option { - match *self { - ChildStdio::Inherit => None, - ChildStdio::Explicit(fd) => Some(fd), - ChildStdio::Owned(ref fd) => Some(fd.raw()), - } - } -} - -fn pair_to_key(key: &OsStr, value: &OsStr, saw_nul: &mut bool) -> CString { - let (key, value) = (key.as_bytes(), value.as_bytes()); - let mut v = Vec::with_capacity(key.len() + value.len() + 1); - v.extend(key); - v.push(b'='); - v.extend(value); - CString::new(v).unwrap_or_else(|_e| { - *saw_nul = true; - CString::new("foo=bar").unwrap() - }) -} - -impl fmt::Debug for Command { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}", self.program)?; - for arg in &self.args { - write!(f, " {:?}", arg)?; - } - Ok(()) - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Processes -//////////////////////////////////////////////////////////////////////////////// - -/// Unix exit statuses -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitStatus(c_int); - -impl ExitStatus { - fn exited(&self) -> bool { - unsafe { libc::WIFEXITED(self.0) } - } - - pub fn success(&self) -> bool { - self.code() == Some(0) - } - - pub fn code(&self) -> Option { - if self.exited() { - Some(unsafe { libc::WEXITSTATUS(self.0) }) - } else { - None - } - } - - pub fn signal(&self) -> Option { - if !self.exited() { - Some(unsafe { libc::WTERMSIG(self.0) }) - } else { - None - } - } -} - -impl From for ExitStatus { - fn from(a: c_int) -> ExitStatus { - ExitStatus(a) - } -} - -impl fmt::Display for ExitStatus { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if let Some(code) = self.code() { - write!(f, "exit code: {}", code) - } else { - let signal = self.signal().unwrap(); - write!(f, "signal: {}", signal) - } - } -} - -/// The unique id of the process (this should never be negative). -#[cfg(not(target_os = "fuchsia"))] -pub struct Process { - pid: pid_t, - status: Option, -} - -#[cfg(target_os = "fuchsia")] -pub struct Process { - launchpad: *mut launchpad_t, - handle: mx_handle_t, - status: Option, -} - -impl Process { - #[cfg(not(target_os = "fuchsia"))] - pub fn id(&self) -> u32 { - self.pid as u32 - } - - #[cfg(target_os = "fuchsia")] - pub fn id(&self) -> u32 { - 0 - } - - #[cfg(not(target_os = "fuchsia"))] - pub fn kill(&mut self) -> io::Result<()> { - // If we've already waited on this process then the pid can be recycled - // and used for another process, and we probably shouldn't be killing - // random processes, so just return an error. - if self.status.is_some() { - Err(Error::new(ErrorKind::InvalidInput, - "invalid argument: can't kill an exited process")) - } else { - cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(|_| ()) - } - } - - #[cfg(target_os = "fuchsia")] - pub fn kill(&mut self) -> io::Result<()> { - use sys::magenta::*; - - // If we've already waited on this process then the pid can be recycled - // and used for another process, and we probably shouldn't be killing - // random processes, so just return an error. - if self.status.is_some() { - Err(Error::new(ErrorKind::InvalidInput, - "invalid argument: can't kill an exited process")) - } else { - unsafe { - mx_cvt(mx_handle_close(self.handle))?; - launchpad_destroy(self.launchpad); - } - Ok(()) - } - } - - #[cfg(not(target_os = "fuchsia"))] - pub fn wait(&mut self) -> io::Result { - use sys::cvt_r; - if let Some(status) = self.status { - return Ok(status) - } - let mut status = 0 as c_int; - cvt_r(|| unsafe { libc::waitpid(self.pid, &mut status, 0) })?; - self.status = Some(ExitStatus(status)); - Ok(ExitStatus(status)) - } - - #[cfg(target_os = "fuchsia")] - pub fn wait(&mut self) -> io::Result { - use default::Default; - use sys::magenta::*; - - if let Some(status) = self.status { - return Ok(status) - } - - let mut proc_info: mx_info_process_t = Default::default(); - let mut actual: mx_size_t = 0; - let mut avail: mx_size_t = 0; - - unsafe { - mx_cvt(mx_handle_wait_one(self.handle, MX_TASK_TERMINATED, - MX_TIME_INFINITE, ptr::null_mut()))?; - mx_cvt(mx_object_get_info(self.handle, MX_INFO_PROCESS, - &mut proc_info as *mut _ as *mut libc::c_void, - mem::size_of::(), &mut actual, - &mut avail))?; - } - if actual != 1 { - return Err(Error::new(ErrorKind::InvalidInput, - "Failed to get exit status of process")); - } - self.status = Some(ExitStatus(proc_info.rec.return_code)); - unsafe { - mx_cvt(mx_handle_close(self.handle))?; - launchpad_destroy(self.launchpad); - } - Ok(ExitStatus(proc_info.rec.return_code)) - } -} - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use super::*; - - use ffi::OsStr; - use mem; - use ptr; - use libc; - use sys::cvt; - - macro_rules! t { - ($e:expr) => { - match $e { - Ok(t) => t, - Err(e) => panic!("received error for `{}`: {}", stringify!($e), e), - } - } - } - - #[cfg(not(target_os = "android"))] - extern { - #[cfg_attr(target_os = "netbsd", link_name = "__sigaddset14")] - fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int; - } - - #[cfg(target_os = "android")] - unsafe fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int { - use slice; - - let raw = slice::from_raw_parts_mut(set as *mut u8, mem::size_of::()); - let bit = (signum - 1) as usize; - raw[bit / 8] |= 1 << (bit % 8); - return 0; - } - - // See #14232 for more information, but it appears that signal delivery to a - // newly spawned process may just be raced in the OSX, so to prevent this - // test from being flaky we ignore it on OSX. - #[test] - #[cfg_attr(target_os = "macos", ignore)] - #[cfg_attr(target_os = "nacl", ignore)] // no signals on NaCl. - fn test_process_mask() { - unsafe { - // Test to make sure that a signal mask does not get inherited. - let mut cmd = Command::new(OsStr::new("cat")); - - let mut set: libc::sigset_t = mem::uninitialized(); - let mut old_set: libc::sigset_t = mem::uninitialized(); - t!(cvt(libc::sigemptyset(&mut set))); - t!(cvt(sigaddset(&mut set, libc::SIGINT))); - t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &set, &mut old_set))); - - cmd.stdin(Stdio::MakePipe); - cmd.stdout(Stdio::MakePipe); - - let (mut cat, mut pipes) = t!(cmd.spawn(Stdio::Null, true)); - let stdin_write = pipes.stdin.take().unwrap(); - let stdout_read = pipes.stdout.take().unwrap(); - - t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &old_set, - ptr::null_mut()))); - - t!(cvt(libc::kill(cat.id() as libc::pid_t, libc::SIGINT))); - // We need to wait until SIGINT is definitely delivered. The - // easiest way is to write something to cat, and try to read it - // back: if SIGINT is unmasked, it'll get delivered when cat is - // next scheduled. - let _ = stdin_write.write(b"Hello"); - drop(stdin_write); - - // Either EOF or failure (EPIPE) is okay. - let mut buf = [0; 5]; - if let Ok(ret) = stdout_read.read(&mut buf) { - assert!(ret == 0); - } - - t!(cat.wait()); - } - } -} diff --git a/src/libstd/sys/unix/process/mod.rs b/src/libstd/sys/unix/process/mod.rs new file mode 100644 index 00000000000..82c3971ee40 --- /dev/null +++ b/src/libstd/sys/unix/process/mod.rs @@ -0,0 +1,20 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub use self::process_common::{Command, ExitStatus, Stdio, StdioPipes}; +pub use self::process_inner::Process; + +mod process_common; +#[cfg(not(target_os = "fuchsia"))] +#[path = "process_unix.rs"] +mod process_inner; +#[cfg(target_os = "fuchsia")] +#[path = "process_fuchsia.rs"] +mod process_inner; diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs new file mode 100644 index 00000000000..24b8b61edea --- /dev/null +++ b/src/libstd/sys/unix/process/process_common.rs @@ -0,0 +1,480 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use os::unix::prelude::*; + +use collections::hash_map::{HashMap, Entry}; +use env; +use ffi::{OsString, OsStr, CString, CStr}; +use fmt; +use io; +use libc::{self, c_int, gid_t, uid_t, c_char}; +use ptr; +use sys::fd::FileDesc; +use sys::fs::{File, OpenOptions}; +use sys::pipe::{self, AnonPipe}; + +//////////////////////////////////////////////////////////////////////////////// +// Command +//////////////////////////////////////////////////////////////////////////////// + +pub struct Command { + // Currently we try hard to ensure that the call to `.exec()` doesn't + // actually allocate any memory. While many platforms try to ensure that + // memory allocation works after a fork in a multithreaded process, it's + // been observed to be buggy and somewhat unreliable, so we do our best to + // just not do it at all! + // + // Along those lines, the `argv` and `envp` raw pointers here are exactly + // what's gonna get passed to `execvp`. The `argv` array starts with the + // `program` and ends with a NULL, and the `envp` pointer, if present, is + // also null-terminated. + // + // Right now we don't support removing arguments, so there's no much fancy + // support there, but we support adding and removing environment variables, + // so a side table is used to track where in the `envp` array each key is + // located. Whenever we add a key we update it in place if it's already + // present, and whenever we remove a key we update the locations of all + // other keys. + program: CString, + args: Vec, + env: Option>, + argv: Vec<*const c_char>, + envp: Option>, + + cwd: Option, + uid: Option, + gid: Option, + saw_nul: bool, + closures: Vec io::Result<()> + Send + Sync>>, + stdin: Option, + stdout: Option, + stderr: Option, +} + +// passed back to std::process with the pipes connected to the child, if any +// were requested +pub struct StdioPipes { + pub stdin: Option, + pub stdout: Option, + pub stderr: Option, +} + +// passed to do_exec() with configuration of what the child stdio should look +// like +pub struct ChildPipes { + pub stdin: ChildStdio, + pub stdout: ChildStdio, + pub stderr: ChildStdio, +} + +pub enum ChildStdio { + Inherit, + Explicit(c_int), + Owned(FileDesc), +} + +pub enum Stdio { + Inherit, + Null, + MakePipe, + Fd(FileDesc), +} + +impl Command { + pub fn new(program: &OsStr) -> Command { + let mut saw_nul = false; + let program = os2c(program, &mut saw_nul); + Command { + argv: vec![program.as_ptr(), ptr::null()], + program: program, + args: Vec::new(), + env: None, + envp: None, + cwd: None, + uid: None, + gid: None, + saw_nul: saw_nul, + closures: Vec::new(), + stdin: None, + stdout: None, + stderr: None, + } + } + + pub fn arg(&mut self, arg: &OsStr) { + // Overwrite the trailing NULL pointer in `argv` and then add a new null + // pointer. + let arg = os2c(arg, &mut self.saw_nul); + self.argv[self.args.len() + 1] = arg.as_ptr(); + self.argv.push(ptr::null()); + + // Also make sure we keep track of the owned value to schedule a + // destructor for this memory. + self.args.push(arg); + } + + fn init_env_map(&mut self) -> (&mut HashMap, + &mut Vec<*const c_char>) { + if self.env.is_none() { + let mut map = HashMap::new(); + let mut envp = Vec::new(); + for (k, v) in env::vars_os() { + let s = pair_to_key(&k, &v, &mut self.saw_nul); + envp.push(s.as_ptr()); + map.insert(k, (envp.len() - 1, s)); + } + envp.push(ptr::null()); + self.env = Some(map); + self.envp = Some(envp); + } + (self.env.as_mut().unwrap(), self.envp.as_mut().unwrap()) + } + + pub fn env(&mut self, key: &OsStr, val: &OsStr) { + let new_key = pair_to_key(key, val, &mut self.saw_nul); + let (map, envp) = self.init_env_map(); + + // If `key` is already present then we just update `envp` in place + // (and store the owned value), but if it's not there we override the + // trailing NULL pointer, add a new NULL pointer, and store where we + // were located. + match map.entry(key.to_owned()) { + Entry::Occupied(mut e) => { + let (i, ref mut s) = *e.get_mut(); + envp[i] = new_key.as_ptr(); + *s = new_key; + } + Entry::Vacant(e) => { + let len = envp.len(); + envp[len - 1] = new_key.as_ptr(); + envp.push(ptr::null()); + e.insert((len - 1, new_key)); + } + } + } + + pub fn env_remove(&mut self, key: &OsStr) { + let (map, envp) = self.init_env_map(); + + // If we actually ended up removing a key, then we need to update the + // position of all keys that come after us in `envp` because they're all + // one element sooner now. + if let Some((i, _)) = map.remove(key) { + envp.remove(i); + + for (_, &mut (ref mut j, _)) in map.iter_mut() { + if *j >= i { + *j -= 1; + } + } + } + } + + pub fn env_clear(&mut self) { + self.env = Some(HashMap::new()); + self.envp = Some(vec![ptr::null()]); + } + + pub fn cwd(&mut self, dir: &OsStr) { + self.cwd = Some(os2c(dir, &mut self.saw_nul)); + } + pub fn uid(&mut self, id: uid_t) { + self.uid = Some(id); + } + pub fn gid(&mut self, id: gid_t) { + self.gid = Some(id); + } + + pub fn saw_nul(&self) -> bool { + self.saw_nul + } + pub fn get_envp(&self) -> &Option> { + &self.envp + } + pub fn get_argv(&self) -> &Vec<*const c_char> { + &self.argv + } + + #[cfg(not(target_os="fuchsia"))] + pub fn get_cwd(&self) -> &Option { + &self.cwd + } + #[cfg(not(target_os="fuchsia"))] + pub fn get_uid(&self) -> Option { + self.uid + } + #[cfg(not(target_os="fuchsia"))] + pub fn get_gid(&self) -> Option { + self.gid + } + + pub fn get_closures(&mut self) -> &mut Vec io::Result<()> + Send + Sync>> { + &mut self.closures + } + + pub fn before_exec(&mut self, + f: Box io::Result<()> + Send + Sync>) { + self.closures.push(f); + } + + pub fn stdin(&mut self, stdin: Stdio) { + self.stdin = Some(stdin); + } + + pub fn stdout(&mut self, stdout: Stdio) { + self.stdout = Some(stdout); + } + + pub fn stderr(&mut self, stderr: Stdio) { + self.stderr = Some(stderr); + } + + pub fn setup_io(&self, default: Stdio, needs_stdin: bool) + -> io::Result<(StdioPipes, ChildPipes)> { + let null = Stdio::Null; + let default_stdin = if needs_stdin {&default} else {&null}; + let stdin = self.stdin.as_ref().unwrap_or(default_stdin); + let stdout = self.stdout.as_ref().unwrap_or(&default); + let stderr = self.stderr.as_ref().unwrap_or(&default); + let (their_stdin, our_stdin) = stdin.to_child_stdio(true)?; + let (their_stdout, our_stdout) = stdout.to_child_stdio(false)?; + let (their_stderr, our_stderr) = stderr.to_child_stdio(false)?; + let ours = StdioPipes { + stdin: our_stdin, + stdout: our_stdout, + stderr: our_stderr, + }; + let theirs = ChildPipes { + stdin: their_stdin, + stdout: their_stdout, + stderr: their_stderr, + }; + Ok((ours, theirs)) + } +} + +fn os2c(s: &OsStr, saw_nul: &mut bool) -> CString { + CString::new(s.as_bytes()).unwrap_or_else(|_e| { + *saw_nul = true; + CString::new("").unwrap() + }) +} + +impl Stdio { + pub fn to_child_stdio(&self, readable: bool) + -> io::Result<(ChildStdio, Option)> { + match *self { + Stdio::Inherit => { + Ok((ChildStdio::Inherit, None)) + }, + + // Make sure that the source descriptors are not an stdio + // descriptor, otherwise the order which we set the child's + // descriptors may blow away a descriptor which we are hoping to + // save. For example, suppose we want the child's stderr to be the + // parent's stdout, and the child's stdout to be the parent's + // stderr. No matter which we dup first, the second will get + // overwritten prematurely. + Stdio::Fd(ref fd) => { + if fd.raw() >= 0 && fd.raw() <= libc::STDERR_FILENO { + Ok((ChildStdio::Owned(fd.duplicate()?), None)) + } else { + Ok((ChildStdio::Explicit(fd.raw()), None)) + } + } + + Stdio::MakePipe => { + let (reader, writer) = pipe::anon_pipe()?; + let (ours, theirs) = if readable { + (writer, reader) + } else { + (reader, writer) + }; + Ok((ChildStdio::Owned(theirs.into_fd()), Some(ours))) + } + + Stdio::Null => { + let mut opts = OpenOptions::new(); + opts.read(readable); + opts.write(!readable); + let path = unsafe { + CStr::from_ptr("/dev/null\0".as_ptr() as *const _) + }; + let fd = File::open_c(&path, &opts)?; + Ok((ChildStdio::Owned(fd.into_fd()), None)) + } + } + } +} + +impl ChildStdio { + pub fn fd(&self) -> Option { + match *self { + ChildStdio::Inherit => None, + ChildStdio::Explicit(fd) => Some(fd), + ChildStdio::Owned(ref fd) => Some(fd.raw()), + } + } +} + +fn pair_to_key(key: &OsStr, value: &OsStr, saw_nul: &mut bool) -> CString { + let (key, value) = (key.as_bytes(), value.as_bytes()); + let mut v = Vec::with_capacity(key.len() + value.len() + 1); + v.extend(key); + v.push(b'='); + v.extend(value); + CString::new(v).unwrap_or_else(|_e| { + *saw_nul = true; + CString::new("foo=bar").unwrap() + }) +} + +impl fmt::Debug for Command { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}", self.program)?; + for arg in &self.args { + write!(f, " {:?}", arg)?; + } + Ok(()) + } +} + +/// Unix exit statuses +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct ExitStatus(c_int); + +impl ExitStatus { + pub fn new(status: c_int) -> ExitStatus { + ExitStatus(status) + } + + fn exited(&self) -> bool { + unsafe { libc::WIFEXITED(self.0) } + } + + pub fn success(&self) -> bool { + self.code() == Some(0) + } + + pub fn code(&self) -> Option { + if self.exited() { + Some(unsafe { libc::WEXITSTATUS(self.0) }) + } else { + None + } + } + + pub fn signal(&self) -> Option { + if !self.exited() { + Some(unsafe { libc::WTERMSIG(self.0) }) + } else { + None + } + } +} + +impl From for ExitStatus { + fn from(a: c_int) -> ExitStatus { + ExitStatus(a) + } +} + +impl fmt::Display for ExitStatus { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some(code) = self.code() { + write!(f, "exit code: {}", code) + } else { + let signal = self.signal().unwrap(); + write!(f, "signal: {}", signal) + } + } +} + +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests { + use super::*; + + use ffi::OsStr; + use mem; + use ptr; + use libc; + use sys::cvt; + + macro_rules! t { + ($e:expr) => { + match $e { + Ok(t) => t, + Err(e) => panic!("received error for `{}`: {}", stringify!($e), e), + } + } + } + + #[cfg(not(target_os = "android"))] + extern { + #[cfg_attr(target_os = "netbsd", link_name = "__sigaddset14")] + fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int; + } + + #[cfg(target_os = "android")] + unsafe fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int { + use slice; + + let raw = slice::from_raw_parts_mut(set as *mut u8, mem::size_of::()); + let bit = (signum - 1) as usize; + raw[bit / 8] |= 1 << (bit % 8); + return 0; + } + + // See #14232 for more information, but it appears that signal delivery to a + // newly spawned process may just be raced in the OSX, so to prevent this + // test from being flaky we ignore it on OSX. + #[test] + #[cfg_attr(target_os = "macos", ignore)] + #[cfg_attr(target_os = "nacl", ignore)] // no signals on NaCl. + fn test_process_mask() { + unsafe { + // Test to make sure that a signal mask does not get inherited. + let mut cmd = Command::new(OsStr::new("cat")); + + let mut set: libc::sigset_t = mem::uninitialized(); + let mut old_set: libc::sigset_t = mem::uninitialized(); + t!(cvt(libc::sigemptyset(&mut set))); + t!(cvt(sigaddset(&mut set, libc::SIGINT))); + t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &set, &mut old_set))); + + cmd.stdin(Stdio::MakePipe); + cmd.stdout(Stdio::MakePipe); + + let (mut cat, mut pipes) = t!(cmd.spawn(Stdio::Null, true)); + let stdin_write = pipes.stdin.take().unwrap(); + let stdout_read = pipes.stdout.take().unwrap(); + + t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &old_set, + ptr::null_mut()))); + + t!(cvt(libc::kill(cat.id() as libc::pid_t, libc::SIGINT))); + // We need to wait until SIGINT is definitely delivered. The + // easiest way is to write something to cat, and try to read it + // back: if SIGINT is unmasked, it'll get delivered when cat is + // next scheduled. + let _ = stdin_write.write(b"Hello"); + drop(stdin_write); + + // Either EOF or failure (EPIPE) is okay. + let mut buf = [0; 5]; + if let Ok(ret) = stdout_read.read(&mut buf) { + assert!(ret == 0); + } + + t!(cat.wait()); + } + } +} diff --git a/src/libstd/sys/unix/process/process_fuchsia.rs b/src/libstd/sys/unix/process/process_fuchsia.rs new file mode 100644 index 00000000000..30e5555df69 --- /dev/null +++ b/src/libstd/sys/unix/process/process_fuchsia.rs @@ -0,0 +1,190 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use io; +use libc; +use mem; +use ptr; + +use sys::mx_cvt; +use sys::magenta::{launchpad_t, mx_handle_t}; +use sys::process::process_common::*; + +//////////////////////////////////////////////////////////////////////////////// +// Command +//////////////////////////////////////////////////////////////////////////////// + +impl Command { + pub fn spawn(&mut self, default: Stdio, needs_stdin: bool) + -> io::Result<(Process, StdioPipes)> { + if self.saw_nul() { + return Err(io::Error::new(io::ErrorKind::InvalidInput, + "nul byte found in provided data")); + } + + let (ours, theirs) = self.setup_io(default, needs_stdin)?; + + let (launchpad, process_handle) = unsafe { self.do_exec(theirs)? }; + + Ok((Process { launchpad: launchpad, handle: process_handle, status: None }, ours)) + } + + pub fn exec(&mut self, default: Stdio) -> io::Error { + if self.saw_nul() { + return io::Error::new(io::ErrorKind::InvalidInput, + "nul byte found in provided data") + } + + match self.setup_io(default, true) { + Ok((_, _)) => { + // FIXME: This is tough because we don't support the exec syscalls + unimplemented!(); + }, + Err(e) => e, + } + } + + unsafe fn do_exec(&mut self, stdio: ChildPipes) + -> io::Result<(*mut launchpad_t, mx_handle_t)> { + use sys::magenta::*; + + let job_handle = mxio_get_startup_handle(mx_hnd_info(MX_HND_TYPE_JOB, 0)); + let envp = match *self.get_envp() { + Some(ref envp) => envp.as_ptr(), + None => ptr::null(), + }; + + // To make sure launchpad_destroy gets called on the launchpad if this function fails + struct LaunchpadDestructor(*mut launchpad_t); + impl Drop for LaunchpadDestructor { + fn drop(&mut self) { unsafe { launchpad_destroy(self.0); } } + } + + let mut launchpad: *mut launchpad_t = ptr::null_mut(); + let launchpad_destructor = LaunchpadDestructor(launchpad); + + // Duplicate the job handle + let mut job_copy: mx_handle_t = MX_HANDLE_INVALID; + mx_cvt(mx_handle_duplicate(job_handle, MX_RIGHT_SAME_RIGHTS, + &mut job_copy as *mut mx_handle_t))?; + // Create a launchpad + mx_cvt(launchpad_create(job_copy, self.get_argv()[0], + &mut launchpad as *mut *mut launchpad_t))?; + // Set the process argv + mx_cvt(launchpad_arguments(launchpad, self.get_argv().len() as i32 - 1, + self.get_argv().as_ptr()))?; + // Setup the environment vars + mx_cvt(launchpad_environ(launchpad, envp))?; + mx_cvt(launchpad_add_vdso_vmo(launchpad))?; + mx_cvt(launchpad_clone_mxio_root(launchpad))?; + // Load the executable + mx_cvt(launchpad_elf_load(launchpad, launchpad_vmo_from_file(self.get_argv()[0])))?; + mx_cvt(launchpad_load_vdso(launchpad, MX_HANDLE_INVALID))?; + mx_cvt(launchpad_clone_mxio_cwd(launchpad))?; + + // Clone stdin, stdout, and stderr + if let Some(fd) = stdio.stdin.fd() { + launchpad_transfer_fd(launchpad, fd, 0); + } else { + launchpad_clone_fd(launchpad, 0, 0); + } + if let Some(fd) = stdio.stdout.fd() { + launchpad_transfer_fd(launchpad, fd, 1); + } else { + launchpad_clone_fd(launchpad, 1, 1); + } + if let Some(fd) = stdio.stderr.fd() { + launchpad_transfer_fd(launchpad, fd, 2); + } else { + launchpad_clone_fd(launchpad, 2, 2); + } + + // We don't want FileDesc::drop to be called on any stdio. It would close their fds. The + // fds will be closed once the child process finishes. + mem::forget(stdio); + + for callback in self.get_closures().iter_mut() { + callback()?; + } + + let process_handle = mx_cvt(launchpad_start(launchpad))?; + + // Successfully started the launchpad, so launchpad_destroy shouldn't get called + mem::forget(launchpad_destructor); + + Ok((launchpad, process_handle)) + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Processes +//////////////////////////////////////////////////////////////////////////////// + +pub struct Process { + launchpad: *mut launchpad_t, + handle: mx_handle_t, + status: Option, +} + +impl Process { + pub fn id(&self) -> u32 { + self.handle as u32 + } + + pub fn kill(&mut self) -> io::Result<()> { + use sys::magenta::*; + + // If we've already waited on this process then the pid can be recycled + // and used for another process, and we probably shouldn't be killing + // random processes, so just return an error. + if self.status.is_some() { + Err(io::Error::new(io::ErrorKind::InvalidInput, + "invalid argument: can't kill an exited process")) + } else { + unsafe { + mx_cvt(mx_handle_close(self.handle))?; + launchpad_destroy(self.launchpad); + } + Ok(()) + } + } + + pub fn wait(&mut self) -> io::Result { + use default::Default; + use sys::magenta::*; + + if let Some(status) = self.status { + return Ok(status) + } + + let mut proc_info: mx_info_process_t = Default::default(); + let mut actual: mx_size_t = 0; + let mut avail: mx_size_t = 0; + + unsafe { + mx_cvt(mx_handle_wait_one(self.handle, MX_TASK_TERMINATED, + MX_TIME_INFINITE, ptr::null_mut()))?; + mx_cvt(mx_object_get_info(self.handle, MX_INFO_PROCESS, + &mut proc_info as *mut _ as *mut libc::c_void, + mem::size_of::(), &mut actual, + &mut avail))?; + } + if actual != 1 { + return Err(io::Error::new(io::ErrorKind::InvalidInput, + "Failed to get exit status of process")); + } + self.status = Some(ExitStatus::new(proc_info.rec.return_code)); + unsafe { + mx_cvt(mx_handle_close(self.handle))?; + launchpad_destroy(self.launchpad); + } + Ok(ExitStatus::new(proc_info.rec.return_code)) + } +} diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs new file mode 100644 index 00000000000..aa426722025 --- /dev/null +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -0,0 +1,250 @@ +// 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 io::{self, Error, ErrorKind}; +use libc::{self, c_int, gid_t, pid_t, uid_t}; +use mem; +use ptr; + +use sys::cvt; +use sys::process::process_common::*; + +//////////////////////////////////////////////////////////////////////////////// +// Command +//////////////////////////////////////////////////////////////////////////////// + +impl Command { + pub fn spawn(&mut self, default: Stdio, needs_stdin: bool) + -> io::Result<(Process, StdioPipes)> { + use sys; + + const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX"; + + if self.saw_nul() { + return Err(io::Error::new(ErrorKind::InvalidInput, + "nul byte found in provided data")); + } + + let (ours, theirs) = self.setup_io(default, needs_stdin)?; + let (input, output) = sys::pipe::anon_pipe()?; + + let pid = unsafe { + match cvt(libc::fork())? { + 0 => { + drop(input); + let err = self.do_exec(theirs); + let errno = err.raw_os_error().unwrap_or(libc::EINVAL) as u32; + let bytes = [ + (errno >> 24) as u8, + (errno >> 16) as u8, + (errno >> 8) as u8, + (errno >> 0) as u8, + CLOEXEC_MSG_FOOTER[0], CLOEXEC_MSG_FOOTER[1], + CLOEXEC_MSG_FOOTER[2], CLOEXEC_MSG_FOOTER[3] + ]; + // pipe I/O up to PIPE_BUF bytes should be atomic, and then + // we want to be sure we *don't* run at_exit destructors as + // we're being torn down regardless + assert!(output.write(&bytes).is_ok()); + libc::_exit(1) + } + n => n, + } + }; + + let mut p = Process { pid: pid, status: None }; + drop(output); + let mut bytes = [0; 8]; + + // loop to handle EINTR + loop { + match input.read(&mut bytes) { + Ok(0) => return Ok((p, ours)), + Ok(8) => { + assert!(combine(CLOEXEC_MSG_FOOTER) == combine(&bytes[4.. 8]), + "Validation on the CLOEXEC pipe failed: {:?}", bytes); + let errno = combine(&bytes[0.. 4]); + assert!(p.wait().is_ok(), + "wait() should either return Ok or panic"); + return Err(Error::from_raw_os_error(errno)) + } + Err(ref e) if e.kind() == ErrorKind::Interrupted => {} + Err(e) => { + assert!(p.wait().is_ok(), + "wait() should either return Ok or panic"); + panic!("the CLOEXEC pipe failed: {:?}", e) + }, + Ok(..) => { // pipe I/O up to PIPE_BUF bytes should be atomic + assert!(p.wait().is_ok(), + "wait() should either return Ok or panic"); + panic!("short read on the CLOEXEC pipe") + } + } + } + + fn combine(arr: &[u8]) -> i32 { + let a = arr[0] as u32; + let b = arr[1] as u32; + let c = arr[2] as u32; + let d = arr[3] as u32; + + ((a << 24) | (b << 16) | (c << 8) | (d << 0)) as i32 + } + } + + pub fn exec(&mut self, default: Stdio) -> io::Error { + if self.saw_nul() { + return io::Error::new(ErrorKind::InvalidInput, + "nul byte found in provided data") + } + + match self.setup_io(default, true) { + Ok((_, theirs)) => unsafe { self.do_exec(theirs) }, + Err(e) => e, + } + } + + // And at this point we've reached a special time in the life of the + // child. The child must now be considered hamstrung and unable to + // do anything other than syscalls really. Consider the following + // scenario: + // + // 1. Thread A of process 1 grabs the malloc() mutex + // 2. Thread B of process 1 forks(), creating thread C + // 3. Thread C of process 2 then attempts to malloc() + // 4. The memory of process 2 is the same as the memory of + // process 1, so the mutex is locked. + // + // This situation looks a lot like deadlock, right? It turns out + // that this is what pthread_atfork() takes care of, which is + // presumably implemented across platforms. The first thing that + // threads to *before* forking is to do things like grab the malloc + // mutex, and then after the fork they unlock it. + // + // Despite this information, libnative's spawn has been witnessed to + // deadlock on both OSX and FreeBSD. I'm not entirely sure why, but + // all collected backtraces point at malloc/free traffic in the + // child spawned process. + // + // For this reason, the block of code below should contain 0 + // invocations of either malloc of free (or their related friends). + // + // As an example of not having malloc/free traffic, we don't close + // this file descriptor by dropping the FileDesc (which contains an + // allocation). Instead we just close it manually. This will never + // have the drop glue anyway because this code never returns (the + // child will either exec() or invoke libc::exit) + unsafe fn do_exec(&mut self, stdio: ChildPipes) -> io::Error { + use sys::{self, cvt_r}; + + macro_rules! t { + ($e:expr) => (match $e { + Ok(e) => e, + Err(e) => return e, + }) + } + + if let Some(fd) = stdio.stdin.fd() { + t!(cvt_r(|| libc::dup2(fd, libc::STDIN_FILENO))); + } + if let Some(fd) = stdio.stdout.fd() { + t!(cvt_r(|| libc::dup2(fd, libc::STDOUT_FILENO))); + } + if let Some(fd) = stdio.stderr.fd() { + t!(cvt_r(|| libc::dup2(fd, libc::STDERR_FILENO))); + } + + if let Some(u) = self.get_gid() { + t!(cvt(libc::setgid(u as gid_t))); + } + if let Some(u) = self.get_uid() { + // When dropping privileges from root, the `setgroups` call + // will remove any extraneous groups. If we don't call this, + // then even though our uid has dropped, we may still have + // groups that enable us to do super-user things. This will + // fail if we aren't root, so don't bother checking the + // return value, this is just done as an optimistic + // privilege dropping function. + let _ = libc::setgroups(0, ptr::null()); + + t!(cvt(libc::setuid(u as uid_t))); + } + if let Some(ref cwd) = *self.get_cwd() { + t!(cvt(libc::chdir(cwd.as_ptr()))); + } + if let Some(ref envp) = *self.get_envp() { + *sys::os::environ() = envp.as_ptr(); + } + + // NaCl has no signal support. + if cfg!(not(any(target_os = "nacl", target_os = "emscripten"))) { + // Reset signal handling so the child process starts in a + // standardized state. libstd ignores SIGPIPE, and signal-handling + // libraries often set a mask. Child processes inherit ignored + // signals and the signal mask from their parent, but most + // UNIX programs do not reset these things on their own, so we + // need to clean things up now to avoid confusing the program + // we're about to run. + let mut set: libc::sigset_t = mem::uninitialized(); + t!(cvt(libc::sigemptyset(&mut set))); + t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &set, + ptr::null_mut()))); + let ret = sys::signal(libc::SIGPIPE, libc::SIG_DFL); + if ret == libc::SIG_ERR { + return io::Error::last_os_error() + } + } + + for callback in self.get_closures().iter_mut() { + t!(callback()); + } + + libc::execvp(self.get_argv()[0], self.get_argv().as_ptr()); + io::Error::last_os_error() + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Processes +//////////////////////////////////////////////////////////////////////////////// + +/// The unique id of the process (this should never be negative). +pub struct Process { + pid: pid_t, + status: Option, +} + +impl Process { + pub fn id(&self) -> u32 { + self.pid as u32 + } + + pub fn kill(&mut self) -> io::Result<()> { + // If we've already waited on this process then the pid can be recycled + // and used for another process, and we probably shouldn't be killing + // random processes, so just return an error. + if self.status.is_some() { + Err(Error::new(ErrorKind::InvalidInput, + "invalid argument: can't kill an exited process")) + } else { + cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(|_| ()) + } + } + pub fn wait(&mut self) -> io::Result { + use sys::cvt_r; + if let Some(status) = self.status { + return Ok(status) + } + let mut status = 0 as c_int; + cvt_r(|| unsafe { libc::waitpid(self.pid, &mut status, 0) })?; + self.status = Some(ExitStatus::new(status)); + Ok(ExitStatus::new(status)) + } +} From 12c5f8cb75b0320f4ba9557417e5e554ffe2001b Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Thu, 24 Nov 2016 01:40:52 +0200 Subject: [PATCH 044/293] rustdoc: use libsyntax ast::Attribute instead of "cleaning" them. --- src/librustdoc/clean/inline.rs | 8 +- src/librustdoc/clean/mod.rs | 171 +++++++++++--------- src/librustdoc/html/render.rs | 103 ++++++------ src/librustdoc/lib.rs | 172 +++++++++++---------- src/librustdoc/passes/collapse_docs.rs | 37 ++--- src/librustdoc/passes/strip_hidden.rs | 4 +- src/librustdoc/passes/unindent_comments.rs | 25 ++- src/librustdoc/visit_ast.rs | 13 +- src/librustdoc/visit_lib.rs | 7 +- 9 files changed, 272 insertions(+), 268 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 185f897c1ba..e7575468640 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -135,8 +135,8 @@ fn try_inline_def<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, } pub fn load_attrs<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, - did: DefId) -> Vec { - tcx.get_attrs(did).iter().map(|a| a.clean(cx)).collect() + did: DefId) -> clean::Attributes { + tcx.get_attrs(did).clean(cx) } /// Record an external fully qualified name in the external_paths cache. @@ -377,7 +377,7 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, default, ), source: clean::Span::empty(), - attrs: vec![], + attrs: clean::Attributes::default(), visibility: None, stability: tcx.lookup_stability(item.def_id).clean(cx), deprecation: tcx.lookup_deprecation(item.def_id).clean(cx), @@ -424,7 +424,7 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, name: Some(item.name.clean(cx)), inner: clean::TypedefItem(typedef, true), source: clean::Span::empty(), - attrs: vec![], + attrs: clean::Attributes::default(), visibility: None, stability: tcx.lookup_stability(item.def_id).clean(cx), deprecation: tcx.lookup_deprecation(item.def_id).clean(cx), diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 2cc1882ce3e..18cb9630f49 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -14,7 +14,6 @@ pub use self::Type::*; pub use self::Mutability::*; pub use self::ItemEnum::*; -pub use self::Attribute::*; pub use self::TyParamBound::*; pub use self::SelfTy::*; pub use self::FunctionRetTy::*; @@ -25,7 +24,6 @@ use syntax::ast; use syntax::attr; use syntax::codemap::Spanned; use syntax::ptr::P; -use syntax::print::pprust as syntax_pprust; use syntax::symbol::keywords; use syntax_pos::{self, DUMMY_SP, Pos}; @@ -44,6 +42,7 @@ use rustc::hir; use std::path::PathBuf; use std::rc::Rc; +use std::slice; use std::sync::Arc; use std::u32; use std::env::current_dir; @@ -227,7 +226,7 @@ impl<'a, 'tcx> Clean for visit_ast::RustdocVisitor<'a, 'tcx> { #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct ExternalCrate { pub name: String, - pub attrs: Vec, + pub attrs: Attributes, pub primitives: Vec, } @@ -258,7 +257,7 @@ pub struct Item { pub source: Span, /// Not everything has a name. E.g., impls pub name: Option, - pub attrs: Vec, + pub attrs: Attributes, pub inner: ItemEnum, pub visibility: Option, pub def_id: DefId, @@ -270,7 +269,7 @@ impl Item { /// Finds the `doc` attribute as a NameValue and returns the corresponding /// value found. pub fn doc_value<'a>(&'a self) -> Option<&'a str> { - self.attrs.value("doc") + self.attrs.doc_value() } pub fn is_crate(&self) -> bool { match self.inner { @@ -459,86 +458,104 @@ impl Clean for doctree::Module { } } -pub trait Attributes { - fn has_word(&self, &str) -> bool; - fn value<'a>(&'a self, &str) -> Option<&'a str>; - fn list<'a>(&'a self, &str) -> &'a [Attribute]; +pub struct ListAttributesIter<'a> { + attrs: slice::Iter<'a, ast::Attribute>, + current_list: slice::Iter<'a, ast::NestedMetaItem>, + name: &'a str } -impl Attributes for [Attribute] { - /// Returns whether the attribute list contains a specific `Word` - fn has_word(&self, word: &str) -> bool { - for attr in self { - if let Word(ref w) = *attr { - if word == *w { - return true; - } - } - } - false - } +impl<'a> Iterator for ListAttributesIter<'a> { + type Item = &'a ast::NestedMetaItem; - /// Finds an attribute as NameValue and returns the corresponding value found. - fn value<'a>(&'a self, name: &str) -> Option<&'a str> { - for attr in self { - if let NameValue(ref x, ref v) = *attr { - if name == *x { - return Some(v); + fn next(&mut self) -> Option { + if let Some(nested) = self.current_list.next() { + return Some(nested); + } + + for attr in &mut self.attrs { + if let Some(ref list) = attr.meta_item_list() { + if attr.check_name(self.name) { + self.current_list = list.iter(); + if let Some(nested) = self.current_list.next() { + return Some(nested); + } } } } + None } +} +pub trait AttributesExt { /// Finds an attribute as List and returns the list of attributes nested inside. - fn list<'a>(&'a self, name: &str) -> &'a [Attribute] { - for attr in self { - if let List(ref x, ref list) = *attr { - if name == *x { - return &list[..]; + fn lists<'a>(&'a self, &'a str) -> ListAttributesIter<'a>; +} + +impl AttributesExt for [ast::Attribute] { + fn lists<'a>(&'a self, name: &'a str) -> ListAttributesIter<'a> { + ListAttributesIter { + attrs: self.iter(), + current_list: [].iter(), + name: name + } + } +} + +pub trait NestedAttributesExt { + /// Returns whether the attribute list contains a specific `Word` + fn has_word(self, &str) -> bool; +} + +impl<'a, I: IntoIterator> NestedAttributesExt for I { + fn has_word(self, word: &str) -> bool { + self.into_iter().any(|attr| attr.is_word() && attr.check_name(word)) + } +} + +#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug, Default)] +pub struct Attributes { + pub doc_strings: Vec, + pub other_attrs: Vec +} + +impl Attributes { + pub fn from_ast(attrs: &[ast::Attribute]) -> Attributes { + let mut doc_strings = vec![]; + let other_attrs = attrs.iter().filter_map(|attr| { + attr.with_desugared_doc(|attr| { + if let Some(value) = attr.value_str() { + if attr.check_name("doc") { + doc_strings.push(value.to_string()); + return None; + } } - } - } - &[] - } -} -/// This is a flattened version of the AST's Attribute + MetaItem. -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] -pub enum Attribute { - Word(String), - List(String, Vec), - NameValue(String, String), - Literal(String), -} - -impl Clean for ast::NestedMetaItem { - fn clean(&self, cx: &DocContext) -> Attribute { - if let Some(mi) = self.meta_item() { - mi.clean(cx) - } else { // must be a literal - let lit = self.literal().unwrap(); - Literal(syntax_pprust::lit_to_string(lit)) + Some(attr.clone()) + }) + }).collect(); + Attributes { + doc_strings: doc_strings, + other_attrs: other_attrs } } -} -impl Clean for ast::MetaItem { - fn clean(&self, cx: &DocContext) -> Attribute { - if self.is_word() { - Word(self.name().to_string()) - } else if let Some(v) = self.value_str() { - NameValue(self.name().to_string(), v.to_string()) - } else { // must be a list - let l = self.meta_item_list().unwrap(); - List(self.name().to_string(), l.clean(cx)) - } + /// Finds the `doc` attribute as a NameValue and returns the corresponding + /// value found. + pub fn doc_value<'a>(&'a self) -> Option<&'a str> { + self.doc_strings.first().map(|s| &s[..]) } } -impl Clean for ast::Attribute { - fn clean(&self, cx: &DocContext) -> Attribute { - self.with_desugared_doc(|a| a.meta().clean(cx)) +impl AttributesExt for Attributes { + fn lists<'a>(&'a self, name: &'a str) -> ListAttributesIter<'a> { + self.other_attrs.lists(name) + } +} + +impl Clean for [ast::Attribute] { + fn clean(&self, _cx: &DocContext) -> Attributes { + Attributes::from_ast(self) } } @@ -1048,7 +1065,7 @@ impl Clean for hir::MethodSig { }, output: self.decl.output.clean(cx), variadic: false, - attrs: Vec::new() + attrs: Attributes::default() }; Method { generics: self.generics.clean(cx), @@ -1076,7 +1093,7 @@ impl Clean for hir::MethodSig { }, output: self.decl.output.clean(cx), variadic: false, - attrs: Vec::new() + attrs: Attributes::default() }; TyMethod { unsafety: self.unsafety.clone(), @@ -1122,7 +1139,7 @@ pub struct FnDecl { pub inputs: Arguments, pub output: FunctionRetTy, pub variadic: bool, - pub attrs: Vec, + pub attrs: Attributes, } impl FnDecl { @@ -1148,7 +1165,7 @@ impl Clean for hir::FnDecl { }, output: self.output.clean(cx), variadic: self.variadic, - attrs: Vec::new() + attrs: Attributes::default() } } } @@ -1163,7 +1180,7 @@ impl<'a, 'tcx> Clean for (DefId, &'a ty::PolyFnSig<'tcx>) { }.peekable(); FnDecl { output: Return(sig.0.output.clean(cx)), - attrs: Vec::new(), + attrs: Attributes::default(), variadic: sig.0.variadic, inputs: Arguments { values: sig.0.inputs.iter().map(|t| { @@ -1616,11 +1633,11 @@ impl PrimitiveType { } } - fn find(attrs: &[Attribute]) -> Option { - for attr in attrs.list("doc") { - if let NameValue(ref k, ref v) = *attr { - if "primitive" == *k { - if let ret@Some(..) = PrimitiveType::from_str(v) { + fn find(attrs: &Attributes) -> Option { + for attr in attrs.lists("doc") { + if let Some(v) = attr.value_str() { + if attr.check_name("primitive") { + if let ret@Some(..) = PrimitiveType::from_str(&v.as_str()) { return ret; } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 31fbcb5059f..757db81c440 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -53,7 +53,7 @@ use std::sync::Arc; use externalfiles::ExternalHtml; use serialize::json::{ToJson, Json, as_json}; -use syntax::abi; +use syntax::{abi, ast}; use syntax::feature_gate::UnstableFeatures; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, LOCAL_CRATE}; use rustc::middle::privacy::AccessLevels; @@ -62,7 +62,7 @@ use rustc::hir; use rustc::util::nodemap::{FxHashMap, FxHashSet}; use rustc_data_structures::flock; -use clean::{self, Attributes, GetDefId, SelfTy, Mutability}; +use clean::{self, AttributesExt, GetDefId, SelfTy, Mutability}; use doctree; use fold::DocFolder; use html::escape::Escape; @@ -453,30 +453,26 @@ pub fn run(mut krate: clean::Crate, // Crawl the crate attributes looking for attributes which control how we're // going to emit HTML - if let Some(attrs) = krate.module.as_ref().map(|m| m.attrs.list("doc")) { - for attr in attrs { - match *attr { - clean::NameValue(ref x, ref s) - if "html_favicon_url" == *x => { + if let Some(attrs) = krate.module.as_ref().map(|m| &m.attrs) { + for attr in attrs.lists("doc") { + let name = attr.name().map(|s| s.as_str()); + match (name.as_ref().map(|s| &s[..]), attr.value_str()) { + (Some("html_favicon_url"), Some(s)) => { scx.layout.favicon = s.to_string(); } - clean::NameValue(ref x, ref s) - if "html_logo_url" == *x => { + (Some("html_logo_url"), Some(s)) => { scx.layout.logo = s.to_string(); } - clean::NameValue(ref x, ref s) - if "html_playground_url" == *x => { + (Some("html_playground_url"), Some(s)) => { markdown::PLAYGROUND.with(|slot| { let name = krate.name.clone(); - *slot.borrow_mut() = Some((Some(name), s.clone())); + *slot.borrow_mut() = Some((Some(name), s.to_string())); }); } - clean::NameValue(ref x, ref s) - if "issue_tracker_base_url" == *x => { + (Some("issue_tracker_base_url"), Some(s)) => { scx.issue_tracker_base_url = Some(s.to_string()); } - clean::Word(ref x) - if "html_no_source" == *x => { + (Some("html_no_source"), None) if attr.is_word() => { scx.include_sources = false; } _ => {} @@ -860,13 +856,16 @@ fn extern_location(e: &clean::ExternalCrate, dst: &Path) -> ExternalLocation { // Failing that, see if there's an attribute specifying where to find this // external crate - e.attrs.list("doc").value("html_root_url").map(|url| { - let mut url = url.to_owned(); + e.attrs.lists("doc") + .filter(|a| a.check_name("html_root_url")) + .filter_map(|a| a.value_str()) + .map(|url| { + let mut url = url.to_string(); if !url.ends_with("/") { url.push('/') } Remote(url) - }).unwrap_or(Unknown) // Well, at least we tried. + }).next().unwrap_or(Unknown) // Well, at least we tried. } impl<'a> DocFolder for SourceCollector<'a> { @@ -2511,49 +2510,47 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, Ok(()) } -fn attribute_without_value(s: &str) -> bool { - ["must_use", "no_mangle", "unsafe_destructor_blind_to_params"].iter().any(|x| x == &s) -} +fn render_attribute(attr: &ast::MetaItem) -> Option { + let name = attr.name(); -fn attribute_with_value(s: &str) -> bool { - ["export_name", "lang", "link_section", "must_use"].iter().any(|x| x == &s) -} + if attr.is_word() { + Some(format!("{}", name)) + } else if let Some(v) = attr.value_str() { + Some(format!("{} = {:?}", name, &v.as_str()[..])) + } else if let Some(values) = attr.meta_item_list() { + let display: Vec<_> = values.iter().filter_map(|attr| { + attr.meta_item().and_then(|mi| render_attribute(mi)) + }).collect(); -fn attribute_with_values(s: &str) -> bool { - ["repr"].iter().any(|x| x == &s) -} - -fn render_attribute(attr: &clean::Attribute, recurse: bool) -> Option { - match *attr { - clean::Word(ref s) if attribute_without_value(&*s) || recurse => { - Some(format!("{}", s)) - } - clean::NameValue(ref k, ref v) if attribute_with_value(&*k) => { - Some(format!("{} = \"{}\"", k, v)) - } - clean::List(ref k, ref values) if attribute_with_values(&*k) => { - let display: Vec<_> = values.iter() - .filter_map(|value| render_attribute(value, true)) - .map(|entry| format!("{}", entry)) - .collect(); - - if display.len() > 0 { - Some(format!("{}({})", k, display.join(", "))) - } else { - None - } - } - _ => { + if display.len() > 0 { + Some(format!("{}({})", name, display.join(", "))) + } else { None } + } else { + None } } +const ATTRIBUTE_WHITELIST: &'static [&'static str] = &[ + "export_name", + "lang", + "link_section", + "must_use", + "no_mangle", + "repr", + "unsafe_destructor_blind_to_params" +]; + fn render_attributes(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result { let mut attrs = String::new(); - for attr in &it.attrs { - if let Some(s) = render_attribute(attr, false) { + for attr in &it.attrs.other_attrs { + let name = attr.name(); + if !ATTRIBUTE_WHITELIST.contains(&&name.as_str()[..]) { + continue; + } + if let Some(s) = render_attribute(attr.meta()) { attrs.push_str(&format!("#[{}]\n", s)); } } @@ -2810,7 +2807,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi } write!(w, "")?; write!(w, "\n")?; - if let Some(ref dox) = i.impl_item.attrs.value("doc") { + if let Some(ref dox) = i.impl_item.doc_value() { write!(w, "
{}
", Markdown(dox))?; } } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 3af7c20c133..60ce7ea5395 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -89,7 +89,7 @@ pub mod visit_ast; pub mod visit_lib; pub mod test; -use clean::Attributes; +use clean::AttributesExt; struct Output { krate: clean::Crate, @@ -280,43 +280,45 @@ pub fn main_args(args: &[String]) -> isize { !matches.opt_present("markdown-no-toc")), (false, false) => {} } - let out = match acquire_input(input, externs, &matches) { - Ok(out) => out, - Err(s) => { - println!("input error: {}", s); - return 1; + + let output_format = matches.opt_str("w"); + let res = acquire_input(input, externs, &matches, move |out| { + let Output { krate, passes, renderinfo } = out; + info!("going to format"); + match output_format.as_ref().map(|s| &**s) { + Some("html") | None => { + html::render::run(krate, &external_html, + output.unwrap_or(PathBuf::from("doc")), + passes.into_iter().collect(), + css_file_extension, + renderinfo) + .expect("failed to generate documentation"); + 0 + } + Some(s) => { + println!("unknown output format: {}", s); + 1 + } } - }; - let Output { krate, passes, renderinfo } = out; - info!("going to format"); - match matches.opt_str("w").as_ref().map(|s| &**s) { - Some("html") | None => { - html::render::run(krate, &external_html, - output.unwrap_or(PathBuf::from("doc")), - passes.into_iter().collect(), - css_file_extension, - renderinfo) - .expect("failed to generate documentation"); - 0 - } - Some(s) => { - println!("unknown output format: {}", s); - 1 - } - } + }); + res.unwrap_or_else(|s| { + println!("input error: {}", s); + 1 + }) } /// Looks inside the command line arguments to extract the relevant input format /// and files and then generates the necessary rustdoc output for formatting. -fn acquire_input(input: &str, - externs: Externs, - matches: &getopts::Matches) -> Result { +fn acquire_input(input: &str, + externs: Externs, + matches: &getopts::Matches, + f: F) + -> Result +where R: 'static + Send, F: 'static + Send + FnOnce(Output) -> R { match matches.opt_str("r").as_ref().map(|s| &**s) { - Some("rust") => Ok(rust_input(input, externs, matches)), + Some("rust") => Ok(rust_input(input, externs, matches, f)), Some(s) => Err(format!("unknown input format: {}", s)), - None => { - Ok(rust_input(input, externs, matches)) - } + None => Ok(rust_input(input, externs, matches, f)) } } @@ -342,7 +344,8 @@ fn parse_externs(matches: &getopts::Matches) -> Result { /// generated from the cleaned AST of the crate. /// /// This form of input will run all of the plug/cleaning passes -fn rust_input(cratefile: &str, externs: Externs, matches: &getopts::Matches) -> Output { +fn rust_input(cratefile: &str, externs: Externs, matches: &getopts::Matches, f: F) -> R +where R: 'static + Send, F: 'static + Send + FnOnce(Output) -> R { let mut default_passes = !matches.opt_present("no-defaults"); let mut passes = matches.opt_strs("passes"); let mut plugins = matches.opt_strs("plugins"); @@ -355,6 +358,8 @@ fn rust_input(cratefile: &str, externs: Externs, matches: &getopts::Matches) -> let cfgs = matches.opt_strs("cfg"); let triple = matches.opt_str("target"); let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from); + let crate_name = matches.opt_str("crate-name"); + let plugin_path = matches.opt_str("plugin-path"); let cr = PathBuf::from(cratefile); info!("starting to run rustc"); @@ -363,67 +368,68 @@ fn rust_input(cratefile: &str, externs: Externs, matches: &getopts::Matches) -> rustc_driver::monitor(move || { use rustc::session::config::Input; - tx.send(core::run_core(paths, cfgs, externs, Input::File(cr), - triple, maybe_sysroot)).unwrap(); - }); - let (mut krate, renderinfo) = rx.recv().unwrap(); - info!("finished with rustc"); + let (mut krate, renderinfo) = + core::run_core(paths, cfgs, externs, Input::File(cr), triple, maybe_sysroot); - if let Some(name) = matches.opt_str("crate-name") { - krate.name = name - } + info!("finished with rustc"); - // Process all of the crate attributes, extracting plugin metadata along - // with the passes which we are supposed to run. - for attr in krate.module.as_ref().unwrap().attrs.list("doc") { - match *attr { - clean::Word(ref w) if "no_default_passes" == *w => { - default_passes = false; - }, - clean::NameValue(ref name, ref value) => { - let sink = match &name[..] { - "passes" => &mut passes, - "plugins" => &mut plugins, + if let Some(name) = crate_name { + krate.name = name + } + + // Process all of the crate attributes, extracting plugin metadata along + // with the passes which we are supposed to run. + for attr in krate.module.as_ref().unwrap().attrs.lists("doc") { + let name = attr.name().map(|s| s.as_str()); + let name = name.as_ref().map(|s| &s[..]); + if attr.is_word() { + if name == Some("no_default_passes") { + default_passes = false; + } + } else if let Some(value) = attr.value_str() { + let sink = match name { + Some("passes") => &mut passes, + Some("plugins") => &mut plugins, _ => continue, }; - for p in value.split_whitespace() { + for p in value.as_str().split_whitespace() { sink.push(p.to_string()); } } - _ => (), } - } - if default_passes { - for name in passes::DEFAULT_PASSES.iter().rev() { - passes.insert(0, name.to_string()); + if default_passes { + for name in passes::DEFAULT_PASSES.iter().rev() { + passes.insert(0, name.to_string()); + } } - } - // Load all plugins/passes into a PluginManager - let path = matches.opt_str("plugin-path") - .unwrap_or("/tmp/rustdoc/plugins".to_string()); - let mut pm = plugins::PluginManager::new(PathBuf::from(path)); - for pass in &passes { - let plugin = match passes::PASSES.iter() - .position(|&(p, ..)| { - p == *pass - }) { - Some(i) => passes::PASSES[i].1, - None => { - error!("unknown pass {}, skipping", *pass); - continue - }, - }; - pm.add_plugin(plugin); - } - info!("loading plugins..."); - for pname in plugins { - pm.load_plugin(pname); - } + // Load all plugins/passes into a PluginManager + let path = plugin_path.unwrap_or("/tmp/rustdoc/plugins".to_string()); + let mut pm = plugins::PluginManager::new(PathBuf::from(path)); + for pass in &passes { + let plugin = match passes::PASSES.iter() + .position(|&(p, ..)| { + p == *pass + }) { + Some(i) => passes::PASSES[i].1, + None => { + error!("unknown pass {}, skipping", *pass); + continue + }, + }; + pm.add_plugin(plugin); + } + info!("loading plugins..."); + for pname in plugins { + pm.load_plugin(pname); + } - // Run everything! - info!("Executing passes/plugins"); - let krate = pm.run_plugins(krate); - Output { krate: krate, renderinfo: renderinfo, passes: passes } + // Run everything! + info!("Executing passes/plugins"); + let krate = pm.run_plugins(krate); + + tx.send(f(Output { krate: krate, renderinfo: renderinfo, passes: passes })).unwrap(); + }); + rx.recv().unwrap() } diff --git a/src/librustdoc/passes/collapse_docs.rs b/src/librustdoc/passes/collapse_docs.rs index c034ef93268..3c63302127c 100644 --- a/src/librustdoc/passes/collapse_docs.rs +++ b/src/librustdoc/passes/collapse_docs.rs @@ -8,40 +8,33 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::string::String; - use clean::{self, Item}; use plugins; use fold; use fold::DocFolder; pub fn collapse_docs(krate: clean::Crate) -> plugins::PluginResult { - let mut collapser = Collapser; - let krate = collapser.fold_crate(krate); - krate + Collapser.fold_crate(krate) } struct Collapser; impl fold::DocFolder for Collapser { fn fold_item(&mut self, mut i: Item) -> Option { - let mut docstr = String::new(); - for attr in &i.attrs { - if let clean::NameValue(ref x, ref s) = *attr { - if "doc" == *x { - docstr.push_str(s); - docstr.push('\n'); - } - } - } - let mut a: Vec = i.attrs.iter().filter(|&a| match a { - &clean::NameValue(ref x, _) if "doc" == *x => false, - _ => true - }).cloned().collect(); - if !docstr.is_empty() { - a.push(clean::NameValue("doc".to_string(), docstr)); - } - i.attrs = a; + i.attrs.collapse_doc_comments(); self.fold_item_recur(i) } } + +impl clean::Attributes { + pub fn collapse_doc_comments(&mut self) { + let mut doc_string = self.doc_strings.join("\n"); + if doc_string.is_empty() { + self.doc_strings = vec![]; + } else { + // FIXME(eddyb) Is this still needed? + doc_string.push('\n'); + self.doc_strings = vec![doc_string]; + } + } +} diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index 927ccf91719..68c1231fc6f 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -11,7 +11,7 @@ use rustc::util::nodemap::DefIdSet; use std::mem; -use clean::{self, Attributes}; +use clean::{self, AttributesExt, NestedAttributesExt}; use clean::Item; use plugins; use fold; @@ -41,7 +41,7 @@ struct Stripper<'a> { impl<'a> fold::DocFolder for Stripper<'a> { fn fold_item(&mut self, i: Item) -> Option { - if i.attrs.list("doc").has_word("hidden") { + if i.attrs.lists("doc").has_word("hidden") { debug!("found one in strip_hidden; removing"); // use a dedicated hidden item for given item type if any match i.inner { diff --git a/src/librustdoc/passes/unindent_comments.rs b/src/librustdoc/passes/unindent_comments.rs index 20640f3f885..4d94c308478 100644 --- a/src/librustdoc/passes/unindent_comments.rs +++ b/src/librustdoc/passes/unindent_comments.rs @@ -17,31 +17,26 @@ use plugins; use fold::{self, DocFolder}; pub fn unindent_comments(krate: clean::Crate) -> plugins::PluginResult { - let mut cleaner = CommentCleaner; - let krate = cleaner.fold_crate(krate); - krate + CommentCleaner.fold_crate(krate) } struct CommentCleaner; impl fold::DocFolder for CommentCleaner { fn fold_item(&mut self, mut i: Item) -> Option { - let mut avec: Vec = Vec::new(); - for attr in &i.attrs { - match attr { - &clean::NameValue(ref x, ref s) - if "doc" == *x => { - avec.push(clean::NameValue("doc".to_string(), - unindent(s))) - } - x => avec.push(x.clone()) - } - } - i.attrs = avec; + i.attrs.unindent_doc_comments(); self.fold_item_recur(i) } } +impl clean::Attributes { + pub fn unindent_doc_comments(&mut self) { + for doc_string in &mut self.doc_strings { + *doc_string = unindent(doc_string); + } + } +} + fn unindent(s: &str) -> String { let lines = s.lines().collect:: >(); let mut saw_first_line = false; diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 939fd6ccfc8..f1eb65ee16e 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -28,7 +28,7 @@ use rustc::util::nodemap::FxHashSet; use rustc::hir; use core; -use clean::{self, Clean, Attributes}; +use clean::{self, AttributesExt, NestedAttributesExt}; use doctree::*; // looks to me like the first two of these are actually @@ -281,8 +281,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { fn inherits_doc_hidden(cx: &core::DocContext, mut node: ast::NodeId) -> bool { while let Some(id) = cx.map.get_enclosing_scope(node) { node = id; - let attrs = cx.map.attrs(node).clean(cx); - if attrs.list("doc").has_word("hidden") { + if cx.map.attrs(node).lists("doc").has_word("hidden") { return true; } if node == ast::CRATE_NODE_ID { @@ -299,10 +298,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let def = tcx.expect_def(id); let def_did = def.def_id(); - let use_attrs = tcx.map.attrs(id).clean(self.cx); + let use_attrs = tcx.map.attrs(id); // Don't inline doc(hidden) imports so they can be stripped at a later stage. - let is_no_inline = use_attrs.list("doc").has_word("no_inline") || - use_attrs.list("doc").has_word("hidden"); + let is_no_inline = use_attrs.lists("doc").has_word("no_inline") || + use_attrs.lists("doc").has_word("hidden"); // For cross-crate impl inlining we need to know whether items are // reachable in documentation - a previously nonreachable item can be @@ -310,7 +309,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { // (this is done here because we need to know this upfront) if !def_did.is_local() && !is_no_inline { let attrs = clean::inline::load_attrs(self.cx, tcx, def_did); - let self_is_hidden = attrs.list("doc").has_word("hidden"); + let self_is_hidden = attrs.lists("doc").has_word("hidden"); match def { Def::Trait(did) | Def::Struct(did) | diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs index 6d2830c5619..172d070c55d 100644 --- a/src/librustdoc/visit_lib.rs +++ b/src/librustdoc/visit_lib.rs @@ -16,7 +16,7 @@ use rustc::ty::Visibility; use std::cell::RefMut; -use clean::{Attributes, Clean}; +use clean::{AttributesExt, NestedAttributesExt}; // FIXME: this may not be exhaustive, but is sufficient for rustdocs current uses @@ -49,10 +49,7 @@ impl<'a, 'b, 'tcx> LibEmbargoVisitor<'a, 'b, 'tcx> { // Updates node level and returns the updated level fn update(&mut self, did: DefId, level: Option) -> Option { - let attrs: Vec<_> = self.cx.tcx().get_attrs(did).iter() - .map(|a| a.clean(self.cx)) - .collect(); - let is_hidden = attrs.list("doc").has_word("hidden"); + let is_hidden = self.cx.tcx().get_attrs(did).lists("doc").has_word("hidden"); let old_level = self.access_levels.map.get(&did).cloned(); // Accessibility levels can only grow From e68ad42dfa94a25a6b1a30bba3bbddb1fde7ba2d Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sun, 20 Nov 2016 03:11:20 +0200 Subject: [PATCH 045/293] rustdoc: sidestep the main pipeline for test collection. --- src/librustdoc/test.rs | 179 ++++++++++++++++++++++------------------- 1 file changed, 96 insertions(+), 83 deletions(-) diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 12d33dcb207..9f29319430d 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::cell::Cell; use std::env; use std::ffi::OsString; use std::io::prelude::*; @@ -23,7 +22,8 @@ use std::sync::{Arc, Mutex}; use testing; use rustc_lint; use rustc::dep_graph::DepGraph; -use rustc::hir::map as hir_map; +use rustc::hir; +use rustc::hir::intravisit; use rustc::session::{self, config}; use rustc::session::config::{OutputType, OutputTypes, Externs}; use rustc::session::search_paths::{SearchPaths, PathKind}; @@ -33,18 +33,15 @@ use rustc_driver::{driver, Compilation}; use rustc_driver::driver::phase_2_configure_and_expand; use rustc_metadata::cstore::CStore; use rustc_resolve::MakeGlobMap; +use rustc_trans::back::link; +use syntax::ast; use syntax::codemap::CodeMap; use syntax::feature_gate::UnstableFeatures; use errors; use errors::emitter::ColorConfig; -use core; -use clean; -use clean::Clean; -use fold::DocFolder; +use clean::Attributes; use html::markdown; -use passes; -use visit_ast::RustdocVisitor; #[derive(Clone, Default)] pub struct TestOptions { @@ -87,48 +84,36 @@ pub fn run(input: &str, config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone())); let krate = panictry!(driver::phase_1_parse_input(&sess, &input)); - let driver::ExpansionResult { defs, mut hir_forest, analysis, .. } = { + let driver::ExpansionResult { defs, mut hir_forest, .. } = { phase_2_configure_and_expand( &sess, &cstore, krate, None, "rustdoc-test", None, MakeGlobMap::No, |_| Ok(()) ).expect("phase_2_configure_and_expand aborted in rustdoc!") }; - let dep_graph = DepGraph::new(false); + let crate_name = crate_name.unwrap_or_else(|| { + link::find_crate_name(None, &hir_forest.krate().attrs, &input) + }); let opts = scrape_test_config(hir_forest.krate()); - let _ignore = dep_graph.in_ignore(); - let map = hir_map::map_crate(&mut hir_forest, defs); - - let ctx = core::DocContext { - map: &map, - maybe_typed: core::NotTyped(&sess), - input: input, - populated_all_crate_impls: Cell::new(false), - external_traits: Default::default(), - deref_trait_did: Cell::new(None), - deref_mut_trait_did: Cell::new(None), - access_levels: Default::default(), - renderinfo: Default::default(), - ty_substs: Default::default(), - lt_substs: Default::default(), - export_map: analysis.export_map, - }; - - let mut v = RustdocVisitor::new(&ctx); - v.visit(ctx.map.krate()); - let mut krate = v.clean(&ctx); - if let Some(name) = crate_name { - krate.name = name; - } - let krate = passes::collapse_docs(krate); - let krate = passes::unindent_comments(krate); - - let mut collector = Collector::new(krate.name.to_string(), + let mut collector = Collector::new(crate_name, cfgs, libs, externs, false, opts); - collector.fold_crate(krate); + + { + let dep_graph = DepGraph::new(false); + let _ignore = dep_graph.in_ignore(); + let map = hir::map::map_crate(&mut hir_forest, defs); + let krate = map.krate(); + let mut hir_collector = HirCollector { + collector: &mut collector, + map: &map + }; + hir_collector.visit_testable("".to_string(), &krate.attrs, |this| { + intravisit::walk_crate(this, krate); + }); + } test_args.insert(0, "rustdoctest".to_string()); @@ -472,56 +457,84 @@ impl Collector { } } -impl DocFolder for Collector { - fn fold_item(&mut self, item: clean::Item) -> Option { - let current_name = match item.name { - Some(ref name) if !name.is_empty() => Some(name.clone()), - _ => typename_if_impl(&item) - }; +struct HirCollector<'a, 'hir: 'a> { + collector: &'a mut Collector, + map: &'a hir::map::Map<'hir> +} - let pushed = current_name.map(|name| self.names.push(name)).is_some(); - - if let Some(doc) = item.doc_value() { - self.cnt = 0; - markdown::find_testable_code(doc, &mut *self); +impl<'a, 'hir> HirCollector<'a, 'hir> { + fn visit_testable(&mut self, + name: String, + attrs: &[ast::Attribute], + nested: F) { + let has_name = !name.is_empty(); + if has_name { + self.collector.names.push(name); } - let ret = self.fold_item_recur(item); - if pushed { - self.names.pop(); + let mut attrs = Attributes::from_ast(attrs); + attrs.collapse_doc_comments(); + attrs.unindent_doc_comments(); + if let Some(doc) = attrs.doc_value() { + self.collector.cnt = 0; + markdown::find_testable_code(doc, self.collector); } - return ret; + nested(self); - // FIXME: it would be better to not have the escaped version in the first place - fn unescape_for_testname(mut s: String) -> String { - // for refs `&foo` - if s.contains("&") { - s = s.replace("&", "&"); - - // `::&'a mut Foo::` looks weird, let's make it `::<&'a mut Foo>`:: - if let Some('&') = s.chars().nth(0) { - s = format!("<{}>", s); - } - } - - // either `<..>` or `->` - if s.contains(">") { - s.replace(">", ">") - .replace("<", "<") - } else { - s - } - } - - fn typename_if_impl(item: &clean::Item) -> Option { - if let clean::ItemEnum::ImplItem(ref impl_) = item.inner { - let path = impl_.for_.to_string(); - let unescaped_path = unescape_for_testname(path); - Some(unescaped_path) - } else { - None - } + if has_name { + self.collector.names.pop(); } } } + +impl<'a, 'hir> intravisit::Visitor<'hir> for HirCollector<'a, 'hir> { + fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'hir>> { + Some(self.map) + } + + fn visit_item(&mut self, item: &'hir hir::Item) { + let name = if let hir::ItemImpl(.., ref ty, _) = item.node { + hir::print::ty_to_string(ty) + } else { + item.name.to_string() + }; + + self.visit_testable(name, &item.attrs, |this| { + intravisit::walk_item(this, item); + }); + } + + fn visit_trait_item(&mut self, item: &'hir hir::TraitItem) { + self.visit_testable(item.name.to_string(), &item.attrs, |this| { + intravisit::walk_trait_item(this, item); + }); + } + + fn visit_impl_item(&mut self, item: &'hir hir::ImplItem) { + self.visit_testable(item.name.to_string(), &item.attrs, |this| { + intravisit::walk_impl_item(this, item); + }); + } + + fn visit_foreign_item(&mut self, item: &'hir hir::ForeignItem) { + self.visit_testable(item.name.to_string(), &item.attrs, |this| { + intravisit::walk_foreign_item(this, item); + }); + } + + fn visit_variant(&mut self, + v: &'hir hir::Variant, + g: &'hir hir::Generics, + item_id: ast::NodeId) { + self.visit_testable(v.node.name.to_string(), &v.node.attrs, |this| { + intravisit::walk_variant(this, v, g, item_id); + }); + } + + fn visit_struct_field(&mut self, f: &'hir hir::StructField) { + self.visit_testable(f.name.to_string(), &f.attrs, |this| { + intravisit::walk_struct_field(this, f); + }); + } +} From 4be778633073cb3b4a036b8ecc469b2892f12367 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sun, 20 Nov 2016 03:42:54 +0200 Subject: [PATCH 046/293] rustdoc: we can now assume DocContext always has a TyCtxt. --- src/librustdoc/clean/inline.rs | 189 +++++++++------------ src/librustdoc/clean/mod.rs | 283 +++++++++++++------------------ src/librustdoc/clean/simplify.rs | 2 +- src/librustdoc/core.rs | 42 +---- src/librustdoc/visit_ast.rs | 30 ++-- src/librustdoc/visit_lib.rs | 2 +- 6 files changed, 220 insertions(+), 328 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index e7575468640..c5562ae3b7f 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -18,7 +18,7 @@ use rustc::hir; use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def_id::DefId; use rustc::hir::print as pprust; -use rustc::ty::{self, TyCtxt}; +use rustc::ty; use rustc::util::nodemap::FxHashSet; use rustc_const_eval::lookup_const_by_id; @@ -43,17 +43,13 @@ use super::Clean; /// of a vector of items if it was successfully expanded. pub fn try_inline(cx: &DocContext, id: ast::NodeId, into: Option) -> Option> { - let tcx = match cx.tcx_opt() { - Some(tcx) => tcx, - None => return None, - }; - let def = match tcx.expect_def_or_none(id) { + let def = match cx.tcx.expect_def_or_none(id) { Some(def) => def, None => return None, }; let did = def.def_id(); if did.is_local() { return None } - try_inline_def(cx, tcx, def).map(|vec| { + try_inline_def(cx, def).map(|vec| { vec.into_iter().map(|mut item| { match into { Some(into) if item.name.is_some() => { @@ -66,39 +62,38 @@ pub fn try_inline(cx: &DocContext, id: ast::NodeId, into: Option) }) } -fn try_inline_def<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, - def: Def) -> Option> { +fn try_inline_def(cx: &DocContext, def: Def) -> Option> { + let tcx = cx.tcx; let mut ret = Vec::new(); - let did = def.def_id(); let inner = match def { Def::Trait(did) => { record_extern_fqn(cx, did, clean::TypeKind::Trait); - ret.extend(build_impls(cx, tcx, did)); - clean::TraitItem(build_external_trait(cx, tcx, did)) + ret.extend(build_impls(cx, did)); + clean::TraitItem(build_external_trait(cx, did)) } Def::Fn(did) => { record_extern_fqn(cx, did, clean::TypeKind::Function); - clean::FunctionItem(build_external_function(cx, tcx, did)) + clean::FunctionItem(build_external_function(cx, did)) } Def::Struct(did) => { record_extern_fqn(cx, did, clean::TypeKind::Struct); - ret.extend(build_impls(cx, tcx, did)); - clean::StructItem(build_struct(cx, tcx, did)) + ret.extend(build_impls(cx, did)); + clean::StructItem(build_struct(cx, did)) } Def::Union(did) => { record_extern_fqn(cx, did, clean::TypeKind::Union); - ret.extend(build_impls(cx, tcx, did)); - clean::UnionItem(build_union(cx, tcx, did)) + ret.extend(build_impls(cx, did)); + clean::UnionItem(build_union(cx, did)) } Def::TyAlias(did) => { record_extern_fqn(cx, did, clean::TypeKind::Typedef); - ret.extend(build_impls(cx, tcx, did)); - clean::TypedefItem(build_type_alias(cx, tcx, did), false) + ret.extend(build_impls(cx, did)); + clean::TypedefItem(build_type_alias(cx, did), false) } Def::Enum(did) => { record_extern_fqn(cx, did, clean::TypeKind::Enum); - ret.extend(build_impls(cx, tcx, did)); - clean::EnumItem(build_enum(cx, tcx, did)) + ret.extend(build_impls(cx, did)); + clean::EnumItem(build_enum(cx, did)) } // Assume that the enum type is reexported next to the variant, and // variants don't show up in documentation specially. @@ -108,23 +103,24 @@ fn try_inline_def<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, Def::StructCtor(..) => return Some(Vec::new()), Def::Mod(did) => { record_extern_fqn(cx, did, clean::TypeKind::Module); - clean::ModuleItem(build_module(cx, tcx, did)) + clean::ModuleItem(build_module(cx, did)) } Def::Static(did, mtbl) => { record_extern_fqn(cx, did, clean::TypeKind::Static); - clean::StaticItem(build_static(cx, tcx, did, mtbl)) + clean::StaticItem(build_static(cx, did, mtbl)) } Def::Const(did) => { record_extern_fqn(cx, did, clean::TypeKind::Const); - clean::ConstantItem(build_const(cx, tcx, did)) + clean::ConstantItem(build_const(cx, did)) } _ => return None, }; + let did = def.def_id(); cx.renderinfo.borrow_mut().inlined.insert(did); ret.push(clean::Item { source: clean::Span::empty(), name: Some(tcx.item_name(did).to_string()), - attrs: load_attrs(cx, tcx, did), + attrs: load_attrs(cx, did), inner: inner, visibility: Some(clean::Public), stability: tcx.lookup_stability(did).clean(cx), @@ -134,9 +130,8 @@ fn try_inline_def<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, Some(ret) } -pub fn load_attrs<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, - did: DefId) -> clean::Attributes { - tcx.get_attrs(did).clean(cx) +pub fn load_attrs(cx: &DocContext, did: DefId) -> clean::Attributes { + cx.tcx.get_attrs(did).clean(cx) } /// Record an external fully qualified name in the external_paths cache. @@ -144,27 +139,24 @@ pub fn load_attrs<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, /// These names are used later on by HTML rendering to generate things like /// source links back to the original item. pub fn record_extern_fqn(cx: &DocContext, did: DefId, kind: clean::TypeKind) { - if let Some(tcx) = cx.tcx_opt() { - let crate_name = tcx.sess.cstore.crate_name(did.krate).to_string(); - let relative = tcx.def_path(did).data.into_iter().filter_map(|elem| { - // extern blocks have an empty name - let s = elem.data.to_string(); - if !s.is_empty() { - Some(s) - } else { - None - } - }); - let fqn = once(crate_name).chain(relative).collect(); - cx.renderinfo.borrow_mut().external_paths.insert(did, (fqn, kind)); - } + let crate_name = cx.tcx.sess.cstore.crate_name(did.krate).to_string(); + let relative = cx.tcx.def_path(did).data.into_iter().filter_map(|elem| { + // extern blocks have an empty name + let s = elem.data.to_string(); + if !s.is_empty() { + Some(s) + } else { + None + } + }); + let fqn = once(crate_name).chain(relative).collect(); + cx.renderinfo.borrow_mut().external_paths.insert(did, (fqn, kind)); } -pub fn build_external_trait<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, - did: DefId) -> clean::Trait { - let def = tcx.lookup_trait_def(did); - let trait_items = tcx.associated_items(did).map(|item| item.clean(cx)).collect(); - let predicates = tcx.item_predicates(did); +pub fn build_external_trait(cx: &DocContext, did: DefId) -> clean::Trait { + let def = cx.tcx.lookup_trait_def(did); + let trait_items = cx.tcx.associated_items(did).map(|item| item.clean(cx)).collect(); + let predicates = cx.tcx.item_predicates(did); let generics = (def.generics, &predicates).clean(cx); let generics = filter_non_trait_generics(did, generics); let (generics, supertrait_bounds) = separate_supertrait_bounds(generics); @@ -176,45 +168,42 @@ pub fn build_external_trait<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tc } } -fn build_external_function<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, - did: DefId) -> clean::Function { - let ty = tcx.item_type(did); +fn build_external_function(cx: &DocContext, did: DefId) -> clean::Function { + let ty = cx.tcx.item_type(did); let (decl, style, abi) = match ty.sty { ty::TyFnDef(.., ref f) => ((did, &f.sig).clean(cx), f.unsafety, f.abi), _ => panic!("bad function"), }; - let constness = if tcx.sess.cstore.is_const_fn(did) { + let constness = if cx.tcx.sess.cstore.is_const_fn(did) { hir::Constness::Const } else { hir::Constness::NotConst }; - let predicates = tcx.item_predicates(did); + let predicates = cx.tcx.item_predicates(did); clean::Function { decl: decl, - generics: (tcx.item_generics(did), &predicates).clean(cx), + generics: (cx.tcx.item_generics(did), &predicates).clean(cx), unsafety: style, constness: constness, abi: abi, } } -fn build_enum<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, - did: DefId) -> clean::Enum { - let predicates = tcx.item_predicates(did); +fn build_enum(cx: &DocContext, did: DefId) -> clean::Enum { + let predicates = cx.tcx.item_predicates(did); clean::Enum { - generics: (tcx.item_generics(did), &predicates).clean(cx), + generics: (cx.tcx.item_generics(did), &predicates).clean(cx), variants_stripped: false, - variants: tcx.lookup_adt_def(did).variants.clean(cx), + variants: cx.tcx.lookup_adt_def(did).variants.clean(cx), } } -fn build_struct<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, - did: DefId) -> clean::Struct { - let predicates = tcx.item_predicates(did); - let variant = tcx.lookup_adt_def(did).struct_variant(); +fn build_struct(cx: &DocContext, did: DefId) -> clean::Struct { + let predicates = cx.tcx.item_predicates(did); + let variant = cx.tcx.lookup_adt_def(did).struct_variant(); clean::Struct { struct_type: match variant.ctor_kind { @@ -222,44 +211,41 @@ fn build_struct<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, CtorKind::Fn => doctree::Tuple, CtorKind::Const => doctree::Unit, }, - generics: (tcx.item_generics(did), &predicates).clean(cx), + generics: (cx.tcx.item_generics(did), &predicates).clean(cx), fields: variant.fields.clean(cx), fields_stripped: false, } } -fn build_union<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, - did: DefId) -> clean::Union { - let predicates = tcx.item_predicates(did); - let variant = tcx.lookup_adt_def(did).struct_variant(); +fn build_union(cx: &DocContext, did: DefId) -> clean::Union { + let predicates = cx.tcx.item_predicates(did); + let variant = cx.tcx.lookup_adt_def(did).struct_variant(); clean::Union { struct_type: doctree::Plain, - generics: (tcx.item_generics(did), &predicates).clean(cx), + generics: (cx.tcx.item_generics(did), &predicates).clean(cx), fields: variant.fields.clean(cx), fields_stripped: false, } } -fn build_type_alias<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, - did: DefId) -> clean::Typedef { - let predicates = tcx.item_predicates(did); +fn build_type_alias(cx: &DocContext, did: DefId) -> clean::Typedef { + let predicates = cx.tcx.item_predicates(did); clean::Typedef { - type_: tcx.item_type(did).clean(cx), - generics: (tcx.item_generics(did), &predicates).clean(cx), + type_: cx.tcx.item_type(did).clean(cx), + generics: (cx.tcx.item_generics(did), &predicates).clean(cx), } } -pub fn build_impls<'a, 'tcx>(cx: &DocContext, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - did: DefId) -> Vec { +pub fn build_impls(cx: &DocContext, did: DefId) -> Vec { + let tcx = cx.tcx; tcx.populate_inherent_implementations_for_type_if_necessary(did); let mut impls = Vec::new(); if let Some(i) = tcx.inherent_impls.borrow().get(&did) { for &did in i.iter() { - build_impl(cx, tcx, did, &mut impls); + build_impl(cx, did, &mut impls); } } // If this is the first time we've inlined something from another crate, then @@ -277,7 +263,7 @@ pub fn build_impls<'a, 'tcx>(cx: &DocContext, cx.populated_all_crate_impls.set(true); for did in tcx.sess.cstore.implementations_of_trait(None) { - build_impl(cx, tcx, did, &mut impls); + build_impl(cx, did, &mut impls); } // Also try to inline primitive impls from other crates. @@ -303,22 +289,20 @@ pub fn build_impls<'a, 'tcx>(cx: &DocContext, for def_id in primitive_impls.iter().filter_map(|&def_id| def_id) { if !def_id.is_local() { - build_impl(cx, tcx, def_id, &mut impls); + build_impl(cx, def_id, &mut impls); } } impls } -pub fn build_impl<'a, 'tcx>(cx: &DocContext, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - did: DefId, - ret: &mut Vec) { +pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { if !cx.renderinfo.borrow_mut().inlined.insert(did) { return } - let attrs = load_attrs(cx, tcx, did); + let attrs = load_attrs(cx, did); + let tcx = cx.tcx; let associated_trait = tcx.impl_trait_ref(did); // Only inline impl if the implemented trait is @@ -440,15 +424,15 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, clean::RegionBound(..) => unreachable!(), } }); - if trait_.def_id() == cx.deref_trait_did.get() { + if trait_.def_id() == tcx.lang_items.deref_trait() { super::build_deref_target_impls(cx, &trait_items, ret); } let provided = trait_.def_id().map(|did| { - cx.tcx().provided_trait_methods(did) - .into_iter() - .map(|meth| meth.name.to_string()) - .collect() + tcx.provided_trait_methods(did) + .into_iter() + .map(|meth| meth.name.to_string()) + .collect() }).unwrap_or(FxHashSet()); ret.push(clean::Item { @@ -471,26 +455,24 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, }); } -fn build_module<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, - did: DefId) -> clean::Module { +fn build_module(cx: &DocContext, did: DefId) -> clean::Module { let mut items = Vec::new(); - fill_in(cx, tcx, did, &mut items); + fill_in(cx, did, &mut items); return clean::Module { items: items, is_crate: false, }; - fn fill_in<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, - did: DefId, items: &mut Vec) { + fn fill_in(cx: &DocContext, did: DefId, items: &mut Vec) { // If we're reexporting a reexport it may actually reexport something in // two namespaces, so the target may be listed twice. Make sure we only // visit each node at most once. let mut visited = FxHashSet(); - for item in tcx.sess.cstore.item_children(did) { + for item in cx.tcx.sess.cstore.item_children(did) { let def_id = item.def.def_id(); - if tcx.sess.cstore.visibility(def_id) == ty::Visibility::Public { + if cx.tcx.sess.cstore.visibility(def_id) == ty::Visibility::Public { if !visited.insert(def_id) { continue } - if let Some(i) = try_inline_def(cx, tcx, item.def) { + if let Some(i) = try_inline_def(cx, item.def) { items.extend(i) } } @@ -498,9 +480,8 @@ fn build_module<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -fn build_const<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, - did: DefId) -> clean::Constant { - let (expr, ty) = lookup_const_by_id(tcx, did, None).unwrap_or_else(|| { +fn build_const(cx: &DocContext, did: DefId) -> clean::Constant { + let (expr, ty) = lookup_const_by_id(cx.tcx, did, None).unwrap_or_else(|| { panic!("expected lookup_const_by_id to succeed for {:?}", did); }); debug!("converting constant expr {:?} to snippet", expr); @@ -508,16 +489,14 @@ fn build_const<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("got snippet {}", sn); clean::Constant { - type_: ty.map(|t| t.clean(cx)).unwrap_or_else(|| tcx.item_type(did).clean(cx)), + type_: ty.map(|t| t.clean(cx)).unwrap_or_else(|| cx.tcx.item_type(did).clean(cx)), expr: sn } } -fn build_static<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, - did: DefId, - mutable: bool) -> clean::Static { +fn build_static(cx: &DocContext, did: DefId, mutable: bool) -> clean::Static { clean::Static { - type_: tcx.item_type(did).clean(cx), + type_: cx.tcx.item_type(did).clean(cx), mutability: if mutable {clean::Mutable} else {clean::Immutable}, expr: "\n\n\n".to_string(), // trigger the "[definition]" links } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 18cb9630f49..a19ec4e8b5e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -58,11 +58,11 @@ mod simplify; // extract the stability index for a node from tcx, if possible fn get_stability(cx: &DocContext, def_id: DefId) -> Option { - cx.tcx_opt().and_then(|tcx| tcx.lookup_stability(def_id)).clean(cx) + cx.tcx.lookup_stability(def_id).clean(cx) } fn get_deprecation(cx: &DocContext, def_id: DefId) -> Option { - cx.tcx_opt().and_then(|tcx| tcx.lookup_deprecation(def_id)).clean(cx) + cx.tcx.lookup_deprecation(def_id).clean(cx) } pub trait Clean { @@ -125,20 +125,17 @@ impl<'a, 'tcx> Clean for visit_ast::RustdocVisitor<'a, 'tcx> { use rustc::session::config::Input; use ::visit_lib::LibEmbargoVisitor; - if let Some(t) = cx.tcx_opt() { - cx.deref_trait_did.set(t.lang_items.deref_trait()); - cx.renderinfo.borrow_mut().deref_trait_did = cx.deref_trait_did.get(); - cx.deref_mut_trait_did.set(t.lang_items.deref_mut_trait()); - cx.renderinfo.borrow_mut().deref_mut_trait_did = cx.deref_mut_trait_did.get(); + { + let mut r = cx.renderinfo.borrow_mut(); + r.deref_trait_did = cx.tcx.lang_items.deref_trait(); + r.deref_mut_trait_did = cx.tcx.lang_items.deref_mut_trait(); } let mut externs = Vec::new(); for cnum in cx.sess().cstore.crates() { externs.push((cnum, CrateNum(cnum).clean(cx))); - if cx.tcx_opt().is_some() { - // Analyze doc-reachability for extern items - LibEmbargoVisitor::new(cx).visit_lib(cnum); - } + // Analyze doc-reachability for extern items + LibEmbargoVisitor::new(cx).visit_lib(cnum); } externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b)); @@ -234,12 +231,10 @@ impl Clean for CrateNum { fn clean(&self, cx: &DocContext) -> ExternalCrate { let mut primitives = Vec::new(); let root = DefId { krate: self.0, index: CRATE_DEF_INDEX }; - cx.tcx_opt().map(|tcx| { - for item in tcx.sess.cstore.item_children(root) { - let attrs = inline::load_attrs(cx, tcx, item.def.def_id()); - PrimitiveType::find(&attrs).map(|prim| primitives.push(prim)); - } - }); + for item in cx.tcx.sess.cstore.item_children(root) { + let attrs = inline::load_attrs(cx, item.def.def_id()); + PrimitiveType::find(&attrs).map(|prim| primitives.push(prim)); + } ExternalCrate { name: cx.sess().cstore.crate_name(self.0).to_string(), attrs: cx.sess().cstore.item_attrs(root).clean(cx), @@ -449,7 +444,7 @@ impl Clean for doctree::Module { visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), - def_id: cx.map.local_def_id(self.id), + def_id: cx.tcx.map.local_def_id(self.id), inner: ModuleItem(Module { is_crate: self.is_crate, items: items @@ -571,7 +566,7 @@ impl Clean for hir::TyParam { fn clean(&self, cx: &DocContext) -> TyParam { TyParam { name: self.name.clean(cx), - did: cx.map.local_def_id(self.id), + did: cx.tcx.map.local_def_id(self.id), bounds: self.bounds.clean(cx), default: self.default.clean(cx), } @@ -608,11 +603,9 @@ impl TyParamBound { fn is_sized_bound(&self, cx: &DocContext) -> bool { use rustc::hir::TraitBoundModifier as TBM; - if let Some(tcx) = cx.tcx_opt() { - if let TyParamBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self { - if trait_.def_id() == tcx.lang_items.sized_trait() { - return true; - } + if let TyParamBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self { + if trait_.def_id() == cx.tcx.lang_items.sized_trait() { + return true; } } false @@ -633,9 +626,9 @@ fn external_path_params(cx: &DocContext, trait_did: Option, has_self: boo let lifetimes = substs.regions().filter_map(|v| v.clean(cx)).collect(); let types = substs.types().skip(has_self as usize).collect::>(); - match (trait_did, cx.tcx_opt()) { + match trait_did { // Attempt to sugar an external path like Fn<(A, B,), C> to Fn(A, B) -> C - (Some(did), Some(ref tcx)) if tcx.lang_items.fn_trait_kind(did).is_some() => { + Some(did) if cx.tcx.lang_items.fn_trait_kind(did).is_some() => { assert_eq!(types.len(), 1); let inputs = match types[0].sty { ty::TyTuple(ref tys) => tys.iter().map(|t| t.clean(cx)).collect(), @@ -658,7 +651,7 @@ fn external_path_params(cx: &DocContext, trait_did: Option, has_self: boo output: output } }, - (..) => { + _ => { PathParameters::AngleBracketed { lifetimes: lifetimes, types: types.clean(cx), @@ -683,10 +676,7 @@ fn external_path(cx: &DocContext, name: &str, trait_did: Option, has_self impl Clean for ty::BuiltinBound { fn clean(&self, cx: &DocContext) -> TyParamBound { - let tcx = match cx.tcx_opt() { - Some(tcx) => tcx, - None => return RegionBound(Lifetime::statik()) - }; + let tcx = cx.tcx; let empty = tcx.intern_substs(&[]); let (did, path) = match *self { ty::BoundSend => @@ -717,12 +707,8 @@ impl Clean for ty::BuiltinBound { impl<'tcx> Clean for ty::TraitRef<'tcx> { fn clean(&self, cx: &DocContext) -> TyParamBound { - let tcx = match cx.tcx_opt() { - Some(tcx) => tcx, - None => return RegionBound(Lifetime::statik()) - }; inline::record_extern_fqn(cx, self.def_id, TypeKind::Trait); - let path = external_path(cx, &tcx.item_name(self.def_id).as_str(), + let path = external_path(cx, &cx.tcx.item_name(self.def_id).as_str(), Some(self.def_id), true, vec![], self.substs); debug!("ty::TraitRef\n subst: {:?}\n", self.substs); @@ -789,18 +775,16 @@ impl Lifetime { impl Clean for hir::Lifetime { fn clean(&self, cx: &DocContext) -> Lifetime { - if let Some(tcx) = cx.tcx_opt() { - let def = tcx.named_region_map.defs.get(&self.id).cloned(); - match def { - Some(DefEarlyBoundRegion(_, node_id)) | - Some(DefLateBoundRegion(_, node_id)) | - Some(DefFreeRegion(_, node_id)) => { - if let Some(lt) = cx.lt_substs.borrow().get(&node_id).cloned() { - return lt; - } + let def = cx.tcx.named_region_map.defs.get(&self.id).cloned(); + match def { + Some(DefEarlyBoundRegion(_, node_id)) | + Some(DefLateBoundRegion(_, node_id)) | + Some(DefFreeRegion(_, node_id)) => { + if let Some(lt) = cx.lt_substs.borrow().get(&node_id).cloned() { + return lt; } - _ => {} } + _ => {} } Lifetime(self.name.to_string()) } @@ -1122,7 +1106,7 @@ impl Clean for doctree::Function { visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), - def_id: cx.map.local_def_id(self.id), + def_id: cx.tcx.map.local_def_id(self.id), inner: FunctionItem(Function { decl: self.decl.clean(cx), generics: self.generics.clean(cx), @@ -1173,10 +1157,10 @@ impl Clean for hir::FnDecl { impl<'a, 'tcx> Clean for (DefId, &'a ty::PolyFnSig<'tcx>) { fn clean(&self, cx: &DocContext) -> FnDecl { let (did, sig) = *self; - let mut names = if cx.map.as_local_node_id(did).is_some() { + let mut names = if cx.tcx.map.as_local_node_id(did).is_some() { vec![].into_iter() } else { - cx.tcx().sess.cstore.fn_arg_names(did).into_iter() + cx.tcx.sess.cstore.fn_arg_names(did).into_iter() }.peekable(); FnDecl { output: Return(sig.0.output.clean(cx)), @@ -1264,7 +1248,7 @@ impl Clean for doctree::Trait { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - def_id: cx.map.local_def_id(self.id), + def_id: cx.tcx.map.local_def_id(self.id), visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), @@ -1314,10 +1298,10 @@ impl Clean for hir::TraitItem { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.span.clean(cx), - def_id: cx.map.local_def_id(self.id), + def_id: cx.tcx.map.local_def_id(self.id), visibility: None, - stability: get_stability(cx, cx.map.local_def_id(self.id)), - deprecation: get_deprecation(cx, cx.map.local_def_id(self.id)), + stability: get_stability(cx, cx.tcx.map.local_def_id(self.id)), + deprecation: get_deprecation(cx, cx.tcx.map.local_def_id(self.id)), inner: inner } } @@ -1346,10 +1330,10 @@ impl Clean for hir::ImplItem { name: Some(self.name.clean(cx)), source: self.span.clean(cx), attrs: self.attrs.clean(cx), - def_id: cx.map.local_def_id(self.id), + def_id: cx.tcx.map.local_def_id(self.id), visibility: self.vis.clean(cx), - stability: get_stability(cx, cx.map.local_def_id(self.id)), - deprecation: get_deprecation(cx, cx.map.local_def_id(self.id)), + stability: get_stability(cx, cx.tcx.map.local_def_id(self.id)), + deprecation: get_deprecation(cx, cx.tcx.map.local_def_id(self.id)), inner: inner } } @@ -1359,13 +1343,13 @@ impl<'tcx> Clean for ty::AssociatedItem { fn clean(&self, cx: &DocContext) -> Item { let inner = match self.kind { ty::AssociatedKind::Const => { - let ty = cx.tcx().item_type(self.def_id); + let ty = cx.tcx.item_type(self.def_id); AssociatedConstItem(ty.clean(cx), None) } ty::AssociatedKind::Method => { - let generics = (cx.tcx().item_generics(self.def_id), - &cx.tcx().item_predicates(self.def_id)).clean(cx); - let fty = match cx.tcx().item_type(self.def_id).sty { + let generics = (cx.tcx.item_generics(self.def_id), + &cx.tcx.item_predicates(self.def_id)).clean(cx); + let fty = match cx.tcx.item_type(self.def_id).sty { ty::TyFnDef(_, _, f) => f, _ => unreachable!() }; @@ -1374,9 +1358,9 @@ impl<'tcx> Clean for ty::AssociatedItem { if self.method_has_self_argument { let self_ty = match self.container { ty::ImplContainer(def_id) => { - cx.tcx().item_type(def_id) + cx.tcx.item_type(def_id) } - ty::TraitContainer(_) => cx.tcx().mk_self_type() + ty::TraitContainer(_) => cx.tcx.mk_self_type() }; let self_arg_ty = *fty.sig.input(0).skip_binder(); if self_arg_ty == self_ty { @@ -1422,8 +1406,8 @@ impl<'tcx> Clean for ty::AssociatedItem { // are actually located on the trait/impl itself, so we need to load // all of the generics from there and then look for bounds that are // applied to this associated type in question. - let def = cx.tcx().lookup_trait_def(did); - let predicates = cx.tcx().item_predicates(did); + let def = cx.tcx.lookup_trait_def(did); + let predicates = cx.tcx.item_predicates(did); let generics = (def.generics, &predicates).clean(cx); generics.where_predicates.iter().filter_map(|pred| { let (name, self_type, trait_, bounds) = match *pred { @@ -1459,7 +1443,7 @@ impl<'tcx> Clean for ty::AssociatedItem { } let ty = if self.defaultness.has_value() { - Some(cx.tcx().item_type(self.def_id)) + Some(cx.tcx.item_type(self.def_id)) } else { None }; @@ -1474,7 +1458,7 @@ impl<'tcx> Clean for ty::AssociatedItem { stability: get_stability(cx, self.def_id), deprecation: get_deprecation(cx, self.def_id), def_id: self.def_id, - attrs: inline::load_attrs(cx, cx.tcx(), self.def_id), + attrs: inline::load_attrs(cx, self.def_id), source: Span::empty(), inner: inner, } @@ -1727,53 +1711,44 @@ impl Clean for hir::Ty { type_: box m.ty.clean(cx)}, TySlice(ref ty) => Vector(box ty.clean(cx)), TyArray(ref ty, ref e) => { - let n = if let Some(tcx) = cx.tcx_opt() { - use rustc_const_math::{ConstInt, ConstUsize}; - use rustc_const_eval::eval_const_expr; - use rustc::middle::const_val::ConstVal; - match eval_const_expr(tcx, e) { - ConstVal::Integral(ConstInt::Usize(u)) => match u { - ConstUsize::Us16(u) => u.to_string(), - ConstUsize::Us32(u) => u.to_string(), - ConstUsize::Us64(u) => u.to_string(), - }, - // after type checking this can't fail - _ => unreachable!(), - } - } else { - pprust::expr_to_string(e) + use rustc_const_math::{ConstInt, ConstUsize}; + use rustc_const_eval::eval_const_expr; + use rustc::middle::const_val::ConstVal; + + let n = match eval_const_expr(cx.tcx, e) { + ConstVal::Integral(ConstInt::Usize(u)) => match u { + ConstUsize::Us16(u) => u.to_string(), + ConstUsize::Us32(u) => u.to_string(), + ConstUsize::Us64(u) => u.to_string(), + }, + // after type checking this can't fail + _ => unreachable!(), }; FixedVector(box ty.clean(cx), n) }, TyTup(ref tys) => Tuple(tys.clean(cx)), TyPath(None, ref path) => { - let tcx_and_def = cx.tcx_opt().map(|tcx| (tcx, tcx.expect_def(self.id))); - if let Some((_, def)) = tcx_and_def { - if let Some(new_ty) = cx.ty_substs.borrow().get(&def).cloned() { - return new_ty; - } + let def = cx.tcx.expect_def(self.id); + if let Some(new_ty) = cx.ty_substs.borrow().get(&def).cloned() { + return new_ty; } - let tcx_and_alias = tcx_and_def.and_then(|(tcx, def)| { - if let Def::TyAlias(def_id) = def { - // Substitute private type aliases - tcx.map.as_local_node_id(def_id).and_then(|node_id| { - if !cx.access_levels.borrow().is_exported(def_id) { - Some((tcx, &tcx.map.expect_item(node_id).node)) - } else { - None - } - }) - } else { - None + let mut alias = None; + if let Def::TyAlias(def_id) = def { + // Substitute private type aliases + if let Some(node_id) = cx.tcx.map.as_local_node_id(def_id) { + if !cx.access_levels.borrow().is_exported(def_id) { + alias = Some(&cx.tcx.map.expect_item(node_id).node); + } } - }); - if let Some((tcx, &hir::ItemTy(ref ty, ref generics))) = tcx_and_alias { + }; + + if let Some(&hir::ItemTy(ref ty, ref generics)) = alias { let provided_params = &path.segments.last().unwrap().parameters; let mut ty_substs = FxHashMap(); let mut lt_substs = FxHashMap(); for (i, ty_param) in generics.ty_params.iter().enumerate() { - let ty_param_def = tcx.expect_def(ty_param.id); + let ty_param_def = cx.tcx.expect_def(ty_param.id); if let Some(ty) = provided_params.types().get(i).cloned() .cloned() { ty_substs.insert(ty_param_def, ty.unwrap().clean(cx)); @@ -1841,9 +1816,7 @@ impl<'tcx> Clean for ty::Ty<'tcx> { ty::TyFloat(float_ty) => Primitive(float_ty.into()), ty::TyStr => Primitive(PrimitiveType::Str), ty::TyBox(t) => { - let box_did = cx.tcx_opt().and_then(|tcx| { - tcx.lang_items.owned_box() - }); + let box_did = cx.tcx.lang_items.owned_box(); lang_struct(cx, box_did, t, "Box", Unique) } ty::TySlice(ty) => Vector(box ty.clean(cx)), @@ -1863,7 +1836,7 @@ impl<'tcx> Clean for ty::Ty<'tcx> { type_params: Vec::new(), where_predicates: Vec::new() }, - decl: (cx.map.local_def_id(ast::CRATE_NODE_ID), &fty.sig).clean(cx), + decl: (cx.tcx.map.local_def_id(ast::CRATE_NODE_ID), &fty.sig).clean(cx), abi: fty.abi, }), ty::TyAdt(def, substs) => { @@ -1874,7 +1847,7 @@ impl<'tcx> Clean for ty::Ty<'tcx> { AdtKind::Enum => TypeKind::Enum, }; inline::record_extern_fqn(cx, did, kind); - let path = external_path(cx, &cx.tcx().item_name(did).as_str(), + let path = external_path(cx, &cx.tcx.item_name(did).as_str(), None, false, vec![], substs); ResolvedPath { path: path, @@ -1901,7 +1874,7 @@ impl<'tcx> Clean for ty::Ty<'tcx> { }); } - let path = external_path(cx, &cx.tcx().item_name(did).as_str(), + let path = external_path(cx, &cx.tcx.item_name(did).as_str(), Some(did), false, bindings, obj.principal.0.substs); ResolvedPath { path: path, @@ -1919,9 +1892,9 @@ impl<'tcx> Clean for ty::Ty<'tcx> { ty::TyAnon(def_id, substs) => { // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, // by looking up the projections associated with the def_id. - let item_predicates = cx.tcx().item_predicates(def_id); - let substs = cx.tcx().lift(&substs).unwrap(); - let bounds = item_predicates.instantiate(cx.tcx(), substs); + let item_predicates = cx.tcx.item_predicates(def_id); + let substs = cx.tcx.lift(&substs).unwrap(); + let bounds = item_predicates.instantiate(cx.tcx, substs); ImplTrait(bounds.predicates.into_iter().filter_map(|predicate| { predicate.to_opt_poly_trait_ref().clean(cx) }).collect()) @@ -1942,9 +1915,9 @@ impl Clean for hir::StructField { attrs: self.attrs.clean(cx), source: self.span.clean(cx), visibility: self.vis.clean(cx), - stability: get_stability(cx, cx.map.local_def_id(self.id)), - deprecation: get_deprecation(cx, cx.map.local_def_id(self.id)), - def_id: cx.map.local_def_id(self.id), + stability: get_stability(cx, cx.tcx.map.local_def_id(self.id)), + deprecation: get_deprecation(cx, cx.tcx.map.local_def_id(self.id)), + def_id: cx.tcx.map.local_def_id(self.id), inner: StructFieldItem(self.ty.clean(cx)), } } @@ -1954,7 +1927,7 @@ impl<'tcx> Clean for ty::FieldDefData<'tcx, 'static> { fn clean(&self, cx: &DocContext) -> Item { Item { name: Some(self.name).clean(cx), - attrs: cx.tcx().get_attrs(self.did).clean(cx), + attrs: cx.tcx.get_attrs(self.did).clean(cx), source: Span::empty(), visibility: self.vis.clean(cx), stability: get_stability(cx, self.did), @@ -2005,7 +1978,7 @@ impl Clean for doctree::Struct { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - def_id: cx.map.local_def_id(self.id), + def_id: cx.tcx.map.local_def_id(self.id), visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), @@ -2025,7 +1998,7 @@ impl Clean for doctree::Union { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - def_id: cx.map.local_def_id(self.id), + def_id: cx.tcx.map.local_def_id(self.id), visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), @@ -2072,7 +2045,7 @@ impl Clean for doctree::Enum { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - def_id: cx.map.local_def_id(self.id), + def_id: cx.tcx.map.local_def_id(self.id), visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), @@ -2099,7 +2072,7 @@ impl Clean for doctree::Variant { visibility: None, stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), - def_id: cx.map.local_def_id(self.def.id()), + def_id: cx.tcx.map.local_def_id(self.def.id()), inner: VariantItem(Variant { kind: self.def.clean(cx), }), @@ -2124,7 +2097,7 @@ impl<'tcx> Clean for ty::VariantDefData<'tcx, 'static> { Item { source: Span::empty(), name: Some(field.name.clean(cx)), - attrs: cx.tcx().get_attrs(field.did).clean(cx), + attrs: cx.tcx.get_attrs(field.did).clean(cx), visibility: field.vis.clean(cx), def_id: field.did, stability: get_stability(cx, field.did), @@ -2137,7 +2110,7 @@ impl<'tcx> Clean for ty::VariantDefData<'tcx, 'static> { }; Item { name: Some(self.name.clean(cx)), - attrs: inline::load_attrs(cx, cx.tcx(), self.did), + attrs: inline::load_attrs(cx, self.did), source: Span::empty(), visibility: Some(Inherited), def_id: self.did, @@ -2322,7 +2295,7 @@ impl Clean for doctree::Typedef { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - def_id: cx.map.local_def_id(self.id.clone()), + def_id: cx.tcx.map.local_def_id(self.id.clone()), visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), @@ -2374,7 +2347,7 @@ impl Clean for doctree::Static { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - def_id: cx.map.local_def_id(self.id), + def_id: cx.tcx.map.local_def_id(self.id), visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), @@ -2399,7 +2372,7 @@ impl Clean for doctree::Constant { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - def_id: cx.map.local_def_id(self.id), + def_id: cx.tcx.map.local_def_id(self.id), visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), @@ -2460,24 +2433,22 @@ impl Clean> for doctree::Impl { // If this impl block is an implementation of the Deref trait, then we // need to try inlining the target's inherent impl blocks as well. - if trait_.def_id() == cx.deref_trait_did.get() { + if trait_.def_id() == cx.tcx.lang_items.deref_trait() { build_deref_target_impls(cx, &items, &mut ret); } - let provided = trait_.def_id().and_then(|did| { - cx.tcx_opt().map(|tcx| { - tcx.provided_trait_methods(did) - .into_iter() - .map(|meth| meth.name.to_string()) - .collect() - }) + let provided = trait_.def_id().map(|did| { + cx.tcx.provided_trait_methods(did) + .into_iter() + .map(|meth| meth.name.to_string()) + .collect() }).unwrap_or(FxHashSet()); ret.push(Item { name: None, attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - def_id: cx.map.local_def_id(self.id), + def_id: cx.tcx.map.local_def_id(self.id), visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), @@ -2498,10 +2469,7 @@ impl Clean> for doctree::Impl { fn build_deref_target_impls(cx: &DocContext, items: &[Item], ret: &mut Vec) { - let tcx = match cx.tcx_opt() { - Some(t) => t, - None => return, - }; + let tcx = cx.tcx; for item in items { let target = match item.inner { @@ -2511,7 +2479,7 @@ fn build_deref_target_impls(cx: &DocContext, let primitive = match *target { ResolvedPath { did, .. } if did.is_local() => continue, ResolvedPath { did, .. } => { - ret.extend(inline::build_impls(cx, tcx, did)); + ret.extend(inline::build_impls(cx, did)); continue } _ => match target.primitive_type() { @@ -2542,7 +2510,7 @@ fn build_deref_target_impls(cx: &DocContext, }; if let Some(did) = did { if !did.is_local() { - inline::build_impl(cx, tcx, did, ret); + inline::build_impl(cx, did, ret); } } } @@ -2560,7 +2528,7 @@ impl Clean for doctree::DefaultImpl { name: None, attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - def_id: cx.map.local_def_id(self.id), + def_id: cx.tcx.map.local_def_id(self.id), visibility: Some(Public), stability: None, deprecation: None, @@ -2644,7 +2612,7 @@ impl Clean> for doctree::Import { name: None, attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - def_id: cx.map.local_def_id(ast::CRATE_NODE_ID), + def_id: cx.tcx.map.local_def_id(ast::CRATE_NODE_ID), visibility: self.vis.clean(cx), stability: None, deprecation: None, @@ -2723,10 +2691,10 @@ impl Clean for hir::ForeignItem { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.span.clean(cx), - def_id: cx.map.local_def_id(self.id), + def_id: cx.tcx.map.local_def_id(self.id), visibility: self.vis.clean(cx), - stability: get_stability(cx, cx.map.local_def_id(self.id)), - deprecation: get_deprecation(cx, cx.map.local_def_id(self.id)), + stability: get_stability(cx, cx.tcx.map.local_def_id(self.id)), + deprecation: get_deprecation(cx, cx.tcx.map.local_def_id(self.id)), inner: inner, } } @@ -2793,22 +2761,7 @@ fn resolve_type(cx: &DocContext, path: Path, id: ast::NodeId) -> Type { debug!("resolve_type({:?},{:?})", path, id); - let tcx = match cx.tcx_opt() { - Some(tcx) => tcx, - // If we're extracting tests, this return value's accuracy is not - // important, all we want is a string representation to help people - // figure out what doctests are failing. - None => { - let did = DefId::local(DefIndex::from_u32(0)); - return ResolvedPath { - path: path, - typarams: None, - did: did, - is_generic: false - }; - } - }; - let def = tcx.expect_def(id); + let def = cx.tcx.expect_def(id); debug!("resolve_type: def={:?}", def); let is_generic = match def { @@ -2833,8 +2786,6 @@ fn resolve_type(cx: &DocContext, fn register_def(cx: &DocContext, def: Def) -> DefId { debug!("register_def({:?})", def); - let tcx = cx.tcx(); - let (did, kind) = match def { Def::Fn(i) => (i, TypeKind::Function), Def::TyAlias(i) => (i, TypeKind::Typedef), @@ -2844,7 +2795,7 @@ fn register_def(cx: &DocContext, def: Def) -> DefId { Def::Union(i) => (i, TypeKind::Union), Def::Mod(i) => (i, TypeKind::Module), Def::Static(i, _) => (i, TypeKind::Static), - Def::Variant(i) => (tcx.parent_def_id(i).unwrap(), TypeKind::Enum), + Def::Variant(i) => (cx.tcx.parent_def_id(i).unwrap(), TypeKind::Enum), Def::SelfTy(Some(def_id), _) => (def_id, TypeKind::Trait), Def::SelfTy(_, Some(impl_def_id)) => { return impl_def_id @@ -2854,7 +2805,7 @@ fn register_def(cx: &DocContext, def: Def) -> DefId { if did.is_local() { return did } inline::record_extern_fqn(cx, did, kind); if let TypeKind::Trait = kind { - let t = inline::build_external_trait(cx, tcx, did); + let t = inline::build_external_trait(cx, did); cx.external_traits.borrow_mut().insert(did, t); } did @@ -2868,9 +2819,7 @@ fn resolve_use_source(cx: &DocContext, path: Path, id: ast::NodeId) -> ImportSou } fn resolve_def(cx: &DocContext, id: ast::NodeId) -> Option { - cx.tcx_opt().and_then(|tcx| { - tcx.expect_def_or_none(id).map(|def| register_def(cx, def)) - }) + cx.tcx.expect_def_or_none(id).map(|def| register_def(cx, def)) } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] @@ -2889,7 +2838,7 @@ impl Clean for doctree::Macro { visibility: Some(Public), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), - def_id: cx.map.local_def_id(self.id), + def_id: cx.tcx.map.local_def_id(self.id), inner: MacroItem(Macro { source: format!("macro_rules! {} {{\n{}}}", name, diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 19e084905aa..7240f0aedbd 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -153,7 +153,7 @@ fn trait_is_same_or_supertrait(cx: &DocContext, child: DefId, if child == trait_ { return true } - let predicates = cx.tcx().item_super_predicates(child).predicates; + let predicates = cx.tcx.item_super_predicates(child).predicates; predicates.iter().filter_map(|pred| { if let ty::Predicate::Trait(ref pred) = *pred { if pred.0.trait_ref.self_ty().is_self() { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index a25cb0bacc5..7d7b7fead58 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -7,7 +7,6 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -pub use self::MaybeTyped::*; use rustc_lint; use rustc_driver::{driver, target_features, abort_on_err}; @@ -42,21 +41,12 @@ use html::render::RenderInfo; pub use rustc::session::config::Input; pub use rustc::session::search_paths::SearchPaths; -/// Are we generating documentation (`Typed`) or tests (`NotTyped`)? -pub enum MaybeTyped<'a, 'tcx: 'a> { - Typed(TyCtxt<'a, 'tcx, 'tcx>), - NotTyped(&'a session::Session) -} - pub type ExternalPaths = FxHashMap, clean::TypeKind)>; pub struct DocContext<'a, 'tcx: 'a> { - pub map: &'a hir_map::Map<'tcx>, - pub maybe_typed: MaybeTyped<'a, 'tcx>, + pub tcx: TyCtxt<'a, 'tcx, 'tcx>, pub input: Input, pub populated_all_crate_impls: Cell, - pub deref_trait_did: Cell>, - pub deref_mut_trait_did: Cell>, // Note that external items for which `doc(hidden)` applies to are shown as // non-reachable while local items aren't. This is because we're reusing // the access levels from crateanalysis. @@ -77,24 +67,9 @@ pub struct DocContext<'a, 'tcx: 'a> { pub export_map: ExportMap, } -impl<'b, 'tcx> DocContext<'b, 'tcx> { - pub fn sess<'a>(&'a self) -> &'a session::Session { - match self.maybe_typed { - Typed(tcx) => &tcx.sess, - NotTyped(ref sess) => sess - } - } - - pub fn tcx_opt<'a>(&'a self) -> Option> { - match self.maybe_typed { - Typed(tcx) => Some(tcx), - NotTyped(_) => None - } - } - - pub fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> { - let tcx_opt = self.tcx_opt(); - tcx_opt.expect("tcx not present") +impl<'a, 'tcx> DocContext<'a, 'tcx> { + pub fn sess(&self) -> &session::Session { + &self.tcx.sess } /// Call the closure with the given parameters set as @@ -208,12 +183,9 @@ pub fn run_core(search_paths: SearchPaths, }; let ctxt = DocContext { - map: &tcx.map, - maybe_typed: Typed(tcx), + tcx: tcx, input: input, populated_all_crate_impls: Cell::new(false), - deref_trait_did: Cell::new(None), - deref_mut_trait_did: Cell::new(None), access_levels: RefCell::new(access_levels), external_traits: Default::default(), renderinfo: Default::default(), @@ -221,11 +193,11 @@ pub fn run_core(search_paths: SearchPaths, lt_substs: Default::default(), export_map: export_map, }; - debug!("crate: {:?}", ctxt.map.krate()); + debug!("crate: {:?}", tcx.map.krate()); let krate = { let mut v = RustdocVisitor::new(&ctxt); - v.visit(ctxt.map.krate()); + v.visit(tcx.map.krate()); v.clean(&ctxt) }; diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index f1eb65ee16e..8ed0567d820 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -65,18 +65,13 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } fn stability(&self, id: ast::NodeId) -> Option { - self.cx.tcx_opt().and_then(|tcx| { - self.cx.map.opt_local_def_id(id) - .and_then(|def_id| tcx.lookup_stability(def_id)) - .cloned() - }) + self.cx.tcx.map.opt_local_def_id(id) + .and_then(|def_id| self.cx.tcx.lookup_stability(def_id)).cloned() } fn deprecation(&self, id: ast::NodeId) -> Option { - self.cx.tcx_opt().and_then(|tcx| { - self.cx.map.opt_local_def_id(id) - .and_then(|def_id| tcx.lookup_deprecation(def_id)) - }) + self.cx.tcx.map.opt_local_def_id(id) + .and_then(|def_id| self.cx.tcx.lookup_deprecation(def_id)) } pub fn visit(&mut self, krate: &hir::Crate) { @@ -196,7 +191,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let orig_inside_public_path = self.inside_public_path; self.inside_public_path &= vis == hir::Public; for i in &m.item_ids { - let item = self.cx.map.expect_item(i.id); + let item = self.cx.tcx.map.expect_item(i.id); self.visit_item(item, None, &mut om); } self.inside_public_path = orig_inside_public_path; @@ -279,9 +274,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { glob: bool, om: &mut Module, please_inline: bool) -> bool { fn inherits_doc_hidden(cx: &core::DocContext, mut node: ast::NodeId) -> bool { - while let Some(id) = cx.map.get_enclosing_scope(node) { + while let Some(id) = cx.tcx.map.get_enclosing_scope(node) { node = id; - if cx.map.attrs(node).lists("doc").has_word("hidden") { + if cx.tcx.map.attrs(node).lists("doc").has_word("hidden") { return true; } if node == ast::CRATE_NODE_ID { @@ -291,10 +286,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { false } - let tcx = match self.cx.tcx_opt() { - Some(tcx) => tcx, - None => return false - }; + let tcx = self.cx.tcx; let def = tcx.expect_def(id); let def_did = def.def_id(); @@ -308,7 +300,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { // made reachable by cross-crate inlining which we're checking here. // (this is done here because we need to know this upfront) if !def_did.is_local() && !is_no_inline { - let attrs = clean::inline::load_attrs(self.cx, tcx, def_did); + let attrs = clean::inline::load_attrs(self.cx, def_did); let self_is_hidden = attrs.lists("doc").has_word("hidden"); match def { Def::Trait(did) | @@ -347,7 +339,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { match it.node { hir::ItemMod(ref m) => { for i in &m.item_ids { - let i = self.cx.map.expect_item(i.id); + let i = self.cx.tcx.map.expect_item(i.id); self.visit_item(i, None, om); } } @@ -506,7 +498,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { // regardless of where they're located. if !self.inlining { let items = item_ids.iter() - .map(|ii| self.cx.map.impl_item(ii.id).clone()) + .map(|ii| self.cx.tcx.map.impl_item(ii.id).clone()) .collect(); let i = Impl { unsafety: unsafety, diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs index 172d070c55d..cee292f9915 100644 --- a/src/librustdoc/visit_lib.rs +++ b/src/librustdoc/visit_lib.rs @@ -49,7 +49,7 @@ impl<'a, 'b, 'tcx> LibEmbargoVisitor<'a, 'b, 'tcx> { // Updates node level and returns the updated level fn update(&mut self, did: DefId, level: Option) -> Option { - let is_hidden = self.cx.tcx().get_attrs(did).lists("doc").has_word("hidden"); + let is_hidden = self.cx.tcx.get_attrs(did).lists("doc").has_word("hidden"); let old_level = self.access_levels.map.get(&did).cloned(); // Accessibility levels can only grow From ba07a1b58d72fb460734014f5d314a206dad7359 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 23 Nov 2016 21:49:54 -0500 Subject: [PATCH 047/293] std: make compilation of libpanic_unwind optional via a Cargo feature with this feature disabled, you can (Cargo) compile std with "panic=abort" rustbuild will build std with this feature enabled, to maintain the status quo fixes #37252 --- src/bootstrap/lib.rs | 2 +- src/libstd/Cargo.toml | 5 +++-- src/rustc/std_shim/Cargo.toml | 5 +++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 828e82d3832..b751031e88b 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -507,7 +507,7 @@ impl Build { /// Get the space-separated set of activated features for the standard /// library. fn std_features(&self) -> String { - let mut features = String::new(); + let mut features = "panic-unwind".to_string(); if self.config.debug_jemalloc { features.push_str(" debug-jemalloc"); } diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index 21e6acc37f3..b9f52e20fdd 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -13,7 +13,7 @@ crate-type = ["dylib", "rlib"] alloc = { path = "../liballoc" } alloc_jemalloc = { path = "../liballoc_jemalloc", optional = true } alloc_system = { path = "../liballoc_system" } -panic_unwind = { path = "../libpanic_unwind" } +panic_unwind = { path = "../libpanic_unwind", optional = true } panic_abort = { path = "../libpanic_abort" } collections = { path = "../libcollections" } core = { path = "../libcore" } @@ -29,5 +29,6 @@ gcc = "0.3.27" [features] backtrace = [] -jemalloc = ["alloc_jemalloc"] debug-jemalloc = ["alloc_jemalloc/debug"] +jemalloc = ["alloc_jemalloc"] +panic-unwind = ["panic_unwind"] diff --git a/src/rustc/std_shim/Cargo.toml b/src/rustc/std_shim/Cargo.toml index 58a7bd8a1cb..b4b7acc4e66 100644 --- a/src/rustc/std_shim/Cargo.toml +++ b/src/rustc/std_shim/Cargo.toml @@ -45,6 +45,7 @@ core = { path = "../../libcore" } # Reexport features from std [features] -jemalloc = ["std/jemalloc"] -debug-jemalloc = ["std/debug-jemalloc"] backtrace = ["std/backtrace"] +debug-jemalloc = ["std/debug-jemalloc"] +jemalloc = ["std/jemalloc"] +panic-unwind = ["std/panic-unwind"] From b7982bbbe0a002272b86ed2f7f7902b2c3471087 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 22 Nov 2016 23:32:16 -0800 Subject: [PATCH 048/293] review comments --- src/librustc_errors/emitter.rs | 82 +++++-------- src/librustc_errors/snippet.rs | 108 +++++++++--------- src/libsyntax/test_snippet.rs | 100 ++++++++++++++++ ...dropck-eyepatch-implies-unsafe-impl.stderr | 4 +- .../consider-using-explicit-lifetime.stderr | 2 +- src/test/ui/span/multiline-span-simple.rs | 2 +- src/test/ui/span/multiline-span-simple.stderr | 7 +- 7 files changed, 191 insertions(+), 114 deletions(-) diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 808a1683b84..808fe504b95 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -14,7 +14,7 @@ use syntax_pos::{COMMAND_LINE_SP, DUMMY_SP, FileMap, Span, MultiSpan, CharPos}; use {Level, CodeSuggestion, DiagnosticBuilder, SubDiagnostic, CodeMapper}; use RenderSpan::*; -use snippet::{Annotation, AnnotationType, Line, StyledString, Style}; +use snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, StyledString, Style}; use styled_buffer::StyledBuffer; use std::io::prelude::*; @@ -181,12 +181,17 @@ impl EmitterWriter { if is_minimized { ann.annotation_type = AnnotationType::Minimized; } else if lo.line != hi.line { - ann.annotation_type = AnnotationType::Multiline { + let ml = MultilineAnnotation { depth: 1, line_start: lo.line, line_end: hi.line, + start_col: lo.col.0, + end_col: hi.col.0, + is_primary: span_label.is_primary, + label: span_label.label.clone(), }; - multiline_annotations.push((lo.file.clone(), ann.clone())); + ann.annotation_type = AnnotationType::Multiline(ml.clone()); + multiline_annotations.push((lo.file.clone(), ml)); }; if !ann.is_multiline() { @@ -200,65 +205,34 @@ impl EmitterWriter { // Find overlapping multiline annotations, put them at different depths multiline_annotations.sort_by(|a, b| { - if let AnnotationType::Multiline { - line_start: a_start, - line_end: a_end, - .. - } = a.1.annotation_type { - if let AnnotationType::Multiline { - line_start: b_start, - line_end: b_end, - .. - } = b.1.annotation_type { - (a_start, a_end).cmp(&(b_start, b_end)) - } else { - panic!("tried to sort multiline annotations, but found `{:?}`", b) - } - } else { - panic!("tried to sort multiline annotations, but found `{:?}`", a) - } + (a.1.line_start, a.1.line_end).cmp(&(b.1.line_start, b.1.line_end)) }); for item in multiline_annotations.clone() { let ann = item.1; - if let AnnotationType::Multiline {line_start, line_end, ..} = ann.annotation_type { - for item in multiline_annotations.iter_mut() { - let ref mut a = item.1; - if let AnnotationType::Multiline { - line_start: start, - line_end: end, - .. - } = a.annotation_type { - // Move all other multiline annotations overlapping with this one - // one level to the right. - if &ann != a && num_overlap(line_start, line_end, start, end, true) { - a.annotation_type.increase_depth(); - } else { - break; - } - } else { - panic!("tried to find depth for multiline annotation, but found `{:?}`", - ann) - }; + for item in multiline_annotations.iter_mut() { + let ref mut a = item.1; + // Move all other multiline annotations overlapping with this one + // one level to the right. + if &ann != a && + num_overlap(ann.line_start, ann.line_end, a.line_start, a.line_end, true) + { + a.increase_depth(); + } else { + break; } - } else { - panic!("tried to find depth for multiline annotation, but found `{:?}`", ann) - }; + } } let mut max_depth = 0; // max overlapping multiline spans for (file, ann) in multiline_annotations { - if let AnnotationType::Multiline {line_start, line_end, depth} = ann.annotation_type { - if depth > max_depth { - max_depth = depth; - } - add_annotation_to_file(&mut output, file.clone(), line_start, ann.as_start()); - for line in line_start + 1..line_end { - add_annotation_to_file(&mut output, file.clone(), line, ann.as_line()); - } - add_annotation_to_file(&mut output, file, line_end, ann.as_end()); - } else { - panic!("non-multiline annotation `{:?}` in `multiline_annotations`!", ann); + if ann.depth > max_depth { + max_depth = ann.depth; } + add_annotation_to_file(&mut output, file.clone(), ann.line_start, ann.as_start()); + for line in ann.line_start + 1..ann.line_end { + add_annotation_to_file(&mut output, file.clone(), line, ann.as_line()); + } + add_annotation_to_file(&mut output, file, ann.line_end, ann.as_end()); } for file_vec in output.iter_mut() { file_vec.multiline_depth = max_depth; @@ -572,7 +546,7 @@ impl EmitterWriter { // | | something about `foo` // | something about `fn foo()` annotations_position.sort_by(|a, b| { - fn len(a: Annotation) -> usize { + fn len(a: &Annotation) -> usize { // Account for usize underflows if a.end_col > a.start_col { a.end_col - a.start_col diff --git a/src/librustc_errors/snippet.rs b/src/librustc_errors/snippet.rs index 3bf428af994..b8c1726443d 100644 --- a/src/librustc_errors/snippet.rs +++ b/src/librustc_errors/snippet.rs @@ -41,6 +41,57 @@ pub struct Line { pub annotations: Vec, } + +#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] +pub struct MultilineAnnotation { + pub depth: usize, + pub line_start: usize, + pub line_end: usize, + pub start_col: usize, + pub end_col: usize, + pub is_primary: bool, + pub label: Option, +} + +impl MultilineAnnotation { + pub fn increase_depth(&mut self) { + self.depth += 1; + } + + pub fn as_start(&self) -> Annotation { + Annotation { + start_col: self.start_col, + end_col: self.start_col + 1, + is_primary: self.is_primary, + label: Some("starting here...".to_owned()), + annotation_type: AnnotationType::MultilineStart(self.depth) + } + } + + pub fn as_end(&self) -> Annotation { + Annotation { + start_col: self.end_col - 1, + end_col: self.end_col, + is_primary: self.is_primary, + label: match self.label { + Some(ref label) => Some(format!("...ending here: {}", label)), + None => Some("...ending here".to_owned()), + }, + annotation_type: AnnotationType::MultilineEnd(self.depth) + } + } + + pub fn as_line(&self) -> Annotation { + Annotation { + start_col: 0, + end_col: 0, + is_primary: self.is_primary, + label: None, + annotation_type: AnnotationType::MultilineLine(self.depth) + } + } +} + #[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] pub enum AnnotationType { /// Annotation under a single line of code @@ -50,11 +101,7 @@ pub enum AnnotationType { Minimized, /// Annotation enclosing the first and last character of a multiline span - Multiline { - depth: usize, - line_start: usize, - line_end: usize, - }, + Multiline(MultilineAnnotation), // The Multiline type above is replaced with the following three in order // to reuse the current label drawing code. @@ -74,24 +121,6 @@ pub enum AnnotationType { MultilineLine(usize), } -impl AnnotationType { - pub fn depth(&self) -> usize { - match self { - &AnnotationType::Multiline {depth, ..} | - &AnnotationType::MultilineStart(depth) | - &AnnotationType::MultilineLine(depth) | - &AnnotationType::MultilineEnd(depth) => depth, - _ => 0, - } - } - - pub fn increase_depth(&mut self) { - if let AnnotationType::Multiline {ref mut depth, ..} = *self { - *depth += 1; - } - } -} - #[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] pub struct Annotation { /// Start column, 0-based indexing -- counting *characters*, not @@ -124,39 +153,14 @@ impl Annotation { pub fn is_multiline(&self) -> bool { match self.annotation_type { - AnnotationType::Multiline {..} | - AnnotationType::MultilineStart(_) | - AnnotationType::MultilineLine(_) | - AnnotationType::MultilineEnd(_) => true, + AnnotationType::Multiline(_) | + AnnotationType::MultilineStart(_) | + AnnotationType::MultilineLine(_) | + AnnotationType::MultilineEnd(_) => true, _ => false, } } - pub fn as_start(&self) -> Annotation { - let mut a = self.clone(); - a.annotation_type = AnnotationType::MultilineStart(self.annotation_type.depth()); - a.end_col = a.start_col + 1; - a.label = Some("starting here...".to_owned()); - a - } - - pub fn as_end(&self) -> Annotation { - let mut a = self.clone(); - a.annotation_type = AnnotationType::MultilineEnd(self.annotation_type.depth()); - a.start_col = a.end_col - 1; - a.label = match a.label { - Some(l) => Some(format!("...ending here: {}", l)), - None => Some("..ending here".to_owned()), - }; - a - } - - pub fn as_line(&self) -> Annotation { - let mut a = self.clone(); - a.annotation_type = AnnotationType::MultilineLine(self.annotation_type.depth()); - a.label = None; - a - } } #[derive(Debug)] diff --git a/src/libsyntax/test_snippet.rs b/src/libsyntax/test_snippet.rs index 4ce51076adc..98e574867b4 100644 --- a/src/libsyntax/test_snippet.rs +++ b/src/libsyntax/test_snippet.rs @@ -444,3 +444,103 @@ error: foo "#); } + +#[test] +fn non_overlaping() { + test_harness(r#" +fn foo() { + X0 Y0 Z0 + X1 Y1 Z1 + X2 Y2 Z2 + X3 Y3 Z3 +} +"#, + vec![ + SpanLabel { + start: Position { + string: "Y0", + count: 1, + }, + end: Position { + string: "X1", + count: 1, + }, + label: "`X` is a good letter", + }, + SpanLabel { + start: Position { + string: "Y2", + count: 1, + }, + end: Position { + string: "Z3", + count: 1, + }, + label: "`Y` is a good letter too", + }, + ], + r#" +error: foo + --> test.rs:3:6 + | +3 | X0 Y0 Z0 + | ______^ starting here... +4 | | X1 Y1 Z1 + | |____^ ...ending here: `X` is a good letter +5 | X2 Y2 Z2 + | ______- starting here... +6 | | X3 Y3 Z3 + | |__________- ...ending here: `Y` is a good letter too + +"#); +} +#[test] +fn overlaping_start_and_end() { + test_harness(r#" +fn foo() { + X0 Y0 Z0 + X1 Y1 Z1 + X2 Y2 Z2 + X3 Y3 Z3 +} +"#, + vec![ + SpanLabel { + start: Position { + string: "Y0", + count: 1, + }, + end: Position { + string: "X1", + count: 1, + }, + label: "`X` is a good letter", + }, + SpanLabel { + start: Position { + string: "Z1", + count: 1, + }, + end: Position { + string: "Z3", + count: 1, + }, + label: "`Y` is a good letter too", + }, + ], + r#" +error: foo + --> test.rs:3:6 + | +3 | X0 Y0 Z0 + | ______^ starting here... +4 | | X1 Y1 Z1 + | |____^____- starting here... + | ||____| + | | ...ending here: `X` is a good letter +5 | | X2 Y2 Z2 +6 | | X3 Y3 Z3 + | |___________- ...ending here: `Y` is a good letter too + +"#); +} diff --git a/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr b/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr index b3e72f28d88..92e2fe8e936 100644 --- a/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr +++ b/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr @@ -8,7 +8,7 @@ error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attri 35 | | // (unsafe to access self.1 due to #[may_dangle] on A) 36 | | fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); } 37 | | } - | |_^ ..ending here + | |_^ ...ending here error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attribute --> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:38:1 @@ -20,7 +20,7 @@ error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attri 41 | | // (unsafe to access self.1 due to #[may_dangle] on 'a) 42 | | fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); } 43 | | } - | |_^ ..ending here + | |_^ ...ending here error: aborting due to 2 previous errors diff --git a/src/test/ui/lifetimes/consider-using-explicit-lifetime.stderr b/src/test/ui/lifetimes/consider-using-explicit-lifetime.stderr index 1d1bc58805a..153aaa07833 100644 --- a/src/test/ui/lifetimes/consider-using-explicit-lifetime.stderr +++ b/src/test/ui/lifetimes/consider-using-explicit-lifetime.stderr @@ -19,7 +19,7 @@ help: consider using an explicit lifetime parameter as shown: fn from_str(path: | _____^ starting here... 26 | | Ok(Foo { field: path }) 27 | | } - | |_____^ ..ending here + | |_____^ ...ending here error: aborting due to 2 previous errors diff --git a/src/test/ui/span/multiline-span-simple.rs b/src/test/ui/span/multiline-span-simple.rs index 16414766f39..451492ba693 100644 --- a/src/test/ui/span/multiline-span-simple.rs +++ b/src/test/ui/span/multiline-span-simple.rs @@ -20,7 +20,7 @@ fn main() { let x = 1; let y = 2; let z = 3; - foo(1 + + foo(1 as u32 + bar(x, diff --git a/src/test/ui/span/multiline-span-simple.stderr b/src/test/ui/span/multiline-span-simple.stderr index 26acef64c89..b801325114c 100644 --- a/src/test/ui/span/multiline-span-simple.stderr +++ b/src/test/ui/span/multiline-span-simple.stderr @@ -1,20 +1,19 @@ -error[E0277]: the trait bound `{integer}: std::ops::Add<()>` is not satisfied +error[E0277]: the trait bound `u32: std::ops::Add<()>` is not satisfied --> $DIR/multiline-span-simple.rs:23:9 | -23 | foo(1 + +23 | foo(1 as u32 + | _________^ starting here... 24 | | 25 | | bar(x, 26 | | 27 | | y), - | |______________^ ...ending here: the trait `std::ops::Add<()>` is not implemented for `{integer}` + | |______________^ ...ending here: the trait `std::ops::Add<()>` is not implemented for `u32` | = help: the following implementations were found: = help: = help: <&'a u32 as std::ops::Add> = help: > = help: <&'b u32 as std::ops::Add<&'a u32>> - = help: and 90 others error: aborting due to previous error From a3e03e42e1298b49b647c8f80050421458414385 Mon Sep 17 00:00:00 2001 From: fkjogu Date: Thu, 24 Nov 2016 09:49:30 +0100 Subject: [PATCH 049/293] Define `bound` argument in std::sync::mpsc::sync_channel The `bound` argument in `std::sync::mpsc::sync:channel(bound: usize)` was not defined in the documentation. --- src/libstd/sync/mpsc/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 2773629c7d7..ca6e46eb15a 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -491,11 +491,11 @@ pub fn channel() -> (Sender, Receiver) { /// becomes available. These channels differ greatly in the semantics of the /// sender from asynchronous channels, however. /// -/// This channel has an internal buffer on which messages will be queued. When -/// the internal buffer becomes full, future sends will *block* waiting for the -/// buffer to open up. Note that a buffer size of 0 is valid, in which case this -/// becomes "rendezvous channel" where each send will not return until a recv -/// is paired with it. +/// This channel has an internal buffer on which messages will be queued. `bound` +/// specifies the buffer size. When the internal buffer becomes full, future sends +/// will *block* waiting for the buffer to open up. Note that a buffer size of 0 +/// is valid, in which case this becomes "rendezvous channel" where each send will +/// not return until a recv is paired with it. /// /// As with asynchronous channels, all senders will panic in `send` if the /// `Receiver` has been destroyed. From 9383fcf07f85d8e8b91a6150cf4ca252b37a5383 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 14 Nov 2016 17:46:20 +0100 Subject: [PATCH 050/293] Add `-Z print-type-sizes`, a tool for digging into how variants are laid out. --- src/librustc/session/config.rs | 2 + src/librustc/session/mod.rs | 74 ++++++++- src/librustc_driver/driver.rs | 10 ++ src/librustc_mir/transform/mod.rs | 1 + .../transform/print_type_sizes.rs | 152 ++++++++++++++++++ 5 files changed, 238 insertions(+), 1 deletion(-) create mode 100644 src/librustc_mir/transform/print_type_sizes.rs diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index f3677b80819..26dafed7019 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -909,6 +909,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "keep the AST after lowering it to HIR"), show_span: Option = (None, parse_opt_string, [TRACKED], "show spans for compiler debugging (expr|pat|ty)"), + print_type_sizes: bool = (false, parse_bool, [UNTRACKED], + "print layout information for each type encountered"), print_trans_items: Option = (None, parse_opt_string, [UNTRACKED], "print the result of the translation item collection pass"), mir_opt_level: Option = (None, parse_opt_uint, [TRACKED], diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 9577a25b3f8..128e4d878a8 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -112,9 +112,80 @@ pub struct Session { /// Some measurements that are being gathered during compilation. pub perf_stats: PerfStats, + /// Data about code being compiled, gathered during compilation. + pub code_stats: RefCell, + next_node_id: Cell, } +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum VariantSize { + Exact(u64), + Min(u64), +} + +#[derive(PartialEq, Eq, Debug)] +pub struct TypeSizeInfo { + pub type_description: String, + pub overall_size: u64, + pub variant_sizes: Option>, +} + +#[derive(PartialEq, Eq, Debug)] +pub struct CodeStats { + pub type_sizes: Vec, +} + +impl CodeStats { + fn new() -> Self { + CodeStats { type_sizes: Vec::new() } + } + + pub fn record_type_size(&mut self, + type_desc: S, + overall_size: u64, + variant_sizes: Vec) { + let sizes = if variant_sizes.len() == 0 { None } else { Some(variant_sizes) }; + let info = TypeSizeInfo { + type_description: type_desc.to_string(), + overall_size: overall_size, + variant_sizes: sizes, + }; + if !self.type_sizes.contains(&info) { + self.type_sizes.push(info); + } + } + + pub fn sort_by_type_description(&mut self) { + self.type_sizes.sort_by(|info1, info2| { + info1.type_description.cmp(&info2.type_description) + }); + } + + pub fn sort_by_overall_size(&mut self) { + self.type_sizes.sort_by(|info1, info2| { + // (reversing cmp order to get large-to-small ordering) + info2.overall_size.cmp(&info1.overall_size) + }); + } + + pub fn print_type_sizes(&self) { + for info in &self.type_sizes { + println!("print-type-size t: `{}` overall bytes: {}", + info.type_description, info.overall_size); + if let Some(ref variant_sizes) = info.variant_sizes { + for (i, variant_size) in variant_sizes.iter().enumerate() { + let (kind, s) = match *variant_size { + VariantSize::Exact(s) => { ("exact", s) } + VariantSize::Min(s) => { (" min", s) } + }; + println!("print-type-size variant[{}] {} bytes: {}", i, kind, s); + } + } + } + } +} + pub struct PerfStats { // The accumulated time needed for computing the SVH of the crate pub svh_time: Cell, @@ -624,7 +695,8 @@ pub fn build_session_(sopts: config::Options, incr_comp_hashes_count: Cell::new(0), incr_comp_bytes_hashed: Cell::new(0), symbol_hash_time: Cell::new(Duration::from_secs(0)), - } + }, + code_stats: RefCell::new(CodeStats::new()), }; init_llvm(&sess); diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 5cbb8f93fc9..a91525c6b2d 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -215,6 +215,13 @@ pub fn compile_input(sess: &Session, })?? }; + if sess.opts.debugging_opts.print_type_sizes { + // (these are stable sorts) + sess.code_stats.borrow_mut().sort_by_type_description(); + sess.code_stats.borrow_mut().sort_by_overall_size(); + sess.code_stats.borrow().print_type_sizes(); + } + let phase5_result = phase_5_run_llvm_passes(sess, &trans, &outputs); controller_entry_point!(after_llvm, @@ -1008,6 +1015,9 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, time(time_passes, "MIR optimisations", || { let mut passes = ::rustc::mir::transform::Passes::new(); passes.push_hook(box mir::transform::dump_mir::DumpMir); + if tcx.sess.opts.debugging_opts.print_type_sizes { + passes.push_pass(box mir::transform::print_type_sizes::GatherTypeSizesMir::new()); + } passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads); passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("no-landing-pads")); diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index ae255f70fb7..eed4763c17d 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -13,6 +13,7 @@ pub mod simplify; pub mod erase_regions; pub mod no_landing_pads; pub mod type_check; +pub mod print_type_sizes; pub mod add_call_guards; pub mod promote_consts; pub mod qualify_consts; diff --git a/src/librustc_mir/transform/print_type_sizes.rs b/src/librustc_mir/transform/print_type_sizes.rs new file mode 100644 index 00000000000..617a5ac78df --- /dev/null +++ b/src/librustc_mir/transform/print_type_sizes.rs @@ -0,0 +1,152 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This pass implements instrumentation to gather the layout of every type. + +use rustc::session::{VariantSize}; +use rustc::traits::{Reveal}; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::fold::{TypeFoldable}; +use rustc::ty::layout::{Layout}; +use rustc::mir::{Mir}; +use rustc::mir::transform::{MirPass, MirPassHook, MirSource, Pass}; +use rustc::mir::visit::Visitor; + +use std::collections::HashSet; + +pub struct GatherTypeSizesMir { + _hidden: (), +} + +impl GatherTypeSizesMir { + pub fn new() -> Self { + GatherTypeSizesMir { _hidden: () } + } +} + +impl Pass for GatherTypeSizesMir { +} + +impl<'tcx> MirPassHook<'tcx> for GatherTypeSizesMir { + fn on_mir_pass<'a>(&mut self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + src: MirSource, + mir: &Mir<'tcx>, + _pass: &Pass, + _is_after: bool) { + debug!("on_mir_pass: {}", tcx.node_path_str(src.item_id())); + self.go(tcx, mir); + } +} + +impl<'tcx> MirPass<'tcx> for GatherTypeSizesMir { + fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, + src: MirSource, mir: &mut Mir<'tcx>) { + debug!("run_pass: {}", tcx.node_path_str(src.item_id())); + self.go(tcx, mir); + } +} + +impl GatherTypeSizesMir { + fn go<'a, 'tcx>(&mut self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + mir: &Mir<'tcx>) { + if tcx.sess.err_count() > 0 { + // compiling a broken program can obviously result in a + // broken MIR, so do not bother trying to process it. + return; + } + + let mut visitor = TypeVisitor { + tcx: tcx, + seen: HashSet::new(), + }; + visitor.visit_mir(mir); + } +} + +struct TypeVisitor<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + seen: HashSet>, +} + +impl<'a, 'tcx: 'a> Visitor<'tcx> for TypeVisitor<'a, 'tcx> { + fn visit_ty(&mut self, ty: &Ty<'tcx>) { + debug!("TypeVisitor::visit_ty ty=`{:?}`", ty); + + match ty.sty { + ty::TyAdt(..) | + ty::TyClosure(..) => {} // fall through + _ => { + debug!("print-type-size t: `{:?}` skip non-nominal", ty); + return; + } + } + + if ty.has_param_types() { + debug!("print-type-size t: `{:?}` skip has param types", ty); + return; + } + if ty.has_projection_types() { + debug!("print-type-size t: `{:?}` skip has projections", ty); + return; + } + + if self.seen.contains(ty) { + return; + } + self.seen.insert(ty); + + let reveal = Reveal::All; + // let reveal = Reveal::NotSpecializable; + + self.tcx.infer_ctxt(None, None, reveal).enter(|infcx| { + match ty.layout(&infcx) { + Ok(layout) => { + let type_desc = format!("{:?}", ty); + let overall_size = layout.size(&Default::default()); + + let variant_sizes: Vec<_> = match *layout { + Layout::General { ref variants, .. } => { + variants.iter() + .map(|v| if v.sized { + VariantSize::Exact(v.min_size.bytes()) + } else { + VariantSize::Min(v.min_size.bytes()) + }) + .collect() + } + + Layout::UntaggedUnion { variants: _ } => { + /* layout does not currently store info about each variant... */ + Vec::new() + } + + // RawNullablePointer/StructWrappedNullablePointer + // don't provide any interesting size info + // beyond what we already reported for their + // total size. + _ => { + Vec::new() + } + }; + + self.tcx.sess.code_stats.borrow_mut() + .record_type_size(type_desc, + overall_size.bytes(), + variant_sizes); + } + Err(err) => { + self.tcx.sess.warn(&format!("print-type-size t: `{:?}` err: {:?}", ty, err)); + } + } + }); + } +} From 70e5ca2ab49ca31485780f6fa981c5164b2cc848 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 15 Nov 2016 17:48:07 +0100 Subject: [PATCH 051/293] Revisions from review comments, squashed. Biggest change: Revised print-type-sizes output to include breakdown of layout. Includes info about field sizes (and alignment + padding when padding is injected; the injected padding is derived from the offsets computed by layout module). Output format is illustrated in commit that has the ui tests. Note: there exists (at least) one case of variant w/o name: empty enums. Namely, empty enums use anonymous univariant repr. So for such cases, print the number of the variant instead of the name. ---- Also, eddyb suggested of reading from `layout_cache` post-trans. (For casual readers: the compiler source often uses the word "cache" for tables that are in fact not periodically purged, and thus are useful as the basis for data like this.) Some types that were previously not printed are now included in the output. (See e.g. the tests `print_type_sizes/generics.rs` and `print_type_sizes/variants.rs`) ---- Other review feedback: switch to an exhaustive match when filtering in just structural types. switch to hashset for layout info and move sort into print method. ---- Driveby change: Factored session::code_stats into its own module ---- incorporate njn feedback re output formatting. --- src/librustc/session/code_stats.rs | 173 ++++++++++++++++ src/librustc/session/mod.rs | 72 +------ src/librustc/ty/layout.rs | 7 + src/librustc_driver/driver.rs | 6 - src/librustc_mir/transform/mod.rs | 1 - .../transform/print_type_sizes.rs | 152 -------------- src/librustc_trans/adt.rs | 1 + src/librustc_trans/base.rs | 193 +++++++++++++++++- 8 files changed, 377 insertions(+), 228 deletions(-) create mode 100644 src/librustc/session/code_stats.rs delete mode 100644 src/librustc_mir/transform/print_type_sizes.rs diff --git a/src/librustc/session/code_stats.rs b/src/librustc/session/code_stats.rs new file mode 100644 index 00000000000..8308c54d70b --- /dev/null +++ b/src/librustc/session/code_stats.rs @@ -0,0 +1,173 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use ty::AdtKind; +use ty::layout::{Align, Size}; + +use rustc_data_structures::fx::{FxHashSet}; + +use std::cmp::{self, Ordering}; + +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub struct VariantInfo { + pub name: Option, + pub kind: SizeKind, + pub size: u64, + pub align: u64, + pub fields: Vec, +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub enum SizeKind { Exact, Min } + +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub struct FieldInfo { + pub name: String, + pub offset: u64, + pub size: u64, + pub align: u64, +} + +impl From for DataTypeKind { + fn from(kind: AdtKind) -> Self { + match kind { + AdtKind::Struct => DataTypeKind::Struct, + AdtKind::Enum => DataTypeKind::Enum, + AdtKind::Union => DataTypeKind::Union, + } + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub enum DataTypeKind { + Struct, + Union, + Enum, + Closure, +} + +#[derive(PartialEq, Eq, Hash, Debug)] +pub struct TypeSizeInfo { + pub kind: DataTypeKind, + pub type_description: String, + pub align: u64, + pub overall_size: u64, + pub opt_discr_size: Option, + pub variants: Vec, +} + +#[derive(PartialEq, Eq, Debug)] +pub struct CodeStats { + type_sizes: FxHashSet, +} + +impl CodeStats { + pub fn new() -> Self { CodeStats { type_sizes: FxHashSet() } } + + pub fn record_type_size(&mut self, + kind: DataTypeKind, + type_desc: S, + align: Align, + overall_size: Size, + opt_discr_size: Option, + variants: Vec) { + let info = TypeSizeInfo { + kind: kind, + type_description: type_desc.to_string(), + align: align.abi(), + overall_size: overall_size.bytes(), + opt_discr_size: opt_discr_size.map(|s| s.bytes()), + variants: variants, + }; + self.type_sizes.insert(info); + } + + pub fn print_type_sizes(&self) { + let mut sorted: Vec<_> = self.type_sizes.iter().collect(); + + // Primary sort: large-to-small. + // Secondary sort: description (dictionary order) + sorted.sort_by(|info1, info2| { + // (reversing cmp order to get large-to-small ordering) + match info2.overall_size.cmp(&info1.overall_size) { + Ordering::Equal => info1.type_description.cmp(&info2.type_description), + other => other, + } + }); + + for info in &sorted { + println!("print-type-size type: `{}`: {} bytes, alignment: {} bytes", + info.type_description, info.overall_size, info.align); + let indent = " "; + + let discr_size = if let Some(discr_size) = info.opt_discr_size { + println!("print-type-size {}discriminant: {} bytes", + indent, discr_size); + discr_size + } else { + 0 + }; + + // We start this at discr_size (rather than 0) because + // things like C-enums do not have variants but we still + // want the max_variant_size at the end of the loop below + // to reflect the presence of the discriminant. + let mut max_variant_size = discr_size; + + let struct_like = match info.kind { + DataTypeKind::Struct | DataTypeKind::Closure => true, + DataTypeKind::Enum | DataTypeKind::Union => false, + }; + for (i, variant_info) in info.variants.iter().enumerate() { + let VariantInfo { ref name, kind: _, align: _, size, ref fields } = *variant_info; + let indent = if !struct_like { + let name = match name.as_ref() { + Some(name) => format!("{}", name), + None => format!("{}", i), + }; + println!("print-type-size {}variant `{}`: {} bytes", + indent, name, size - discr_size); + " " + } else { + assert!(i < 1); + " " + }; + max_variant_size = cmp::max(max_variant_size, size); + + let mut min_offset = discr_size; + for field in fields { + let FieldInfo { ref name, offset, size, align } = *field; + + // Include field alignment in output only if it caused padding injection + if min_offset != offset { + let pad = offset - min_offset; + println!("print-type-size {}padding: {} bytes", + indent, pad); + println!("print-type-size {}field `.{}`: {} bytes, alignment: {} bytes", + indent, name, size, align); + } else { + println!("print-type-size {}field `.{}`: {} bytes", + indent, name, size); + } + + min_offset = offset + size; + } + } + + assert!(max_variant_size <= info.overall_size, + "max_variant_size {} !<= {} overall_size", + max_variant_size, info.overall_size); + if max_variant_size < info.overall_size { + println!("print-type-size {}end padding: {} bytes", + indent, info.overall_size - max_variant_size); + } + } + } +} diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 128e4d878a8..3d8cfd19961 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +pub use self::code_stats::{CodeStats, DataTypeKind, FieldInfo}; +pub use self::code_stats::{SizeKind, TypeSizeInfo, VariantInfo}; + use dep_graph::DepGraph; use hir::def_id::{CrateNum, DefIndex}; use hir::svh::Svh; @@ -49,6 +52,7 @@ use std::fmt; use std::time::Duration; use libc::c_int; +mod code_stats; pub mod config; pub mod filesearch; pub mod search_paths; @@ -118,74 +122,6 @@ pub struct Session { next_node_id: Cell, } -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum VariantSize { - Exact(u64), - Min(u64), -} - -#[derive(PartialEq, Eq, Debug)] -pub struct TypeSizeInfo { - pub type_description: String, - pub overall_size: u64, - pub variant_sizes: Option>, -} - -#[derive(PartialEq, Eq, Debug)] -pub struct CodeStats { - pub type_sizes: Vec, -} - -impl CodeStats { - fn new() -> Self { - CodeStats { type_sizes: Vec::new() } - } - - pub fn record_type_size(&mut self, - type_desc: S, - overall_size: u64, - variant_sizes: Vec) { - let sizes = if variant_sizes.len() == 0 { None } else { Some(variant_sizes) }; - let info = TypeSizeInfo { - type_description: type_desc.to_string(), - overall_size: overall_size, - variant_sizes: sizes, - }; - if !self.type_sizes.contains(&info) { - self.type_sizes.push(info); - } - } - - pub fn sort_by_type_description(&mut self) { - self.type_sizes.sort_by(|info1, info2| { - info1.type_description.cmp(&info2.type_description) - }); - } - - pub fn sort_by_overall_size(&mut self) { - self.type_sizes.sort_by(|info1, info2| { - // (reversing cmp order to get large-to-small ordering) - info2.overall_size.cmp(&info1.overall_size) - }); - } - - pub fn print_type_sizes(&self) { - for info in &self.type_sizes { - println!("print-type-size t: `{}` overall bytes: {}", - info.type_description, info.overall_size); - if let Some(ref variant_sizes) = info.variant_sizes { - for (i, variant_size) in variant_sizes.iter().enumerate() { - let (kind, s) = match *variant_size { - VariantSize::Exact(s) => { ("exact", s) } - VariantSize::Min(s) => { (" min", s) } - }; - println!("print-type-size variant[{}] {} bytes: {}", i, kind, s); - } - } - } - } -} - pub struct PerfStats { // The accumulated time needed for computing the SVH of the crate pub svh_time: Cell, diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 5ee1c3678d6..bc3c5d6ed4e 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -559,11 +559,14 @@ impl<'a, 'gcx, 'tcx> Struct { self.offsets.push(offset); + debug!("Struct::extend offset: {:?} field: {:?} {:?}", offset, field, field.size(dl)); offset = offset.checked_add(field.size(dl), dl) .map_or(Err(LayoutError::SizeOverflow(scapegoat)), Ok)?; } + debug!("Struct::extend min_size: {:?}", offset); + self.min_size = offset; Ok(()) @@ -707,12 +710,16 @@ impl<'a, 'gcx, 'tcx> Union { index, scapegoat); } + debug!("Union::extend field: {:?} {:?}", field, field.size(dl)); + if !self.packed { self.align = self.align.max(field.align(dl)); } self.min_size = cmp::max(self.min_size, field.size(dl)); } + debug!("Union::extend min-size: {:?}", self.min_size); + Ok(()) } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index a91525c6b2d..9a4ecef0c0e 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -216,9 +216,6 @@ pub fn compile_input(sess: &Session, }; if sess.opts.debugging_opts.print_type_sizes { - // (these are stable sorts) - sess.code_stats.borrow_mut().sort_by_type_description(); - sess.code_stats.borrow_mut().sort_by_overall_size(); sess.code_stats.borrow().print_type_sizes(); } @@ -1015,9 +1012,6 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, time(time_passes, "MIR optimisations", || { let mut passes = ::rustc::mir::transform::Passes::new(); passes.push_hook(box mir::transform::dump_mir::DumpMir); - if tcx.sess.opts.debugging_opts.print_type_sizes { - passes.push_pass(box mir::transform::print_type_sizes::GatherTypeSizesMir::new()); - } passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads); passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("no-landing-pads")); diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index eed4763c17d..ae255f70fb7 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -13,7 +13,6 @@ pub mod simplify; pub mod erase_regions; pub mod no_landing_pads; pub mod type_check; -pub mod print_type_sizes; pub mod add_call_guards; pub mod promote_consts; pub mod qualify_consts; diff --git a/src/librustc_mir/transform/print_type_sizes.rs b/src/librustc_mir/transform/print_type_sizes.rs deleted file mode 100644 index 617a5ac78df..00000000000 --- a/src/librustc_mir/transform/print_type_sizes.rs +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! This pass implements instrumentation to gather the layout of every type. - -use rustc::session::{VariantSize}; -use rustc::traits::{Reveal}; -use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::fold::{TypeFoldable}; -use rustc::ty::layout::{Layout}; -use rustc::mir::{Mir}; -use rustc::mir::transform::{MirPass, MirPassHook, MirSource, Pass}; -use rustc::mir::visit::Visitor; - -use std::collections::HashSet; - -pub struct GatherTypeSizesMir { - _hidden: (), -} - -impl GatherTypeSizesMir { - pub fn new() -> Self { - GatherTypeSizesMir { _hidden: () } - } -} - -impl Pass for GatherTypeSizesMir { -} - -impl<'tcx> MirPassHook<'tcx> for GatherTypeSizesMir { - fn on_mir_pass<'a>(&mut self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - src: MirSource, - mir: &Mir<'tcx>, - _pass: &Pass, - _is_after: bool) { - debug!("on_mir_pass: {}", tcx.node_path_str(src.item_id())); - self.go(tcx, mir); - } -} - -impl<'tcx> MirPass<'tcx> for GatherTypeSizesMir { - fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - src: MirSource, mir: &mut Mir<'tcx>) { - debug!("run_pass: {}", tcx.node_path_str(src.item_id())); - self.go(tcx, mir); - } -} - -impl GatherTypeSizesMir { - fn go<'a, 'tcx>(&mut self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - mir: &Mir<'tcx>) { - if tcx.sess.err_count() > 0 { - // compiling a broken program can obviously result in a - // broken MIR, so do not bother trying to process it. - return; - } - - let mut visitor = TypeVisitor { - tcx: tcx, - seen: HashSet::new(), - }; - visitor.visit_mir(mir); - } -} - -struct TypeVisitor<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - seen: HashSet>, -} - -impl<'a, 'tcx: 'a> Visitor<'tcx> for TypeVisitor<'a, 'tcx> { - fn visit_ty(&mut self, ty: &Ty<'tcx>) { - debug!("TypeVisitor::visit_ty ty=`{:?}`", ty); - - match ty.sty { - ty::TyAdt(..) | - ty::TyClosure(..) => {} // fall through - _ => { - debug!("print-type-size t: `{:?}` skip non-nominal", ty); - return; - } - } - - if ty.has_param_types() { - debug!("print-type-size t: `{:?}` skip has param types", ty); - return; - } - if ty.has_projection_types() { - debug!("print-type-size t: `{:?}` skip has projections", ty); - return; - } - - if self.seen.contains(ty) { - return; - } - self.seen.insert(ty); - - let reveal = Reveal::All; - // let reveal = Reveal::NotSpecializable; - - self.tcx.infer_ctxt(None, None, reveal).enter(|infcx| { - match ty.layout(&infcx) { - Ok(layout) => { - let type_desc = format!("{:?}", ty); - let overall_size = layout.size(&Default::default()); - - let variant_sizes: Vec<_> = match *layout { - Layout::General { ref variants, .. } => { - variants.iter() - .map(|v| if v.sized { - VariantSize::Exact(v.min_size.bytes()) - } else { - VariantSize::Min(v.min_size.bytes()) - }) - .collect() - } - - Layout::UntaggedUnion { variants: _ } => { - /* layout does not currently store info about each variant... */ - Vec::new() - } - - // RawNullablePointer/StructWrappedNullablePointer - // don't provide any interesting size info - // beyond what we already reported for their - // total size. - _ => { - Vec::new() - } - }; - - self.tcx.sess.code_stats.borrow_mut() - .record_type_size(type_desc, - overall_size.bytes(), - variant_sizes); - } - Err(err) => { - self.tcx.sess.warn(&format!("print-type-size t: `{:?}` err: {:?}", ty, err)); - } - } - }); - } -} diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index c3340281d07..e091ba07d4f 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -247,6 +247,7 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // of the size. let size = size.bytes(); let align = align.abi(); + assert!(align <= std::u32::MAX as u64); let discr_ty = Type::from_integer(cx, discr); let discr_size = discr.size().bytes(); let padded_discr_size = roundup(discr_size, align as u32); diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 4353c7bd586..d697a5bafb7 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -47,7 +47,7 @@ use rustc::hir::map as hir_map; use rustc::util::common::time; use session::config::{self, NoDebugInfo}; use rustc_incremental::IncrementalHashesMap; -use session::Session; +use session::{self, DataTypeKind, Session}; use abi::{self, Abi, FnType}; use adt; use attributes; @@ -93,6 +93,7 @@ use std::i32; use syntax_pos::{Span, DUMMY_SP}; use syntax::attr; use rustc::hir; +use rustc::ty::layout::{self, Layout}; use syntax::ast; thread_local! { @@ -1741,6 +1742,10 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, .collect()) }); + if tcx.sess.opts.debugging_opts.print_type_sizes { + gather_type_sizes(tcx); + } + if sess.target.target.options.is_like_msvc && sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib) { create_imps(&crate_context_list); @@ -1771,6 +1776,192 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } +fn gather_type_sizes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { + let layout_cache = tcx.layout_cache.borrow(); + for (ty, layout) in layout_cache.iter() { + + // (delay format until we actually need it) + let record = |kind, opt_discr_size, variants| { + let type_desc = format!("{:?}", ty); + let overall_size = layout.size(&tcx.data_layout); + let align = layout.align(&tcx.data_layout); + tcx.sess.code_stats.borrow_mut().record_type_size(kind, + type_desc, + align, + overall_size, + opt_discr_size, + variants); + }; + + let (adt_def, substs) = match ty.sty { + ty::TyAdt(ref adt_def, substs) => { + debug!("print-type-size t: `{:?}` process adt", ty); + (adt_def, substs) + } + + ty::TyClosure(..) => { + debug!("print-type-size t: `{:?}` record closure", ty); + record(DataTypeKind::Closure, None, vec![]); + continue; + } + + _ => { + debug!("print-type-size t: `{:?}` skip non-nominal", ty); + continue; + } + }; + + let adt_kind = adt_def.adt_kind(); + + let build_field_info = |(field_name, field_ty): (ast::Name, Ty), offset: &layout::Size| { + match layout_cache.get(&field_ty) { + None => bug!("no layout found for field {} type: `{:?}`", field_name, field_ty), + Some(field_layout) => { + session::FieldInfo { + name: field_name.to_string(), + offset: offset.bytes(), + size: field_layout.size(&tcx.data_layout).bytes(), + align: field_layout.align(&tcx.data_layout).abi(), + } + } + } + }; + + let build_primitive_info = |name: ast::Name, value: &layout::Primitive| { + session::VariantInfo { + name: Some(name.to_string()), + kind: session::SizeKind::Exact, + align: value.align(&tcx.data_layout).abi(), + size: value.size(&tcx.data_layout).bytes(), + fields: vec![], + } + }; + + enum Fields<'a> { + WithDiscrim(&'a layout::Struct), + NoDiscrim(&'a layout::Struct), + } + + let build_variant_info = |n: Option, flds: &[(ast::Name, Ty)], layout: Fields| { + let (s, field_offsets) = match layout { + Fields::WithDiscrim(s) => (s, &s.offsets[1..]), + Fields::NoDiscrim(s) => (s, &s.offsets[0..]), + }; + let field_info: Vec<_> = flds.iter() + .zip(field_offsets.iter()) + .map(|(&field_name_ty, offset)| build_field_info(field_name_ty, offset)) + .collect(); + + session::VariantInfo { + name: n.map(|n|n.to_string()), + kind: if s.sized { + session::SizeKind::Exact + } else { + session::SizeKind::Min + }, + align: s.align.abi(), + size: s.min_size.bytes(), + fields: field_info, + } + }; + + match **layout { + Layout::StructWrappedNullablePointer { nonnull: ref variant_layout, + nndiscr, + discrfield: _ } => { + debug!("print-type-size t: `{:?}` adt struct-wrapped nullable nndiscr {} is {:?}", + ty, nndiscr, variant_layout); + let variant_def = &adt_def.variants[nndiscr as usize]; + let fields: Vec<_> = variant_def.fields.iter() + .map(|field_def| (field_def.name, field_def.ty(tcx, substs))) + .collect(); + record(adt_kind.into(), + None, + vec![build_variant_info(Some(variant_def.name), + &fields, + Fields::NoDiscrim(variant_layout))]); + } + Layout::RawNullablePointer { nndiscr, value } => { + debug!("print-type-size t: `{:?}` adt raw nullable nndiscr {} is {:?}", + ty, nndiscr, value); + let variant_def = &adt_def.variants[nndiscr as usize]; + record(adt_kind.into(), None, + vec![build_primitive_info(variant_def.name, &value)]); + } + Layout::Univariant { variant: ref variant_layout, non_zero: _ } => { + let variant_names = || { + adt_def.variants.iter().map(|v|format!("{}", v.name)).collect::>() + }; + debug!("print-type-size t: `{:?}` adt univariant {:?} variants: {:?}", + ty, variant_layout, variant_names()); + assert!(adt_def.variants.len() <= 1, + "univariant with variants {:?}", variant_names()); + if adt_def.variants.len() == 1 { + let variant_def = &adt_def.variants[0]; + let fields: Vec<_> = variant_def.fields.iter() + .map(|field_def| (field_def.name, field_def.ty(tcx, substs))) + .collect(); + record(adt_kind.into(), + None, + vec![build_variant_info(Some(variant_def.name), + &fields, + Fields::NoDiscrim(variant_layout))]); + } else { + // (This case arises for *empty* enums; so give it + // zero variants.) + record(adt_kind.into(), None, vec![]); + } + } + + Layout::General { ref variants, discr, .. } => { + debug!("print-type-size t: `{:?}` adt general variants def {} layouts {} {:?}", + ty, adt_def.variants.len(), variants.len(), variants); + let variant_infos: Vec<_> = adt_def.variants.iter() + .zip(variants.iter()) + .map(|(variant_def, variant_layout)| { + let fields: Vec<_> = variant_def.fields.iter() + .map(|field_def| (field_def.name, field_def.ty(tcx, substs))) + .collect(); + build_variant_info(Some(variant_def.name), + &fields, + Fields::WithDiscrim(variant_layout)) + }) + .collect(); + record(adt_kind.into(), Some(discr.size()), variant_infos); + } + + Layout::UntaggedUnion { ref variants } => { + debug!("print-type-size t: `{:?}` adt union variants {:?}", + ty, variants); + // layout does not currently store info about each + // variant... + record(adt_kind.into(), None, Vec::new()); + } + + Layout::CEnum { discr, .. } => { + debug!("print-type-size t: `{:?}` adt c-like enum", ty); + let variant_infos: Vec<_> = adt_def.variants.iter() + .map(|variant_def| { + build_primitive_info(variant_def.name, + &layout::Primitive::Int(discr)) + }) + .collect(); + record(adt_kind.into(), Some(discr.size()), variant_infos); + } + + // other cases provide little interesting (i.e. adjustable + // via representation tweaks) size info beyond total size. + Layout::Scalar { .. } | + Layout::Vector { .. } | + Layout::Array { .. } | + Layout::FatPointer { .. } => { + debug!("print-type-size t: `{:?}` adt other", ty); + record(adt_kind.into(), None, Vec::new()) + } + } + } +} + /// For each CGU, identify if we can reuse an existing object file (or /// maybe other context). fn trans_reuse_previous_work_products(tcx: TyCtxt, From 75825fe1df47866e1821d8b09f4c75930b6e57c1 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 24 Nov 2016 10:28:29 +0100 Subject: [PATCH 052/293] Tests of `-Z print-type-sizes` functionality. Note that the tests have been updated to initialize the local variables; originally it was enough just to declare them. Back when I started this, the `layout_cache` contained entries even just for types that had been declared but not initialized. Apparently things have changed in the interim so that if I want one of those layouts to be computed, I need to actually initialize the value. (Incidentally, this shows a weakness in the strategy of just walking the `layout_cache`; the original strategy of using a MIR visitor would probably have exhibited more robustness in terms of consistent output, but it had other weaknesses so I chose not to reimplement it. At least, not yet.) ---- Also, I have updated tests to avoid target-specific alignments. --- src/test/ui/print_type_sizes/anonymous.rs | 27 +++++++ src/test/ui/print_type_sizes/generics.rs | 73 +++++++++++++++++++ src/test/ui/print_type_sizes/generics.stdout | 14 ++++ .../ui/print_type_sizes/multiple_types.rs | 28 +++++++ .../ui/print_type_sizes/multiple_types.stdout | 10 +++ src/test/ui/print_type_sizes/no_duplicates.rs | 25 +++++++ .../ui/print_type_sizes/no_duplicates.stdout | 2 + src/test/ui/print_type_sizes/nullable.rs | 69 ++++++++++++++++++ src/test/ui/print_type_sizes/nullable.stdout | 27 +++++++ src/test/ui/print_type_sizes/packed.rs | 49 +++++++++++++ src/test/ui/print_type_sizes/packed.stdout | 17 +++++ src/test/ui/print_type_sizes/padding.rs | 39 ++++++++++ src/test/ui/print_type_sizes/padding.stdout | 21 ++++++ src/test/ui/print_type_sizes/variants.rs | 31 ++++++++ src/test/ui/print_type_sizes/variants.stdout | 10 +++ 15 files changed, 442 insertions(+) create mode 100644 src/test/ui/print_type_sizes/anonymous.rs create mode 100644 src/test/ui/print_type_sizes/generics.rs create mode 100644 src/test/ui/print_type_sizes/generics.stdout create mode 100644 src/test/ui/print_type_sizes/multiple_types.rs create mode 100644 src/test/ui/print_type_sizes/multiple_types.stdout create mode 100644 src/test/ui/print_type_sizes/no_duplicates.rs create mode 100644 src/test/ui/print_type_sizes/no_duplicates.stdout create mode 100644 src/test/ui/print_type_sizes/nullable.rs create mode 100644 src/test/ui/print_type_sizes/nullable.stdout create mode 100644 src/test/ui/print_type_sizes/packed.rs create mode 100644 src/test/ui/print_type_sizes/packed.stdout create mode 100644 src/test/ui/print_type_sizes/padding.rs create mode 100644 src/test/ui/print_type_sizes/padding.stdout create mode 100644 src/test/ui/print_type_sizes/variants.rs create mode 100644 src/test/ui/print_type_sizes/variants.stdout diff --git a/src/test/ui/print_type_sizes/anonymous.rs b/src/test/ui/print_type_sizes/anonymous.rs new file mode 100644 index 00000000000..dc93bddbad8 --- /dev/null +++ b/src/test/ui/print_type_sizes/anonymous.rs @@ -0,0 +1,27 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z print-type-sizes + +// All of the types that occur in this function are uninteresting, in +// that one cannot control the sizes of these types with the same sort +// of enum-variant manipulation tricks. + +pub fn main() { + let _byte: u8 = 0; + let _word: usize = 0; + let _tuple: (u8, usize)= (0, 0); + let _array: [u8; 128] = [0; 128]; + let _fn: fn (u8) -> u8 = id; + let _diverging: fn (u8) -> ! = bye; + + fn id(x: u8) -> u8 { x }; + fn bye(_: u8) -> ! { loop { } } +} diff --git a/src/test/ui/print_type_sizes/generics.rs b/src/test/ui/print_type_sizes/generics.rs new file mode 100644 index 00000000000..93bcd1c36e5 --- /dev/null +++ b/src/test/ui/print_type_sizes/generics.rs @@ -0,0 +1,73 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z print-type-sizes + +// This file illustrates how generics are handled: types have to be +// monomorphized, in the MIR of the original function in which they +// occur, to have their size reported. + +// In an ad-hoc attempt to avoid the injection of unwinding code +// (which clutters the output of `-Z print-type-sizes` with types from +// `unwind::libunwind`): +// +// * I am not using Default to build values because that seems to +// cause the injection of unwinding code. (Instead I just make `fn new` +// methods.) +// +// * Pair derive Copy to ensure that we don't inject +// unwinding code into generic uses of Pair when T itself is also +// Copy. +// +// (I suspect this reflect some naivety within the rust compiler +// itself; it should be checking for drop glue, i.e. a destructor +// somewhere in the monomorphized types. It should not matter whether +// the type is Copy.) +#[derive(Copy, Clone)] +pub struct Pair { + _car: T, + _cdr: T, +} + +impl Pair { + fn new(a: T, d: T) -> Self { + Pair { + _car: a, + _cdr: d, + } + } +} + +#[derive(Copy, Clone)] +pub struct SevenBytes([u8; 7]); +pub struct FiftyBytes([u8; 50]); + +pub struct ZeroSized; + +impl SevenBytes { + fn new() -> Self { SevenBytes([0; 7]) } +} + +impl FiftyBytes { + fn new() -> Self { FiftyBytes([0; 50]) } +} + +pub fn f1(x: T) { + let _v: Pair = Pair::new(x, x); + let _v2: Pair = + Pair::new(FiftyBytes::new(), FiftyBytes::new()); +} + +pub fn main() { + let _b: Pair = Pair::new(0, 0); + let _s: Pair = Pair::new(SevenBytes::new(), SevenBytes::new()); + let _z: ZeroSized = ZeroSized; + f1::(SevenBytes::new()); +} diff --git a/src/test/ui/print_type_sizes/generics.stdout b/src/test/ui/print_type_sizes/generics.stdout new file mode 100644 index 00000000000..0f02f397953 --- /dev/null +++ b/src/test/ui/print_type_sizes/generics.stdout @@ -0,0 +1,14 @@ +print-type-size type: `Pair`: 100 bytes, alignment: 1 bytes +print-type-size field `._car`: 50 bytes +print-type-size field `._cdr`: 50 bytes +print-type-size type: `FiftyBytes`: 50 bytes, alignment: 1 bytes +print-type-size field `.0`: 50 bytes +print-type-size type: `Pair`: 14 bytes, alignment: 1 bytes +print-type-size field `._car`: 7 bytes +print-type-size field `._cdr`: 7 bytes +print-type-size type: `SevenBytes`: 7 bytes, alignment: 1 bytes +print-type-size field `.0`: 7 bytes +print-type-size type: `Pair`: 2 bytes, alignment: 1 bytes +print-type-size field `._car`: 1 bytes +print-type-size field `._cdr`: 1 bytes +print-type-size type: `ZeroSized`: 0 bytes, alignment: 1 bytes diff --git a/src/test/ui/print_type_sizes/multiple_types.rs b/src/test/ui/print_type_sizes/multiple_types.rs new file mode 100644 index 00000000000..2b5010767fd --- /dev/null +++ b/src/test/ui/print_type_sizes/multiple_types.rs @@ -0,0 +1,28 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z print-type-sizes + +// This file illustrates that when multiple structural types occur in +// a function, every one of them is included in the output. + +pub struct SevenBytes([u8; 7]); +pub struct FiftyBytes([u8; 50]); + +pub enum Enum { + Small(SevenBytes), + Large(FiftyBytes), +} + +pub fn main() { + let _e: Enum; + let _f: FiftyBytes; + let _s: SevenBytes; +} diff --git a/src/test/ui/print_type_sizes/multiple_types.stdout b/src/test/ui/print_type_sizes/multiple_types.stdout new file mode 100644 index 00000000000..eed9af26987 --- /dev/null +++ b/src/test/ui/print_type_sizes/multiple_types.stdout @@ -0,0 +1,10 @@ +print-type-size type: `Enum`: 51 bytes, alignment: 1 bytes +print-type-size discriminant: 1 bytes +print-type-size variant `Small`: 7 bytes +print-type-size field `.0`: 7 bytes +print-type-size variant `Large`: 50 bytes +print-type-size field `.0`: 50 bytes +print-type-size type: `FiftyBytes`: 50 bytes, alignment: 1 bytes +print-type-size field `.0`: 50 bytes +print-type-size type: `SevenBytes`: 7 bytes, alignment: 1 bytes +print-type-size field `.0`: 7 bytes diff --git a/src/test/ui/print_type_sizes/no_duplicates.rs b/src/test/ui/print_type_sizes/no_duplicates.rs new file mode 100644 index 00000000000..6008a346c05 --- /dev/null +++ b/src/test/ui/print_type_sizes/no_duplicates.rs @@ -0,0 +1,25 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z print-type-sizes + +// This file illustrates that when the same type occurs repeatedly +// (even if multiple functions), it is only printed once in the +// print-type-sizes output. + +pub struct SevenBytes([u8; 7]); + +pub fn f1() { + let _s: SevenBytes = SevenBytes([0; 7]); +} + +pub fn main() { + let _s: SevenBytes = SevenBytes([0; 7]); +} diff --git a/src/test/ui/print_type_sizes/no_duplicates.stdout b/src/test/ui/print_type_sizes/no_duplicates.stdout new file mode 100644 index 00000000000..50180f356ea --- /dev/null +++ b/src/test/ui/print_type_sizes/no_duplicates.stdout @@ -0,0 +1,2 @@ +print-type-size type: `SevenBytes`: 7 bytes, alignment: 1 bytes +print-type-size field `.0`: 7 bytes diff --git a/src/test/ui/print_type_sizes/nullable.rs b/src/test/ui/print_type_sizes/nullable.rs new file mode 100644 index 00000000000..f7fdcac81da --- /dev/null +++ b/src/test/ui/print_type_sizes/nullable.rs @@ -0,0 +1,69 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z print-type-sizes + +// This file illustrates how enums with a non-null field are handled, +// modelled after cases like `Option<&u32>` and such. +// +// It uses NonZero directly, rather than `&_` or `Unique<_>`, because +// the test is not set up to deal with target-dependent pointer width. +// +// It avoids using u64/i64 because on some targets that is only 4-byte +// aligned (while on most it is 8-byte aligned) and so the resulting +// padding and overall computed sizes can be quite different. + +#![feature(nonzero)] +#![allow(dead_code)] + +extern crate core; +use core::nonzero::{NonZero, Zeroable}; + +pub enum MyOption { None, Some(T) } + +impl Default for MyOption { + fn default() -> Self { MyOption::None } +} + +pub enum EmbeddedDiscr { + None, + Record { pre: u8, val: NonZero, post: u16 }, +} + +impl Default for EmbeddedDiscr { + fn default() -> Self { EmbeddedDiscr::None } +} + +#[derive(Default)] +pub struct IndirectNonZero { + pre: u8, + nested: NestedNonZero, + post: u16, +} + +pub struct NestedNonZero { + pre: u8, + val: NonZero, + post: u16, +} + +impl Default for NestedNonZero { + fn default() -> Self { + unsafe { + NestedNonZero { pre: 0, val: NonZero::new(Default::default()), post: 0 } + } + } +} + +pub fn main() { + let _x: MyOption> = Default::default(); + let _y: EmbeddedDiscr = Default::default(); + let _z: MyOption> = Default::default(); +} diff --git a/src/test/ui/print_type_sizes/nullable.stdout b/src/test/ui/print_type_sizes/nullable.stdout new file mode 100644 index 00000000000..dd999c4a5e4 --- /dev/null +++ b/src/test/ui/print_type_sizes/nullable.stdout @@ -0,0 +1,27 @@ +print-type-size type: `IndirectNonZero`: 20 bytes, alignment: 4 bytes +print-type-size field `.pre`: 1 bytes +print-type-size padding: 3 bytes +print-type-size field `.nested`: 12 bytes, alignment: 4 bytes +print-type-size field `.post`: 2 bytes +print-type-size end padding: 2 bytes +print-type-size type: `MyOption>`: 20 bytes, alignment: 4 bytes +print-type-size variant `Some`: 20 bytes +print-type-size field `.0`: 20 bytes +print-type-size type: `EmbeddedDiscr`: 12 bytes, alignment: 4 bytes +print-type-size variant `Record`: 10 bytes +print-type-size field `.pre`: 1 bytes +print-type-size padding: 3 bytes +print-type-size field `.val`: 4 bytes, alignment: 4 bytes +print-type-size field `.post`: 2 bytes +print-type-size end padding: 2 bytes +print-type-size type: `NestedNonZero`: 12 bytes, alignment: 4 bytes +print-type-size field `.pre`: 1 bytes +print-type-size padding: 3 bytes +print-type-size field `.val`: 4 bytes, alignment: 4 bytes +print-type-size field `.post`: 2 bytes +print-type-size end padding: 2 bytes +print-type-size type: `MyOption>`: 4 bytes, alignment: 4 bytes +print-type-size variant `Some`: 4 bytes +print-type-size field `.0`: 4 bytes +print-type-size type: `core::nonzero::NonZero`: 4 bytes, alignment: 4 bytes +print-type-size field `.0`: 4 bytes diff --git a/src/test/ui/print_type_sizes/packed.rs b/src/test/ui/print_type_sizes/packed.rs new file mode 100644 index 00000000000..cd7ef86d70e --- /dev/null +++ b/src/test/ui/print_type_sizes/packed.rs @@ -0,0 +1,49 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z print-type-sizes + +// This file illustrates how packing is handled; it should cause +// the elimination of padding that would normally be introduced +// to satisfy alignment desirata. +// +// It avoids using u64/i64 because on some targets that is only 4-byte +// aligned (while on most it is 8-byte aligned) and so the resulting +// padding and overall computed sizes can be quite different. + +#![feature(untagged_unions)] + +#![allow(dead_code)] + +#[derive(Default)] +#[repr(packed)] +struct Packed { + a: u8, + b: u8, + g: i32, + c: u8, + h: i16, + d: u8, +} + +#[derive(Default)] +struct Padded { + a: u8, + b: u8, + g: i32, + c: u8, + h: i16, + d: u8, +} + +pub fn main() { + let _c: Packed = Default::default(); + let _d: Padded = Default::default(); +} diff --git a/src/test/ui/print_type_sizes/packed.stdout b/src/test/ui/print_type_sizes/packed.stdout new file mode 100644 index 00000000000..1278a7d7c92 --- /dev/null +++ b/src/test/ui/print_type_sizes/packed.stdout @@ -0,0 +1,17 @@ +print-type-size type: `Padded`: 16 bytes, alignment: 4 bytes +print-type-size field `.a`: 1 bytes +print-type-size field `.b`: 1 bytes +print-type-size padding: 2 bytes +print-type-size field `.g`: 4 bytes, alignment: 4 bytes +print-type-size field `.c`: 1 bytes +print-type-size padding: 1 bytes +print-type-size field `.h`: 2 bytes, alignment: 2 bytes +print-type-size field `.d`: 1 bytes +print-type-size end padding: 3 bytes +print-type-size type: `Packed`: 10 bytes, alignment: 1 bytes +print-type-size field `.a`: 1 bytes +print-type-size field `.b`: 1 bytes +print-type-size field `.g`: 4 bytes +print-type-size field `.c`: 1 bytes +print-type-size field `.h`: 2 bytes +print-type-size field `.d`: 1 bytes diff --git a/src/test/ui/print_type_sizes/padding.rs b/src/test/ui/print_type_sizes/padding.rs new file mode 100644 index 00000000000..af34a908ce8 --- /dev/null +++ b/src/test/ui/print_type_sizes/padding.rs @@ -0,0 +1,39 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z print-type-sizes + +// This file illustrates how padding is handled: alignment +// requirements can lead to the introduction of padding, either before +// fields or at the end of the structure as a whole. +// +// It avoids using u64/i64 because on some targets that is only 4-byte +// aligned (while on most it is 8-byte aligned) and so the resulting +// padding and overall computed sizes can be quite different. + +#![allow(dead_code)] + +struct S { + a: bool, + b: bool, + g: i32, +} + +enum E1 { + A(i32, i8), + B(S), +} + +enum E2 { + A(i8, i32), + B(S), +} + +fn main() { } diff --git a/src/test/ui/print_type_sizes/padding.stdout b/src/test/ui/print_type_sizes/padding.stdout new file mode 100644 index 00000000000..bb95f790bd9 --- /dev/null +++ b/src/test/ui/print_type_sizes/padding.stdout @@ -0,0 +1,21 @@ +print-type-size type: `E1`: 12 bytes, alignment: 4 bytes +print-type-size discriminant: 4 bytes +print-type-size variant `A`: 5 bytes +print-type-size field `.0`: 4 bytes +print-type-size field `.1`: 1 bytes +print-type-size variant `B`: 8 bytes +print-type-size field `.0`: 8 bytes +print-type-size type: `E2`: 12 bytes, alignment: 4 bytes +print-type-size discriminant: 1 bytes +print-type-size variant `A`: 7 bytes +print-type-size field `.0`: 1 bytes +print-type-size padding: 2 bytes +print-type-size field `.1`: 4 bytes, alignment: 4 bytes +print-type-size variant `B`: 11 bytes +print-type-size padding: 3 bytes +print-type-size field `.0`: 8 bytes, alignment: 4 bytes +print-type-size type: `S`: 8 bytes, alignment: 4 bytes +print-type-size field `.a`: 1 bytes +print-type-size field `.b`: 1 bytes +print-type-size padding: 2 bytes +print-type-size field `.g`: 4 bytes, alignment: 4 bytes diff --git a/src/test/ui/print_type_sizes/variants.rs b/src/test/ui/print_type_sizes/variants.rs new file mode 100644 index 00000000000..875edb4515a --- /dev/null +++ b/src/test/ui/print_type_sizes/variants.rs @@ -0,0 +1,31 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z print-type-sizes + +// This file illustrates two things: +// +// 1. Only types that appear in a monomorphized function appear in the +// print-type-sizes output, and +// +// 2. For an enum, the print-type-sizes output will also include the +// size of each variant. + +pub struct SevenBytes([u8; 7]); +pub struct FiftyBytes([u8; 50]); + +pub enum Enum { + Small(SevenBytes), + Large(FiftyBytes), +} + +pub fn main() { + let _e: Enum; +} diff --git a/src/test/ui/print_type_sizes/variants.stdout b/src/test/ui/print_type_sizes/variants.stdout new file mode 100644 index 00000000000..eed9af26987 --- /dev/null +++ b/src/test/ui/print_type_sizes/variants.stdout @@ -0,0 +1,10 @@ +print-type-size type: `Enum`: 51 bytes, alignment: 1 bytes +print-type-size discriminant: 1 bytes +print-type-size variant `Small`: 7 bytes +print-type-size field `.0`: 7 bytes +print-type-size variant `Large`: 50 bytes +print-type-size field `.0`: 50 bytes +print-type-size type: `FiftyBytes`: 50 bytes, alignment: 1 bytes +print-type-size field `.0`: 50 bytes +print-type-size type: `SevenBytes`: 7 bytes, alignment: 1 bytes +print-type-size field `.0`: 7 bytes From 4d0618ee3014b96287bb6914296b78bd474b0290 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 24 Nov 2016 21:10:08 +1100 Subject: [PATCH 053/293] Avoid more unnecessary mk_ty calls in Ty::super_fold_with. This speeds up several rustc-benchmarks by 1--5%. --- src/librustc/ty/structural_impls.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index e73be23a42c..877da7ee3b5 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -481,7 +481,12 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::TyUint(_) | ty::TyFloat(_) | ty::TyError | ty::TyInfer(_) | ty::TyParam(..) | ty::TyNever => return self }; - folder.tcx().mk_ty(sty) + + if self.sty == sty { + self + } else { + folder.tcx().mk_ty(sty) + } } fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { From 730400167ad2ce88bb48af3f36f3443ea4493d50 Mon Sep 17 00:00:00 2001 From: Robin Kruppe Date: Thu, 24 Nov 2016 17:33:47 +0100 Subject: [PATCH 054/293] Support LLVM 4.0 in OptimizationDiagnostic FFI - getMsg() changed to return std::string by-value. Fix: copy the data to a rust String during unpacking. - getPassName() changed to return StringRef --- src/librustc_llvm/diagnostic.rs | 33 +++++++++++++++++--------------- src/librustc_llvm/ffi.rs | 2 +- src/librustc_trans/back/write.rs | 2 +- src/rustllvm/RustWrapper.cpp | 9 +++++++-- 4 files changed, 27 insertions(+), 19 deletions(-) diff --git a/src/librustc_llvm/diagnostic.rs b/src/librustc_llvm/diagnostic.rs index 8767f03b3e7..e11274f2064 100644 --- a/src/librustc_llvm/diagnostic.rs +++ b/src/librustc_llvm/diagnostic.rs @@ -48,29 +48,32 @@ pub struct OptimizationDiagnostic { pub pass_name: *const c_char, pub function: ValueRef, pub debug_loc: DebugLocRef, - pub message: TwineRef, + pub message: String, } impl OptimizationDiagnostic { unsafe fn unpack(kind: OptimizationDiagnosticKind, di: DiagnosticInfoRef) -> OptimizationDiagnostic { + let mut pass_name = ptr::null(); + let mut function = ptr::null_mut(); + let mut debug_loc = ptr::null_mut(); - let mut opt = OptimizationDiagnostic { + let message = super::build_string(|message| + super::LLVMRustUnpackOptimizationDiagnostic(di, + &mut pass_name, + &mut function, + &mut debug_loc, + message) + ); + + OptimizationDiagnostic { kind: kind, - pass_name: ptr::null(), - function: ptr::null_mut(), - debug_loc: ptr::null_mut(), - message: ptr::null_mut(), - }; - - super::LLVMRustUnpackOptimizationDiagnostic(di, - &mut opt.pass_name, - &mut opt.function, - &mut opt.debug_loc, - &mut opt.message); - - opt + pass_name: pass_name, + function: function, + debug_loc: debug_loc, + message: message.expect("got a non-UTF8 OptimizationDiagnostic message from LLVM") + } } } diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 470e8d1fd45..15bca0207c7 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -1823,7 +1823,7 @@ extern "C" { pass_name_out: *mut *const c_char, function_out: *mut ValueRef, debugloc_out: *mut DebugLocRef, - message_out: *mut TwineRef); + message_out: RustStringRef); pub fn LLVMRustUnpackInlineAsmDiagnostic(DI: DiagnosticInfoRef, cookie_out: *mut c_uint, message_out: *mut TwineRef, diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 01eea08c50b..02993047258 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -417,7 +417,7 @@ unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_vo opt.kind.describe(), pass_name, if loc.is_empty() { "[unknown]" } else { &*loc }, - llvm::twine_to_string(opt.message))); + opt.message)); } } diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index b035e134e37..7cde282444d 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -871,16 +871,21 @@ LLVMRustUnpackOptimizationDiagnostic( const char **pass_name_out, LLVMValueRef *function_out, LLVMDebugLocRef *debugloc_out, - LLVMTwineRef *message_out) + RustStringRef message_out) { // Undefined to call this not on an optimization diagnostic! llvm::DiagnosticInfoOptimizationBase *opt = static_cast(unwrap(di)); +#if LLVM_VERSION_GE(4, 0) + *pass_name_out = opt->getPassName().data(); +#else *pass_name_out = opt->getPassName(); +#endif *function_out = wrap(&opt->getFunction()); *debugloc_out = wrap(&opt->getDebugLoc()); - *message_out = wrap(&opt->getMsg()); + raw_rust_string_ostream os(message_out); + os << opt->getMsg(); } extern "C" void From e1269ff68804e4ce16102cf60817f7219f6891b1 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Thu, 24 Nov 2016 16:26:21 -0500 Subject: [PATCH 055/293] Remove completed FIXME. https://github.com/rust-lang/rust/issues/30530 --- src/libstd/panicking.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 1f5b3437b61..04050a5edc4 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -153,7 +153,7 @@ pub fn take_hook() -> Box { match hook { Hook::Default => Box::new(default_hook), - Hook::Custom(ptr) => {Box::from_raw(ptr)} // FIXME #30530 + Hook::Custom(ptr) => Box::from_raw(ptr), } } } From 7d15250b0e5180137f5055b2e4333d5aac6579fe Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 22 Oct 2016 03:33:36 +0300 Subject: [PATCH 056/293] Support `?Sized` in where clauses --- src/librustc/hir/lowering.rs | 66 +++++++++++++++++-- src/librustc_passes/ast_validation.rs | 20 +++++- src/libsyntax/parse/parser.rs | 37 +++-------- .../compile-fail/maybe-bounds-where-cpass.rs | 19 ++++++ src/test/compile-fail/maybe-bounds-where.rs | 37 +++++++++++ src/test/compile-fail/maybe-bounds.rs | 17 +++++ 6 files changed, 161 insertions(+), 35 deletions(-) create mode 100644 src/test/compile-fail/maybe-bounds-where-cpass.rs create mode 100644 src/test/compile-fail/maybe-bounds-where.rs create mode 100644 src/test/compile-fail/maybe-bounds.rs diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 5af7c18e1a1..ce80f617afd 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -46,6 +46,7 @@ use hir::map::definitions::DefPathData; use hir::def_id::{DefIndex, DefId}; use hir::def::{Def, PathResolution}; use session::Session; +use util::nodemap::NodeMap; use std::collections::BTreeMap; use std::iter; @@ -394,7 +395,7 @@ impl<'a> LoweringContext<'a> { } } - fn lower_ty_param(&mut self, tp: &TyParam) -> hir::TyParam { + fn lower_ty_param(&mut self, tp: &TyParam, add_bounds: &[TyParamBound]) -> hir::TyParam { let mut name = tp.ident.name; // Don't expose `Self` (recovered "keyword used as ident" parse error). @@ -404,18 +405,26 @@ impl<'a> LoweringContext<'a> { name = Symbol::gensym("Self"); } + let mut bounds = self.lower_bounds(&tp.bounds); + if !add_bounds.is_empty() { + bounds = bounds.into_iter().chain(self.lower_bounds(add_bounds).into_iter()).collect(); + } + hir::TyParam { id: tp.id, name: name, - bounds: self.lower_bounds(&tp.bounds), + bounds: bounds, default: tp.default.as_ref().map(|x| self.lower_ty(x)), span: tp.span, pure_wrt_drop: tp.attrs.iter().any(|attr| attr.check_name("may_dangle")), } } - fn lower_ty_params(&mut self, tps: &P<[TyParam]>) -> hir::HirVec { - tps.iter().map(|tp| self.lower_ty_param(tp)).collect() + fn lower_ty_params(&mut self, tps: &P<[TyParam]>, add_bounds: &NodeMap>) + -> hir::HirVec { + tps.iter().map(|tp| { + self.lower_ty_param(tp, add_bounds.get(&tp.id).map_or(&[][..], |x| &x)) + }).collect() } fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime { @@ -447,8 +456,47 @@ impl<'a> LoweringContext<'a> { } fn lower_generics(&mut self, g: &Generics) -> hir::Generics { + // Collect `?Trait` bounds in where clause and move them to parameter definitions. + let mut add_bounds = NodeMap(); + for pred in &g.where_clause.predicates { + if let WherePredicate::BoundPredicate(ref bound_pred) = *pred { + 'next_bound: for bound in &bound_pred.bounds { + if let TraitTyParamBound(_, TraitBoundModifier::Maybe) = *bound { + let report_error = |this: &mut Self| { + this.diagnostic().span_err(bound_pred.bounded_ty.span, + "`?Trait` bounds are only permitted at the \ + point where a type parameter is declared"); + }; + // Check if the where clause type is a plain type parameter. + match bound_pred.bounded_ty.node { + TyKind::Path(None, ref path) + if !path.global && path.segments.len() == 1 && + bound_pred.bound_lifetimes.is_empty() => { + if let Some(Def::TyParam(def_id)) = + self.resolver.get_resolution(bound_pred.bounded_ty.id) + .map(|d| d.base_def) { + if let Some(node_id) = + self.resolver.definitions().as_local_node_id(def_id) { + for ty_param in &g.ty_params { + if node_id == ty_param.id { + add_bounds.entry(ty_param.id).or_insert(Vec::new()) + .push(bound.clone()); + continue 'next_bound; + } + } + } + } + report_error(self) + } + _ => report_error(self) + } + } + } + } + } + hir::Generics { - ty_params: self.lower_ty_params(&g.ty_params), + ty_params: self.lower_ty_params(&g.ty_params, &add_bounds), lifetimes: self.lower_lifetime_defs(&g.lifetimes), where_clause: self.lower_where_clause(&g.where_clause), span: g.span, @@ -474,7 +522,11 @@ impl<'a> LoweringContext<'a> { hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { bound_lifetimes: self.lower_lifetime_defs(bound_lifetimes), bounded_ty: self.lower_ty(bounded_ty), - bounds: bounds.iter().map(|x| self.lower_ty_param_bound(x)).collect(), + bounds: bounds.iter().filter_map(|bound| match *bound { + // Ignore `?Trait` bounds, they were copied into type parameters already. + TraitTyParamBound(_, TraitBoundModifier::Maybe) => None, + _ => Some(self.lower_ty_param_bound(bound)) + }).collect(), span: span, }) } @@ -563,7 +615,7 @@ impl<'a> LoweringContext<'a> { } } - fn lower_bounds(&mut self, bounds: &TyParamBounds) -> hir::TyParamBounds { + fn lower_bounds(&mut self, bounds: &[TyParamBound]) -> hir::TyParamBounds { bounds.iter().map(|bound| self.lower_ty_param_bound(bound)).collect() } diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index a3916e7eca3..fa07006aa63 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -86,6 +86,19 @@ impl<'a> AstValidator<'a> { _ => {} } } + + fn no_questions_in_bounds(&self, bounds: &TyParamBounds, where_: &str, is_trait: bool) { + for bound in bounds { + if let TraitTyParamBound(ref poly, TraitBoundModifier::Maybe) = *bound { + let mut err = self.err_handler().struct_span_err(poly.span, + &format!("`?Trait` is not permitted in {}", where_)); + if is_trait { + err.note(&format!("traits are `?{}` by default", poly.trait_ref.path)); + } + err.emit(); + } + } + } } impl<'a> Visitor for AstValidator<'a> { @@ -130,6 +143,10 @@ impl<'a> Visitor for AstValidator<'a> { err.emit(); }); } + TyKind::ObjectSum(_, ref bounds) | + TyKind::PolyTraitRef(ref bounds) => { + self.no_questions_in_bounds(bounds, "trait object types", false); + } _ => {} } @@ -189,7 +206,8 @@ impl<'a> Visitor for AstValidator<'a> { } } } - ItemKind::Trait(.., ref trait_items) => { + ItemKind::Trait(.., ref bounds, ref trait_items) => { + self.no_questions_in_bounds(bounds, "supertraits", true); for trait_item in trait_items { if let TraitItemKind::Method(ref sig, ref block) = trait_item.node { self.check_trait_fn_not_const(sig.constness); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 49226be4147..bdd1606805f 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -88,13 +88,6 @@ pub enum PathStyle { Expr, } -/// How to parse a bound, whether to allow bound modifiers such as `?`. -#[derive(Copy, Clone, PartialEq)] -pub enum BoundParsingMode { - Bare, - Modified, -} - #[derive(Clone, Copy, PartialEq)] pub enum SemiColonMode { Break, @@ -1041,7 +1034,7 @@ impl<'a> Parser<'a> { trait_ref: trait_ref, span: mk_sp(lo, hi)}; let other_bounds = if self.eat(&token::BinOp(token::Plus)) { - self.parse_ty_param_bounds(BoundParsingMode::Bare)? + self.parse_ty_param_bounds()? } else { P::new() }; @@ -1059,7 +1052,7 @@ impl<'a> Parser<'a> { The `impl` has already been consumed. */ - let bounds = self.parse_ty_param_bounds(BoundParsingMode::Modified)?; + let bounds = self.parse_ty_param_bounds()?; if !bounds.iter().any(|b| if let TraitTyParamBound(..) = *b { true } else { false }) { self.span_err(self.prev_span, "at least one trait must be specified"); @@ -1271,7 +1264,7 @@ impl<'a> Parser<'a> { return Ok(lhs); } - let bounds = self.parse_ty_param_bounds(BoundParsingMode::Bare)?; + let bounds = self.parse_ty_param_bounds()?; // In type grammar, `+` is treated like a binary operator, // and hence both L and R side are required. @@ -4148,14 +4141,12 @@ impl<'a> Parser<'a> { // Parses a sequence of bounds if a `:` is found, // otherwise returns empty list. - fn parse_colon_then_ty_param_bounds(&mut self, - mode: BoundParsingMode) - -> PResult<'a, TyParamBounds> + fn parse_colon_then_ty_param_bounds(&mut self) -> PResult<'a, TyParamBounds> { if !self.eat(&token::Colon) { Ok(P::new()) } else { - self.parse_ty_param_bounds(mode) + self.parse_ty_param_bounds() } } @@ -4163,9 +4154,7 @@ impl<'a> Parser<'a> { // where boundseq = ( polybound + boundseq ) | polybound // and polybound = ( 'for' '<' 'region '>' )? bound // and bound = 'region | trait_ref - fn parse_ty_param_bounds(&mut self, - mode: BoundParsingMode) - -> PResult<'a, TyParamBounds> + fn parse_ty_param_bounds(&mut self) -> PResult<'a, TyParamBounds> { let mut result = vec![]; loop { @@ -4187,13 +4176,7 @@ impl<'a> Parser<'a> { token::ModSep | token::Ident(..) => { let poly_trait_ref = self.parse_poly_trait_ref()?; let modifier = if ate_question { - if mode == BoundParsingMode::Modified { - TraitBoundModifier::Maybe - } else { - self.span_err(question_span, - "unexpected `?`"); - TraitBoundModifier::None - } + TraitBoundModifier::Maybe } else { TraitBoundModifier::None }; @@ -4215,7 +4198,7 @@ impl<'a> Parser<'a> { let span = self.span; let ident = self.parse_ident()?; - let bounds = self.parse_colon_then_ty_param_bounds(BoundParsingMode::Modified)?; + let bounds = self.parse_colon_then_ty_param_bounds()?; let default = if self.check(&token::Eq) { self.bump(); @@ -4439,7 +4422,7 @@ impl<'a> Parser<'a> { let bounded_ty = self.parse_ty()?; if self.eat(&token::Colon) { - let bounds = self.parse_ty_param_bounds(BoundParsingMode::Bare)?; + let bounds = self.parse_ty_param_bounds()?; let hi = self.prev_span.hi; let span = mk_sp(lo, hi); @@ -4901,7 +4884,7 @@ impl<'a> Parser<'a> { let mut tps = self.parse_generics()?; // Parse supertrait bounds. - let bounds = self.parse_colon_then_ty_param_bounds(BoundParsingMode::Bare)?; + let bounds = self.parse_colon_then_ty_param_bounds()?; tps.where_clause = self.parse_where_clause()?; diff --git a/src/test/compile-fail/maybe-bounds-where-cpass.rs b/src/test/compile-fail/maybe-bounds-where-cpass.rs new file mode 100644 index 00000000000..f10526200ff --- /dev/null +++ b/src/test/compile-fail/maybe-bounds-where-cpass.rs @@ -0,0 +1,19 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(rustc_attrs)] + +struct S(*const T) where T: ?Sized; + +#[rustc_error] +fn main() { //~ ERROR compilation successful + let u = vec![1, 2, 3]; + let _s: S<[u8]> = S(&u[..]); +} diff --git a/src/test/compile-fail/maybe-bounds-where.rs b/src/test/compile-fail/maybe-bounds-where.rs new file mode 100644 index 00000000000..211fac2ee23 --- /dev/null +++ b/src/test/compile-fail/maybe-bounds-where.rs @@ -0,0 +1,37 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct S1(T) where (T): ?Sized; +//~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared + +struct S2(T) where u8: ?Sized; +//~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared + +struct S3(T) where &'static T: ?Sized; +//~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared + +trait Trait<'a> {} + +struct S4(T) where for<'a> T: ?Trait<'a>; +//~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared + +struct S5(*const T) where T: ?Trait<'static> + ?Sized; +//~^ ERROR type parameter has more than one relaxed default bound +//~| WARN default bound relaxed for a type parameter + +impl S1 { + fn f() where T: ?Sized {} + //~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared +} + +fn main() { + let u = vec![1, 2, 3]; + let _s: S5<[u8]> = S5(&u[..]); // OK +} diff --git a/src/test/compile-fail/maybe-bounds.rs b/src/test/compile-fail/maybe-bounds.rs new file mode 100644 index 00000000000..b0b412bbf89 --- /dev/null +++ b/src/test/compile-fail/maybe-bounds.rs @@ -0,0 +1,17 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Tr: ?Sized {} //~ ERROR `?Trait` is not permitted in supertraits + //~^ NOTE traits are `?Sized` by default + +type A1 = Tr + ?Sized; //~ ERROR `?Trait` is not permitted in trait object types +type A2 = for<'a> Tr + ?Sized; //~ ERROR `?Trait` is not permitted in trait object types + +fn main() {} From 2cdde5aef494b303b6d4e634f0d5bcce02d0acdc Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Thu, 24 Nov 2016 22:12:36 +0000 Subject: [PATCH 057/293] Delay error reporting of filename mismatch. When cross compiling with procedural macros, the crate loader starts by looking for a target crate, before trying with a host crate. Rather than emitting an error immediately if the host and target extension differ, the compiler should delay it until both attempts have failed. Fixes #37899 r? @jseyfried --- src/librustc_metadata/creader.rs | 3 +++ src/librustc_metadata/locator.rs | 26 +++++++++++++++++++------- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 27c00481bfd..372152d2b0a 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -344,6 +344,7 @@ impl<'a> CrateLoader<'a> { rejected_via_triple: vec![], rejected_via_kind: vec![], rejected_via_version: vec![], + rejected_via_filename: vec![], should_match_name: true, is_proc_macro: Some(false), }; @@ -359,6 +360,7 @@ impl<'a> CrateLoader<'a> { rejected_via_triple: vec![], rejected_via_kind: vec![], rejected_via_version: vec![], + rejected_via_filename: vec![], is_proc_macro: Some(true), ..locate_ctxt }; @@ -502,6 +504,7 @@ impl<'a> CrateLoader<'a> { rejected_via_triple: vec![], rejected_via_kind: vec![], rejected_via_version: vec![], + rejected_via_filename: vec![], should_match_name: true, is_proc_macro: None, }; diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs index 868bc363791..de465ea92f6 100644 --- a/src/librustc_metadata/locator.rs +++ b/src/librustc_metadata/locator.rs @@ -269,6 +269,7 @@ pub struct Context<'a> { pub rejected_via_triple: Vec, pub rejected_via_kind: Vec, pub rejected_via_version: Vec, + pub rejected_via_filename: Vec, pub should_match_name: bool, pub is_proc_macro: Option, } @@ -417,6 +418,18 @@ impl<'a> Context<'a> { got)); } } + if !self.rejected_via_filename.is_empty() { + let dylibname = self.dylibname(); + let mismatches = self.rejected_via_filename.iter(); + for &CrateMismatch { ref path, .. } in mismatches { + err.note(&format!("extern location for {} is of an unknown type: {}", + self.crate_name, + path.display())) + .help(&format!("file name should be lib*.rlib or {}*.{}", + dylibname.0, + dylibname.1)); + } + } err.emit(); self.sess.abort_if_errors(); @@ -743,13 +756,12 @@ impl<'a> Context<'a> { return true; } } - sess.struct_err(&format!("extern location for {} is of an unknown type: {}", - self.crate_name, - loc.display())) - .help(&format!("file name should be lib*.rlib or {}*.{}", - dylibname.0, - dylibname.1)) - .emit(); + + self.rejected_via_filename.push(CrateMismatch { + path: loc.clone(), + got: String::new(), + }); + false }); From 5787643800433d6e4cb2e2750670d571fac5bdbc Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Fri, 25 Nov 2016 16:50:47 +1300 Subject: [PATCH 058/293] save-analysis: redirect a module decl to the start of the defining file --- src/librustc_save_analysis/json_dumper.rs | 56 ++++++++++++++++------- 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/src/librustc_save_analysis/json_dumper.rs b/src/librustc_save_analysis/json_dumper.rs index eb613c3afda..f97272ad544 100644 --- a/src/librustc_save_analysis/json_dumper.rs +++ b/src/librustc_save_analysis/json_dumper.rs @@ -62,7 +62,6 @@ impl<'b, W: Write + 'b> Dump for JsonDumper<'b, W> { impl_fn!(function, FunctionData, defs); impl_fn!(method, MethodData, defs); impl_fn!(macro_data, MacroData, defs); - impl_fn!(mod_data, ModData, defs); impl_fn!(typedef, TypeDefData, defs); impl_fn!(variable, VariableData, defs); @@ -75,6 +74,43 @@ impl<'b, W: Write + 'b> Dump for JsonDumper<'b, W> { impl_fn!(macro_use, MacroUseData, macro_refs); + fn mod_data(&mut self, data: ModData) { + let id: Id = From::from(data.id); + let mut def = Def { + kind: DefKind::Mod, + id: id, + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.filename, + children: data.items.into_iter().map(|id| From::from(id)).collect(), + decl_id: None, + docs: data.docs, + }; + if def.span.file_name != def.value { + // If the module is an out-of-line defintion, then we'll make the + // defintion the first character in the module's file and turn the + // the declaration into a reference to it. + let rf = Ref { + kind: RefKind::Mod, + span: def.span, + ref_id: id, + }; + self.result.refs.push(rf); + def.span = SpanData { + file_name: def.value.clone(), + byte_start: 0, + byte_end: 0, + line_start: 1, + line_end: 1, + column_start: 1, + column_end: 1, + } + } + + self.result.defs.push(def); + } + // FIXME store this instead of throwing it away. fn impl_data(&mut self, _data: ImplData) {} fn inheritance(&mut self, _data: InheritanceData) {} @@ -111,7 +147,7 @@ impl Analysis { // DefId::index is a newtype and so the JSON serialisation is ugly. Therefore // we use our own Id which is the same, but without the newtype. -#[derive(Debug, RustcEncodable)] +#[derive(Clone, Copy, Debug, RustcEncodable)] struct Id { krate: u32, index: u32, @@ -337,21 +373,7 @@ impl From for Def { } } } -impl From for Def { - fn from(data:ModData) -> Def { - Def { - kind: DefKind::Mod, - id: From::from(data.id), - span: data.span, - name: data.name, - qualname: data.qualname, - value: data.filename, - children: data.items.into_iter().map(|id| From::from(id)).collect(), - decl_id: None, - docs: data.docs, - } - } -} + impl From for Def { fn from(data: TypeDefData) -> Def { Def { From 2e6d49de07bad57f4619f70326bfa5c2e332fb89 Mon Sep 17 00:00:00 2001 From: Robin Kruppe Date: Fri, 25 Nov 2016 17:23:25 +0100 Subject: [PATCH 059/293] Pass new argument ExportSymbol to DIBuilder::createNameSpace --- src/rustllvm/RustWrapper.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index b035e134e37..62de60d3a26 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -747,7 +747,11 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateNameSpace( unwrapDI(Scope), Name, unwrapDI(File), - LineNo)); + LineNo +#if LLVM_VERSION_GE(4, 0) + , false // ExportSymbols (only relevant for C++ anonymous namespaces) +#endif + )); } extern "C" void LLVMRustDICompositeTypeSetTypeArray( From a3ce39898c6d534dd75fb617f985fc7bc8c8fb29 Mon Sep 17 00:00:00 2001 From: Vickenty Fesunov Date: Fri, 25 Nov 2016 17:59:04 +0100 Subject: [PATCH 060/293] Follow our own recommendations in the examples Remove exclamation marks from the the example error descriptions: > The description [...] should not contain newlines or sentence-ending punctuation --- src/libstd/error.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 454fa47cfbc..e115263d2eb 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -109,7 +109,7 @@ pub trait Error: Debug + Display { /// /// impl Error for SuperError { /// fn description(&self) -> &str { - /// "I'm the superhero of errors!" + /// "I'm the superhero of errors" /// } /// /// fn cause(&self) -> Option<&Error> { @@ -128,7 +128,7 @@ pub trait Error: Debug + Display { /// /// impl Error for SuperErrorSideKick { /// fn description(&self) -> &str { - /// "I'm SuperError side kick!" + /// "I'm SuperError side kick" /// } /// } /// From b1566baa0bb1a410af22bd47adf9d40de25bd402 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Fri, 25 Nov 2016 22:13:59 +0100 Subject: [PATCH 061/293] rustbuild: Add bench subcommand Add command `./x.py bench`; use `./x.py bench --help -v` to list all available benchmark targets. --- src/bootstrap/check.rs | 34 +++++++++++++++++++++++++++-- src/bootstrap/flags.rs | 17 ++++++++++++++- src/bootstrap/lib.rs | 4 +++- src/bootstrap/metadata.rs | 1 + src/bootstrap/step.rs | 46 ++++++++++++++++++++++++++++++--------- 5 files changed, 88 insertions(+), 14 deletions(-) diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index ac6be2a870b..150232e4ab4 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -15,6 +15,7 @@ use std::collections::HashSet; use std::env; +use std::fmt; use std::fs; use std::path::{PathBuf, Path}; use std::process::Command; @@ -26,6 +27,34 @@ use util::{self, dylib_path, dylib_path_var}; const ADB_TEST_DIR: &'static str = "/data/tmp"; +/// The two modes of the test runner; tests or benchmarks. +#[derive(Copy, Clone)] +pub enum TestKind { + /// Run `cargo test` + Test, + /// Run `cargo bench` + Bench, +} + +impl TestKind { + // Return the cargo subcommand for this test kind + fn subcommand(self) -> &'static str { + match self { + TestKind::Test => "test", + TestKind::Bench => "bench", + } + } +} + +impl fmt::Display for TestKind { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(match *self { + TestKind::Test => "Testing", + TestKind::Bench => "Benchmarking", + }) + } +} + /// Runs the `linkchecker` tool as compiled in `stage` by the `host` compiler. /// /// This tool in `src/tools` will verify the validity of all our links in the @@ -278,6 +307,7 @@ pub fn krate(build: &Build, compiler: &Compiler, target: &str, mode: Mode, + test_kind: TestKind, krate: Option<&str>) { let (name, path, features, root) = match mode { Mode::Libstd => { @@ -291,7 +321,7 @@ pub fn krate(build: &Build, } _ => panic!("can only test libraries"), }; - println!("Testing {} stage{} ({} -> {})", name, compiler.stage, + println!("{} {} stage{} ({} -> {})", test_kind, name, compiler.stage, compiler.host, target); // Build up the base `cargo test` command. @@ -299,7 +329,7 @@ pub fn krate(build: &Build, // Pass in some standard flags then iterate over the graph we've discovered // in `cargo metadata` with the maps above and figure out what `-p` // arguments need to get passed. - let mut cargo = build.cargo(compiler, mode, target, "test"); + let mut cargo = build.cargo(compiler, mode, target, test_kind.subcommand()); cargo.arg("--manifest-path") .arg(build.src.join(path).join("Cargo.toml")) .arg("--features").arg(features); diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index d7516954f12..a7d80e4cdc4 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -49,6 +49,10 @@ pub enum Subcommand { paths: Vec, test_args: Vec, }, + Bench { + paths: Vec, + test_args: Vec, + }, Clean, Dist { install: bool, @@ -141,6 +145,7 @@ Arguments: command == "dist" || command == "doc" || command == "test" || + command == "bench" || command == "clean" { println!("Available invocations:"); if args.iter().any(|a| a == "-v") { @@ -163,6 +168,7 @@ println!("\ Subcommands: build Compile either the compiler or libraries test Build and run some test suites + bench Build and run some benchmarks doc Build documentation clean Clean out build directories dist Build and/or install distribution artifacts @@ -210,6 +216,14 @@ To learn more about a subcommand, run `./x.py -h` test_args: m.opt_strs("test-args"), } } + "bench" => { + opts.optmulti("", "test-args", "extra arguments", "ARGS"); + m = parse(&opts); + Subcommand::Bench { + paths: remaining_as_path(&m), + test_args: m.opt_strs("test-args"), + } + } "clean" => { m = parse(&opts); if m.free.len() > 0 { @@ -259,7 +273,8 @@ To learn more about a subcommand, run `./x.py -h` impl Subcommand { pub fn test_args(&self) -> Vec<&str> { match *self { - Subcommand::Test { ref test_args, .. } => { + Subcommand::Test { ref test_args, .. } | + Subcommand::Bench { ref test_args, .. } => { test_args.iter().flat_map(|s| s.split_whitespace()).collect() } _ => Vec::new(), diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 828e82d3832..518eafb6f36 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -141,6 +141,7 @@ struct Crate { doc_step: String, build_step: String, test_step: String, + bench_step: String, } /// The various "modes" of invoking Cargo. @@ -457,7 +458,8 @@ impl Build { if self.config.verbose || self.flags.verbose { cargo.arg("-v"); } - if self.config.rust_optimize { + // FIXME: cargo bench does not accept `--release` + if self.config.rust_optimize && cmd != "bench" { cargo.arg("--release"); } if self.config.vendor { diff --git a/src/bootstrap/metadata.rs b/src/bootstrap/metadata.rs index bf5cc6a4ad8..8befb105ff6 100644 --- a/src/bootstrap/metadata.rs +++ b/src/bootstrap/metadata.rs @@ -70,6 +70,7 @@ fn build_krate(build: &mut Build, krate: &str) { build_step: format!("build-crate-{}", package.name), doc_step: format!("doc-crate-{}", package.name), test_step: format!("test-crate-{}", package.name), + bench_step: format!("bench-crate-{}", package.name), name: package.name, deps: Vec::new(), path: path, diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 56be2ccb235..4c1f58e52d9 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -11,7 +11,7 @@ use std::collections::{HashMap, HashSet}; use std::mem; -use check; +use check::{self, TestKind}; use compile; use dist; use doc; @@ -268,37 +268,55 @@ pub fn build_rules(build: &Build) -> Rules { rules.test(&krate.test_step, path) .dep(|s| s.name("libtest")) .run(move |s| check::krate(build, &s.compiler(), s.target, - Mode::Libstd, Some(&krate.name))); + Mode::Libstd, TestKind::Test, + Some(&krate.name))); } rules.test("check-std-all", "path/to/nowhere") .dep(|s| s.name("libtest")) .default(true) - .run(move |s| check::krate(build, &s.compiler(), s.target, Mode::Libstd, - None)); + .run(move |s| check::krate(build, &s.compiler(), s.target, + Mode::Libstd, TestKind::Test, None)); + + // std benchmarks + for (krate, path, _default) in krates("std_shim") { + rules.bench(&krate.bench_step, path) + .dep(|s| s.name("libtest")) + .run(move |s| check::krate(build, &s.compiler(), s.target, + Mode::Libstd, TestKind::Bench, + Some(&krate.name))); + } + rules.bench("bench-std-all", "path/to/nowhere") + .dep(|s| s.name("libtest")) + .default(true) + .run(move |s| check::krate(build, &s.compiler(), s.target, + Mode::Libstd, TestKind::Bench, None)); + for (krate, path, _default) in krates("test_shim") { rules.test(&krate.test_step, path) .dep(|s| s.name("libtest")) .run(move |s| check::krate(build, &s.compiler(), s.target, - Mode::Libtest, Some(&krate.name))); + Mode::Libtest, TestKind::Test, + Some(&krate.name))); } rules.test("check-test-all", "path/to/nowhere") .dep(|s| s.name("libtest")) .default(true) - .run(move |s| check::krate(build, &s.compiler(), s.target, Mode::Libtest, - None)); + .run(move |s| check::krate(build, &s.compiler(), s.target, + Mode::Libtest, TestKind::Test, None)); for (krate, path, _default) in krates("rustc-main") { rules.test(&krate.test_step, path) .dep(|s| s.name("librustc")) .host(true) .run(move |s| check::krate(build, &s.compiler(), s.target, - Mode::Librustc, Some(&krate.name))); + Mode::Librustc, TestKind::Test, + Some(&krate.name))); } rules.test("check-rustc-all", "path/to/nowhere") .dep(|s| s.name("librustc")) .default(true) .host(true) - .run(move |s| check::krate(build, &s.compiler(), s.target, Mode::Librustc, - None)); + .run(move |s| check::krate(build, &s.compiler(), s.target, + Mode::Librustc, TestKind::Test, None)); rules.test("check-linkchecker", "src/tools/linkchecker") .dep(|s| s.name("tool-linkchecker")) @@ -449,6 +467,7 @@ struct Rule<'a> { enum Kind { Build, Test, + Bench, Dist, Doc, } @@ -538,6 +557,11 @@ impl<'a> Rules<'a> { self.rule(name, path, Kind::Test) } + fn bench<'b>(&'b mut self, name: &'a str, path: &'a str) + -> RuleBuilder<'a, 'b> { + self.rule(name, path, Kind::Bench) + } + fn doc<'b>(&'b mut self, name: &'a str, path: &'a str) -> RuleBuilder<'a, 'b> { self.rule(name, path, Kind::Doc) @@ -583,6 +607,7 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd? "build" => Kind::Build, "doc" => Kind::Doc, "test" => Kind::Test, + "bench" => Kind::Bench, "dist" => Kind::Dist, _ => return, }; @@ -606,6 +631,7 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd? Subcommand::Build { ref paths } => (Kind::Build, &paths[..]), Subcommand::Doc { ref paths } => (Kind::Doc, &paths[..]), Subcommand::Test { ref paths, test_args: _ } => (Kind::Test, &paths[..]), + Subcommand::Bench { ref paths, test_args: _ } => (Kind::Bench, &paths[..]), Subcommand::Dist { install } => { if install { return vec![self.sbuild.name("install")] From 42e66344b5b036ae1853591786ebf22e2c66c045 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Fri, 25 Nov 2016 22:13:59 +0100 Subject: [PATCH 062/293] rustbuild: Point to core and collections's external benchmarks. --- src/libcollections/Cargo.toml | 4 ++++ src/libcore/Cargo.toml | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/src/libcollections/Cargo.toml b/src/libcollections/Cargo.toml index 65d456e750f..3056977d224 100644 --- a/src/libcollections/Cargo.toml +++ b/src/libcollections/Cargo.toml @@ -15,3 +15,7 @@ rustc_unicode = { path = "../librustc_unicode" } [[test]] name = "collectionstest" path = "../libcollectionstest/lib.rs" + +[[bench]] +name = "collectionstest" +path = "../libcollectionstest/lib.rs" diff --git a/src/libcore/Cargo.toml b/src/libcore/Cargo.toml index 3b406ac0447..a72c712ad17 100644 --- a/src/libcore/Cargo.toml +++ b/src/libcore/Cargo.toml @@ -7,7 +7,12 @@ version = "0.0.0" name = "core" path = "lib.rs" test = false +bench = false [[test]] name = "coretest" path = "../libcoretest/lib.rs" + +[[bench]] +name = "coretest" +path = "../libcoretest/lib.rs" From 56529cd2862bde1771633a2106d87eea0b02d50a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 25 Nov 2016 18:54:42 +0100 Subject: [PATCH 063/293] Add missing urls and examples to TcpStream --- src/libstd/net/tcp.rs | 193 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 185 insertions(+), 8 deletions(-) diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 159aa997b27..a3a248e5b72 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -86,18 +86,52 @@ impl TcpStream { /// documentation for concrete examples. /// In case `ToSocketAddrs::to_socket_addrs()` returns more than one entry, /// then the first valid and reachable address is used. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpStream; + /// + /// if let Ok(stream) = TcpStream::connect("127.0.0.1:8080") { + /// println!("Connected to the server!"); + /// } else { + /// println!("Couldn't connect to server..."); + /// } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn connect(addr: A) -> io::Result { super::each_addr(addr, net_imp::TcpStream::connect).map(TcpStream) } /// Returns the socket address of the remote peer of this TCP connection. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpStream}; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// assert_eq!(stream.peer_addr().unwrap(), + /// SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080))); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn peer_addr(&self) -> io::Result { self.0.peer_addr() } /// Returns the socket address of the local half of this TCP connection. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpStream}; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// assert_eq!(stream.local_addr().unwrap(), + /// SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080))); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn local_addr(&self) -> io::Result { self.0.socket_addr() @@ -107,7 +141,19 @@ impl TcpStream { /// /// This function will cause all pending and future I/O on the specified /// portions to return immediately with an appropriate value (see the - /// documentation of `Shutdown`). + /// documentation of [`Shutdown`]). + /// + /// [`Shutdown`]: ../../std/net/enum.Shutdown.html + /// + /// # Examples + /// + /// ```no_run + /// use std::net::{Shutdown, TcpStream}; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// stream.shutdown(Shutdown::Both).expect("shutdown call failed"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { self.0.shutdown(how) @@ -119,6 +165,16 @@ impl TcpStream { /// object references. Both handles will read and write the same stream of /// data, and options set on one stream will be propagated to the other /// stream. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpStream; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// let stream_clone = stream.try_clone().expect("clone failed..."); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn try_clone(&self) -> io::Result { self.0.duplicate().map(TcpStream) @@ -126,7 +182,7 @@ impl TcpStream { /// Sets the read timeout to the timeout specified. /// - /// If the value specified is `None`, then `read` calls will block + /// If the value specified is [`None`], then [`read()`] calls will block /// indefinitely. It is an error to pass the zero `Duration` to this /// method. /// @@ -134,7 +190,22 @@ impl TcpStream { /// /// Platforms may return a different error code whenever a read times out as /// a result of setting this option. For example Unix typically returns an - /// error of the kind `WouldBlock`, but Windows may return `TimedOut`. + /// error of the kind [`WouldBlock`], but Windows may return [`TimedOut`]. + /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`read()`]: ../../std/io/trait.Read.html#tymethod.read + /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock + /// [`TimedOut`]: ../../std/io/enum.ErrorKind.html#variant.TimedOut + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpStream; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// stream.set_read_timeout(None).expect("set_read_timeout call failed"); + /// ``` #[stable(feature = "socket_timeout", since = "1.4.0")] pub fn set_read_timeout(&self, dur: Option) -> io::Result<()> { self.0.set_read_timeout(dur) @@ -142,15 +213,31 @@ impl TcpStream { /// Sets the write timeout to the timeout specified. /// - /// If the value specified is `None`, then `write` calls will block - /// indefinitely. It is an error to pass the zero `Duration` to this + /// If the value specified is [`None`], then [`write()`] calls will block + /// indefinitely. It is an error to pass the zero [`Duration`] to this /// method. /// /// # Note /// /// Platforms may return a different error code whenever a write times out /// as a result of setting this option. For example Unix typically returns - /// an error of the kind `WouldBlock`, but Windows may return `TimedOut`. + /// an error of the kind [`WouldBlock`], but Windows may return [`TimedOut`]. + /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`write()`]: ../../std/io/trait.Write.html#tymethod.write + /// [`Duration`]: ../../std/time/struct.Duration.html + /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock + /// [`TimedOut`]: ../../std/io/enum.ErrorKind.html#variant.TimedOut + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpStream; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// stream.set_write_timeout(None).expect("set_write_timeout call failed"); + /// ``` #[stable(feature = "socket_timeout", since = "1.4.0")] pub fn set_write_timeout(&self, dur: Option) -> io::Result<()> { self.0.set_write_timeout(dur) @@ -158,11 +245,25 @@ impl TcpStream { /// Returns the read timeout of this socket. /// - /// If the timeout is `None`, then `read` calls will block indefinitely. + /// If the timeout is [`None`], then [`read()`] calls will block indefinitely. /// /// # Note /// /// Some platforms do not provide access to the current timeout. + /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`read()`]: ../../std/io/trait.Read.html#tymethod.read + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpStream; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// stream.set_read_timeout(None).expect("set_read_timeout call failed"); + /// assert_eq!(stream.read_timeout().unwrap(), None); + /// ``` #[stable(feature = "socket_timeout", since = "1.4.0")] pub fn read_timeout(&self) -> io::Result> { self.0.read_timeout() @@ -170,11 +271,25 @@ impl TcpStream { /// Returns the write timeout of this socket. /// - /// If the timeout is `None`, then `write` calls will block indefinitely. + /// If the timeout is [`None`], then [`write()`] calls will block indefinitely. /// /// # Note /// /// Some platforms do not provide access to the current timeout. + /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`write()`]: ../../std/io/trait.Write.html#tymethod.write + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpStream; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// stream.set_write_timeout(None).expect("set_write_timeout call failed"); + /// assert_eq!(stream.write_timeout().unwrap(), None); + /// ``` #[stable(feature = "socket_timeout", since = "1.4.0")] pub fn write_timeout(&self) -> io::Result> { self.0.write_timeout() @@ -187,6 +302,16 @@ impl TcpStream { /// small amount of data. When not set, data is buffered until there is a /// sufficient amount to send out, thereby avoiding the frequent sending of /// small packets. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpStream; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// stream.set_nodelay(true).expect("set_nodelay call failed"); + /// ``` #[stable(feature = "net2_mutators", since = "1.9.0")] pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { self.0.set_nodelay(nodelay) @@ -197,6 +322,17 @@ impl TcpStream { /// For more information about this option, see [`set_nodelay`][link]. /// /// [link]: #method.set_nodelay + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpStream; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// stream.set_nodelay(true).expect("set_nodelay call failed"); + /// assert_eq!(stream.nodelay().unwrap_or(false), true); + /// ``` #[stable(feature = "net2_mutators", since = "1.9.0")] pub fn nodelay(&self) -> io::Result { self.0.nodelay() @@ -206,6 +342,16 @@ impl TcpStream { /// /// This value sets the time-to-live field that is used in every packet sent /// from this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpStream; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// stream.set_ttl(100).expect("set_ttl call failed"); + /// ``` #[stable(feature = "net2_mutators", since = "1.9.0")] pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { self.0.set_ttl(ttl) @@ -216,6 +362,17 @@ impl TcpStream { /// For more information about this option, see [`set_ttl`][link]. /// /// [link]: #method.set_ttl + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpStream; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// stream.set_ttl(100).expect("set_ttl call failed"); + /// assert_eq!(stream.ttl().unwrap_or(0), 100); + /// ``` #[stable(feature = "net2_mutators", since = "1.9.0")] pub fn ttl(&self) -> io::Result { self.0.ttl() @@ -226,6 +383,16 @@ impl TcpStream { /// This will retrieve the stored error in the underlying socket, clearing /// the field in the process. This can be useful for checking errors between /// calls. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpStream; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// stream.take_error().expect("No error was expected..."); + /// ``` #[stable(feature = "net2_mutators", since = "1.9.0")] pub fn take_error(&self) -> io::Result> { self.0.take_error() @@ -235,6 +402,16 @@ impl TcpStream { /// /// On Unix this corresponds to calling fcntl, and on Windows this /// corresponds to calling ioctlsocket. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpStream; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// stream.set_nonblocking(true).expect("set_nonblocking call failed"); + /// ``` #[stable(feature = "net2_mutators", since = "1.9.0")] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { self.0.set_nonblocking(nonblocking) From 17cb7bdd8340d9f83450ebd3e58b9f76e11cc01b Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Sat, 26 Nov 2016 00:26:44 +0100 Subject: [PATCH 064/293] rustbuild: Add bench = false to std shim crates --- src/libcompiler_builtins/Cargo.toml | 1 + src/libpanic_abort/Cargo.toml | 1 + src/libpanic_unwind/Cargo.toml | 1 + src/librustc_unicode/Cargo.toml | 1 + src/libunwind/Cargo.toml | 1 + src/rustc/libc_shim/Cargo.toml | 1 + 6 files changed, 6 insertions(+) diff --git a/src/libcompiler_builtins/Cargo.toml b/src/libcompiler_builtins/Cargo.toml index 9e91e390a57..79570dc0252 100644 --- a/src/libcompiler_builtins/Cargo.toml +++ b/src/libcompiler_builtins/Cargo.toml @@ -8,6 +8,7 @@ version = "0.0.0" name = "compiler_builtins" path = "lib.rs" test = false +bench = false [dependencies] core = { path = "../libcore" } diff --git a/src/libpanic_abort/Cargo.toml b/src/libpanic_abort/Cargo.toml index 9d62be64fc4..d90d2864813 100644 --- a/src/libpanic_abort/Cargo.toml +++ b/src/libpanic_abort/Cargo.toml @@ -6,6 +6,7 @@ version = "0.0.0" [lib] path = "lib.rs" test = false +bench = false [dependencies] core = { path = "../libcore" } diff --git a/src/libpanic_unwind/Cargo.toml b/src/libpanic_unwind/Cargo.toml index 18f37a8bb17..90c16fff6f1 100644 --- a/src/libpanic_unwind/Cargo.toml +++ b/src/libpanic_unwind/Cargo.toml @@ -6,6 +6,7 @@ version = "0.0.0" [lib] path = "lib.rs" test = false +bench = false [dependencies] alloc = { path = "../liballoc" } diff --git a/src/librustc_unicode/Cargo.toml b/src/librustc_unicode/Cargo.toml index 1f4213f0abe..e2b4afb2a51 100644 --- a/src/librustc_unicode/Cargo.toml +++ b/src/librustc_unicode/Cargo.toml @@ -7,6 +7,7 @@ version = "0.0.0" name = "rustc_unicode" path = "lib.rs" test = false +bench = false [dependencies] core = { path = "../libcore" } diff --git a/src/libunwind/Cargo.toml b/src/libunwind/Cargo.toml index b537c6b1b71..36f361b7238 100644 --- a/src/libunwind/Cargo.toml +++ b/src/libunwind/Cargo.toml @@ -8,6 +8,7 @@ build = "build.rs" name = "unwind" path = "lib.rs" test = false +bench = false [dependencies] core = { path = "../libcore" } diff --git a/src/rustc/libc_shim/Cargo.toml b/src/rustc/libc_shim/Cargo.toml index 8fc713e0f1b..e501766fbed 100644 --- a/src/rustc/libc_shim/Cargo.toml +++ b/src/rustc/libc_shim/Cargo.toml @@ -16,6 +16,7 @@ build = "build.rs" name = "libc" path = "../../liblibc/src/lib.rs" test = false +bench = false [dependencies] core = { path = "../../libcore" } From 276d91d8cb9627eb9e748f1adb5c8c5f79ed4ae3 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Fri, 25 Nov 2016 17:43:06 -0500 Subject: [PATCH 065/293] Document how the `RwLockReadGuard` structure is created. --- src/libstd/sync/rwlock.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index f08b7641521..729ada48b44 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -77,6 +77,13 @@ unsafe impl Sync for RwLock {} /// RAII structure used to release the shared read access of a lock when /// dropped. +/// +/// This structure is created by the [`read()`] and [`try_read()`] methods on +/// [`RwLock`]. +/// +/// [`read()`]: struct.RwLock.html#method.read +/// [`try_read()`]: struct.RwLock.html#method.try_read +/// [`RwLock`]: struct.RwLock.html #[must_use] #[stable(feature = "rust1", since = "1.0.0")] pub struct RwLockReadGuard<'a, T: ?Sized + 'a> { From 6b4de8bf91f5cb21be3637de96b9fdd5a518f411 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Fri, 25 Nov 2016 17:46:12 -0500 Subject: [PATCH 066/293] Document how the `RwLockWriteGuard` structure is created. --- src/libstd/sync/rwlock.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index 729ada48b44..f83cf7ba9c2 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -95,6 +95,13 @@ impl<'a, T: ?Sized> !marker::Send for RwLockReadGuard<'a, T> {} /// RAII structure used to release the exclusive write access of a lock when /// dropped. +/// +/// This structure is created by the [`write()`] and [`try_write()`] methods +/// on [`RwLock`]. +/// +/// [`write()`]: struct.RwLock.html#method.write +/// [`try_write()`]: struct.RwLock.html#method.try_write +/// [`RwLock`]: struct.RwLock.html #[must_use] #[stable(feature = "rust1", since = "1.0.0")] pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> { From 6075af4ac0b031f738da624ee0e9962f25f57e4c Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Fri, 25 Nov 2016 17:48:45 -0500 Subject: [PATCH 067/293] Document how the `MutexGuard` structure is created. Also, end sentence with a period. --- src/libstd/sync/mutex.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 812724c7a16..df4a3746a49 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -133,7 +133,14 @@ unsafe impl Sync for Mutex { } /// dropped (falls out of scope), the lock will be unlocked. /// /// The data protected by the mutex can be access through this guard via its -/// `Deref` and `DerefMut` implementations +/// `Deref` and `DerefMut` implementations. +/// +/// This structure is created by the [`lock()`] and [`try_lock()`] methods on +/// [`Mutex`]. +/// +/// [`lock()`]: struct.Mutex.html#method.lock +/// [`try_lock()`]: struct.Mutex.html#method.try_lock +/// [`Mutex`]: struct.Mutex.html #[must_use] #[stable(feature = "rust1", since = "1.0.0")] pub struct MutexGuard<'a, T: ?Sized + 'a> { From 591c1344560c9e231738a0218770bc14c96f29ae Mon Sep 17 00:00:00 2001 From: Martin Pool Date: Sat, 26 Nov 2016 09:24:38 -0800 Subject: [PATCH 068/293] Clearer description of std::path::MAIN_SEPARATOR. --- src/libstd/path.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index bb6883236e8..03404845017 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -247,7 +247,9 @@ pub fn is_separator(c: char) -> bool { c.is_ascii() && is_sep_byte(c as u8) } -/// The primary separator for the current platform +/// The primary separator of path components for the current platform. +/// +/// For example, `/` on Unix and `\` on Windows. #[stable(feature = "rust1", since = "1.0.0")] pub const MAIN_SEPARATOR: char = ::sys::path::MAIN_SEP; From 5377b5e9c4270222cbbca99dae45715dd9d87d1c Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 19 Jul 2016 10:50:52 +0200 Subject: [PATCH 069/293] Overload get{,_mut}{,_unchecked} --- src/libcollections/lib.rs | 1 + src/libcollections/slice.rs | 18 +- src/libcore/slice.rs | 505 ++++++++++++------ src/libcoretest/slice.rs | 44 ++ .../compile-fail/indexing-requires-a-uint.rs | 2 +- src/test/compile-fail/integral-indexing.rs | 8 +- .../on-unimplemented/slice-index.rs | 17 +- 7 files changed, 407 insertions(+), 188 deletions(-) diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index f6d83b25b0d..08288b4de8b 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -54,6 +54,7 @@ #![feature(trusted_len)] #![feature(unicode)] #![feature(unique)] +#![feature(slice_get_slice)] #![cfg_attr(test, feature(rand, test))] #![no_std] diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 75796cf94bf..e615e780d2b 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -118,6 +118,8 @@ pub use core::slice::{SplitMut, ChunksMut, Split}; pub use core::slice::{SplitN, RSplitN, SplitNMut, RSplitNMut}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{from_raw_parts, from_raw_parts_mut}; +#[unstable(feature = "slice_get_slice", issue = "35729")] +pub use core::slice::SliceIndex; //////////////////////////////////////////////////////////////////////////////// // Basic slice extension methods @@ -353,7 +355,9 @@ impl [T] { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn get(&self, index: usize) -> Option<&T> { + pub fn get(&self, index: I) -> Option<&I::Output> + where I: SliceIndex + { core_slice::SliceExt::get(self, index) } @@ -372,7 +376,9 @@ impl [T] { /// or `None` if the index is out of bounds #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn get_mut(&mut self, index: usize) -> Option<&mut T> { + pub fn get_mut(&mut self, index: I) -> Option<&mut I::Output> + where I: SliceIndex + { core_slice::SliceExt::get_mut(self, index) } @@ -390,7 +396,9 @@ impl [T] { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub unsafe fn get_unchecked(&self, index: usize) -> &T { + pub unsafe fn get_unchecked(&self, index: I) -> &I::Output + where I: SliceIndex + { core_slice::SliceExt::get_unchecked(self, index) } @@ -410,7 +418,9 @@ impl [T] { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut T { + pub unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output + where I: SliceIndex + { core_slice::SliceExt::get_unchecked_mut(self, index) } diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index ede45111ebb..a4a90e7a9da 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -38,10 +38,14 @@ use cmp; use fmt; use intrinsics::assume; use iter::*; -use ops::{self, RangeFull}; +use ops::{FnMut, self}; +use option::Option; +use option::Option::{None, Some}; +use result::Result; +use result::Result::{Ok, Err}; use ptr; use mem; -use marker; +use marker::{Copy, Send, Sync, Sized, self}; use iter_private::TrustedRandomAccess; #[repr(C)] @@ -80,7 +84,8 @@ pub trait SliceExt { #[stable(feature = "core", since = "1.6.0")] fn chunks(&self, size: usize) -> Chunks; #[stable(feature = "core", since = "1.6.0")] - fn get(&self, index: usize) -> Option<&Self::Item>; + fn get(&self, index: I) -> Option<&I::Output> + where I: SliceIndex; #[stable(feature = "core", since = "1.6.0")] fn first(&self) -> Option<&Self::Item>; #[stable(feature = "core", since = "1.6.0")] @@ -90,7 +95,8 @@ pub trait SliceExt { #[stable(feature = "core", since = "1.6.0")] fn last(&self) -> Option<&Self::Item>; #[stable(feature = "core", since = "1.6.0")] - unsafe fn get_unchecked(&self, index: usize) -> &Self::Item; + unsafe fn get_unchecked(&self, index: I) -> &I::Output + where I: SliceIndex; #[stable(feature = "core", since = "1.6.0")] fn as_ptr(&self) -> *const Self::Item; #[stable(feature = "core", since = "1.6.0")] @@ -108,7 +114,8 @@ pub trait SliceExt { #[stable(feature = "core", since = "1.6.0")] fn is_empty(&self) -> bool { self.len() == 0 } #[stable(feature = "core", since = "1.6.0")] - fn get_mut(&mut self, index: usize) -> Option<&mut Self::Item>; + fn get_mut(&mut self, index: I) -> Option<&mut I::Output> + where I: SliceIndex; #[stable(feature = "core", since = "1.6.0")] fn iter_mut(&mut self) -> IterMut; #[stable(feature = "core", since = "1.6.0")] @@ -137,7 +144,8 @@ pub trait SliceExt { #[stable(feature = "core", since = "1.6.0")] fn reverse(&mut self); #[stable(feature = "core", since = "1.6.0")] - unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut Self::Item; + unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output + where I: SliceIndex; #[stable(feature = "core", since = "1.6.0")] fn as_mut_ptr(&mut self) -> *mut Self::Item; @@ -258,8 +266,10 @@ impl SliceExt for [T] { } #[inline] - fn get(&self, index: usize) -> Option<&T> { - if index < self.len() { Some(&self[index]) } else { None } + fn get(&self, index: I) -> Option<&I::Output> + where I: SliceIndex + { + index.get(self) } #[inline] @@ -284,8 +294,10 @@ impl SliceExt for [T] { } #[inline] - unsafe fn get_unchecked(&self, index: usize) -> &T { - &*(self.as_ptr().offset(index as isize)) + unsafe fn get_unchecked(&self, index: I) -> &I::Output + where I: SliceIndex + { + index.get_unchecked(self) } #[inline] @@ -323,8 +335,10 @@ impl SliceExt for [T] { } #[inline] - fn get_mut(&mut self, index: usize) -> Option<&mut T> { - if index < self.len() { Some(&mut self[index]) } else { None } + fn get_mut(&mut self, index: I) -> Option<&mut I::Output> + where I: SliceIndex + { + index.get_mut(self) } #[inline] @@ -451,8 +465,10 @@ impl SliceExt for [T] { } #[inline] - unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut T { - &mut *self.as_mut_ptr().offset(index as isize) + unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output + where I: SliceIndex + { + index.get_unchecked_mut(self) } #[inline] @@ -515,23 +531,26 @@ impl SliceExt for [T] { } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented = "slice indices are of type `usize`"] -impl ops::Index for [T] { - type Output = T; +#[rustc_on_unimplemented = "slice indices are of type `usize` or ranges of `usize`"] +impl ops::Index for [T] + where I: SliceIndex +{ + type Output = I::Output; - fn index(&self, index: usize) -> &T { - // NB built-in indexing - &(*self)[index] + #[inline] + fn index(&self, index: I) -> &I::Output { + index.index(self) } } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented = "slice indices are of type `usize`"] -impl ops::IndexMut for [T] { +#[rustc_on_unimplemented = "slice indices are of type `usize` or ranges of `usize`"] +impl ops::IndexMut for [T] + where I: SliceIndex +{ #[inline] - fn index_mut(&mut self, index: usize) -> &mut T { - // NB built-in indexing - &mut (*self)[index] + fn index_mut(&mut self, index: I) -> &mut I::Output { + index.index_mut(self) } } @@ -547,205 +566,349 @@ fn slice_index_order_fail(index: usize, end: usize) -> ! { panic!("slice index starts at {} but ends at {}", index, end); } +/// A helper trait used for indexing operations. +#[unstable(feature = "slice_get_slice", issue = "35729")] +#[rustc_on_unimplemented = "slice indices are of type `usize` or ranges of `usize`"] +pub trait SliceIndex { + /// The output type returned by methods. + type Output: ?Sized; -/// Implements slicing with syntax `&self[begin .. end]`. -/// -/// Returns a slice of self for the index range [`begin`..`end`). -/// -/// This operation is `O(1)`. -/// -/// # Panics -/// -/// Requires that `begin <= end` and `end <= self.len()`, -/// otherwise slicing will panic. -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented = "slice indices are of type `usize`"] -impl ops::Index> for [T] { + /// Returns a shared reference to the output at this location, if in + /// bounds. + fn get(self, slice: &[T]) -> Option<&Self::Output>; + + /// Returns a mutable reference to the output at this location, if in + /// bounds. + fn get_mut(self, slice: &mut [T]) -> Option<&mut Self::Output>; + + /// Returns a shared reference to the output at this location, without + /// performing any bounds checking. + unsafe fn get_unchecked(self, slice: &[T]) -> &Self::Output; + + /// Returns a mutable reference to the output at this location, without + /// performing any bounds checking. + unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut Self::Output; + + /// Returns a shared reference to the output at this location, panicking + /// if out of bounds. + fn index(self, slice: &[T]) -> &Self::Output; + + /// Returns a mutable reference to the output at this location, panicking + /// if out of bounds. + fn index_mut(self, slice: &mut [T]) -> &mut Self::Output; +} + +#[stable(feature = "slice-get-slice-impls", since = "1.13.0")] +impl SliceIndex for usize { + type Output = T; + + #[inline] + fn get(self, slice: &[T]) -> Option<&T> { + if self < slice.len() { + unsafe { + Some(self.get_unchecked(slice)) + } + } else { + None + } + } + + #[inline] + fn get_mut(self, slice: &mut [T]) -> Option<&mut T> { + if self < slice.len() { + unsafe { + Some(self.get_unchecked_mut(slice)) + } + } else { + None + } + } + + #[inline] + unsafe fn get_unchecked(self, slice: &[T]) -> &T { + &*slice.as_ptr().offset(self as isize) + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut T { + &mut *slice.as_mut_ptr().offset(self as isize) + } + + #[inline] + fn index(self, slice: &[T]) -> &T { + // NB: use intrinsic indexing + &(*slice)[self] + } + + #[inline] + fn index_mut(self, slice: &mut [T]) -> &mut T { + // NB: use intrinsic indexing + &mut (*slice)[self] + } +} + +#[stable(feature = "slice-get-slice-impls", since = "1.13.0")] +impl SliceIndex for ops::Range { type Output = [T]; #[inline] - fn index(&self, index: ops::Range) -> &[T] { - if index.start > index.end { - slice_index_order_fail(index.start, index.end); - } else if index.end > self.len() { - slice_index_len_fail(index.end, self.len()); + fn get(self, slice: &[T]) -> Option<&[T]> { + if self.start > self.end || self.end > slice.len() { + None + } else { + unsafe { + Some(self.get_unchecked(slice)) + } + } + } + + #[inline] + fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { + if self.start > self.end || self.end > slice.len() { + None + } else { + unsafe { + Some(self.get_unchecked_mut(slice)) + } + } + } + + #[inline] + unsafe fn get_unchecked(self, slice: &[T]) -> &[T] { + from_raw_parts(slice.as_ptr().offset(self.start as isize), self.end - self.start) + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] { + from_raw_parts_mut(slice.as_mut_ptr().offset(self.start as isize), self.end - self.start) + } + + #[inline] + fn index(self, slice: &[T]) -> &[T] { + if self.start > self.end { + slice_index_order_fail(self.start, self.end); + } else if self.end > slice.len() { + slice_index_len_fail(self.end, slice.len()); } unsafe { - from_raw_parts ( - self.as_ptr().offset(index.start as isize), - index.end - index.start - ) + self.get_unchecked(slice) + } + } + + #[inline] + fn index_mut(self, slice: &mut [T]) -> &mut [T] { + if self.start > self.end { + slice_index_order_fail(self.start, self.end); + } else if self.end > slice.len() { + slice_index_len_fail(self.end, slice.len()); + } + unsafe { + self.get_unchecked_mut(slice) } } } -/// Implements slicing with syntax `&self[.. end]`. -/// -/// Returns a slice of self from the beginning until but not including -/// the index `end`. -/// -/// Equivalent to `&self[0 .. end]` -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented = "slice indices are of type `usize`"] -impl ops::Index> for [T] { +#[stable(feature = "slice-get-slice-impls", since = "1.13.0")] +impl SliceIndex for ops::RangeTo { type Output = [T]; #[inline] - fn index(&self, index: ops::RangeTo) -> &[T] { - self.index(0 .. index.end) + fn get(self, slice: &[T]) -> Option<&[T]> { + (0..self.end).get(slice) + } + + #[inline] + fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { + (0..self.end).get_mut(slice) + } + + #[inline] + unsafe fn get_unchecked(self, slice: &[T]) -> &[T] { + (0..self.end).get_unchecked(slice) + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] { + (0..self.end).get_unchecked_mut(slice) + } + + #[inline] + fn index(self, slice: &[T]) -> &[T] { + (0..self.end).index(slice) + } + + #[inline] + fn index_mut(self, slice: &mut [T]) -> &mut [T] { + (0..self.end).index_mut(slice) } } -/// Implements slicing with syntax `&self[begin ..]`. -/// -/// Returns a slice of self from and including the index `begin` until the end. -/// -/// Equivalent to `&self[begin .. self.len()]` -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented = "slice indices are of type `usize`"] -impl ops::Index> for [T] { +#[stable(feature = "slice-get-slice-impls", since = "1.13.0")] +impl SliceIndex for ops::RangeFrom { type Output = [T]; #[inline] - fn index(&self, index: ops::RangeFrom) -> &[T] { - self.index(index.start .. self.len()) + fn get(self, slice: &[T]) -> Option<&[T]> { + (self.start..slice.len()).get(slice) + } + + #[inline] + fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { + (self.start..slice.len()).get_mut(slice) + } + + #[inline] + unsafe fn get_unchecked(self, slice: &[T]) -> &[T] { + (self.start..slice.len()).get_unchecked(slice) + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] { + (self.start..slice.len()).get_unchecked_mut(slice) + } + + #[inline] + fn index(self, slice: &[T]) -> &[T] { + (self.start..slice.len()).index(slice) + } + + #[inline] + fn index_mut(self, slice: &mut [T]) -> &mut [T] { + (self.start..slice.len()).index_mut(slice) } } -/// Implements slicing with syntax `&self[..]`. -/// -/// Returns a slice of the whole slice. This operation cannot panic. -/// -/// Equivalent to `&self[0 .. self.len()]` -#[stable(feature = "rust1", since = "1.0.0")] -impl ops::Index for [T] { +#[stable(feature = "slice-get-slice-impls", since = "1.13.0")] +impl SliceIndex for ops::RangeFull { type Output = [T]; #[inline] - fn index(&self, _index: RangeFull) -> &[T] { - self + fn get(self, slice: &[T]) -> Option<&[T]> { + Some(slice) + } + + #[inline] + fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { + Some(slice) + } + + #[inline] + unsafe fn get_unchecked(self, slice: &[T]) -> &[T] { + slice + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] { + slice + } + + #[inline] + fn index(self, slice: &[T]) -> &[T] { + slice + } + + #[inline] + fn index_mut(self, slice: &mut [T]) -> &mut [T] { + slice } } -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] -#[rustc_on_unimplemented = "slice indices are of type `usize`"] -impl ops::Index> for [T] { + +#[stable(feature = "slice-get-slice-impls", since = "1.13.0")] +impl SliceIndex for ops::RangeInclusive { type Output = [T]; #[inline] - fn index(&self, index: ops::RangeInclusive) -> &[T] { - match index { + fn get(self, slice: &[T]) -> Option<&[T]> { + match self { + ops::RangeInclusive::Empty { .. } => Some(&[]), + ops::RangeInclusive::NonEmpty { end, .. } if end == usize::max_value() => None, + ops::RangeInclusive::NonEmpty { start, end } => (start..end + 1).get(slice), + } + } + + #[inline] + fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { + match self { + ops::RangeInclusive::Empty { .. } => Some(&mut []), + ops::RangeInclusive::NonEmpty { end, .. } if end == usize::max_value() => None, + ops::RangeInclusive::NonEmpty { start, end } => (start..end + 1).get_mut(slice), + } + } + + #[inline] + unsafe fn get_unchecked(self, slice: &[T]) -> &[T] { + match self { ops::RangeInclusive::Empty { .. } => &[], - ops::RangeInclusive::NonEmpty { end, .. } if end == usize::max_value() => - panic!("attempted to index slice up to maximum usize"), - ops::RangeInclusive::NonEmpty { start, end } => - self.index(start .. end+1) + ops::RangeInclusive::NonEmpty { start, end } => (start..end + 1).get_unchecked(slice), + } + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] { + match self { + ops::RangeInclusive::Empty { .. } => &mut [], + ops::RangeInclusive::NonEmpty { start, end } => { + (start..end + 1).get_unchecked_mut(slice) + } + } + } + + #[inline] + fn index(self, slice: &[T]) -> &[T] { + match self { + ops::RangeInclusive::Empty { .. } => &[], + ops::RangeInclusive::NonEmpty { end, .. } if end == usize::max_value() => { + panic!("attempted to index slice up to maximum usize"); + }, + ops::RangeInclusive::NonEmpty { start, end } => (start..end + 1).index(slice), + } + } + + #[inline] + fn index_mut(self, slice: &mut [T]) -> &mut [T] { + match self { + ops::RangeInclusive::Empty { .. } => &mut [], + ops::RangeInclusive::NonEmpty { end, .. } if end == usize::max_value() => { + panic!("attempted to index slice up to maximum usize"); + }, + ops::RangeInclusive::NonEmpty { start, end } => (start..end + 1).index_mut(slice), } } } -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] -#[rustc_on_unimplemented = "slice indices are of type `usize`"] -impl ops::Index> for [T] { + +#[stable(feature = "slice-get-slice-impls", since = "1.13.0")] +impl SliceIndex for ops::RangeToInclusive { type Output = [T]; #[inline] - fn index(&self, index: ops::RangeToInclusive) -> &[T] { - self.index(0...index.end) + fn get(self, slice: &[T]) -> Option<&[T]> { + (0...self.end).get(slice) } -} -/// Implements mutable slicing with syntax `&mut self[begin .. end]`. -/// -/// Returns a slice of self for the index range [`begin`..`end`). -/// -/// This operation is `O(1)`. -/// -/// # Panics -/// -/// Requires that `begin <= end` and `end <= self.len()`, -/// otherwise slicing will panic. -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented = "slice indices are of type `usize`"] -impl ops::IndexMut> for [T] { #[inline] - fn index_mut(&mut self, index: ops::Range) -> &mut [T] { - if index.start > index.end { - slice_index_order_fail(index.start, index.end); - } else if index.end > self.len() { - slice_index_len_fail(index.end, self.len()); - } - unsafe { - from_raw_parts_mut( - self.as_mut_ptr().offset(index.start as isize), - index.end - index.start - ) - } + fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { + (0...self.end).get_mut(slice) } -} -/// Implements mutable slicing with syntax `&mut self[.. end]`. -/// -/// Returns a slice of self from the beginning until but not including -/// the index `end`. -/// -/// Equivalent to `&mut self[0 .. end]` -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented = "slice indices are of type `usize`"] -impl ops::IndexMut> for [T] { #[inline] - fn index_mut(&mut self, index: ops::RangeTo) -> &mut [T] { - self.index_mut(0 .. index.end) + unsafe fn get_unchecked(self, slice: &[T]) -> &[T] { + (0...self.end).get_unchecked(slice) } -} -/// Implements mutable slicing with syntax `&mut self[begin ..]`. -/// -/// Returns a slice of self from and including the index `begin` until the end. -/// -/// Equivalent to `&mut self[begin .. self.len()]` -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented = "slice indices are of type `usize`"] -impl ops::IndexMut> for [T] { #[inline] - fn index_mut(&mut self, index: ops::RangeFrom) -> &mut [T] { - let len = self.len(); - self.index_mut(index.start .. len) + unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] { + (0...self.end).get_unchecked_mut(slice) } -} -/// Implements mutable slicing with syntax `&mut self[..]`. -/// -/// Returns a slice of the whole slice. This operation can not panic. -/// -/// Equivalent to `&mut self[0 .. self.len()]` -#[stable(feature = "rust1", since = "1.0.0")] -impl ops::IndexMut for [T] { #[inline] - fn index_mut(&mut self, _index: RangeFull) -> &mut [T] { - self + fn index(self, slice: &[T]) -> &[T] { + (0...self.end).index(slice) } -} -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] -#[rustc_on_unimplemented = "slice indices are of type `usize`"] -impl ops::IndexMut> for [T] { #[inline] - fn index_mut(&mut self, index: ops::RangeInclusive) -> &mut [T] { - match index { - ops::RangeInclusive::Empty { .. } => &mut [], - ops::RangeInclusive::NonEmpty { end, .. } if end == usize::max_value() => - panic!("attempted to index slice up to maximum usize"), - ops::RangeInclusive::NonEmpty { start, end } => - self.index_mut(start .. end+1) - } - } -} -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] -#[rustc_on_unimplemented = "slice indices are of type `usize`"] -impl ops::IndexMut> for [T] { - #[inline] - fn index_mut(&mut self, index: ops::RangeToInclusive) -> &mut [T] { - self.index_mut(0...index.end) + fn index_mut(self, slice: &mut [T]) -> &mut [T] { + (0...self.end).index_mut(slice) } } diff --git a/src/libcoretest/slice.rs b/src/libcoretest/slice.rs index f82ab44adad..ad39e6b081b 100644 --- a/src/libcoretest/slice.rs +++ b/src/libcoretest/slice.rs @@ -180,3 +180,47 @@ fn test_windows_last() { let c2 = v2.windows(2); assert_eq!(c2.last().unwrap()[0], 3); } + +#[test] +fn get_range() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + assert_eq!(v.get(..), Some(&[0, 1, 2, 3, 4, 5][..])); + assert_eq!(v.get(..2), Some(&[0, 1][..])); + assert_eq!(v.get(2..), Some(&[2, 3, 4, 5][..])); + assert_eq!(v.get(1..4), Some(&[1, 2, 3][..])); + assert_eq!(v.get(7..), None); + assert_eq!(v.get(7..10), None); +} + +#[test] +fn get_mut_range() { + let mut v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + assert_eq!(v.get_mut(..), Some(&mut [0, 1, 2, 3, 4, 5][..])); + assert_eq!(v.get_mut(..2), Some(&mut [0, 1][..])); + assert_eq!(v.get_mut(2..), Some(&mut [2, 3, 4, 5][..])); + assert_eq!(v.get_mut(1..4), Some(&mut [1, 2, 3][..])); + assert_eq!(v.get_mut(7..), None); + assert_eq!(v.get_mut(7..10), None); +} + +#[test] +fn get_unchecked_range() { + unsafe { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + assert_eq!(v.get_unchecked(..), &[0, 1, 2, 3, 4, 5][..]); + assert_eq!(v.get_unchecked(..2), &[0, 1][..]); + assert_eq!(v.get_unchecked(2..), &[2, 3, 4, 5][..]); + assert_eq!(v.get_unchecked(1..4), &[1, 2, 3][..]); + } +} + +#[test] +fn get_unchecked_mut_range() { + unsafe { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + assert_eq!(v.get_unchecked_mut(..), &mut [0, 1, 2, 3, 4, 5][..]); + assert_eq!(v.get_unchecked_mut(..2), &mut [0, 1][..]); + assert_eq!(v.get_unchecked_mut(2..), &mut[2, 3, 4, 5][..]); + assert_eq!(v.get_unchecked_mut(1..4), &mut [1, 2, 3][..]); + } +} diff --git a/src/test/compile-fail/indexing-requires-a-uint.rs b/src/test/compile-fail/indexing-requires-a-uint.rs index 61d54b3f8e4..1889d76c03c 100644 --- a/src/test/compile-fail/indexing-requires-a-uint.rs +++ b/src/test/compile-fail/indexing-requires-a-uint.rs @@ -13,7 +13,7 @@ fn main() { fn bar(_: T) {} - [0][0u8]; //~ ERROR: `[{integer}]: std::ops::Index` is not satisfied + [0][0u8]; //~ ERROR: the trait bound `u8: std::slice::SliceIndex<{integer}>` is not satisfied [0][0]; // should infer to be a usize diff --git a/src/test/compile-fail/integral-indexing.rs b/src/test/compile-fail/integral-indexing.rs index c8f33c3caf8..1815d0e978a 100644 --- a/src/test/compile-fail/integral-indexing.rs +++ b/src/test/compile-fail/integral-indexing.rs @@ -19,8 +19,8 @@ pub fn main() { v[3i32]; //~ERROR : std::ops::Index` is not satisfied s.as_bytes()[3_usize]; s.as_bytes()[3]; - s.as_bytes()[3u8]; //~ERROR : std::ops::Index` is not satisfied - s.as_bytes()[3i8]; //~ERROR : std::ops::Index` is not satisfied - s.as_bytes()[3u32]; //~ERROR : std::ops::Index` is not satisfied - s.as_bytes()[3i32]; //~ERROR : std::ops::Index` is not satisfied + s.as_bytes()[3u8]; //~ERROR : std::slice::SliceIndex` is not satisfied + s.as_bytes()[3i8]; //~ERROR : std::slice::SliceIndex` is not satisfied + s.as_bytes()[3u32]; //~ERROR : std::slice::SliceIndex` is not satisfied + s.as_bytes()[3i32]; //~ERROR : std::slice::SliceIndex` is not satisfied } diff --git a/src/test/compile-fail/on-unimplemented/slice-index.rs b/src/test/compile-fail/on-unimplemented/slice-index.rs index d528d0e626a..d28b823ddc1 100644 --- a/src/test/compile-fail/on-unimplemented/slice-index.rs +++ b/src/test/compile-fail/on-unimplemented/slice-index.rs @@ -9,6 +9,7 @@ // except according to those terms. // Test new Index error message for slices +// ignore-tidy-linelength #![feature(rustc_attrs)] @@ -17,12 +18,12 @@ use std::ops::Index; #[rustc_error] fn main() { let x = &[1, 2, 3] as &[i32]; - x[1i32]; - //~^ ERROR E0277 - //~| NOTE the trait `std::ops::Index` is not implemented for `[i32]` - //~| NOTE slice indices are of type `usize` - x[..1i32]; - //~^ ERROR E0277 - //~| NOTE the trait `std::ops::Index>` is not implemented for `[i32]` - //~| NOTE slice indices are of type `usize` + x[1i32]; //~ ERROR E0277 + //~| NOTE slice indices are of type `usize` or ranges of `usize` + //~| NOTE trait `std::slice::SliceIndex` is not implemented for `i32` + //~| NOTE required because of the requirements on the impl of `std::ops::Index` + x[..1i32]; //~ ERROR E0277 + //~| NOTE slice indices are of type `usize` or ranges of `usize` + //~| NOTE trait `std::slice::SliceIndex` is not implemented for `std::ops::RangeTo` + //~| NOTE requirements on the impl of `std::ops::Index>` } From 9fb81b92f9f04d4715a5ff474fd976a695bd3fe1 Mon Sep 17 00:00:00 2001 From: Andrew Lygin Date: Fri, 25 Nov 2016 22:58:30 +0300 Subject: [PATCH 070/293] Fix error explanation formatting --- src/librustc_metadata/diagnostics.rs | 7 ++++--- src/librustc_typeck/diagnostics.rs | 5 +++-- src/libsyntax/diagnostic_list.rs | 10 +++++----- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/librustc_metadata/diagnostics.rs b/src/librustc_metadata/diagnostics.rs index b2f4760727a..e327be3d503 100644 --- a/src/librustc_metadata/diagnostics.rs +++ b/src/librustc_metadata/diagnostics.rs @@ -56,9 +56,10 @@ An unknown "kind" was specified for a link attribute. Erroneous code example: ``` Please specify a valid "kind" value, from one of the following: - * static - * dylib - * framework + + - static + - dylib + - framework "##, E0459: r##" diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index f5432c6e0fc..e64a312d8e1 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1377,8 +1377,9 @@ let x = |_| {}; // error: cannot determine a type for this expression ``` You have two possibilities to solve this situation: - * Give an explicit definition of the expression - * Infer the expression + + - Give an explicit definition of the expression + - Infer the expression Examples: diff --git a/src/libsyntax/diagnostic_list.rs b/src/libsyntax/diagnostic_list.rs index 9110e989a8a..ace3af0f102 100644 --- a/src/libsyntax/diagnostic_list.rs +++ b/src/libsyntax/diagnostic_list.rs @@ -65,8 +65,8 @@ fn main() {} The `inline` attribute only supports two arguments: - * always - * never + - always + - never All other arguments given to the `inline` attribute will return this error. Example: @@ -121,9 +121,9 @@ pub fn main() {} The `cfg` attribute supports only three kinds of predicates: - * any - * all - * not + - any + - all + - not Example: From 984c039e4e08ab28dca9bec2fa20baf4c0f4452a Mon Sep 17 00:00:00 2001 From: Andrew Lygin Date: Sat, 26 Nov 2016 21:19:30 +0300 Subject: [PATCH 071/293] Fix error explanation formatting --- src/librustc_metadata/diagnostics.rs | 7 ++++--- src/librustc_typeck/diagnostics.rs | 4 ++-- src/libsyntax/diagnostic_list.rs | 10 +++++----- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/librustc_metadata/diagnostics.rs b/src/librustc_metadata/diagnostics.rs index e327be3d503..6cf1a9e8a39 100644 --- a/src/librustc_metadata/diagnostics.rs +++ b/src/librustc_metadata/diagnostics.rs @@ -57,9 +57,10 @@ An unknown "kind" was specified for a link attribute. Erroneous code example: Please specify a valid "kind" value, from one of the following: - - static - - dylib - - framework + * static + * dylib + * framework + "##, E0459: r##" diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index e64a312d8e1..04314045733 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1378,8 +1378,8 @@ let x = |_| {}; // error: cannot determine a type for this expression You have two possibilities to solve this situation: - - Give an explicit definition of the expression - - Infer the expression + * Give an explicit definition of the expression + * Infer the expression Examples: diff --git a/src/libsyntax/diagnostic_list.rs b/src/libsyntax/diagnostic_list.rs index ace3af0f102..9110e989a8a 100644 --- a/src/libsyntax/diagnostic_list.rs +++ b/src/libsyntax/diagnostic_list.rs @@ -65,8 +65,8 @@ fn main() {} The `inline` attribute only supports two arguments: - - always - - never + * always + * never All other arguments given to the `inline` attribute will return this error. Example: @@ -121,9 +121,9 @@ pub fn main() {} The `cfg` attribute supports only three kinds of predicates: - - any - - all - - not + * any + * all + * not Example: From ebcc6d2571aa462657ced6f1b917d2c99fcea008 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 26 Nov 2016 21:35:41 +0100 Subject: [PATCH 072/293] Add part of missing UdpSocket's urls and examples --- src/libstd/net/udp.rs | 226 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 215 insertions(+), 11 deletions(-) diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index 559250adac5..b280f466dd4 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -48,8 +48,18 @@ pub struct UdpSocket(net_imp::UdpSocket); impl UdpSocket { /// Creates a UDP socket from the given address. /// - /// The address type can be any implementor of `ToSocketAddr` trait. See + /// The address type can be any implementor of [`ToSocketAddrs`] trait. See /// its documentation for concrete examples. + /// + /// [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn bind(addr: A) -> io::Result { super::each_addr(addr, net_imp::UdpSocket::bind).map(UdpSocket) @@ -57,6 +67,17 @@ impl UdpSocket { /// Receives data from the socket. On success, returns the number of bytes /// read and the address from whence the data came. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// let mut buf = [0; 10]; + /// let (number_of_bytes, src_addr) = socket.recv_from(&mut buf) + /// .expect("Didn't receive data"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { self.0.recv_from(buf) @@ -65,11 +86,24 @@ impl UdpSocket { /// Sends data on the socket to the given address. On success, returns the /// number of bytes written. /// - /// Address type can be any implementor of `ToSocketAddrs` trait. See its + /// Address type can be any implementor of [`ToSocketAddrs`] trait. See its /// documentation for concrete examples. + /// /// This will return an error when the IP version of the local socket - /// does not match that returned from `ToSocketAddrs` + /// does not match that returned from [`ToSocketAddrs`]. + /// /// See https://github.com/rust-lang/rust/issues/34202 for more details. + /// + /// [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.send_to(&[0; 10], "127.0.0.1:4242").expect("couldn't send data"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn send_to(&self, buf: &[u8], addr: A) -> io::Result { @@ -81,6 +115,16 @@ impl UdpSocket { } /// Returns the socket address that this socket was created from. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket}; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// assert_eq!(socket.local_addr().unwrap(), + /// SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 34254))); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn local_addr(&self) -> io::Result { self.0.socket_addr() @@ -91,6 +135,15 @@ impl UdpSocket { /// The returned `UdpSocket` is a reference to the same socket that this /// object references. Both handles will read and write the same port, and /// options set on one socket will be propagated to the other. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// let socket_clone = socket.try_clone().expect("couldn't clone the socket"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn try_clone(&self) -> io::Result { self.0.duplicate().map(UdpSocket) @@ -98,15 +151,30 @@ impl UdpSocket { /// Sets the read timeout to the timeout specified. /// - /// If the value specified is `None`, then `read` calls will block - /// indefinitely. It is an error to pass the zero `Duration` to this + /// If the value specified is [`None`], then [`read()`] calls will block + /// indefinitely. It is an error to pass the zero [`Duration`] to this /// method. /// /// # Note /// /// Platforms may return a different error code whenever a read times out as /// a result of setting this option. For example Unix typically returns an - /// error of the kind `WouldBlock`, but Windows may return `TimedOut`. + /// error of the kind [`WouldBlock`], but Windows may return [`TimedOut`]. + /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`read()`]: ../../std/io/trait.Read.html#tymethod.read + /// [`Duration`]: ../../std/time/struct.Duration.html + /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock + /// [`TimedOut`]: ../../std/io/enum.ErrorKind.html#variant.TimedOut + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.set_read_timeout(None).expect("set_read_timeout call failed"); + /// ``` #[stable(feature = "socket_timeout", since = "1.4.0")] pub fn set_read_timeout(&self, dur: Option) -> io::Result<()> { self.0.set_read_timeout(dur) @@ -114,15 +182,30 @@ impl UdpSocket { /// Sets the write timeout to the timeout specified. /// - /// If the value specified is `None`, then `write` calls will block - /// indefinitely. It is an error to pass the zero `Duration` to this + /// If the value specified is [`None`], then [`write()`] calls will block + /// indefinitely. It is an error to pass the zero [`Duration`] to this /// method. /// /// # Note /// /// Platforms may return a different error code whenever a write times out /// as a result of setting this option. For example Unix typically returns - /// an error of the kind `WouldBlock`, but Windows may return `TimedOut`. + /// an error of the kind [`WouldBlock`], but Windows may return [`TimedOut`]. + /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`write()`]: ../../std/io/trait.Write.html#tymethod.write + /// [`Duration`]: ../../std/time/struct.Duration.html + /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock + /// [`TimedOut`]: ../../std/io/enum.ErrorKind.html#variant.TimedOut + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.set_write_timeout(None).expect("set_write_timeout call failed"); + /// ``` #[stable(feature = "socket_timeout", since = "1.4.0")] pub fn set_write_timeout(&self, dur: Option) -> io::Result<()> { self.0.set_write_timeout(dur) @@ -130,7 +213,20 @@ impl UdpSocket { /// Returns the read timeout of this socket. /// - /// If the timeout is `None`, then `read` calls will block indefinitely. + /// If the timeout is [`None`], then [`read()`] calls will block indefinitely. + /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`read()`]: ../../std/io/trait.Read.html#tymethod.read + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.set_read_timeout(None).expect("set_read_timeout call failed"); + /// assert_eq!(socket.read_timeout().unwrap(), None); + /// ``` #[stable(feature = "socket_timeout", since = "1.4.0")] pub fn read_timeout(&self) -> io::Result> { self.0.read_timeout() @@ -138,7 +234,20 @@ impl UdpSocket { /// Returns the write timeout of this socket. /// - /// If the timeout is `None`, then `write` calls will block indefinitely. + /// If the timeout is [`None`], then [`write()`] calls will block indefinitely. + /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`write()`]: ../../std/io/trait.Write.html#tymethod.write + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.set_write_timeout(None).expect("set_write_timeout call failed"); + /// assert_eq!(socket.write_timeout().unwrap(), None); + /// ``` #[stable(feature = "socket_timeout", since = "1.4.0")] pub fn write_timeout(&self) -> io::Result> { self.0.write_timeout() @@ -148,6 +257,15 @@ impl UdpSocket { /// /// When enabled, this socket is allowed to send packets to a broadcast /// address. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.set_broadcast(false).expect("set_broadcast call failed"); + /// ``` #[stable(feature = "net2_mutators", since = "1.9.0")] pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> { self.0.set_broadcast(broadcast) @@ -159,6 +277,16 @@ impl UdpSocket { /// [`set_broadcast`][link]. /// /// [link]: #method.set_broadcast + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.set_broadcast(false).expect("set_broadcast call failed"); + /// assert_eq!(socket.broadcast().unwrap(), false); + /// ``` #[stable(feature = "net2_mutators", since = "1.9.0")] pub fn broadcast(&self) -> io::Result { self.0.broadcast() @@ -168,6 +296,15 @@ impl UdpSocket { /// /// If enabled, multicast packets will be looped back to the local socket. /// Note that this may not have any affect on IPv6 sockets. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.set_multicast_loop_v4(false).expect("set_multicast_loop_v4 call failed"); + /// ``` #[stable(feature = "net2_mutators", since = "1.9.0")] pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> { self.0.set_multicast_loop_v4(multicast_loop_v4) @@ -179,6 +316,16 @@ impl UdpSocket { /// [`set_multicast_loop_v4`][link]. /// /// [link]: #method.set_multicast_loop_v4 + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.set_multicast_loop_v4(false).expect("set_multicast_loop_v4 call failed"); + /// assert_eq!(socket.multicast_loop_v4().unwrap(), false); + /// ``` #[stable(feature = "net2_mutators", since = "1.9.0")] pub fn multicast_loop_v4(&self) -> io::Result { self.0.multicast_loop_v4() @@ -191,6 +338,15 @@ impl UdpSocket { /// don't leave the local network unless explicitly requested. /// /// Note that this may not have any affect on IPv6 sockets. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.set_multicast_ttl_v4(42).expect("set_multicast_ttl_v4 call failed"); + /// ``` #[stable(feature = "net2_mutators", since = "1.9.0")] pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> { self.0.set_multicast_ttl_v4(multicast_ttl_v4) @@ -202,6 +358,16 @@ impl UdpSocket { /// [`set_multicast_ttl_v4`][link]. /// /// [link]: #method.set_multicast_ttl_v4 + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.set_multicast_ttl_v4(42).expect("set_multicast_ttl_v4 call failed"); + /// assert_eq!(socket.multicast_ttl_v4().unwrap(), 42); + /// ``` #[stable(feature = "net2_mutators", since = "1.9.0")] pub fn multicast_ttl_v4(&self) -> io::Result { self.0.multicast_ttl_v4() @@ -211,6 +377,15 @@ impl UdpSocket { /// /// Controls whether this socket sees the multicast packets it sends itself. /// Note that this may not have any affect on IPv4 sockets. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.set_multicast_loop_v6(false).expect("set_multicast_loop_v6 call failed"); + /// ``` #[stable(feature = "net2_mutators", since = "1.9.0")] pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> { self.0.set_multicast_loop_v6(multicast_loop_v6) @@ -222,6 +397,16 @@ impl UdpSocket { /// [`set_multicast_loop_v6`][link]. /// /// [link]: #method.set_multicast_loop_v6 + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.set_multicast_loop_v6(false).expect("set_multicast_loop_v6 call failed"); + /// assert_eq!(socket.multicast_loop_v6().unwrap(), false); + /// ``` #[stable(feature = "net2_mutators", since = "1.9.0")] pub fn multicast_loop_v6(&self) -> io::Result { self.0.multicast_loop_v6() @@ -231,6 +416,15 @@ impl UdpSocket { /// /// This value sets the time-to-live field that is used in every packet sent /// from this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.set_ttl(42).expect("set_ttl call failed"); + /// ``` #[stable(feature = "net2_mutators", since = "1.9.0")] pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { self.0.set_ttl(ttl) @@ -241,6 +435,16 @@ impl UdpSocket { /// For more information about this option, see [`set_ttl`][link]. /// /// [link]: #method.set_ttl + /// + /// # Examples + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); + /// socket.set_ttl(42).expect("set_ttl call failed"); + /// assert_eq!(socket.ttl().unwrap(), 42); + /// ``` #[stable(feature = "net2_mutators", since = "1.9.0")] pub fn ttl(&self) -> io::Result { self.0.ttl() From fcebf3beab25386f1fbf98ceef859b355ad70f15 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sun, 27 Nov 2016 02:15:07 +0200 Subject: [PATCH 073/293] don't double-apply variant padding to const enums Fixes #38002. --- src/librustc_trans/adt.rs | 14 ++++------ src/test/run-pass/issue-38002.rs | 45 ++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 9 deletions(-) create mode 100644 src/test/run-pass/issue-38002.rs diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index e091ba07d4f..8ee362bae35 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -688,9 +688,8 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, discr: D let lldiscr = C_integral(Type::from_integer(ccx, d), discr.0 as u64, true); let mut vals_with_discr = vec![lldiscr]; vals_with_discr.extend_from_slice(vals); - let mut contents = build_const_struct(ccx, &variant, - &vals_with_discr[..]); - let needed_padding = l.size(dl).bytes() - variant.min_size.bytes(); + let mut contents = build_const_struct(ccx, &variant, &vals_with_discr[..]); + let needed_padding = l.size(dl).bytes() - variant.stride().bytes(); if needed_padding > 0 { contents.push(padding(ccx, needed_padding)); } @@ -703,8 +702,7 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, discr: D } layout::Univariant { ref variant, .. } => { assert_eq!(discr, Disr(0)); - let contents = build_const_struct(ccx, - &variant, vals); + let contents = build_const_struct(ccx, &variant, vals); C_struct(ccx, &contents[..], variant.packed) } layout::Vector { .. } => { @@ -721,8 +719,7 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, discr: D } layout::StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => { if discr.0 == nndiscr { - C_struct(ccx, &build_const_struct(ccx, &nonnull, vals), - false) + C_struct(ccx, &build_const_struct(ccx, &nonnull, vals), false) } else { let fields = compute_fields(ccx, t, nndiscr as usize, false); let vals = fields.iter().map(|&ty| { @@ -730,8 +727,7 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, discr: D // field; see #8506. C_null(type_of::sizing_type_of(ccx, ty)) }).collect::>(); - C_struct(ccx, &build_const_struct(ccx, &nonnull, &vals[..]), - false) + C_struct(ccx, &build_const_struct(ccx, &nonnull, &vals[..]), false) } } _ => bug!("trans_const: cannot handle type {} repreented as {:#?}", t, l) diff --git a/src/test/run-pass/issue-38002.rs b/src/test/run-pass/issue-38002.rs new file mode 100644 index 00000000000..489d35e9147 --- /dev/null +++ b/src/test/run-pass/issue-38002.rs @@ -0,0 +1,45 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that constant ADTs are translated OK, part k of N. + +#![feature(slice_patterns)] + +enum Bar { + C +} + +enum Foo { + A {}, + B { + y: usize, + z: Bar + }, +} + +const LIST: [(usize, Foo); 2] = [ + (51, Foo::B { y: 42, z: Bar::C }), + (52, Foo::B { y: 45, z: Bar::C }), +]; + +pub fn main() { + match LIST { + [ + (51, Foo::B { y: 42, z: Bar::C }), + (52, Foo::B { y: 45, z: Bar::C }) + ] => {} + _ => { + // I would want to print the enum here, but if + // the discriminant is garbage this causes an + // `unreachable` and silent process exit. + panic!("trivial match failed") + } + } +} From f216f1fc5357a03044b4245f728ea61b355a9221 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 24 Nov 2016 21:21:53 +0100 Subject: [PATCH 074/293] Add examples for TcpListener struct --- src/libstd/net/tcp.rs | 121 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 118 insertions(+), 3 deletions(-) diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 159aa997b27..2e0ed1eb73e 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -297,12 +297,30 @@ impl TcpListener { /// /// The address type can be any implementor of `ToSocketAddrs` trait. See /// its documentation for concrete examples. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpListener; + /// + /// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn bind(addr: A) -> io::Result { super::each_addr(addr, net_imp::TcpListener::bind).map(TcpListener) } /// Returns the local socket address of this listener. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpListener}; + /// + /// let listener = TcpListener::bind("127.0.0.1:8080").unwrap(); + /// assert_eq!(listener.local_addr().unwrap(), + /// SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080))); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn local_addr(&self) -> io::Result { self.0.socket_addr() @@ -313,6 +331,15 @@ impl TcpListener { /// The returned `TcpListener` is a reference to the same socket that this /// object references. Both handles can be used to accept incoming /// connections and options set on one listener will affect the other. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpListener; + /// + /// let listener = TcpListener::bind("127.0.0.1:8080").unwrap(); + /// let listener_clone = listener.try_clone().unwrap(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn try_clone(&self) -> io::Result { self.0.duplicate().map(TcpListener) @@ -323,6 +350,18 @@ impl TcpListener { /// This function will block the calling thread until a new TCP connection /// is established. When established, the corresponding `TcpStream` and the /// remote peer's address will be returned. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpListener; + /// + /// let listener = TcpListener::bind("127.0.0.1:8080").unwrap(); + /// match listener.accept() { + /// Ok((_socket, addr)) => println!("new client: {:?}", addr), + /// Err(e) => println!("couldn't get client: {:?}", e), + /// } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { self.0.accept().map(|(a, b)| (TcpStream(a), b)) @@ -331,8 +370,28 @@ impl TcpListener { /// Returns an iterator over the connections being received on this /// listener. /// - /// The returned iterator will never return `None` and will also not yield - /// the peer's `SocketAddr` structure. + /// The returned iterator will never return [`None`] and will also not yield + /// the peer's [`SocketAddr`] structure. + /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpListener; + /// + /// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); + /// + /// for stream in listener.incoming() { + /// match stream { + /// Ok(stream) => { + /// println!("new client!"); + /// } + /// Err(e) => { /* connection failed */ } + /// } + /// } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn incoming(&self) -> Incoming { Incoming { listener: self } @@ -342,6 +401,15 @@ impl TcpListener { /// /// This value sets the time-to-live field that is used in every packet sent /// from this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpListener; + /// + /// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); + /// listener.set_ttl(100).expect("could not set TTL"); + /// ``` #[stable(feature = "net2_mutators", since = "1.9.0")] pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { self.0.set_ttl(ttl) @@ -349,9 +417,19 @@ impl TcpListener { /// Gets the value of the `IP_TTL` option for this socket. /// - /// For more information about this option, see [`set_ttl`][link]. + /// For more information about this option, see [`set_ttl()`][link]. /// /// [link]: #method.set_ttl + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpListener; + /// + /// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); + /// listener.set_ttl(100).expect("could not set TTL"); + /// assert_eq!(listener.ttl().unwrap_or(0), 100); + /// ``` #[stable(feature = "net2_mutators", since = "1.9.0")] pub fn ttl(&self) -> io::Result { self.0.ttl() @@ -365,6 +443,15 @@ impl TcpListener { /// /// If this is set to `false` then the socket can be used to send and /// receive packets from an IPv4-mapped IPv6 address. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpListener; + /// + /// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); + /// listener.set_only_v6(true).expect("Cannot set to IPv6"); + /// ``` #[stable(feature = "net2_mutators", since = "1.9.0")] pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> { self.0.set_only_v6(only_v6) @@ -375,6 +462,16 @@ impl TcpListener { /// For more information about this option, see [`set_only_v6`][link]. /// /// [link]: #method.set_only_v6 + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpListener; + /// + /// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); + /// listener.set_only_v6(true).expect("Cannot set to IPv6"); + /// assert_eq!(listener.only_v6().unwrap_or(false), true); + /// ``` #[stable(feature = "net2_mutators", since = "1.9.0")] pub fn only_v6(&self) -> io::Result { self.0.only_v6() @@ -385,6 +482,15 @@ impl TcpListener { /// This will retrieve the stored error in the underlying socket, clearing /// the field in the process. This can be useful for checking errors between /// calls. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpListener; + /// + /// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); + /// listener.take_error().expect("No error was expected"); + /// ``` #[stable(feature = "net2_mutators", since = "1.9.0")] pub fn take_error(&self) -> io::Result> { self.0.take_error() @@ -394,6 +500,15 @@ impl TcpListener { /// /// On Unix this corresponds to calling fcntl, and on Windows this /// corresponds to calling ioctlsocket. + /// + /// # Examples + /// + /// ```no_run + /// use std::net::TcpListener; + /// + /// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); + /// listener.set_nonblocking(true).expect("Cannot set non-blocking"); + /// ``` #[stable(feature = "net2_mutators", since = "1.9.0")] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { self.0.set_nonblocking(nonblocking) From cb0e24eafa233ddf5eee1937f161f3bda1745f2c Mon Sep 17 00:00:00 2001 From: Robin Kruppe Date: Sun, 27 Nov 2016 14:48:47 +0100 Subject: [PATCH 075/293] Adapt LLVMRustPrintPasses to LLVM 4.0 preferring `StringRef` over `char *` --- src/rustllvm/PassWrapper.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 70f7ee3004d..9230c639833 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -529,10 +529,17 @@ LLVMRustPrintPasses() { LLVMInitializePasses(); struct MyListener : PassRegistrationListener { void passEnumerate(const PassInfo *info) { +#if LLVM_VERSION_GE(4, 0) + if (!info->getPassArgument().empty()) { + printf("%15s - %s\n", info->getPassArgument().data(), + info->getPassName().data()); + } +#else if (info->getPassArgument() && *info->getPassArgument()) { printf("%15s - %s\n", info->getPassArgument(), info->getPassName()); } +#endif } } listener; From 0bcb05cf50624fc54162823f998df40658e158b1 Mon Sep 17 00:00:00 2001 From: Stefan Schindler Date: Sun, 27 Nov 2016 15:34:32 +0100 Subject: [PATCH 076/293] Finishing d2f8fb0a0a9dd from @jseyfried --- src/grammar/verify.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/grammar/verify.rs b/src/grammar/verify.rs index 48be58f731c..482f3f7d839 100644 --- a/src/grammar/verify.rs +++ b/src/grammar/verify.rs @@ -37,6 +37,8 @@ use syntax::parse::token::{self, BinOpToken, DelimToken, Lit, Token}; use syntax::parse::lexer::TokenAndSpan; use syntax_pos::Pos; +use syntax::symbol::Symbol; + fn parse_token_list(file: &str) -> HashMap { fn id() -> token::Token { Token::Ident(ast::Ident::with_empty_ctxt(Name(0))) @@ -158,7 +160,7 @@ fn fix(mut lit: &str) -> ast::Name { let leading_hashes = count(lit); // +1/-1 to adjust for single quotes - parse::token::intern(&lit[leading_hashes + 1..lit.len() - leading_hashes - 1]) + Symbol::intern(&lit[leading_hashes + 1..lit.len() - leading_hashes - 1]) } /// Assuming a char/byte literal, strip the 'b' prefix and the single quotes. @@ -168,7 +170,7 @@ fn fixchar(mut lit: &str) -> ast::Name { lit = &lit[1..]; } - parse::token::intern(&lit[1..lit.len() - 1]) + Symbol::intern(&lit[1..lit.len() - 1]) } fn count(lit: &str) -> usize { @@ -196,7 +198,7 @@ fn parse_antlr_token(s: &str, tokens: &HashMap, surrogate_ let not_found = format!("didn't find token {:?} in the map", toknum); let proto_tok = tokens.get(toknum).expect(¬_found[..]); - let nm = parse::token::intern(content); + let nm = Symbol::intern(content); debug!("What we got: content (`{}`), proto: {:?}", content, proto_tok); From 2dc3fdf2bd6153ad640544776abb62ad17d6b6be Mon Sep 17 00:00:00 2001 From: Stefan Schindler Date: Sun, 27 Nov 2016 16:45:09 +0100 Subject: [PATCH 077/293] Resolve visibility issues use syntax::ast::Name; is a reexport of syntax::symbol::Symbol(u32); --- src/grammar/verify.rs | 26 ++++++++++++-------------- src/libsyntax/symbol.rs | 4 ++++ 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/grammar/verify.rs b/src/grammar/verify.rs index 482f3f7d839..1903c9125e4 100644 --- a/src/grammar/verify.rs +++ b/src/grammar/verify.rs @@ -23,7 +23,6 @@ use std::fs::File; use std::io::{BufRead, Read}; use std::path::Path; -use syntax::parse; use syntax::parse::lexer; use rustc::dep_graph::DepGraph; use rustc::session::{self, config}; @@ -31,7 +30,6 @@ use rustc::middle::cstore::DummyCrateStore; use std::rc::Rc; use syntax::ast; -use syntax::ast::Name; use syntax::codemap; use syntax::parse::token::{self, BinOpToken, DelimToken, Lit, Token}; use syntax::parse::lexer::TokenAndSpan; @@ -41,7 +39,7 @@ use syntax::symbol::Symbol; fn parse_token_list(file: &str) -> HashMap { fn id() -> token::Token { - Token::Ident(ast::Ident::with_empty_ctxt(Name(0))) + Token::Ident(ast::Ident::with_empty_ctxt(Symbol::invalid())) } let mut res = HashMap::new(); @@ -67,7 +65,7 @@ fn parse_token_list(file: &str) -> HashMap { "SHL" => Token::BinOp(BinOpToken::Shl), "LBRACE" => Token::OpenDelim(DelimToken::Brace), "RARROW" => Token::RArrow, - "LIT_STR" => Token::Literal(Lit::Str_(Name(0)), None), + "LIT_STR" => Token::Literal(Lit::Str_(Symbol::invalid()), None), "DOTDOT" => Token::DotDot, "MOD_SEP" => Token::ModSep, "DOTDOTDOT" => Token::DotDotDot, @@ -77,21 +75,21 @@ fn parse_token_list(file: &str) -> HashMap { "ANDAND" => Token::AndAnd, "AT" => Token::At, "LBRACKET" => Token::OpenDelim(DelimToken::Bracket), - "LIT_STR_RAW" => Token::Literal(Lit::StrRaw(Name(0), 0), None), + "LIT_STR_RAW" => Token::Literal(Lit::StrRaw(Symbol::invalid(), 0), None), "RPAREN" => Token::CloseDelim(DelimToken::Paren), "SLASH" => Token::BinOp(BinOpToken::Slash), "COMMA" => Token::Comma, - "LIFETIME" => Token::Lifetime(ast::Ident::with_empty_ctxt(Name(0))), + "LIFETIME" => Token::Lifetime(ast::Ident::with_empty_ctxt(Symbol::invalid())), "CARET" => Token::BinOp(BinOpToken::Caret), "TILDE" => Token::Tilde, "IDENT" => id(), "PLUS" => Token::BinOp(BinOpToken::Plus), - "LIT_CHAR" => Token::Literal(Lit::Char(Name(0)), None), - "LIT_BYTE" => Token::Literal(Lit::Byte(Name(0)), None), + "LIT_CHAR" => Token::Literal(Lit::Char(Symbol::invalid()), None), + "LIT_BYTE" => Token::Literal(Lit::Byte(Symbol::invalid()), None), "EQ" => Token::Eq, "RBRACKET" => Token::CloseDelim(DelimToken::Bracket), "COMMENT" => Token::Comment, - "DOC_COMMENT" => Token::DocComment(Name(0)), + "DOC_COMMENT" => Token::DocComment(Symbol::invalid()), "DOT" => Token::Dot, "EQEQ" => Token::EqEq, "NE" => Token::Ne, @@ -101,9 +99,9 @@ fn parse_token_list(file: &str) -> HashMap { "BINOP" => Token::BinOp(BinOpToken::Plus), "POUND" => Token::Pound, "OROR" => Token::OrOr, - "LIT_INTEGER" => Token::Literal(Lit::Integer(Name(0)), None), + "LIT_INTEGER" => Token::Literal(Lit::Integer(Symbol::invalid()), None), "BINOPEQ" => Token::BinOpEq(BinOpToken::Plus), - "LIT_FLOAT" => Token::Literal(Lit::Float(Name(0)), None), + "LIT_FLOAT" => Token::Literal(Lit::Float(Symbol::invalid()), None), "WHITESPACE" => Token::Whitespace, "UNDERSCORE" => Token::Underscore, "MINUS" => Token::BinOp(BinOpToken::Minus), @@ -113,10 +111,10 @@ fn parse_token_list(file: &str) -> HashMap { "OR" => Token::BinOp(BinOpToken::Or), "GT" => Token::Gt, "LE" => Token::Le, - "LIT_BINARY" => Token::Literal(Lit::ByteStr(Name(0)), None), - "LIT_BINARY_RAW" => Token::Literal(Lit::ByteStrRaw(Name(0), 0), None), + "LIT_BINARY" => Token::Literal(Lit::ByteStr(Symbol::invalid()), None), + "LIT_BINARY_RAW" => Token::Literal(Lit::ByteStrRaw(Symbol::invalid(), 0), None), "QUESTION" => Token::Question, - "SHEBANG" => Token::Shebang(Name(0)), + "SHEBANG" => Token::Shebang(Symbol::invalid()), _ => continue, }; diff --git a/src/libsyntax/symbol.rs b/src/libsyntax/symbol.rs index fe9a176179c..e2dcc240932 100644 --- a/src/libsyntax/symbol.rs +++ b/src/libsyntax/symbol.rs @@ -35,6 +35,10 @@ impl Symbol { with_interner(|interner| interner.gensym(string)) } + pub fn invalid() -> Self { + Symbol(0u32) + } + pub fn as_str(self) -> InternedString { with_interner(|interner| unsafe { InternedString { From 28b64dc1b955afd6e89b21499dfa1fd1d452e31c Mon Sep 17 00:00:00 2001 From: Stefan Schindler Date: Sun, 27 Nov 2016 17:59:36 +0100 Subject: [PATCH 078/293] Use keywords::Invalid --- src/grammar/verify.rs | 28 +++++++++++++++------------- src/libsyntax/symbol.rs | 4 ---- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/grammar/verify.rs b/src/grammar/verify.rs index 1903c9125e4..919fc98e438 100644 --- a/src/grammar/verify.rs +++ b/src/grammar/verify.rs @@ -35,11 +35,11 @@ use syntax::parse::token::{self, BinOpToken, DelimToken, Lit, Token}; use syntax::parse::lexer::TokenAndSpan; use syntax_pos::Pos; -use syntax::symbol::Symbol; +use syntax::symbol::{Symbol, keywords}; fn parse_token_list(file: &str) -> HashMap { fn id() -> token::Token { - Token::Ident(ast::Ident::with_empty_ctxt(Symbol::invalid())) + Token::Ident(ast::Ident::with_empty_ctxt(keywords::Invalid.name())) } let mut res = HashMap::new(); @@ -65,7 +65,7 @@ fn parse_token_list(file: &str) -> HashMap { "SHL" => Token::BinOp(BinOpToken::Shl), "LBRACE" => Token::OpenDelim(DelimToken::Brace), "RARROW" => Token::RArrow, - "LIT_STR" => Token::Literal(Lit::Str_(Symbol::invalid()), None), + "LIT_STR" => Token::Literal(Lit::Str_(keywords::Invalid.name()), None), "DOTDOT" => Token::DotDot, "MOD_SEP" => Token::ModSep, "DOTDOTDOT" => Token::DotDotDot, @@ -75,21 +75,22 @@ fn parse_token_list(file: &str) -> HashMap { "ANDAND" => Token::AndAnd, "AT" => Token::At, "LBRACKET" => Token::OpenDelim(DelimToken::Bracket), - "LIT_STR_RAW" => Token::Literal(Lit::StrRaw(Symbol::invalid(), 0), None), + "LIT_STR_RAW" => Token::Literal(Lit::StrRaw(keywords::Invalid.name(), 0), None), "RPAREN" => Token::CloseDelim(DelimToken::Paren), "SLASH" => Token::BinOp(BinOpToken::Slash), "COMMA" => Token::Comma, - "LIFETIME" => Token::Lifetime(ast::Ident::with_empty_ctxt(Symbol::invalid())), + "LIFETIME" => Token::Lifetime( + ast::Ident::with_empty_ctxt(keywords::Invalid.name())), "CARET" => Token::BinOp(BinOpToken::Caret), "TILDE" => Token::Tilde, "IDENT" => id(), "PLUS" => Token::BinOp(BinOpToken::Plus), - "LIT_CHAR" => Token::Literal(Lit::Char(Symbol::invalid()), None), - "LIT_BYTE" => Token::Literal(Lit::Byte(Symbol::invalid()), None), + "LIT_CHAR" => Token::Literal(Lit::Char(keywords::Invalid.name()), None), + "LIT_BYTE" => Token::Literal(Lit::Byte(keywords::Invalid.name()), None), "EQ" => Token::Eq, "RBRACKET" => Token::CloseDelim(DelimToken::Bracket), "COMMENT" => Token::Comment, - "DOC_COMMENT" => Token::DocComment(Symbol::invalid()), + "DOC_COMMENT" => Token::DocComment(keywords::Invalid.name()), "DOT" => Token::Dot, "EQEQ" => Token::EqEq, "NE" => Token::Ne, @@ -99,9 +100,9 @@ fn parse_token_list(file: &str) -> HashMap { "BINOP" => Token::BinOp(BinOpToken::Plus), "POUND" => Token::Pound, "OROR" => Token::OrOr, - "LIT_INTEGER" => Token::Literal(Lit::Integer(Symbol::invalid()), None), + "LIT_INTEGER" => Token::Literal(Lit::Integer(keywords::Invalid.name()), None), "BINOPEQ" => Token::BinOpEq(BinOpToken::Plus), - "LIT_FLOAT" => Token::Literal(Lit::Float(Symbol::invalid()), None), + "LIT_FLOAT" => Token::Literal(Lit::Float(keywords::Invalid.name()), None), "WHITESPACE" => Token::Whitespace, "UNDERSCORE" => Token::Underscore, "MINUS" => Token::BinOp(BinOpToken::Minus), @@ -111,10 +112,11 @@ fn parse_token_list(file: &str) -> HashMap { "OR" => Token::BinOp(BinOpToken::Or), "GT" => Token::Gt, "LE" => Token::Le, - "LIT_BINARY" => Token::Literal(Lit::ByteStr(Symbol::invalid()), None), - "LIT_BINARY_RAW" => Token::Literal(Lit::ByteStrRaw(Symbol::invalid(), 0), None), + "LIT_BINARY" => Token::Literal(Lit::ByteStr(keywords::Invalid.name()), None), + "LIT_BINARY_RAW" => Token::Literal( + Lit::ByteStrRaw(keywords::Invalid.name(), 0), None), "QUESTION" => Token::Question, - "SHEBANG" => Token::Shebang(Symbol::invalid()), + "SHEBANG" => Token::Shebang(keywords::Invalid.name()), _ => continue, }; diff --git a/src/libsyntax/symbol.rs b/src/libsyntax/symbol.rs index e2dcc240932..fe9a176179c 100644 --- a/src/libsyntax/symbol.rs +++ b/src/libsyntax/symbol.rs @@ -35,10 +35,6 @@ impl Symbol { with_interner(|interner| interner.gensym(string)) } - pub fn invalid() -> Self { - Symbol(0u32) - } - pub fn as_str(self) -> InternedString { with_interner(|interner| unsafe { InternedString { From 178e29df7d2927641ddbadaaa92e1f1c17fa5c92 Mon Sep 17 00:00:00 2001 From: arthurprs Date: Sun, 27 Nov 2016 00:57:09 +0100 Subject: [PATCH 079/293] Use displacement instead of initial bucket in HashMap code --- src/libstd/collections/hash/map.rs | 39 ++++++++++++++++-------------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index ece51d6d826..f102a1bf630 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -371,9 +371,9 @@ fn search_hashed(table: M, hash: SafeHash, mut is_match: F) -> Inter return InternalEntry::TableIsEmpty; } - let size = table.size() as isize; + let size = table.size(); let mut probe = Bucket::new(table, hash); - let ib = probe.index() as isize; + let mut displacement = 0; loop { let full = match probe.peek() { @@ -387,15 +387,15 @@ fn search_hashed(table: M, hash: SafeHash, mut is_match: F) -> Inter Full(bucket) => bucket, }; - let robin_ib = full.index() as isize - full.displacement() as isize; + let probe_displacement = full.displacement(); - if ib < robin_ib { + if probe_displacement < displacement { // Found a luckier bucket than me. // We can finish the search early if we hit any bucket // with a lower distance to initial bucket than we've probed. return InternalEntry::Vacant { hash: hash, - elem: NeqElem(full, robin_ib as usize), + elem: NeqElem(full, probe_displacement), }; } @@ -406,9 +406,9 @@ fn search_hashed(table: M, hash: SafeHash, mut is_match: F) -> Inter return InternalEntry::Occupied { elem: full }; } } - + displacement += 1; probe = full.next(); - debug_assert!(probe.index() as isize != ib + size + 1); + debug_assert!(displacement <= size); } } @@ -431,12 +431,11 @@ fn pop_internal(starting_bucket: FullBucketMut) -> (K, V) { } /// Perform robin hood bucket stealing at the given `bucket`. You must -/// also pass the position of that bucket's initial bucket so we don't have -/// to recalculate it. +/// also pass that bucket's displacement so we don't have to recalculate it. /// /// `hash`, `k`, and `v` are the elements to "robin hood" into the hashtable. fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>, - mut ib: usize, + mut displacement: usize, mut hash: SafeHash, mut key: K, mut val: V) @@ -457,6 +456,7 @@ fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>, val = old_val; loop { + displacement += 1; let probe = bucket.next(); debug_assert!(probe.index() != idx_end); @@ -476,13 +476,13 @@ fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>, Full(bucket) => bucket, }; - let probe_ib = full_bucket.index() - full_bucket.displacement(); + let probe_displacement = full_bucket.displacement(); bucket = full_bucket; // Robin hood! Steal the spot. - if ib < probe_ib { - ib = probe_ib; + if probe_displacement < displacement { + displacement = probe_displacement; break; } } @@ -520,13 +520,16 @@ impl HashMap search_hashed(&mut self.table, hash, |k| q.eq(k.borrow())) } - // The caller should ensure that invariants by Robin Hood Hashing hold. + // The caller should ensure that invariants by Robin Hood Hashing hold + // and that there's space in the underlying table. fn insert_hashed_ordered(&mut self, hash: SafeHash, k: K, v: V) { let raw_cap = self.raw_capacity(); let mut buckets = Bucket::new(&mut self.table, hash); - let ib = buckets.index(); + // note that buckets.index() keeps increasing + // even if the pointer wraps back to the first bucket. + let limit_bucket = buckets.index() + raw_cap; - while buckets.index() != ib + raw_cap { + loop { // We don't need to compare hashes for value swap. // Not even DIBs for Robin Hood. buckets = match buckets.peek() { @@ -537,8 +540,8 @@ impl HashMap Full(b) => b.into_bucket(), }; buckets.next(); + debug_assert!(buckets.index() < limit_bucket); } - panic!("Internal HashMap error: Out of space."); } } @@ -1959,7 +1962,7 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(self, value: V) -> &'a mut V { match self.elem { - NeqElem(bucket, ib) => robin_hood(bucket, ib, self.hash, self.key, value), + NeqElem(bucket, disp) => robin_hood(bucket, disp, self.hash, self.key, value), NoElem(bucket) => bucket.put(self.hash, self.key, value).into_mut_refs().1, } } From 34d1352f0eb7e7511e34b1e7640e854ffaf3f137 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Mon, 17 Oct 2016 06:02:23 +0300 Subject: [PATCH 080/293] rustc: encode the optionality of type parameters in HIR paths. --- src/librustc/hir/lowering.rs | 98 ++++++++++++++++++--------- src/librustc/hir/mod.rs | 6 ++ src/librustc/hir/print.rs | 10 +++ src/librustc/infer/error_reporting.rs | 1 + src/librustc_typeck/astconv.rs | 59 +++------------- src/librustc_typeck/check/mod.rs | 44 ++++++------ 6 files changed, 112 insertions(+), 106 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 5af7c18e1a1..264a5722bcd 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -101,6 +101,14 @@ pub fn lower_crate(sess: &Session, }.lower_crate(krate) } +#[derive(Copy, Clone, PartialEq, Eq)] +enum ParamMode { + /// Any path in a type context. + Explicit, + /// The `module::Type` in `module::Type::method` in an expression. + Optional +} + impl<'a> LoweringContext<'a> { fn lower_crate(&mut self, c: &Crate) -> hir::Crate { struct ItemLowerer<'lcx, 'interner: 'lcx> { @@ -179,13 +187,14 @@ impl<'a> LoweringContext<'a> { P(Spanned { node: match view_path.node { ViewPathSimple(ident, ref path) => { - hir::ViewPathSimple(ident.name, self.lower_path(path)) + hir::ViewPathSimple(ident.name, + self.lower_path(path, None, ParamMode::Explicit)) } ViewPathGlob(ref path) => { - hir::ViewPathGlob(self.lower_path(path)) + hir::ViewPathGlob(self.lower_path(path, None, ParamMode::Explicit)) } ViewPathList(ref path, ref path_list_idents) => { - hir::ViewPathList(self.lower_path(path), + hir::ViewPathList(self.lower_path(path, None, ParamMode::Explicit), path_list_idents.iter() .map(|item| self.lower_path_list_item(item)) .collect()) @@ -256,7 +265,8 @@ impl<'a> LoweringContext<'a> { position: position, } }); - hir::TyPath(qself, self.lower_path(path)) + let path = self.lower_path(path, qself.as_ref(), ParamMode::Explicit); + hir::TyPath(qself, path) } TyKind::ObjectSum(ref ty, ref bounds) => { hir::TyObjectSum(self.lower_ty(ty), self.lower_bounds(bounds)) @@ -298,38 +308,56 @@ impl<'a> LoweringContext<'a> { } } - fn lower_path(&mut self, p: &Path) -> hir::Path { + fn lower_path(&mut self, + p: &Path, + qself: Option<&hir::QSelf>, + param_mode: ParamMode) + -> hir::Path { hir::Path { global: p.global, - segments: p.segments - .iter() - .map(|&PathSegment { identifier, ref parameters }| { - hir::PathSegment { - name: identifier.name, - parameters: self.lower_path_parameters(parameters), - } - }) - .collect(), + segments: p.segments.iter().enumerate().map(|(i, segment)| { + let PathSegment { identifier, ref parameters } = *segment; + let param_mode = match (qself, param_mode) { + (Some(qself), ParamMode::Optional) if i < qself.position => { + // This segment is part of the trait path in a + // qualified path - one of `a`, `b` or `Trait` + // in `::T::U::method`. + ParamMode::Explicit + } + _ => param_mode + }; + hir::PathSegment { + name: identifier.name, + parameters: self.lower_path_parameters(parameters, param_mode), + } + }).collect(), span: p.span, } } - fn lower_path_parameters(&mut self, path_parameters: &PathParameters) -> hir::PathParameters { + fn lower_path_parameters(&mut self, + path_parameters: &PathParameters, + param_mode: ParamMode) + -> hir::PathParameters { match *path_parameters { - PathParameters::AngleBracketed(ref data) => - hir::AngleBracketedParameters(self.lower_angle_bracketed_parameter_data(data)), + PathParameters::AngleBracketed(ref data) => { + let data = self.lower_angle_bracketed_parameter_data(data, param_mode); + hir::AngleBracketedParameters(data) + } PathParameters::Parenthesized(ref data) => hir::ParenthesizedParameters(self.lower_parenthesized_parameter_data(data)), } } fn lower_angle_bracketed_parameter_data(&mut self, - data: &AngleBracketedParameterData) + data: &AngleBracketedParameterData, + param_mode: ParamMode) -> hir::AngleBracketedParameterData { let &AngleBracketedParameterData { ref lifetimes, ref types, ref bindings } = data; hir::AngleBracketedParameterData { lifetimes: self.lower_lifetimes(lifetimes), types: types.iter().map(|ty| self.lower_ty(ty)).collect(), + infer_types: types.is_empty() && param_mode == ParamMode::Optional, bindings: bindings.iter().map(|b| self.lower_ty_binding(b)).collect(), } } @@ -493,7 +521,7 @@ impl<'a> LoweringContext<'a> { span}) => { hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { id: id, - path: self.lower_path(path), + path: self.lower_path(path, None, ParamMode::Explicit), ty: self.lower_ty(ty), span: span, }) @@ -523,7 +551,7 @@ impl<'a> LoweringContext<'a> { fn lower_trait_ref(&mut self, p: &TraitRef) -> hir::TraitRef { hir::TraitRef { - path: self.lower_path(&p.path), + path: self.lower_path(&p.path, None, ParamMode::Explicit), ref_id: p.ref_id, } } @@ -887,17 +915,19 @@ impl<'a> LoweringContext<'a> { } PatKind::Lit(ref e) => hir::PatKind::Lit(P(self.lower_expr(e))), PatKind::TupleStruct(ref path, ref pats, ddpos) => { - hir::PatKind::TupleStruct(self.lower_path(path), - pats.iter().map(|x| self.lower_pat(x)).collect(), ddpos) + hir::PatKind::TupleStruct(self.lower_path(path, None, ParamMode::Optional), + pats.iter().map(|x| self.lower_pat(x)).collect(), + ddpos) } - PatKind::Path(ref opt_qself, ref path) => { - let opt_qself = opt_qself.as_ref().map(|qself| { + PatKind::Path(ref qself, ref path) => { + let qself = qself.as_ref().map(|qself| { hir::QSelf { ty: self.lower_ty(&qself.ty), position: qself.position } }); - hir::PatKind::Path(opt_qself, self.lower_path(path)) + let path = self.lower_path(path, qself.as_ref(), ParamMode::Optional); + hir::PatKind::Path(qself, path) } PatKind::Struct(ref pth, ref fields, etc) => { - let pth = self.lower_path(pth); + let pth = self.lower_path(pth, None, ParamMode::Optional); let fs = fields.iter() .map(|f| { Spanned { @@ -1236,13 +1266,14 @@ impl<'a> LoweringContext<'a> { }; } ExprKind::Path(ref qself, ref path) => { - let hir_qself = qself.as_ref().map(|&QSelf { ref ty, position }| { + let qself = qself.as_ref().map(|&QSelf { ref ty, position }| { hir::QSelf { ty: self.lower_ty(ty), position: position, } }); - hir::ExprPath(hir_qself, self.lower_path(path)) + let path = self.lower_path(path, qself.as_ref(), ParamMode::Optional); + hir::ExprPath(qself, path) } ExprKind::Break(opt_ident, ref opt_expr) => { hir::ExprBreak(self.lower_opt_sp_ident(opt_ident), @@ -1275,7 +1306,7 @@ impl<'a> LoweringContext<'a> { hir::ExprInlineAsm(P(hir_asm), outputs, inputs) } ExprKind::Struct(ref path, ref fields, ref maybe_expr) => { - hir::ExprStruct(P(self.lower_path(path)), + hir::ExprStruct(P(self.lower_path(path, None, ParamMode::Optional)), fields.iter().map(|x| self.lower_field(x)).collect(), maybe_expr.as_ref().map(|x| P(self.lower_expr(x)))) } @@ -1655,8 +1686,12 @@ impl<'a> LoweringContext<'a> { match *v { Visibility::Public => hir::Public, Visibility::Crate(_) => hir::Visibility::Crate, - Visibility::Restricted { ref path, id } => - hir::Visibility::Restricted { path: P(self.lower_path(path)), id: id }, + Visibility::Restricted { ref path, id } => { + hir::Visibility::Restricted { + path: P(self.lower_path(path, None, ParamMode::Explicit)), + id: id + } + } Visibility::Inherited => hir::Inherited, } } @@ -1949,6 +1984,7 @@ impl<'a> LoweringContext<'a> { parameters: hir::AngleBracketedParameters(hir::AngleBracketedParameterData { lifetimes: lifetimes, types: types, + infer_types: true, bindings: bindings, }), }); diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 31648765224..6f0a3a02380 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -167,6 +167,7 @@ impl PathParameters { AngleBracketedParameters(AngleBracketedParameterData { lifetimes: HirVec::new(), types: HirVec::new(), + infer_types: true, bindings: HirVec::new(), }) } @@ -241,6 +242,11 @@ pub struct AngleBracketedParameterData { pub lifetimes: HirVec, /// The type parameters for this path segment, if present. pub types: HirVec>, + /// Whether to infer remaining type parameters, if any. + /// This only applies to expression and pattern paths, and + /// out of those only the segments with no type parameters + /// to begin with, e.g. `Vec::new` is `>::new::<..>`. + pub infer_types: bool, /// Bindings (equality constraints) on associated types, if present. /// E.g., `Foo`. pub bindings: HirVec, diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index c109e84bf61..9934259c5d1 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1696,6 +1696,16 @@ impl<'a> State<'a> { comma = true; } + // FIXME(eddyb) This would leak into error messages, e.g.: + // "non-exhaustive patterns: `Some::<..>(_)` not covered". + if data.infer_types && false { + if comma { + self.word_space(",")? + } + word(&mut self.s, "..")?; + comma = true; + } + for binding in data.bindings.iter() { if comma { self.word_space(",")? diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 8db09d0b73d..b9b97473340 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -1609,6 +1609,7 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> { hir::AngleBracketedParameters(hir::AngleBracketedParameterData { lifetimes: new_lts.into(), types: new_types, + infer_types: data.infer_types, bindings: new_bindings, }) } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index c5db8bc8ced..831426c3f06 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -149,14 +149,6 @@ pub trait AstConv<'gcx, 'tcx> { fn set_tainted_by_errors(&self); } -#[derive(PartialEq, Eq)] -pub enum PathParamMode { - // Any path in a type context. - Explicit, - // The `module::Type` in `module::Type::method` in an expression. - Optional -} - struct ConvertedBinding<'tcx> { item_name: ast::Name, ty: Ty<'tcx>, @@ -341,7 +333,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { pub fn ast_path_substs_for_ty(&self, rscope: &RegionScope, span: Span, - param_mode: PathParamMode, def_id: DefId, item_segment: &hir::PathSegment) -> &'tcx Substs<'tcx> @@ -367,7 +358,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let (substs, assoc_bindings) = self.create_substs_for_ast_path(rscope, span, - param_mode, def_id, &item_segment.parameters, None); @@ -385,7 +375,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { fn create_substs_for_ast_path(&self, rscope: &RegionScope, span: Span, - param_mode: PathParamMode, def_id: DefId, parameters: &hir::PathParameters, self_ty: Option>) @@ -397,15 +386,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { parameters={:?})", def_id, self_ty, parameters); - let (lifetimes, num_types_provided) = match *parameters { + let (lifetimes, num_types_provided, infer_types) = match *parameters { hir::AngleBracketedParameters(ref data) => { - if param_mode == PathParamMode::Optional && data.types.is_empty() { - (&data.lifetimes[..], None) - } else { - (&data.lifetimes[..], Some(data.types.len())) - } + (&data.lifetimes[..], data.types.len(), data.infer_types) } - hir::ParenthesizedParameters(_) => (&[][..], Some(1)) + hir::ParenthesizedParameters(_) => (&[][..], 1, false) }; // If the type is parameterized by this region, then replace this @@ -443,9 +428,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { assert_eq!(decl_generics.has_self, self_ty.is_some()); // Check the number of type parameters supplied by the user. - if let Some(num_provided) = num_types_provided { - let ty_param_defs = &decl_generics.types[self_ty.is_some() as usize..]; - check_type_argument_count(tcx, span, num_provided, ty_param_defs); + let ty_param_defs = &decl_generics.types[self_ty.is_some() as usize..]; + if !infer_types || num_types_provided > ty_param_defs.len() { + check_type_argument_count(tcx, span, num_types_provided, ty_param_defs); } let is_object = self_ty.map_or(false, |ty| ty.sty == TRAIT_OBJECT_DUMMY_SELF); @@ -474,7 +459,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } let i = i - self_ty.is_some() as usize - decl_generics.regions.len(); - if num_types_provided.map_or(false, |n| i < n) { + if i < num_types_provided { // A provided type parameter. match *parameters { hir::AngleBracketedParameters(ref data) => { @@ -488,7 +473,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { ty } } - } else if num_types_provided.is_none() { + } else if infer_types { // No type parameters were provided, we can infer all. let ty_var = if !default_needs_object_self(def) { self.ty_infer_for_def(def, substs, span) @@ -664,7 +649,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let trait_def_id = self.trait_def_id(trait_ref); self.ast_path_to_poly_trait_ref(rscope, trait_ref.path.span, - PathParamMode::Explicit, trait_def_id, self_ty, trait_ref.ref_id, @@ -687,7 +671,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let trait_def_id = self.trait_def_id(trait_ref); self.ast_path_to_mono_trait_ref(rscope, trait_ref.path.span, - PathParamMode::Explicit, trait_def_id, self_ty, trait_ref.path.segments.last().unwrap()) @@ -710,7 +693,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { fn ast_path_to_poly_trait_ref(&self, rscope: &RegionScope, span: Span, - param_mode: PathParamMode, trait_def_id: DefId, self_ty: Ty<'tcx>, path_id: ast::NodeId, @@ -729,7 +711,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let (substs, assoc_bindings) = self.create_substs_for_ast_trait_ref(shifted_rscope, span, - param_mode, trait_def_id, self_ty, trait_segment); @@ -752,7 +733,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { fn ast_path_to_mono_trait_ref(&self, rscope: &RegionScope, span: Span, - param_mode: PathParamMode, trait_def_id: DefId, self_ty: Ty<'tcx>, trait_segment: &hir::PathSegment) @@ -761,7 +741,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let (substs, assoc_bindings) = self.create_substs_for_ast_trait_ref(rscope, span, - param_mode, trait_def_id, self_ty, trait_segment); @@ -772,7 +751,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { fn create_substs_for_ast_trait_ref(&self, rscope: &RegionScope, span: Span, - param_mode: PathParamMode, trait_def_id: DefId, self_ty: Ty<'tcx>, trait_segment: &hir::PathSegment) @@ -817,7 +795,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { self.create_substs_for_ast_path(rscope, span, - param_mode, trait_def_id, &trait_segment.parameters, Some(self_ty)) @@ -929,7 +906,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { fn ast_path_to_ty(&self, rscope: &RegionScope, span: Span, - param_mode: PathParamMode, did: DefId, item_segment: &hir::PathSegment) -> Ty<'tcx> @@ -944,7 +920,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let substs = self.ast_path_substs_for_ty(rscope, span, - param_mode, did, item_segment); @@ -983,7 +958,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { Def::Trait(trait_def_id) if resolution.depth == 0 => { self.trait_path_to_object_type(rscope, path.span, - PathParamMode::Explicit, trait_def_id, ty.id, path.segments.last().unwrap(), @@ -1055,7 +1029,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { fn trait_path_to_object_type(&self, rscope: &RegionScope, path_span: Span, - param_mode: PathParamMode, trait_def_id: DefId, trait_path_ref_id: ast::NodeId, trait_segment: &hir::PathSegment, @@ -1068,7 +1041,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let dummy_self = tcx.mk_ty(TRAIT_OBJECT_DUMMY_SELF); let principal = self.ast_path_to_poly_trait_ref(rscope, path_span, - param_mode, trait_def_id, dummy_self, trait_path_ref_id, @@ -1377,7 +1349,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { fn qpath_to_ty(&self, rscope: &RegionScope, span: Span, - param_mode: PathParamMode, opt_self_ty: Option>, trait_def_id: DefId, trait_segment: &hir::PathSegment, @@ -1403,7 +1374,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let trait_ref = self.ast_path_to_mono_trait_ref(rscope, span, - param_mode, trait_def_id, self_ty, trait_segment); @@ -1448,7 +1418,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { fn base_def_to_ty(&self, rscope: &RegionScope, span: Span, - param_mode: PathParamMode, def: Def, opt_self_ty: Option>, base_path_ref_id: ast::NodeId, @@ -1469,7 +1438,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { self.trait_path_to_object_type(rscope, span, - param_mode, trait_def_id, base_path_ref_id, base_segments.last().unwrap(), @@ -1478,11 +1446,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) | Def::Union(did) => { tcx.prohibit_type_params(base_segments.split_last().unwrap().1); - self.ast_path_to_ty(rscope, - span, - param_mode, - did, - base_segments.last().unwrap()) + self.ast_path_to_ty(rscope, span, did, base_segments.last().unwrap()) } Def::Variant(did) if permit_variants => { // Convert "variant type" as if it were a real type. @@ -1535,7 +1499,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let trait_did = tcx.parent_def_id(def_id).unwrap(); self.qpath_to_ty(rscope, span, - param_mode, opt_self_ty, trait_did, &base_segments[base_segments.len()-2], @@ -1577,7 +1540,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { pub fn finish_resolving_def_to_ty(&self, rscope: &RegionScope, span: Span, - param_mode: PathParamMode, base_def: Def, opt_self_ty: Option>, base_path_ref_id: ast::NodeId, @@ -1594,7 +1556,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { assoc_segments); let base_ty = self.base_def_to_ty(rscope, span, - param_mode, base_def, opt_self_ty, base_path_ref_id, @@ -1749,7 +1710,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { }); let (ty, def) = self.finish_resolving_def_to_ty(rscope, ast_ty.span, - PathParamMode::Explicit, path_res.base_def, opt_self_ty, ast_ty.id, @@ -2007,7 +1967,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let trait_def_id = self.trait_def_id(trait_ref); self.trait_path_to_object_type(rscope, trait_ref.path.span, - PathParamMode::Explicit, trait_def_id, trait_ref.ref_id, trait_ref.path.segments.last().unwrap(), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index eeb7bb28700..ea84786e06b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -80,7 +80,7 @@ pub use self::Expectation::*; pub use self::compare_method::{compare_impl_method, compare_const_impl}; use self::TupleArgumentsFlag::*; -use astconv::{AstConv, ast_region_to_region, PathParamMode}; +use astconv::{AstConv, ast_region_to_region}; use dep_graph::DepNode; use fmt_macros::{Parser, Piece, Position}; use hir::def::{Def, CtorKind, PathResolution}; @@ -4006,7 +4006,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let path_res = self.tcx.expect_resolution(node_id); let base_ty_end = path.segments.len() - path_res.depth; let (ty, def) = AstConv::finish_resolving_def_to_ty(self, self, path.span, - PathParamMode::Optional, path_res.base_def, None, node_id, @@ -4038,7 +4037,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let ty_segments = path.segments.split_last().unwrap().1; let base_ty_end = path.segments.len() - path_res.depth; let (ty, _def) = AstConv::finish_resolving_def_to_ty(self, self, span, - PathParamMode::Optional, path_res.base_def, opt_self_ty, node_id, @@ -4379,11 +4377,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => bug!("unexpected definition: {:?}", def), } - // In `>::method`, `A` and `B` are mandatory, but - // `opt_self_ty` can also be Some for `Foo::method`, where Foo's - // type parameters are not mandatory. - let require_type_space = opt_self_ty.is_some() && ufcs_associated.is_none(); - debug!("type_segment={:?} fn_segment={:?}", type_segment, fn_segment); // Now that we have categorized what space the parameters for each @@ -4414,8 +4407,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // variables. If the user provided some types, we may still need // to add defaults. If the user provided *too many* types, that's // a problem. - self.check_path_parameter_count(span, !require_type_space, &mut type_segment); - self.check_path_parameter_count(span, true, &mut fn_segment); + self.check_path_parameter_count(span, &mut type_segment); + self.check_path_parameter_count(span, &mut fn_segment); let (fn_start, has_self) = match (type_segment, fn_segment) { (_, Some((_, generics))) => { @@ -4450,7 +4443,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }, |def, substs| { let mut i = def.index as usize; - let can_omit = i >= fn_start || !require_type_space; let segment = if i < fn_start { // Handle Self first, so we can adjust the index to match the AST. if has_self && i == 0 { @@ -4464,10 +4456,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { i -= fn_start; fn_segment }; - let types = match segment.map(|(s, _)| &s.parameters) { - Some(&hir::AngleBracketedParameters(ref data)) => &data.types[..], + let (types, infer_types) = match segment.map(|(s, _)| &s.parameters) { + Some(&hir::AngleBracketedParameters(ref data)) => { + (&data.types[..], data.infer_types) + } Some(&hir::ParenthesizedParameters(_)) => bug!(), - None => &[] + None => (&[][..], true) }; // Skip over the lifetimes in the same segment. @@ -4475,11 +4469,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { i -= generics.regions.len(); } - let omitted = can_omit && types.is_empty(); if let Some(ast_ty) = types.get(i) { // A provided type parameter. self.to_ty(ast_ty) - } else if let (false, Some(default)) = (omitted, def.default) { + } else if let (false, Some(default)) = (infer_types, def.default) { // No type parameter provided, but a default exists. default.subst_spanned(self.tcx, substs, Some(span)) } else { @@ -4539,16 +4532,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// Report errors if the provided parameters are too few or too many. fn check_path_parameter_count(&self, span: Span, - can_omit: bool, segment: &mut Option<(&hir::PathSegment, &ty::Generics)>) { - let (lifetimes, types, bindings) = match segment.map(|(s, _)| &s.parameters) { - Some(&hir::AngleBracketedParameters(ref data)) => { - (&data.lifetimes[..], &data.types[..], &data.bindings[..]) + let (lifetimes, types, infer_types, bindings) = { + match segment.map(|(s, _)| &s.parameters) { + Some(&hir::AngleBracketedParameters(ref data)) => { + (&data.lifetimes[..], &data.types[..], data.infer_types, &data.bindings[..]) + } + Some(&hir::ParenthesizedParameters(_)) => { + span_bug!(span, "parenthesized parameters cannot appear in ExprPath"); + } + None => (&[][..], &[][..], true, &[][..]) } - Some(&hir::ParenthesizedParameters(_)) => { - span_bug!(span, "parenthesized parameters cannot appear in ExprPath"); - } - None => (&[][..], &[][..], &[][..]) }; let count = |n| { @@ -4597,7 +4591,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // type parameters, we force instantiate_value_path to // use inference variables instead of the provided types. *segment = None; - } else if !(can_omit && types.len() == 0) && types.len() < required_len { + } else if !infer_types && types.len() < required_len { let adjust = |len| if len > 1 { "parameters" } else { "parameter" }; let required_param_str = adjust(required_len); let actual_param_str = adjust(types.len()); From 16b5c2cfef811feebe2797bcb7e01d2b6ff12db1 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Thu, 27 Oct 2016 05:17:42 +0300 Subject: [PATCH 081/293] rustc: desugar UFCS as much as possible during HIR lowering. --- src/librustc/cfg/construct.rs | 4 +- src/librustc/hir/intravisit.rs | 51 +++-- src/librustc/hir/lowering.rs | 189 ++++++++++++------ src/librustc/hir/mod.rs | 68 ++++--- src/librustc/hir/pat_util.rs | 13 +- src/librustc/hir/print.rs | 118 ++++++----- src/librustc/infer/error_reporting.rs | 11 +- src/librustc/middle/astconv_util.rs | 24 +-- src/librustc/middle/dead.rs | 3 + src/librustc/middle/effect.rs | 2 +- src/librustc/middle/expr_use_visitor.rs | 2 +- src/librustc/middle/intrinsicck.rs | 32 +-- src/librustc/middle/liveness.rs | 16 +- src/librustc/middle/mem_categorization.rs | 4 +- src/librustc/middle/reachable.rs | 2 +- src/librustc/middle/resolve_lifetime.rs | 7 +- src/librustc/middle/stability.rs | 28 +++ src/librustc/ty/mod.rs | 11 +- src/librustc_const_eval/_match.rs | 11 +- src/librustc_const_eval/eval.rs | 46 +++-- .../calculate_svh/svh_visitor.rs | 16 +- src/librustc_lint/bad_style.rs | 2 +- src/librustc_lint/builtin.rs | 8 +- src/librustc_lint/unused.rs | 2 +- src/librustc_mir/hair/cx/expr.rs | 4 +- src/librustc_passes/consts.rs | 2 +- src/librustc_passes/hir_stats.rs | 5 +- src/librustc_passes/static_recursion.rs | 2 +- src/librustc_privacy/lib.rs | 34 ++-- src/librustc_typeck/astconv.rs | 165 ++++++--------- src/librustc_typeck/check/_match.rs | 31 ++- src/librustc_typeck/check/method/suggest.rs | 3 +- src/librustc_typeck/check/mod.rs | 144 +++++++------ src/librustc_typeck/check/regionck.rs | 2 +- src/librustc_typeck/collect.rs | 2 +- src/librustdoc/clean/mod.rs | 41 +++- src/test/compile-fail/issue-28992-empty.rs | 2 +- .../compile-fail/method-path-in-pattern.rs | 8 +- .../compile-fail/qualified-path-params.rs | 2 +- .../unspecified-self-in-trait-ref.rs | 4 +- src/test/pretty/issue-4264.pp | 2 +- 41 files changed, 637 insertions(+), 486 deletions(-) diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index c399623462b..609d492a93a 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -100,7 +100,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { fn pat(&mut self, pat: &hir::Pat, pred: CFGIndex) -> CFGIndex { match pat.node { PatKind::Binding(.., None) | - PatKind::Path(..) | + PatKind::Path(_) | PatKind::Lit(..) | PatKind::Range(..) | PatKind::Wild => { @@ -361,7 +361,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { hir::ExprClosure(..) | hir::ExprLit(..) | - hir::ExprPath(..) => { + hir::ExprPath(_) => { self.straightline(expr, pred, None::.iter()) } } diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 7dd88e36dd1..743eed74d0c 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -244,6 +244,9 @@ pub trait Visitor<'v> : Sized { fn visit_lifetime_def(&mut self, lifetime: &'v LifetimeDef) { walk_lifetime_def(self, lifetime) } + fn visit_qpath(&mut self, qpath: &'v QPath, id: NodeId, span: Span) { + walk_qpath(self, qpath, id, span) + } fn visit_path(&mut self, path: &'v Path, _id: NodeId) { walk_path(self, path) } @@ -481,11 +484,8 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { walk_fn_decl(visitor, &function_declaration.decl); walk_list!(visitor, visit_lifetime_def, &function_declaration.lifetimes); } - TyPath(ref maybe_qself, ref path) => { - if let Some(ref qself) = *maybe_qself { - visitor.visit_ty(&qself.ty); - } - visitor.visit_path(path, typ.id); + TyPath(ref qpath) => { + visitor.visit_qpath(qpath, typ.id, typ.span); } TyObjectSum(ref ty, ref bounds) => { visitor.visit_ty(ty); @@ -508,6 +508,21 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { } } +pub fn walk_qpath<'v, V: Visitor<'v>>(visitor: &mut V, qpath: &'v QPath, id: NodeId, span: Span) { + match *qpath { + QPath::Resolved(ref maybe_qself, ref path) => { + if let Some(ref qself) = *maybe_qself { + visitor.visit_ty(qself); + } + visitor.visit_path(path, id) + } + QPath::TypeRelative(ref qself, ref segment) => { + visitor.visit_ty(qself); + visitor.visit_path_segment(span, segment); + } + } +} + pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path) { for segment in &path.segments { visitor.visit_path_segment(path.span, segment); @@ -555,18 +570,15 @@ pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V, pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { visitor.visit_id(pattern.id); match pattern.node { - PatKind::TupleStruct(ref path, ref children, _) => { - visitor.visit_path(path, pattern.id); + PatKind::TupleStruct(ref qpath, ref children, _) => { + visitor.visit_qpath(qpath, pattern.id, pattern.span); walk_list!(visitor, visit_pat, children); } - PatKind::Path(ref opt_qself, ref path) => { - if let Some(ref qself) = *opt_qself { - visitor.visit_ty(&qself.ty); - } - visitor.visit_path(path, pattern.id) + PatKind::Path(ref qpath) => { + visitor.visit_qpath(qpath, pattern.id, pattern.span); } - PatKind::Struct(ref path, ref fields, _) => { - visitor.visit_path(path, pattern.id); + PatKind::Struct(ref qpath, ref fields, _) => { + visitor.visit_qpath(qpath, pattern.id, pattern.span); for field in fields { visitor.visit_name(field.span, field.node.name); visitor.visit_pat(&field.node.pat) @@ -840,8 +852,8 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { visitor.visit_expr(element); visitor.visit_expr(count) } - ExprStruct(ref path, ref fields, ref optional_base) => { - visitor.visit_path(path, expression.id); + ExprStruct(ref qpath, ref fields, ref optional_base) => { + visitor.visit_qpath(qpath, expression.id, expression.span); for field in fields { visitor.visit_name(field.name.span, field.name.node); visitor.visit_expr(&field.expr) @@ -917,11 +929,8 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { visitor.visit_expr(main_expression); visitor.visit_expr(index_expression) } - ExprPath(ref maybe_qself, ref path) => { - if let Some(ref qself) = *maybe_qself { - visitor.visit_ty(&qself.ty); - } - visitor.visit_path(path, expression.id) + ExprPath(ref qpath) => { + visitor.visit_qpath(qpath, expression.id, expression.span); } ExprBreak(ref opt_sp_name, ref opt_expr) => { walk_opt_sp_name(visitor, opt_sp_name); diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 264a5722bcd..056c1b90620 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -188,13 +188,13 @@ impl<'a> LoweringContext<'a> { node: match view_path.node { ViewPathSimple(ident, ref path) => { hir::ViewPathSimple(ident.name, - self.lower_path(path, None, ParamMode::Explicit)) + self.lower_path(path, ParamMode::Explicit)) } ViewPathGlob(ref path) => { - hir::ViewPathGlob(self.lower_path(path, None, ParamMode::Explicit)) + hir::ViewPathGlob(self.lower_path(path, ParamMode::Explicit)) } ViewPathList(ref path, ref path_list_idents) => { - hir::ViewPathList(self.lower_path(path, None, ParamMode::Explicit), + hir::ViewPathList(self.lower_path(path, ParamMode::Explicit), path_list_idents.iter() .map(|item| self.lower_path_list_item(item)) .collect()) @@ -259,14 +259,7 @@ impl<'a> LoweringContext<'a> { return self.lower_ty(ty); } TyKind::Path(ref qself, ref path) => { - let qself = qself.as_ref().map(|&QSelf { ref ty, position }| { - hir::QSelf { - ty: self.lower_ty(ty), - position: position, - } - }); - let path = self.lower_path(path, qself.as_ref(), ParamMode::Explicit); - hir::TyPath(qself, path) + hir::TyPath(self.lower_qpath(t.id, qself, path, ParamMode::Explicit)) } TyKind::ObjectSum(ref ty, ref bounds) => { hir::TyObjectSum(self.lower_ty(ty), self.lower_bounds(bounds)) @@ -308,17 +301,24 @@ impl<'a> LoweringContext<'a> { } } - fn lower_path(&mut self, - p: &Path, - qself: Option<&hir::QSelf>, - param_mode: ParamMode) - -> hir::Path { - hir::Path { + fn lower_qpath(&mut self, + id: NodeId, + qself: &Option, + p: &Path, + param_mode: ParamMode) + -> hir::QPath { + let qself_position = qself.as_ref().map(|q| q.position); + let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty)); + + let resolution = self.resolver.get_resolution(id) + .unwrap_or(PathResolution::new(Def::Err)); + + let proj_start = p.segments.len() - resolution.depth; + let path = P(hir::Path { global: p.global, - segments: p.segments.iter().enumerate().map(|(i, segment)| { - let PathSegment { identifier, ref parameters } = *segment; - let param_mode = match (qself, param_mode) { - (Some(qself), ParamMode::Optional) if i < qself.position => { + segments: p.segments[..proj_start].iter().enumerate().map(|(i, segment)| { + let param_mode = match (qself_position, param_mode) { + (Some(j), ParamMode::Optional) if i < j => { // This segment is part of the trait path in a // qualified path - one of `a`, `b` or `Trait` // in `::T::U::method`. @@ -326,26 +326,91 @@ impl<'a> LoweringContext<'a> { } _ => param_mode }; - hir::PathSegment { - name: identifier.name, - parameters: self.lower_path_parameters(parameters, param_mode), - } + self.lower_path_segment(segment, param_mode) + }).collect(), + span: p.span, + }); + + // Simple case, either no projections, or only fully-qualified. + // E.g. `std::mem::size_of` or `::Item`. + if resolution.depth == 0 { + return hir::QPath::Resolved(qself, path); + } + + // Create the innermost type that we're projecting from. + let mut ty = if path.segments.is_empty() { + // If the base path is empty that means there exists a + // syntactical `Self`, e.g. `&i32` in `<&i32>::clone`. + qself.expect("missing QSelf for ::...") + } else { + // Otherwise, the base path is an implicit `Self` type path, + // e.g. `Vec` in `Vec::new` or `::Item` in + // `::Item::default`. + let ty = self.ty(p.span, hir::TyPath(hir::QPath::Resolved(qself, path))); + + // Associate that innermost path type with the base Def. + self.resolver.record_resolution(ty.id, resolution.base_def); + + ty + }; + + // Anything after the base path are associated "extensions", + // out of which all but the last one are associated types, + // e.g. for `std::vec::Vec::::IntoIter::Item::clone`: + // * base path is `std::vec::Vec` + // * "extensions" are `IntoIter`, `Item` and `clone` + // * type nodes are: + // 1. `std::vec::Vec` (created above) + // 2. `>::IntoIter` + // 3. `<>::IntoIter>::Item` + // * final path is `<<>::IntoIter>::Item>::clone` + for (i, segment) in p.segments.iter().enumerate().skip(proj_start) { + let segment = P(self.lower_path_segment(segment, param_mode)); + let qpath = hir::QPath::TypeRelative(ty, segment); + + // It's finished, return the extension of the right node type. + if i == p.segments.len() - 1 { + return qpath; + } + + // Wrap the associated extension in another type node. + ty = self.ty(p.span, hir::TyPath(qpath)); + } + + // Should've returned in the for loop above. + span_bug!(p.span, "lower_qpath: no final extension segment in {}..{}", + proj_start, p.segments.len()) + } + + fn lower_path(&mut self, + p: &Path, + param_mode: ParamMode) + -> hir::Path { + hir::Path { + global: p.global, + segments: p.segments.iter().map(|segment| { + self.lower_path_segment(segment, param_mode) }).collect(), span: p.span, } } - fn lower_path_parameters(&mut self, - path_parameters: &PathParameters, - param_mode: ParamMode) - -> hir::PathParameters { - match *path_parameters { + fn lower_path_segment(&mut self, + segment: &PathSegment, + param_mode: ParamMode) + -> hir::PathSegment { + let parameters = match segment.parameters { PathParameters::AngleBracketed(ref data) => { let data = self.lower_angle_bracketed_parameter_data(data, param_mode); hir::AngleBracketedParameters(data) } PathParameters::Parenthesized(ref data) => hir::ParenthesizedParameters(self.lower_parenthesized_parameter_data(data)), + }; + + hir::PathSegment { + name: segment.identifier.name, + parameters: parameters, } } @@ -521,7 +586,7 @@ impl<'a> LoweringContext<'a> { span}) => { hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { id: id, - path: self.lower_path(path, None, ParamMode::Explicit), + path: self.lower_path(path, ParamMode::Explicit), ty: self.lower_ty(ty), span: span, }) @@ -551,7 +616,7 @@ impl<'a> LoweringContext<'a> { fn lower_trait_ref(&mut self, p: &TraitRef) -> hir::TraitRef { hir::TraitRef { - path: self.lower_path(&p.path, None, ParamMode::Explicit), + path: self.lower_path(&p.path, ParamMode::Explicit), ref_id: p.ref_id, } } @@ -908,26 +973,26 @@ impl<'a> LoweringContext<'a> { respan(pth1.span, pth1.node.name), sub.as_ref().map(|x| this.lower_pat(x))) } - _ => hir::PatKind::Path(None, hir::Path::from_name(pth1.span, - pth1.node.name)) + _ => { + let path = hir::Path::from_name(pth1.span, pth1.node.name); + hir::PatKind::Path(hir::QPath::Resolved(None, P(path))) + } } }) } PatKind::Lit(ref e) => hir::PatKind::Lit(P(self.lower_expr(e))), PatKind::TupleStruct(ref path, ref pats, ddpos) => { - hir::PatKind::TupleStruct(self.lower_path(path, None, ParamMode::Optional), + let qpath = self.lower_qpath(p.id, &None, path, ParamMode::Optional); + hir::PatKind::TupleStruct(qpath, pats.iter().map(|x| self.lower_pat(x)).collect(), ddpos) } PatKind::Path(ref qself, ref path) => { - let qself = qself.as_ref().map(|qself| { - hir::QSelf { ty: self.lower_ty(&qself.ty), position: qself.position } - }); - let path = self.lower_path(path, qself.as_ref(), ParamMode::Optional); - hir::PatKind::Path(qself, path) + hir::PatKind::Path(self.lower_qpath(p.id, qself, path, ParamMode::Optional)) } - PatKind::Struct(ref pth, ref fields, etc) => { - let pth = self.lower_path(pth, None, ParamMode::Optional); + PatKind::Struct(ref path, ref fields, etc) => { + let qpath = self.lower_qpath(p.id, &None, path, ParamMode::Optional); + let fs = fields.iter() .map(|f| { Spanned { @@ -940,7 +1005,7 @@ impl<'a> LoweringContext<'a> { } }) .collect(); - hir::PatKind::Struct(pth, fs, etc) + hir::PatKind::Struct(qpath, fs, etc) } PatKind::Tuple(ref elts, ddpos) => { hir::PatKind::Tuple(elts.iter().map(|x| self.lower_pat(x)).collect(), ddpos) @@ -1266,14 +1331,7 @@ impl<'a> LoweringContext<'a> { }; } ExprKind::Path(ref qself, ref path) => { - let qself = qself.as_ref().map(|&QSelf { ref ty, position }| { - hir::QSelf { - ty: self.lower_ty(ty), - position: position, - } - }); - let path = self.lower_path(path, qself.as_ref(), ParamMode::Optional); - hir::ExprPath(qself, path) + hir::ExprPath(self.lower_qpath(e.id, qself, path, ParamMode::Optional)) } ExprKind::Break(opt_ident, ref opt_expr) => { hir::ExprBreak(self.lower_opt_sp_ident(opt_ident), @@ -1306,7 +1364,7 @@ impl<'a> LoweringContext<'a> { hir::ExprInlineAsm(P(hir_asm), outputs, inputs) } ExprKind::Struct(ref path, ref fields, ref maybe_expr) => { - hir::ExprStruct(P(self.lower_path(path, None, ParamMode::Optional)), + hir::ExprStruct(self.lower_qpath(e.id, &None, path, ParamMode::Optional), fields.iter().map(|x| self.lower_field(x)).collect(), maybe_expr.as_ref().map(|x| P(self.lower_expr(x)))) } @@ -1688,7 +1746,7 @@ impl<'a> LoweringContext<'a> { Visibility::Crate(_) => hir::Visibility::Crate, Visibility::Restricted { ref path, id } => { hir::Visibility::Restricted { - path: P(self.lower_path(path, None, ParamMode::Explicit)), + path: P(self.lower_path(path, ParamMode::Explicit)), id: id } } @@ -1774,7 +1832,8 @@ impl<'a> LoweringContext<'a> { } fn expr_ident(&mut self, span: Span, id: Name, binding: NodeId) -> hir::Expr { - let expr_path = hir::ExprPath(None, self.path_ident(span, id)); + let path = self.path_ident(span, id); + let expr_path = hir::ExprPath(hir::QPath::Resolved(None, P(path))); let expr = self.expr(span, expr_path, ThinVec::new()); let def = { @@ -1792,9 +1851,9 @@ impl<'a> LoweringContext<'a> { fn expr_path(&mut self, path: hir::Path, attrs: ThinVec) -> P { let def = self.resolver.resolve_generated_global_path(&path, true); - let expr = P(self.expr(path.span, hir::ExprPath(None, path), attrs)); + let expr = self.expr(path.span, hir::ExprPath(hir::QPath::Resolved(None, P(path))), attrs); self.resolver.record_resolution(expr.id, def); - expr + P(expr) } fn expr_match(&mut self, @@ -1821,9 +1880,10 @@ impl<'a> LoweringContext<'a> { e: Option>, attrs: ThinVec) -> P { let def = self.resolver.resolve_generated_global_path(&path, false); - let expr = P(self.expr(sp, hir::ExprStruct(P(path), fields, e), attrs)); + let qpath = hir::QPath::Resolved(None, P(path)); + let expr = self.expr(sp, hir::ExprStruct(qpath, fields, e), attrs); self.resolver.record_resolution(expr.id, def); - expr + P(expr) } fn expr(&mut self, span: Span, node: hir::Expr_, attrs: ThinVec) -> hir::Expr { @@ -1902,10 +1962,11 @@ impl<'a> LoweringContext<'a> { fn pat_enum(&mut self, span: Span, path: hir::Path, subpats: hir::HirVec>) -> P { let def = self.resolver.resolve_generated_global_path(&path, true); + let qpath = hir::QPath::Resolved(None, P(path)); let pt = if subpats.is_empty() { - hir::PatKind::Path(None, path) + hir::PatKind::Path(qpath) } else { - hir::PatKind::TupleStruct(path, subpats, None) + hir::PatKind::TupleStruct(qpath, subpats, None) }; let pat = self.pat(span, pt); self.resolver.record_resolution(pat.id, def); @@ -2045,4 +2106,12 @@ impl<'a> LoweringContext<'a> { }); self.expr_block(block, attrs) } + + fn ty(&mut self, span: Span, node: hir::Ty_) -> P { + P(hir::Ty { + id: self.next_id(), + node: node, + span: span, + }) + } } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 6f0a3a02380..e9e84eed3e7 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -533,7 +533,7 @@ impl Pat { PatKind::Lit(_) | PatKind::Range(..) | PatKind::Binding(..) | - PatKind::Path(..) => { + PatKind::Path(_) => { true } } @@ -576,16 +576,15 @@ pub enum PatKind { /// A struct or struct variant pattern, e.g. `Variant {x, y, ..}`. /// The `bool` is `true` in the presence of a `..`. - Struct(Path, HirVec>, bool), + Struct(QPath, HirVec>, bool), /// A tuple struct/variant pattern `Variant(x, y, .., z)`. /// If the `..` pattern fragment is present, then `Option` denotes its position. /// 0 <= position <= subpats.len() - TupleStruct(Path, HirVec>, Option), + TupleStruct(QPath, HirVec>, Option), - /// A possibly qualified path pattern. - /// Such pattern can be resolved to a unit struct/variant or a constant. - Path(Option, Path), + /// A path pattern for an unit struct/variant or a (maybe-associated) constant. + Path(QPath), /// A tuple pattern `(a, b)`. /// If the `..` pattern fragment is present, then `Option` denotes its position. @@ -940,12 +939,8 @@ pub enum Expr_ { /// An indexing operation (`foo[2]`) ExprIndex(P, P), - /// Variable reference, possibly containing `::` and/or type - /// parameters, e.g. foo::bar::. - /// - /// Optionally "qualified", - /// e.g. ` as SomeTrait>::SomeType`. - ExprPath(Option, Path), + /// Path to a definition, possibly containing lifetime or type parameters. + ExprPath(QPath), /// A referencing operation (`&a` or `&mut a`) ExprAddrOf(Mutability, P), @@ -963,7 +958,7 @@ pub enum Expr_ { /// /// For example, `Foo {x: 1, y: 2}`, or /// `Foo {x: 1, .. base}`, where `base` is the `Option`. - ExprStruct(P, HirVec, Option>), + ExprStruct(QPath, HirVec, Option>), /// An array literal constructed from one repeated element. /// @@ -972,22 +967,30 @@ pub enum Expr_ { ExprRepeat(P, P), } -/// The explicit Self type in a "qualified path". The actual -/// path, including the trait and the associated item, is stored -/// separately. `position` represents the index of the associated -/// item qualified with this Self type. -/// -/// as a::b::Trait>::AssociatedItem -/// ^~~~~ ~~~~~~~~~~~~~~^ -/// ty position = 3 -/// -/// >::AssociatedItem -/// ^~~~~ ^ -/// ty position = 0 +/// Optionally `Self`-qualified value/type path or associated extension. #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub struct QSelf { - pub ty: P, - pub position: usize, +pub enum QPath { + /// Path to a definition, optionally "fully-qualified" with a `Self` + /// type, if the path points to an associated item in a trait. + /// + /// E.g. an unqualified path like `Clone::clone` has `None` for `Self`, + /// while ` as Clone>::clone` has `Some(Vec)` for `Self`, + /// even though they both have the same two-segment `Clone::clone` `Path`. + Resolved(Option>, P), + + /// Type-related paths, e.g. `::default` or `::Output`. + /// Will be resolved by type-checking to an associated item. + /// + /// UFCS source paths can desugar into this, with `Vec::new` turning into + /// `::new`, and `T::X::Y::method` into `<<::X>::Y>::method`, + /// the `X` and `Y` nodes being each a `TyPath(QPath::TypeRelative(..))`. + TypeRelative(P, P) +} + +impl fmt::Display for QPath { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", print::qpath_to_string(self)) + } } /// Hints at the original code for a `match _ { .. }` @@ -1161,11 +1164,12 @@ pub enum Ty_ { TyNever, /// A tuple (`(A, B, C, D,...)`) TyTup(HirVec>), - /// A path (`module::module::...::Type`), optionally - /// "qualified", e.g. ` as SomeTrait>::SomeType`. + /// A path to a type definition (`module::module::...::Type`), or an + /// associated type, e.g. ` as Trait>::Type` or `::Target`. /// - /// Type parameters are stored in the Path itself - TyPath(Option, Path), + /// Type parameters may be stored in each `PathSegment`. + TyPath(QPath), + /// Something like `A+B`. Note that `B` must always be a path. TyObjectSum(P, TyParamBounds), /// A type like `for<'a> Foo<&'a Bar>` diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs index 0deea941463..8e39fde367b 100644 --- a/src/librustc/hir/pat_util.rs +++ b/src/librustc/hir/pat_util.rs @@ -53,9 +53,13 @@ impl EnumerateAndAdjustIterator for T { pub fn pat_is_refutable(dm: &DefMap, pat: &hir::Pat) -> bool { match pat.node { - PatKind::Lit(_) | PatKind::Range(..) | PatKind::Path(Some(..), _) => true, + PatKind::Lit(_) | + PatKind::Range(..) | + PatKind::Path(hir::QPath::Resolved(Some(..), _)) | + PatKind::Path(hir::QPath::TypeRelative(..)) => true, + PatKind::TupleStruct(..) | - PatKind::Path(..) | + PatKind::Path(hir::QPath::Resolved(..)) | PatKind::Struct(..) => { match dm.get(&pat.id).map(|d| d.full_def()) { Some(Def::Variant(..)) | Some(Def::VariantCtor(..)) => true, @@ -69,7 +73,8 @@ pub fn pat_is_refutable(dm: &DefMap, pat: &hir::Pat) -> bool { pub fn pat_is_const(dm: &DefMap, pat: &hir::Pat) -> bool { match pat.node { - PatKind::Path(..) => { + PatKind::Path(hir::QPath::TypeRelative(..)) => true, + PatKind::Path(hir::QPath::Resolved(..)) => { match dm.get(&pat.id).map(|d| d.full_def()) { Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => true, _ => false @@ -171,7 +176,7 @@ pub fn necessary_variants(dm: &DefMap, pat: &hir::Pat) -> Vec { pat.walk(|p| { match p.node { PatKind::TupleStruct(..) | - PatKind::Path(..) | + PatKind::Path(hir::QPath::Resolved(..)) | PatKind::Struct(..) => { match dm.get(&p.id).map(|d| d.full_def()) { Some(Def::Variant(id)) | diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 9934259c5d1..448139c37e6 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -272,7 +272,11 @@ pub fn fn_block_to_string(p: &hir::FnDecl) -> String { } pub fn path_to_string(p: &hir::Path) -> String { - to_string(|s| s.print_path(p, false, 0)) + to_string(|s| s.print_path(p, false)) +} + +pub fn qpath_to_string(p: &hir::QPath) -> String { + to_string(|s| s.print_qpath(p, false)) } pub fn name_to_string(name: ast::Name) -> String { @@ -528,11 +532,8 @@ impl<'a> State<'a> { }; self.print_ty_fn(f.abi, f.unsafety, &f.decl, None, &generics)?; } - hir::TyPath(None, ref path) => { - self.print_path(path, false, 0)?; - } - hir::TyPath(Some(ref qself), ref path) => { - self.print_qpath(path, qself, false)? + hir::TyPath(ref qpath) => { + self.print_qpath(qpath, false)? } hir::TyObjectSum(ref ty, ref bounds) => { self.print_type(&ty)?; @@ -845,7 +846,7 @@ impl<'a> State<'a> { } fn print_trait_ref(&mut self, t: &hir::TraitRef) -> io::Result<()> { - self.print_path(&t.path, false, 0) + self.print_path(&t.path, false) } fn print_formal_lifetime_list(&mut self, lifetimes: &[hir::LifetimeDef]) -> io::Result<()> { @@ -1237,11 +1238,11 @@ impl<'a> State<'a> { } fn print_expr_struct(&mut self, - path: &hir::Path, + qpath: &hir::QPath, fields: &[hir::Field], wth: &Option>) -> io::Result<()> { - self.print_path(path, true, 0)?; + self.print_qpath(qpath, true)?; word(&mut self.s, "{")?; self.commasep_cmnt(Consistent, &fields[..], @@ -1345,8 +1346,8 @@ impl<'a> State<'a> { hir::ExprRepeat(ref element, ref count) => { self.print_expr_repeat(&element, &count)?; } - hir::ExprStruct(ref path, ref fields, ref wth) => { - self.print_expr_struct(path, &fields[..], wth)?; + hir::ExprStruct(ref qpath, ref fields, ref wth) => { + self.print_expr_struct(qpath, &fields[..], wth)?; } hir::ExprTup(ref exprs) => { self.print_expr_tup(exprs)?; @@ -1465,11 +1466,8 @@ impl<'a> State<'a> { self.print_expr(&index)?; word(&mut self.s, "]")?; } - hir::ExprPath(None, ref path) => { - self.print_path(path, true, 0)? - } - hir::ExprPath(Some(ref qself), ref path) => { - self.print_qpath(path, qself, true)? + hir::ExprPath(ref qpath) => { + self.print_qpath(qpath, true)? } hir::ExprBreak(opt_name, ref opt_expr) => { word(&mut self.s, "break")?; @@ -1622,13 +1620,12 @@ impl<'a> State<'a> { fn print_path(&mut self, path: &hir::Path, - colons_before_params: bool, - depth: usize) + colons_before_params: bool) -> io::Result<()> { self.maybe_print_comment(path.span.lo)?; let mut first = !path.global; - for segment in &path.segments[..path.segments.len() - depth] { + for segment in &path.segments { if first { first = false } else { @@ -1644,23 +1641,45 @@ impl<'a> State<'a> { } fn print_qpath(&mut self, - path: &hir::Path, - qself: &hir::QSelf, + qpath: &hir::QPath, colons_before_params: bool) -> io::Result<()> { - word(&mut self.s, "<")?; - self.print_type(&qself.ty)?; - if qself.position > 0 { - space(&mut self.s)?; - self.word_space("as")?; - let depth = path.segments.len() - qself.position; - self.print_path(&path, false, depth)?; + match *qpath { + hir::QPath::Resolved(None, ref path) => { + self.print_path(path, colons_before_params) + } + hir::QPath::Resolved(Some(ref qself), ref path) => { + word(&mut self.s, "<")?; + self.print_type(qself)?; + space(&mut self.s)?; + self.word_space("as")?; + + let mut first = !path.global; + for segment in &path.segments[..path.segments.len() - 1] { + if first { + first = false + } else { + word(&mut self.s, "::")? + } + self.print_name(segment.name)?; + self.print_path_parameters(&segment.parameters, colons_before_params)?; + } + + word(&mut self.s, ">")?; + word(&mut self.s, "::")?; + let item_segment = path.segments.last().unwrap(); + self.print_name(item_segment.name)?; + self.print_path_parameters(&item_segment.parameters, colons_before_params) + } + hir::QPath::TypeRelative(ref qself, ref item_segment) => { + word(&mut self.s, "<")?; + self.print_type(qself)?; + word(&mut self.s, ">")?; + word(&mut self.s, "::")?; + self.print_name(item_segment.name)?; + self.print_path_parameters(&item_segment.parameters, colons_before_params) + } } - word(&mut self.s, ">")?; - word(&mut self.s, "::")?; - let item_segment = path.segments.last().unwrap(); - self.print_name(item_segment.name)?; - self.print_path_parameters(&item_segment.parameters, colons_before_params) } fn print_path_parameters(&mut self, @@ -1668,7 +1687,15 @@ impl<'a> State<'a> { colons_before_params: bool) -> io::Result<()> { if parameters.is_empty() { - return Ok(()); + let infer_types = match *parameters { + hir::AngleBracketedParameters(ref data) => data.infer_types, + hir::ParenthesizedParameters(_) => false + }; + + // FIXME(eddyb) See the comment below about infer_types. + if !(infer_types && false) { + return Ok(()); + } } if colons_before_params { @@ -1760,8 +1787,8 @@ impl<'a> State<'a> { self.print_pat(&p)?; } } - PatKind::TupleStruct(ref path, ref elts, ddpos) => { - self.print_path(path, true, 0)?; + PatKind::TupleStruct(ref qpath, ref elts, ddpos) => { + self.print_qpath(qpath, true)?; self.popen()?; if let Some(ddpos) = ddpos { self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p))?; @@ -1778,14 +1805,11 @@ impl<'a> State<'a> { } self.pclose()?; } - PatKind::Path(None, ref path) => { - self.print_path(path, true, 0)?; + PatKind::Path(ref qpath) => { + self.print_qpath(qpath, true)?; } - PatKind::Path(Some(ref qself), ref path) => { - self.print_qpath(path, qself, false)?; - } - PatKind::Struct(ref path, ref fields, etc) => { - self.print_path(path, true, 0)?; + PatKind::Struct(ref qpath, ref fields, etc) => { + self.print_qpath(qpath, true)?; self.nbsp()?; self.word_space("{")?; self.commasep_cmnt(Consistent, @@ -2118,7 +2142,7 @@ impl<'a> State<'a> { } } &hir::WherePredicate::EqPredicate(hir::WhereEqPredicate{ref path, ref ty, ..}) => { - self.print_path(path, false, 0)?; + self.print_path(path, false)?; space(&mut self.s)?; self.word_space("=")?; self.print_type(&ty)?; @@ -2132,7 +2156,7 @@ impl<'a> State<'a> { pub fn print_view_path(&mut self, vp: &hir::ViewPath) -> io::Result<()> { match vp.node { hir::ViewPathSimple(name, ref path) => { - self.print_path(path, false, 0)?; + self.print_path(path, false)?; if path.segments.last().unwrap().name != name { space(&mut self.s)?; @@ -2144,7 +2168,7 @@ impl<'a> State<'a> { } hir::ViewPathGlob(ref path) => { - self.print_path(path, false, 0)?; + self.print_path(path, false)?; word(&mut self.s, "::*") } @@ -2152,7 +2176,7 @@ impl<'a> State<'a> { if path.segments.is_empty() { word(&mut self.s, "{")?; } else { - self.print_path(path, false, 0)?; + self.print_path(path, false)?; word(&mut self.s, "::{")?; } self.commasep(Inconsistent, &segments[..], |s, w| s.print_name(w.node.name))?; diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index b9b97473340..406d345992a 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -1440,7 +1440,7 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> { } ty_queue.push(&mut_ty.ty); } - hir::TyPath(ref maybe_qself, ref path) => { + hir::TyPath(hir::QPath::Resolved(ref maybe_qself, ref path)) => { match self.tcx.expect_def(cur_ty.id) { Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) | Def::Union(did) => { @@ -1476,15 +1476,12 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> { }; let new_path = self.rebuild_path(rebuild_info, lifetime); let qself = maybe_qself.as_ref().map(|qself| { - hir::QSelf { - ty: self.rebuild_arg_ty_or_output(&qself.ty, lifetime, - anon_nums, region_names), - position: qself.position - } + self.rebuild_arg_ty_or_output(qself, lifetime, + anon_nums, region_names) }); let to = hir::Ty { id: cur_ty.id, - node: hir::TyPath(qself, new_path), + node: hir::TyPath(hir::QPath::Resolved(qself, P(new_path))), span: cur_ty.span }; new_ty = self.rebuild_ty(new_ty, P(to)); diff --git a/src/librustc/middle/astconv_util.rs b/src/librustc/middle/astconv_util.rs index 86422835c8c..5b0f241f8a8 100644 --- a/src/librustc/middle/astconv_util.rs +++ b/src/librustc/middle/astconv_util.rs @@ -14,14 +14,14 @@ * Almost certainly this could (and should) be refactored out of existence. */ +use hir; use hir::def::Def; use ty::{Ty, TyCtxt}; use syntax_pos::Span; -use hir as ast; impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { - pub fn prohibit_type_params(self, segments: &[ast::PathSegment]) { + pub fn prohibit_type_params(self, segments: &[hir::PathSegment]) { for segment in segments { for typ in segment.parameters.types() { struct_span_err!(self.sess, typ.span, E0109, @@ -53,24 +53,24 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn prim_ty_to_ty(self, - segments: &[ast::PathSegment], - nty: ast::PrimTy) + segments: &[hir::PathSegment], + nty: hir::PrimTy) -> Ty<'tcx> { self.prohibit_type_params(segments); match nty { - ast::TyBool => self.types.bool, - ast::TyChar => self.types.char, - ast::TyInt(it) => self.mk_mach_int(it), - ast::TyUint(uit) => self.mk_mach_uint(uit), - ast::TyFloat(ft) => self.mk_mach_float(ft), - ast::TyStr => self.mk_str() + hir::TyBool => self.types.bool, + hir::TyChar => self.types.char, + hir::TyInt(it) => self.mk_mach_int(it), + hir::TyUint(uit) => self.mk_mach_uint(uit), + hir::TyFloat(ft) => self.mk_mach_float(ft), + hir::TyStr => self.mk_str() } } /// If a type in the AST is a primitive type, return the ty::Ty corresponding /// to it. - pub fn ast_ty_to_prim_ty(self, ast_ty: &ast::Ty) -> Option> { - if let ast::TyPath(None, ref path) = ast_ty.node { + pub fn ast_ty_to_prim_ty(self, ast_ty: &hir::Ty) -> Option> { + if let hir::TyPath(hir::QPath::Resolved(None, ref path)) = ast_ty.node { if let Def::PrimTy(nty) = self.expect_def(ast_ty.id) { Some(self.prim_ty_to_ty(&path.segments, nty)) } else { diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index f47eab013c2..efbec7bf13b 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -240,6 +240,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &hir::Expr) { match expr.node { + hir::ExprPath(hir::QPath::TypeRelative(..)) => { + self.lookup_and_handle_definition(expr.id); + } hir::ExprMethodCall(..) => { self.lookup_and_handle_method(expr.id); } diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index 25fe407271b..2892f249c5e 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -186,7 +186,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { hir::ExprInlineAsm(..) => { self.require_unsafe(expr.span, "use of inline assembly"); } - hir::ExprPath(..) => { + hir::ExprPath(hir::QPath::Resolved(..)) => { if let Def::Static(def_id, mutbl) = self.tcx.expect_def(expr.id) { if mutbl { self.require_unsafe(expr.span, "use of mutable static"); diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 594ed408d8c..6c952825554 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -374,7 +374,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { self.walk_adjustment(expr); match expr.node { - hir::ExprPath(..) => { } + hir::ExprPath(_) => { } hir::ExprType(ref subexpr, _) => { self.walk_expr(&subexpr) diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index 80cf64865ab..c610c6f75b0 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -160,23 +160,27 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ItemVisitor<'a, 'tcx> { impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for ExprVisitor<'a, 'gcx, 'tcx> { fn visit_expr(&mut self, expr: &hir::Expr) { - if let hir::ExprPath(..) = expr.node { - match self.infcx.tcx.expect_def(expr.id) { - Def::Fn(did) if self.def_id_is_transmute(did) => { - let typ = self.infcx.tcx.tables().node_id_to_type(expr.id); - match typ.sty { - ty::TyFnDef(.., ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => { - let from = bare_fn_ty.sig.0.inputs[0]; - let to = bare_fn_ty.sig.0.output; - self.check_transmute(expr.span, from, to, expr.id); - } - _ => { - span_bug!(expr.span, "transmute wasn't a bare fn?!"); - } + let def = match expr.node { + hir::ExprPath(_) => { + self.infcx.tcx.expect_def(expr.id) + } + _ => Def::Err + }; + match def { + Def::Fn(did) if self.def_id_is_transmute(did) => { + let typ = self.infcx.tcx.tables().node_id_to_type(expr.id); + match typ.sty { + ty::TyFnDef(.., ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => { + let from = bare_fn_ty.sig.0.inputs[0]; + let to = bare_fn_ty.sig.0.output; + self.check_transmute(expr.span, from, to, expr.id); + } + _ => { + span_bug!(expr.span, "transmute wasn't a bare fn?!"); } } - _ => {} } + _ => {} } intravisit::walk_expr(self, expr); diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 4b1787ba593..eefed0a5a74 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -443,7 +443,7 @@ fn visit_arm(ir: &mut IrMaps, arm: &hir::Arm) { fn visit_expr(ir: &mut IrMaps, expr: &Expr) { match expr.node { // live nodes required for uses or definitions of variables: - hir::ExprPath(..) => { + hir::ExprPath(_) => { let def = ir.tcx.expect_def(expr.id); debug!("expr {}: path that leads to {:?}", expr.id, def); if let Def::Local(..) = def { @@ -922,7 +922,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { match expr.node { // Interesting cases with control flow or which gen/kill - hir::ExprPath(..) => { + hir::ExprPath(hir::QPath::Resolved(..)) => { self.access_path(expr, succ, ACC_READ | ACC_USE) } @@ -1171,7 +1171,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.propagate_through_exprs(inputs, succ) } - hir::ExprLit(..) => { + hir::ExprLit(..) | hir::ExprPath(hir::QPath::TypeRelative(..)) => { succ } @@ -1235,7 +1235,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // just ignore such cases and treat them as reads. match expr.node { - hir::ExprPath(..) => succ, + hir::ExprPath(_) => succ, hir::ExprField(ref e, _) => self.propagate_through_expr(&e, succ), hir::ExprTupField(ref e, _) => self.propagate_through_expr(&e, succ), _ => self.propagate_through_expr(expr, succ) @@ -1246,7 +1246,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn write_lvalue(&mut self, expr: &Expr, succ: LiveNode, acc: u32) -> LiveNode { match expr.node { - hir::ExprPath(..) => { + hir::ExprPath(hir::QPath::Resolved(..)) => { self.access_path(expr, succ, acc) } @@ -1431,8 +1431,8 @@ fn check_expr(this: &mut Liveness, expr: &Expr) { hir::ExprBreak(..) | hir::ExprAgain(..) | hir::ExprLit(_) | hir::ExprBlock(..) | hir::ExprAddrOf(..) | hir::ExprStruct(..) | hir::ExprRepeat(..) | - hir::ExprClosure(..) | hir::ExprPath(..) | hir::ExprBox(..) | - hir::ExprType(..) => { + hir::ExprClosure(..) | hir::ExprPath(_) | + hir::ExprBox(..) | hir::ExprType(..) => { intravisit::walk_expr(this, expr); } } @@ -1482,7 +1482,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn check_lvalue(&mut self, expr: &Expr) { match expr.node { - hir::ExprPath(..) => { + hir::ExprPath(hir::QPath::Resolved(..)) => { if let Def::Local(def_id) = self.ir.tcx.expect_def(expr.id) { // Assignment to an immutable variable or argument: only legal // if there is no later assignment. If this local is actually diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index fedf8c2ec74..1ca078dcd2e 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -488,7 +488,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } } - hir::ExprPath(..) => { + hir::ExprPath(_) => { self.cat_def(expr.id, expr.span, expr_ty, self.tcx().expect_def(expr.id)) } @@ -1157,7 +1157,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } } - PatKind::Path(..) | PatKind::Binding(.., None) | + PatKind::Path(_) | PatKind::Binding(.., None) | PatKind::Lit(..) | PatKind::Range(..) | PatKind::Wild => { // always ok } diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 35e0e494771..0329b4c4a30 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -91,7 +91,7 @@ struct ReachableContext<'a, 'tcx: 'a> { impl<'a, 'tcx, 'v> Visitor<'v> for ReachableContext<'a, 'tcx> { fn visit_expr(&mut self, expr: &hir::Expr) { match expr.node { - hir::ExprPath(..) => { + hir::ExprPath(_) => { let def = self.tcx.expect_def(expr.id); let def_id = def.def_id(); if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) { diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 41da5562e23..c65fd25950d 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -244,7 +244,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { intravisit::walk_ty(this, ty); }); } - hir::TyPath(None, ref path) => { + hir::TyPath(hir::QPath::Resolved(None, ref path)) => { // if this path references a trait, then this will resolve to // a trait ref, which introduces a binding scope. match self.def_map.get(&ty.id).map(|d| (d.base_def, d.depth)) { @@ -944,13 +944,14 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap, impl<'v> Visitor<'v> for ConstrainedCollector { fn visit_ty(&mut self, ty: &'v hir::Ty) { match ty.node { - hir::TyPath(Some(_), _) => { + hir::TyPath(hir::QPath::Resolved(Some(_), _)) | + hir::TyPath(hir::QPath::TypeRelative(..)) => { // ignore lifetimes appearing in associated type // projections, as they are not *constrained* // (defined above) } - hir::TyPath(None, ref path) => { + hir::TyPath(hir::QPath::Resolved(None, ref path)) => { // consider only the lifetimes on the final // segment; I am not sure it's even currently // valid to have them elsewhere, but even if it diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 86a89eff3a4..a044ffd9a7f 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -486,6 +486,12 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { intravisit::walk_pat(self, pat) } + fn visit_ty(&mut self, ty: &'tcx hir::Ty) { + check_ty(self.tcx, ty, + &mut |id, sp, stab, depr| self.check(id, sp, stab, depr)); + intravisit::walk_ty(self, ty) + } + fn visit_block(&mut self, b: &'tcx hir::Block) { let old_skip_count = self.in_skip_block; match b.rules { @@ -553,6 +559,10 @@ pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr, let method_call = ty::MethodCall::expr(e.id); tcx.tables().method_map[&method_call].def_id } + hir::ExprPath(hir::QPath::TypeRelative(..)) => { + span = e.span; + tcx.expect_def(e.id).def_id() + } hir::ExprField(ref base_e, ref field) => { span = field.span; match tcx.tables().expr_ty_adjusted(base_e).sty { @@ -633,6 +643,11 @@ pub fn check_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &hir::Pat, debug!("check_pat(pat = {:?})", pat); if is_internal(tcx, pat.span) { return; } + if let PatKind::Path(hir::QPath::TypeRelative(..)) = pat.node { + let def_id = tcx.expect_def(pat.id).def_id(); + maybe_do_stability_check(tcx, def_id, pat.span, cb) + } + let v = match tcx.tables().pat_ty_opt(pat).map(|ty| &ty.sty) { Some(&ty::TyAdt(adt, _)) if !adt.is_enum() => adt.struct_variant(), _ => return, @@ -656,6 +671,19 @@ pub fn check_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &hir::Pat, } } +pub fn check_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: &hir::Ty, + cb: &mut FnMut(DefId, Span, + &Option<&Stability>, + &Option)) { + debug!("check_ty(ty = {:?})", ty); + if is_internal(tcx, ty.span) { return; } + + if let hir::TyPath(hir::QPath::TypeRelative(..)) = ty.node { + let def_id = tcx.expect_def(ty.id).def_id(); + maybe_do_stability_check(tcx, def_id, ty.span, cb); + } +} + fn maybe_do_stability_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId, span: Span, cb: &mut FnMut(DefId, Span, diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 7982c641ede..3d02ff4651f 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2059,11 +2059,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn expr_is_lval(self, expr: &hir::Expr) -> bool { match expr.node { - hir::ExprPath(..) => { - // This function can be used during type checking when not all paths are - // fully resolved. Partially resolved paths in expressions can only legally - // refer to associated items which are always rvalues. - match self.expect_resolution(expr.id).base_def { + hir::ExprPath(hir::QPath::Resolved(..)) => { + match self.expect_def(expr.id) { Def::Local(..) | Def::Upvar(..) | Def::Static(..) | Def::Err => true, _ => false, } @@ -2080,6 +2077,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { true } + // Partially qualified paths in expressions can only legally + // refer to associated items which are always rvalues. + hir::ExprPath(hir::QPath::TypeRelative(..)) | + hir::ExprCall(..) | hir::ExprMethodCall(..) | hir::ExprStruct(..) | diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs index c48811cb295..4731cea0206 100644 --- a/src/librustc_const_eval/_match.rs +++ b/src/librustc_const_eval/_match.rs @@ -324,6 +324,7 @@ impl Witness { ty::TyAdt(adt, _) => { let v = ctor.variant_for_adt(adt); + let qpath = hir::QPath::Resolved(None, P(def_to_path(cx.tcx, v.did))); match v.ctor_kind { CtorKind::Fictive => { let field_pats: hir::HirVec<_> = v.fields.iter() @@ -338,16 +339,12 @@ impl Witness { } }).collect(); let has_more_fields = field_pats.len() < arity; - PatKind::Struct( - def_to_path(cx.tcx, v.did), field_pats, has_more_fields) + PatKind::Struct(qpath, field_pats, has_more_fields) } CtorKind::Fn => { - PatKind::TupleStruct( - def_to_path(cx.tcx, v.did), pats.collect(), None) - } - CtorKind::Const => { - PatKind::Path(None, def_to_path(cx.tcx, v.did)) + PatKind::TupleStruct(qpath, pats.collect(), None) } + CtorKind::Const => PatKind::Path(qpath) } } diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index b594fe9853a..e8c05ec1a35 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -286,9 +286,11 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if let Vacant(entry) = tcx.def_map.borrow_mut().entry(expr.id) { entry.insert(PathResolution::new(def)); } - let path = match def { + let qpath = match def { Def::StructCtor(def_id, CtorKind::Fn) | - Def::VariantCtor(def_id, CtorKind::Fn) => def_to_path(tcx, def_id), + Def::VariantCtor(def_id, CtorKind::Fn) => { + hir::QPath::Resolved(None, P(def_to_path(tcx, def_id))) + } Def::Fn(..) | Def::Method(..) => return Ok(P(hir::Pat { id: expr.id, node: PatKind::Lit(P(expr.clone())), @@ -299,10 +301,10 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let pats = args.iter() .map(|expr| const_expr_to_pat(tcx, &*expr, pat_id, span)) .collect::>()?; - PatKind::TupleStruct(path, pats, None) + PatKind::TupleStruct(qpath, pats, None) } - hir::ExprStruct(ref path, ref fields, None) => { + hir::ExprStruct(ref qpath, ref fields, None) => { let field_pats = fields.iter() .map(|field| Ok(codemap::Spanned { @@ -314,7 +316,7 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }, })) .collect::>()?; - PatKind::Struct((**path).clone(), field_pats, false) + PatKind::Struct(qpath.clone(), field_pats, false) } hir::ExprArray(ref exprs) => { @@ -324,10 +326,17 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, PatKind::Slice(pats, None, hir::HirVec::new()) } - hir::ExprPath(_, ref path) => { + hir::ExprPath(_) => { match tcx.expect_def(expr.id) { Def::StructCtor(_, CtorKind::Const) | - Def::VariantCtor(_, CtorKind::Const) => PatKind::Path(None, path.clone()), + Def::VariantCtor(_, CtorKind::Const) => { + match expr.node { + hir::ExprPath(hir::QPath::Resolved(_, ref path)) => { + PatKind::Path(hir::QPath::Resolved(None, path.clone())) + } + _ => bug!() + } + } Def::Const(def_id) | Def::AssociatedConst(def_id) => { let substs = Some(tcx.tables().node_id_item_substs(expr.id) .unwrap_or_else(|| tcx.intern_substs(&[]))); @@ -788,14 +797,14 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }), } } - hir::ExprPath(..) => { + hir::ExprPath(_) => { // This function can be used before type checking when not all paths are fully resolved. // FIXME: There's probably a better way to make sure we don't panic here. - let resolution = tcx.expect_resolution(e.id); - if resolution.depth != 0 { - signal!(e, UnresolvedPath); - } - match resolution.base_def { + let def = match tcx.expect_def_or_none(e.id) { + Some(def) => def, + None => signal!(e, UnresolvedPath) + }; + match def { Def::Const(def_id) | Def::AssociatedConst(def_id) => { let substs = if let ExprTypeChecked = ty_hint { @@ -1358,17 +1367,12 @@ pub fn eval_length<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut diag = report_const_eval_err( tcx, &err, count_expr.span, reason); - match count_expr.node { - hir::ExprPath(None, hir::Path { - global: false, - ref segments, - .. - }) if segments.len() == 1 => { + if let hir::ExprPath(hir::QPath::Resolved(None, ref path)) = count_expr.node { + if !path.global && path.segments.len() == 1 { if let Some(Def::Local(..)) = tcx.expect_def_or_none(count_expr.id) { - diag.note(&format!("`{}` is a variable", segments[0].name)); + diag.note(&format!("`{}` is a variable", path.segments[0].name)); } } - _ => {} } diag.emit(); diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index fd0856393fc..ec405311012 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -185,6 +185,7 @@ enum SawAbiComponent<'a> { SawImplItem(SawTraitOrImplItemComponent), SawStructField, SawVariant, + SawQPath, SawPath(bool), SawPathSegment, SawPathParameters, @@ -259,7 +260,7 @@ enum SawExprComponent<'a> { SawExprAssign, SawExprAssignOp(hir::BinOp_), SawExprIndex, - SawExprPath(Option), + SawExprPath, SawExprAddrOf(hir::Mutability), SawExprRet, SawExprInlineAsm(&'a hir::InlineAsm), @@ -333,7 +334,7 @@ fn saw_expr<'a>(node: &'a Expr_, ExprField(_, name) => (SawExprField(name.node.as_str()), false), ExprTupField(_, id) => (SawExprTupField(id.node), false), ExprIndex(..) => (SawExprIndex, true), - ExprPath(ref qself, _) => (SawExprPath(qself.as_ref().map(|q| q.position)), false), + ExprPath(_) => (SawExprPath, false), ExprAddrOf(m, _) => (SawExprAddrOf(m), false), ExprBreak(id, _) => (SawExprBreak(id.map(|id| id.node.as_str())), false), ExprAgain(id) => (SawExprAgain(id.map(|id| id.node.as_str())), false), @@ -411,7 +412,7 @@ fn saw_pat(node: &PatKind) -> SawPatComponent { PatKind::Binding(bindingmode, ..) => SawPatBinding(bindingmode), PatKind::Struct(..) => SawPatStruct, PatKind::TupleStruct(..) => SawPatTupleStruct, - PatKind::Path(..) => SawPatPath, + PatKind::Path(_) => SawPatPath, PatKind::Tuple(..) => SawPatTuple, PatKind::Box(..) => SawPatBox, PatKind::Ref(_, mutability) => SawPatRef(mutability), @@ -447,7 +448,7 @@ fn saw_ty(node: &Ty_) -> SawTyComponent { TyBareFn(ref barefnty) => SawTyBareFn(barefnty.unsafety, barefnty.abi), TyNever => SawTyNever, TyTup(..) => SawTyTup, - TyPath(..) => SawTyPath, + TyPath(_) => SawTyPath, TyObjectSum(..) => SawTyObjectSum, TyPolyTraitRef(..) => SawTyPolyTraitRef, TyImplTrait(..) => SawTyImplTrait, @@ -655,6 +656,13 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has visit::walk_struct_field(self, s) } + fn visit_qpath(&mut self, qpath: &'tcx QPath, id: NodeId, span: Span) { + debug!("visit_qpath: st={:?}", self.st); + SawQPath.hash(self.st); + self.hash_discriminant(qpath); + visit::walk_qpath(self, qpath, id, span) + } + fn visit_path(&mut self, path: &'tcx Path, _: ast::NodeId) { debug!("visit_path: st={:?}", self.st); SawPath(path.global).hash(self.st); diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs index 4440cb41dc5..25ea3d65993 100644 --- a/src/librustc_lint/bad_style.rs +++ b/src/librustc_lint/bad_style.rs @@ -376,7 +376,7 @@ impl LateLintPass for NonUpperCaseGlobals { fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) { // Lint for constants that look like binding identifiers (#7526) - if let PatKind::Path(None, ref path) = p.node { + if let PatKind::Path(hir::QPath::Resolved(None, ref path)) = p.node { if !path.global && path.segments.len() == 1 && path.segments[0].parameters.is_empty() { if let Def::Const(..) = cx.tcx.expect_def(p.id) { NonUpperCaseGlobals::check_upper_case(cx, diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 0b2ae588523..7be591293c9 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -718,6 +718,12 @@ impl LateLintPass for Deprecated { &mut |id, sp, stab, depr| self.lint(cx, id, sp, &stab, &depr)); } + fn check_ty(&mut self, cx: &LateContext, ty: &hir::Ty) { + stability::check_ty(cx.tcx, ty, + &mut |id, sp, stab, depr| + self.lint(cx, id, sp, &stab, &depr)); + } + fn check_impl_item(&mut self, _: &LateContext, item: &hir::ImplItem) { self.push_item(item.id); } @@ -1204,7 +1210,7 @@ impl LateLintPass for MutableTransmutes { expr: &hir::Expr) -> Option<(&'tcx ty::TypeVariants<'tcx>, &'tcx ty::TypeVariants<'tcx>)> { match expr.node { - hir::ExprPath(..) => (), + hir::ExprPath(_) => (), _ => return None, } if let Def::Fn(did) = cx.tcx.expect_def(expr.id) { diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index fa452017f0c..d0ad682fb58 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -218,7 +218,7 @@ impl LintPass for PathStatements { impl LateLintPass for PathStatements { fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) { if let hir::StmtSemi(ref expr, _) = s.node { - if let hir::ExprPath(..) = expr.node { + if let hir::ExprPath(_) = expr.node { cx.span_lint(PATH_STATEMENTS, s.span, "path statement with no effect"); } } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 6fa26725935..0c796ad42bb 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -265,7 +265,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, args: vec![fun.to_ref(), tupled_args.to_ref()] } } else { - let adt_data = if let hir::ExprPath(..) = fun.node { + let adt_data = if let hir::ExprPath(hir::QPath::Resolved(..)) = fun.node { // Tuple-like ADTs are represented as ExprCall. We convert them here. expr_ty.ty_adt_def().and_then(|adt_def|{ match cx.tcx.expect_def(fun.id) { @@ -531,7 +531,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } } - hir::ExprPath(..) => { + hir::ExprPath(_) => { convert_path_expr(cx, expr) } diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 4d8520ed044..ff46273a997 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -487,7 +487,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node _ => {} } } - hir::ExprPath(..) => { + hir::ExprPath(_) => { match v.tcx.expect_def(e.id) { Def::VariantCtor(_, CtorKind::Const) => { // Size is determined by the whole enum, may be non-zero. diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs index dafb7bc6e60..9028821ef11 100644 --- a/src/librustc_passes/hir_stats.rs +++ b/src/librustc_passes/hir_stats.rs @@ -218,6 +218,10 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { self.record("LifetimeDef", Id::None, lifetime); hir_visit::walk_lifetime_def(self, lifetime) } + fn visit_qpath(&mut self, qpath: &'v hir::QPath, id: NodeId, span: Span) { + self.record("QPath", Id::None, qpath); + hir_visit::walk_qpath(self, qpath, id, span) + } fn visit_path(&mut self, path: &'v hir::Path, _id: NodeId) { self.record("Path", Id::None, path); hir_visit::walk_path(self, path) @@ -234,7 +238,6 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { self.record("PathSegment", Id::None, path_segment); hir_visit::walk_path_segment(self, path_span, path_segment) } - fn visit_assoc_type_binding(&mut self, type_binding: &'v hir::TypeBinding) { self.record("TypeBinding", Id::Node(type_binding.id), type_binding); hir_visit::walk_assoc_type_binding(self, type_binding) diff --git a/src/librustc_passes/static_recursion.rs b/src/librustc_passes/static_recursion.rs index 5f76f865c4a..b98cf7e602b 100644 --- a/src/librustc_passes/static_recursion.rs +++ b/src/librustc_passes/static_recursion.rs @@ -250,7 +250,7 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> { fn visit_expr(&mut self, e: &'ast hir::Expr) { match e.node { - hir::ExprPath(..) => { + hir::ExprPath(_) => { match self.def_map.get(&e.id).map(|d| d.base_def) { Some(Def::Static(def_id, _)) | Some(Def::AssociatedConst(def_id)) | diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index b116408269e..55e11caac6d 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -67,7 +67,7 @@ struct ReachEverythingInTheInterfaceVisitor<'b, 'a: 'b, 'tcx: 'a> { impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> { fn ty_level(&self, ty: &hir::Ty) -> Option { - if let hir::TyPath(..) = ty.node { + if let hir::TyPath(_) = ty.node { match self.tcx.expect_def(ty.id) { Def::PrimTy(..) | Def::SelfTy(..) | Def::TyParam(..) => { Some(AccessLevel::Public) @@ -306,11 +306,11 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { impl<'b, 'a, 'tcx: 'a> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> { // Make the type hidden under a type alias reachable - fn reach_aliased_type(&mut self, item: &'tcx hir::Item, path: &'tcx hir::Path) { + fn reach_aliased_type(&mut self, item: &'tcx hir::Item, segment: &'tcx hir::PathSegment) { if let hir::ItemTy(ref ty, ref generics) = item.node { // See `fn is_public_type_alias` for details self.visit_ty(ty); - let provided_params = path.segments.last().unwrap().parameters.types().len(); + let provided_params = segment.parameters.types().len(); for ty_param in &generics.ty_params[provided_params..] { if let Some(ref default_ty) = ty_param.default { self.visit_ty(default_ty); @@ -328,7 +328,12 @@ impl<'b, 'a, 'tcx: 'a> Visitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'b } fn visit_ty(&mut self, ty: &'tcx hir::Ty) { - if let hir::TyPath(_, ref path) = ty.node { + let path_segment = match ty.node { + hir::TyPath(hir::QPath::Resolved(_, ref path)) => path.segments.last(), + hir::TyPath(hir::QPath::TypeRelative(_, ref segment)) => Some(&**segment), + _ => None + }; + if let Some(segment) = path_segment { let def = self.ev.tcx.expect_def(ty.id); match def { Def::Struct(def_id) | Def::Union(def_id) | Def::Enum(def_id) | @@ -344,7 +349,7 @@ impl<'b, 'a, 'tcx: 'a> Visitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'b // Type aliases are substituted. Associated type aliases are not // substituted yet, but ideally they should be. if self.ev.get(item.id).is_none() { - self.reach_aliased_type(item, path); + self.reach_aliased_type(item, segment); } } else { self.ev.update(item.id, Some(AccessLevel::Reachable)); @@ -461,7 +466,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivacyVisitor<'a, 'tcx> { } } } - hir::ExprPath(..) => { + hir::ExprPath(hir::QPath::Resolved(..)) => { if let def @ Def::StructCtor(_, CtorKind::Fn) = self.tcx.expect_def(expr.id) { let adt_def = self.tcx.expect_variant_def(def); let private_indexes = adt_def.fields.iter().enumerate().filter(|&(_, field)| { @@ -606,7 +611,7 @@ impl<'a, 'tcx> ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { impl<'a, 'b, 'tcx, 'v> Visitor<'v> for ObsoleteCheckTypeForPrivatenessVisitor<'a, 'b, 'tcx> { fn visit_ty(&mut self, ty: &hir::Ty) { - if let hir::TyPath(..) = ty.node { + if let hir::TyPath(_) = ty.node { if self.inner.path_is_private_type(ty.id) { self.contains_private = true; // found what we're looking for so let's stop @@ -844,7 +849,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { } fn visit_ty(&mut self, t: &'tcx hir::Ty) { - if let hir::TyPath(..) = t.node { + if let hir::TyPath(_) = t.node { if self.path_is_private_type(t.id) { self.old_error_set.insert(t.id); } @@ -906,7 +911,7 @@ impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> { impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> { // Return the visibility of the type alias's least visible component type when substituted - fn substituted_alias_visibility(&self, item: &hir::Item, path: &hir::Path) + fn substituted_alias_visibility(&self, item: &hir::Item, segment: &hir::PathSegment) -> Option { // Type alias is considered public if the aliased type is // public, even if the type alias itself is private. So, something @@ -921,7 +926,7 @@ impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> { // type Alias = T; // pub fn f() -> Alias {...} // `Private` is implicitly used here, so it must be public // ``` - let provided_params = path.segments.last().unwrap().parameters.types().len(); + let provided_params = segment.parameters.types().len(); for ty_param in &generics.ty_params[provided_params..] { if let Some(ref default_ty) = ty_param.default { check.visit_ty(default_ty); @@ -936,7 +941,12 @@ impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> { impl<'a, 'tcx: 'a, 'v> Visitor<'v> for SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> { fn visit_ty(&mut self, ty: &hir::Ty) { - if let hir::TyPath(_, ref path) = ty.node { + let path_segment = match ty.node { + hir::TyPath(hir::QPath::Resolved(_, ref path)) => path.segments.last(), + hir::TyPath(hir::QPath::TypeRelative(_, ref segment)) => Some(&**segment), + _ => None + }; + if let Some(segment) = path_segment { match self.tcx.expect_def(ty.id) { Def::PrimTy(..) | Def::SelfTy(..) | Def::TyParam(..) => { // Public @@ -961,7 +971,7 @@ impl<'a, 'tcx: 'a, 'v> Visitor<'v> for SearchInterfaceForPrivateItemsVisitor<'a, } let item = self.tcx.map.expect_item(node_id); - let vis = match self.substituted_alias_visibility(item, path) { + let vis = match self.substituted_alias_visibility(item, segment) { Some(vis) => vis, None => ty::Visibility::from_hir(&item.vis, node_id, self.tcx), }; diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 831426c3f06..7d02678679a 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -952,7 +952,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let tcx = self.tcx(); match ty.node { - hir::TyPath(None, ref path) => { + hir::TyPath(hir::QPath::Resolved(None, ref path)) => { let resolution = tcx.expect_resolution(ty.id); match resolution.base_def { Def::Trait(trait_def_id) if resolution.depth == 0 => { @@ -1261,12 +1261,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // the whole path. // Will fail except for T::A and Self::A; i.e., if ty/ty_path_def are not a type // parameter or Self. - fn associated_path_def_to_ty(&self, - span: Span, - ty: Ty<'tcx>, - ty_path_def: Def, - item_segment: &hir::PathSegment) - -> (Ty<'tcx>, Def) + pub fn associated_path_def_to_ty(&self, + span: Span, + ty: Ty<'tcx>, + ty_path_def: Def, + item_segment: &hir::PathSegment) + -> (Ty<'tcx>, Def) { let tcx = self.tcx(); let assoc_name = item_segment.name; @@ -1412,54 +1412,55 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } } - // Check the base def in a PathResolution and convert it to a Ty. If there are - // associated types in the PathResolution, these will need to be separately - // resolved. - fn base_def_to_ty(&self, - rscope: &RegionScope, - span: Span, - def: Def, - opt_self_ty: Option>, - base_path_ref_id: ast::NodeId, - base_segments: &[hir::PathSegment], - permit_variants: bool) - -> Ty<'tcx> { + // Check a type Def and convert it to a Ty. + pub fn def_to_ty(&self, + rscope: &RegionScope, + span: Span, + def: Def, + opt_self_ty: Option>, + path_id: ast::NodeId, + path_segments: &[hir::PathSegment], + permit_variants: bool) + -> Ty<'tcx> { let tcx = self.tcx(); - debug!("base_def_to_ty(def={:?}, opt_self_ty={:?}, base_segments={:?})", - def, opt_self_ty, base_segments); + debug!("base_def_to_ty(def={:?}, opt_self_ty={:?}, path_segments={:?})", + def, opt_self_ty, path_segments); match def { Def::Trait(trait_def_id) => { // N.B. this case overlaps somewhat with // TyObjectSum, see that fn for details - tcx.prohibit_type_params(base_segments.split_last().unwrap().1); + assert_eq!(opt_self_ty, None); + tcx.prohibit_type_params(path_segments.split_last().unwrap().1); self.trait_path_to_object_type(rscope, span, trait_def_id, - base_path_ref_id, - base_segments.last().unwrap(), + path_id, + path_segments.last().unwrap(), span, partition_bounds(tcx, span, &[])) } Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) | Def::Union(did) => { - tcx.prohibit_type_params(base_segments.split_last().unwrap().1); - self.ast_path_to_ty(rscope, span, did, base_segments.last().unwrap()) + assert_eq!(opt_self_ty, None); + tcx.prohibit_type_params(path_segments.split_last().unwrap().1); + self.ast_path_to_ty(rscope, span, did, path_segments.last().unwrap()) } Def::Variant(did) if permit_variants => { // Convert "variant type" as if it were a real type. // The resulting `Ty` is type of the variant's enum for now. - tcx.prohibit_type_params(base_segments.split_last().unwrap().1); + assert_eq!(opt_self_ty, None); + tcx.prohibit_type_params(path_segments.split_last().unwrap().1); self.ast_path_to_ty(rscope, span, - param_mode, tcx.parent_def_id(did).unwrap(), - base_segments.last().unwrap()) + path_segments.last().unwrap()) } Def::TyParam(did) => { - tcx.prohibit_type_params(base_segments); + assert_eq!(opt_self_ty, None); + tcx.prohibit_type_params(path_segments); let node_id = tcx.map.as_local_node_id(did).unwrap(); let param = tcx.ty_param_defs.borrow().get(&node_id) @@ -1481,7 +1482,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { Def::SelfTy(_, Some(def_id)) => { // Self in impl (we know the concrete type). - tcx.prohibit_type_params(base_segments); + assert_eq!(opt_self_ty, None); + tcx.prohibit_type_params(path_segments); let ty = tcx.item_type(def_id); if let Some(free_substs) = self.get_free_substs() { ty.subst(tcx, free_substs) @@ -1491,34 +1493,23 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } Def::SelfTy(Some(_), None) => { // Self in trait. - tcx.prohibit_type_params(base_segments); + assert_eq!(opt_self_ty, None); + tcx.prohibit_type_params(path_segments); tcx.mk_self_type() } Def::AssociatedTy(def_id) => { - tcx.prohibit_type_params(&base_segments[..base_segments.len()-2]); + tcx.prohibit_type_params(&path_segments[..path_segments.len()-2]); let trait_did = tcx.parent_def_id(def_id).unwrap(); self.qpath_to_ty(rscope, span, opt_self_ty, trait_did, - &base_segments[base_segments.len()-2], - base_segments.last().unwrap()) - } - Def::Mod(..) => { - // Used as sentinel by callers to indicate the `::A::B::C` form. - // FIXME(#22519) This part of the resolution logic should be - // avoided entirely for that form, once we stop needed a Def - // for `associated_path_def_to_ty`. - // Fixing this will also let use resolve ::Foo the same way we - // resolve Self::Foo, at the moment we can't resolve the former because - // we don't have the trait information around, which is just sad. - - assert!(base_segments.is_empty()); - - opt_self_ty.expect("missing T in ::a::b::c") + &path_segments[path_segments.len()-2], + path_segments.last().unwrap()) } Def::PrimTy(prim_ty) => { - tcx.prim_ty_to_ty(base_segments, prim_ty) + assert_eq!(opt_self_ty, None); + tcx.prim_ty_to_ty(path_segments, prim_ty) } Def::Err => { self.set_tainted_by_errors(); @@ -1535,50 +1526,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } } - // Resolve possibly associated type path into a type and final definition. - // Note that both base_segments and assoc_segments may be empty, although not at same time. - pub fn finish_resolving_def_to_ty(&self, - rscope: &RegionScope, - span: Span, - base_def: Def, - opt_self_ty: Option>, - base_path_ref_id: ast::NodeId, - base_segments: &[hir::PathSegment], - assoc_segments: &[hir::PathSegment], - permit_variants: bool) - -> (Ty<'tcx>, Def) { - // Convert the base type. - debug!("finish_resolving_def_to_ty(base_def={:?}, \ - base_segments={:?}, \ - assoc_segments={:?})", - base_def, - base_segments, - assoc_segments); - let base_ty = self.base_def_to_ty(rscope, - span, - base_def, - opt_self_ty, - base_path_ref_id, - base_segments, - permit_variants); - debug!("finish_resolving_def_to_ty: base_def_to_ty returned {:?}", base_ty); - - // If any associated type segments remain, attempt to resolve them. - let (mut ty, mut def) = (base_ty, base_def); - for segment in assoc_segments { - debug!("finish_resolving_def_to_ty: segment={:?}", segment); - // This is pretty bad (it will fail except for T::A and Self::A). - let (new_ty, new_def) = self.associated_path_def_to_ty(span, ty, def, segment); - ty = new_ty; - def = new_def; - - if def == Def::Err { - break; - } - } - (ty, def) - } - /// Parses the programmer's textual representation of a type into our /// internal notion of a type. pub fn ast_ty_to_ty(&self, rscope: &RegionScope, ast_ty: &hir::Ty) -> Ty<'tcx> { @@ -1701,26 +1648,28 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { tcx.types.err } } - hir::TyPath(ref maybe_qself, ref path) => { + hir::TyPath(hir::QPath::Resolved(ref maybe_qself, ref path)) => { debug!("ast_ty_to_ty: maybe_qself={:?} path={:?}", maybe_qself, path); - let path_res = tcx.expect_resolution(ast_ty.id); - let base_ty_end = path.segments.len() - path_res.depth; let opt_self_ty = maybe_qself.as_ref().map(|qself| { - self.ast_ty_to_ty(rscope, &qself.ty) + self.ast_ty_to_ty(rscope, qself) }); - let (ty, def) = self.finish_resolving_def_to_ty(rscope, - ast_ty.span, - path_res.base_def, - opt_self_ty, - ast_ty.id, - &path.segments[..base_ty_end], - &path.segments[base_ty_end..], - false); + self.def_to_ty(rscope, + ast_ty.span, + tcx.expect_def(ast_ty.id), + opt_self_ty, + ast_ty.id, + &path.segments, + false) + } + hir::TyPath(hir::QPath::TypeRelative(ref qself, ref segment)) => { + debug!("ast_ty_to_ty: qself={:?} segment={:?}", qself, segment); + let ty = self.ast_ty_to_ty(rscope, qself); + + let def = tcx.expect_def_or_none(qself.id).unwrap_or(Def::Err); + let (ty, def) = self.associated_path_def_to_ty(ast_ty.span, ty, def, segment); // Write back the new resolution. - if path_res.depth != 0 { - tcx.def_map.borrow_mut().insert(ast_ty.id, PathResolution::new(def)); - } + tcx.def_map.borrow_mut().insert(ast_ty.id, PathResolution::new(def)); ty } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 556d1f84fcc..3e62b22d36f 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -148,15 +148,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { typ } - PatKind::TupleStruct(ref path, ref subpats, ddpos) => { - self.check_pat_tuple_struct(pat, path, &subpats, ddpos, expected) + PatKind::TupleStruct(ref qpath, ref subpats, ddpos) => { + self.check_pat_tuple_struct(pat, qpath, &subpats, ddpos, expected) } - PatKind::Path(ref opt_qself, ref path) => { - let opt_qself_ty = opt_qself.as_ref().map(|qself| self.to_ty(&qself.ty)); - self.check_pat_path(pat, opt_qself_ty, path, expected) + PatKind::Path(ref qpath) => { + self.check_pat_path(pat, qpath, expected) } - PatKind::Struct(ref path, ref fields, etc) => { - self.check_pat_struct(pat, path, fields, etc, expected) + PatKind::Struct(ref qpath, ref fields, etc) => { + self.check_pat_struct(pat, qpath, fields, etc, expected) } PatKind::Tuple(ref elements, ddpos) => { let mut expected_len = elements.len(); @@ -496,13 +495,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn check_pat_struct(&self, pat: &'gcx hir::Pat, - path: &hir::Path, + qpath: &hir::QPath, fields: &'gcx [Spanned], etc: bool, expected: Ty<'tcx>) -> Ty<'tcx> { // Resolve the path and check the definition for errors. - let (variant, pat_ty) = if let Some(variant_ty) = self.check_struct_path(path, pat.id) { + let (variant, pat_ty) = if let Some(variant_ty) = self.check_struct_path(qpath, pat.id) { variant_ty } else { for field in fields { @@ -521,20 +520,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn check_pat_path(&self, pat: &hir::Pat, - opt_self_ty: Option>, - path: &hir::Path, + qpath: &hir::QPath, expected: Ty<'tcx>) -> Ty<'tcx> { let tcx = self.tcx; let report_unexpected_def = |def: Def| { span_err!(tcx.sess, pat.span, E0533, "expected unit struct/variant or constant, found {} `{}`", - def.kind_name(), path); + def.kind_name(), qpath); }; // Resolve the path and check the definition for errors. - let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(opt_self_ty, path, - pat.id, pat.span); + let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(qpath, pat.id, pat.span); match def { Def::Err => { self.set_tainted_by_errors(); @@ -558,7 +555,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn check_pat_tuple_struct(&self, pat: &hir::Pat, - path: &hir::Path, + qpath: &hir::QPath, subpats: &'gcx [P], ddpos: Option, expected: Ty<'tcx>) -> Ty<'tcx> @@ -571,14 +568,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; let report_unexpected_def = |def: Def| { let msg = format!("expected tuple struct/variant, found {} `{}`", - def.kind_name(), path); + def.kind_name(), qpath); struct_span_err!(tcx.sess, pat.span, E0164, "{}", msg) .span_label(pat.span, &format!("not a tuple variant or struct")).emit(); on_error(); }; // Resolve the path and check the definition for errors. - let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(None, path, pat.id, pat.span); + let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(qpath, pat.id, pat.span); let variant = match def { Def::Err => { self.set_tainted_by_errors(); diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 4ae15740cf2..6598790355e 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -28,7 +28,6 @@ use syntax_pos::Span; use rustc::hir::print as pprust; use rustc::hir; -use rustc::hir::Expr_; use std::cell; use std::cmp::Ordering; @@ -210,7 +209,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(expr) = rcvr_expr { if let Ok(expr_string) = tcx.sess.codemap().span_to_snippet(expr.span) { report_function!(expr.span, expr_string); - } else if let Expr_::ExprPath(_, path) = expr.node.clone() { + } else if let hir::ExprPath(hir::QPath::Resolved(_, ref path)) = expr.node { if let Some(segment) = path.segments.last() { report_function!(expr.span, segment.name); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index ea84786e06b..33b123d0a6d 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3301,10 +3301,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } pub fn check_struct_path(&self, - path: &hir::Path, + qpath: &hir::QPath, node_id: ast::NodeId) -> Option<(ty::VariantDef<'tcx>, Ty<'tcx>)> { - let (def, ty) = self.finish_resolving_struct_path(path, node_id); + let path_span = match *qpath { + hir::QPath::Resolved(_, ref path) => path.span, + hir::QPath::TypeRelative(ref qself, _) => qself.span + }; + let (def, ty) = self.finish_resolving_struct_path(qpath, path_span, node_id); let variant = match def { Def::Err => { self.set_tainted_by_errors(); @@ -3324,7 +3328,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Def::AssociatedTy(..) | Def::SelfTy(..) if !self.tcx.sess.features.borrow().more_struct_aliases => { emit_feature_err(&self.tcx.sess.parse_sess, - "more_struct_aliases", path.span, GateIssue::Language, + "more_struct_aliases", path_span, GateIssue::Language, "`Self` and associated types in struct \ expressions and patterns are unstable"); } @@ -3342,17 +3346,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some((variant, did, substs)) = variant { // Check bounds on type arguments used in the path. - let bounds = self.instantiate_bounds(path.span, did, substs); - let cause = traits::ObligationCause::new(path.span, self.body_id, + let bounds = self.instantiate_bounds(path_span, did, substs); + let cause = traits::ObligationCause::new(path_span, self.body_id, traits::ItemObligation(did)); self.add_obligations_for_parameters(cause, &bounds); Some((variant, ty)) } else { - struct_span_err!(self.tcx.sess, path.span, E0071, + struct_span_err!(self.tcx.sess, path_span, E0071, "expected struct, variant or union type, found {}", ty.sort_string(self.tcx)) - .span_label(path.span, &format!("not a struct")) + .span_label(path_span, &format!("not a struct")) .emit(); None } @@ -3360,19 +3364,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn check_expr_struct(&self, expr: &hir::Expr, - path: &hir::Path, + qpath: &hir::QPath, fields: &'gcx [hir::Field], base_expr: &'gcx Option>) -> Ty<'tcx> { // Find the relevant variant - let (variant, struct_ty) = if let Some(variant_ty) = self.check_struct_path(path, expr.id) { + let (variant, struct_ty) = + if let Some(variant_ty) = self.check_struct_path(qpath, expr.id) { variant_ty } else { self.check_struct_fields_on_error(fields, base_expr); return self.tcx.types.err; }; - self.check_expr_struct_fields(struct_ty, path.span, variant, fields, + let path_span = match *qpath { + hir::QPath::Resolved(_, ref path) => path.span, + hir::QPath::TypeRelative(ref qself, _) => qself.span + }; + + self.check_expr_struct_fields(struct_ty, path_span, variant, fields, base_expr.is_none()); if let &Some(ref base_expr) = base_expr { self.check_expr_has_type(base_expr, struct_ty); @@ -3590,9 +3600,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { tcx.mk_ref(region, tm) } } - hir::ExprPath(ref opt_qself, ref path) => { - let opt_self_ty = opt_qself.as_ref().map(|qself| self.to_ty(&qself.ty)); - let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(opt_self_ty, path, + hir::ExprPath(ref qpath) => { + let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(qpath, expr.id, expr.span); let ty = if def != Def::Err { self.instantiate_value_path(segments, opt_ty, def, expr.span, id) @@ -3930,8 +3939,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { tuple } } - hir::ExprStruct(ref path, ref fields, ref base_expr) => { - self.check_expr_struct(expr, path, fields, base_expr) + hir::ExprStruct(ref qpath, ref fields, ref base_expr) => { + self.check_expr_struct(expr, qpath, fields, base_expr) } hir::ExprField(ref base, ref field) => { self.check_field(expr, lvalue_pref, &base, field) @@ -3999,72 +4008,75 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary. // The newly resolved definition is written into `def_map`. fn finish_resolving_struct_path(&self, - path: &hir::Path, + qpath: &hir::QPath, + path_span: Span, node_id: ast::NodeId) -> (Def, Ty<'tcx>) { - let path_res = self.tcx.expect_resolution(node_id); - let base_ty_end = path.segments.len() - path_res.depth; - let (ty, def) = AstConv::finish_resolving_def_to_ty(self, self, path.span, - path_res.base_def, - None, - node_id, - &path.segments[..base_ty_end], - &path.segments[base_ty_end..], - true); - // Write back the new resolution. - if path_res.depth != 0 { - self.tcx.def_map.borrow_mut().insert(node_id, PathResolution::new(def)); + match *qpath { + hir::QPath::Resolved(ref maybe_qself, ref path) => { + let opt_self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself)); + let def = self.tcx.expect_def(node_id); + let ty = AstConv::def_to_ty(self, self, + path.span, + def, + opt_self_ty, + node_id, + &path.segments, + true); + (def, ty) + } + hir::QPath::TypeRelative(ref qself, ref segment) => { + let ty = self.to_ty(qself); + + let def = self.tcx.expect_def_or_none(qself.id).unwrap_or(Def::Err); + let (ty, def) = AstConv::associated_path_def_to_ty(self, path_span, + ty, def, segment); + + // Write back the new resolution. + self.tcx.def_map.borrow_mut().insert(node_id, PathResolution::new(def)); + + (def, ty) + } } - (def, ty) } // Resolve associated value path into a base type and associated constant or method definition. // The newly resolved definition is written into `def_map`. pub fn resolve_ty_and_def_ufcs<'b>(&self, - opt_self_ty: Option>, - path: &'b hir::Path, + qpath: &'b hir::QPath, node_id: ast::NodeId, span: Span) -> (Def, Option>, &'b [hir::PathSegment]) { - let path_res = self.tcx.expect_resolution(node_id); - if path_res.depth == 0 { - // If fully resolved already, we don't have to do anything. - (path_res.base_def, opt_self_ty, &path.segments) - } else { - // Try to resolve everything except for the last segment as a type. - let ty_segments = path.segments.split_last().unwrap().1; - let base_ty_end = path.segments.len() - path_res.depth; - let (ty, _def) = AstConv::finish_resolving_def_to_ty(self, self, span, - path_res.base_def, - opt_self_ty, - node_id, - &ty_segments[..base_ty_end], - &ty_segments[base_ty_end..], - false); - - // Resolve an associated constant or method on the previously resolved type. - let item_segment = path.segments.last().unwrap(); - let item_name = item_segment.name; - let def = match self.resolve_ufcs(span, item_name, ty, node_id) { - Ok(def) => def, - Err(error) => { - let def = match error { - method::MethodError::PrivateMatch(def) => def, - _ => Def::Err, - }; - if item_name != keywords::Invalid.name() { - self.report_method_error(span, ty, item_name, None, error); - } - def + let (ty, item_segment) = match *qpath { + hir::QPath::Resolved(ref opt_qself, ref path) => { + return (self.tcx.expect_def(node_id), + opt_qself.as_ref().map(|qself| self.to_ty(qself)), + &path.segments[..]); + } + hir::QPath::TypeRelative(ref qself, ref segment) => { + (self.to_ty(qself), segment) + } + }; + let item_name = item_segment.name; + let def = match self.resolve_ufcs(span, item_name, ty, node_id) { + Ok(def) => def, + Err(error) => { + let def = match error { + method::MethodError::PrivateMatch(def) => def, + _ => Def::Err, + }; + if item_name != keywords::Invalid.name() { + self.report_method_error(span, ty, item_name, None, error); } - }; + def + } + }; - // Write back the new resolution. - self.tcx.def_map.borrow_mut().insert(node_id, PathResolution::new(def)); - (def, Some(ty), slice::ref_slice(item_segment)) - } + // Write back the new resolution. + self.tcx.def_map.borrow_mut().insert(node_id, PathResolution::new(def)); + (def, Some(ty), slice::ref_slice(&**item_segment)) } pub fn check_decl_initializer(&self, diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index c613b62bf2d..2b1bea89c52 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -603,7 +603,7 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for RegionCtxt<'a, 'gcx, 'tcx> { debug!("regionck::visit_expr(e={:?}, repeating_scope={}) - visiting subexprs", expr, self.repeating_scope); match expr.node { - hir::ExprPath(..) => { + hir::ExprPath(_) => { self.fcx.opt_node_ty_substs(expr.id, |item_substs| { let origin = infer::ParameterOrigin::Path; self.substs_wf_in_scope(origin, &item_substs.substs, expr.span, expr_region); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 48d79a3ba4c..ca5208b7a03 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -542,7 +542,7 @@ fn is_param<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_id: ast::NodeId) -> bool { - if let hir::TyPath(None, _) = ast_ty.node { + if let hir::TyPath(hir::QPath::Resolved(None, _)) = ast_ty.node { let path_res = tcx.expect_resolution(ast_ty.id); match path_res.base_def { Def::SelfTy(Some(def_id), None) | diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index a19ec4e8b5e..aff38404349 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1727,7 +1727,7 @@ impl Clean for hir::Ty { FixedVector(box ty.clean(cx), n) }, TyTup(ref tys) => Tuple(tys.clean(cx)), - TyPath(None, ref path) => { + TyPath(hir::QPath::Resolved(None, ref path)) => { let def = cx.tcx.expect_def(self.id); if let Some(new_ty) = cx.ty_substs.borrow().get(&def).cloned() { return new_ty; @@ -1766,7 +1766,7 @@ impl Clean for hir::Ty { } resolve_type(cx, path.clean(cx), self.id) } - TyPath(Some(ref qself), ref p) => { + TyPath(hir::QPath::Resolved(Some(ref qself), ref p)) => { let mut segments: Vec<_> = p.segments.clone().into(); segments.pop(); let trait_path = hir::Path { @@ -1776,7 +1776,19 @@ impl Clean for hir::Ty { }; Type::QPath { name: p.segments.last().unwrap().name.clean(cx), - self_type: box qself.ty.clean(cx), + self_type: box qself.clean(cx), + trait_: box resolve_type(cx, trait_path.clean(cx), self.id) + } + } + TyPath(hir::QPath::TypeRelative(ref qself, ref segment)) => { + let trait_path = hir::Path { + span: self.span, + global: false, + segments: vec![].into(), + }; + Type::QPath { + name: segment.name.clean(cx), + self_type: box qself.clean(cx), trait_: box resolve_type(cx, trait_path.clean(cx), self.id) } } @@ -2263,11 +2275,20 @@ impl Clean for hir::PathSegment { } } -fn path_to_string(p: &hir::Path) -> String { +fn qpath_to_string(p: &hir::QPath) -> String { + let (segments, global) = match *p { + hir::QPath::Resolved(_, ref path) => { + (&path.segments, path.global) + } + hir::QPath::TypeRelative(_, ref segment) => { + return segment.name.to_string() + } + }; + let mut s = String::new(); let mut first = true; - for i in p.segments.iter().map(|x| x.name.as_str()) { - if !first || p.global { + for i in segments.iter().map(|x| x.name.as_str()) { + if !first || global { s.push_str("::"); } else { first = false; @@ -2725,17 +2746,15 @@ fn name_from_pat(p: &hir::Pat) -> String { match p.node { PatKind::Wild => "_".to_string(), PatKind::Binding(_, ref p, _) => p.node.to_string(), - PatKind::TupleStruct(ref p, ..) | PatKind::Path(None, ref p) => path_to_string(p), - PatKind::Path(..) => panic!("tried to get argument name from qualified PatKind::Path, \ - which is not allowed in function arguments"), + PatKind::TupleStruct(ref p, ..) | PatKind::Path(ref p) => qpath_to_string(p), PatKind::Struct(ref name, ref fields, etc) => { - format!("{} {{ {}{} }}", path_to_string(name), + format!("{} {{ {}{} }}", qpath_to_string(name), fields.iter().map(|&Spanned { node: ref fp, .. }| format!("{}: {}", fp.name, name_from_pat(&*fp.pat))) .collect::>().join(", "), if etc { ", ..." } else { "" } ) - }, + } PatKind::Tuple(ref elts, _) => format!("({})", elts.iter().map(|p| name_from_pat(&**p)) .collect::>().join(", ")), PatKind::Box(ref p) => name_from_pat(&**p), diff --git a/src/test/compile-fail/issue-28992-empty.rs b/src/test/compile-fail/issue-28992-empty.rs index d47fdda0203..48aabce708e 100644 --- a/src/test/compile-fail/issue-28992-empty.rs +++ b/src/test/compile-fail/issue-28992-empty.rs @@ -23,5 +23,5 @@ impl S { fn main() { if let C1(..) = 0 {} //~ ERROR expected tuple struct/variant, found constant `C1` if let S::C2(..) = 0 {} - //~^ ERROR expected tuple struct/variant, found associated constant `S::C2` + //~^ ERROR expected tuple struct/variant, found associated constant `::C2` } diff --git a/src/test/compile-fail/method-path-in-pattern.rs b/src/test/compile-fail/method-path-in-pattern.rs index aaa89b22829..671a518073c 100644 --- a/src/test/compile-fail/method-path-in-pattern.rs +++ b/src/test/compile-fail/method-path-in-pattern.rs @@ -22,13 +22,15 @@ impl MyTrait for Foo {} fn main() { match 0u32 { - Foo::bar => {} //~ ERROR expected unit struct/variant or constant, found method `Foo::bar` + Foo::bar => {} + //~^ ERROR expected unit struct/variant or constant, found method `::bar` } match 0u32 { - ::bar => {} //~ ERROR expected unit struct/variant or constant, found method `bar` + ::bar => {} + //~^ ERROR expected unit struct/variant or constant, found method `::bar` } match 0u32 { ::trait_bar => {} - //~^ ERROR expected unit struct/variant or constant, found method `trait_bar` + //~^ ERROR expected unit struct/variant or constant, found method `::trait_bar` } } diff --git a/src/test/compile-fail/qualified-path-params.rs b/src/test/compile-fail/qualified-path-params.rs index 82b0536a64a..a7bc27e1749 100644 --- a/src/test/compile-fail/qualified-path-params.rs +++ b/src/test/compile-fail/qualified-path-params.rs @@ -28,7 +28,7 @@ impl S { fn main() { match 10 { ::A::f:: => {} - //~^ ERROR expected unit struct/variant or constant, found method `Tr::A::f` + //~^ ERROR expected unit struct/variant or constant, found method `<::A>::f` 0 ... ::A::f:: => {} //~ ERROR only char and numeric types are allowed in range } } diff --git a/src/test/compile-fail/unspecified-self-in-trait-ref.rs b/src/test/compile-fail/unspecified-self-in-trait-ref.rs index 2c2f113a779..84bcca3fc7b 100644 --- a/src/test/compile-fail/unspecified-self-in-trait-ref.rs +++ b/src/test/compile-fail/unspecified-self-in-trait-ref.rs @@ -9,11 +9,11 @@ // except according to those terms. pub trait Foo { - fn foo(); + fn foo(&self); } pub trait Bar { - fn foo(); + fn foo(&self); } fn main() { diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index 24b0f90d08e..fdb7f9c68b9 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -40,7 +40,7 @@ pub fn bar() ({ (($crate::fmt::format as - fn(std::fmt::Arguments<'_>) -> std::string::String {std::fmt::format})(((::std::fmt::Arguments::new_v1 + fn(std::fmt::Arguments<'_>) -> std::string::String {std::fmt::format})(((<::std::fmt::Arguments>::new_v1 as fn(&[&str], &[std::fmt::ArgumentV1<'_>]) -> std::fmt::Arguments<'_> {std::fmt::Arguments<'_>::new_v1})(({ static __STATIC_FMTSTR: From 6ebc6d8154eb80eef585603a143d1b0008b93e91 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Sun, 30 Oct 2016 08:04:52 +0200 Subject: [PATCH 082/293] rustc: track hir::{TraitRef, Visibility} in the HIR map. --- src/librustc/hir/map/collector.rs | 29 ++++++++++++++++++++++------- src/librustc/hir/map/mod.rs | 30 +++++++++++++++++++++++++++--- src/librustc/hir/print.rs | 2 +- 3 files changed, 50 insertions(+), 11 deletions(-) diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index 89217e83ca2..64bf4bbf080 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -124,13 +124,6 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { this.insert(struct_def.id(), NodeStructCtor(struct_def)); } } - ItemTrait(.., ref bounds, _) => { - for b in bounds.iter() { - if let TraitTyParamBound(ref t, TraitBoundModifier::None) = *b { - this.insert(t.trait_ref.ref_id, NodeItem(i)); - } - } - } ItemUse(ref view_path) => { match view_path.node { ViewPathList(_, ref paths) => { @@ -217,6 +210,14 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { }); } + fn visit_trait_ref(&mut self, tr: &'ast TraitRef) { + self.insert(tr.ref_id, NodeTraitRef(tr)); + + self.with_parent(tr.ref_id, |this| { + intravisit::walk_trait_ref(this, tr); + }); + } + fn visit_fn(&mut self, fk: intravisit::FnKind<'ast>, fd: &'ast FnDecl, b: &'ast Expr, s: Span, id: NodeId) { assert_eq!(self.parent_node, id); @@ -234,6 +235,20 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { self.insert(lifetime.id, NodeLifetime(lifetime)); } + fn visit_vis(&mut self, visibility: &'ast Visibility) { + match *visibility { + Visibility::Public | + Visibility::Crate | + Visibility::Inherited => {} + Visibility::Restricted { id, .. } => { + self.insert(id, NodeVisibility(visibility)); + self.with_parent(id, |this| { + intravisit::walk_vis(this, visibility); + }); + } + } + } + fn visit_macro_def(&mut self, macro_def: &'ast MacroDef) { self.insert_entry(macro_def.id, NotPresent); } diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index a90577b3426..7f6c85eeaac 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -49,6 +49,7 @@ pub enum Node<'ast> { NodeExpr(&'ast Expr), NodeStmt(&'ast Stmt), NodeTy(&'ast Ty), + NodeTraitRef(&'ast TraitRef), NodeLocal(&'ast Pat), NodePat(&'ast Pat), NodeBlock(&'ast Block), @@ -57,7 +58,8 @@ pub enum Node<'ast> { NodeStructCtor(&'ast VariantData), NodeLifetime(&'ast Lifetime), - NodeTyParam(&'ast TyParam) + NodeTyParam(&'ast TyParam), + NodeVisibility(&'ast Visibility), } /// Represents an entry and its parent NodeID. @@ -76,12 +78,14 @@ pub enum MapEntry<'ast> { EntryExpr(NodeId, &'ast Expr), EntryStmt(NodeId, &'ast Stmt), EntryTy(NodeId, &'ast Ty), + EntryTraitRef(NodeId, &'ast TraitRef), EntryLocal(NodeId, &'ast Pat), EntryPat(NodeId, &'ast Pat), EntryBlock(NodeId, &'ast Block), EntryStructCtor(NodeId, &'ast VariantData), EntryLifetime(NodeId, &'ast Lifetime), EntryTyParam(NodeId, &'ast TyParam), + EntryVisibility(NodeId, &'ast Visibility), /// Roots for node trees. RootCrate, @@ -105,12 +109,14 @@ impl<'ast> MapEntry<'ast> { NodeExpr(n) => EntryExpr(p, n), NodeStmt(n) => EntryStmt(p, n), NodeTy(n) => EntryTy(p, n), + NodeTraitRef(n) => EntryTraitRef(p, n), NodeLocal(n) => EntryLocal(p, n), NodePat(n) => EntryPat(p, n), NodeBlock(n) => EntryBlock(p, n), NodeStructCtor(n) => EntryStructCtor(p, n), NodeLifetime(n) => EntryLifetime(p, n), NodeTyParam(n) => EntryTyParam(p, n), + NodeVisibility(n) => EntryVisibility(p, n), } } @@ -124,12 +130,14 @@ impl<'ast> MapEntry<'ast> { EntryExpr(id, _) => id, EntryStmt(id, _) => id, EntryTy(id, _) => id, + EntryTraitRef(id, _) => id, EntryLocal(id, _) => id, EntryPat(id, _) => id, EntryBlock(id, _) => id, EntryStructCtor(id, _) => id, EntryLifetime(id, _) => id, EntryTyParam(id, _) => id, + EntryVisibility(id, _) => id, NotPresent | RootCrate | @@ -147,12 +155,14 @@ impl<'ast> MapEntry<'ast> { EntryExpr(_, n) => NodeExpr(n), EntryStmt(_, n) => NodeStmt(n), EntryTy(_, n) => NodeTy(n), + EntryTraitRef(_, n) => NodeTraitRef(n), EntryLocal(_, n) => NodeLocal(n), EntryPat(_, n) => NodePat(n), EntryBlock(_, n) => NodeBlock(n), EntryStructCtor(_, n) => NodeStructCtor(n), EntryLifetime(_, n) => NodeLifetime(n), EntryTyParam(_, n) => NodeTyParam(n), + EntryVisibility(_, n) => NodeVisibility(n), _ => return None }) } @@ -266,12 +276,14 @@ impl<'ast> Map<'ast> { EntryExpr(p, _) | EntryStmt(p, _) | EntryTy(p, _) | + EntryTraitRef(p, _) | EntryLocal(p, _) | EntryPat(p, _) | EntryBlock(p, _) | EntryStructCtor(p, _) | EntryLifetime(p, _) | - EntryTyParam(p, _) => + EntryTyParam(p, _) | + EntryVisibility(p, _) => id = p, RootCrate => @@ -307,12 +319,14 @@ impl<'ast> Map<'ast> { EntryExpr(p, _) | EntryStmt(p, _) | EntryTy(p, _) | + EntryTraitRef(p, _) | EntryLocal(p, _) | EntryPat(p, _) | EntryBlock(p, _) | EntryStructCtor(p, _) | EntryLifetime(p, _) | - EntryTyParam(p, _) => + EntryTyParam(p, _) | + EntryVisibility(p, _) => id = p, RootInlinedParent(parent) => match *parent { @@ -707,11 +721,13 @@ impl<'ast> Map<'ast> { Some(NodeExpr(expr)) => expr.span, Some(NodeStmt(stmt)) => stmt.span, Some(NodeTy(ty)) => ty.span, + Some(NodeTraitRef(tr)) => tr.path.span, Some(NodeLocal(pat)) => pat.span, Some(NodePat(pat)) => pat.span, Some(NodeBlock(block)) => block.span, Some(NodeStructCtor(_)) => self.expect_item(self.get_parent(id)).span, Some(NodeTyParam(ty_param)) => ty_param.span, + Some(NodeVisibility(&Visibility::Restricted { ref path, .. })) => path.span, _ => return None, }; Some(sp) @@ -926,9 +942,11 @@ impl<'a> NodePrinter for pprust::State<'a> { NodeExpr(a) => self.print_expr(&a), NodeStmt(a) => self.print_stmt(&a), NodeTy(a) => self.print_type(&a), + NodeTraitRef(a) => self.print_trait_ref(&a), NodePat(a) => self.print_pat(&a), NodeBlock(a) => self.print_block(&a), NodeLifetime(a) => self.print_lifetime(&a), + NodeVisibility(a) => self.print_visibility(&a), NodeTyParam(_) => bug!("cannot print TyParam"), // these cases do not carry enough information in the // ast_map to reconstruct their full structure for pretty @@ -1018,6 +1036,9 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String { Some(NodeTy(ref ty)) => { format!("type {}{}", pprust::ty_to_string(&ty), id_str) } + Some(NodeTraitRef(ref tr)) => { + format!("trait_ref {}{}", pprust::path_to_string(&tr.path), id_str) + } Some(NodeLocal(ref pat)) => { format!("local {}{}", pprust::pat_to_string(&pat), id_str) } @@ -1037,6 +1058,9 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String { Some(NodeTyParam(ref ty_param)) => { format!("typaram {:?}{}", ty_param, id_str) } + Some(NodeVisibility(ref vis)) => { + format!("visibility {:?}{}", vis, id_str) + } None => { format!("unknown node{}", id_str) } diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 448139c37e6..f6f40a91bf4 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -845,7 +845,7 @@ impl<'a> State<'a> { self.ann.post(self, NodeItem(item)) } - fn print_trait_ref(&mut self, t: &hir::TraitRef) -> io::Result<()> { + pub fn print_trait_ref(&mut self, t: &hir::TraitRef) -> io::Result<()> { self.print_path(&t.path, false) } From bc096549e84d1edbd051f0b42662c038dd935ff6 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Thu, 24 Nov 2016 06:11:31 +0200 Subject: [PATCH 083/293] rustc: desugar `use a::{b,c};` into `use a::b; use a::c;` in HIR. --- src/librustc/hir/intravisit.rs | 29 +-- src/librustc/hir/lowering.rs | 194 +++++++++++------- src/librustc/hir/map/collector.rs | 10 - src/librustc/hir/map/def_collector.rs | 15 +- src/librustc/hir/map/mod.rs | 12 +- src/librustc/hir/mod.rs | 46 ++--- src/librustc/hir/print.rs | 50 ++--- src/librustc/lint/context.rs | 5 - src/librustc/lint/mod.rs | 1 - src/librustc/middle/dead.rs | 5 - src/librustc/middle/reachable.rs | 2 +- src/librustc/middle/resolve_lifetime.rs | 2 +- src/librustc/middle/stability.rs | 14 -- .../calculate_svh/svh_visitor.rs | 13 +- src/librustc_lint/builtin.rs | 8 - src/librustc_lint/lib.rs | 2 +- src/librustc_lint/unused.rs | 10 +- src/librustc_metadata/encoder.rs | 4 +- src/librustc_passes/hir_stats.rs | 6 - src/librustc_typeck/check_unused.rs | 13 +- src/librustc_typeck/collect.rs | 2 +- src/librustc_typeck/variance/constraints.rs | 2 +- src/librustc_typeck/variance/terms.rs | 2 +- src/librustdoc/clean/mod.rs | 72 ++----- src/librustdoc/doctree.rs | 4 +- src/librustdoc/html/format.rs | 27 --- src/librustdoc/visit_ast.rs | 59 ++---- src/test/rustdoc/viewpath-rename.rs | 7 +- src/test/rustdoc/viewpath-self.rs | 7 +- 29 files changed, 228 insertions(+), 395 deletions(-) diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 743eed74d0c..3de788b8c1a 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -250,9 +250,6 @@ pub trait Visitor<'v> : Sized { fn visit_path(&mut self, path: &'v Path, _id: NodeId) { walk_path(self, path) } - fn visit_path_list_item(&mut self, prefix: &'v Path, item: &'v PathListItem) { - walk_path_list_item(self, prefix, item) - } fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v PathSegment) { walk_path_segment(self, path_span, path_segment) } @@ -352,23 +349,9 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { visitor.visit_id(item.id); walk_opt_name(visitor, item.span, opt_name) } - ItemUse(ref vp) => { + ItemUse(ref path, _) => { visitor.visit_id(item.id); - match vp.node { - ViewPathSimple(name, ref path) => { - visitor.visit_name(vp.span, name); - visitor.visit_path(path, item.id); - } - ViewPathGlob(ref path) => { - visitor.visit_path(path, item.id); - } - ViewPathList(ref prefix, ref list) => { - visitor.visit_path(prefix, item.id); - for item in list { - visitor.visit_path_list_item(prefix, item) - } - } - } + visitor.visit_path(path, item.id); } ItemStatic(ref typ, _, ref expr) | ItemConst(ref typ, ref expr) => { @@ -529,14 +512,6 @@ pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path) { } } -pub fn walk_path_list_item<'v, V>(visitor: &mut V, _prefix: &'v Path, item: &'v PathListItem) - where V: Visitor<'v>, -{ - visitor.visit_id(item.node.id); - visitor.visit_name(item.span, item.node.name); - walk_opt_name(visitor, item.span, item.node.rename); -} - pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V, path_span: Span, segment: &'v PathSegment) { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 056c1b90620..af0448cc277 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -55,6 +55,7 @@ use syntax::ptr::P; use syntax::codemap::{respan, Spanned}; use syntax::std_inject; use syntax::symbol::{Symbol, keywords}; +use syntax::util::small_vector::SmallVector; use syntax::visit::{self, Visitor}; use syntax_pos::Span; @@ -67,6 +68,11 @@ pub struct LoweringContext<'a> { // a definition, then we can properly create the def id. parent_def: Option, resolver: &'a mut Resolver, + + /// The items being lowered are collected here. + items: BTreeMap, + + impl_items: BTreeMap, } pub trait Resolver { @@ -98,6 +104,8 @@ pub fn lower_crate(sess: &Session, sess: sess, parent_def: None, resolver: resolver, + items: BTreeMap::new(), + impl_items: BTreeMap::new(), }.lower_crate(krate) } @@ -110,41 +118,35 @@ enum ParamMode { } impl<'a> LoweringContext<'a> { - fn lower_crate(&mut self, c: &Crate) -> hir::Crate { + fn lower_crate(mut self, c: &Crate) -> hir::Crate { struct ItemLowerer<'lcx, 'interner: 'lcx> { - items: BTreeMap, - impl_items: BTreeMap, lctx: &'lcx mut LoweringContext<'interner>, } impl<'lcx, 'interner> Visitor for ItemLowerer<'lcx, 'interner> { fn visit_item(&mut self, item: &Item) { - self.items.insert(item.id, self.lctx.lower_item(item)); + let hir_item = self.lctx.lower_item(item); + self.lctx.items.insert(item.id, hir_item); visit::walk_item(self, item); } fn visit_impl_item(&mut self, item: &ImplItem) { let id = self.lctx.lower_impl_item_ref(item).id; - self.impl_items.insert(id, self.lctx.lower_impl_item(item)); + let hir_item = self.lctx.lower_impl_item(item); + self.lctx.impl_items.insert(id, hir_item); visit::walk_impl_item(self, item); } } - let (items, impl_items) = { - let mut item_lowerer = ItemLowerer { items: BTreeMap::new(), - impl_items: BTreeMap::new(), - lctx: self }; - visit::walk_crate(&mut item_lowerer, c); - (item_lowerer.items, item_lowerer.impl_items) - }; + visit::walk_crate(&mut ItemLowerer { lctx: &mut self }, c); hir::Crate { module: self.lower_mod(&c.module), attrs: self.lower_attrs(&c.attrs), span: c.span, exported_macros: c.exported_macros.iter().map(|m| self.lower_macro_def(m)).collect(), - items: items, - impl_items: impl_items, + items: self.items, + impl_items: self.impl_items, } } @@ -183,38 +185,6 @@ impl<'a> LoweringContext<'a> { attrs.clone().into() } - fn lower_view_path(&mut self, view_path: &ViewPath) -> P { - P(Spanned { - node: match view_path.node { - ViewPathSimple(ident, ref path) => { - hir::ViewPathSimple(ident.name, - self.lower_path(path, ParamMode::Explicit)) - } - ViewPathGlob(ref path) => { - hir::ViewPathGlob(self.lower_path(path, ParamMode::Explicit)) - } - ViewPathList(ref path, ref path_list_idents) => { - hir::ViewPathList(self.lower_path(path, ParamMode::Explicit), - path_list_idents.iter() - .map(|item| self.lower_path_list_item(item)) - .collect()) - } - }, - span: view_path.span, - }) - } - - fn lower_path_list_item(&mut self, path_list_ident: &PathListItem) -> hir::PathListItem { - Spanned { - node: hir::PathListItem_ { - id: path_list_ident.node.id, - name: path_list_ident.node.name.name, - rename: path_list_ident.node.rename.map(|rename| rename.name), - }, - span: path_list_ident.span, - } - } - fn lower_arm(&mut self, arm: &Arm) -> hir::Arm { hir::Arm { attrs: self.lower_attrs(&arm.attrs), @@ -382,19 +352,32 @@ impl<'a> LoweringContext<'a> { proj_start, p.segments.len()) } - fn lower_path(&mut self, - p: &Path, - param_mode: ParamMode) - -> hir::Path { + fn lower_path_extra(&mut self, + p: &Path, + name: Option, + param_mode: ParamMode) + -> hir::Path { hir::Path { global: p.global, segments: p.segments.iter().map(|segment| { self.lower_path_segment(segment, param_mode) - }).collect(), + }).chain(name.map(|name| { + hir::PathSegment { + name: name, + parameters: hir::PathParameters::none() + } + })).collect(), span: p.span, } } + fn lower_path(&mut self, + p: &Path, + param_mode: ParamMode) + -> hir::Path { + self.lower_path_extra(p, None, param_mode) + } + fn lower_path_segment(&mut self, segment: &PathSegment, param_mode: ParamMode) @@ -661,12 +644,10 @@ impl<'a> LoweringContext<'a> { } fn lower_block(&mut self, b: &Block) -> P { - let mut stmts = Vec::new(); let mut expr = None; - if let Some((last, rest)) = b.stmts.split_last() { - stmts = rest.iter().map(|s| self.lower_stmt(s)).collect::>(); - let last = self.lower_stmt(last); + let mut stmts = b.stmts.iter().flat_map(|s| self.lower_stmt(s)).collect::>(); + if let Some(last) = stmts.pop() { if let hir::StmtExpr(e, _) = last.node { expr = Some(e); } else { @@ -683,11 +664,65 @@ impl<'a> LoweringContext<'a> { }) } - fn lower_item_kind(&mut self, i: &ItemKind) -> hir::Item_ { + fn lower_item_kind(&mut self, + name: &mut Name, + attrs: &hir::HirVec, + vis: &mut hir::Visibility, + i: &ItemKind) + -> hir::Item_ { match *i { ItemKind::ExternCrate(string) => hir::ItemExternCrate(string), ItemKind::Use(ref view_path) => { - hir::ItemUse(self.lower_view_path(view_path)) + let path = match view_path.node { + ViewPathSimple(_, ref path) => path, + ViewPathGlob(ref path) => path, + ViewPathList(ref path, ref path_list_idents) => { + for &Spanned { node: ref import, span } in path_list_idents { + // `use a::{self as x, b as y};` lowers to + // `use a as x; use a::b as y;` + let mut ident = import.name; + let suffix = if ident.name == keywords::SelfValue.name() { + if let Some(last) = path.segments.last() { + ident = last.identifier; + } + None + } else { + Some(ident.name) + }; + + let mut path = self.lower_path_extra(path, suffix, + ParamMode::Explicit); + path.span = span; + self.items.insert(import.id, hir::Item { + id: import.id, + name: import.rename.unwrap_or(ident).name, + attrs: attrs.clone(), + node: hir::ItemUse(P(path), hir::UseKind::Single), + vis: vis.clone(), + span: span, + }); + } + path + } + }; + let path = P(self.lower_path(path, ParamMode::Explicit)); + let kind = match view_path.node { + ViewPathSimple(ident, _) => { + *name = ident.name; + hir::UseKind::Single + } + ViewPathGlob(_) => { + hir::UseKind::Glob + } + ViewPathList(..) => { + // Privatize the degenerate import base, used only to check + // the stability of `use a::{};`, to avoid it showing up as + // a reexport by accident when `pub`, e.g. in documentation. + *vis = hir::Inherited; + hir::UseKind::ListStem + } + }; + hir::ItemUse(path, kind) } ItemKind::Static(ref t, m, ref e) => { hir::ItemStatic(self.lower_ty(t), @@ -835,7 +870,7 @@ impl<'a> LoweringContext<'a> { fn lower_mod(&mut self, m: &Mod) -> hir::Mod { hir::Mod { inner: m.inner, - item_ids: m.items.iter().map(|x| self.lower_item_id(x)).collect(), + item_ids: m.items.iter().flat_map(|x| self.lower_item_id(x)).collect(), } } @@ -851,21 +886,30 @@ impl<'a> LoweringContext<'a> { } } - fn lower_item_id(&mut self, i: &Item) -> hir::ItemId { - hir::ItemId { id: i.id } + fn lower_item_id(&mut self, i: &Item) -> SmallVector { + if let ItemKind::Use(ref view_path) = i.node { + if let ViewPathList(_, ref imports) = view_path.node { + return iter::once(i.id).chain(imports.iter().map(|import| import.node.id)) + .map(|id| hir::ItemId { id: id }).collect(); + } + } + SmallVector::one(hir::ItemId { id: i.id }) } pub fn lower_item(&mut self, i: &Item) -> hir::Item { + let mut name = i.ident.name; + let attrs = self.lower_attrs(&i.attrs); + let mut vis = self.lower_visibility(&i.vis); let node = self.with_parent_def(i.id, |this| { - this.lower_item_kind(&i.node) + this.lower_item_kind(&mut name, &attrs, &mut vis, &i.node) }); hir::Item { id: i.id, - name: i.ident.name, - attrs: self.lower_attrs(&i.attrs), + name: name, + attrs: attrs, node: node, - vis: self.lower_visibility(&i.vis), + vis: vis, span: i.span, } } @@ -1701,8 +1745,8 @@ impl<'a> LoweringContext<'a> { } } - fn lower_stmt(&mut self, s: &Stmt) -> hir::Stmt { - match s.node { + fn lower_stmt(&mut self, s: &Stmt) -> SmallVector { + SmallVector::one(match s.node { StmtKind::Local(ref l) => Spanned { node: hir::StmtDecl(P(Spanned { node: hir::DeclLocal(self.lower_local(l)), @@ -1710,13 +1754,17 @@ impl<'a> LoweringContext<'a> { }), s.id), span: s.span, }, - StmtKind::Item(ref it) => Spanned { - node: hir::StmtDecl(P(Spanned { - node: hir::DeclItem(self.lower_item_id(it)), + StmtKind::Item(ref it) => { + // Can only use the ID once. + let mut id = Some(s.id); + return self.lower_item_id(it).into_iter().map(|item_id| Spanned { + node: hir::StmtDecl(P(Spanned { + node: hir::DeclItem(item_id), + span: s.span, + }), id.take().unwrap_or_else(|| self.next_id())), span: s.span, - }), s.id), - span: s.span, - }, + }).collect(); + } StmtKind::Expr(ref e) => { Spanned { node: hir::StmtExpr(P(self.lower_expr(e)), s.id), @@ -1730,7 +1778,7 @@ impl<'a> LoweringContext<'a> { } } StmtKind::Mac(..) => panic!("Shouldn't exist here"), - } + }) } fn lower_capture_clause(&mut self, c: CaptureBy) -> hir::CaptureClause { diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index 64bf4bbf080..67e9b24f42d 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -124,16 +124,6 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { this.insert(struct_def.id(), NodeStructCtor(struct_def)); } } - ItemUse(ref view_path) => { - match view_path.node { - ViewPathList(_, ref paths) => { - for path in paths { - this.insert(path.node.id, NodeItem(i)); - } - } - _ => () - } - } _ => {} } intravisit::walk_item(this, i); diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index 7486d954c48..9d1c7d41faa 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -155,7 +155,20 @@ impl<'a> visit::Visitor for DefCollector<'a> { DefPathData::ValueNs(i.ident.name.as_str()), ItemKind::Mac(..) if i.id == DUMMY_NODE_ID => return, // Scope placeholder ItemKind::Mac(..) => return self.visit_macro_invoc(i.id, false), - ItemKind::Use(..) => DefPathData::Misc, + ItemKind::Use(ref view_path) => { + match view_path.node { + ViewPathGlob(..) => {} + + // FIXME(eddyb) Should use the real name. Which namespace? + ViewPathSimple(..) => {} + ViewPathList(_, ref imports) => { + for import in imports { + self.create_def(import.node.id, DefPathData::Misc); + } + } + } + DefPathData::Misc + } }; let def = self.create_def(i.id, def_data); diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 7f6c85eeaac..a8986530d1d 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -250,16 +250,8 @@ impl<'ast> Map<'ast> { loop { match map[id.as_usize()] { EntryItem(_, item) => { - let def_id = self.local_def_id(item.id); - // NB ^~~~~~~ - // - // You would expect that `item.id == id`, but this - // is not always the case. In particular, for a - // ViewPath item like `use self::{mem, foo}`, we - // map the ids for `mem` and `foo` to the - // enclosing view path item. This seems mega super - // ultra wrong, but then who am I to judge? - // -nmatsakis + assert_eq!(id, item.id); + let def_id = self.local_def_id(id); assert!(!self.is_inlined_def_id(def_id)); return DepNode::Hir(def_id); } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index e9e84eed3e7..da759b2d4da 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -27,7 +27,6 @@ pub use self::Ty_::*; pub use self::TyParamBound::*; pub use self::UnOp::*; pub use self::UnsafeSource::*; -pub use self::ViewPath_::*; pub use self::Visibility::{Public, Inherited}; pub use self::PathParameters::*; @@ -1385,32 +1384,20 @@ pub struct Variant_ { pub type Variant = Spanned; -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] -pub struct PathListItem_ { - pub name: Name, - /// renamed in list, eg `use foo::{bar as baz};` - pub rename: Option, - pub id: NodeId, -} +#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum UseKind { + /// One import, e.g. `use foo::bar` or `use foo::bar as baz`. + /// Also produced for each element of a list `use`, e.g. + // `use foo::{a, b}` lowers to `use foo::a; use foo::b;`. + Single, -pub type PathListItem = Spanned; + /// Glob import, e.g. `use foo::*`. + Glob, -pub type ViewPath = Spanned; - -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub enum ViewPath_ { - /// `foo::bar::baz as quux` - /// - /// or just - /// - /// `foo::bar::baz` (with `as baz` implicitly on the right) - ViewPathSimple(Name, Path), - - /// `foo::bar::*` - ViewPathGlob(Path), - - /// `foo::bar::{a,b,c}` - ViewPathList(Path, HirVec), + /// Degenerate list import, e.g. `use foo::{a, b}` produces + /// an additional `use foo::{}` for performing checks such as + /// unstable feature gating. May be removed in the future. + ListStem, } /// TraitRef's appear in impls. @@ -1544,8 +1531,13 @@ pub enum Item_ { /// /// e.g. `extern crate foo` or `extern crate foo_bar as foo` ItemExternCrate(Option), - /// A `use` or `pub use` item - ItemUse(P), + + /// `use foo::bar::*;` or `use foo::bar::baz as quux;` + /// + /// or just + /// + /// `use foo::bar::baz;` (with `as baz` implicitly on the right) + ItemUse(P, UseKind), /// A `static` item ItemStatic(P, Mutability, P), diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index f6f40a91bf4..4dd08def251 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -669,10 +669,22 @@ impl<'a> State<'a> { self.end()?; // end inner head-block self.end()?; // end outer head-block } - hir::ItemUse(ref vp) => { + hir::ItemUse(ref path, kind) => { self.head(&visibility_qualified(&item.vis, "use"))?; - self.print_view_path(&vp)?; - word(&mut self.s, ";")?; + self.print_path(path, false)?; + + match kind { + hir::UseKind::Single => { + if path.segments.last().unwrap().name != item.name { + space(&mut self.s)?; + self.word_space("as")?; + self.print_name(item.name)?; + } + word(&mut self.s, ";")?; + } + hir::UseKind::Glob => word(&mut self.s, "::*;")?, + hir::UseKind::ListStem => word(&mut self.s, "::{};")? + } self.end()?; // end inner head-block self.end()?; // end outer head-block } @@ -2153,38 +2165,6 @@ impl<'a> State<'a> { Ok(()) } - pub fn print_view_path(&mut self, vp: &hir::ViewPath) -> io::Result<()> { - match vp.node { - hir::ViewPathSimple(name, ref path) => { - self.print_path(path, false)?; - - if path.segments.last().unwrap().name != name { - space(&mut self.s)?; - self.word_space("as")?; - self.print_name(name)?; - } - - Ok(()) - } - - hir::ViewPathGlob(ref path) => { - self.print_path(path, false)?; - word(&mut self.s, "::*") - } - - hir::ViewPathList(ref path, ref segments) => { - if path.segments.is_empty() { - word(&mut self.s, "{")?; - } else { - self.print_path(path, false)?; - word(&mut self.s, "::{")?; - } - self.commasep(Inconsistent, &segments[..], |s, w| s.print_name(w.node.name))?; - word(&mut self.s, "}") - } - } - } - pub fn print_mutability(&mut self, mutbl: hir::Mutability) -> io::Result<()> { match mutbl { hir::MutMutable => self.word_nbsp("mut"), diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 4a082944010..41c8d413486 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -948,11 +948,6 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { hir_visit::walk_path(self, p); } - fn visit_path_list_item(&mut self, prefix: &'tcx hir::Path, item: &'tcx hir::PathListItem) { - run_lints!(self, check_path_list_item, late_passes, item); - hir_visit::walk_path_list_item(self, prefix, item); - } - fn visit_attribute(&mut self, attr: &ast::Attribute) { check_lint_name_attribute(self, attr); run_lints!(self, check_attribute, late_passes, attr); diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 6f7102229f8..4e06e0abf01 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -168,7 +168,6 @@ pub trait LateLintPass: LintPass { fn check_lifetime(&mut self, _: &LateContext, _: &hir::Lifetime) { } fn check_lifetime_def(&mut self, _: &LateContext, _: &hir::LifetimeDef) { } fn check_path(&mut self, _: &LateContext, _: &hir::Path, _: ast::NodeId) { } - fn check_path_list_item(&mut self, _: &LateContext, _: &hir::PathListItem) { } fn check_attribute(&mut self, _: &LateContext, _: &ast::Attribute) { } /// Called when entering a syntax node that can have lint attributes such diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index efbec7bf13b..ec064e264ab 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -297,11 +297,6 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> { self.lookup_and_handle_definition(id); intravisit::walk_path(self, path); } - - fn visit_path_list_item(&mut self, path: &hir::Path, item: &hir::PathListItem) { - self.lookup_and_handle_definition(item.node.id); - intravisit::walk_path_list_item(self, path, item); - } } fn has_allow_dead_code_or_lang_attr(attrs: &[ast::Attribute]) -> bool { diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 0329b4c4a30..91c1c63d890 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -265,7 +265,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { // These are normal, nothing reachable about these // inherently and their children are already in the // worklist, as determined by the privacy pass - hir::ItemExternCrate(_) | hir::ItemUse(_) | + hir::ItemExternCrate(_) | hir::ItemUse(..) | hir::ItemTy(..) | hir::ItemStatic(..) | hir::ItemMod(..) | hir::ItemForeignMod(..) | hir::ItemImpl(..) | hir::ItemTrait(..) | diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index c65fd25950d..f256d6d9b4f 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -151,7 +151,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { intravisit::walk_item(this, item); } hir::ItemExternCrate(_) | - hir::ItemUse(_) | + hir::ItemUse(..) | hir::ItemMod(..) | hir::ItemDefaultImpl(..) | hir::ItemForeignMod(..) | diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index a044ffd9a7f..d7a29e190a8 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -474,12 +474,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { intravisit::walk_path(self, path) } - fn visit_path_list_item(&mut self, prefix: &'tcx hir::Path, item: &'tcx hir::PathListItem) { - check_path_list_item(self.tcx, item, - &mut |id, sp, stab, depr| self.check(id, sp, stab, depr)); - intravisit::walk_path_list_item(self, prefix, item) - } - fn visit_pat(&mut self, pat: &'tcx hir::Pat) { check_pat(self.tcx, pat, &mut |id, sp, stab, depr| self.check(id, sp, stab, depr)); @@ -628,14 +622,6 @@ pub fn check_path<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -pub fn check_path_list_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - item: &hir::PathListItem, - cb: &mut FnMut(DefId, Span, - &Option<&Stability>, - &Option)) { - maybe_do_stability_check(tcx, tcx.expect_def(item.node.id).def_id(), item.span, cb); -} - pub fn check_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &hir::Pat, cb: &mut FnMut(DefId, Span, &Option<&Stability>, diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index ec405311012..8c6d8dffa1d 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -189,7 +189,6 @@ enum SawAbiComponent<'a> { SawPath(bool), SawPathSegment, SawPathParameters, - SawPathListItem, SawBlock, SawPat(SawPatComponent), SawLocal, @@ -357,7 +356,7 @@ fn saw_lit(lit: &ast::Lit) -> SawExprComponent<'static> { #[derive(Hash)] enum SawItemComponent { SawItemExternCrate, - SawItemUse, + SawItemUse(UseKind), SawItemStatic(Mutability), SawItemConst, SawItemFn(Unsafety, Constness, Abi), @@ -375,7 +374,7 @@ enum SawItemComponent { fn saw_item(node: &Item_) -> SawItemComponent { match *node { ItemExternCrate(..) => SawItemExternCrate, - ItemUse(..) => SawItemUse, + ItemUse(_, kind) => SawItemUse(kind), ItemStatic(_, mutability, _) => SawItemStatic(mutability), ItemConst(..) =>SawItemConst, ItemFn(_, unsafety, constness, abi, _, _) => SawItemFn(unsafety, constness, abi), @@ -747,14 +746,6 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has visit::walk_poly_trait_ref(self, t, m) } - fn visit_path_list_item(&mut self, prefix: &'tcx Path, item: &'tcx PathListItem) { - debug!("visit_path_list_item: st={:?}", self.st); - SawPathListItem.hash(self.st); - self.hash_discriminant(&item.node); - hash_span!(self, item.span); - visit::walk_path_list_item(self, prefix, item) - } - fn visit_path_segment(&mut self, path_span: Span, path_segment: &'tcx PathSegment) { debug!("visit_path_segment: st={:?}", self.st); SawPathSegment.hash(self.st); diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 7be591293c9..d91327bc86b 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -704,14 +704,6 @@ impl LateLintPass for Deprecated { &mut |id, sp, stab, depr| self.lint(cx, id, sp, &stab, &depr)); } - fn check_path_list_item(&mut self, cx: &LateContext, item: &hir::PathListItem) { - stability::check_path_list_item(cx.tcx, - item, - &mut |id, sp, stab, depr| { - self.lint(cx, id, sp, &stab, &depr) - }); - } - fn check_pat(&mut self, cx: &LateContext, pat: &hir::Pat) { stability::check_pat(cx.tcx, pat, diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 1a3ea5db871..0b92107c817 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -111,6 +111,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { add_early_builtin!(sess, UnusedParens, + UnusedImportBraces, ); add_early_builtin_with_new!(sess, @@ -129,7 +130,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { NonCamelCaseTypes, NonSnakeCase, NonUpperCaseGlobals, - UnusedImportBraces, NonShorthandFieldPatterns, UnusedUnsafe, UnsafeCode, diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index d0ad682fb58..324cbd17ab3 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -406,11 +406,11 @@ impl LintPass for UnusedImportBraces { } } -impl LateLintPass for UnusedImportBraces { - fn check_item(&mut self, cx: &LateContext, item: &hir::Item) { - if let hir::ItemUse(ref view_path) = item.node { - if let hir::ViewPathList(_, ref items) = view_path.node { - if items.len() == 1 && items[0].node.name != keywords::SelfValue.name() { +impl EarlyLintPass for UnusedImportBraces { + fn check_item(&mut self, cx: &EarlyContext, item: &ast::Item) { + if let ast::ItemKind::Use(ref view_path) = item.node { + if let ast::ViewPathList(_, ref items) = view_path.node { + if items.len() == 1 && items[0].node.name.name != keywords::SelfValue.name() { let msg = format!("braces around {} is unnecessary", items[0].node.name); cx.span_lint(UNUSED_IMPORT_BRACES, item.span, &msg); } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 665f3de0a3b..8f3e8a48b1a 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -729,7 +729,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { EntryKind::Trait(self.lazy(&data)) } hir::ItemExternCrate(_) | - hir::ItemUse(_) => bug!("cannot encode info for item {:?}", item), + hir::ItemUse(..) => bug!("cannot encode info for item {:?}", item), }; Entry { @@ -982,7 +982,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> { let def_id = self.index.tcx.map.local_def_id(item.id); match item.node { hir::ItemExternCrate(_) | - hir::ItemUse(_) => (), // ignore these + hir::ItemUse(..) => (), // ignore these _ => self.index.record(def_id, EncodeContext::encode_info_for_item, (def_id, item)), } self.index.encode_addl_info_for_item(item); diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs index 9028821ef11..ba236ea93a4 100644 --- a/src/librustc_passes/hir_stats.rs +++ b/src/librustc_passes/hir_stats.rs @@ -226,12 +226,6 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { self.record("Path", Id::None, path); hir_visit::walk_path(self, path) } - fn visit_path_list_item(&mut self, - prefix: &'v hir::Path, - item: &'v hir::PathListItem) { - self.record("PathListItem", Id::Node(item.node.id), item); - hir_visit::walk_path_list_item(self, prefix, item) - } fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v hir::PathSegment) { diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index b4a10c52270..0034a85f8e2 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -45,17 +45,8 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for UnusedTraitImportVisitor<'a, 'tcx> { if item.vis == hir::Public || item.span == DUMMY_SP { return; } - if let hir::ItemUse(ref path) = item.node { - match path.node { - hir::ViewPathSimple(..) | hir::ViewPathGlob(..) => { - self.check_import(item.id, path.span); - } - hir::ViewPathList(_, ref path_list) => { - for path_item in path_list { - self.check_import(path_item.node.id, path_item.span); - } - } - } + if let hir::ItemUse(ref path, _) = item.node { + self.check_import(item.id, path.span); } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index ca5208b7a03..b83e453b2de 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -696,7 +696,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { debug!("convert: item {} with id {}", it.name, it.id); match it.node { // These don't define types. - hir::ItemExternCrate(_) | hir::ItemUse(_) | hir::ItemMod(_) => { + hir::ItemExternCrate(_) | hir::ItemUse(..) | hir::ItemMod(_) => { } hir::ItemForeignMod(ref foreign_mod) => { for item in &foreign_mod.items { diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 8a0c1c68322..686d1a4a771 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -104,7 +104,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> { } hir::ItemExternCrate(_) | - hir::ItemUse(_) | + hir::ItemUse(..) | hir::ItemStatic(..) | hir::ItemConst(..) | hir::ItemFn(..) | diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs index 0a3238480d9..851cfcd8723 100644 --- a/src/librustc_typeck/variance/terms.rs +++ b/src/librustc_typeck/variance/terms.rs @@ -246,7 +246,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> { } hir::ItemExternCrate(_) | - hir::ItemUse(_) | + hir::ItemUse(..) | hir::ItemDefaultImpl(..) | hir::ItemImpl(..) | hir::ItemStatic(..) | diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index aff38404349..5e1b12e80d4 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2589,47 +2589,19 @@ impl Clean> for doctree::Import { None => false, } }); - let (mut ret, inner) = match self.node { - hir::ViewPathGlob(ref p) => { - (vec![], Import::Glob(resolve_use_source(cx, p.clean(cx), self.id))) - } - hir::ViewPathList(ref p, ref list) => { - // Attempt to inline all reexported items, but be sure - // to keep any non-inlineable reexports so they can be - // listed in the documentation. - let mut ret = vec![]; - let remaining = if !denied { - let mut remaining = vec![]; - for path in list { - match inline::try_inline(cx, path.node.id, path.node.rename) { - Some(items) => { - ret.extend(items); - } - None => { - remaining.push(path.clean(cx)); - } - } - } - remaining - } else { - list.clean(cx) - }; - if remaining.is_empty() { - return ret; + let path = self.path.clean(cx); + let inner = if self.glob { + Import::Glob(resolve_use_source(cx, path, self.id)) + } else { + let name = self.name; + if !denied { + if let Some(items) = inline::try_inline(cx, self.id, Some(name)) { + return items; } - (ret, Import::List(resolve_use_source(cx, p.clean(cx), self.id), remaining)) - } - hir::ViewPathSimple(name, ref p) => { - if !denied { - if let Some(items) = inline::try_inline(cx, self.id, Some(name)) { - return items; - } - } - (vec![], Import::Simple(name.clean(cx), - resolve_use_source(cx, p.clean(cx), self.id))) } + Import::Simple(name.clean(cx), resolve_use_source(cx, path, self.id)) }; - ret.push(Item { + vec![Item { name: None, attrs: self.attrs.clean(cx), source: self.whence.clean(cx), @@ -2638,8 +2610,7 @@ impl Clean> for doctree::Import { stability: None, deprecation: None, inner: ImportItem(inner) - }); - ret + }] } } @@ -2648,9 +2619,7 @@ pub enum Import { // use source as str; Simple(String, ImportSource), // use source::*; - Glob(ImportSource), - // use source::{a, b, c}; - List(ImportSource, Vec), + Glob(ImportSource) } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] @@ -2659,23 +2628,6 @@ pub struct ImportSource { pub did: Option, } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] -pub struct ViewListIdent { - pub name: String, - pub rename: Option, - pub source: Option, -} - -impl Clean for hir::PathListItem { - fn clean(&self, cx: &DocContext) -> ViewListIdent { - ViewListIdent { - name: self.node.name.clean(cx), - rename: self.node.rename.map(|r| r.clean(cx)), - source: resolve_def(cx, self.node.id) - } - } -} - impl Clean> for hir::ForeignMod { fn clean(&self, cx: &DocContext) -> Vec { let mut items = self.items.clean(cx); diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 609ae0c0e6d..21fc135eaad 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -254,10 +254,12 @@ pub struct ExternCrate { } pub struct Import { + pub name: Name, pub id: NodeId, pub vis: hir::Visibility, pub attrs: hir::HirVec, - pub node: hir::ViewPath_, + pub path: hir::Path, + pub glob: bool, pub whence: Span, } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index eef530081ab..aed41916f5c 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -969,16 +969,6 @@ impl fmt::Display for clean::Import { clean::Import::Glob(ref src) => { write!(f, "use {}::*;", *src) } - clean::Import::List(ref src, ref names) => { - write!(f, "use {}::{{", *src)?; - for (i, n) in names.iter().enumerate() { - if i > 0 { - write!(f, ", ")?; - } - write!(f, "{}", *n)?; - } - write!(f, "}};") - } } } } @@ -1000,23 +990,6 @@ impl fmt::Display for clean::ImportSource { } } -impl fmt::Display for clean::ViewListIdent { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self.source { - Some(did) => { - let path = clean::Path::singleton(self.name.clone()); - resolved_path(f, did, &path, false)?; - } - _ => write!(f, "{}", self.name)?, - } - - if let Some(ref name) = self.rename { - write!(f, " as {}", name)?; - } - Ok(()) - } -} - impl fmt::Display for clean::TypeBinding { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if f.alternate() { diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 8ed0567d820..fcf747a7c17 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -225,42 +225,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { om } - fn visit_view_path(&mut self, path: hir::ViewPath_, - om: &mut Module, - id: ast::NodeId, - please_inline: bool) -> Option { - match path { - hir::ViewPathSimple(dst, base) => { - if self.maybe_inline_local(id, Some(dst), false, om, please_inline) { - None - } else { - Some(hir::ViewPathSimple(dst, base)) - } - } - hir::ViewPathList(p, paths) => { - let mine = paths.into_iter().filter(|path| { - !self.maybe_inline_local(path.node.id, path.node.rename, - false, om, please_inline) - }).collect::>(); - - if mine.is_empty() { - None - } else { - Some(hir::ViewPathList(p, mine)) - } - } - - hir::ViewPathGlob(base) => { - if self.maybe_inline_local(id, None, true, om, please_inline) { - None - } else { - Some(hir::ViewPathGlob(base)) - } - } - } - - } - /// Tries to resolve the target of a `pub use` statement and inlines the /// target if it is defined locally and would not be documented otherwise, /// or when it is specifically requested with `please_inline`. @@ -388,11 +352,13 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { whence: item.span, }) } - hir::ItemUse(ref vpath) => { - let node = vpath.node.clone(); + hir::ItemUse(_, hir::UseKind::ListStem) => {} + hir::ItemUse(ref path, kind) => { + let is_glob = kind == hir::UseKind::Glob; + // If there was a private module in the current path then don't bother inlining // anything as it will probably be stripped anyway. - let node = if item.vis == hir::Public && self.inside_public_path { + if item.vis == hir::Public && self.inside_public_path { let please_inline = item.attrs.iter().any(|item| { match item.meta_item_list() { Some(list) if item.check_name("doc") => { @@ -401,18 +367,19 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { _ => false, } }); - match self.visit_view_path(node, om, item.id, please_inline) { - None => return, - Some(p) => p + let name = if is_glob { None } else { Some(name) }; + if self.maybe_inline_local(item.id, name, is_glob, om, please_inline) { + return; } - } else { - node - }; + } + om.imports.push(Import { + name: item.name, id: item.id, vis: item.vis.clone(), attrs: item.attrs.clone(), - node: node, + path: (**path).clone(), + glob: is_glob, whence: item.span, }); } diff --git a/src/test/rustdoc/viewpath-rename.rs b/src/test/rustdoc/viewpath-rename.rs index ccc0acab7f3..4b6843d33f7 100644 --- a/src/test/rustdoc/viewpath-rename.rs +++ b/src/test/rustdoc/viewpath-rename.rs @@ -21,8 +21,11 @@ pub enum Maybe
{ // @has foo/prelude/index.html pub mod prelude { - // @has foo/prelude/index.html '//code' 'pub use io::{self as FooIo, Reader as FooReader}' + // @has foo/prelude/index.html '//code' 'pub use io as FooIo;' + // @has foo/prelude/index.html '//code' 'pub use io::Reader as FooReader;' #[doc(no_inline)] pub use io::{self as FooIo, Reader as FooReader}; - // @has foo/prelude/index.html '//code' 'pub use Maybe::{self, Just as MaybeJust, Nothing}' + // @has foo/prelude/index.html '//code' 'pub use Maybe;' + // @has foo/prelude/index.html '//code' 'pub use Maybe::Just as MaybeJust;' + // @has foo/prelude/index.html '//code' 'pub use Maybe::Nothing;' #[doc(no_inline)] pub use Maybe::{self, Just as MaybeJust, Nothing}; } diff --git a/src/test/rustdoc/viewpath-self.rs b/src/test/rustdoc/viewpath-self.rs index 65a981353f0..000960ad972 100644 --- a/src/test/rustdoc/viewpath-self.rs +++ b/src/test/rustdoc/viewpath-self.rs @@ -21,8 +21,11 @@ pub enum Maybe { // @has foo/prelude/index.html pub mod prelude { - // @has foo/prelude/index.html '//code' 'pub use io::{self, Reader}' + // @has foo/prelude/index.html '//code' 'pub use io;' + // @has foo/prelude/index.html '//code' 'pub use io::Reader;' #[doc(no_inline)] pub use io::{self, Reader}; - // @has foo/prelude/index.html '//code' 'pub use Maybe::{self, Just, Nothing}' + // @has foo/prelude/index.html '//code' 'pub use Maybe;' + // @has foo/prelude/index.html '//code' 'pub use Maybe::Just;' + // @has foo/prelude/index.html '//code' 'pub use Maybe::Nothing;' #[doc(no_inline)] pub use Maybe::{self, Just, Nothing}; } From 962633cdbbe2ce87c1311edbaa0d4e0aca022b6d Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Fri, 25 Nov 2016 13:21:19 +0200 Subject: [PATCH 084/293] rustc: embed path resolutions into the HIR instead of keeping DefMap. --- src/librustc/cfg/construct.rs | 27 +- src/librustc/hir/def.rs | 8 - src/librustc/hir/intravisit.rs | 22 +- src/librustc/hir/lowering.rs | 260 ++++++++-------- src/librustc/hir/map/def_collector.rs | 2 +- src/librustc/hir/map/mod.rs | 2 +- src/librustc/hir/mod.rs | 45 +-- src/librustc/hir/pat_util.rs | 277 +++++++++--------- src/librustc/hir/print.rs | 16 +- src/librustc/infer/error_reporting.rs | 3 +- src/librustc/middle/astconv_util.rs | 2 +- src/librustc/middle/dead.rs | 33 +-- src/librustc/middle/effect.rs | 4 +- src/librustc/middle/expr_use_visitor.rs | 30 +- src/librustc/middle/intrinsicck.rs | 9 +- src/librustc/middle/liveness.rs | 59 ++-- src/librustc/middle/mem_categorization.rs | 37 ++- src/librustc/middle/reachable.rs | 63 ++-- src/librustc/middle/resolve_lifetime.rs | 12 +- src/librustc/middle/stability.rs | 25 +- src/librustc/ty/context.rs | 23 +- src/librustc/ty/mod.rs | 26 +- src/librustc/ty/util.rs | 9 - .../borrowck/gather_loans/gather_moves.rs | 2 +- src/librustc_const_eval/_match.rs | 11 +- src/librustc_const_eval/check_match.rs | 50 ++-- src/librustc_const_eval/eval.rs | 74 ++--- src/librustc_const_eval/pattern.rs | 32 +- src/librustc_driver/driver.rs | 9 +- src/librustc_driver/test.rs | 3 +- .../calculate_svh/svh_visitor.rs | 20 +- src/librustc_lint/bad_style.rs | 15 +- src/librustc_lint/builtin.rs | 37 ++- src/librustc_lint/unused.rs | 3 +- src/librustc_metadata/astencode.rs | 11 +- src/librustc_metadata/encoder.rs | 2 +- src/librustc_mir/build/mod.rs | 4 +- src/librustc_mir/hair/cx/expr.rs | 46 +-- src/librustc_passes/consts.rs | 20 +- src/librustc_passes/loops.rs | 19 +- src/librustc_passes/static_recursion.rs | 19 +- src/librustc_privacy/lib.rs | 78 +++-- src/librustc_resolve/lib.rs | 7 +- src/librustc_save_analysis/dump_visitor.rs | 20 +- src/librustc_save_analysis/lib.rs | 50 +++- src/librustc_typeck/astconv.rs | 93 +++--- src/librustc_typeck/check/_match.rs | 18 +- src/librustc_typeck/check/callee.rs | 14 +- src/librustc_typeck/check/mod.rs | 148 ++++------ src/librustc_typeck/check/regionck.rs | 3 +- src/librustc_typeck/collect.rs | 10 +- src/librustdoc/clean/inline.rs | 19 +- src/librustdoc/clean/mod.rs | 45 +-- src/librustdoc/visit_ast.rs | 22 +- src/test/compile-fail/issue-3521.rs | 2 +- 55 files changed, 951 insertions(+), 949 deletions(-) diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 609d492a93a..f21d98a0fc7 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -10,8 +10,6 @@ use rustc_data_structures::graph; use cfg::*; -use hir::def::Def; -use hir::pat_util; use ty::{self, TyCtxt}; use syntax::ast; use syntax::ptr::P; @@ -284,7 +282,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { hir::ExprBreak(label, ref opt_expr) => { let v = self.opt_expr(opt_expr, pred); - let loop_scope = self.find_scope(expr, label.map(|l| l.node)); + let loop_scope = self.find_scope(expr, label); let b = self.add_ast_node(expr.id, &[v]); self.add_exiting_edge(expr, b, loop_scope, loop_scope.break_index); @@ -292,7 +290,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { } hir::ExprAgain(label) => { - let loop_scope = self.find_scope(expr, label.map(|l| l.node)); + let loop_scope = self.find_scope(expr, label); let a = self.add_ast_node(expr.id, &[pred]); self.add_exiting_edge(expr, a, loop_scope, loop_scope.continue_index); @@ -457,7 +455,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { // Visit the guard expression let guard_exit = self.expr(&guard, guard_start); - let this_has_bindings = pat_util::pat_contains_bindings_or_wild(&pat); + let this_has_bindings = pat.contains_bindings_or_wild(); // If both this pattern and the previous pattern // were free of bindings, they must consist only @@ -570,23 +568,16 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { fn find_scope(&self, expr: &hir::Expr, - label: Option) -> LoopScope { - if label.is_none() { - return *self.loop_scopes.last().unwrap(); - } - - match self.tcx.expect_def(expr.id) { - Def::Label(loop_id) => { + label: Option) -> LoopScope { + match label { + None => *self.loop_scopes.last().unwrap(), + Some(label) => { for l in &self.loop_scopes { - if l.loop_id == loop_id { + if l.loop_id == label.loop_id { return *l; } } - span_bug!(expr.span, "no loop scope for id {}", loop_id); - } - - r => { - span_bug!(expr.span, "bad entry `{:?}` in def_map for label", r); + span_bug!(expr.span, "no loop scope for id {}", label.loop_id); } } } diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index feefc43f401..b6fce2d6ca0 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -83,14 +83,6 @@ impl PathResolution { PathResolution { base_def: def, depth: 0 } } - /// Get the definition, if fully resolved, otherwise panic. - pub fn full_def(&self) -> Def { - if self.depth != 0 { - bug!("path not fully resolved: {:?}", self); - } - self.base_def - } - pub fn kind_name(&self) -> &'static str { if self.depth != 0 { "associated item" diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 3de788b8c1a..94da10d33f8 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -38,6 +38,7 @@ use syntax::ast::{NodeId, CRATE_NODE_ID, Name, Attribute}; use syntax::codemap::Spanned; use syntax_pos::Span; use hir::*; +use hir::def::Def; use hir::map::Map; use super::itemlikevisit::DeepVisitor; @@ -155,6 +156,9 @@ pub trait Visitor<'v> : Sized { fn visit_id(&mut self, _node_id: NodeId) { // Nothing to do. } + fn visit_def_mention(&mut self, _def: Def) { + // Nothing to do. + } fn visit_name(&mut self, _span: Span, _name: Name) { // Nothing to do. } @@ -507,6 +511,7 @@ pub fn walk_qpath<'v, V: Visitor<'v>>(visitor: &mut V, qpath: &'v QPath, id: Nod } pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path) { + visitor.visit_def_mention(path.def); for segment in &path.segments { visitor.visit_path_segment(path.span, segment); } @@ -566,7 +571,8 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { PatKind::Ref(ref subpattern, _) => { visitor.visit_pat(subpattern) } - PatKind::Binding(_, ref pth1, ref optional_subpattern) => { + PatKind::Binding(_, def_id, ref pth1, ref optional_subpattern) => { + visitor.visit_def_mention(Def::Local(def_id)); visitor.visit_name(pth1.span, pth1.node); walk_list!(visitor, visit_pat, optional_subpattern); } @@ -907,12 +913,18 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { ExprPath(ref qpath) => { visitor.visit_qpath(qpath, expression.id, expression.span); } - ExprBreak(ref opt_sp_name, ref opt_expr) => { - walk_opt_sp_name(visitor, opt_sp_name); + ExprBreak(None, ref opt_expr) => { walk_list!(visitor, visit_expr, opt_expr); } - ExprAgain(ref opt_sp_name) => { - walk_opt_sp_name(visitor, opt_sp_name); + ExprBreak(Some(label), ref opt_expr) => { + visitor.visit_def_mention(Def::Label(label.loop_id)); + visitor.visit_name(label.span, label.name); + walk_list!(visitor, visit_expr, opt_expr); + } + ExprAgain(None) => {} + ExprAgain(Some(label)) => { + visitor.visit_def_mention(Def::Label(label.loop_id)); + visitor.visit_name(label.span, label.name); } ExprRet(ref optional_expression) => { walk_list!(visitor, visit_expr, optional_expression); diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index af0448cc277..aea05357a84 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -77,7 +77,7 @@ pub struct LoweringContext<'a> { pub trait Resolver { // Resolve a global hir path generated by the lowerer when expanding `for`, `if let`, etc. - fn resolve_generated_global_path(&mut self, path: &hir::Path, is_value: bool) -> Def; + fn resolve_generated_global_path(&mut self, path: &mut hir::Path, is_value: bool); // Obtain the resolution for a node id fn get_resolution(&mut self, id: NodeId) -> Option; @@ -154,6 +154,15 @@ impl<'a> LoweringContext<'a> { self.sess.next_node_id() } + fn expect_full_def(&mut self, id: NodeId) -> Def { + self.resolver.get_resolution(id).map_or(Def::Err, |pr| { + if pr.depth != 0 { + bug!("path not fully resolved: {:?}", pr); + } + pr.base_def + }) + } + fn diagnostic(&self) -> &errors::Handler { self.sess.diagnostic() } @@ -181,6 +190,19 @@ impl<'a> LoweringContext<'a> { o_id.map(|sp_ident| respan(sp_ident.span, sp_ident.node.name)) } + fn lower_label(&mut self, id: NodeId, label: Option>) -> Option { + label.map(|sp_ident| { + hir::Label { + span: sp_ident.span, + name: sp_ident.node.name, + loop_id: match self.expect_full_def(id) { + Def::Label(loop_id) => loop_id, + _ => DUMMY_NODE_ID + } + } + }) + } + fn lower_attrs(&mut self, attrs: &Vec) -> hir::HirVec { attrs.clone().into() } @@ -286,6 +308,7 @@ impl<'a> LoweringContext<'a> { let proj_start = p.segments.len() - resolution.depth; let path = P(hir::Path { global: p.global, + def: resolution.base_def, segments: p.segments[..proj_start].iter().enumerate().map(|(i, segment)| { let param_mode = match (qself_position, param_mode) { (Some(j), ParamMode::Optional) if i < j => { @@ -353,12 +376,14 @@ impl<'a> LoweringContext<'a> { } fn lower_path_extra(&mut self, + id: NodeId, p: &Path, name: Option, param_mode: ParamMode) -> hir::Path { hir::Path { global: p.global, + def: self.expect_full_def(id), segments: p.segments.iter().map(|segment| { self.lower_path_segment(segment, param_mode) }).chain(name.map(|name| { @@ -372,10 +397,11 @@ impl<'a> LoweringContext<'a> { } fn lower_path(&mut self, + id: NodeId, p: &Path, param_mode: ParamMode) -> hir::Path { - self.lower_path_extra(p, None, param_mode) + self.lower_path_extra(id, p, None, param_mode) } fn lower_path_segment(&mut self, @@ -569,7 +595,7 @@ impl<'a> LoweringContext<'a> { span}) => { hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { id: id, - path: self.lower_path(path, ParamMode::Explicit), + path: self.lower_path(id, path, ParamMode::Explicit), ty: self.lower_ty(ty), span: span, }) @@ -599,7 +625,7 @@ impl<'a> LoweringContext<'a> { fn lower_trait_ref(&mut self, p: &TraitRef) -> hir::TraitRef { hir::TraitRef { - path: self.lower_path(&p.path, ParamMode::Explicit), + path: self.lower_path(p.ref_id, &p.path, ParamMode::Explicit), ref_id: p.ref_id, } } @@ -665,6 +691,7 @@ impl<'a> LoweringContext<'a> { } fn lower_item_kind(&mut self, + id: NodeId, name: &mut Name, attrs: &hir::HirVec, vis: &mut hir::Visibility, @@ -690,7 +717,7 @@ impl<'a> LoweringContext<'a> { Some(ident.name) }; - let mut path = self.lower_path_extra(path, suffix, + let mut path = self.lower_path_extra(import.id, path, suffix, ParamMode::Explicit); path.span = span; self.items.insert(import.id, hir::Item { @@ -705,7 +732,7 @@ impl<'a> LoweringContext<'a> { path } }; - let path = P(self.lower_path(path, ParamMode::Explicit)); + let path = P(self.lower_path(id, path, ParamMode::Explicit)); let kind = match view_path.node { ViewPathSimple(ident, _) => { *name = ident.name; @@ -901,7 +928,7 @@ impl<'a> LoweringContext<'a> { let attrs = self.lower_attrs(&i.attrs); let mut vis = self.lower_visibility(&i.vis); let node = self.with_parent_def(i.id, |this| { - this.lower_item_kind(&mut name, &attrs, &mut vis, &i.node) + this.lower_item_kind(i.id, &mut name, &attrs, &mut vis, &i.node) }); hir::Item { @@ -1012,14 +1039,24 @@ impl<'a> LoweringContext<'a> { self.with_parent_def(p.id, |this| { match this.resolver.get_resolution(p.id).map(|d| d.base_def) { // `None` can occur in body-less function signatures - None | Some(Def::Local(..)) => { + def @ None | def @ Some(Def::Local(_)) => { + let def_id = def.map(|d| d.def_id()).unwrap_or_else(|| { + this.resolver.definitions().local_def_id(p.id) + }); hir::PatKind::Binding(this.lower_binding_mode(binding_mode), + def_id, respan(pth1.span, pth1.node.name), sub.as_ref().map(|x| this.lower_pat(x))) } - _ => { - let path = hir::Path::from_name(pth1.span, pth1.node.name); - hir::PatKind::Path(hir::QPath::Resolved(None, P(path))) + Some(def) => { + hir::PatKind::Path(hir::QPath::Resolved(None, P(hir::Path { + span: pth1.span, + global: false, + def: def, + segments: hir_vec![ + hir::PathSegment::from_name(pth1.node.name) + ], + }))) } } }) @@ -1120,8 +1157,7 @@ impl<'a> LoweringContext<'a> { let inplace_finalize = ["ops", "InPlace", "finalize"]; let make_call = |this: &mut LoweringContext, p, args| { - let path = this.std_path(e.span, p); - let path = this.expr_path(path, ThinVec::new()); + let path = this.expr_std_path(e.span, p, ThinVec::new()); P(this.expr_call(e.span, path, args)) }; @@ -1315,13 +1351,12 @@ impl<'a> LoweringContext<'a> { ast_expr: &Expr, path: &[&str], fields: &[(&str, &P)]) -> hir::Expr { - let struct_path = this.std_path(ast_expr.span, - &iter::once(&"ops").chain(path) - .map(|s| *s) - .collect::>()); + let struct_path = &iter::once(&"ops").chain(path).map(|s| *s) + .collect::>(); let hir_expr = if fields.len() == 0 { - this.expr_path(struct_path, ast_expr.attrs.clone()) + this.expr_std_path(ast_expr.span, struct_path, + ast_expr.attrs.clone()) } else { let fields = fields.into_iter().map(|&(s, e)| { let expr = P(this.lower_expr(&e)); @@ -1334,7 +1369,7 @@ impl<'a> LoweringContext<'a> { }).collect(); let attrs = ast_expr.attrs.clone(); - this.expr_struct(ast_expr.span, struct_path, fields, None, attrs) + this.expr_std_struct(ast_expr.span, struct_path, fields, None, attrs) }; this.signal_block_expr(hir_vec![], @@ -1378,10 +1413,10 @@ impl<'a> LoweringContext<'a> { hir::ExprPath(self.lower_qpath(e.id, qself, path, ParamMode::Optional)) } ExprKind::Break(opt_ident, ref opt_expr) => { - hir::ExprBreak(self.lower_opt_sp_ident(opt_ident), + hir::ExprBreak(self.lower_label(e.id, opt_ident), opt_expr.as_ref().map(|x| P(self.lower_expr(x)))) } - ExprKind::Continue(opt_ident) => hir::ExprAgain(self.lower_opt_sp_ident(opt_ident)), + ExprKind::Continue(opt_ident) => hir::ExprAgain(self.lower_label(e.id, opt_ident)), ExprKind::Ret(ref e) => hir::ExprRet(e.as_ref().map(|x| P(self.lower_expr(x)))), ExprKind::InlineAsm(ref asm) => { let hir_asm = hir::InlineAsm { @@ -1608,10 +1643,10 @@ impl<'a> LoweringContext<'a> { // `match ::std::iter::Iterator::next(&mut iter) { ... }` let match_expr = { - let next_path = self.std_path(e.span, &["iter", "Iterator", "next"]); let iter = P(self.expr_ident(e.span, iter, iter_pat.id)); let ref_mut_iter = self.expr_mut_addr_of(e.span, iter); - let next_path = self.expr_path(next_path, ThinVec::new()); + let next_path = &["iter", "Iterator", "next"]; + let next_path = self.expr_std_path(e.span, next_path, ThinVec::new()); let next_expr = P(self.expr_call(e.span, next_path, hir_vec![ref_mut_iter])); let arms = hir_vec![pat_arm, break_arm]; @@ -1638,10 +1673,8 @@ impl<'a> LoweringContext<'a> { // `match ::std::iter::IntoIterator::into_iter() { ... }` let into_iter_expr = { - let into_iter_path = self.std_path(e.span, - &["iter", "IntoIterator", "into_iter"]); - - let into_iter = self.expr_path(into_iter_path, ThinVec::new()); + let into_iter_path = &["iter", "IntoIterator", "into_iter"]; + let into_iter = self.expr_std_path(e.span, into_iter_path, ThinVec::new()); P(self.expr_call(e.span, into_iter, hir_vec![head])) }; @@ -1684,8 +1717,8 @@ impl<'a> LoweringContext<'a> { hir::PopUnstableBlock, ThinVec::new()); - let path = self.std_path(e.span, &["ops", "Carrier", "translate"]); - let path = self.expr_path(path, ThinVec::new()); + let path = &["ops", "Carrier", "translate"]; + let path = self.expr_std_path(e.span,path, ThinVec::new()); let call = P(self.expr_call(e.span, path, hir_vec![sub_expr])); P(self.signal_block_expr(hir_vec![], @@ -1710,15 +1743,15 @@ impl<'a> LoweringContext<'a> { let err_ident = self.str_to_ident("err"); let err_local = self.pat_ident(e.span, err_ident); let from_expr = { - let path = self.std_path(e.span, &["convert", "From", "from"]); - let from = self.expr_path(path, ThinVec::new()); + let path = &["convert", "From", "from"]; + let from = self.expr_std_path(e.span, path, ThinVec::new()); let err_expr = self.expr_ident(e.span, err_ident, err_local.id); self.expr_call(e.span, from, hir_vec![err_expr]) }; let from_err_expr = { - let path = self.std_path(e.span, &["ops", "Carrier", "from_error"]); - let from_err = self.expr_path(path, ThinVec::new()); + let path = &["ops", "Carrier", "from_error"]; + let from_err = self.expr_std_path(e.span, path, ThinVec::new()); P(self.expr_call(e.span, from_err, hir_vec![from_expr])) }; @@ -1794,7 +1827,7 @@ impl<'a> LoweringContext<'a> { Visibility::Crate(_) => hir::Visibility::Crate, Visibility::Restricted { ref path, id } => { hir::Visibility::Restricted { - path: P(self.lower_path(path, ParamMode::Explicit)), + path: P(self.lower_path(id, path, ParamMode::Explicit)), id: id } } @@ -1880,14 +1913,18 @@ impl<'a> LoweringContext<'a> { } fn expr_ident(&mut self, span: Span, id: Name, binding: NodeId) -> hir::Expr { - let path = self.path_ident(span, id); - let expr_path = hir::ExprPath(hir::QPath::Resolved(None, P(path))); - let expr = self.expr(span, expr_path, ThinVec::new()); - let def = { let defs = self.resolver.definitions(); Def::Local(defs.local_def_id(binding)) }; + + let expr_path = hir::ExprPath(hir::QPath::Resolved(None, P(hir::Path { + span: span, + global: false, + def: def, + segments: hir_vec![hir::PathSegment::from_name(id)], + }))); + let expr = self.expr(span, expr_path, ThinVec::new()); self.resolver.record_resolution(expr.id, def); expr @@ -1897,9 +1934,14 @@ impl<'a> LoweringContext<'a> { self.expr(span, hir::ExprAddrOf(hir::MutMutable, e), ThinVec::new()) } - fn expr_path(&mut self, path: hir::Path, attrs: ThinVec) -> P { - let def = self.resolver.resolve_generated_global_path(&path, true); - let expr = self.expr(path.span, hir::ExprPath(hir::QPath::Resolved(None, P(path))), attrs); + fn expr_std_path(&mut self, + span: Span, + components: &[&str], + attrs: ThinVec) + -> P { + let path = self.std_path(span, components, true); + let def = path.def; + let expr = self.expr(span, hir::ExprPath(hir::QPath::Resolved(None, P(path))), attrs); self.resolver.record_resolution(expr.id, def); P(expr) } @@ -1921,15 +1963,16 @@ impl<'a> LoweringContext<'a> { P(self.expr(sp, hir::ExprTup(exprs), ThinVec::new())) } - fn expr_struct(&mut self, - sp: Span, - path: hir::Path, - fields: hir::HirVec, - e: Option>, - attrs: ThinVec) -> P { - let def = self.resolver.resolve_generated_global_path(&path, false); + fn expr_std_struct(&mut self, + span: Span, + components: &[&str], + fields: hir::HirVec, + e: Option>, + attrs: ThinVec) -> P { + let path = self.std_path(span, components, false); + let def = path.def; let qpath = hir::QPath::Resolved(None, P(path)); - let expr = self.expr(sp, hir::ExprStruct(qpath, fields, e), attrs); + let expr = self.expr(span, hir::ExprStruct(qpath, fields, e), attrs); self.resolver.record_resolution(expr.id, def); P(expr) } @@ -1988,28 +2031,28 @@ impl<'a> LoweringContext<'a> { } fn pat_ok(&mut self, span: Span, pat: P) -> P { - let path = self.std_path(span, &["result", "Result", "Ok"]); - self.pat_enum(span, path, hir_vec![pat]) + self.pat_std_enum(span, &["result", "Result", "Ok"], hir_vec![pat]) } fn pat_err(&mut self, span: Span, pat: P) -> P { - let path = self.std_path(span, &["result", "Result", "Err"]); - self.pat_enum(span, path, hir_vec![pat]) + self.pat_std_enum(span, &["result", "Result", "Err"], hir_vec![pat]) } fn pat_some(&mut self, span: Span, pat: P) -> P { - let path = self.std_path(span, &["option", "Option", "Some"]); - self.pat_enum(span, path, hir_vec![pat]) + self.pat_std_enum(span, &["option", "Option", "Some"], hir_vec![pat]) } fn pat_none(&mut self, span: Span) -> P { - let path = self.std_path(span, &["option", "Option", "None"]); - self.pat_enum(span, path, hir_vec![]) + self.pat_std_enum(span, &["option", "Option", "None"], hir_vec![]) } - fn pat_enum(&mut self, span: Span, path: hir::Path, subpats: hir::HirVec>) - -> P { - let def = self.resolver.resolve_generated_global_path(&path, true); + fn pat_std_enum(&mut self, + span: Span, + components: &[&str], + subpats: hir::HirVec>) + -> P { + let path = self.std_path(span, components, true); + let def = path.def; let qpath = hir::QPath::Resolved(None, P(path)); let pt = if subpats.is_empty() { hir::PatKind::Path(qpath) @@ -2027,25 +2070,27 @@ impl<'a> LoweringContext<'a> { fn pat_ident_binding_mode(&mut self, span: Span, name: Name, bm: hir::BindingMode) -> P { - let pat_ident = hir::PatKind::Binding(bm, - Spanned { - span: span, - node: name, - }, - None); - - let pat = self.pat(span, pat_ident); - + let id = self.next_id(); let parent_def = self.parent_def; - let def = { + let def_id = { let defs = self.resolver.definitions(); let def_path_data = DefPathData::Binding(name.as_str()); - let def_index = defs.create_def_with_parent(parent_def, pat.id, def_path_data); - Def::Local(DefId::local(def_index)) + let def_index = defs.create_def_with_parent(parent_def, id, def_path_data); + DefId::local(def_index) }; - self.resolver.record_resolution(pat.id, def); + self.resolver.record_resolution(id, Def::Local(def_id)); - pat + P(hir::Pat { + id: id, + node: hir::PatKind::Binding(bm, + def_id, + Spanned { + span: span, + node: name, + }, + None), + span: span, + }) } fn pat_wild(&mut self, span: Span) -> P { @@ -2060,64 +2105,25 @@ impl<'a> LoweringContext<'a> { }) } - fn path_ident(&mut self, span: Span, id: Name) -> hir::Path { - self.path(span, vec![id]) - } + /// Given suffix ["b","c","d"], returns path `::std::b::c::d` when + /// `fld.cx.use_std`, and `::core::b::c::d` otherwise. + /// The path is also resolved according to `is_value`. + fn std_path(&mut self, span: Span, components: &[&str], is_value: bool) -> hir::Path { + let idents = self.crate_root.iter().chain(components); - fn path(&mut self, span: Span, strs: Vec) -> hir::Path { - self.path_all(span, false, strs, hir::HirVec::new(), hir::HirVec::new(), hir::HirVec::new()) - } - - fn path_global(&mut self, span: Span, strs: Vec) -> hir::Path { - self.path_all(span, true, strs, hir::HirVec::new(), hir::HirVec::new(), hir::HirVec::new()) - } - - fn path_all(&mut self, - sp: Span, - global: bool, - mut names: Vec, - lifetimes: hir::HirVec, - types: hir::HirVec>, - bindings: hir::HirVec) - -> hir::Path { - let last_identifier = names.pop().unwrap(); - let mut segments: Vec = names.into_iter().map(|name| { - hir::PathSegment { - name: name, - parameters: hir::PathParameters::none(), - } + let segments: Vec<_> = idents.map(|name| { + hir::PathSegment::from_name(Symbol::intern(name)) }).collect(); - segments.push(hir::PathSegment { - name: last_identifier, - parameters: hir::AngleBracketedParameters(hir::AngleBracketedParameterData { - lifetimes: lifetimes, - types: types, - infer_types: true, - bindings: bindings, - }), - }); - hir::Path { - span: sp, - global: global, + let mut path = hir::Path { + span: span, + global: true, + def: Def::Err, segments: segments.into(), - } - } + }; - fn std_path_components(&mut self, components: &[&str]) -> Vec { - let mut v = Vec::new(); - if let Some(s) = self.crate_root { - v.push(Symbol::intern(s)); - } - v.extend(components.iter().map(|s| Symbol::intern(s))); - return v; - } - - // Given suffix ["b","c","d"], returns path `::std::b::c::d` when - // `fld.cx.use_std`, and `::core::b::c::d` otherwise. - fn std_path(&mut self, span: Span, components: &[&str]) -> hir::Path { - let idents = self.std_path_components(components); - self.path_global(span, idents) + self.resolver.resolve_generated_global_path(&mut path, is_value); + path } fn signal_block_expr(&mut self, diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index 9d1c7d41faa..a08060e7927 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -436,7 +436,7 @@ impl<'ast> intravisit::Visitor<'ast> for DefCollector<'ast> { fn visit_pat(&mut self, pat: &'ast hir::Pat) { let parent_def = self.parent_def; - if let hir::PatKind::Binding(_, name, _) = pat.node { + if let hir::PatKind::Binding(_, _, name, _) = pat.node { let def = self.create_def(pat.id, DefPathData::Binding(name.node.as_str())); self.parent_def = Some(def); } diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index a8986530d1d..c4ed98ce6e0 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -658,7 +658,7 @@ impl<'ast> Map<'ast> { NodeVariant(v) => v.node.name, NodeLifetime(lt) => lt.name, NodeTyParam(tp) => tp.name, - NodeLocal(&Pat { node: PatKind::Binding(_,l,_), .. }) => l.node, + NodeLocal(&Pat { node: PatKind::Binding(_,_,l,_), .. }) => l.node, NodeStructCtor(_) => self.name(self.get_parent(id)), _ => bug!("no name for {}", self.node_to_string(id)) } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index da759b2d4da..1e70ebf5851 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -107,6 +107,8 @@ pub struct Path { /// A `::foo` path, is relative to the crate root rather than current /// module (like paths in an import). pub global: bool, + /// The definition that the path resolved to. + pub def: Def, /// The segments in the path: the things separated by `::`. pub segments: HirVec, } @@ -123,21 +125,6 @@ impl fmt::Display for Path { } } -impl Path { - /// Convert a span and an identifier to the corresponding - /// 1-segment path. - pub fn from_name(s: Span, name: Name) -> Path { - Path { - span: s, - global: false, - segments: hir_vec![PathSegment { - name: name, - parameters: PathParameters::none() - }], - } - } -} - /// A segment of a path: an identifier, an optional lifetime, and a set of /// types. #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] @@ -153,6 +140,16 @@ pub struct PathSegment { pub parameters: PathParameters, } +impl PathSegment { + /// Convert an identifier to the corresponding segment. + pub fn from_name(name: Name) -> PathSegment { + PathSegment { + name: name, + parameters: PathParameters::none() + } + } +} + #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum PathParameters { /// The `<'a, A,B,C>` in `foo::bar::baz::<'a, A,B,C>` @@ -571,7 +568,8 @@ pub enum PatKind { Wild, /// A fresh binding `ref mut binding @ OPT_SUBPATTERN`. - Binding(BindingMode, Spanned, Option>), + /// The `DefId` is for the definition of the variable being bound. + Binding(BindingMode, DefId, Spanned, Option>), /// A struct or struct variant pattern, e.g. `Variant {x, y, ..}`. /// The `bool` is `true` in the presence of a `..`. @@ -944,9 +942,9 @@ pub enum Expr_ { /// A referencing operation (`&a` or `&mut a`) ExprAddrOf(Mutability, P), /// A `break`, with an optional label to break - ExprBreak(Option>, Option>), + ExprBreak(Option", @@ -487,14 +487,16 @@ fn primitive_link(f: &mut fmt::Formatter, prim.to_url_str())?; needs_termination = true; } - Some(&cnum) => { - let loc = match m.extern_locations[&cnum] { - (ref cname, render::Remote(ref s)) => Some((cname, s.to_string())), - (ref cname, render::Local) => { + Some(&def_id) => { + let loc = match m.extern_locations[&def_id.krate] { + (ref cname, _, render::Remote(ref s)) => { + Some((cname, s.to_string())) + } + (ref cname, _, render::Local) => { let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len()); Some((cname, repeat("../").take(len).collect::())) } - (_, render::Unknown) => None, + (.., render::Unknown) => None, }; if let Some((cname, root)) = loc { write!(f, "", diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 757db81c440..cbf93662811 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -55,7 +55,7 @@ use externalfiles::ExternalHtml; use serialize::json::{ToJson, Json, as_json}; use syntax::{abi, ast}; use syntax::feature_gate::UnstableFeatures; -use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, LOCAL_CRATE}; +use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId}; use rustc::middle::privacy::AccessLevels; use rustc::middle::stability; use rustc::hir; @@ -241,10 +241,10 @@ pub struct Cache { pub implementors: FxHashMap>, /// Cache of where external crate documentation can be found. - pub extern_locations: FxHashMap, + pub extern_locations: FxHashMap, /// Cache of where documentation for primitives can be found. - pub primitive_locations: FxHashMap, + pub primitive_locations: FxHashMap, // Note that external items for which `doc(hidden)` applies to are shown as // non-reachable while local items aren't. This is because we're reusing @@ -523,8 +523,13 @@ pub fn run(mut krate: clean::Crate, // Cache where all our extern crates are located for &(n, ref e) in &krate.externs { - cache.extern_locations.insert(n, (e.name.clone(), + let src_root = match Path::new(&e.src).parent() { + Some(p) => p.to_path_buf(), + None => PathBuf::new(), + }; + cache.extern_locations.insert(n, (e.name.clone(), src_root, extern_location(e, &cx.dst))); + let did = DefId { krate: n, index: CRATE_DEF_INDEX }; cache.external_paths.insert(did, (vec![e.name.to_string()], ItemType::Module)); } @@ -533,13 +538,13 @@ pub fn run(mut krate: clean::Crate, // // Favor linking to as local extern as possible, so iterate all crates in // reverse topological order. - for &(n, ref e) in krate.externs.iter().rev() { - for &prim in &e.primitives { - cache.primitive_locations.insert(prim, n); + for &(_, ref e) in krate.externs.iter().rev() { + for &(def_id, prim, _) in &e.primitives { + cache.primitive_locations.insert(prim, def_id); } } - for &prim in &krate.primitives { - cache.primitive_locations.insert(prim, LOCAL_CRATE); + for &(def_id, prim, _) in &krate.primitives { + cache.primitive_locations.insert(prim, def_id); } cache.stack.push(krate.name.clone()); @@ -875,6 +880,8 @@ impl<'a> DocFolder for SourceCollector<'a> { if self.scx.include_sources // skip all invalid spans && item.source.filename != "" + // skip non-local items + && item.def_id.is_local() // Macros from other libraries get special filenames which we can // safely ignore. && !(item.source.filename.starts_with("<") @@ -1127,13 +1134,15 @@ impl DocFolder for Cache { true } ref t => { - match t.primitive_type() { - Some(prim) => { - let did = DefId::local(prim.to_def_index()); + let prim_did = t.primitive_type().and_then(|t| { + self.primitive_locations.get(&t).cloned() + }); + match prim_did { + Some(did) => { self.parent_stack.push(did); true } - _ => false, + None => false, } } } @@ -1158,10 +1167,7 @@ impl DocFolder for Cache { } ref t => { t.primitive_type().and_then(|t| { - self.primitive_locations.get(&t).map(|n| { - let id = t.to_def_index(); - DefId { krate: *n, index: id } - }) + self.primitive_locations.get(&t).cloned() }) } } @@ -1439,79 +1445,50 @@ impl<'a> Item<'a> { /// If `None` is returned, then a source link couldn't be generated. This /// may happen, for example, with externally inlined items where the source /// of their crate documentation isn't known. - fn href(&self) -> Option { - let href = if self.item.source.loline == self.item.source.hiline { + fn src_href(&self) -> Option { + let mut root = self.cx.root_path(); + + let cache = cache(); + let mut path = String::new(); + let (krate, path) = if self.item.def_id.is_local() { + let path = PathBuf::from(&self.item.source.filename); + if let Some(path) = self.cx.shared.local_sources.get(&path) { + (&self.cx.shared.layout.krate, path) + } else { + return None; + } + } else { + let (krate, src_root) = match cache.extern_locations.get(&self.item.def_id.krate) { + Some(&(ref name, ref src, Local)) => (name, src), + Some(&(ref name, ref src, Remote(ref s))) => { + root = s.to_string(); + (name, src) + } + Some(&(_, _, Unknown)) | None => return None, + }; + + let file = Path::new(&self.item.source.filename); + clean_srcpath(&src_root, file, false, |component| { + path.push_str(component); + path.push('/'); + }); + let mut fname = file.file_name().expect("source has no filename") + .to_os_string(); + fname.push(".html"); + path.push_str(&fname.to_string_lossy()); + (krate, &path) + }; + + let lines = if self.item.source.loline == self.item.source.hiline { format!("{}", self.item.source.loline) } else { format!("{}-{}", self.item.source.loline, self.item.source.hiline) }; - - // First check to see if this is an imported macro source. In this case - // we need to handle it specially as cross-crate inlined macros have... - // odd locations! - let imported_macro_from = match self.item.inner { - clean::MacroItem(ref m) => m.imported_from.as_ref(), - _ => None, - }; - if let Some(krate) = imported_macro_from { - let cache = cache(); - let root = cache.extern_locations.values().find(|&&(ref n, _)| { - *krate == *n - }).map(|l| &l.1); - let root = match root { - Some(&Remote(ref s)) => s.to_string(), - Some(&Local) => self.cx.root_path(), - None | Some(&Unknown) => return None, - }; - Some(format!("{root}/{krate}/macro.{name}.html?gotomacrosrc=1", - root = root, - krate = krate, - name = self.item.name.as_ref().unwrap())) - - // If this item is part of the local crate, then we're guaranteed to - // know the span, so we plow forward and generate a proper url. The url - // has anchors for the line numbers that we're linking to. - } else if self.item.def_id.is_local() { - let path = PathBuf::from(&self.item.source.filename); - self.cx.shared.local_sources.get(&path).map(|path| { - format!("{root}src/{krate}/{path}#{href}", - root = self.cx.root_path(), - krate = self.cx.shared.layout.krate, - path = path, - href = href) - }) - // If this item is not part of the local crate, then things get a little - // trickier. We don't actually know the span of the external item, but - // we know that the documentation on the other end knows the span! - // - // In this case, we generate a link to the *documentation* for this type - // in the original crate. There's an extra URL parameter which says that - // we want to go somewhere else, and the JS on the destination page will - // pick it up and instantly redirect the browser to the source code. - // - // If we don't know where the external documentation for this crate is - // located, then we return `None`. - } else { - let cache = cache(); - let external_path = match cache.external_paths.get(&self.item.def_id) { - Some(&(ref path, _)) => path, - None => return None, - }; - let mut path = match cache.extern_locations.get(&self.item.def_id.krate) { - Some(&(_, Remote(ref s))) => s.to_string(), - Some(&(_, Local)) => self.cx.root_path(), - Some(&(_, Unknown)) => return None, - None => return None, - }; - for item in &external_path[..external_path.len() - 1] { - path.push_str(item); - path.push_str("/"); - } - Some(format!("{path}{file}?gotosrc={goto}", - path = path, - file = item_path(self.item.type_(), external_path.last().unwrap()), - goto = self.item.def_id.index.as_usize())) - } + Some(format!("{root}src/{krate}/{path}#{lines}", + root = root, + krate = krate, + path = path, + lines = lines)) } } @@ -1576,10 +1553,9 @@ impl<'a> fmt::Display for Item<'a> { // this page, and this link will be auto-clicked. The `id` attribute is // used to find the link to auto-click. if self.cx.shared.include_sources && !self.item.is_primitive() { - if let Some(l) = self.href() { - write!(fmt, "[src]", - self.item.def_id.index.as_usize(), l, "goto source code")?; + if let Some(l) = self.src_href() { + write!(fmt, "[src]", + l, "goto source code")?; } } @@ -2781,8 +2757,7 @@ fn render_deref_methods(w: &mut fmt::Formatter, cx: &Context, impl_: &Impl, render_assoc_items(w, cx, container_item, did, what) } else { if let Some(prim) = target.primitive_type() { - if let Some(c) = cache().primitive_locations.get(&prim) { - let did = DefId { krate: *c, index: prim.to_def_index() }; + if let Some(&did) = cache().primitive_locations.get(&prim) { render_assoc_items(w, cx, container_item, did, what)?; } } @@ -2796,12 +2771,11 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi write!(w, "

{}", i.inner_impl())?; write!(w, "")?; let since = i.impl_item.stability.as_ref().map(|s| &s.since[..]); - if let Some(l) = (Item { item: &i.impl_item, cx: cx }).href() { + if let Some(l) = (Item { item: &i.impl_item, cx: cx }).src_href() { write!(w, "
")?; render_stability_since_raw(w, since, outer_version)?; - write!(w, "[src]", - i.impl_item.def_id.index.as_usize(), l, "goto source code")?; + write!(w, "[src]", + l, "goto source code")?; } else { render_stability_since_raw(w, since, outer_version)?; } diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 5ffab949d01..6ea25fa1241 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -923,15 +923,6 @@ window.register_implementors(window.pending_implementors); } - // See documentation in html/render.rs for what this is doing. - var query = getQueryStringParams(); - if (query['gotosrc']) { - window.location = $('#src-' + query['gotosrc']).attr('href'); - } - if (query['gotomacrosrc']) { - window.location = $('.srclink').attr('href'); - } - function labelForToggleButton(sectionIsCollapsed) { if (sectionIsCollapsed) { // button will expand the section diff --git a/src/test/rustdoc/issue-34274.rs b/src/test/rustdoc/issue-34274.rs index 971c89b1619..12f88042161 100644 --- a/src/test/rustdoc/issue-34274.rs +++ b/src/test/rustdoc/issue-34274.rs @@ -16,5 +16,5 @@ extern crate issue_34274; -// @has foo/fn.extern_c_fn.html '//a/@href' '../issue_34274/fn.extern_c_fn.html?gotosrc=' +// @has foo/fn.extern_c_fn.html '//a/@href' '../src/issue_34274/issue-34274.rs.html#12' pub use issue_34274::extern_c_fn; diff --git a/src/test/rustdoc/src-links-external.rs b/src/test/rustdoc/src-links-external.rs index e9db4f519ed..d3307bb4d42 100644 --- a/src/test/rustdoc/src-links-external.rs +++ b/src/test/rustdoc/src-links-external.rs @@ -11,12 +11,13 @@ // aux-build:src-links-external.rs // build-aux-docs // ignore-cross-compile +// ignore-tidy-linelength #![crate_name = "foo"] extern crate src_links_external; -// @has foo/bar/index.html '//a/@href' '../src_links_external/index.html?gotosrc=' +// @has foo/bar/index.html '//a/@href' '../../src/src_links_external/src-links-external.rs.html#11' pub use src_links_external as bar; -// @has foo/bar/struct.Foo.html '//a/@href' '../src_links_external/struct.Foo.html?gotosrc=' +// @has foo/bar/struct.Foo.html '//a/@href' '../../src/src_links_external/src-links-external.rs.html#11' From 336e5dd33de28830410e0ffcda9339af619c2f9b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 29 Nov 2016 14:28:16 -0800 Subject: [PATCH 162/293] Add missing examples for IpAddr enum --- src/libstd/net/ip.rs | 88 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 7b7be6e2eee..edeea12ec00 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -79,8 +79,18 @@ pub enum Ipv6MulticastScope { impl IpAddr { /// Returns true for the special 'unspecified' address ([IPv4], [IPv6]). + /// /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_unspecified /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_unspecified + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)).is_unspecified(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)).is_unspecified(), true); + /// ``` #[stable(feature = "ip_shared", since = "1.12.0")] pub fn is_unspecified(&self) -> bool { match *self { @@ -90,8 +100,18 @@ impl IpAddr { } /// Returns true if this is a loopback address ([IPv4], [IPv6]). + /// /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_loopback /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_loopback + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).is_loopback(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1)).is_loopback(), true); + /// ``` #[stable(feature = "ip_shared", since = "1.12.0")] pub fn is_loopback(&self) -> bool { match *self { @@ -101,8 +121,23 @@ impl IpAddr { } /// Returns true if the address appears to be globally routable ([IPv4], [IPv6]). + /// /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_global /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_global + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// fn main() { + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(80, 9, 12, 3)).is_global(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1)).is_global(), + /// true); + /// } + /// ``` pub fn is_global(&self) -> bool { match *self { IpAddr::V4(ref a) => a.is_global(), @@ -111,8 +146,18 @@ impl IpAddr { } /// Returns true if this is a multicast address ([IPv4], [IPv6]). + /// /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_multicast /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_multicast + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(224, 254, 0, 0)).is_multicast(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0)).is_multicast(), true); + /// ``` #[stable(feature = "ip_shared", since = "1.12.0")] pub fn is_multicast(&self) -> bool { match *self { @@ -122,8 +167,23 @@ impl IpAddr { } /// Returns true if this address is in a range designated for documentation ([IPv4], [IPv6]). + /// /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_documentation /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_documentation + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// fn main() { + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_documentation(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)) + /// .is_documentation(), true); + /// } + /// ``` pub fn is_documentation(&self) -> bool { match *self { IpAddr::V4(ref a) => a.is_documentation(), @@ -132,6 +192,20 @@ impl IpAddr { } /// Returns true if this address is a valid IPv4 address, false if it's a valid IPv6 address. + /// + /// # Examples + /// + /// ``` + /// #![feature(ipaddr_checker)] + /// + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// fn main() { + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv4(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv4(), + /// false); + /// } + /// ``` #[unstable(feature = "ipaddr_checker", issue = "36949")] pub fn is_ipv4(&self) -> bool { match *self { @@ -141,6 +215,20 @@ impl IpAddr { } /// Returns true if this address is a valid IPv6 address, false if it's a valid IPv4 address. + /// + /// # Examples + /// + /// ``` + /// #![feature(ipaddr_checker)] + /// + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// fn main() { + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv6(), false); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv6(), + /// true); + /// } + /// ``` #[unstable(feature = "ipaddr_checker", issue = "36949")] pub fn is_ipv6(&self) -> bool { match *self { From 274777a1588660b11a278ef52366743d82eb63ab Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Tue, 29 Nov 2016 14:38:08 -0500 Subject: [PATCH 163/293] Rename 'librustc_unicode' crate to 'libstd_unicode'. Fixes #26554. --- mk/crates.mk | 14 +++++++------- mk/tests.mk | 2 +- src/Cargo.lock | 18 +++++++++--------- src/libcollections/Cargo.toml | 2 +- src/libcollections/lib.rs | 2 +- src/libcollections/str.rs | 8 ++++---- src/libcollections/string.rs | 4 ++-- src/libcollectionstest/lib.rs | 2 +- src/libcollectionstest/str.rs | 4 ++-- src/libcollectionstest/string.rs | 2 +- src/libcore/char.rs | 2 +- src/libcoretest/lib.rs | 2 +- src/librustc_errors/lib.rs | 2 +- src/librustdoc/lib.rs | 2 +- src/librustdoc/test.rs | 2 +- src/libserialize/lib.rs | 2 +- src/libstd/Cargo.toml | 2 +- src/libstd/io/mod.rs | 2 +- src/libstd/lib.rs | 4 ++-- .../Cargo.toml | 4 ++-- .../char.rs | 0 .../lib.rs | 2 +- .../tables.rs | 0 .../u_str.rs | 0 src/libsyntax/lib.rs | 2 +- src/libsyntax/parse/lexer/mod.rs | 2 +- 26 files changed, 44 insertions(+), 44 deletions(-) rename src/{librustc_unicode => libstd_unicode}/Cargo.toml (78%) rename src/{librustc_unicode => libstd_unicode}/char.rs (100%) rename src/{librustc_unicode => libstd_unicode}/lib.rs (98%) rename src/{librustc_unicode => libstd_unicode}/tables.rs (100%) rename src/{librustc_unicode => libstd_unicode}/u_str.rs (100%) diff --git a/mk/crates.mk b/mk/crates.mk index 7ae5846c54b..e871efa5b7c 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -52,7 +52,7 @@ TARGET_CRATES := libc std term \ getopts collections test rand \ compiler_builtins core alloc \ - rustc_unicode rustc_bitflags \ + std_unicode rustc_bitflags \ alloc_system alloc_jemalloc \ panic_abort panic_unwind unwind RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_driver \ @@ -69,11 +69,11 @@ DEPS_compiler_builtins := core DEPS_alloc := core libc alloc_system DEPS_alloc_system := core libc DEPS_alloc_jemalloc := core libc native:jemalloc -DEPS_collections := core alloc rustc_unicode +DEPS_collections := core alloc std_unicode DEPS_libc := core DEPS_rand := core DEPS_rustc_bitflags := core -DEPS_rustc_unicode := core +DEPS_std_unicode := core DEPS_panic_abort := libc alloc DEPS_panic_unwind := libc alloc unwind DEPS_unwind := libc @@ -85,7 +85,7 @@ RUSTFLAGS1_panic_abort := -C panic=abort RUSTFLAGS2_panic_abort := -C panic=abort RUSTFLAGS3_panic_abort := -C panic=abort -DEPS_std := core libc rand alloc collections compiler_builtins rustc_unicode \ +DEPS_std := core libc rand alloc collections compiler_builtins std_unicode \ native:backtrace \ alloc_system panic_abort panic_unwind unwind DEPS_arena := std @@ -100,7 +100,7 @@ DEPS_serialize := std log DEPS_term := std DEPS_test := std getopts term native:rust_test_helpers -DEPS_syntax := std term serialize log arena libc rustc_bitflags rustc_unicode rustc_errors syntax_pos rustc_data_structures +DEPS_syntax := std term serialize log arena libc rustc_bitflags std_unicode rustc_errors syntax_pos rustc_data_structures DEPS_syntax_ext := syntax syntax_pos rustc_errors fmt_macros proc_macro DEPS_syntax_pos := serialize DEPS_proc_macro_tokens := syntax syntax_pos log @@ -162,7 +162,7 @@ ONLY_RLIB_libc := 1 ONLY_RLIB_alloc := 1 ONLY_RLIB_rand := 1 ONLY_RLIB_collections := 1 -ONLY_RLIB_rustc_unicode := 1 +ONLY_RLIB_std_unicode := 1 ONLY_RLIB_rustc_bitflags := 1 ONLY_RLIB_alloc_system := 1 ONLY_RLIB_alloc_jemalloc := 1 @@ -173,7 +173,7 @@ ONLY_RLIB_unwind := 1 TARGET_SPECIFIC_alloc_jemalloc := 1 # Documented-by-default crates -DOC_CRATES := std alloc collections core libc rustc_unicode +DOC_CRATES := std alloc collections core libc std_unicode ifeq ($(CFG_DISABLE_JEMALLOC),) RUSTFLAGS_rustc_back := --cfg 'feature="jemalloc"' diff --git a/mk/tests.mk b/mk/tests.mk index 35ee7697a7a..345fc1679b0 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -15,7 +15,7 @@ # The names of crates that must be tested -# libcore/librustc_unicode tests are in a separate crate +# libcore/libstd_unicode tests are in a separate crate DEPS_coretest := $(eval $(call RUST_CRATE,coretest)) diff --git a/src/Cargo.lock b/src/Cargo.lock index ab1c1c453dd..5935ebc483a 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -73,7 +73,7 @@ version = "0.0.0" dependencies = [ "alloc 0.0.0", "core 0.0.0", - "rustc_unicode 0.0.0", + "std_unicode 0.0.0", ] [[package]] @@ -550,13 +550,6 @@ dependencies = [ "syntax_pos 0.0.0", ] -[[package]] -name = "rustc_unicode" -version = "0.0.0" -dependencies = [ - "core 0.0.0", -] - [[package]] name = "rustdoc" version = "0.0.0" @@ -604,7 +597,7 @@ dependencies = [ "panic_abort 0.0.0", "panic_unwind 0.0.0", "rand 0.0.0", - "rustc_unicode 0.0.0", + "std_unicode 0.0.0", "unwind 0.0.0", ] @@ -616,6 +609,13 @@ dependencies = [ "std 0.0.0", ] +[[package]] +name = "std_unicode" +version = "0.0.0" +dependencies = [ + "core 0.0.0", +] + [[package]] name = "syntax" version = "0.0.0" diff --git a/src/libcollections/Cargo.toml b/src/libcollections/Cargo.toml index 3056977d224..ab882fde9c2 100644 --- a/src/libcollections/Cargo.toml +++ b/src/libcollections/Cargo.toml @@ -10,7 +10,7 @@ path = "lib.rs" [dependencies] alloc = { path = "../liballoc" } core = { path = "../libcore" } -rustc_unicode = { path = "../librustc_unicode" } +std_unicode = { path = "../libstd_unicode" } [[test]] name = "collectionstest" diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 08288b4de8b..17248214bae 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -59,7 +59,7 @@ #![no_std] -extern crate rustc_unicode; +extern crate std_unicode; extern crate alloc; #[cfg(test)] diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 48a74bdecbb..d4be0914f15 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -24,12 +24,12 @@ use core::str::pattern::Pattern; use core::str::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; use core::mem; use core::iter::FusedIterator; -use rustc_unicode::str::{UnicodeStr, Utf16Encoder}; +use std_unicode::str::{UnicodeStr, Utf16Encoder}; use vec_deque::VecDeque; use borrow::{Borrow, ToOwned}; use string::String; -use rustc_unicode; +use std_unicode; use vec::Vec; use slice::SliceConcatExt; use boxed::Box; @@ -54,7 +54,7 @@ pub use core::str::{from_utf8, Chars, CharIndices, Bytes}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::{from_utf8_unchecked, ParseBoolError}; #[stable(feature = "rust1", since = "1.0.0")] -pub use rustc_unicode::str::SplitWhitespace; +pub use std_unicode::str::SplitWhitespace; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::pattern; @@ -1705,7 +1705,7 @@ impl str { } fn case_ignoreable_then_cased>(iter: I) -> bool { - use rustc_unicode::derived_property::{Cased, Case_Ignorable}; + use std_unicode::derived_property::{Cased, Case_Ignorable}; match iter.skip_while(|&c| Case_Ignorable(c)).next() { Some(c) => Cased(c), None => false, diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 348eb6fb5ff..a10fdde4315 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -63,8 +63,8 @@ use core::mem; use core::ops::{self, Add, AddAssign, Index, IndexMut}; use core::ptr; use core::str::pattern::Pattern; -use rustc_unicode::char::{decode_utf16, REPLACEMENT_CHARACTER}; -use rustc_unicode::str as unicode_str; +use std_unicode::char::{decode_utf16, REPLACEMENT_CHARACTER}; +use std_unicode::str as unicode_str; use borrow::{Cow, ToOwned}; use range::RangeArgument; diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs index 1e08074b14d..7d696f2aebd 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollectionstest/lib.rs @@ -32,7 +32,7 @@ extern crate collections; extern crate test; -extern crate rustc_unicode; +extern crate std_unicode; use std::hash::{Hash, Hasher}; use std::collections::hash_map::DefaultHasher; diff --git a/src/libcollectionstest/str.rs b/src/libcollectionstest/str.rs index 14a0819d381..384579ce6b8 100644 --- a/src/libcollectionstest/str.rs +++ b/src/libcollectionstest/str.rs @@ -530,7 +530,7 @@ fn from_utf8_mostly_ascii() { #[test] fn test_is_utf16() { - use rustc_unicode::str::is_utf16; + use std_unicode::str::is_utf16; macro_rules! pos { ($($e:expr),*) => { { $(assert!(is_utf16($e));)* } } @@ -1186,7 +1186,7 @@ fn test_rev_split_char_iterator_no_trailing() { #[test] fn test_utf16_code_units() { - use rustc_unicode::str::Utf16Encoder; + use std_unicode::str::Utf16Encoder; assert_eq!(Utf16Encoder::new(vec!['é', '\u{1F4A9}'].into_iter()).collect::>(), [0xE9, 0xD83D, 0xDCA9]) } diff --git a/src/libcollectionstest/string.rs b/src/libcollectionstest/string.rs index 98de33bdaa8..4935e7a9ee9 100644 --- a/src/libcollectionstest/string.rs +++ b/src/libcollectionstest/string.rs @@ -132,7 +132,7 @@ fn test_from_utf16() { let s_as_utf16 = s.encode_utf16().collect::>(); let u_as_string = String::from_utf16(&u).unwrap(); - assert!(::rustc_unicode::str::is_utf16(&u)); + assert!(::std_unicode::str::is_utf16(&u)); assert_eq!(s_as_utf16, u); assert_eq!(u_as_string, s); diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 966481e7b32..7f3ac13bac1 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -10,7 +10,7 @@ //! Character manipulation. //! -//! For more details, see ::rustc_unicode::char (a.k.a. std::char) +//! For more details, see ::std_unicode::char (a.k.a. std::char) #![allow(non_snake_case)] #![stable(feature = "core_char", since = "1.2.0")] diff --git a/src/libcoretest/lib.rs b/src/libcoretest/lib.rs index b8c01e570f5..92fb01e535c 100644 --- a/src/libcoretest/lib.rs +++ b/src/libcoretest/lib.rs @@ -40,7 +40,7 @@ extern crate core; extern crate test; extern crate libc; -extern crate rustc_unicode; +extern crate std_unicode; extern crate rand; mod any; diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index badee66b83d..ef472d0f059 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -32,7 +32,7 @@ extern crate term; extern crate log; #[macro_use] extern crate libc; -extern crate rustc_unicode; +extern crate std_unicode; extern crate serialize as rustc_serialize; // used by deriving extern crate syntax_pos; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 60ce7ea5395..35d14b3f8a6 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -47,7 +47,7 @@ extern crate serialize; #[macro_use] extern crate syntax; extern crate syntax_pos; extern crate test as testing; -extern crate rustc_unicode; +extern crate std_unicode; #[macro_use] extern crate log; extern crate rustc_errors as errors; diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 009330065f3..13a793d3d4b 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -345,7 +345,7 @@ pub fn maketest(s: &str, cratename: Option<&str>, dont_insert_main: bool, } fn partition_source(s: &str) -> (String, String) { - use rustc_unicode::str::UnicodeStr; + use std_unicode::str::UnicodeStr; let mut after_header = false; let mut before = String::new(); diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index 884f24ddc4c..8d37c5e839b 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -42,7 +42,7 @@ Core encoding and decoding interfaces. #[cfg(test)] extern crate test; #[macro_use] extern crate log; -extern crate rustc_unicode; +extern crate std_unicode; extern crate collections; pub use self::serialize::{Decoder, Encoder, Decodable, Encodable}; diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index b9f52e20fdd..fcf84cb7169 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -20,7 +20,7 @@ core = { path = "../libcore" } libc = { path = "../rustc/libc_shim" } rand = { path = "../librand" } compiler_builtins = { path = "../libcompiler_builtins" } -rustc_unicode = { path = "../librustc_unicode" } +std_unicode = { path = "../libstd_unicode" } unwind = { path = "../libunwind" } [build-dependencies] diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index ad9ae5638b6..b3b89213df1 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -256,7 +256,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use cmp; -use rustc_unicode::str as core_str; +use std_unicode::str as core_str; use error as std_error; use fmt; use result; diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 12dbbe3c469..a438eb6bea4 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -324,7 +324,7 @@ extern crate collections as core_collections; #[allow(deprecated)] extern crate rand as core_rand; extern crate alloc; -extern crate rustc_unicode; +extern crate std_unicode; extern crate libc; // We always need an unwinder currently for backtraces @@ -421,7 +421,7 @@ pub use core_collections::string; #[stable(feature = "rust1", since = "1.0.0")] pub use core_collections::vec; #[stable(feature = "rust1", since = "1.0.0")] -pub use rustc_unicode::char; +pub use std_unicode::char; pub mod f32; pub mod f64; diff --git a/src/librustc_unicode/Cargo.toml b/src/libstd_unicode/Cargo.toml similarity index 78% rename from src/librustc_unicode/Cargo.toml rename to src/libstd_unicode/Cargo.toml index e2b4afb2a51..28fbd3c1aa9 100644 --- a/src/librustc_unicode/Cargo.toml +++ b/src/libstd_unicode/Cargo.toml @@ -1,10 +1,10 @@ [package] authors = ["The Rust Project Developers"] -name = "rustc_unicode" +name = "std_unicode" version = "0.0.0" [lib] -name = "rustc_unicode" +name = "std_unicode" path = "lib.rs" test = false bench = false diff --git a/src/librustc_unicode/char.rs b/src/libstd_unicode/char.rs similarity index 100% rename from src/librustc_unicode/char.rs rename to src/libstd_unicode/char.rs diff --git a/src/librustc_unicode/lib.rs b/src/libstd_unicode/lib.rs similarity index 98% rename from src/librustc_unicode/lib.rs rename to src/libstd_unicode/lib.rs index 65bd717e01a..b086658ee0d 100644 --- a/src/librustc_unicode/lib.rs +++ b/src/libstd_unicode/lib.rs @@ -20,7 +20,7 @@ //! provide for basic string-related manipulations. This crate does not //! (yet) aim to provide a full set of Unicode tables. -#![crate_name = "rustc_unicode"] +#![crate_name = "std_unicode"] #![unstable(feature = "unicode", issue = "27783")] #![crate_type = "rlib"] #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", diff --git a/src/librustc_unicode/tables.rs b/src/libstd_unicode/tables.rs similarity index 100% rename from src/librustc_unicode/tables.rs rename to src/libstd_unicode/tables.rs diff --git a/src/librustc_unicode/u_str.rs b/src/libstd_unicode/u_str.rs similarity index 100% rename from src/librustc_unicode/u_str.rs rename to src/libstd_unicode/u_str.rs diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 5a1b0d4005e..8427a5005e2 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -43,7 +43,7 @@ extern crate term; extern crate libc; #[macro_use] extern crate log; #[macro_use] #[no_link] extern crate rustc_bitflags; -extern crate rustc_unicode; +extern crate std_unicode; pub extern crate rustc_errors as errors; extern crate syntax_pos; extern crate rustc_data_structures; diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 681dec0ab56..818742e4492 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -16,7 +16,7 @@ use ext::tt::transcribe::tt_next_token; use parse::token; use str::char_at; use symbol::{Symbol, keywords}; -use rustc_unicode::property::Pattern_White_Space; +use std_unicode::property::Pattern_White_Space; use std::borrow::Cow; use std::char; From cd7fade0a9c1c8762d2fba7c65c1b82e8d369711 Mon Sep 17 00:00:00 2001 From: Ruud van Asseldonk Date: Wed, 2 Nov 2016 22:49:27 +0100 Subject: [PATCH 164/293] Add small-copy optimization for io::Cursor During benchmarking, I found that one of my programs spent between 5 and 10 percent of the time doing memmoves. Ultimately I tracked these down to single-byte slices being copied with a memcopy in io::Cursor::read(). Doing a manual copy if only one byte is requested can speed things up significantly. For my program, this reduced the running time by 20%. Why special-case only a single byte, and not a "small" slice in general? I tried doing this for slices of at most 64 bytes and of at most 8 bytes. In both cases my test program was significantly slower. --- src/libstd/io/cursor.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index 1b5023380a7..9b50168a954 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -219,9 +219,21 @@ impl io::Seek for Cursor where T: AsRef<[u8]> { #[stable(feature = "rust1", since = "1.0.0")] impl Read for Cursor where T: AsRef<[u8]> { fn read(&mut self, buf: &mut [u8]) -> io::Result { - let n = Read::read(&mut self.fill_buf()?, buf)?; - self.pos += n as u64; - Ok(n) + // First check if the amount of bytes we want to read is small: the read + // in the else branch will end up calling `<&[u8] as Read>::read()`, + // which will copy the buffer using a memcopy. If we only want to read a + // single byte, then the overhead of the function call is significant. + let num_read = { + let mut inner_buf = self.fill_buf()?; + if buf.len() == 1 && inner_buf.len() > 0 { + buf[0] = inner_buf[0]; + 1 + } else { + Read::read(&mut inner_buf, buf)? + } + }; + self.pos += num_read as u64; + Ok(num_read) } } From 341805288e8a055162bef64055a7962ecffbf103 Mon Sep 17 00:00:00 2001 From: Ruud van Asseldonk Date: Fri, 4 Nov 2016 00:20:11 +0100 Subject: [PATCH 165/293] Move small-copy optimization into copy_from_slice Ultimately copy_from_slice is being a bottleneck, not io::Cursor::read. It might be worthwhile to move the check here, so more places can benefit from it. --- src/libcore/slice.rs | 16 +++++++++++++--- src/libstd/io/cursor.rs | 18 +++--------------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index a4a90e7a9da..b238623eaba 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -515,9 +515,19 @@ impl SliceExt for [T] { fn copy_from_slice(&mut self, src: &[T]) where T: Copy { assert!(self.len() == src.len(), "destination and source slices have different lengths"); - unsafe { - ptr::copy_nonoverlapping( - src.as_ptr(), self.as_mut_ptr(), self.len()); + // First check if the amount of elements we want to copy is small: + // `copy_nonoverlapping` will do a memcopy, which involves an indirect + // function call when `memcpy` is in the dynamically-linked libc. For + // small elements (such as a single byte or pointer), the overhead is + // significant. If the element is big then the assignment is a memcopy + // anyway. + if self.len() == 1 { + self[0] = src[0]; + } else { + unsafe { + ptr::copy_nonoverlapping( + src.as_ptr(), self.as_mut_ptr(), self.len()); + } } } diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index 9b50168a954..1b5023380a7 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -219,21 +219,9 @@ impl io::Seek for Cursor where T: AsRef<[u8]> { #[stable(feature = "rust1", since = "1.0.0")] impl Read for Cursor where T: AsRef<[u8]> { fn read(&mut self, buf: &mut [u8]) -> io::Result { - // First check if the amount of bytes we want to read is small: the read - // in the else branch will end up calling `<&[u8] as Read>::read()`, - // which will copy the buffer using a memcopy. If we only want to read a - // single byte, then the overhead of the function call is significant. - let num_read = { - let mut inner_buf = self.fill_buf()?; - if buf.len() == 1 && inner_buf.len() > 0 { - buf[0] = inner_buf[0]; - 1 - } else { - Read::read(&mut inner_buf, buf)? - } - }; - self.pos += num_read as u64; - Ok(num_read) + let n = Read::read(&mut self.fill_buf()?, buf)?; + self.pos += n as u64; + Ok(n) } } From 3be2c3b3092e934bdc2db67d5bdcabd611deca9c Mon Sep 17 00:00:00 2001 From: Ruud van Asseldonk Date: Sat, 12 Nov 2016 15:58:58 +0100 Subject: [PATCH 166/293] Move small-copy optimization into <&[u8] as Read> Based on the discussion in https://github.com/rust-lang/rust/pull/37573, it is likely better to keep this limited to std::io, instead of modifying a function which users expect to be a memcpy. --- src/libcore/slice.rs | 16 +++------------- src/libstd/io/impls.rs | 22 ++++++++++++++++++++-- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index b238623eaba..a4a90e7a9da 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -515,19 +515,9 @@ impl SliceExt for [T] { fn copy_from_slice(&mut self, src: &[T]) where T: Copy { assert!(self.len() == src.len(), "destination and source slices have different lengths"); - // First check if the amount of elements we want to copy is small: - // `copy_nonoverlapping` will do a memcopy, which involves an indirect - // function call when `memcpy` is in the dynamically-linked libc. For - // small elements (such as a single byte or pointer), the overhead is - // significant. If the element is big then the assignment is a memcopy - // anyway. - if self.len() == 1 { - self[0] = src[0]; - } else { - unsafe { - ptr::copy_nonoverlapping( - src.as_ptr(), self.as_mut_ptr(), self.len()); - } + unsafe { + ptr::copy_nonoverlapping( + src.as_ptr(), self.as_mut_ptr(), self.len()); } } diff --git a/src/libstd/io/impls.rs b/src/libstd/io/impls.rs index 6b26c016638..f691289811b 100644 --- a/src/libstd/io/impls.rs +++ b/src/libstd/io/impls.rs @@ -157,7 +157,16 @@ impl<'a> Read for &'a [u8] { fn read(&mut self, buf: &mut [u8]) -> io::Result { let amt = cmp::min(buf.len(), self.len()); let (a, b) = self.split_at(amt); - buf[..amt].copy_from_slice(a); + + // First check if the amount of bytes we want to read is small: + // `copy_from_slice` will generally expand to a call to `memcpy`, and + // for a single byte the overhead is significant. + if amt == 1 { + buf[0] = a[0]; + } else { + buf[..amt].copy_from_slice(a); + } + *self = b; Ok(amt) } @@ -169,7 +178,16 @@ impl<'a> Read for &'a [u8] { "failed to fill whole buffer")); } let (a, b) = self.split_at(buf.len()); - buf.copy_from_slice(a); + + // First check if the amount of bytes we want to read is small: + // `copy_from_slice` will generally expand to a call to `memcpy`, and + // for a single byte the overhead is significant. + if buf.len() == 1 { + buf[0] = a[0]; + } else { + buf.copy_from_slice(a); + } + *self = b; Ok(()) } From 75927569fbb8dd6430abd335b861d3c81ddb3763 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Tue, 29 Nov 2016 18:49:09 +0100 Subject: [PATCH 167/293] Add i686-unknown-openbsd target. --- mk/cfg/i686-unknown-openbsd.mk | 24 +++++++++++++++ .../target/i686_unknown_openbsd.rs | 30 +++++++++++++++++++ src/librustc_back/target/mod.rs | 3 ++ 3 files changed, 57 insertions(+) create mode 100644 mk/cfg/i686-unknown-openbsd.mk create mode 100644 src/librustc_back/target/i686_unknown_openbsd.rs diff --git a/mk/cfg/i686-unknown-openbsd.mk b/mk/cfg/i686-unknown-openbsd.mk new file mode 100644 index 00000000000..b839937c976 --- /dev/null +++ b/mk/cfg/i686-unknown-openbsd.mk @@ -0,0 +1,24 @@ +# i686-unknown-openbsd configuration +CC_i686-unknown-openbsd=$(CC) +CXX_i686-unknown-openbsd=$(CXX) +CPP_i686-unknown-openbsd=$(CPP) +AR_i686-unknown-openbsd=$(AR) +CFG_LIB_NAME_i686-unknown-openbsd=lib$(1).so +CFG_STATIC_LIB_NAME_i686-unknown-openbsd=lib$(1).a +CFG_LIB_GLOB_i686-unknown-openbsd=lib$(1)-*.so +CFG_LIB_DSYM_GLOB_i686-unknown-openbsd=$(1)-*.dylib.dSYM +CFG_JEMALLOC_CFLAGS_i686-unknown-openbsd := -m32 -I/usr/include $(CFLAGS) +CFG_GCCISH_CFLAGS_i686-unknown-openbsd := -g -fPIC -m32 -I/usr/include $(CFLAGS) +CFG_GCCISH_LINK_FLAGS_i686-unknown-openbsd := -shared -fPIC -g -pthread -m32 +CFG_GCCISH_DEF_FLAG_i686-unknown-openbsd := -Wl,--export-dynamic,--dynamic-list= +CFG_LLC_FLAGS_i686-unknown-openbsd := +CFG_INSTALL_NAME_i686-unknown-openbsd = +CFG_EXE_SUFFIX_i686-unknown-openbsd := +CFG_WINDOWSY_i686-unknown-openbsd := +CFG_UNIXY_i686-unknown-openbsd := 1 +CFG_LDPATH_i686-unknown-openbsd := +CFG_RUN_i686-unknown-openbsd=$(2) +CFG_RUN_TARG_i686-unknown-openbsd=$(call CFG_RUN_i686-unknown-openbsd,,$(2)) +CFG_GNU_TRIPLE_i686-unknown-openbsd := i686-unknown-openbsd +RUSTC_FLAGS_i686-unknown-openbsd=-C linker=$(call FIND_COMPILER,$(CC)) +CFG_DISABLE_JEMALLOC_i686-unknown-openbsd := 1 diff --git a/src/librustc_back/target/i686_unknown_openbsd.rs b/src/librustc_back/target/i686_unknown_openbsd.rs new file mode 100644 index 00000000000..81efd37386a --- /dev/null +++ b/src/librustc_back/target/i686_unknown_openbsd.rs @@ -0,0 +1,30 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use target::{Target, TargetResult}; + +pub fn target() -> TargetResult { + let mut base = super::openbsd_base::opts(); + base.cpu = "pentium4".to_string(); + base.max_atomic_width = Some(64); + base.pre_link_args.push("-m32".to_string()); + + Ok(Target { + llvm_target: "i686-unknown-openbsd".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + data_layout: "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128".to_string(), + arch: "x86".to_string(), + target_os: "openbsd".to_string(), + target_env: "".to_string(), + target_vendor: "unknown".to_string(), + options: base, + }) +} diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index f195ccb3f42..496ba6cba18 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -168,7 +168,10 @@ supported_targets! { ("x86_64-unknown-dragonfly", x86_64_unknown_dragonfly), ("x86_64-unknown-bitrig", x86_64_unknown_bitrig), + + ("i686-unknown-openbsd", i686_unknown_openbsd), ("x86_64-unknown-openbsd", x86_64_unknown_openbsd), + ("x86_64-unknown-netbsd", x86_64_unknown_netbsd), ("x86_64-rumprun-netbsd", x86_64_rumprun_netbsd), From d21861dd89e2df8c567c97756d9cc18e39a5283f Mon Sep 17 00:00:00 2001 From: Mark-Simulacrum Date: Sun, 27 Nov 2016 06:54:50 -0700 Subject: [PATCH 168/293] Refactor one_bound_for_assoc_type to take an Iterator instead of Vec. --- src/librustc_typeck/astconv.rs | 66 +++++++++++++++++----------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 032ad6efe1f..96088db9d8e 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -884,10 +884,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // those that do. self.ensure_super_predicates(binding.span, trait_ref.def_id())?; - let candidates: Vec = + let candidates = traits::supertraits(tcx, trait_ref.clone()) - .filter(|r| self.trait_defines_associated_type_named(r.def_id(), binding.item_name)) - .collect(); + .filter(|r| self.trait_defines_associated_type_named(r.def_id(), binding.item_name)); let candidate = self.one_bound_for_assoc_type(candidates, &trait_ref.to_string(), @@ -1191,10 +1190,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // Check that there is exactly one way to find an associated type with the // correct name. - let suitable_bounds: Vec<_> = + let suitable_bounds = traits::transitive_bounds(tcx, &bounds) - .filter(|b| self.trait_defines_associated_type_named(b.def_id(), assoc_name)) - .collect(); + .filter(|b| self.trait_defines_associated_type_named(b.def_id(), assoc_name)); self.one_bound_for_assoc_type(suitable_bounds, &ty_param_name.as_str(), @@ -1205,31 +1203,29 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // Checks that bounds contains exactly one element and reports appropriate // errors otherwise. - fn one_bound_for_assoc_type(&self, - bounds: Vec>, + fn one_bound_for_assoc_type(&self, + mut bounds: I, ty_param_name: &str, assoc_name: &str, span: Span) -> Result, ErrorReported> + where I: Iterator> { - if bounds.is_empty() { - struct_span_err!(self.tcx().sess, span, E0220, - "associated type `{}` not found for `{}`", - assoc_name, - ty_param_name) - .span_label(span, &format!("associated type `{}` not found", assoc_name)) - .emit(); - return Err(ErrorReported); - } - - if bounds.len() > 1 { - let spans = bounds.iter().map(|b| { - self.tcx().associated_items(b.def_id()).find(|item| { - item.kind == ty::AssociatedKind::Type && item.name == assoc_name - }) - .and_then(|item| self.tcx().map.span_if_local(item.def_id)) - }); + let bound = match bounds.next() { + Some(bound) => bound, + None => { + struct_span_err!(self.tcx().sess, span, E0220, + "associated type `{}` not found for `{}`", + assoc_name, + ty_param_name) + .span_label(span, &format!("associated type `{}` not found", assoc_name)) + .emit(); + return Err(ErrorReported); + } + }; + if let Some(bound2) = bounds.next() { + let bounds = iter::once(bound).chain(iter::once(bound2)).chain(bounds); let mut err = struct_span_err!( self.tcx().sess, span, E0221, "ambiguous associated type `{}` in bounds of `{}`", @@ -1237,22 +1233,27 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { ty_param_name); err.span_label(span, &format!("ambiguous associated type `{}`", assoc_name)); - for span_and_bound in spans.zip(&bounds) { - if let Some(span) = span_and_bound.0 { + for bound in bounds { + let bound_span = self.tcx().associated_items(bound.def_id()).find(|item| { + item.kind == ty::AssociatedKind::Type && item.name == assoc_name + }) + .and_then(|item| self.tcx().map.span_if_local(item.def_id)); + + if let Some(span) = bound_span { err.span_label(span, &format!("ambiguous `{}` from `{}`", assoc_name, - span_and_bound.1)); + bound)); } else { span_note!(&mut err, span, "associated type `{}` could derive from `{}`", ty_param_name, - span_and_bound.1); + bound); } } err.emit(); } - Ok(bounds[0].clone()) + return Ok(bound); } // Create a type from a path to an associated type. @@ -1293,11 +1294,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { return (tcx.types.err, Def::Err); } - let candidates: Vec = + let candidates = traits::supertraits(tcx, ty::Binder(trait_ref)) .filter(|r| self.trait_defines_associated_type_named(r.def_id(), - assoc_name)) - .collect(); + assoc_name)); match self.one_bound_for_assoc_type(candidates, "Self", From 7cbd18a690da89251390db373d499b1770f20753 Mon Sep 17 00:00:00 2001 From: Johannes Oertel Date: Wed, 30 Nov 2016 15:23:11 +0100 Subject: [PATCH 169/293] Remove the `unmarked_api` feature Closes #37981. --- src/doc/reference.md | 5 ----- src/librustc/middle/stability.rs | 18 +----------------- src/libsyntax/feature_gate.rs | 7 +++---- 3 files changed, 4 insertions(+), 26 deletions(-) diff --git a/src/doc/reference.md b/src/doc/reference.md index 4fbe5183967..fe0507fd4a5 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -2462,11 +2462,6 @@ The currently implemented features of the reference compiler are: * `unboxed_closures` - Rust's new closure design, which is currently a work in progress feature with many known bugs. -* `unmarked_api` - Allows use of items within a `#![staged_api]` crate - which have not been marked with a stability marker. - Such items should not be allowed by the compiler to exist, - so if you need this there probably is a compiler bug. - * `allow_internal_unstable` - Allows `macro_rules!` macros to be tagged with the `#[allow_internal_unstable]` attribute, designed to allow `std` macros to call diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index f3890f1c3b7..3e32957aecf 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -513,23 +513,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // handled by the lint emitting logic above. } None => { - // This is an 'unmarked' API, which should not exist - // in the standard library. - if self.sess.features.borrow().unmarked_api { - self.sess.struct_span_warn(span, "use of unmarked library feature") - .span_note(span, "this is either a bug in the library you are \ - using or a bug in the compiler - please \ - report it in both places") - .emit() - } else { - self.sess.struct_span_err(span, "use of unmarked library feature") - .span_note(span, "this is either a bug in the library you are \ - using or a bug in the compiler - please \ - report it in both places") - .span_note(span, "use #![feature(unmarked_api)] in the \ - crate attributes to override this") - .emit() - } + span_bug!(span, "encountered unmarked API"); } } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index aa6a29b78b0..52374f232de 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -153,10 +153,6 @@ declare_features! ( // rustc internal (active, staged_api, "1.0.0", None), - // Allows using items which are missing stability attributes - // rustc internal - (active, unmarked_api, "1.0.0", None), - // Allows using #![no_core] (active, no_core, "1.3.0", Some(29639)), @@ -330,6 +326,9 @@ declare_features! ( (removed, test_removed_feature, "1.0.0", None), (removed, visible_private_types, "1.0.0", None), (removed, unsafe_no_drop_flag, "1.0.0", None), + // Allows using items which are missing stability attributes + // rustc internal + (removed, unmarked_api, "1.0.0", None), ); declare_features! ( From a15d2dbef6d9a370c3048c8c3f620399e9090a5f Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 30 Nov 2016 12:17:38 -0500 Subject: [PATCH 170/293] debuginfo: Ignore macro-stepping test on aarch64 --- src/test/debuginfo/macro-stepping.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/debuginfo/macro-stepping.rs b/src/test/debuginfo/macro-stepping.rs index 52a2a58ed7d..37355ed377b 100644 --- a/src/test/debuginfo/macro-stepping.rs +++ b/src/test/debuginfo/macro-stepping.rs @@ -10,6 +10,7 @@ // ignore-windows // ignore-android +// ignore-aarch64 // min-lldb-version: 310 // aux-build:macro-stepping.rs From 8e6ae19bb51c6248384889670830fc7838617c33 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 30 Nov 2016 09:44:33 -0800 Subject: [PATCH 171/293] Add cloned example for Option --- src/libcore/option.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 607e16887a8..8871e1fa840 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -659,6 +659,16 @@ impl Option { impl<'a, T: Clone> Option<&'a T> { /// Maps an `Option<&T>` to an `Option` by cloning the contents of the /// option. + /// + /// # Examples + /// + /// ``` + /// let x = 12; + /// let opt_x = Some(&x); + /// assert_eq!(opt_x, Some(&12)); + /// let cloned = opt_x.cloned(); + /// assert_eq!(cloned, Some(12)); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn cloned(self) -> Option { self.map(|t| t.clone()) From 2186660b5169cb7784b89a7fc0a25eb7889d1e6b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 16 Nov 2016 09:19:02 -0800 Subject: [PATCH 172/293] Update the bootstrap compiler Now that we've got a beta build, let's use it! --- mk/crates.mk | 8 +- mk/main.mk | 10 +- src/Cargo.lock | 7 - src/Cargo.toml | 17 ++ src/bootstrap/Cargo.toml | 1 - src/bootstrap/channel.rs | 17 -- src/bootstrap/check.rs | 2 +- src/bootstrap/compile.rs | 4 +- src/bootstrap/lib.rs | 16 +- src/libcore/lib.rs | 1 - src/libgraphviz/lib.rs | 1 - src/librustc/lib.rs | 2 - src/librustc_back/lib.rs | 1 - src/librustc_borrowck/lib.rs | 2 - src/librustc_const_eval/lib.rs | 2 - src/librustc_const_math/lib.rs | 1 - src/librustc_driver/lib.rs | 2 - src/librustc_errors/lib.rs | 1 - src/librustc_incremental/lib.rs | 2 - src/librustc_lint/lib.rs | 1 - src/librustc_llvm/lib.rs | 4 +- src/librustc_metadata/lib.rs | 2 - src/librustc_mir/lib.rs | 2 - src/librustc_passes/lib.rs | 1 - src/librustc_privacy/lib.rs | 1 - src/librustc_resolve/lib.rs | 1 - src/librustc_save_analysis/lib.rs | 1 - src/librustc_trans/lib.rs | 2 - src/librustc_typeck/lib.rs | 2 - src/librustdoc/lib.rs | 2 - src/libserialize/lib.rs | 1 - src/libstd/lib.rs | 2 - src/libsyntax/lib.rs | 2 - src/libsyntax_ext/lib.rs | 1 - src/libsyntax_pos/lib.rs | 1 - src/libterm/lib.rs | 1 - src/libtest/lib.rs | 1 - src/rustc/Cargo.toml | 11 - src/rustc/std_shim/Cargo.toml | 11 - src/rustc/test_shim/Cargo.toml | 11 - src/stage0.txt | 4 +- src/tools/compiletest/Cargo.toml | 6 - src/tools/compiletest/src/main.rs | 2 - src/vendor/md5/.cargo-checksum.json | 1 - src/vendor/md5/.cargo-ok | 0 src/vendor/md5/.gitignore | 2 - src/vendor/md5/.travis.yml | 11 - src/vendor/md5/Cargo.toml | 9 - src/vendor/md5/LICENSE.txt | 21 -- src/vendor/md5/README.md | 19 -- src/vendor/md5/benches/lib.rs | 16 -- src/vendor/md5/src/lib.rs | 340 ---------------------------- 52 files changed, 30 insertions(+), 559 deletions(-) delete mode 100644 src/vendor/md5/.cargo-checksum.json delete mode 100644 src/vendor/md5/.cargo-ok delete mode 100644 src/vendor/md5/.gitignore delete mode 100644 src/vendor/md5/.travis.yml delete mode 100644 src/vendor/md5/Cargo.toml delete mode 100644 src/vendor/md5/LICENSE.txt delete mode 100644 src/vendor/md5/README.md delete mode 100644 src/vendor/md5/benches/lib.rs delete mode 100644 src/vendor/md5/src/lib.rs diff --git a/mk/crates.mk b/mk/crates.mk index cf985a0d980..acb36b2f7da 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -65,7 +65,7 @@ HOST_CRATES := syntax syntax_ext proc_macro_tokens proc_macro_plugin syntax_pos TOOLS := compiletest rustdoc rustc rustbook error_index_generator DEPS_core := -DEPS_compiler_builtins := core +DEPS_compiler_builtins := core native:compiler-rt DEPS_alloc := core libc alloc_system DEPS_alloc_system := core libc DEPS_alloc_jemalloc := core libc native:jemalloc @@ -79,11 +79,7 @@ DEPS_panic_unwind := libc alloc unwind DEPS_unwind := libc RUSTFLAGS_compiler_builtins := -lstatic=compiler-rt - -# FIXME(stage0): change this to just `RUSTFLAGS_panic_abort := ...` -RUSTFLAGS1_panic_abort := -C panic=abort -RUSTFLAGS2_panic_abort := -C panic=abort -RUSTFLAGS3_panic_abort := -C panic=abort +RUSTFLAGS_panic_abort := -C panic=abort DEPS_std := core libc rand alloc collections compiler_builtins rustc_unicode \ native:backtrace \ diff --git a/mk/main.mk b/mk/main.mk index 9936c5b59be..49fdfc4118d 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -372,15 +372,12 @@ CFG_INFO := $(info cfg: disabling unstable features (CFG_DISABLE_UNSTABLE_FEATUR # Turn on feature-staging export CFG_DISABLE_UNSTABLE_FEATURES # Subvert unstable feature lints to do the self-build -export RUSTC_BOOTSTRAP=1 endif ifdef CFG_MUSL_ROOT export CFG_MUSL_ROOT endif -# FIXME: Transitionary measure to bootstrap using the old bootstrap logic. -# Remove this once the bootstrap compiler uses the new login in Issue #36548. -export RUSTC_BOOTSTRAP_KEY=62b3e239 +export RUSTC_BOOTSTRAP := 1 ###################################################################### # Per-stage targets and runner @@ -443,10 +440,7 @@ endif TSREQ$(1)_T_$(2)_H_$(3) = \ $$(HSREQ$(1)_H_$(3)) \ $$(foreach obj,$$(REQUIRED_OBJECTS_$(2)),\ - $$(TLIB$(1)_T_$(2)_H_$(3))/$$(obj)) \ - $$(TLIB0_T_$(2)_H_$(3))/$$(call CFG_STATIC_LIB_NAME_$(2),compiler-rt) -# ^ This copies `libcompiler-rt.a` to the stage0 sysroot -# ^ TODO(stage0) update this to not copy `libcompiler-rt.a` to stage0 + $$(TLIB$(1)_T_$(2)_H_$(3))/$$(obj)) # Prerequisites for a working stageN compiler and libraries, for a specific # target diff --git a/src/Cargo.lock b/src/Cargo.lock index ab1c1c453dd..bff6ef20677 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -45,7 +45,6 @@ dependencies = [ "gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", - "md5 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", @@ -172,11 +171,6 @@ name = "log" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "md5" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "num_cpus" version = "0.2.13" @@ -686,7 +680,6 @@ dependencies = [ "checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685" "checksum libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "044d1360593a78f5c8e5e710beccdc24ab71d1f01bc19a29bcacdba22e8475d8" "checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054" -"checksum md5 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a5539a8dee9b4ae308c9c406a379838b435a8f2c84cf9fedc6d5a576be9888db" "checksum num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "cee7e88156f3f9e19bdd598f8d6c9db7bf4078f99f8381f43a55b09648d1a6e3" "checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b" "checksum toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "0590d72182e50e879c4da3b11c6488dae18fccb1ae0c7a3eda18e16795844796" diff --git a/src/Cargo.toml b/src/Cargo.toml index dbd2f7743dc..8fb5c70c41b 100644 --- a/src/Cargo.toml +++ b/src/Cargo.toml @@ -11,3 +11,20 @@ members = [ "tools/rustbook", "tools/tidy", ] + +# Curiously, compiletest will segfault if compiled with opt-level=3 on 64-bit +# MSVC when running the compile-fail test suite when a should-fail test panics. +# But hey if this is removed and it gets past the bots, sounds good to me. +[profile.release] +opt-level = 2 +[profile.bench] +opt-level = 2 + +# These options are controlled from our rustc wrapper script, so turn them off +# here and have them controlled elsewhere. +[profile.dev] +debug = false +debug-assertions = false +[profile.test] +debug = false +debug-assertions = false diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 4c9b578c134..35f8fb43f7b 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -29,4 +29,3 @@ getopts = "0.2" rustc-serialize = "0.3" gcc = "0.3.38" libc = "0.2" -md5 = "0.1" diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs index 879c383404a..b2341f59787 100644 --- a/src/bootstrap/channel.rs +++ b/src/bootstrap/channel.rs @@ -20,7 +20,6 @@ use std::io::prelude::*; use std::process::Command; use build_helper::output; -use md5; use Build; @@ -91,20 +90,4 @@ pub fn collect(build: &mut Build) { build.ver_hash = Some(ver_hash); build.short_ver_hash = Some(short_ver_hash); } - - // Calculate this compiler's bootstrap key, which is currently defined as - // the first 8 characters of the md5 of the release string. - let key = md5::compute(build.release.as_bytes()); - build.bootstrap_key = format!("{:02x}{:02x}{:02x}{:02x}", - key[0], key[1], key[2], key[3]); - - // Slurp up the stage0 bootstrap key as we're bootstrapping from an - // otherwise stable compiler. - let mut s = String::new(); - t!(t!(File::open(build.src.join("src/stage0.txt"))).read_to_string(&mut s)); - if let Some(line) = s.lines().find(|l| l.starts_with("rustc_key")) { - if let Some(key) = line.split(": ").nth(1) { - build.bootstrap_key_stage0 = key.to_string(); - } - } } diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 150232e4ab4..b67eab38f5d 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -220,7 +220,7 @@ pub fn compiletest(build: &Build, } } } - build.add_bootstrap_key(&mut cmd); + cmd.env("RUSTC_BOOTSTRAP", "1"); cmd.arg("--adb-path").arg("adb"); cmd.arg("--adb-test-dir").arg(ADB_TEST_DIR); diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 236989dbcfe..b268686ca6c 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -120,8 +120,8 @@ fn build_startup_objects(build: &Build, target: &str, into: &Path) { for file in t!(fs::read_dir(build.src.join("src/rtstartup"))) { let file = t!(file); let mut cmd = Command::new(&compiler_path); - build.add_bootstrap_key(&mut cmd); - build.run(cmd.arg("--target").arg(target) + build.run(cmd.env("RUSTC_BOOTSTRAP", "1") + .arg("--target").arg(target) .arg("--emit=obj") .arg("--out-dir").arg(into) .arg(file.path())); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 03c74ff081a..590c967d147 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -22,7 +22,6 @@ extern crate cmake; extern crate filetime; extern crate gcc; extern crate getopts; -extern crate md5; extern crate num_cpus; extern crate rustc_serialize; extern crate toml; @@ -120,8 +119,6 @@ pub struct Build { version: String, package_vers: String, local_rebuild: bool, - bootstrap_key: String, - bootstrap_key_stage0: String, // Probed tools at runtime lldb_version: Option, @@ -205,8 +202,6 @@ impl Build { ver_date: None, version: String::new(), local_rebuild: local_rebuild, - bootstrap_key: String::new(), - bootstrap_key_stage0: String::new(), package_vers: String::new(), cc: HashMap::new(), cxx: HashMap::new(), @@ -438,7 +433,8 @@ impl Build { .env("RUSTDOC_REAL", self.rustdoc(compiler)) .env("RUSTC_FLAGS", self.rustc_flags(target).join(" ")); - self.add_bootstrap_key(&mut cargo); + // Enable usage of unstable features + cargo.env("RUSTC_BOOTSTRAP", "1"); // Specify some various options for build scripts used throughout // the build. @@ -655,14 +651,6 @@ impl Build { add_lib_path(vec![self.rustc_libdir(compiler)], cmd); } - /// Adds the compiler's bootstrap key to the environment of `cmd`. - fn add_bootstrap_key(&self, cmd: &mut Command) { - cmd.env("RUSTC_BOOTSTRAP", "1"); - // FIXME: Transitionary measure to bootstrap using the old bootstrap logic. - // Remove this once the bootstrap compiler uses the new login in Issue #36548. - cmd.env("RUSTC_BOOTSTRAP_KEY", "62b3e239"); - } - /// Returns the compiler's libdir where it stores the dynamic libraries that /// it itself links against. /// diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 07f5e725e20..9834fca5fdc 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -89,7 +89,6 @@ #![feature(specialization)] #![feature(staged_api)] #![feature(unboxed_closures)] -#![cfg_attr(stage0, feature(question_mark))] #![feature(never_type)] #![feature(prelude_import)] diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index 03057af4a84..220051c9d35 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -295,7 +295,6 @@ #![cfg_attr(not(stage0), deny(warnings))] #![feature(str_escape)] -#![cfg_attr(stage0, feature(question_mark))] use self::LabelText::*; diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index c0ea8d6b1e3..7c26b710a53 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -31,7 +31,6 @@ #![feature(conservative_impl_trait)] #![feature(const_fn)] #![feature(core_intrinsics)] -#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![cfg_attr(stage0, feature(item_like_imports))] #![feature(libc)] #![feature(nonzero)] @@ -41,7 +40,6 @@ #![feature(slice_patterns)] #![feature(staged_api)] #![feature(unboxed_closures)] -#![cfg_attr(stage0, feature(question_mark))] #![cfg_attr(test, feature(test))] extern crate arena; diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs index da5f787bdf3..3dc577b3c64 100644 --- a/src/librustc_back/lib.rs +++ b/src/librustc_back/lib.rs @@ -36,7 +36,6 @@ #![feature(rand)] #![feature(rustc_private)] #![feature(staged_api)] -#![cfg_attr(stage0, feature(question_mark))] #![cfg_attr(test, feature(rand))] extern crate syntax; diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs index 2cd709dbd36..1ff232da427 100644 --- a/src/librustc_borrowck/lib.rs +++ b/src/librustc_borrowck/lib.rs @@ -19,14 +19,12 @@ #![allow(non_camel_case_types)] -#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] #![feature(staged_api)] #![feature(associated_consts)] #![feature(nonzero)] -#![cfg_attr(stage0, feature(question_mark))] #[macro_use] extern crate log; #[macro_use] extern crate syntax; extern crate syntax_pos; diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs index 3fa60f86c98..7a6cc493723 100644 --- a/src/librustc_const_eval/lib.rs +++ b/src/librustc_const_eval/lib.rs @@ -22,12 +22,10 @@ html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(rustc_private)] #![feature(staged_api)] #![feature(rustc_diagnostic_macros)] #![feature(slice_patterns)] -#![cfg_attr(stage0, feature(question_mark))] #![feature(box_patterns)] #![feature(box_syntax)] diff --git a/src/librustc_const_math/lib.rs b/src/librustc_const_math/lib.rs index 31fccb41ce5..f667ff23b27 100644 --- a/src/librustc_const_math/lib.rs +++ b/src/librustc_const_math/lib.rs @@ -25,7 +25,6 @@ #![feature(rustc_private)] #![feature(staged_api)] -#![cfg_attr(stage0, feature(question_mark))] #[macro_use] extern crate log; #[macro_use] extern crate syntax; diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index a0863e0d294..b79eca0c22d 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -24,14 +24,12 @@ #![cfg_attr(not(stage0), deny(warnings))] #![feature(box_syntax)] -#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(libc)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] #![feature(set_stdio)] #![feature(staged_api)] -#![cfg_attr(stage0, feature(question_mark))] extern crate arena; extern crate flate; diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index badee66b83d..d7c15f550e0 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -21,7 +21,6 @@ #![allow(unused_attributes)] #![feature(rustc_private)] #![feature(staged_api)] -#![cfg_attr(stage0, feature(question_mark))] #![feature(range_contains)] #![feature(libc)] #![feature(unicode)] diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 4a5a6b9bea9..b72766bccea 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -19,8 +19,6 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![cfg_attr(not(stage0), deny(warnings))] -#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] -#![cfg_attr(stage0, feature(question_mark))] #![feature(rustc_private)] #![feature(staged_api)] #![feature(rand)] diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index ec0a124770c..6c9a3e99a04 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -31,7 +31,6 @@ #![cfg_attr(test, feature(test))] #![feature(box_patterns)] #![feature(box_syntax)] -#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index c4ec418f224..0229776c948 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -24,11 +24,11 @@ #![feature(associated_consts)] #![feature(box_syntax)] +#![feature(concat_idents)] #![feature(libc)] #![feature(link_args)] -#![feature(staged_api)] #![feature(linked_from)] -#![feature(concat_idents)] +#![feature(staged_api)] extern crate libc; diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 2fd40181d7c..56f3cfc12c9 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -20,10 +20,8 @@ #![feature(box_patterns)] #![feature(conservative_impl_trait)] #![feature(core_intrinsics)] -#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(proc_macro_internals)] #![feature(proc_macro_lib)] -#![cfg_attr(stage0, feature(question_mark))] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 62e405564db..617bd81d96a 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -22,12 +22,10 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(associated_consts)] #![feature(box_patterns)] -#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![cfg_attr(stage0, feature(item_like_imports))] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] #![feature(staged_api)] -#![cfg_attr(stage0, feature(question_mark))] #[macro_use] extern crate log; extern crate graphviz as dot; diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs index 039a76d25c7..525d49ddd82 100644 --- a/src/librustc_passes/lib.rs +++ b/src/librustc_passes/lib.rs @@ -23,7 +23,6 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![cfg_attr(not(stage0), deny(warnings))] -#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(rustc_diagnostic_macros)] #![feature(staged_api)] #![feature(rustc_private)] diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 4020c45f59e..1071203af2b 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -17,7 +17,6 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![cfg_attr(not(stage0), deny(warnings))] -#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] #![feature(staged_api)] diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 058c8266a35..0259e5bedae 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -19,7 +19,6 @@ #![feature(associated_consts)] #![feature(borrow_state)] -#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] #![feature(staged_api)] diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 389892193c3..7a2b74c06db 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -18,7 +18,6 @@ #![cfg_attr(not(stage0), deny(warnings))] #![feature(custom_attribute)] -#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![allow(unused_attributes)] #![feature(rustc_private)] #![feature(staged_api)] diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index d0cb302e1ab..0e7ead30a93 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -29,7 +29,6 @@ #![feature(cell_extras)] #![feature(const_fn)] #![feature(custom_attribute)] -#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![allow(unused_attributes)] #![feature(libc)] #![feature(quote)] @@ -38,7 +37,6 @@ #![feature(slice_patterns)] #![feature(staged_api)] #![feature(unicode)] -#![cfg_attr(stage0, feature(question_mark))] use rustc::dep_graph::WorkProduct; diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 049add6f062..dfa66259029 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -77,12 +77,10 @@ This API is completely unstable and subject to change. #![feature(box_patterns)] #![feature(box_syntax)] #![feature(conservative_impl_trait)] -#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] #![feature(staged_api)] -#![cfg_attr(stage0, feature(question_mark))] #[macro_use] extern crate log; #[macro_use] extern crate syntax; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 60ce7ea5395..5073baa420e 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -20,7 +20,6 @@ #![feature(box_patterns)] #![feature(box_syntax)] -#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(libc)] #![feature(rustc_private)] #![feature(set_stdio)] @@ -28,7 +27,6 @@ #![feature(staged_api)] #![feature(test)] #![feature(unicode)] -#![cfg_attr(stage0, feature(question_mark))] extern crate arena; extern crate getopts; diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index 884f24ddc4c..d432ed42066 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -35,7 +35,6 @@ Core encoding and decoding interfaces. #![feature(specialization)] #![feature(staged_api)] #![feature(unicode)] -#![cfg_attr(stage0, feature(question_mark))] #![cfg_attr(test, feature(test))] // test harness access diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 12dbbe3c469..8132b139260 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -249,7 +249,6 @@ #![feature(const_fn)] #![feature(core_float)] #![feature(core_intrinsics)] -#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(dropck_parametricity)] #![feature(float_extras)] #![feature(float_from_str_radix)] @@ -276,7 +275,6 @@ #![feature(panic_unwind)] #![feature(placement_in_syntax)] #![feature(prelude_import)] -#![cfg_attr(stage0, feature(question_mark))] #![feature(rand)] #![feature(raw)] #![feature(repr_simd)] diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 7a9347ded12..3e8dfda4a9a 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -32,10 +32,8 @@ #![feature(staged_api)] #![feature(str_escape)] #![feature(unicode)] -#![cfg_attr(stage0, feature(question_mark))] #![feature(rustc_diagnostic_macros)] #![feature(specialization)] -#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] extern crate core; extern crate serialize; diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index e83fd55cd71..66d6c0570ac 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -19,7 +19,6 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![cfg_attr(not(stage0), deny(warnings))] -#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(proc_macro_lib)] #![feature(proc_macro_internals)] #![feature(rustc_private)] diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index d6e45aa0b9f..44067b3132c 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -27,7 +27,6 @@ #![allow(unused_attributes)] #![feature(rustc_private)] #![feature(staged_api)] -#![cfg_attr(stage0, feature(question_mark))] #![feature(specialization)] use std::cell::{Cell, RefCell}; diff --git a/src/libterm/lib.rs b/src/libterm/lib.rs index caef808f474..01daa938142 100644 --- a/src/libterm/lib.rs +++ b/src/libterm/lib.rs @@ -59,7 +59,6 @@ #![cfg_attr(windows, feature(libc))] // Handle rustfmt skips #![feature(custom_attribute)] -#![cfg_attr(stage0, feature(question_mark))] #![allow(unused_attributes)] use std::io::prelude::*; diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 8749a64e5fd..142ae86c6a3 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -38,7 +38,6 @@ #![feature(rustc_private)] #![feature(set_stdio)] #![feature(staged_api)] -#![cfg_attr(stage0, feature(question_mark))] #![feature(panic_unwind)] extern crate getopts; diff --git a/src/rustc/Cargo.toml b/src/rustc/Cargo.toml index 24499cb8f08..dce1a0a8ec8 100644 --- a/src/rustc/Cargo.toml +++ b/src/rustc/Cargo.toml @@ -11,17 +11,6 @@ path = "rustc.rs" name = "rustdoc" path = "rustdoc.rs" -[profile.release] -opt-level = 2 -[profile.bench] -opt-level = 2 - -# These options are controlled from our rustc wrapper script, so turn them off -# here and have them controlled elsewhere. -[profile.dev] -debug = false -debug-assertions = false - # All optional dependencies so the features passed to this Cargo.toml select # what should actually be built. [dependencies] diff --git a/src/rustc/std_shim/Cargo.toml b/src/rustc/std_shim/Cargo.toml index b4b7acc4e66..18680dc4fd9 100644 --- a/src/rustc/std_shim/Cargo.toml +++ b/src/rustc/std_shim/Cargo.toml @@ -28,17 +28,6 @@ authors = ["The Rust Project Developers"] name = "std_shim" path = "lib.rs" -[profile.release] -opt-level = 2 -[profile.bench] -opt-level = 2 - -# These options are controlled from our rustc wrapper script, so turn them off -# here and have them controlled elsewhere. -[profile.dev] -debug = false -debug-assertions = false - [dependencies] std = { path = "../../libstd" } core = { path = "../../libcore" } diff --git a/src/rustc/test_shim/Cargo.toml b/src/rustc/test_shim/Cargo.toml index 87f2ccd51e8..ac7842770f5 100644 --- a/src/rustc/test_shim/Cargo.toml +++ b/src/rustc/test_shim/Cargo.toml @@ -12,16 +12,5 @@ authors = ["The Rust Project Developers"] name = "test_shim" path = "lib.rs" -[profile.release] -opt-level = 2 -[profile.bench] -opt-level = 2 - -# These options are controlled from our rustc wrapper script, so turn them off -# here and have them controlled elsewhere. -[profile.dev] -debug = false -debug-assertions = false - [dependencies] test = { path = "../../libtest" } diff --git a/src/stage0.txt b/src/stage0.txt index ac2050a6fc8..223974186b1 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -12,5 +12,5 @@ # tarball for a stable release you'll likely see `1.x.0-$date` where `1.x.0` was # released on `$date` -rustc: beta-2016-09-28 -cargo: nightly-2016-09-26 +rustc: beta-2016-11-16 +cargo: nightly-2016-11-16 diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index e05d57365f8..227b695635d 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -4,12 +4,6 @@ name = "compiletest" version = "0.0.0" build = "build.rs" -# Curiously, this will segfault if compiled with opt-level=3 on 64-bit MSVC when -# running the compile-fail test suite when a should-fail test panics. But hey if -# this is removed and it gets past the bots, sounds good to me. -[profile.release] -opt-level = 2 - [dependencies] log = "0.3" env_logger = { version = "0.3.5", default-features = false } diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 806363679d1..d8681c9d6ed 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -16,8 +16,6 @@ #![feature(test)] #![feature(libc)] -#![cfg_attr(stage0, feature(question_mark))] - #![deny(warnings)] extern crate libc; diff --git a/src/vendor/md5/.cargo-checksum.json b/src/vendor/md5/.cargo-checksum.json deleted file mode 100644 index 5d44203c12c..00000000000 --- a/src/vendor/md5/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"944bf600c6230664922a011cbca026699969f2f89f6c7ff689835836ccd7b1de",".travis.yml":"3d7b50e89ac6ecc0c3a31273c1785a905aa528ccf70503973bf34fa49537519f","Cargo.toml":"7ed65153877c1057bac21ad6483ae2f6feb7713da2516f788528c81c222e1686","LICENSE.txt":"2362080adc3f0fb1a071ffe7dc5557cbb420058f319e284d53213a1e05687242","README.md":"f96785f9a0782f425cde37f0e4ec577f1097f92c38af291509e3953c20e9b87f","benches/lib.rs":"7ae37fded40473821a1e0d898d3e978efddfd1a2d2efcd550b84089932c8db23","src/lib.rs":"208c67b843ebbc02be1649dd40235088bf87d00c1a336a162118b4f352a03cb0"},"package":"a5539a8dee9b4ae308c9c406a379838b435a8f2c84cf9fedc6d5a576be9888db"} \ No newline at end of file diff --git a/src/vendor/md5/.cargo-ok b/src/vendor/md5/.cargo-ok deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/vendor/md5/.gitignore b/src/vendor/md5/.gitignore deleted file mode 100644 index fa8d85ac52f..00000000000 --- a/src/vendor/md5/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -Cargo.lock -target diff --git a/src/vendor/md5/.travis.yml b/src/vendor/md5/.travis.yml deleted file mode 100644 index f68b0f3293b..00000000000 --- a/src/vendor/md5/.travis.yml +++ /dev/null @@ -1,11 +0,0 @@ -language: rust -sudo: required - -after_success: curl https://stainless-steel.github.io/travis/after_success.sh | bash - -env: - global: - secure: wq8fhRMctnvAck7rhva9151pveqKYK9uER9Dytdz1UIzWGbtuS5vpGdgc7txW/xtdyuLGbioPvziCvFvoQbGd3NfWpRM1fo4AIwaOxFpKgPPywgFrlBtqp1XmBmJUaAxcwMtQCbY7f0Q48ycQZsmuXRQSkMEXlXURNh8us96MP5Rm9B4UndArVUe/tEXqy8SNKFMHqKja6okvDg03hRDtfQtk8lu1+QkguA5Zd0tpNBw9UjxoUn/FL0yCP0hq0VP6It680hRAJmhpJ8XRayGvbb+PX2VZNcgHpMxtsoY2zAR5j+I6mVwjC8VMIeUMQQbu6yUeFrDQYpBC9d4syRupluNLLzbxzl3Pb6yUYjT6deniRJA5H4Bs5V68a5/wTaapmqkAUIZKiPYpQr4L0MGSyHvLuWf1L3WdOmJkUvsPUIJExqEpNFRhEPIc7a5ZcyzeFFYRTa1VnMaNlLB0ZP5fF5Mgjmh0cvq88LnrSZI9t3obJMD4F0GKLuI2tJM57WWCHETWziAtQ2h2Cx8J/tivH/zT78yrkzl4tX5garFG4C2OWDdyhX/8zFG197RYKb9fI802um9FHXO6fpq1G3GUH8sZhDZYn3MeexGvbKI0Rb48toBl7EjbPaIuE/PE4O0UoK5WJqJCS2lBgZMs64phcRef7/sRHga4znBea75TTI= - -notifications: - email: false diff --git a/src/vendor/md5/Cargo.toml b/src/vendor/md5/Cargo.toml deleted file mode 100644 index 30e221473a8..00000000000 --- a/src/vendor/md5/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "md5" -version = "0.1.1" -authors = ["Ivan Ukhov "] -license = "MIT" -repository = "https://github.com/stainless-steel/md5" -homepage = "https://github.com/stainless-steel/md5" -documentation = "https://stainless-steel.github.io/md5" -description = "The package provides the MD5 hash function." diff --git a/src/vendor/md5/LICENSE.txt b/src/vendor/md5/LICENSE.txt deleted file mode 100644 index 73b5827524f..00000000000 --- a/src/vendor/md5/LICENSE.txt +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright 2015 Ivan Ukhov - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/src/vendor/md5/README.md b/src/vendor/md5/README.md deleted file mode 100644 index 6104556dc6f..00000000000 --- a/src/vendor/md5/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# MD5 [![Version][version-img]][version-url] [![Status][status-img]][status-url] - -The package provides the [MD5][1] hash function. - -## [Documentation][doc] - -## Contributing - -1. Fork the project. -2. Implement your idea. -3. Open a pull request. - -[1]: https://en.wikipedia.org/wiki/MD5 - -[version-img]: https://img.shields.io/crates/v/md5.svg -[version-url]: https://crates.io/crates/md5 -[status-img]: https://travis-ci.org/stainless-steel/md5.svg?branch=master -[status-url]: https://travis-ci.org/stainless-steel/md5 -[doc]: https://stainless-steel.github.io/md5 diff --git a/src/vendor/md5/benches/lib.rs b/src/vendor/md5/benches/lib.rs deleted file mode 100644 index 6e898085b0f..00000000000 --- a/src/vendor/md5/benches/lib.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![feature(test)] - -extern crate md5; -extern crate test; - -#[bench] fn compute_0001000(bencher: &mut test::Bencher) { compute( 1000, bencher); } -#[bench] fn compute_0010000(bencher: &mut test::Bencher) { compute( 10000, bencher); } -#[bench] fn compute_0100000(bencher: &mut test::Bencher) { compute( 100000, bencher); } -#[bench] fn compute_1000000(bencher: &mut test::Bencher) { compute(1_000000, bencher); } - -fn compute(size: usize, bencher: &mut test::Bencher) { - let data = &vec![0xFFu8; size][..]; - bencher.iter(|| { - test::black_box(md5::compute(data)); - }); -} diff --git a/src/vendor/md5/src/lib.rs b/src/vendor/md5/src/lib.rs deleted file mode 100644 index 5f28269ccea..00000000000 --- a/src/vendor/md5/src/lib.rs +++ /dev/null @@ -1,340 +0,0 @@ -//! The [MD5][1] hash function. -//! -//! [1]: https://en.wikipedia.org/wiki/MD5 - -// The implementation is based on: -// http://people.csail.mit.edu/rivest/Md5.c - -use std::convert::From; -use std::io::{Result, Write}; -use std::mem; - -/// A digest. -pub type Digest = [u8; 16]; - -/// A context. -#[derive(Copy)] -pub struct Context { - handled: [u32; 2], - buffer: [u32; 4], - input: [u8; 64], -} - -impl Clone for Context { - #[inline] - fn clone(&self) -> Context { *self } -} - -const PADDING: [u8; 64] = [ - 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -]; - -impl Context { - /// Create a context for computing a digest. - #[inline] - pub fn new() -> Context { - Context { - handled: [0, 0], - buffer: [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476], - input: unsafe { mem::uninitialized() }, - } - } - - /// Consume data. - pub fn consume(&mut self, data: &[u8]) { - let mut input: [u32; 16] = unsafe { mem::uninitialized() }; - let mut k = ((self.handled[0] >> 3) & 0x3F) as usize; - - let length = data.len() as u32; - if (self.handled[0] + (length << 3)) < self.handled[0] { - self.handled[1] += 1; - } - self.handled[0] += length << 3; - self.handled[1] += length >> 29; - - for &value in data { - self.input[k] = value; - k += 1; - if k != 0x40 { - continue; - } - let mut j = 0; - for i in 0..16 { - input[i] = ((self.input[j + 3] as u32) << 24) | - ((self.input[j + 2] as u32) << 16) | - ((self.input[j + 1] as u32) << 8) | - ((self.input[j ] as u32) ); - j += 4; - } - transform(&mut self.buffer, &input); - k = 0; - } - } - - /// Finalize and return the digest. - pub fn compute(mut self) -> Digest { - let mut input: [u32; 16] = unsafe { mem::uninitialized() }; - let k = ((self.handled[0] >> 3) & 0x3F) as usize; - - input[14] = self.handled[0]; - input[15] = self.handled[1]; - - self.consume(&PADDING[..(if k < 56 { 56 - k } else { 120 - k })]); - - let mut j = 0; - for i in 0..14 { - input[i] = ((self.input[j + 3] as u32) << 24) | - ((self.input[j + 2] as u32) << 16) | - ((self.input[j + 1] as u32) << 8) | - ((self.input[j ] as u32) ); - j += 4; - } - transform(&mut self.buffer, &input); - - let mut digest: Digest = unsafe { mem::uninitialized() }; - - let mut j = 0; - for i in 0..4 { - digest[j ] = ((self.buffer[i] ) & 0xFF) as u8; - digest[j + 1] = ((self.buffer[i] >> 8) & 0xFF) as u8; - digest[j + 2] = ((self.buffer[i] >> 16) & 0xFF) as u8; - digest[j + 3] = ((self.buffer[i] >> 24) & 0xFF) as u8; - j += 4; - } - - digest - } -} - -impl Write for Context { - #[inline] - fn write(&mut self, data: &[u8]) -> Result { - self.consume(data); - Ok(data.len()) - } - - #[inline] - fn flush(&mut self) -> Result<()> { - Ok(()) - } -} - -impl From for Digest { - #[inline] - fn from(context: Context) -> Digest { - context.compute() - } -} - -/// Compute the digest of data. -#[inline] -pub fn compute(data: &[u8]) -> Digest { - let mut context = Context::new(); - context.consume(data); - context.compute() -} - -fn transform(buffer: &mut [u32; 4], input: &[u32; 16]) { - let (mut a, mut b, mut c, mut d) = (buffer[0], buffer[1], buffer[2], buffer[3]); - - macro_rules! add( - ($a:expr, $b:expr) => ($a.wrapping_add($b)); - ); - macro_rules! rotate( - ($x:expr, $n:expr) => (($x << $n) | ($x >> (32 - $n))); - ); - - { - macro_rules! F( - ($x:expr, $y:expr, $z:expr) => (($x & $y) | (!$x & $z)); - ); - macro_rules! T( - ($a:expr, $b:expr, $c:expr, $d:expr, $x:expr, $s:expr, $ac:expr) => ({ - $a = add!(add!(add!($a, F!($b, $c, $d)), $x), $ac); - $a = rotate!($a, $s); - $a = add!($a, $b); - }); - ); - - const S1: u32 = 7; - const S2: u32 = 12; - const S3: u32 = 17; - const S4: u32 = 22; - - T!(a, b, c, d, input[ 0], S1, 3614090360); - T!(d, a, b, c, input[ 1], S2, 3905402710); - T!(c, d, a, b, input[ 2], S3, 606105819); - T!(b, c, d, a, input[ 3], S4, 3250441966); - T!(a, b, c, d, input[ 4], S1, 4118548399); - T!(d, a, b, c, input[ 5], S2, 1200080426); - T!(c, d, a, b, input[ 6], S3, 2821735955); - T!(b, c, d, a, input[ 7], S4, 4249261313); - T!(a, b, c, d, input[ 8], S1, 1770035416); - T!(d, a, b, c, input[ 9], S2, 2336552879); - T!(c, d, a, b, input[10], S3, 4294925233); - T!(b, c, d, a, input[11], S4, 2304563134); - T!(a, b, c, d, input[12], S1, 1804603682); - T!(d, a, b, c, input[13], S2, 4254626195); - T!(c, d, a, b, input[14], S3, 2792965006); - T!(b, c, d, a, input[15], S4, 1236535329); - } - - { - macro_rules! F( - ($x:expr, $y:expr, $z:expr) => (($x & $z) | ($y & !$z)); - ); - macro_rules! T( - ($a:expr, $b:expr, $c:expr, $d:expr, $x:expr, $s:expr, $ac:expr) => ({ - $a = add!(add!(add!($a, F!($b, $c, $d)), $x), $ac); - $a = rotate!($a, $s); - $a = add!($a, $b); - }); - ); - - const S1: u32 = 5; - const S2: u32 = 9; - const S3: u32 = 14; - const S4: u32 = 20; - - T!(a, b, c, d, input[ 1], S1, 4129170786); - T!(d, a, b, c, input[ 6], S2, 3225465664); - T!(c, d, a, b, input[11], S3, 643717713); - T!(b, c, d, a, input[ 0], S4, 3921069994); - T!(a, b, c, d, input[ 5], S1, 3593408605); - T!(d, a, b, c, input[10], S2, 38016083); - T!(c, d, a, b, input[15], S3, 3634488961); - T!(b, c, d, a, input[ 4], S4, 3889429448); - T!(a, b, c, d, input[ 9], S1, 568446438); - T!(d, a, b, c, input[14], S2, 3275163606); - T!(c, d, a, b, input[ 3], S3, 4107603335); - T!(b, c, d, a, input[ 8], S4, 1163531501); - T!(a, b, c, d, input[13], S1, 2850285829); - T!(d, a, b, c, input[ 2], S2, 4243563512); - T!(c, d, a, b, input[ 7], S3, 1735328473); - T!(b, c, d, a, input[12], S4, 2368359562); - } - - { - macro_rules! F( - ($x:expr, $y:expr, $z:expr) => ($x ^ $y ^ $z); - ); - macro_rules! T( - ($a:expr, $b:expr, $c:expr, $d:expr, $x:expr, $s:expr, $ac:expr) => ({ - $a = add!(add!(add!($a, F!($b, $c, $d)), $x), $ac); - $a = rotate!($a, $s); - $a = add!($a, $b); - }); - ); - - const S1: u32 = 4; - const S2: u32 = 11; - const S3: u32 = 16; - const S4: u32 = 23; - - T!(a, b, c, d, input[ 5], S1, 4294588738); - T!(d, a, b, c, input[ 8], S2, 2272392833); - T!(c, d, a, b, input[11], S3, 1839030562); - T!(b, c, d, a, input[14], S4, 4259657740); - T!(a, b, c, d, input[ 1], S1, 2763975236); - T!(d, a, b, c, input[ 4], S2, 1272893353); - T!(c, d, a, b, input[ 7], S3, 4139469664); - T!(b, c, d, a, input[10], S4, 3200236656); - T!(a, b, c, d, input[13], S1, 681279174); - T!(d, a, b, c, input[ 0], S2, 3936430074); - T!(c, d, a, b, input[ 3], S3, 3572445317); - T!(b, c, d, a, input[ 6], S4, 76029189); - T!(a, b, c, d, input[ 9], S1, 3654602809); - T!(d, a, b, c, input[12], S2, 3873151461); - T!(c, d, a, b, input[15], S3, 530742520); - T!(b, c, d, a, input[ 2], S4, 3299628645); - } - - { - macro_rules! F( - ($x:expr, $y:expr, $z:expr) => ($y ^ ($x | !$z)); - ); - macro_rules! T( - ($a:expr, $b:expr, $c:expr, $d:expr, $x:expr, $s:expr, $ac:expr) => ({ - $a = add!(add!(add!($a, F!($b, $c, $d)), $x), $ac); - $a = rotate!($a, $s); - $a = add!($a, $b); - }); - ); - - const S1: u32 = 6; - const S2: u32 = 10; - const S3: u32 = 15; - const S4: u32 = 21; - - T!(a, b, c, d, input[ 0], S1, 4096336452); - T!(d, a, b, c, input[ 7], S2, 1126891415); - T!(c, d, a, b, input[14], S3, 2878612391); - T!(b, c, d, a, input[ 5], S4, 4237533241); - T!(a, b, c, d, input[12], S1, 1700485571); - T!(d, a, b, c, input[ 3], S2, 2399980690); - T!(c, d, a, b, input[10], S3, 4293915773); - T!(b, c, d, a, input[ 1], S4, 2240044497); - T!(a, b, c, d, input[ 8], S1, 1873313359); - T!(d, a, b, c, input[15], S2, 4264355552); - T!(c, d, a, b, input[ 6], S3, 2734768916); - T!(b, c, d, a, input[13], S4, 1309151649); - T!(a, b, c, d, input[ 4], S1, 4149444226); - T!(d, a, b, c, input[11], S2, 3174756917); - T!(c, d, a, b, input[ 2], S3, 718787259); - T!(b, c, d, a, input[ 9], S4, 3951481745); - } - - buffer[0] = add!(buffer[0], a); - buffer[1] = add!(buffer[1], b); - buffer[2] = add!(buffer[2], c); - buffer[3] = add!(buffer[3], d); -} - -#[cfg(test)] -mod tests { - macro_rules! digest( - ($string:expr) => ({ - let mut context = ::Context::new(); - context.consume($string.as_bytes()); - let mut digest = String::with_capacity(2 * 16); - for x in &context.compute()[..] { - digest.push_str(&format!("{:02x}", x)); - } - digest - }); - ); - - #[test] - fn compute() { - let inputs = [ - "", - "a", - "abc", - "message digest", - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", - "12345678901234567890123456789012345678901234567890123456789012345678901234567890", - ]; - - let outputs = [ - "d41d8cd98f00b204e9800998ecf8427e", - "0cc175b9c0f1b6a831c399e269772661", - "900150983cd24fb0d6963f7d28e17f72", - "f96b697d7cb7938d525a2f31aaf161d0", - "c3fcd3d76192e4007dfb496cca67e13b", - "d174ab98d277d9f5a5611c2c9f419d9f", - "57edf4a22be3c955ac49da2e2107b67a", - ]; - - for (input, &output) in inputs.iter().zip(outputs.iter()) { - assert_eq!(&digest!(input)[..], output); - } - } -} From ff1ba6a5052a3d995c31a2266e0b9cd6b1d44c1e Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 30 Nov 2016 18:14:17 +0100 Subject: [PATCH 173/293] Adds `-Z mir-stats`, which is similar to `-Z hir-stats`. Some notes: * This code attempts to present the breakdown of each variant for every enum in the MIR. This is meant to guide decisions about how to revise representations e.g. when to box payloads for rare variants to shrink the size of the enum overall. * I left out the "Total:" line that hir-stats presents, because this implementation uses the MIR Visitor infrastructure, and the memory usage of structures directly embedded in other structures (e.g. the `func: Operand` in a `TerminatorKind:Call`) is not distinguished from similar structures allocated in a `Vec` (e.g. the `args: Vec` in a `TerminatorKind::Call`). This means that a naive summation of all the accumulated sizes is misleading, because it will double-count the contribution of the `Operand` of the `func` as well as the size of the whole `TerminatorKind`. * I did consider abandoning the MIR Visitor and instead hand-coding a traversal that distinguished embedded storage from indirect storage. But such code would be fragile; better to just require people to take care when interpreting the presented results. * This traverses the `mir.promoted` rvalues to capture stats for MIR stored there, even though the MIR visitor super_mir method does not do so. (I did not observe any new mir being traversed when compiling the rustc crate, however.) * It might be nice to try to unify this code with hir-stats. Then again, the reporting portion is the only common code (I think), and it is small compared to the visitors in hir-stats and mir-stats. --- src/librustc/session/config.rs | 2 + src/librustc_driver/driver.rs | 14 +- src/librustc_passes/lib.rs | 1 + src/librustc_passes/mir_stats.rs | 319 +++++++++++++++++++++++++++++++ 4 files changed, 335 insertions(+), 1 deletion(-) create mode 100644 src/librustc_passes/mir_stats.rs diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 26dafed7019..d5555a919fe 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -923,6 +923,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "print some performance-related statistics"), hir_stats: bool = (false, parse_bool, [UNTRACKED], "print some statistics about AST and HIR"), + mir_stats: bool = (false, parse_bool, [UNTRACKED], + "print some statistics about MIR"), } pub fn default_lib_output() -> CrateType { diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index bee79103b41..f55656c7fcc 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -37,7 +37,7 @@ use rustc_privacy; use rustc_plugin::registry::Registry; use rustc_plugin as plugin; use rustc_passes::{ast_validation, no_asm, loops, consts, rvalues, - static_recursion, hir_stats}; + static_recursion, hir_stats, mir_stats}; use rustc_const_eval::check_match; use super::Compilation; @@ -932,6 +932,10 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, "MIR dump", || mir::mir_map::build_mir_for_crate(tcx)); + if sess.opts.debugging_opts.mir_stats { + mir_stats::print_mir_stats(tcx, "PRE CLEANUP MIR STATS"); + } + time(time_passes, "MIR cleanup and validation", || { let mut passes = sess.mir_passes.borrow_mut(); // Push all the built-in validation passes. @@ -1000,6 +1004,10 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, "resolving dependency formats", || dependency_format::calculate(&tcx.sess)); + if tcx.sess.opts.debugging_opts.mir_stats { + mir_stats::print_mir_stats(tcx, "PRE OPTIMISATION MIR STATS"); + } + // Run the passes that transform the MIR into a more suitable form for translation to LLVM // code. time(time_passes, "MIR optimisations", || { @@ -1028,6 +1036,10 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, passes.run_passes(tcx); }); + if tcx.sess.opts.debugging_opts.mir_stats { + mir_stats::print_mir_stats(tcx, "POST OPTIMISATION MIR STATS"); + } + let translation = time(time_passes, "translation", diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs index 039a76d25c7..aea0b929f35 100644 --- a/src/librustc_passes/lib.rs +++ b/src/librustc_passes/lib.rs @@ -47,6 +47,7 @@ pub mod ast_validation; pub mod consts; pub mod hir_stats; pub mod loops; +pub mod mir_stats; pub mod no_asm; pub mod rvalues; pub mod static_recursion; diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs new file mode 100644 index 00000000000..cec1c20519b --- /dev/null +++ b/src/librustc_passes/mir_stats.rs @@ -0,0 +1,319 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// The visitors in this module collect sizes and counts of the most important +// pieces of MIR. The resulting numbers are good approximations but not +// completely accurate (some things might be counted twice, others missed). + +use rustc_const_math::{ConstUsize}; +use rustc::middle::const_val::{ConstVal}; +use rustc::mir::{AggregateKind, AssertMessage, BasicBlock, BasicBlockData}; +use rustc::mir::{Constant, Literal, Location, LocalDecl}; +use rustc::mir::{Lvalue, LvalueElem, LvalueProjection}; +use rustc::mir::{Mir, Operand, ProjectionElem}; +use rustc::mir::{Rvalue, SourceInfo, Statement, StatementKind}; +use rustc::mir::{Terminator, TerminatorKind, TypedConstVal, VisibilityScope, VisibilityScopeData}; +use rustc::mir::visit as mir_visit; +use rustc::mir::visit::Visitor; +use rustc::ty::{ClosureSubsts, TyCtxt}; +use rustc::util::common::to_readable_str; +use rustc::util::nodemap::{FxHashMap}; + +struct NodeData { + count: usize, + size: usize, +} + +struct StatCollector<'a, 'tcx: 'a> { + _tcx: TyCtxt<'a, 'tcx, 'tcx>, + data: FxHashMap<&'static str, NodeData>, +} + +pub fn print_mir_stats<'tcx, 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, title: &str) { + let mut collector = StatCollector { + _tcx: tcx, + data: FxHashMap(), + }; + // For debugging instrumentation like this, we don't need to worry + // about maintaining the dep graph. + let _ignore = tcx.dep_graph.in_ignore(); + let mir_map = tcx.mir_map.borrow(); + for def_id in mir_map.keys() { + let mir = mir_map.get(&def_id).unwrap(); + collector.visit_mir(&mir.borrow()); + } + collector.print(title); +} + +impl<'a, 'tcx> StatCollector<'a, 'tcx> { + + fn record_with_size(&mut self, label: &'static str, node_size: usize) { + let entry = self.data.entry(label).or_insert(NodeData { + count: 0, + size: 0, + }); + + entry.count += 1; + entry.size = node_size; + } + + fn record(&mut self, label: &'static str, node: &T) { + self.record_with_size(label, ::std::mem::size_of_val(node)); + } + + fn print(&self, title: &str) { + let mut stats: Vec<_> = self.data.iter().collect(); + + stats.sort_by_key(|&(_, ref d)| d.count * d.size); + + println!("\n{}\n", title); + + println!("{:<32}{:>18}{:>14}{:>14}", + "Name", "Accumulated Size", "Count", "Item Size"); + println!("------------------------------------------------------------------------------"); + + for (label, data) in stats { + println!("{:<32}{:>18}{:>14}{:>14}", + label, + to_readable_str(data.count * data.size), + to_readable_str(data.count), + to_readable_str(data.size)); + } + println!("------------------------------------------------------------------------------"); + } +} + +impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> { + fn visit_mir(&mut self, mir: &Mir<'tcx>) { + self.record("Mir", mir); + + // since the `super_mir` method does not traverse the MIR of + // promoted rvalues, (but we still want to gather statistics + // on the structures represented there) we manually traverse + // the promoted rvalues here. + for promoted_mir in &mir.promoted { + self.visit_mir(promoted_mir); + } + + self.super_mir(mir); + } + + fn visit_basic_block_data(&mut self, + block: BasicBlock, + data: &BasicBlockData<'tcx>) { + self.record("BasicBlockData", data); + self.super_basic_block_data(block, data); + } + + fn visit_visibility_scope_data(&mut self, + scope_data: &VisibilityScopeData) { + self.record("VisibilityScopeData", scope_data); + self.super_visibility_scope_data(scope_data); + } + + fn visit_statement(&mut self, + block: BasicBlock, + statement: &Statement<'tcx>, + location: Location) { + self.record("Statement", statement); + self.record(match statement.kind { + StatementKind::Assign(..) => "StatementKind::Assign", + StatementKind::SetDiscriminant { .. } => "StatementKind::SetDiscriminant", + StatementKind::StorageLive(..) => "StatementKind::StorageLive", + StatementKind::StorageDead(..) => "StatementKind::StorageDead", + StatementKind::Nop => "StatementKind::Nop", + }, &statement.kind); + self.super_statement(block, statement, location); + } + + fn visit_terminator(&mut self, + block: BasicBlock, + terminator: &Terminator<'tcx>, + location: Location) { + self.record("Terminator", terminator); + self.super_terminator(block, terminator, location); + } + + fn visit_terminator_kind(&mut self, + block: BasicBlock, + kind: &TerminatorKind<'tcx>, + location: Location) { + self.record("TerminatorKind", kind); + self.record(match *kind { + TerminatorKind::Goto { .. } => "TerminatorKind::Goto", + TerminatorKind::If { .. } => "TerminatorKind::If", + TerminatorKind::Switch { .. } => "TerminatorKind::Switch", + TerminatorKind::SwitchInt { .. } => "TerminatorKind::SwitchInt", + TerminatorKind::Resume => "TerminatorKind::Resume", + TerminatorKind::Return => "TerminatorKind::Return", + TerminatorKind::Unreachable => "TerminatorKind::Unreachable", + TerminatorKind::Drop { .. } => "TerminatorKind::Drop", + TerminatorKind::DropAndReplace { .. } => "TerminatorKind::DropAndReplace", + TerminatorKind::Call { .. } => "TerminatorKind::Call", + TerminatorKind::Assert { .. } => "TerminatorKind::Assert", + }, kind); + self.super_terminator_kind(block, kind, location); + } + + fn visit_assert_message(&mut self, + msg: &AssertMessage<'tcx>, + location: Location) { + self.record("AssertMessage", msg); + self.record(match *msg { + AssertMessage::BoundsCheck { .. } => "AssertMessage::BoundsCheck", + AssertMessage::Math(..) => "AssertMessage::Math", + }, msg); + self.super_assert_message(msg, location); + } + + fn visit_rvalue(&mut self, + rvalue: &Rvalue<'tcx>, + location: Location) { + self.record("Rvalue", rvalue); + let rvalue_kind = match *rvalue { + Rvalue::Use(..) => "Rvalue::Use", + Rvalue::Repeat(..) => "Rvalue::Repeat", + Rvalue::Ref(..) => "Rvalue::Ref", + Rvalue::Len(..) => "Rvalue::Len", + Rvalue::Cast(..) => "Rvalue::Cast", + Rvalue::BinaryOp(..) => "Rvalue::BinaryOp", + Rvalue::CheckedBinaryOp(..) => "Rvalue::CheckedBinaryOp", + Rvalue::UnaryOp(..) => "Rvalue::UnaryOp", + Rvalue::Box(..) => "Rvalue::Box", + Rvalue::Aggregate(ref kind, ref _operands) => { + // AggregateKind is not distinguished by visit API, so + // record it. (`super_rvalue` handles `_operands`.) + self.record(match *kind { + AggregateKind::Array => "AggregateKind::Array", + AggregateKind::Tuple => "AggregateKind::Tuple", + AggregateKind::Adt(..) => "AggregateKind::Adt", + AggregateKind::Closure(..) => "AggregateKind::Closure", + }, kind); + + "Rvalue::Aggregate" + } + Rvalue::InlineAsm { .. } => "Rvalue::InlineAsm", + }; + self.record(rvalue_kind, rvalue); + self.super_rvalue(rvalue, location); + } + + fn visit_operand(&mut self, + operand: &Operand<'tcx>, + location: Location) { + self.record("Operand", operand); + self.record(match *operand { + Operand::Consume(..) => "Operand::Consume", + Operand::Constant(..) => "Operand::Constant", + }, operand); + self.super_operand(operand, location); + } + + fn visit_lvalue(&mut self, + lvalue: &Lvalue<'tcx>, + context: mir_visit::LvalueContext<'tcx>, + location: Location) { + self.record("Lvalue", lvalue); + self.record(match *lvalue { + Lvalue::Local(..) => "Lvalue::Local", + Lvalue::Static(..) => "Lvalue::Static", + Lvalue::Projection(..) => "Lvalue::Projection", + }, lvalue); + self.super_lvalue(lvalue, context, location); + } + + fn visit_projection(&mut self, + lvalue: &LvalueProjection<'tcx>, + context: mir_visit::LvalueContext<'tcx>, + location: Location) { + self.record("LvalueProjection", lvalue); + self.super_projection(lvalue, context, location); + } + + fn visit_projection_elem(&mut self, + lvalue: &LvalueElem<'tcx>, + context: mir_visit::LvalueContext<'tcx>, + location: Location) { + self.record("LvalueElem", lvalue); + self.record(match *lvalue { + ProjectionElem::Deref => "LvalueElem::Deref", + ProjectionElem::Subslice { .. } => "LvalueElem::Subslice", + ProjectionElem::Field(..) => "LvalueElem::Field", + ProjectionElem::Index(..) => "LvalueElem::Index", + ProjectionElem::ConstantIndex { .. } => "LvalueElem::ConstantIndex", + ProjectionElem::Downcast(..) => "LvalueElem::Downcast", + }, lvalue); + self.super_projection_elem(lvalue, context, location); + } + + fn visit_constant(&mut self, + constant: &Constant<'tcx>, + location: Location) { + self.record("Constant", constant); + self.super_constant(constant, location); + } + + fn visit_literal(&mut self, + literal: &Literal<'tcx>, + location: Location) { + self.record("Literal", literal); + self.record(match *literal { + Literal::Item { .. } => "Literal::Item", + Literal::Value { .. } => "Literal::Value", + Literal::Promoted { .. } => "Literal::Promoted", + }, literal); + self.super_literal(literal, location); + } + + fn visit_source_info(&mut self, + source_info: &SourceInfo) { + self.record("SourceInfo", source_info); + self.super_source_info(source_info); + } + + fn visit_closure_substs(&mut self, + substs: &ClosureSubsts<'tcx>) { + self.record("ClosureSubsts", substs); + self.super_closure_substs(substs); + } + + fn visit_const_val(&mut self, + const_val: &ConstVal, + _: Location) { + self.record("ConstVal", const_val); + self.super_const_val(const_val); + } + + fn visit_const_usize(&mut self, + const_usize: &ConstUsize, + _: Location) { + self.record("ConstUsize", const_usize); + self.super_const_usize(const_usize); + } + + fn visit_typed_const_val(&mut self, + val: &TypedConstVal<'tcx>, + location: Location) { + self.record("TypedConstVal", val); + self.super_typed_const_val(val, location); + } + + fn visit_local_decl(&mut self, + local_decl: &LocalDecl<'tcx>) { + self.record("LocalDecl", local_decl); + self.super_local_decl(local_decl); + } + + fn visit_visibility_scope(&mut self, + scope: &VisibilityScope) { + self.record("VisiblityScope", scope); + self.super_visibility_scope(scope); + } +} From 29791ada1ddfbb37c5ad90fc8149577f426cc995 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sun, 27 Nov 2016 10:27:41 +0000 Subject: [PATCH 174/293] Minor cleanup. --- src/librustc_resolve/build_reduced_graph.rs | 8 +++----- src/librustc_resolve/lib.rs | 8 ++++++++ src/librustc_resolve/macros.rs | 12 ++++++------ 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index d90a49213d1..7bcc543023e 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -501,11 +501,9 @@ impl<'b> Resolver<'b> { }) } - pub fn get_macro(&mut self, binding: &'b NameBinding<'b>) -> Rc { - let def_id = match binding.kind { - NameBindingKind::Def(Def::Macro(def_id)) => def_id, - NameBindingKind::Import { binding, .. } => return self.get_macro(binding), - NameBindingKind::Ambiguity { b1, .. } => return self.get_macro(b1), + pub fn get_macro(&mut self, def: Def) -> Rc { + let def_id = match def { + Def::Macro(def_id) => def_id, _ => panic!("Expected Def::Macro(..)"), }; if let Some(ext) = self.macro_map.get(&def_id) { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index e1200149dcc..1c8c77a13d9 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -925,6 +925,14 @@ impl<'a> NameBinding<'a> { } } + fn get_macro(&self, resolver: &mut Resolver<'a>) -> Rc { + match self.kind { + NameBindingKind::Import { binding, .. } => binding.get_macro(resolver), + NameBindingKind::Ambiguity { b1, .. } => b1.get_macro(resolver), + _ => resolver.get_macro(self.def()), + } + } + // We sometimes need to treat variants as `pub` for backwards compatibility fn pseudo_vis(&self) -> ty::Visibility { if self.is_variant() { ty::Visibility::Public } else { self.vis } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 3b34a60c585..ff91e7dc971 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -193,7 +193,7 @@ impl<'a> base::Resolver for Resolver<'a> { fn find_attr_invoc(&mut self, attrs: &mut Vec) -> Option { for i in 0..attrs.len() { match self.builtin_macros.get(&attrs[i].name()).cloned() { - Some(binding) => match *self.get_macro(binding) { + Some(binding) => match *binding.get_macro(self) { MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => { return Some(attrs.remove(i)) } @@ -215,11 +215,11 @@ impl<'a> base::Resolver for Resolver<'a> { let invocation = self.invocations[&scope]; self.current_module = invocation.module.get(); - let result = match self.resolve_legacy_scope(&invocation.legacy_scope, name, false) { - Some(MacroBinding::Legacy(binding)) => Ok(binding.ext.clone()), - Some(MacroBinding::Modern(binding)) => Ok(self.get_macro(binding)), + let ext = match self.resolve_legacy_scope(&invocation.legacy_scope, name, false) { + Some(MacroBinding::Legacy(binding)) => binding.ext.clone(), + Some(MacroBinding::Modern(binding)) => binding.get_macro(self), None => match self.resolve_in_item_lexical_scope(name, MacroNS, None) { - Some(binding) => Ok(self.get_macro(binding)), + Some(binding) => binding.get_macro(self), None => return Err(if force { let msg = format!("macro undefined: '{}!'", name); let mut err = self.session.struct_span_err(path.span, &msg); @@ -236,7 +236,7 @@ impl<'a> base::Resolver for Resolver<'a> { self.current_module.legacy_macro_resolutions.borrow_mut() .push((scope, name, path.span)); } - result + Ok(ext) } } From 8d9d07a1ca25d003b57b08f5930ae3e9a27cd37c Mon Sep 17 00:00:00 2001 From: Theodore DeRego Date: Wed, 30 Nov 2016 14:20:44 -0800 Subject: [PATCH 175/293] Removed Option member from fuchsia Process struct. Destroy launchpads and close handles in Drop impls rather than manually --- src/libstd/sys/unix/magenta.rs | 26 ++++++++++ .../sys/unix/process/process_fuchsia.rs | 51 +++++++------------ 2 files changed, 45 insertions(+), 32 deletions(-) diff --git a/src/libstd/sys/unix/magenta.rs b/src/libstd/sys/unix/magenta.rs index 155259d2645..20e077ccaca 100644 --- a/src/libstd/sys/unix/magenta.rs +++ b/src/libstd/sys/unix/magenta.rs @@ -42,6 +42,30 @@ pub const MX_INFO_PROCESS : mx_object_info_topic_t = 3; pub const MX_HND_TYPE_JOB: u32 = 6; +// Safe wrapper around mx_handle_t +pub struct Handle { + raw: mx_handle_t, +} + +impl Handle { + pub fn new(raw: mx_handle_t) -> Handle { + Handle { + raw: raw, + } + } + + pub fn raw(&self) -> mx_handle_t { + self.raw + } +} + +impl Drop for Handle { + fn drop(&mut self) { + use sys::mx_cvt; + unsafe { mx_cvt(mx_handle_close(self.raw)).expect("Failed to close mx_handle_t"); } + } +} + // Common MX_INFO header #[derive(Default)] #[repr(C)] @@ -68,6 +92,8 @@ pub struct mx_info_process_t { } extern { + pub fn mx_task_kill(handle: mx_handle_t) -> mx_status_t; + pub fn mx_handle_close(handle: mx_handle_t) -> mx_status_t; pub fn mx_handle_duplicate(handle: mx_handle_t, rights: mx_rights_t, diff --git a/src/libstd/sys/unix/process/process_fuchsia.rs b/src/libstd/sys/unix/process/process_fuchsia.rs index 30e5555df69..77340664b6a 100644 --- a/src/libstd/sys/unix/process/process_fuchsia.rs +++ b/src/libstd/sys/unix/process/process_fuchsia.rs @@ -14,7 +14,7 @@ use mem; use ptr; use sys::mx_cvt; -use sys::magenta::{launchpad_t, mx_handle_t}; +use sys::magenta::{Handle, launchpad_t, mx_handle_t}; use sys::process::process_common::*; //////////////////////////////////////////////////////////////////////////////// @@ -33,7 +33,7 @@ impl Command { let (launchpad, process_handle) = unsafe { self.do_exec(theirs)? }; - Ok((Process { launchpad: launchpad, handle: process_handle, status: None }, ours)) + Ok((Process { launchpad: launchpad, handle: Handle::new(process_handle) }, ours)) } pub fn exec(&mut self, default: Stdio) -> io::Error { @@ -116,7 +116,7 @@ impl Command { let process_handle = mx_cvt(launchpad_start(launchpad))?; - // Successfully started the launchpad, so launchpad_destroy shouldn't get called + // Successfully started the launchpad mem::forget(launchpad_destructor); Ok((launchpad, process_handle)) @@ -129,62 +129,49 @@ impl Command { pub struct Process { launchpad: *mut launchpad_t, - handle: mx_handle_t, - status: Option, + handle: Handle, } impl Process { pub fn id(&self) -> u32 { - self.handle as u32 + self.handle.raw() as u32 } pub fn kill(&mut self) -> io::Result<()> { use sys::magenta::*; - // If we've already waited on this process then the pid can be recycled - // and used for another process, and we probably shouldn't be killing - // random processes, so just return an error. - if self.status.is_some() { - Err(io::Error::new(io::ErrorKind::InvalidInput, - "invalid argument: can't kill an exited process")) - } else { - unsafe { - mx_cvt(mx_handle_close(self.handle))?; - launchpad_destroy(self.launchpad); - } - Ok(()) - } + unsafe { mx_cvt(mx_task_kill(self.handle.raw()))?; } + + Ok(()) } pub fn wait(&mut self) -> io::Result { use default::Default; use sys::magenta::*; - if let Some(status) = self.status { - return Ok(status) - } - let mut proc_info: mx_info_process_t = Default::default(); let mut actual: mx_size_t = 0; let mut avail: mx_size_t = 0; unsafe { - mx_cvt(mx_handle_wait_one(self.handle, MX_TASK_TERMINATED, + mx_cvt(mx_handle_wait_one(self.handle.raw(), MX_TASK_TERMINATED, MX_TIME_INFINITE, ptr::null_mut()))?; - mx_cvt(mx_object_get_info(self.handle, MX_INFO_PROCESS, + mx_cvt(mx_object_get_info(self.handle.raw(), MX_INFO_PROCESS, &mut proc_info as *mut _ as *mut libc::c_void, mem::size_of::(), &mut actual, &mut avail))?; } if actual != 1 { - return Err(io::Error::new(io::ErrorKind::InvalidInput, - "Failed to get exit status of process")); - } - self.status = Some(ExitStatus::new(proc_info.rec.return_code)); - unsafe { - mx_cvt(mx_handle_close(self.handle))?; - launchpad_destroy(self.launchpad); + return Err(io::Error::new(io::ErrorKind::InvalidData, + "Failed to get exit status of process")); } Ok(ExitStatus::new(proc_info.rec.return_code)) } } + +impl Drop for Process { + fn drop(&mut self) { + use sys::magenta::launchpad_destroy; + unsafe { launchpad_destroy(self.launchpad); } + } +} From 29a6ffa4010d965a6c587c9ffd1ce88bbea164c9 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 30 Nov 2016 17:33:52 -0500 Subject: [PATCH 176/293] incr.comp.: Add more output to -Z incremental-info. --- .../persist/file_format.rs | 16 +++++++++- src/librustc_incremental/persist/fs.rs | 4 +-- src/librustc_incremental/persist/hash.rs | 2 +- src/librustc_incremental/persist/load.rs | 32 ++++++++++++------- src/librustc_trans/base.rs | 5 +++ 5 files changed, 44 insertions(+), 15 deletions(-) diff --git a/src/librustc_incremental/persist/file_format.rs b/src/librustc_incremental/persist/file_format.rs index 7c2b69e762b..b67caa6750a 100644 --- a/src/librustc_incremental/persist/file_format.rs +++ b/src/librustc_incremental/persist/file_format.rs @@ -24,6 +24,7 @@ use std::path::Path; use std::fs::File; use std::env; +use rustc::session::Session; use rustc::session::config::nightly_options; /// The first few bytes of files generated by incremental compilation @@ -59,7 +60,7 @@ pub fn write_file_header(stream: &mut W) -> io::Result<()> { /// incompatible version of the compiler. /// - Returns `Err(..)` if some kind of IO error occurred while reading the /// file. -pub fn read_file(path: &Path) -> io::Result>> { +pub fn read_file(sess: &Session, path: &Path) -> io::Result>> { if !path.exists() { return Ok(None); } @@ -72,6 +73,7 @@ pub fn read_file(path: &Path) -> io::Result>> { let mut file_magic = [0u8; 4]; file.read_exact(&mut file_magic)?; if file_magic != FILE_MAGIC { + report_format_mismatch(sess, path, "Wrong FILE_MAGIC"); return Ok(None) } } @@ -85,6 +87,7 @@ pub fn read_file(path: &Path) -> io::Result>> { ((header_format_version[1] as u16) << 8); if header_format_version != HEADER_FORMAT_VERSION { + report_format_mismatch(sess, path, "Wrong HEADER_FORMAT_VERSION"); return Ok(None) } } @@ -99,6 +102,7 @@ pub fn read_file(path: &Path) -> io::Result>> { file.read_exact(&mut buffer[..])?; if &buffer[..] != rustc_version().as_bytes() { + report_format_mismatch(sess, path, "Different compiler version"); return Ok(None); } } @@ -109,6 +113,16 @@ pub fn read_file(path: &Path) -> io::Result>> { Ok(Some(data)) } +fn report_format_mismatch(sess: &Session, file: &Path, message: &str) { + debug!("read_file: {}", message); + + if sess.opts.debugging_opts.incremental_info { + println!("incremental: ignoring cache artifact `{}`: {}", + file.file_name().unwrap().to_string_lossy(), + message); + } +} + fn rustc_version() -> String { if nightly_options::is_nightly_build() { if let Some(val) = env::var_os("RUSTC_FORCE_INCR_COMP_ARTIFACT_HEADER") { diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs index 26181dbaf50..2ad37e98c70 100644 --- a/src/librustc_incremental/persist/fs.rs +++ b/src/librustc_incremental/persist/fs.rs @@ -435,8 +435,8 @@ fn copy_files(target_dir: &Path, } if print_stats_on_success { - println!("incr. comp. session directory: {} files hard-linked", files_linked); - println!("incr. comp. session directory: {} files copied", files_copied); + println!("incremental: session directory: {} files hard-linked", files_linked); + println!("incremental: session directory: {} files copied", files_copied); } Ok(files_linked > 0 || files_copied == 0) diff --git a/src/librustc_incremental/persist/hash.rs b/src/librustc_incremental/persist/hash.rs index 562efa4b0d2..e5203ea02b4 100644 --- a/src/librustc_incremental/persist/hash.rs +++ b/src/librustc_incremental/persist/hash.rs @@ -156,7 +156,7 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> { let hashes_file_path = metadata_hash_import_path(&session_dir); - match file_format::read_file(&hashes_file_path) + match file_format::read_file(self.tcx.sess, &hashes_file_path) { Ok(Some(data)) => { match self.load_from_data(cnum, &data, svh) { diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index 12bf74c9511..ec7e0bf2cf7 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -93,7 +93,7 @@ fn load_dep_graph_if_exists<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } fn load_data(sess: &Session, path: &Path) -> Option> { - match file_format::read_file(path) { + match file_format::read_file(sess, path) { Ok(Some(data)) => return Some(data), Ok(None) => { // The file either didn't exist or was produced by an incompatible @@ -132,6 +132,10 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let prev_commandline_args_hash = u64::decode(&mut dep_graph_decoder)?; if prev_commandline_args_hash != tcx.sess.opts.dep_tracking_hash() { + if tcx.sess.opts.debugging_opts.incremental_info { + println!("incremental: completely ignoring cache because of \ + differing commandline arguments"); + } // We can't reuse the cache, purge it. debug!("decode_dep_graph: differing commandline arg hashes"); for swp in work_products { @@ -192,7 +196,8 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if tcx.sess.opts.debugging_opts.incremental_info { // It'd be nice to pretty-print these paths better than just // using the `Debug` impls, but wev. - println!("module {:?} is dirty because {:?} changed or was removed", + println!("incremental: module {:?} is dirty because {:?} \ + changed or was removed", target_node, raw_source_node.map_def(|&index| { Some(directory.def_path_string(tcx, index)) @@ -277,14 +282,19 @@ fn reconcile_work_products<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("reconcile_work_products: dep-node for {:?} is dirty", swp); delete_dirty_work_product(tcx, swp); } else { - let all_files_exist = - swp.work_product - .saved_files - .iter() - .all(|&(_, ref file_name)| { - let path = in_incr_comp_dir_sess(tcx.sess, &file_name); - path.exists() - }); + let mut all_files_exist = true; + for &(_, ref file_name) in swp.work_product.saved_files.iter() { + let path = in_incr_comp_dir_sess(tcx.sess, file_name); + if !path.exists() { + all_files_exist = false; + + if tcx.sess.opts.debugging_opts.incremental_info { + println!("incremental: could not find file for up-to-date work product: {}", + path.display()); + } + } + } + if all_files_exist { debug!("reconcile_work_products: all files for {:?} exist", swp); tcx.dep_graph.insert_previous_work_product(&swp.id, swp.work_product); @@ -331,7 +341,7 @@ fn load_prev_metadata_hashes(tcx: TyCtxt, debug!("load_prev_metadata_hashes() - File: {}", file_path.display()); - let data = match file_format::read_file(&file_path) { + let data = match file_format::read_file(tcx.sess, &file_path) { Ok(Some(data)) => data, Ok(None) => { debug!("load_prev_metadata_hashes() - File produced by incompatible \ diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index f1126e6fd25..259ef2a780c 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1981,6 +1981,11 @@ fn trans_reuse_previous_work_products(tcx: TyCtxt, debug!("trans_reuse_previous_work_products: reusing {:?}", work_product); return Some(work_product); } else { + if tcx.sess.opts.debugging_opts.incremental_info { + println!("incremental: CGU `{}` invalidated because of \ + changed partitioning hash.", + cgu.name()); + } debug!("trans_reuse_previous_work_products: \ not reusing {:?} because hash changed to {:?}", work_product, hash); From ed9a09d40c7c12d87f8923fad5264beb69749d38 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sun, 27 Nov 2016 10:58:46 +0000 Subject: [PATCH 177/293] Support paths in macro invocations. --- src/librustc_resolve/lib.rs | 27 ++++-- src/librustc_resolve/macros.rs | 118 ++++++++++++++++-------- src/librustc_resolve/resolve_imports.rs | 17 +++- src/libsyntax/ext/expand.rs | 7 +- 4 files changed, 116 insertions(+), 53 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 1c8c77a13d9..47e6d21cd7d 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -783,6 +783,7 @@ pub struct ModuleS<'a> { resolutions: RefCell>>>, legacy_macro_resolutions: RefCell>, + macro_resolutions: RefCell, PathScope, Span)>>, // Macro invocations that can expand into items in this module. unresolved_invocations: RefCell>, @@ -811,6 +812,7 @@ impl<'a> ModuleS<'a> { normal_ancestor_id: None, resolutions: RefCell::new(FxHashMap()), legacy_macro_resolutions: RefCell::new(Vec::new()), + macro_resolutions: RefCell::new(Vec::new()), unresolved_invocations: RefCell::new(FxHashSet()), no_implicit_prelude: false, glob_importers: RefCell::new(Vec::new()), @@ -1316,6 +1318,7 @@ impl<'a> Resolver<'a> { pub fn resolve_crate(&mut self, krate: &Crate) { ImportResolver { resolver: self }.finalize_imports(); self.current_module = self.graph_root; + self.finalize_current_module_macro_resolutions(); visit::walk_crate(self, krate); check_unused::check_crate(self, krate); @@ -2359,10 +2362,13 @@ impl<'a> Resolver<'a> { let binding = if let Some(module) = module { self.resolve_name_in_module(module, ident.name, ns, false, record_used) + } else if opt_ns == Some(MacroNS) { + self.resolve_lexical_macro_path_segment(ident.name, ns, record_used) } else { match self.resolve_ident_in_lexical_scope(ident, ns, record_used) { Some(LexicalScopeBinding::Item(binding)) => Ok(binding), - Some(LexicalScopeBinding::Def(def)) if opt_ns.is_some() => { + Some(LexicalScopeBinding::Def(def)) + if opt_ns == Some(TypeNS) || opt_ns == Some(ValueNS) => { return PathResult::NonModule(PathResolution { base_def: def, depth: path.len() - 1, @@ -2378,7 +2384,7 @@ impl<'a> Resolver<'a> { module = Some(next_module); } else if binding.def() == Def::Err { return PathResult::NonModule(err_path_resolution()); - } else if opt_ns.is_some() { + } else if opt_ns.is_some() && !(opt_ns == Some(MacroNS) && !is_last) { return PathResult::NonModule(PathResolution { base_def: binding.def(), depth: path.len() - i - 1, @@ -3059,15 +3065,22 @@ impl<'a> Resolver<'a> { for &AmbiguityError { span, name, b1, b2, lexical } in &self.ambiguity_errors { if !reported_spans.insert(span) { continue } - let msg1 = format!("`{}` could resolve to the name imported here", name); - let msg2 = format!("`{}` could also resolve to the name imported here", name); + let participle = |binding: &NameBinding| { + if binding.is_import() { "imported" } else { "defined" } + }; + let msg1 = format!("`{}` could resolve to the name {} here", name, participle(b1)); + let msg2 = format!("`{}` could also resolve to the name {} here", name, participle(b2)); self.session.struct_span_err(span, &format!("`{}` is ambiguous", name)) .span_note(b1.span, &msg1) .span_note(b2.span, &msg2) - .note(&if lexical || !b1.is_glob_import() { - "macro-expanded macro imports do not shadow".to_owned() - } else { + .note(&if !lexical && b1.is_glob_import() { format!("consider adding an explicit import of `{}` to disambiguate", name) + } else if let Def::Macro(..) = b1.def() { + format!("macro-expanded {} do not shadow", + if b1.is_import() { "macro imports" } else { "macros" }) + } else { + format!("macro-expanded {} do not shadow when used in a macro invocation path", + if b1.is_import() { "imports" } else { "items" }) }) .emit(); } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index ff91e7dc971..6c02967672d 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -8,7 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use {Module, ModuleKind, NameBinding, NameBindingKind, Resolver, AmbiguityError}; +use {AmbiguityError, Resolver, ResolutionError, resolve_error}; +use {Module, ModuleKind, NameBinding, NameBindingKind, PathScope, PathResult}; use Namespace::{self, MacroNS}; use build_reduced_graph::BuildReducedGraphVisitor; use resolve_imports::ImportResolver; @@ -25,6 +26,7 @@ use syntax::ext::base::{NormalTT, SyntaxExtension}; use syntax::ext::expand::Expansion; use syntax::ext::hygiene::Mark; use syntax::ext::tt::macro_rules; +use syntax::feature_gate::{emit_feature_err, GateIssue}; use syntax::fold::Folder; use syntax::ptr::P; use syntax::util::lev_distance::find_best_match_for_name; @@ -207,48 +209,72 @@ impl<'a> base::Resolver for Resolver<'a> { fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, force: bool) -> Result, Determinacy> { - if path.segments.len() > 1 || path.global || !path.segments[0].parameters.is_empty() { - self.session.span_err(path.span, "expected macro name without module separators"); + let ast::Path { ref segments, global, span } = *path; + if segments.iter().any(|segment| !segment.parameters.is_empty()) { + let kind = + if segments.last().unwrap().parameters.is_empty() { "module" } else { "macro" }; + let msg = format!("type parameters are not allowed on {}s", kind); + self.session.span_err(path.span, &msg); return Err(Determinacy::Determined); } - let name = path.segments[0].identifier.name; + let path_scope = if global { PathScope::Global } else { PathScope::Lexical }; + let path: Vec<_> = segments.iter().map(|seg| seg.identifier).collect(); let invocation = self.invocations[&scope]; self.current_module = invocation.module.get(); - let ext = match self.resolve_legacy_scope(&invocation.legacy_scope, name, false) { - Some(MacroBinding::Legacy(binding)) => binding.ext.clone(), - Some(MacroBinding::Modern(binding)) => binding.get_macro(self), - None => match self.resolve_in_item_lexical_scope(name, MacroNS, None) { - Some(binding) => binding.get_macro(self), - None => return Err(if force { + + if path.len() > 1 || global { + if !self.use_extern_macros { + let msg = "non-ident macro paths are experimental"; + let feature = "use_extern_macros"; + emit_feature_err(&self.session.parse_sess, feature, span, GateIssue::Language, msg); + return Err(Determinacy::Determined); + } + + let ext = match self.resolve_path(&path, path_scope, Some(MacroNS), None) { + PathResult::NonModule(path_res) => Ok(self.get_macro(path_res.base_def)), + PathResult::Module(..) => unreachable!(), + PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined), + _ => Err(Determinacy::Determined), + }; + self.current_module.macro_resolutions.borrow_mut() + .push((path.into_boxed_slice(), path_scope, span)); + return ext; + } + + let name = path[0].name; + let result = match self.resolve_legacy_scope(&invocation.legacy_scope, name, false) { + Some(MacroBinding::Legacy(binding)) => Ok(binding.ext.clone()), + Some(MacroBinding::Modern(binding)) => Ok(binding.get_macro(self)), + None => match self.resolve_lexical_macro_path_segment(name, MacroNS, None) { + Ok(binding) => Ok(binding.get_macro(self)), + Err(Determinacy::Undetermined) if !force => return Err(Determinacy::Undetermined), + _ => { let msg = format!("macro undefined: '{}!'", name); - let mut err = self.session.struct_span_err(path.span, &msg); + let mut err = self.session.struct_span_err(span, &msg); self.suggest_macro_name(&name.as_str(), &mut err); err.emit(); - Determinacy::Determined - } else { - Determinacy::Undetermined - }), + return Err(Determinacy::Determined); + }, }, }; if self.use_extern_macros { - self.current_module.legacy_macro_resolutions.borrow_mut() - .push((scope, name, path.span)); + self.current_module.legacy_macro_resolutions.borrow_mut().push((scope, name, span)); } - Ok(ext) + result } } impl<'a> Resolver<'a> { - // Resolve the name in the module's lexical scope, excluding non-items. - fn resolve_in_item_lexical_scope(&mut self, - name: Name, - ns: Namespace, - record_used: Option) - -> Option<&'a NameBinding<'a>> { + // Resolve the initial segment of a non-global macro path (e.g. `foo` in `foo::bar!();`) + pub fn resolve_lexical_macro_path_segment(&mut self, + name: Name, + ns: Namespace, + record_used: Option) + -> Result<&'a NameBinding<'a>, Determinacy> { let mut module = self.current_module; - let mut potential_expanded_shadower = None; + let mut potential_expanded_shadower: Option<&NameBinding> = None; loop { // Since expanded macros may not shadow the lexical scope (enforced below), // we can ignore unresolved invocations (indicated by the penultimate argument). @@ -256,26 +282,30 @@ impl<'a> Resolver<'a> { Ok(binding) => { let span = match record_used { Some(span) => span, - None => return Some(binding), + None => return Ok(binding), }; - if let Some(shadower) = potential_expanded_shadower { - self.ambiguity_errors.push(AmbiguityError { - span: span, name: name, b1: shadower, b2: binding, lexical: true, - }); - return Some(shadower); - } else if binding.expansion == Mark::root() { - return Some(binding); - } else { - potential_expanded_shadower = Some(binding); + match potential_expanded_shadower { + Some(shadower) if shadower.def() != binding.def() => { + self.ambiguity_errors.push(AmbiguityError { + span: span, name: name, b1: shadower, b2: binding, lexical: true, + }); + return Ok(shadower); + } + _ if binding.expansion == Mark::root() => return Ok(binding), + _ => potential_expanded_shadower = Some(binding), } }, - Err(Determinacy::Undetermined) => return None, + Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined), Err(Determinacy::Determined) => {} } match module.kind { ModuleKind::Block(..) => module = module.parent.unwrap(), - ModuleKind::Def(..) => return potential_expanded_shadower, + ModuleKind::Def(..) => return match potential_expanded_shadower { + Some(binding) => Ok(binding), + None if record_used.is_some() => Err(Determinacy::Determined), + None => Err(Determinacy::Undetermined), + }, } } } @@ -343,12 +373,22 @@ impl<'a> Resolver<'a> { pub fn finalize_current_module_macro_resolutions(&mut self) { let module = self.current_module; + for &(ref path, scope, span) in module.macro_resolutions.borrow().iter() { + match self.resolve_path(path, scope, Some(MacroNS), Some(span)) { + PathResult::NonModule(_) => {}, + PathResult::Failed(msg, _) => { + resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); + } + _ => unreachable!(), + } + } + for &(mark, name, span) in module.legacy_macro_resolutions.borrow().iter() { let legacy_scope = &self.invocations[&mark].legacy_scope; let legacy_resolution = self.resolve_legacy_scope(legacy_scope, name, true); - let resolution = self.resolve_in_item_lexical_scope(name, MacroNS, Some(span)); + let resolution = self.resolve_lexical_macro_path_segment(name, MacroNS, Some(span)); let (legacy_resolution, resolution) = match (legacy_resolution, resolution) { - (Some(legacy_resolution), Some(resolution)) => (legacy_resolution, resolution), + (Some(legacy_resolution), Ok(resolution)) => (legacy_resolution, resolution), _ => continue, }; let (legacy_span, participle) = match legacy_resolution { diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 2a803d72fd1..b634d57a842 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -10,7 +10,7 @@ use self::ImportDirectiveSubclass::*; -use {Module, PerNS}; +use {AmbiguityError, Module, PerNS}; use Namespace::{self, TypeNS, MacroNS}; use {NameBinding, NameBindingKind, PathResult, PathScope, PrivacyError, ToNameBinding}; use Resolver; @@ -73,6 +73,7 @@ pub struct NameResolution<'a> { single_imports: SingleImports<'a>, /// The least shadowable known binding for this name, or None if there are no known bindings. pub binding: Option<&'a NameBinding<'a>>, + shadows_glob: Option<&'a NameBinding<'a>>, } #[derive(Clone, Debug)] @@ -151,6 +152,18 @@ impl<'a> Resolver<'a> { if let Some(span) = record_used { if let Some(binding) = resolution.binding { + if let Some(shadowed_glob) = resolution.shadows_glob { + // If we ignore unresolved invocations, we must forbid + // expanded shadowing to avoid time travel. + if ignore_unresolved_invocations && + binding.expansion != Mark::root() && + ns != MacroNS && // In MacroNS, `try_define` always forbids this shadowing + binding.def() != shadowed_glob.def() { + self.ambiguity_errors.push(AmbiguityError { + span: span, name: name, lexical: false, b1: binding, b2: shadowed_glob, + }); + } + } if self.record_use(name, ns, binding, span) { return Ok(self.dummy_binding); } @@ -298,6 +311,7 @@ impl<'a> Resolver<'a> { if binding.is_glob_import() { if !old_binding.is_glob_import() && !(ns == MacroNS && old_binding.expansion != Mark::root()) { + resolution.shadows_glob = Some(binding); } else if binding.def() != old_binding.def() { resolution.binding = Some(this.ambiguity(old_binding, binding)); } else if !old_binding.vis.is_at_least(binding.vis, this) { @@ -310,6 +324,7 @@ impl<'a> Resolver<'a> { resolution.binding = Some(this.ambiguity(binding, old_binding)); } else { resolution.binding = Some(binding); + resolution.shadows_glob = Some(old_binding); } } else { return Err(old_binding); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index fd6cae1e1b6..4138acafac6 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -400,12 +400,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { &self.cx.ecfg.features.unwrap()); } - if path.segments.len() > 1 || path.global || !path.segments[0].parameters.is_empty() { - self.cx.span_err(path.span, "expected macro name without module separators"); - return kind.dummy(span); - } - - let extname = path.segments[0].identifier.name; + let extname = path.segments.last().unwrap().identifier.name; let ident = ident.unwrap_or(keywords::Invalid.ident()); let marked_tts = mark_tts(&tts, mark); let opt_expanded = match *ext { From ff621ec70eac9c687d0154df5405600669041ab3 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 28 Nov 2016 07:57:17 +0000 Subject: [PATCH 178/293] Add tests. --- src/test/compile-fail/imports/macro-paths.rs | 42 +++++++++++++++++ .../compile-fail/macro-with-seps-err-msg.rs | 6 +-- .../paths-in-macro-invocations.rs | 38 --------------- src/test/run-pass/auxiliary/two_macros.rs | 4 +- .../run-pass/paths-in-macro-invocations.rs | 46 +++++++++++++++++++ 5 files changed, 93 insertions(+), 43 deletions(-) create mode 100644 src/test/compile-fail/imports/macro-paths.rs delete mode 100644 src/test/compile-fail/paths-in-macro-invocations.rs create mode 100644 src/test/run-pass/paths-in-macro-invocations.rs diff --git a/src/test/compile-fail/imports/macro-paths.rs b/src/test/compile-fail/imports/macro-paths.rs new file mode 100644 index 00000000000..97c05392e7d --- /dev/null +++ b/src/test/compile-fail/imports/macro-paths.rs @@ -0,0 +1,42 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:two_macros.rs + +#![feature(use_extern_macros)] + +extern crate two_macros; + +mod foo { + pub mod bar { + pub use two_macros::m; + } +} + +fn f() { + use foo::*; //~ NOTE could also resolve to the name imported here + bar::m! { //~ ERROR ambiguous + //~| NOTE macro-expanded items do not shadow when used in a macro invocation path + mod bar { pub use two_macros::m; } //~ NOTE could resolve to the name defined here + //~^^^ NOTE in this expansion + } +} + +pub mod baz { //~ NOTE could also resolve to the name defined here + pub use two_macros::m; +} + +fn g() { + baz::m! { //~ ERROR ambiguous + //~| NOTE macro-expanded items do not shadow when used in a macro invocation path + mod baz { pub use two_macros::m; } //~ NOTE could resolve to the name defined here + //~^^^ NOTE in this expansion + } +} diff --git a/src/test/compile-fail/macro-with-seps-err-msg.rs b/src/test/compile-fail/macro-with-seps-err-msg.rs index 408bb15ba28..d5fc9a510f0 100644 --- a/src/test/compile-fail/macro-with-seps-err-msg.rs +++ b/src/test/compile-fail/macro-with-seps-err-msg.rs @@ -9,7 +9,7 @@ // except according to those terms. fn main() { - globnar::brotz!(); //~ ERROR expected macro name without module separators - ::foo!(); //~ ERROR expected macro name without module separators - foo::!(); //~ ERROR expected macro name without module separators + globnar::brotz!(); //~ ERROR non-ident macro paths are experimental + ::foo!(); //~ ERROR non-ident macro paths are experimental + foo::!(); //~ ERROR type parameters are not allowed on macros } diff --git a/src/test/compile-fail/paths-in-macro-invocations.rs b/src/test/compile-fail/paths-in-macro-invocations.rs deleted file mode 100644 index c69b7e526cc..00000000000 --- a/src/test/compile-fail/paths-in-macro-invocations.rs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -::foo::bar!(); //~ ERROR expected macro name without module separators -foo::bar!(); //~ ERROR expected macro name without module separators - -trait T { - foo::bar!(); //~ ERROR expected macro name without module separators - ::foo::bar!(); //~ ERROR expected macro name without module separators -} - -struct S { - x: foo::bar!(), //~ ERROR expected macro name without module separators - y: ::foo::bar!(), //~ ERROR expected macro name without module separators -} - -impl S { - foo::bar!(); //~ ERROR expected macro name without module separators - ::foo::bar!(); //~ ERROR expected macro name without module separators -} - -fn main() { - foo::bar!(); //~ ERROR expected macro name without module separators - ::foo::bar!(); //~ ERROR expected macro name without module separators - - let _ = foo::bar!(); //~ ERROR expected macro name without module separators - let _ = ::foo::bar!(); //~ ERROR expected macro name without module separators - - let foo::bar!() = 0; //~ ERROR expected macro name without module separators - let ::foo::bar!() = 0; //~ ERROR expected macro name without module separators -} diff --git a/src/test/run-pass/auxiliary/two_macros.rs b/src/test/run-pass/auxiliary/two_macros.rs index 060960f0dbc..0da6ba13696 100644 --- a/src/test/run-pass/auxiliary/two_macros.rs +++ b/src/test/run-pass/auxiliary/two_macros.rs @@ -9,7 +9,7 @@ // except according to those terms. #[macro_export] -macro_rules! macro_one { () => ("one") } +macro_rules! macro_one { ($($t:tt)*) => ($($t)*) } #[macro_export] -macro_rules! macro_two { () => ("two") } +macro_rules! macro_two { ($($t:tt)*) => ($($t)*) } diff --git a/src/test/run-pass/paths-in-macro-invocations.rs b/src/test/run-pass/paths-in-macro-invocations.rs new file mode 100644 index 00000000000..69f8906778a --- /dev/null +++ b/src/test/run-pass/paths-in-macro-invocations.rs @@ -0,0 +1,46 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:two_macros.rs + +#![feature(use_extern_macros)] + +extern crate two_macros; + +::two_macros::macro_one!(); +two_macros::macro_one!(); + +mod foo { pub use two_macros::macro_one as bar; } + +trait T { + foo::bar!(); + ::foo::bar!(); +} + +struct S { + x: foo::bar!(i32), + y: ::foo::bar!(i32), +} + +impl S { + foo::bar!(); + ::foo::bar!(); +} + +fn main() { + foo::bar!(); + ::foo::bar!(); + + let _ = foo::bar!(0); + let _ = ::foo::bar!(0); + + let foo::bar!(_) = 0; + let ::foo::bar!(_) = 0; +} From 8b1c4cbbaf0252ed68f62b0613a8da9725141262 Mon Sep 17 00:00:00 2001 From: Ted Mielczarek Date: Wed, 30 Nov 2016 19:44:07 -0500 Subject: [PATCH 179/293] Add std::os::windows::process::CommandExt, with set_creation_flags and add_creation_flags methods. Fixes #37827 This adds a CommandExt trait for Windows along with an implementation of it for std::process::Command with methods to set the process creation flags that are passed to CreateProcess. --- src/libstd/process.rs | 57 +++++++++++++++++++++++++++ src/libstd/sys/windows/ext/process.rs | 31 ++++++++++++++- src/libstd/sys/windows/process.rs | 10 ++++- 3 files changed, 96 insertions(+), 2 deletions(-) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index c99fda9febc..912cc122e92 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1159,4 +1159,61 @@ mod tests { Ok(_) => panic!(), } } + + /// Test that process creation flags work by debugging a process. + /// Other creation flags make it hard or impossible to detect + /// behavioral changes in the process. + #[test] + #[cfg(windows)] + fn test_creation_flags() { + use os::windows::process::CommandExt; + use sys::c::{BOOL, DWORD, INFINITE}; + #[repr(C, packed)] + struct DEBUG_EVENT { + pub event_code: DWORD, + pub process_id: DWORD, + pub thread_id: DWORD, + // This is a union in the real struct, but we don't + // need this data for the purposes of this test. + pub _junk: [u8; 164], + } + + extern "system" { + fn WaitForDebugEvent(lpDebugEvent: *mut DEBUG_EVENT, dwMilliseconds: DWORD) -> BOOL; + fn ContinueDebugEvent(dwProcessId: DWORD, dwThreadId: DWORD, dwContinueStatus: DWORD) -> BOOL; + } + + const DEBUG_PROCESS: DWORD = 1; + const EXIT_PROCESS_DEBUG_EVENT: DWORD = 5; + const DBG_EXCEPTION_NOT_HANDLED: DWORD = 0x80010001; + + let mut child = Command::new("cmd") + .add_creation_flags(DEBUG_PROCESS) + .stdin(Stdio::piped()).spawn().unwrap(); + child.stdin.take().unwrap().write_all(b"exit\r\n").unwrap(); + let mut events = 0; + let mut event = DEBUG_EVENT { + event_code: 0, + process_id: 0, + thread_id: 0, + _junk: [0; 164], + }; + loop { + if unsafe { WaitForDebugEvent(&mut event as *mut DEBUG_EVENT, INFINITE) } == 0 { + panic!("WaitForDebugEvent failed!"); + } + events += 1; + + if event.event_code == EXIT_PROCESS_DEBUG_EVENT { + break; + } + + if unsafe { ContinueDebugEvent(event.process_id, + event.thread_id, + DBG_EXCEPTION_NOT_HANDLED) } == 0 { + panic!("ContinueDebugEvent failed!"); + } + } + assert!(events > 0); + } } diff --git a/src/libstd/sys/windows/ext/process.rs b/src/libstd/sys/windows/ext/process.rs index bce32959a23..f5bf3354637 100644 --- a/src/libstd/sys/windows/ext/process.rs +++ b/src/libstd/sys/windows/ext/process.rs @@ -15,7 +15,7 @@ use os::windows::io::{FromRawHandle, RawHandle, AsRawHandle, IntoRawHandle}; use process; use sys; -use sys_common::{AsInner, FromInner, IntoInner}; +use sys_common::{AsInnerMut, AsInner, FromInner, IntoInner}; #[stable(feature = "process_extensions", since = "1.2.0")] impl FromRawHandle for process::Stdio { @@ -97,3 +97,32 @@ impl ExitStatusExt for process::ExitStatus { process::ExitStatus::from_inner(From::from(raw)) } } + +/// Windows-specific extensions to the `std::process::Command` builder +#[unstable(feature = "windows_process_extensions", issue = "37827")] +pub trait CommandExt { + /// Sets the [process creation flags][1] to be passed to `CreateProcess`. + /// + /// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`. + /// [1]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx + #[unstable(feature = "windows_process_extensions", issue = "37827")] + fn set_creation_flags(&mut self, flags: u32) -> &mut process::Command; + /// Add `flags` to the the [process creation flags][1] to be passed to `CreateProcess`. + /// + /// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`. + /// [1]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx + #[unstable(feature = "windows_process_extensions", issue = "37827")] + fn add_creation_flags(&mut self, flags: u32) -> &mut process::Command; +} + +#[unstable(feature = "windows_process_extensions", issue = "37827")] +impl CommandExt for process::Command { + fn set_creation_flags(&mut self, flags: u32) -> &mut process::Command { + self.as_inner_mut().set_creation_flags(flags); + self + } + fn add_creation_flags(&mut self, flags: u32) -> &mut process::Command { + self.as_inner_mut().add_creation_flags(flags); + self + } +} diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index d371714ff0e..a221c67efd9 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -54,6 +54,7 @@ pub struct Command { args: Vec, env: Option>, cwd: Option, + flags: u32, detach: bool, // not currently exposed in std::process stdin: Option, stdout: Option, @@ -84,6 +85,7 @@ impl Command { args: Vec::new(), env: None, cwd: None, + flags: 0, detach: false, stdin: None, stdout: None, @@ -124,6 +126,12 @@ impl Command { pub fn stderr(&mut self, stderr: Stdio) { self.stderr = Some(stderr); } + pub fn set_creation_flags(&mut self, flags: u32) { + self.flags = flags; + } + pub fn add_creation_flags(&mut self, flags: u32) { + self.flags = self.flags | flags; + } pub fn spawn(&mut self, default: Stdio, needs_stdin: bool) -> io::Result<(Process, StdioPipes)> { @@ -157,7 +165,7 @@ impl Command { cmd_str.push(0); // add null terminator // stolen from the libuv code. - let mut flags = c::CREATE_UNICODE_ENVIRONMENT; + let mut flags = self.flags | c::CREATE_UNICODE_ENVIRONMENT; if self.detach { flags |= c::DETACHED_PROCESS | c::CREATE_NEW_PROCESS_GROUP; } From db936773608d1f9b24d90c87ec224a9b9f501489 Mon Sep 17 00:00:00 2001 From: Martin Pool Date: Sat, 26 Nov 2016 09:15:33 -0800 Subject: [PATCH 180/293] Document that Process::command will search the PATH --- src/libstd/process.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 9d21a76e81b..d96c5e244d7 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -253,6 +253,14 @@ impl Command { /// Builder methods are provided to change these defaults and /// otherwise configure the process. /// + /// If `program` is not an absolute path, the `PATH` will be searched in + /// an OS-defined way. + /// + /// The search path to be used may be controlled by setting the + /// `PATH` environment variable on the Command, + /// but this has some implementation limitations on Windows + /// (see https://github.com/rust-lang/rust/issues/37519). + /// /// # Examples /// /// Basic usage: From e6975e974841c59a6e67e8a158b306f29d35d513 Mon Sep 17 00:00:00 2001 From: Ted Mielczarek Date: Wed, 30 Nov 2016 21:31:47 -0500 Subject: [PATCH 181/293] just add one method named creation_flags, fix the tidy error --- src/libstd/process.rs | 5 +++-- src/libstd/sys/windows/ext/process.rs | 16 +++------------- src/libstd/sys/windows/process.rs | 5 +---- 3 files changed, 7 insertions(+), 19 deletions(-) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 912cc122e92..f41fbcc66b4 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1180,7 +1180,8 @@ mod tests { extern "system" { fn WaitForDebugEvent(lpDebugEvent: *mut DEBUG_EVENT, dwMilliseconds: DWORD) -> BOOL; - fn ContinueDebugEvent(dwProcessId: DWORD, dwThreadId: DWORD, dwContinueStatus: DWORD) -> BOOL; + fn ContinueDebugEvent(dwProcessId: DWORD, dwThreadId: DWORD, + dwContinueStatus: DWORD) -> BOOL; } const DEBUG_PROCESS: DWORD = 1; @@ -1188,7 +1189,7 @@ mod tests { const DBG_EXCEPTION_NOT_HANDLED: DWORD = 0x80010001; let mut child = Command::new("cmd") - .add_creation_flags(DEBUG_PROCESS) + .creation_flags(DEBUG_PROCESS) .stdin(Stdio::piped()).spawn().unwrap(); child.stdin.take().unwrap().write_all(b"exit\r\n").unwrap(); let mut events = 0; diff --git a/src/libstd/sys/windows/ext/process.rs b/src/libstd/sys/windows/ext/process.rs index f5bf3354637..0a3221aeae6 100644 --- a/src/libstd/sys/windows/ext/process.rs +++ b/src/libstd/sys/windows/ext/process.rs @@ -106,23 +106,13 @@ pub trait CommandExt { /// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`. /// [1]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx #[unstable(feature = "windows_process_extensions", issue = "37827")] - fn set_creation_flags(&mut self, flags: u32) -> &mut process::Command; - /// Add `flags` to the the [process creation flags][1] to be passed to `CreateProcess`. - /// - /// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`. - /// [1]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx - #[unstable(feature = "windows_process_extensions", issue = "37827")] - fn add_creation_flags(&mut self, flags: u32) -> &mut process::Command; + fn creation_flags(&mut self, flags: u32) -> &mut process::Command; } #[unstable(feature = "windows_process_extensions", issue = "37827")] impl CommandExt for process::Command { - fn set_creation_flags(&mut self, flags: u32) -> &mut process::Command { - self.as_inner_mut().set_creation_flags(flags); - self - } - fn add_creation_flags(&mut self, flags: u32) -> &mut process::Command { - self.as_inner_mut().add_creation_flags(flags); + fn creation_flags(&mut self, flags: u32) -> &mut process::Command { + self.as_inner_mut().creation_flags(flags); self } } diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index a221c67efd9..969de6b85a6 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -126,12 +126,9 @@ impl Command { pub fn stderr(&mut self, stderr: Stdio) { self.stderr = Some(stderr); } - pub fn set_creation_flags(&mut self, flags: u32) { + pub fn creation_flags(&mut self, flags: u32) { self.flags = flags; } - pub fn add_creation_flags(&mut self, flags: u32) { - self.flags = self.flags | flags; - } pub fn spawn(&mut self, default: Stdio, needs_stdin: bool) -> io::Result<(Process, StdioPipes)> { From cbf734f9abe06d240db086f55a0bd4387b77eb94 Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Mon, 28 Nov 2016 13:54:55 -0500 Subject: [PATCH 182/293] Add String::split_off. --- src/libcollections/string.rs | 33 +++++++++++++++++++++++++++ src/libcollectionstest/lib.rs | 1 + src/libcollectionstest/string.rs | 39 ++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+) diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 348eb6fb5ff..ddde9d06d81 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1260,6 +1260,39 @@ impl String { self.len() == 0 } + /// Divide one string into two at an index. + /// + /// The argument, `mid`, should be a byte offset from the start of the string. It must also + /// be on the boundary of a UTF-8 code point. + /// + /// The two strings returned go from the start of the string to `mid`, and from `mid` to the end + /// of the string. + /// + /// # Panics + /// + /// Panics if `mid` is not on a `UTF-8` code point boundary, or if it is beyond the last + /// code point of the string. + /// + /// # Examples + /// + /// ``` + /// # #![feature(string_split_off)] + /// # fn main() { + /// let mut hello = String::from("Hello, World!"); + /// let world = hello.split_off(7); + /// assert_eq!(hello, "Hello, "); + /// assert_eq!(world, "World!"); + /// # } + /// ``` + #[inline] + #[unstable(feature = "string_split_off", issue = "38080")] + pub fn split_off(&mut self, mid: usize) -> String { + assert!(self.is_char_boundary(mid)); + assert!(mid <= self.len()); + let other = self.vec.split_off(mid); + unsafe { String::from_utf8_unchecked(other) } + } + /// Truncates this `String`, removing all contents. /// /// While this means the `String` will have a length of zero, it does not diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs index 1e08074b14d..58ce78eab9a 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollectionstest/lib.rs @@ -25,6 +25,7 @@ #![feature(step_by)] #![feature(str_escape)] #![feature(str_replacen)] +#![feature(string_split_off)] #![feature(test)] #![feature(unboxed_closures)] #![feature(unicode)] diff --git a/src/libcollectionstest/string.rs b/src/libcollectionstest/string.rs index 98de33bdaa8..cb4fcb58452 100644 --- a/src/libcollectionstest/string.rs +++ b/src/libcollectionstest/string.rs @@ -231,6 +231,45 @@ fn test_pop() { assert_eq!(data, "ประเทศไทย中"); } +#[test] +fn test_split_off_empty() { + let orig = "Hello, world!"; + let mut split = String::from(orig); + let empty: String = split.split_off(orig.len()); + assert!(empty.is_empty()); +} + +#[test] +#[should_panic] +fn test_split_off_past_end() { + let orig = "Hello, world!"; + let mut split = String::from(orig); + split.split_off(orig.len() + 1); +} + +#[test] +#[should_panic] +fn test_split_off_mid_char() { + let mut orig = String::from("山"); + orig.split_off(1); +} + +#[test] +fn test_split_off_ascii() { + let mut ab = String::from("ABCD"); + let cd = ab.split_off(2); + assert_eq!(ab, "AB"); + assert_eq!(cd, "CD"); +} + +#[test] +fn test_split_off_unicode() { + let mut nihon = String::from("日本語"); + let go = nihon.split_off("日本".len()); + assert_eq!(nihon, "日本"); + assert_eq!(go, "語"); +} + #[test] fn test_str_truncate() { let mut s = String::from("12345"); From ee83f365ee7fb4b8b59d191bb20509a03196dd12 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Thu, 1 Dec 2016 01:48:58 +0100 Subject: [PATCH 183/293] Update llvm fork to 3ec14daffb4b8c0604df50b7fb0ab552f456e381 --- src/llvm | 2 +- src/rustllvm/llvm-auto-clean-trigger | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/llvm b/src/llvm index c1d962263bf..3ec14daffb4 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit c1d962263bf76a10bea0c761621fcd98d6214b2e +Subproject commit 3ec14daffb4b8c0604df50b7fb0ab552f456e381 diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-auto-clean-trigger index 37fded948e1..768ba2d5b77 100644 --- a/src/rustllvm/llvm-auto-clean-trigger +++ b/src/rustllvm/llvm-auto-clean-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be forcibly cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2016-10-29 +2016-12-01 From d6ec686d379efca7296d6c53abe7968bdfae5723 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Thu, 1 Dec 2016 13:10:49 +0000 Subject: [PATCH 184/293] rustdoc: Sort lines in search index and implementors js This means the files are generated deterministically even with rustdoc running in parallel. --- src/librustdoc/html/render.rs | 58 ++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index cbf93662811..57fb0aa3f7a 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -40,7 +40,7 @@ use std::cmp::Ordering; use std::collections::BTreeMap; use std::default::Default; use std::error; -use std::fmt::{self, Display, Formatter}; +use std::fmt::{self, Display, Formatter, Write as FmtWrite}; use std::fs::{self, File, OpenOptions}; use std::io::prelude::*; use std::io::{self, BufWriter, BufReader}; @@ -718,10 +718,13 @@ fn write_shared(cx: &Context, // Update the search index let dst = cx.dst.join("search-index.js"); - let all_indexes = try_err!(collect(&dst, &krate.name, "searchIndex"), &dst); + let mut all_indexes = try_err!(collect(&dst, &krate.name, "searchIndex"), &dst); + all_indexes.push(search_index); + // Sort the indexes by crate so the file will be generated identically even + // with rustdoc running in parallel. + all_indexes.sort(); let mut w = try_err!(File::create(&dst), &dst); try_err!(writeln!(&mut w, "var searchIndex = {{}};"), &dst); - try_err!(writeln!(&mut w, "{}", search_index), &dst); for index in &all_indexes { try_err!(writeln!(&mut w, "{}", *index), &dst); } @@ -729,7 +732,6 @@ fn write_shared(cx: &Context, // Update the list of all implementors for traits let dst = cx.dst.join("implementors"); - try_err!(mkdir(&dst), &dst); for (&did, imps) in &cache.implementors { // Private modules can leak through to this phase of rustdoc, which // could contain implementations for otherwise private types. In some @@ -746,37 +748,37 @@ fn write_shared(cx: &Context, } }; - let mut mydst = dst.clone(); - for part in &remote_path[..remote_path.len() - 1] { - mydst.push(part); - try_err!(mkdir(&mydst), &mydst); - } - mydst.push(&format!("{}.{}.js", - remote_item_type.css_class(), - remote_path[remote_path.len() - 1])); - let all_implementors = try_err!(collect(&mydst, &krate.name, - "implementors"), - &mydst); - - try_err!(mkdir(mydst.parent().unwrap()), - &mydst.parent().unwrap().to_path_buf()); - let mut f = BufWriter::new(try_err!(File::create(&mydst), &mydst)); - try_err!(writeln!(&mut f, "(function() {{var implementors = {{}};"), &mydst); - - for implementor in &all_implementors { - try_err!(write!(&mut f, "{}", *implementor), &mydst); - } - - try_err!(write!(&mut f, r#"implementors["{}"] = ["#, krate.name), &mydst); + let mut implementors = format!(r#"implementors["{}"] = ["#, krate.name); for imp in imps { // If the trait and implementation are in the same crate, then // there's no need to emit information about it (there's inlining // going on). If they're in different crates then the crate defining // the trait will be interested in our implementation. if imp.def_id.krate == did.krate { continue } - try_err!(write!(&mut f, r#""{}","#, imp.impl_), &mydst); + write!(implementors, r#""{}","#, imp.impl_).unwrap(); + } + implementors.push_str("];"); + + let mut mydst = dst.clone(); + for part in &remote_path[..remote_path.len() - 1] { + mydst.push(part); + } + try_err!(fs::create_dir_all(&mydst), &mydst); + mydst.push(&format!("{}.{}.js", + remote_item_type.css_class(), + remote_path[remote_path.len() - 1])); + + let mut all_implementors = try_err!(collect(&mydst, &krate.name, "implementors"), &mydst); + all_implementors.push(implementors); + // Sort the implementors by crate so the file will be generated + // identically even with rustdoc running in parallel. + all_implementors.sort(); + + let mut f = try_err!(File::create(&mydst), &mydst); + try_err!(writeln!(&mut f, "(function() {{var implementors = {{}};"), &mydst); + for implementor in &all_implementors { + try_err!(writeln!(&mut f, "{}", *implementor), &mydst); } - try_err!(writeln!(&mut f, r"];"), &mydst); try_err!(writeln!(&mut f, "{}", r" if (window.register_implementors) { window.register_implementors(implementors); From bfdd2d4177391312022b48a328ff4f177769055c Mon Sep 17 00:00:00 2001 From: Josh Driver Date: Tue, 22 Nov 2016 00:02:58 +1030 Subject: [PATCH 185/293] Allow --test to be used on proc-macro crates --- src/libsyntax_ext/proc_macro_registrar.rs | 6 ++++-- .../proc-macro/derive-test.rs} | 14 +++++++++++--- 2 files changed, 15 insertions(+), 5 deletions(-) rename src/test/{compile-fail-fulldeps/proc-macro/error-on-test.rs => run-pass-fulldeps/proc-macro/derive-test.rs} (74%) diff --git a/src/libsyntax_ext/proc_macro_registrar.rs b/src/libsyntax_ext/proc_macro_registrar.rs index bbdbda701ae..6256440bc81 100644 --- a/src/libsyntax_ext/proc_macro_registrar.rs +++ b/src/libsyntax_ext/proc_macro_registrar.rs @@ -75,6 +75,10 @@ pub fn modify(sess: &ParseSess, handler.err("cannot mix `proc-macro` crate type with others"); } + if is_test_crate { + return krate; + } + krate.module.items.push(mk_registrar(&mut cx, &collect.derives)); if krate.exported_macros.len() > 0 { @@ -141,8 +145,6 @@ impl<'a> Visitor for CollectCustomDerives<'a> { } if self.is_test_crate { - self.handler.span_err(attr.span(), - "`--test` cannot be used with proc-macro crates"); return; } diff --git a/src/test/compile-fail-fulldeps/proc-macro/error-on-test.rs b/src/test/run-pass-fulldeps/proc-macro/derive-test.rs similarity index 74% rename from src/test/compile-fail-fulldeps/proc-macro/error-on-test.rs rename to src/test/run-pass-fulldeps/proc-macro/derive-test.rs index 4751679ddb8..2f44515a873 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/error-on-test.rs +++ b/src/test/run-pass-fulldeps/proc-macro/derive-test.rs @@ -8,15 +8,23 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// no-prefer-dynamic // compile-flags: --test #![crate_type = "proc-macro"] +#![feature(proc_macro)] #![feature(proc_macro, proc_macro_lib)] extern crate proc_macro; -#[proc_macro_derive(A)] -//~^ ERROR: `--test` cannot be used with proc-macro crates -pub fn foo1(input: proc_macro::TokenStream) -> proc_macro::TokenStream { +use proc_macro::TokenStream; + +#[proc_macro_derive(Foo)] +pub fn derive_foo(_input: TokenStream) -> TokenStream { "".parse().unwrap() } + +#[test] +pub fn test_derive() { + assert!(true); +} From d950ca175ab5e7a9827353f9fb7d9d6e3f6e7658 Mon Sep 17 00:00:00 2001 From: Steve Smith Date: Thu, 1 Dec 2016 16:30:34 +0000 Subject: [PATCH 186/293] Minor fix to testing concurrency section --- src/doc/book/testing.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/doc/book/testing.md b/src/doc/book/testing.md index 14a05102b9a..ebeb9923197 100644 --- a/src/doc/book/testing.md +++ b/src/doc/book/testing.md @@ -589,11 +589,11 @@ please see the [Documentation chapter](documentation.html). # Testing and concurrency -One thing that is important to note when writing tests are run concurrently -using threads. For this reason you should take care that your tests are written -in such a way as to not depend on each-other, or on any shared state. "Shared -state" can also include the environment, such as the current working directory, -or environment variables. +One thing that is important to note when writing tests is that they may be run +concurrently using threads. For this reason you should take care that your tests +are written in such a way as to not depend on each-other, or on any shared +state. "Shared state" can also include the environment, such as the current +working directory, or environment variables. If this is an issue it is possible to control this concurrency, either by setting the environment variable `RUST_TEST_THREADS`, or by passing the argument From 57ffda6158b6b6a119fa8f59b19f321cae9d0850 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 1 Dec 2016 12:29:28 -0500 Subject: [PATCH 187/293] add a `-Z incremental-dump-hash` flag This causes us to dump a bunch of has information to stdout that can be useful in tracking down incremental compilation invalidations, particularly across crates. --- src/librustc/session/config.rs | 2 ++ src/librustc_incremental/persist/load.rs | 13 +++++++++++++ src/librustc_incremental/persist/save.rs | 15 +++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 26dafed7019..0052fe25b05 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -885,6 +885,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "enable incremental compilation (experimental)"), incremental_info: bool = (false, parse_bool, [UNTRACKED], "print high-level information about incremental reuse (or the lack thereof)"), + incremental_dump_hash: bool = (false, parse_bool, [UNTRACKED], + "dump hash information in textual format to stdout"), dump_dep_graph: bool = (false, parse_bool, [UNTRACKED], "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv)"), query_dep_graph: bool = (false, parse_bool, [UNTRACKED], diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index 12bf74c9511..ead353512c7 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -250,11 +250,24 @@ fn dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, current_hash); continue; } + + if tcx.sess.opts.debugging_opts.incremental_dump_hash { + println!("node {:?} is dirty as hash is {:?} was {:?}", + dep_node.map_def(|&def_id| Some(tcx.def_path(def_id))).unwrap(), + current_hash, + hash.hash); + } + debug!("initial_dirty_nodes: {:?} is dirty as hash is {:?}, was {:?}", dep_node.map_def(|&def_id| Some(tcx.def_path(def_id))).unwrap(), current_hash, hash.hash); } else { + if tcx.sess.opts.debugging_opts.incremental_dump_hash { + println!("node {:?} is dirty as it was removed", + hash.dep_node); + } + debug!("initial_dirty_nodes: {:?} is dirty as it was removed", hash.dep_node); } diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index 05e21aa19b1..1ce4bf7f033 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -159,6 +159,12 @@ pub fn encode_dep_graph(preds: &Predecessors, } } + if tcx.sess.opts.debugging_opts.incremental_dump_hash { + for (dep_node, hash) in &preds.hashes { + println!("HIR hash for {:?} is {}", dep_node, hash); + } + } + // Create the serialized dep-graph. let graph = SerializedDepGraph { edges: edges, @@ -248,6 +254,15 @@ pub fn encode_metadata_hashes(tcx: TyCtxt, let hash = state.finish(); debug!("save: metadata hash for {:?} is {}", def_id, hash); + + if tcx.sess.opts.debugging_opts.incremental_dump_hash { + println!("metadata hash for {:?} is {}", def_id, hash); + for dep_node in sources { + println!("metadata hash for {:?} depends on {:?} with hash {}", + def_id, dep_node, preds.hashes[dep_node]); + } + } + serialized_hashes.hashes.push(SerializedMetadataHash { def_index: def_id.index, hash: hash, From acad8cceb7a60833a54650ff84300a21af754434 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 1 Dec 2016 13:17:01 -0500 Subject: [PATCH 188/293] don't rebuild alloc_jemalloc if jemalloc's .git directory has changed the .git directory is modified by `bootstrap` when it updates this git submodule; this triggered rebuilds every time `bootstrap` was called. likely fixes #38094 --- src/liballoc_jemalloc/build.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/liballoc_jemalloc/build.rs b/src/liballoc_jemalloc/build.rs index 08a1f8ae8c6..50149dfd65f 100644 --- a/src/liballoc_jemalloc/build.rs +++ b/src/liballoc_jemalloc/build.rs @@ -69,6 +69,7 @@ fn main() { .read_dir() .unwrap() .map(|e| e.unwrap()) + .filter(|e| &*e.file_name() != ".git") .collect::>(); while let Some(entry) = stack.pop() { let path = entry.path(); From fa22fc387ad17510d5af9eb16db5e5e01bde38b4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 21 Nov 2016 12:17:13 -0500 Subject: [PATCH 189/293] in region, treat current (and future) item-likes alike The `visit_fn` code mutates its surrounding context. Between *items*, this was saved/restored, but between impl items it was not. This meant that we wound up with `CallSiteScope` entries with two parents (or more!). As far as I can tell, this is harmless in actual type-checking, since the regions you interact with are always from at most one of those branches. But it can slow things down. Before, the effect was limited, since it only applied to impl items within an impl. After #37660, impl items are visisted all together at the end, and hence this could create a very messed up hierarchy. Isolating impl item properly solves both issues. I cannot come up with a way to unit-test this; for posterity, however, you can observe the messed up hierarchies with a test as simple as the following, which would create a callsite scope with two parents both before and after ``` struct Foo { } impl Foo { fn bar(&self) -> usize { 22 } fn baz(&self) -> usize { 22 } } fn main() { } ``` Fixes #37864. --- src/librustc/middle/region.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 05fa619ce41..930c9e284f6 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -1066,7 +1066,9 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, } } -fn resolve_item<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, item: &'tcx hir::Item) { +fn resolve_item_like<'a, 'tcx, F>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, id: ast::NodeId, walk: F) + where F: FnOnce(&mut RegionResolutionVisitor<'tcx, 'a>) +{ // Items create a new outer block scope as far as we're concerned. let prev_cx = visitor.cx; let prev_ts = mem::replace(&mut visitor.terminating_scopes, NodeSet()); @@ -1075,8 +1077,8 @@ fn resolve_item<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, item: var_parent: ROOT_CODE_EXTENT, parent: ROOT_CODE_EXTENT }; - intravisit::walk_item(visitor, item); - visitor.create_item_scope_if_needed(item.id); + walk(visitor); + visitor.create_item_scope_if_needed(id); visitor.cx = prev_cx; visitor.terminating_scopes = prev_ts; } @@ -1179,17 +1181,15 @@ impl<'ast, 'a> Visitor<'ast> for RegionResolutionVisitor<'ast, 'a> { } fn visit_item(&mut self, i: &'ast Item) { - resolve_item(self, i); + resolve_item_like(self, i.id, |this| intravisit::walk_item(this, i)); } fn visit_impl_item(&mut self, ii: &'ast hir::ImplItem) { - intravisit::walk_impl_item(self, ii); - self.create_item_scope_if_needed(ii.id); + resolve_item_like(self, ii.id, |this| intravisit::walk_impl_item(this, ii)); } fn visit_trait_item(&mut self, ti: &'ast hir::TraitItem) { - intravisit::walk_trait_item(self, ti); - self.create_item_scope_if_needed(ti.id); + resolve_item_like(self, ti.id, |this| intravisit::walk_trait_item(this, ti)); } fn visit_fn(&mut self, fk: FnKind<'ast>, fd: &'ast FnDecl, From 6fe4bffb406cb13d633730b05e029925cef0deb0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 29 Nov 2016 11:51:35 -0500 Subject: [PATCH 190/293] test for #37290 using lint --- .../run-pass/issue-37290/auxiliary/lint.rs | 68 +++++++++++++++++++ src/test/run-pass/issue-37290/main.rs | 30 ++++++++ 2 files changed, 98 insertions(+) create mode 100644 src/test/run-pass/issue-37290/auxiliary/lint.rs create mode 100644 src/test/run-pass/issue-37290/main.rs diff --git a/src/test/run-pass/issue-37290/auxiliary/lint.rs b/src/test/run-pass/issue-37290/auxiliary/lint.rs new file mode 100644 index 00000000000..33d072eb6a8 --- /dev/null +++ b/src/test/run-pass/issue-37290/auxiliary/lint.rs @@ -0,0 +1,68 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This flag is needed for plugins to work: +// compile-flags: -C prefer-dynamic + +#![feature(plugin_registrar, rustc_private)] +#![crate_type = "dylib"] +#![deny(region_hierarchy)] + +extern crate syntax; +#[macro_use] +extern crate rustc; +extern crate rustc_plugin; + +use rustc::lint::{LateContext, LintPass, LateLintPass, LintArray, LintContext}; +use rustc::hir; +use rustc::hir::intravisit::FnKind; +use rustc::middle::region::CodeExtent; +use rustc::util::nodemap::FxHashMap; + +use syntax::ast::{self, NodeId}; +use syntax::codemap::Span; + +declare_lint!(REGION_HIERARCHY, Warn, "warn about bogus region hierarchy"); + +struct Pass { + map: FxHashMap +} + +impl LintPass for Pass { + fn get_lints(&self) -> LintArray { lint_array!(REGION_HIERARCHY) } +} + +impl LateLintPass for Pass { + fn check_fn(&mut self, cx: &LateContext, + fk: FnKind, _: &hir::FnDecl, expr: &hir::Expr, + span: Span, node: ast::NodeId) + { + if let FnKind::Closure(..) = fk { return } + + let mut extent = cx.tcx.region_maps.node_extent(expr.id); + while let Some(parent) = cx.tcx.region_maps.opt_encl_scope(extent) { + extent = parent; + } + if let Some(other) = self.map.insert(extent, node) { + cx.span_lint(REGION_HIERARCHY, span, &format!( + "different fns {:?}, {:?} with the same root extent {:?}", + cx.tcx.map.local_def_id(other), + cx.tcx.map.local_def_id(node), + extent)); + } + } +} + +#[plugin_registrar] +pub fn plugin_registrar(reg: &mut ::rustc_plugin::Registry) { + reg.register_late_lint_pass(Box::new( + Pass { map: FxHashMap() } + )); +} diff --git a/src/test/run-pass/issue-37290/main.rs b/src/test/run-pass/issue-37290/main.rs new file mode 100644 index 00000000000..394ad92b1d8 --- /dev/null +++ b/src/test/run-pass/issue-37290/main.rs @@ -0,0 +1,30 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:lint.rs + +#![feature(plugin)] +#![plugin(lint)] + +struct Foo { +} + +impl Foo { + fn bar(&self) -> usize { + 22 + } + + fn baz(&self) -> usize { + 22 + } +} + +fn main() { } + From e1b752b2a1bea9c05e89e52632f2f87ee9777062 Mon Sep 17 00:00:00 2001 From: Theodore DeRego Date: Thu, 1 Dec 2016 12:01:07 -0800 Subject: [PATCH 191/293] std::process fuchsia support cleanup --- src/libstd/sys/unix/mod.rs | 20 ------------------- src/libstd/sys/unix/{ => process}/magenta.rs | 15 +++++++++++++- src/libstd/sys/unix/process/mod.rs | 2 ++ src/libstd/sys/unix/process/process_common.rs | 6 +++--- .../sys/unix/process/process_fuchsia.rs | 17 +++++++--------- 5 files changed, 26 insertions(+), 34 deletions(-) rename src/libstd/sys/unix/{ => process}/magenta.rs (93%) diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index 8fe55af51d5..fd7dc17cccd 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -13,11 +13,6 @@ use io::{self, ErrorKind}; use libc; -#[cfg(target_os = "fuchsia")] -use convert::TryInto; -#[cfg(target_os = "fuchsia")] -pub use self::magenta::mx_status_t; - #[cfg(target_os = "android")] pub use os::android as platform; #[cfg(target_os = "bitrig")] pub use os::bitrig as platform; #[cfg(target_os = "dragonfly")] pub use os::dragonfly as platform; @@ -46,8 +41,6 @@ pub mod ext; pub mod fast_thread_local; pub mod fd; pub mod fs; -#[cfg(target_os = "fuchsia")] -pub mod magenta; pub mod memchr; pub mod mutex; pub mod net; @@ -171,19 +164,6 @@ pub fn cvt_r(mut f: F) -> io::Result } } -#[cfg(target_os = "fuchsia")] -pub fn mx_cvt(t: T) -> io::Result where T: TryInto+Copy { - if let Ok(status) = TryInto::try_into(t) { - if status < 0 { - Err(io::Error::from_raw_os_error(status)) - } else { - Ok(t) - } - } else { - Err(io::Error::last_os_error()) - } -} - // On Unix-like platforms, libc::abort will unregister signal handlers // including the SIGABRT handler, preventing the abort from being blocked, and // fclose streams, with the side effect of flushing them so libc bufferred diff --git a/src/libstd/sys/unix/magenta.rs b/src/libstd/sys/unix/process/magenta.rs similarity index 93% rename from src/libstd/sys/unix/magenta.rs rename to src/libstd/sys/unix/process/magenta.rs index 20e077ccaca..319fbce35cd 100644 --- a/src/libstd/sys/unix/magenta.rs +++ b/src/libstd/sys/unix/process/magenta.rs @@ -10,6 +10,8 @@ #![allow(non_camel_case_types)] +use convert::TryInto; +use io; use os::raw::c_char; use u64; @@ -42,6 +44,18 @@ pub const MX_INFO_PROCESS : mx_object_info_topic_t = 3; pub const MX_HND_TYPE_JOB: u32 = 6; +pub fn mx_cvt(t: T) -> io::Result where T: TryInto+Copy { + if let Ok(status) = TryInto::try_into(t) { + if status < 0 { + Err(io::Error::from_raw_os_error(status)) + } else { + Ok(t) + } + } else { + Err(io::Error::last_os_error()) + } +} + // Safe wrapper around mx_handle_t pub struct Handle { raw: mx_handle_t, @@ -61,7 +75,6 @@ impl Handle { impl Drop for Handle { fn drop(&mut self) { - use sys::mx_cvt; unsafe { mx_cvt(mx_handle_close(self.raw)).expect("Failed to close mx_handle_t"); } } } diff --git a/src/libstd/sys/unix/process/mod.rs b/src/libstd/sys/unix/process/mod.rs index 82c3971ee40..b50384d8eee 100644 --- a/src/libstd/sys/unix/process/mod.rs +++ b/src/libstd/sys/unix/process/mod.rs @@ -18,3 +18,5 @@ mod process_inner; #[cfg(target_os = "fuchsia")] #[path = "process_fuchsia.rs"] mod process_inner; +#[cfg(target_os = "fuchsia")] +mod magenta; diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs index 24b8b61edea..3497b266340 100644 --- a/src/libstd/sys/unix/process/process_common.rs +++ b/src/libstd/sys/unix/process/process_common.rs @@ -203,15 +203,15 @@ impl Command { &self.argv } - #[cfg(not(target_os="fuchsia"))] + #[allow(dead_code)] pub fn get_cwd(&self) -> &Option { &self.cwd } - #[cfg(not(target_os="fuchsia"))] + #[allow(dead_code)] pub fn get_uid(&self) -> Option { self.uid } - #[cfg(not(target_os="fuchsia"))] + #[allow(dead_code)] pub fn get_gid(&self) -> Option { self.gid } diff --git a/src/libstd/sys/unix/process/process_fuchsia.rs b/src/libstd/sys/unix/process/process_fuchsia.rs index 77340664b6a..f0a42b12799 100644 --- a/src/libstd/sys/unix/process/process_fuchsia.rs +++ b/src/libstd/sys/unix/process/process_fuchsia.rs @@ -13,8 +13,7 @@ use libc; use mem; use ptr; -use sys::mx_cvt; -use sys::magenta::{Handle, launchpad_t, mx_handle_t}; +use sys::process::magenta::{Handle, launchpad_t, mx_handle_t}; use sys::process::process_common::*; //////////////////////////////////////////////////////////////////////////////// @@ -53,7 +52,7 @@ impl Command { unsafe fn do_exec(&mut self, stdio: ChildPipes) -> io::Result<(*mut launchpad_t, mx_handle_t)> { - use sys::magenta::*; + use sys::process::magenta::*; let job_handle = mxio_get_startup_handle(mx_hnd_info(MX_HND_TYPE_JOB, 0)); let envp = match *self.get_envp() { @@ -72,11 +71,9 @@ impl Command { // Duplicate the job handle let mut job_copy: mx_handle_t = MX_HANDLE_INVALID; - mx_cvt(mx_handle_duplicate(job_handle, MX_RIGHT_SAME_RIGHTS, - &mut job_copy as *mut mx_handle_t))?; + mx_cvt(mx_handle_duplicate(job_handle, MX_RIGHT_SAME_RIGHTS, &mut job_copy))?; // Create a launchpad - mx_cvt(launchpad_create(job_copy, self.get_argv()[0], - &mut launchpad as *mut *mut launchpad_t))?; + mx_cvt(launchpad_create(job_copy, self.get_argv()[0], &mut launchpad))?; // Set the process argv mx_cvt(launchpad_arguments(launchpad, self.get_argv().len() as i32 - 1, self.get_argv().as_ptr()))?; @@ -138,7 +135,7 @@ impl Process { } pub fn kill(&mut self) -> io::Result<()> { - use sys::magenta::*; + use sys::process::magenta::*; unsafe { mx_cvt(mx_task_kill(self.handle.raw()))?; } @@ -147,7 +144,7 @@ impl Process { pub fn wait(&mut self) -> io::Result { use default::Default; - use sys::magenta::*; + use sys::process::magenta::*; let mut proc_info: mx_info_process_t = Default::default(); let mut actual: mx_size_t = 0; @@ -171,7 +168,7 @@ impl Process { impl Drop for Process { fn drop(&mut self) { - use sys::magenta::launchpad_destroy; + use sys::process::magenta::launchpad_destroy; unsafe { launchpad_destroy(self.launchpad); } } } From 242cd7ebe295d44c7b612e2e1da8b83412d31f49 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 15 Nov 2016 23:25:59 +0200 Subject: [PATCH 192/293] limit the length of types in monomorphization This adds the new insta-stable `#![type_size_limit]` crate attribute to control the limit, and is obviously a [breaking-change] fixable by that. --- src/librustc/middle/recursion_limit.rs | 21 ++++++++--- src/librustc/session/mod.rs | 4 +++ src/librustc_driver/driver.rs | 2 +- src/librustc_trans/collector.rs | 35 +++++++++++++++++++ src/libsyntax/feature_gate.rs | 1 + src/test/compile-fail/issue-22638.rs | 3 +- src/test/compile-fail/type_length_limit.rs | 35 +++++++++++++++++++ .../issue-37311.rs | 30 ++++++++++++++++ .../issue-37311.stderr | 13 +++++++ 9 files changed, 137 insertions(+), 7 deletions(-) create mode 100644 src/test/compile-fail/type_length_limit.rs create mode 100644 src/test/ui/issue-37311-type-length-limit/issue-37311.rs create mode 100644 src/test/ui/issue-37311-type-length-limit/issue-37311.stderr diff --git a/src/librustc/middle/recursion_limit.rs b/src/librustc/middle/recursion_limit.rs index 7f89461a3f4..6c87f750376 100644 --- a/src/librustc/middle/recursion_limit.rs +++ b/src/librustc/middle/recursion_limit.rs @@ -18,20 +18,31 @@ use session::Session; use syntax::ast; -pub fn update_recursion_limit(sess: &Session, krate: &ast::Crate) { +use std::cell::Cell; + +pub fn update_limits(sess: &Session, krate: &ast::Crate) { + update_limit(sess, krate, &sess.recursion_limit, "recursion_limit", + "recursion limit"); + update_limit(sess, krate, &sess.type_length_limit, "type_length_limit", + "type length limit"); +} + +fn update_limit(sess: &Session, krate: &ast::Crate, limit: &Cell, + name: &str, description: &str) { for attr in &krate.attrs { - if !attr.check_name("recursion_limit") { + if !attr.check_name(name) { continue; } if let Some(s) = attr.value_str() { if let Some(n) = s.as_str().parse().ok() { - sess.recursion_limit.set(n); + limit.set(n); return; } } - span_err!(sess, attr.span, E0296, "malformed recursion limit attribute, \ - expected #![recursion_limit=\"N\"]"); + span_err!(sess, attr.span, E0296, + "malformed {} attribute, expected #![{}=\"N\"]", + description, name); } } diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 3d8cfd19961..91765e68ae6 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -100,6 +100,9 @@ pub struct Session { /// operations such as auto-dereference and monomorphization. pub recursion_limit: Cell, + /// The maximum length of types during monomorphization. + pub type_length_limit: Cell, + /// The metadata::creader module may inject an allocator/panic_runtime /// dependency if it didn't already find one, and this tracks what was /// injected. @@ -620,6 +623,7 @@ pub fn build_session_(sopts: config::Options, crate_disambiguator: RefCell::new(Symbol::intern("")), features: RefCell::new(feature_gate::Features::new()), recursion_limit: Cell::new(64), + type_length_limit: Cell::new(1048576), next_node_id: Cell::new(NodeId::new(1)), injected_allocator: Cell::new(None), injected_panic_runtime: Cell::new(None), diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index bee79103b41..069f0a89bef 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -566,7 +566,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, *sess.crate_disambiguator.borrow_mut() = Symbol::intern(&compute_crate_disambiguator(sess)); time(time_passes, "recursion limit", || { - middle::recursion_limit::update_recursion_limit(sess, &krate); + middle::recursion_limit::update_limits(sess, &krate); }); krate = time(time_passes, "crate injection", || { diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 120e1a562eb..7416b86bfeb 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -361,6 +361,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>, recursion_depth_reset = Some(check_recursion_limit(scx.tcx(), instance, recursion_depths)); + check_type_length_limit(scx.tcx(), instance); // Scan the MIR in order to find function calls, closures, and // drop-glue @@ -432,6 +433,40 @@ fn check_recursion_limit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (instance.def, recursion_depth) } +fn check_type_length_limit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + instance: Instance<'tcx>) +{ + let type_length = instance.substs.types().flat_map(|ty| ty.walk()).count(); + debug!(" => type length={}", type_length); + + // Rust code can easily create exponentially-long types using only a + // polynomial recursion depth. Even with the default recursion + // depth, you can easily get cases that take >2^60 steps to run, + // which means that rustc basically hangs. + // + // Bail out in these cases to avoid that bad user experience. + let type_length_limit = tcx.sess.type_length_limit.get(); + if type_length > type_length_limit { + // The instance name is already known to be too long for rustc. Use + // `{:.64}` to avoid blasting the user's terminal with thousands of + // lines of type-name. + let instance_name = instance.to_string(); + let msg = format!("reached the type-length limit while instantiating `{:.64}...`", + instance_name); + let mut diag = if let Some(node_id) = tcx.map.as_local_node_id(instance.def) { + tcx.sess.struct_span_fatal(tcx.map.span(node_id), &msg) + } else { + tcx.sess.struct_fatal(&msg) + }; + + diag.note(&format!( + "consider adding a `#![type_length_limit=\"{}\"]` attribute to your crate", + type_length_limit*2)); + diag.emit(); + tcx.sess.abort_if_errors(); + } +} + struct MirNeighborCollector<'a, 'tcx: 'a> { scx: &'a SharedCrateContext<'a, 'tcx>, mir: &'a mir::Mir<'tcx>, diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index aa6a29b78b0..2a745e979a7 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -738,6 +738,7 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG ("no_main", CrateLevel, Ungated), ("no_builtins", CrateLevel, Ungated), ("recursion_limit", CrateLevel, Ungated), + ("type_length_limit", CrateLevel, Ungated), ]; // cfg(...)'s that are feature gated diff --git a/src/test/compile-fail/issue-22638.rs b/src/test/compile-fail/issue-22638.rs index 0c8c2311dca..65d1d837d7d 100644 --- a/src/test/compile-fail/issue-22638.rs +++ b/src/test/compile-fail/issue-22638.rs @@ -10,7 +10,8 @@ #![allow(unused)] -#![recursion_limit = "32"] +#![recursion_limit = "20"] +#![type_length_limit = "20000000"] #[derive(Clone)] struct A (B); diff --git a/src/test/compile-fail/type_length_limit.rs b/src/test/compile-fail/type_length_limit.rs new file mode 100644 index 00000000000..d283f392d76 --- /dev/null +++ b/src/test/compile-fail/type_length_limit.rs @@ -0,0 +1,35 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// error-pattern: reached the type-length limit while instantiating + +// Test that the type length limit can be changed. + +#![allow(dead_code)] +#![type_length_limit="256"] + +macro_rules! link { + ($id:ident, $t:ty) => { + pub type $id = ($t, $t, $t); + } +} + +link! { A, B } +link! { B, C } +link! { C, D } +link! { D, E } +link! { E, F } +link! { F, G } + +pub struct G; + +fn main() { + drop::>(None); +} diff --git a/src/test/ui/issue-37311-type-length-limit/issue-37311.rs b/src/test/ui/issue-37311-type-length-limit/issue-37311.rs new file mode 100644 index 00000000000..add96461f1b --- /dev/null +++ b/src/test/ui/issue-37311-type-length-limit/issue-37311.rs @@ -0,0 +1,30 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Mirror { + type Image; +} + +impl Mirror for T { type Image = T; } + +trait Foo { + fn recurse(&self); +} + +impl Foo for T { + #[allow(unconditional_recursion)] + fn recurse(&self) { + (self, self).recurse(); + } +} + +fn main() { + ().recurse(); +} diff --git a/src/test/ui/issue-37311-type-length-limit/issue-37311.stderr b/src/test/ui/issue-37311-type-length-limit/issue-37311.stderr new file mode 100644 index 00000000000..5a63d235a7f --- /dev/null +++ b/src/test/ui/issue-37311-type-length-limit/issue-37311.stderr @@ -0,0 +1,13 @@ +error: reached the type-length limit while instantiating `<(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(), &()), &(&()...` + --> $DIR/issue-37311.rs:23:5 + | +23 | fn recurse(&self) { + | _____^ starting here... +24 | | (self, self).recurse(); +25 | | } + | |_____^ ...ending here + | + = note: consider adding a `#![type_length_limit="2097152"]` attribute to your crate + +error: aborting due to previous error + From 8285ab5c99db166e2137fb4b92fedd03b56acaa0 Mon Sep 17 00:00:00 2001 From: Doug Goldstein Date: Thu, 1 Dec 2016 16:26:47 -0600 Subject: [PATCH 193/293] convert --print options to a vector To allow manipulation of the options that appear in --print, convert it to a vector. Signed-off-by: Doug Goldstein --- src/librustc/session/config.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 26dafed7019..9dd341c7674 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1138,6 +1138,10 @@ mod opt { /// including metadata for each option, such as whether the option is /// part of the stable long-term interface for rustc. pub fn rustc_short_optgroups() -> Vec { + let mut print_opts = vec!["crate-name", "file-names", "sysroot", "cfg", + "target-list", "target-cpus", "target-features", + "relocation-models", "code-models"]; + vec![ opt::flag_s("h", "help", "Display this message"), opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"), @@ -1157,9 +1161,7 @@ pub fn rustc_short_optgroups() -> Vec { the compiler to emit", "[asm|llvm-bc|llvm-ir|obj|link|dep-info]"), opt::multi_s("", "print", "Comma separated list of compiler information to \ - print on stdout", - "[crate-name|file-names|sysroot|cfg|target-list|target-cpus|\ - target-features|relocation-models|code-models]"), + print on stdout", &print_opts.join("|")), opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"), opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"), opt::opt_s("o", "", "Write output to ", "FILENAME"), From bc019dfb39bab6979009bb89ecc2d3af460b3c37 Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Wed, 23 Nov 2016 16:09:51 -0800 Subject: [PATCH 194/293] Emit 'dllimport' attribute for dylib foreign items on Windows. --- src/librustc/middle/cstore.rs | 11 +-- src/librustc_metadata/creader.rs | 84 ++++++++++++------- src/librustc_metadata/cstore.rs | 21 +++-- src/librustc_metadata/cstore_impl.rs | 14 +++- src/librustc_metadata/decoder.rs | 17 +++- src/librustc_trans/base.rs | 3 +- src/librustc_trans/callee.rs | 6 +- src/librustc_trans/consts.rs | 13 ++- .../codegen/dllimports/auxiliary/dummy.rs | 16 ++++ .../codegen/dllimports/auxiliary/wrapper.rs | 24 ++++++ src/test/codegen/dllimports/main.rs | 63 ++++++++++++++ 11 files changed, 223 insertions(+), 49 deletions(-) create mode 100644 src/test/codegen/dllimports/auxiliary/dummy.rs create mode 100644 src/test/codegen/dllimports/auxiliary/wrapper.rs create mode 100644 src/test/codegen/dllimports/main.rs diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 484e2f1535e..9275c01c8b1 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -131,6 +131,7 @@ pub struct NativeLibrary { pub kind: NativeLibraryKind, pub name: Symbol, pub cfg: Option, + pub foreign_items: Vec, } /// The data we save and restore about an inlined item or method. This is not @@ -305,7 +306,8 @@ pub trait CrateStore<'tcx> { fn is_defaulted_trait(&self, did: DefId) -> bool; fn is_default_impl(&self, impl_did: DefId) -> bool; fn is_foreign_item(&self, did: DefId) -> bool; - fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool; + fn is_dllimport_foreign_item(&self, def: DefId) -> bool; + fn is_statically_included_foreign_item(&self, def_id: DefId) -> bool; // crate metadata fn dylib_dependency_formats(&self, cnum: CrateNum) @@ -462,7 +464,8 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn is_defaulted_trait(&self, did: DefId) -> bool { bug!("is_defaulted_trait") } fn is_default_impl(&self, impl_did: DefId) -> bool { bug!("is_default_impl") } fn is_foreign_item(&self, did: DefId) -> bool { bug!("is_foreign_item") } - fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool { false } + fn is_dllimport_foreign_item(&self, id: DefId) -> bool { false } + fn is_statically_included_foreign_item(&self, def_id: DefId) -> bool { false } // crate metadata fn dylib_dependency_formats(&self, cnum: CrateNum) @@ -526,9 +529,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { // This is basically a 1-based range of ints, which is a little // silly - I may fix that. fn crates(&self) -> Vec { vec![] } - fn used_libraries(&self) -> Vec { - vec![] - } + fn used_libraries(&self) -> Vec { vec![] } fn used_link_args(&self) -> Vec { vec![] } // utility functions diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 2c266068fe8..436b1b3159f 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -52,7 +52,7 @@ pub struct CrateLoader<'a> { pub sess: &'a Session, cstore: &'a CStore, next_crate_num: CrateNum, - foreign_item_map: FxHashMap>, + foreign_item_map: FxHashMap>, local_crate_name: Symbol, } @@ -310,6 +310,7 @@ impl<'a> CrateLoader<'a> { rlib: rlib, rmeta: rmeta, }, + dllimport_foreign_items: RefCell::new(None), }); self.cstore.set_crate_data(cnum, cmeta.clone()); @@ -640,18 +641,36 @@ impl<'a> CrateLoader<'a> { } } - fn register_statically_included_foreign_items(&mut self) { + fn get_foreign_items_of_kind(&self, kind: cstore::NativeLibraryKind) -> Vec { + let mut items = vec![]; let libs = self.cstore.get_used_libraries(); - for (foreign_lib, list) in self.foreign_item_map.iter() { - let is_static = libs.borrow().iter().any(|lib| { - lib.name == &**foreign_lib && lib.kind == cstore::NativeStatic - }); - if is_static { - for id in list { - self.cstore.add_statically_included_foreign_item(*id); - } + for lib in libs.borrow().iter() { + if lib.kind == kind { + items.extend(&lib.foreign_items); } } + for (foreign_lib, list) in self.foreign_item_map.iter() { + let kind_matches = libs.borrow().iter().any(|lib| { + lib.name == &**foreign_lib && lib.kind == kind + }); + if kind_matches { + items.extend(list) + } + } + items + } + + fn register_statically_included_foreign_items(&mut self) { + for id in self.get_foreign_items_of_kind(cstore::NativeStatic) { + self.cstore.add_statically_included_foreign_item(id); + } + } + + fn register_dllimport_foreign_items(&mut self) { + let mut dllimports = self.cstore.dllimport_foreign_items.borrow_mut(); + for id in self.get_foreign_items_of_kind(cstore::NativeUnknown) { + dllimports.insert(id); + } } fn inject_panic_runtime(&mut self, krate: &ast::Crate) { @@ -861,7 +880,8 @@ impl<'a> CrateLoader<'a> { } } - fn process_foreign_mod(&mut self, i: &ast::Item, fm: &ast::ForeignMod) { + fn process_foreign_mod(&mut self, i: &ast::Item, fm: &ast::ForeignMod, + definitions: &Definitions) { if fm.abi == Abi::Rust || fm.abi == Abi::RustIntrinsic || fm.abi == Abi::PlatformIntrinsic { return; } @@ -912,10 +932,14 @@ impl<'a> CrateLoader<'a> { let cfg = cfg.map(|list| { list[0].meta_item().unwrap().clone() }); + let foreign_items = fm.items.iter() + .map(|it| definitions.opt_def_index(it.id).unwrap()) + .collect(); let lib = NativeLibrary { name: n, kind: kind, cfg: cfg, + foreign_items: foreign_items, }; register_native_lib(self.sess, self.cstore, Some(m.span), lib); } @@ -928,7 +952,7 @@ impl<'a> CrateLoader<'a> { }; let list = self.foreign_item_map.entry(lib_name.to_string()) .or_insert(Vec::new()); - list.extend(fm.items.iter().map(|it| it.id)); + list.extend(fm.items.iter().map(|it| definitions.opt_def_index(it.id).unwrap())); } } } @@ -947,30 +971,34 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { name: Symbol::intern(name), kind: kind, cfg: None, + foreign_items: Vec::new(), }; register_native_lib(self.sess, self.cstore, None, lib); } self.register_statically_included_foreign_items(); + self.register_dllimport_foreign_items(); } fn process_item(&mut self, item: &ast::Item, definitions: &Definitions) { match item.node { - ast::ItemKind::ExternCrate(_) => {} - ast::ItemKind::ForeignMod(ref fm) => return self.process_foreign_mod(item, fm), - _ => return, + ast::ItemKind::ForeignMod(ref fm) => { + self.process_foreign_mod(item, fm, definitions) + }, + ast::ItemKind::ExternCrate(_) => { + let info = self.extract_crate_info(item).unwrap(); + let (cnum, ..) = self.resolve_crate( + &None, info.ident, info.name, None, item.span, PathKind::Crate, info.dep_kind, + ); + + let def_id = definitions.opt_local_def_id(item.id).unwrap(); + let len = definitions.def_path(def_id.index).data.len(); + + let extern_crate = + ExternCrate { def_id: def_id, span: item.span, direct: true, path_len: len }; + self.update_extern_crate(cnum, extern_crate, &mut FxHashSet()); + self.cstore.add_extern_mod_stmt_cnum(info.id, cnum); + } + _ => {} } - - let info = self.extract_crate_info(item).unwrap(); - let (cnum, ..) = self.resolve_crate( - &None, info.ident, info.name, None, item.span, PathKind::Crate, info.dep_kind, - ); - - let def_id = definitions.opt_local_def_id(item.id).unwrap(); - let len = definitions.def_path(def_id.index).data.len(); - - let extern_crate = - ExternCrate { def_id: def_id, span: item.span, direct: true, path_len: len }; - self.update_extern_crate(cnum, extern_crate, &mut FxHashSet()); - self.cstore.add_extern_mod_stmt_cnum(info.id, cnum); } } diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 73e03a45196..279ef5bfb72 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -15,13 +15,13 @@ use locator; use schema; use rustc::dep_graph::DepGraph; -use rustc::hir::def_id::{CRATE_DEF_INDEX, CrateNum, DefIndex, DefId}; +use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, CrateNum, DefIndex, DefId}; use rustc::hir::map::DefKey; use rustc::hir::svh::Svh; use rustc::middle::cstore::{DepKind, ExternCrate}; use rustc_back::PanicStrategy; use rustc_data_structures::indexed_vec::IndexVec; -use rustc::util::nodemap::{FxHashMap, NodeMap, NodeSet, DefIdMap}; +use rustc::util::nodemap::{FxHashMap, FxHashSet, NodeMap, DefIdMap}; use std::cell::{RefCell, Cell}; use std::rc::Rc; @@ -31,7 +31,7 @@ use syntax::ext::base::SyntaxExtension; use syntax::symbol::Symbol; use syntax_pos; -pub use rustc::middle::cstore::{NativeLibrary, LinkagePreference}; +pub use rustc::middle::cstore::{NativeLibrary, NativeLibraryKind, LinkagePreference}; pub use rustc::middle::cstore::{NativeStatic, NativeFramework, NativeUnknown}; pub use rustc::middle::cstore::{CrateSource, LinkMeta, LibSource}; @@ -84,6 +84,8 @@ pub struct CrateMetadata { pub source: CrateSource, pub proc_macros: Option)>>, + // Foreign items imported from a dylib (Windows only) + pub dllimport_foreign_items: RefCell>>, } pub struct CachedInlinedItem { @@ -100,7 +102,8 @@ pub struct CStore { extern_mod_crate_map: RefCell>, used_libraries: RefCell>, used_link_args: RefCell>, - statically_included_foreign_items: RefCell, + statically_included_foreign_items: RefCell>, + pub dllimport_foreign_items: RefCell>, pub inlined_item_cache: RefCell>>, pub defid_for_inlined_node: RefCell>, pub visible_parent_map: RefCell>, @@ -114,7 +117,8 @@ impl CStore { extern_mod_crate_map: RefCell::new(FxHashMap()), used_libraries: RefCell::new(Vec::new()), used_link_args: RefCell::new(Vec::new()), - statically_included_foreign_items: RefCell::new(NodeSet()), + statically_included_foreign_items: RefCell::new(FxHashSet()), + dllimport_foreign_items: RefCell::new(FxHashSet()), visible_parent_map: RefCell::new(FxHashMap()), inlined_item_cache: RefCell::new(FxHashMap()), defid_for_inlined_node: RefCell::new(FxHashMap()), @@ -246,12 +250,13 @@ impl CStore { self.extern_mod_crate_map.borrow_mut().insert(emod_id, cnum); } - pub fn add_statically_included_foreign_item(&self, id: ast::NodeId) { + pub fn add_statically_included_foreign_item(&self, id: DefIndex) { self.statically_included_foreign_items.borrow_mut().insert(id); } - pub fn do_is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool { - self.statically_included_foreign_items.borrow().contains(&id) + pub fn do_is_statically_included_foreign_item(&self, def_id: DefId) -> bool { + assert!(def_id.krate == LOCAL_CRATE); + self.statically_included_foreign_items.borrow().contains(&def_id.index) } pub fn do_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option { diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index c41c3afb83e..e3193d322bf 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -19,7 +19,7 @@ use rustc::hir::def::{self, Def}; use rustc::middle::lang_items; use rustc::session::Session; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX}; +use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc::dep_graph::DepNode; use rustc::hir::map as hir_map; @@ -217,9 +217,17 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { self.get_crate_data(did.krate).is_foreign_item(did.index) } - fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool + fn is_statically_included_foreign_item(&self, def_id: DefId) -> bool { - self.do_is_statically_included_foreign_item(id) + self.do_is_statically_included_foreign_item(def_id) + } + + fn is_dllimport_foreign_item(&self, def_id: DefId) -> bool { + if def_id.krate == LOCAL_CRATE { + self.dllimport_foreign_items.borrow().contains(&def_id.index) + } else { + self.get_crate_data(def_id.krate).is_dllimport_foreign_item(def_id.index) + } } fn dylib_dependency_formats(&self, cnum: CrateNum) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 308cd6a83db..f8f80a60c16 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -11,13 +11,13 @@ // Decoding metadata from a single crate's metadata use astencode::decode_inlined_item; -use cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary}; +use cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary, NativeLibraryKind}; use index::Index; use schema::*; use rustc::hir::map as hir_map; use rustc::hir::map::{DefKey, DefPathData}; -use rustc::util::nodemap::FxHashMap; +use rustc::util::nodemap::{FxHashMap, FxHashSet}; use rustc::hir; use rustc::hir::intravisit::IdRange; @@ -36,6 +36,7 @@ use rustc::mir::Mir; use std::borrow::Cow; use std::cell::Ref; use std::io; +use std::iter::FromIterator; use std::mem; use std::str; use std::u32; @@ -1087,6 +1088,18 @@ impl<'a, 'tcx> CrateMetadata { } } + pub fn is_dllimport_foreign_item(&self, id: DefIndex) -> bool { + if self.dllimport_foreign_items.borrow().is_none() { + *self.dllimport_foreign_items.borrow_mut() = Some(FxHashSet::from_iter( + self.get_native_libraries().iter() + .filter(|lib| lib.kind == NativeLibraryKind::NativeUnknown) + .flat_map(|lib| &lib.foreign_items) + .map(|id| *id) + )); + } + self.dllimport_foreign_items.borrow().as_ref().unwrap().contains(&id) + } + pub fn is_defaulted_trait(&self, trait_id: DefIndex) -> bool { match self.entry(trait_id).kind { EntryKind::Trait(data) => data.decode(self).has_default_impl, diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index f1126e6fd25..6a9c81dfd5d 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1498,7 +1498,8 @@ pub fn filter_reachable_ids(tcx: TyCtxt, reachable: NodeSet) -> NodeSet { // let it through if it's included statically. match tcx.map.get(id) { hir_map::NodeForeignItem(..) => { - tcx.sess.cstore.is_statically_included_foreign_item(id) + let def_id = tcx.map.local_def_id(id); + tcx.sess.cstore.is_statically_included_foreign_item(def_id) } // Only consider nodes that actually have exported symbols. diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index df56e27128c..9fd61caf6fe 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -629,7 +629,11 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage); } } - + if ccx.use_dll_storage_attrs() && ccx.sess().cstore.is_dllimport_foreign_item(def_id) { + unsafe { + llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport); + } + } llfn }; diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 4186721c122..730a4025a59 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -191,7 +191,12 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef { llvm::set_thread_local(g, true); } } - if ccx.use_dll_storage_attrs() { + if ccx.use_dll_storage_attrs() && !ccx.sess().cstore.is_foreign_item(def_id) { + // This item is external but not foreign, i.e. it originates from an external Rust + // crate. Since we don't know whether this crate will be linked dynamically or + // statically in the final application, we always mark such symbols as 'dllimport'. + // If final linkage happens to be static, we rely on compiler-emitted __imp_ stubs to + // make things work. unsafe { llvm::LLVMSetDLLStorageClass(g, llvm::DLLStorageClass::DllImport); } @@ -199,6 +204,12 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef { g }; + if ccx.use_dll_storage_attrs() && ccx.sess().cstore.is_dllimport_foreign_item(def_id) { + // For foreign (native) libs we know the exact storage type to use. + unsafe { + llvm::LLVMSetDLLStorageClass(g, llvm::DLLStorageClass::DllImport); + } + } ccx.instances().borrow_mut().insert(instance, g); ccx.statics().borrow_mut().insert(g, def_id); g diff --git a/src/test/codegen/dllimports/auxiliary/dummy.rs b/src/test/codegen/dllimports/auxiliary/dummy.rs new file mode 100644 index 00000000000..06001c6b014 --- /dev/null +++ b/src/test/codegen/dllimports/auxiliary/dummy.rs @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// no-prefer-dynamic +#![crate_type = "staticlib"] + +// Since codegen tests don't actually perform linking, this library doesn't need to export +// any symbols. It's here just to satisfy the compiler looking for a .lib file when processing +// #[link(...)] attributes in wrapper.rs. diff --git a/src/test/codegen/dllimports/auxiliary/wrapper.rs b/src/test/codegen/dllimports/auxiliary/wrapper.rs new file mode 100644 index 00000000000..c03f88092e5 --- /dev/null +++ b/src/test/codegen/dllimports/auxiliary/wrapper.rs @@ -0,0 +1,24 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// no-prefer-dynamic +#![crate_type = "rlib"] + +#[link(name = "dummy", kind="dylib")] +extern "C" { + pub fn dylib_func2(x: i32) -> i32; + pub static dylib_global2: i32; +} + +#[link(name = "dummy", kind="static")] +extern "C" { + pub fn static_func2(x: i32) -> i32; + pub static static_global2: i32; +} diff --git a/src/test/codegen/dllimports/main.rs b/src/test/codegen/dllimports/main.rs new file mode 100644 index 00000000000..140d95fb7be --- /dev/null +++ b/src/test/codegen/dllimports/main.rs @@ -0,0 +1,63 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This test is for Windows only. +// ignore-android +// ignore-bitrig +// ignore-macos +// ignore-dragonfly +// ignore-freebsd +// ignore-haiku +// ignore-ios +// ignore-linux +// ignore-netbsd +// ignore-openbsd +// ignore-solaris +// ignore-emscripten + +// aux-build:dummy.rs +// aux-build:wrapper.rs + +extern crate wrapper; + +// Check that external symbols coming from foreign dylibs are adorned with 'dllimport', +// whereas symbols coming from foreign staticlibs are not. (RFC-1717) + +// CHECK: @dylib_global1 = external dllimport local_unnamed_addr global i32 +// CHECK: @dylib_global2 = external dllimport local_unnamed_addr global i32 +// CHECK: @static_global1 = external local_unnamed_addr global i32 +// CHECK: @static_global2 = external local_unnamed_addr global i32 + +// CHECK: declare dllimport i32 @dylib_func1(i32) +// CHECK: declare dllimport i32 @dylib_func2(i32) +// CHECK: declare i32 @static_func1(i32) +// CHECK: declare i32 @static_func2(i32) + +#[link(name = "dummy", kind="dylib")] +extern "C" { + pub fn dylib_func1(x: i32) -> i32; + pub static dylib_global1: i32; +} + +#[link(name = "dummy", kind="static")] +extern "C" { + pub fn static_func1(x: i32) -> i32; + pub static static_global1: i32; +} + +fn main() { + unsafe { + dylib_func1(dylib_global1); + wrapper::dylib_func2(wrapper::dylib_global2); + + static_func1(static_global1); + wrapper::static_func2(wrapper::static_global2); + } +} From 4508e8a847c57b2eb8c7bf7e318c49b7cd327cb7 Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Wed, 23 Nov 2016 16:09:51 -0800 Subject: [PATCH 195/293] Fix rust_test_helpers linkage. --- src/test/run-pass/abi-sysv64-arg-passing.rs | 2 +- src/test/run-pass/anon-extern-mod.rs | 2 +- src/test/run-pass/auxiliary/anon-extern-mod-cross-crate-1.rs | 2 +- src/test/run-pass/auxiliary/extern-crosscrate-source.rs | 2 +- src/test/run-pass/auxiliary/foreign_lib.rs | 2 +- src/test/run-pass/c-stack-as-value.rs | 2 +- src/test/run-pass/cabi-int-widening.rs | 2 +- src/test/run-pass/extern-call-deep.rs | 2 +- src/test/run-pass/extern-call-deep2.rs | 2 +- src/test/run-pass/extern-call-indirect.rs | 2 +- src/test/run-pass/extern-call-scrub.rs | 2 +- src/test/run-pass/extern-pass-TwoU16s.rs | 2 +- src/test/run-pass/extern-pass-TwoU32s.rs | 2 +- src/test/run-pass/extern-pass-TwoU64s.rs | 2 +- src/test/run-pass/extern-pass-TwoU8s.rs | 2 +- src/test/run-pass/extern-pass-char.rs | 2 +- src/test/run-pass/extern-pass-double.rs | 2 +- src/test/run-pass/extern-pass-empty.rs | 2 +- src/test/run-pass/extern-pass-u32.rs | 2 +- src/test/run-pass/extern-pass-u64.rs | 2 +- src/test/run-pass/extern-return-TwoU16s.rs | 2 +- src/test/run-pass/extern-return-TwoU32s.rs | 2 +- src/test/run-pass/extern-return-TwoU64s.rs | 2 +- src/test/run-pass/extern-return-TwoU8s.rs | 2 +- src/test/run-pass/foreign-call-no-runtime.rs | 2 +- src/test/run-pass/foreign-fn-with-byval.rs | 2 +- src/test/run-pass/foreign-no-abi.rs | 2 +- src/test/run-pass/issue-28676.rs | 2 +- src/test/run-pass/mir_trans_calls_variadic.rs | 2 +- src/test/run-pass/segfault-no-out-of-stack.rs | 2 +- src/test/run-pass/static-mut-foreign.rs | 2 +- src/test/run-pass/struct-return.rs | 2 +- src/test/run-pass/union/union-c-interop.rs | 2 +- src/test/run-pass/variadic-ffi.rs | 2 +- 34 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/test/run-pass/abi-sysv64-arg-passing.rs b/src/test/run-pass/abi-sysv64-arg-passing.rs index 989155bdfd9..23dd0603184 100644 --- a/src/test/run-pass/abi-sysv64-arg-passing.rs +++ b/src/test/run-pass/abi-sysv64-arg-passing.rs @@ -98,7 +98,7 @@ mod tests { #[derive(Copy, Clone)] pub struct Floats { a: f64, b: u8, c: f64 } - #[link(name = "rust_test_helpers")] + #[link(name = "rust_test_helpers", kind = "static")] extern "sysv64" { pub fn rust_int8_to_int32(_: i8) -> i32; pub fn rust_dbg_extern_identity_u8(v: u8) -> u8; diff --git a/src/test/run-pass/anon-extern-mod.rs b/src/test/run-pass/anon-extern-mod.rs index e96b0cc1442..208b4df3c3e 100644 --- a/src/test/run-pass/anon-extern-mod.rs +++ b/src/test/run-pass/anon-extern-mod.rs @@ -14,7 +14,7 @@ extern crate libc; -#[link(name = "rust_test_helpers")] +#[link(name = "rust_test_helpers", kind = "static")] extern { fn rust_get_test_int() -> libc::intptr_t; } diff --git a/src/test/run-pass/auxiliary/anon-extern-mod-cross-crate-1.rs b/src/test/run-pass/auxiliary/anon-extern-mod-cross-crate-1.rs index 197fb9a6d01..741ce351da3 100644 --- a/src/test/run-pass/auxiliary/anon-extern-mod-cross-crate-1.rs +++ b/src/test/run-pass/auxiliary/anon-extern-mod-cross-crate-1.rs @@ -13,7 +13,7 @@ extern crate libc; -#[link(name="rust_test_helpers")] +#[link(name = "rust_test_helpers", kind = "static")] extern { pub fn rust_get_test_int() -> libc::intptr_t; } diff --git a/src/test/run-pass/auxiliary/extern-crosscrate-source.rs b/src/test/run-pass/auxiliary/extern-crosscrate-source.rs index fc2e328f686..150dffeea88 100644 --- a/src/test/run-pass/auxiliary/extern-crosscrate-source.rs +++ b/src/test/run-pass/auxiliary/extern-crosscrate-source.rs @@ -17,7 +17,7 @@ extern crate libc; pub mod rustrt { extern crate libc; - #[link(name = "rust_test_helpers")] + #[link(name = "rust_test_helpers", kind = "static")] extern { pub fn rust_dbg_call(cb: extern "C" fn(libc::uintptr_t) -> libc::uintptr_t, data: libc::uintptr_t) diff --git a/src/test/run-pass/auxiliary/foreign_lib.rs b/src/test/run-pass/auxiliary/foreign_lib.rs index 460d0a0088c..cef36274c62 100644 --- a/src/test/run-pass/auxiliary/foreign_lib.rs +++ b/src/test/run-pass/auxiliary/foreign_lib.rs @@ -15,7 +15,7 @@ pub mod rustrt { extern crate libc; - #[link(name = "rust_test_helpers")] + #[link(name = "rust_test_helpers", kind = "static")] extern { pub fn rust_get_test_int() -> libc::intptr_t; } diff --git a/src/test/run-pass/c-stack-as-value.rs b/src/test/run-pass/c-stack-as-value.rs index b678f149fa2..5319693405b 100644 --- a/src/test/run-pass/c-stack-as-value.rs +++ b/src/test/run-pass/c-stack-as-value.rs @@ -15,7 +15,7 @@ mod rustrt { extern crate libc; - #[link(name = "rust_test_helpers")] + #[link(name = "rust_test_helpers", kind = "static")] extern { pub fn rust_get_test_int() -> libc::intptr_t; } diff --git a/src/test/run-pass/cabi-int-widening.rs b/src/test/run-pass/cabi-int-widening.rs index c7a22759333..bf94dd17882 100644 --- a/src/test/run-pass/cabi-int-widening.rs +++ b/src/test/run-pass/cabi-int-widening.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[link(name = "rust_test_helpers")] +#[link(name = "rust_test_helpers", kind = "static")] extern { fn rust_int8_to_int32(_: i8) -> i32; } diff --git a/src/test/run-pass/extern-call-deep.rs b/src/test/run-pass/extern-call-deep.rs index 2138b12fb12..6a9da767ad6 100644 --- a/src/test/run-pass/extern-call-deep.rs +++ b/src/test/run-pass/extern-call-deep.rs @@ -15,7 +15,7 @@ extern crate libc; mod rustrt { extern crate libc; - #[link(name = "rust_test_helpers")] + #[link(name = "rust_test_helpers", kind = "static")] extern { pub fn rust_dbg_call(cb: extern "C" fn(libc::uintptr_t) -> libc::uintptr_t, data: libc::uintptr_t) diff --git a/src/test/run-pass/extern-call-deep2.rs b/src/test/run-pass/extern-call-deep2.rs index 1a0191b7053..3bdc8c18864 100644 --- a/src/test/run-pass/extern-call-deep2.rs +++ b/src/test/run-pass/extern-call-deep2.rs @@ -18,7 +18,7 @@ use std::thread; mod rustrt { extern crate libc; - #[link(name = "rust_test_helpers")] + #[link(name = "rust_test_helpers", kind = "static")] extern { pub fn rust_dbg_call(cb: extern "C" fn(libc::uintptr_t) -> libc::uintptr_t, data: libc::uintptr_t) diff --git a/src/test/run-pass/extern-call-indirect.rs b/src/test/run-pass/extern-call-indirect.rs index 4f1abbeb5c7..256eedccb8b 100644 --- a/src/test/run-pass/extern-call-indirect.rs +++ b/src/test/run-pass/extern-call-indirect.rs @@ -15,7 +15,7 @@ extern crate libc; mod rustrt { extern crate libc; - #[link(name = "rust_test_helpers")] + #[link(name = "rust_test_helpers", kind = "static")] extern { pub fn rust_dbg_call(cb: extern "C" fn(libc::uintptr_t) -> libc::uintptr_t, data: libc::uintptr_t) diff --git a/src/test/run-pass/extern-call-scrub.rs b/src/test/run-pass/extern-call-scrub.rs index 1beb6d3519a..a27474dcf86 100644 --- a/src/test/run-pass/extern-call-scrub.rs +++ b/src/test/run-pass/extern-call-scrub.rs @@ -22,7 +22,7 @@ use std::thread; mod rustrt { extern crate libc; - #[link(name = "rust_test_helpers")] + #[link(name = "rust_test_helpers", kind = "static")] extern { pub fn rust_dbg_call(cb: extern "C" fn(libc::uintptr_t) -> libc::uintptr_t, data: libc::uintptr_t) diff --git a/src/test/run-pass/extern-pass-TwoU16s.rs b/src/test/run-pass/extern-pass-TwoU16s.rs index 9d304ea9e10..afdd53db775 100644 --- a/src/test/run-pass/extern-pass-TwoU16s.rs +++ b/src/test/run-pass/extern-pass-TwoU16s.rs @@ -16,7 +16,7 @@ pub struct TwoU16s { one: u16, two: u16 } -#[link(name = "rust_test_helpers")] +#[link(name = "rust_test_helpers", kind = "static")] extern { pub fn rust_dbg_extern_identity_TwoU16s(v: TwoU16s) -> TwoU16s; } diff --git a/src/test/run-pass/extern-pass-TwoU32s.rs b/src/test/run-pass/extern-pass-TwoU32s.rs index 8dae0473fd5..035084ae9bd 100644 --- a/src/test/run-pass/extern-pass-TwoU32s.rs +++ b/src/test/run-pass/extern-pass-TwoU32s.rs @@ -16,7 +16,7 @@ pub struct TwoU32s { one: u32, two: u32 } -#[link(name = "rust_test_helpers")] +#[link(name = "rust_test_helpers", kind = "static")] extern { pub fn rust_dbg_extern_identity_TwoU32s(v: TwoU32s) -> TwoU32s; } diff --git a/src/test/run-pass/extern-pass-TwoU64s.rs b/src/test/run-pass/extern-pass-TwoU64s.rs index 14aeea34657..cb1a4d27825 100644 --- a/src/test/run-pass/extern-pass-TwoU64s.rs +++ b/src/test/run-pass/extern-pass-TwoU64s.rs @@ -16,7 +16,7 @@ pub struct TwoU64s { one: u64, two: u64 } -#[link(name = "rust_test_helpers")] +#[link(name = "rust_test_helpers", kind = "static")] extern { pub fn rust_dbg_extern_identity_TwoU64s(v: TwoU64s) -> TwoU64s; } diff --git a/src/test/run-pass/extern-pass-TwoU8s.rs b/src/test/run-pass/extern-pass-TwoU8s.rs index 75a109e4429..657348c99aa 100644 --- a/src/test/run-pass/extern-pass-TwoU8s.rs +++ b/src/test/run-pass/extern-pass-TwoU8s.rs @@ -16,7 +16,7 @@ pub struct TwoU8s { one: u8, two: u8 } -#[link(name = "rust_test_helpers")] +#[link(name = "rust_test_helpers", kind = "static")] extern { pub fn rust_dbg_extern_identity_TwoU8s(v: TwoU8s) -> TwoU8s; } diff --git a/src/test/run-pass/extern-pass-char.rs b/src/test/run-pass/extern-pass-char.rs index e75aa2d72c9..9042aed6639 100644 --- a/src/test/run-pass/extern-pass-char.rs +++ b/src/test/run-pass/extern-pass-char.rs @@ -11,7 +11,7 @@ // Test a function that takes/returns a u8. -#[link(name = "rust_test_helpers")] +#[link(name = "rust_test_helpers", kind = "static")] extern { pub fn rust_dbg_extern_identity_u8(v: u8) -> u8; } diff --git a/src/test/run-pass/extern-pass-double.rs b/src/test/run-pass/extern-pass-double.rs index e92f9b6a1a1..38d29180fbc 100644 --- a/src/test/run-pass/extern-pass-double.rs +++ b/src/test/run-pass/extern-pass-double.rs @@ -9,7 +9,7 @@ // except according to those terms. -#[link(name = "rust_test_helpers")] +#[link(name = "rust_test_helpers", kind = "static")] extern { pub fn rust_dbg_extern_identity_double(v: f64) -> f64; } diff --git a/src/test/run-pass/extern-pass-empty.rs b/src/test/run-pass/extern-pass-empty.rs index 801a3c40ab4..cce7dc5bf32 100644 --- a/src/test/run-pass/extern-pass-empty.rs +++ b/src/test/run-pass/extern-pass-empty.rs @@ -30,7 +30,7 @@ struct ManyInts { struct Empty; -#[link(name = "rust_test_helpers")] +#[link(name = "rust_test_helpers", kind = "static")] extern { fn rust_dbg_extern_empty_struct(v1: ManyInts, e: Empty, v2: ManyInts); } diff --git a/src/test/run-pass/extern-pass-u32.rs b/src/test/run-pass/extern-pass-u32.rs index 0753ea1bcfe..ed254ac46f2 100644 --- a/src/test/run-pass/extern-pass-u32.rs +++ b/src/test/run-pass/extern-pass-u32.rs @@ -11,7 +11,7 @@ // Test a function that takes/returns a u32. -#[link(name = "rust_test_helpers")] +#[link(name = "rust_test_helpers", kind = "static")] extern { pub fn rust_dbg_extern_identity_u32(v: u32) -> u32; } diff --git a/src/test/run-pass/extern-pass-u64.rs b/src/test/run-pass/extern-pass-u64.rs index 89faa3bb471..6fc630e6d7e 100644 --- a/src/test/run-pass/extern-pass-u64.rs +++ b/src/test/run-pass/extern-pass-u64.rs @@ -11,7 +11,7 @@ // Test a call to a function that takes/returns a u64. -#[link(name = "rust_test_helpers")] +#[link(name = "rust_test_helpers", kind = "static")] extern { pub fn rust_dbg_extern_identity_u64(v: u64) -> u64; } diff --git a/src/test/run-pass/extern-return-TwoU16s.rs b/src/test/run-pass/extern-return-TwoU16s.rs index 3c58646e0c3..ec1c6130e7a 100644 --- a/src/test/run-pass/extern-return-TwoU16s.rs +++ b/src/test/run-pass/extern-return-TwoU16s.rs @@ -13,7 +13,7 @@ pub struct TwoU16s { one: u16, two: u16 } -#[link(name = "rust_test_helpers")] +#[link(name = "rust_test_helpers", kind = "static")] extern { pub fn rust_dbg_extern_return_TwoU16s() -> TwoU16s; } diff --git a/src/test/run-pass/extern-return-TwoU32s.rs b/src/test/run-pass/extern-return-TwoU32s.rs index 0eb6be2d687..e829e993052 100644 --- a/src/test/run-pass/extern-return-TwoU32s.rs +++ b/src/test/run-pass/extern-return-TwoU32s.rs @@ -13,7 +13,7 @@ pub struct TwoU32s { one: u32, two: u32 } -#[link(name = "rust_test_helpers")] +#[link(name = "rust_test_helpers", kind = "static")] extern { pub fn rust_dbg_extern_return_TwoU32s() -> TwoU32s; } diff --git a/src/test/run-pass/extern-return-TwoU64s.rs b/src/test/run-pass/extern-return-TwoU64s.rs index d5eab86351e..ef7325b33fe 100644 --- a/src/test/run-pass/extern-return-TwoU64s.rs +++ b/src/test/run-pass/extern-return-TwoU64s.rs @@ -13,7 +13,7 @@ pub struct TwoU64s { one: u64, two: u64 } -#[link(name = "rust_test_helpers")] +#[link(name = "rust_test_helpers", kind = "static")] extern { pub fn rust_dbg_extern_return_TwoU64s() -> TwoU64s; } diff --git a/src/test/run-pass/extern-return-TwoU8s.rs b/src/test/run-pass/extern-return-TwoU8s.rs index d8f476bcd0c..46f2e81a556 100644 --- a/src/test/run-pass/extern-return-TwoU8s.rs +++ b/src/test/run-pass/extern-return-TwoU8s.rs @@ -13,7 +13,7 @@ pub struct TwoU8s { one: u8, two: u8 } -#[link(name = "rust_test_helpers")] +#[link(name = "rust_test_helpers", kind = "static")] extern { pub fn rust_dbg_extern_return_TwoU8s() -> TwoU8s; } diff --git a/src/test/run-pass/foreign-call-no-runtime.rs b/src/test/run-pass/foreign-call-no-runtime.rs index ca118899798..697e9074c44 100644 --- a/src/test/run-pass/foreign-call-no-runtime.rs +++ b/src/test/run-pass/foreign-call-no-runtime.rs @@ -18,7 +18,7 @@ extern crate libc; use std::mem; use std::thread; -#[link(name = "rust_test_helpers")] +#[link(name = "rust_test_helpers", kind = "static")] extern { fn rust_dbg_call(cb: extern "C" fn(libc::uintptr_t), data: libc::uintptr_t) -> libc::uintptr_t; diff --git a/src/test/run-pass/foreign-fn-with-byval.rs b/src/test/run-pass/foreign-fn-with-byval.rs index d3d872620c3..2d4542540e7 100644 --- a/src/test/run-pass/foreign-fn-with-byval.rs +++ b/src/test/run-pass/foreign-fn-with-byval.rs @@ -16,7 +16,7 @@ pub struct S { z: u64, } -#[link(name = "rust_test_helpers")] +#[link(name = "rust_test_helpers", kind = "static")] extern { pub fn get_x(x: S) -> u64; pub fn get_y(x: S) -> u64; diff --git a/src/test/run-pass/foreign-no-abi.rs b/src/test/run-pass/foreign-no-abi.rs index a9b3f60566d..979e57eba9d 100644 --- a/src/test/run-pass/foreign-no-abi.rs +++ b/src/test/run-pass/foreign-no-abi.rs @@ -17,7 +17,7 @@ mod rustrt { extern crate libc; - #[link(name = "rust_test_helpers")] + #[link(name = "rust_test_helpers", kind = "static")] extern { pub fn rust_get_test_int() -> libc::intptr_t; } diff --git a/src/test/run-pass/issue-28676.rs b/src/test/run-pass/issue-28676.rs index b8d43c392dd..8f83e51f0a0 100644 --- a/src/test/run-pass/issue-28676.rs +++ b/src/test/run-pass/issue-28676.rs @@ -15,7 +15,7 @@ pub struct Quad { a: u64, b: u64, c: u64, d: u64 } mod rustrt { use super::Quad; - #[link(name = "rust_test_helpers")] + #[link(name = "rust_test_helpers", kind = "static")] extern { pub fn get_c_many_params(_: *const (), _: *const (), _: *const (), _: *const (), f: Quad) -> u64; diff --git a/src/test/run-pass/mir_trans_calls_variadic.rs b/src/test/run-pass/mir_trans_calls_variadic.rs index 4e06738da4f..e4d528e80e1 100644 --- a/src/test/run-pass/mir_trans_calls_variadic.rs +++ b/src/test/run-pass/mir_trans_calls_variadic.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[link(name = "rust_test_helpers")] +#[link(name = "rust_test_helpers", kind = "static")] extern { fn rust_interesting_average(_: i64, ...) -> f64; } diff --git a/src/test/run-pass/segfault-no-out-of-stack.rs b/src/test/run-pass/segfault-no-out-of-stack.rs index df64d7140b4..0f98cfe27f6 100644 --- a/src/test/run-pass/segfault-no-out-of-stack.rs +++ b/src/test/run-pass/segfault-no-out-of-stack.rs @@ -17,7 +17,7 @@ extern crate libc; use std::process::{Command, ExitStatus}; use std::env; -#[link(name = "rust_test_helpers")] +#[link(name = "rust_test_helpers", kind = "static")] extern { fn rust_get_null_ptr() -> *mut ::libc::c_char; } diff --git a/src/test/run-pass/static-mut-foreign.rs b/src/test/run-pass/static-mut-foreign.rs index 4dcb82c4b43..24d58487f06 100644 --- a/src/test/run-pass/static-mut-foreign.rs +++ b/src/test/run-pass/static-mut-foreign.rs @@ -17,7 +17,7 @@ extern crate libc; -#[link(name = "rust_test_helpers")] +#[link(name = "rust_test_helpers", kind = "static")] extern { static mut rust_dbg_static_mut: libc::c_int; pub fn rust_dbg_static_mut_check_four(); diff --git a/src/test/run-pass/struct-return.rs b/src/test/run-pass/struct-return.rs index 6f23263790c..3d4601ad0cf 100644 --- a/src/test/run-pass/struct-return.rs +++ b/src/test/run-pass/struct-return.rs @@ -18,7 +18,7 @@ pub struct Floats { a: f64, b: u8, c: f64 } mod rustrt { use super::{Floats, Quad}; - #[link(name = "rust_test_helpers")] + #[link(name = "rust_test_helpers", kind = "static")] extern { pub fn rust_dbg_abi_1(q: Quad) -> Quad; pub fn rust_dbg_abi_2(f: Floats) -> Floats; diff --git a/src/test/run-pass/union/union-c-interop.rs b/src/test/run-pass/union/union-c-interop.rs index bea4d5f923e..13dfd414615 100644 --- a/src/test/run-pass/union/union-c-interop.rs +++ b/src/test/run-pass/union/union-c-interop.rs @@ -25,7 +25,7 @@ union LARGE_INTEGER { QuadPart: u64, } -#[link(name = "rust_test_helpers")] +#[link(name = "rust_test_helpers", kind = "static")] extern "C" { fn increment_all_parts(_: LARGE_INTEGER) -> LARGE_INTEGER; } diff --git a/src/test/run-pass/variadic-ffi.rs b/src/test/run-pass/variadic-ffi.rs index 0131563d36d..ec6261febc5 100644 --- a/src/test/run-pass/variadic-ffi.rs +++ b/src/test/run-pass/variadic-ffi.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[link(name = "rust_test_helpers")] +#[link(name = "rust_test_helpers", kind = "static")] extern { fn rust_interesting_average(_: u64, ...) -> f64; } From 13477c77bf07b1c9a8ddcbd4613e173312c33d59 Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Wed, 23 Nov 2016 16:09:51 -0800 Subject: [PATCH 196/293] Implement native library kind and name overrides from the command line. --- src/librustc/session/config.rs | 72 +++++++++++++------ src/librustc_metadata/creader.rs | 22 +++--- src/librustc_metadata/cstore.rs | 17 +++++ .../run-pass/rfc1717/auxiliary/clibrary.rs | 15 ++++ src/test/run-pass/rfc1717/library-override.rs | 23 ++++++ 5 files changed, 119 insertions(+), 30 deletions(-) create mode 100644 src/test/run-pass/rfc1717/auxiliary/clibrary.rs create mode 100644 src/test/run-pass/rfc1717/library-override.rs diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 26dafed7019..48bc390ddca 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -262,7 +262,7 @@ top_level_options!( // much sense: The search path can stay the same while the // things discovered there might have changed on disk. search_paths: SearchPaths [TRACKED], - libs: Vec<(String, cstore::NativeLibraryKind)> [TRACKED], + libs: Vec<(String, Option, cstore::NativeLibraryKind)> [TRACKED], maybe_sysroot: Option [TRACKED], target_triple: String [TRACKED], @@ -1439,6 +1439,8 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) } let libs = matches.opt_strs("l").into_iter().map(|s| { + // Parse string of the form "[KIND=]lib[:new_name]", + // where KIND is one of "dylib", "framework", "static". let mut parts = s.splitn(2, '='); let kind = parts.next().unwrap(); let (name, kind) = match (parts.next(), kind) { @@ -1452,7 +1454,10 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) s)); } }; - (name.to_string(), kind) + let mut name_parts = name.splitn(2, ':'); + let name = name_parts.next().unwrap(); + let new_name = name_parts.next(); + (name.to_string(), new_name.map(|n| n.to_string()), kind) }).collect(); let cfg = parse_cfgspecs(matches.opt_strs("cfg")); @@ -1716,8 +1721,8 @@ mod dep_tracking { impl_dep_tracking_hash_for_sortable_vec_of!(String); impl_dep_tracking_hash_for_sortable_vec_of!(CrateType); impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level)); - impl_dep_tracking_hash_for_sortable_vec_of!((String, cstore::NativeLibraryKind)); - + impl_dep_tracking_hash_for_sortable_vec_of!((String, Option, + cstore::NativeLibraryKind)); impl DepTrackingHash for SearchPaths { fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) { let mut elems: Vec<_> = self @@ -1740,6 +1745,21 @@ mod dep_tracking { } } + impl DepTrackingHash for (T1, T2, T3) + where T1: DepTrackingHash, + T2: DepTrackingHash, + T3: DepTrackingHash + { + fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) { + Hash::hash(&0, hasher); + DepTrackingHash::hash(&self.0, hasher, error_format); + Hash::hash(&1, hasher); + DepTrackingHash::hash(&self.1, hasher, error_format); + Hash::hash(&2, hasher); + DepTrackingHash::hash(&self.2, hasher, error_format); + } + } + // This is a stable hash because BTreeMap is a sorted container pub fn stable_hash(sub_hashes: BTreeMap<&'static str, &DepTrackingHash>, hasher: &mut DefaultHasher, @@ -2143,29 +2163,37 @@ mod tests { let mut v1 = super::basic_options(); let mut v2 = super::basic_options(); let mut v3 = super::basic_options(); + let mut v4 = super::basic_options(); // Reference - v1.libs = vec![(String::from("a"), cstore::NativeStatic), - (String::from("b"), cstore::NativeFramework), - (String::from("c"), cstore::NativeUnknown)]; + v1.libs = vec![(String::from("a"), None, cstore::NativeStatic), + (String::from("b"), None, cstore::NativeFramework), + (String::from("c"), None, cstore::NativeUnknown)]; // Change label - v2.libs = vec![(String::from("a"), cstore::NativeStatic), - (String::from("X"), cstore::NativeFramework), - (String::from("c"), cstore::NativeUnknown)]; + v2.libs = vec![(String::from("a"), None, cstore::NativeStatic), + (String::from("X"), None, cstore::NativeFramework), + (String::from("c"), None, cstore::NativeUnknown)]; // Change kind - v3.libs = vec![(String::from("a"), cstore::NativeStatic), - (String::from("b"), cstore::NativeStatic), - (String::from("c"), cstore::NativeUnknown)]; + v3.libs = vec![(String::from("a"), None, cstore::NativeStatic), + (String::from("b"), None, cstore::NativeStatic), + (String::from("c"), None, cstore::NativeUnknown)]; + + // Change new-name + v4.libs = vec![(String::from("a"), None, cstore::NativeStatic), + (String::from("b"), Some(String::from("X")), cstore::NativeFramework), + (String::from("c"), None, cstore::NativeUnknown)]; assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash()); assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash()); + assert!(v1.dep_tracking_hash() != v4.dep_tracking_hash()); // Check clone assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash()); assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash()); assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash()); + assert_eq!(v4.dep_tracking_hash(), v4.clone().dep_tracking_hash()); } #[test] @@ -2175,17 +2203,17 @@ mod tests { let mut v3 = super::basic_options(); // Reference - v1.libs = vec![(String::from("a"), cstore::NativeStatic), - (String::from("b"), cstore::NativeFramework), - (String::from("c"), cstore::NativeUnknown)]; + v1.libs = vec![(String::from("a"), None, cstore::NativeStatic), + (String::from("b"), None, cstore::NativeFramework), + (String::from("c"), None, cstore::NativeUnknown)]; - v2.libs = vec![(String::from("b"), cstore::NativeFramework), - (String::from("a"), cstore::NativeStatic), - (String::from("c"), cstore::NativeUnknown)]; + v2.libs = vec![(String::from("b"), None, cstore::NativeFramework), + (String::from("a"), None, cstore::NativeStatic), + (String::from("c"), None, cstore::NativeUnknown)]; - v3.libs = vec![(String::from("c"), cstore::NativeUnknown), - (String::from("a"), cstore::NativeStatic), - (String::from("b"), cstore::NativeFramework)]; + v3.libs = vec![(String::from("c"), None, cstore::NativeUnknown), + (String::from("a"), None, cstore::NativeStatic), + (String::from("b"), None, cstore::NativeFramework)]; assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash()); assert!(v1.dep_tracking_hash() == v3.dep_tracking_hash()); diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 436b1b3159f..ccbe90ebe7c 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -966,14 +966,20 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { dump_crates(&self.cstore); } - for &(ref name, kind) in &self.sess.opts.libs { - let lib = NativeLibrary { - name: Symbol::intern(name), - kind: kind, - cfg: None, - foreign_items: Vec::new(), - }; - register_native_lib(self.sess, self.cstore, None, lib); + // Process libs passed on the command line + for &(ref name, ref new_name, kind) in &self.sess.opts.libs { + // First, try to update existing lib(s) added via #[link(...)] + let new_name = new_name.as_ref().map(|s| &**s); // &Option -> Option<&str> + if !self.cstore.update_used_library(name, new_name, kind) { + // Add if not found + let lib = NativeLibrary { + name: Symbol::intern(name), + kind: kind, + cfg: None, + foreign_items: Vec::new(), + }; + register_native_lib(self.sess, self.cstore, None, lib); + } } self.register_statically_included_foreign_items(); self.register_dllimport_foreign_items(); diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 279ef5bfb72..e00278d28db 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -232,6 +232,23 @@ impl CStore { self.used_libraries.borrow_mut().push(lib); } + // Update kind and, optionally, the name of all native libaries (there may be more than one) + // with the specified name. + pub fn update_used_library(&self, name: &str, new_name: Option<&str>, + new_kind: NativeLibraryKind) -> bool { + let mut found = false; + for item in self.used_libraries.borrow_mut().iter_mut() { + if item.name == name { + item.kind = new_kind; + if let Some(new_name) = new_name { + item.name = Symbol::intern(new_name); + } + found = true; + } + } + found + } + pub fn get_used_libraries(&self) -> &RefCell> { &self.used_libraries } diff --git a/src/test/run-pass/rfc1717/auxiliary/clibrary.rs b/src/test/run-pass/rfc1717/auxiliary/clibrary.rs new file mode 100644 index 00000000000..7438ba21bfc --- /dev/null +++ b/src/test/run-pass/rfc1717/auxiliary/clibrary.rs @@ -0,0 +1,15 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// no-prefer-dynamic +#![crate_type = "staticlib"] + +#[no_mangle] +pub extern "C" fn foo(x:i32) -> i32 { x } diff --git a/src/test/run-pass/rfc1717/library-override.rs b/src/test/run-pass/rfc1717/library-override.rs new file mode 100644 index 00000000000..d6ef96c5add --- /dev/null +++ b/src/test/run-pass/rfc1717/library-override.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:clibrary.rs +// compile-flags: -lstatic=wronglibrary:clibrary + +#[link(name = "wronglibrary", kind = "dylib")] +extern "C" { + pub fn foo(x:i32) -> i32; +} + +fn main() { + unsafe { + foo(42); + } +} From c735d7f2a53d6b3ecf9151e43066f8a30f42921c Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Thu, 1 Dec 2016 16:33:48 -0800 Subject: [PATCH 197/293] Point arg num mismatch errors back to their definition --- src/librustc_typeck/check/callee.rs | 16 ++++--- src/librustc_typeck/check/mod.rs | 47 +++++++++---------- src/test/compile-fail/E0060.rs | 3 +- src/test/compile-fail/E0061.rs | 7 +-- src/test/compile-fail/issue-18819.rs | 6 +-- src/test/compile-fail/issue-3044.rs | 4 +- src/test/compile-fail/issue-4935.rs | 3 +- src/test/compile-fail/method-call-err-msg.rs | 8 ++-- src/test/compile-fail/not-enough-arguments.rs | 4 +- src/test/compile-fail/overloaded-calls-bad.rs | 4 +- src/test/compile-fail/variadic-ffi-3.rs | 8 ++-- src/test/ui/span/E0057.stderr | 8 +--- 12 files changed, 59 insertions(+), 59 deletions(-) diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 6d00f481fa2..5b17b37e279 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -193,9 +193,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { -> Ty<'tcx> { let error_fn_sig; - let fn_sig = match callee_ty.sty { - ty::TyFnDef(.., &ty::BareFnTy {ref sig, ..}) | - ty::TyFnPtr(&ty::BareFnTy {ref sig, ..}) => sig, + let (fn_sig, def_span) = match callee_ty.sty { + ty::TyFnDef(def_id, .., &ty::BareFnTy {ref sig, ..}) => { + (sig, self.tcx.map.span_if_local(def_id)) + } + ty::TyFnPtr(&ty::BareFnTy {ref sig, ..}) => (sig, None), ref t => { let mut unit_variant = None; if let &ty::TyAdt(adt_def, ..) = t { @@ -241,7 +243,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { variadic: false, }); - &error_fn_sig + (&error_fn_sig, None) } }; @@ -266,7 +268,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { &expected_arg_tys[..], arg_exprs, fn_sig.variadic, - TupleArgumentsFlag::DontTupleArguments); + TupleArgumentsFlag::DontTupleArguments, + def_span); fn_sig.output } @@ -292,7 +295,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { &expected_arg_tys, arg_exprs, fn_sig.variadic, - TupleArgumentsFlag::TupleArguments); + TupleArgumentsFlag::TupleArguments, + None); fn_sig.output } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 0c4e5e4fa0d..8ac5b526f24 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2465,17 +2465,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; self.check_argument_types(sp, &err_inputs[..], &[], args_no_rcvr, - false, tuple_arguments); + false, tuple_arguments, None); self.tcx.types.err } else { match method_fn_ty.sty { - ty::TyFnDef(.., ref fty) => { + ty::TyFnDef(def_id, .., ref fty) => { // HACK(eddyb) ignore self in the definition (see above). let expected_arg_tys = self.expected_types_for_fn_args(sp, expected, fty.sig.0.output, &fty.sig.0.inputs[1..]); + self.check_argument_types(sp, &fty.sig.0.inputs[1..], &expected_arg_tys[..], - args_no_rcvr, fty.sig.0.variadic, tuple_arguments); + args_no_rcvr, fty.sig.0.variadic, tuple_arguments, + self.tcx.map.span_if_local(def_id)); fty.sig.0.output } _ => { @@ -2493,7 +2495,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expected_arg_tys: &[Ty<'tcx>], args: &'gcx [hir::Expr], variadic: bool, - tuple_arguments: TupleArgumentsFlag) { + tuple_arguments: TupleArgumentsFlag, + def_span: Option) { let tcx = self.tcx; // Grab the argument types, supplying fresh type variables @@ -2528,9 +2531,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { sp }; - fn parameter_count_error<'tcx>(sess: &Session, sp: Span, fn_inputs: &[Ty<'tcx>], - expected_count: usize, arg_count: usize, error_code: &str, - variadic: bool) { + fn parameter_count_error<'tcx>(sess: &Session, sp: Span, expected_count: usize, + arg_count: usize, error_code: &str, variadic: bool, + def_span: Option) { let mut err = sess.struct_span_err_with_code(sp, &format!("this function takes {}{} parameter{} but {} parameter{} supplied", if variadic {"at least "} else {""}, @@ -2540,18 +2543,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if arg_count == 1 {" was"} else {"s were"}), error_code); - let input_types = fn_inputs.iter().map(|i| format!("{:?}", i)).collect::>(); - if input_types.len() > 1 { - err.note("the following parameter types were expected:"); - err.note(&input_types.join(", ")); - } else if input_types.len() > 0 { - err.note(&format!("the following parameter type was expected: {}", - input_types[0])); - } else { - err.span_label(sp, &format!("expected {}{} parameter{}", - if variadic {"at least "} else {""}, - expected_count, - if expected_count == 1 {""} else {"s"})); + err.span_label(sp, &format!("expected {}{} parameter{}", + if variadic {"at least "} else {""}, + expected_count, + if expected_count == 1 {""} else {"s"})); + if let Some(def_s) = def_span { + err.span_label(def_s, &format!("defined here")); } err.emit(); } @@ -2560,8 +2557,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]); match tuple_type.sty { ty::TyTuple(arg_types) if arg_types.len() != args.len() => { - parameter_count_error(tcx.sess, sp_args, fn_inputs, arg_types.len(), args.len(), - "E0057", false); + parameter_count_error(tcx.sess, sp_args, arg_types.len(), args.len(), + "E0057", false, def_span); expected_arg_tys = &[]; self.err_args(args.len()) } @@ -2589,14 +2586,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if supplied_arg_count >= expected_arg_count { fn_inputs.to_vec() } else { - parameter_count_error(tcx.sess, sp_args, fn_inputs, expected_arg_count, - supplied_arg_count, "E0060", true); + parameter_count_error(tcx.sess, sp_args, expected_arg_count, + supplied_arg_count, "E0060", true, def_span); expected_arg_tys = &[]; self.err_args(supplied_arg_count) } } else { - parameter_count_error(tcx.sess, sp_args, fn_inputs, expected_arg_count, - supplied_arg_count, "E0061", false); + parameter_count_error(tcx.sess, sp_args, expected_arg_count, + supplied_arg_count, "E0061", false, def_span); expected_arg_tys = &[]; self.err_args(supplied_arg_count) }; diff --git a/src/test/compile-fail/E0060.rs b/src/test/compile-fail/E0060.rs index 5182a2bf5a0..8246c42a4d4 100644 --- a/src/test/compile-fail/E0060.rs +++ b/src/test/compile-fail/E0060.rs @@ -10,10 +10,11 @@ extern "C" { fn printf(_: *const u8, ...) -> u32; + //~^ NOTE defined here } fn main() { unsafe { printf(); } //~^ ERROR E0060 - //~| NOTE the following parameter type was expected: *const u8 + //~| expected at least 1 parameter } diff --git a/src/test/compile-fail/E0061.rs b/src/test/compile-fail/E0061.rs index 4c7c0dfd44c..ebd4ad2e292 100644 --- a/src/test/compile-fail/E0061.rs +++ b/src/test/compile-fail/E0061.rs @@ -9,16 +9,17 @@ // except according to those terms. fn f(a: u16, b: &str) {} +//~^ NOTE defined here fn f2(a: u16) {} +//~^ NOTE defined here fn main() { f(0); //~^ ERROR E0061 - //~| NOTE the following parameter types were expected: - //~| NOTE u16, &str + //~| expected 2 parameters f2(); //~^ ERROR E0061 - //~| NOTE the following parameter type was expected: u16 + //~| expected 1 parameter } diff --git a/src/test/compile-fail/issue-18819.rs b/src/test/compile-fail/issue-18819.rs index 8035d798e32..148eea31ec6 100644 --- a/src/test/compile-fail/issue-18819.rs +++ b/src/test/compile-fail/issue-18819.rs @@ -19,12 +19,12 @@ impl Foo for X { } fn print_x(_: &Foo, extra: &str) { + //~^ NOTE defined here println!("{}", extra); } fn main() { print_x(X); - //~^ ERROR this function takes 2 parameters but 1 parameter was supplied - //~| NOTE the following parameter types were expected: - //~| NOTE &Foo, &str + //~^ ERROR E0061 + //~| NOTE expected 2 parameters } diff --git a/src/test/compile-fail/issue-3044.rs b/src/test/compile-fail/issue-3044.rs index c7b276da573..4c63f7761a6 100644 --- a/src/test/compile-fail/issue-3044.rs +++ b/src/test/compile-fail/issue-3044.rs @@ -14,7 +14,5 @@ fn main() { needlesArr.iter().fold(|x, y| { }); //~^^ ERROR this function takes 2 parameters but 1 parameter was supplied - //~| NOTE the following parameter types were expected - //~| NOTE _, _ - // the first error is, um, non-ideal. + //~| NOTE expected 2 parameters } diff --git a/src/test/compile-fail/issue-4935.rs b/src/test/compile-fail/issue-4935.rs index 08707a187df..e9f8367378a 100644 --- a/src/test/compile-fail/issue-4935.rs +++ b/src/test/compile-fail/issue-4935.rs @@ -11,6 +11,7 @@ // Regression test for issue #4935 fn foo(a: usize) {} +//~^ defined here fn main() { foo(5, 6) } //~^ ERROR this function takes 1 parameter but 2 parameters were supplied -//~| NOTE the following parameter type was expected +//~| NOTE expected 1 parameter diff --git a/src/test/compile-fail/method-call-err-msg.rs b/src/test/compile-fail/method-call-err-msg.rs index b7e0c5b81d9..b8eb8434b35 100644 --- a/src/test/compile-fail/method-call-err-msg.rs +++ b/src/test/compile-fail/method-call-err-msg.rs @@ -13,8 +13,11 @@ pub struct Foo; impl Foo { fn zero(self) -> Foo { self } + //~^ NOTE defined here fn one(self, _: isize) -> Foo { self } + //~^ NOTE defined here fn two(self, _: isize, _: isize) -> Foo { self } + //~^ NOTE defined here } fn main() { @@ -22,10 +25,9 @@ fn main() { x.zero(0) //~ ERROR this function takes 0 parameters but 1 parameter was supplied //~^ NOTE expected 0 parameters .one() //~ ERROR this function takes 1 parameter but 0 parameters were supplied - //~^ NOTE the following parameter type was expected + //~^ NOTE expected 1 parameter .two(0); //~ ERROR this function takes 2 parameters but 1 parameter was supplied - //~^ NOTE the following parameter types were expected - //~| NOTE isize, isize + //~^ NOTE expected 2 parameters let y = Foo; y.zero() diff --git a/src/test/compile-fail/not-enough-arguments.rs b/src/test/compile-fail/not-enough-arguments.rs index 660d48da4db..e13008df0d9 100644 --- a/src/test/compile-fail/not-enough-arguments.rs +++ b/src/test/compile-fail/not-enough-arguments.rs @@ -13,12 +13,12 @@ // unrelated errors. fn foo(a: isize, b: isize, c: isize, d:isize) { + //~^ NOTE defined here panic!(); } fn main() { foo(1, 2, 3); //~^ ERROR this function takes 4 parameters but 3 - //~| NOTE the following parameter types were expected: - //~| NOTE isize, isize, isize, isize + //~| NOTE expected 4 parameters } diff --git a/src/test/compile-fail/overloaded-calls-bad.rs b/src/test/compile-fail/overloaded-calls-bad.rs index 1b8284debb4..3295e2bebd2 100644 --- a/src/test/compile-fail/overloaded-calls-bad.rs +++ b/src/test/compile-fail/overloaded-calls-bad.rs @@ -41,8 +41,8 @@ fn main() { //~| NOTE found type let ans = s(); //~^ ERROR this function takes 1 parameter but 0 parameters were supplied - //~| NOTE the following parameter type was expected + //~| NOTE expected 1 parameter let ans = s("burma", "shave"); //~^ ERROR this function takes 1 parameter but 2 parameters were supplied - //~| NOTE the following parameter type was expected + //~| NOTE expected 1 parameter } diff --git a/src/test/compile-fail/variadic-ffi-3.rs b/src/test/compile-fail/variadic-ffi-3.rs index 334b8bb08ae..565d8549b37 100644 --- a/src/test/compile-fail/variadic-ffi-3.rs +++ b/src/test/compile-fail/variadic-ffi-3.rs @@ -10,6 +10,8 @@ extern { fn foo(f: isize, x: u8, ...); + //~^ defined here + //~| defined here } extern "C" fn bar(f: isize, x: u8) {} @@ -17,11 +19,9 @@ extern "C" fn bar(f: isize, x: u8) {} fn main() { unsafe { foo(); //~ ERROR: this function takes at least 2 parameters but 0 parameters were supplied - //~^ NOTE the following parameter types were expected: - //~| NOTE isize, u8 + //~| NOTE expected at least 2 parameters foo(1); //~ ERROR: this function takes at least 2 parameters but 1 parameter was supplied - //~^ NOTE the following parameter types were expected: - //~| NOTE isize, u8 + //~| NOTE expected at least 2 parameters let x: unsafe extern "C" fn(f: isize, x: u8) = foo; //~^ ERROR: mismatched types diff --git a/src/test/ui/span/E0057.stderr b/src/test/ui/span/E0057.stderr index 656fdbe2b29..0d6b0a552e4 100644 --- a/src/test/ui/span/E0057.stderr +++ b/src/test/ui/span/E0057.stderr @@ -2,17 +2,13 @@ error[E0057]: this function takes 1 parameter but 0 parameters were supplied --> $DIR/E0057.rs:13:13 | 13 | let a = f(); //~ ERROR E0057 - | ^^^ - | - = note: the following parameter type was expected: (_,) + | ^^^ expected 1 parameter error[E0057]: this function takes 1 parameter but 2 parameters were supplied --> $DIR/E0057.rs:15:15 | 15 | let c = f(2, 3); //~ ERROR E0057 - | ^^^^ - | - = note: the following parameter type was expected: (_,) + | ^^^^ expected 1 parameter error: aborting due to 2 previous errors From a9a6f8c8eddba12c72a8caa73bdb236f089bda3c Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Thu, 1 Dec 2016 15:21:59 -0800 Subject: [PATCH 198/293] Remove the "linked_from" feature. --- src/librustc_llvm/ffi.rs | 8 +++---- src/librustc_llvm/lib.rs | 2 +- src/librustc_metadata/creader.rs | 23 +------------------ src/libsyntax/feature_gate.rs | 7 ------ .../compile-fail/feature-gate-linked-from.rs | 16 ------------- src/test/run-make/issue-15460/foo.rs | 2 -- src/test/run-pass/auxiliary/issue-25185-1.rs | 3 --- 7 files changed, 5 insertions(+), 56 deletions(-) delete mode 100644 src/test/compile-fail/feature-gate-linked-from.rs diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 98816826b9e..4ee157233ed 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -465,11 +465,9 @@ pub mod debuginfo { // generates an llvmdeps.rs file next to this one which will be // automatically updated whenever LLVM is updated to include an up-to-date // set of the libraries we need to link to LLVM for. -#[link(name = "rustllvm", kind = "static")] -#[cfg(not(cargobuild))] -extern "C" {} - -#[linked_from = "rustllvm"] // not quite true but good enough +#[cfg_attr(not(all(stage0,cargobuild)), + link(name = "rustllvm", kind = "static"))] // not quite true but good enough +#[cfg_attr(stage0, linked_from = "rustllvm")] extern "C" { // Create and destroy contexts. pub fn LLVMContextCreate() -> ContextRef; diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 0229776c948..8ac2c4677ee 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -27,7 +27,7 @@ #![feature(concat_idents)] #![feature(libc)] #![feature(link_args)] -#![feature(linked_from)] +#![cfg_attr(stage0, feature(linked_from))] #![feature(staged_api)] extern crate libc; diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index ccbe90ebe7c..90bd65386e4 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -22,7 +22,7 @@ use rustc_back::PanicStrategy; use rustc::session::search_paths::PathKind; use rustc::middle; use rustc::middle::cstore::{CrateStore, validate_crate_name, ExternCrate}; -use rustc::util::nodemap::{FxHashMap, FxHashSet}; +use rustc::util::nodemap::FxHashSet; use rustc::middle::cstore::NativeLibrary; use rustc::hir::map::Definitions; @@ -52,7 +52,6 @@ pub struct CrateLoader<'a> { pub sess: &'a Session, cstore: &'a CStore, next_crate_num: CrateNum, - foreign_item_map: FxHashMap>, local_crate_name: Symbol, } @@ -148,7 +147,6 @@ impl<'a> CrateLoader<'a> { sess: sess, cstore: cstore, next_crate_num: cstore.next_crate_num(), - foreign_item_map: FxHashMap(), local_crate_name: Symbol::intern(local_crate_name), } } @@ -649,14 +647,6 @@ impl<'a> CrateLoader<'a> { items.extend(&lib.foreign_items); } } - for (foreign_lib, list) in self.foreign_item_map.iter() { - let kind_matches = libs.borrow().iter().any(|lib| { - lib.name == &**foreign_lib && lib.kind == kind - }); - if kind_matches { - items.extend(list) - } - } items } @@ -943,17 +933,6 @@ impl<'a> CrateLoader<'a> { }; register_native_lib(self.sess, self.cstore, Some(m.span), lib); } - - // Finally, process the #[linked_from = "..."] attribute - for m in i.attrs.iter().filter(|a| a.check_name("linked_from")) { - let lib_name = match m.value_str() { - Some(name) => name, - None => continue, - }; - let list = self.foreign_item_map.entry(lib_name.to_string()) - .or_insert(Vec::new()); - list.extend(fm.items.iter().map(|it| definitions.opt_def_index(it.id).unwrap())); - } } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index aa6a29b78b0..33d99d37c2d 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -132,7 +132,6 @@ declare_features! ( (active, allocator, "1.0.0", Some(27389)), (active, fundamental, "1.0.0", Some(29635)), - (active, linked_from, "1.3.0", Some(29629)), (active, main, "1.0.0", Some(29634)), (active, needs_allocator, "1.4.0", Some(27389)), (active, on_unimplemented, "1.0.0", Some(29628)), @@ -636,12 +635,6 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG is an experimental feature", cfg_fn!(fundamental))), - ("linked_from", Normal, Gated(Stability::Unstable, - "linked_from", - "the `#[linked_from]` attribute \ - is an experimental feature", - cfg_fn!(linked_from))), - ("proc_macro_derive", Normal, Gated(Stability::Unstable, "proc_macro", "the `#[proc_macro_derive]` attribute \ diff --git a/src/test/compile-fail/feature-gate-linked-from.rs b/src/test/compile-fail/feature-gate-linked-from.rs deleted file mode 100644 index 8705684111e..00000000000 --- a/src/test/compile-fail/feature-gate-linked-from.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[linked_from = "foo"] //~ ERROR experimental feature -extern { - fn foo(); -} - -fn main() {} diff --git a/src/test/run-make/issue-15460/foo.rs b/src/test/run-make/issue-15460/foo.rs index 8b96fe36824..6917fa55579 100644 --- a/src/test/run-make/issue-15460/foo.rs +++ b/src/test/run-make/issue-15460/foo.rs @@ -8,11 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(linked_from)] #![crate_type = "dylib"] #[link(name = "foo", kind = "static")] -#[linked_from = "foo"] extern { pub fn foo(); } diff --git a/src/test/run-pass/auxiliary/issue-25185-1.rs b/src/test/run-pass/auxiliary/issue-25185-1.rs index 1ec29501b76..b9da39cbbcb 100644 --- a/src/test/run-pass/auxiliary/issue-25185-1.rs +++ b/src/test/run-pass/auxiliary/issue-25185-1.rs @@ -10,12 +10,9 @@ // no-prefer-dynamic -#![feature(linked_from)] - #![crate_type = "rlib"] #[link(name = "rust_test_helpers", kind = "static")] -#[linked_from = "rust_test_helpers"] extern { pub fn rust_dbg_extern_identity_u32(u: u32) -> u32; } From a23c4704336b7869f3671ef6a6eb416701511ddb Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Thu, 1 Dec 2016 15:57:16 -0800 Subject: [PATCH 199/293] Tighten up error checking of library renames. --- src/librustc_metadata/creader.rs | 42 ++++++++++++++++--- src/librustc_metadata/cstore.rs | 17 -------- .../compile-fail/rfc1717/missing-link-attr.rs | 14 +++++++ .../compile-fail/rfc1717/multiple-renames.rs | 17 ++++++++ .../compile-fail/rfc1717/rename-to-empty.rs | 17 ++++++++ 5 files changed, 85 insertions(+), 22 deletions(-) create mode 100644 src/test/compile-fail/rfc1717/missing-link-attr.rs create mode 100644 src/test/compile-fail/rfc1717/multiple-renames.rs create mode 100644 src/test/compile-fail/rfc1717/rename-to-empty.rs diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 90bd65386e4..e46162f39d9 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -946,19 +946,51 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { } // Process libs passed on the command line + // First, check for errors + let mut renames = FxHashSet(); + for &(ref name, ref new_name, _) in &self.sess.opts.libs { + if let &Some(ref new_name) = new_name { + if new_name.is_empty() { + self.sess.err( + &format!("an empty renaming target was specified for library `{}`",name)); + } else if !self.cstore.get_used_libraries().borrow().iter() + .any(|lib| lib.name == name as &str) { + self.sess.err(&format!("renaming of the library `{}` was specified, \ + however this crate contains no #[link(...)] \ + attributes referencing this library.", name)); + } else if renames.contains(name) { + self.sess.err(&format!("multiple renamings were specified for library `{}` .", + name)); + } else { + renames.insert(name); + } + } + } + // Update kind and, optionally, the name of all native libaries + // (there may be more than one) with the specified name. for &(ref name, ref new_name, kind) in &self.sess.opts.libs { - // First, try to update existing lib(s) added via #[link(...)] - let new_name = new_name.as_ref().map(|s| &**s); // &Option -> Option<&str> - if !self.cstore.update_used_library(name, new_name, kind) { + let mut found = false; + for lib in self.cstore.get_used_libraries().borrow_mut().iter_mut() { + if lib.name == name as &str { + lib.kind = kind; + if let &Some(ref new_name) = new_name { + lib.name = Symbol::intern(new_name); + } + found = true; + break; + } + } + if !found { // Add if not found + let new_name = new_name.as_ref().map(|s| &**s); // &Option -> Option<&str> let lib = NativeLibrary { - name: Symbol::intern(name), + name: Symbol::intern(new_name.unwrap_or(name)), kind: kind, cfg: None, foreign_items: Vec::new(), }; register_native_lib(self.sess, self.cstore, None, lib); - } + } } self.register_statically_included_foreign_items(); self.register_dllimport_foreign_items(); diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index e00278d28db..279ef5bfb72 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -232,23 +232,6 @@ impl CStore { self.used_libraries.borrow_mut().push(lib); } - // Update kind and, optionally, the name of all native libaries (there may be more than one) - // with the specified name. - pub fn update_used_library(&self, name: &str, new_name: Option<&str>, - new_kind: NativeLibraryKind) -> bool { - let mut found = false; - for item in self.used_libraries.borrow_mut().iter_mut() { - if item.name == name { - item.kind = new_kind; - if let Some(new_name) = new_name { - item.name = Symbol::intern(new_name); - } - found = true; - } - } - found - } - pub fn get_used_libraries(&self) -> &RefCell> { &self.used_libraries } diff --git a/src/test/compile-fail/rfc1717/missing-link-attr.rs b/src/test/compile-fail/rfc1717/missing-link-attr.rs new file mode 100644 index 00000000000..810efdedfd6 --- /dev/null +++ b/src/test/compile-fail/rfc1717/missing-link-attr.rs @@ -0,0 +1,14 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -l foo:bar +// error-pattern: renaming of the library `foo` was specified + +#![crate_type = "lib"] diff --git a/src/test/compile-fail/rfc1717/multiple-renames.rs b/src/test/compile-fail/rfc1717/multiple-renames.rs new file mode 100644 index 00000000000..e75c1a14b24 --- /dev/null +++ b/src/test/compile-fail/rfc1717/multiple-renames.rs @@ -0,0 +1,17 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -l foo:bar -l foo:baz +// error-pattern: multiple renamings were specified for library + +#![crate_type = "lib"] + +#[link(name = "foo")] +extern "C" {} diff --git a/src/test/compile-fail/rfc1717/rename-to-empty.rs b/src/test/compile-fail/rfc1717/rename-to-empty.rs new file mode 100644 index 00000000000..ab8c238bc27 --- /dev/null +++ b/src/test/compile-fail/rfc1717/rename-to-empty.rs @@ -0,0 +1,17 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -l foo: +// error-pattern: an empty renaming target was specified for library + +#![crate_type = "lib"] + +#[link(name = "foo")] +extern "C" {} From ff112644defc6a982bfd6a793afbeb3155173742 Mon Sep 17 00:00:00 2001 From: Doug Goldstein Date: Thu, 7 Apr 2016 16:36:35 -0500 Subject: [PATCH 200/293] rustc: add --print target-spec option This option provides the user the ability to dump the configuration that is in use by rustc for the target they are building for. Signed-off-by: Doug Goldstein --- src/librustc/session/config.rs | 6 ++++++ src/librustc_driver/lib.rs | 3 +++ 2 files changed, 9 insertions(+) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 9dd341c7674..478b6b80414 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -308,6 +308,7 @@ pub enum PrintRequest { TargetFeatures, RelocationModels, CodeModels, + TargetSpec, } pub enum Input { @@ -1141,6 +1142,9 @@ pub fn rustc_short_optgroups() -> Vec { let mut print_opts = vec!["crate-name", "file-names", "sysroot", "cfg", "target-list", "target-cpus", "target-features", "relocation-models", "code-models"]; + if nightly_options::is_nightly_build() { + print_opts.push("target-spec-json"); + } vec![ opt::flag_s("h", "help", "Display this message"), @@ -1471,6 +1475,8 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) "target-features" => PrintRequest::TargetFeatures, "relocation-models" => PrintRequest::RelocationModels, "code-models" => PrintRequest::CodeModels, + "target-spec-json" if nightly_options::is_unstable_enabled(matches) + => PrintRequest::TargetSpec, req => { early_error(error_format, &format!("unknown print request `{}`", req)) } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index b79eca0c22d..f84622c2f02 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -80,6 +80,8 @@ use rustc_metadata::locator; use rustc_metadata::cstore::CStore; use rustc::util::common::time; +use serialize::json::ToJson; + use std::cmp::max; use std::cmp::Ordering::Equal; use std::default::Default; @@ -584,6 +586,7 @@ impl RustcDefaultCalls { println!("{}", targets.join("\n")); }, PrintRequest::Sysroot => println!("{}", sess.sysroot().display()), + PrintRequest::TargetSpec => println!("{}", sess.target.target.to_json().pretty()), PrintRequest::FileNames | PrintRequest::CrateName => { let input = match input { From 7151b5ad7821dc7c1990af0bd2850fcbcbe100e7 Mon Sep 17 00:00:00 2001 From: Doug Goldstein Date: Sun, 10 Apr 2016 22:17:27 -0500 Subject: [PATCH 201/293] rustc: add basic test for --print target-spec This is a very basic test of the --print target-spec feature. Signed-off-by: Doug Goldstein --- src/test/run-make/target-specs/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/run-make/target-specs/Makefile b/src/test/run-make/target-specs/Makefile index 0c9a0169c1a..6b58ad7b6df 100644 --- a/src/test/run-make/target-specs/Makefile +++ b/src/test/run-make/target-specs/Makefile @@ -6,3 +6,4 @@ all: $(RUSTC) foo.rs --target=my-incomplete-platform.json 2>&1 | grep 'Field llvm-target' RUST_TARGET_PATH=. $(RUSTC) foo.rs --target=my-awesome-platform --crate-type=lib --emit=asm RUST_TARGET_PATH=. $(RUSTC) foo.rs --target=x86_64-unknown-linux-gnu --crate-type=lib --emit=asm + $(RUSTC) -Z unstable-options --target=my-awesome-platform.json --print target-spec-json > $(TMPDIR)/test-platform.json && $(RUSTC) -Z unstable-options --target=$(TMPDIR)/test-platform.json --print target-spec-json | diff -q $(TMPDIR)/test-platform.json - From ecf6f1b96aae615698ce3283750f442a18130138 Mon Sep 17 00:00:00 2001 From: jethrogb Date: Fri, 2 Dec 2016 09:19:38 -0800 Subject: [PATCH 202/293] Update items section in reference Make clear that items must be definitions, and add missing extern block --- src/doc/reference.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/doc/reference.md b/src/doc/reference.md index 4fbe5183967..8655bab4b21 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -740,13 +740,14 @@ There are several kinds of item: * [`extern crate` declarations](#extern-crate-declarations) * [`use` declarations](#use-declarations) * [modules](#modules) -* [functions](#functions) +* [function definitions](#functions) +* [`extern` blocks](#external-blocks) * [type definitions](grammar.html#type-definitions) -* [structs](#structs) -* [enumerations](#enumerations) +* [struct definitions](#structs) +* [enumeration definitions](#enumerations) * [constant items](#constant-items) * [static items](#static-items) -* [traits](#traits) +* [trait definitions](#traits) * [implementations](#implementations) Some items form an implicit scope for the declaration of sub-items. In other From e39c8d6dc8d55a4b8681d52d58305645ceefdf0d Mon Sep 17 00:00:00 2001 From: Doug Goldstein Date: Fri, 2 Dec 2016 08:43:03 -0600 Subject: [PATCH 203/293] configure: only req CMake if we're building LLVM CMake is only necessary if LLVM is going to be built and not in any other case. Signed-off-by: Doug Goldstein --- configure | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/configure b/configure index 5311bf4b064..e49b081a3de 100755 --- a/configure +++ b/configure @@ -848,7 +848,10 @@ then fi # For building LLVM -probe_need CFG_CMAKE cmake +if [ -z "$CFG_LLVM_ROOT" ] +then + probe_need CFG_CMAKE cmake +fi # On MacOS X, invoking `javac` pops up a dialog if the JDK is not # installed. Since `javac` is only used if `antlr4` is available, From f83eb4009e3e5a52bcb2dddc9fa7764aa9c12841 Mon Sep 17 00:00:00 2001 From: Doug Goldstein Date: Fri, 2 Dec 2016 11:25:43 -0600 Subject: [PATCH 204/293] configure: quote variables These should probably be quoted. Signed-off-by: Doug Goldstein --- configure | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index e49b081a3de..483471604cb 100755 --- a/configure +++ b/configure @@ -1474,7 +1474,7 @@ fi step_msg "configuring submodules" # Have to be in the top of src directory for this -if [ -z $CFG_DISABLE_MANAGE_SUBMODULES ] && [ -z $CFG_ENABLE_RUSTBUILD ] +if [ -z "$CFG_DISABLE_MANAGE_SUBMODULES" ] && [ -z "$CFG_ENABLE_RUSTBUILD" ] then cd ${CFG_SRC_DIR} @@ -1550,7 +1550,7 @@ do then msg "not configuring LLVM, rustbuild in use" do_reconfigure=0 - elif [ -z $CFG_LLVM_ROOT ] + elif [ -z "$CFG_LLVM_ROOT" ] then LLVM_BUILD_DIR=${CFG_BUILD_DIR}$t/llvm LLVM_INST_DIR=$LLVM_BUILD_DIR From 0adb1b1b0259ea6cccdf92698eecc83b2ecc8936 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 2 Dec 2016 14:18:09 -0500 Subject: [PATCH 205/293] pacify the mercilous tidy --- src/librustc/middle/region.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 930c9e284f6..b1e35e54eb9 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -1066,7 +1066,9 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, } } -fn resolve_item_like<'a, 'tcx, F>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, id: ast::NodeId, walk: F) +fn resolve_item_like<'a, 'tcx, F>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, + id: ast::NodeId, + walk: F) where F: FnOnce(&mut RegionResolutionVisitor<'tcx, 'a>) { // Items create a new outer block scope as far as we're concerned. From bc3618e5c007e69e6b21b2aa4d2aad110da6655e Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Fri, 2 Dec 2016 21:13:57 +0100 Subject: [PATCH 206/293] core: Remove Self: Sized from Iterator::nth It is an unnecessary restriction; nth neither needs self to be sized nor needs to be exempted from the trait object. It increases the utility of the nth method, because type specific implementations are available through `&mut I` or through an iterator trait object. It is a backwards compatible change due to the special cases of the `where Self: Sized` bound; it was already optional to include this bound in `Iterator` implementations. --- src/liballoc/boxed.rs | 3 +++ src/libcore/iter/iterator.rs | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 28f4dda1408..d10d7a5e58d 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -524,6 +524,9 @@ impl Iterator for Box { fn size_hint(&self) -> (usize, Option) { (**self).size_hint() } + fn nth(&mut self, n: usize) -> Option { + (**self).nth(n) + } } #[stable(feature = "rust1", since = "1.0.0")] impl DoubleEndedIterator for Box { diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index f6b74a91c19..48808b601c1 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -247,7 +247,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - fn nth(&mut self, mut n: usize) -> Option where Self: Sized { + fn nth(&mut self, mut n: usize) -> Option { for x in self { if n == 0 { return Some(x) } n -= 1; @@ -2179,4 +2179,7 @@ impl<'a, I: Iterator + ?Sized> Iterator for &'a mut I { type Item = I::Item; fn next(&mut self) -> Option { (**self).next() } fn size_hint(&self) -> (usize, Option) { (**self).size_hint() } + fn nth(&mut self, n: usize) -> Option { + (**self).nth(n) + } } From 923034ffd28ce2f5bc05da11a34f848b71b99b01 Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Fri, 2 Dec 2016 17:51:54 -0800 Subject: [PATCH 207/293] Rename _all_ library instances. --- src/librustc_metadata/creader.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index e46162f39d9..691bec19994 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -977,7 +977,6 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { lib.name = Symbol::intern(new_name); } found = true; - break; } } if !found { From dbdd60e6d7b3a812c9461f854f3cd3368ec85942 Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Fri, 18 Nov 2016 17:15:14 -0500 Subject: [PATCH 208/293] [LLVM] Introduce a stable representation of DIFlags In LLVM 4.0, this enum becomes an actual type-safe enum, which breaks all of the interfaces. Introduce our own copy of the bitflags that we can then safely convert to the LLVM one. --- src/Cargo.lock | 1 + src/librustc_llvm/Cargo.lock | 22 +++++ src/librustc_llvm/Cargo.toml | 3 + src/librustc_llvm/ffi.rs | 54 ++++++------ src/librustc_llvm/lib.rs | 4 + src/librustc_trans/debuginfo/metadata.rs | 35 ++++---- src/librustc_trans/debuginfo/mod.rs | 7 +- src/rustllvm/RustWrapper.cpp | 106 ++++++++++++++++++++--- 8 files changed, 172 insertions(+), 60 deletions(-) create mode 100644 src/librustc_llvm/Cargo.lock diff --git a/src/Cargo.lock b/src/Cargo.lock index bff6ef20677..b3388563adc 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -403,6 +403,7 @@ version = "0.0.0" dependencies = [ "build_helper 0.1.0", "gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_bitflags 0.0.0", ] [[package]] diff --git a/src/librustc_llvm/Cargo.lock b/src/librustc_llvm/Cargo.lock new file mode 100644 index 00000000000..17678ef2bbd --- /dev/null +++ b/src/librustc_llvm/Cargo.lock @@ -0,0 +1,22 @@ +[root] +name = "rustc_llvm" +version = "0.0.0" +dependencies = [ + "build_helper 0.1.0", + "gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_bitflags 0.0.0", +] + +[[package]] +name = "build_helper" +version = "0.1.0" + +[[package]] +name = "gcc" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rustc_bitflags" +version = "0.0.0" + diff --git a/src/librustc_llvm/Cargo.toml b/src/librustc_llvm/Cargo.toml index 88f8c0553ad..f97daa22ff6 100644 --- a/src/librustc_llvm/Cargo.toml +++ b/src/librustc_llvm/Cargo.toml @@ -12,6 +12,9 @@ crate-type = ["dylib"] [features] static-libstdcpp = [] +[dependencies] +rustc_bitflags = { path = "../librustc_bitflags" } + [build-dependencies] build_helper = { path = "../build_helper" } gcc = "0.3.27" diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 98816826b9e..aa64693f6d7 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -11,7 +11,7 @@ use debuginfo::{DIBuilderRef, DIDescriptor, DIFile, DILexicalBlock, DISubprogram, DIType, DIBasicType, DIDerivedType, DICompositeType, DIScope, DIVariable, DIGlobalVariable, DIArray, DISubrange, DITemplateTypeParameter, DIEnumerator, - DINameSpace}; + DINameSpace, DIFlags}; use libc::{c_uint, c_int, size_t, c_char}; use libc::{c_longlong, c_ulonglong, c_void}; @@ -408,7 +408,6 @@ pub enum Visibility { } pub mod debuginfo { - pub use self::DIDescriptorFlags::*; use super::MetadataRef; #[allow(missing_copy_implementations)] @@ -433,24 +432,29 @@ pub mod debuginfo { pub type DIEnumerator = DIDescriptor; pub type DITemplateTypeParameter = DIDescriptor; - #[derive(Copy, Clone)] - pub enum DIDescriptorFlags { - FlagPrivate = 1 << 0, - FlagProtected = 1 << 1, - FlagFwdDecl = 1 << 2, - FlagAppleBlock = 1 << 3, - FlagBlockByrefStruct = 1 << 4, - FlagVirtual = 1 << 5, - FlagArtificial = 1 << 6, - FlagExplicit = 1 << 7, - FlagPrototyped = 1 << 8, - FlagObjcClassComplete = 1 << 9, - FlagObjectPointer = 1 << 10, - FlagVector = 1 << 11, - FlagStaticMember = 1 << 12, - FlagIndirectVariable = 1 << 13, - FlagLValueReference = 1 << 14, - FlagRValueReference = 1 << 15, + // These values **must** match with LLVMRustDIFlags!! + bitflags! { + #[repr(C)] + #[derive(Debug, Default)] + flags DIFlags: ::libc::uint32_t { + const FlagZero = 0, + const FlagPrivate = 1, + const FlagProtected = 2, + const FlagPublic = 3, + const FlagFwdDecl = (1 << 2), + const FlagAppleBlock = (1 << 3), + const FlagBlockByrefStruct = (1 << 4), + const FlagVirtual = (1 << 5), + const FlagArtificial = (1 << 6), + const FlagExplicit = (1 << 7), + const FlagPrototyped = (1 << 8), + const FlagObjcClassComplete = (1 << 9), + const FlagObjectPointer = (1 << 10), + const FlagVector = (1 << 11), + const FlagStaticMember = (1 << 12), + const FlagLValueReference = (1 << 13), + const FlagRValueReference = (1 << 14), + } } } @@ -1567,7 +1571,7 @@ extern "C" { isLocalToUnit: bool, isDefinition: bool, ScopeLine: c_uint, - Flags: c_uint, + Flags: DIFlags, isOptimized: bool, Fn: ValueRef, TParam: DIArray, @@ -1595,7 +1599,7 @@ extern "C" { LineNumber: c_uint, SizeInBits: u64, AlignInBits: u64, - Flags: c_uint, + Flags: DIFlags, DerivedFrom: DIType, Elements: DIArray, RunTimeLang: c_uint, @@ -1611,7 +1615,7 @@ extern "C" { SizeInBits: u64, AlignInBits: u64, OffsetInBits: u64, - Flags: c_uint, + Flags: DIFlags, Ty: DIType) -> DIDerivedType; @@ -1647,7 +1651,7 @@ extern "C" { LineNo: c_uint, Ty: DIType, AlwaysPreserve: bool, - Flags: c_uint, + Flags: DIFlags, ArgNo: c_uint) -> DIVariable; @@ -1707,7 +1711,7 @@ extern "C" { LineNumber: c_uint, SizeInBits: u64, AlignInBits: u64, - Flags: c_uint, + Flags: DIFlags, Elements: DIArray, RunTimeLang: c_uint, UniqueId: *const c_char) diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 0229776c948..f2d978d2d25 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -29,8 +29,12 @@ #![feature(link_args)] #![feature(linked_from)] #![feature(staged_api)] +#![cfg_attr(not(stage0), feature(rustc_private))] extern crate libc; +#[macro_use] +#[no_link] +extern crate rustc_bitflags; pub use self::IntPredicate::*; pub use self::RealPredicate::*; diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index df0e1f1fc05..ca76211dc4c 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -22,7 +22,8 @@ use context::SharedCrateContext; use session::Session; use llvm::{self, ValueRef}; -use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor, DICompositeType, DILexicalBlock}; +use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor, + DICompositeType, DILexicalBlock, DIFlags}; use rustc::hir::def::CtorKind; use rustc::hir::def_id::DefId; @@ -69,8 +70,6 @@ pub const UNKNOWN_COLUMN_NUMBER: c_uint = 0; // ptr::null() doesn't work :( pub const NO_SCOPE_METADATA: DIScope = (0 as DIScope); -const FLAGS_NONE: c_uint = 0; - #[derive(Copy, Debug, Hash, Eq, PartialEq, Clone)] pub struct UniqueTypeId(ast::Name); @@ -347,14 +346,14 @@ fn vec_slice_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, llvm_type: member_llvm_types[0], type_metadata: element_type_metadata, offset: ComputedMemberOffset, - flags: FLAGS_NONE + flags: DIFlags::FlagZero, }, MemberDescription { name: "length".to_string(), llvm_type: member_llvm_types[1], type_metadata: type_metadata(cx, cx.tcx().types.usize, span), offset: ComputedMemberOffset, - flags: FLAGS_NONE + flags: DIFlags::FlagZero, }, ]; @@ -838,7 +837,7 @@ struct MemberDescription { llvm_type: Type, type_metadata: DIType, offset: MemberOffset, - flags: c_uint + flags: DIFlags, } // A factory for MemberDescriptions. It produces a list of member descriptions @@ -922,7 +921,7 @@ impl<'tcx> StructMemberDescriptionFactory<'tcx> { llvm_type: type_of::type_of(cx, fty), type_metadata: type_metadata(cx, fty, self.span), offset: offset, - flags: FLAGS_NONE, + flags: DIFlags::FlagZero, } }).collect() } @@ -987,7 +986,7 @@ impl<'tcx> TupleMemberDescriptionFactory<'tcx> { llvm_type: type_of::type_of(cx, component_type), type_metadata: type_metadata(cx, component_type, self.span), offset: ComputedMemberOffset, - flags: FLAGS_NONE, + flags: DIFlags::FlagZero, } }).collect() } @@ -1039,7 +1038,7 @@ impl<'tcx> UnionMemberDescriptionFactory<'tcx> { llvm_type: type_of::type_of(cx, fty), type_metadata: type_metadata(cx, fty, self.span), offset: FixedMemberOffset { bytes: 0 }, - flags: FLAGS_NONE, + flags: DIFlags::FlagZero, } }).collect() } @@ -1137,7 +1136,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { llvm_type: variant_llvm_type, type_metadata: variant_type_metadata, offset: FixedMemberOffset { bytes: 0 }, - flags: FLAGS_NONE + flags: DIFlags::FlagZero } }).collect() }, @@ -1171,7 +1170,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { llvm_type: variant_llvm_type, type_metadata: variant_type_metadata, offset: FixedMemberOffset { bytes: 0 }, - flags: FLAGS_NONE + flags: DIFlags::FlagZero } ] } @@ -1208,7 +1207,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { llvm_type: non_null_llvm_type, type_metadata: non_null_type_metadata, offset: FixedMemberOffset { bytes: 0 }, - flags: FLAGS_NONE + flags: DIFlags::FlagZero }; let unique_type_id = debug_context(cx).type_map @@ -1245,7 +1244,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { llvm_type: artificial_struct_llvm_type, type_metadata: artificial_struct_metadata, offset: FixedMemberOffset { bytes: 0 }, - flags: FLAGS_NONE + flags: DIFlags::FlagZero } ] }, @@ -1289,7 +1288,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { llvm_type: variant_llvm_type, type_metadata: variant_type_metadata, offset: FixedMemberOffset { bytes: 0 }, - flags: FLAGS_NONE + flags: DIFlags::FlagZero } ] }, @@ -1318,7 +1317,7 @@ impl<'tcx> VariantMemberDescriptionFactory<'tcx> { _ => type_metadata(cx, ty, self.span) }, offset: ComputedMemberOffset, - flags: FLAGS_NONE + flags: DIFlags::FlagZero } }).collect() } @@ -1535,7 +1534,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, UNKNOWN_LINE_NUMBER, bytes_to_bits(enum_type_size), bytes_to_bits(enum_type_align), - 0, // Flags + DIFlags::FlagZero, ptr::null_mut(), 0, // RuntimeLang unique_type_id_str.as_ptr()) @@ -1680,7 +1679,7 @@ fn create_struct_stub(cx: &CrateContext, UNKNOWN_LINE_NUMBER, bytes_to_bits(struct_size), bytes_to_bits(struct_align), - 0, + DIFlags::FlagZero, ptr::null_mut(), empty_array, 0, @@ -1717,7 +1716,7 @@ fn create_union_stub(cx: &CrateContext, UNKNOWN_LINE_NUMBER, bytes_to_bits(union_size), bytes_to_bits(union_align), - 0, // Flags + DIFlags::FlagZero, empty_array, 0, // RuntimeLang unique_type_id.as_ptr()) diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 482275d298b..e023e654d51 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -22,8 +22,7 @@ use self::source_loc::InternalDebugLocation::{self, UnknownLocation}; use llvm; use llvm::{ModuleRef, ContextRef, ValueRef}; -use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilderRef, DISubprogram, DIArray, - FlagPrototyped}; +use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilderRef, DISubprogram, DIArray, DIFlags}; use rustc::hir::def_id::DefId; use rustc::ty::subst::Substs; @@ -286,7 +285,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, is_local_to_unit, true, scope_line as c_uint, - FlagPrototyped as c_uint, + DIFlags::FlagPrototyped, cx.sess().opts.optimize != config::OptLevel::No, llfn, template_parameters, @@ -478,7 +477,7 @@ pub fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, loc.line as c_uint, type_metadata, cx.sess().opts.optimize != config::OptLevel::No, - 0, + DIFlags::FlagZero, argument_index) }; source_loc::set_debug_location(cx, None, diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 818737dfe7c..07a7cbdd3d4 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -352,6 +352,86 @@ DIT* unwrapDIptr(LLVMRustMetadataRef ref) { #define DIArray DINodeArray #define unwrapDI unwrapDIptr +// These values **must** match debuginfo::DIFlags! They also *happen* +// to match LLVM, but that isn't required as we do giant sets of +// matching below. The value shouldn't be directly passed to LLVM. +enum class LLVMRustDIFlags : uint32_t { + FlagZero = 0, + FlagPrivate = 1, + FlagProtected = 2, + FlagPublic = 3, + FlagFwdDecl = (1 << 2), + FlagAppleBlock = (1 << 3), + FlagBlockByrefStruct = (1 << 4), + FlagVirtual = (1 << 5), + FlagArtificial = (1 << 6), + FlagExplicit = (1 << 7), + FlagPrototyped = (1 << 8), + FlagObjcClassComplete = (1 << 9), + FlagObjectPointer = (1 << 10), + FlagVector = (1 << 11), + FlagStaticMember = (1 << 12), + FlagLValueReference = (1 << 13), + FlagRValueReference = (1 << 14), + // Do not add values that are not supported by the minimum LLVM + // version we support! +}; + +inline LLVMRustDIFlags operator& (LLVMRustDIFlags a, LLVMRustDIFlags b) { + return static_cast(static_cast(a) & static_cast(b)); +} + +inline LLVMRustDIFlags operator| (LLVMRustDIFlags a, LLVMRustDIFlags b) { + return static_cast(static_cast(a) | static_cast(b)); +} + +inline LLVMRustDIFlags& operator|= (LLVMRustDIFlags& a, LLVMRustDIFlags b) { + return a = a | b; +} + +inline bool is_set(LLVMRustDIFlags f) { + return f != LLVMRustDIFlags::FlagZero; +} + +inline LLVMRustDIFlags visibility(LLVMRustDIFlags f) { + return static_cast(static_cast(f) & 0x3); +} + +static unsigned from_rust(LLVMRustDIFlags flags) { + unsigned result = 0; + + switch (visibility(flags)) { + case LLVMRustDIFlags::FlagPrivate: + result |= DINode::DIFlags::FlagPrivate; + break; + case LLVMRustDIFlags::FlagProtected: + result |= DINode::DIFlags::FlagProtected; + break; + case LLVMRustDIFlags::FlagPublic: + result |= DINode::DIFlags::FlagPublic; + break; + default: + // The rest are handled below + break; + } + + if (is_set(flags & LLVMRustDIFlags::FlagFwdDecl)) { result |= DINode::DIFlags::FlagFwdDecl; } + if (is_set(flags & LLVMRustDIFlags::FlagAppleBlock)) { result |= DINode::DIFlags::FlagAppleBlock; } + if (is_set(flags & LLVMRustDIFlags::FlagBlockByrefStruct)) { result |= DINode::DIFlags::FlagBlockByrefStruct; } + if (is_set(flags & LLVMRustDIFlags::FlagVirtual)) { result |= DINode::DIFlags::FlagVirtual; } + if (is_set(flags & LLVMRustDIFlags::FlagArtificial)) { result |= DINode::DIFlags::FlagArtificial; } + if (is_set(flags & LLVMRustDIFlags::FlagExplicit)) { result |= DINode::DIFlags::FlagExplicit; } + if (is_set(flags & LLVMRustDIFlags::FlagPrototyped)) { result |= DINode::DIFlags::FlagPrototyped; } + if (is_set(flags & LLVMRustDIFlags::FlagObjcClassComplete)) { result |= DINode::DIFlags::FlagObjcClassComplete; } + if (is_set(flags & LLVMRustDIFlags::FlagObjectPointer)) { result |= DINode::DIFlags::FlagObjectPointer; } + if (is_set(flags & LLVMRustDIFlags::FlagVector)) { result |= DINode::DIFlags::FlagVector; } + if (is_set(flags & LLVMRustDIFlags::FlagStaticMember)) { result |= DINode::DIFlags::FlagStaticMember; } + if (is_set(flags & LLVMRustDIFlags::FlagLValueReference)) { result |= DINode::DIFlags::FlagLValueReference; } + if (is_set(flags & LLVMRustDIFlags::FlagRValueReference)) { result |= DINode::DIFlags::FlagRValueReference; } + + return result; +} + extern "C" uint32_t LLVMRustDebugMetadataVersion() { return DEBUG_METADATA_VERSION; } @@ -431,7 +511,7 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateFunction( bool isLocalToUnit, bool isDefinition, unsigned ScopeLine, - unsigned Flags, + LLVMRustDIFlags Flags, bool isOptimized, LLVMValueRef Fn, LLVMRustMetadataRef TParam, @@ -443,7 +523,7 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateFunction( unwrapDI(Scope), Name, LinkageName, unwrapDI(File), LineNo, unwrapDI(Ty), isLocalToUnit, isDefinition, ScopeLine, - Flags, isOptimized, + from_rust(Flags), isOptimized, TParams, unwrapDIptr(Decl)); unwrap(Fn)->setSubprogram(Sub); @@ -453,7 +533,7 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateFunction( unwrapDI(Scope), Name, LinkageName, unwrapDI(File), LineNo, unwrapDI(Ty), isLocalToUnit, isDefinition, ScopeLine, - Flags, isOptimized, + from_rust(Flags), isOptimized, unwrap(Fn), unwrapDIptr(TParam), unwrapDIptr(Decl))); @@ -489,7 +569,7 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateStructType( unsigned LineNumber, uint64_t SizeInBits, uint64_t AlignInBits, - unsigned Flags, + LLVMRustDIFlags Flags, LLVMRustMetadataRef DerivedFrom, LLVMRustMetadataRef Elements, unsigned RunTimeLang, @@ -502,7 +582,7 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateStructType( LineNumber, SizeInBits, AlignInBits, - Flags, + from_rust(Flags), unwrapDI(DerivedFrom), DINodeArray(unwrapDI(Elements)), RunTimeLang, @@ -520,12 +600,12 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateMemberType( uint64_t SizeInBits, uint64_t AlignInBits, uint64_t OffsetInBits, - unsigned Flags, + LLVMRustDIFlags Flags, LLVMRustMetadataRef Ty) { return wrap(Builder->createMemberType( unwrapDI(Scope), Name, unwrapDI(File), LineNo, - SizeInBits, AlignInBits, OffsetInBits, Flags, + SizeInBits, AlignInBits, OffsetInBits, from_rust(Flags), unwrapDI(Ty))); } @@ -581,7 +661,7 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateVariable( unsigned LineNo, LLVMRustMetadataRef Ty, bool AlwaysPreserve, - unsigned Flags, + LLVMRustDIFlags Flags, unsigned ArgNo) { #if LLVM_VERSION_GE(3, 8) if (Tag == 0x100) { // DW_TAG_auto_variable @@ -589,20 +669,20 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateVariable( unwrapDI(Scope), Name, unwrapDI(File), LineNo, - unwrapDI(Ty), AlwaysPreserve, Flags)); + unwrapDI(Ty), AlwaysPreserve, from_rust(Flags))); } else { return wrap(Builder->createParameterVariable( unwrapDI(Scope), Name, ArgNo, unwrapDI(File), LineNo, - unwrapDI(Ty), AlwaysPreserve, Flags)); + unwrapDI(Ty), AlwaysPreserve, from_rust(Flags))); } #else return wrap(Builder->createLocalVariable(Tag, unwrapDI(Scope), Name, unwrapDI(File), LineNo, - unwrapDI(Ty), AlwaysPreserve, Flags, ArgNo)); + unwrapDI(Ty), AlwaysPreserve, from_rust(Flags), ArgNo)); #endif } @@ -701,7 +781,7 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateUnionType( unsigned LineNumber, uint64_t SizeInBits, uint64_t AlignInBits, - unsigned Flags, + LLVMRustDIFlags Flags, LLVMRustMetadataRef Elements, unsigned RunTimeLang, const char* UniqueId) @@ -713,7 +793,7 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateUnionType( LineNumber, SizeInBits, AlignInBits, - Flags, + from_rust(Flags), DINodeArray(unwrapDI(Elements)), RunTimeLang, UniqueId From 757a9cea3f106483901deab928ad4688d098be3c Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Fri, 18 Nov 2016 16:22:39 -0500 Subject: [PATCH 209/293] [LLVM 4.0] Support new DIFlags enum --- src/rustllvm/RustWrapper.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 07a7cbdd3d4..51859a928c4 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -397,8 +397,13 @@ inline LLVMRustDIFlags visibility(LLVMRustDIFlags f) { return static_cast(static_cast(f) & 0x3); } +#if LLVM_VERSION_GE(4, 0) +static DINode::DIFlags from_rust(LLVMRustDIFlags flags) { + DINode::DIFlags result = DINode::DIFlags::FlagZero; +#else static unsigned from_rust(LLVMRustDIFlags flags) { unsigned result = 0; +#endif switch (visibility(flags)) { case LLVMRustDIFlags::FlagPrivate: From 60d1660748b30e2f3c69738e068d252271715268 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 2 Dec 2016 20:16:12 -0800 Subject: [PATCH 210/293] Add Component examples --- src/libstd/path.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index d215f368d1e..d13baea40a9 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -457,7 +457,17 @@ pub enum Component<'a> { } impl<'a> Component<'a> { - /// Extracts the underlying `OsStr` slice + /// Extracts the underlying `OsStr` slice. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("./tmp/foo/bar.txt"); + /// let components: Vec<_> = path.components().map(|comp| comp.as_os_str()).collect(); + /// assert_eq!(&components, &[".", "tmp", "foo", "bar.txt"]); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn as_os_str(self) -> &'a OsStr { match self { From 4dd590ac8c93e99c946aee28def4662b9c6b5865 Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Tue, 29 Nov 2016 14:18:59 -0500 Subject: [PATCH 211/293] Remove redundant assertion near is_char_boundary. --- src/libcollections/string.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index ddde9d06d81..fff7c160e31 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1129,8 +1129,6 @@ impl String { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(&mut self, idx: usize, ch: char) { - let len = self.len(); - assert!(idx <= len); assert!(self.is_char_boundary(idx)); let mut bits = [0; 4]; let bits = ch.encode_utf8(&mut bits).as_bytes(); @@ -1184,7 +1182,6 @@ impl String { reason = "recent addition", issue = "35553")] pub fn insert_str(&mut self, idx: usize, string: &str) { - assert!(idx <= self.len()); assert!(self.is_char_boundary(idx)); unsafe { @@ -1288,7 +1285,6 @@ impl String { #[unstable(feature = "string_split_off", issue = "38080")] pub fn split_off(&mut self, mid: usize) -> String { assert!(self.is_char_boundary(mid)); - assert!(mid <= self.len()); let other = self.vec.split_off(mid); unsafe { String::from_utf8_unchecked(other) } } From 53ebf5a0a7b08886d99c31bed7cf989f9af6c442 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Wed, 30 Nov 2016 15:39:20 +0100 Subject: [PATCH 212/293] update src/liblibc to include i686-unknown-openbsd libc definition --- src/liblibc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/liblibc b/src/liblibc index 6e8c1b490cc..0ac39c5ccf6 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit 6e8c1b490ccbe5e84d248bab883515bc85394b5f +Subproject commit 0ac39c5ccf6a04395b7c40dd62321cb91f63f160 From b8d8ab87c08f1a662db82198ab598f549df9cc22 Mon Sep 17 00:00:00 2001 From: Mikhail Modin Date: Sat, 10 Sep 2016 00:11:31 +0300 Subject: [PATCH 213/293] fix stack overflow by enum and cont issue #36163, some paths were skipped while checking for recursion. --- src/librustc_passes/static_recursion.rs | 125 ++++++++++++------------ src/test/compile-fail/issue-36163.rs | 26 +++++ 2 files changed, 86 insertions(+), 65 deletions(-) create mode 100644 src/test/compile-fail/issue-36163.rs diff --git a/src/librustc_passes/static_recursion.rs b/src/librustc_passes/static_recursion.rs index ffb5045fe3b..b5be4aa5e64 100644 --- a/src/librustc_passes/static_recursion.rs +++ b/src/librustc_passes/static_recursion.rs @@ -15,7 +15,7 @@ use rustc::dep_graph::DepNode; use rustc::hir::map as ast_map; use rustc::session::{CompileResult, Session}; use rustc::hir::def::{Def, CtorKind}; -use rustc::util::nodemap::NodeMap; +use rustc::util::nodemap::{NodeMap, NodeSet}; use syntax::ast; use syntax::feature_gate::{GateIssue, emit_feature_err}; @@ -23,8 +23,6 @@ use syntax_pos::Span; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::hir; -use std::cell::RefCell; - struct CheckCrateVisitor<'a, 'ast: 'a> { sess: &'a Session, ast_map: &'a ast_map::Map<'ast>, @@ -32,7 +30,8 @@ struct CheckCrateVisitor<'a, 'ast: 'a> { // variant definitions with the discriminant expression that applies to // each one. If the variant uses the default values (starting from `0`), // then `None` is stored. - discriminant_map: RefCell>>, + discriminant_map: NodeMap>, + detected_recursive_ids: NodeSet, } impl<'a, 'ast: 'a> Visitor<'ast> for CheckCrateVisitor<'a, 'ast> { @@ -90,15 +89,14 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckCrateVisitor<'a, 'ast> { } } -pub fn check_crate<'ast>(sess: &Session, - ast_map: &ast_map::Map<'ast>) - -> CompileResult { +pub fn check_crate<'ast>(sess: &Session, ast_map: &ast_map::Map<'ast>) -> CompileResult { let _task = ast_map.dep_graph.in_task(DepNode::CheckStaticRecursion); let mut visitor = CheckCrateVisitor { sess: sess, ast_map: ast_map, - discriminant_map: RefCell::new(NodeMap()), + discriminant_map: NodeMap(), + detected_recursive_ids: NodeSet(), }; sess.track_errors(|| { // FIXME(#37712) could use ItemLikeVisitor if trait items were item-like @@ -106,30 +104,34 @@ pub fn check_crate<'ast>(sess: &Session, }) } -struct CheckItemRecursionVisitor<'a, 'ast: 'a> { - root_span: &'a Span, - sess: &'a Session, - ast_map: &'a ast_map::Map<'ast>, - discriminant_map: &'a RefCell>>, +struct CheckItemRecursionVisitor<'a, 'b: 'a, 'ast: 'b> { + root_span: &'b Span, + sess: &'b Session, + ast_map: &'b ast_map::Map<'ast>, + discriminant_map: &'a mut NodeMap>, idstack: Vec, + detected_recursive_ids: &'a mut NodeSet, } -impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> { - fn new(v: &'a CheckCrateVisitor<'a, 'ast>, - span: &'a Span) - -> CheckItemRecursionVisitor<'a, 'ast> { +impl<'a, 'b: 'a, 'ast: 'b> CheckItemRecursionVisitor<'a, 'b, 'ast> { + fn new(v: &'a mut CheckCrateVisitor<'b, 'ast>, span: &'b Span) -> Self { CheckItemRecursionVisitor { root_span: span, sess: v.sess, ast_map: v.ast_map, - discriminant_map: &v.discriminant_map, + discriminant_map: &mut v.discriminant_map, idstack: Vec::new(), + detected_recursive_ids: &mut v.detected_recursive_ids, } } fn with_item_id_pushed(&mut self, id: ast::NodeId, f: F, span: Span) where F: Fn(&mut Self) { if self.idstack.iter().any(|&x| x == id) { + if self.detected_recursive_ids.contains(&id) { + return; + } + self.detected_recursive_ids.insert(id); let any_static = self.idstack.iter().any(|&x| { if let ast_map::NodeItem(item) = self.ast_map.get(x) { if let hir::ItemStatic(..) = item.node { @@ -168,15 +170,14 @@ impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> { // So for every variant, we need to track whether there is an expression // somewhere in the enum definition that controls its discriminant. We do // this by starting from the end and searching backward. - fn populate_enum_discriminants(&self, enum_definition: &'ast hir::EnumDef) { + fn populate_enum_discriminants(&mut self, enum_definition: &'ast hir::EnumDef) { // Get the map, and return if we already processed this enum or if it // has no variants. - let mut discriminant_map = self.discriminant_map.borrow_mut(); match enum_definition.variants.first() { None => { return; } - Some(variant) if discriminant_map.contains_key(&variant.node.data.id()) => { + Some(variant) if self.discriminant_map.contains_key(&variant.node.data.id()) => { return; } _ => {} @@ -190,7 +191,7 @@ impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> { // is affected by that expression. if let Some(ref expr) = variant.node.disr_expr { for id in &variant_stack { - discriminant_map.insert(*id, Some(expr)); + self.discriminant_map.insert(*id, Some(expr)); } variant_stack.clear() } @@ -198,16 +199,15 @@ impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> { // If we are at the top, that always starts at 0, so any variant on the // stack has a default value and does not need to be checked. for id in &variant_stack { - discriminant_map.insert(*id, None); + self.discriminant_map.insert(*id, None); } } } -impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> { +impl<'a, 'b: 'a, 'ast: 'b> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'b, 'ast> { fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'ast> { NestedVisitorMap::OnlyBodies(&self.ast_map) } - fn visit_item(&mut self, it: &'ast hir::Item) { self.with_item_id_pushed(it.id, |v| intravisit::walk_item(v, it), it.span); } @@ -227,7 +227,7 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> { _: ast::NodeId) { let variant_id = variant.node.data.id(); let maybe_expr; - if let Some(get_expr) = self.discriminant_map.borrow().get(&variant_id) { + if let Some(get_expr) = self.discriminant_map.get(&variant_id) { // This is necessary because we need to let the `discriminant_map` // borrow fall out of scope, so that we can reborrow farther down. maybe_expr = (*get_expr).clone(); @@ -251,51 +251,46 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> { self.with_item_id_pushed(ii.id, |v| intravisit::walk_impl_item(v, ii), ii.span); } - fn visit_expr(&mut self, e: &'ast hir::Expr) { - match e.node { - hir::ExprPath(hir::QPath::Resolved(_, ref path)) => { - match path.def { - Def::Static(def_id, _) | - Def::AssociatedConst(def_id) | - Def::Const(def_id) => { - if let Some(node_id) = self.ast_map.as_local_node_id(def_id) { - match self.ast_map.get(node_id) { - ast_map::NodeItem(item) => self.visit_item(item), - ast_map::NodeTraitItem(item) => self.visit_trait_item(item), - ast_map::NodeImplItem(item) => self.visit_impl_item(item), - ast_map::NodeForeignItem(_) => {} - _ => { - span_bug!(e.span, - "expected item, found {}", - self.ast_map.node_to_string(node_id)); - } - } + fn visit_path(&mut self, path: &'ast hir::Path, _: ast::NodeId) { + match path.def { + Def::Static(def_id, _) | + Def::AssociatedConst(def_id) | + Def::Const(def_id) => { + if let Some(node_id) = self.ast_map.as_local_node_id(def_id) { + match self.ast_map.get(node_id) { + ast_map::NodeItem(item) => self.visit_item(item), + ast_map::NodeTraitItem(item) => self.visit_trait_item(item), + ast_map::NodeImplItem(item) => self.visit_impl_item(item), + ast_map::NodeForeignItem(_) => {} + _ => { + span_bug!(path.span, + "expected item, found {}", + self.ast_map.node_to_string(node_id)); } } - // For variants, we only want to check expressions that - // affect the specific variant used, but we need to check - // the whole enum definition to see what expression that - // might be (if any). - Def::VariantCtor(variant_id, CtorKind::Const) => { - if let Some(variant_id) = self.ast_map.as_local_node_id(variant_id) { - let variant = self.ast_map.expect_variant(variant_id); - let enum_id = self.ast_map.get_parent(variant_id); - let enum_item = self.ast_map.expect_item(enum_id); - if let hir::ItemEnum(ref enum_def, ref generics) = enum_item.node { - self.populate_enum_discriminants(enum_def); - self.visit_variant(variant, generics, enum_id); - } else { - span_bug!(e.span, - "`check_static_recursion` found \ - non-enum in Def::VariantCtor"); - } - } + } + } + // For variants, we only want to check expressions that + // affect the specific variant used, but we need to check + // the whole enum definition to see what expression that + // might be (if any). + Def::VariantCtor(variant_id, CtorKind::Const) => { + if let Some(variant_id) = self.ast_map.as_local_node_id(variant_id) { + let variant = self.ast_map.expect_variant(variant_id); + let enum_id = self.ast_map.get_parent(variant_id); + let enum_item = self.ast_map.expect_item(enum_id); + if let hir::ItemEnum(ref enum_def, ref generics) = enum_item.node { + self.populate_enum_discriminants(enum_def); + self.visit_variant(variant, generics, enum_id); + } else { + span_bug!(path.span, + "`check_static_recursion` found \ + non-enum in Def::VariantCtor"); } - _ => (), } } _ => (), } - intravisit::walk_expr(self, e); + intravisit::walk_path(self, path); } } diff --git a/src/test/compile-fail/issue-36163.rs b/src/test/compile-fail/issue-36163.rs new file mode 100644 index 00000000000..9dad6ede776 --- /dev/null +++ b/src/test/compile-fail/issue-36163.rs @@ -0,0 +1,26 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +const A: i32 = Foo::B; //~ ERROR E0265 + //~^ NOTE recursion not allowed in constant + +enum Foo { + B = A, //~ ERROR E0265 + //~^ NOTE recursion not allowed in constant +} + +enum Bar { + C = Bar::C, //~ ERROR E0265 + //~^ NOTE recursion not allowed in constant +} + +const D: i32 = A; + +fn main() {} From a1882ca769ed82fa16a06f113f386fa48366c331 Mon Sep 17 00:00:00 2001 From: Mathieu Poumeyrol Date: Sat, 3 Dec 2016 19:47:27 +0100 Subject: [PATCH 214/293] fix objc ABI in std::env::args --- src/libstd/sys/unix/args.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/libstd/sys/unix/args.rs b/src/libstd/sys/unix/args.rs index c04fd863674..0f447ff4ec4 100644 --- a/src/libstd/sys/unix/args.rs +++ b/src/libstd/sys/unix/args.rs @@ -172,10 +172,23 @@ mod imp { extern { fn sel_registerName(name: *const libc::c_uchar) -> Sel; - fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId; fn objc_getClass(class_name: *const libc::c_uchar) -> NsId; } + #[cfg(target_arch="aarch64")] + extern { + fn objc_msgSend(obj: NsId, sel: Sel) -> NsId; + #[link_name="objc_msgSend"] + fn objc_msgSend_ul(obj: NsId, sel: Sel, i: libc::c_ulong) -> NsId; + } + + #[cfg(not(target_arch="aarch64"))] + extern { + fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId; + #[link_name="objc_msgSend"] + fn objc_msgSend_ul(obj: NsId, sel: Sel, ...) -> NsId; + } + #[link(name = "Foundation", kind = "framework")] #[link(name = "objc")] #[cfg(not(cargobuild))] @@ -199,7 +212,7 @@ mod imp { let cnt: usize = mem::transmute(objc_msgSend(args, count_sel)); for i in 0..cnt { - let tmp = objc_msgSend(args, object_at_sel, i); + let tmp = objc_msgSend_ul(args, object_at_sel, i as libc::c_ulong); let utf_c_str: *const libc::c_char = mem::transmute(objc_msgSend(tmp, utf8_sel)); let bytes = CStr::from_ptr(utf_c_str).to_bytes(); From f8097066f8d40ef2716b6d679324ef894038b261 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 3 Dec 2016 14:42:34 -0500 Subject: [PATCH 215/293] move test for #37290 into run-pass-fulldeps --- .../{run-pass => run-pass-fulldeps}/issue-37290/auxiliary/lint.rs | 0 src/test/{run-pass => run-pass-fulldeps}/issue-37290/main.rs | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/test/{run-pass => run-pass-fulldeps}/issue-37290/auxiliary/lint.rs (100%) rename src/test/{run-pass => run-pass-fulldeps}/issue-37290/main.rs (100%) diff --git a/src/test/run-pass/issue-37290/auxiliary/lint.rs b/src/test/run-pass-fulldeps/issue-37290/auxiliary/lint.rs similarity index 100% rename from src/test/run-pass/issue-37290/auxiliary/lint.rs rename to src/test/run-pass-fulldeps/issue-37290/auxiliary/lint.rs diff --git a/src/test/run-pass/issue-37290/main.rs b/src/test/run-pass-fulldeps/issue-37290/main.rs similarity index 100% rename from src/test/run-pass/issue-37290/main.rs rename to src/test/run-pass-fulldeps/issue-37290/main.rs From 2e03549e67a48b6a2b3a83d26dd3540c294b9d6a Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Sat, 3 Dec 2016 15:01:09 -0800 Subject: [PATCH 216/293] Ignore test on -windows-gnu. --- src/test/codegen/dllimports/main.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/codegen/dllimports/main.rs b/src/test/codegen/dllimports/main.rs index 140d95fb7be..64f516aa272 100644 --- a/src/test/codegen/dllimports/main.rs +++ b/src/test/codegen/dllimports/main.rs @@ -8,7 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// This test is for Windows only. +// This test is for *-windows-msvc only. +// ignore-gnu // ignore-android // ignore-bitrig // ignore-macos From f90986e3a8d21d979e871c1af304ccfbe2c81093 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 3 Dec 2016 15:46:28 -0800 Subject: [PATCH 217/293] Add examples for exit function --- src/libstd/process.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 9e1b57c7412..70453a74d2c 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -827,6 +827,14 @@ impl Child { /// will be run. If a clean shutdown is needed it is recommended to only call /// this function at a known point where there are no more destructors left /// to run. +/// +/// # Examples +/// +/// ``` +/// use std::process; +/// +/// process::exit(0); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn exit(code: i32) -> ! { ::sys_common::cleanup(); From 3d069e1b38c983e846ea8db1f07af729bdc79fe7 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Mon, 28 Nov 2016 10:08:08 -0800 Subject: [PATCH 218/293] Add TypeVariableOrigin enum --- src/librustc/infer/glb.rs | 5 ++ src/librustc/infer/lattice.rs | 9 +++- src/librustc/infer/lub.rs | 5 ++ src/librustc/infer/mod.rs | 19 ++++--- src/librustc/infer/type_variable.rs | 25 ++++++++- src/librustc/traits/error_reporting.rs | 9 ++-- src/librustc/traits/project.rs | 15 +++++- src/librustc_driver/test.rs | 8 +-- src/librustc_typeck/check/_match.rs | 16 ++++-- src/librustc_typeck/check/closure.rs | 3 +- src/librustc_typeck/check/method/probe.rs | 5 +- src/librustc_typeck/check/method/suggest.rs | 4 +- src/librustc_typeck/check/mod.rs | 56 ++++++++++++--------- src/librustc_typeck/check/op.rs | 3 +- 14 files changed, 129 insertions(+), 53 deletions(-) diff --git a/src/librustc/infer/glb.rs b/src/librustc/infer/glb.rs index a5709e18808..8ccadc6b2af 100644 --- a/src/librustc/infer/glb.rs +++ b/src/librustc/infer/glb.rs @@ -13,6 +13,7 @@ use super::InferCtxt; use super::lattice::{self, LatticeDir}; use super::Subtype; +use traits::ObligationCause; use ty::{self, Ty, TyCtxt}; use ty::relate::{Relate, RelateResult, TypeRelation}; @@ -83,6 +84,10 @@ impl<'combine, 'infcx, 'gcx, 'tcx> LatticeDir<'infcx, 'gcx, 'tcx> self.fields.infcx } + fn cause(&self) -> &ObligationCause<'tcx> { + &self.fields.trace.cause + } + fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { let mut sub = self.fields.sub(self.a_is_expected); sub.relate(&v, &a)?; diff --git a/src/librustc/infer/lattice.rs b/src/librustc/infer/lattice.rs index eda78428e61..f7b26a918b3 100644 --- a/src/librustc/infer/lattice.rs +++ b/src/librustc/infer/lattice.rs @@ -30,7 +30,9 @@ //! a lattice. use super::InferCtxt; +use super::type_variable::TypeVariableOrigin; +use traits::ObligationCause; use ty::TyVar; use ty::{self, Ty}; use ty::relate::{RelateResult, TypeRelation}; @@ -38,6 +40,8 @@ use ty::relate::{RelateResult, TypeRelation}; pub trait LatticeDir<'f, 'gcx: 'f+'tcx, 'tcx: 'f> : TypeRelation<'f, 'gcx, 'tcx> { fn infcx(&self) -> &'f InferCtxt<'f, 'gcx, 'tcx>; + fn cause(&self) -> &ObligationCause<'tcx>; + // Relates the type `v` to `a` and `b` such that `v` represents // the LUB/GLB of `a` and `b` as appropriate. fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>; @@ -64,14 +68,15 @@ pub fn super_lattice_tys<'a, 'gcx, 'tcx, L>(this: &mut L, match (&a.sty, &b.sty) { (&ty::TyInfer(TyVar(..)), &ty::TyInfer(TyVar(..))) if infcx.type_var_diverges(a) && infcx.type_var_diverges(b) => { - let v = infcx.next_diverging_ty_var(); + let v = infcx.next_diverging_ty_var( + TypeVariableOrigin::LatticeVariable(this.cause().span)); this.relate_bound(v, a, b)?; Ok(v) } (&ty::TyInfer(TyVar(..)), _) | (_, &ty::TyInfer(TyVar(..))) => { - let v = infcx.next_ty_var(); + let v = infcx.next_ty_var(TypeVariableOrigin::LatticeVariable(this.cause().span)); this.relate_bound(v, a, b)?; Ok(v) } diff --git a/src/librustc/infer/lub.rs b/src/librustc/infer/lub.rs index 7d352be67d3..89571dea10c 100644 --- a/src/librustc/infer/lub.rs +++ b/src/librustc/infer/lub.rs @@ -13,6 +13,7 @@ use super::InferCtxt; use super::lattice::{self, LatticeDir}; use super::Subtype; +use traits::ObligationCause; use ty::{self, Ty, TyCtxt}; use ty::relate::{Relate, RelateResult, TypeRelation}; @@ -83,6 +84,10 @@ impl<'combine, 'infcx, 'gcx, 'tcx> LatticeDir<'infcx, 'gcx, 'tcx> self.fields.infcx } + fn cause(&self) -> &ObligationCause<'tcx> { + &self.fields.trace.cause + } + fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { let mut sub = self.fields.sub(self.a_is_expected); sub.relate(&a, &v)?; diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 72ef987aefd..9b58334e658 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -45,6 +45,7 @@ use util::nodemap::{FxHashMap, FxHashSet, NodeMap}; use self::combine::CombineFields; use self::higher_ranked::HrMatchResult; use self::region_inference::{RegionVarBindings, RegionSnapshot}; +use self::type_variable::TypeVariableOrigin; use self::unify_key::ToType; mod bivariate; @@ -114,7 +115,7 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // We instantiate UnificationTable with bounds because the // types that might instantiate a general type variable have an // order, represented by its upper and lower bounds. - type_variables: RefCell>, + pub type_variables: RefCell>, // Map from integral variable to the kind of integer it represents int_unification_table: RefCell>, @@ -1054,18 +1055,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { }) } - pub fn next_ty_var_id(&self, diverging: bool) -> TyVid { + pub fn next_ty_var_id(&self, diverging: bool, origin: TypeVariableOrigin) -> TyVid { self.type_variables .borrow_mut() - .new_var(diverging, None) + .new_var(diverging, origin, None) } - pub fn next_ty_var(&self) -> Ty<'tcx> { - self.tcx.mk_var(self.next_ty_var_id(false)) + pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { + self.tcx.mk_var(self.next_ty_var_id(false, origin)) } - pub fn next_diverging_ty_var(&self) -> Ty<'tcx> { - self.tcx.mk_var(self.next_ty_var_id(true)) + pub fn next_diverging_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { + self.tcx.mk_var(self.next_ty_var_id(true, origin)) } pub fn next_int_var_id(&self) -> IntVid { @@ -1118,7 +1119,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let ty_var_id = self.type_variables .borrow_mut() - .new_var(false, default); + .new_var(false, + TypeVariableOrigin::TypeParameterDefinition(span, def.name), + default); self.tcx.mk_var(ty_var_id) } diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 804765ec881..9c8419d9546 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -13,6 +13,7 @@ use self::TypeVariableValue::*; use self::UndoEntry::*; use hir::def_id::{DefId}; use syntax::util::small_vector::SmallVector; +use syntax::ast; use syntax_pos::Span; use ty::{self, Ty}; @@ -28,8 +29,24 @@ pub struct TypeVariableTable<'tcx> { eq_relations: ut::UnificationTable, } +/// Reasons to create a type inference variable +pub enum TypeVariableOrigin { + MiscVariable(Span), + NormalizeProjectionType(Span), + TypeInference(Span), + TypeParameterDefinition(Span, ast::Name), + TransformedUpvar(Span), + SubstitutionPlaceholder(Span), + AutoDeref(Span), + AdjustmentType(Span), + DivergingStmt(Span), + DivergingBlockExpr(Span), + LatticeVariable(Span), +} + struct TypeVariableData<'tcx> { value: TypeVariableValue<'tcx>, + origin: TypeVariableOrigin, diverging: bool } @@ -107,6 +124,10 @@ impl<'tcx> TypeVariableTable<'tcx> { self.values.get(vid.index as usize).diverging } + pub fn var_origin(&self, vid: ty::TyVid) -> &TypeVariableOrigin { + &self.values.get(vid.index as usize).origin + } + /// Records that `a <: b`, `a :> b`, or `a == b`, depending on `dir`. /// /// Precondition: neither `a` nor `b` are known. @@ -173,10 +194,12 @@ impl<'tcx> TypeVariableTable<'tcx> { pub fn new_var(&mut self, diverging: bool, - default: Option>) -> ty::TyVid { + origin: TypeVariableOrigin, + default: Option>,) -> ty::TyVid { self.eq_relations.new_key(()); let index = self.values.push(TypeVariableData { value: Bounded { relations: vec![], default: default }, + origin: origin, diverging: diverging }); let v = ty::TyVid { index: index as u32 }; diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 2e8e45468dd..bed834e237d 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -27,6 +27,7 @@ use super::{ use fmt_macros::{Parser, Piece, Position}; use hir::def_id::DefId; use infer::{self, InferCtxt}; +use infer::type_variable::TypeVariableOrigin; use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL; use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; use ty::error::ExpectedFound; @@ -38,7 +39,7 @@ use util::nodemap::{FxHashMap, FxHashSet}; use std::cmp; use std::fmt; use syntax::ast; -use syntax_pos::Span; +use syntax_pos::{DUMMY_SP, Span}; use errors::DiagnosticBuilder; #[derive(Debug, PartialEq, Eq, Hash)] @@ -790,9 +791,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.infcx.tcx } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - if let ty::TyParam(..) = ty.sty { + if let ty::TyParam(ty::ParamTy {name, ..}) = ty.sty { let infcx = self.infcx; - self.var_map.entry(ty).or_insert_with(|| infcx.next_ty_var()) + self.var_map.entry(ty).or_insert_with(|| + infcx.next_ty_var( + TypeVariableOrigin::TypeParameterDefinition(DUMMY_SP, name))) } else { ty.super_fold_with(self) } diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 27b7adf0ef3..865bc2a9560 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -25,6 +25,7 @@ use super::util; use hir::def_id::DefId; use infer::InferOk; +use infer::type_variable::TypeVariableOrigin; use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap}; use syntax::ast; use syntax::symbol::Symbol; @@ -382,7 +383,12 @@ pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>( // and a deferred predicate to resolve this when more type // information is available. - let ty_var = selcx.infcx().next_ty_var(); + let tcx = selcx.infcx().tcx; + let def_id = tcx.associated_items(projection_ty.trait_ref.def_id).find(|i| + i.name == projection_ty.item_name && i.kind == ty::AssociatedKind::Type + ).map(|i| i.def_id).unwrap(); + let ty_var = selcx.infcx().next_ty_var( + TypeVariableOrigin::NormalizeProjectionType(tcx.def_span(def_id))); let projection = ty::Binder(ty::ProjectionPredicate { projection_ty: projection_ty, ty: ty_var @@ -596,7 +602,12 @@ fn normalize_to_error<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 'tc let trait_obligation = Obligation { cause: cause, recursion_depth: depth, predicate: trait_ref.to_predicate() }; - let new_value = selcx.infcx().next_ty_var(); + let tcx = selcx.infcx().tcx; + let def_id = tcx.associated_items(projection_ty.trait_ref.def_id).find(|i| + i.name == projection_ty.item_name && i.kind == ty::AssociatedKind::Type + ).map(|i| i.def_id).unwrap(); + let new_value = selcx.infcx().next_ty_var( + TypeVariableOrigin::NormalizeProjectionType(tcx.def_span(def_id))); Normalized { value: new_value, obligations: vec![trait_obligation] diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 464e15faeaf..ad7def42b89 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -24,6 +24,7 @@ use rustc::ty::subst::{Kind, Subst}; use rustc::traits::{ObligationCause, Reveal}; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::infer::{self, InferOk, InferResult}; +use rustc::infer::type_variable::TypeVariableOrigin; use rustc_metadata::cstore::CStore; use rustc::hir::map as hir_map; use rustc::session::{self, config}; @@ -36,6 +37,7 @@ use errors::emitter::Emitter; use errors::{Level, DiagnosticBuilder}; use syntax::feature_gate::UnstableFeatures; use syntax::symbol::Symbol; +use syntax_pos::DUMMY_SP; use rustc::hir; @@ -494,7 +496,7 @@ fn sub_free_bound_false_infer() { //! does NOT hold for any instantiation of `_#1`. test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { - let t_infer1 = env.infcx.next_ty_var(); + let t_infer1 = env.infcx.next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP)); let t_rptr_bound1 = env.t_rptr_late_bound(1); env.check_not_sub(env.t_fn(&[t_infer1], env.tcx().types.isize), env.t_fn(&[t_rptr_bound1], env.tcx().types.isize)); @@ -513,7 +515,7 @@ fn lub_free_bound_infer() { test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { env.create_simple_region_hierarchy(); - let t_infer1 = env.infcx.next_ty_var(); + let t_infer1 = env.infcx.next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP)); let t_rptr_bound1 = env.t_rptr_late_bound(1); let t_rptr_free1 = env.t_rptr_free(1, 1); env.check_lub(env.t_fn(&[t_infer1], env.tcx().types.isize), @@ -633,7 +635,7 @@ fn glb_bound_free() { fn glb_bound_free_infer() { test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { let t_rptr_bound1 = env.t_rptr_late_bound(1); - let t_infer1 = env.infcx.next_ty_var(); + let t_infer1 = env.infcx.next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP)); // compute GLB(fn(_) -> isize, for<'b> fn(&'b isize) -> isize), // which should yield for<'b> fn(&'b isize) -> isize diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 6e2b42881a7..b652f3c4ad7 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -12,6 +12,7 @@ use rustc::hir::{self, PatKind}; use rustc::hir::def::{Def, CtorKind}; use rustc::hir::pat_util::EnumerateAndAdjustIterator; use rustc::infer; +use rustc::infer::type_variable::TypeVariableOrigin; use rustc::traits::ObligationCauseCode; use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference}; use check::{FnCtxt, Expectation, Diverges}; @@ -162,7 +163,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } let max_len = cmp::max(expected_len, elements.len()); - let element_tys_iter = (0..max_len).map(|_| self.next_ty_var()); + let element_tys_iter = (0..max_len).map(|_| self.next_ty_var( + // FIXME: MiscVariable for now, obtaining the span and name information + // from all tuple elements isn't trivial. + TypeVariableOrigin::TypeInference(pat.span))); let element_tys = tcx.mk_type_list(element_tys_iter); let pat_ty = tcx.mk_ty(ty::TyTuple(element_tys)); self.demand_eqtype(pat.span, expected, pat_ty); @@ -172,7 +176,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pat_ty } PatKind::Box(ref inner) => { - let inner_ty = self.next_ty_var(); + let inner_ty = self.next_ty_var(TypeVariableOrigin::TypeInference(inner.span)); let uniq_ty = tcx.mk_box(inner_ty); if self.check_dereferencable(pat.span, expected, &inner) { @@ -203,7 +207,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { (expected, mt.ty) } _ => { - let inner_ty = self.next_ty_var(); + let inner_ty = self.next_ty_var( + TypeVariableOrigin::TypeInference(inner.span)); let mt = ty::TypeAndMut { ty: inner_ty, mutbl: mutbl }; let region = self.next_region_var(infer::PatternRegion(pat.span)); let rptr_ty = tcx.mk_ref(region, mt); @@ -379,7 +384,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // ...but otherwise we want to use any supertype of the // discriminant. This is sort of a workaround, see note (*) in // `check_pat` for some details. - discrim_ty = self.next_ty_var(); + discrim_ty = self.next_ty_var(TypeVariableOrigin::TypeInference(discrim.span)); self.check_expr_has_type(discrim, discrim_ty); }; let discrim_diverges = self.diverges.get(); @@ -407,7 +412,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // of execution reach it, we will panic, so bottom is an appropriate // type in that case) let expected = expected.adjust_for_branches(self); - let mut result_ty = self.next_diverging_ty_var(); + let mut result_ty = self.next_diverging_ty_var( + TypeVariableOrigin::DivergingBlockExpr(expr.span)); let mut all_arms_diverge = Diverges::WarnedAlways; let coerce_first = match expected { // We don't coerce to `()` so that if the match expression is a diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 486f8fc25bb..870c3045e6b 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -13,6 +13,7 @@ use super::{check_fn, Expectation, FnCtxt}; use astconv::AstConv; +use rustc::infer::type_variable::TypeVariableOrigin; use rustc::ty::{self, ToPolyTraitRef, Ty}; use std::cmp; use syntax::abi::Abi; @@ -65,7 +66,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let closure_type = self.tcx.mk_closure(expr_def_id, self.parameter_environment.free_substs.extend_to(self.tcx, expr_def_id, |_, _| span_bug!(expr.span, "closure has region param"), - |_, _| self.infcx.next_ty_var() + |_, _| self.infcx.next_ty_var(TypeVariableOrigin::TransformedUpvar(expr.span)) ) ); diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index b0787d75c9c..5cb0804b1bc 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -20,6 +20,7 @@ use rustc::infer::InferOk; use rustc::ty::subst::{Subst, Substs}; use rustc::traits::{self, ObligationCause}; use rustc::ty::{self, Ty, ToPolyTraitRef, TraitRef, TypeFoldable}; +use rustc::infer::type_variable::TypeVariableOrigin; use rustc::util::nodemap::FxHashSet; use syntax::ast; use syntax_pos::Span; @@ -1225,7 +1226,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let substs = Substs::for_item(self.tcx, impl_def_id, |_, _| self.tcx.mk_region(ty::ReErased), - |_, _| self.next_ty_var()); + |_, _| self.next_ty_var( + TypeVariableOrigin::SubstitutionPlaceholder( + self.tcx.def_span(impl_def_id)))); (impl_ty, substs) } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 7cfefefc0d9..86bfede87b3 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -28,6 +28,7 @@ use syntax_pos::Span; use rustc::hir::print as pprust; use rustc::hir; +use rustc::infer::type_variable::TypeVariableOrigin; use std::cell; use std::cmp::Ordering; @@ -53,7 +54,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.autoderef(span, ty).any(|(ty, _)| { self.probe(|_| { - let fn_once_substs = tcx.mk_substs_trait(ty, &[self.next_ty_var()]); + let fn_once_substs = tcx.mk_substs_trait(ty, + &[self.next_ty_var(TypeVariableOrigin::MiscVariable(span))]); let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs); let poly_trait_ref = trait_ref.to_poly_trait_ref(); let obligation = diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 8d51f52e998..502a93a4aa2 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -85,8 +85,8 @@ use dep_graph::DepNode; use fmt_macros::{Parser, Piece, Position}; use hir::def::{Def, CtorKind}; use hir::def_id::{DefId, LOCAL_CRATE}; -use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin, - TypeTrace, type_variable}; +use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin, TypeTrace}; +use rustc::infer::type_variable::{self, TypeVariableOrigin}; use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal}; use rustc::ty::{ParamTy, ParameterEnvironment}; @@ -117,7 +117,7 @@ use syntax::feature_gate::{GateIssue, emit_feature_err}; use syntax::ptr::P; use syntax::symbol::{Symbol, InternedString, keywords}; use syntax::util::lev_distance::find_best_match_for_name; -use syntax_pos::{self, BytePos, Span}; +use syntax_pos::{self, BytePos, Span, DUMMY_SP}; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::hir::itemlikevisit::ItemLikeVisitor; @@ -683,11 +683,11 @@ struct GatherLocalsVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { } impl<'a, 'gcx, 'tcx> GatherLocalsVisitor<'a, 'gcx, 'tcx> { - fn assign(&mut self, _span: Span, nid: ast::NodeId, ty_opt: Option>) -> Ty<'tcx> { + fn assign(&mut self, span: Span, nid: ast::NodeId, ty_opt: Option>) -> Ty<'tcx> { match ty_opt { None => { // infer the variable's type - let var_ty = self.fcx.next_ty_var(); + let var_ty = self.fcx.next_ty_var(TypeVariableOrigin::TypeInference(span)); self.fcx.locals.borrow_mut().insert(nid, var_ty); var_ty } @@ -1442,8 +1442,8 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { Ok(r) } - fn ty_infer(&self, _span: Span) -> Ty<'tcx> { - self.next_ty_var() + fn ty_infer(&self, span: Span) -> Ty<'tcx> { + self.next_ty_var(TypeVariableOrigin::TypeInference(span)) } fn ty_infer_for_def(&self, @@ -1749,13 +1749,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(ty_var) = self.anon_types.borrow().get(&def_id) { return ty_var; } - let ty_var = self.next_ty_var(); + let span = self.tcx.def_span(def_id); + let ty_var = self.next_ty_var(TypeVariableOrigin::TypeInference(span)); self.anon_types.borrow_mut().insert(def_id, ty_var); let item_predicates = self.tcx.item_predicates(def_id); let bounds = item_predicates.instantiate(self.tcx, substs); - let span = self.tcx.def_span(def_id); for predicate in bounds.predicates { // Change the predicate to refer to the type variable, // which will be the concrete type, instead of the TyAnon. @@ -2202,7 +2202,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let conflicting_default = self.find_conflicting_default(&unbound_tyvars, &default_map, conflict) .unwrap_or(type_variable::Default { - ty: self.next_ty_var(), + ty: self.next_ty_var( + TypeVariableOrigin::MiscVariable(syntax_pos::DUMMY_SP)), origin_span: syntax_pos::DUMMY_SP, // what do I put here? def_id: self.tcx.map.local_def_id(ast::CRATE_NODE_ID) @@ -2396,7 +2397,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { unsize, index_ty); - let input_ty = self.next_ty_var(); + let input_ty = self.next_ty_var(TypeVariableOrigin::AutoDeref(base_expr.span)); // First, try built-in indexing. match (adjusted_ty.builtin_index(), &index_ty.sty) { @@ -3485,8 +3486,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Add adjustments to !-expressions if ty.is_never() { - if let Some(hir::map::NodeExpr(_)) = self.tcx.map.find(expr.id) { - let adj_ty = self.next_diverging_ty_var(); + if let Some(hir::map::NodeExpr(node_expr)) = self.tcx.map.find(expr.id) { + let adj_ty = self.next_diverging_ty_var( + TypeVariableOrigin::AdjustmentType(node_expr.span)); self.write_adjustment(expr.id, adjustment::Adjustment { kind: adjustment::Adjust::NeverToAny, target: adj_ty @@ -3778,7 +3780,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } hir::ExprLoop(ref body, _, _) => { - let unified = self.next_ty_var(); + let unified = self.next_ty_var(TypeVariableOrigin::TypeInference(body.span)); let coerce_to = expected.only_has_type(self).unwrap_or(unified); let ctxt = LoopCtxt { unified: unified, @@ -3857,7 +3859,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }); - let mut unified = self.next_ty_var(); + let mut unified = self.next_ty_var(TypeVariableOrigin::TypeInference(expr.span)); let coerce_to = uty.unwrap_or(unified); for (i, e) in args.iter().enumerate() { @@ -3902,7 +3904,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { (uty, uty) } None => { - let t: Ty = self.next_ty_var(); + let t: Ty = self.next_ty_var(TypeVariableOrigin::MiscVariable(element.span)); let element_ty = self.check_expr_has_type(&element, t); (element_ty, t) } @@ -4151,31 +4153,35 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.diverges.set(Diverges::Maybe); self.has_errors.set(false); - let node_id = match stmt.node { + let (node_id, span) = match stmt.node { hir::StmtDecl(ref decl, id) => { - match decl.node { + let span = match decl.node { hir::DeclLocal(ref l) => { self.check_decl_local(&l); + l.span } - hir::DeclItem(_) => {/* ignore for now */ } - } - id + hir::DeclItem(_) => {/* ignore for now */ + DUMMY_SP + } + }; + (id, span) } hir::StmtExpr(ref expr, id) => { // Check with expected type of () self.check_expr_has_type(&expr, self.tcx.mk_nil()); - id + (id, expr.span) } hir::StmtSemi(ref expr, id) => { self.check_expr(&expr); - id + (id, expr.span) } }; if self.has_errors.get() { self.write_error(node_id); } else if self.diverges.get().always() { - self.write_ty(node_id, self.next_diverging_ty_var()); + self.write_ty(node_id, self.next_diverging_ty_var( + TypeVariableOrigin::DivergingStmt(span))); } else { self.write_nil(node_id); } @@ -4221,7 +4227,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - ty = self.next_diverging_ty_var(); + ty = self.next_diverging_ty_var(TypeVariableOrigin::DivergingBlockExpr(blk.span)); } else if let ExpectHasType(ety) = expected { if let Some(ref e) = blk.expr { // Coerce the tail expression to the right type. diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index adb8c6be42b..d1a9b8ef85a 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -13,6 +13,7 @@ use super::FnCtxt; use hir::def_id::DefId; use rustc::ty::{Ty, TypeFoldable, PreferMutLvalue}; +use rustc::infer::type_variable::TypeVariableOrigin; use syntax::ast; use syntax::symbol::Symbol; use rustc::hir; @@ -179,7 +180,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // using this variable as the expected type, which sometimes lets // us do better coercions than we would be able to do otherwise, // particularly for things like `String + &String`. - let rhs_ty_var = self.next_ty_var(); + let rhs_ty_var = self.next_ty_var(TypeVariableOrigin::MiscVariable(rhs_expr.span)); let return_ty = match self.lookup_op_method(expr, lhs_ty, vec![rhs_ty_var], Symbol::intern(name), trait_def_id, From 9fcb6a2b883d5bee027e78fa462edd0ddc34f62b Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Mon, 28 Nov 2016 10:08:29 -0800 Subject: [PATCH 219/293] Display better error messages for E0282 --- src/librustc/traits/error_reporting.rs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index bed834e237d..205a273df62 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -827,12 +827,26 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { fn need_type_info(&self, span: Span, ty: Ty<'tcx>) { + let ty = self.resolve_type_vars_if_possible(&ty); + let name = if let ty::TyInfer(ty::TyVar(ty_vid)) = ty.sty { + let ty_vars = self.type_variables.borrow(); + if let TypeVariableOrigin::TypeParameterDefinition(_, name) = + *ty_vars.var_origin(ty_vid) + { + name.to_string() + } else { + ty.to_string() + } + } else { + ty.to_string() + }; + let mut err = struct_span_err!(self.tcx.sess, span, E0282, "unable to infer enough type information about `{}`", - ty); + name); err.note("type annotations or generic parameter binding required"); - err.span_label(span, &format!("cannot infer type for `{}`", ty)); - err.emit() + err.span_label(span, &format!("cannot infer type for `{}`", name)); + err.emit(); } fn note_obligation_cause(&self, From 87e76e6ca4647817b88dd897e5447bec26da492d Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Mon, 28 Nov 2016 11:54:47 -0800 Subject: [PATCH 220/293] Update error expectations --- src/test/compile-fail/issue-23046.rs | 2 +- src/test/compile-fail/issue-5062.rs | 2 +- src/test/compile-fail/issue-6458-2.rs | 2 +- src/test/compile-fail/issue-6458-3.rs | 4 ++-- src/test/compile-fail/issue-6458.rs | 4 ++-- src/test/compile-fail/issue-7813.rs | 4 ++-- .../compile-fail/method-ambig-one-trait-unknown-int-type.rs | 2 +- .../compile-fail/traits-multidispatch-convert-ambig-dest.rs | 4 ++-- src/test/compile-fail/unconstrained-none.rs | 4 ++-- src/test/compile-fail/unconstrained-ref.rs | 4 ++-- src/test/compile-fail/vector-no-ann.rs | 4 ++-- src/test/ui/codemap_tests/repair_span_std_macros.stderr | 4 ++-- 12 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/test/compile-fail/issue-23046.rs b/src/test/compile-fail/issue-23046.rs index dba9c32f9b4..c274665530f 100644 --- a/src/test/compile-fail/issue-23046.rs +++ b/src/test/compile-fail/issue-23046.rs @@ -25,6 +25,6 @@ pub fn let_<'var, VAR, F: for<'v: 'var> Fn(Expr<'v, VAR>) -> Expr<'v, VAR>> fn main() { let ex = |x| { - let_(add(x,x), |y| { //~ ERROR unable to infer enough type information about `_` + let_(add(x,x), |y| { //~ ERROR unable to infer enough type information about `VAR` let_(add(x, x), |x|x)})}; } diff --git a/src/test/compile-fail/issue-5062.rs b/src/test/compile-fail/issue-5062.rs index f5aa4fadbed..cf78d6d8c0a 100644 --- a/src/test/compile-fail/issue-5062.rs +++ b/src/test/compile-fail/issue-5062.rs @@ -9,4 +9,4 @@ // except according to those terms. fn main() { format!("{:?}", None); } - //~^ ERROR unable to infer enough type information about `_` [E0282] + //~^ ERROR unable to infer enough type information about `T` [E0282] diff --git a/src/test/compile-fail/issue-6458-2.rs b/src/test/compile-fail/issue-6458-2.rs index 71f28054579..3816896d43d 100644 --- a/src/test/compile-fail/issue-6458-2.rs +++ b/src/test/compile-fail/issue-6458-2.rs @@ -11,5 +11,5 @@ fn main() { // Unconstrained type: format!("{:?}", None); - //~^ ERROR unable to infer enough type information about `_` [E0282] + //~^ ERROR unable to infer enough type information about `T` [E0282] } diff --git a/src/test/compile-fail/issue-6458-3.rs b/src/test/compile-fail/issue-6458-3.rs index e397805565b..8029522f5d3 100644 --- a/src/test/compile-fail/issue-6458-3.rs +++ b/src/test/compile-fail/issue-6458-3.rs @@ -12,7 +12,7 @@ use std::mem; fn main() { mem::transmute(0); - //~^ ERROR unable to infer enough type information about `_` [E0282] - //~| NOTE cannot infer type for `_` + //~^ ERROR unable to infer enough type information about `U` [E0282] + //~| NOTE cannot infer type for `U` //~| NOTE type annotations or generic parameter binding } diff --git a/src/test/compile-fail/issue-6458.rs b/src/test/compile-fail/issue-6458.rs index a64522a0e5b..f8354ddbf12 100644 --- a/src/test/compile-fail/issue-6458.rs +++ b/src/test/compile-fail/issue-6458.rs @@ -17,8 +17,8 @@ pub fn foo(_: TypeWithState) {} pub fn bar() { foo(TypeWithState(marker::PhantomData)); - //~^ ERROR unable to infer enough type information about `_` [E0282] - //~| NOTE cannot infer type for `_` + //~^ ERROR unable to infer enough type information about `State` [E0282] + //~| NOTE cannot infer type for `State` //~| NOTE type annotations or generic parameter binding } diff --git a/src/test/compile-fail/issue-7813.rs b/src/test/compile-fail/issue-7813.rs index e3cb1d0c7da..e37a8816423 100644 --- a/src/test/compile-fail/issue-7813.rs +++ b/src/test/compile-fail/issue-7813.rs @@ -10,7 +10,7 @@ fn main() { let v = &[]; - let it = v.iter(); //~ ERROR unable to infer enough type information about `_` [E0282] - //~| NOTE cannot infer type for `_` + let it = v.iter(); //~ ERROR unable to infer enough type information about `T` [E0282] + //~| NOTE cannot infer type for `T` //~| NOTE type annotations or generic parameter binding } diff --git a/src/test/compile-fail/method-ambig-one-trait-unknown-int-type.rs b/src/test/compile-fail/method-ambig-one-trait-unknown-int-type.rs index 4f86909765e..1cf41f95a2d 100644 --- a/src/test/compile-fail/method-ambig-one-trait-unknown-int-type.rs +++ b/src/test/compile-fail/method-ambig-one-trait-unknown-int-type.rs @@ -32,7 +32,7 @@ impl foo for Vec { fn m1() { // we couldn't infer the type of the vector just based on calling foo()... let mut x = Vec::new(); - //~^ ERROR unable to infer enough type information about `_` [E0282] + //~^ ERROR unable to infer enough type information about `T` [E0282] x.foo(); } diff --git a/src/test/compile-fail/traits-multidispatch-convert-ambig-dest.rs b/src/test/compile-fail/traits-multidispatch-convert-ambig-dest.rs index e6545063dbd..ed2ffa995e5 100644 --- a/src/test/compile-fail/traits-multidispatch-convert-ambig-dest.rs +++ b/src/test/compile-fail/traits-multidispatch-convert-ambig-dest.rs @@ -34,8 +34,8 @@ where T : Convert fn a() { test(22, std::default::Default::default()); - //~^ ERROR unable to infer enough type information about `_` [E0282] - //~| NOTE cannot infer type for `_` + //~^ ERROR unable to infer enough type information about `U` [E0282] + //~| NOTE cannot infer type for `U` //~| NOTE type annotations or generic parameter binding } diff --git a/src/test/compile-fail/unconstrained-none.rs b/src/test/compile-fail/unconstrained-none.rs index 380cdd266cd..88080bc70ca 100644 --- a/src/test/compile-fail/unconstrained-none.rs +++ b/src/test/compile-fail/unconstrained-none.rs @@ -11,7 +11,7 @@ // Issue #5062 fn main() { - None; //~ ERROR unable to infer enough type information about `_` [E0282] - //~| NOTE cannot infer type for `_` + None; //~ ERROR unable to infer enough type information about `T` [E0282] + //~| NOTE cannot infer type for `T` //~| NOTE type annotations or generic parameter binding } diff --git a/src/test/compile-fail/unconstrained-ref.rs b/src/test/compile-fail/unconstrained-ref.rs index ba94bf613d2..12278549215 100644 --- a/src/test/compile-fail/unconstrained-ref.rs +++ b/src/test/compile-fail/unconstrained-ref.rs @@ -13,7 +13,7 @@ struct S<'a, T:'a> { } fn main() { - S { o: &None }; //~ ERROR unable to infer enough type information about `_` [E0282] - //~| NOTE cannot infer type for `_` + S { o: &None }; //~ ERROR unable to infer enough type information about `T` [E0282] + //~| NOTE cannot infer type for `T` //~| NOTE type annotations or generic parameter binding } diff --git a/src/test/compile-fail/vector-no-ann.rs b/src/test/compile-fail/vector-no-ann.rs index 25709f35246..d559caf77a1 100644 --- a/src/test/compile-fail/vector-no-ann.rs +++ b/src/test/compile-fail/vector-no-ann.rs @@ -11,7 +11,7 @@ fn main() { let _foo = Vec::new(); - //~^ ERROR unable to infer enough type information about `_` [E0282] - //~| NOTE cannot infer type for `_` + //~^ ERROR unable to infer enough type information about `T` [E0282] + //~| NOTE cannot infer type for `T` //~| NOTE type annotations or generic parameter binding } diff --git a/src/test/ui/codemap_tests/repair_span_std_macros.stderr b/src/test/ui/codemap_tests/repair_span_std_macros.stderr index 73a1c5bae85..7e0d778a3b2 100644 --- a/src/test/ui/codemap_tests/repair_span_std_macros.stderr +++ b/src/test/ui/codemap_tests/repair_span_std_macros.stderr @@ -1,8 +1,8 @@ -error[E0282]: unable to infer enough type information about `_` +error[E0282]: unable to infer enough type information about `T` --> $DIR/repair_span_std_macros.rs:12:13 | 12 | let x = vec![]; - | ^^^^^^ cannot infer type for `_` + | ^^^^^^ cannot infer type for `T` | = note: type annotations or generic parameter binding required = note: this error originates in a macro outside of the current crate From 6774e7aa92f5866657f778f08261c0fe219f01a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Sat, 3 Dec 2016 18:58:21 +0100 Subject: [PATCH 221/293] OpenBSD under x86 has particular ABI for returning a struct. It is like OSX or Windows: small structs are returned as integers. --- src/librustc_back/target/mod.rs | 6 ++++++ src/librustc_back/target/openbsd_base.rs | 1 + src/librustc_trans/cabi_x86.rs | 3 ++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 496ba6cba18..351d469ea28 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -302,6 +302,9 @@ pub struct TargetOptions { pub staticlib_suffix: String, /// OS family to use for conditional compilation. Valid options: "unix", "windows". pub target_family: Option, + /// Whether the target toolchain is like OpenBSD's. + /// Only useful for compiling against OpenBSD, for configuring abi when returning a struct. + pub is_like_openbsd: bool, /// Whether the target toolchain is like OSX's. Only useful for compiling against iOS/OS X, in /// particular running dsymutil and some other stuff like `-dead_strip`. Defaults to false. pub is_like_osx: bool, @@ -406,6 +409,7 @@ impl Default for TargetOptions { staticlib_prefix: "lib".to_string(), staticlib_suffix: ".a".to_string(), target_family: None, + is_like_openbsd: false, is_like_osx: false, is_like_solaris: false, is_like_windows: false, @@ -572,6 +576,7 @@ impl Target { key!(staticlib_prefix); key!(staticlib_suffix); key!(target_family, optional); + key!(is_like_openbsd, bool); key!(is_like_osx, bool); key!(is_like_solaris, bool); key!(is_like_windows, bool); @@ -733,6 +738,7 @@ impl ToJson for Target { target_option_val!(staticlib_prefix); target_option_val!(staticlib_suffix); target_option_val!(target_family); + target_option_val!(is_like_openbsd); target_option_val!(is_like_osx); target_option_val!(is_like_solaris); target_option_val!(is_like_windows); diff --git a/src/librustc_back/target/openbsd_base.rs b/src/librustc_back/target/openbsd_base.rs index 90e6631841b..1f74170e399 100644 --- a/src/librustc_back/target/openbsd_base.rs +++ b/src/librustc_back/target/openbsd_base.rs @@ -17,6 +17,7 @@ pub fn opts() -> TargetOptions { executables: true, linker_is_gnu: true, has_rpath: true, + is_like_openbsd: true, pre_link_args: vec![ // GNU-style linkers will use this to omit linking to libraries // which don't actually fulfill any relocations, but only for diff --git a/src/librustc_trans/cabi_x86.rs b/src/librustc_trans/cabi_x86.rs index 5377b49a2b4..ce85234f203 100644 --- a/src/librustc_trans/cabi_x86.rs +++ b/src/librustc_trans/cabi_x86.rs @@ -25,7 +25,8 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { // http://www.angelcode.com/dev/callconv/callconv.html // Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp let t = &ccx.sess().target.target; - if t.options.is_like_osx || t.options.is_like_windows { + if t.options.is_like_osx || t.options.is_like_windows + || t.options.is_like_openbsd { match llsize_of_alloc(ccx, fty.ret.ty) { 1 => fty.ret.cast = Some(Type::i8(ccx)), 2 => fty.ret.cast = Some(Type::i16(ccx)), From b5ea8c00a3927acbee9452d2623b28b076bfc6c4 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 4 Dec 2016 00:48:11 -0800 Subject: [PATCH 222/293] Fix small typo --- src/libstd/sys/unix/ext/io.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/sys/unix/ext/io.rs b/src/libstd/sys/unix/ext/io.rs index 4163ede46af..296235e173d 100644 --- a/src/libstd/sys/unix/ext/io.rs +++ b/src/libstd/sys/unix/ext/io.rs @@ -43,7 +43,7 @@ pub trait AsRawFd { /// descriptor. #[stable(feature = "from_raw_os", since = "1.1.0")] pub trait FromRawFd { - /// Constructs a new instances of `Self` from the given raw file + /// Constructs a new instance of `Self` from the given raw file /// descriptor. /// /// This function **consumes ownership** of the specified file From 257f643ee327252a4cd6dba25f64ac3768adcb45 Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Fri, 25 Nov 2016 19:17:21 +1100 Subject: [PATCH 223/293] Disable ICF opt of MSVC for non-opt build --- src/librustc_trans/back/linker.rs | 11 ++++++++++- src/test/run-make/codegen-options-parsing/Makefile | 4 ++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index 860903d259f..0080dfb7eca 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -320,7 +320,16 @@ impl<'a> Linker for MsvcLinker<'a> { } fn gc_sections(&mut self, _keep_metadata: bool) { - self.cmd.arg("/OPT:REF,ICF"); + // MSVC's ICF (Identical COMDAT Folding) link optimization is + // slow for Rust and thus we disable it by default when not in + // optimization build. + if self.sess.opts.optimize != config::OptLevel::No { + self.cmd.arg("/OPT:REF,ICF"); + } else { + // It is necessary to specify NOICF here, because /OPT:REF + // implies ICF by default. + self.cmd.arg("/OPT:REF,NOICF"); + } } fn link_dylib(&mut self, lib: &str) { diff --git a/src/test/run-make/codegen-options-parsing/Makefile b/src/test/run-make/codegen-options-parsing/Makefile index 9543fad8e53..2b8b0712cc7 100644 --- a/src/test/run-make/codegen-options-parsing/Makefile +++ b/src/test/run-make/codegen-options-parsing/Makefile @@ -25,7 +25,7 @@ all: # Should not link dead code... $(RUSTC) -Z print-link-args dummy.rs 2>&1 | \ - grep -e '--gc-sections' -e '-dead_strip' -e '/OPT:REF,ICF' + grep -e '--gc-sections' -e '-dead_strip' -e '/OPT:REF' # ... unless you specifically ask to keep it $(RUSTC) -Z print-link-args -C link-dead-code dummy.rs 2>&1 | \ - (! grep -e '--gc-sections' -e '-dead_strip' -e '/OPT:REF,ICF') + (! grep -e '--gc-sections' -e '-dead_strip' -e '/OPT:REF') From dd3e63aea5680b8c55a165d51691b426b86d657a Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Sat, 3 Dec 2016 21:43:51 +0100 Subject: [PATCH 224/293] core: Forward ExactSizeIterator::is_empty for Bytes --- src/libcore/str/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index b4cd52e59f6..de418b831cc 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -618,6 +618,11 @@ impl<'a> ExactSizeIterator for Bytes<'a> { fn len(&self) -> usize { self.0.len() } + + #[inline] + fn is_empty(&self) -> bool { + self.0.is_empty() + } } #[unstable(feature = "fused", issue = "35602")] From 7ba762253ccf487ae61b2be45a9edfdf19b79cc0 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Sat, 3 Dec 2016 21:59:00 +0100 Subject: [PATCH 225/293] std: Forward ExactSizeIterator::is_empty for Args, ArgsOs iterators --- src/libstd/env.rs | 2 ++ src/libstd/lib.rs | 1 + 2 files changed, 3 insertions(+) diff --git a/src/libstd/env.rs b/src/libstd/env.rs index baa2b5d2846..ee6a907f616 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -630,6 +630,7 @@ impl Iterator for Args { #[stable(feature = "env", since = "1.0.0")] impl ExactSizeIterator for Args { fn len(&self) -> usize { self.inner.len() } + fn is_empty(&self) -> bool { self.inner.is_empty() } } #[stable(feature = "env_iterators", since = "1.11.0")] @@ -649,6 +650,7 @@ impl Iterator for ArgsOs { #[stable(feature = "env", since = "1.0.0")] impl ExactSizeIterator for ArgsOs { fn len(&self) -> usize { self.inner.len() } + fn is_empty(&self) -> bool { self.inner.is_empty() } } #[stable(feature = "env_iterators", since = "1.11.0")] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 8132b139260..1f40d3fd1d3 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -250,6 +250,7 @@ #![feature(core_float)] #![feature(core_intrinsics)] #![feature(dropck_parametricity)] +#![feature(exact_size_is_empty)] #![feature(float_extras)] #![feature(float_from_str_radix)] #![feature(fn_traits)] From 343b4c321d9ab0e1efc7953a15ee0dbc62c722a9 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Sat, 3 Dec 2016 22:11:06 +0100 Subject: [PATCH 226/293] collections: Simplify VecDeque::is_empty Improve is_empty on the VecDeque and its iterators by just comparing tail and head; this saves a few instructions (to be able to remove the `& (size - 1)` computation, it would have to know that size is a power of two). --- src/libcollections/vec_deque.rs | 20 ++++++++++++++++---- src/libcollectionstest/vec_deque.rs | 21 +++++++++++++++++++++ 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 5397193cab4..dbe3fec205c 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -810,7 +810,7 @@ impl VecDeque { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn is_empty(&self) -> bool { - self.len() == 0 + self.tail == self.head } /// Create a draining iterator that removes the specified range in the @@ -1916,7 +1916,11 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> ExactSizeIterator for Iter<'a, T> {} +impl<'a, T> ExactSizeIterator for Iter<'a, T> { + fn is_empty(&self) -> bool { + self.head == self.tail + } +} #[unstable(feature = "fused", issue = "35602")] impl<'a, T> FusedIterator for Iter<'a, T> {} @@ -1980,7 +1984,11 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> ExactSizeIterator for IterMut<'a, T> {} +impl<'a, T> ExactSizeIterator for IterMut<'a, T> { + fn is_empty(&self) -> bool { + self.head == self.tail + } +} #[unstable(feature = "fused", issue = "35602")] impl<'a, T> FusedIterator for IterMut<'a, T> {} @@ -2017,7 +2025,11 @@ impl DoubleEndedIterator for IntoIter { } #[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for IntoIter {} +impl ExactSizeIterator for IntoIter { + fn is_empty(&self) -> bool { + self.inner.is_empty() + } +} #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for IntoIter {} diff --git a/src/libcollectionstest/vec_deque.rs b/src/libcollectionstest/vec_deque.rs index f1ea85a6c5b..cdf022e4f02 100644 --- a/src/libcollectionstest/vec_deque.rs +++ b/src/libcollectionstest/vec_deque.rs @@ -1007,3 +1007,24 @@ fn assert_covariance() { d } } + +#[test] +fn test_is_empty() { + let mut v = VecDeque::::new(); + assert!(v.is_empty()); + assert!(v.iter().is_empty()); + assert!(v.iter_mut().is_empty()); + v.extend(&[2, 3, 4]); + assert!(!v.is_empty()); + assert!(!v.iter().is_empty()); + assert!(!v.iter_mut().is_empty()); + while let Some(_) = v.pop_front() { + assert_eq!(v.is_empty(), v.len() == 0); + assert_eq!(v.iter().is_empty(), v.iter().len() == 0); + assert_eq!(v.iter_mut().is_empty(), v.iter_mut().len() == 0); + } + assert!(v.is_empty()); + assert!(v.iter().is_empty()); + assert!(v.iter_mut().is_empty()); + assert!(v.into_iter().is_empty()); +} From 28852c3c7cec558307e4bd775127c08816ab3c3f Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Sat, 3 Dec 2016 22:44:57 +0100 Subject: [PATCH 227/293] binary_heap: Forward ExactSizeIterator::is_empty --- src/libcollections/binary_heap.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index b4be8a43213..8d0c76c3646 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -986,7 +986,11 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> ExactSizeIterator for Iter<'a, T> {} +impl<'a, T> ExactSizeIterator for Iter<'a, T> { + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} #[unstable(feature = "fused", issue = "35602")] impl<'a, T> FusedIterator for Iter<'a, T> {} @@ -1022,7 +1026,11 @@ impl DoubleEndedIterator for IntoIter { } #[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for IntoIter {} +impl ExactSizeIterator for IntoIter { + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for IntoIter {} @@ -1057,7 +1065,11 @@ impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> { } #[stable(feature = "drain", since = "1.6.0")] -impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> {} +impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> { + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} #[unstable(feature = "fused", issue = "35602")] impl<'a, T: 'a> FusedIterator for Drain<'a, T> {} From 705e295b7b93c0861c9d8af4177f6701126683a9 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Sat, 3 Dec 2016 22:47:33 +0100 Subject: [PATCH 228/293] iter: Forward ExactSizeIterator methods for &mut I --- src/libcore/iter/traits.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index e94582cda7c..c5465549adf 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -552,7 +552,14 @@ pub trait ExactSizeIterator: Iterator { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, I: ExactSizeIterator + ?Sized> ExactSizeIterator for &'a mut I {} +impl<'a, I: ExactSizeIterator + ?Sized> ExactSizeIterator for &'a mut I { + fn len(&self) -> usize { + (**self).len() + } + fn is_empty(&self) -> bool { + (**self).is_empty() + } +} /// Trait to represent types that can be created by summing up an iterator. /// From d53f82c1d037bf224a72a11747e7788f14b52db5 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Sat, 3 Dec 2016 21:42:03 +0100 Subject: [PATCH 229/293] alloc: Forward ExactSizeIterator methods in Iterator for Box --- src/liballoc/boxed.rs | 9 ++++++++- src/liballoc/lib.rs | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 28f4dda1408..6d7a9b1d1f9 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -532,7 +532,14 @@ impl DoubleEndedIterator for Box { } } #[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Box {} +impl ExactSizeIterator for Box { + fn len(&self) -> usize { + (**self).len() + } + fn is_empty(&self) -> bool { + (**self).is_empty() + } +} #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for Box {} diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 0d450184ed8..acce4ce0358 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -79,6 +79,7 @@ #![feature(core_intrinsics)] #![feature(custom_attribute)] #![feature(dropck_parametricity)] +#![cfg_attr(not(test), feature(exact_size_is_empty))] #![feature(fundamental)] #![feature(lang_items)] #![feature(needs_allocator)] From d5f6125fb32078d3331f4c2fddfbcfa303e82232 Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Thu, 17 Nov 2016 09:10:19 -0500 Subject: [PATCH 230/293] [LLVM 4.0] New bitcode headers and API --- src/rustllvm/RustWrapper.cpp | 17 ++++++++++++++++- src/rustllvm/rustllvm.h | 8 +++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 51859a928c4..a6334cf479f 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -892,19 +892,34 @@ extern "C" void LLVMRustWriteValueToString(LLVMValueRef Value, RustStringRef str extern "C" bool LLVMRustLinkInExternalBitcode(LLVMModuleRef dst, char *bc, size_t len) { Module *Dst = unwrap(dst); + std::unique_ptr buf = MemoryBuffer::getMemBufferCopy(StringRef(bc, len)); + +#if LLVM_VERSION_GE(4, 0) + Expected> SrcOrError = + llvm::getLazyBitcodeModule(buf->getMemBufferRef(), Dst->getContext()); + if (!SrcOrError) { + LLVMRustSetLastError(toString(SrcOrError.takeError()).c_str()); + return false; + } + + auto Src = std::move(*SrcOrError); +#else ErrorOr> Src = llvm::getLazyBitcodeModule(std::move(buf), Dst->getContext()); if (!Src) { LLVMRustSetLastError(Src.getError().message().c_str()); return false; } +#endif std::string Err; raw_string_ostream Stream(Err); DiagnosticPrinterRawOStream DP(Stream); -#if LLVM_VERSION_GE(3, 8) +#if LLVM_VERSION_GE(4, 0) + if (Linker::linkModules(*Dst, std::move(Src))) { +#elif LLVM_VERSION_GE(3, 8) if (Linker::linkModules(*Dst, std::move(Src.get()))) { #else if (Linker::LinkModules(Dst, Src->get(), [&](const DiagnosticInfo &DI) { DI.print(DP); })) { diff --git a/src/rustllvm/rustllvm.h b/src/rustllvm/rustllvm.h index 346153d578c..b8c4076f4ce 100644 --- a/src/rustllvm/rustllvm.h +++ b/src/rustllvm/rustllvm.h @@ -39,7 +39,6 @@ #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/Instrumentation.h" #include "llvm/Transforms/Vectorize.h" -#include "llvm/Bitcode/ReaderWriter.h" #include "llvm-c/Core.h" #include "llvm-c/BitReader.h" #include "llvm-c/ExecutionEngine.h" @@ -60,6 +59,13 @@ #include "llvm/PassManager.h" #endif +#if LLVM_VERSION_GE(4, 0) +#include "llvm/Bitcode/BitcodeReader.h" +#include "llvm/Bitcode/BitcodeWriter.h" +#else +#include "llvm/Bitcode/ReaderWriter.h" +#endif + #include "llvm/IR/IRPrintingPasses.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DIBuilder.h" From dbfcdd45c607762ee8371494ce8a6326086a9596 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Sun, 4 Dec 2016 15:56:51 -0500 Subject: [PATCH 231/293] reference: fix definition of :tt The reference says that $x:tt matches "either side of the `=>` in macro_rules` which is technically true but completely uninformative. This changes that bullet point to what the book says (a single token or sequence of token trees inside brackets). --- src/doc/reference.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/reference.md b/src/doc/reference.md index 8655bab4b21..5d20738a1e3 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -603,7 +603,8 @@ syntax named by _designator_. Valid designators are: * `ty`: a [type](#types) * `ident`: an [identifier](#identifiers) * `path`: a [path](#paths) -* `tt`: either side of the `=>` in macro rules +* `tt`: a token tree (a single [token](#tokens) or a sequence of token trees surrounded + by matching `()`, `[]`, or `{}`) * `meta`: the contents of an [attribute](#attributes) In the transcriber, the From 55180d04f22b6a01db6f8b212fdf4aaf3d0f7a6a Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Mon, 5 Dec 2016 00:41:13 +0200 Subject: [PATCH 232/293] erase lifetimes when translating specialized substs Projections can generate lifetime variables with equality constraints, that will not be resolved by `resolve_type_vars_if_possible`, so substs need to be lifetime-erased after that. Fixes #36848. --- src/librustc/traits/specialize/mod.rs | 1 + ...on-translate-projections-with-lifetimes.rs | 41 +++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 src/test/run-pass/specialization/specialization-translate-projections-with-lifetimes.rs diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 870494363c8..59e3d398b2f 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -127,6 +127,7 @@ pub fn find_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs); let substs = translate_substs(&infcx, impl_data.impl_def_id, substs, node_item.node); + let substs = infcx.tcx.erase_regions(&substs); tcx.lift(&substs).unwrap_or_else(|| { bug!("find_method: translate_substs \ returned {:?} which contains inference types/regions", diff --git a/src/test/run-pass/specialization/specialization-translate-projections-with-lifetimes.rs b/src/test/run-pass/specialization/specialization-translate-projections-with-lifetimes.rs new file mode 100644 index 00000000000..9702f632413 --- /dev/null +++ b/src/test/run-pass/specialization/specialization-translate-projections-with-lifetimes.rs @@ -0,0 +1,41 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(specialization)] + +trait Iterator { + fn next(&self); +} + +trait WithAssoc { + type Item; +} + +impl<'a> WithAssoc for &'a () { + type Item = &'a u32; +} + +struct Cloned(I); + +impl<'a, I, T: 'a> Iterator for Cloned + where I: WithAssoc, T: Clone +{ + fn next(&self) {} +} + +impl<'a, I, T: 'a> Iterator for Cloned + where I: WithAssoc, T: Copy +{ + +} + +fn main() { + Cloned(&()).next(); +} From d9b5ae992450d26098e7d81aa3868ef808595582 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 1 Dec 2016 17:29:53 -0800 Subject: [PATCH 233/293] Add missing examples for panicking objects --- src/libstd/panicking.rs | 106 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 104 insertions(+), 2 deletions(-) diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 04050a5edc4..45a10d24528 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -159,6 +159,23 @@ pub fn take_hook() -> Box { } /// A struct providing information about a panic. +/// +/// `PanicInfo` structure is passed to a panic hook set by the [`set_hook()`] +/// function. +/// +/// [`set_hook()`]: ../../std/panic/fn.set_hook.html +/// +/// # Examples +/// +/// ```should_panic +/// use std::panic; +/// +/// panic::set_hook(Box::new(|panic_info| { +/// println!("panic occured: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap()); +/// })); +/// +/// panic!("Normal panic"); +/// ``` #[stable(feature = "panic_hooks", since = "1.10.0")] pub struct PanicInfo<'a> { payload: &'a (Any + Send), @@ -168,7 +185,21 @@ pub struct PanicInfo<'a> { impl<'a> PanicInfo<'a> { /// Returns the payload associated with the panic. /// - /// This will commonly, but not always, be a `&'static str` or `String`. + /// This will commonly, but not always, be a `&'static str` or [`String`]. + /// + /// [`String`]: ../../std/string/struct.String.html + /// + /// # Examples + /// + /// ```should_panic + /// use std::panic; + /// + /// panic::set_hook(Box::new(|panic_info| { + /// println!("panic occured: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap()); + /// })); + /// + /// panic!("Normal panic"); + /// ``` #[stable(feature = "panic_hooks", since = "1.10.0")] pub fn payload(&self) -> &(Any + Send) { self.payload @@ -177,8 +208,26 @@ impl<'a> PanicInfo<'a> { /// Returns information about the location from which the panic originated, /// if available. /// - /// This method will currently always return `Some`, but this may change + /// This method will currently always return [`Some`], but this may change /// in future versions. + /// + /// [`Some`]: ../../std/option/enum.Option.html#variant.Some + /// + /// # Examples + /// + /// ```should_panic + /// use std::panic; + /// + /// panic::set_hook(Box::new(|panic_info| { + /// if let Some(location) = panic_info.location() { + /// println!("panic occured in file '{}' at line {}", location.file(), location.line()); + /// } else { + /// println!("panic occured but can't get location information..."); + /// } + /// })); + /// + /// panic!("Normal panic"); + /// ``` #[stable(feature = "panic_hooks", since = "1.10.0")] pub fn location(&self) -> Option<&Location> { Some(&self.location) @@ -186,6 +235,27 @@ impl<'a> PanicInfo<'a> { } /// A struct containing information about the location of a panic. +/// +/// This structure is created by the [`location()`] method of [`PanicInfo`]. +/// +/// [`location()`]: ../../std/panic/struct.PanicInfo.html#method.location +/// [`PanicInfo`]: ../../std/panic/struct.PanicInfo.html +/// +/// # Examples +/// +/// ```should_panic +/// use std::panic; +/// +/// panic::set_hook(Box::new(|panic_info| { +/// if let Some(location) = panic_info.location() { +/// println!("panic occured in file '{}' at line {}", location.file(), location.line()); +/// } else { +/// println!("panic occured but can't get location information..."); +/// } +/// })); +/// +/// panic!("Normal panic"); +/// ``` #[stable(feature = "panic_hooks", since = "1.10.0")] pub struct Location<'a> { file: &'a str, @@ -194,12 +264,44 @@ pub struct Location<'a> { impl<'a> Location<'a> { /// Returns the name of the source file from which the panic originated. + /// + /// # Examples + /// + /// ```should_panic + /// use std::panic; + /// + /// panic::set_hook(Box::new(|panic_info| { + /// if let Some(location) = panic_info.location() { + /// println!("panic occured in file '{}'", location.file()); + /// } else { + /// println!("panic occured but can't get location information..."); + /// } + /// })); + /// + /// panic!("Normal panic"); + /// ``` #[stable(feature = "panic_hooks", since = "1.10.0")] pub fn file(&self) -> &str { self.file } /// Returns the line number from which the panic originated. + /// + /// # Examples + /// + /// ```should_panic + /// use std::panic; + /// + /// panic::set_hook(Box::new(|panic_info| { + /// if let Some(location) = panic_info.location() { + /// println!("panic occured at line {}", location.line()); + /// } else { + /// println!("panic occured but can't get location information..."); + /// } + /// })); + /// + /// panic!("Normal panic"); + /// ``` #[stable(feature = "panic_hooks", since = "1.10.0")] pub fn line(&self) -> u32 { self.line From d1a6d47f943d8df9d565de835babc1e2f3e8d45a Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 28 Nov 2016 17:44:51 -0500 Subject: [PATCH 234/293] Make LLVM symbol visibility FFI types more stable. --- src/librustc_llvm/ffi.rs | 19 +++++++++------- src/librustc_trans/declare.rs | 2 +- src/rustllvm/RustWrapper.cpp | 42 +++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 9 deletions(-) diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index b8f1540ad84..d2592a3acee 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -64,6 +64,15 @@ pub enum Linkage { CommonLinkage = 10, } +// LLVMRustVisibility +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[repr(C)] +pub enum Visibility { + Default = 0, + Hidden = 1, + Protected = 2, +} + /// LLVMDiagnosticSeverity #[derive(Copy, Clone, Debug)] #[repr(C)] @@ -399,13 +408,6 @@ pub type OperandBundleDefRef = *mut OperandBundleDef_opaque; pub type DiagnosticHandler = unsafe extern "C" fn(DiagnosticInfoRef, *mut c_void); pub type InlineAsmDiagHandler = unsafe extern "C" fn(SMDiagnosticRef, *const c_void, c_uint); -/// LLVMVisibility -#[repr(C)] -pub enum Visibility { - Default, - Hidden, - Protected, -} pub mod debuginfo { use super::MetadataRef; @@ -655,7 +657,8 @@ extern "C" { pub fn LLVMRustSetLinkage(Global: ValueRef, RustLinkage: Linkage); pub fn LLVMGetSection(Global: ValueRef) -> *const c_char; pub fn LLVMSetSection(Global: ValueRef, Section: *const c_char); - pub fn LLVMSetVisibility(Global: ValueRef, Viz: Visibility); + pub fn LLVMRustGetVisibility(Global: ValueRef) -> Visibility; + pub fn LLVMRustSetVisibility(Global: ValueRef, Viz: Visibility); pub fn LLVMGetAlignment(Global: ValueRef) -> c_uint; pub fn LLVMSetAlignment(Global: ValueRef, Bytes: c_uint); pub fn LLVMSetDLLStorageClass(V: ValueRef, C: DLLStorageClass); diff --git a/src/librustc_trans/declare.rs b/src/librustc_trans/declare.rs index 7d6a672077a..eef3b9b1147 100644 --- a/src/librustc_trans/declare.rs +++ b/src/librustc_trans/declare.rs @@ -78,7 +78,7 @@ fn declare_raw_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, ty: // don't want the symbols to get exported. if attr::contains_name(ccx.tcx().map.krate_attrs(), "compiler_builtins") { unsafe { - llvm::LLVMSetVisibility(llfn, llvm::Visibility::Hidden); + llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); } } diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 51859a928c4..6a95b65d5e9 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -1408,3 +1408,45 @@ extern "C" void LLVMRustSetLinkage(LLVMValueRef V, LLVMRustLinkage RustLinkage) extern "C" LLVMContextRef LLVMRustGetValueContext(LLVMValueRef V) { return wrap(&unwrap(V)->getContext()); } + +enum class LLVMRustVisibility { + Default = 0, + Hidden = 1, + Protected = 2, +}; + +static LLVMRustVisibility to_rust(LLVMVisibility vis) { + switch (vis) { + case LLVMDefaultVisibility: + return LLVMRustVisibility::Default; + case LLVMHiddenVisibility: + return LLVMRustVisibility::Hidden; + case LLVMProtectedVisibility: + return LLVMRustVisibility::Protected; + + default: + llvm_unreachable("Invalid LLVMRustVisibility value!"); + } +} + +static LLVMVisibility from_rust(LLVMRustVisibility vis) { + switch (vis) { + case LLVMRustVisibility::Default: + return LLVMDefaultVisibility; + case LLVMRustVisibility::Hidden: + return LLVMHiddenVisibility; + case LLVMRustVisibility::Protected: + return LLVMProtectedVisibility; + + default: + llvm_unreachable("Invalid LLVMRustVisibility value!"); + } +} + +extern "C" LLVMRustVisibility LLVMRustGetVisibility(LLVMValueRef V) { + return to_rust(LLVMGetVisibility(V)); +} + +extern "C" void LLVMRustSetVisibility(LLVMValueRef V, LLVMRustVisibility RustVisibility) { + LLVMSetVisibility(V, from_rust(RustVisibility)); +} From 5fd7c2bfef50e00fdd6b2f5dc07b17c2c324f396 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 28 Nov 2016 18:05:53 -0500 Subject: [PATCH 235/293] trans: Rename `reachable` to `exported_symbols` where appropriate. --- src/librustc/middle/cstore.rs | 4 +-- src/librustc_metadata/cstore_impl.rs | 4 +-- src/librustc_metadata/decoder.rs | 4 +-- src/librustc_metadata/encoder.rs | 24 +++++++++--------- src/librustc_metadata/schema.rs | 2 +- src/librustc_trans/back/linker.rs | 10 ++++---- src/librustc_trans/back/lto.rs | 6 ++--- src/librustc_trans/back/write.rs | 14 +++++------ src/librustc_trans/base.rs | 36 +++++++++++++-------------- src/librustc_trans/context.rs | 16 ++++++------ src/librustc_trans/debuginfo/utils.rs | 2 +- src/librustc_trans/lib.rs | 2 +- 12 files changed, 62 insertions(+), 62 deletions(-) diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 822fb4d6770..34224b924b9 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -329,7 +329,7 @@ pub trait CrateStore<'tcx> { fn crate_disambiguator(&self, cnum: CrateNum) -> Symbol; fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option; fn native_libraries(&self, cnum: CrateNum) -> Vec; - fn reachable_ids(&self, cnum: CrateNum) -> Vec; + fn exported_symbols(&self, cnum: CrateNum) -> Vec; fn is_no_builtins(&self, cnum: CrateNum) -> bool; // resolve @@ -493,7 +493,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { { bug!("plugin_registrar_fn") } fn native_libraries(&self, cnum: CrateNum) -> Vec { bug!("native_libraries") } - fn reachable_ids(&self, cnum: CrateNum) -> Vec { bug!("reachable_ids") } + fn exported_symbols(&self, cnum: CrateNum) -> Vec { bug!("exported_symbols") } fn is_no_builtins(&self, cnum: CrateNum) -> bool { bug!("is_no_builtins") } // resolve diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 3150f74e61e..2965e545eca 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -311,9 +311,9 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { self.get_crate_data(cnum).get_native_libraries() } - fn reachable_ids(&self, cnum: CrateNum) -> Vec + fn exported_symbols(&self, cnum: CrateNum) -> Vec { - self.get_crate_data(cnum).get_reachable_ids() + self.get_crate_data(cnum).get_exported_symbols() } fn is_no_builtins(&self, cnum: CrateNum) -> bool { diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index fe536b69c61..43635eae76c 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1038,8 +1038,8 @@ impl<'a, 'tcx> CrateMetadata { arg_names.decode(self).collect() } - pub fn get_reachable_ids(&self) -> Vec { - self.root.reachable_ids.decode(self).map(|index| self.local_def_id(index)).collect() + pub fn get_exported_symbols(&self) -> Vec { + self.root.exported_symbols.decode(self).map(|index| self.local_def_id(index)).collect() } pub fn get_macro(&self, id: DefIndex) -> (ast::Name, MacroDef) { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 83904b24de3..01cb0f823e8 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -50,7 +50,7 @@ pub struct EncodeContext<'a, 'tcx: 'a> { reexports: &'a def::ExportMap, link_meta: &'a LinkMeta, cstore: &'a cstore::CStore, - reachable: &'a NodeSet, + exported_symbols: &'a NodeSet, lazy_state: LazyState, type_shorthands: FxHashMap, usize>, @@ -1223,16 +1223,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy_seq(all_impls) } - // Encodes all reachable symbols in this crate into the metadata. + // Encodes all symbols exported from this crate into the metadata. // // This pass is seeded off the reachability list calculated in the // middle::reachable module but filters out items that either don't have a // symbol associated with them (they weren't translated) or if they're an FFI // definition (as that's not defined in this crate). - fn encode_reachable(&mut self) -> LazySeq { - let reachable = self.reachable; + fn encode_exported_symbols(&mut self) -> LazySeq { + let exported_symbols = self.exported_symbols; let tcx = self.tcx; - self.lazy_seq(reachable.iter().map(|&id| tcx.map.local_def_id(id).index)) + self.lazy_seq(exported_symbols.iter().map(|&id| tcx.map.local_def_id(id).index)) } fn encode_dylib_dependency_formats(&mut self) -> LazySeq> { @@ -1278,10 +1278,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let impls = self.encode_impls(); let impl_bytes = self.position() - i; - // Encode reachability info. + // Encode exported symbols info. i = self.position(); - let reachable_ids = self.encode_reachable(); - let reachable_bytes = self.position() - i; + let exported_symbols = self.encode_exported_symbols(); + let exported_symbols_bytes = self.position() - i; // Encode and index the items. i = self.position(); @@ -1319,7 +1319,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { native_libraries: native_libraries, codemap: codemap, impls: impls, - reachable_ids: reachable_ids, + exported_symbols: exported_symbols, index: index, }); @@ -1339,7 +1339,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { println!(" native bytes: {}", native_lib_bytes); println!(" codemap bytes: {}", codemap_bytes); println!(" impl bytes: {}", impl_bytes); - println!(" reachable bytes: {}", reachable_bytes); + println!(" exp. symbols bytes: {}", exported_symbols_bytes); println!(" item bytes: {}", item_bytes); println!(" index bytes: {}", index_bytes); println!(" zero bytes: {}", zero_bytes); @@ -1377,7 +1377,7 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cstore: &cstore::CStore, reexports: &def::ExportMap, link_meta: &LinkMeta, - reachable: &NodeSet) + exported_symbols: &NodeSet) -> Vec { let mut cursor = Cursor::new(vec![]); cursor.write_all(METADATA_HEADER).unwrap(); @@ -1392,7 +1392,7 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, reexports: reexports, link_meta: link_meta, cstore: cstore, - reachable: reachable, + exported_symbols: exported_symbols, lazy_state: LazyState::NoNode, type_shorthands: Default::default(), predicate_shorthands: Default::default(), diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 00c3709435d..f92051cbf19 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -180,7 +180,7 @@ pub struct CrateRoot { pub native_libraries: LazySeq, pub codemap: LazySeq, pub impls: LazySeq, - pub reachable_ids: LazySeq, + pub exported_symbols: LazySeq, pub index: LazySeq, } diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index 860903d259f..b8d5fc9042f 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -34,10 +34,10 @@ pub struct LinkerInfo { impl<'a, 'tcx> LinkerInfo { pub fn new(scx: &SharedCrateContext<'a, 'tcx>, - reachable: &[String]) -> LinkerInfo { + exports: &[String]) -> LinkerInfo { LinkerInfo { exports: scx.sess().crate_types.borrow().iter().map(|&c| { - (c, exported_symbols(scx, reachable, c)) + (c, exported_symbols(scx, exports, c)) }).collect(), } } @@ -473,7 +473,7 @@ impl<'a> Linker for MsvcLinker<'a> { } fn exported_symbols(scx: &SharedCrateContext, - reachable: &[String], + exported_symbols: &[String], crate_type: CrateType) -> Vec { // See explanation in GnuLinker::export_symbols, for @@ -485,7 +485,7 @@ fn exported_symbols(scx: &SharedCrateContext, } } - let mut symbols = reachable.to_vec(); + let mut symbols = exported_symbols.to_vec(); // If we're producing anything other than a dylib then the `reachable` array // above is the exhaustive set of symbols we should be exporting. @@ -507,7 +507,7 @@ fn exported_symbols(scx: &SharedCrateContext, None } }).flat_map(|cnum| { - cstore.reachable_ids(cnum) + cstore.exported_symbols(cnum) }).map(|did| -> String { Instance::mono(scx, did).symbol_name(scx) })); diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index 522864c6ec3..46b1241de36 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -25,7 +25,7 @@ use std::ffi::CString; use std::path::Path; pub fn run(sess: &session::Session, llmod: ModuleRef, - tm: TargetMachineRef, reachable: &[String], + tm: TargetMachineRef, exported_symbols: &[String], config: &ModuleConfig, temp_no_opt_bc_filename: &Path) { if sess.opts.cg.prefer_dynamic { @@ -118,8 +118,8 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, } }); - // Internalize everything but the reachable symbols of the current module - let cstrs: Vec = reachable.iter().map(|s| { + // Internalize everything but the exported symbols of the current module + let cstrs: Vec = exported_symbols.iter().map(|s| { CString::new(s.clone()).unwrap() }).collect(); let arr: Vec<*const libc::c_char> = cstrs.iter().map(|c| c.as_ptr()).collect(); diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index ae5d02c7e04..84bba64dd70 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -343,9 +343,9 @@ struct CodegenContext<'a> { } impl<'a> CodegenContext<'a> { - fn new_with_session(sess: &'a Session, reachable: &'a [String]) -> CodegenContext<'a> { + fn new_with_session(sess: &'a Session, exported_symbols: &'a [String]) -> CodegenContext<'a> { CodegenContext { - lto_ctxt: Some((sess, reachable)), + lto_ctxt: Some((sess, exported_symbols)), handler: sess.diagnostic(), plugin_passes: sess.plugin_llvm_passes.borrow().clone(), remark: sess.opts.cg.remark.clone(), @@ -516,14 +516,14 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, llvm::LLVMDisposePassManager(mpm); match cgcx.lto_ctxt { - Some((sess, reachable)) if sess.lto() => { + Some((sess, exported_symbols)) if sess.lto() => { time(sess.time_passes(), "all lto passes", || { let temp_no_opt_bc_filename = output_names.temp_path_ext("no-opt.lto.bc", module_name); lto::run(sess, llmod, tm, - reachable, + exported_symbols, &config, &temp_no_opt_bc_filename); }); @@ -753,7 +753,7 @@ pub fn run_passes(sess: &Session, // potentially create hundreds of them). let num_workers = work_items.len() - 1; if num_workers == 1 { - run_work_singlethreaded(sess, &trans.reachable, work_items); + run_work_singlethreaded(sess, &trans.exported_symbols, work_items); } else { run_work_multithreaded(sess, work_items, num_workers); } @@ -997,9 +997,9 @@ fn execute_work_item(cgcx: &CodegenContext, } fn run_work_singlethreaded(sess: &Session, - reachable: &[String], + exported_symbols: &[String], work_items: Vec) { - let cgcx = CodegenContext::new_with_session(sess, reachable); + let cgcx = CodegenContext::new_with_session(sess, exported_symbols); // Since we're running single-threaded, we can pass the session to // the proc, allowing `optimize_and_codegen` to perform LTO. diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 259ef2a780c..74e6a1dac80 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1243,7 +1243,7 @@ fn contains_null(s: &str) -> bool { } fn write_metadata(cx: &SharedCrateContext, - reachable_ids: &NodeSet) -> Vec { + exported_symbols: &NodeSet) -> Vec { use flate; #[derive(PartialEq, Eq, PartialOrd, Ord)] @@ -1275,7 +1275,7 @@ fn write_metadata(cx: &SharedCrateContext, let metadata = cstore.encode_metadata(cx.tcx(), cx.export_map(), cx.link_meta(), - reachable_ids); + exported_symbols); if kind == MetadataKind::Uncompressed { return metadata; } @@ -1313,7 +1313,7 @@ fn write_metadata(cx: &SharedCrateContext, fn internalize_symbols<'a, 'tcx>(sess: &Session, ccxs: &CrateContextList<'a, 'tcx>, symbol_map: &SymbolMap<'tcx>, - reachable: &FxHashSet<&str>) { + exported_symbols: &FxHashSet<&str>) { let scx = ccxs.shared(); let tcx = scx.tcx(); @@ -1379,7 +1379,7 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session, let name_cow = Cow::Borrowed(name_str); let is_referenced_somewhere = referenced_somewhere.contains(&name_cstr); - let is_reachable = reachable.contains(&name_str); + let is_reachable = exported_symbols.contains(&name_str); let has_fixed_linkage = linkage_fixed_explicitly.contains(&name_cow); if !is_referenced_somewhere && !is_reachable && !has_fixed_linkage { @@ -1481,7 +1481,7 @@ fn iter_functions(llmod: llvm::ModuleRef) -> ValueIter { /// /// This list is later used by linkers to determine the set of symbols needed to /// be exposed from a dynamic library and it's also encoded into the metadata. -pub fn filter_reachable_ids(tcx: TyCtxt, reachable: NodeSet) -> NodeSet { +pub fn find_exported_symbols(tcx: TyCtxt, reachable: NodeSet) -> NodeSet { reachable.into_iter().filter(|&id| { // Next, we want to ignore some FFI functions that are not exposed from // this crate. Reachable FFI functions can be lumped into two @@ -1535,7 +1535,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let krate = tcx.map.krate(); let ty::CrateAnalysis { export_map, reachable, name, .. } = analysis; - let reachable = filter_reachable_ids(tcx, reachable); + let exported_symbols = find_exported_symbols(tcx, reachable); let check_overflow = if let Some(v) = tcx.sess.opts.debugging_opts.force_overflow_checks { v @@ -1548,11 +1548,11 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let shared_ccx = SharedCrateContext::new(tcx, export_map, link_meta.clone(), - reachable, + exported_symbols, check_overflow); // Translate the metadata. let metadata = time(tcx.sess.time_passes(), "write metadata", || { - write_metadata(&shared_ccx, shared_ccx.reachable()) + write_metadata(&shared_ccx, shared_ccx.exported_symbols()) }); let metadata_module = ModuleTranslation { @@ -1608,7 +1608,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, metadata_module: metadata_module, link: link_meta, metadata: metadata, - reachable: vec![], + exported_symbols: vec![], no_builtins: no_builtins, linker_info: linker_info, windows_subsystem: None, @@ -1688,17 +1688,17 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } let sess = shared_ccx.sess(); - let mut reachable_symbols = shared_ccx.reachable().iter().map(|&id| { + let mut exported_symbols = shared_ccx.exported_symbols().iter().map(|&id| { let def_id = shared_ccx.tcx().map.local_def_id(id); symbol_for_def_id(def_id, &shared_ccx, &symbol_map) }).collect::>(); if sess.entry_fn.borrow().is_some() { - reachable_symbols.push("main".to_string()); + exported_symbols.push("main".to_string()); } if sess.crate_types.borrow().contains(&config::CrateTypeDylib) { - reachable_symbols.push(shared_ccx.metadata_symbol_name()); + exported_symbols.push(shared_ccx.metadata_symbol_name()); } // For the purposes of LTO or when creating a cdylib, we add to the @@ -1708,10 +1708,10 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // // Note that this happens even if LTO isn't requested or we're not creating // a cdylib. In those cases, though, we're not even reading the - // `reachable_symbols` list later on so it should be ok. + // `exported_symbols` list later on so it should be ok. for cnum in sess.cstore.crates() { - let syms = sess.cstore.reachable_ids(cnum); - reachable_symbols.extend(syms.into_iter().filter(|&def_id| { + let syms = sess.cstore.exported_symbols(cnum); + exported_symbols.extend(syms.into_iter().filter(|&def_id| { let applicable = match sess.cstore.describe_def(def_id) { Some(Def::Static(..)) => true, Some(Def::Fn(_)) => { @@ -1735,7 +1735,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, internalize_symbols(sess, &crate_context_list, &symbol_map, - &reachable_symbols.iter() + &exported_symbols.iter() .map(|s| &s[..]) .collect()) }); @@ -1749,7 +1749,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, create_imps(&crate_context_list); } - let linker_info = LinkerInfo::new(&shared_ccx, &reachable_symbols); + let linker_info = LinkerInfo::new(&shared_ccx, &exported_symbols); let subsystem = attr::first_attr_value_str_by_name(&krate.attrs, "windows_subsystem"); @@ -1767,7 +1767,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, metadata_module: metadata_module, link: link_meta, metadata: metadata, - reachable: reachable_symbols, + exported_symbols: exported_symbols, no_builtins: no_builtins, linker_info: linker_info, windows_subsystem: windows_subsystem, diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index c0d7c64bd19..262b8362397 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -67,7 +67,7 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> { metadata_llcx: ContextRef, export_map: ExportMap, - reachable: NodeSet, + exported_symbols: NodeSet, link_meta: LinkMeta, tcx: TyCtxt<'a, 'tcx, 'tcx>, stats: Stats, @@ -437,7 +437,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { pub fn new(tcx: TyCtxt<'b, 'tcx, 'tcx>, export_map: ExportMap, link_meta: LinkMeta, - reachable: NodeSet, + exported_symbols: NodeSet, check_overflow: bool) -> SharedCrateContext<'b, 'tcx> { let (metadata_llcx, metadata_llmod) = unsafe { @@ -454,7 +454,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { // they're not available to be linked against. This poses a few problems // for the compiler, some of which are somewhat fundamental, but we use // the `use_dll_storage_attrs` variable below to attach the `dllexport` - // attribute to all LLVM functions that are reachable (e.g. they're + // attribute to all LLVM functions that are exported e.g. they're // already tagged with external linkage). This is suboptimal for a few // reasons: // @@ -493,7 +493,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { metadata_llmod: metadata_llmod, metadata_llcx: metadata_llcx, export_map: export_map, - reachable: reachable, + exported_symbols: exported_symbols, link_meta: link_meta, tcx: tcx, stats: Stats { @@ -527,8 +527,8 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { &self.export_map } - pub fn reachable<'a>(&'a self) -> &'a NodeSet { - &self.reachable + pub fn exported_symbols<'a>(&'a self) -> &'a NodeSet { + &self.exported_symbols } pub fn trait_cache(&self) -> &RefCell>> { @@ -768,8 +768,8 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.shared.export_map } - pub fn reachable<'a>(&'a self) -> &'a NodeSet { - &self.shared.reachable + pub fn exported_symbols<'a>(&'a self) -> &'a NodeSet { + &self.shared.exported_symbols } pub fn link_meta<'a>(&'a self) -> &'a LinkMeta { diff --git a/src/librustc_trans/debuginfo/utils.rs b/src/librustc_trans/debuginfo/utils.rs index 7cac9172a9c..3ee2497009f 100644 --- a/src/librustc_trans/debuginfo/utils.rs +++ b/src/librustc_trans/debuginfo/utils.rs @@ -34,7 +34,7 @@ pub fn is_node_local_to_unit(cx: &CrateContext, node_id: ast::NodeId) -> bool // visible). It might better to use the `exported_items` set from // `driver::CrateAnalysis` in the future, but (atm) this set is not // available in the translation pass. - !cx.reachable().contains(&node_id) + !cx.exported_symbols().contains(&node_id) } #[allow(non_snake_case)] diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 0e7ead30a93..8a7ab16ee2b 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -169,7 +169,7 @@ pub struct CrateTranslation { pub metadata_module: ModuleTranslation, pub link: middle::cstore::LinkMeta, pub metadata: Vec, - pub reachable: Vec, + pub exported_symbols: Vec, pub no_builtins: bool, pub windows_subsystem: Option, pub linker_info: back::linker::LinkerInfo From 133aeacf2f28b985bba88eebc08c7a9924453738 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 30 Nov 2016 10:03:42 -0500 Subject: [PATCH 236/293] Refactor symbol export list generation. --- src/librustc/middle/cstore.rs | 3 + src/librustc_metadata/cstore_impl.rs | 8 + src/librustc_trans/back/linker.rs | 54 ++---- src/librustc_trans/back/lto.rs | 65 +++++-- src/librustc_trans/back/symbol_export.rs | 185 ++++++++++++++++++ src/librustc_trans/back/write.rs | 9 +- src/librustc_trans/base.rs | 202 +++++++++----------- src/librustc_trans/lib.rs | 3 +- src/test/run-make/sepcomp-inlining/Makefile | 4 +- 9 files changed, 367 insertions(+), 166 deletions(-) create mode 100644 src/librustc_trans/back/symbol_export.rs diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 34224b924b9..4357518b332 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -328,6 +328,7 @@ pub trait CrateStore<'tcx> { fn crate_hash(&self, cnum: CrateNum) -> Svh; fn crate_disambiguator(&self, cnum: CrateNum) -> Symbol; fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option; + fn derive_registrar_fn(&self, cnum: CrateNum) -> Option; fn native_libraries(&self, cnum: CrateNum) -> Vec; fn exported_symbols(&self, cnum: CrateNum) -> Vec; fn is_no_builtins(&self, cnum: CrateNum) -> bool; @@ -491,6 +492,8 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { -> Symbol { bug!("crate_disambiguator") } fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option { bug!("plugin_registrar_fn") } + fn derive_registrar_fn(&self, cnum: CrateNum) -> Option + { bug!("derive_registrar_fn") } fn native_libraries(&self, cnum: CrateNum) -> Vec { bug!("native_libraries") } fn exported_symbols(&self, cnum: CrateNum) -> Vec { bug!("exported_symbols") } diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 2965e545eca..aca1d2f7612 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -306,6 +306,14 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { }) } + fn derive_registrar_fn(&self, cnum: CrateNum) -> Option + { + self.get_crate_data(cnum).root.macro_derive_registrar.map(|index| DefId { + krate: cnum, + index: index + }) + } + fn native_libraries(&self, cnum: CrateNum) -> Vec { self.get_crate_data(cnum).get_native_libraries() diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index b8d5fc9042f..933813ac4d9 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -17,11 +17,11 @@ use std::path::{Path, PathBuf}; use std::process::Command; use context::SharedCrateContext; -use monomorphize::Instance; use back::archive; +use back::symbol_export::{self, ExportedSymbols}; use middle::dependency_format::Linkage; -use rustc::hir::def_id::CrateNum; +use rustc::hir::def_id::{LOCAL_CRATE, CrateNum}; use session::Session; use session::config::CrateType; use session::config; @@ -34,7 +34,7 @@ pub struct LinkerInfo { impl<'a, 'tcx> LinkerInfo { pub fn new(scx: &SharedCrateContext<'a, 'tcx>, - exports: &[String]) -> LinkerInfo { + exports: &ExportedSymbols) -> LinkerInfo { LinkerInfo { exports: scx.sess().crate_types.borrow().iter().map(|&c| { (c, exported_symbols(scx, exports, c)) @@ -473,43 +473,29 @@ impl<'a> Linker for MsvcLinker<'a> { } fn exported_symbols(scx: &SharedCrateContext, - exported_symbols: &[String], + exported_symbols: &ExportedSymbols, crate_type: CrateType) -> Vec { - // See explanation in GnuLinker::export_symbols, for - // why we don't ever need dylib symbols on non-MSVC. - if crate_type == CrateType::CrateTypeDylib || - crate_type == CrateType::CrateTypeProcMacro { - if !scx.sess().target.target.options.is_like_msvc { - return vec![]; - } - } + let export_threshold = symbol_export::crate_export_threshold(crate_type); - let mut symbols = exported_symbols.to_vec(); + let mut symbols = Vec::new(); + exported_symbols.for_each_exported_symbol(LOCAL_CRATE, export_threshold, |name, _| { + symbols.push(name.to_owned()); + }); - // If we're producing anything other than a dylib then the `reachable` array - // above is the exhaustive set of symbols we should be exporting. - // - // For dylibs, however, we need to take a look at how all upstream crates - // are linked into this dynamic library. For all statically linked - // libraries we take all their reachable symbols and emit them as well. - if crate_type != CrateType::CrateTypeDylib { - return symbols - } - - let cstore = &scx.sess().cstore; let formats = scx.sess().dependency_formats.borrow(); let deps = formats[&crate_type].iter(); - symbols.extend(deps.enumerate().filter_map(|(i, f)| { - if *f == Linkage::Static { - Some(CrateNum::new(i + 1)) - } else { - None + + for (index, dep_format) in deps.enumerate() { + let cnum = CrateNum::new(index + 1); + // For each dependency that we are linking to statically ... + if *dep_format == Linkage::Static { + // ... we add its symbol list to our export list. + exported_symbols.for_each_exported_symbol(cnum, export_threshold, |name, _| { + symbols.push(name.to_owned()); + }) } - }).flat_map(|cnum| { - cstore.exported_symbols(cnum) - }).map(|did| -> String { - Instance::mono(scx, did).symbol_name(scx) - })); + } + symbols } diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index 46b1241de36..1960b368278 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -8,14 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::link; -use super::write; +use back::link; +use back::write; +use back::symbol_export::{self, ExportedSymbols}; use rustc::session::{self, config}; use llvm; use llvm::archive_ro::ArchiveRO; use llvm::{ModuleRef, TargetMachineRef, True, False}; use rustc::util::common::time; use rustc::util::common::path2cstr; +use rustc::hir::def_id::LOCAL_CRATE; use back::write::{ModuleConfig, with_llvm_pmb}; use libc; @@ -24,8 +26,23 @@ use flate; use std::ffi::CString; use std::path::Path; -pub fn run(sess: &session::Session, llmod: ModuleRef, - tm: TargetMachineRef, exported_symbols: &[String], +pub fn crate_type_allows_lto(crate_type: config::CrateType) -> bool { + match crate_type { + config::CrateTypeExecutable | + config::CrateTypeStaticlib | + config::CrateTypeCdylib => true, + + config::CrateTypeDylib | + config::CrateTypeRlib | + config::CrateTypeMetadata | + config::CrateTypeProcMacro => false, + } +} + +pub fn run(sess: &session::Session, + llmod: ModuleRef, + tm: TargetMachineRef, + exported_symbols: &ExportedSymbols, config: &ModuleConfig, temp_no_opt_bc_filename: &Path) { if sess.opts.cg.prefer_dynamic { @@ -38,17 +55,31 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, // Make sure we actually can run LTO for crate_type in sess.crate_types.borrow().iter() { - match *crate_type { - config::CrateTypeExecutable | - config::CrateTypeCdylib | - config::CrateTypeStaticlib => {} - _ => { - sess.fatal("lto can only be run for executables and \ + if !crate_type_allows_lto(*crate_type) { + sess.fatal("lto can only be run for executables and \ static library outputs"); - } } } + let export_threshold = + symbol_export::crates_export_threshold(&sess.crate_types.borrow()[..]); + + let symbol_filter = &|&(ref name, level): &(String, _)| { + if symbol_export::is_below_threshold(level, export_threshold) { + let mut bytes = Vec::with_capacity(name.len() + 1); + bytes.extend(name.bytes()); + Some(CString::new(bytes).unwrap()) + } else { + None + } + }; + + let mut symbol_white_list: Vec = exported_symbols + .exported_symbols(LOCAL_CRATE) + .iter() + .filter_map(symbol_filter) + .collect(); + // For each of our upstream dependencies, find the corresponding rlib and // load the bitcode from the archive. Then merge it into the current LLVM // module that we've got. @@ -58,6 +89,11 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, return; } + symbol_white_list.extend( + exported_symbols.exported_symbols(cnum) + .iter() + .filter_map(symbol_filter)); + let archive = ArchiveRO::open(&path).expect("wanted an rlib"); let bytecodes = archive.iter().filter_map(|child| { child.ok().and_then(|c| c.name().map(|name| (name, c))) @@ -119,10 +155,9 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, }); // Internalize everything but the exported symbols of the current module - let cstrs: Vec = exported_symbols.iter().map(|s| { - CString::new(s.clone()).unwrap() - }).collect(); - let arr: Vec<*const libc::c_char> = cstrs.iter().map(|c| c.as_ptr()).collect(); + let arr: Vec<*const libc::c_char> = symbol_white_list.iter() + .map(|c| c.as_ptr()) + .collect(); let ptr = arr.as_ptr(); unsafe { llvm::LLVMRustRunRestrictionPass(llmod, diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs new file mode 100644 index 00000000000..2290cb0f487 --- /dev/null +++ b/src/librustc_trans/back/symbol_export.rs @@ -0,0 +1,185 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use context::SharedCrateContext; +use monomorphize::Instance; +use symbol_map::SymbolMap; +use util::nodemap::FxHashMap; +use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE}; +use rustc::session::config; +use syntax::attr; +use trans_item::TransItem; + +/// The SymbolExportLevel of a symbols specifies from which kinds of crates +/// the symbol will be exported. `C` symbols will be exported from any +/// kind of crate, including cdylibs which export very few things. +/// `Rust` will only be exported if the crate produced is a Rust +/// dylib. +#[derive(Eq, PartialEq, Debug, Copy, Clone)] +pub enum SymbolExportLevel { + C, + Rust, +} + +/// The set of symbols exported from each crate in the crate graph. +pub struct ExportedSymbols { + exports: FxHashMap>, +} + +impl ExportedSymbols { + + pub fn empty() -> ExportedSymbols { + ExportedSymbols { + exports: FxHashMap(), + } + } + + pub fn compute_from<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, + symbol_map: &SymbolMap<'tcx>) + -> ExportedSymbols { + let mut local_crate: Vec<_> = scx + .exported_symbols() + .iter() + .map(|&node_id| { + scx.tcx().map.local_def_id(node_id) + }) + .map(|def_id| { + (symbol_for_def_id(scx, def_id, symbol_map), + export_level(scx, def_id)) + }) + .collect(); + + if scx.sess().entry_fn.borrow().is_some() { + local_crate.push(("main".to_string(), SymbolExportLevel::C)); + } + + if scx.sess().crate_types.borrow().contains(&config::CrateTypeDylib) { + local_crate.push((scx.metadata_symbol_name(), + SymbolExportLevel::Rust)); + } + + let mut exports = FxHashMap(); + exports.insert(LOCAL_CRATE, local_crate); + + for cnum in scx.sess().cstore.crates() { + debug_assert!(cnum != LOCAL_CRATE); + + if scx.sess().cstore.plugin_registrar_fn(cnum).is_some() || + scx.sess().cstore.derive_registrar_fn(cnum).is_some() { + continue; + } + + let crate_exports = scx + .sess() + .cstore + .exported_symbols(cnum) + .iter() + .map(|&def_id| { + debug!("EXTERN-SYMBOL: {:?}", def_id); + let name = Instance::mono(scx, def_id).symbol_name(scx); + (name, export_level(scx, def_id)) + }) + .collect(); + + exports.insert(cnum, crate_exports); + } + + return ExportedSymbols { + exports: exports + }; + + fn export_level(scx: &SharedCrateContext, + sym_def_id: DefId) + -> SymbolExportLevel { + let attrs = scx.tcx().get_attrs(sym_def_id); + if attr::contains_extern_indicator(scx.sess().diagnostic(), &attrs) { + SymbolExportLevel::C + } else { + SymbolExportLevel::Rust + } + } + } + + pub fn exported_symbols(&self, + cnum: CrateNum) + -> &[(String, SymbolExportLevel)] { + match self.exports.get(&cnum) { + Some(exports) => &exports[..], + None => &[] + } + } + + pub fn for_each_exported_symbol(&self, + cnum: CrateNum, + export_threshold: SymbolExportLevel, + mut f: F) + where F: FnMut(&str, SymbolExportLevel) + { + for &(ref name, export_level) in self.exported_symbols(cnum) { + if is_below_threshold(export_level, export_threshold) { + f(&name[..], export_level) + } + } + } +} + +pub fn crate_export_threshold(crate_type: config::CrateType) + -> SymbolExportLevel { + match crate_type { + config::CrateTypeExecutable | + config::CrateTypeStaticlib | + config::CrateTypeCdylib => SymbolExportLevel::C, + config::CrateTypeProcMacro | + config::CrateTypeRlib | + config::CrateTypeMetadata | + config::CrateTypeDylib => SymbolExportLevel::Rust, + } +} + +pub fn crates_export_threshold(crate_types: &[config::CrateType]) + -> SymbolExportLevel { + if crate_types.iter().any(|&crate_type| { + crate_export_threshold(crate_type) == SymbolExportLevel::Rust + }) { + SymbolExportLevel::Rust + } else { + SymbolExportLevel::C + } +} + +pub fn is_below_threshold(level: SymbolExportLevel, + threshold: SymbolExportLevel) + -> bool { + if threshold == SymbolExportLevel::Rust { + // We export everything from Rust dylibs + true + } else { + level == SymbolExportLevel::C + } +} + +fn symbol_for_def_id<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, + def_id: DefId, + symbol_map: &SymbolMap<'tcx>) + -> String { + // Just try to look things up in the symbol map. If nothing's there, we + // recompute. + if let Some(node_id) = scx.tcx().map.as_local_node_id(def_id) { + if let Some(sym) = symbol_map.get(TransItem::Static(node_id)) { + return sym.to_owned(); + } + } + + let instance = Instance::mono(scx, def_id); + + symbol_map.get(TransItem::Fn(instance)) + .map(str::to_owned) + .unwrap_or_else(|| instance.symbol_name(scx)) +} diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 84bba64dd70..ffab0bde7ab 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -10,6 +10,7 @@ use back::lto; use back::link::{get_linker, remove}; +use back::symbol_export::ExportedSymbols; use rustc_incremental::{save_trans_partition, in_incr_comp_dir}; use session::config::{OutputFilenames, OutputTypes, Passes, SomePasses, AllPasses}; use session::Session; @@ -328,7 +329,7 @@ impl ModuleConfig { struct CodegenContext<'a> { // Extra resources used for LTO: (sess, reachable). This will be `None` // when running in a worker thread. - lto_ctxt: Option<(&'a Session, &'a [String])>, + lto_ctxt: Option<(&'a Session, &'a ExportedSymbols)>, // Handler to use for diagnostics produced during codegen. handler: &'a Handler, // LLVM passes added by plugins. @@ -343,7 +344,9 @@ struct CodegenContext<'a> { } impl<'a> CodegenContext<'a> { - fn new_with_session(sess: &'a Session, exported_symbols: &'a [String]) -> CodegenContext<'a> { + fn new_with_session(sess: &'a Session, + exported_symbols: &'a ExportedSymbols) + -> CodegenContext<'a> { CodegenContext { lto_ctxt: Some((sess, exported_symbols)), handler: sess.diagnostic(), @@ -997,7 +1000,7 @@ fn execute_work_item(cgcx: &CodegenContext, } fn run_work_singlethreaded(sess: &Session, - exported_symbols: &[String], + exported_symbols: &ExportedSymbols, work_items: Vec) { let cgcx = CodegenContext::new_with_session(sess, exported_symbols); diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 74e6a1dac80..a31b61e42c4 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -33,10 +33,10 @@ use super::ModuleTranslation; use assert_module_sources; use back::link; use back::linker::LinkerInfo; +use back::symbol_export::{self, ExportedSymbols}; use llvm::{Linkage, ValueRef, Vector, get_param}; use llvm; -use rustc::hir::def::Def; -use rustc::hir::def_id::DefId; +use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem}; use rustc::ty::subst::Substs; use rustc::traits; @@ -84,7 +84,6 @@ use util::nodemap::{NodeSet, FxHashMap, FxHashSet}; use arena::TypedArena; use libc::c_uint; use std::ffi::{CStr, CString}; -use std::borrow::Cow; use std::cell::{Cell, RefCell}; use std::ptr; use std::rc::Rc; @@ -1313,16 +1312,23 @@ fn write_metadata(cx: &SharedCrateContext, fn internalize_symbols<'a, 'tcx>(sess: &Session, ccxs: &CrateContextList<'a, 'tcx>, symbol_map: &SymbolMap<'tcx>, - exported_symbols: &FxHashSet<&str>) { + exported_symbols: &ExportedSymbols) { + let export_threshold = + symbol_export::crates_export_threshold(&sess.crate_types.borrow()[..]); + + let exported_symbols = exported_symbols + .exported_symbols(LOCAL_CRATE) + .iter() + .filter(|&&(_, export_level)| { + symbol_export::is_below_threshold(export_level, export_threshold) + }) + .map(|&(ref name, _)| &name[..]) + .collect::>(); + let scx = ccxs.shared(); let tcx = scx.tcx(); - // In incr. comp. mode, we can't necessarily see all refs since we - // don't generate LLVM IR for reused modules, so skip this - // step. Later we should get smarter. - if sess.opts.debugging_opts.incremental.is_some() { - return; - } + let incr_comp = sess.opts.debugging_opts.incremental.is_some(); // 'unsafe' because we are holding on to CStr's from the LLVM module within // this block. @@ -1330,34 +1336,43 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session, let mut referenced_somewhere = FxHashSet(); // Collect all symbols that need to stay externally visible because they - // are referenced via a declaration in some other codegen unit. - for ccx in ccxs.iter_need_trans() { - for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) { - let linkage = llvm::LLVMRustGetLinkage(val); - // We only care about external declarations (not definitions) - // and available_externally definitions. - let is_available_externally = linkage == llvm::Linkage::AvailableExternallyLinkage; - let is_decl = llvm::LLVMIsDeclaration(val) != 0; + // are referenced via a declaration in some other codegen unit. In + // incremental compilation, we don't need to collect. See below for more + // information. + if !incr_comp { + for ccx in ccxs.iter_need_trans() { + for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) { + let linkage = llvm::LLVMRustGetLinkage(val); + // We only care about external declarations (not definitions) + // and available_externally definitions. + let is_available_externally = + linkage == llvm::Linkage::AvailableExternallyLinkage; + let is_decl = llvm::LLVMIsDeclaration(val) == llvm::True; - if is_decl || is_available_externally { - let symbol_name = CStr::from_ptr(llvm::LLVMGetValueName(val)); - referenced_somewhere.insert(symbol_name); + if is_decl || is_available_externally { + let symbol_name = CStr::from_ptr(llvm::LLVMGetValueName(val)); + referenced_somewhere.insert(symbol_name); + } } } } // Also collect all symbols for which we cannot adjust linkage, because - // it is fixed by some directive in the source code (e.g. #[no_mangle]). - let linkage_fixed_explicitly: FxHashSet<_> = scx - .translation_items() - .borrow() - .iter() - .cloned() - .filter(|trans_item|{ - trans_item.explicit_linkage(tcx).is_some() - }) - .map(|trans_item| symbol_map.get_or_compute(scx, trans_item)) - .collect(); + // it is fixed by some directive in the source code. + let (locally_defined_symbols, linkage_fixed_explicitly) = { + let mut locally_defined_symbols = FxHashSet(); + let mut linkage_fixed_explicitly = FxHashSet(); + + for trans_item in scx.translation_items().borrow().iter() { + let symbol_name = symbol_map.get_or_compute(scx, *trans_item); + if trans_item.explicit_linkage(tcx).is_some() { + linkage_fixed_explicitly.insert(symbol_name.clone()); + } + locally_defined_symbols.insert(symbol_name); + } + + (locally_defined_symbols, linkage_fixed_explicitly) + }; // Examine each external definition. If the definition is not used in // any other compilation unit, and is not reachable from other crates, @@ -1369,23 +1384,46 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session, let is_externally_visible = (linkage == llvm::Linkage::ExternalLinkage) || (linkage == llvm::Linkage::LinkOnceODRLinkage) || (linkage == llvm::Linkage::WeakODRLinkage); - let is_definition = llvm::LLVMIsDeclaration(val) == 0; - // If this is a definition (as opposed to just a declaration) - // and externally visible, check if we can internalize it - if is_definition && is_externally_visible { - let name_cstr = CStr::from_ptr(llvm::LLVMGetValueName(val)); - let name_str = name_cstr.to_str().unwrap(); - let name_cow = Cow::Borrowed(name_str); + if !is_externally_visible { + // This symbol is not visible outside of its codegen unit, + // so there is nothing to do for it. + continue; + } - let is_referenced_somewhere = referenced_somewhere.contains(&name_cstr); - let is_reachable = exported_symbols.contains(&name_str); - let has_fixed_linkage = linkage_fixed_explicitly.contains(&name_cow); + let name_cstr = CStr::from_ptr(llvm::LLVMGetValueName(val)); + let name_str = name_cstr.to_str().unwrap(); - if !is_referenced_somewhere && !is_reachable && !has_fixed_linkage { - llvm::LLVMRustSetLinkage(val, llvm::Linkage::InternalLinkage); - llvm::LLVMSetDLLStorageClass(val, - llvm::DLLStorageClass::Default); + if exported_symbols.contains(&name_str) { + // This symbol is explicitly exported, so we can't + // mark it as internal or hidden. + continue; + } + + let is_declaration = llvm::LLVMIsDeclaration(val) == llvm::True; + + if is_declaration { + if locally_defined_symbols.contains(name_str) { + // Only mark declarations from the current crate as hidden. + // Otherwise we would mark things as hidden that are + // imported from other crates or native libraries. + llvm::LLVMRustSetVisibility(val, llvm::Visibility::Hidden); + } + } else { + let has_fixed_linkage = linkage_fixed_explicitly.contains(name_str); + + if !has_fixed_linkage { + // In incremental compilation mode, we can't be sure that + // we saw all references because we don't know what's in + // cached compilation units, so we always assume that the + // given item has been referenced. + if incr_comp || referenced_somewhere.contains(&name_cstr) { + llvm::LLVMRustSetVisibility(val, llvm::Visibility::Hidden); + } else { + llvm::LLVMRustSetLinkage(val, llvm::Linkage::InternalLinkage); + } + + llvm::LLVMSetDLLStorageClass(val, llvm::DLLStorageClass::Default); llvm::UnsetComdat(val); } } @@ -1602,13 +1640,13 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Skip crate items and just output metadata in -Z no-trans mode. if tcx.sess.opts.debugging_opts.no_trans || tcx.sess.crate_types.borrow().iter().all(|ct| ct == &config::CrateTypeMetadata) { - let linker_info = LinkerInfo::new(&shared_ccx, &[]); + let linker_info = LinkerInfo::new(&shared_ccx, &ExportedSymbols::empty()); return CrateTranslation { modules: modules, metadata_module: metadata_module, link: link_meta, metadata: metadata, - exported_symbols: vec![], + exported_symbols: ExportedSymbols::empty(), no_builtins: no_builtins, linker_info: linker_info, windows_subsystem: None, @@ -1688,56 +1726,17 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } let sess = shared_ccx.sess(); - let mut exported_symbols = shared_ccx.exported_symbols().iter().map(|&id| { - let def_id = shared_ccx.tcx().map.local_def_id(id); - symbol_for_def_id(def_id, &shared_ccx, &symbol_map) - }).collect::>(); - if sess.entry_fn.borrow().is_some() { - exported_symbols.push("main".to_string()); - } - - if sess.crate_types.borrow().contains(&config::CrateTypeDylib) { - exported_symbols.push(shared_ccx.metadata_symbol_name()); - } - - // For the purposes of LTO or when creating a cdylib, we add to the - // reachable set all of the upstream reachable extern fns. These functions - // are all part of the public ABI of the final product, so we need to - // preserve them. - // - // Note that this happens even if LTO isn't requested or we're not creating - // a cdylib. In those cases, though, we're not even reading the - // `exported_symbols` list later on so it should be ok. - for cnum in sess.cstore.crates() { - let syms = sess.cstore.exported_symbols(cnum); - exported_symbols.extend(syms.into_iter().filter(|&def_id| { - let applicable = match sess.cstore.describe_def(def_id) { - Some(Def::Static(..)) => true, - Some(Def::Fn(_)) => { - shared_ccx.tcx().item_generics(def_id).types.is_empty() - } - _ => false - }; - - if applicable { - let attrs = shared_ccx.tcx().get_attrs(def_id); - attr::contains_extern_indicator(sess.diagnostic(), &attrs) - } else { - false - } - }).map(|did| { - symbol_for_def_id(did, &shared_ccx, &symbol_map) - })); - } + let exported_symbols = ExportedSymbols::compute_from(&shared_ccx, + &symbol_map); + // Now that we have all symbols that are exported from the CGUs of this + // crate, we can run the `internalize_symbols` pass. time(shared_ccx.sess().time_passes(), "internalize symbols", || { internalize_symbols(sess, &crate_context_list, &symbol_map, - &exported_symbols.iter() - .map(|s| &s[..]) - .collect()) + &exported_symbols); }); if tcx.sess.opts.debugging_opts.print_type_sizes { @@ -2107,22 +2106,3 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a (codegen_units, symbol_map) } - -fn symbol_for_def_id<'a, 'tcx>(def_id: DefId, - scx: &SharedCrateContext<'a, 'tcx>, - symbol_map: &SymbolMap<'tcx>) - -> String { - // Just try to look things up in the symbol map. If nothing's there, we - // recompute. - if let Some(node_id) = scx.tcx().map.as_local_node_id(def_id) { - if let Some(sym) = symbol_map.get(TransItem::Static(node_id)) { - return sym.to_owned(); - } - } - - let instance = Instance::mono(scx, def_id); - - symbol_map.get(TransItem::Fn(instance)) - .map(str::to_owned) - .unwrap_or_else(|| instance.symbol_name(scx)) -} diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 8a7ab16ee2b..e2da635b159 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -78,6 +78,7 @@ pub mod back { pub mod linker; pub mod link; pub mod lto; + pub mod symbol_export; pub mod symbol_names; pub mod write; pub mod msvc; @@ -169,7 +170,7 @@ pub struct CrateTranslation { pub metadata_module: ModuleTranslation, pub link: middle::cstore::LinkMeta, pub metadata: Vec, - pub exported_symbols: Vec, + pub exported_symbols: back::symbol_export::ExportedSymbols, pub no_builtins: bool, pub windows_subsystem: Option, pub linker_info: back::linker::LinkerInfo diff --git a/src/test/run-make/sepcomp-inlining/Makefile b/src/test/run-make/sepcomp-inlining/Makefile index ef43b0d97e4..720dfff2c04 100644 --- a/src/test/run-make/sepcomp-inlining/Makefile +++ b/src/test/run-make/sepcomp-inlining/Makefile @@ -10,5 +10,5 @@ all: $(RUSTC) foo.rs --emit=llvm-ir -C codegen-units=3 [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ i32\ .*inlined)" -eq "0" ] [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ internal\ i32\ .*inlined)" -eq "2" ] - [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ i32\ .*normal)" -eq "1" ] - [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c declare\ i32\ .*normal)" -eq "2" ] + [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ hidden\ i32\ .*normal)" -eq "1" ] + [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c declare\ hidden\ i32\ .*normal)" -eq "2" ] From e48160f6e40352a7f72ab108e78754ef1f3f5da1 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 30 Nov 2016 13:16:53 -0500 Subject: [PATCH 237/293] Generate a version script for linkers on Linux. --- src/librustc_trans/back/linker.rs | 49 +++++++++++++++---------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index 933813ac4d9..67c8d268a81 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -253,7 +253,20 @@ impl<'a> Linker for GnuLinker<'a> { let mut arg = OsString::new(); let path = tmpdir.join("list"); - if self.sess.target.target.options.is_like_solaris { + if self.sess.target.target.options.is_like_osx { + // Write a plain, newline-separated list of symbols + let res = (|| -> io::Result<()> { + let mut f = BufWriter::new(File::create(&path)?); + for sym in self.info.exports[&crate_type].iter() { + writeln!(f, "_{}", sym)?; + } + Ok(()) + })(); + if let Err(e) = res { + self.sess.fatal(&format!("failed to write lib.def file: {}", e)); + } + } else { + // Write an LD version script let res = (|| -> io::Result<()> { let mut f = BufWriter::new(File::create(&path)?); writeln!(f, "{{\n global:")?; @@ -266,33 +279,17 @@ impl<'a> Linker for GnuLinker<'a> { if let Err(e) = res { self.sess.fatal(&format!("failed to write version script: {}", e)); } - - arg.push("-Wl,-M,"); - arg.push(&path); - } else { - let prefix = if self.sess.target.target.options.is_like_osx { - "_" - } else { - "" - }; - let res = (|| -> io::Result<()> { - let mut f = BufWriter::new(File::create(&path)?); - for sym in self.info.exports[&crate_type].iter() { - writeln!(f, "{}{}", prefix, sym)?; - } - Ok(()) - })(); - if let Err(e) = res { - self.sess.fatal(&format!("failed to write lib.def file: {}", e)); - } - if self.sess.target.target.options.is_like_osx { - arg.push("-Wl,-exported_symbols_list,"); - } else { - arg.push("-Wl,--retain-symbols-file="); - } - arg.push(&path); } + if self.sess.target.target.options.is_like_osx { + arg.push("-Wl,-exported_symbols_list,"); + } else if self.sess.target.target.options.is_like_solaris { + arg.push("-Wl,-M,"); + } else { + arg.push("-Wl,--version-script="); + } + + arg.push(&path); self.cmd.arg(arg); } From bfd4910fa2c7a1487d06c7c9cb764bc31e787f12 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 1 Dec 2016 14:57:46 -0500 Subject: [PATCH 238/293] Linking: Include export lists in debug output. --- src/librustc_trans/back/linker.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index 67c8d268a81..d59ee5d825d 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -253,11 +253,14 @@ impl<'a> Linker for GnuLinker<'a> { let mut arg = OsString::new(); let path = tmpdir.join("list"); + debug!("EXPORTED SYMBOLS:"); + if self.sess.target.target.options.is_like_osx { // Write a plain, newline-separated list of symbols let res = (|| -> io::Result<()> { let mut f = BufWriter::new(File::create(&path)?); for sym in self.info.exports[&crate_type].iter() { + debug!(" _{}", sym); writeln!(f, "_{}", sym)?; } Ok(()) @@ -271,6 +274,7 @@ impl<'a> Linker for GnuLinker<'a> { let mut f = BufWriter::new(File::create(&path)?); writeln!(f, "{{\n global:")?; for sym in self.info.exports[&crate_type].iter() { + debug!(" {};", sym); writeln!(f, " {};", sym)?; } writeln!(f, "\n local:\n *;\n}};")?; From ea9f61353a77a704c9abf3fb1f8e19fdcecff6a9 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 1 Dec 2016 15:06:33 -0500 Subject: [PATCH 239/293] Add test case for symbol visibility in dylibs. --- src/test/run-make/symbol-visibility/Makefile | 26 +++++++++++++++++++ .../run-make/symbol-visibility/a_cdylib.rs | 22 ++++++++++++++++ .../symbol-visibility/a_rust_dylib.rs | 20 ++++++++++++++ .../symbol-visibility/an_executable.rs | 17 ++++++++++++ .../run-make/symbol-visibility/an_rlib.rs | 16 ++++++++++++ 5 files changed, 101 insertions(+) create mode 100644 src/test/run-make/symbol-visibility/Makefile create mode 100644 src/test/run-make/symbol-visibility/a_cdylib.rs create mode 100644 src/test/run-make/symbol-visibility/a_rust_dylib.rs create mode 100644 src/test/run-make/symbol-visibility/an_executable.rs create mode 100644 src/test/run-make/symbol-visibility/an_rlib.rs diff --git a/src/test/run-make/symbol-visibility/Makefile b/src/test/run-make/symbol-visibility/Makefile new file mode 100644 index 00000000000..d6c31d148b3 --- /dev/null +++ b/src/test/run-make/symbol-visibility/Makefile @@ -0,0 +1,26 @@ +include ../tools.mk + +all: + $(RUSTC) an_rlib.rs + $(RUSTC) a_cdylib.rs + $(RUSTC) a_rust_dylib.rs + $(RUSTC) an_executable.rs + + # Check that a cdylib exports its public #[no_mangle] functions + [ "$$(nm -D $(TMPDIR)/liba_cdylib.so | grep -c public_c_function_from_cdylib)" -eq "1" ] + # Check that a cdylib exports the public #[no_mangle] functions of dependencies + [ "$$(nm -D $(TMPDIR)/liba_cdylib.so | grep -c public_c_function_from_rlib)" -eq "1" ] + # Check that a cdylib DOES NOT export any public Rust functions + [ "$$(nm -D $(TMPDIR)/liba_cdylib.so | grep -c _ZN.*h.*E)" -eq "0" ] + + # Check that a Rust dylib exports its monomorphic functions + [ "$$(nm -D $(TMPDIR)/liba_rust_dylib.so | grep -c public_c_function_from_rust_dylib)" -eq "1" ] + [ "$$(nm -D $(TMPDIR)/liba_rust_dylib.so | grep -c _ZN.*public_rust_function_from_rust_dylib.*E)" -eq "1" ] + + # Check that a Rust dylib exports the monomorphic functions from its dependencies + [ "$$(nm -D $(TMPDIR)/liba_rust_dylib.so | grep -c public_c_function_from_rlib)" -eq "1" ] + [ "$$(nm -D $(TMPDIR)/liba_rust_dylib.so | grep -c public_rust_function_from_rlib)" -eq "1" ] + + # Check that an executable does not export any dynamic symbols + [ "$$(nm -D $(TMPDIR)/an_executable | grep -c public_c_function_from_rlib)" -eq "0" ] + [ "$$(nm -D $(TMPDIR)/an_executable | grep -c public_rust_function_from_exe)" -eq "0" ] diff --git a/src/test/run-make/symbol-visibility/a_cdylib.rs b/src/test/run-make/symbol-visibility/a_cdylib.rs new file mode 100644 index 00000000000..9a70542c06c --- /dev/null +++ b/src/test/run-make/symbol-visibility/a_cdylib.rs @@ -0,0 +1,22 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type="cdylib"] + +extern crate an_rlib; + +// This should not be exported +pub fn public_rust_function_from_cdylib() {} + +// This should be exported +#[no_mangle] +pub extern "C" fn public_c_function_from_cdylib() { + an_rlib::public_c_function_from_rlib(); +} diff --git a/src/test/run-make/symbol-visibility/a_rust_dylib.rs b/src/test/run-make/symbol-visibility/a_rust_dylib.rs new file mode 100644 index 00000000000..b826211c9a4 --- /dev/null +++ b/src/test/run-make/symbol-visibility/a_rust_dylib.rs @@ -0,0 +1,20 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type="dylib"] + +extern crate an_rlib; + +// This should be exported +pub fn public_rust_function_from_rust_dylib() {} + +// This should be exported +#[no_mangle] +pub extern "C" fn public_c_function_from_rust_dylib() {} diff --git a/src/test/run-make/symbol-visibility/an_executable.rs b/src/test/run-make/symbol-visibility/an_executable.rs new file mode 100644 index 00000000000..73059c5e374 --- /dev/null +++ b/src/test/run-make/symbol-visibility/an_executable.rs @@ -0,0 +1,17 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type="bin"] + +extern crate an_rlib; + +pub fn public_rust_function_from_exe() {} + +fn main() {} diff --git a/src/test/run-make/symbol-visibility/an_rlib.rs b/src/test/run-make/symbol-visibility/an_rlib.rs new file mode 100644 index 00000000000..cd19500d140 --- /dev/null +++ b/src/test/run-make/symbol-visibility/an_rlib.rs @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type="rlib"] + +pub fn public_rust_function_from_rlib() {} + +#[no_mangle] +pub extern "C" fn public_c_function_from_rlib() {} From 93da4f81bfb879eea9236d5fd16734a68836c97c Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 2 Dec 2016 18:00:41 -0500 Subject: [PATCH 240/293] Export the plugin registrar from proc-macro crates (and not much else) --- src/librustc_trans/back/symbol_export.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index 2290cb0f487..f99f543d9b7 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -60,6 +60,14 @@ impl ExportedSymbols { local_crate.push(("main".to_string(), SymbolExportLevel::C)); } + if let Some(id) = scx.sess().derive_registrar_fn.get() { + let svh = &scx.link_meta().crate_hash; + let def_id = scx.tcx().map.local_def_id(id); + let idx = def_id.index; + let registrar = scx.sess().generate_derive_registrar_symbol(svh, idx); + local_crate.push((registrar, SymbolExportLevel::C)); + } + if scx.sess().crate_types.borrow().contains(&config::CrateTypeDylib) { local_crate.push((scx.metadata_symbol_name(), SymbolExportLevel::Rust)); @@ -135,8 +143,8 @@ pub fn crate_export_threshold(crate_type: config::CrateType) match crate_type { config::CrateTypeExecutable | config::CrateTypeStaticlib | - config::CrateTypeCdylib => SymbolExportLevel::C, config::CrateTypeProcMacro | + config::CrateTypeCdylib => SymbolExportLevel::C, config::CrateTypeRlib | config::CrateTypeMetadata | config::CrateTypeDylib => SymbolExportLevel::Rust, From 3548c8f56011ade169453231389bade8ca8a6bb1 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 2 Dec 2016 18:02:14 -0500 Subject: [PATCH 241/293] Mention cdylibs in LTO error message. --- src/librustc_trans/back/lto.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index 1960b368278..f137bfff034 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -56,7 +56,7 @@ pub fn run(sess: &session::Session, // Make sure we actually can run LTO for crate_type in sess.crate_types.borrow().iter() { if !crate_type_allows_lto(*crate_type) { - sess.fatal("lto can only be run for executables and \ + sess.fatal("lto can only be run for executables, cdylibs and \ static library outputs"); } } From 8ecdc4ee3bde4a7986bafe4010f5358d89a4eeab Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 2 Dec 2016 18:02:46 -0500 Subject: [PATCH 242/293] Make symbol-visibility test case work on all platforms. --- src/test/run-make/symbol-visibility/Makefile | 42 +++++++++++++++----- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/src/test/run-make/symbol-visibility/Makefile b/src/test/run-make/symbol-visibility/Makefile index d6c31d148b3..988c9473f6a 100644 --- a/src/test/run-make/symbol-visibility/Makefile +++ b/src/test/run-make/symbol-visibility/Makefile @@ -1,5 +1,27 @@ include ../tools.mk +ifdef IS_WINDOWS +# Do nothing on MSVC. +# On MINGW the --version-script, --dynamic-list, and --retain-symbol args don't +# seem to work reliably. +all: + exit 0 +else + +NM=nm -D +DYLIB_EXT=so +CDYLIB_NAME=liba_cdylib.so +RDYLIB_NAME=liba_rust_dylib.so +EXE_NAME=an_executable + +ifeq ($(UNAME),Darwin) +NM=nm -gU +DYLIB_EXT=dylib +CDYLIB_NAME=liba_cdylib.dylib +RDYLIB_NAME=liba_rust_dylib.dylib +EXE_NAME=an_executable +endif + all: $(RUSTC) an_rlib.rs $(RUSTC) a_cdylib.rs @@ -7,20 +29,22 @@ all: $(RUSTC) an_executable.rs # Check that a cdylib exports its public #[no_mangle] functions - [ "$$(nm -D $(TMPDIR)/liba_cdylib.so | grep -c public_c_function_from_cdylib)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c public_c_function_from_cdylib)" -eq "1" ] # Check that a cdylib exports the public #[no_mangle] functions of dependencies - [ "$$(nm -D $(TMPDIR)/liba_cdylib.so | grep -c public_c_function_from_rlib)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ] # Check that a cdylib DOES NOT export any public Rust functions - [ "$$(nm -D $(TMPDIR)/liba_cdylib.so | grep -c _ZN.*h.*E)" -eq "0" ] + [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c _ZN.*h.*E)" -eq "0" ] # Check that a Rust dylib exports its monomorphic functions - [ "$$(nm -D $(TMPDIR)/liba_rust_dylib.so | grep -c public_c_function_from_rust_dylib)" -eq "1" ] - [ "$$(nm -D $(TMPDIR)/liba_rust_dylib.so | grep -c _ZN.*public_rust_function_from_rust_dylib.*E)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_c_function_from_rust_dylib)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_rust_function_from_rust_dylib.*E)" -eq "1" ] # Check that a Rust dylib exports the monomorphic functions from its dependencies - [ "$$(nm -D $(TMPDIR)/liba_rust_dylib.so | grep -c public_c_function_from_rlib)" -eq "1" ] - [ "$$(nm -D $(TMPDIR)/liba_rust_dylib.so | grep -c public_rust_function_from_rlib)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_rust_function_from_rlib)" -eq "1" ] # Check that an executable does not export any dynamic symbols - [ "$$(nm -D $(TMPDIR)/an_executable | grep -c public_c_function_from_rlib)" -eq "0" ] - [ "$$(nm -D $(TMPDIR)/an_executable | grep -c public_rust_function_from_exe)" -eq "0" ] + [ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -c public_c_function_from_rlib)" -eq "0" ] + [ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -c public_rust_function_from_exe)" -eq "0" ] + +endif From b700dd35e7fe9f3a987cca47a00ac0bdd1cfd425 Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Mon, 5 Dec 2016 16:31:05 -0800 Subject: [PATCH 243/293] Annotate more tests with kind="static" --- src/test/run-make/c-static-dylib/foo.rs | 2 +- src/test/run-make/c-static-rlib/foo.rs | 2 +- src/test/run-make/extern-fn-generic/test.rs | 2 +- src/test/run-make/extern-fn-generic/testcrate.rs | 2 +- src/test/run-make/interdependent-c-libraries/bar.rs | 2 +- src/test/run-make/interdependent-c-libraries/foo.rs | 2 +- src/test/run-make/issue-25581/test.rs | 2 +- src/test/run-make/link-path-order/main.rs | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/test/run-make/c-static-dylib/foo.rs b/src/test/run-make/c-static-dylib/foo.rs index 04253be71d4..44be5ac890d 100644 --- a/src/test/run-make/c-static-dylib/foo.rs +++ b/src/test/run-make/c-static-dylib/foo.rs @@ -10,7 +10,7 @@ #![crate_type = "dylib"] -#[link(name = "cfoo")] +#[link(name = "cfoo", kind = "static")] extern { fn foo(); } diff --git a/src/test/run-make/c-static-rlib/foo.rs b/src/test/run-make/c-static-rlib/foo.rs index a1f01bd2b62..cbd7b020bd8 100644 --- a/src/test/run-make/c-static-rlib/foo.rs +++ b/src/test/run-make/c-static-rlib/foo.rs @@ -10,7 +10,7 @@ #![crate_type = "rlib"] -#[link(name = "cfoo")] +#[link(name = "cfoo", kind = "static")] extern { fn foo(); } diff --git a/src/test/run-make/extern-fn-generic/test.rs b/src/test/run-make/extern-fn-generic/test.rs index ee0485683ec..8f5ff091b3b 100644 --- a/src/test/run-make/extern-fn-generic/test.rs +++ b/src/test/run-make/extern-fn-generic/test.rs @@ -12,7 +12,7 @@ extern crate testcrate; extern "C" fn bar(ts: testcrate::TestStruct) -> T { ts.y } -#[link(name = "test")] +#[link(name = "test", kind = "static")] extern { fn call(c: extern "C" fn(testcrate::TestStruct) -> i32) -> i32; } diff --git a/src/test/run-make/extern-fn-generic/testcrate.rs b/src/test/run-make/extern-fn-generic/testcrate.rs index 5fd61bb419c..d02c05047c0 100644 --- a/src/test/run-make/extern-fn-generic/testcrate.rs +++ b/src/test/run-make/extern-fn-generic/testcrate.rs @@ -18,7 +18,7 @@ pub struct TestStruct { pub extern "C" fn foo(ts: TestStruct) -> T { ts.y } -#[link(name = "test")] +#[link(name = "test", kind = "static")] extern { pub fn call(c: extern "C" fn(TestStruct) -> i32) -> i32; } diff --git a/src/test/run-make/interdependent-c-libraries/bar.rs b/src/test/run-make/interdependent-c-libraries/bar.rs index 88fc98615f0..1963976b4b0 100644 --- a/src/test/run-make/interdependent-c-libraries/bar.rs +++ b/src/test/run-make/interdependent-c-libraries/bar.rs @@ -12,7 +12,7 @@ extern crate foo; -#[link(name = "bar")] +#[link(name = "bar", kind = "static")] extern { fn bar(); } diff --git a/src/test/run-make/interdependent-c-libraries/foo.rs b/src/test/run-make/interdependent-c-libraries/foo.rs index f94c6edb97d..7a0fe6bb18f 100644 --- a/src/test/run-make/interdependent-c-libraries/foo.rs +++ b/src/test/run-make/interdependent-c-libraries/foo.rs @@ -10,7 +10,7 @@ #![crate_type = "rlib"] -#[link(name = "foo")] +#[link(name = "foo", kind = "static")] extern { fn foo(); } diff --git a/src/test/run-make/issue-25581/test.rs b/src/test/run-make/issue-25581/test.rs index e2e86df59cd..6717d16cb7c 100644 --- a/src/test/run-make/issue-25581/test.rs +++ b/src/test/run-make/issue-25581/test.rs @@ -12,7 +12,7 @@ extern crate libc; -#[link(name = "test")] +#[link(name = "test", kind = "static")] extern { fn slice_len(s: &[u8]) -> libc::size_t; fn slice_elem(s: &[u8], idx: libc::size_t) -> u8; diff --git a/src/test/run-make/link-path-order/main.rs b/src/test/run-make/link-path-order/main.rs index 450460cf192..aaac3927f1c 100644 --- a/src/test/run-make/link-path-order/main.rs +++ b/src/test/run-make/link-path-order/main.rs @@ -12,7 +12,7 @@ extern crate libc; -#[link(name="foo")] +#[link(name="foo", kind = "static")] extern { fn should_return_one() -> libc::c_int; } From 7d05d1e7f0add9e5151d48d51d92b6fb5885e257 Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Mon, 5 Dec 2016 10:15:14 -0800 Subject: [PATCH 244/293] Consider only libs that aren't excluded by #[link(cfg=...)] --- src/librustc_metadata/creader.rs | 24 ++++++++++++++++++++---- src/librustc_metadata/cstore.rs | 2 +- src/librustc_metadata/decoder.rs | 15 +++------------ 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 691bec19994..d36242537b8 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -113,6 +113,13 @@ fn register_native_lib(sess: &Session, cstore.add_used_library(lib); } +fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool { + match lib.cfg { + Some(ref cfg) => attr::cfg_matches(cfg, &sess.parse_sess, None), + None => true, + } +} + // Extra info about a crate loaded for plugins or exported macros. struct ExtensionCrate { metadata: PMDSource, @@ -290,7 +297,7 @@ impl<'a> CrateLoader<'a> { let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span, dep_kind); - let cmeta = Rc::new(cstore::CrateMetadata { + let mut cmeta = cstore::CrateMetadata { name: name, extern_crate: Cell::new(None), key_map: metadata.load_key_map(crate_root.index), @@ -308,9 +315,18 @@ impl<'a> CrateLoader<'a> { rlib: rlib, rmeta: rmeta, }, - dllimport_foreign_items: RefCell::new(None), - }); + dllimport_foreign_items: FxHashSet(), + }; + let dllimports: Vec<_> = cmeta.get_native_libraries().iter() + .filter(|lib| relevant_lib(self.sess, lib) && + lib.kind == cstore::NativeLibraryKind::NativeUnknown) + .flat_map(|lib| &lib.foreign_items) + .map(|id| *id) + .collect(); + cmeta.dllimport_foreign_items.extend(dllimports); + + let cmeta = Rc::new(cmeta); self.cstore.set_crate_data(cnum, cmeta.clone()); (cnum, cmeta) } @@ -643,7 +659,7 @@ impl<'a> CrateLoader<'a> { let mut items = vec![]; let libs = self.cstore.get_used_libraries(); for lib in libs.borrow().iter() { - if lib.kind == kind { + if relevant_lib(self.sess, lib) && lib.kind == kind { items.extend(&lib.foreign_items); } } diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 279ef5bfb72..7700ebde181 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -85,7 +85,7 @@ pub struct CrateMetadata { pub proc_macros: Option)>>, // Foreign items imported from a dylib (Windows only) - pub dllimport_foreign_items: RefCell>>, + pub dllimport_foreign_items: FxHashSet, } pub struct CachedInlinedItem { diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index f8f80a60c16..5bd1dea1d79 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -11,13 +11,13 @@ // Decoding metadata from a single crate's metadata use astencode::decode_inlined_item; -use cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary, NativeLibraryKind}; +use cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary}; use index::Index; use schema::*; use rustc::hir::map as hir_map; use rustc::hir::map::{DefKey, DefPathData}; -use rustc::util::nodemap::{FxHashMap, FxHashSet}; +use rustc::util::nodemap::FxHashMap; use rustc::hir; use rustc::hir::intravisit::IdRange; @@ -36,7 +36,6 @@ use rustc::mir::Mir; use std::borrow::Cow; use std::cell::Ref; use std::io; -use std::iter::FromIterator; use std::mem; use std::str; use std::u32; @@ -1089,15 +1088,7 @@ impl<'a, 'tcx> CrateMetadata { } pub fn is_dllimport_foreign_item(&self, id: DefIndex) -> bool { - if self.dllimport_foreign_items.borrow().is_none() { - *self.dllimport_foreign_items.borrow_mut() = Some(FxHashSet::from_iter( - self.get_native_libraries().iter() - .filter(|lib| lib.kind == NativeLibraryKind::NativeUnknown) - .flat_map(|lib| &lib.foreign_items) - .map(|id| *id) - )); - } - self.dllimport_foreign_items.borrow().as_ref().unwrap().contains(&id) + self.dllimport_foreign_items.contains(&id) } pub fn is_defaulted_trait(&self, trait_id: DefIndex) -> bool { From 58e70e7b14fcf58ea4ee0cedd198cd1ab5ececa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 30 Nov 2016 00:07:31 -0800 Subject: [PATCH 245/293] Warn when an import list is empty For a given file ```rust use std::*; use std::{}; ``` output the following warnings ``` warning: unused import: `use std::{};`, #[warn(unused_imports)] on by default --> file.rs:2:1 | 2 | use std::{}; | ^^^^^^^^^^^^ warning: unused import: `std::*;`, #[warn(unused_imports)] on by default --> file.rs:1:5 | 1 | use std::*; | ^^^^^^^ ``` --- src/librustc_resolve/check_unused.rs | 6 ++++++ src/test/compile-fail/issue-28388-1.rs | 4 +++- src/test/compile-fail/issue-28388-2.rs | 3 ++- src/test/compile-fail/issue-28388-3.rs | 3 ++- src/test/compile-fail/lint-unused-imports.rs | 2 ++ 5 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs index 492c5e695bb..5db622a4e7d 100644 --- a/src/librustc_resolve/check_unused.rs +++ b/src/librustc_resolve/check_unused.rs @@ -103,6 +103,12 @@ impl<'a, 'b> Visitor for UnusedImportCheckVisitor<'a, 'b> { } ViewPathList(_, ref list) => { + if list.len() == 0 { + self.unused_imports + .entry(item.id) + .or_insert_with(NodeMap) + .insert(item.id, item.span); + } for i in list { self.check_import(item.id, i.node.id, i.span); } diff --git a/src/test/compile-fail/issue-28388-1.rs b/src/test/compile-fail/issue-28388-1.rs index bee05cd5313..ed7851ec0f1 100644 --- a/src/test/compile-fail/issue-28388-1.rs +++ b/src/test/compile-fail/issue-28388-1.rs @@ -10,6 +10,8 @@ // Prefix in imports with empty braces should be resolved and checked privacy, stability, etc. -use foo::{}; //~ ERROR failed to resolve. Maybe a missing `extern crate foo;`? +use foo::{}; +//~^ ERROR failed to resolve. Maybe a missing `extern crate foo;`? +//~| NOTE foo fn main() {} diff --git a/src/test/compile-fail/issue-28388-2.rs b/src/test/compile-fail/issue-28388-2.rs index 837dc67c804..4ed5bfab06f 100644 --- a/src/test/compile-fail/issue-28388-2.rs +++ b/src/test/compile-fail/issue-28388-2.rs @@ -14,6 +14,7 @@ mod m { mod n {} } -use m::n::{}; //~ ERROR module `n` is private +use m::n::{}; +//~^ ERROR module `n` is private fn main() {} diff --git a/src/test/compile-fail/issue-28388-3.rs b/src/test/compile-fail/issue-28388-3.rs index 0cb669f5f8f..4baaa16e772 100644 --- a/src/test/compile-fail/issue-28388-3.rs +++ b/src/test/compile-fail/issue-28388-3.rs @@ -14,7 +14,8 @@ extern crate lint_stability; -use lint_stability::UnstableStruct::{}; //~ ERROR use of unstable library feature 'test_feature' +use lint_stability::UnstableStruct::{}; +//~^ ERROR use of unstable library feature 'test_feature' use lint_stability::StableStruct::{}; // OK fn main() {} diff --git a/src/test/compile-fail/lint-unused-imports.rs b/src/test/compile-fail/lint-unused-imports.rs index 5b1c04946a4..f6f7c210f46 100644 --- a/src/test/compile-fail/lint-unused-imports.rs +++ b/src/test/compile-fail/lint-unused-imports.rs @@ -15,6 +15,8 @@ use bar::c::cc as cal; use std::mem::*; // shouldn't get errors for not using // everything imported +use std::fmt::{}; +//~^ ERROR unused import: `use std::fmt::{};` // Should get errors for both 'Some' and 'None' use std::option::Option::{Some, None}; From 5caec61a7f459c2a62c2ab1c32bbd565e079766f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 5 Dec 2016 18:33:03 -0800 Subject: [PATCH 246/293] Add missing links to Rc doc --- src/liballoc/rc.rs | 88 ++++++++++++++++++++++++---------------------- 1 file changed, 45 insertions(+), 43 deletions(-) diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 8d863d7d9e9..d1e0e333b8f 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -12,35 +12,35 @@ //! Single-threaded reference-counting pointers. //! -//! The type [`Rc`][rc] provides shared ownership of a value of type `T`, -//! allocated in the heap. Invoking [`clone`][clone] on `Rc` produces a new -//! pointer to the same value in the heap. When the last `Rc` pointer to a +//! The type [`Rc`][`Rc`] provides shared ownership of a value of type `T`, +//! allocated in the heap. Invoking [`clone()`][clone] on [`Rc`] produces a new +//! pointer to the same value in the heap. When the last [`Rc`] pointer to a //! given value is destroyed, the pointed-to value is also destroyed. //! //! Shared references in Rust disallow mutation by default, and `Rc` is no -//! exception. If you need to mutate through an `Rc`, use [`Cell`][cell] or -//! [`RefCell`][refcell]. +//! exception. If you need to mutate through an [`Rc`], use [`Cell`] or +//! [`RefCell`]. //! -//! `Rc` uses non-atomic reference counting. This means that overhead is very -//! low, but an `Rc` cannot be sent between threads, and consequently `Rc` +//! [`Rc`] uses non-atomic reference counting. This means that overhead is very +//! low, but an [`Rc`] cannot be sent between threads, and consequently [`Rc`] //! does not implement [`Send`][send]. As a result, the Rust compiler -//! will check *at compile time* that you are not sending `Rc`s between +//! will check *at compile time* that you are not sending [`Rc`]s between //! threads. If you need multi-threaded, atomic reference counting, use //! [`sync::Arc`][arc]. //! -//! The [`downgrade`][downgrade] method can be used to create a non-owning -//! [`Weak`][weak] pointer. A `Weak` pointer can be [`upgrade`][upgrade]d -//! to an `Rc`, but this will return [`None`][option] if the value has +//! The [`downgrade()`][downgrade] method can be used to create a non-owning +//! [`Weak`] pointer. A [`Weak`] pointer can be [`upgrade`][upgrade]d +//! to an [`Rc`], but this will return [`None`] if the value has //! already been dropped. //! -//! A cycle between `Rc` pointers will never be deallocated. For this reason, -//! `Weak` is used to break cycles. For example, a tree could have strong -//! `Rc` pointers from parent nodes to children, and `Weak` pointers from +//! A cycle between [`Rc`] pointers will never be deallocated. For this reason, +//! [`Weak`] is used to break cycles. For example, a tree could have strong +//! [`Rc`] pointers from parent nodes to children, and [`Weak`] pointers from //! children back to their parents. //! -//! `Rc` automatically dereferences to `T` (via the [`Deref`][deref] trait), -//! so you can call `T`'s methods on a value of type `Rc`. To avoid name -//! clashes with `T`'s methods, the methods of `Rc` itself are [associated +//! `Rc` automatically dereferences to `T` (via the [`Deref`] trait), +//! so you can call `T`'s methods on a value of type [`Rc`][`Rc`]. To avoid name +//! clashes with `T`'s methods, the methods of [`Rc`][`Rc`] itself are [associated //! functions][assoc], called using function-like syntax: //! //! ``` @@ -50,28 +50,15 @@ //! Rc::downgrade(&my_rc); //! ``` //! -//! `Weak` does not auto-dereference to `T`, because the value may have +//! [`Weak`][`Weak`] does not auto-dereference to `T`, because the value may have //! already been destroyed. //! -//! [rc]: struct.Rc.html -//! [weak]: struct.Weak.html -//! [clone]: ../../std/clone/trait.Clone.html#tymethod.clone -//! [cell]: ../../std/cell/struct.Cell.html -//! [refcell]: ../../std/cell/struct.RefCell.html -//! [send]: ../../std/marker/trait.Send.html -//! [arc]: ../../std/sync/struct.Arc.html -//! [deref]: ../../std/ops/trait.Deref.html -//! [downgrade]: struct.Rc.html#method.downgrade -//! [upgrade]: struct.Weak.html#method.upgrade -//! [option]: ../../std/option/enum.Option.html -//! [assoc]: ../../book/method-syntax.html#associated-functions -//! //! # Examples //! //! Consider a scenario where a set of `Gadget`s are owned by a given `Owner`. //! We want to have our `Gadget`s point to their `Owner`. We can't do this with //! unique ownership, because more than one gadget may belong to the same -//! `Owner`. `Rc` allows us to share an `Owner` between multiple `Gadget`s, +//! `Owner`. [`Rc`] allows us to share an `Owner` between multiple `Gadget`s, //! and have the `Owner` remain allocated as long as any `Gadget` points at it. //! //! ``` @@ -127,20 +114,20 @@ //! ``` //! //! If our requirements change, and we also need to be able to traverse from -//! `Owner` to `Gadget`, we will run into problems. An `Rc` pointer from `Owner` +//! `Owner` to `Gadget`, we will run into problems. An [`Rc`] pointer from `Owner` //! to `Gadget` introduces a cycle between the values. This means that their //! reference counts can never reach 0, and the values will remain allocated -//! forever: a memory leak. In order to get around this, we can use `Weak` +//! forever: a memory leak. In order to get around this, we can use [`Weak`] //! pointers. //! //! Rust actually makes it somewhat difficult to produce this loop in the first //! place. In order to end up with two values that point at each other, one of -//! them needs to be mutable. This is difficult because `Rc` enforces +//! them needs to be mutable. This is difficult because [`Rc`] enforces //! memory safety by only giving out shared references to the value it wraps, //! and these don't allow direct mutation. We need to wrap the part of the -//! value we wish to mutate in a [`RefCell`][refcell], which provides *interior +//! value we wish to mutate in a [`RefCell`], which provides *interior //! mutability*: a method to achieve mutability through a shared reference. -//! `RefCell` enforces Rust's borrowing rules at runtime. +//! [`RefCell`] enforces Rust's borrowing rules at runtime. //! //! ``` //! use std::rc::Rc; @@ -214,6 +201,19 @@ //! // Gadget Man, so he gets destroyed as well. //! } //! ``` +//! +//! [`Rc`]: struct.Rc.html +//! [`Weak`]: struct.Weak.html +//! [clone]: ../../std/clone/trait.Clone.html#tymethod.clone +//! [`Cell`]: ../../std/cell/struct.Cell.html +//! [`RefCell`]: ../../std/cell/struct.RefCell.html +//! [send]: ../../std/marker/trait.Send.html +//! [arc]: ../../std/sync/struct.Arc.html +//! [`Deref`]: ../../std/ops/trait.Deref.html +//! [downgrade]: struct.Rc.html#method.downgrade +//! [upgrade]: struct.Weak.html#method.upgrade +//! [`None`]: ../../std/option/enum.Option.html#variant.None +//! [assoc]: ../../book/method-syntax.html#associated-functions #![stable(feature = "rust1", since = "1.0.0")] @@ -251,9 +251,11 @@ struct RcBox { /// See the [module-level documentation](./index.html) for more details. /// /// The inherent methods of `Rc` are all associated functions, which means -/// that you have to call them as e.g. `Rc::get_mut(&value)` instead of -/// `value.get_mut()`. This avoids conflicts with methods of the inner +/// that you have to call them as e.g. [`Rc::get_mut(&value)`][get_mut] instead of +/// `value.get_mut()`. This avoids conflicts with methods of the inner /// type `T`. +/// +/// [get_mut]: #method.get_mut #[stable(feature = "rust1", since = "1.0.0")] pub struct Rc { ptr: Shared>, @@ -337,10 +339,10 @@ impl Rc { } /// Checks whether [`Rc::try_unwrap`][try_unwrap] would return - /// [`Ok`][result]. + /// [`Ok`]. /// /// [try_unwrap]: struct.Rc.html#method.try_unwrap - /// [result]: ../../std/result/enum.Result.html + /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok /// /// # Examples /// @@ -543,14 +545,14 @@ impl Rc { /// Returns a mutable reference to the inner value, if there are /// no other `Rc` or [`Weak`][weak] pointers to the same value. /// - /// Returns [`None`][option] otherwise, because it is not safe to + /// Returns [`None`] otherwise, because it is not safe to /// mutate a shared value. /// /// See also [`make_mut`][make_mut], which will [`clone`][clone] /// the inner value when it's shared. /// /// [weak]: struct.Weak.html - /// [option]: ../../std/option/enum.Option.html + /// [`None`]: ../../std/option/enum.Option.html#variant.None /// [make_mut]: struct.Rc.html#method.make_mut /// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone /// From 1eab19dba844f0545527b043c5f812152658939d Mon Sep 17 00:00:00 2001 From: Mark-Simulacrum Date: Mon, 28 Nov 2016 19:35:38 -0700 Subject: [PATCH 247/293] Refactor ty::FnSig to privatize all fields --- src/librustc/middle/intrinsicck.rs | 4 +-- src/librustc/traits/object_safety.rs | 4 +-- src/librustc/traits/select.rs | 14 ++------ src/librustc/traits/util.rs | 7 ++-- src/librustc/ty/fast_reject.rs | 2 +- src/librustc/ty/flags.rs | 4 +-- src/librustc/ty/relate.rs | 35 ++++++------------- src/librustc/ty/structural_impls.rs | 18 ++++------ src/librustc/ty/sty.rs | 30 ++++++++++++---- src/librustc/ty/util.rs | 2 +- src/librustc/ty/walk.rs | 4 +-- src/librustc/util/ppaux.rs | 4 +-- src/librustc_lint/builtin.rs | 4 +-- src/librustc_lint/types.rs | 12 +++---- src/librustc_mir/build/expr/into.rs | 2 +- src/librustc_mir/hair/cx/expr.rs | 4 +-- src/librustc_mir/mir_map.rs | 4 +-- src/librustc_mir/transform/type_check.rs | 16 ++++----- src/librustc_trans/abi.rs | 16 ++++----- src/librustc_trans/base.rs | 6 ++-- src/librustc_trans/callee.rs | 32 ++++++++++++----- src/librustc_trans/common.rs | 19 ++++++----- src/librustc_trans/debuginfo/metadata.rs | 8 ++--- src/librustc_trans/debuginfo/mod.rs | 14 ++++---- src/librustc_trans/debuginfo/type_names.rs | 12 +++---- src/librustc_trans/declare.rs | 2 +- src/librustc_trans/intrinsic.rs | 20 ++++------- src/librustc_trans/mir/block.rs | 8 ++--- src/librustc_trans/trans_item.rs | 24 +++++-------- src/librustc_typeck/astconv.rs | 19 ++++------- src/librustc_typeck/check/callee.rs | 38 ++++++++++----------- src/librustc_typeck/check/closure.rs | 11 +++--- src/librustc_typeck/check/compare_method.rs | 13 +++---- src/librustc_typeck/check/intrinsic.rs | 20 ++++------- src/librustc_typeck/check/method/mod.rs | 2 +- src/librustc_typeck/check/mod.rs | 17 +++++---- src/librustc_typeck/check/regionck.rs | 11 +++--- src/librustc_typeck/check/wfcheck.rs | 12 +++---- src/librustc_typeck/collect.rs | 10 ++---- src/librustc_typeck/lib.rs | 16 ++++----- src/librustc_typeck/variance/constraints.rs | 4 +-- src/librustdoc/clean/mod.rs | 6 ++-- 42 files changed, 238 insertions(+), 272 deletions(-) diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index 6896c69d7db..2357549c82e 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -178,8 +178,8 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for ExprVisitor<'a, 'gcx, 'tcx> { let typ = self.infcx.tcx.tables().node_id_to_type(expr.id); match typ.sty { ty::TyFnDef(.., ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => { - let from = bare_fn_ty.sig.0.inputs[0]; - let to = bare_fn_ty.sig.0.output; + let from = bare_fn_ty.sig.skip_binder().inputs()[0]; + let to = bare_fn_ty.sig.skip_binder().output(); self.check_transmute(expr.span, from, to, expr.id); } _ => { diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index ceee6c236e4..0d5c9b98941 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -241,12 +241,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // The `Self` type is erased, so it should not appear in list of // arguments or return type apart from the receiver. let ref sig = self.item_type(method.def_id).fn_sig(); - for &input_ty in &sig.0.inputs[1..] { + for input_ty in &sig.skip_binder().inputs()[1..] { if self.contains_illegal_self_type_reference(trait_def_id, input_ty) { return Some(MethodViolationCode::ReferencesSelf); } } - if self.contains_illegal_self_type_reference(trait_def_id, sig.0.output) { + if self.contains_illegal_self_type_reference(trait_def_id, sig.output().skip_binder()) { return Some(MethodViolationCode::ReferencesSelf); } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index c54c0bf74ef..23cfc251759 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1368,21 +1368,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::TyFnDef(.., &ty::BareFnTy { unsafety: hir::Unsafety::Normal, abi: Abi::Rust, - sig: ty::Binder(ty::FnSig { - inputs: _, - output: _, - variadic: false - }) + ref sig, }) | ty::TyFnPtr(&ty::BareFnTy { unsafety: hir::Unsafety::Normal, abi: Abi::Rust, - sig: ty::Binder(ty::FnSig { - inputs: _, - output: _, - variadic: false - }) - }) => { + ref sig + }) if !sig.variadic() => { candidates.vec.push(FnPointerCandidate); } diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 321936fe54b..cebd8bf87d7 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -487,14 +487,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>)> { let arguments_tuple = match tuple_arguments { - TupleArgumentsFlag::No => sig.0.inputs[0], - TupleArgumentsFlag::Yes => self.intern_tup(&sig.0.inputs[..]), + TupleArgumentsFlag::No => sig.skip_binder().inputs()[0], + TupleArgumentsFlag::Yes => + self.intern_tup(sig.skip_binder().inputs()), }; let trait_ref = ty::TraitRef { def_id: fn_trait_def_id, substs: self.mk_substs_trait(self_ty, &[arguments_tuple]), }; - ty::Binder((trait_ref, sig.0.output)) + ty::Binder((trait_ref, sig.skip_binder().output())) } } diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs index ade6cad6866..7b4d76ad497 100644 --- a/src/librustc/ty/fast_reject.rs +++ b/src/librustc/ty/fast_reject.rs @@ -81,7 +81,7 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, Some(TupleSimplifiedType(tys.len())) } ty::TyFnDef(.., ref f) | ty::TyFnPtr(ref f) => { - Some(FunctionSimplifiedType(f.sig.0.inputs.len())) + Some(FunctionSimplifiedType(f.sig.skip_binder().inputs().len())) } ty::TyProjection(_) | ty::TyParam(_) => { if can_simplify_params { diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 2bcbccb7d05..a06d3ed6cf4 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -180,8 +180,8 @@ impl FlagComputation { fn add_fn_sig(&mut self, fn_sig: &ty::PolyFnSig) { let mut computation = FlagComputation::new(); - computation.add_tys(&fn_sig.0.inputs); - computation.add_ty(fn_sig.0.output); + computation.add_tys(fn_sig.skip_binder().inputs()); + computation.add_ty(fn_sig.skip_binder().output()); self.add_bound_computation(&computation); } diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 8cb1483107f..171519b0664 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -180,37 +180,24 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> { -> RelateResult<'tcx, ty::FnSig<'tcx>> where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a { - if a.variadic != b.variadic { + if a.variadic() != b.variadic() { return Err(TypeError::VariadicMismatch( - expected_found(relation, &a.variadic, &b.variadic))); + expected_found(relation, &a.variadic(), &b.variadic()))); } - let inputs = relate_arg_vecs(relation, - &a.inputs, - &b.inputs)?; - let output = relation.relate(&a.output, &b.output)?; + if a.inputs().len() != b.inputs().len() { + return Err(TypeError::ArgCount); + } - Ok(ty::FnSig {inputs: inputs, - output: output, - variadic: a.variadic}) + let inputs = a.inputs().iter().zip(b.inputs()).map(|(&a, &b)| { + relation.relate_with_variance(ty::Contravariant, &a, &b) + }).collect::, _>>()?; + let output = relation.relate(&a.output(), &b.output())?; + + Ok(ty::FnSig::new(inputs, output, a.variadic())) } } -fn relate_arg_vecs<'a, 'gcx, 'tcx, R>(relation: &mut R, - a_args: &[Ty<'tcx>], - b_args: &[Ty<'tcx>]) - -> RelateResult<'tcx, Vec>> - where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a -{ - if a_args.len() != b_args.len() { - return Err(TypeError::ArgCount); - } - - a_args.iter().zip(b_args) - .map(|(a, b)| relation.relate_with_variance(ty::Contravariant, a, b)) - .collect() -} - impl<'tcx> Relate<'tcx> for ast::Unsafety { fn relate<'a, 'gcx, R>(relation: &mut R, a: &ast::Unsafety, diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 88de3575274..9ca30850bcd 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -232,13 +232,9 @@ impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::AutoBorrow<'a> { impl<'a, 'tcx> Lift<'tcx> for ty::FnSig<'a> { type Lifted = ty::FnSig<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { - tcx.lift(&self.inputs[..]).and_then(|inputs| { - tcx.lift(&self.output).map(|output| { - ty::FnSig { - inputs: inputs, - output: output, - variadic: self.variadic - } + tcx.lift(self.inputs()).and_then(|inputs| { + tcx.lift(&self.output()).map(|output| { + ty::FnSig::new(inputs, output, self.variadic()) }) }) } @@ -589,9 +585,9 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeAndMut<'tcx> { impl<'tcx> TypeFoldable<'tcx> for ty::FnSig<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - ty::FnSig { inputs: self.inputs.fold_with(folder), - output: self.output.fold_with(folder), - variadic: self.variadic } + ty::FnSig::new(self.inputs().to_owned().fold_with(folder), + self.output().fold_with(folder), + self.variadic()) } fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { @@ -599,7 +595,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::FnSig<'tcx> { } fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.inputs.visit_with(visitor) || self.output.visit_with(visitor) + self.inputs().to_owned().visit_with(visitor) || self.output().visit_with(visitor) } } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 59f774b954c..6c54d558ab7 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -563,16 +563,34 @@ pub struct ClosureTy<'tcx> { /// - `variadic` indicates whether this is a variadic function. (only true for foreign fns) #[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct FnSig<'tcx> { - pub inputs: Vec>, - pub output: Ty<'tcx>, - pub variadic: bool + inputs: Vec>, + output: Ty<'tcx>, + variadic: bool +} + +impl<'tcx> FnSig<'tcx> { + pub fn new(inputs: Vec>, output: Ty<'tcx>, variadic: bool) -> Self { + FnSig { inputs: inputs, output: output, variadic: variadic } + } + + pub fn inputs(&self) -> &[Ty<'tcx>] { + &self.inputs + } + + pub fn output(&self) -> Ty<'tcx> { + self.output + } + + pub fn variadic(&self) -> bool { + self.variadic + } } pub type PolyFnSig<'tcx> = Binder>; impl<'tcx> PolyFnSig<'tcx> { - pub fn inputs(&self) -> ty::Binder>> { - self.map_bound_ref(|fn_sig| fn_sig.inputs.clone()) + pub fn inputs<'a>(&'a self) -> Binder<&[Ty<'tcx>]> { + Binder(self.0.inputs()) } pub fn input(&self, index: usize) -> ty::Binder> { self.map_bound_ref(|fn_sig| fn_sig.inputs[index]) @@ -1244,7 +1262,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { // Type accessors for substructures of types pub fn fn_args(&self) -> ty::Binder>> { - self.fn_sig().inputs() + ty::Binder(self.fn_sig().inputs().skip_binder().iter().cloned().collect::>()) } pub fn fn_ret(&self) -> Binder> { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 6bb9d67db6f..e6db35cc3f5 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -530,7 +530,7 @@ impl<'a, 'gcx, 'tcx, H: Hasher> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tc self.hash(f.unsafety); self.hash(f.abi); self.hash(f.sig.variadic()); - self.hash(f.sig.inputs().skip_binder().len()); + self.hash(f.sig.skip_binder().inputs().len()); } TyDynamic(ref data, ..) => { if let Some(p) = data.principal() { diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index 0848dcd2c8d..3fa7a803141 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -126,6 +126,6 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) { } fn push_sig_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, sig: &ty::PolyFnSig<'tcx>) { - stack.push(sig.0.output); - stack.extend(sig.0.inputs.iter().cloned().rev()); + stack.push(sig.skip_binder().output()); + stack.extend(sig.skip_binder().inputs().iter().cloned().rev()); } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index b4c87e0ce42..3a973fe7bc5 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -595,7 +595,7 @@ impl<'tcx> fmt::Debug for ty::InstantiatedPredicates<'tcx> { impl<'tcx> fmt::Display for ty::FnSig<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "fn")?; - fn_sig(f, &self.inputs, self.variadic, self.output) + fn_sig(f, self.inputs(), self.variadic(), self.output()) } } @@ -625,7 +625,7 @@ impl fmt::Debug for ty::RegionVid { impl<'tcx> fmt::Debug for ty::FnSig<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "({:?}; variadic: {})->{:?}", self.inputs, self.variadic, self.output) + write!(f, "({:?}; variadic: {})->{:?}", self.inputs(), self.variadic(), self.output()) } } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index f14fa7d4fdc..ee6af643154 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1084,8 +1084,8 @@ impl LateLintPass for MutableTransmutes { let typ = cx.tcx.tables().node_id_to_type(expr.id); match typ.sty { ty::TyFnDef(.., ref bare_fn) if bare_fn.abi == RustIntrinsic => { - let from = bare_fn.sig.0.inputs[0]; - let to = bare_fn.sig.0.output; + let from = bare_fn.sig.skip_binder().inputs()[0]; + let to = bare_fn.sig.skip_binder().output(); return Some((&from.sty, &to.sty)); } _ => (), diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index bba31c8237d..6475166192a 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -603,8 +603,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } let sig = cx.erase_late_bound_regions(&bare_fn.sig); - if !sig.output.is_nil() { - let r = self.check_type_for_ffi(cache, sig.output); + if !sig.output().is_nil() { + let r = self.check_type_for_ffi(cache, sig.output()); match r { FfiSafe => {} _ => { @@ -612,7 +612,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } } } - for arg in sig.inputs { + for arg in sig.inputs() { let r = self.check_type_for_ffi(cache, arg); match r { FfiSafe => {} @@ -678,12 +678,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { let sig = self.cx.tcx.item_type(def_id).fn_sig(); let sig = self.cx.tcx.erase_late_bound_regions(&sig); - for (&input_ty, input_hir) in sig.inputs.iter().zip(&decl.inputs) { - self.check_type_for_ffi_and_report_errors(input_hir.ty.span, &input_ty); + for (input_ty, input_hir) in sig.inputs().iter().zip(&decl.inputs) { + self.check_type_for_ffi_and_report_errors(input_hir.ty.span, input_ty); } if let hir::Return(ref ret_hir) = decl.output { - let ret_ty = sig.output; + let ret_ty = sig.output(); if !ret_ty.is_nil() { self.check_type_for_ffi_and_report_errors(ret_hir.span, ret_ty); } diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 5a77de08070..ffd9525933b 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -208,7 +208,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let diverges = match ty.sty { ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => { // FIXME(canndrew): This is_never should probably be an is_uninhabited - f.sig.0.output.is_never() + f.sig.skip_binder().output().is_never() } _ => false }; diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index e850f6c4b04..bd4724159b4 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -247,10 +247,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, span_bug!(expr.span, "method call has late-bound regions") }); - assert_eq!(sig.inputs.len(), 2); + assert_eq!(sig.inputs().len(), 2); let tupled_args = Expr { - ty: sig.inputs[1], + ty: sig.inputs()[1], temp_lifetime: temp_lifetime, span: expr.span, kind: ExprKind::Tuple { diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index 88d02d7d004..e2a516edbc8 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -238,14 +238,14 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> { .iter() .enumerate() .map(|(index, arg)| { - (fn_sig.inputs[index], Some(&*arg.pat)) + (fn_sig.inputs()[index], Some(&*arg.pat)) }); let body = self.tcx.map.expr(body_id); let arguments = implicit_argument.into_iter().chain(explicit_arguments); self.cx(MirSource::Fn(id)).build(|cx| { - build::construct_fn(cx, id, arguments, abi, fn_sig.output, body) + build::construct_fn(cx, id, arguments, abi, fn_sig.output(), body) }); intravisit::walk_fn(self, fk, decl, body_id, span, id); diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 0ceed274b6d..f65b4e55d47 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -506,15 +506,15 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { match *destination { Some((ref dest, _)) => { let dest_ty = dest.ty(mir, tcx).to_ty(tcx); - if let Err(terr) = self.sub_types(sig.output, dest_ty) { + if let Err(terr) = self.sub_types(sig.output(), dest_ty) { span_mirbug!(self, term, "call dest mismatch ({:?} <- {:?}): {:?}", - dest_ty, sig.output, terr); + dest_ty, sig.output(), terr); } }, None => { // FIXME(canndrew): This is_never should probably be an is_uninhabited - if !sig.output.is_never() { + if !sig.output().is_never() { span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig); } }, @@ -528,11 +528,11 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { args: &[Operand<'tcx>]) { debug!("check_call_inputs({:?}, {:?})", sig, args); - if args.len() < sig.inputs.len() || - (args.len() > sig.inputs.len() && !sig.variadic) { + if args.len() < sig.inputs().len() || + (args.len() > sig.inputs().len() && !sig.variadic()) { span_mirbug!(self, term, "call to {:?} with wrong # of args", sig); } - for (n, (fn_arg, op_arg)) in sig.inputs.iter().zip(args).enumerate() { + for (n, (fn_arg, op_arg)) in sig.inputs().iter().zip(args).enumerate() { let op_arg_ty = op_arg.ty(mir, self.tcx()); if let Err(terr) = self.sub_types(op_arg_ty, fn_arg) { span_mirbug!(self, term, "bad arg #{:?} ({:?} <- {:?}): {:?}", @@ -562,12 +562,12 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { // box_free takes a Box as a pointer. Allow for that. - if sig.inputs.len() != 1 { + if sig.inputs().len() != 1 { span_mirbug!(self, term, "box_free should take 1 argument"); return; } - let pointee_ty = match sig.inputs[0].sty { + let pointee_ty = match sig.inputs()[0].sty { ty::TyRawPtr(mt) => mt.ty, _ => { span_mirbug!(self, term, "box_free should take a raw ptr"); diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 07f53466b49..e780b8685e1 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -367,13 +367,13 @@ impl FnType { Cdecl => llvm::CCallConv, }; - let mut inputs = &sig.inputs[..]; + let mut inputs = sig.inputs(); let extra_args = if abi == RustCall { - assert!(!sig.variadic && extra_args.is_empty()); + assert!(!sig.variadic() && extra_args.is_empty()); - match inputs[inputs.len() - 1].sty { + match sig.inputs().last().unwrap().sty { ty::TyTuple(ref tupled_arguments) => { - inputs = &inputs[..inputs.len() - 1]; + inputs = &sig.inputs()[0..sig.inputs().len() - 1]; &tupled_arguments[..] } _ => { @@ -382,7 +382,7 @@ impl FnType { } } } else { - assert!(sig.variadic || extra_args.is_empty()); + assert!(sig.variadic() || extra_args.is_empty()); extra_args }; @@ -428,7 +428,7 @@ impl FnType { } }; - let ret_ty = sig.output; + let ret_ty = sig.output(); let mut ret = arg_of(ret_ty, true); if !type_is_fat_ptr(ccx.tcx(), ret_ty) { @@ -525,7 +525,7 @@ impl FnType { FnType { args: args, ret: ret, - variadic: sig.variadic, + variadic: sig.variadic(), cconv: cconv } } @@ -569,7 +569,7 @@ impl FnType { }; // Fat pointers are returned by-value. if !self.ret.is_ignore() { - if !type_is_fat_ptr(ccx.tcx(), sig.output) { + if !type_is_fat_ptr(ccx.tcx(), sig.output()) { fixup(&mut self.ret); } } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index a31b61e42c4..8cc47dc8168 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1077,8 +1077,8 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let dest_val = adt::MaybeSizedValue::sized(dest); // Can return unsized value let mut llarg_idx = fcx.fn_ty.ret.is_indirect() as usize; let mut arg_idx = 0; - for (i, arg_ty) in sig.inputs.into_iter().enumerate() { - let lldestptr = adt::trans_field_ptr(bcx, sig.output, dest_val, Disr::from(disr), i); + for (i, arg_ty) in sig.inputs().into_iter().enumerate() { + let lldestptr = adt::trans_field_ptr(bcx, sig.output(), dest_val, Disr::from(disr), i); let arg = &fcx.fn_ty.args[arg_idx]; arg_idx += 1; let b = &bcx.build(); @@ -1091,7 +1091,7 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg.store_fn_arg(b, &mut llarg_idx, lldestptr); } } - adt::trans_set_discr(bcx, sig.output, dest, disr); + adt::trans_set_discr(bcx, sig.output(), dest, disr); } fcx.finish(bcx, DebugLoc::None); diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index df56e27128c..0d1fd4d69b1 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -329,7 +329,14 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( // Make a version with the type of by-ref closure. let ty::ClosureTy { unsafety, abi, mut sig } = tcx.closure_type(def_id, substs); - sig.0.inputs.insert(0, ref_closure_ty); // sig has no self type as of yet + sig.0 = ty::FnSig::new({ + let mut inputs = sig.0.inputs().to_owned(); + inputs.insert(0, ref_closure_ty); // sig has no self type as of yet + inputs + }, + sig.0.output(), + sig.0.variadic() + ); let llref_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { unsafety: unsafety, abi: abi, @@ -342,7 +349,15 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( // Make a version of the closure type with the same arguments, but // with argument #0 being by value. assert_eq!(abi, Abi::RustCall); - sig.0.inputs[0] = closure_ty; + sig.0 = ty::FnSig::new( + { + let mut inputs = sig.0.inputs().to_owned(); + inputs[0] = closure_ty; + inputs + }, + sig.0.output(), + sig.0.variadic() + ); let sig = tcx.erase_late_bound_regions_and_normalize(&sig); let fn_ty = FnType::new(ccx, abi, &sig, &[]); @@ -491,13 +506,12 @@ fn trans_fn_pointer_shim<'a, 'tcx>( } }; let sig = tcx.erase_late_bound_regions_and_normalize(sig); - let tuple_input_ty = tcx.intern_tup(&sig.inputs[..]); - let sig = ty::FnSig { - inputs: vec![bare_fn_ty_maybe_ref, - tuple_input_ty], - output: sig.output, - variadic: false - }; + let tuple_input_ty = tcx.intern_tup(sig.inputs()); + let sig = ty::FnSig::new( + vec![bare_fn_ty_maybe_ref, tuple_input_ty], + sig.output(), + false + ); let fn_ty = FnType::new(ccx, Abi::RustCall, &sig, &[]); let tuple_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { unsafety: hir::Unsafety::Normal, diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 29925d964da..2682c37095a 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -418,11 +418,11 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> { let ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { unsafety: hir::Unsafety::Unsafe, abi: Abi::C, - sig: ty::Binder(ty::FnSig { - inputs: vec![tcx.mk_mut_ptr(tcx.types.u8)], - output: tcx.types.never, - variadic: false - }), + sig: ty::Binder(ty::FnSig::new( + vec![tcx.mk_mut_ptr(tcx.types.u8)], + tcx.types.never, + false + )), })); let unwresume = ccx.eh_unwind_resume(); @@ -1091,10 +1091,11 @@ pub fn ty_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty::ClosureKind::FnOnce => ty, }; - let sig = sig.map_bound(|sig| ty::FnSig { - inputs: iter::once(env_ty).chain(sig.inputs).collect(), - ..sig - }); + let sig = sig.map_bound(|sig| ty::FnSig::new( + iter::once(env_ty).chain(sig.inputs().into_iter().cloned()).collect(), + sig.output(), + sig.variadic() + )); Cow::Owned(ty::BareFnTy { unsafety: unsafety, abi: abi, sig: sig }) } _ => bug!("unexpected type {:?} to ty_fn_sig", ty) diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index ca76211dc4c..cda9fa46f17 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -390,16 +390,16 @@ fn subroutine_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, { let signature = cx.tcx().erase_late_bound_regions(signature); - let mut signature_metadata: Vec = Vec::with_capacity(signature.inputs.len() + 1); + let mut signature_metadata: Vec = Vec::with_capacity(signature.inputs().len() + 1); // return type - signature_metadata.push(match signature.output.sty { + signature_metadata.push(match signature.output().sty { ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(), - _ => type_metadata(cx, signature.output, span) + _ => type_metadata(cx, signature.output(), span) }); // regular arguments - for &argument_type in &signature.inputs { + for &argument_type in signature.inputs() { signature_metadata.push(type_metadata(cx, argument_type, span)); } diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index e023e654d51..aab70ab252a 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -308,18 +308,18 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, return create_DIArray(DIB(cx), &[]); } - let mut signature = Vec::with_capacity(sig.inputs.len() + 1); + let mut signature = Vec::with_capacity(sig.inputs().len() + 1); // Return type -- llvm::DIBuilder wants this at index 0 - signature.push(match sig.output.sty { + signature.push(match sig.output().sty { ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(), - _ => type_metadata(cx, sig.output, syntax_pos::DUMMY_SP) + _ => type_metadata(cx, sig.output(), syntax_pos::DUMMY_SP) }); let inputs = if abi == Abi::RustCall { - &sig.inputs[..sig.inputs.len()-1] + &sig.inputs()[..sig.inputs().len() - 1] } else { - &sig.inputs[..] + sig.inputs() }; // Arguments types @@ -327,8 +327,8 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, signature.push(type_metadata(cx, argument_type, syntax_pos::DUMMY_SP)); } - if abi == Abi::RustCall && !sig.inputs.is_empty() { - if let ty::TyTuple(args) = sig.inputs[sig.inputs.len() - 1].sty { + if abi == Abi::RustCall && !sig.inputs().is_empty() { + if let ty::TyTuple(args) = sig.inputs()[sig.inputs().len() - 1].sty { for &argument_type in args { signature.push(type_metadata(cx, argument_type, syntax_pos::DUMMY_SP)); } diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index 80e6bd7aa29..5eb632f63ab 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_trans/debuginfo/type_names.rs @@ -116,8 +116,8 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.push_str("fn("); let sig = cx.tcx().erase_late_bound_regions_and_normalize(sig); - if !sig.inputs.is_empty() { - for ¶meter_type in &sig.inputs { + if !sig.inputs().is_empty() { + for ¶meter_type in sig.inputs() { push_debuginfo_type_name(cx, parameter_type, true, output); output.push_str(", "); } @@ -125,8 +125,8 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.pop(); } - if sig.variadic { - if !sig.inputs.is_empty() { + if sig.variadic() { + if !sig.inputs().is_empty() { output.push_str(", ..."); } else { output.push_str("..."); @@ -135,9 +135,9 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.push(')'); - if !sig.output.is_nil() { + if !sig.output().is_nil() { output.push_str(" -> "); - push_debuginfo_type_name(cx, sig.output, true, output); + push_debuginfo_type_name(cx, sig.output(), true, output); } }, ty::TyClosure(..) => { diff --git a/src/librustc_trans/declare.rs b/src/librustc_trans/declare.rs index eef3b9b1147..9bf023fc189 100644 --- a/src/librustc_trans/declare.rs +++ b/src/librustc_trans/declare.rs @@ -124,7 +124,7 @@ pub fn declare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, let llfn = declare_raw_fn(ccx, name, fty.cconv, fty.llvm_type(ccx)); // FIXME(canndrew): This is_never should really be an is_uninhabited - if sig.output.is_never() { + if sig.output().is_never() { llvm::Attribute::NoReturn.apply_llfn(Function, llfn); } diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 016a76a7253..cf1dddf0f49 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -105,8 +105,8 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, }; let sig = tcx.erase_late_bound_regions_and_normalize(&fty.sig); - let arg_tys = sig.inputs; - let ret_ty = sig.output; + let arg_tys = sig.inputs(); + let ret_ty = sig.output(); let name = &*tcx.item_name(def_id).as_str(); let span = match call_debug_location { @@ -674,7 +674,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, // again to find them and extract the arguments intr.inputs.iter() .zip(llargs) - .zip(&arg_tys) + .zip(arg_tys) .flat_map(|((t, llarg), ty)| modify_as_needed(bcx, t, ty, *llarg)) .collect() }; @@ -1012,11 +1012,7 @@ fn gen_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>, trans: &mut for<'b> FnMut(Block<'b, 'tcx>)) -> ValueRef { let ccx = fcx.ccx; - let sig = ty::FnSig { - inputs: inputs, - output: output, - variadic: false, - }; + let sig = ty::FnSig::new(inputs, output, false); let fn_ty = FnType::new(ccx, Abi::Rust, &sig, &[]); let rust_fn_ty = ccx.tcx().mk_fn_ptr(ccx.tcx().mk_bare_fn(ty::BareFnTy { @@ -1051,11 +1047,7 @@ fn get_rust_try_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>, let fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { unsafety: hir::Unsafety::Unsafe, abi: Abi::Rust, - sig: ty::Binder(ty::FnSig { - inputs: vec![i8p], - output: tcx.mk_nil(), - variadic: false, - }), + sig: ty::Binder(ty::FnSig::new(vec![i8p], tcx.mk_nil(), false)), })); let output = tcx.types.i32; let rust_try = gen_fn(fcx, "__rust_try", vec![fn_ty, i8p, i8p], output, trans); @@ -1108,7 +1100,7 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> let tcx = bcx.tcx(); let sig = tcx.erase_late_bound_regions_and_normalize(callee_ty.fn_sig()); - let arg_tys = sig.inputs; + let arg_tys = sig.inputs(); // every intrinsic takes a SIMD vector as its first argument require_simd!(arg_tys[0], "input"); diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 29e6f6af416..76f5f32b5dc 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -453,7 +453,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { return; } - let extra_args = &args[sig.inputs.len()..]; + let extra_args = &args[sig.inputs().len()..]; let extra_args = extra_args.iter().map(|op_arg| { let op_ty = op_arg.ty(&self.mir, bcx.tcx()); bcx.monomorphize(&op_ty) @@ -546,7 +546,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { // Make a fake operand for store_return let op = OperandRef { val: Ref(dst), - ty: sig.output, + ty: sig.output(), }; self.store_return(&bcx, ret_dest, fn_ty.ret, op); } @@ -584,7 +584,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { debug_loc.apply_to_bcx(ret_bcx); let op = OperandRef { val: Immediate(invokeret), - ty: sig.output, + ty: sig.output(), }; self.store_return(&ret_bcx, ret_dest, fn_ty.ret, op); }); @@ -595,7 +595,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { if let Some((_, target)) = *destination { let op = OperandRef { val: Immediate(llret), - ty: sig.output, + ty: sig.output(), }; self.store_return(&bcx, ret_dest, fn_ty.ret, op); funclet_br(self, bcx, target); diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 322c5eb6e18..3ae97d0cfcf 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -187,11 +187,7 @@ impl<'a, 'tcx> TransItem<'tcx> { assert_eq!(dg.ty(), glue::get_drop_glue_type(tcx, dg.ty())); let t = dg.ty(); - let sig = ty::FnSig { - inputs: vec![tcx.mk_mut_ptr(tcx.types.i8)], - output: tcx.mk_nil(), - variadic: false, - }; + let sig = ty::FnSig::new(vec![tcx.mk_mut_ptr(tcx.types.i8)], tcx.mk_nil(), false); // Create a FnType for fn(*mut i8) and substitute the real type in // later - that prevents FnType from splitting fat pointers up. @@ -480,14 +476,10 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { output.push_str("fn("); - let ty::FnSig { - inputs: sig_inputs, - output: sig_output, - variadic: sig_variadic - } = self.tcx.erase_late_bound_regions_and_normalize(sig); + let sig = self.tcx.erase_late_bound_regions_and_normalize(sig); - if !sig_inputs.is_empty() { - for ¶meter_type in &sig_inputs { + if !sig.inputs().is_empty() { + for ¶meter_type in sig.inputs() { self.push_type_name(parameter_type, output); output.push_str(", "); } @@ -495,8 +487,8 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { output.pop(); } - if sig_variadic { - if !sig_inputs.is_empty() { + if sig.variadic() { + if !sig.inputs().is_empty() { output.push_str(", ..."); } else { output.push_str("..."); @@ -505,9 +497,9 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { output.push(')'); - if !sig_output.is_nil() { + if !sig.output().is_nil() { output.push_str(" -> "); - self.push_type_name(sig_output, output); + self.push_type_name(sig.output(), output); } }, ty::TyClosure(def_id, ref closure_substs) => { diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index b5531b8bb9e..1fd0b794441 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1595,7 +1595,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // checking for here would be considered early bound // anyway.) let inputs = bare_fn_ty.sig.inputs(); - let late_bound_in_args = tcx.collect_constrained_late_bound_regions(&inputs); + let late_bound_in_args = tcx.collect_constrained_late_bound_regions( + &inputs.map_bound(|i| i.to_owned())); let output = bare_fn_ty.sig.output(); let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(&output); for br in late_bound_in_ret.difference(&late_bound_in_args) { @@ -1803,11 +1804,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { self.tcx().mk_bare_fn(ty::BareFnTy { unsafety: unsafety, abi: abi, - sig: ty::Binder(ty::FnSig { - inputs: input_tys, - output: output_ty, - variadic: decl.variadic - }), + sig: ty::Binder(ty::FnSig::new(input_tys, output_ty, decl.variadic)), }) } @@ -1853,8 +1850,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let expected_arg_ty = expected_sig.as_ref().and_then(|e| { // no guarantee that the correct number of expected args // were supplied - if i < e.inputs.len() { - Some(e.inputs[i]) + if i < e.inputs().len() { + Some(e.inputs()[i]) } else { None } @@ -1862,7 +1859,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { self.ty_of_arg(&rb, a, expected_arg_ty) }).collect(); - let expected_ret_ty = expected_sig.map(|e| e.output); + let expected_ret_ty = expected_sig.map(|e| e.output()); let is_infer = match decl.output { hir::Return(ref output) if output.node == hir::TyInfer => true, @@ -1885,9 +1882,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { ty::ClosureTy { unsafety: unsafety, abi: abi, - sig: ty::Binder(ty::FnSig {inputs: input_tys, - output: output_ty, - variadic: decl.variadic}), + sig: ty::Binder(ty::FnSig::new(input_tys, output_ty, decl.variadic)), } } diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 5b17b37e279..a49a15b2aa9 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -237,11 +237,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // This is the "default" function signature, used in case of error. // In that case, we check each argument against "error" in order to // set up all the node type bindings. - error_fn_sig = ty::Binder(ty::FnSig { - inputs: self.err_args(arg_exprs.len()), - output: self.tcx.types.err, - variadic: false, - }); + error_fn_sig = ty::Binder(ty::FnSig::new( + self.err_args(arg_exprs.len()), + self.tcx.types.err, + false, + )); (&error_fn_sig, None) } @@ -261,17 +261,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let expected_arg_tys = self.expected_types_for_fn_args(call_expr.span, expected, - fn_sig.output, - &fn_sig.inputs); + fn_sig.output(), + fn_sig.inputs()); self.check_argument_types(call_expr.span, - &fn_sig.inputs, + fn_sig.inputs(), &expected_arg_tys[..], arg_exprs, - fn_sig.variadic, + fn_sig.variadic(), TupleArgumentsFlag::DontTupleArguments, def_span); - fn_sig.output + fn_sig.output() } fn confirm_deferred_closure_call(&self, @@ -287,18 +287,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let expected_arg_tys = self.expected_types_for_fn_args(call_expr.span, expected, - fn_sig.output.clone(), - &fn_sig.inputs); + fn_sig.output().clone(), + fn_sig.inputs()); self.check_argument_types(call_expr.span, - &fn_sig.inputs, + fn_sig.inputs(), &expected_arg_tys, arg_exprs, - fn_sig.variadic, + fn_sig.variadic(), TupleArgumentsFlag::TupleArguments, None); - fn_sig.output + fn_sig.output() } fn confirm_overloaded_call(&self, @@ -365,12 +365,12 @@ impl<'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> for CallResolution<'gcx, 'tc debug!("attempt_resolution: method_callee={:?}", method_callee); - for (&method_arg_ty, &self_arg_ty) in - method_sig.inputs[1..].iter().zip(&self.fn_sig.inputs) { - fcx.demand_eqtype(self.call_expr.span, self_arg_ty, method_arg_ty); + for (method_arg_ty, self_arg_ty) in + method_sig.inputs().into_iter().skip(1).zip(self.fn_sig.inputs()) { + fcx.demand_eqtype(self.call_expr.span, &self_arg_ty, &method_arg_ty); } - fcx.demand_eqtype(self.call_expr.span, method_sig.output, self.fn_sig.output); + fcx.demand_eqtype(self.call_expr.span, method_sig.output(), self.fn_sig.output()); fcx.write_overloaded_call_method_map(self.call_expr, method_callee); } diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 486f8fc25bb..d0bc3f69187 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -86,7 +86,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Tuple up the arguments and insert the resulting function type into // the `closures` table. - fn_ty.sig.0.inputs = vec![self.tcx.intern_tup(&fn_ty.sig.0.inputs[..])]; + fn_ty.sig.0 = ty::FnSig::new(vec![self.tcx.intern_tup(fn_ty.sig.skip_binder().inputs())], + fn_ty.sig.skip_binder().output(), + fn_ty.sig.variadic() + ); debug!("closure for {:?} --> sig={:?} opt_kind={:?}", expr_def_id, @@ -224,11 +227,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("deduce_sig_from_projection: ret_param_ty {:?}", ret_param_ty); - let fn_sig = ty::FnSig { - inputs: input_tys, - output: ret_param_ty, - variadic: false, - }; + let fn_sig = ty::FnSig::new(input_tys, ret_param_ty, false); debug!("deduce_sig_from_projection: fn_sig {:?}", fn_sig); Some(fn_sig) diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 2602ff05bad..e85dac1a44c 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -495,8 +495,8 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a _ => bug!("{:?} is not a MethodTraitItem", trait_m), }; - let impl_iter = impl_sig.inputs.iter(); - let trait_iter = trait_sig.inputs.iter(); + let impl_iter = impl_sig.inputs().iter(); + let trait_iter = trait_sig.inputs().iter(); impl_iter.zip(trait_iter) .zip(impl_m_iter) .zip(trait_m_iter) @@ -508,7 +508,8 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a }) .next() .unwrap_or_else(|| { - if infcx.sub_types(false, &cause, impl_sig.output, trait_sig.output) + if infcx.sub_types(false, &cause, impl_sig.output(), + trait_sig.output()) .is_err() { (impl_m_output.span(), Some(trait_m_output.span())) } else { @@ -681,9 +682,9 @@ fn compare_number_of_method_arguments<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, }; let impl_m_fty = m_fty(impl_m); let trait_m_fty = m_fty(trait_m); - if impl_m_fty.sig.0.inputs.len() != trait_m_fty.sig.0.inputs.len() { - let trait_number_args = trait_m_fty.sig.0.inputs.len(); - let impl_number_args = impl_m_fty.sig.0.inputs.len(); + let trait_number_args = trait_m_fty.sig.inputs().skip_binder().len(); + let impl_number_args = impl_m_fty.sig.inputs().skip_binder().len(); + if trait_number_args != impl_number_args { let trait_m_node_id = tcx.map.as_local_node_id(trait_m.def_id); let trait_span = if let Some(trait_id) = trait_m_node_id { match tcx.map.expect_trait_item(trait_id).node { diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index a07573a7b9e..23915880167 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -42,11 +42,7 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let fty = tcx.mk_fn_def(def_id, substs, tcx.mk_bare_fn(ty::BareFnTy { unsafety: hir::Unsafety::Unsafe, abi: abi, - sig: ty::Binder(FnSig { - inputs: inputs, - output: output, - variadic: false, - }), + sig: ty::Binder(FnSig::new(inputs, output, false)), })); let i_n_tps = tcx.item_generics(def_id).types.len(); if i_n_tps != n_tps { @@ -299,11 +295,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) { let fn_ty = tcx.mk_bare_fn(ty::BareFnTy { unsafety: hir::Unsafety::Normal, abi: Abi::Rust, - sig: ty::Binder(FnSig { - inputs: vec![mut_u8], - output: tcx.mk_nil(), - variadic: false, - }), + sig: ty::Binder(FnSig::new(vec![mut_u8], tcx.mk_nil(), false)), }); (0, vec![tcx.mk_fn_ptr(fn_ty), mut_u8, mut_u8], tcx.types.i32) } @@ -377,21 +369,21 @@ pub fn check_platform_intrinsic_type(ccx: &CrateCtxt, let sig = tcx.item_type(def_id).fn_sig(); let sig = tcx.no_late_bound_regions(sig).unwrap(); - if intr.inputs.len() != sig.inputs.len() { + if intr.inputs.len() != sig.inputs().len() { span_err!(tcx.sess, it.span, E0444, "platform-specific intrinsic has invalid number of \ arguments: found {}, expected {}", - sig.inputs.len(), intr.inputs.len()); + sig.inputs().len(), intr.inputs.len()); return } - let input_pairs = intr.inputs.iter().zip(&sig.inputs); + let input_pairs = intr.inputs.iter().zip(sig.inputs()); for (i, (expected_arg, arg)) in input_pairs.enumerate() { match_intrinsic_type_to_type(ccx, &format!("argument {}", i + 1), it.span, &mut structural_to_nomimal, expected_arg, arg); } match_intrinsic_type_to_type(ccx, "return value", it.span, &mut structural_to_nomimal, - &intr.output, sig.output); + &intr.output, sig.output()); return } None => { diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 2e66f6290a0..b29eab780e0 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -246,7 +246,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { infer::FnCall, &fty.sig).0; let fn_sig = self.instantiate_type_scheme(span, trait_ref.substs, &fn_sig); - let transformed_self_ty = fn_sig.inputs[0]; + let transformed_self_ty = fn_sig.inputs()[0]; let method_ty = tcx.mk_fn_def(def_id, trait_ref.substs, tcx.mk_bare_fn(ty::BareFnTy { sig: ty::Binder(fn_sig), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 1950adf8329..058bb9254d8 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -785,18 +785,18 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, // Create the function context. This is either derived from scratch or, // in the case of function expressions, based on the outer context. - let mut fcx = FnCtxt::new(inherited, fn_sig.output, body.id); + let mut fcx = FnCtxt::new(inherited, fn_sig.output(), body.id); *fcx.ps.borrow_mut() = UnsafetyState::function(unsafety, unsafety_id); fcx.require_type_is_sized(fcx.ret_ty, decl.output.span(), traits::ReturnType); fcx.ret_ty = fcx.instantiate_anon_types(&fcx.ret_ty); - fn_sig.output = fcx.ret_ty; + fn_sig = ty::FnSig::new(fn_sig.inputs().to_owned(), fcx.ret_ty, fn_sig.variadic()); { let mut visit = GatherLocalsVisitor { fcx: &fcx, }; // Add formal parameters. - for (arg_ty, input) in fn_sig.inputs.iter().zip(&decl.inputs) { + for (arg_ty, input) in fn_sig.inputs().iter().zip(&decl.inputs) { // The type of the argument must be well-formed. // // NB -- this is now checked in wfcheck, but that @@ -2474,13 +2474,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty::TyFnDef(def_id, .., ref fty) => { // HACK(eddyb) ignore self in the definition (see above). let expected_arg_tys = self.expected_types_for_fn_args(sp, expected, - fty.sig.0.output, - &fty.sig.0.inputs[1..]); - - self.check_argument_types(sp, &fty.sig.0.inputs[1..], &expected_arg_tys[..], - args_no_rcvr, fty.sig.0.variadic, tuple_arguments, + fty.sig.0.output(), + &fty.sig.0.inputs()[1..]); + self.check_argument_types(sp, &fty.sig.0.inputs()[1..], &expected_arg_tys[..], + args_no_rcvr, fty.sig.0.variadic(), tuple_arguments, self.tcx.map.span_if_local(def_id)); - fty.sig.0.output + fty.sig.0.output() } _ => { span_bug!(callee_expr.span, "method without bare fn type"); diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index c0bf5773ed5..eb08e70d4c3 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -296,10 +296,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // // FIXME(#27579) return types should not be implied bounds let fn_sig_tys: Vec<_> = - fn_sig.inputs.iter() - .cloned() - .chain(Some(fn_sig.output)) - .collect(); + fn_sig.inputs().iter().cloned().chain(Some(fn_sig.output())).collect(); let old_body_id = self.set_body_id(body_id.node_id()); self.relate_free_regions(&fn_sig_tys[..], body_id.node_id(), span); @@ -940,7 +937,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { let fn_sig = method.ty.fn_sig(); let fn_sig = // late-bound regions should have been instantiated self.tcx.no_late_bound_regions(fn_sig).unwrap(); - let self_ty = fn_sig.inputs[0]; + let self_ty = fn_sig.inputs()[0]; let (m, r) = match self_ty.sty { ty::TyRef(r, ref m) => (m.mutbl, r), _ => { @@ -967,8 +964,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { self.type_must_outlive(infer::CallRcvr(deref_expr.span), self_ty, r_deref_expr); self.type_must_outlive(infer::CallReturn(deref_expr.span), - fn_sig.output, r_deref_expr); - fn_sig.output + fn_sig.output(), r_deref_expr); + fn_sig.output() } None => derefd_ty }; diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 7870b3677d0..7f35c8efeff 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -449,15 +449,15 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { let fty = fcx.instantiate_type_scheme(span, free_substs, &fty); let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &fty.sig); - for &input_ty in &sig.inputs { - fcx.register_wf_obligation(input_ty, span, self.code.clone()); + for input_ty in sig.inputs() { + fcx.register_wf_obligation(&input_ty, span, self.code.clone()); } - implied_bounds.extend(sig.inputs); + implied_bounds.extend(sig.inputs()); - fcx.register_wf_obligation(sig.output, span, self.code.clone()); + fcx.register_wf_obligation(sig.output(), span, self.code.clone()); // FIXME(#25759) return types should not be implied bounds - implied_bounds.push(sig.output); + implied_bounds.push(sig.output()); self.check_where_clauses(fcx, span, predicates); } @@ -487,7 +487,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { debug!("check_method_receiver: sig={:?}", sig); - let self_arg_ty = sig.inputs[0]; + let self_arg_ty = sig.inputs()[0]; let rcvr_ty = match ExplicitSelf::determine(self_ty, self_arg_ty) { ExplicitSelf::ByValue => self_ty, ExplicitSelf::ByReference(region, mutbl) => { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 3bb7d6a77ba..a965753a9c1 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -930,11 +930,7 @@ fn convert_variant_ctor<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, tcx.mk_fn_def(def_id, substs, tcx.mk_bare_fn(ty::BareFnTy { unsafety: hir::Unsafety::Normal, abi: abi::Abi::Rust, - sig: ty::Binder(ty::FnSig { - inputs: inputs, - output: ty, - variadic: false - }) + sig: ty::Binder(ty::FnSig::new(inputs, ty, false)) })) } }; @@ -2085,9 +2081,7 @@ fn compute_type_of_foreign_fn_decl<'a, 'tcx>( ccx.tcx.mk_fn_def(def_id, substs, ccx.tcx.mk_bare_fn(ty::BareFnTy { abi: abi, unsafety: hir::Unsafety::Unsafe, - sig: ty::Binder(ty::FnSig {inputs: input_tys, - output: output, - variadic: decl.variadic}), + sig: ty::Binder(ty::FnSig::new(input_tys, output, decl.variadic)), })) } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index dfa66259029..0017676dae4 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -222,11 +222,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt, tcx.mk_bare_fn(ty::BareFnTy { unsafety: hir::Unsafety::Normal, abi: Abi::Rust, - sig: ty::Binder(ty::FnSig { - inputs: Vec::new(), - output: tcx.mk_nil(), - variadic: false - }) + sig: ty::Binder(ty::FnSig::new(Vec::new(), tcx.mk_nil(), false)) })); require_same_types( @@ -274,14 +270,14 @@ fn check_start_fn_ty(ccx: &CrateCtxt, tcx.mk_bare_fn(ty::BareFnTy { unsafety: hir::Unsafety::Normal, abi: Abi::Rust, - sig: ty::Binder(ty::FnSig { - inputs: vec![ + sig: ty::Binder(ty::FnSig::new( + vec![ tcx.types.isize, tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8)) ], - output: tcx.types.isize, - variadic: false, - }), + tcx.types.isize, + false, + )), })); require_same_types( diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index ded9df25d5c..39f996ee62b 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -467,10 +467,10 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { sig: &ty::PolyFnSig<'tcx>, variance: VarianceTermPtr<'a>) { let contra = self.contravariant(variance); - for &input in &sig.0.inputs { + for &input in sig.0.inputs() { self.add_constraints_from_ty(generics, input, contra); } - self.add_constraints_from_ty(generics, sig.0.output, variance); + self.add_constraints_from_ty(generics, sig.0.output(), variance); } /// Adds constraints appropriate for a region appearing in a diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index bc8472bb6b7..28ca92f5db6 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1152,11 +1152,11 @@ impl<'a, 'tcx> Clean for (DefId, &'a ty::PolyFnSig<'tcx>) { cx.tcx.sess.cstore.fn_arg_names(did).into_iter() }.peekable(); FnDecl { - output: Return(sig.0.output.clean(cx)), + output: Return(sig.skip_binder().output().clean(cx)), attrs: Attributes::default(), - variadic: sig.0.variadic, + variadic: sig.skip_binder().variadic, inputs: Arguments { - values: sig.0.inputs.iter().map(|t| { + values: sig.skip_binder().inputs().iter().map(|t| { Argument { type_: t.clean(cx), id: ast::CRATE_NODE_ID, From 296ec5f9b7bf5aec05ed6672d3499079d35e4594 Mon Sep 17 00:00:00 2001 From: Mark-Simulacrum Date: Mon, 28 Nov 2016 20:25:33 -0700 Subject: [PATCH 248/293] Refactor FnSig to contain a Slice for its inputs and outputs. --- src/librustc/ty/context.rs | 11 ++++++++ src/librustc/ty/relate.rs | 27 ++++++++++++++------ src/librustc/ty/structural_impls.rs | 20 +++++++++------ src/librustc/ty/sty.rs | 29 ++++++++-------------- src/librustc/util/ppaux.rs | 4 +-- src/librustc_driver/test.rs | 7 +----- src/librustc_mir/transform/type_check.rs | 2 +- src/librustc_trans/abi.rs | 6 ++--- src/librustc_trans/base.rs | 2 +- src/librustc_trans/callee.rs | 24 +++++++----------- src/librustc_trans/common.rs | 10 ++++---- src/librustc_trans/debuginfo/type_names.rs | 2 +- src/librustc_trans/intrinsic.rs | 5 ++-- src/librustc_trans/trans_item.rs | 4 +-- src/librustc_typeck/astconv.rs | 18 +++++++------- src/librustc_typeck/check/callee.rs | 10 ++++---- src/librustc_typeck/check/closure.rs | 12 ++++----- src/librustc_typeck/check/intrinsic.rs | 7 +++--- src/librustc_typeck/check/mod.rs | 13 ++++++---- src/librustc_typeck/collect.rs | 13 +++------- src/librustc_typeck/lib.rs | 9 ++++--- 21 files changed, 121 insertions(+), 114 deletions(-) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 17c335fc9c7..4854a14f733 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1542,6 +1542,17 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } + pub fn mk_fn_sig(self, inputs: I, output: I::Item, variadic: bool) + -> , ty::FnSig<'tcx>>>::Output + where I: Iterator, + I::Item: InternIteratorElement, ty::FnSig<'tcx>> + { + inputs.chain(iter::once(output)).intern_with(|xs| ty::FnSig { + inputs_and_output: self.intern_type_list(xs), + variadic: variadic + }) + } + pub fn mk_existential_predicates], &'tcx Slice>>>(self, iter: I) -> I::Output { diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 171519b0664..76c26d01ac8 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -18,8 +18,10 @@ use ty::subst::{Kind, Substs}; use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::error::{ExpectedFound, TypeError}; use std::rc::Rc; +use std::iter; use syntax::abi; use hir as ast; +use rustc_data_structures::accumulate_vec::AccumulateVec; pub type RelateResult<'tcx, T> = Result>; @@ -180,21 +182,30 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> { -> RelateResult<'tcx, ty::FnSig<'tcx>> where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a { - if a.variadic() != b.variadic() { + if a.variadic != b.variadic { return Err(TypeError::VariadicMismatch( - expected_found(relation, &a.variadic(), &b.variadic()))); + expected_found(relation, &a.variadic, &b.variadic))); } if a.inputs().len() != b.inputs().len() { return Err(TypeError::ArgCount); } - let inputs = a.inputs().iter().zip(b.inputs()).map(|(&a, &b)| { - relation.relate_with_variance(ty::Contravariant, &a, &b) - }).collect::, _>>()?; - let output = relation.relate(&a.output(), &b.output())?; - - Ok(ty::FnSig::new(inputs, output, a.variadic())) + let inputs_and_output = a.inputs().iter().cloned() + .zip(b.inputs().iter().cloned()) + .map(|x| (x, false)) + .chain(iter::once(((a.output(), b.output()), true))) + .map(|((a, b), is_output)| { + if is_output { + relation.relate(&a, &b) + } else { + relation.relate_with_variance(ty::Contravariant, &a, &b) + } + }).collect::, _>>()?; + Ok(ty::FnSig { + inputs_and_output: relation.tcx().intern_type_list(&inputs_and_output), + variadic: a.variadic + }) } } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 9ca30850bcd..0f0478bc8cd 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -232,10 +232,11 @@ impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::AutoBorrow<'a> { impl<'a, 'tcx> Lift<'tcx> for ty::FnSig<'a> { type Lifted = ty::FnSig<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { - tcx.lift(self.inputs()).and_then(|inputs| { - tcx.lift(&self.output()).map(|output| { - ty::FnSig::new(inputs, output, self.variadic()) - }) + tcx.lift(&self.inputs_and_output).map(|x| { + ty::FnSig { + inputs_and_output: x, + variadic: self.variadic + } }) } } @@ -585,9 +586,11 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeAndMut<'tcx> { impl<'tcx> TypeFoldable<'tcx> for ty::FnSig<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - ty::FnSig::new(self.inputs().to_owned().fold_with(folder), - self.output().fold_with(folder), - self.variadic()) + let inputs_and_output = self.inputs_and_output.fold_with(folder); + ty::FnSig { + inputs_and_output: folder.tcx().intern_type_list(&inputs_and_output), + variadic: self.variadic, + } } fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { @@ -595,7 +598,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::FnSig<'tcx> { } fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.inputs().to_owned().visit_with(visitor) || self.output().visit_with(visitor) + self.inputs().iter().any(|i| i.visit_with(visitor)) || + self.output().visit_with(visitor) } } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 6c54d558ab7..3b7c46ef7fe 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -563,40 +563,31 @@ pub struct ClosureTy<'tcx> { /// - `variadic` indicates whether this is a variadic function. (only true for foreign fns) #[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct FnSig<'tcx> { - inputs: Vec>, - output: Ty<'tcx>, - variadic: bool + pub inputs_and_output: &'tcx Slice>, + pub variadic: bool } impl<'tcx> FnSig<'tcx> { - pub fn new(inputs: Vec>, output: Ty<'tcx>, variadic: bool) -> Self { - FnSig { inputs: inputs, output: output, variadic: variadic } - } - pub fn inputs(&self) -> &[Ty<'tcx>] { - &self.inputs + &self.inputs_and_output[..self.inputs_and_output.len() - 1] } pub fn output(&self) -> Ty<'tcx> { - self.output - } - - pub fn variadic(&self) -> bool { - self.variadic + self.inputs_and_output[self.inputs_and_output.len() - 1] } } pub type PolyFnSig<'tcx> = Binder>; impl<'tcx> PolyFnSig<'tcx> { - pub fn inputs<'a>(&'a self) -> Binder<&[Ty<'tcx>]> { - Binder(self.0.inputs()) + pub fn inputs(&self) -> Binder<&[Ty<'tcx>]> { + Binder(self.skip_binder().inputs()) } pub fn input(&self, index: usize) -> ty::Binder> { - self.map_bound_ref(|fn_sig| fn_sig.inputs[index]) + self.map_bound_ref(|fn_sig| fn_sig.inputs()[index]) } pub fn output(&self) -> ty::Binder> { - self.map_bound_ref(|fn_sig| fn_sig.output.clone()) + self.map_bound_ref(|fn_sig| fn_sig.output().clone()) } pub fn variadic(&self) -> bool { self.skip_binder().variadic @@ -1261,8 +1252,8 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } // Type accessors for substructures of types - pub fn fn_args(&self) -> ty::Binder>> { - ty::Binder(self.fn_sig().inputs().skip_binder().iter().cloned().collect::>()) + pub fn fn_args(&self) -> ty::Binder<&[Ty<'tcx>]> { + self.fn_sig().inputs() } pub fn fn_ret(&self) -> Binder> { diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 3a973fe7bc5..38b38e5b497 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -595,7 +595,7 @@ impl<'tcx> fmt::Debug for ty::InstantiatedPredicates<'tcx> { impl<'tcx> fmt::Display for ty::FnSig<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "fn")?; - fn_sig(f, self.inputs(), self.variadic(), self.output()) + fn_sig(f, self.inputs(), self.variadic, self.output()) } } @@ -625,7 +625,7 @@ impl fmt::Debug for ty::RegionVid { impl<'tcx> fmt::Debug for ty::FnSig<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "({:?}; variadic: {})->{:?}", self.inputs(), self.variadic(), self.output()) + write!(f, "({:?}; variadic: {})->{:?}", self.inputs(), self.variadic, self.output()) } } diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 464e15faeaf..b7cebe31073 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -265,15 +265,10 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { } pub fn t_fn(&self, input_tys: &[Ty<'tcx>], output_ty: Ty<'tcx>) -> Ty<'tcx> { - let input_args = input_tys.iter().cloned().collect(); self.infcx.tcx.mk_fn_ptr(self.infcx.tcx.mk_bare_fn(ty::BareFnTy { unsafety: hir::Unsafety::Normal, abi: Abi::Rust, - sig: ty::Binder(ty::FnSig { - inputs: input_args, - output: output_ty, - variadic: false, - }), + sig: ty::Binder(self.infcx.tcx.mk_fn_sig(input_tys.iter().cloned(), output_ty, false)), })) } diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index f65b4e55d47..4c86331a525 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -529,7 +529,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { { debug!("check_call_inputs({:?}, {:?})", sig, args); if args.len() < sig.inputs().len() || - (args.len() > sig.inputs().len() && !sig.variadic()) { + (args.len() > sig.inputs().len() && !sig.variadic) { span_mirbug!(self, term, "call to {:?} with wrong # of args", sig); } for (n, (fn_arg, op_arg)) in sig.inputs().iter().zip(args).enumerate() { diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index e780b8685e1..0ac853e99ee 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -369,7 +369,7 @@ impl FnType { let mut inputs = sig.inputs(); let extra_args = if abi == RustCall { - assert!(!sig.variadic() && extra_args.is_empty()); + assert!(!sig.variadic && extra_args.is_empty()); match sig.inputs().last().unwrap().sty { ty::TyTuple(ref tupled_arguments) => { @@ -382,7 +382,7 @@ impl FnType { } } } else { - assert!(sig.variadic() || extra_args.is_empty()); + assert!(sig.variadic || extra_args.is_empty()); extra_args }; @@ -525,7 +525,7 @@ impl FnType { FnType { args: args, ret: ret, - variadic: sig.variadic(), + variadic: sig.variadic, cconv: cconv } } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 8cc47dc8168..867e4dce19a 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1077,7 +1077,7 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let dest_val = adt::MaybeSizedValue::sized(dest); // Can return unsized value let mut llarg_idx = fcx.fn_ty.ret.is_indirect() as usize; let mut arg_idx = 0; - for (i, arg_ty) in sig.inputs().into_iter().enumerate() { + for (i, arg_ty) in sig.inputs().iter().enumerate() { let lldestptr = adt::trans_field_ptr(bcx, sig.output(), dest_val, Disr::from(disr), i); let arg = &fcx.fn_ty.args[arg_idx]; arg_idx += 1; diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 0d1fd4d69b1..7fb57dc19fc 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -38,6 +38,7 @@ use type_of; use Disr; use rustc::ty::{self, Ty, TypeFoldable}; use rustc::hir; +use std::iter; use syntax_pos::DUMMY_SP; @@ -329,13 +330,10 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( // Make a version with the type of by-ref closure. let ty::ClosureTy { unsafety, abi, mut sig } = tcx.closure_type(def_id, substs); - sig.0 = ty::FnSig::new({ - let mut inputs = sig.0.inputs().to_owned(); - inputs.insert(0, ref_closure_ty); // sig has no self type as of yet - inputs - }, + sig.0 = tcx.mk_fn_sig( + iter::once(ref_closure_ty).chain(sig.0.inputs().iter().cloned()), sig.0.output(), - sig.0.variadic() + sig.0.variadic ); let llref_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { unsafety: unsafety, @@ -349,14 +347,10 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( // Make a version of the closure type with the same arguments, but // with argument #0 being by value. assert_eq!(abi, Abi::RustCall); - sig.0 = ty::FnSig::new( - { - let mut inputs = sig.0.inputs().to_owned(); - inputs[0] = closure_ty; - inputs - }, + sig.0 = tcx.mk_fn_sig( + iter::once(closure_ty).chain(sig.0.inputs().iter().skip(1).cloned()), sig.0.output(), - sig.0.variadic() + sig.0.variadic ); let sig = tcx.erase_late_bound_regions_and_normalize(&sig); @@ -507,8 +501,8 @@ fn trans_fn_pointer_shim<'a, 'tcx>( }; let sig = tcx.erase_late_bound_regions_and_normalize(sig); let tuple_input_ty = tcx.intern_tup(sig.inputs()); - let sig = ty::FnSig::new( - vec![bare_fn_ty_maybe_ref, tuple_input_ty], + let sig = tcx.mk_fn_sig( + [bare_fn_ty_maybe_ref, tuple_input_ty].iter().cloned(), sig.output(), false ); diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 2682c37095a..b1d61cea39c 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -418,8 +418,8 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> { let ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { unsafety: hir::Unsafety::Unsafe, abi: Abi::C, - sig: ty::Binder(ty::FnSig::new( - vec![tcx.mk_mut_ptr(tcx.types.u8)], + sig: ty::Binder(tcx.mk_fn_sig( + iter::once(tcx.mk_mut_ptr(tcx.types.u8)), tcx.types.never, false )), @@ -1091,10 +1091,10 @@ pub fn ty_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty::ClosureKind::FnOnce => ty, }; - let sig = sig.map_bound(|sig| ty::FnSig::new( - iter::once(env_ty).chain(sig.inputs().into_iter().cloned()).collect(), + let sig = sig.map_bound(|sig| tcx.mk_fn_sig( + iter::once(env_ty).chain(sig.inputs().iter().cloned()), sig.output(), - sig.variadic() + sig.variadic )); Cow::Owned(ty::BareFnTy { unsafety: unsafety, abi: abi, sig: sig }) } diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index 5eb632f63ab..788ce32937d 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_trans/debuginfo/type_names.rs @@ -125,7 +125,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.pop(); } - if sig.variadic() { + if sig.variadic { if !sig.inputs().is_empty() { output.push_str(", ..."); } else { diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index cf1dddf0f49..577ffbad134 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -36,6 +36,7 @@ use rustc::session::Session; use syntax_pos::{Span, DUMMY_SP}; use std::cmp::Ordering; +use std::iter; fn get_simple_intrinsic(ccx: &CrateContext, name: &str) -> Option { let llvm_name = match name { @@ -1012,7 +1013,7 @@ fn gen_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>, trans: &mut for<'b> FnMut(Block<'b, 'tcx>)) -> ValueRef { let ccx = fcx.ccx; - let sig = ty::FnSig::new(inputs, output, false); + let sig = ccx.tcx().mk_fn_sig(inputs.into_iter(), output, false); let fn_ty = FnType::new(ccx, Abi::Rust, &sig, &[]); let rust_fn_ty = ccx.tcx().mk_fn_ptr(ccx.tcx().mk_bare_fn(ty::BareFnTy { @@ -1047,7 +1048,7 @@ fn get_rust_try_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>, let fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { unsafety: hir::Unsafety::Unsafe, abi: Abi::Rust, - sig: ty::Binder(ty::FnSig::new(vec![i8p], tcx.mk_nil(), false)), + sig: ty::Binder(tcx.mk_fn_sig(iter::once(i8p), tcx.mk_nil(), false)), })); let output = tcx.types.i32; let rust_try = gen_fn(fcx, "__rust_try", vec![fn_ty, i8p, i8p], output, trans); diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 3ae97d0cfcf..214eaeb817f 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -187,7 +187,7 @@ impl<'a, 'tcx> TransItem<'tcx> { assert_eq!(dg.ty(), glue::get_drop_glue_type(tcx, dg.ty())); let t = dg.ty(); - let sig = ty::FnSig::new(vec![tcx.mk_mut_ptr(tcx.types.i8)], tcx.mk_nil(), false); + let sig = tcx.mk_fn_sig(iter::once(tcx.mk_mut_ptr(tcx.types.i8)), tcx.mk_nil(), false); // Create a FnType for fn(*mut i8) and substitute the real type in // later - that prevents FnType from splitting fat pointers up. @@ -487,7 +487,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { output.pop(); } - if sig.variadic() { + if sig.variadic { if !sig.inputs().is_empty() { output.push_str(", ..."); } else { diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 1fd0b794441..d458c7c009e 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1796,15 +1796,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { hir::DefaultReturn(..) => self.tcx().mk_nil(), }; - let input_tys = self_ty.into_iter().chain(arg_tys).collect(); - - debug!("ty_of_method_or_bare_fn: input_tys={:?}", input_tys); debug!("ty_of_method_or_bare_fn: output_ty={:?}", output_ty); self.tcx().mk_bare_fn(ty::BareFnTy { unsafety: unsafety, abi: abi, - sig: ty::Binder(ty::FnSig::new(input_tys, output_ty, decl.variadic)), + sig: ty::Binder(self.tcx().mk_fn_sig( + self_ty.into_iter().chain(arg_tys), + output_ty, + decl.variadic + )), }) } @@ -1846,7 +1847,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // that function type let rb = rscope::BindingRscope::new(); - let input_tys: Vec<_> = decl.inputs.iter().enumerate().map(|(i, a)| { + let input_tys = decl.inputs.iter().enumerate().map(|(i, a)| { let expected_arg_ty = expected_sig.as_ref().and_then(|e| { // no guarantee that the correct number of expected args // were supplied @@ -1857,9 +1858,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } }); self.ty_of_arg(&rb, a, expected_arg_ty) - }).collect(); + }); - let expected_ret_ty = expected_sig.map(|e| e.output()); + let expected_ret_ty = expected_sig.as_ref().map(|e| e.output()); let is_infer = match decl.output { hir::Return(ref output) if output.node == hir::TyInfer => true, @@ -1876,13 +1877,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { hir::DefaultReturn(..) => bug!(), }; - debug!("ty_of_closure: input_tys={:?}", input_tys); debug!("ty_of_closure: output_ty={:?}", output_ty); ty::ClosureTy { unsafety: unsafety, abi: abi, - sig: ty::Binder(ty::FnSig::new(input_tys, output_ty, decl.variadic)), + sig: ty::Binder(self.tcx().mk_fn_sig(input_tys, output_ty, decl.variadic)), } } diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index a49a15b2aa9..4fba29def22 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -237,8 +237,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // This is the "default" function signature, used in case of error. // In that case, we check each argument against "error" in order to // set up all the node type bindings. - error_fn_sig = ty::Binder(ty::FnSig::new( - self.err_args(arg_exprs.len()), + error_fn_sig = ty::Binder(self.tcx.mk_fn_sig( + self.err_args(arg_exprs.len()).into_iter(), self.tcx.types.err, false, )); @@ -267,7 +267,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn_sig.inputs(), &expected_arg_tys[..], arg_exprs, - fn_sig.variadic(), + fn_sig.variadic, TupleArgumentsFlag::DontTupleArguments, def_span); @@ -294,7 +294,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn_sig.inputs(), &expected_arg_tys, arg_exprs, - fn_sig.variadic(), + fn_sig.variadic, TupleArgumentsFlag::TupleArguments, None); @@ -366,7 +366,7 @@ impl<'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> for CallResolution<'gcx, 'tc debug!("attempt_resolution: method_callee={:?}", method_callee); for (method_arg_ty, self_arg_ty) in - method_sig.inputs().into_iter().skip(1).zip(self.fn_sig.inputs()) { + method_sig.inputs().iter().skip(1).zip(self.fn_sig.inputs()) { fcx.demand_eqtype(self.call_expr.span, &self_arg_ty, &method_arg_ty); } diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index d0bc3f69187..142a8b97111 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -15,6 +15,7 @@ use super::{check_fn, Expectation, FnCtxt}; use astconv::AstConv; use rustc::ty::{self, ToPolyTraitRef, Ty}; use std::cmp; +use std::iter; use syntax::abi::Abi; use rustc::hir; @@ -86,7 +87,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Tuple up the arguments and insert the resulting function type into // the `closures` table. - fn_ty.sig.0 = ty::FnSig::new(vec![self.tcx.intern_tup(fn_ty.sig.skip_binder().inputs())], + fn_ty.sig.0 = self.tcx.mk_fn_sig( + iter::once(self.tcx.intern_tup(fn_ty.sig.skip_binder().inputs())), fn_ty.sig.skip_binder().output(), fn_ty.sig.variadic() ); @@ -215,19 +217,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { arg_param_ty); let input_tys = match arg_param_ty.sty { - ty::TyTuple(tys) => tys.to_vec(), + ty::TyTuple(tys) => tys.into_iter(), _ => { return None; } }; - debug!("deduce_sig_from_projection: input_tys {:?}", input_tys); let ret_param_ty = projection.0.ty; let ret_param_ty = self.resolve_type_vars_if_possible(&ret_param_ty); - debug!("deduce_sig_from_projection: ret_param_ty {:?}", - ret_param_ty); + debug!("deduce_sig_from_projection: ret_param_ty {:?}", ret_param_ty); - let fn_sig = ty::FnSig::new(input_tys, ret_param_ty, false); + let fn_sig = self.tcx.mk_fn_sig(input_tys.cloned(), ret_param_ty, false); debug!("deduce_sig_from_projection: fn_sig {:?}", fn_sig); Some(fn_sig) diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 23915880167..183a2a48ff5 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -14,7 +14,6 @@ use intrinsics; use rustc::traits::{ObligationCause, ObligationCauseCode}; use rustc::ty::subst::Substs; -use rustc::ty::FnSig; use rustc::ty::{self, Ty}; use rustc::util::nodemap::FxHashMap; use {CrateCtxt, require_same_types}; @@ -26,6 +25,8 @@ use syntax_pos::Span; use rustc::hir; +use std::iter; + fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::ForeignItem, n_tps: usize, @@ -42,7 +43,7 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let fty = tcx.mk_fn_def(def_id, substs, tcx.mk_bare_fn(ty::BareFnTy { unsafety: hir::Unsafety::Unsafe, abi: abi, - sig: ty::Binder(FnSig::new(inputs, output, false)), + sig: ty::Binder(tcx.mk_fn_sig(inputs.into_iter(), output, false)), })); let i_n_tps = tcx.item_generics(def_id).types.len(); if i_n_tps != n_tps { @@ -295,7 +296,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) { let fn_ty = tcx.mk_bare_fn(ty::BareFnTy { unsafety: hir::Unsafety::Normal, abi: Abi::Rust, - sig: ty::Binder(FnSig::new(vec![mut_u8], tcx.mk_nil(), false)), + sig: ty::Binder(tcx.mk_fn_sig(iter::once(mut_u8), tcx.mk_nil(), false)), }); (0, vec![tcx.mk_fn_ptr(fn_ty), mut_u8, mut_u8], tcx.types.i32) } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 058bb9254d8..1b35081d524 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -790,7 +790,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, fcx.require_type_is_sized(fcx.ret_ty, decl.output.span(), traits::ReturnType); fcx.ret_ty = fcx.instantiate_anon_types(&fcx.ret_ty); - fn_sig = ty::FnSig::new(fn_sig.inputs().to_owned(), fcx.ret_ty, fn_sig.variadic()); + fn_sig = fcx.tcx.mk_fn_sig(fn_sig.inputs().iter().cloned(), &fcx.ret_ty, fn_sig.variadic); { let mut visit = GatherLocalsVisitor { fcx: &fcx, }; @@ -2473,11 +2473,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match method_fn_ty.sty { ty::TyFnDef(def_id, .., ref fty) => { // HACK(eddyb) ignore self in the definition (see above). - let expected_arg_tys = self.expected_types_for_fn_args(sp, expected, - fty.sig.0.output(), - &fty.sig.0.inputs()[1..]); + let expected_arg_tys = self.expected_types_for_fn_args( + sp, + expected, + fty.sig.0.output(), + &fty.sig.0.inputs()[1..] + ); self.check_argument_types(sp, &fty.sig.0.inputs()[1..], &expected_arg_tys[..], - args_no_rcvr, fty.sig.0.variadic(), tuple_arguments, + args_no_rcvr, fty.sig.0.variadic, tuple_arguments, self.tcx.map.span_if_local(def_id)); fty.sig.0.output() } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index a965753a9c1..fba77d17179 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -920,17 +920,12 @@ fn convert_variant_ctor<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let ctor_ty = match variant.ctor_kind { CtorKind::Fictive | CtorKind::Const => ty, CtorKind::Fn => { - let inputs: Vec<_> = - variant.fields - .iter() - .map(|field| tcx.item_type(field.did)) - .collect(); - let substs = mk_item_substs(&ccx.icx(&predicates), - ccx.tcx.map.span(ctor_id), def_id); + let inputs = variant.fields.iter().map(|field| tcx.item_type(field.did)); + let substs = mk_item_substs(&ccx.icx(&predicates), ccx.tcx.map.span(ctor_id), def_id); tcx.mk_fn_def(def_id, substs, tcx.mk_bare_fn(ty::BareFnTy { unsafety: hir::Unsafety::Normal, abi: abi::Abi::Rust, - sig: ty::Binder(ty::FnSig::new(inputs, ty, false)) + sig: ty::Binder(ccx.tcx.mk_fn_sig(inputs, ty, false)) })) } }; @@ -2081,7 +2076,7 @@ fn compute_type_of_foreign_fn_decl<'a, 'tcx>( ccx.tcx.mk_fn_def(def_id, substs, ccx.tcx.mk_bare_fn(ty::BareFnTy { abi: abi, unsafety: hir::Unsafety::Unsafe, - sig: ty::Binder(ty::FnSig::new(input_tys, output, decl.variadic)), + sig: ty::Binder(ccx.tcx.mk_fn_sig(input_tys.into_iter(), output, decl.variadic)), })) } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 0017676dae4..50d4c3cd0c9 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -116,6 +116,7 @@ use syntax::ast; use syntax::abi::Abi; use syntax_pos::Span; +use std::iter; use std::cell::RefCell; use util::nodemap::NodeMap; @@ -222,7 +223,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt, tcx.mk_bare_fn(ty::BareFnTy { unsafety: hir::Unsafety::Normal, abi: Abi::Rust, - sig: ty::Binder(ty::FnSig::new(Vec::new(), tcx.mk_nil(), false)) + sig: ty::Binder(tcx.mk_fn_sig(iter::empty(), tcx.mk_nil(), false)) })); require_same_types( @@ -270,11 +271,11 @@ fn check_start_fn_ty(ccx: &CrateCtxt, tcx.mk_bare_fn(ty::BareFnTy { unsafety: hir::Unsafety::Normal, abi: Abi::Rust, - sig: ty::Binder(ty::FnSig::new( - vec![ + sig: ty::Binder(tcx.mk_fn_sig( + [ tcx.types.isize, tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8)) - ], + ].iter().cloned(), tcx.types.isize, false, )), From 02bf1ce9cc617979478aac09a95486696f2c4b36 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Mon, 5 Dec 2016 21:48:53 +0100 Subject: [PATCH 249/293] vec: More specialization for Extend<&T> for vec Specialize to use copy_from_slice when extending a Vec with &[T] where T: Copy. --- src/libcollections/vec.rs | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index f2632412700..c9f9e513ef3 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1244,7 +1244,7 @@ impl Vec { /// ``` #[stable(feature = "vec_extend_from_slice", since = "1.6.0")] pub fn extend_from_slice(&mut self, other: &[T]) { - self.extend(other.iter().cloned()) + self.spec_extend(other.iter()) } } @@ -1499,7 +1499,7 @@ impl ops::DerefMut for Vec { impl FromIterator for Vec { #[inline] fn from_iter>(iter: I) -> Vec { - >::from_iter(iter.into_iter()) + >::from_iter(iter.into_iter()) } } @@ -1572,12 +1572,12 @@ impl Extend for Vec { } // Specialization trait used for Vec::from_iter and Vec::extend -trait SpecExtend { +trait SpecExtend { fn from_iter(iter: I) -> Self; fn spec_extend(&mut self, iter: I); } -impl SpecExtend for Vec +impl SpecExtend for Vec where I: Iterator, { default fn from_iter(mut iterator: I) -> Self { @@ -1607,7 +1607,7 @@ impl SpecExtend for Vec } } -impl SpecExtend for Vec +impl SpecExtend for Vec where I: TrustedLen, { fn from_iter(iterator: I) -> Self { @@ -1642,6 +1642,33 @@ impl SpecExtend for Vec } } +impl<'a, T: 'a, I> SpecExtend<&'a T, I> for Vec + where I: Iterator, + T: Clone, +{ + default fn from_iter(iterator: I) -> Self { + SpecExtend::from_iter(iterator.cloned()) + } + + default fn spec_extend(&mut self, iterator: I) { + self.spec_extend(iterator.cloned()) + } +} + +impl<'a, T: 'a> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec + where T: Copy, +{ + fn spec_extend(&mut self, iterator: slice::Iter<'a, T>) { + let slice = iterator.as_slice(); + self.reserve(slice.len()); + unsafe { + let len = self.len(); + self.set_len(len + slice.len()); + self.get_unchecked_mut(len..).copy_from_slice(slice); + } + } +} + impl Vec { fn extend_desugared>(&mut self, mut iterator: I) { // This is the case for a general iterator. @@ -1669,7 +1696,7 @@ impl Vec { #[stable(feature = "extend_ref", since = "1.2.0")] impl<'a, T: 'a + Copy> Extend<&'a T> for Vec { fn extend>(&mut self, iter: I) { - self.extend(iter.into_iter().map(|&x| x)) + self.spec_extend(iter.into_iter()) } } From 2c5d2403d770e624bbb0b9ce8e970efa914a8602 Mon Sep 17 00:00:00 2001 From: arthurprs Date: Sat, 26 Nov 2016 17:30:29 +0100 Subject: [PATCH 250/293] Smarter HashMap/HashSet extend --- src/libstd/collections/hash/map.rs | 17 +++++++++++++---- src/libstd/collections/hash/set.rs | 10 +++------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index ece51d6d826..9f9d0429fca 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1971,10 +1971,8 @@ impl FromIterator<(K, V)> for HashMap S: BuildHasher + Default { fn from_iter>(iter: T) -> HashMap { - let iterator = iter.into_iter(); - let lower = iterator.size_hint().0; - let mut map = HashMap::with_capacity_and_hasher(lower, Default::default()); - map.extend(iterator); + let mut map = HashMap::with_hasher(Default::default()); + map.extend(iter); map } } @@ -1985,6 +1983,17 @@ impl Extend<(K, V)> for HashMap S: BuildHasher { fn extend>(&mut self, iter: T) { + // Keys may be already present or show multiple times in the iterator. + // Reserve the entire hint lower bound if the map is empty. + // Otherwise reserve half the hint (rounded up), so the map + // will only resize twice in the worst case. + let iter = iter.into_iter(); + let reserve = if self.is_empty() { + iter.size_hint().0 + } else { + (iter.size_hint().0 + 1) / 2 + }; + self.reserve(reserve); for (k, v) in iter { self.insert(k, v); } diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index 1ec7a4a7b63..72af612f569 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -663,10 +663,8 @@ impl FromIterator for HashSet S: BuildHasher + Default { fn from_iter>(iter: I) -> HashSet { - let iterator = iter.into_iter(); - let lower = iterator.size_hint().0; - let mut set = HashSet::with_capacity_and_hasher(lower, Default::default()); - set.extend(iterator); + let mut set = HashSet::with_hasher(Default::default()); + set.extend(iter); set } } @@ -677,9 +675,7 @@ impl Extend for HashSet S: BuildHasher { fn extend>(&mut self, iter: I) { - for k in iter { - self.insert(k); - } + self.map.extend(iter.into_iter().map(|k| (k, ()))); } } From 5e51edb0de138d3805db5ca16160c829d3d32291 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 6 Dec 2016 11:26:52 +0100 Subject: [PATCH 251/293] annotate stricter lifetimes on LateLintPass methods to allow them to forward to a Visitor --- src/librustc/hir/check_attr.rs | 4 +- src/librustc/hir/lowering.rs | 6 +- src/librustc/hir/map/def_collector.rs | 24 +-- src/librustc/lint/context.rs | 72 +++---- src/librustc/lint/mod.rs | 133 +++++++++---- src/librustc_lint/bad_style.rs | 58 +++--- src/librustc_lint/builtin.rs | 118 +++++++----- src/librustc_lint/types.rs | 6 +- src/librustc_lint/unused.rs | 30 +-- src/librustc_passes/ast_validation.rs | 16 +- src/librustc_passes/hir_stats.rs | 58 +++--- src/librustc_passes/no_asm.rs | 4 +- src/librustc_resolve/build_reduced_graph.rs | 14 +- src/librustc_resolve/check_unused.rs | 4 +- src/librustc_resolve/lib.rs | 28 +-- src/librustc_save_analysis/dump_visitor.rs | 101 +++++----- src/librustc_save_analysis/lib.rs | 2 +- src/libsyntax/ext/expand.rs | 2 +- src/libsyntax/feature_gate.rs | 28 +-- src/libsyntax/parse/mod.rs | 4 +- src/libsyntax/show_span.rs | 10 +- src/libsyntax/util/node_count.rs | 2 +- src/libsyntax/visit.rs | 175 ++++++++++-------- src/libsyntax_ext/deriving/custom.rs | 3 +- src/libsyntax_ext/deriving/generic/mod.rs | 4 +- src/libsyntax_ext/proc_macro_registrar.rs | 25 +-- .../auxiliary/lint_for_crate.rs | 2 +- .../auxiliary/lint_group_plugin_test.rs | 2 +- .../auxiliary/lint_for_crate.rs | 2 +- .../auxiliary/lint_group_plugin_test.rs | 2 +- .../issue-37290/auxiliary/lint.rs | 6 +- 31 files changed, 525 insertions(+), 420 deletions(-) diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index abc35634d15..6f5f548aa78 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -129,8 +129,8 @@ impl<'a> CheckAttrVisitor<'a> { } } -impl<'a> Visitor for CheckAttrVisitor<'a> { - fn visit_item(&mut self, item: &ast::Item) { +impl<'a> Visitor<'a> for CheckAttrVisitor<'a> { + fn visit_item(&mut self, item: &'a ast::Item) { let target = Target::from_item(item); for attr in &item.attrs { self.check_attribute(attr, target); diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 615738277bf..74876eb59ee 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -143,14 +143,14 @@ impl<'a> LoweringContext<'a> { lctx: &'lcx mut LoweringContext<'interner>, } - impl<'lcx, 'interner> Visitor for ItemLowerer<'lcx, 'interner> { - fn visit_item(&mut self, item: &Item) { + impl<'lcx, 'interner> Visitor<'lcx> for ItemLowerer<'lcx, 'interner> { + fn visit_item(&mut self, item: &'lcx Item) { let hir_item = self.lctx.lower_item(item); self.lctx.items.insert(item.id, hir_item); visit::walk_item(self, item); } - fn visit_impl_item(&mut self, item: &ImplItem) { + fn visit_impl_item(&mut self, item: &'lcx ImplItem) { let id = self.lctx.lower_impl_item_ref(item).id; let hir_item = self.lctx.lower_impl_item(item); self.lctx.impl_items.insert(id, hir_item); diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index 273094b735c..eb5a89f320e 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -135,8 +135,8 @@ impl<'a> DefCollector<'a> { } } -impl<'a> visit::Visitor for DefCollector<'a> { - fn visit_item(&mut self, i: &Item) { +impl<'a> visit::Visitor<'a> for DefCollector<'a> { + fn visit_item(&mut self, i: &'a Item) { debug!("visit_item: {:?}", i); // Pick the def data. This need not be unique, but the more @@ -211,7 +211,7 @@ impl<'a> visit::Visitor for DefCollector<'a> { }); } - fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) { + fn visit_foreign_item(&mut self, foreign_item: &'a ForeignItem) { let def = self.create_def(foreign_item.id, DefPathData::ValueNs(foreign_item.ident.name.as_str())); @@ -220,7 +220,7 @@ impl<'a> visit::Visitor for DefCollector<'a> { }); } - fn visit_generics(&mut self, generics: &Generics) { + fn visit_generics(&mut self, generics: &'a Generics) { for ty_param in generics.ty_params.iter() { self.create_def(ty_param.id, DefPathData::TypeParam(ty_param.ident.name.as_str())); } @@ -228,7 +228,7 @@ impl<'a> visit::Visitor for DefCollector<'a> { visit::walk_generics(self, generics); } - fn visit_trait_item(&mut self, ti: &TraitItem) { + fn visit_trait_item(&mut self, ti: &'a TraitItem) { let def_data = match ti.node { TraitItemKind::Method(..) | TraitItemKind::Const(..) => DefPathData::ValueNs(ti.ident.name.as_str()), @@ -246,7 +246,7 @@ impl<'a> visit::Visitor for DefCollector<'a> { }); } - fn visit_impl_item(&mut self, ii: &ImplItem) { + fn visit_impl_item(&mut self, ii: &'a ImplItem) { let def_data = match ii.node { ImplItemKind::Method(..) | ImplItemKind::Const(..) => DefPathData::ValueNs(ii.ident.name.as_str()), @@ -264,7 +264,7 @@ impl<'a> visit::Visitor for DefCollector<'a> { }); } - fn visit_pat(&mut self, pat: &Pat) { + fn visit_pat(&mut self, pat: &'a Pat) { let parent_def = self.parent_def; match pat.node { @@ -280,7 +280,7 @@ impl<'a> visit::Visitor for DefCollector<'a> { self.parent_def = parent_def; } - fn visit_expr(&mut self, expr: &Expr) { + fn visit_expr(&mut self, expr: &'a Expr) { let parent_def = self.parent_def; match expr.node { @@ -297,7 +297,7 @@ impl<'a> visit::Visitor for DefCollector<'a> { self.parent_def = parent_def; } - fn visit_ty(&mut self, ty: &Ty) { + fn visit_ty(&mut self, ty: &'a Ty) { match ty.node { TyKind::Mac(..) => return self.visit_macro_invoc(ty.id, false), TyKind::Array(_, ref length) => self.visit_ast_const_integer(length), @@ -309,15 +309,15 @@ impl<'a> visit::Visitor for DefCollector<'a> { visit::walk_ty(self, ty); } - fn visit_lifetime_def(&mut self, def: &LifetimeDef) { + fn visit_lifetime_def(&mut self, def: &'a LifetimeDef) { self.create_def(def.lifetime.id, DefPathData::LifetimeDef(def.lifetime.name.as_str())); } - fn visit_macro_def(&mut self, macro_def: &MacroDef) { + fn visit_macro_def(&mut self, macro_def: &'a MacroDef) { self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.ident.name.as_str())); } - fn visit_stmt(&mut self, stmt: &Stmt) { + fn visit_stmt(&mut self, stmt: &'a Stmt) { match stmt.node { StmtKind::Mac(..) => self.visit_macro_invoc(stmt.id, false), _ => visit::walk_stmt(self, stmt), diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index fba4f35074d..3ff2abac277 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -496,13 +496,13 @@ pub fn raw_struct_lint<'a, S>(sess: &'a Session, err } -pub trait LintContext: Sized { +pub trait LintContext<'tcx>: Sized { fn sess(&self) -> &Session; fn lints(&self) -> &LintStore; fn mut_lints(&mut self) -> &mut LintStore; fn level_stack(&mut self) -> &mut Vec<(LintId, LevelSource)>; - fn enter_attrs(&mut self, attrs: &[ast::Attribute]); - fn exit_attrs(&mut self, attrs: &[ast::Attribute]); + fn enter_attrs(&mut self, attrs: &'tcx [ast::Attribute]); + fn exit_attrs(&mut self, attrs: &'tcx [ast::Attribute]); /// Get the level of `lint` at the current position of the lint /// traversal. @@ -606,7 +606,7 @@ pub trait LintContext: Sized { /// current lint context, call the provided function, then reset the /// lints in effect to their previous state. fn with_lint_attrs(&mut self, - attrs: &[ast::Attribute], + attrs: &'tcx [ast::Attribute], f: F) where F: FnOnce(&mut Self), { @@ -729,7 +729,7 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> { } } -impl<'a, 'tcx> LintContext for LateContext<'a, 'tcx> { +impl<'a, 'tcx> LintContext<'tcx> for LateContext<'a, 'tcx> { /// Get the overall compiler `Session` object. fn sess(&self) -> &Session { &self.tcx.sess @@ -747,18 +747,18 @@ impl<'a, 'tcx> LintContext for LateContext<'a, 'tcx> { &mut self.level_stack } - fn enter_attrs(&mut self, attrs: &[ast::Attribute]) { + fn enter_attrs(&mut self, attrs: &'tcx [ast::Attribute]) { debug!("late context: enter_attrs({:?})", attrs); run_lints!(self, enter_lint_attrs, late_passes, attrs); } - fn exit_attrs(&mut self, attrs: &[ast::Attribute]) { + fn exit_attrs(&mut self, attrs: &'tcx [ast::Attribute]) { debug!("late context: exit_attrs({:?})", attrs); run_lints!(self, exit_lint_attrs, late_passes, attrs); } } -impl<'a> LintContext for EarlyContext<'a> { +impl<'a> LintContext<'a> for EarlyContext<'a> { /// Get the overall compiler `Session` object. fn sess(&self) -> &Session { &self.sess @@ -776,12 +776,12 @@ impl<'a> LintContext for EarlyContext<'a> { &mut self.level_stack } - fn enter_attrs(&mut self, attrs: &[ast::Attribute]) { + fn enter_attrs(&mut self, attrs: &'a [ast::Attribute]) { debug!("early context: enter_attrs({:?})", attrs); run_lints!(self, enter_lint_attrs, early_passes, attrs); } - fn exit_attrs(&mut self, attrs: &[ast::Attribute]) { + fn exit_attrs(&mut self, attrs: &'a [ast::Attribute]) { debug!("early context: exit_attrs({:?})", attrs); run_lints!(self, exit_lint_attrs, early_passes, attrs); } @@ -949,14 +949,14 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { hir_visit::walk_path(self, p); } - fn visit_attribute(&mut self, attr: &ast::Attribute) { + fn visit_attribute(&mut self, attr: &'tcx ast::Attribute) { check_lint_name_attribute(self, attr); run_lints!(self, check_attribute, late_passes, attr); } } -impl<'a> ast_visit::Visitor for EarlyContext<'a> { - fn visit_item(&mut self, it: &ast::Item) { +impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> { + fn visit_item(&mut self, it: &'a ast::Item) { self.with_lint_attrs(&it.attrs, |cx| { run_lints!(cx, check_item, early_passes, it); ast_visit::walk_item(cx, it); @@ -964,7 +964,7 @@ impl<'a> ast_visit::Visitor for EarlyContext<'a> { }) } - fn visit_foreign_item(&mut self, it: &ast::ForeignItem) { + fn visit_foreign_item(&mut self, it: &'a ast::ForeignItem) { self.with_lint_attrs(&it.attrs, |cx| { run_lints!(cx, check_foreign_item, early_passes, it); ast_visit::walk_foreign_item(cx, it); @@ -972,24 +972,24 @@ impl<'a> ast_visit::Visitor for EarlyContext<'a> { }) } - fn visit_pat(&mut self, p: &ast::Pat) { + fn visit_pat(&mut self, p: &'a ast::Pat) { run_lints!(self, check_pat, early_passes, p); ast_visit::walk_pat(self, p); } - fn visit_expr(&mut self, e: &ast::Expr) { + fn visit_expr(&mut self, e: &'a ast::Expr) { self.with_lint_attrs(&e.attrs, |cx| { run_lints!(cx, check_expr, early_passes, e); ast_visit::walk_expr(cx, e); }) } - fn visit_stmt(&mut self, s: &ast::Stmt) { + fn visit_stmt(&mut self, s: &'a ast::Stmt) { run_lints!(self, check_stmt, early_passes, s); ast_visit::walk_stmt(self, s); } - fn visit_fn(&mut self, fk: ast_visit::FnKind, decl: &ast::FnDecl, + fn visit_fn(&mut self, fk: ast_visit::FnKind<'a>, decl: &'a ast::FnDecl, span: Span, id: ast::NodeId) { run_lints!(self, check_fn, early_passes, fk, decl, span, id); ast_visit::walk_fn(self, fk, decl, span); @@ -997,9 +997,9 @@ impl<'a> ast_visit::Visitor for EarlyContext<'a> { } fn visit_variant_data(&mut self, - s: &ast::VariantData, + s: &'a ast::VariantData, ident: ast::Ident, - g: &ast::Generics, + g: &'a ast::Generics, item_id: ast::NodeId, _: Span) { run_lints!(self, check_struct_def, early_passes, s, ident, g, item_id); @@ -1007,14 +1007,14 @@ impl<'a> ast_visit::Visitor for EarlyContext<'a> { run_lints!(self, check_struct_def_post, early_passes, s, ident, g, item_id); } - fn visit_struct_field(&mut self, s: &ast::StructField) { + fn visit_struct_field(&mut self, s: &'a ast::StructField) { self.with_lint_attrs(&s.attrs, |cx| { run_lints!(cx, check_struct_field, early_passes, s); ast_visit::walk_struct_field(cx, s); }) } - fn visit_variant(&mut self, v: &ast::Variant, g: &ast::Generics, item_id: ast::NodeId) { + fn visit_variant(&mut self, v: &'a ast::Variant, g: &'a ast::Generics, item_id: ast::NodeId) { self.with_lint_attrs(&v.node.attrs, |cx| { run_lints!(cx, check_variant, early_passes, v, g); ast_visit::walk_variant(cx, v, g, item_id); @@ -1022,7 +1022,7 @@ impl<'a> ast_visit::Visitor for EarlyContext<'a> { }) } - fn visit_ty(&mut self, t: &ast::Ty) { + fn visit_ty(&mut self, t: &'a ast::Ty) { run_lints!(self, check_ty, early_passes, t); ast_visit::walk_ty(self, t); } @@ -1031,40 +1031,40 @@ impl<'a> ast_visit::Visitor for EarlyContext<'a> { run_lints!(self, check_ident, early_passes, sp, id); } - fn visit_mod(&mut self, m: &ast::Mod, s: Span, n: ast::NodeId) { + fn visit_mod(&mut self, m: &'a ast::Mod, s: Span, n: ast::NodeId) { run_lints!(self, check_mod, early_passes, m, s, n); ast_visit::walk_mod(self, m); run_lints!(self, check_mod_post, early_passes, m, s, n); } - fn visit_local(&mut self, l: &ast::Local) { + fn visit_local(&mut self, l: &'a ast::Local) { self.with_lint_attrs(&l.attrs, |cx| { run_lints!(cx, check_local, early_passes, l); ast_visit::walk_local(cx, l); }) } - fn visit_block(&mut self, b: &ast::Block) { + fn visit_block(&mut self, b: &'a ast::Block) { run_lints!(self, check_block, early_passes, b); ast_visit::walk_block(self, b); run_lints!(self, check_block_post, early_passes, b); } - fn visit_arm(&mut self, a: &ast::Arm) { + fn visit_arm(&mut self, a: &'a ast::Arm) { run_lints!(self, check_arm, early_passes, a); ast_visit::walk_arm(self, a); } - fn visit_expr_post(&mut self, e: &ast::Expr) { + fn visit_expr_post(&mut self, e: &'a ast::Expr) { run_lints!(self, check_expr_post, early_passes, e); } - fn visit_generics(&mut self, g: &ast::Generics) { + fn visit_generics(&mut self, g: &'a ast::Generics) { run_lints!(self, check_generics, early_passes, g); ast_visit::walk_generics(self, g); } - fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) { + fn visit_trait_item(&mut self, trait_item: &'a ast::TraitItem) { self.with_lint_attrs(&trait_item.attrs, |cx| { run_lints!(cx, check_trait_item, early_passes, trait_item); ast_visit::walk_trait_item(cx, trait_item); @@ -1072,7 +1072,7 @@ impl<'a> ast_visit::Visitor for EarlyContext<'a> { }); } - fn visit_impl_item(&mut self, impl_item: &ast::ImplItem) { + fn visit_impl_item(&mut self, impl_item: &'a ast::ImplItem) { self.with_lint_attrs(&impl_item.attrs, |cx| { run_lints!(cx, check_impl_item, early_passes, impl_item); ast_visit::walk_impl_item(cx, impl_item); @@ -1080,25 +1080,25 @@ impl<'a> ast_visit::Visitor for EarlyContext<'a> { }); } - fn visit_lifetime(&mut self, lt: &ast::Lifetime) { + fn visit_lifetime(&mut self, lt: &'a ast::Lifetime) { run_lints!(self, check_lifetime, early_passes, lt); } - fn visit_lifetime_def(&mut self, lt: &ast::LifetimeDef) { + fn visit_lifetime_def(&mut self, lt: &'a ast::LifetimeDef) { run_lints!(self, check_lifetime_def, early_passes, lt); } - fn visit_path(&mut self, p: &ast::Path, id: ast::NodeId) { + fn visit_path(&mut self, p: &'a ast::Path, id: ast::NodeId) { run_lints!(self, check_path, early_passes, p, id); ast_visit::walk_path(self, p); } - fn visit_path_list_item(&mut self, prefix: &ast::Path, item: &ast::PathListItem) { + fn visit_path_list_item(&mut self, prefix: &'a ast::Path, item: &'a ast::PathListItem) { run_lints!(self, check_path_list_item, early_passes, item); ast_visit::walk_path_list_item(self, prefix, item); } - fn visit_attribute(&mut self, attr: &ast::Attribute) { + fn visit_attribute(&mut self, attr: &'a ast::Attribute) { run_lints!(self, check_attribute, early_passes, attr); } } diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 4e06e0abf01..0f85494d1ab 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -131,51 +131,104 @@ pub trait LintPass { // contains a few lint-specific methods with no equivalent in `Visitor`. pub trait LateLintPass: LintPass { fn check_name(&mut self, _: &LateContext, _: Span, _: ast::Name) { } - fn check_crate(&mut self, _: &LateContext, _: &hir::Crate) { } - fn check_crate_post(&mut self, _: &LateContext, _: &hir::Crate) { } - fn check_mod(&mut self, _: &LateContext, _: &hir::Mod, _: Span, _: ast::NodeId) { } - fn check_mod_post(&mut self, _: &LateContext, _: &hir::Mod, _: Span, _: ast::NodeId) { } - fn check_foreign_item(&mut self, _: &LateContext, _: &hir::ForeignItem) { } - fn check_foreign_item_post(&mut self, _: &LateContext, _: &hir::ForeignItem) { } - fn check_item(&mut self, _: &LateContext, _: &hir::Item) { } - fn check_item_post(&mut self, _: &LateContext, _: &hir::Item) { } - fn check_local(&mut self, _: &LateContext, _: &hir::Local) { } - fn check_block(&mut self, _: &LateContext, _: &hir::Block) { } - fn check_block_post(&mut self, _: &LateContext, _: &hir::Block) { } - fn check_stmt(&mut self, _: &LateContext, _: &hir::Stmt) { } - fn check_arm(&mut self, _: &LateContext, _: &hir::Arm) { } - fn check_pat(&mut self, _: &LateContext, _: &hir::Pat) { } - fn check_decl(&mut self, _: &LateContext, _: &hir::Decl) { } - fn check_expr(&mut self, _: &LateContext, _: &hir::Expr) { } - fn check_expr_post(&mut self, _: &LateContext, _: &hir::Expr) { } - fn check_ty(&mut self, _: &LateContext, _: &hir::Ty) { } - fn check_generics(&mut self, _: &LateContext, _: &hir::Generics) { } - fn check_fn(&mut self, _: &LateContext, - _: FnKind, _: &hir::FnDecl, _: &hir::Expr, _: Span, _: ast::NodeId) { } - fn check_fn_post(&mut self, _: &LateContext, - _: FnKind, _: &hir::FnDecl, _: &hir::Expr, _: Span, _: ast::NodeId) { } - fn check_trait_item(&mut self, _: &LateContext, _: &hir::TraitItem) { } - fn check_trait_item_post(&mut self, _: &LateContext, _: &hir::TraitItem) { } - fn check_impl_item(&mut self, _: &LateContext, _: &hir::ImplItem) { } - fn check_impl_item_post(&mut self, _: &LateContext, _: &hir::ImplItem) { } - fn check_struct_def(&mut self, _: &LateContext, - _: &hir::VariantData, _: ast::Name, _: &hir::Generics, _: ast::NodeId) { } - fn check_struct_def_post(&mut self, _: &LateContext, - _: &hir::VariantData, _: ast::Name, _: &hir::Generics, _: ast::NodeId) { } - fn check_struct_field(&mut self, _: &LateContext, _: &hir::StructField) { } - fn check_variant(&mut self, _: &LateContext, _: &hir::Variant, _: &hir::Generics) { } - fn check_variant_post(&mut self, _: &LateContext, _: &hir::Variant, _: &hir::Generics) { } - fn check_lifetime(&mut self, _: &LateContext, _: &hir::Lifetime) { } - fn check_lifetime_def(&mut self, _: &LateContext, _: &hir::LifetimeDef) { } - fn check_path(&mut self, _: &LateContext, _: &hir::Path, _: ast::NodeId) { } - fn check_attribute(&mut self, _: &LateContext, _: &ast::Attribute) { } + fn check_crate<'a, 'tcx:'a >(&mut self, _: &'a LateContext<'a, 'tcx>, _: &'tcx hir::Crate) { } + fn check_crate_post<'a, 'tcx: 'a>(&mut self, + _: &'a LateContext<'a, 'tcx>, + _: &'tcx hir::Crate) { } + fn check_mod<'a, 'tcx: 'a>(&mut self, + _: &'a LateContext<'a, 'tcx>, + _: &'tcx hir::Mod, + _: Span, + _: ast::NodeId) { } + fn check_mod_post<'a, 'tcx: 'a>(&mut self, + _: &'a LateContext<'a, 'tcx>, + _: &'tcx hir::Mod, + _: Span, + _: ast::NodeId) { } + fn check_foreign_item<'a, 'tcx: 'a>(&mut self, + _: &'a LateContext<'a, 'tcx>, + _: &'tcx hir::ForeignItem) { } + fn check_foreign_item_post<'a, 'tcx: 'a>(&mut self, + _: &'a LateContext<'a, 'tcx>, + _: &'tcx hir::ForeignItem) { } + fn check_item<'a, 'tcx: 'a>(&mut self, + _: &'a LateContext<'a, 'tcx>, + _: &'tcx hir::Item) { } + fn check_item_post<'a, 'tcx: 'a>(&mut self, + _: &'a LateContext<'a, 'tcx>, + _: &'tcx hir::Item) { } + fn check_local<'a, 'tcx: 'a>(&mut self, _: &'a LateContext<'a, 'tcx>, _: &'tcx hir::Local) { } + fn check_block<'a, 'tcx: 'a>(&mut self, _: &'a LateContext<'a, 'tcx>, _: &'tcx hir::Block) { } + fn check_block_post<'a, 'tcx: 'a>(&mut self, + _: &'a LateContext<'a, 'tcx>, + _: &'tcx hir::Block) { } + fn check_stmt<'a, 'tcx: 'a>(&mut self, _: &'a LateContext<'a, 'tcx>, _: &'tcx hir::Stmt) { } + fn check_arm<'a, 'tcx: 'a>(&mut self, _: &'a LateContext<'a, 'tcx>, _: &'tcx hir::Arm) { } + fn check_pat<'a, 'tcx: 'a>(&mut self, _: &'a LateContext<'a, 'tcx>, _: &'tcx hir::Pat) { } + fn check_decl<'a, 'tcx: 'a>(&mut self, _: &'a LateContext<'a, 'tcx>, _: &'tcx hir::Decl) { } + fn check_expr<'a, 'tcx: 'a>(&mut self, _: &'a LateContext<'a, 'tcx>, _: &'tcx hir::Expr) { } + fn check_expr_post<'a, 'tcx: 'a>(&mut self, + _: &'a LateContext<'a, 'tcx>, + _: &'tcx hir::Expr) { } + fn check_ty<'a, 'tcx: 'a>(&mut self, _: &'a LateContext<'a, 'tcx>, _: &'tcx hir::Ty) { } + fn check_generics<'a, 'tcx: 'a>(&mut self, + _: &'a LateContext<'a, 'tcx>, + _: &'tcx hir::Generics) { } + fn check_fn<'a, 'tcx: 'a>(&mut self, _: &'a LateContext<'a, 'tcx>, + _: FnKind<'tcx>, _: &'tcx hir::FnDecl, _: &'tcx hir::Expr, _: Span, _: ast::NodeId) { } + fn check_fn_post<'a, 'tcx: 'a>(&mut self, _: &'a LateContext<'a, 'tcx>, + _: FnKind<'tcx>, _: &'tcx hir::FnDecl, _: &'tcx hir::Expr, _: Span, _: ast::NodeId) { } + fn check_trait_item<'a, 'tcx: 'a>(&mut self, + _: &'a LateContext<'a, 'tcx>, + _: &'tcx hir::TraitItem) { } + fn check_trait_item_post<'a, 'tcx: 'a>(&mut self, + _: &'a LateContext<'a, 'tcx>, + _: &'tcx hir::TraitItem) { } + fn check_impl_item<'a, 'tcx: 'a>(&mut self, + _: &'a LateContext<'a, 'tcx>, + _: &'tcx hir::ImplItem) { } + fn check_impl_item_post<'a, 'tcx: 'a>(&mut self, + _: &'a LateContext<'a, 'tcx>, + _: &'tcx hir::ImplItem) { } + fn check_struct_def<'a, 'tcx: 'a>(&mut self, _: &'a LateContext<'a, 'tcx>, + _: &'tcx hir::VariantData, _: ast::Name, _: &'tcx hir::Generics, _: ast::NodeId) { } + fn check_struct_def_post<'a, 'tcx: 'a>(&mut self, _: &'a LateContext<'a, 'tcx>, + _: &'tcx hir::VariantData, _: ast::Name, _: &'tcx hir::Generics, _: ast::NodeId) { } + fn check_struct_field<'a, 'tcx: 'a>(&mut self, + _: &'a LateContext<'a, 'tcx>, + _: &'tcx hir::StructField) { } + fn check_variant<'a, 'tcx: 'a>(&mut self, + _: &'a LateContext<'a, 'tcx>, + _: &'tcx hir::Variant, + _: &'tcx hir::Generics) { } + fn check_variant_post<'a, 'tcx: 'a>(&mut self, + _: &'a LateContext<'a, 'tcx>, + _: &'tcx hir::Variant, + _: &'tcx hir::Generics) { } + fn check_lifetime<'a, 'tcx: 'a>(&mut self, + _: &'a LateContext<'a, 'tcx>, + _: &'tcx hir::Lifetime) { } + fn check_lifetime_def<'a, 'tcx: 'a>(&mut self, + _: &'a LateContext<'a, 'tcx>, + _: &'tcx hir::LifetimeDef) { } + fn check_path<'a, 'tcx: 'a>(&mut self, + _: &'a LateContext<'a, 'tcx>, + _: &'tcx hir::Path, + _: ast::NodeId) { } + fn check_attribute<'a, 'tcx: 'a>(&mut self, + _: &'a LateContext<'a, 'tcx>, + _: &'tcx ast::Attribute) { } /// Called when entering a syntax node that can have lint attributes such /// as `#[allow(...)]`. Called with *all* the attributes of that node. - fn enter_lint_attrs(&mut self, _: &LateContext, _: &[ast::Attribute]) { } + fn enter_lint_attrs<'a, 'tcx: 'a>(&mut self, + _: &'a LateContext<'a, 'tcx>, + _: &'tcx [ast::Attribute]) { } /// Counterpart to `enter_lint_attrs`. - fn exit_lint_attrs(&mut self, _: &LateContext, _: &[ast::Attribute]) { } + fn exit_lint_attrs<'a, 'tcx: 'a>(&mut self, + _: &'a LateContext<'a, 'tcx>, + _: &'tcx [ast::Attribute]) { } } pub trait EarlyLintPass: LintPass { diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs index 7c3ea656124..f2bcd135063 100644 --- a/src/librustc_lint/bad_style.rs +++ b/src/librustc_lint/bad_style.rs @@ -100,7 +100,7 @@ impl LintPass for NonCamelCaseTypes { } impl LateLintPass for NonCamelCaseTypes { - fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { + fn check_item<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { let extern_repr_count = it.attrs .iter() .filter(|attr| { @@ -133,7 +133,9 @@ impl LateLintPass for NonCamelCaseTypes { } } - fn check_generics(&mut self, cx: &LateContext, it: &hir::Generics) { + fn check_generics<'a, 'tcx: 'a>(&mut self, + cx: &LateContext<'a, 'tcx>, + it: &'tcx hir::Generics) { for gen in it.ty_params.iter() { self.check_case(cx, "type parameter", gen.name, gen.span); } @@ -227,7 +229,7 @@ impl LintPass for NonSnakeCase { } impl LateLintPass for NonSnakeCase { - fn check_crate(&mut self, cx: &LateContext, cr: &hir::Crate) { + fn check_crate<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, cr: &'tcx hir::Crate) { let attr_crate_name = cr.attrs .iter() .find(|at| at.check_name("crate_name")) @@ -239,13 +241,13 @@ impl LateLintPass for NonSnakeCase { } } - fn check_fn(&mut self, - cx: &LateContext, - fk: FnKind, - _: &hir::FnDecl, - _: &hir::Expr, - span: Span, - id: ast::NodeId) { + fn check_fn<'a, 'tcx: 'a>(&mut self, + cx: &LateContext<'a, 'tcx>, + fk: FnKind, + _: &'tcx hir::FnDecl, + _: &'tcx hir::Expr, + span: Span, + id: ast::NodeId) { match fk { FnKind::Method(name, ..) => { match method_context(cx, id, span) { @@ -265,13 +267,15 @@ impl LateLintPass for NonSnakeCase { } } - fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { + fn check_item<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { if let hir::ItemMod(_) = it.node { self.check_snake_case(cx, "module", &it.name.as_str(), Some(it.span)); } } - fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) { + fn check_trait_item<'a, 'tcx: 'a>(&mut self, + cx: &LateContext<'a, 'tcx>, + trait_item: &'tcx hir::TraitItem) { if let hir::MethodTraitItem(_, None) = trait_item.node { self.check_snake_case(cx, "trait method", @@ -280,14 +284,16 @@ impl LateLintPass for NonSnakeCase { } } - fn check_lifetime_def(&mut self, cx: &LateContext, t: &hir::LifetimeDef) { + fn check_lifetime_def<'a, 'tcx: 'a>(&mut self, + cx: &LateContext<'a, 'tcx>, + t: &'tcx hir::LifetimeDef) { self.check_snake_case(cx, "lifetime", &t.lifetime.name.as_str(), Some(t.lifetime.span)); } - fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) { + fn check_pat<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, p: &'tcx hir::Pat) { // Exclude parameter names from foreign functions let parent_node = cx.tcx.map.get_parent_node(p.id); if let hir::map::NodeForeignItem(item) = cx.tcx.map.get(parent_node) { @@ -301,12 +307,12 @@ impl LateLintPass for NonSnakeCase { } } - fn check_struct_def(&mut self, - cx: &LateContext, - s: &hir::VariantData, - _: ast::Name, - _: &hir::Generics, - _: ast::NodeId) { + fn check_struct_def<'a, 'tcx: 'a>(&mut self, + cx: &LateContext<'a, 'tcx>, + s: &'tcx hir::VariantData, + _: ast::Name, + _: &'tcx hir::Generics, + _: ast::NodeId) { for sf in s.fields() { self.check_snake_case(cx, "structure field", &sf.name.as_str(), Some(sf.span)); } @@ -349,7 +355,7 @@ impl LintPass for NonUpperCaseGlobals { } impl LateLintPass for NonUpperCaseGlobals { - fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { + fn check_item<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { match it.node { hir::ItemStatic(..) => { NonUpperCaseGlobals::check_upper_case(cx, "static variable", it.name, it.span); @@ -361,7 +367,9 @@ impl LateLintPass for NonUpperCaseGlobals { } } - fn check_trait_item(&mut self, cx: &LateContext, ti: &hir::TraitItem) { + fn check_trait_item<'a, 'tcx: 'a>(&mut self, + cx: &LateContext<'a, 'tcx>, + ti: &'tcx hir::TraitItem) { match ti.node { hir::ConstTraitItem(..) => { NonUpperCaseGlobals::check_upper_case(cx, "associated constant", ti.name, ti.span); @@ -370,7 +378,9 @@ impl LateLintPass for NonUpperCaseGlobals { } } - fn check_impl_item(&mut self, cx: &LateContext, ii: &hir::ImplItem) { + fn check_impl_item<'a, 'tcx: 'a>(&mut self, + cx: &LateContext<'a, 'tcx>, + ii: &'tcx hir::ImplItem) { match ii.node { hir::ImplItemKind::Const(..) => { NonUpperCaseGlobals::check_upper_case(cx, "associated constant", ii.name, ii.span); @@ -379,7 +389,7 @@ impl LateLintPass for NonUpperCaseGlobals { } } - fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) { + fn check_pat<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, p: &'tcx hir::Pat) { // Lint for constants that look like binding identifiers (#7526) if let PatKind::Path(hir::QPath::Resolved(None, ref path)) = p.node { if !path.global && path.segments.len() == 1 && path.segments[0].parameters.is_empty() { diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index f14fa7d4fdc..f3cb4d8820a 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -70,7 +70,7 @@ impl LintPass for WhileTrue { } impl LateLintPass for WhileTrue { - fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { + fn check_expr<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) { if let hir::ExprWhile(ref cond, ..) = e.node { if let hir::ExprLit(ref lit) = cond.node { if let ast::LitKind::Bool(true) = lit.node { @@ -110,7 +110,7 @@ impl LintPass for BoxPointers { } impl LateLintPass for BoxPointers { - fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { + fn check_item<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { match it.node { hir::ItemFn(..) | hir::ItemTy(..) | @@ -137,7 +137,7 @@ impl LateLintPass for BoxPointers { } } - fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { + fn check_expr<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) { let ty = cx.tcx.tables().node_id_to_type(e.id); self.check_heap_type(cx, e.span, ty); } @@ -159,7 +159,7 @@ impl LintPass for NonShorthandFieldPatterns { } impl LateLintPass for NonShorthandFieldPatterns { - fn check_pat(&mut self, cx: &LateContext, pat: &hir::Pat) { + fn check_pat<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, pat: &'tcx hir::Pat) { if let PatKind::Struct(_, ref field_pats, _) = pat.node { for fieldpat in field_pats { if fieldpat.node.is_shorthand { @@ -195,7 +195,7 @@ impl LintPass for UnsafeCode { } impl LateLintPass for UnsafeCode { - fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { + fn check_expr<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) { if let hir::ExprBlock(ref blk) = e.node { // Don't warn about generated blocks, that'll just pollute the output. if blk.rules == hir::UnsafeBlock(hir::UserProvided) { @@ -204,7 +204,7 @@ impl LateLintPass for UnsafeCode { } } - fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { + fn check_item<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { match it.node { hir::ItemTrait(hir::Unsafety::Unsafe, ..) => { cx.span_lint(UNSAFE_CODE, it.span, "declaration of an `unsafe` trait") @@ -218,13 +218,13 @@ impl LateLintPass for UnsafeCode { } } - fn check_fn(&mut self, - cx: &LateContext, - fk: FnKind, - _: &hir::FnDecl, - _: &hir::Expr, - span: Span, - _: ast::NodeId) { + fn check_fn<'a, 'tcx: 'a>(&mut self, + cx: &LateContext<'a, 'tcx>, + fk: FnKind<'tcx>, + _: &'tcx hir::FnDecl, + _: &'tcx hir::Expr, + span: Span, + _: ast::NodeId) { match fk { FnKind::ItemFn(_, _, hir::Unsafety::Unsafe, ..) => { cx.span_lint(UNSAFE_CODE, span, "declaration of an `unsafe` function") @@ -240,7 +240,9 @@ impl LateLintPass for UnsafeCode { } } - fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) { + fn check_trait_item<'a, 'tcx: 'a>(&mut self, + cx: &LateContext<'a, 'tcx>, + trait_item: &'tcx hir::TraitItem) { if let hir::MethodTraitItem(ref sig, None) = trait_item.node { if sig.unsafety == hir::Unsafety::Unsafe { cx.span_lint(UNSAFE_CODE, @@ -328,7 +330,9 @@ impl LintPass for MissingDoc { } impl LateLintPass for MissingDoc { - fn enter_lint_attrs(&mut self, _: &LateContext, attrs: &[ast::Attribute]) { + fn enter_lint_attrs<'a, 'tcx: 'a>(&mut self, + _: &LateContext<'a, 'tcx>, + attrs: &'tcx [ast::Attribute]) { let doc_hidden = self.doc_hidden() || attrs.iter().any(|attr| { attr.check_name("doc") && @@ -340,34 +344,36 @@ impl LateLintPass for MissingDoc { self.doc_hidden_stack.push(doc_hidden); } - fn exit_lint_attrs(&mut self, _: &LateContext, _: &[ast::Attribute]) { + fn exit_lint_attrs<'a, 'tcx: 'a>(&mut self, + _: &LateContext<'a, 'tcx>, + _attrs: &'tcx [ast::Attribute]) { self.doc_hidden_stack.pop().expect("empty doc_hidden_stack"); } - fn check_struct_def(&mut self, - _: &LateContext, - _: &hir::VariantData, - _: ast::Name, - _: &hir::Generics, - item_id: ast::NodeId) { + fn check_struct_def<'a, 'tcx: 'a>(&mut self, + _: &LateContext<'a, 'tcx>, + _: &'tcx hir::VariantData, + _: ast::Name, + _: &'tcx hir::Generics, + item_id: ast::NodeId) { self.struct_def_stack.push(item_id); } - fn check_struct_def_post(&mut self, - _: &LateContext, - _: &hir::VariantData, - _: ast::Name, - _: &hir::Generics, - item_id: ast::NodeId) { + fn check_struct_def_post<'a, 'tcx: 'a>(&mut self, + _: &LateContext<'a, 'tcx>, + _: &'tcx hir::VariantData, + _: ast::Name, + _: &'tcx hir::Generics, + item_id: ast::NodeId) { let popped = self.struct_def_stack.pop().expect("empty struct_def_stack"); assert!(popped == item_id); } - fn check_crate(&mut self, cx: &LateContext, krate: &hir::Crate) { + fn check_crate<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, krate: &'tcx hir::Crate) { self.check_missing_docs_attrs(cx, None, &krate.attrs, krate.span, "crate"); } - fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { + fn check_item<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { let desc = match it.node { hir::ItemFn(..) => "a function", hir::ItemMod(..) => "a module", @@ -412,7 +418,9 @@ impl LateLintPass for MissingDoc { self.check_missing_docs_attrs(cx, Some(it.id), &it.attrs, it.span, desc); } - fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) { + fn check_trait_item<'a, 'tcx: 'a>(&mut self, + cx: &LateContext<'a, 'tcx>, + trait_item: &'tcx hir::TraitItem) { if self.private_traits.contains(&trait_item.id) { return; } @@ -430,7 +438,9 @@ impl LateLintPass for MissingDoc { desc); } - fn check_impl_item(&mut self, cx: &LateContext, impl_item: &hir::ImplItem) { + fn check_impl_item<'a, 'tcx: 'a>(&mut self, + cx: &LateContext<'a, 'tcx>, + impl_item: &'tcx hir::ImplItem) { // If the method is an impl for a trait, don't doc. if method_context(cx, impl_item.id, impl_item.span) == MethodLateContext::TraitImpl { return; @@ -448,7 +458,9 @@ impl LateLintPass for MissingDoc { desc); } - fn check_struct_field(&mut self, cx: &LateContext, sf: &hir::StructField) { + fn check_struct_field<'a, 'tcx: 'a>(&mut self, + cx: &LateContext<'a, 'tcx>, + sf: &'tcx hir::StructField) { if !sf.is_positional() { if sf.vis == hir::Public || self.in_variant { let cur_struct_def = *self.struct_def_stack @@ -463,7 +475,10 @@ impl LateLintPass for MissingDoc { } } - fn check_variant(&mut self, cx: &LateContext, v: &hir::Variant, _: &hir::Generics) { + fn check_variant<'a, 'tcx: 'a>(&mut self, + cx: &LateContext<'a, 'tcx>, + v: &'tcx hir::Variant, + _: &'tcx hir::Generics) { self.check_missing_docs_attrs(cx, Some(v.node.data.id()), &v.node.attrs, @@ -473,7 +488,10 @@ impl LateLintPass for MissingDoc { self.in_variant = true; } - fn check_variant_post(&mut self, _: &LateContext, _: &hir::Variant, _: &hir::Generics) { + fn check_variant_post<'a, 'tcx: 'a>(&mut self, + _: &LateContext<'a, 'tcx>, + _: &'tcx hir::Variant, + _: &'tcx hir::Generics) { assert!(self.in_variant); self.in_variant = false; } @@ -495,7 +513,7 @@ impl LintPass for MissingCopyImplementations { } impl LateLintPass for MissingCopyImplementations { - fn check_item(&mut self, cx: &LateContext, item: &hir::Item) { + fn check_item<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) { if !cx.access_levels.is_reachable(item.id) { return; } @@ -564,7 +582,7 @@ impl LintPass for MissingDebugImplementations { } impl LateLintPass for MissingDebugImplementations { - fn check_item(&mut self, cx: &LateContext, item: &hir::Item) { + fn check_item<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) { if !cx.access_levels.is_reachable(item.id) { return; } @@ -670,13 +688,13 @@ impl LintPass for UnconditionalRecursion { } impl LateLintPass for UnconditionalRecursion { - fn check_fn(&mut self, - cx: &LateContext, - fn_kind: FnKind, - _: &hir::FnDecl, - blk: &hir::Expr, - sp: Span, - id: ast::NodeId) { + fn check_fn<'a, 'tcx: 'a>(&mut self, + cx: &LateContext<'a, 'tcx>, + fn_kind: FnKind<'tcx>, + _: &'tcx hir::FnDecl, + blk: &'tcx hir::Expr, + sp: Span, + id: ast::NodeId) { let method = match fn_kind { FnKind::ItemFn(..) => None, FnKind::Method(..) => { @@ -933,7 +951,7 @@ impl LintPass for PluginAsLibrary { } impl LateLintPass for PluginAsLibrary { - fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { + fn check_item<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { if cx.sess().plugin_registrar_fn.get().is_some() { // We're compiling a plugin; it's fine to link other plugins. return; @@ -999,7 +1017,7 @@ impl LintPass for InvalidNoMangleItems { } impl LateLintPass for InvalidNoMangleItems { - fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { + fn check_item<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { match it.node { hir::ItemFn(.., ref generics, _) => { if attr::contains_name(&it.attrs, "no_mangle") { @@ -1053,7 +1071,7 @@ impl LintPass for MutableTransmutes { } impl LateLintPass for MutableTransmutes { - fn check_expr(&mut self, cx: &LateContext, expr: &hir::Expr) { + fn check_expr<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) { use syntax::abi::Abi::RustIntrinsic; let msg = "mutating transmuted &mut T from &T may cause undefined behavior, \ @@ -1121,7 +1139,9 @@ impl LintPass for UnstableFeatures { } impl LateLintPass for UnstableFeatures { - fn check_attribute(&mut self, ctx: &LateContext, attr: &ast::Attribute) { + fn check_attribute<'a, 'tcx: 'a>(&mut self, + ctx: &LateContext<'a, 'tcx>, + attr: &'tcx ast::Attribute) { if attr.meta().check_name("feature") { if let Some(items) = attr.meta().meta_item_list() { for item in items { @@ -1148,7 +1168,7 @@ impl LintPass for UnionsWithDropFields { } impl LateLintPass for UnionsWithDropFields { - fn check_item(&mut self, ctx: &LateContext, item: &hir::Item) { + fn check_item<'a, 'tcx: 'a>(&mut self, ctx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) { if let hir::ItemUnion(ref vdata, _) = item.node { let param_env = &ty::ParameterEnvironment::for_item(ctx.tcx, item.id); for field in vdata.fields() { diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index bba31c8237d..48c209e1665 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -104,7 +104,7 @@ impl LintPass for TypeLimits { } impl LateLintPass for TypeLimits { - fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { + fn check_expr<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) { match e.node { hir::ExprUnary(hir::UnNeg, ref expr) => { if let hir::ExprLit(ref lit) = expr.node { @@ -707,7 +707,7 @@ impl LintPass for ImproperCTypes { } impl LateLintPass for ImproperCTypes { - fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { + fn check_item<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { let mut vis = ImproperCTypesVisitor { cx: cx }; if let hir::ItemForeignMod(ref nmod) = it.node { if nmod.abi != Abi::RustIntrinsic && nmod.abi != Abi::PlatformIntrinsic { @@ -735,7 +735,7 @@ impl LintPass for VariantSizeDifferences { } impl LateLintPass for VariantSizeDifferences { - fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { + fn check_item<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { if let hir::ItemEnum(ref enum_definition, ref gens) = it.node { if gens.ty_params.is_empty() { // sizes only make sense for non-generic types diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 873c141065e..23fd7a86640 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -78,7 +78,7 @@ impl LintPass for UnusedMut { } impl LateLintPass for UnusedMut { - fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { + fn check_expr<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) { if let hir::ExprMatch(_, ref arms, _) = e.node { for a in arms { self.check_unused_mut_pat(cx, &a.pats) @@ -86,7 +86,7 @@ impl LateLintPass for UnusedMut { } } - fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) { + fn check_stmt<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, s: &'tcx hir::Stmt) { if let hir::StmtDecl(ref d, _) = s.node { if let hir::DeclLocal(ref l) = d.node { self.check_unused_mut_pat(cx, slice::ref_slice(&l.pat)); @@ -94,13 +94,13 @@ impl LateLintPass for UnusedMut { } } - fn check_fn(&mut self, - cx: &LateContext, - _: FnKind, - decl: &hir::FnDecl, - _: &hir::Expr, - _: Span, - _: ast::NodeId) { + fn check_fn<'a, 'tcx: 'a>(&mut self, + cx: &LateContext<'a, 'tcx>, + _: FnKind<'tcx>, + decl: &'tcx hir::FnDecl, + _: &'tcx hir::Expr, + _: Span, + _: ast::NodeId) { for a in &decl.inputs { self.check_unused_mut_pat(cx, slice::ref_slice(&a.pat)); } @@ -129,7 +129,7 @@ impl LintPass for UnusedResults { } impl LateLintPass for UnusedResults { - fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) { + fn check_stmt<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, s: &'tcx hir::Stmt) { let expr = match s.node { hir::StmtSemi(ref expr, _) => &**expr, _ => return, @@ -188,7 +188,7 @@ impl LintPass for UnusedUnsafe { } impl LateLintPass for UnusedUnsafe { - fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { + fn check_expr<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) { if let hir::ExprBlock(ref blk) = e.node { // Don't warn about generated blocks, that'll just pollute the output. if blk.rules == hir::UnsafeBlock(hir::UserProvided) && @@ -215,7 +215,7 @@ impl LintPass for PathStatements { } impl LateLintPass for PathStatements { - fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) { + fn check_stmt<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, s: &'tcx hir::Stmt) { if let hir::StmtSemi(ref expr, _) = s.node { if let hir::ExprPath(_) = expr.node { cx.span_lint(PATH_STATEMENTS, s.span, "path statement with no effect"); @@ -240,7 +240,9 @@ impl LintPass for UnusedAttributes { } impl LateLintPass for UnusedAttributes { - fn check_attribute(&mut self, cx: &LateContext, attr: &ast::Attribute) { + fn check_attribute<'a, 'tcx: 'a>(&mut self, + cx: &LateContext<'a, 'tcx>, + attr: &'tcx ast::Attribute) { debug!("checking attribute: {:?}", attr); // Note that check_name() marks the attribute as used if it matches. @@ -434,7 +436,7 @@ impl LintPass for UnusedAllocation { } impl LateLintPass for UnusedAllocation { - fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { + fn check_expr<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) { match e.node { hir::ExprBox(_) => {} _ => return, diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index fa07006aa63..2d0f0864752 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -101,8 +101,8 @@ impl<'a> AstValidator<'a> { } } -impl<'a> Visitor for AstValidator<'a> { - fn visit_lifetime(&mut self, lt: &Lifetime) { +impl<'a> Visitor<'a> for AstValidator<'a> { + fn visit_lifetime(&mut self, lt: &'a Lifetime) { if lt.name == "'_" { self.session.add_lint(lint::builtin::LIFETIME_UNDERSCORE, lt.id, @@ -113,7 +113,7 @@ impl<'a> Visitor for AstValidator<'a> { visit::walk_lifetime(self, lt) } - fn visit_expr(&mut self, expr: &Expr) { + fn visit_expr(&mut self, expr: &'a Expr) { match expr.node { ExprKind::While(.., Some(ident)) | ExprKind::Loop(_, Some(ident)) | @@ -129,7 +129,7 @@ impl<'a> Visitor for AstValidator<'a> { visit::walk_expr(self, expr) } - fn visit_ty(&mut self, ty: &Ty) { + fn visit_ty(&mut self, ty: &'a Ty) { match ty.node { TyKind::BareFn(ref bfty) => { self.check_decl_no_pat(&bfty.decl, |span, _| { @@ -153,7 +153,7 @@ impl<'a> Visitor for AstValidator<'a> { visit::walk_ty(self, ty) } - fn visit_path(&mut self, path: &Path, id: NodeId) { + fn visit_path(&mut self, path: &'a Path, id: NodeId) { if path.global && path.segments.len() > 0 { let ident = path.segments[0].identifier; if token::Ident(ident).is_path_segment_keyword() { @@ -167,7 +167,7 @@ impl<'a> Visitor for AstValidator<'a> { visit::walk_path(self, path) } - fn visit_item(&mut self, item: &Item) { + fn visit_item(&mut self, item: &'a Item) { match item.node { ItemKind::Use(ref view_path) => { let path = view_path.node.path(); @@ -249,7 +249,7 @@ impl<'a> Visitor for AstValidator<'a> { visit::walk_item(self, item) } - fn visit_foreign_item(&mut self, fi: &ForeignItem) { + fn visit_foreign_item(&mut self, fi: &'a ForeignItem) { match fi.node { ForeignItemKind::Fn(ref decl, _) => { self.check_decl_no_pat(decl, |span, is_recent| { @@ -272,7 +272,7 @@ impl<'a> Visitor for AstValidator<'a> { visit::walk_foreign_item(self, fi) } - fn visit_vis(&mut self, vis: &Visibility) { + fn visit_vis(&mut self, vis: &'a Visibility) { match *vis { Visibility::Restricted { ref path, .. } => { if !path.segments.iter().all(|segment| segment.parameters.is_empty()) { diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs index b7858013988..f7e026866e2 100644 --- a/src/librustc_passes/hir_stats.rs +++ b/src/librustc_passes/hir_stats.rs @@ -48,7 +48,7 @@ pub fn print_hir_stats(krate: &hir::Crate) { collector.print("HIR STATS"); } -pub fn print_ast_stats(krate: &ast::Crate, title: &str) { +pub fn print_ast_stats<'v>(krate: &'v ast::Crate, title: &str) { let mut collector = StatCollector { krate: None, data: FxHashMap(), @@ -245,133 +245,133 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { } } -impl<'v> ast_visit::Visitor for StatCollector<'v> { +impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { - fn visit_mod(&mut self, m: &ast::Mod, _s: Span, _n: NodeId) { + fn visit_mod(&mut self, m: &'v ast::Mod, _s: Span, _n: NodeId) { self.record("Mod", Id::None, m); ast_visit::walk_mod(self, m) } - fn visit_foreign_item(&mut self, i: &ast::ForeignItem) { + fn visit_foreign_item(&mut self, i: &'v ast::ForeignItem) { self.record("ForeignItem", Id::None, i); ast_visit::walk_foreign_item(self, i) } - fn visit_item(&mut self, i: &ast::Item) { + fn visit_item(&mut self, i: &'v ast::Item) { self.record("Item", Id::None, i); ast_visit::walk_item(self, i) } - fn visit_local(&mut self, l: &ast::Local) { + fn visit_local(&mut self, l: &'v ast::Local) { self.record("Local", Id::None, l); ast_visit::walk_local(self, l) } - fn visit_block(&mut self, b: &ast::Block) { + fn visit_block(&mut self, b: &'v ast::Block) { self.record("Block", Id::None, b); ast_visit::walk_block(self, b) } - fn visit_stmt(&mut self, s: &ast::Stmt) { + fn visit_stmt(&mut self, s: &'v ast::Stmt) { self.record("Stmt", Id::None, s); ast_visit::walk_stmt(self, s) } - fn visit_arm(&mut self, a: &ast::Arm) { + fn visit_arm(&mut self, a: &'v ast::Arm) { self.record("Arm", Id::None, a); ast_visit::walk_arm(self, a) } - fn visit_pat(&mut self, p: &ast::Pat) { + fn visit_pat(&mut self, p: &'v ast::Pat) { self.record("Pat", Id::None, p); ast_visit::walk_pat(self, p) } - fn visit_expr(&mut self, ex: &ast::Expr) { + fn visit_expr(&mut self, ex: &'v ast::Expr) { self.record("Expr", Id::None, ex); ast_visit::walk_expr(self, ex) } - fn visit_ty(&mut self, t: &ast::Ty) { + fn visit_ty(&mut self, t: &'v ast::Ty) { self.record("Ty", Id::None, t); ast_visit::walk_ty(self, t) } fn visit_fn(&mut self, - fk: ast_visit::FnKind, - fd: &ast::FnDecl, + fk: ast_visit::FnKind<'v>, + fd: &'v ast::FnDecl, s: Span, _: NodeId) { self.record("FnDecl", Id::None, fd); ast_visit::walk_fn(self, fk, fd, s) } - fn visit_trait_item(&mut self, ti: &ast::TraitItem) { + fn visit_trait_item(&mut self, ti: &'v ast::TraitItem) { self.record("TraitItem", Id::None, ti); ast_visit::walk_trait_item(self, ti) } - fn visit_impl_item(&mut self, ii: &ast::ImplItem) { + fn visit_impl_item(&mut self, ii: &'v ast::ImplItem) { self.record("ImplItem", Id::None, ii); ast_visit::walk_impl_item(self, ii) } - fn visit_ty_param_bound(&mut self, bounds: &ast::TyParamBound) { + fn visit_ty_param_bound(&mut self, bounds: &'v ast::TyParamBound) { self.record("TyParamBound", Id::None, bounds); ast_visit::walk_ty_param_bound(self, bounds) } - fn visit_struct_field(&mut self, s: &ast::StructField) { + fn visit_struct_field(&mut self, s: &'v ast::StructField) { self.record("StructField", Id::None, s); ast_visit::walk_struct_field(self, s) } fn visit_variant(&mut self, - v: &ast::Variant, - g: &ast::Generics, + v: &'v ast::Variant, + g: &'v ast::Generics, item_id: NodeId) { self.record("Variant", Id::None, v); ast_visit::walk_variant(self, v, g, item_id) } - fn visit_lifetime(&mut self, lifetime: &ast::Lifetime) { + fn visit_lifetime(&mut self, lifetime: &'v ast::Lifetime) { self.record("Lifetime", Id::None, lifetime); ast_visit::walk_lifetime(self, lifetime) } - fn visit_lifetime_def(&mut self, lifetime: &ast::LifetimeDef) { + fn visit_lifetime_def(&mut self, lifetime: &'v ast::LifetimeDef) { self.record("LifetimeDef", Id::None, lifetime); ast_visit::walk_lifetime_def(self, lifetime) } - fn visit_mac(&mut self, mac: &ast::Mac) { + fn visit_mac(&mut self, mac: &'v ast::Mac) { self.record("Mac", Id::None, mac); } fn visit_path_list_item(&mut self, - prefix: &ast::Path, - item: &ast::PathListItem) { + prefix: &'v ast::Path, + item: &'v ast::PathListItem) { self.record("PathListItem", Id::None, item); ast_visit::walk_path_list_item(self, prefix, item) } fn visit_path_segment(&mut self, path_span: Span, - path_segment: &ast::PathSegment) { + path_segment: &'v ast::PathSegment) { self.record("PathSegment", Id::None, path_segment); ast_visit::walk_path_segment(self, path_span, path_segment) } - fn visit_assoc_type_binding(&mut self, type_binding: &ast::TypeBinding) { + fn visit_assoc_type_binding(&mut self, type_binding: &'v ast::TypeBinding) { self.record("TypeBinding", Id::None, type_binding); ast_visit::walk_assoc_type_binding(self, type_binding) } - fn visit_attribute(&mut self, attr: &ast::Attribute) { + fn visit_attribute(&mut self, attr: &'v ast::Attribute) { self.record("Attribute", Id::None, attr); } - fn visit_macro_def(&mut self, macro_def: &ast::MacroDef) { + fn visit_macro_def(&mut self, macro_def: &'v ast::MacroDef) { self.record("MacroDef", Id::None, macro_def); ast_visit::walk_macro_def(self, macro_def) } diff --git a/src/librustc_passes/no_asm.rs b/src/librustc_passes/no_asm.rs index af3065d64e8..4dbf57a99bc 100644 --- a/src/librustc_passes/no_asm.rs +++ b/src/librustc_passes/no_asm.rs @@ -31,8 +31,8 @@ struct CheckNoAsm<'a> { sess: &'a Session, } -impl<'a> Visitor for CheckNoAsm<'a> { - fn visit_expr(&mut self, e: &ast::Expr) { +impl<'a> Visitor<'a> for CheckNoAsm<'a> { + fn visit_expr(&mut self, e: &'a ast::Expr) { match e.node { ast::ExprKind::InlineAsm(_) => { span_err!(self.sess, diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 7bcc543023e..25a37931ba3 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -678,7 +678,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { macro_rules! method { ($visit:ident: $ty:ty, $invoc:path, $walk:ident) => { - fn $visit(&mut self, node: &$ty) { + fn $visit(&mut self, node: &'a $ty) { if let $invoc(..) = node.node { self.visit_invoc(node.id); } else { @@ -688,13 +688,13 @@ macro_rules! method { } } -impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> { +impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> { method!(visit_impl_item: ast::ImplItem, ast::ImplItemKind::Macro, walk_impl_item); method!(visit_expr: ast::Expr, ast::ExprKind::Mac, walk_expr); method!(visit_pat: ast::Pat, ast::PatKind::Mac, walk_pat); method!(visit_ty: ast::Ty, ast::TyKind::Mac, walk_ty); - fn visit_item(&mut self, item: &Item) { + fn visit_item(&mut self, item: &'a Item) { let macro_use = match item.node { ItemKind::Mac(..) if item.id == ast::DUMMY_NODE_ID => return, // Scope placeholder ItemKind::Mac(..) => { @@ -713,7 +713,7 @@ impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> { } } - fn visit_stmt(&mut self, stmt: &ast::Stmt) { + fn visit_stmt(&mut self, stmt: &'a ast::Stmt) { if let ast::StmtKind::Mac(..) = stmt.node { self.legacy_scope = LegacyScope::Expansion(self.visit_invoc(stmt.id)); } else { @@ -721,12 +721,12 @@ impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> { } } - fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) { + fn visit_foreign_item(&mut self, foreign_item: &'a ForeignItem) { self.resolver.build_reduced_graph_for_foreign_item(foreign_item, self.expansion); visit::walk_foreign_item(self, foreign_item); } - fn visit_block(&mut self, block: &Block) { + fn visit_block(&mut self, block: &'a Block) { let (parent, legacy_scope) = (self.resolver.current_module, self.legacy_scope); self.resolver.build_reduced_graph_for_block(block); visit::walk_block(self, block); @@ -734,7 +734,7 @@ impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> { self.legacy_scope = legacy_scope; } - fn visit_trait_item(&mut self, item: &TraitItem) { + fn visit_trait_item(&mut self, item: &'a TraitItem) { let parent = self.resolver.current_module; let def_id = parent.def_id().unwrap(); diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs index 492c5e695bb..19aa5f78fd5 100644 --- a/src/librustc_resolve/check_unused.rs +++ b/src/librustc_resolve/check_unused.rs @@ -74,8 +74,8 @@ impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> { } } -impl<'a, 'b> Visitor for UnusedImportCheckVisitor<'a, 'b> { - fn visit_item(&mut self, item: &ast::Item) { +impl<'a, 'b> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b> { + fn visit_item(&mut self, item: &'a ast::Item) { visit::walk_item(self, item); // Ignore is_public import statements because there's no way to be sure // whether they're used or not. Also ignore imports with a dummy span diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index d5297a5a47d..f7aaf2475f6 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -557,26 +557,28 @@ impl ::std::ops::IndexMut for PerNS { } } -impl<'a> Visitor for Resolver<'a> { - fn visit_item(&mut self, item: &Item) { +impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { + fn visit_item(&mut self, item: &'tcx Item) { self.resolve_item(item); } - fn visit_arm(&mut self, arm: &Arm) { + fn visit_arm(&mut self, arm: &'tcx Arm) { self.resolve_arm(arm); } - fn visit_block(&mut self, block: &Block) { + fn visit_block(&mut self, block: &'tcx Block) { self.resolve_block(block); } - fn visit_expr(&mut self, expr: &Expr) { + fn visit_expr(&mut self, expr: &'tcx Expr) { self.resolve_expr(expr, None); } - fn visit_local(&mut self, local: &Local) { + fn visit_local(&mut self, local: &'tcx Local) { self.resolve_local(local); } - fn visit_ty(&mut self, ty: &Ty) { + fn visit_ty(&mut self, ty: &'tcx Ty) { self.resolve_type(ty); } - fn visit_poly_trait_ref(&mut self, tref: &ast::PolyTraitRef, m: &ast::TraitBoundModifier) { + fn visit_poly_trait_ref(&mut self, + tref: &'tcx ast::PolyTraitRef, + m: &'tcx ast::TraitBoundModifier) { let ast::Path { ref segments, span, global } = tref.trait_ref.path; let path: Vec<_> = segments.iter().map(|seg| seg.identifier).collect(); let def = self.resolve_trait_reference(&path, global, None, span); @@ -584,8 +586,8 @@ impl<'a> Visitor for Resolver<'a> { visit::walk_poly_trait_ref(self, tref, m); } fn visit_variant(&mut self, - variant: &ast::Variant, - generics: &Generics, + variant: &'tcx ast::Variant, + generics: &'tcx Generics, item_id: ast::NodeId) { if let Some(ref dis_expr) = variant.node.disr_expr { // resolve the discriminator expr as a constant @@ -601,7 +603,7 @@ impl<'a> Visitor for Resolver<'a> { item_id, variant.span); } - fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) { + fn visit_foreign_item(&mut self, foreign_item: &'tcx ForeignItem) { let type_parameters = match foreign_item.node { ForeignItemKind::Fn(_, ref generics) => { HasTypeParameters(generics, ItemRibKind) @@ -613,8 +615,8 @@ impl<'a> Visitor for Resolver<'a> { }); } fn visit_fn(&mut self, - function_kind: FnKind, - declaration: &FnDecl, + function_kind: FnKind<'tcx>, + declaration: &'tcx FnDecl, _: Span, node_id: NodeId) { let rib_kind = match function_kind { diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 4cd28e0a46d..ec368c6bc1f 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -345,7 +345,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } } - fn process_formals(&mut self, formals: &Vec, qualname: &str) { + fn process_formals(&mut self, formals: &'l [ast::Arg], qualname: &str) { for arg in formals { self.visit_pat(&arg.pat); let mut collector = PathCollector::new(); @@ -379,12 +379,12 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } fn process_method(&mut self, - sig: &ast::MethodSig, - body: Option<&ast::Block>, + sig: &'l ast::MethodSig, + body: Option<&'l ast::Block>, id: ast::NodeId, name: ast::Name, vis: Visibility, - attrs: &[Attribute], + attrs: &'l [Attribute], span: Span) { debug!("process_method: {}:{}", id, name); @@ -465,7 +465,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } } - fn process_trait_ref(&mut self, trait_ref: &ast::TraitRef) { + fn process_trait_ref(&mut self, trait_ref: &'l ast::TraitRef) { let trait_ref_data = self.save_ctxt.get_trait_ref_data(trait_ref, self.cur_scope); if let Some(trait_ref_data) = trait_ref_data { if !self.span.filter_generated(Some(trait_ref_data.span), trait_ref.path.span) { @@ -488,7 +488,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { // Dump generic params bindings, then visit_generics fn process_generic_params(&mut self, - generics: &ast::Generics, + generics: &'l ast::Generics, full_span: Span, prefix: &str, id: NodeId) { @@ -522,10 +522,10 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } fn process_fn(&mut self, - item: &ast::Item, - decl: &ast::FnDecl, - ty_params: &ast::Generics, - body: &ast::Block) { + item: &'l ast::Item, + decl: &'l ast::FnDecl, + ty_params: &'l ast::Generics, + body: &'l ast::Block) { if let Some(fn_data) = self.save_ctxt.get_item_data(item) { down_cast_data!(fn_data, FunctionData, item.span); if !self.span.filter_generated(Some(fn_data.span), item.span) { @@ -547,7 +547,10 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { self.nest(item.id, |v| v.visit_block(&body)); } - fn process_static_or_const_item(&mut self, item: &ast::Item, typ: &ast::Ty, expr: &ast::Expr) { + fn process_static_or_const_item(&mut self, + item: &'l ast::Item, + typ: &'l ast::Ty, + expr: &'l ast::Expr) { if let Some(var_data) = self.save_ctxt.get_item_data(item) { down_cast_data!(var_data, VariableData, item.span); if !self.span.filter_generated(Some(var_data.span), item.span) { @@ -562,11 +565,11 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { id: ast::NodeId, name: ast::Name, span: Span, - typ: &ast::Ty, - expr: &ast::Expr, + typ: &'l ast::Ty, + expr: &'l ast::Expr, parent_id: DefId, vis: Visibility, - attrs: &[Attribute]) { + attrs: &'l [Attribute]) { let qualname = format!("::{}", self.tcx.node_path_str(id)); let sub_span = self.span.sub_span_after_keyword(span, keywords::Const); @@ -594,9 +597,9 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { // FIXME tuple structs should generate tuple-specific data. fn process_struct(&mut self, - item: &ast::Item, - def: &ast::VariantData, - ty_params: &ast::Generics) { + item: &'l ast::Item, + def: &'l ast::VariantData, + ty_params: &'l ast::Generics) { let name = item.ident.to_string(); let qualname = format!("::{}", self.tcx.node_path_str(item.id)); @@ -641,9 +644,9 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } fn process_enum(&mut self, - item: &ast::Item, - enum_definition: &ast::EnumDef, - ty_params: &ast::Generics) { + item: &'l ast::Item, + enum_definition: &'l ast::EnumDef, + ty_params: &'l ast::Generics) { let enum_data = self.save_ctxt.get_item_data(item); let enum_data = match enum_data { None => return, @@ -721,11 +724,11 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } fn process_impl(&mut self, - item: &ast::Item, - type_parameters: &ast::Generics, - trait_ref: &Option, - typ: &ast::Ty, - impl_items: &[ast::ImplItem]) { + item: &'l ast::Item, + type_parameters: &'l ast::Generics, + trait_ref: &'l Option, + typ: &'l ast::Ty, + impl_items: &'l [ast::ImplItem]) { let mut has_self_ref = false; if let Some(impl_data) = self.save_ctxt.get_item_data(item) { down_cast_data!(impl_data, ImplData, item.span); @@ -764,10 +767,10 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } fn process_trait(&mut self, - item: &ast::Item, - generics: &ast::Generics, - trait_refs: &ast::TyParamBounds, - methods: &[ast::TraitItem]) { + item: &'l ast::Item, + generics: &'l ast::Generics, + trait_refs: &'l ast::TyParamBounds, + methods: &'l [ast::TraitItem]) { let name = item.ident.to_string(); let qualname = format!("::{}", self.tcx.node_path_str(item.id)); let mut val = name.clone(); @@ -938,11 +941,11 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } fn process_struct_lit(&mut self, - ex: &ast::Expr, - path: &ast::Path, - fields: &Vec, - variant: &ty::VariantDef, - base: &Option>) { + ex: &'l ast::Expr, + path: &'l ast::Path, + fields: &'l [ast::Field], + variant: &'l ty::VariantDef, + base: &'l Option>) { self.write_sub_paths_truncated(path, false); if let Some(struct_lit_data) = self.save_ctxt.get_expr_data(ex) { @@ -969,7 +972,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { walk_list!(self, visit_expr, base); } - fn process_method_call(&mut self, ex: &ast::Expr, args: &Vec>) { + fn process_method_call(&mut self, ex: &'l ast::Expr, args: &'l [P]) { if let Some(mcd) = self.save_ctxt.get_expr_data(ex) { down_cast_data!(mcd, MethodCallData, ex.span); if !self.span.filter_generated(Some(mcd.span), ex.span) { @@ -981,7 +984,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { walk_list!(self, visit_expr, args); } - fn process_pat(&mut self, p: &ast::Pat) { + fn process_pat(&mut self, p: &'l ast::Pat) { match p.node { PatKind::Struct(ref path, ref fields, _) => { visit::walk_path(self, path); @@ -1014,7 +1017,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } - fn process_var_decl(&mut self, p: &ast::Pat, value: String) { + fn process_var_decl(&mut self, p: &'l ast::Pat, value: String) { // The local could declare multiple new vars, we must walk the // pattern and collect them all. let mut collector = PathCollector::new(); @@ -1105,7 +1108,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } } - fn process_trait_item(&mut self, trait_item: &ast::TraitItem, trait_id: DefId) { + fn process_trait_item(&mut self, trait_item: &'l ast::TraitItem, trait_id: DefId) { self.process_macro_use(trait_item.span, trait_item.id); match trait_item.node { ast::TraitItemKind::Const(ref ty, Some(ref expr)) => { @@ -1133,7 +1136,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } } - fn process_impl_item(&mut self, impl_item: &ast::ImplItem, impl_id: DefId) { + fn process_impl_item(&mut self, impl_item: &'l ast::ImplItem, impl_id: DefId) { self.process_macro_use(impl_item.span, impl_item.id); match impl_item.node { ast::ImplItemKind::Const(ref ty, ref expr) => { @@ -1161,8 +1164,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } } -impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> { - fn visit_item(&mut self, item: &ast::Item) { +impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, D> { + fn visit_item(&mut self, item: &'l ast::Item) { use syntax::ast::ItemKind::*; self.process_macro_use(item.span, item.id); match item.node { @@ -1306,7 +1309,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> } } - fn visit_generics(&mut self, generics: &ast::Generics) { + fn visit_generics(&mut self, generics: &'l ast::Generics) { for param in generics.ty_params.iter() { for bound in param.bounds.iter() { if let ast::TraitTyParamBound(ref trait_ref, _) = *bound { @@ -1319,7 +1322,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> } } - fn visit_ty(&mut self, t: &ast::Ty) { + fn visit_ty(&mut self, t: &'l ast::Ty) { self.process_macro_use(t.span, t.id); match t.node { ast::TyKind::Path(_, ref path) => { @@ -1343,7 +1346,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> } } - fn visit_expr(&mut self, ex: &ast::Expr) { + fn visit_expr(&mut self, ex: &'l ast::Expr) { self.process_macro_use(ex.span, ex.id); match ex.node { ast::ExprKind::Call(ref _f, ref _args) => { @@ -1451,17 +1454,17 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> } } - fn visit_mac(&mut self, mac: &ast::Mac) { + fn visit_mac(&mut self, mac: &'l ast::Mac) { // These shouldn't exist in the AST at this point, log a span bug. span_bug!(mac.span, "macro invocation should have been expanded out of AST"); } - fn visit_pat(&mut self, p: &ast::Pat) { + fn visit_pat(&mut self, p: &'l ast::Pat) { self.process_macro_use(p.span, p.id); self.process_pat(p); } - fn visit_arm(&mut self, arm: &ast::Arm) { + fn visit_arm(&mut self, arm: &'l ast::Arm) { let mut collector = PathCollector::new(); for pattern in &arm.pats { // collect paths from the arm's patterns @@ -1524,12 +1527,12 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> self.visit_expr(&arm.body); } - fn visit_stmt(&mut self, s: &ast::Stmt) { + fn visit_stmt(&mut self, s: &'l ast::Stmt) { self.process_macro_use(s.span, s.id); visit::walk_stmt(self, s) } - fn visit_local(&mut self, l: &ast::Local) { + fn visit_local(&mut self, l: &'l ast::Local) { self.process_macro_use(l.span, l.id); let value = l.init.as_ref().map(|i| self.span.snippet(i.span)).unwrap_or(String::new()); self.process_var_decl(&l.pat, value); diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 33b9f8c9034..b5cf8141da2 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -741,7 +741,7 @@ impl PathCollector { } } -impl Visitor for PathCollector { +impl<'a> Visitor<'a> for PathCollector { fn visit_pat(&mut self, p: &ast::Pat) { match p.node { PatKind::Struct(ref path, ..) => { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 4138acafac6..e3979926680 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -85,7 +85,7 @@ macro_rules! expansions { } } - pub fn visit_with(&self, visitor: &mut V) { + pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) { match *self { Expansion::OptExpr(Some(ref expr)) => visitor.visit_expr(expr), Expansion::OptExpr(None) => {} diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 29854260899..4d4eecdb652 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -1014,7 +1014,7 @@ fn starts_with_digit(s: &str) -> bool { s.as_bytes().first().cloned().map_or(false, |b| b >= b'0' && b <= b'9') } -impl<'a> Visitor for PostExpansionVisitor<'a> { +impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_attribute(&mut self, attr: &ast::Attribute) { if !self.context.cm.span_allows_unstable(attr.span) { // check for gated attributes @@ -1035,7 +1035,7 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { } } - fn visit_item(&mut self, i: &ast::Item) { + fn visit_item(&mut self, i: &'a ast::Item) { match i.node { ast::ItemKind::ExternCrate(_) => { if attr::contains_name(&i.attrs[..], "macro_reexport") { @@ -1128,7 +1128,7 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { visit::walk_item(self, i); } - fn visit_foreign_item(&mut self, i: &ast::ForeignItem) { + fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) { let links_to_llvm = match attr::first_attr_value_str_by_name(&i.attrs, "link_name") { Some(val) => val.as_str().starts_with("llvm."), _ => false @@ -1141,7 +1141,7 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { visit::walk_foreign_item(self, i) } - fn visit_ty(&mut self, ty: &ast::Ty) { + fn visit_ty(&mut self, ty: &'a ast::Ty) { match ty.node { ast::TyKind::BareFn(ref bare_fn_ty) => { self.check_abi(bare_fn_ty.abi, ty.span); @@ -1159,7 +1159,7 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { visit::walk_ty(self, ty) } - fn visit_fn_ret_ty(&mut self, ret_ty: &ast::FunctionRetTy) { + fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FunctionRetTy) { if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty { match output_ty.node { ast::TyKind::Never => return, @@ -1169,7 +1169,7 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { } } - fn visit_expr(&mut self, e: &ast::Expr) { + fn visit_expr(&mut self, e: &'a ast::Expr) { match e.node { ast::ExprKind::Box(_) => { gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX); @@ -1208,7 +1208,7 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { visit::walk_expr(self, e); } - fn visit_pat(&mut self, pattern: &ast::Pat) { + fn visit_pat(&mut self, pattern: &'a ast::Pat) { match pattern.node { PatKind::Slice(_, Some(_), ref last) if !last.is_empty() => { gate_feature_post!(&self, advanced_slice_patterns, @@ -1242,8 +1242,8 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { } fn visit_fn(&mut self, - fn_kind: FnKind, - fn_decl: &ast::FnDecl, + fn_kind: FnKind<'a>, + fn_decl: &'a ast::FnDecl, span: Span, _node_id: NodeId) { // check for const fn declarations @@ -1269,7 +1269,7 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { visit::walk_fn(self, fn_kind, fn_decl, span); } - fn visit_trait_item(&mut self, ti: &ast::TraitItem) { + fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) { match ti.node { ast::TraitItemKind::Const(..) => { gate_feature_post!(&self, associated_consts, @@ -1293,7 +1293,7 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { visit::walk_trait_item(self, ti); } - fn visit_impl_item(&mut self, ii: &ast::ImplItem) { + fn visit_impl_item(&mut self, ii: &'a ast::ImplItem) { if ii.defaultness == ast::Defaultness::Default { gate_feature_post!(&self, specialization, ii.span, @@ -1316,7 +1316,7 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { visit::walk_impl_item(self, ii); } - fn visit_vis(&mut self, vis: &ast::Visibility) { + fn visit_vis(&mut self, vis: &'a ast::Visibility) { let span = match *vis { ast::Visibility::Crate(span) => span, ast::Visibility::Restricted { ref path, .. } => path.span, @@ -1327,7 +1327,7 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { visit::walk_vis(self, vis) } - fn visit_generics(&mut self, g: &ast::Generics) { + fn visit_generics(&mut self, g: &'a ast::Generics) { for t in &g.ty_params { if !t.attrs.is_empty() { gate_feature_post!(&self, generic_param_attrs, t.attrs[0].span, @@ -1337,7 +1337,7 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { visit::walk_generics(self, g) } - fn visit_lifetime_def(&mut self, lifetime_def: &ast::LifetimeDef) { + fn visit_lifetime_def(&mut self, lifetime_def: &'a ast::LifetimeDef) { if !lifetime_def.attrs.is_empty() { gate_feature_post!(&self, generic_param_attrs, lifetime_def.attrs[0].span, "attributes on lifetime bindings are experimental"); diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index bfaf00a3d3f..e5b66f88958 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -940,8 +940,8 @@ mod tests { struct PatIdentVisitor { spans: Vec } - impl ::visit::Visitor for PatIdentVisitor { - fn visit_pat(&mut self, p: &ast::Pat) { + impl<'a> ::visit::Visitor<'a> for PatIdentVisitor { + fn visit_pat(&mut self, p: &'a ast::Pat) { match p.node { PatKind::Ident(_ , ref spannedident, _) => { self.spans.push(spannedident.span.clone()); diff --git a/src/libsyntax/show_span.rs b/src/libsyntax/show_span.rs index 928ffb202d0..263a4f13c1b 100644 --- a/src/libsyntax/show_span.rs +++ b/src/libsyntax/show_span.rs @@ -44,29 +44,29 @@ struct ShowSpanVisitor<'a> { mode: Mode, } -impl<'a> Visitor for ShowSpanVisitor<'a> { - fn visit_expr(&mut self, e: &ast::Expr) { +impl<'a> Visitor<'a> for ShowSpanVisitor<'a> { + fn visit_expr(&mut self, e: &'a ast::Expr) { if let Mode::Expression = self.mode { self.span_diagnostic.span_warn(e.span, "expression"); } visit::walk_expr(self, e); } - fn visit_pat(&mut self, p: &ast::Pat) { + fn visit_pat(&mut self, p: &'a ast::Pat) { if let Mode::Pattern = self.mode { self.span_diagnostic.span_warn(p.span, "pattern"); } visit::walk_pat(self, p); } - fn visit_ty(&mut self, t: &ast::Ty) { + fn visit_ty(&mut self, t: &'a ast::Ty) { if let Mode::Type = self.mode { self.span_diagnostic.span_warn(t.span, "type"); } visit::walk_ty(self, t); } - fn visit_mac(&mut self, mac: &ast::Mac) { + fn visit_mac(&mut self, mac: &'a ast::Mac) { visit::walk_mac(self, mac); } } diff --git a/src/libsyntax/util/node_count.rs b/src/libsyntax/util/node_count.rs index a1f07381db7..b90802d1e7e 100644 --- a/src/libsyntax/util/node_count.rs +++ b/src/libsyntax/util/node_count.rs @@ -26,7 +26,7 @@ impl NodeCounter { } } -impl Visitor for NodeCounter { +impl<'ast> Visitor<'ast> for NodeCounter { fn visit_ident(&mut self, span: Span, ident: Ident) { self.count += 1; walk_ident(self, span, ident); diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index da36225fb32..3e0353d532d 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -49,56 +49,56 @@ pub enum FnKind<'a> { /// explicitly, you need to override each method. (And you also need /// to monitor future changes to `Visitor` in case a new method with a /// new default implementation gets introduced.) -pub trait Visitor: Sized { +pub trait Visitor<'ast>: Sized { fn visit_name(&mut self, _span: Span, _name: Name) { // Nothing to do. } fn visit_ident(&mut self, span: Span, ident: Ident) { walk_ident(self, span, ident); } - fn visit_mod(&mut self, m: &Mod, _s: Span, _n: NodeId) { walk_mod(self, m) } - fn visit_foreign_item(&mut self, i: &ForeignItem) { walk_foreign_item(self, i) } - fn visit_item(&mut self, i: &Item) { walk_item(self, i) } - fn visit_local(&mut self, l: &Local) { walk_local(self, l) } - fn visit_block(&mut self, b: &Block) { walk_block(self, b) } - fn visit_stmt(&mut self, s: &Stmt) { walk_stmt(self, s) } - fn visit_arm(&mut self, a: &Arm) { walk_arm(self, a) } - fn visit_pat(&mut self, p: &Pat) { walk_pat(self, p) } - fn visit_expr(&mut self, ex: &Expr) { walk_expr(self, ex) } - fn visit_expr_post(&mut self, _ex: &Expr) { } - fn visit_ty(&mut self, t: &Ty) { walk_ty(self, t) } - fn visit_generics(&mut self, g: &Generics) { walk_generics(self, g) } - fn visit_fn(&mut self, fk: FnKind, fd: &FnDecl, s: Span, _: NodeId) { + fn visit_mod(&mut self, m: &'ast Mod, _s: Span, _n: NodeId) { walk_mod(self, m) } + fn visit_foreign_item(&mut self, i: &'ast ForeignItem) { walk_foreign_item(self, i) } + fn visit_item(&mut self, i: &'ast Item) { walk_item(self, i) } + fn visit_local(&mut self, l: &'ast Local) { walk_local(self, l) } + fn visit_block(&mut self, b: &'ast Block) { walk_block(self, b) } + fn visit_stmt(&mut self, s: &'ast Stmt) { walk_stmt(self, s) } + fn visit_arm(&mut self, a: &'ast Arm) { walk_arm(self, a) } + fn visit_pat(&mut self, p: &'ast Pat) { walk_pat(self, p) } + fn visit_expr(&mut self, ex: &'ast Expr) { walk_expr(self, ex) } + fn visit_expr_post(&mut self, _ex: &'ast Expr) { } + fn visit_ty(&mut self, t: &'ast Ty) { walk_ty(self, t) } + fn visit_generics(&mut self, g: &'ast Generics) { walk_generics(self, g) } + fn visit_fn(&mut self, fk: FnKind<'ast>, fd: &'ast FnDecl, s: Span, _: NodeId) { walk_fn(self, fk, fd, s) } - fn visit_trait_item(&mut self, ti: &TraitItem) { walk_trait_item(self, ti) } - fn visit_impl_item(&mut self, ii: &ImplItem) { walk_impl_item(self, ii) } - fn visit_trait_ref(&mut self, t: &TraitRef) { walk_trait_ref(self, t) } - fn visit_ty_param_bound(&mut self, bounds: &TyParamBound) { + fn visit_trait_item(&mut self, ti: &'ast TraitItem) { walk_trait_item(self, ti) } + fn visit_impl_item(&mut self, ii: &'ast ImplItem) { walk_impl_item(self, ii) } + fn visit_trait_ref(&mut self, t: &'ast TraitRef) { walk_trait_ref(self, t) } + fn visit_ty_param_bound(&mut self, bounds: &'ast TyParamBound) { walk_ty_param_bound(self, bounds) } - fn visit_poly_trait_ref(&mut self, t: &PolyTraitRef, m: &TraitBoundModifier) { + fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) { walk_poly_trait_ref(self, t, m) } - fn visit_variant_data(&mut self, s: &VariantData, _: Ident, - _: &Generics, _: NodeId, _: Span) { + fn visit_variant_data(&mut self, s: &'ast VariantData, _: Ident, + _: &'ast Generics, _: NodeId, _: Span) { walk_struct_def(self, s) } - fn visit_struct_field(&mut self, s: &StructField) { walk_struct_field(self, s) } - fn visit_enum_def(&mut self, enum_definition: &EnumDef, - generics: &Generics, item_id: NodeId, _: Span) { + fn visit_struct_field(&mut self, s: &'ast StructField) { walk_struct_field(self, s) } + fn visit_enum_def(&mut self, enum_definition: &'ast EnumDef, + generics: &'ast Generics, item_id: NodeId, _: Span) { walk_enum_def(self, enum_definition, generics, item_id) } - fn visit_variant(&mut self, v: &Variant, g: &Generics, item_id: NodeId) { + fn visit_variant(&mut self, v: &'ast Variant, g: &'ast Generics, item_id: NodeId) { walk_variant(self, v, g, item_id) } - fn visit_lifetime(&mut self, lifetime: &Lifetime) { + fn visit_lifetime(&mut self, lifetime: &'ast Lifetime) { walk_lifetime(self, lifetime) } - fn visit_lifetime_def(&mut self, lifetime: &LifetimeDef) { + fn visit_lifetime_def(&mut self, lifetime: &'ast LifetimeDef) { walk_lifetime_def(self, lifetime) } - fn visit_mac(&mut self, _mac: &Mac) { + fn visit_mac(&mut self, _mac: &'ast Mac) { panic!("visit_mac disabled by default"); // NB: see note about macros above. // if you really want a visitor that @@ -106,29 +106,29 @@ pub trait Visitor: Sized { // definition in your trait impl: // visit::walk_mac(self, _mac) } - fn visit_path(&mut self, path: &Path, _id: NodeId) { + fn visit_path(&mut self, path: &'ast Path, _id: NodeId) { walk_path(self, path) } - fn visit_path_list_item(&mut self, prefix: &Path, item: &PathListItem) { + fn visit_path_list_item(&mut self, prefix: &'ast Path, item: &'ast PathListItem) { walk_path_list_item(self, prefix, item) } - fn visit_path_segment(&mut self, path_span: Span, path_segment: &PathSegment) { + fn visit_path_segment(&mut self, path_span: Span, path_segment: &'ast PathSegment) { walk_path_segment(self, path_span, path_segment) } - fn visit_path_parameters(&mut self, path_span: Span, path_parameters: &PathParameters) { + fn visit_path_parameters(&mut self, path_span: Span, path_parameters: &'ast PathParameters) { walk_path_parameters(self, path_span, path_parameters) } - fn visit_assoc_type_binding(&mut self, type_binding: &TypeBinding) { + fn visit_assoc_type_binding(&mut self, type_binding: &'ast TypeBinding) { walk_assoc_type_binding(self, type_binding) } - fn visit_attribute(&mut self, _attr: &Attribute) {} - fn visit_macro_def(&mut self, macro_def: &MacroDef) { + fn visit_attribute(&mut self, _attr: &'ast Attribute) {} + fn visit_macro_def(&mut self, macro_def: &'ast MacroDef) { walk_macro_def(self, macro_def) } - fn visit_vis(&mut self, vis: &Visibility) { + fn visit_vis(&mut self, vis: &'ast Visibility) { walk_vis(self, vis) } - fn visit_fn_ret_ty(&mut self, ret_ty: &FunctionRetTy) { + fn visit_fn_ret_ty(&mut self, ret_ty: &'ast FunctionRetTy) { walk_fn_ret_ty(self, ret_ty) } } @@ -147,45 +147,46 @@ macro_rules! walk_list { } } -pub fn walk_opt_name(visitor: &mut V, span: Span, opt_name: Option) { +pub fn walk_opt_name<'a, V: Visitor<'a>>(visitor: &mut V, span: Span, opt_name: Option) { if let Some(name) = opt_name { visitor.visit_name(span, name); } } -pub fn walk_opt_ident(visitor: &mut V, span: Span, opt_ident: Option) { +pub fn walk_opt_ident<'a, V: Visitor<'a>>(visitor: &mut V, span: Span, opt_ident: Option) { if let Some(ident) = opt_ident { visitor.visit_ident(span, ident); } } -pub fn walk_opt_sp_ident(visitor: &mut V, opt_sp_ident: &Option>) { +pub fn walk_opt_sp_ident<'a, V: Visitor<'a>>(visitor: &mut V, + opt_sp_ident: &Option>) { if let Some(ref sp_ident) = *opt_sp_ident { visitor.visit_ident(sp_ident.span, sp_ident.node); } } -pub fn walk_ident(visitor: &mut V, span: Span, ident: Ident) { +pub fn walk_ident<'a, V: Visitor<'a>>(visitor: &mut V, span: Span, ident: Ident) { visitor.visit_name(span, ident.name); } -pub fn walk_crate(visitor: &mut V, krate: &Crate) { +pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) { visitor.visit_mod(&krate.module, krate.span, CRATE_NODE_ID); walk_list!(visitor, visit_attribute, &krate.attrs); walk_list!(visitor, visit_macro_def, &krate.exported_macros); } -pub fn walk_macro_def(visitor: &mut V, macro_def: &MacroDef) { +pub fn walk_macro_def<'a, V: Visitor<'a>>(visitor: &mut V, macro_def: &'a MacroDef) { visitor.visit_ident(macro_def.span, macro_def.ident); walk_opt_ident(visitor, macro_def.span, macro_def.imported_from); walk_list!(visitor, visit_attribute, ¯o_def.attrs); } -pub fn walk_mod(visitor: &mut V, module: &Mod) { +pub fn walk_mod<'a, V: Visitor<'a>>(visitor: &mut V, module: &'a Mod) { walk_list!(visitor, visit_item, &module.items); } -pub fn walk_local(visitor: &mut V, local: &Local) { +pub fn walk_local<'a, V: Visitor<'a>>(visitor: &mut V, local: &'a Local) { for attr in local.attrs.iter() { visitor.visit_attribute(attr); } @@ -194,28 +195,30 @@ pub fn walk_local(visitor: &mut V, local: &Local) { walk_list!(visitor, visit_expr, &local.init); } -pub fn walk_lifetime(visitor: &mut V, lifetime: &Lifetime) { +pub fn walk_lifetime<'a, V: Visitor<'a>>(visitor: &mut V, lifetime: &'a Lifetime) { visitor.visit_name(lifetime.span, lifetime.name); } -pub fn walk_lifetime_def(visitor: &mut V, lifetime_def: &LifetimeDef) { +pub fn walk_lifetime_def<'a, V: Visitor<'a>>(visitor: &mut V, lifetime_def: &'a LifetimeDef) { visitor.visit_lifetime(&lifetime_def.lifetime); walk_list!(visitor, visit_lifetime, &lifetime_def.bounds); walk_list!(visitor, visit_attribute, &*lifetime_def.attrs); } -pub fn walk_poly_trait_ref(visitor: &mut V, trait_ref: &PolyTraitRef, _: &TraitBoundModifier) - where V: Visitor, +pub fn walk_poly_trait_ref<'a, V>(visitor: &mut V, + trait_ref: &'a PolyTraitRef, + _: &TraitBoundModifier) + where V: Visitor<'a>, { walk_list!(visitor, visit_lifetime_def, &trait_ref.bound_lifetimes); visitor.visit_trait_ref(&trait_ref.trait_ref); } -pub fn walk_trait_ref(visitor: &mut V, trait_ref: &TraitRef) { +pub fn walk_trait_ref<'a, V: Visitor<'a>>(visitor: &mut V, trait_ref: &'a TraitRef) { visitor.visit_path(&trait_ref.path, trait_ref.ref_id) } -pub fn walk_item(visitor: &mut V, item: &Item) { +pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { visitor.visit_vis(&item.vis); visitor.visit_ident(item.span, item.ident); match item.node { @@ -294,15 +297,18 @@ pub fn walk_item(visitor: &mut V, item: &Item) { walk_list!(visitor, visit_attribute, &item.attrs); } -pub fn walk_enum_def(visitor: &mut V, - enum_definition: &EnumDef, - generics: &Generics, +pub fn walk_enum_def<'a, V: Visitor<'a>>(visitor: &mut V, + enum_definition: &'a EnumDef, + generics: &'a Generics, item_id: NodeId) { walk_list!(visitor, visit_variant, &enum_definition.variants, generics, item_id); } -pub fn walk_variant(visitor: &mut V, variant: &Variant, generics: &Generics, item_id: NodeId) - where V: Visitor, +pub fn walk_variant<'a, V>(visitor: &mut V, + variant: &'a Variant, + generics: &'a Generics, + item_id: NodeId) + where V: Visitor<'a>, { visitor.visit_ident(variant.span, variant.node.name); visitor.visit_variant_data(&variant.node.data, variant.node.name, @@ -311,7 +317,7 @@ pub fn walk_variant(visitor: &mut V, variant: &Variant, generics: &Generics, walk_list!(visitor, visit_attribute, &variant.node.attrs); } -pub fn walk_ty(visitor: &mut V, typ: &Ty) { +pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) { match typ.node { TyKind::Slice(ref ty) | TyKind::Paren(ref ty) => { visitor.visit_ty(ty) @@ -361,24 +367,30 @@ pub fn walk_ty(visitor: &mut V, typ: &Ty) { } } -pub fn walk_path(visitor: &mut V, path: &Path) { +pub fn walk_path<'a, V: Visitor<'a>>(visitor: &mut V, path: &'a Path) { for segment in &path.segments { visitor.visit_path_segment(path.span, segment); } } -pub fn walk_path_list_item(visitor: &mut V, _prefix: &Path, item: &PathListItem) { +pub fn walk_path_list_item<'a, V: Visitor<'a>>(visitor: &mut V, + _prefix: &Path, + item: &'a PathListItem) { visitor.visit_ident(item.span, item.node.name); walk_opt_ident(visitor, item.span, item.node.rename); } -pub fn walk_path_segment(visitor: &mut V, path_span: Span, segment: &PathSegment) { +pub fn walk_path_segment<'a, V: Visitor<'a>>(visitor: &mut V, + path_span: Span, + segment: &'a PathSegment) { visitor.visit_ident(path_span, segment.identifier); visitor.visit_path_parameters(path_span, &segment.parameters); } -pub fn walk_path_parameters(visitor: &mut V, _path_span: Span, path_parameters: &PathParameters) - where V: Visitor, +pub fn walk_path_parameters<'a, V>(visitor: &mut V, + _path_span: Span, + path_parameters: &'a PathParameters) + where V: Visitor<'a>, { match *path_parameters { PathParameters::AngleBracketed(ref data) => { @@ -393,12 +405,13 @@ pub fn walk_path_parameters(visitor: &mut V, _path_span: Span, path_parameter } } -pub fn walk_assoc_type_binding(visitor: &mut V, type_binding: &TypeBinding) { +pub fn walk_assoc_type_binding<'a, V: Visitor<'a>>(visitor: &mut V, + type_binding: &'a TypeBinding) { visitor.visit_ident(type_binding.span, type_binding.ident); visitor.visit_ty(&type_binding.ty); } -pub fn walk_pat(visitor: &mut V, pattern: &Pat) { +pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) { match pattern.node { PatKind::TupleStruct(ref path, ref children, _) => { visitor.visit_path(path, pattern.id); @@ -443,7 +456,7 @@ pub fn walk_pat(visitor: &mut V, pattern: &Pat) { } } -pub fn walk_foreign_item(visitor: &mut V, foreign_item: &ForeignItem) { +pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, foreign_item: &'a ForeignItem) { visitor.visit_vis(&foreign_item.vis); visitor.visit_ident(foreign_item.span, foreign_item.ident); @@ -458,7 +471,7 @@ pub fn walk_foreign_item(visitor: &mut V, foreign_item: &ForeignItem walk_list!(visitor, visit_attribute, &foreign_item.attrs); } -pub fn walk_ty_param_bound(visitor: &mut V, bound: &TyParamBound) { +pub fn walk_ty_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a TyParamBound) { match *bound { TraitTyParamBound(ref typ, ref modifier) => { visitor.visit_poly_trait_ref(typ, modifier); @@ -469,7 +482,7 @@ pub fn walk_ty_param_bound(visitor: &mut V, bound: &TyParamBound) { } } -pub fn walk_generics(visitor: &mut V, generics: &Generics) { +pub fn walk_generics<'a, V: Visitor<'a>>(visitor: &mut V, generics: &'a Generics) { for param in &generics.ty_params { visitor.visit_ident(param.span, param.ident); walk_list!(visitor, visit_ty_param_bound, ¶m.bounds); @@ -504,13 +517,13 @@ pub fn walk_generics(visitor: &mut V, generics: &Generics) { } } -pub fn walk_fn_ret_ty(visitor: &mut V, ret_ty: &FunctionRetTy) { +pub fn walk_fn_ret_ty<'a, V: Visitor<'a>>(visitor: &mut V, ret_ty: &'a FunctionRetTy) { if let FunctionRetTy::Ty(ref output_ty) = *ret_ty { visitor.visit_ty(output_ty) } } -pub fn walk_fn_decl(visitor: &mut V, function_declaration: &FnDecl) { +pub fn walk_fn_decl<'a, V: Visitor<'a>>(visitor: &mut V, function_declaration: &'a FnDecl) { for argument in &function_declaration.inputs { visitor.visit_pat(&argument.pat); visitor.visit_ty(&argument.ty) @@ -518,8 +531,8 @@ pub fn walk_fn_decl(visitor: &mut V, function_declaration: &FnDecl) visitor.visit_fn_ret_ty(&function_declaration.output) } -pub fn walk_fn(visitor: &mut V, kind: FnKind, declaration: &FnDecl, _span: Span) - where V: Visitor, +pub fn walk_fn<'a, V>(visitor: &mut V, kind: FnKind<'a>, declaration: &'a FnDecl, _span: Span) + where V: Visitor<'a>, { match kind { FnKind::ItemFn(_, generics, _, _, _, _, body) => { @@ -539,7 +552,7 @@ pub fn walk_fn(visitor: &mut V, kind: FnKind, declaration: &FnDecl, _span: Sp } } -pub fn walk_trait_item(visitor: &mut V, trait_item: &TraitItem) { +pub fn walk_trait_item<'a, V: Visitor<'a>>(visitor: &mut V, trait_item: &'a TraitItem) { visitor.visit_ident(trait_item.span, trait_item.ident); walk_list!(visitor, visit_attribute, &trait_item.attrs); match trait_item.node { @@ -565,7 +578,7 @@ pub fn walk_trait_item(visitor: &mut V, trait_item: &TraitItem) { } } -pub fn walk_impl_item(visitor: &mut V, impl_item: &ImplItem) { +pub fn walk_impl_item<'a, V: Visitor<'a>>(visitor: &mut V, impl_item: &'a ImplItem) { visitor.visit_vis(&impl_item.vis); visitor.visit_ident(impl_item.span, impl_item.ident); walk_list!(visitor, visit_attribute, &impl_item.attrs); @@ -587,22 +600,22 @@ pub fn walk_impl_item(visitor: &mut V, impl_item: &ImplItem) { } } -pub fn walk_struct_def(visitor: &mut V, struct_definition: &VariantData) { +pub fn walk_struct_def<'a, V: Visitor<'a>>(visitor: &mut V, struct_definition: &'a VariantData) { walk_list!(visitor, visit_struct_field, struct_definition.fields()); } -pub fn walk_struct_field(visitor: &mut V, struct_field: &StructField) { +pub fn walk_struct_field<'a, V: Visitor<'a>>(visitor: &mut V, struct_field: &'a StructField) { visitor.visit_vis(&struct_field.vis); walk_opt_ident(visitor, struct_field.span, struct_field.ident); visitor.visit_ty(&struct_field.ty); walk_list!(visitor, visit_attribute, &struct_field.attrs); } -pub fn walk_block(visitor: &mut V, block: &Block) { +pub fn walk_block<'a, V: Visitor<'a>>(visitor: &mut V, block: &'a Block) { walk_list!(visitor, visit_stmt, &block.stmts); } -pub fn walk_stmt(visitor: &mut V, statement: &Stmt) { +pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) { match statement.node { StmtKind::Local(ref local) => visitor.visit_local(local), StmtKind::Item(ref item) => visitor.visit_item(item), @@ -619,11 +632,11 @@ pub fn walk_stmt(visitor: &mut V, statement: &Stmt) { } } -pub fn walk_mac(_: &mut V, _: &Mac) { +pub fn walk_mac<'a, V: Visitor<'a>>(_: &mut V, _: &Mac) { // Empty! } -pub fn walk_expr(visitor: &mut V, expression: &Expr) { +pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { for attr in expression.attrs.iter() { visitor.visit_attribute(attr); } @@ -776,14 +789,14 @@ pub fn walk_expr(visitor: &mut V, expression: &Expr) { visitor.visit_expr_post(expression) } -pub fn walk_arm(visitor: &mut V, arm: &Arm) { +pub fn walk_arm<'a, V: Visitor<'a>>(visitor: &mut V, arm: &'a Arm) { walk_list!(visitor, visit_pat, &arm.pats); walk_list!(visitor, visit_expr, &arm.guard); visitor.visit_expr(&arm.body); walk_list!(visitor, visit_attribute, &arm.attrs); } -pub fn walk_vis(visitor: &mut V, vis: &Visibility) { +pub fn walk_vis<'a, V: Visitor<'a>>(visitor: &mut V, vis: &'a Visibility) { if let Visibility::Restricted { ref path, id } = *vis { visitor.visit_path(path, id); } diff --git a/src/libsyntax_ext/deriving/custom.rs b/src/libsyntax_ext/deriving/custom.rs index 1076a6a6d63..6f02a348f91 100644 --- a/src/libsyntax_ext/deriving/custom.rs +++ b/src/libsyntax_ext/deriving/custom.rs @@ -21,7 +21,7 @@ use syntax::visit::Visitor; struct MarkAttrs<'a>(&'a [ast::Name]); -impl<'a> Visitor for MarkAttrs<'a> { +impl<'a> Visitor<'a> for MarkAttrs<'a> { fn visit_attribute(&mut self, attr: &Attribute) { if self.0.contains(&attr.name()) { mark_used(attr); @@ -101,4 +101,3 @@ impl MultiItemModifier for CustomDerive { res } } - diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 63cd7678321..51199819dfc 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -361,8 +361,8 @@ fn find_type_parameters(ty: &ast::Ty, types: Vec>, } - impl<'a, 'b> visit::Visitor for Visitor<'a, 'b> { - fn visit_ty(&mut self, ty: &ast::Ty) { + impl<'a, 'b> visit::Visitor<'a> for Visitor<'a, 'b> { + fn visit_ty(&mut self, ty: &'a ast::Ty) { match ty.node { ast::TyKind::Path(_, ref path) if !path.global => { if let Some(segment) = path.segments.first() { diff --git a/src/libsyntax_ext/proc_macro_registrar.rs b/src/libsyntax_ext/proc_macro_registrar.rs index 6256440bc81..8fbd11a7a6e 100644 --- a/src/libsyntax_ext/proc_macro_registrar.rs +++ b/src/libsyntax_ext/proc_macro_registrar.rs @@ -52,14 +52,17 @@ pub fn modify(sess: &ParseSess, let ecfg = ExpansionConfig::default("proc_macro".to_string()); let mut cx = ExtCtxt::new(sess, ecfg, resolver); - let mut collect = CollectCustomDerives { - derives: Vec::new(), - in_root: true, - handler: handler, - is_proc_macro_crate: is_proc_macro_crate, - is_test_crate: is_test_crate, + let derives = { + let mut collect = CollectCustomDerives { + derives: Vec::new(), + in_root: true, + handler: handler, + is_proc_macro_crate: is_proc_macro_crate, + is_test_crate: is_test_crate, + }; + visit::walk_crate(&mut collect, &krate); + collect.derives }; - visit::walk_crate(&mut collect, &krate); if !is_proc_macro_crate { return krate @@ -79,7 +82,7 @@ pub fn modify(sess: &ParseSess, return krate; } - krate.module.items.push(mk_registrar(&mut cx, &collect.derives)); + krate.module.items.push(mk_registrar(&mut cx, &derives)); if krate.exported_macros.len() > 0 { handler.err("cannot export macro_rules! macros from a `proc-macro` \ @@ -103,8 +106,8 @@ impl<'a> CollectCustomDerives<'a> { } } -impl<'a> Visitor for CollectCustomDerives<'a> { - fn visit_item(&mut self, item: &ast::Item) { +impl<'a> Visitor<'a> for CollectCustomDerives<'a> { + fn visit_item(&mut self, item: &'a ast::Item) { // First up, make sure we're checking a bare function. If we're not then // we're just not interested in this item. // @@ -240,7 +243,7 @@ impl<'a> Visitor for CollectCustomDerives<'a> { visit::walk_item(self, item); } - fn visit_mod(&mut self, m: &ast::Mod, _s: Span, id: NodeId) { + fn visit_mod(&mut self, m: &'a ast::Mod, _s: Span, id: NodeId) { let mut prev_in_root = self.in_root; if id != ast::CRATE_NODE_ID { prev_in_root = mem::replace(&mut self.in_root, false); diff --git a/src/test/compile-fail-fulldeps/auxiliary/lint_for_crate.rs b/src/test/compile-fail-fulldeps/auxiliary/lint_for_crate.rs index a424517da12..b255cf11db0 100644 --- a/src/test/compile-fail-fulldeps/auxiliary/lint_for_crate.rs +++ b/src/test/compile-fail-fulldeps/auxiliary/lint_for_crate.rs @@ -33,7 +33,7 @@ impl LintPass for Pass { } impl LateLintPass for Pass { - fn check_crate(&mut self, cx: &LateContext, krate: &hir::Crate) { + fn check_crate<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, krate: &'tcx hir::Crate) { if !attr::contains_name(&krate.attrs, "crate_okay") { cx.span_lint(CRATE_NOT_OKAY, krate.span, "crate is not marked with #![crate_okay]"); diff --git a/src/test/compile-fail-fulldeps/auxiliary/lint_group_plugin_test.rs b/src/test/compile-fail-fulldeps/auxiliary/lint_group_plugin_test.rs index 1e9a77724a8..ec3401e7b21 100644 --- a/src/test/compile-fail-fulldeps/auxiliary/lint_group_plugin_test.rs +++ b/src/test/compile-fail-fulldeps/auxiliary/lint_group_plugin_test.rs @@ -35,7 +35,7 @@ impl LintPass for Pass { } impl LateLintPass for Pass { - fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { + fn check_item<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { match &*it.name.as_str() { "lintme" => cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'"), "pleaselintme" => cx.span_lint(PLEASE_LINT, it.span, "item is named 'pleaselintme'"), diff --git a/src/test/run-pass-fulldeps/auxiliary/lint_for_crate.rs b/src/test/run-pass-fulldeps/auxiliary/lint_for_crate.rs index a424517da12..b255cf11db0 100644 --- a/src/test/run-pass-fulldeps/auxiliary/lint_for_crate.rs +++ b/src/test/run-pass-fulldeps/auxiliary/lint_for_crate.rs @@ -33,7 +33,7 @@ impl LintPass for Pass { } impl LateLintPass for Pass { - fn check_crate(&mut self, cx: &LateContext, krate: &hir::Crate) { + fn check_crate<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, krate: &'tcx hir::Crate) { if !attr::contains_name(&krate.attrs, "crate_okay") { cx.span_lint(CRATE_NOT_OKAY, krate.span, "crate is not marked with #![crate_okay]"); diff --git a/src/test/run-pass-fulldeps/auxiliary/lint_group_plugin_test.rs b/src/test/run-pass-fulldeps/auxiliary/lint_group_plugin_test.rs index 1e9a77724a8..ec3401e7b21 100644 --- a/src/test/run-pass-fulldeps/auxiliary/lint_group_plugin_test.rs +++ b/src/test/run-pass-fulldeps/auxiliary/lint_group_plugin_test.rs @@ -35,7 +35,7 @@ impl LintPass for Pass { } impl LateLintPass for Pass { - fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { + fn check_item<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { match &*it.name.as_str() { "lintme" => cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'"), "pleaselintme" => cx.span_lint(PLEASE_LINT, it.span, "item is named 'pleaselintme'"), diff --git a/src/test/run-pass-fulldeps/issue-37290/auxiliary/lint.rs b/src/test/run-pass-fulldeps/issue-37290/auxiliary/lint.rs index 33d072eb6a8..947d2dd22db 100644 --- a/src/test/run-pass-fulldeps/issue-37290/auxiliary/lint.rs +++ b/src/test/run-pass-fulldeps/issue-37290/auxiliary/lint.rs @@ -40,9 +40,9 @@ impl LintPass for Pass { } impl LateLintPass for Pass { - fn check_fn(&mut self, cx: &LateContext, - fk: FnKind, _: &hir::FnDecl, expr: &hir::Expr, - span: Span, node: ast::NodeId) + fn check_fn<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, + fk: FnKind<'tcx>, _: &'tcx hir::FnDecl, expr: &'tcx hir::Expr, + span: Span, node: ast::NodeId) { if let FnKind::Closure(..) = fk { return } From cc6edb27269c8d0c69035ee4c18f890b13a24e2e Mon Sep 17 00:00:00 2001 From: Mark-Simulacrum Date: Sun, 27 Nov 2016 09:52:44 -0700 Subject: [PATCH 252/293] Simplify calling find_implied_output_region. @nnethercote added the optimization that find_implied_output_region takes a closure as an optimization in #37014, but passing an iterator is simpler, and more ergonomic for callers. --- src/librustc_typeck/astconv.rs | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index b5531b8bb9e..33af948263e 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -538,14 +538,15 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { /// Returns the appropriate lifetime to use for any output lifetimes /// (if one exists) and a vector of the (pattern, number of lifetimes) /// corresponding to each input type/pattern. - fn find_implied_output_region(&self, + fn find_implied_output_region(&self, input_tys: &[Ty<'tcx>], - input_pats: F) -> ElidedLifetime - where F: FnOnce() -> Vec + input_pats: I) -> ElidedLifetime + where I: Iterator { let tcx = self.tcx(); - let mut lifetimes_for_params = Vec::new(); + let mut lifetimes_for_params = Vec::with_capacity(input_tys.len()); let mut possible_implied_output_region = None; + let mut lifetimes = 0; for input_type in input_tys.iter() { let mut regions = FxHashSet(); @@ -554,7 +555,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { debug!("find_implied_output_regions: collected {:?} from {:?} \ have_bound_regions={:?}", ®ions, input_type, have_bound_regions); - if regions.len() == 1 { + lifetimes += regions.len(); + + if lifetimes == 1 && regions.len() == 1 { // there's a chance that the unique lifetime of this // iteration will be the appropriate lifetime for output // parameters, so lets store it. @@ -571,12 +574,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { }); } - if lifetimes_for_params.iter().map(|e| e.lifetime_count).sum::() == 1 { + if lifetimes == 1 { Ok(*possible_implied_output_region.unwrap()) } else { // Fill in the expensive `name` fields now that we know they're // needed. - for (info, input_pat) in lifetimes_for_params.iter_mut().zip(input_pats()) { + for (info, input_pat) in lifetimes_for_params.iter_mut().zip(input_pats) { info.name = input_pat; } Err(Some(lifetimes_for_params)) @@ -615,8 +618,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let inputs = self.tcx().mk_type_list(data.inputs.iter().map(|a_t| { self.ast_ty_arg_to_ty(&binding_rscope, None, region_substs, a_t) })); - let inputs_len = inputs.len(); - let input_params = || vec![String::new(); inputs_len]; + let input_params = iter::repeat(String::new()).take(inputs.len()); let implied_output_region = self.find_implied_output_region(&inputs, input_params); let (output, output_span) = match data.output { @@ -1776,14 +1778,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let implied_output_region = match explicit_self { Some(ExplicitSelf::ByReference(region, _)) => Ok(*region), _ => { - // `pat_to_string` is expensive and - // `find_implied_output_region` only needs its result when - // there's an error. So we wrap it in a closure to avoid - // calling it until necessary. - let arg_pats = || { - arg_params.iter().map(|a| pprust::pat_to_string(&a.pat)).collect() - }; - self.find_implied_output_region(&arg_tys, arg_pats) + self.find_implied_output_region(&arg_tys, + arg_params.iter() + .map(|a| pprust::pat_to_string(&a.pat))) + } }; From 9a3340a0486f0c38f38a8b3cd1b85b5645d28bf3 Mon Sep 17 00:00:00 2001 From: Robin Kruppe Date: Tue, 6 Dec 2016 17:23:04 +0100 Subject: [PATCH 253/293] [LLVM 4.0] test/run-make/llvm-pass/ --- src/test/run-make/llvm-pass/llvm-function-pass.so.cc | 7 ++++++- src/test/run-make/llvm-pass/llvm-module-pass.so.cc | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/test/run-make/llvm-pass/llvm-function-pass.so.cc b/src/test/run-make/llvm-pass/llvm-function-pass.so.cc index 4470c400760..880c9bce562 100644 --- a/src/test/run-make/llvm-pass/llvm-function-pass.so.cc +++ b/src/test/run-make/llvm-pass/llvm-function-pass.so.cc @@ -28,7 +28,12 @@ namespace { bool runOnFunction(Function &F) override; - const char *getPassName() const override { +#if LLVM_VERSION_MAJOR >= 4 + StringRef +#else + const char * +#endif + getPassName() const override { return "Some LLVM pass"; } diff --git a/src/test/run-make/llvm-pass/llvm-module-pass.so.cc b/src/test/run-make/llvm-pass/llvm-module-pass.so.cc index 510375a5e66..280eca7e8f0 100644 --- a/src/test/run-make/llvm-pass/llvm-module-pass.so.cc +++ b/src/test/run-make/llvm-pass/llvm-module-pass.so.cc @@ -27,7 +27,12 @@ namespace { bool runOnModule(Module &M) override; - const char *getPassName() const override { +#if LLVM_VERSION_MAJOR >= 4 + StringRef +#else + const char * +#endif + getPassName() const override { return "Some LLVM pass"; } From 25564dcda70eefa1359b105a51df198e409f5127 Mon Sep 17 00:00:00 2001 From: Robin Kruppe Date: Tue, 6 Dec 2016 17:37:32 +0100 Subject: [PATCH 254/293] [LLVM 4.0] rustllvm archive support Error handling is being transitioned from ErrorOr to Expected which has a different API and requires explicitly handling all errors --- src/rustllvm/ArchiveWrapper.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/rustllvm/ArchiveWrapper.cpp b/src/rustllvm/ArchiveWrapper.cpp index 12cd81ec700..5adb05d6089 100644 --- a/src/rustllvm/ArchiveWrapper.cpp +++ b/src/rustllvm/ArchiveWrapper.cpp @@ -163,9 +163,20 @@ LLVMRustArchiveIteratorFree(LLVMRustArchiveIteratorRef rai) { extern "C" const char* LLVMRustArchiveChildName(LLVMRustArchiveChildConstRef child, size_t *size) { +#if LLVM_VERSION_GE(4, 0) + Expected name_or_err = child->getName(); + if (!name_or_err) { + // rustc_llvm currently doesn't use this error string, but it might be useful + // in the future, and in the mean time this tells LLVM that the error was + // not ignored and that it shouldn't abort the process. + LLVMRustSetLastError(toString(name_or_err.takeError()).c_str()); + return NULL; + } +#else ErrorOr name_or_err = child->getName(); if (name_or_err.getError()) return NULL; +#endif StringRef name = name_or_err.get(); *size = name.size(); return name.data(); @@ -174,11 +185,19 @@ LLVMRustArchiveChildName(LLVMRustArchiveChildConstRef child, size_t *size) { extern "C" const char* LLVMRustArchiveChildData(LLVMRustArchiveChildRef child, size_t *size) { StringRef buf; +#if LLVM_VERSION_GE(4, 0) + Expected buf_or_err = child->getBuffer(); + if (!buf_or_err) { + LLVMRustSetLastError(toString(buf_or_err.takeError()).c_str()); + return NULL; + } +#else ErrorOr buf_or_err = child->getBuffer(); if (buf_or_err.getError()) { LLVMRustSetLastError(buf_or_err.getError().message().c_str()); return NULL; } +#endif buf = buf_or_err.get(); *size = buf.size(); return buf.data(); From dfd3b908f5de623ae3fee4b2451b15f6cd6f0e87 Mon Sep 17 00:00:00 2001 From: Michael Neumann Date: Tue, 6 Dec 2016 19:31:48 +0100 Subject: [PATCH 255/293] Fix current_exe() on DragonFly (again) This is a follow up on [this pull request][1]. Since DragonFly 4.6.1 ([this commit][2]), the "kern.proc.pathname" sysctl works correctly, i.e. it does not return paths including a ":" (see [here][3]). Use it and don't try to fix old versions of DragonFly! There are not many DragonFly installations out there that we can't control and no one is compiling Rust from source. If someone wants to run Rust on a pre-4.6.1 DragonFly system, the ports system should provide a patch. [1]: https://github.com/rust-lang/rust/pull/35494 [2]: https://gitweb.dragonflybsd.org/dragonfly.git/commit/726f7ca07e193db73635e9c4e24e40c96087d6d9 [3]: https://gist.github.com/mneumann/a2f6b6a0a03935b561d6185872a4b222 --- src/libstd/sys/unix/os.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index e591f25cac1..6992a17832e 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -78,7 +78,7 @@ pub fn errno() -> i32 { static errno: c_int; } - errno as i32 + unsafe { errno as i32 } } /// Gets a detailed string description for the given error number. @@ -193,7 +193,7 @@ impl StdError for JoinPathsError { fn description(&self) -> &str { "failed to join paths" } } -#[cfg(target_os = "freebsd")] +#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] pub fn current_exe() -> io::Result { unsafe { let mut mib = [libc::CTL_KERN as c_int, @@ -218,11 +218,6 @@ pub fn current_exe() -> io::Result { } } -#[cfg(target_os = "dragonfly")] -pub fn current_exe() -> io::Result { - ::fs::read_link("/proc/curproc/file") -} - #[cfg(target_os = "netbsd")] pub fn current_exe() -> io::Result { ::fs::read_link("/proc/curproc/exe") From c6b64f76cf6d22c0a325dd980b4400ac96a9cbc8 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 6 Dec 2016 13:27:36 -1000 Subject: [PATCH 256/293] save-analysis: fix a few generated code errors --- src/librustc_save_analysis/dump_visitor.rs | 18 ++++++++++-------- src/librustc_save_analysis/lib.rs | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index c3b1649662a..cdd7d269931 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1323,16 +1323,18 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> self.process_macro_use(t.span, t.id); match t.node { ast::TyKind::Path(_, ref path) => { + if self.span.filter_generated(None, t.span) { + return; + } + if let Some(id) = self.lookup_def_id(t.id) { let sub_span = self.span.sub_span_for_type_name(t.span); - if !self.span.filter_generated(sub_span, t.span) { - self.dumper.type_ref(TypeRefData { - span: sub_span.expect("No span found for type ref"), - ref_id: Some(id), - scope: self.cur_scope, - qualname: String::new() - }.lower(self.tcx)); - } + self.dumper.type_ref(TypeRefData { + span: sub_span.expect("No span found for type ref"), + ref_id: Some(id), + scope: self.cur_scope, + qualname: String::new() + }.lower(self.tcx)); } self.write_sub_paths_truncated(path, false); diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 7a2b74c06db..5c8921d1868 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -250,8 +250,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { match typ.node { // Common case impl for a struct or something basic. ast::TyKind::Path(None, ref path) => { + filter!(self.span_utils, None, path.span, None); sub_span = self.span_utils.sub_span_for_type_name(path.span); - filter!(self.span_utils, sub_span, path.span, None); type_data = self.lookup_ref_id(typ.id).map(|id| { TypeRefData { span: sub_span.unwrap(), From 3cd98685e41b62498b1cca62e2fb39cccf46f1dc Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Mon, 5 Dec 2016 15:34:19 -0800 Subject: [PATCH 257/293] Add doc comment for `Default` `impl` on `DefaultHasher`. --- src/libstd/collections/hash/map.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index f102a1bf630..0f998bc21b7 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -2108,6 +2108,10 @@ impl DefaultHasher { #[stable(feature = "hashmap_default_hasher", since = "1.13.0")] impl Default for DefaultHasher { + /// Creates a new `DefaultHasher` using [`DefaultHasher::new`]. See + /// [`DefaultHasher::new`] documentation for more information. + /// + /// [`DefaultHasher::new`]: #method.new fn default() -> DefaultHasher { DefaultHasher::new() } From 0e272de69f4a9c889e5f1a024a88b3e1f60cb6c5 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 16 Nov 2016 12:31:19 -0800 Subject: [PATCH 258/293] mk: Switch rustbuild to the default build system This commit switches the default build system for Rust from the makefiles to rustbuild. The rustbuild build system has been in development for almost a year now and has become quite mature over time. This commit is an implementation of the proposal on [internals] which slates deletion of the makefiles on 2016-01-02. [internals]: https://internals.rust-lang.org/t/proposal-for-promoting-rustbuild-to-official-status/4368 This commit also updates various documentation in `README.md`, `CONTRIBUTING.md`, `src/bootstrap/README.md`, and throughout the source code of rustbuild itself. Closes #37858 --- .travis.yml | 27 +- CONTRIBUTING.md | 147 ++++++--- README.md | 50 +-- appveyor.yml | 56 ++-- configure | 39 ++- src/bootstrap/README.md | 29 +- src/bootstrap/bootstrap.py | 91 ++++-- src/bootstrap/cc.rs | 23 +- src/bootstrap/check.rs | 54 +++- src/bootstrap/clean.rs | 3 + src/bootstrap/flags.rs | 1 + src/bootstrap/lib.rs | 96 +++++- src/bootstrap/mk/Makefile.in | 20 +- src/bootstrap/native.rs | 14 +- src/bootstrap/sanity.rs | 12 +- src/bootstrap/step.rs | 296 ++++++++++++++---- src/bootstrap/util.rs | 17 + src/ci/docker/arm-android/Dockerfile | 6 +- src/ci/docker/cross/Dockerfile | 1 - src/ci/docker/run.sh | 10 +- src/ci/docker/x86_64-freebsd/Dockerfile | 3 +- src/ci/docker/x86_64-gnu-cargotest/Dockerfile | 4 +- src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile | 2 - .../Dockerfile | 3 +- src/ci/docker/x86_64-musl/Dockerfile | 4 +- src/ci/run.sh | 26 +- src/liballoc_jemalloc/build.rs | 16 +- src/rustllvm/llvm-auto-clean-trigger | 2 +- src/test/run-pass/no-stdio.rs | 1 + 29 files changed, 756 insertions(+), 297 deletions(-) rename src/ci/docker/{x86_64-gnu-rustbuild => x86_64-gnu-make}/Dockerfile (73%) diff --git a/.travis.yml b/.travis.yml index a1bbb8a884f..996e5ec07b5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ -language: rust +language: minimal sudo: required dist: trusty services: @@ -20,7 +20,7 @@ matrix: - env: IMAGE=x86_64-gnu-cargotest - env: IMAGE=x86_64-gnu-debug - env: IMAGE=x86_64-gnu-nopt - - env: IMAGE=x86_64-gnu-rustbuild + - env: IMAGE=x86_64-gnu-make - env: IMAGE=x86_64-gnu-llvm-3.7 ALLOW_PR=1 RUST_BACKTRACE=1 - env: IMAGE=x86_64-musl @@ -39,7 +39,7 @@ matrix: install: brew install ccache - env: > RUST_CHECK_TARGET=check - RUST_CONFIGURE_ARGS=--target=x86_64-apple-darwin --enable-rustbuild + RUST_CONFIGURE_ARGS=--target=x86_64-apple-darwin --disable-rustbuild SRC=. os: osx install: brew install ccache @@ -51,17 +51,16 @@ matrix: install: brew install ccache script: - - if [ -z "$ALLOW_PR" ] && [ "$TRAVIS_BRANCH" != "auto" ]; then - echo skipping, not a full build; - elif [ -z "$ENABLE_AUTO" ] then - echo skipping, not quite ready yet - elif [ "$TRAVIS_OS_NAME" = "osx" ]; then - git submodule update --init; - src/ci/run.sh; - else - git submodule update --init; - src/ci/docker/run.sh $IMAGE; - fi + - > + if [ "$ALLOW_PR" = "" ] && [ "$TRAVIS_BRANCH" != "auto" ]; then + echo skipping, not a full build; + elif [ "$TRAVIS_OS_NAME" = "osx" ]; then + git submodule update --init; + src/ci/run.sh; + else + git submodule update --init; + src/ci/docker/run.sh $IMAGE; + fi # Save tagged docker images we created and load them if they're available before_cache: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4c0f93c3703..20a0bd2e256 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -86,13 +86,17 @@ benchmarks, generate documentation, install a fresh build of Rust, and more. It's your best friend when working on Rust, allowing you to compile & test your contributions before submission. -All the configuration for the build system lives in [the `mk` directory][mkdir] -in the project root. It can be hard to follow in places, as it uses some -advanced Make features which make for some challenging reading. If you have -questions on the build system internals, try asking in -[`#rust-internals`][pound-rust-internals]. +The build system lives in [the `src/bootstrap` directory][bootstrap] in the +project root. Our build system is itself written in Rust and is based on Cargo +to actually build all the compiler's crates. If you have questions on the build +system internals, try asking in [`#rust-internals`][pound-rust-internals]. -[mkdir]: https://github.com/rust-lang/rust/tree/master/mk/ +[bootstrap]: https://github.com/rust-lang/rust/tree/master/src/bootstrap/ + +> **Note**: the build system was recently rewritten from a jungle of makefiles +> to the current incarnation you'll see in `src/bootstrap`. If you experience +> bugs you can temporarily revert back to the makefiles with +> `--disable-rustbuild` passed to `./configure`. ### Configuration @@ -119,42 +123,111 @@ configuration used later in the build process. Some options to note: To see a full list of options, run `./configure --help`. -### Useful Targets +### Building -Some common make targets are: +Although the `./configure` script will generate a `Makefile`, this is actually +just a thin veneer over the actual build system driver, `x.py`. This file, at +the root of the repository, is used to build, test, and document various parts +of the compiler. You can execute it as: -- `make tips` - show useful targets, variables and other tips for working with - the build system. -- `make rustc-stage1` - build up to (and including) the first stage. For most - cases we don't need to build the stage2 compiler, so we can save time by not - building it. The stage1 compiler is a fully functioning compiler and - (probably) will be enough to determine if your change works as expected. -- `make $host/stage1/bin/rustc` - Where $host is a target triple like x86_64-unknown-linux-gnu. - This will build just rustc, without libstd. This is the fastest way to recompile after - you changed only rustc source code. Note however that the resulting rustc binary - won't have a stdlib to link against by default. You can build libstd once with - `make rustc-stage1`, rustc will pick it up afterwards. libstd is only guaranteed to - work if recompiled, so if there are any issues recompile it. -- `make check` - build the full compiler & run all tests (takes a while). This +```sh +python x.py build +``` + +On some systems you can also use the shorter version: + +```sh +./x.py build +``` + +To learn more about the driver and top-level targets, you can execute: + +```sh +python x.py --help +``` + +The general format for the driver script is: + +```sh +python x.py [] +``` + +Some example commands are `build`, `test`, and `doc`. These will build, test, +and document the specified directory. The second argument, ``, is +optional and defaults to working over the entire compiler. If specified, +however, only that specific directory will be built. For example: + +```sh +# build the entire compiler +python x.py build + +# build all documentation +python x.py doc + +# run all test suites +python x.py test + +# build only the standard library +python x.py build src/libstd + +# test only one particular test suite +python x.py test src/test/rustdoc + +# build only the stage0 libcore library +python x.py build src/libcore --stage 0 +``` + +You can explore the build system throught the various `--help` pages for each +subcommand. For example to learn more about a command you can run: + +``` +python x.py build --help +``` + +To learn about all possible rules you can execute, run: + +``` +python x.py build --help --verbose +``` + +### Useful commands + +Some common invocations of `x.py` are: + +- `x.py build --help` - show the help message and explain the subcommand +- `x.py build src/libtest --stage 1` - build up to (and including) the first + stage. For most cases we don't need to build the stage2 compiler, so we can + save time by not building it. The stage1 compiler is a fully functioning + compiler and (probably) will be enough to determine if your change works as + expected. +- `x.py build src/rustc --stage 1` - This will build just rustc, without libstd. + This is the fastest way to recompile after you changed only rustc source code. + Note however that the resulting rustc binary won't have a stdlib to link + against by default. You can build libstd once with `x.py build src/libstd`, + but it is is only guaranteed to work if recompiled, so if there are any issues + recompile it. +- `x.py test` - build the full compiler & run all tests (takes a while). This is what gets run by the continuous integration system against your pull request. You should run this before submitting to make sure your tests pass & everything builds in the correct manner. -- `make check-stage1-std NO_REBUILD=1` - test the standard library without - rebuilding the entire compiler -- `make check TESTNAME=` - Run a matching set of tests. +- `x.py test src/libstd --stage 1` - test the standard library without + recompiling stage 2. +- `x.py test src/test/run-pass --filter TESTNAME` - Run a matching set of tests. - `TESTNAME` should be a substring of the tests to match against e.g. it could be the fully qualified test name, or just a part of it. `TESTNAME=collections::hash::map::test_map::test_capacity_not_less_than_len` or `TESTNAME=test_capacity_not_less_than_len`. -- `make check-stage1-rpass TESTNAME=` - Run a single - rpass test with the stage1 compiler (this will be quicker than running the - command above as we only build the stage1 compiler, not the entire thing). - You can also leave off the `-rpass` to run all stage1 test types. -- `make check-stage1-coretest` - Run stage1 tests in `libcore`. -- `make tidy` - Check that the source code is in compliance with Rust's style - guidelines. There is no official document describing Rust's full guidelines - as of yet, but basic rules like 4 spaces for indentation and no more than 99 - characters in a single line should be kept in mind when writing code. +- `x.py test src/test/run-pass --stage 1 --filter ` - + Run a single rpass test with the stage1 compiler (this will be quicker than + running the command above as we only build the stage1 compiler, not the entire + thing). You can also leave off the directory argument to run all stage1 test + types. +- `x.py test src/libcore --stage 1` - Run stage1 tests in `libcore`. +- `x.py test src/tools/tidy` - Check that the source code is in compliance with + Rust's style guidelines. There is no official document describing Rust's full + guidelines as of yet, but basic rules like 4 spaces for indentation and no + more than 99 characters in a single line should be kept in mind when writing + code. ## Pull Requests @@ -172,19 +245,17 @@ amount of time you have to wait. You need to have built the compiler at least once before running these will work, but that’s only one full build rather than one each time. - $ make -j8 rustc-stage1 && make check-stage1 + $ python x.py test --stage 1 is one such example, which builds just `rustc`, and then runs the tests. If you’re adding something to the standard library, try - $ make -j8 check-stage1-std NO_REBUILD=1 - -This will not rebuild the compiler, but will run the tests. + $ python x.py test src/libstd --stage 1 Please make sure your pull request is in compliance with Rust's style guidelines by running - $ make tidy + $ python x.py test src/tools/tidy Make this check before every pull request (and every new commit in a pull request) ; you can add [git hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks) diff --git a/README.md b/README.md index 7360651095b..2133b17de0f 100644 --- a/README.md +++ b/README.md @@ -36,16 +36,14 @@ Read ["Installing Rust"] from [The Book]. ```sh $ ./configure - $ make && make install + $ make && sudo make install ``` - > ***Note:*** You may need to use `sudo make install` if you do not - > normally have permission to modify the destination directory. The - > install locations can be adjusted by passing a `--prefix` argument - > to `configure`. Various other options are also supported – pass + > ***Note:*** Install locations can be adjusted by passing a `--prefix` + > argument to `configure`. Various other options are also supported – pass > `--help` for more information on them. - When complete, `make install` will place several programs into + When complete, `sudo make install` will place several programs into `/usr/local/bin`: `rustc`, the Rust compiler, and `rustdoc`, the API-documentation tool. This install does not include [Cargo], Rust's package manager, which you may also want to build. @@ -108,30 +106,22 @@ MSVC builds of Rust additionally require an installation of Visual Studio 2013 (or later) so `rustc` can use its linker. Make sure to check the “C++ tools” option. -With these dependencies installed, the build takes two steps: +With these dependencies installed, you can build the compiler in a `cmd.exe` +shell with: ```sh -$ ./configure +> python x.py build +``` + +If you're running inside of an msys shell, however, you can run: + +```sh +$ ./configure --build=x86_64-pc-windows-msvc $ make && make install ``` -#### MSVC with rustbuild - -The old build system, based on makefiles, is currently being rewritten into a -Rust-based build system called rustbuild. This can be used to bootstrap the -compiler on MSVC without needing to install MSYS or MinGW. All you need are -[Python 2](https://www.python.org/downloads/), -[CMake](https://cmake.org/download/), and -[Git](https://git-scm.com/downloads) in your PATH (make sure you do not use the -ones from MSYS if you have it installed). You'll also need Visual Studio 2013 or -newer with the C++ tools. Then all you need to do is to kick off rustbuild. - -``` -python x.py build -``` - -Currently rustbuild only works with some known versions of Visual Studio. If you -have a more recent version installed that a part of rustbuild doesn't understand +Currently building Rust only works with some known versions of Visual Studio. If +you have a more recent version installed the build system doesn't understand then you may need to force rustbuild to use an older version. This can be done by manually calling the appropriate vcvars file before running the bootstrap. @@ -149,16 +139,6 @@ $ ./configure $ make docs ``` -Building the documentation requires building the compiler, so the above -details will apply. Once you have the compiler built, you can - -```sh -$ make docs NO_REBUILD=1 -``` - -To make sure you don’t re-build the compiler because you made a change -to some documentation. - The generated documentation will appear in a top-level `doc` directory, created by the `make` rule. diff --git a/appveyor.yml b/appveyor.yml index 686c48abb30..bf75439b74a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,25 +2,22 @@ environment: matrix: # 32/64 bit MSVC - MSYS_BITS: 64 - TARGET: x86_64-pc-windows-msvc - CHECK: check - CONFIGURE_ARGS: --enable-llvm-assertions --enable-debug-assertions + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc + RUST_CHECK_TARGET: check - MSYS_BITS: 32 - TARGET: i686-pc-windows-msvc - CHECK: check - CONFIGURE_ARGS: --enable-llvm-assertions --enable-debug-assertions + RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc + RUST_CHECK_TARGET: check - # MSVC rustbuild + # MSVC makefiles - MSYS_BITS: 64 - CONFIGURE_ARGS: --enable-rustbuild --enable-llvm-assertions --enable-debug-assertions - TARGET: x86_64-pc-windows-msvc - CHECK: check + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --disable-rustbuild + RUST_CHECK_TARGET: check # MSVC cargotest - MSYS_BITS: 64 - CONFIGURE_ARGS: --enable-rustbuild --enable-llvm-assertions --enable-debug-assertions - TARGET: x86_64-pc-windows-msvc - CHECK: check-cargotest + NO_VENDOR: 1 + RUST_CHECK_TARGET: check-cargotest + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc # 32/64-bit MinGW builds. # @@ -47,24 +44,22 @@ environment: # *not* use debug assertions and llvm assertions. This is because they take # too long on appveyor and this is tested by rustbuild below. - MSYS_BITS: 32 - TARGET: i686-pc-windows-gnu - CHECK: check + RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu + RUST_CHECK_TARGET: check MINGW_URL: https://s3.amazonaws.com/rust-lang-ci MINGW_ARCHIVE: i686-4.9.2-release-win32-dwarf-rt_v4-rev4.7z MINGW_DIR: mingw32 - MSYS_BITS: 32 - CONFIGURE_ARGS: --enable-rustbuild --enable-llvm-assertions --enable-debug-assertions - TARGET: i686-pc-windows-gnu - CHECK: check + RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --disable-rustbuild + RUST_CHECK_TARGET: check MINGW_URL: https://s3.amazonaws.com/rust-lang-ci MINGW_ARCHIVE: i686-4.9.2-release-win32-dwarf-rt_v4-rev4.7z MINGW_DIR: mingw32 - MSYS_BITS: 64 - CONFIGURE_ARGS: --enable-llvm-assertions --enable-debug-assertions - TARGET: x86_64-pc-windows-gnu - CHECK: check + RUST_CHECK_TARGET: check + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu MINGW_URL: https://s3.amazonaws.com/rust-lang-ci MINGW_ARCHIVE: x86_64-4.9.2-release-win32-seh-rt_v4-rev4.7z MINGW_DIR: mingw64 @@ -90,15 +85,20 @@ install: - if NOT defined MINGW_URL set PATH=C:\msys64\mingw%MSYS_BITS%\bin;C:\msys64\usr\bin;%PATH% test_script: - - sh ./configure - %CONFIGURE_ARGS% - --build=%TARGET% - - bash -c "make -j$(nproc)" - - bash -c "make %CHECK% -j$(nproc)" + - git submodule update --init + - set SRC=. + - set NO_CCACHE=1 + - sh src/ci/run.sh cache: - - build/%TARGET%/llvm -> src/rustllvm/llvm-auto-clean-trigger - - "%TARGET%/llvm -> src/rustllvm/llvm-auto-clean-trigger" + - "build/i686-pc-windows-gnu/llvm -> src/rustllvm/llvm-auto-clean-trigger" + - "build/x86_64-pc-windows-gnu/llvm -> src/rustllvm/llvm-auto-clean-trigger" + - "build/i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-auto-clean-trigger" + - "build/x86_64-pc-windows-msvc/llvm -> src/rustllvm/llvm-auto-clean-trigger" + - "i686-pc-windows-gnu/llvm -> src/rustllvm/llvm-auto-clean-trigger" + - "x86_64-pc-windows-gnu/llvm -> src/rustllvm/llvm-auto-clean-trigger" + - "i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-auto-clean-trigger" + - "x86_64-pc-windows-msvc/llvm -> src/rustllvm/llvm-auto-clean-trigger" branches: only: diff --git a/configure b/configure index 483471604cb..a287291c280 100755 --- a/configure +++ b/configure @@ -631,7 +631,7 @@ opt stage0-landing-pads 1 "enable landing pads during bootstrap with stage0" opt dist-host-only 0 "only install bins for the host architecture" opt inject-std-version 1 "inject the current compiler version of libstd into programs" opt llvm-version-check 1 "check if the LLVM version is supported, build anyway" -opt rustbuild 0 "use the rust and cargo based build system" +opt rustbuild 1 "use the rust and cargo based build system" opt codegen-tests 1 "run the src/test/codegen tests" opt option-checking 1 "complain about unrecognized options in this configure script" opt ninja 0 "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)" @@ -664,11 +664,11 @@ valopt armv7-linux-androideabi-ndk "" "armv7-linux-androideabi NDK standalone pa valopt aarch64-linux-android-ndk "" "aarch64-linux-android NDK standalone path" valopt nacl-cross-path "" "NaCl SDK path (Pepper Canary is recommended). Must be absolute!" valopt musl-root "/usr/local" "MUSL root installation directory (deprecated)" -valopt musl-root-x86_64 "/usr/local" "x86_64-unknown-linux-musl install directory" -valopt musl-root-i686 "/usr/local" "i686-unknown-linux-musl install directory" -valopt musl-root-arm "/usr/local" "arm-unknown-linux-musleabi install directory" -valopt musl-root-armhf "/usr/local" "arm-unknown-linux-musleabihf install directory" -valopt musl-root-armv7 "/usr/local" "armv7-unknown-linux-musleabihf install directory" +valopt musl-root-x86_64 "" "x86_64-unknown-linux-musl install directory" +valopt musl-root-i686 "" "i686-unknown-linux-musl install directory" +valopt musl-root-arm "" "arm-unknown-linux-musleabi install directory" +valopt musl-root-armhf "" "arm-unknown-linux-musleabihf install directory" +valopt musl-root-armv7 "" "armv7-unknown-linux-musleabihf install directory" valopt extra-filename "" "Additional data that is hashed and passed to the -C extra-filename flag" if [ -e ${CFG_SRC_DIR}.git ] @@ -1374,7 +1374,7 @@ then fi fi -if [ -z "$CFG_ENABLE_RUSTBUILD" ]; then +if [ -n "$CFG_DISABLE_RUSTBUILD" ]; then step_msg "making directories" @@ -1474,7 +1474,7 @@ fi step_msg "configuring submodules" # Have to be in the top of src directory for this -if [ -z "$CFG_DISABLE_MANAGE_SUBMODULES" ] && [ -z "$CFG_ENABLE_RUSTBUILD" ] +if [ -z "$CFG_DISABLE_MANAGE_SUBMODULES" ] && [ -n "$CFG_DISABLE_RUSTBUILD" ] then cd ${CFG_SRC_DIR} @@ -1546,7 +1546,7 @@ do ;; esac - if [ -n "$CFG_ENABLE_RUSTBUILD" ] + if [ -z "$CFG_DISABLE_RUSTBUILD" ] then msg "not configuring LLVM, rustbuild in use" do_reconfigure=0 @@ -1871,7 +1871,7 @@ do putvar $CFG_LLVM_INST_DIR done -if [ -n "$CFG_ENABLE_RUSTBUILD" ] +if [ -z "$CFG_DISABLE_RUSTBUILD" ] then INPUT_MAKEFILE=src/bootstrap/mk/Makefile.in else @@ -1890,5 +1890,22 @@ else step_msg "complete" fi -msg "run \`make help\`" +if [ -z "$CFG_DISABLE_RUSTBUILD" ]; then + msg "NOTE you have now configured rust to use a rewritten build system" + msg " called rustbuild, and as a result this may have bugs that " + msg " you did not see before. If you experience any issues you can" + msg " go back to the old build system with --disable-rustbuild and" + msg " please feel free to report any bugs!" + msg "" + msg "run \`python x.py --help\`" +else + warn "the makefile-based build system is deprecated in favor of rustbuild" + msg "" + msg "It is recommended you avoid passing --disable-rustbuild to get your" + msg "build working as the makefiles will be deleted on 2017-02-02. If you" + msg "encounter bugs with rustbuild please file issues against rust-lang/rust" + msg "" + msg "run \`make help\`" +fi + msg diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md index 24d716c1195..d0b501e4d89 100644 --- a/src/bootstrap/README.md +++ b/src/bootstrap/README.md @@ -66,17 +66,6 @@ The script accepts commands, flags, and filters to determine what to do: * `doc` - a command for building documentation. Like above can take arguments for what to document. -If you're more used to `./configure` and `make`, however, then you can also -configure the build system to use rustbuild instead of the old makefiles: - -``` -./configure --enable-rustbuild -make -``` - -Afterwards the `Makefile` which is generated will have a few commands like -`make check`, `make tidy`, etc. - ## Configuring rustbuild There are currently two primary methods for configuring the rustbuild build @@ -90,6 +79,13 @@ be found at `src/bootstrap/config.toml.example`, and the configuration file can also be passed as `--config path/to/config.toml` if the build system is being invoked manually (via the python script). +Finally, rustbuild makes use of the [gcc-rs crate] which has [its own +method][env-vars] of configuring C compilers and C flags via environment +variables. + +[gcc-rs crate]: https://github.com/alexcrichton/gcc-rs +[env-vars]: https://github.com/alexcrichton/gcc-rs#external-configuration-via-environment-variables + ## Build stages The rustbuild build system goes through a few phases to actually build the @@ -273,16 +269,17 @@ After that, each module in rustbuild should have enough documentation to keep you up and running. Some general areas that you may be interested in modifying are: -* Adding a new build tool? Take a look at `build/step.rs` for examples of other - tools, as well as `build/mod.rs`. +* Adding a new build tool? Take a look at `bootstrap/step.rs` for examples of + other tools. * Adding a new compiler crate? Look no further! Adding crates can be done by adding a new directory with `Cargo.toml` followed by configuring all `Cargo.toml` files accordingly. * Adding a new dependency from crates.io? We're still working on that, so hold off on that for now. -* Adding a new configuration option? Take a look at `build/config.rs` or perhaps - `build/flags.rs` and then modify the build elsewhere to read that option. -* Adding a sanity check? Take a look at `build/sanity.rs`. +* Adding a new configuration option? Take a look at `bootstrap/config.rs` or + perhaps `bootstrap/flags.rs` and then modify the build elsewhere to read that + option. +* Adding a sanity check? Take a look at `bootstrap/sanity.rs`. If you have any questions feel free to reach out on `#rust-internals` on IRC or open an issue in the bug tracker! diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index a3fabbb3e80..0dda7f12007 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -30,32 +30,37 @@ def get(url, path, verbose=False): sha_path = sha_file.name try: - download(sha_path, sha_url, verbose) + download(sha_path, sha_url, False, verbose) if os.path.exists(path): if verify(path, sha_path, False): - print("using already-download file " + path) + if verbose: + print("using already-download file " + path) return else: - print("ignoring already-download file " + path + " due to failed verification") + if verbose: + print("ignoring already-download file " + path + " due to failed verification") os.unlink(path) - download(temp_path, url, verbose) - if not verify(temp_path, sha_path, True): + download(temp_path, url, True, verbose) + if not verify(temp_path, sha_path, verbose): raise RuntimeError("failed verification") - print("moving {} to {}".format(temp_path, path)) + if verbose: + print("moving {} to {}".format(temp_path, path)) shutil.move(temp_path, path) finally: - delete_if_present(sha_path) - delete_if_present(temp_path) + delete_if_present(sha_path, verbose) + delete_if_present(temp_path, verbose) -def delete_if_present(path): +def delete_if_present(path, verbose): if os.path.isfile(path): - print("removing " + path) + if verbose: + print("removing " + path) os.unlink(path) -def download(path, url, verbose): - print("downloading {} to {}".format(url, path)) +def download(path, url, probably_big, verbose): + if probably_big or verbose: + print("downloading {}".format(url)) # see http://serverfault.com/questions/301128/how-to-download if sys.platform == 'win32': run(["PowerShell.exe", "/nologo", "-Command", @@ -63,17 +68,22 @@ def download(path, url, verbose): ".DownloadFile('{}', '{}')".format(url, path)], verbose=verbose) else: - run(["curl", "-o", path, url], verbose=verbose) + if probably_big or verbose: + option = "-#" + else: + option = "-s" + run(["curl", option, "-Sf", "-o", path, url], verbose=verbose) def verify(path, sha_path, verbose): - print("verifying " + path) + if verbose: + print("verifying " + path) with open(path, "rb") as f: found = hashlib.sha256(f.read()).hexdigest() with open(sha_path, "r") as f: expected, _ = f.readline().split() verified = found == expected - if not verified and verbose: + if not verified: print("invalid checksum:\n" " found: {}\n" " expected: {}".format(found, expected)) @@ -144,6 +154,7 @@ class RustBuild(object): if self.rustc().startswith(self.bin_root()) and \ (not os.path.exists(self.rustc()) or self.rustc_out_of_date()): + self.print_what_it_means_to_bootstrap() if os.path.exists(self.bin_root()): shutil.rmtree(self.bin_root()) channel = self.stage0_rustc_channel() @@ -167,6 +178,7 @@ class RustBuild(object): if self.cargo().startswith(self.bin_root()) and \ (not os.path.exists(self.cargo()) or self.cargo_out_of_date()): + self.print_what_it_means_to_bootstrap() channel = self.stage0_cargo_channel() filename = "cargo-{}-{}.tar.gz".format(channel, self.build) url = "https://static.rust-lang.org/cargo-dist/" + self.stage0_cargo_date() @@ -251,7 +263,27 @@ class RustBuild(object): else: return '' + def print_what_it_means_to_bootstrap(self): + if hasattr(self, 'printed'): + return + self.printed = True + if os.path.exists(self.bootstrap_binary()): + return + if not '--help' in sys.argv or len(sys.argv) == 1: + return + + print('info: the build system for Rust is written in Rust, so this') + print(' script is now going to download a stage0 rust compiler') + print(' and then compile the build system itself') + print('') + print('info: in the meantime you can read more about rustbuild at') + print(' src/bootstrap/README.md before the download finishes') + + def bootstrap_binary(self): + return os.path.join(self.build_dir, "bootstrap/debug/bootstrap") + def build_bootstrap(self): + self.print_what_it_means_to_bootstrap() build_dir = os.path.join(self.build_dir, "bootstrap") if self.clean and os.path.exists(build_dir): shutil.rmtree(build_dir) @@ -408,22 +440,31 @@ def main(): rb.use_vendored_sources = '\nvendor = true' in rb.config_toml or \ 'CFG_ENABLE_VENDOR' in rb.config_mk + if 'SUDO_USER' in os.environ: + if os.environ['USER'] != os.environ['SUDO_USER']: + rb.use_vendored_sources = True + print('info: looks like you are running this command under `sudo`') + print(' and so in order to preserve your $HOME this will now') + print(' use vendored sources by default. Note that if this') + print(' does not work you should run a normal build first') + print(' before running a command like `sudo make intall`') + if rb.use_vendored_sources: if not os.path.exists('.cargo'): os.makedirs('.cargo') - f = open('.cargo/config','w') - f.write(""" - [source.crates-io] - replace-with = 'vendored-sources' - registry = 'https://example.com' + with open('.cargo/config','w') as f: + f.write(""" + [source.crates-io] + replace-with = 'vendored-sources' + registry = 'https://example.com' - [source.vendored-sources] - directory = '{}/src/vendor' - """.format(rb.rust_root)) - f.close() + [source.vendored-sources] + directory = '{}/src/vendor' + """.format(rb.rust_root)) else: if os.path.exists('.cargo'): shutil.rmtree('.cargo') + data = stage0_data(rb.rust_root) rb._rustc_channel, rb._rustc_date = data['rustc'].split('-', 1) rb._cargo_channel, rb._cargo_date = data['cargo'].split('-', 1) @@ -438,7 +479,7 @@ def main(): sys.stdout.flush() # Run the bootstrap - args = [os.path.join(rb.build_dir, "bootstrap/debug/bootstrap")] + args = [rb.bootstrap_binary()] args.extend(sys.argv[1:]) env = os.environ.copy() env["BUILD"] = rb.build diff --git a/src/bootstrap/cc.rs b/src/bootstrap/cc.rs index e2bde4a6586..aa70e24d952 100644 --- a/src/bootstrap/cc.rs +++ b/src/bootstrap/cc.rs @@ -51,7 +51,7 @@ pub fn find(build: &mut Build) { if let Some(cc) = config.and_then(|c| c.cc.as_ref()) { cfg.compiler(cc); } else { - set_compiler(&mut cfg, "gcc", target, config); + set_compiler(&mut cfg, "gcc", target, config, build); } let compiler = cfg.get_compiler(); @@ -72,7 +72,7 @@ pub fn find(build: &mut Build) { if let Some(cxx) = config.and_then(|c| c.cxx.as_ref()) { cfg.compiler(cxx); } else { - set_compiler(&mut cfg, "g++", host, config); + set_compiler(&mut cfg, "g++", host, config, build); } let compiler = cfg.get_compiler(); build.verbose(&format!("CXX_{} = {:?}", host, compiler.path())); @@ -83,7 +83,8 @@ pub fn find(build: &mut Build) { fn set_compiler(cfg: &mut gcc::Config, gnu_compiler: &str, target: &str, - config: Option<&Target>) { + config: Option<&Target>, + build: &Build) { match target { // When compiling for android we may have the NDK configured in the // config.toml in which case we look there. Otherwise the default @@ -119,6 +120,22 @@ fn set_compiler(cfg: &mut gcc::Config, } } + "mips-unknown-linux-musl" => { + cfg.compiler("mips-linux-musl-gcc"); + } + "mipsel-unknown-linux-musl" => { + cfg.compiler("mipsel-linux-musl-gcc"); + } + + t if t.contains("musl") => { + if let Some(root) = build.musl_root(target) { + let guess = root.join("bin/musl-gcc"); + if guess.exists() { + cfg.compiler(guess); + } + } + } + _ => {} } } diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index b67eab38f5d..c5675fd46cb 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Implementation of the various `check-*` targets of the build system. +//! Implementation of the test-related targets of the build system. //! //! This file implements the various regression test suites that we execute on //! our CI. @@ -62,6 +62,8 @@ impl fmt::Display for TestKind { pub fn linkcheck(build: &Build, stage: u32, host: &str) { println!("Linkcheck stage{} ({})", stage, host); let compiler = Compiler::new(stage, host); + + let _time = util::timeit(); build.run(build.tool_cmd(&compiler, "linkchecker") .arg(build.out.join(host).join("doc"))); } @@ -87,6 +89,7 @@ pub fn cargotest(build: &Build, stage: u32, host: &str) { let out_dir = build.out.join("ct"); t!(fs::create_dir_all(&out_dir)); + let _time = util::timeit(); build.run(build.tool_cmd(compiler, "cargotest") .env("PATH", newpath) .arg(&build.cargo) @@ -119,7 +122,8 @@ pub fn compiletest(build: &Build, target: &str, mode: &str, suite: &str) { - println!("Check compiletest {} ({} -> {})", suite, compiler.host, target); + println!("Check compiletest suite={} mode={} ({} -> {})", + suite, mode, compiler.host, target); let mut cmd = build.tool_cmd(compiler, "compiletest"); // compiletest currently has... a lot of arguments, so let's just pass all @@ -213,6 +217,9 @@ pub fn compiletest(build: &Build, // Running a C compiler on MSVC requires a few env vars to be set, to be // sure to set them here. + // + // Note that if we encounter `PATH` we make sure to append to our own `PATH` + // rather than stomp over it. if target.contains("msvc") { for &(ref k, ref v) in build.cc[target].0.env() { if k != "PATH" { @@ -221,6 +228,7 @@ pub fn compiletest(build: &Build, } } cmd.env("RUSTC_BOOTSTRAP", "1"); + build.add_rust_test_threads(&mut cmd); cmd.arg("--adb-path").arg("adb"); cmd.arg("--adb-test-dir").arg(ADB_TEST_DIR); @@ -232,6 +240,7 @@ pub fn compiletest(build: &Build, cmd.arg("--android-cross-path").arg(""); } + let _time = util::timeit(); build.run(&mut cmd); } @@ -244,6 +253,7 @@ pub fn docs(build: &Build, compiler: &Compiler) { // Do a breadth-first traversal of the `src/doc` directory and just run // tests for all files that end in `*.md` let mut stack = vec![build.src.join("src/doc")]; + let _time = util::timeit(); while let Some(p) = stack.pop() { if p.is_dir() { @@ -272,6 +282,8 @@ pub fn error_index(build: &Build, compiler: &Compiler) { let dir = testdir(build, compiler.host); t!(fs::create_dir_all(&dir)); let output = dir.join("error-index.md"); + + let _time = util::timeit(); build.run(build.tool_cmd(compiler, "error_index_generator") .arg("markdown") .arg(&output) @@ -283,6 +295,7 @@ pub fn error_index(build: &Build, compiler: &Compiler) { fn markdown_test(build: &Build, compiler: &Compiler, markdown: &Path) { let mut cmd = Command::new(build.rustdoc(compiler)); build.add_rustc_lib_path(compiler, &mut cmd); + build.add_rust_test_threads(&mut cmd); cmd.arg("--test"); cmd.arg(markdown); @@ -366,16 +379,25 @@ pub fn krate(build: &Build, dylib_path.insert(0, build.sysroot_libdir(compiler, target)); cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap()); + if target.contains("android") { + cargo.arg("--no-run"); + } else if target.contains("emscripten") { + cargo.arg("--no-run"); + } + + cargo.arg("--"); + if build.config.quiet_tests { - cargo.arg("--"); cargo.arg("--quiet"); } + let _time = util::timeit(); + if target.contains("android") { - build.run(cargo.arg("--no-run")); + build.run(&mut cargo); krate_android(build, compiler, target, mode); } else if target.contains("emscripten") { - build.run(cargo.arg("--no-run")); + build.run(&mut cargo); krate_emscripten(build, compiler, target, mode); } else { cargo.args(&build.flags.cmd.test_args()); @@ -402,14 +424,17 @@ fn krate_android(build: &Build, target, compiler.host, test_file_name); + let quiet = if build.config.quiet_tests { "--quiet" } else { "" }; let program = format!("(cd {dir}; \ LD_LIBRARY_PATH=./{target} ./{test} \ --logfile {log} \ + {quiet} \ {args})", dir = ADB_TEST_DIR, target = target, test = test_file_name, log = log, + quiet = quiet, args = build.flags.cmd.test_args().join(" ")); let output = output(Command::new("adb").arg("shell").arg(&program)); @@ -438,18 +463,13 @@ fn krate_emscripten(build: &Build, let test_file_name = test.to_string_lossy().into_owned(); println!("running {}", test_file_name); let nodejs = build.config.nodejs.as_ref().expect("nodejs not configured"); - let status = Command::new(nodejs) - .arg(&test_file_name) - .stderr(::std::process::Stdio::inherit()) - .status(); - match status { - Ok(status) => { - if !status.success() { - panic!("some tests failed"); - } - } - Err(e) => panic!(format!("failed to execute command: {}", e)), - }; + let mut cmd = Command::new(nodejs); + cmd.arg(&test_file_name) + .stderr(::std::process::Stdio::inherit()); + if build.config.quiet_tests { + cmd.arg("--quiet"); + } + build.run(&mut cmd); } } diff --git a/src/bootstrap/clean.rs b/src/bootstrap/clean.rs index 75bcbfee6ee..e7655458aed 100644 --- a/src/bootstrap/clean.rs +++ b/src/bootstrap/clean.rs @@ -46,6 +46,9 @@ fn rm_rf(build: &Build, path: &Path) { if !path.exists() { return } + if path.is_file() { + return do_op(path, "remove file", |p| fs::remove_file(p)); + } for file in t!(fs::read_dir(path)) { let file = t!(file).path(); diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index a7d80e4cdc4..7a2d56fc5d3 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -239,6 +239,7 @@ To learn more about a subcommand, run `./x.py -h` install: m.opt_present("install"), } } + "--help" => usage(0, &opts), cmd => { println!("unknown command: {}", cmd); usage(1, &opts); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 590c967d147..912b5864c81 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -13,9 +13,56 @@ //! This module, and its descendants, are the implementation of the Rust build //! system. Most of this build system is backed by Cargo but the outer layer //! here serves as the ability to orchestrate calling Cargo, sequencing Cargo -//! builds, building artifacts like LLVM, etc. +//! builds, building artifacts like LLVM, etc. The goals of rustbuild are: //! -//! More documentation can be found in each respective module below. +//! * To be an easily understandable, easily extensible, and maintainable build +//! system. +//! * Leverage standard tools in the Rust ecosystem to build the compiler, aka +//! crates.io and Cargo. +//! * A standard interface to build across all platforms, including MSVC +//! +//! ## Architecture +//! +//! Although this build system defers most of the complicated logic to Cargo +//! itself, it still needs to maintain a list of targets and dependencies which +//! it can itself perform. Rustbuild is made up of a list of rules with +//! dependencies amongst them (created in the `step` module) and then knows how +//! to execute each in sequence. Each time rustbuild is invoked, it will simply +//! iterate through this list of steps and execute each serially in turn. For +//! each step rustbuild relies on the step internally being incremental and +//! parallel. Note, though, that the `-j` parameter to rustbuild gets forwarded +//! to appropriate test harnesses and such. +//! +//! Most of the "meaty" steps that matter are backed by Cargo, which does indeed +//! have its own parallelism and incremental management. Later steps, like +//! tests, aren't incremental and simply run the entire suite currently. +//! +//! When you execute `x.py build`, the steps which are executed are: +//! +//! * First, the python script is run. This will automatically download the +//! stage0 rustc and cargo according to `src/stage0.txt`, or using the cached +//! versions if they're available. These are then used to compile rustbuild +//! itself (using Cargo). Finally, control is then transferred to rustbuild. +//! +//! * Rustbuild takes over, performs sanity checks, probes the environment, +//! reads configuration, builds up a list of steps, and then starts executing +//! them. +//! +//! * The stage0 libstd is compiled +//! * The stage0 libtest is compiled +//! * The stage0 librustc is compiled +//! * The stage1 compiler is assembled +//! * The stage1 libstd, libtest, librustc are compiled +//! * The stage2 compiler is assembled +//! * The stage2 libstd, libtest, librustc are compiled +//! +//! Each step is driven by a separate Cargo project and rustbuild orchestrates +//! copying files between steps and otherwise preparing for Cargo to run. +//! +//! ## Further information +//! +//! More documentation can be found in each respective module below, and you can +//! also check out the `src/bootstrap/README.md` file for more information. extern crate build_helper; extern crate cmake; @@ -28,6 +75,7 @@ extern crate toml; use std::collections::HashMap; use std::env; +use std::ffi::OsString; use std::fs::{self, File}; use std::path::{Component, PathBuf, Path}; use std::process::Command; @@ -128,6 +176,7 @@ pub struct Build { cc: HashMap)>, cxx: HashMap, crates: HashMap, + is_sudo: bool, } #[derive(Debug)] @@ -187,6 +236,16 @@ impl Build { }; let local_rebuild = config.local_rebuild; + let is_sudo = match env::var_os("SUDO_USER") { + Some(sudo_user) => { + match env::var_os("USER") { + Some(user) => user != sudo_user, + None => false, + } + } + None => false, + }; + Build { flags: flags, config: config, @@ -208,6 +267,7 @@ impl Build { crates: HashMap::new(), lldb_version: None, lldb_python_dir: None, + is_sudo: is_sudo, } } @@ -414,7 +474,7 @@ impl Build { // how the actual compiler itself is called. // // These variables are primarily all read by - // src/bootstrap/{rustc,rustdoc.rs} + // src/bootstrap/bin/{rustc.rs,rustdoc.rs} cargo.env("RUSTC", self.out.join("bootstrap/debug/rustc")) .env("RUSTC_REAL", self.compiler_path(compiler)) .env("RUSTC_STAGE", stage.to_string()) @@ -435,6 +495,7 @@ impl Build { // Enable usage of unstable features cargo.env("RUSTC_BOOTSTRAP", "1"); + self.add_rust_test_threads(&mut cargo); // Specify some various options for build scripts used throughout // the build. @@ -458,7 +519,7 @@ impl Build { if self.config.rust_optimize && cmd != "bench" { cargo.arg("--release"); } - if self.config.vendor { + if self.config.vendor || self.is_sudo { cargo.arg("--frozen"); } return cargo @@ -492,12 +553,30 @@ impl Build { fn tool_cmd(&self, compiler: &Compiler, tool: &str) -> Command { let mut cmd = Command::new(self.tool(&compiler, tool)); let host = compiler.host; - let paths = vec![ + let mut paths = vec![ self.cargo_out(compiler, Mode::Libstd, host).join("deps"), self.cargo_out(compiler, Mode::Libtest, host).join("deps"), self.cargo_out(compiler, Mode::Librustc, host).join("deps"), self.cargo_out(compiler, Mode::Tool, host).join("deps"), ]; + + // On MSVC a tool may invoke a C compiler (e.g. compiletest in run-make + // mode) and that C compiler may need some extra PATH modification. Do + // so here. + if compiler.host.contains("msvc") { + let curpaths = env::var_os("PATH").unwrap_or(OsString::new()); + let curpaths = env::split_paths(&curpaths).collect::>(); + for &(ref k, ref v) in self.cc[compiler.host].0.env() { + if k != "PATH" { + continue + } + for path in env::split_paths(v) { + if !curpaths.contains(&path) { + paths.push(path); + } + } + } + } add_lib_path(paths, &mut cmd); return cmd } @@ -651,6 +730,13 @@ impl Build { add_lib_path(vec![self.rustc_libdir(compiler)], cmd); } + /// Adds the `RUST_TEST_THREADS` env var if necessary + fn add_rust_test_threads(&self, cmd: &mut Command) { + if env::var_os("RUST_TEST_THREADS").is_none() { + cmd.env("RUST_TEST_THREADS", self.jobs().to_string()); + } + } + /// Returns the compiler's libdir where it stores the dynamic libraries that /// it itself links against. /// diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index 1e73595ec99..b165048b7b6 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -23,9 +23,14 @@ all: $(Q)$(BOOTSTRAP) build $(BOOTSTRAP_ARGS) $(Q)$(BOOTSTRAP) doc $(BOOTSTRAP_ARGS) -# Don’t use $(Q) here, always show how to invoke the bootstrap script directly help: - $(BOOTSTRAP) --help + $(Q)echo 'Welcome to the rustbuild build system!' + $(Q)echo + $(Q)echo This makefile is a thin veneer over the ./x.py script located + $(Q)echo in this directory. To get the full power of the build system + $(Q)echo you can run x.py directly. + $(Q)echo + $(Q)echo To learn more run \`./x.py --help\` clean: $(Q)$(BOOTSTRAP) clean $(BOOTSTRAP_ARGS) @@ -51,15 +56,14 @@ check-cargotest: dist: $(Q)$(BOOTSTRAP) dist $(BOOTSTRAP_ARGS) install: -ifeq (root user, $(USER) $(patsubst %,user,$(SUDO_USER))) - $(Q)echo "'sudo make install' is not supported currently." -else $(Q)$(BOOTSTRAP) dist --install $(BOOTSTRAP_ARGS) -endif tidy: $(Q)$(BOOTSTRAP) test src/tools/tidy $(BOOTSTRAP_ARGS) --stage 0 -check-stage2-android: - $(Q)$(BOOTSTRAP) --step check-target --target arm-linux-androideabi +check-stage2-T-arm-linux-androideabi-H-x86_64-unknown-linux-gnu: + $(Q)$(BOOTSTRAP) test --target arm-linux-androideabi +check-stage2-T-x86_64-unknown-linux-musl-H-x86_64-unknown-linux-gnu: + $(Q)$(BOOTSTRAP) test --target x86_64-unknown-linux-gnu + .PHONY: dist diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 96d1b695dd7..ffa3fe1cbf2 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -28,7 +28,7 @@ use cmake; use gcc; use Build; -use util::up_to_date; +use util::{self, up_to_date}; /// Compile LLVM for `target`. pub fn llvm(build: &Build, target: &str) { @@ -58,6 +58,7 @@ pub fn llvm(build: &Build, target: &str) { println!("Building LLVM for {}", target); + let _time = util::timeit(); let _ = fs::remove_dir_all(&dst.join("build")); t!(fs::create_dir_all(&dst.join("build"))); let assertions = if build.config.llvm_assertions {"ON"} else {"OFF"}; @@ -158,6 +159,17 @@ pub fn test_helpers(build: &Build, target: &str) { println!("Building test helpers"); t!(fs::create_dir_all(&dst)); let mut cfg = gcc::Config::new(); + + // We may have found various cross-compilers a little differently due to our + // extra configuration, so inform gcc of these compilers. Note, though, that + // on MSVC we still need gcc's detection of env vars (ugh). + if !target.contains("msvc") { + if let Some(ar) = build.ar(target) { + cfg.archiver(ar); + } + cfg.compiler(build.cc(target)); + } + cfg.cargo_metadata(false) .out_dir(&dst) .target(target) diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index 47efa695217..f3fe22698bb 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -41,10 +41,14 @@ pub fn check(build: &mut Build) { } } let have_cmd = |cmd: &OsStr| { - for path in env::split_paths(&path).map(|p| p.join(cmd)) { - if fs::metadata(&path).is_ok() || - fs::metadata(path.with_extension("exe")).is_ok() { - return Some(path); + for path in env::split_paths(&path) { + let target = path.join(cmd); + let mut cmd_alt = cmd.to_os_string(); + cmd_alt.push(".exe"); + if target.exists() || + target.with_extension("exe").exists() || + target.join(cmd_alt).exists() { + return Some(target); } } return None; diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index b8683831af1..ca169bd146c 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -8,6 +8,24 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! Definition of steps of the build system. +//! +//! This is where some of the real meat of rustbuild is located, in how we +//! define targets and the dependencies amongst them. This file can sort of be +//! viewed as just defining targets in a makefile which shell out to predefined +//! functions elsewhere about how to execute the target. +//! +//! The primary function here you're likely interested in is the `build_rules` +//! function. This will create a `Rules` structure which basically just lists +//! everything that rustbuild can do. Each rule has a human-readable name, a +//! path associated with it, some dependencies, and then a closure of how to +//! actually perform the rule. +//! +//! All steps below are defined in self-contained units, so adding a new target +//! to the build system should just involve adding the meta information here +//! along with the actual implementation elsewhere. You can find more comments +//! about how to define rules themselves below. + use std::collections::{HashMap, HashSet}; use std::mem; @@ -20,36 +38,6 @@ use install; use native; use {Compiler, Build, Mode}; -#[derive(PartialEq, Eq, Hash, Clone, Debug)] -struct Step<'a> { - name: &'a str, - stage: u32, - host: &'a str, - target: &'a str, -} - -impl<'a> Step<'a> { - fn name(&self, name: &'a str) -> Step<'a> { - Step { name: name, ..*self } - } - - fn stage(&self, stage: u32) -> Step<'a> { - Step { stage: stage, ..*self } - } - - fn host(&self, host: &'a str) -> Step<'a> { - Step { host: host, ..*self } - } - - fn target(&self, target: &'a str) -> Step<'a> { - Step { target: target, ..*self } - } - - fn compiler(&self) -> Compiler<'a> { - Compiler::new(self.stage, self.host) - } -} - pub fn run(build: &Build) { let rules = build_rules(build); let steps = rules.plan(); @@ -57,14 +45,91 @@ pub fn run(build: &Build) { } pub fn build_rules(build: &Build) -> Rules { - let mut rules: Rules = Rules::new(build); + let mut rules = Rules::new(build); + + // This is the first rule that we're going to define for rustbuild, which is + // used to compile LLVM itself. All rules are added through the `rules` + // structure created above and are configured through a builder-style + // interface. + // + // First up we see the `build` method. This represents a rule that's part of + // the top-level `build` subcommand. For example `./x.py build` is what this + // is associating with. Note that this is normally only relevant if you flag + // a rule as `default`, which we'll talk about later. + // + // Next up we'll see two arguments to this method: + // + // * `llvm` - this is the "human readable" name of this target. This name is + // not accessed anywhere outside this file itself (e.g. not in + // the CLI nor elsewhere in rustbuild). The purpose of this is to + // easily define dependencies between rules. That is, other rules + // will depend on this with the name "llvm". + // * `src/llvm` - this is the relevant path to the rule that we're working + // with. This path is the engine behind how commands like + // `./x.py build src/llvm` work. This should typically point + // to the relevant component, but if there's not really a + // path to be assigned here you can pass something like + // `path/to/nowhere` to ignore it. + // + // After we create the rule with the `build` method we can then configure + // various aspects of it. For example this LLVM rule uses `.host(true)` to + // flag that it's a rule only for host targets. In other words, LLVM isn't + // compiled for targets configured through `--target` (e.g. those we're just + // building a standard library for). + // + // Next up the `dep` method will add a dependency to this rule. The closure + // is yielded the step that represents executing the `llvm` rule itself + // (containing information like stage, host, target, ...) and then it must + // return a target that the step depends on. Here LLVM is actually + // interesting where a cross-compiled LLVM depends on the host LLVM, but + // otherwise it has no dependencies. + // + // To handle this we do a bit of dynamic dispatch to see what the dependency + // is. If we're building a LLVM for the build triple, then we don't actually + // have any dependencies! To do that we return a dependency on the "dummy" + // target which does nothing. + // + // If we're build a cross-compiled LLVM, however, we need to assemble the + // libraries from the previous compiler. This step has the same name as + // ours (llvm) but we want it for a different target, so we use the + // builder-style methods on `Step` to configure this target to the build + // triple. + // + // Finally, to finish off this rule, we define how to actually execute it. + // That logic is all defined in the `native` module so we just delegate to + // the relevant function there. The argument to the closure passed to `run` + // is a `Step` (defined below) which encapsulates information like the + // stage, target, host, etc. + rules.build("llvm", "src/llvm") + .host(true) + .dep(move |s| { + if s.target == build.config.build { + dummy(s, build) + } else { + s.target(&build.config.build) + } + }) + .run(move |s| native::llvm(build, s.target)); + + // Ok! After that example rule that's hopefully enough to explain what's + // going on here. You can check out the API docs below and also see a bunch + // more examples of rules directly below as well. + // dummy rule to do nothing, useful when a dep maps to no deps rules.build("dummy", "path/to/nowhere"); - fn dummy<'a>(s: &Step<'a>, build: &'a Build) -> Step<'a> { - s.name("dummy").stage(0) - .target(&build.config.build) - .host(&build.config.build) - } + + // the compiler with no target libraries ready to go + rules.build("rustc", "src/rustc") + .dep(move |s| { + if s.stage == 0 { + dummy(s, build) + } else { + s.name("librustc") + .host(&build.config.build) + .stage(s.stage - 1) + } + }) + .run(move |s| compile::assemble_rustc(build, s.stage, s.target)); // Helper for loading an entire DAG of crates, rooted at `name` let krates = |name: &str| { @@ -85,28 +150,6 @@ pub fn build_rules(build: &Build) -> Rules { return ret }; - rules.build("rustc", "path/to/nowhere") - .dep(move |s| { - if s.stage == 0 { - dummy(s, build) - } else { - s.name("librustc") - .host(&build.config.build) - .stage(s.stage - 1) - } - }) - .run(move |s| compile::assemble_rustc(build, s.stage, s.target)); - rules.build("llvm", "src/llvm") - .host(true) - .dep(move |s| { - if s.target == build.config.build { - dummy(s, build) - } else { - s.target(&build.config.build) - } - }) - .run(move |s| native::llvm(build, s.target)); - // ======================================================================== // Crate compilations // @@ -337,10 +380,10 @@ pub fn build_rules(build: &Build) -> Rules { .host(true) .run(move |s| check::cargotest(build, s.stage, s.target)); rules.test("check-tidy", "src/tools/tidy") - .dep(|s| s.name("tool-tidy")) + .dep(|s| s.name("tool-tidy").stage(0)) .default(true) .host(true) - .run(move |s| check::tidy(build, s.stage, s.target)); + .run(move |s| check::tidy(build, 0, s.target)); rules.test("check-error-index", "src/tools/error_index_generator") .dep(|s| s.name("libstd")) .dep(|s| s.name("tool-error-index").host(s.host)) @@ -457,16 +500,89 @@ pub fn build_rules(build: &Build) -> Rules { .run(move |s| install::install(build, s.stage, s.target)); rules.verify(); - return rules + return rules; + + fn dummy<'a>(s: &Step<'a>, build: &'a Build) -> Step<'a> { + s.name("dummy").stage(0) + .target(&build.config.build) + .host(&build.config.build) + } +} + +#[derive(PartialEq, Eq, Hash, Clone, Debug)] +struct Step<'a> { + /// Human readable name of the rule this step is executing. Possible names + /// are all defined above in `build_rules`. + name: &'a str, + + /// The stage this step is executing in. This is typically 0, 1, or 2. + stage: u32, + + /// This step will likely involve a compiler, and the target that compiler + /// itself is built for is called the host, this variable. Typically this is + /// the target of the build machine itself. + host: &'a str, + + /// The target that this step represents generating. If you're building a + /// standard library for a new suite of targets, for example, this'll be set + /// to those targets. + target: &'a str, +} + +impl<'a> Step<'a> { + /// Creates a new step which is the same as this, except has a new name. + fn name(&self, name: &'a str) -> Step<'a> { + Step { name: name, ..*self } + } + + /// Creates a new step which is the same as this, except has a new stage. + fn stage(&self, stage: u32) -> Step<'a> { + Step { stage: stage, ..*self } + } + + /// Creates a new step which is the same as this, except has a new host. + fn host(&self, host: &'a str) -> Step<'a> { + Step { host: host, ..*self } + } + + /// Creates a new step which is the same as this, except has a new target. + fn target(&self, target: &'a str) -> Step<'a> { + Step { target: target, ..*self } + } + + /// Returns the `Compiler` structure that this step corresponds to. + fn compiler(&self) -> Compiler<'a> { + Compiler::new(self.stage, self.host) + } } struct Rule<'a> { + /// The human readable name of this target, defined in `build_rules`. name: &'a str, + + /// The path associated with this target, used in the `./x.py` driver for + /// easy and ergonomic specification of what to do. path: &'a str, + + /// The "kind" of top-level command that this rule is associated with, only + /// relevant if this is a default rule. kind: Kind, + + /// List of dependencies this rule has. Each dependency is a function from a + /// step that's being executed to another step that should be executed. deps: Vec) -> Step<'a> + 'a>>, + + /// How to actually execute this rule. Takes a step with contextual + /// information and then executes it. run: Box) + 'a>, + + /// Whether or not this is a "default" rule. That basically means that if + /// you run, for example, `./x.py test` whether it's included or not. default: bool, + + /// Whether or not this is a "host" rule, or in other words whether this is + /// only intended for compiler hosts and not for targets that are being + /// generated. host: bool, } @@ -493,6 +609,8 @@ impl<'a> Rule<'a> { } } +/// Builder pattern returned from the various methods on `Rules` which will add +/// the rule to the internal list on `Drop`. struct RuleBuilder<'a: 'b, 'b> { rules: &'b mut Rules<'a>, rule: Rule<'a>, @@ -554,26 +672,35 @@ impl<'a> Rules<'a> { } } + /// Creates a new rule of `Kind::Build` with the specified human readable + /// name and path associated with it. + /// + /// The builder returned should be configured further with information such + /// as how to actually run this rule. fn build<'b>(&'b mut self, name: &'a str, path: &'a str) -> RuleBuilder<'a, 'b> { self.rule(name, path, Kind::Build) } + /// Same as `build`, but for `Kind::Test`. fn test<'b>(&'b mut self, name: &'a str, path: &'a str) -> RuleBuilder<'a, 'b> { self.rule(name, path, Kind::Test) } + /// Same as `build`, but for `Kind::Bench`. fn bench<'b>(&'b mut self, name: &'a str, path: &'a str) -> RuleBuilder<'a, 'b> { self.rule(name, path, Kind::Bench) } + /// Same as `build`, but for `Kind::Doc`. fn doc<'b>(&'b mut self, name: &'a str, path: &'a str) -> RuleBuilder<'a, 'b> { self.rule(name, path, Kind::Doc) } + /// Same as `build`, but for `Kind::Dist`. fn dist<'b>(&'b mut self, name: &'a str, path: &'a str) -> RuleBuilder<'a, 'b> { self.rule(name, path, Kind::Dist) @@ -634,6 +761,31 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd? /// Construct the top-level build steps that we're going to be executing, /// given the subcommand that our build is performing. fn plan(&self) -> Vec> { + // Ok, the logic here is pretty subtle, and involves quite a few + // conditionals. The basic idea here is to: + // + // 1. First, filter all our rules to the relevant ones. This means that + // the command specified corresponds to one of our `Kind` variants, + // and we filter all rules based on that. + // + // 2. Next, we determine which rules we're actually executing. If a + // number of path filters were specified on the command line we look + // for those, otherwise we look for anything tagged `default`. + // + // 3. Finally, we generate some steps with host and target information. + // + // The last step is by far the most complicated and subtle. The basic + // thinking here is that we want to take the cartesian product of + // specified hosts and targets and build rules with that. The list of + // hosts and targets, if not specified, come from the how this build was + // configured. If the rule we're looking at is a host-only rule the we + // ignore the list of targets and instead consider the list of hosts + // also the list of targets. + // + // Once the host and target lists are generated we take the cartesian + // product of the two and then create a step based off them. Note that + // the stage each step is associated was specified with the `--step` + // flag on the command line. let (kind, paths) = match self.build.flags.cmd { Subcommand::Build { ref paths } => (Kind::Build, &paths[..]), Subcommand::Doc { ref paths } => (Kind::Doc, &paths[..]), @@ -664,7 +816,18 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd? } else { &self.build.config.target }; - let arr = if rule.host {hosts} else {targets}; + // If --target was specified but --host wasn't specified, don't run + // any host-only tests + let arr = if rule.host { + if self.build.flags.target.len() > 0 && + self.build.flags.host.len() == 0 { + &hosts[..0] + } else { + hosts + } + } else { + targets + }; hosts.iter().flat_map(move |host| { arr.iter().map(move |target| { @@ -705,6 +868,15 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd? } } + /// Performs topological sort of dependencies rooted at the `step` + /// specified, pushing all results onto the `order` vector provided. + /// + /// In other words, when this method returns, the `order` vector will + /// contain a list of steps which if executed in order will eventually + /// complete the `step` specified as well. + /// + /// The `added` set specified here is the set of steps that are already + /// present in `order` (and hence don't need to be added again). fn fill(&self, step: Step<'a>, order: &mut Vec>, diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index e028c522366..cb5b456a0f2 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -18,6 +18,7 @@ use std::ffi::OsString; use std::fs; use std::path::{Path, PathBuf}; use std::process::Command; +use std::time::Instant; use filetime::FileTime; @@ -189,3 +190,19 @@ pub fn push_exe_path(mut buf: PathBuf, components: &[&str]) -> PathBuf { buf } + +pub struct TimeIt(Instant); + +/// Returns an RAII structure that prints out how long it took to drop. +pub fn timeit() -> TimeIt { + TimeIt(Instant::now()) +} + +impl Drop for TimeIt { + fn drop(&mut self) { + let time = self.0.elapsed(); + println!("\tfinished in {}.{:03}", + time.as_secs(), + time.subsec_nanos() / 1_000_000); + } +} diff --git a/src/ci/docker/arm-android/Dockerfile b/src/ci/docker/arm-android/Dockerfile index c5b70c227c4..121c0263cbc 100644 --- a/src/ci/docker/arm-android/Dockerfile +++ b/src/ci/docker/arm-android/Dockerfile @@ -9,7 +9,6 @@ RUN dpkg --add-architecture i386 && \ curl \ ca-certificates \ python2.7 \ - python-minimal \ git \ cmake \ ccache \ @@ -39,8 +38,7 @@ ENV RUST_CONFIGURE_ARGS \ --arm-linux-androideabi-ndk=/android/ndk-arm-9 \ --armv7-linux-androideabi-ndk=/android/ndk-arm-9 \ --i686-linux-android-ndk=/android/ndk-x86-9 \ - --aarch64-linux-android-ndk=/android/ndk-aarch64 \ - --enable-rustbuild -ENV RUST_CHECK_TARGET check-stage2-android + --aarch64-linux-android-ndk=/android/ndk-aarch64 +ENV XPY_CHECK test --target arm-linux-androideabi RUN mkdir /tmp/obj RUN chmod 777 /tmp/obj diff --git a/src/ci/docker/cross/Dockerfile b/src/ci/docker/cross/Dockerfile index d8af878a958..b7b23d74c9d 100644 --- a/src/ci/docker/cross/Dockerfile +++ b/src/ci/docker/cross/Dockerfile @@ -7,7 +7,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ curl \ ca-certificates \ python2.7 \ - python-minimal \ git \ cmake \ ccache \ diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index c5b1d00fb7c..ff5345d3aac 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -19,17 +19,21 @@ ci_dir="`dirname $docker_dir`" src_dir="`dirname $ci_dir`" root_dir="`dirname $src_dir`" -docker build \ +docker \ + build \ --rm \ -t rust-ci \ "`dirname "$script"`/$image" mkdir -p $HOME/.ccache mkdir -p $HOME/.cargo +mkdir -p $root_dir/obj -exec docker run \ +exec docker \ + run \ --volume "$root_dir:/checkout:ro" \ - --workdir /tmp/obj \ + --volume "$root_dir/obj:/checkout/obj" \ + --workdir /checkout/obj \ --env SRC=/checkout \ --env CCACHE_DIR=/ccache \ --volume "$HOME/.ccache:/ccache" \ diff --git a/src/ci/docker/x86_64-freebsd/Dockerfile b/src/ci/docker/x86_64-freebsd/Dockerfile index dc16c39961c..a3a52f9e6ff 100644 --- a/src/ci/docker/x86_64-freebsd/Dockerfile +++ b/src/ci/docker/x86_64-freebsd/Dockerfile @@ -7,7 +7,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ curl \ ca-certificates \ python2.7 \ - python-minimal \ git \ cmake \ ccache \ @@ -23,7 +22,7 @@ ENV \ AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-ar \ CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-gcc -ENV RUST_CONFIGURE_ARGS --target=x86_64-unknown-freebsd --enable-rustbuild +ENV RUST_CONFIGURE_ARGS --target=x86_64-unknown-freebsd ENV RUST_CHECK_TARGET "" RUN mkdir /tmp/obj RUN chmod 777 /tmp/obj diff --git a/src/ci/docker/x86_64-gnu-cargotest/Dockerfile b/src/ci/docker/x86_64-gnu-cargotest/Dockerfile index 1db01f2b48d..107e2bf8a12 100644 --- a/src/ci/docker/x86_64-gnu-cargotest/Dockerfile +++ b/src/ci/docker/x86_64-gnu-cargotest/Dockerfile @@ -7,14 +7,14 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ curl \ ca-certificates \ python2.7 \ - python-minimal \ git \ cmake \ ccache \ libssl-dev \ sudo -ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --enable-rustbuild +ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu ENV RUST_CHECK_TARGET check-cargotest +ENV NO_VENDOR 1 RUN mkdir /tmp/obj RUN chmod 777 /tmp/obj diff --git a/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile b/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile index ca06940ae5e..c27e3d1325f 100644 --- a/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile +++ b/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile @@ -7,7 +7,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ curl \ ca-certificates \ python2.7 \ - python2.7-minimal \ git \ cmake \ ccache \ @@ -19,7 +18,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ - --enable-rustbuild \ --llvm-root=/usr/lib/llvm-3.7 ENV RUST_CHECK_TARGET check RUN mkdir /tmp/obj diff --git a/src/ci/docker/x86_64-gnu-rustbuild/Dockerfile b/src/ci/docker/x86_64-gnu-make/Dockerfile similarity index 73% rename from src/ci/docker/x86_64-gnu-rustbuild/Dockerfile rename to src/ci/docker/x86_64-gnu-make/Dockerfile index d4d0492e2a2..93229b2a010 100644 --- a/src/ci/docker/x86_64-gnu-rustbuild/Dockerfile +++ b/src/ci/docker/x86_64-gnu-make/Dockerfile @@ -7,14 +7,13 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ curl \ ca-certificates \ python2.7 \ - python-minimal \ git \ cmake \ ccache \ sudo \ gdb -ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --enable-rustbuild +ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --disable-rustbuild ENV RUST_CHECK_TARGET check RUN mkdir /tmp/obj RUN chmod 777 /tmp/obj diff --git a/src/ci/docker/x86_64-musl/Dockerfile b/src/ci/docker/x86_64-musl/Dockerfile index 1afaef2e056..967940fb1f3 100644 --- a/src/ci/docker/x86_64-musl/Dockerfile +++ b/src/ci/docker/x86_64-musl/Dockerfile @@ -20,8 +20,10 @@ RUN sh /build/build-musl.sh && rm -rf /build ENV RUST_CONFIGURE_ARGS \ --target=x86_64-unknown-linux-musl \ - --musl-root=/musl-x86_64 + --musl-root-x86_64=/musl-x86_64 ENV RUST_CHECK_TARGET check-stage2-T-x86_64-unknown-linux-musl-H-x86_64-unknown-linux-gnu +ENV PATH=$PATH:/musl-x86_64/bin +ENV XPY_CHECK test --target x86_64-unknown-linux-musl RUN mkdir /tmp/obj RUN chmod 777 /tmp/obj diff --git a/src/ci/run.sh b/src/ci/run.sh index da238dddeca..10f2d15da34 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -14,12 +14,20 @@ set -e if [ "$LOCAL_USER_ID" != "" ]; then useradd --shell /bin/bash -u $LOCAL_USER_ID -o -c "" -m user export HOME=/home/user - export LOCAL_USER_ID= - exec sudo -E -u user env PATH=$PATH "$0" + unset LOCAL_USER_ID + exec su --preserve-environment -c "env PATH=$PATH \"$0\"" user fi if [ "$NO_LLVM_ASSERTIONS" = "" ]; then - LLVM_ASSERTIONS=--enable-llvm-assertions + ENABLE_LLVM_ASSERTIONS=--enable-llvm-assertions +fi + +if [ "$NO_VENDOR" = "" ]; then + ENABLE_VENDOR=--enable-vendor +fi + +if [ "$NO_CCACHE" = "" ]; then + ENABLE_CCACHE=--enable-ccache fi set -ex @@ -28,9 +36,9 @@ $SRC/configure \ --disable-manage-submodules \ --enable-debug-assertions \ --enable-quiet-tests \ - --enable-ccache \ - --enable-vendor \ - $LLVM_ASSERTIONS \ + $ENABLE_CCACHE \ + $ENABLE_VENDOR \ + $ENABLE_LLVM_ASSERTIONS \ $RUST_CONFIGURE_ARGS if [ "$TRAVIS_OS_NAME" = "osx" ]; then @@ -41,4 +49,8 @@ fi make -j $ncpus tidy make -j $ncpus -exec make $RUST_CHECK_TARGET -j $ncpus +if [ ! -z "$XPY_CHECK" ]; then + exec python2.7 $SRC/x.py $XPY_CHECK +else + exec make $RUST_CHECK_TARGET -j $ncpus +fi diff --git a/src/liballoc_jemalloc/build.rs b/src/liballoc_jemalloc/build.rs index 50149dfd65f..fc849e7a50c 100644 --- a/src/liballoc_jemalloc/build.rs +++ b/src/liballoc_jemalloc/build.rs @@ -151,11 +151,17 @@ fn main() { cmd.arg(format!("--build={}", build_helper::gnu_target(&host))); run(&mut cmd); - run(Command::new("make") - .current_dir(&build_dir) - .arg("build_lib_static") - .arg("-j") - .arg(env::var("NUM_JOBS").expect("NUM_JOBS was not set"))); + let mut make = Command::new("make"); + make.current_dir(&build_dir) + .arg("build_lib_static"); + + // mingw make seems... buggy? unclear... + if !host.contains("windows") { + make.arg("-j") + .arg(env::var("NUM_JOBS").expect("NUM_JOBS was not set")); + } + + run(&mut make); if target.contains("windows") { println!("cargo:rustc-link-lib=static=jemalloc"); diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-auto-clean-trigger index 768ba2d5b77..2d832fcdf2a 100644 --- a/src/rustllvm/llvm-auto-clean-trigger +++ b/src/rustllvm/llvm-auto-clean-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be forcibly cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2016-12-01 +2016-12-06 diff --git a/src/test/run-pass/no-stdio.rs b/src/test/run-pass/no-stdio.rs index ad4d56ec50a..85c63e184fe 100644 --- a/src/test/run-pass/no-stdio.rs +++ b/src/test/run-pass/no-stdio.rs @@ -9,6 +9,7 @@ // except according to those terms. // ignore-emscripten +// ignore-android #![feature(libc)] From 5beeb1eec7c325428f1a1cd6fb1a95c45256e9f8 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 7 Dec 2016 13:14:47 +0100 Subject: [PATCH 259/293] remove useless lifetime outlives bounds --- src/librustc/lint/builtin.rs | 2 +- src/librustc/lint/mod.rs | 169 ++++++++---------- src/librustc_lint/bad_style.rs | 32 ++-- src/librustc_lint/builtin.rs | 84 +++++---- src/librustc_lint/types.rs | 12 +- src/librustc_lint/unused.rs | 28 +-- .../auxiliary/lint_for_crate.rs | 6 +- .../auxiliary/lint_group_plugin_test.rs | 6 +- .../auxiliary/lint_for_crate.rs | 6 +- .../auxiliary/lint_group_plugin_test.rs | 6 +- .../issue-37290/auxiliary/lint.rs | 4 +- 11 files changed, 165 insertions(+), 190 deletions(-) diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 78d5067b273..02c1ece1634 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -262,4 +262,4 @@ impl LintPass for HardwiredLints { } } -impl LateLintPass for HardwiredLints {} +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for HardwiredLints {} diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 0f85494d1ab..ccf53f01cd5 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -129,106 +129,85 @@ pub trait LintPass { // // FIXME: eliminate the duplication with `Visitor`. But this also // contains a few lint-specific methods with no equivalent in `Visitor`. -pub trait LateLintPass: LintPass { +pub trait LateLintPass<'a, 'tcx>: LintPass { fn check_name(&mut self, _: &LateContext, _: Span, _: ast::Name) { } - fn check_crate<'a, 'tcx:'a >(&mut self, _: &'a LateContext<'a, 'tcx>, _: &'tcx hir::Crate) { } - fn check_crate_post<'a, 'tcx: 'a>(&mut self, - _: &'a LateContext<'a, 'tcx>, - _: &'tcx hir::Crate) { } - fn check_mod<'a, 'tcx: 'a>(&mut self, - _: &'a LateContext<'a, 'tcx>, - _: &'tcx hir::Mod, - _: Span, - _: ast::NodeId) { } - fn check_mod_post<'a, 'tcx: 'a>(&mut self, - _: &'a LateContext<'a, 'tcx>, - _: &'tcx hir::Mod, - _: Span, - _: ast::NodeId) { } - fn check_foreign_item<'a, 'tcx: 'a>(&mut self, - _: &'a LateContext<'a, 'tcx>, - _: &'tcx hir::ForeignItem) { } - fn check_foreign_item_post<'a, 'tcx: 'a>(&mut self, - _: &'a LateContext<'a, 'tcx>, - _: &'tcx hir::ForeignItem) { } - fn check_item<'a, 'tcx: 'a>(&mut self, - _: &'a LateContext<'a, 'tcx>, - _: &'tcx hir::Item) { } - fn check_item_post<'a, 'tcx: 'a>(&mut self, - _: &'a LateContext<'a, 'tcx>, - _: &'tcx hir::Item) { } - fn check_local<'a, 'tcx: 'a>(&mut self, _: &'a LateContext<'a, 'tcx>, _: &'tcx hir::Local) { } - fn check_block<'a, 'tcx: 'a>(&mut self, _: &'a LateContext<'a, 'tcx>, _: &'tcx hir::Block) { } - fn check_block_post<'a, 'tcx: 'a>(&mut self, - _: &'a LateContext<'a, 'tcx>, - _: &'tcx hir::Block) { } - fn check_stmt<'a, 'tcx: 'a>(&mut self, _: &'a LateContext<'a, 'tcx>, _: &'tcx hir::Stmt) { } - fn check_arm<'a, 'tcx: 'a>(&mut self, _: &'a LateContext<'a, 'tcx>, _: &'tcx hir::Arm) { } - fn check_pat<'a, 'tcx: 'a>(&mut self, _: &'a LateContext<'a, 'tcx>, _: &'tcx hir::Pat) { } - fn check_decl<'a, 'tcx: 'a>(&mut self, _: &'a LateContext<'a, 'tcx>, _: &'tcx hir::Decl) { } - fn check_expr<'a, 'tcx: 'a>(&mut self, _: &'a LateContext<'a, 'tcx>, _: &'tcx hir::Expr) { } - fn check_expr_post<'a, 'tcx: 'a>(&mut self, - _: &'a LateContext<'a, 'tcx>, - _: &'tcx hir::Expr) { } - fn check_ty<'a, 'tcx: 'a>(&mut self, _: &'a LateContext<'a, 'tcx>, _: &'tcx hir::Ty) { } - fn check_generics<'a, 'tcx: 'a>(&mut self, - _: &'a LateContext<'a, 'tcx>, - _: &'tcx hir::Generics) { } - fn check_fn<'a, 'tcx: 'a>(&mut self, _: &'a LateContext<'a, 'tcx>, - _: FnKind<'tcx>, _: &'tcx hir::FnDecl, _: &'tcx hir::Expr, _: Span, _: ast::NodeId) { } - fn check_fn_post<'a, 'tcx: 'a>(&mut self, _: &'a LateContext<'a, 'tcx>, - _: FnKind<'tcx>, _: &'tcx hir::FnDecl, _: &'tcx hir::Expr, _: Span, _: ast::NodeId) { } - fn check_trait_item<'a, 'tcx: 'a>(&mut self, - _: &'a LateContext<'a, 'tcx>, - _: &'tcx hir::TraitItem) { } - fn check_trait_item_post<'a, 'tcx: 'a>(&mut self, - _: &'a LateContext<'a, 'tcx>, - _: &'tcx hir::TraitItem) { } - fn check_impl_item<'a, 'tcx: 'a>(&mut self, - _: &'a LateContext<'a, 'tcx>, - _: &'tcx hir::ImplItem) { } - fn check_impl_item_post<'a, 'tcx: 'a>(&mut self, - _: &'a LateContext<'a, 'tcx>, - _: &'tcx hir::ImplItem) { } - fn check_struct_def<'a, 'tcx: 'a>(&mut self, _: &'a LateContext<'a, 'tcx>, - _: &'tcx hir::VariantData, _: ast::Name, _: &'tcx hir::Generics, _: ast::NodeId) { } - fn check_struct_def_post<'a, 'tcx: 'a>(&mut self, _: &'a LateContext<'a, 'tcx>, - _: &'tcx hir::VariantData, _: ast::Name, _: &'tcx hir::Generics, _: ast::NodeId) { } - fn check_struct_field<'a, 'tcx: 'a>(&mut self, - _: &'a LateContext<'a, 'tcx>, - _: &'tcx hir::StructField) { } - fn check_variant<'a, 'tcx: 'a>(&mut self, - _: &'a LateContext<'a, 'tcx>, - _: &'tcx hir::Variant, - _: &'tcx hir::Generics) { } - fn check_variant_post<'a, 'tcx: 'a>(&mut self, - _: &'a LateContext<'a, 'tcx>, - _: &'tcx hir::Variant, - _: &'tcx hir::Generics) { } - fn check_lifetime<'a, 'tcx: 'a>(&mut self, - _: &'a LateContext<'a, 'tcx>, - _: &'tcx hir::Lifetime) { } - fn check_lifetime_def<'a, 'tcx: 'a>(&mut self, - _: &'a LateContext<'a, 'tcx>, - _: &'tcx hir::LifetimeDef) { } - fn check_path<'a, 'tcx: 'a>(&mut self, - _: &'a LateContext<'a, 'tcx>, - _: &'tcx hir::Path, - _: ast::NodeId) { } - fn check_attribute<'a, 'tcx: 'a>(&mut self, - _: &'a LateContext<'a, 'tcx>, - _: &'tcx ast::Attribute) { } + fn check_crate(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Crate) { } + fn check_crate_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Crate) { } + fn check_mod(&mut self, + _: &LateContext<'a, 'tcx>, + _: &'tcx hir::Mod, + _: Span, + _: ast::NodeId) { } + fn check_mod_post(&mut self, + _: &LateContext<'a, 'tcx>, + _: &'tcx hir::Mod, + _: Span, + _: ast::NodeId) { } + fn check_foreign_item(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::ForeignItem) { } + fn check_foreign_item_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::ForeignItem) { } + fn check_item(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Item) { } + fn check_item_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Item) { } + fn check_local(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Local) { } + fn check_block(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Block) { } + fn check_block_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Block) { } + fn check_stmt(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Stmt) { } + fn check_arm(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Arm) { } + fn check_pat(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Pat) { } + fn check_decl(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Decl) { } + fn check_expr(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Expr) { } + fn check_expr_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Expr) { } + fn check_ty(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Ty) { } + fn check_generics(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Generics) { } + fn check_fn(&mut self, + _: &LateContext<'a, 'tcx>, + _: FnKind<'tcx>, + _: &'tcx hir::FnDecl, + _: &'tcx hir::Expr, + _: Span, + _: ast::NodeId) { } + fn check_fn_post(&mut self, + _: &LateContext<'a, 'tcx>, + _: FnKind<'tcx>, + _: &'tcx hir::FnDecl, + _: &'tcx hir::Expr, + _: Span, + _: ast::NodeId) { } + fn check_trait_item(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::TraitItem) { } + fn check_trait_item_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::TraitItem) { } + fn check_impl_item(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::ImplItem) { } + fn check_impl_item_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::ImplItem) { } + fn check_struct_def(&mut self, + _: &LateContext<'a, 'tcx>, + _: &'tcx hir::VariantData, + _: ast::Name, + _: &'tcx hir::Generics, + _: ast::NodeId) { } + fn check_struct_def_post(&mut self, + _: &LateContext<'a, 'tcx>, + _: &'tcx hir::VariantData, + _: ast::Name, + _: &'tcx hir::Generics, + _: ast::NodeId) { } + fn check_struct_field(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::StructField) { } + fn check_variant(&mut self, + _: &LateContext<'a, 'tcx>, + _: &'tcx hir::Variant, + _: &'tcx hir::Generics) { } + fn check_variant_post(&mut self, + _: &LateContext<'a, 'tcx>, + _: &'tcx hir::Variant, + _: &'tcx hir::Generics) { } + fn check_lifetime(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Lifetime) { } + fn check_lifetime_def(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::LifetimeDef) { } + fn check_path(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Path, _: ast::NodeId) { } + fn check_attribute(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx ast::Attribute) { } /// Called when entering a syntax node that can have lint attributes such /// as `#[allow(...)]`. Called with *all* the attributes of that node. - fn enter_lint_attrs<'a, 'tcx: 'a>(&mut self, - _: &'a LateContext<'a, 'tcx>, - _: &'tcx [ast::Attribute]) { } + fn enter_lint_attrs(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx [ast::Attribute]) { } /// Counterpart to `enter_lint_attrs`. - fn exit_lint_attrs<'a, 'tcx: 'a>(&mut self, - _: &'a LateContext<'a, 'tcx>, - _: &'tcx [ast::Attribute]) { } + fn exit_lint_attrs(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx [ast::Attribute]) { } } pub trait EarlyLintPass: LintPass { @@ -282,7 +261,7 @@ pub trait EarlyLintPass: LintPass { /// A lint pass boxed up as a trait object. pub type EarlyLintPassObject = Box; -pub type LateLintPassObject = Box; +pub type LateLintPassObject = Box LateLintPass<'a, 'tcx> + 'static>; /// Identifies a lint known to the compiler. #[derive(Clone, Copy, Debug)] diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs index f2bcd135063..4bdd78d55b1 100644 --- a/src/librustc_lint/bad_style.rs +++ b/src/librustc_lint/bad_style.rs @@ -99,8 +99,8 @@ impl LintPass for NonCamelCaseTypes { } } -impl LateLintPass for NonCamelCaseTypes { - fn check_item<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonCamelCaseTypes { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { let extern_repr_count = it.attrs .iter() .filter(|attr| { @@ -133,7 +133,7 @@ impl LateLintPass for NonCamelCaseTypes { } } - fn check_generics<'a, 'tcx: 'a>(&mut self, + fn check_generics(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Generics) { for gen in it.ty_params.iter() { @@ -228,8 +228,8 @@ impl LintPass for NonSnakeCase { } } -impl LateLintPass for NonSnakeCase { - fn check_crate<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, cr: &'tcx hir::Crate) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase { + fn check_crate(&mut self, cx: &LateContext<'a, 'tcx>, cr: &'tcx hir::Crate) { let attr_crate_name = cr.attrs .iter() .find(|at| at.check_name("crate_name")) @@ -241,7 +241,7 @@ impl LateLintPass for NonSnakeCase { } } - fn check_fn<'a, 'tcx: 'a>(&mut self, + fn check_fn(&mut self, cx: &LateContext<'a, 'tcx>, fk: FnKind, _: &'tcx hir::FnDecl, @@ -267,13 +267,13 @@ impl LateLintPass for NonSnakeCase { } } - fn check_item<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { if let hir::ItemMod(_) = it.node { self.check_snake_case(cx, "module", &it.name.as_str(), Some(it.span)); } } - fn check_trait_item<'a, 'tcx: 'a>(&mut self, + fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, trait_item: &'tcx hir::TraitItem) { if let hir::MethodTraitItem(_, None) = trait_item.node { @@ -284,7 +284,7 @@ impl LateLintPass for NonSnakeCase { } } - fn check_lifetime_def<'a, 'tcx: 'a>(&mut self, + fn check_lifetime_def(&mut self, cx: &LateContext<'a, 'tcx>, t: &'tcx hir::LifetimeDef) { self.check_snake_case(cx, @@ -293,7 +293,7 @@ impl LateLintPass for NonSnakeCase { Some(t.lifetime.span)); } - fn check_pat<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, p: &'tcx hir::Pat) { + fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, p: &'tcx hir::Pat) { // Exclude parameter names from foreign functions let parent_node = cx.tcx.map.get_parent_node(p.id); if let hir::map::NodeForeignItem(item) = cx.tcx.map.get(parent_node) { @@ -307,7 +307,7 @@ impl LateLintPass for NonSnakeCase { } } - fn check_struct_def<'a, 'tcx: 'a>(&mut self, + fn check_struct_def(&mut self, cx: &LateContext<'a, 'tcx>, s: &'tcx hir::VariantData, _: ast::Name, @@ -354,8 +354,8 @@ impl LintPass for NonUpperCaseGlobals { } } -impl LateLintPass for NonUpperCaseGlobals { - fn check_item<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonUpperCaseGlobals { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { match it.node { hir::ItemStatic(..) => { NonUpperCaseGlobals::check_upper_case(cx, "static variable", it.name, it.span); @@ -367,7 +367,7 @@ impl LateLintPass for NonUpperCaseGlobals { } } - fn check_trait_item<'a, 'tcx: 'a>(&mut self, + fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, ti: &'tcx hir::TraitItem) { match ti.node { @@ -378,7 +378,7 @@ impl LateLintPass for NonUpperCaseGlobals { } } - fn check_impl_item<'a, 'tcx: 'a>(&mut self, + fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, ii: &'tcx hir::ImplItem) { match ii.node { @@ -389,7 +389,7 @@ impl LateLintPass for NonUpperCaseGlobals { } } - fn check_pat<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, p: &'tcx hir::Pat) { + fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, p: &'tcx hir::Pat) { // Lint for constants that look like binding identifiers (#7526) if let PatKind::Path(hir::QPath::Resolved(None, ref path)) = p.node { if !path.global && path.segments.len() == 1 && path.segments[0].parameters.is_empty() { diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index f3cb4d8820a..ed6eaf0171d 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -69,8 +69,8 @@ impl LintPass for WhileTrue { } } -impl LateLintPass for WhileTrue { - fn check_expr<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for WhileTrue { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) { if let hir::ExprWhile(ref cond, ..) = e.node { if let hir::ExprLit(ref lit) = cond.node { if let ast::LitKind::Bool(true) = lit.node { @@ -109,8 +109,8 @@ impl LintPass for BoxPointers { } } -impl LateLintPass for BoxPointers { - fn check_item<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoxPointers { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { match it.node { hir::ItemFn(..) | hir::ItemTy(..) | @@ -137,7 +137,7 @@ impl LateLintPass for BoxPointers { } } - fn check_expr<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) { let ty = cx.tcx.tables().node_id_to_type(e.id); self.check_heap_type(cx, e.span, ty); } @@ -158,8 +158,8 @@ impl LintPass for NonShorthandFieldPatterns { } } -impl LateLintPass for NonShorthandFieldPatterns { - fn check_pat<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, pat: &'tcx hir::Pat) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonShorthandFieldPatterns { + fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, pat: &'tcx hir::Pat) { if let PatKind::Struct(_, ref field_pats, _) = pat.node { for fieldpat in field_pats { if fieldpat.node.is_shorthand { @@ -194,8 +194,8 @@ impl LintPass for UnsafeCode { } } -impl LateLintPass for UnsafeCode { - fn check_expr<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnsafeCode { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) { if let hir::ExprBlock(ref blk) = e.node { // Don't warn about generated blocks, that'll just pollute the output. if blk.rules == hir::UnsafeBlock(hir::UserProvided) { @@ -204,7 +204,7 @@ impl LateLintPass for UnsafeCode { } } - fn check_item<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { match it.node { hir::ItemTrait(hir::Unsafety::Unsafe, ..) => { cx.span_lint(UNSAFE_CODE, it.span, "declaration of an `unsafe` trait") @@ -218,7 +218,7 @@ impl LateLintPass for UnsafeCode { } } - fn check_fn<'a, 'tcx: 'a>(&mut self, + fn check_fn(&mut self, cx: &LateContext<'a, 'tcx>, fk: FnKind<'tcx>, _: &'tcx hir::FnDecl, @@ -240,7 +240,7 @@ impl LateLintPass for UnsafeCode { } } - fn check_trait_item<'a, 'tcx: 'a>(&mut self, + fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, trait_item: &'tcx hir::TraitItem) { if let hir::MethodTraitItem(ref sig, None) = trait_item.node { @@ -329,10 +329,8 @@ impl LintPass for MissingDoc { } } -impl LateLintPass for MissingDoc { - fn enter_lint_attrs<'a, 'tcx: 'a>(&mut self, - _: &LateContext<'a, 'tcx>, - attrs: &'tcx [ast::Attribute]) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { + fn enter_lint_attrs(&mut self, _: &LateContext<'a, 'tcx>, attrs: &'tcx [ast::Attribute]) { let doc_hidden = self.doc_hidden() || attrs.iter().any(|attr| { attr.check_name("doc") && @@ -344,13 +342,11 @@ impl LateLintPass for MissingDoc { self.doc_hidden_stack.push(doc_hidden); } - fn exit_lint_attrs<'a, 'tcx: 'a>(&mut self, - _: &LateContext<'a, 'tcx>, - _attrs: &'tcx [ast::Attribute]) { + fn exit_lint_attrs(&mut self, _: &LateContext<'a, 'tcx>, _attrs: &'tcx [ast::Attribute]) { self.doc_hidden_stack.pop().expect("empty doc_hidden_stack"); } - fn check_struct_def<'a, 'tcx: 'a>(&mut self, + fn check_struct_def(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::VariantData, _: ast::Name, @@ -359,7 +355,7 @@ impl LateLintPass for MissingDoc { self.struct_def_stack.push(item_id); } - fn check_struct_def_post<'a, 'tcx: 'a>(&mut self, + fn check_struct_def_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::VariantData, _: ast::Name, @@ -369,11 +365,11 @@ impl LateLintPass for MissingDoc { assert!(popped == item_id); } - fn check_crate<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, krate: &'tcx hir::Crate) { + fn check_crate(&mut self, cx: &LateContext<'a, 'tcx>, krate: &'tcx hir::Crate) { self.check_missing_docs_attrs(cx, None, &krate.attrs, krate.span, "crate"); } - fn check_item<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { let desc = match it.node { hir::ItemFn(..) => "a function", hir::ItemMod(..) => "a module", @@ -418,7 +414,7 @@ impl LateLintPass for MissingDoc { self.check_missing_docs_attrs(cx, Some(it.id), &it.attrs, it.span, desc); } - fn check_trait_item<'a, 'tcx: 'a>(&mut self, + fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, trait_item: &'tcx hir::TraitItem) { if self.private_traits.contains(&trait_item.id) { @@ -438,7 +434,7 @@ impl LateLintPass for MissingDoc { desc); } - fn check_impl_item<'a, 'tcx: 'a>(&mut self, + fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, impl_item: &'tcx hir::ImplItem) { // If the method is an impl for a trait, don't doc. @@ -458,7 +454,7 @@ impl LateLintPass for MissingDoc { desc); } - fn check_struct_field<'a, 'tcx: 'a>(&mut self, + fn check_struct_field(&mut self, cx: &LateContext<'a, 'tcx>, sf: &'tcx hir::StructField) { if !sf.is_positional() { @@ -475,7 +471,7 @@ impl LateLintPass for MissingDoc { } } - fn check_variant<'a, 'tcx: 'a>(&mut self, + fn check_variant(&mut self, cx: &LateContext<'a, 'tcx>, v: &'tcx hir::Variant, _: &'tcx hir::Generics) { @@ -488,7 +484,7 @@ impl LateLintPass for MissingDoc { self.in_variant = true; } - fn check_variant_post<'a, 'tcx: 'a>(&mut self, + fn check_variant_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Variant, _: &'tcx hir::Generics) { @@ -512,8 +508,8 @@ impl LintPass for MissingCopyImplementations { } } -impl LateLintPass for MissingCopyImplementations { - fn check_item<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingCopyImplementations { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) { if !cx.access_levels.is_reachable(item.id) { return; } @@ -581,8 +577,8 @@ impl LintPass for MissingDebugImplementations { } } -impl LateLintPass for MissingDebugImplementations { - fn check_item<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDebugImplementations { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) { if !cx.access_levels.is_reachable(item.id) { return; } @@ -687,8 +683,8 @@ impl LintPass for UnconditionalRecursion { } } -impl LateLintPass for UnconditionalRecursion { - fn check_fn<'a, 'tcx: 'a>(&mut self, +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { + fn check_fn(&mut self, cx: &LateContext<'a, 'tcx>, fn_kind: FnKind<'tcx>, _: &'tcx hir::FnDecl, @@ -950,8 +946,8 @@ impl LintPass for PluginAsLibrary { } } -impl LateLintPass for PluginAsLibrary { - fn check_item<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PluginAsLibrary { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { if cx.sess().plugin_registrar_fn.get().is_some() { // We're compiling a plugin; it's fine to link other plugins. return; @@ -1016,8 +1012,8 @@ impl LintPass for InvalidNoMangleItems { } } -impl LateLintPass for InvalidNoMangleItems { - fn check_item<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidNoMangleItems { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { match it.node { hir::ItemFn(.., ref generics, _) => { if attr::contains_name(&it.attrs, "no_mangle") { @@ -1070,8 +1066,8 @@ impl LintPass for MutableTransmutes { } } -impl LateLintPass for MutableTransmutes { - fn check_expr<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutableTransmutes { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) { use syntax::abi::Abi::RustIntrinsic; let msg = "mutating transmuted &mut T from &T may cause undefined behavior, \ @@ -1138,8 +1134,8 @@ impl LintPass for UnstableFeatures { } } -impl LateLintPass for UnstableFeatures { - fn check_attribute<'a, 'tcx: 'a>(&mut self, +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnstableFeatures { + fn check_attribute(&mut self, ctx: &LateContext<'a, 'tcx>, attr: &'tcx ast::Attribute) { if attr.meta().check_name("feature") { @@ -1167,8 +1163,8 @@ impl LintPass for UnionsWithDropFields { } } -impl LateLintPass for UnionsWithDropFields { - fn check_item<'a, 'tcx: 'a>(&mut self, ctx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnionsWithDropFields { + fn check_item(&mut self, ctx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) { if let hir::ItemUnion(ref vdata, _) = item.node { let param_env = &ty::ParameterEnvironment::for_item(ctx.tcx, item.id); for field in vdata.fields() { diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 48c209e1665..98b87a141ea 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -103,8 +103,8 @@ impl LintPass for TypeLimits { } } -impl LateLintPass for TypeLimits { - fn check_expr<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) { match e.node { hir::ExprUnary(hir::UnNeg, ref expr) => { if let hir::ExprLit(ref lit) = expr.node { @@ -706,8 +706,8 @@ impl LintPass for ImproperCTypes { } } -impl LateLintPass for ImproperCTypes { - fn check_item<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypes { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { let mut vis = ImproperCTypesVisitor { cx: cx }; if let hir::ItemForeignMod(ref nmod) = it.node { if nmod.abi != Abi::RustIntrinsic && nmod.abi != Abi::PlatformIntrinsic { @@ -734,8 +734,8 @@ impl LintPass for VariantSizeDifferences { } } -impl LateLintPass for VariantSizeDifferences { - fn check_item<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { if let hir::ItemEnum(ref enum_definition, ref gens) = it.node { if gens.ty_params.is_empty() { // sizes only make sense for non-generic types diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 23fd7a86640..89f8f464ee7 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -77,8 +77,8 @@ impl LintPass for UnusedMut { } } -impl LateLintPass for UnusedMut { - fn check_expr<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedMut { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) { if let hir::ExprMatch(_, ref arms, _) = e.node { for a in arms { self.check_unused_mut_pat(cx, &a.pats) @@ -86,7 +86,7 @@ impl LateLintPass for UnusedMut { } } - fn check_stmt<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, s: &'tcx hir::Stmt) { + fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, s: &'tcx hir::Stmt) { if let hir::StmtDecl(ref d, _) = s.node { if let hir::DeclLocal(ref l) = d.node { self.check_unused_mut_pat(cx, slice::ref_slice(&l.pat)); @@ -94,7 +94,7 @@ impl LateLintPass for UnusedMut { } } - fn check_fn<'a, 'tcx: 'a>(&mut self, + fn check_fn(&mut self, cx: &LateContext<'a, 'tcx>, _: FnKind<'tcx>, decl: &'tcx hir::FnDecl, @@ -128,8 +128,8 @@ impl LintPass for UnusedResults { } } -impl LateLintPass for UnusedResults { - fn check_stmt<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, s: &'tcx hir::Stmt) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { + fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, s: &'tcx hir::Stmt) { let expr = match s.node { hir::StmtSemi(ref expr, _) => &**expr, _ => return, @@ -187,8 +187,8 @@ impl LintPass for UnusedUnsafe { } } -impl LateLintPass for UnusedUnsafe { - fn check_expr<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedUnsafe { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) { if let hir::ExprBlock(ref blk) = e.node { // Don't warn about generated blocks, that'll just pollute the output. if blk.rules == hir::UnsafeBlock(hir::UserProvided) && @@ -214,8 +214,8 @@ impl LintPass for PathStatements { } } -impl LateLintPass for PathStatements { - fn check_stmt<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, s: &'tcx hir::Stmt) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PathStatements { + fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, s: &'tcx hir::Stmt) { if let hir::StmtSemi(ref expr, _) = s.node { if let hir::ExprPath(_) = expr.node { cx.span_lint(PATH_STATEMENTS, s.span, "path statement with no effect"); @@ -239,8 +239,8 @@ impl LintPass for UnusedAttributes { } } -impl LateLintPass for UnusedAttributes { - fn check_attribute<'a, 'tcx: 'a>(&mut self, +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes { + fn check_attribute(&mut self, cx: &LateContext<'a, 'tcx>, attr: &'tcx ast::Attribute) { debug!("checking attribute: {:?}", attr); @@ -435,8 +435,8 @@ impl LintPass for UnusedAllocation { } } -impl LateLintPass for UnusedAllocation { - fn check_expr<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAllocation { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) { match e.node { hir::ExprBox(_) => {} _ => return, diff --git a/src/test/compile-fail-fulldeps/auxiliary/lint_for_crate.rs b/src/test/compile-fail-fulldeps/auxiliary/lint_for_crate.rs index b255cf11db0..4011ce86414 100644 --- a/src/test/compile-fail-fulldeps/auxiliary/lint_for_crate.rs +++ b/src/test/compile-fail-fulldeps/auxiliary/lint_for_crate.rs @@ -32,8 +32,8 @@ impl LintPass for Pass { } } -impl LateLintPass for Pass { - fn check_crate<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, krate: &'tcx hir::Crate) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { + fn check_crate(&mut self, cx: &LateContext<'a, 'tcx>, krate: &'tcx hir::Crate) { if !attr::contains_name(&krate.attrs, "crate_okay") { cx.span_lint(CRATE_NOT_OKAY, krate.span, "crate is not marked with #![crate_okay]"); @@ -43,5 +43,5 @@ impl LateLintPass for Pass { #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { - reg.register_late_lint_pass(box Pass as LateLintPassObject); + reg.register_late_lint_pass(box Pass); } diff --git a/src/test/compile-fail-fulldeps/auxiliary/lint_group_plugin_test.rs b/src/test/compile-fail-fulldeps/auxiliary/lint_group_plugin_test.rs index ec3401e7b21..cc17a011e55 100644 --- a/src/test/compile-fail-fulldeps/auxiliary/lint_group_plugin_test.rs +++ b/src/test/compile-fail-fulldeps/auxiliary/lint_group_plugin_test.rs @@ -34,8 +34,8 @@ impl LintPass for Pass { } } -impl LateLintPass for Pass { - fn check_item<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { match &*it.name.as_str() { "lintme" => cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'"), "pleaselintme" => cx.span_lint(PLEASE_LINT, it.span, "item is named 'pleaselintme'"), @@ -46,6 +46,6 @@ impl LateLintPass for Pass { #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { - reg.register_late_lint_pass(box Pass as LateLintPassObject); + reg.register_late_lint_pass(box Pass); reg.register_lint_group("lint_me", vec![TEST_LINT, PLEASE_LINT]); } diff --git a/src/test/run-pass-fulldeps/auxiliary/lint_for_crate.rs b/src/test/run-pass-fulldeps/auxiliary/lint_for_crate.rs index b255cf11db0..4011ce86414 100644 --- a/src/test/run-pass-fulldeps/auxiliary/lint_for_crate.rs +++ b/src/test/run-pass-fulldeps/auxiliary/lint_for_crate.rs @@ -32,8 +32,8 @@ impl LintPass for Pass { } } -impl LateLintPass for Pass { - fn check_crate<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, krate: &'tcx hir::Crate) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { + fn check_crate(&mut self, cx: &LateContext<'a, 'tcx>, krate: &'tcx hir::Crate) { if !attr::contains_name(&krate.attrs, "crate_okay") { cx.span_lint(CRATE_NOT_OKAY, krate.span, "crate is not marked with #![crate_okay]"); @@ -43,5 +43,5 @@ impl LateLintPass for Pass { #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { - reg.register_late_lint_pass(box Pass as LateLintPassObject); + reg.register_late_lint_pass(box Pass); } diff --git a/src/test/run-pass-fulldeps/auxiliary/lint_group_plugin_test.rs b/src/test/run-pass-fulldeps/auxiliary/lint_group_plugin_test.rs index ec3401e7b21..cc17a011e55 100644 --- a/src/test/run-pass-fulldeps/auxiliary/lint_group_plugin_test.rs +++ b/src/test/run-pass-fulldeps/auxiliary/lint_group_plugin_test.rs @@ -34,8 +34,8 @@ impl LintPass for Pass { } } -impl LateLintPass for Pass { - fn check_item<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { match &*it.name.as_str() { "lintme" => cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'"), "pleaselintme" => cx.span_lint(PLEASE_LINT, it.span, "item is named 'pleaselintme'"), @@ -46,6 +46,6 @@ impl LateLintPass for Pass { #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { - reg.register_late_lint_pass(box Pass as LateLintPassObject); + reg.register_late_lint_pass(box Pass); reg.register_lint_group("lint_me", vec![TEST_LINT, PLEASE_LINT]); } diff --git a/src/test/run-pass-fulldeps/issue-37290/auxiliary/lint.rs b/src/test/run-pass-fulldeps/issue-37290/auxiliary/lint.rs index 947d2dd22db..77996b71a46 100644 --- a/src/test/run-pass-fulldeps/issue-37290/auxiliary/lint.rs +++ b/src/test/run-pass-fulldeps/issue-37290/auxiliary/lint.rs @@ -39,8 +39,8 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(REGION_HIERARCHY) } } -impl LateLintPass for Pass { - fn check_fn<'a, 'tcx: 'a>(&mut self, cx: &LateContext<'a, 'tcx>, +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { + fn check_fn(&mut self, cx: &LateContext<'a, 'tcx>, fk: FnKind<'tcx>, _: &'tcx hir::FnDecl, expr: &'tcx hir::Expr, span: Span, node: ast::NodeId) { From 87a9ae224d946b44f325f42263bf8190584ba21d Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 7 Dec 2016 13:22:21 +0100 Subject: [PATCH 260/293] add a -Z flag to guarantee that MIR is generated for all functions --- src/librustc/session/config.rs | 2 ++ src/librustc_metadata/encoder.rs | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 47f0de3ce57..17b572e7f9e 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -928,6 +928,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "print some statistics about AST and HIR"), mir_stats: bool = (false, parse_bool, [UNTRACKED], "print some statistics about MIR"), + always_encode_mir: bool = (false, parse_bool, [TRACKED], + "encode MIR of all functions into the crate metadata"), } pub fn default_lib_output() -> CrateType { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 01cb0f823e8..d9bcdb36026 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -577,7 +577,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let types = generics.parent_types as usize + generics.types.len(); let needs_inline = types > 0 || attr::requests_inline(&ast_item.attrs); let is_const_fn = sig.constness == hir::Constness::Const; - (is_const_fn, needs_inline || is_const_fn) + let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir; + (is_const_fn, needs_inline || is_const_fn || always_encode_mir) } else { (false, false) }; @@ -842,7 +843,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { hir::ItemFn(_, _, constness, _, ref generics, _) => { let tps_len = generics.ty_params.len(); let needs_inline = tps_len > 0 || attr::requests_inline(&item.attrs); - if needs_inline || constness == hir::Constness::Const { + let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir; + if needs_inline || constness == hir::Constness::Const || always_encode_mir { self.encode_mir(def_id) } else { None From 0f7a18b85d89737a3aab62982ac754ec25ada503 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 7 Dec 2016 13:56:36 +0100 Subject: [PATCH 261/293] remove useless lifetimes on LateLintPass impl methods --- src/librustc_lint/bad_style.rs | 54 ++++----- src/librustc_lint/builtin.rs | 108 ++++++++---------- src/librustc_lint/types.rs | 6 +- src/librustc_lint/unused.rs | 28 +++-- .../auxiliary/lint_for_crate.rs | 2 +- .../auxiliary/lint_group_plugin_test.rs | 2 +- .../auxiliary/lint_for_crate.rs | 2 +- .../auxiliary/lint_group_plugin_test.rs | 2 +- .../issue-37290/auxiliary/lint.rs | 4 +- 9 files changed, 90 insertions(+), 118 deletions(-) diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs index 4bdd78d55b1..2aa74407afc 100644 --- a/src/librustc_lint/bad_style.rs +++ b/src/librustc_lint/bad_style.rs @@ -100,7 +100,7 @@ impl LintPass for NonCamelCaseTypes { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonCamelCaseTypes { - fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { + fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { let extern_repr_count = it.attrs .iter() .filter(|attr| { @@ -133,9 +133,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonCamelCaseTypes { } } - fn check_generics(&mut self, - cx: &LateContext<'a, 'tcx>, - it: &'tcx hir::Generics) { + fn check_generics(&mut self, cx: &LateContext, it: &hir::Generics) { for gen in it.ty_params.iter() { self.check_case(cx, "type parameter", gen.name, gen.span); } @@ -229,7 +227,7 @@ impl LintPass for NonSnakeCase { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase { - fn check_crate(&mut self, cx: &LateContext<'a, 'tcx>, cr: &'tcx hir::Crate) { + fn check_crate(&mut self, cx: &LateContext, cr: &hir::Crate) { let attr_crate_name = cr.attrs .iter() .find(|at| at.check_name("crate_name")) @@ -242,12 +240,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase { } fn check_fn(&mut self, - cx: &LateContext<'a, 'tcx>, - fk: FnKind, - _: &'tcx hir::FnDecl, - _: &'tcx hir::Expr, - span: Span, - id: ast::NodeId) { + cx: &LateContext, + fk: FnKind, + _: &hir::FnDecl, + _: &hir::Expr, + span: Span, + id: ast::NodeId) { match fk { FnKind::Method(name, ..) => { match method_context(cx, id, span) { @@ -267,15 +265,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase { } } - fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { + fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { if let hir::ItemMod(_) = it.node { self.check_snake_case(cx, "module", &it.name.as_str(), Some(it.span)); } } - fn check_trait_item(&mut self, - cx: &LateContext<'a, 'tcx>, - trait_item: &'tcx hir::TraitItem) { + fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) { if let hir::MethodTraitItem(_, None) = trait_item.node { self.check_snake_case(cx, "trait method", @@ -284,16 +280,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase { } } - fn check_lifetime_def(&mut self, - cx: &LateContext<'a, 'tcx>, - t: &'tcx hir::LifetimeDef) { + fn check_lifetime_def(&mut self, cx: &LateContext, t: &hir::LifetimeDef) { self.check_snake_case(cx, "lifetime", &t.lifetime.name.as_str(), Some(t.lifetime.span)); } - fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, p: &'tcx hir::Pat) { + fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) { // Exclude parameter names from foreign functions let parent_node = cx.tcx.map.get_parent_node(p.id); if let hir::map::NodeForeignItem(item) = cx.tcx.map.get(parent_node) { @@ -308,11 +302,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase { } fn check_struct_def(&mut self, - cx: &LateContext<'a, 'tcx>, - s: &'tcx hir::VariantData, - _: ast::Name, - _: &'tcx hir::Generics, - _: ast::NodeId) { + cx: &LateContext, + s: &hir::VariantData, + _: ast::Name, + _: &hir::Generics, + _: ast::NodeId) { for sf in s.fields() { self.check_snake_case(cx, "structure field", &sf.name.as_str(), Some(sf.span)); } @@ -355,7 +349,7 @@ impl LintPass for NonUpperCaseGlobals { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonUpperCaseGlobals { - fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { + fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { match it.node { hir::ItemStatic(..) => { NonUpperCaseGlobals::check_upper_case(cx, "static variable", it.name, it.span); @@ -367,9 +361,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonUpperCaseGlobals { } } - fn check_trait_item(&mut self, - cx: &LateContext<'a, 'tcx>, - ti: &'tcx hir::TraitItem) { + fn check_trait_item(&mut self, cx: &LateContext, ti: &hir::TraitItem) { match ti.node { hir::ConstTraitItem(..) => { NonUpperCaseGlobals::check_upper_case(cx, "associated constant", ti.name, ti.span); @@ -378,9 +370,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonUpperCaseGlobals { } } - fn check_impl_item(&mut self, - cx: &LateContext<'a, 'tcx>, - ii: &'tcx hir::ImplItem) { + fn check_impl_item(&mut self, cx: &LateContext, ii: &hir::ImplItem) { match ii.node { hir::ImplItemKind::Const(..) => { NonUpperCaseGlobals::check_upper_case(cx, "associated constant", ii.name, ii.span); @@ -389,7 +379,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonUpperCaseGlobals { } } - fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, p: &'tcx hir::Pat) { + fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) { // Lint for constants that look like binding identifiers (#7526) if let PatKind::Path(hir::QPath::Resolved(None, ref path)) = p.node { if !path.global && path.segments.len() == 1 && path.segments[0].parameters.is_empty() { diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index ed6eaf0171d..744b08a2a89 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -70,7 +70,7 @@ impl LintPass for WhileTrue { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for WhileTrue { - fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) { + fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { if let hir::ExprWhile(ref cond, ..) = e.node { if let hir::ExprLit(ref lit) = cond.node { if let ast::LitKind::Bool(true) = lit.node { @@ -93,7 +93,7 @@ declare_lint! { pub struct BoxPointers; impl BoxPointers { - fn check_heap_type<'a, 'tcx>(&self, cx: &LateContext<'a, 'tcx>, span: Span, ty: Ty<'tcx>) { + fn check_heap_type<'a, 'tcx>(&self, cx: &LateContext, span: Span, ty: Ty) { for leaf_ty in ty.walk() { if let ty::TyBox(_) = leaf_ty.sty { let m = format!("type uses owned (Box type) pointers: {}", ty); @@ -110,7 +110,7 @@ impl LintPass for BoxPointers { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoxPointers { - fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { + fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { match it.node { hir::ItemFn(..) | hir::ItemTy(..) | @@ -137,7 +137,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoxPointers { } } - fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) { + fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { let ty = cx.tcx.tables().node_id_to_type(e.id); self.check_heap_type(cx, e.span, ty); } @@ -159,7 +159,7 @@ impl LintPass for NonShorthandFieldPatterns { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonShorthandFieldPatterns { - fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, pat: &'tcx hir::Pat) { + fn check_pat(&mut self, cx: &LateContext, pat: &hir::Pat) { if let PatKind::Struct(_, ref field_pats, _) = pat.node { for fieldpat in field_pats { if fieldpat.node.is_shorthand { @@ -195,7 +195,7 @@ impl LintPass for UnsafeCode { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnsafeCode { - fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) { + fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { if let hir::ExprBlock(ref blk) = e.node { // Don't warn about generated blocks, that'll just pollute the output. if blk.rules == hir::UnsafeBlock(hir::UserProvided) { @@ -204,7 +204,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnsafeCode { } } - fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { + fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { match it.node { hir::ItemTrait(hir::Unsafety::Unsafe, ..) => { cx.span_lint(UNSAFE_CODE, it.span, "declaration of an `unsafe` trait") @@ -219,12 +219,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnsafeCode { } fn check_fn(&mut self, - cx: &LateContext<'a, 'tcx>, - fk: FnKind<'tcx>, - _: &'tcx hir::FnDecl, - _: &'tcx hir::Expr, - span: Span, - _: ast::NodeId) { + cx: &LateContext, + fk: FnKind<'tcx>, + _: &hir::FnDecl, + _: &hir::Expr, + span: Span, + _: ast::NodeId) { match fk { FnKind::ItemFn(_, _, hir::Unsafety::Unsafe, ..) => { cx.span_lint(UNSAFE_CODE, span, "declaration of an `unsafe` function") @@ -240,9 +240,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnsafeCode { } } - fn check_trait_item(&mut self, - cx: &LateContext<'a, 'tcx>, - trait_item: &'tcx hir::TraitItem) { + fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) { if let hir::MethodTraitItem(ref sig, None) = trait_item.node { if sig.unsafety == hir::Unsafety::Unsafe { cx.span_lint(UNSAFE_CODE, @@ -330,7 +328,7 @@ impl LintPass for MissingDoc { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { - fn enter_lint_attrs(&mut self, _: &LateContext<'a, 'tcx>, attrs: &'tcx [ast::Attribute]) { + fn enter_lint_attrs(&mut self, _: &LateContext, attrs: &[ast::Attribute]) { let doc_hidden = self.doc_hidden() || attrs.iter().any(|attr| { attr.check_name("doc") && @@ -342,34 +340,34 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { self.doc_hidden_stack.push(doc_hidden); } - fn exit_lint_attrs(&mut self, _: &LateContext<'a, 'tcx>, _attrs: &'tcx [ast::Attribute]) { + fn exit_lint_attrs(&mut self, _: &LateContext, _attrs: &[ast::Attribute]) { self.doc_hidden_stack.pop().expect("empty doc_hidden_stack"); } fn check_struct_def(&mut self, - _: &LateContext<'a, 'tcx>, - _: &'tcx hir::VariantData, - _: ast::Name, - _: &'tcx hir::Generics, - item_id: ast::NodeId) { + _: &LateContext, + _: &hir::VariantData, + _: ast::Name, + _: &hir::Generics, + item_id: ast::NodeId) { self.struct_def_stack.push(item_id); } fn check_struct_def_post(&mut self, - _: &LateContext<'a, 'tcx>, - _: &'tcx hir::VariantData, - _: ast::Name, - _: &'tcx hir::Generics, - item_id: ast::NodeId) { + _: &LateContext, + _: &hir::VariantData, + _: ast::Name, + _: &hir::Generics, + item_id: ast::NodeId) { let popped = self.struct_def_stack.pop().expect("empty struct_def_stack"); assert!(popped == item_id); } - fn check_crate(&mut self, cx: &LateContext<'a, 'tcx>, krate: &'tcx hir::Crate) { + fn check_crate(&mut self, cx: &LateContext, krate: &hir::Crate) { self.check_missing_docs_attrs(cx, None, &krate.attrs, krate.span, "crate"); } - fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { + fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { let desc = match it.node { hir::ItemFn(..) => "a function", hir::ItemMod(..) => "a module", @@ -414,9 +412,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { self.check_missing_docs_attrs(cx, Some(it.id), &it.attrs, it.span, desc); } - fn check_trait_item(&mut self, - cx: &LateContext<'a, 'tcx>, - trait_item: &'tcx hir::TraitItem) { + fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) { if self.private_traits.contains(&trait_item.id) { return; } @@ -434,9 +430,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { desc); } - fn check_impl_item(&mut self, - cx: &LateContext<'a, 'tcx>, - impl_item: &'tcx hir::ImplItem) { + fn check_impl_item(&mut self, cx: &LateContext, impl_item: &hir::ImplItem) { // If the method is an impl for a trait, don't doc. if method_context(cx, impl_item.id, impl_item.span) == MethodLateContext::TraitImpl { return; @@ -454,9 +448,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { desc); } - fn check_struct_field(&mut self, - cx: &LateContext<'a, 'tcx>, - sf: &'tcx hir::StructField) { + fn check_struct_field(&mut self, cx: &LateContext, sf: &hir::StructField) { if !sf.is_positional() { if sf.vis == hir::Public || self.in_variant { let cur_struct_def = *self.struct_def_stack @@ -471,10 +463,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { } } - fn check_variant(&mut self, - cx: &LateContext<'a, 'tcx>, - v: &'tcx hir::Variant, - _: &'tcx hir::Generics) { + fn check_variant(&mut self, cx: &LateContext, v: &hir::Variant, _: &hir::Generics) { self.check_missing_docs_attrs(cx, Some(v.node.data.id()), &v.node.attrs, @@ -484,10 +473,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { self.in_variant = true; } - fn check_variant_post(&mut self, - _: &LateContext<'a, 'tcx>, - _: &'tcx hir::Variant, - _: &'tcx hir::Generics) { + fn check_variant_post(&mut self, _: &LateContext, _: &hir::Variant, _: &hir::Generics) { assert!(self.in_variant); self.in_variant = false; } @@ -509,7 +495,7 @@ impl LintPass for MissingCopyImplementations { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingCopyImplementations { - fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) { + fn check_item(&mut self, cx: &LateContext, item: &hir::Item) { if !cx.access_levels.is_reachable(item.id) { return; } @@ -578,7 +564,7 @@ impl LintPass for MissingDebugImplementations { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDebugImplementations { - fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) { + fn check_item(&mut self, cx: &LateContext, item: &hir::Item) { if !cx.access_levels.is_reachable(item.id) { return; } @@ -685,12 +671,12 @@ impl LintPass for UnconditionalRecursion { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { fn check_fn(&mut self, - cx: &LateContext<'a, 'tcx>, - fn_kind: FnKind<'tcx>, - _: &'tcx hir::FnDecl, - blk: &'tcx hir::Expr, - sp: Span, - id: ast::NodeId) { + cx: &LateContext, + fn_kind: FnKind, + _: &hir::FnDecl, + blk: &hir::Expr, + sp: Span, + id: ast::NodeId) { let method = match fn_kind { FnKind::ItemFn(..) => None, FnKind::Method(..) => { @@ -947,7 +933,7 @@ impl LintPass for PluginAsLibrary { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PluginAsLibrary { - fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { + fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { if cx.sess().plugin_registrar_fn.get().is_some() { // We're compiling a plugin; it's fine to link other plugins. return; @@ -1013,7 +999,7 @@ impl LintPass for InvalidNoMangleItems { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidNoMangleItems { - fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { + fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { match it.node { hir::ItemFn(.., ref generics, _) => { if attr::contains_name(&it.attrs, "no_mangle") { @@ -1067,7 +1053,7 @@ impl LintPass for MutableTransmutes { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutableTransmutes { - fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) { + fn check_expr(&mut self, cx: &LateContext, expr: &hir::Expr) { use syntax::abi::Abi::RustIntrinsic; let msg = "mutating transmuted &mut T from &T may cause undefined behavior, \ @@ -1135,9 +1121,7 @@ impl LintPass for UnstableFeatures { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnstableFeatures { - fn check_attribute(&mut self, - ctx: &LateContext<'a, 'tcx>, - attr: &'tcx ast::Attribute) { + fn check_attribute(&mut self, ctx: &LateContext, attr: &ast::Attribute) { if attr.meta().check_name("feature") { if let Some(items) = attr.meta().meta_item_list() { for item in items { @@ -1164,7 +1148,7 @@ impl LintPass for UnionsWithDropFields { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnionsWithDropFields { - fn check_item(&mut self, ctx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) { + fn check_item(&mut self, ctx: &LateContext, item: &hir::Item) { if let hir::ItemUnion(ref vdata, _) = item.node { let param_env = &ty::ParameterEnvironment::for_item(ctx.tcx, item.id); for field in vdata.fields() { diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 98b87a141ea..8470f063f47 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -104,7 +104,7 @@ impl LintPass for TypeLimits { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { - fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) { + fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { match e.node { hir::ExprUnary(hir::UnNeg, ref expr) => { if let hir::ExprLit(ref lit) = expr.node { @@ -707,7 +707,7 @@ impl LintPass for ImproperCTypes { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypes { - fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { + fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { let mut vis = ImproperCTypesVisitor { cx: cx }; if let hir::ItemForeignMod(ref nmod) = it.node { if nmod.abi != Abi::RustIntrinsic && nmod.abi != Abi::PlatformIntrinsic { @@ -735,7 +735,7 @@ impl LintPass for VariantSizeDifferences { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences { - fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { + fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { if let hir::ItemEnum(ref enum_definition, ref gens) = it.node { if gens.ty_params.is_empty() { // sizes only make sense for non-generic types diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 89f8f464ee7..429bfb8e3d6 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -78,7 +78,7 @@ impl LintPass for UnusedMut { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedMut { - fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) { + fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { if let hir::ExprMatch(_, ref arms, _) = e.node { for a in arms { self.check_unused_mut_pat(cx, &a.pats) @@ -86,7 +86,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedMut { } } - fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, s: &'tcx hir::Stmt) { + fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) { if let hir::StmtDecl(ref d, _) = s.node { if let hir::DeclLocal(ref l) = d.node { self.check_unused_mut_pat(cx, slice::ref_slice(&l.pat)); @@ -95,12 +95,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedMut { } fn check_fn(&mut self, - cx: &LateContext<'a, 'tcx>, - _: FnKind<'tcx>, - decl: &'tcx hir::FnDecl, - _: &'tcx hir::Expr, - _: Span, - _: ast::NodeId) { + cx: &LateContext, + _: FnKind, + decl: &hir::FnDecl, + _: &hir::Expr, + _: Span, + _: ast::NodeId) { for a in &decl.inputs { self.check_unused_mut_pat(cx, slice::ref_slice(&a.pat)); } @@ -129,7 +129,7 @@ impl LintPass for UnusedResults { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { - fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, s: &'tcx hir::Stmt) { + fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) { let expr = match s.node { hir::StmtSemi(ref expr, _) => &**expr, _ => return, @@ -188,7 +188,7 @@ impl LintPass for UnusedUnsafe { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedUnsafe { - fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) { + fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { if let hir::ExprBlock(ref blk) = e.node { // Don't warn about generated blocks, that'll just pollute the output. if blk.rules == hir::UnsafeBlock(hir::UserProvided) && @@ -215,7 +215,7 @@ impl LintPass for PathStatements { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PathStatements { - fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, s: &'tcx hir::Stmt) { + fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) { if let hir::StmtSemi(ref expr, _) = s.node { if let hir::ExprPath(_) = expr.node { cx.span_lint(PATH_STATEMENTS, s.span, "path statement with no effect"); @@ -240,9 +240,7 @@ impl LintPass for UnusedAttributes { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes { - fn check_attribute(&mut self, - cx: &LateContext<'a, 'tcx>, - attr: &'tcx ast::Attribute) { + fn check_attribute(&mut self, cx: &LateContext, attr: &ast::Attribute) { debug!("checking attribute: {:?}", attr); // Note that check_name() marks the attribute as used if it matches. @@ -436,7 +434,7 @@ impl LintPass for UnusedAllocation { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAllocation { - fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) { + fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { match e.node { hir::ExprBox(_) => {} _ => return, diff --git a/src/test/compile-fail-fulldeps/auxiliary/lint_for_crate.rs b/src/test/compile-fail-fulldeps/auxiliary/lint_for_crate.rs index 4011ce86414..fc53031e7f2 100644 --- a/src/test/compile-fail-fulldeps/auxiliary/lint_for_crate.rs +++ b/src/test/compile-fail-fulldeps/auxiliary/lint_for_crate.rs @@ -33,7 +33,7 @@ impl LintPass for Pass { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { - fn check_crate(&mut self, cx: &LateContext<'a, 'tcx>, krate: &'tcx hir::Crate) { + fn check_crate(&mut self, cx: &LateContext, krate: &hir::Crate) { if !attr::contains_name(&krate.attrs, "crate_okay") { cx.span_lint(CRATE_NOT_OKAY, krate.span, "crate is not marked with #![crate_okay]"); diff --git a/src/test/compile-fail-fulldeps/auxiliary/lint_group_plugin_test.rs b/src/test/compile-fail-fulldeps/auxiliary/lint_group_plugin_test.rs index cc17a011e55..490aa0d4693 100644 --- a/src/test/compile-fail-fulldeps/auxiliary/lint_group_plugin_test.rs +++ b/src/test/compile-fail-fulldeps/auxiliary/lint_group_plugin_test.rs @@ -35,7 +35,7 @@ impl LintPass for Pass { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { - fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { + fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { match &*it.name.as_str() { "lintme" => cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'"), "pleaselintme" => cx.span_lint(PLEASE_LINT, it.span, "item is named 'pleaselintme'"), diff --git a/src/test/run-pass-fulldeps/auxiliary/lint_for_crate.rs b/src/test/run-pass-fulldeps/auxiliary/lint_for_crate.rs index 4011ce86414..fc53031e7f2 100644 --- a/src/test/run-pass-fulldeps/auxiliary/lint_for_crate.rs +++ b/src/test/run-pass-fulldeps/auxiliary/lint_for_crate.rs @@ -33,7 +33,7 @@ impl LintPass for Pass { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { - fn check_crate(&mut self, cx: &LateContext<'a, 'tcx>, krate: &'tcx hir::Crate) { + fn check_crate(&mut self, cx: &LateContext, krate: &hir::Crate) { if !attr::contains_name(&krate.attrs, "crate_okay") { cx.span_lint(CRATE_NOT_OKAY, krate.span, "crate is not marked with #![crate_okay]"); diff --git a/src/test/run-pass-fulldeps/auxiliary/lint_group_plugin_test.rs b/src/test/run-pass-fulldeps/auxiliary/lint_group_plugin_test.rs index cc17a011e55..490aa0d4693 100644 --- a/src/test/run-pass-fulldeps/auxiliary/lint_group_plugin_test.rs +++ b/src/test/run-pass-fulldeps/auxiliary/lint_group_plugin_test.rs @@ -35,7 +35,7 @@ impl LintPass for Pass { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { - fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) { + fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { match &*it.name.as_str() { "lintme" => cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'"), "pleaselintme" => cx.span_lint(PLEASE_LINT, it.span, "item is named 'pleaselintme'"), diff --git a/src/test/run-pass-fulldeps/issue-37290/auxiliary/lint.rs b/src/test/run-pass-fulldeps/issue-37290/auxiliary/lint.rs index 77996b71a46..c6892757c68 100644 --- a/src/test/run-pass-fulldeps/issue-37290/auxiliary/lint.rs +++ b/src/test/run-pass-fulldeps/issue-37290/auxiliary/lint.rs @@ -40,8 +40,8 @@ impl LintPass for Pass { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { - fn check_fn(&mut self, cx: &LateContext<'a, 'tcx>, - fk: FnKind<'tcx>, _: &'tcx hir::FnDecl, expr: &'tcx hir::Expr, + fn check_fn(&mut self, cx: &LateContext, + fk: FnKind, _: &hir::FnDecl, expr: &hir::Expr, span: Span, node: ast::NodeId) { if let FnKind::Closure(..) = fk { return } From f58e553001537d52e67720156f9280d122cc242d Mon Sep 17 00:00:00 2001 From: Robin Kruppe Date: Wed, 7 Dec 2016 17:02:34 +0100 Subject: [PATCH 262/293] printf type correctness The %.*s format specifier requires an int for the maximum size, but StringRef::size is a size_t cc @shepmaster --- src/rustllvm/PassWrapper.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index d1eb261abd3..c45d1c2d088 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -533,8 +533,11 @@ LLVMRustPrintPasses() { StringRef PassArg = info->getPassArgument(); StringRef PassName = info->getPassName(); if (!PassArg.empty()) { - printf("%15.*s - %.*s\n", PassArg.size(), PassArg.data(), - PassName.size(), PassName.data()); + // These unsigned->signed casts could theoretically overflow, but + // realistically never will (and even if, the result is implementation + // defined rather plain UB). + printf("%15.*s - %.*s\n", (int)PassArg.size(), PassArg.data(), + (int)PassName.size(), PassName.data()); } #else if (info->getPassArgument() && *info->getPassArgument()) { From 614b74c24bb80e17230e58a74ef5a4725972f84a Mon Sep 17 00:00:00 2001 From: Cobrand Date: Wed, 7 Dec 2016 18:43:07 +0100 Subject: [PATCH 263/293] Update book/ffi to use catch_unwind r? @GuillaumeGomez The doc mentioned to spawn a new thread instead of using catch_unwind, which has been the recommended way to catch panics for foreign function interfaces for a few releases now. --- src/doc/book/ffi.md | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/doc/book/ffi.md b/src/doc/book/ffi.md index 7510cd0b3b5..b53af694428 100644 --- a/src/doc/book/ffi.md +++ b/src/doc/book/ffi.md @@ -662,26 +662,31 @@ attribute turns off Rust's name mangling, so that it is easier to link to. It’s important to be mindful of `panic!`s when working with FFI. A `panic!` across an FFI boundary is undefined behavior. If you’re writing code that may -panic, you should run it in another thread, so that the panic doesn’t bubble up -to C: +panic, you should run it in a closure with [`catch_unwind()`]: ```rust -use std::thread; +use std::panic::catch_unwind; #[no_mangle] pub extern fn oh_no() -> i32 { - let h = thread::spawn(|| { + let result = catch_unwind(|| { panic!("Oops!"); }); - - match h.join() { - Ok(_) => 1, - Err(_) => 0, + match result { + Ok(_) => 0, + Err(_) => 1, } } -# fn main() {} + +fn main() {} ``` +Please note that [`catch_unwind()`] will only catch unwinding panics, not +those who abort the process. See the documentation of [`catch_unwind()`] +for more information. + +[`catch_unwind()`]: https://doc.rust-lang.org/std/panic/fn.catch_unwind.html + # Representing opaque structs Sometimes, a C library wants to provide a pointer to something, but not let you From c8d73ea68a9fbd127d7b78b4c167f0b80523ab7b Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Tue, 6 Dec 2016 12:05:16 +0100 Subject: [PATCH 264/293] Implement a faster sort algorithm This is a complete rewrite of the standard sort algorithm. The new algorithm is a simplified variant of TimSort. In summary, the changes are: * Improved performance, especially on partially sorted inputs. * Performs less comparisons on both random and partially sorted inputs. * Decreased the size of temporary memory: the new sort allocates 4x less. --- src/libcollections/lib.rs | 4 +- src/libcollections/slice.rs | 494 ++++++++++++-------- src/libcollectionstest/slice.rs | 156 ++++--- src/test/run-pass/vector-sort-panic-safe.rs | 161 ++++--- 4 files changed, 490 insertions(+), 325 deletions(-) diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 08288b4de8b..191a6b0b7a9 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -47,14 +47,14 @@ #![feature(placement_in)] #![feature(placement_new_protocol)] #![feature(shared)] +#![feature(slice_get_slice)] #![feature(slice_patterns)] #![feature(specialization)] #![feature(staged_api)] -#![feature(step_by)] #![feature(trusted_len)] #![feature(unicode)] #![feature(unique)] -#![feature(slice_get_slice)] +#![feature(untagged_unions)] #![cfg_attr(test, feature(rand, test))] #![no_std] diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index e615e780d2b..d180d6f2edd 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -98,8 +98,7 @@ #![cfg_attr(test, allow(unused_imports, dead_code))] use alloc::boxed::Box; -use core::cmp::Ordering::{self, Greater, Less}; -use core::cmp; +use core::cmp::Ordering::{self, Greater}; use core::mem::size_of; use core::mem; use core::ptr; @@ -1042,8 +1041,8 @@ impl [T] { /// This is equivalent to `self.sort_by(|a, b| a.cmp(b))`. /// - /// This sort is stable and `O(n log n)` worst-case but allocates - /// approximately `2 * n` where `n` is the length of `self`. + /// This sort is stable and `O(n log n)` worst-case, but allocates + /// temporary storage half the size of `self`. /// /// # Examples /// @@ -1064,8 +1063,8 @@ impl [T] { /// Sorts the slice, in place, using `f` to extract a key by which to /// order the sort by. /// - /// This sort is stable and `O(n log n)` worst-case but allocates - /// approximately `2 * n`, where `n` is the length of `self`. + /// This sort is stable and `O(n log n)` worst-case, but allocates + /// temporary storage half the size of `self`. /// /// # Examples /// @@ -1086,8 +1085,8 @@ impl [T] { /// Sorts the slice, in place, using `compare` to compare /// elements. /// - /// This sort is stable and `O(n log n)` worst-case but allocates - /// approximately `2 * n`, where `n` is the length of `self`. + /// This sort is stable and `O(n log n)` worst-case, but allocates + /// temporary storage half the size of `self`. /// /// # Examples /// @@ -1305,213 +1304,332 @@ impl ToOwned for [T] { // Sorting //////////////////////////////////////////////////////////////////////////////// -fn insertion_sort(v: &mut [T], mut compare: F) +/// Inserts `v[0]` into pre-sorted sequence `v[1..]` so that whole `v[..]` becomes sorted. +/// +/// This is the integral subroutine of insertion sort. +fn insert_head(v: &mut [T], compare: &mut F) where F: FnMut(&T, &T) -> Ordering { - let len = v.len() as isize; - let buf_v = v.as_mut_ptr(); - - // 1 <= i < len; - for i in 1..len { - // j satisfies: 0 <= j <= i; - let mut j = i; + if v.len() >= 2 && compare(&v[0], &v[1]) == Greater { unsafe { - // `i` is in bounds. - let read_ptr = buf_v.offset(i) as *const T; + // There are three ways to implement insertion here: + // + // 1. Swap adjacent elements until the first one gets to its final destination. + // However, this way we copy data around more than is necessary. If elements are big + // structures (costly to copy), this method will be slow. + // + // 2. Iterate until the right place for the first element is found. Then shift the + // elements succeeding it to make room for it and finally place it into the + // remaining hole. This is a good method. + // + // 3. Copy the first element into a temporary variable. Iterate until the right place + // for it is found. As we go along, copy every traversed element into the slot + // preceding it. Finally, copy data from the temporary variable into the remaining + // hole. This method is very good. Benchmarks demonstrated slightly better + // performance than with the 2nd method. + // + // All methods were benchmarked, and the 3rd showed best results. So we chose that one. + let mut tmp = NoDrop { value: ptr::read(&v[0]) }; - // find where to insert, we need to do strict <, - // rather than <=, to maintain stability. + // Intermediate state of the insertion process is always tracked by `hole`, which + // serves two purposes: + // 1. Protects integrity of `v` from panics in `compare`. + // 2. Fills the remaining hole in `v` in the end. + // + // Panic safety: + // + // If `compare` panics at any point during the process, `hole` will get dropped and + // fill the hole in `v` with `tmp`, thus ensuring that `v` still holds every object it + // initially held exactly once. + let mut hole = InsertionHole { + src: &mut tmp.value, + dest: &mut v[1], + }; + ptr::copy_nonoverlapping(&v[1], &mut v[0], 1); - // 0 <= j - 1 < len, so .offset(j - 1) is in bounds. - while j > 0 && compare(&*read_ptr, &*buf_v.offset(j - 1)) == Less { - j -= 1; + for i in 2..v.len() { + if compare(&tmp.value, &v[i]) != Greater { + break; + } + ptr::copy_nonoverlapping(&v[i], &mut v[i - 1], 1); + hole.dest = &mut v[i]; } + // `hole` gets dropped and thus copies `tmp` into the remaining hole in `v`. + } + } - // shift everything to the right, to make space to - // insert this value. + // Holds a value, but never drops it. + #[allow(unions_with_drop_fields)] + union NoDrop { + value: T + } - // j + 1 could be `len` (for the last `i`), but in - // that case, `i == j` so we don't copy. The - // `.offset(j)` is always in bounds. + // When dropped, copies from `src` into `dest`. + struct InsertionHole { + src: *mut T, + dest: *mut T, + } - if i != j { - let tmp = ptr::read(read_ptr); - ptr::copy(&*buf_v.offset(j), buf_v.offset(j + 1), (i - j) as usize); - ptr::copy_nonoverlapping(&tmp, buf_v.offset(j), 1); - mem::forget(tmp); - } + impl Drop for InsertionHole { + fn drop(&mut self) { + unsafe { ptr::copy_nonoverlapping(self.src, self.dest, 1); } } } } -fn merge_sort(v: &mut [T], mut compare: F) +/// Merges non-decreasing runs `v[..mid]` and `v[mid..]` using `buf` as temporary storage, and +/// stores the result into `v[..]`. +/// +/// # Safety +/// +/// The two slices must be non-empty and `mid` must be in bounds. Buffer `buf` must be long enough +/// to hold a copy of the shorter slice. Also, `T` must not be a zero-sized type. +unsafe fn merge(v: &mut [T], mid: usize, buf: *mut T, compare: &mut F) where F: FnMut(&T, &T) -> Ordering { - // warning: this wildly uses unsafe. - const BASE_INSERTION: usize = 32; - const LARGE_INSERTION: usize = 16; - - // FIXME #12092: smaller insertion runs seems to make sorting - // vectors of large elements a little faster on some platforms, - // but hasn't been tested/tuned extensively - let insertion = if size_of::() <= 16 { - BASE_INSERTION - } else { - LARGE_INSERTION - }; - let len = v.len(); + let v = v.as_mut_ptr(); + let v_mid = v.offset(mid as isize); + let v_end = v.offset(len as isize); - // short vectors get sorted in-place via insertion sort to avoid allocations - if len <= insertion { - insertion_sort(v, compare); - return; - } + // The merge process first copies the shorter run into `buf`. Then it traces the newly copied + // run and the longer run forwards (or backwards), comparing their next unconsumed elements and + // copying the lesser (or greater) one into `v`. + // + // As soon as the shorter run is fully consumed, the process is done. If the longer run gets + // consumed first, then we must copy whatever is left of the shorter run into the remaining + // hole in `v`. + // + // Intermediate state of the process is always tracked by `hole`, which serves two purposes: + // 1. Protects integrity of `v` from panics in `compare`. + // 2. Fills the remaining hole in `v` if the longer run gets consumed first. + // + // Panic safety: + // + // If `compare` panics at any point during the process, `hole` will get dropped and fill the + // hole in `v` with the unconsumed range in `buf`, thus ensuring that `v` still holds every + // object it initially held exactly once. + let mut hole; - // allocate some memory to use as scratch memory, we keep the - // length 0 so we can keep shallow copies of the contents of `v` - // without risking the dtors running on an object twice if - // `compare` panics. - let mut working_space = Vec::with_capacity(2 * len); - // these both are buffers of length `len`. - let mut buf_dat = working_space.as_mut_ptr(); - let mut buf_tmp = unsafe { buf_dat.offset(len as isize) }; + if mid <= len - mid { + // The left run is shorter. + ptr::copy_nonoverlapping(v, buf, mid); + hole = MergeHole { + start: buf, + end: buf.offset(mid as isize), + dest: v, + }; - // length `len`. - let buf_v = v.as_ptr(); + // Initially, these pointers point to the beginnings of their arrays. + let left = &mut hole.start; + let mut right = v_mid; + let out = &mut hole.dest; - // step 1. sort short runs with insertion sort. This takes the - // values from `v` and sorts them into `buf_dat`, leaving that - // with sorted runs of length INSERTION. + while *left < hole.end && right < v_end { + // Consume the lesser side. + // If equal, prefer the left run to maintain stability. + let to_copy = if compare(&**left, &*right) == Greater { + get_and_increment(&mut right) + } else { + get_and_increment(left) + }; + ptr::copy_nonoverlapping(to_copy, get_and_increment(out), 1); + } + } else { + // The right run is shorter. + ptr::copy_nonoverlapping(v_mid, buf, len - mid); + hole = MergeHole { + start: buf, + end: buf.offset((len - mid) as isize), + dest: v_mid, + }; - // We could hardcode the sorting comparisons here, and we could - // manipulate/step the pointers themselves, rather than repeatedly - // .offset-ing. - for start in (0..len).step_by(insertion) { - // start <= i < len; - for i in start..cmp::min(start + insertion, len) { - // j satisfies: start <= j <= i; - let mut j = i as isize; - unsafe { - // `i` is in bounds. - let read_ptr = buf_v.offset(i as isize); + // Initially, these pointers point past the ends of their arrays. + let left = &mut hole.dest; + let right = &mut hole.end; + let mut out = v_end; - // find where to insert, we need to do strict <, - // rather than <=, to maintain stability. - - // start <= j - 1 < len, so .offset(j - 1) is in - // bounds. - while j > start as isize && compare(&*read_ptr, &*buf_dat.offset(j - 1)) == Less { - j -= 1; - } - - // shift everything to the right, to make space to - // insert this value. - - // j + 1 could be `len` (for the last `i`), but in - // that case, `i == j` so we don't copy. The - // `.offset(j)` is always in bounds. - ptr::copy(&*buf_dat.offset(j), buf_dat.offset(j + 1), i - j as usize); - ptr::copy_nonoverlapping(read_ptr, buf_dat.offset(j), 1); - } + while v < *left && buf < *right { + // Consume the greater side. + // If equal, prefer the right run to maintain stability. + let to_copy = if compare(&*left.offset(-1), &*right.offset(-1)) == Greater { + decrement_and_get(left) + } else { + decrement_and_get(right) + }; + ptr::copy_nonoverlapping(to_copy, decrement_and_get(&mut out), 1); } } + // Finally, `hole` gets dropped. If the shorter run was not fully consumed, whatever remains of + // it will now be copied into the hole in `v`. - // step 2. merge the sorted runs. - let mut width = insertion; - while width < len { - // merge the sorted runs of length `width` in `buf_dat` two at - // a time, placing the result in `buf_tmp`. - - // 0 <= start <= len. - for start in (0..len).step_by(2 * width) { - // manipulate pointers directly for speed (rather than - // using a `for` loop with `range` and `.offset` inside - // that loop). - unsafe { - // the end of the first run & start of the - // second. Offset of `len` is defined, since this is - // precisely one byte past the end of the object. - let right_start = buf_dat.offset(cmp::min(start + width, len) as isize); - // end of the second. Similar reasoning to the above re safety. - let right_end_idx = cmp::min(start + 2 * width, len); - let right_end = buf_dat.offset(right_end_idx as isize); - - // the pointers to the elements under consideration - // from the two runs. - - // both of these are in bounds. - let mut left = buf_dat.offset(start as isize); - let mut right = right_start; - - // where we're putting the results, it is a run of - // length `2*width`, so we step it once for each step - // of either `left` or `right`. `buf_tmp` has length - // `len`, so these are in bounds. - let mut out = buf_tmp.offset(start as isize); - let out_end = buf_tmp.offset(right_end_idx as isize); - - // If left[last] <= right[0], they are already in order: - // fast-forward the left side (the right side is handled - // in the loop). - // If `right` is not empty then left is not empty, and - // the offsets are in bounds. - if right != right_end && compare(&*right.offset(-1), &*right) != Greater { - let elems = (right_start as usize - left as usize) / mem::size_of::(); - ptr::copy_nonoverlapping(&*left, out, elems); - out = out.offset(elems as isize); - left = right_start; - } - - while out < out_end { - // Either the left or the right run are exhausted, - // so just copy the remainder from the other run - // and move on; this gives a huge speed-up (order - // of 25%) for mostly sorted vectors (the best - // case). - if left == right_start { - // the number remaining in this run. - let elems = (right_end as usize - right as usize) / mem::size_of::(); - ptr::copy_nonoverlapping(&*right, out, elems); - break; - } else if right == right_end { - let elems = (right_start as usize - left as usize) / mem::size_of::(); - ptr::copy_nonoverlapping(&*left, out, elems); - break; - } - - // check which side is smaller, and that's the - // next element for the new run. - - // `left < right_start` and `right < right_end`, - // so these are valid. - let to_copy = if compare(&*left, &*right) == Greater { - step(&mut right) - } else { - step(&mut left) - }; - ptr::copy_nonoverlapping(&*to_copy, out, 1); - step(&mut out); - } - } - } - - mem::swap(&mut buf_dat, &mut buf_tmp); - - width *= 2; - } - - // write the result to `v` in one go, so that there are never two copies - // of the same object in `v`. - unsafe { - ptr::copy_nonoverlapping(&*buf_dat, v.as_mut_ptr(), len); - } - - // increment the pointer, returning the old pointer. - #[inline(always)] - unsafe fn step(ptr: &mut *mut T) -> *mut T { + unsafe fn get_and_increment(ptr: &mut *mut T) -> *mut T { let old = *ptr; *ptr = ptr.offset(1); old } + + unsafe fn decrement_and_get(ptr: &mut *mut T) -> *mut T { + *ptr = ptr.offset(-1); + *ptr + } + + // When dropped, copies the range `start..end` into `dest..`. + struct MergeHole { + start: *mut T, + end: *mut T, + dest: *mut T, + } + + impl Drop for MergeHole { + fn drop(&mut self) { + // `T` is not a zero-sized type, so it's okay to divide by it's size. + let len = (self.end as usize - self.start as usize) / mem::size_of::(); + unsafe { ptr::copy_nonoverlapping(self.start, self.dest, len); } + } + } +} + +/// This merge sort borrows some (but not all) ideas from TimSort, which is described in detail +/// [here](http://svn.python.org/projects/python/trunk/Objects/listsort.txt). +/// +/// The algorithm identifies strictly descending and non-descending subsequences, which are called +/// natural runs. There is a stack of pending runs yet to be merged. Each newly found run is pushed +/// onto the stack, and then some pairs of adjacent runs are merged until these two invariants are +/// satisfied, for every `i` in `0 .. runs.len() - 2`: +/// +/// 1. `runs[i].len > runs[i + 1].len` +/// 2. `runs[i].len > runs[i + 1].len + runs[i + 2].len` +/// +/// The invariants ensure that the total running time is `O(n log n)` worst-case. +fn merge_sort(v: &mut [T], mut compare: F) + where F: FnMut(&T, &T) -> Ordering +{ + // Sorting has no meaningful behavior on zero-sized types. + if size_of::() == 0 { + return; + } + + // FIXME #12092: These numbers are platform-specific and need more extensive testing/tuning. + // + // If `v` has length up to `insertion_len`, simply switch to insertion sort because it is going + // to perform better than merge sort. For bigger types `T`, the threshold is smaller. + // + // Short runs are extended using insertion sort to span at least `min_run` elements, in order + // to improve performance. + let (max_insertion, min_run) = if size_of::() <= 16 { + (64, 32) + } else { + (32, 16) + }; + + let len = v.len(); + + // Short arrays get sorted in-place via insertion sort to avoid allocations. + if len <= max_insertion { + if len >= 2 { + for i in (0..len-1).rev() { + insert_head(&mut v[i..], &mut compare); + } + } + return; + } + + // Allocate a buffer to use as scratch memory. We keep the length 0 so we can keep in it + // shallow copies of the contents of `v` without risking the dtors running on copies if + // `compare` panics. When merging two sorted runs, this buffer holds a copy of the shorter run, + // which will always have length at most `len / 2`. + let mut buf = Vec::with_capacity(len / 2); + + // In order to identify natural runs in `v`, we traverse it backwards. That might seem like a + // strange decision, but consider the fact that merges more often go in the opposite direction + // (forwards). According to benchmarks, merging forwards is slightly faster than merging + // backwards. To conclude, identifying runs by traversing backwards improves performance. + let mut runs = vec![]; + let mut end = len; + while end > 0 { + // Find the next natural run, and reverse it if it's strictly descending. + let mut start = end - 1; + if start > 0 { + start -= 1; + if compare(&v[start], &v[start + 1]) == Greater { + while start > 0 && compare(&v[start - 1], &v[start]) == Greater { + start -= 1; + } + v[start..end].reverse(); + } else { + while start > 0 && compare(&v[start - 1], &v[start]) != Greater { + start -= 1; + } + } + } + + // Insert some more elements into the run if it's too short. Insertion sort is faster than + // merge sort on short sequences, so this significantly improves performance. + while start > 0 && end - start < min_run { + start -= 1; + insert_head(&mut v[start..end], &mut compare); + } + + // Push this run onto the stack. + runs.push(Run { + start: start, + len: end - start, + }); + end = start; + + // Merge some pairs of adjacent runs to satisfy the invariants. + while let Some(r) = collapse(&runs) { + let left = runs[r + 1]; + let right = runs[r]; + unsafe { + merge(&mut v[left.start .. right.start + right.len], left.len, buf.as_mut_ptr(), + &mut compare); + } + runs[r] = Run { + start: left.start, + len: left.len + right.len, + }; + runs.remove(r + 1); + } + } + + // Finally, exactly one run must remain in the stack. + debug_assert!(runs.len() == 1 && runs[0].start == 0 && runs[0].len == len); + + // Examines the stack of runs and identifies the next pair of runs to merge. More specifically, + // if `Some(r)` is returned, that means `runs[r]` and `runs[r + 1]` must be merged next. If the + // algorithm should continue building a new run instead, `None` is returned. + // + // TimSort is infamous for it's buggy implementations, as described here: + // http://envisage-project.eu/timsort-specification-and-verification/ + // + // The gist of the story is: we must enforce the invariants on the top four runs on the stack. + // Enforcing them on just top three is not sufficient to ensure that the invariants will still + // hold for *all* runs in the stack. + // + // This function correctly checks invariants for the top four runs. Additionally, if the top + // run starts at index 0, it will always demand a merge operation until the stack is fully + // collapsed, in order to complete the sort. + fn collapse(runs: &[Run]) -> Option { + let n = runs.len(); + if n >= 2 && (runs[n - 1].start == 0 || + runs[n - 2].len <= runs[n - 1].len || + (n >= 3 && runs[n - 3].len <= runs[n - 2].len + runs[n - 1].len) || + (n >= 4 && runs[n - 4].len <= runs[n - 3].len + runs[n - 2].len)) { + if n >= 3 && runs[n - 3].len < runs[n - 1].len { + Some(n - 3) + } else { + Some(n - 2) + } + } else { + None + } + } + + #[derive(Clone, Copy)] + struct Run { + start: usize, + len: usize, + } } diff --git a/src/libcollectionstest/slice.rs b/src/libcollectionstest/slice.rs index 0e63e8d4a1e..1b52214dee6 100644 --- a/src/libcollectionstest/slice.rs +++ b/src/libcollectionstest/slice.rs @@ -383,7 +383,7 @@ fn test_reverse() { #[test] fn test_sort() { - for len in 4..25 { + for len in (2..25).chain(500..510) { for _ in 0..100 { let mut v: Vec<_> = thread_rng().gen_iter::().take(len).collect(); let mut v1 = v.clone(); @@ -410,7 +410,7 @@ fn test_sort() { #[test] fn test_sort_stability() { - for len in 4..25 { + for len in (2..25).chain(500..510) { for _ in 0..10 { let mut counts = [0; 10]; @@ -441,6 +441,13 @@ fn test_sort_stability() { } } +#[test] +fn test_sort_zero_sized_type() { + // Should not panic. + [(); 10].sort(); + [(); 100].sort(); +} + #[test] fn test_concat() { let v: [Vec; 0] = []; @@ -1338,89 +1345,104 @@ mod bench { }) } - #[bench] - fn sort_random_small(b: &mut Bencher) { + fn gen_ascending(len: usize) -> Vec { + (0..len as u64).collect() + } + + fn gen_descending(len: usize) -> Vec { + (0..len as u64).rev().collect() + } + + fn gen_random(len: usize) -> Vec { let mut rng = thread_rng(); - b.iter(|| { - let mut v: Vec<_> = rng.gen_iter::().take(5).collect(); - v.sort(); - }); - b.bytes = 5 * mem::size_of::() as u64; + rng.gen_iter::().take(len).collect() } - #[bench] - fn sort_random_medium(b: &mut Bencher) { + fn gen_mostly_ascending(len: usize) -> Vec { let mut rng = thread_rng(); - b.iter(|| { - let mut v: Vec<_> = rng.gen_iter::().take(100).collect(); - v.sort(); - }); - b.bytes = 100 * mem::size_of::() as u64; + let mut v = gen_ascending(len); + for _ in (0usize..).take_while(|x| x * x <= len) { + let x = rng.gen::() % len; + let y = rng.gen::() % len; + v.swap(x, y); + } + v } - #[bench] - fn sort_random_large(b: &mut Bencher) { + fn gen_mostly_descending(len: usize) -> Vec { let mut rng = thread_rng(); - b.iter(|| { - let mut v: Vec<_> = rng.gen_iter::().take(10000).collect(); - v.sort(); - }); - b.bytes = 10000 * mem::size_of::() as u64; + let mut v = gen_descending(len); + for _ in (0usize..).take_while(|x| x * x <= len) { + let x = rng.gen::() % len; + let y = rng.gen::() % len; + v.swap(x, y); + } + v } - #[bench] - fn sort_sorted(b: &mut Bencher) { - let mut v: Vec<_> = (0..10000).collect(); - b.iter(|| { - v.sort(); - }); - b.bytes = (v.len() * mem::size_of_val(&v[0])) as u64; - } - - type BigSortable = (u64, u64, u64, u64); - - #[bench] - fn sort_big_random_small(b: &mut Bencher) { + fn gen_big_random(len: usize) -> Vec<[u64; 16]> { let mut rng = thread_rng(); - b.iter(|| { - let mut v = rng.gen_iter::() - .take(5) - .collect::>(); - v.sort(); - }); - b.bytes = 5 * mem::size_of::() as u64; + rng.gen_iter().map(|x| [x; 16]).take(len).collect() } - #[bench] - fn sort_big_random_medium(b: &mut Bencher) { - let mut rng = thread_rng(); - b.iter(|| { - let mut v = rng.gen_iter::() - .take(100) - .collect::>(); - v.sort(); - }); - b.bytes = 100 * mem::size_of::() as u64; + fn gen_big_ascending(len: usize) -> Vec<[u64; 16]> { + (0..len as u64).map(|x| [x; 16]).take(len).collect() } - #[bench] - fn sort_big_random_large(b: &mut Bencher) { - let mut rng = thread_rng(); - b.iter(|| { - let mut v = rng.gen_iter::() - .take(10000) - .collect::>(); - v.sort(); - }); - b.bytes = 10000 * mem::size_of::() as u64; + fn gen_big_descending(len: usize) -> Vec<[u64; 16]> { + (0..len as u64).rev().map(|x| [x; 16]).take(len).collect() } + macro_rules! sort_bench { + ($name:ident, $gen:expr, $len:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + b.iter(|| $gen($len).sort()); + b.bytes = $len * mem::size_of_val(&$gen(1)[0]) as u64; + } + } + } + + sort_bench!(sort_small_random, gen_random, 10); + sort_bench!(sort_small_ascending, gen_ascending, 10); + sort_bench!(sort_small_descending, gen_descending, 10); + + sort_bench!(sort_small_big_random, gen_big_random, 10); + sort_bench!(sort_small_big_ascending, gen_big_ascending, 10); + sort_bench!(sort_small_big_descending, gen_big_descending, 10); + + sort_bench!(sort_medium_random, gen_random, 100); + sort_bench!(sort_medium_ascending, gen_ascending, 100); + sort_bench!(sort_medium_descending, gen_descending, 100); + + sort_bench!(sort_large_random, gen_random, 10000); + sort_bench!(sort_large_ascending, gen_ascending, 10000); + sort_bench!(sort_large_descending, gen_descending, 10000); + sort_bench!(sort_large_mostly_ascending, gen_mostly_ascending, 10000); + sort_bench!(sort_large_mostly_descending, gen_mostly_descending, 10000); + + sort_bench!(sort_large_big_random, gen_big_random, 10000); + sort_bench!(sort_large_big_ascending, gen_big_ascending, 10000); + sort_bench!(sort_large_big_descending, gen_big_descending, 10000); + #[bench] - fn sort_big_sorted(b: &mut Bencher) { - let mut v: Vec = (0..10000).map(|i| (i, i, i, i)).collect(); + fn sort_large_random_expensive(b: &mut Bencher) { + let len = 10000; b.iter(|| { - v.sort(); + let mut count = 0; + let cmp = move |a: &u64, b: &u64| { + count += 1; + if count % 1_000_000_000 == 0 { + panic!("should not happen"); + } + (*a as f64).cos().partial_cmp(&(*b as f64).cos()).unwrap() + }; + + let mut v = gen_random(len); + v.sort_by(cmp); + + black_box(count); }); - b.bytes = (v.len() * mem::size_of_val(&v[0])) as u64; + b.bytes = len as u64 * mem::size_of::() as u64; } } diff --git a/src/test/run-pass/vector-sort-panic-safe.rs b/src/test/run-pass/vector-sort-panic-safe.rs index 911bfc7454c..87f1968918c 100644 --- a/src/test/run-pass/vector-sort-panic-safe.rs +++ b/src/test/run-pass/vector-sort-panic-safe.rs @@ -17,86 +17,111 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use std::__rand::{thread_rng, Rng}; use std::thread; -const REPEATS: usize = 5; -const MAX_LEN: usize = 32; -static drop_counts: [AtomicUsize; MAX_LEN] = - // FIXME #5244: AtomicUsize is not Copy. - [ - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), - ]; +const MAX_LEN: usize = 80; -static creation_count: AtomicUsize = AtomicUsize::new(0); +static DROP_COUNTS: [AtomicUsize; MAX_LEN] = [ + // FIXME #5244: AtomicUsize is not Copy. + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), +]; #[derive(Clone, PartialEq, PartialOrd, Eq, Ord)] -struct DropCounter { x: u32, creation_id: usize } +struct DropCounter { + x: u32, + id: usize, +} impl Drop for DropCounter { fn drop(&mut self) { - drop_counts[self.creation_id].fetch_add(1, Ordering::Relaxed); + DROP_COUNTS[self.id].fetch_add(1, Ordering::Relaxed); } } -pub fn main() { - // len can't go above 64. - for len in 2..MAX_LEN { - for _ in 0..REPEATS { - // reset the count for these new DropCounters, so their - // IDs start from 0. - creation_count.store(0, Ordering::Relaxed); +fn test(input: &[DropCounter]) { + let len = input.len(); - let mut rng = thread_rng(); - let main = (0..len).map(|_| { - DropCounter { - x: rng.next_u32(), - creation_id: creation_count.fetch_add(1, Ordering::Relaxed), + // Work out the total number of comparisons required to sort + // this array... + let mut count = 0usize; + input.to_owned().sort_by(|a, b| { count += 1; a.cmp(b) }); + + // ... and then panic on each and every single one. + for panic_countdown in 0..count { + // Refresh the counters. + for i in 0..len { + DROP_COUNTS[i].store(0, Ordering::Relaxed); + } + + let v = input.to_owned(); + let _ = thread::spawn(move || { + let mut v = v; + let mut panic_countdown = panic_countdown; + v.sort_by(|a, b| { + if panic_countdown == 0 { + panic!(); } - }).collect::>(); + panic_countdown -= 1; + a.cmp(b) + }) + }).join(); - // work out the total number of comparisons required to sort - // this array... - let mut count = 0_usize; - main.clone().sort_by(|a, b| { count += 1; a.cmp(b) }); - - // ... and then panic on each and every single one. - for panic_countdown in 0..count { - // refresh the counters. - for c in &drop_counts { - c.store(0, Ordering::Relaxed); - } - - let v = main.clone(); - - let _ = thread::spawn(move|| { - let mut v = v; - let mut panic_countdown = panic_countdown; - v.sort_by(|a, b| { - if panic_countdown == 0 { - panic!() - } - panic_countdown -= 1; - a.cmp(b) - }) - }).join(); - - // check that the number of things dropped is exactly - // what we expect (i.e. the contents of `v`). - for (i, c) in drop_counts.iter().enumerate().take(len) { - let count = c.load(Ordering::Relaxed); - assert!(count == 1, - "found drop count == {} for i == {}, len == {}", - count, i, len); - } - } + // Check that the number of things dropped is exactly + // what we expect (i.e. the contents of `v`). + for (i, c) in DROP_COUNTS.iter().enumerate().take(len) { + let count = c.load(Ordering::Relaxed); + assert!(count == 1, + "found drop count == {} for i == {}, len == {}", + count, i, len); + } + } +} + +fn main() { + for len in (1..20).chain(70..MAX_LEN) { + // Test on a random array. + let mut rng = thread_rng(); + let input = (0..len).map(|id| { + DropCounter { + x: rng.next_u32(), + id: id, + } + }).collect::>(); + test(&input); + + // Test on a sorted array with two elements randomly swapped, creating several natural + // runs of random lengths. Such arrays have very high chances of hitting all code paths in + // the merge procedure. + for _ in 0..5 { + let mut input = (0..len).map(|i| + DropCounter { + x: i as u32, + id: i, + } + ).collect::>(); + + let a = rng.gen::() % len; + let b = rng.gen::() % len; + input.swap(a, b); + + test(&input); } } } From 03fb5ad7c25eda9582d8da215bc1697af8f2c2ff Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 7 Dec 2016 17:26:48 -0800 Subject: [PATCH 265/293] rustbuild: Print out failing commands Just ensure that we always print out the command line which should aid in debugging. Closes #38228 --- src/bootstrap/check.rs | 3 +-- src/build_helper/lib.rs | 6 ++++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index c5675fd46cb..72e12c55bfc 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -464,8 +464,7 @@ fn krate_emscripten(build: &Build, println!("running {}", test_file_name); let nodejs = build.config.nodejs.as_ref().expect("nodejs not configured"); let mut cmd = Command::new(nodejs); - cmd.arg(&test_file_name) - .stderr(::std::process::Stdio::inherit()); + cmd.arg(&test_file_name); if build.config.quiet_tests { cmd.arg("--quiet"); } diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs index 38844fb6c9e..07f9c91d3c7 100644 --- a/src/build_helper/lib.rs +++ b/src/build_helper/lib.rs @@ -21,7 +21,8 @@ pub fn run(cmd: &mut Command) { pub fn run_silent(cmd: &mut Command) { let status = match cmd.status() { Ok(status) => status, - Err(e) => fail(&format!("failed to execute command: {}", e)), + Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", + cmd, e)), }; if !status.success() { fail(&format!("command did not execute successfully: {:?}\n\ @@ -63,7 +64,8 @@ pub fn cc2ar(cc: &Path, target: &str) -> Option { pub fn output(cmd: &mut Command) -> String { let output = match cmd.stderr(Stdio::inherit()).output() { Ok(status) => status, - Err(e) => fail(&format!("failed to execute command: {}", e)), + Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", + cmd, e)), }; if !output.status.success() { panic!("command did not execute successfully: {:?}\n\ From cc161225bd4ddf271a8c4fbc8bbe6ea3e7729f00 Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Wed, 7 Dec 2016 15:50:48 -0800 Subject: [PATCH 266/293] Prevent Windows from displaying UI on errors. --- src/bootstrap/job.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/bootstrap/job.rs b/src/bootstrap/job.rs index b4d7aff97da..b030538e979 100644 --- a/src/bootstrap/job.rs +++ b/src/bootstrap/job.rs @@ -51,6 +51,7 @@ type LPVOID = *mut u8; type JOBOBJECTINFOCLASS = i32; type SIZE_T = usize; type LARGE_INTEGER = i64; +type UINT = u32; type ULONG_PTR = usize; type ULONGLONG = u64; @@ -59,6 +60,8 @@ const DUPLICATE_SAME_ACCESS: DWORD = 0x2; const PROCESS_DUP_HANDLE: DWORD = 0x40; const JobObjectExtendedLimitInformation: JOBOBJECTINFOCLASS = 9; const JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE: DWORD = 0x2000; +const SEM_FAILCRITICALERRORS: UINT = 0x0001; +const SEM_NOGPFAULTERRORBOX: UINT = 0x0002; extern "system" { fn CreateJobObjectW(lpJobAttributes: *mut u8, lpName: *const u8) -> HANDLE; @@ -79,6 +82,7 @@ extern "system" { JobObjectInformationClass: JOBOBJECTINFOCLASS, lpJobObjectInformation: LPVOID, cbJobObjectInformationLength: DWORD) -> BOOL; + fn SetErrorMode(mode: UINT) -> UINT; } #[repr(C)] @@ -115,6 +119,12 @@ struct JOBOBJECT_BASIC_LIMIT_INFORMATION { } pub unsafe fn setup() { + // Tell Windows to not show any UI on errors (such as not finding a required dll + // during startup or terminating abnormally). This is important for running tests, + // since some of them use abnormal termination by design. + // This mode is inherited by all child processes. + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); + // Create a new job object for us to use let job = CreateJobObjectW(0 as *mut _, 0 as *const _); assert!(job != 0 as *mut _, "{}", io::Error::last_os_error()); From 6404143d8a36c9076cac89b3c386051b130f54c1 Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Wed, 7 Dec 2016 18:05:20 -0800 Subject: [PATCH 267/293] Preserve inherited mode flags. --- src/bootstrap/job.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/job.rs b/src/bootstrap/job.rs index b030538e979..c3859275e6f 100644 --- a/src/bootstrap/job.rs +++ b/src/bootstrap/job.rs @@ -123,7 +123,8 @@ pub unsafe fn setup() { // during startup or terminating abnormally). This is important for running tests, // since some of them use abnormal termination by design. // This mode is inherited by all child processes. - SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); + let mode = SetErrorMode(SEM_NOGPFAULTERRORBOX); // read inherited flags + SetErrorMode(mode | SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); // Create a new job object for us to use let job = CreateJobObjectW(0 as *mut _, 0 as *const _); From 9e158c5c087bab515e428916dbde1b5d3908c624 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 8 Dec 2016 10:34:44 +0100 Subject: [PATCH 268/293] also generate MIR for statics --- src/librustc_metadata/encoder.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index d9bcdb36026..443f3fbaa6e 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -839,6 +839,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { _ => None, }, mir: match item.node { + hir::ItemStatic(..) | hir::ItemConst(..) => self.encode_mir(def_id), hir::ItemFn(_, _, constness, _, ref generics, _) => { let tps_len = generics.ty_params.len(); From 6ffa274bb5095ad13b7df1e284d526a7c39e3f46 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 8 Dec 2016 10:48:07 +0000 Subject: [PATCH 269/293] Fix doc-tests on exported `macro_rules!`. --- src/librustdoc/test.rs | 4 ++++ src/test/rustdoc/issue-38219.rs | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 src/test/rustdoc/issue-38219.rs diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 009330065f3..794b7b91bd2 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -537,4 +537,8 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirCollector<'a, 'hir> { intravisit::walk_struct_field(this, f); }); } + + fn visit_macro_def(&mut self, macro_def: &'hir hir::MacroDef) { + self.visit_testable(macro_def.name.to_string(), ¯o_def.attrs, |_| ()); + } } diff --git a/src/test/rustdoc/issue-38219.rs b/src/test/rustdoc/issue-38219.rs new file mode 100644 index 00000000000..19b338bf560 --- /dev/null +++ b/src/test/rustdoc/issue-38219.rs @@ -0,0 +1,18 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:--test +// should-fail + +/// ``` +/// fail +/// ``` +#[macro_export] +macro_rules! foo { () => {} } From 6c52c3fdaff5784b7cfb0f5eee1c99dfa2300903 Mon Sep 17 00:00:00 2001 From: Vadzim Dambrouski Date: Thu, 8 Dec 2016 16:41:40 +0300 Subject: [PATCH 270/293] LLVM: Update submodule to include patches for MSP430. Fixes #37829 --- src/llvm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm b/src/llvm index 3ec14daffb4..d7342a9a957 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 3ec14daffb4b8c0604df50b7fb0ab552f456e381 +Subproject commit d7342a9a957470bb62c890cf88fc655ccfb755cc From 59a525454fe8108193dfebcb39d6949b4d6cbe73 Mon Sep 17 00:00:00 2001 From: Vadzim Dambrouski Date: Thu, 8 Dec 2016 16:45:18 +0300 Subject: [PATCH 271/293] LLVM: update trigger --- src/rustllvm/llvm-auto-clean-trigger | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-auto-clean-trigger index 2d832fcdf2a..88dd04b6172 100644 --- a/src/rustllvm/llvm-auto-clean-trigger +++ b/src/rustllvm/llvm-auto-clean-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be forcibly cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2016-12-06 +2016-12-08 From c0e150a2a65a762281ff5d28be8574cf6b207594 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Thu, 8 Dec 2016 22:37:36 +0100 Subject: [PATCH 272/293] Inline nested fn collapse Since merge_sort is generic and collapse isn't, that means calls to collapse won't be inlined. inlined. Therefore, we must stick an `#[inline]` above `fn collapse`. --- src/libcollections/slice.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index d180d6f2edd..5fb8cd6e1e2 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -1611,6 +1611,7 @@ fn merge_sort(v: &mut [T], mut compare: F) // This function correctly checks invariants for the top four runs. Additionally, if the top // run starts at index 0, it will always demand a merge operation until the stack is fully // collapsed, in order to complete the sort. + #[inline] fn collapse(runs: &[Run]) -> Option { let n = runs.len(); if n >= 2 && (runs[n - 1].start == 0 || From d602d7b97e737c461fdd0ff724d092ec53707157 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 8 Dec 2016 16:55:51 -0500 Subject: [PATCH 273/293] Extend middle::reachable to also consider provided trait methods. --- src/librustc/middle/reachable.rs | 25 ++++++++++++-- .../run-pass/auxiliary/issue_38226_aux.rs | 33 +++++++++++++++++++ src/test/run-pass/issue-38226.rs | 24 ++++++++++++++ 3 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 src/test/run-pass/auxiliary/issue_38226_aux.rs create mode 100644 src/test/run-pass/issue-38226.rs diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 9798b2d587d..2c4710f1e45 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -323,19 +323,37 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { // items of non-exported traits (or maybe all local traits?) unless their respective // trait items are used from inlinable code through method call syntax or UFCS, or their // trait is a lang item. -struct CollectPrivateImplItemsVisitor<'a> { +struct CollectPrivateImplItemsVisitor<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, access_levels: &'a privacy::AccessLevels, worklist: &'a mut Vec, } -impl<'a, 'v> ItemLikeVisitor<'v> for CollectPrivateImplItemsVisitor<'a> { +impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { // We need only trait impls here, not inherent impls, and only non-exported ones - if let hir::ItemImpl(.., Some(_), _, ref impl_item_refs) = item.node { + if let hir::ItemImpl(.., Some(ref trait_ref), _, ref impl_item_refs) = item.node { if !self.access_levels.is_reachable(item.id) { for impl_item_ref in impl_item_refs { self.worklist.push(impl_item_ref.id.node_id); } + + let trait_def_id = match trait_ref.path.def { + Def::Trait(def_id) => def_id, + _ => unreachable!() + }; + + if !trait_def_id.is_local() { + return + } + + for default_method in self.tcx.provided_trait_methods(trait_def_id) { + let node_id = self.tcx + .map + .as_local_node_id(default_method.def_id) + .unwrap(); + self.worklist.push(node_id); + } } } } @@ -369,6 +387,7 @@ pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } { let mut collect_private_impl_items = CollectPrivateImplItemsVisitor { + tcx: tcx, access_levels: access_levels, worklist: &mut reachable_context.worklist, }; diff --git a/src/test/run-pass/auxiliary/issue_38226_aux.rs b/src/test/run-pass/auxiliary/issue_38226_aux.rs new file mode 100644 index 00000000000..d48a9733685 --- /dev/null +++ b/src/test/run-pass/auxiliary/issue_38226_aux.rs @@ -0,0 +1,33 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type="rlib"] + +#[inline(never)] +pub fn foo() { + let _: Box = Box::new(SomeTraitImpl); +} + +pub fn bar() { + SomeTraitImpl.bar(); +} + +mod submod { + pub trait SomeTrait { + fn bar(&self) { + panic!("NO") + } + } +} + +use self::submod::SomeTrait; + +pub struct SomeTraitImpl; +impl SomeTrait for SomeTraitImpl {} diff --git a/src/test/run-pass/issue-38226.rs b/src/test/run-pass/issue-38226.rs new file mode 100644 index 00000000000..33604212af9 --- /dev/null +++ b/src/test/run-pass/issue-38226.rs @@ -0,0 +1,24 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This test makes sure that we don't run into a linker error because of the +// middle::reachable pass missing trait methods with default impls. + +// aux-build:issue_38226_aux.rs + +// Need -Cno-prepopulate-passes to really disable inlining, otherwise the faulty +// code gets optimized out: +// compile-flags: -Cno-prepopulate-passes + +extern crate issue_38226_aux; + +fn main() { + issue_38226_aux::foo::<()>(); +} From 5d35dfb01edd8f53862ac30e1eaec2cea40bace9 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 8 Dec 2016 16:57:34 -0500 Subject: [PATCH 274/293] Improve debug output in trans::back::symbol_export. --- src/librustc_trans/back/symbol_export.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index f99f543d9b7..eef464eb7f4 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -51,8 +51,10 @@ impl ExportedSymbols { scx.tcx().map.local_def_id(node_id) }) .map(|def_id| { - (symbol_for_def_id(scx, def_id, symbol_map), - export_level(scx, def_id)) + let name = symbol_for_def_id(scx, def_id, symbol_map); + let export_level = export_level(scx, def_id); + debug!("EXPORTED SYMBOL (local): {} ({:?})", name, export_level); + (name, export_level) }) .collect(); @@ -90,9 +92,10 @@ impl ExportedSymbols { .exported_symbols(cnum) .iter() .map(|&def_id| { - debug!("EXTERN-SYMBOL: {:?}", def_id); let name = Instance::mono(scx, def_id).symbol_name(scx); - (name, export_level(scx, def_id)) + let export_level = export_level(scx, def_id); + debug!("EXPORTED SYMBOL (re-export): {} ({:?})", name, export_level); + (name, export_level) }) .collect(); From 25adc4e82ee405127beff6e200499122ed2099dc Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 8 Dec 2016 13:09:20 -1000 Subject: [PATCH 275/293] Fix #38251 but perhaps not BEST fix for it. --- configure | 8 +++++++- src/bootstrap/mk/Makefile.in | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/configure b/configure index a287291c280..0a07e41fb97 100755 --- a/configure +++ b/configure @@ -1890,6 +1890,12 @@ else step_msg "complete" fi +if [ "$CFG_SRC_DIR" = `pwd` ]; then + X_PY=x.py +else + X_PY=${CFG_SRC_DIR_RELATIVE}x.py +fi + if [ -z "$CFG_DISABLE_RUSTBUILD" ]; then msg "NOTE you have now configured rust to use a rewritten build system" msg " called rustbuild, and as a result this may have bugs that " @@ -1897,7 +1903,7 @@ if [ -z "$CFG_DISABLE_RUSTBUILD" ]; then msg " go back to the old build system with --disable-rustbuild and" msg " please feel free to report any bugs!" msg "" - msg "run \`python x.py --help\`" + msg "run \`python ${X_PY} --help\`" else warn "the makefile-based build system is deprecated in favor of rustbuild" msg "" diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index b165048b7b6..a06e2f3fb54 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -1,4 +1,4 @@ -# Copyright 20126 The Rust Project Developers. See the COPYRIGHT +# Copyright 2016 The Rust Project Developers. See the COPYRIGHT # file at the top-level directory of this distribution and at # http://rust-lang.org/COPYRIGHT. # From d38db82b291afe172c9477b44ef99f70013010d9 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 8 Dec 2016 17:13:55 -0800 Subject: [PATCH 276/293] rustbuild: Implement distcheck This commit implements the `distcheck` target for rustbuild which is only ever run on our nightly bots. This essentially just creates a tarball, un-tars it, and then runs a full build, validating that the release tarballs do indeed have everything they need to build Rust. --- src/bootstrap/check.rs | 30 ++++++++++++++++++++++++++++++ src/bootstrap/dist.rs | 7 ++++++- src/bootstrap/mk/Makefile.in | 2 ++ src/bootstrap/step.rs | 12 ++++-------- 4 files changed, 42 insertions(+), 9 deletions(-) diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index c5675fd46cb..46c7fe4753f 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -23,6 +23,7 @@ use std::process::Command; use build_helper::output; use {Build, Compiler, Mode}; +use dist; use util::{self, dylib_path, dylib_path_var}; const ADB_TEST_DIR: &'static str = "/data/tmp"; @@ -517,3 +518,32 @@ pub fn android_copy_libs(build: &Build, } } } + +/// Run "distcheck", a 'make check' from a tarball +pub fn distcheck(build: &Build) { + if build.config.build != "x86_64-unknown-linux-gnu" { + return + } + if !build.config.host.iter().any(|s| s == "x86_64-unknown-linux-gnu") { + return + } + if !build.config.target.iter().any(|s| s == "x86_64-unknown-linux-gnu") { + return + } + + let dir = build.out.join("tmp").join("distcheck"); + let _ = fs::remove_dir_all(&dir); + t!(fs::create_dir_all(&dir)); + + let mut cmd = Command::new("tar"); + cmd.arg("-xzf") + .arg(dist::rust_src_location(build)) + .arg("--strip-components=1") + .current_dir(&dir); + build.run(&mut cmd); + build.run(Command::new("./configure") + .current_dir(&dir)); + build.run(Command::new("make") + .arg("check") + .current_dir(&dir)); +} diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index d603455122e..2fcd45f751c 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -284,6 +284,11 @@ pub fn std(build: &Build, compiler: &Compiler, target: &str) { t!(fs::remove_dir_all(&image)); } +pub fn rust_src_location(build: &Build) -> PathBuf { + let plain_name = format!("rustc-{}-src", package_vers(build)); + distdir(build).join(&format!("{}.tar.gz", plain_name)) +} + /// Creates the `rust-src` installer component and the plain source tarball pub fn rust_src(build: &Build) { println!("Dist src"); @@ -374,7 +379,7 @@ pub fn rust_src(build: &Build) { // Create plain source tarball let mut cmd = Command::new("tar"); - cmd.arg("-czf").arg(sanitize_sh(&distdir(build).join(&format!("{}.tar.gz", plain_name)))) + cmd.arg("-czf").arg(sanitize_sh(&rust_src_location(build))) .arg(&plain_name) .current_dir(&dst); build.run(&mut cmd); diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index b165048b7b6..ef02f21a34b 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -55,6 +55,8 @@ check-cargotest: $(Q)$(BOOTSTRAP) test src/tools/cargotest $(BOOTSTRAP_ARGS) dist: $(Q)$(BOOTSTRAP) dist $(BOOTSTRAP_ARGS) +distcheck: + $(Q)$(BOOTSTRAP) test distcheck install: $(Q)$(BOOTSTRAP) dist --install $(BOOTSTRAP_ARGS) tidy: diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index f9eae41a330..efa3e4e5ea1 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -198,14 +198,6 @@ pub fn build_rules(build: &Build) -> Rules { }); } for (krate, path, default) in krates("rustc-main") { - // We hijacked the `src/rustc` path above for "build just the compiler" - // so let's not reinterpret it here as everything and redirect the - // `src/rustc` path to a nonexistent path. - let path = if path == "src/rustc" { - "path/to/nowhere" - } else { - path - }; rules.build(&krate.build_step, path) .dep(|s| s.name("libtest")) .dep(move |s| s.name("llvm").host(&build.config.build).stage(0)) @@ -403,6 +395,10 @@ pub fn build_rules(build: &Build) -> Rules { .default(true) .host(true) .run(move |s| check::docs(build, &s.compiler())); + rules.test("check-distcheck", "distcheck") + .dep(|s| s.name("dist-src")) + .run(move |_| check::distcheck(build)); + rules.build("test-helpers", "src/rt/rust_test_helpers.c") .run(move |s| native::test_helpers(build, s.target)); From 5a065641fda719b1eeac85419981fee9d1122ded Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 15 Nov 2016 16:09:39 +0100 Subject: [PATCH 277/293] Add checkup for return statement outside of a function --- src/librustc_typeck/check/compare_method.rs | 3 ++- src/librustc_typeck/check/mod.rs | 28 +++++++++++---------- src/librustc_typeck/check/wfcheck.rs | 3 ++- src/librustc_typeck/diagnostics.rs | 28 +++++++++++++++++++++ 4 files changed, 47 insertions(+), 15 deletions(-) diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index e85dac1a44c..21b0b5e6290 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -376,7 +376,8 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, &infcx.parameter_environment.caller_bounds); infcx.resolve_regions_and_report_errors(&free_regions, impl_m_body_id); } else { - let fcx = FnCtxt::new(&inh, tcx.types.err, impl_m_body_id); + let mut fcx = FnCtxt::new(&inh, impl_m_body_id); + fcx.ret_ty = Some(tcx.types.err); fcx.regionck_item(impl_m_body_id, impl_m_span, &[]); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 1b35081d524..755ea718f89 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -451,7 +451,7 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // expects the types within the function to be consistent. err_count_on_creation: usize, - ret_ty: Ty<'tcx>, + ret_ty: Option>, ps: RefCell, @@ -785,11 +785,12 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, // Create the function context. This is either derived from scratch or, // in the case of function expressions, based on the outer context. - let mut fcx = FnCtxt::new(inherited, fn_sig.output(), body.id); + let mut fcx = FnCtxt::new(inherited, body.id); + let ret_ty = fn_sig.output(); *fcx.ps.borrow_mut() = UnsafetyState::function(unsafety, unsafety_id); - fcx.require_type_is_sized(fcx.ret_ty, decl.output.span(), traits::ReturnType); - fcx.ret_ty = fcx.instantiate_anon_types(&fcx.ret_ty); + fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::ReturnType); + fcx.ret_ty = fcx.instantiate_anon_types(&ret_ty); fn_sig = fcx.tcx.mk_fn_sig(fn_sig.inputs().iter().cloned(), &fcx.ret_ty, fn_sig.variadic); { @@ -821,7 +822,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig); - fcx.check_expr_coercable_to_type(body, fcx.ret_ty); + fcx.check_expr_coercable_to_type(body, fcx.ret_ty.unwrap()); fcx } @@ -1245,7 +1246,7 @@ fn check_const_with_type<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, expected_type: Ty<'tcx>, id: ast::NodeId) { ccx.inherited(id).enter(|inh| { - let fcx = FnCtxt::new(&inh, expected_type, expr.id); + let fcx = FnCtxt::new(&inh, expr.id); fcx.require_type_is_sized(expected_type, expr.span, traits::ConstSized); // Gather locals in statics (because of block expressions). @@ -1530,7 +1531,6 @@ enum TupleArgumentsFlag { impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn new(inh: &'a Inherited<'a, 'gcx, 'tcx>, - rty: Ty<'tcx>, body_id: ast::NodeId) -> FnCtxt<'a, 'gcx, 'tcx> { FnCtxt { @@ -1538,7 +1538,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { body_id: body_id, writeback_errors: Cell::new(false), err_count_on_creation: inh.tcx.sess.err_count(), - ret_ty: rty, + ret_ty: None, ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, ast::CRATE_NODE_ID)), diverges: Cell::new(Diverges::Maybe), @@ -3705,14 +3705,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } hir::ExprAgain(_) => { tcx.types.never } hir::ExprRet(ref expr_opt) => { - if let Some(ref e) = *expr_opt { - self.check_expr_coercable_to_type(&e, self.ret_ty); + if self.ret_ty.is_none() { + struct_span_err!(self.tcx.sess, expr.span, E0571, + "return statement cannot be out of a function scope").emit(); + } else if let Some(ref e) = *expr_opt { + self.check_expr_coercable_to_type(&e, self.ret_ty.unwrap()); } else { match self.eq_types(false, &self.misc(expr.span), - self.ret_ty, - tcx.mk_nil()) - { + self.ret_ty.unwrap(), + tcx.mk_nil()) { Ok(ok) => self.register_infer_ok_obligations(ok), Err(_) => { struct_span_err!(tcx.sess, expr.span, E0069, diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 7f35c8efeff..6942bb0934c 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -51,7 +51,8 @@ impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> { let id = self.id; let span = self.span; self.inherited.enter(|inh| { - let fcx = FnCtxt::new(&inh, inh.ccx.tcx.types.never, id); + let mut fcx = FnCtxt::new(&inh, id); + fcx.ret_ty = Some(inh.ccx.tcx.types.never); let wf_tys = f(&fcx, &mut CheckTypeWellFormedVisitor { ccx: fcx.ccx, code: code diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 01e99a296e8..65b606b4582 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4164,6 +4164,34 @@ target / ABI combination is currently unsupported by llvm. If necessary, you can circumvent this check using custom target specifications. "##, +E0571: r##" +A return statement was outside a function scope. + +Erroneous code example: + +```compile_fail,E0571 +const FOO: u32 = return 0; // error: return statement cannot be out of a + // function scope + +fn main() {} +``` + +To fix this issue, just remove the return statement or move it into a function +scope. Example: + +``` +const FOO: u32 = 0; + +fn some_fn() -> i32 { + return FOO; +} + +fn main() { + some_fn(); +} +``` +"##, + } register_diagnostics! { From 8dee5ab805298bcb095a262787ddf60cc48b10ba Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 15 Nov 2016 16:11:06 +0100 Subject: [PATCH 278/293] Add E0571 test --- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/diagnostics.rs | 11 +++++------ src/test/compile-fail/E0571.rs | 13 +++++++++++++ 3 files changed, 19 insertions(+), 7 deletions(-) create mode 100644 src/test/compile-fail/E0571.rs diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 755ea718f89..1ace79b0c55 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3707,7 +3707,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::ExprRet(ref expr_opt) => { if self.ret_ty.is_none() { struct_span_err!(self.tcx.sess, expr.span, E0571, - "return statement cannot be out of a function scope").emit(); + "return statement outside of function body").emit(); } else if let Some(ref e) = *expr_opt { self.check_expr_coercable_to_type(&e, self.ret_ty.unwrap()); } else { diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 65b606b4582..86220cf57c4 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4165,24 +4165,23 @@ If necessary, you can circumvent this check using custom target specifications. "##, E0571: r##" -A return statement was outside a function scope. +A return statement was found outside of a function body. Erroneous code example: ```compile_fail,E0571 -const FOO: u32 = return 0; // error: return statement cannot be out of a - // function scope +const FOO: u32 = return 0; // error: return statement outside of function body fn main() {} ``` -To fix this issue, just remove the return statement or move it into a function -scope. Example: +To fix this issue, just remove the return keyword or move the expression into a +function. Example: ``` const FOO: u32 = 0; -fn some_fn() -> i32 { +fn some_fn() -> u32 { return FOO; } diff --git a/src/test/compile-fail/E0571.rs b/src/test/compile-fail/E0571.rs new file mode 100644 index 00000000000..d300c597008 --- /dev/null +++ b/src/test/compile-fail/E0571.rs @@ -0,0 +1,13 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +const FOO: u32 = return 0; //~ ERROR E0571 + +fn main() {} From 64de44e0a12a1b933d8d01a9873cf030be2af214 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 17 Nov 2016 22:47:30 +0100 Subject: [PATCH 279/293] Set back Ty parameter to FnCntxt --- src/librustc_typeck/check/compare_method.rs | 3 +-- src/librustc_typeck/check/mod.rs | 7 ++++--- src/librustc_typeck/check/wfcheck.rs | 3 +-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 21b0b5e6290..478de167317 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -376,8 +376,7 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, &infcx.parameter_environment.caller_bounds); infcx.resolve_regions_and_report_errors(&free_regions, impl_m_body_id); } else { - let mut fcx = FnCtxt::new(&inh, impl_m_body_id); - fcx.ret_ty = Some(tcx.types.err); + let fcx = FnCtxt::new(&inh, Some(tcx.types.err), impl_m_body_id); fcx.regionck_item(impl_m_body_id, impl_m_span, &[]); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 1ace79b0c55..a43ec0aaf11 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -785,7 +785,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, // Create the function context. This is either derived from scratch or, // in the case of function expressions, based on the outer context. - let mut fcx = FnCtxt::new(inherited, body.id); + let mut fcx = FnCtxt::new(inherited, None, body.id); let ret_ty = fn_sig.output(); *fcx.ps.borrow_mut() = UnsafetyState::function(unsafety, unsafety_id); @@ -1246,7 +1246,7 @@ fn check_const_with_type<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, expected_type: Ty<'tcx>, id: ast::NodeId) { ccx.inherited(id).enter(|inh| { - let fcx = FnCtxt::new(&inh, expr.id); + let fcx = FnCtxt::new(&inh, None, expr.id); fcx.require_type_is_sized(expected_type, expr.span, traits::ConstSized); // Gather locals in statics (because of block expressions). @@ -1531,6 +1531,7 @@ enum TupleArgumentsFlag { impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn new(inh: &'a Inherited<'a, 'gcx, 'tcx>, + rty: Option>, body_id: ast::NodeId) -> FnCtxt<'a, 'gcx, 'tcx> { FnCtxt { @@ -1538,7 +1539,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { body_id: body_id, writeback_errors: Cell::new(false), err_count_on_creation: inh.tcx.sess.err_count(), - ret_ty: None, + ret_ty: rty, ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, ast::CRATE_NODE_ID)), diverges: Cell::new(Diverges::Maybe), diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 6942bb0934c..ffdb56753fd 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -51,8 +51,7 @@ impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> { let id = self.id; let span = self.span; self.inherited.enter(|inh| { - let mut fcx = FnCtxt::new(&inh, id); - fcx.ret_ty = Some(inh.ccx.tcx.types.never); + let fcx = FnCtxt::new(&inh, Some(inh.ccx.tcx.types.never), id); let wf_tys = f(&fcx, &mut CheckTypeWellFormedVisitor { ccx: fcx.ccx, code: code From b1dd793acdde01f7fb50b7c29bc6519e4ce3f22a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 6 Dec 2016 15:32:30 -0800 Subject: [PATCH 280/293] Update to last master --- src/librustc_typeck/check/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a43ec0aaf11..abc1c5e4b4c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -790,8 +790,9 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, *fcx.ps.borrow_mut() = UnsafetyState::function(unsafety, unsafety_id); fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::ReturnType); - fcx.ret_ty = fcx.instantiate_anon_types(&ret_ty); - fn_sig = fcx.tcx.mk_fn_sig(fn_sig.inputs().iter().cloned(), &fcx.ret_ty, fn_sig.variadic); + fcx.ret_ty = fcx.instantiate_anon_types(&Some(ret_ty)); + fn_sig = fcx.tcx.mk_fn_sig(fn_sig.inputs().iter().cloned(), &fcx.ret_ty.unwrap(), + fn_sig.variadic); { let mut visit = GatherLocalsVisitor { fcx: &fcx, }; From ed3c483aa8472bf791718d6f157e4e55873e7e5d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 8 Dec 2016 20:49:26 -0800 Subject: [PATCH 281/293] Change error to E0572 --- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/diagnostics.rs | 4 ++-- src/test/compile-fail/{E0571.rs => E0572.rs} | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename src/test/compile-fail/{E0571.rs => E0572.rs} (91%) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index abc1c5e4b4c..9c8d7caefe5 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3708,7 +3708,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::ExprAgain(_) => { tcx.types.never } hir::ExprRet(ref expr_opt) => { if self.ret_ty.is_none() { - struct_span_err!(self.tcx.sess, expr.span, E0571, + struct_span_err!(self.tcx.sess, expr.span, E0572, "return statement outside of function body").emit(); } else if let Some(ref e) = *expr_opt { self.check_expr_coercable_to_type(&e, self.ret_ty.unwrap()); diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 86220cf57c4..71507063ffc 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4164,12 +4164,12 @@ target / ABI combination is currently unsupported by llvm. If necessary, you can circumvent this check using custom target specifications. "##, -E0571: r##" +E0572: r##" A return statement was found outside of a function body. Erroneous code example: -```compile_fail,E0571 +```compile_fail,E0572 const FOO: u32 = return 0; // error: return statement outside of function body fn main() {} diff --git a/src/test/compile-fail/E0571.rs b/src/test/compile-fail/E0572.rs similarity index 91% rename from src/test/compile-fail/E0571.rs rename to src/test/compile-fail/E0572.rs index d300c597008..bbaab102de7 100644 --- a/src/test/compile-fail/E0571.rs +++ b/src/test/compile-fail/E0572.rs @@ -8,6 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -const FOO: u32 = return 0; //~ ERROR E0571 +const FOO: u32 = return 0; //~ ERROR E0572 fn main() {} From acfb06fd593ed803a3da056c9d5acb399697d0e8 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 9 Dec 2016 11:27:45 +0100 Subject: [PATCH 282/293] remove double negation in comment --- src/librustc_trans/collector.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 087fe4decbf..d64fb95cbb6 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -706,9 +706,9 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { fn can_have_local_instance<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool { - // Take a look if we have the definition available. If not, we - // will not emit code for this item in the local crate, and thus - // don't create a translation item for it. + // Take a look if we have the definition available. If so, we + // will emit code for this item in the local crate, and thus + // create a translation item for it. def_id.is_local() || tcx.sess.cstore.is_item_mir_available(def_id) } From 910c369c9297b7e6a508bcc84b38fada8d5f4d7b Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 9 Dec 2016 16:31:53 +0100 Subject: [PATCH 283/293] enable checking for const fn without needing to go through `entry` --- src/librustc_metadata/decoder.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 2a6063cc4bd..e0786887728 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -504,6 +504,14 @@ impl<'tcx> EntryKind<'tcx> { EntryKind::Closure(_) => return None, }) } + fn is_const_fn(&self, meta: &CrateMetadata) -> bool { + let constness = match *self { + EntryKind::Method(data) => data.decode(meta).fn_data.constness, + EntryKind::Fn(data) => data.decode(meta).constness, + _ => hir::Constness::NotConst, + }; + constness == hir::Constness::Const + } } impl<'a, 'tcx> CrateMetadata { @@ -1051,12 +1059,7 @@ impl<'a, 'tcx> CrateMetadata { } pub fn is_const_fn(&self, id: DefIndex) -> bool { - let constness = match self.entry(id).kind { - EntryKind::Method(data) => data.decode(self).fn_data.constness, - EntryKind::Fn(data) => data.decode(self).constness, - _ => hir::Constness::NotConst, - }; - constness == hir::Constness::Const + self.entry(id).kind.is_const_fn(self) } pub fn is_foreign_item(&self, id: DefIndex) -> bool { From d74d15345cab54860a6e8cf19021372665ce0577 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 9 Dec 2016 17:29:01 +0100 Subject: [PATCH 284/293] move the check for instantiation from metadata encoding to the actual decision site before it was assumed that anything that had a MIR was fair game for local instatiation --- src/librustc/middle/cstore.rs | 8 ++++++++ src/librustc_metadata/cstore_impl.rs | 5 +++++ src/librustc_metadata/decoder.rs | 23 +++++++++++++++++++++++ src/librustc_trans/collector.rs | 5 +---- 4 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 78bbb03f40d..f2be97c8323 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -355,6 +355,11 @@ pub trait CrateStore<'tcx> { fn get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Mir<'tcx>; fn is_item_mir_available(&self, def: DefId) -> bool; + /// Take a look if we need to inline or monomorphize this. If so, we + /// will emit code for this item in the local crate, and thus + /// create a translation item for it. + fn can_have_local_instance<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> bool; + // This is basically a 1-based range of ints, which is a little // silly - I may fix that. fn crates(&self) -> Vec; @@ -528,6 +533,9 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn is_item_mir_available(&self, def: DefId) -> bool { bug!("is_item_mir_available") } + fn can_have_local_instance<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> bool { + bug!("can_have_local_instance") + } // This is basically a 1-based range of ints, which is a little // silly - I may fix that. diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 2882efb75b0..1a1bb1432ee 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -527,6 +527,11 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { self.get_crate_data(def.krate).is_item_mir_available(def.index) } + fn can_have_local_instance<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> bool { + self.dep_graph.read(DepNode::MetaData(def)); + def.is_local() || self.get_crate_data(def.krate).can_have_local_instance(tcx, def.index) + } + fn crates(&self) -> Vec { let mut result = vec![]; diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index e0786887728..54c195b1881 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -847,6 +847,29 @@ impl<'a, 'tcx> CrateMetadata { self.maybe_entry(id).and_then(|item| item.decode(self).mir).is_some() } + pub fn can_have_local_instance(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + id: DefIndex) -> bool { + self.maybe_entry(id).map_or(false, |item| { + let item = item.decode(self); + // if we don't have a MIR, then this item was never meant to be locally instantiated + // or we have a bug in the metadata serialization + item.mir.is_some() && ( + // items with generics always can have local instances if monomorphized + item.generics.map_or(false, |generics| { + let generics = generics.decode((self, tcx)); + generics.parent_types != 0 || !generics.types.is_empty() + }) || + match item.kind { + EntryKind::Closure(_) => true, + _ => false, + } || + item.kind.is_const_fn(self) || + attr::requests_inline(&self.get_attributes(&item)) + ) + }) + } + pub fn maybe_get_item_mir(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefIndex) diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index d64fb95cbb6..3af3ada66b3 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -706,10 +706,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { fn can_have_local_instance<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool { - // Take a look if we have the definition available. If so, we - // will emit code for this item in the local crate, and thus - // create a translation item for it. - def_id.is_local() || tcx.sess.cstore.is_item_mir_available(def_id) + tcx.sess.cstore.can_have_local_instance(tcx, def_id) } fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, From fbc3f11fc18a626ba9b9f6bc52de4fc5ef75154b Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Fri, 9 Dec 2016 16:28:54 +0100 Subject: [PATCH 285/293] mir: Reinstate while loop in deaggregator pass A previous commit must have removed the `while let` loop here by mistake; for each basic block, it should find and deaggregate multiple statements in their index order, and the `curr` index tracks the progress through the block. This fixes both the case of deaggregating statements in separate basic blocks (preserving `curr` could prevent that) as well as multiple times in the same block (missing loop prevented that). --- src/librustc_mir/transform/deaggregator.rs | 119 +++++++++--------- src/test/mir-opt/deaggregator_test_enum_2.rs | 57 +++++++++ .../mir-opt/deaggregator_test_multiple.rs | 48 +++++++ 3 files changed, 164 insertions(+), 60 deletions(-) create mode 100644 src/test/mir-opt/deaggregator_test_enum_2.rs create mode 100644 src/test/mir-opt/deaggregator_test_multiple.rs diff --git a/src/librustc_mir/transform/deaggregator.rs b/src/librustc_mir/transform/deaggregator.rs index fcdeae6d6c0..e13c8e02137 100644 --- a/src/librustc_mir/transform/deaggregator.rs +++ b/src/librustc_mir/transform/deaggregator.rs @@ -36,71 +36,70 @@ impl<'tcx> MirPass<'tcx> for Deaggregator { // In fact, we might not want to trigger in other cases. // Ex: when we could use SROA. See issue #35259 - let mut curr: usize = 0; for bb in mir.basic_blocks_mut() { - let idx = match get_aggregate_statement_index(curr, &bb.statements) { - Some(idx) => idx, - None => continue, - }; - // do the replacement - debug!("removing statement {:?}", idx); - let src_info = bb.statements[idx].source_info; - let suffix_stmts = bb.statements.split_off(idx+1); - let orig_stmt = bb.statements.pop().unwrap(); - let (lhs, rhs) = match orig_stmt.kind { - StatementKind::Assign(ref lhs, ref rhs) => (lhs, rhs), - _ => span_bug!(src_info.span, "expected assign, not {:?}", orig_stmt), - }; - let (agg_kind, operands) = match rhs { - &Rvalue::Aggregate(ref agg_kind, ref operands) => (agg_kind, operands), - _ => span_bug!(src_info.span, "expected aggregate, not {:?}", rhs), - }; - let (adt_def, variant, substs) = match agg_kind { - &AggregateKind::Adt(adt_def, variant, substs, None) => (adt_def, variant, substs), - _ => span_bug!(src_info.span, "expected struct, not {:?}", rhs), - }; - let n = bb.statements.len(); - bb.statements.reserve(n + operands.len() + suffix_stmts.len()); - for (i, op) in operands.iter().enumerate() { - let ref variant_def = adt_def.variants[variant]; - let ty = variant_def.fields[i].ty(tcx, substs); - let rhs = Rvalue::Use(op.clone()); + let mut curr: usize = 0; + while let Some(idx) = get_aggregate_statement_index(curr, &bb.statements) { + // do the replacement + debug!("removing statement {:?}", idx); + let src_info = bb.statements[idx].source_info; + let suffix_stmts = bb.statements.split_off(idx+1); + let orig_stmt = bb.statements.pop().unwrap(); + let (lhs, rhs) = match orig_stmt.kind { + StatementKind::Assign(ref lhs, ref rhs) => (lhs, rhs), + _ => span_bug!(src_info.span, "expected assign, not {:?}", orig_stmt), + }; + let (agg_kind, operands) = match rhs { + &Rvalue::Aggregate(ref agg_kind, ref operands) => (agg_kind, operands), + _ => span_bug!(src_info.span, "expected aggregate, not {:?}", rhs), + }; + let (adt_def, variant, substs) = match agg_kind { + &AggregateKind::Adt(adt_def, variant, substs, None) + => (adt_def, variant, substs), + _ => span_bug!(src_info.span, "expected struct, not {:?}", rhs), + }; + let n = bb.statements.len(); + bb.statements.reserve(n + operands.len() + suffix_stmts.len()); + for (i, op) in operands.iter().enumerate() { + let ref variant_def = adt_def.variants[variant]; + let ty = variant_def.fields[i].ty(tcx, substs); + let rhs = Rvalue::Use(op.clone()); - let lhs_cast = if adt_def.variants.len() > 1 { - Lvalue::Projection(Box::new(LvalueProjection { - base: lhs.clone(), - elem: ProjectionElem::Downcast(adt_def, variant), - })) - } else { - lhs.clone() + let lhs_cast = if adt_def.variants.len() > 1 { + Lvalue::Projection(Box::new(LvalueProjection { + base: lhs.clone(), + elem: ProjectionElem::Downcast(adt_def, variant), + })) + } else { + lhs.clone() + }; + + let lhs_proj = Lvalue::Projection(Box::new(LvalueProjection { + base: lhs_cast, + elem: ProjectionElem::Field(Field::new(i), ty), + })); + let new_statement = Statement { + source_info: src_info, + kind: StatementKind::Assign(lhs_proj, rhs), + }; + debug!("inserting: {:?} @ {:?}", new_statement, idx + i); + bb.statements.push(new_statement); + } + + // if the aggregate was an enum, we need to set the discriminant + if adt_def.variants.len() > 1 { + let set_discriminant = Statement { + kind: StatementKind::SetDiscriminant { + lvalue: lhs.clone(), + variant_index: variant, + }, + source_info: src_info, + }; + bb.statements.push(set_discriminant); }; - let lhs_proj = Lvalue::Projection(Box::new(LvalueProjection { - base: lhs_cast, - elem: ProjectionElem::Field(Field::new(i), ty), - })); - let new_statement = Statement { - source_info: src_info, - kind: StatementKind::Assign(lhs_proj, rhs), - }; - debug!("inserting: {:?} @ {:?}", new_statement, idx + i); - bb.statements.push(new_statement); + curr = bb.statements.len(); + bb.statements.extend(suffix_stmts); } - - // if the aggregate was an enum, we need to set the discriminant - if adt_def.variants.len() > 1 { - let set_discriminant = Statement { - kind: StatementKind::SetDiscriminant { - lvalue: lhs.clone(), - variant_index: variant, - }, - source_info: src_info, - }; - bb.statements.push(set_discriminant); - }; - - curr = bb.statements.len(); - bb.statements.extend(suffix_stmts); } } } diff --git a/src/test/mir-opt/deaggregator_test_enum_2.rs b/src/test/mir-opt/deaggregator_test_enum_2.rs new file mode 100644 index 00000000000..02d496b2901 --- /dev/null +++ b/src/test/mir-opt/deaggregator_test_enum_2.rs @@ -0,0 +1,57 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that deaggregate fires in more than one basic block + +enum Foo { + A(i32), + B(i32), +} + +fn test1(x: bool, y: i32) -> Foo { + if x { + Foo::A(y) + } else { + Foo::B(y) + } +} + +fn main() {} + +// END RUST SOURCE +// START rustc.node12.Deaggregator.before.mir +// bb1: { +// _6 = _4; +// _0 = Foo::A(_6,); +// goto -> bb3; +// } +// +// bb2: { +// _7 = _4; +// _0 = Foo::B(_7,); +// goto -> bb3; +// } +// END rustc.node12.Deaggregator.before.mir +// START rustc.node12.Deaggregator.after.mir +// bb1: { +// _6 = _4; +// ((_0 as A).0: i32) = _6; +// discriminant(_0) = 0; +// goto -> bb3; +// } +// +// bb2: { +// _7 = _4; +// ((_0 as B).0: i32) = _7; +// discriminant(_0) = 1; +// goto -> bb3; +// } +// END rustc.node12.Deaggregator.after.mir +// diff --git a/src/test/mir-opt/deaggregator_test_multiple.rs b/src/test/mir-opt/deaggregator_test_multiple.rs new file mode 100644 index 00000000000..a180a69be55 --- /dev/null +++ b/src/test/mir-opt/deaggregator_test_multiple.rs @@ -0,0 +1,48 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that deaggregate fires more than once per block + +enum Foo { + A(i32), + B, +} + +fn test(x: i32) -> [Foo; 2] { + [Foo::A(x), Foo::A(x)] +} + +fn main() { } + +// END RUST SOURCE +// START rustc.node10.Deaggregator.before.mir +// bb0: { +// _2 = _1; +// _4 = _2; +// _3 = Foo::A(_4,); +// _6 = _2; +// _5 = Foo::A(_6,); +// _0 = [_3, _5]; +// return; +// } +// END rustc.node10.Deaggregator.before.mir +// START rustc.node10.Deaggregator.after.mir +// bb0: { +// _2 = _1; +// _4 = _2; +// ((_3 as A).0: i32) = _4; +// discriminant(_3) = 0; +// _6 = _2; +// ((_5 as A).0: i32) = _6; +// discriminant(_5) = 0; +// _0 = [_3, _5]; +// return; +// } +// END rustc.node10.Deaggregator.after.mir From c49ba058a0d61b929975f47daf25f19dd22de9c6 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 27 Oct 2016 11:41:56 +1300 Subject: [PATCH 286/293] Create tar balls of save-analysis-api metadata for the standard libraries as part of `make dist`. --- src/bootstrap/bin/rustc.rs | 5 +++++ src/bootstrap/dist.rs | 46 +++++++++++++++++++++++++++++++++++++- src/bootstrap/lib.rs | 4 ++++ src/bootstrap/step.rs | 4 ++++ 4 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 879eca60cc7..2f674a311fe 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -125,6 +125,11 @@ fn main() { cmd.arg("-C").arg(format!("codegen-units={}", s)); } + // Emit save-analysis info. + if env::var("RUSTC_SAVE_ANALYSIS") == Ok("api".to_string()) { + cmd.arg("-Zsave-analysis-api"); + } + // Dealing with rpath here is a little special, so let's go into some // detail. First off, `-rpath` is a linker option on Unix platforms // which adds to the runtime dynamic loader path when looking for diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 2fcd45f751c..1d3445a9eac 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -23,7 +23,7 @@ use std::io::Write; use std::path::{PathBuf, Path}; use std::process::Command; -use {Build, Compiler}; +use {Build, Compiler, Mode}; use util::{cp_r, libdir, is_dylib, cp_filtered, copy}; pub fn package_vers(build: &Build) -> &str { @@ -289,6 +289,50 @@ pub fn rust_src_location(build: &Build) -> PathBuf { distdir(build).join(&format!("{}.tar.gz", plain_name)) } +/// Creates a tarball of save-analysis metadata, if available. +pub fn analysis(build: &Build, compiler: &Compiler, target: &str) { + println!("Dist analysis"); + + if build.config.channel != "nightly" { + println!("Skipping dist-analysis - not on nightly channel"); + return; + } + if compiler.stage != 2 { + return + } + + let name = format!("rust-analysis-{}", package_vers(build)); + let image = tmpdir(build).join(format!("{}-{}-image", name, target)); + + let src = build.stage_out(compiler, Mode::Libstd).join(target).join("release").join("deps"); + + let image_src = src.join("save-analysis"); + let dst = image.join("lib/rustlib").join(target).join("analysis"); + t!(fs::create_dir_all(&dst)); + cp_r(&image_src, &dst); + + let mut cmd = Command::new("sh"); + cmd.arg(sanitize_sh(&build.src.join("src/rust-installer/gen-installer.sh"))) + .arg("--product-name=Rust") + .arg("--rel-manifest-dir=rustlib") + .arg("--success-message=save-analysis-saved.") + .arg(format!("--image-dir={}", sanitize_sh(&image))) + .arg(format!("--work-dir={}", sanitize_sh(&tmpdir(build)))) + .arg(format!("--output-dir={}", sanitize_sh(&distdir(build)))) + .arg(format!("--package-name={}-{}", name, target)) + .arg(format!("--component-name=rust-analysis-{}", target)) + .arg("--legacy-manifest-dirs=rustlib,cargo"); + build.run(&mut cmd); + t!(fs::remove_dir_all(&image)); + + // Create plain source tarball + let mut cmd = Command::new("tar"); + cmd.arg("-czf").arg(sanitize_sh(&distdir(build).join(&format!("{}.tar.gz", name)))) + .arg("analysis") + .current_dir(&src); + build.run(&mut cmd); +} + /// Creates the `rust-src` installer component and the plain source tarball pub fn rust_src(build: &Build) { println!("Dist src"); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 912b5864c81..cd80c4298dc 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -507,6 +507,10 @@ impl Build { .env(format!("CFLAGS_{}", target), self.cflags(target).join(" ")); } + if self.config.channel == "nightly" && compiler.stage == 2 { + cargo.env("RUSTC_SAVE_ANALYSIS", "api".to_string()); + } + // Environment variables *required* needed throughout the build // // FIXME: should update code to not require this env var diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index efa3e4e5ea1..884cc7da8ea 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -499,6 +499,10 @@ pub fn build_rules(build: &Build) -> Rules { .default(true) .dep(|s| s.name("default:doc")) .run(move |s| dist::docs(build, s.stage, s.target)); + rules.dist("dist-analysis", "src/libstd") + .dep(|s| s.name("dist-std")) + .default(true) + .run(move |s| dist::analysis(build, &s.compiler(), s.target)); rules.dist("install", "src") .dep(|s| s.name("default:dist")) .run(move |s| install::install(build, s.stage, s.target)); From 4a494ed8df3e3fadf59a25f70265c067b36f94b6 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 9 Dec 2016 17:13:13 -0500 Subject: [PATCH 287/293] incr.comp.: Take symbol visibility into account for CGU hashes. --- src/librustc_incremental/lib.rs | 1 + src/librustc_trans/base.rs | 14 ++++++++------ src/librustc_trans/context.rs | 7 ++++++- src/librustc_trans/partitioning.rs | 28 ++++++++++++++++++++++------ 4 files changed, 37 insertions(+), 13 deletions(-) diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index b72766bccea..3cb5244413b 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -48,6 +48,7 @@ pub mod ich; pub use assert_dep_graph::assert_dep_graph; pub use calculate_svh::compute_incremental_hashes_map; pub use calculate_svh::IncrementalHashesMap; +pub use calculate_svh::hasher::IchHasher; pub use persist::load_dep_graph; pub use persist::save_dep_graph; pub use persist::save_trans_partition; diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 5b79f040d0f..f70c24c3ccb 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1610,7 +1610,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let symbol_map = Rc::new(symbol_map); - let previous_work_products = trans_reuse_previous_work_products(tcx, + let previous_work_products = trans_reuse_previous_work_products(&shared_ccx, &codegen_units, &symbol_map); @@ -1630,7 +1630,9 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ModuleTranslation { name: String::from(ccx.codegen_unit().name()), - symbol_name_hash: ccx.codegen_unit().compute_symbol_name_hash(tcx, &symbol_map), + symbol_name_hash: ccx.codegen_unit() + .compute_symbol_name_hash(&shared_ccx, + &symbol_map), source: source, } }) @@ -1962,7 +1964,7 @@ fn gather_type_sizes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { /// For each CGU, identify if we can reuse an existing object file (or /// maybe other context). -fn trans_reuse_previous_work_products(tcx: TyCtxt, +fn trans_reuse_previous_work_products(scx: &SharedCrateContext, codegen_units: &[CodegenUnit], symbol_map: &SymbolMap) -> Vec> { @@ -1972,16 +1974,16 @@ fn trans_reuse_previous_work_products(tcx: TyCtxt, .map(|cgu| { let id = cgu.work_product_id(); - let hash = cgu.compute_symbol_name_hash(tcx, symbol_map); + let hash = cgu.compute_symbol_name_hash(scx, symbol_map); debug!("trans_reuse_previous_work_products: id={:?} hash={}", id, hash); - if let Some(work_product) = tcx.dep_graph.previous_work_product(&id) { + if let Some(work_product) = scx.dep_graph().previous_work_product(&id) { if work_product.input_hash == hash { debug!("trans_reuse_previous_work_products: reusing {:?}", work_product); return Some(work_product); } else { - if tcx.sess.opts.debugging_opts.incremental_info { + if scx.sess().opts.debugging_opts.incremental_info { println!("incremental: CGU `{}` invalidated because of \ changed partitioning hash.", cgu.name()); diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 262b8362397..8b98eb57814 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -10,7 +10,8 @@ use llvm; use llvm::{ContextRef, ModuleRef, ValueRef, BuilderRef}; -use rustc::dep_graph::{DepNode, DepTrackingMap, DepTrackingMapConfig, WorkProduct}; +use rustc::dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig, + WorkProduct}; use middle::cstore::LinkMeta; use rustc::hir::def::ExportMap; use rustc::hir::def_id::DefId; @@ -551,6 +552,10 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { &self.tcx.sess } + pub fn dep_graph<'a>(&'a self) -> &'a DepGraph { + &self.tcx.dep_graph + } + pub fn stats<'a>(&'a self) -> &'a Stats { &self.stats } diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index a36960993e4..d93bbec7efa 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -126,10 +126,10 @@ use rustc::hir::map::DefPathData; use rustc::session::config::NUMBERED_CODEGEN_UNIT_MARKER; use rustc::ty::TyCtxt; use rustc::ty::item_path::characteristic_def_id_of_type; +use rustc_incremental::IchHasher; use std::cmp::Ordering; -use std::hash::{Hash, Hasher}; +use std::hash::Hash; use std::sync::Arc; -use std::collections::hash_map::DefaultHasher; use symbol_map::SymbolMap; use syntax::ast::NodeId; use syntax::symbol::{Symbol, InternedString}; @@ -188,14 +188,30 @@ impl<'tcx> CodegenUnit<'tcx> { DepNode::WorkProduct(self.work_product_id()) } - pub fn compute_symbol_name_hash(&self, tcx: TyCtxt, symbol_map: &SymbolMap) -> u64 { - let mut state = DefaultHasher::new(); - let all_items = self.items_in_deterministic_order(tcx, symbol_map); + pub fn compute_symbol_name_hash(&self, + scx: &SharedCrateContext, + symbol_map: &SymbolMap) -> u64 { + let mut state = IchHasher::new(); + let exported_symbols = scx.exported_symbols(); + let all_items = self.items_in_deterministic_order(scx.tcx(), symbol_map); for (item, _) in all_items { let symbol_name = symbol_map.get(item).unwrap(); + symbol_name.len().hash(&mut state); symbol_name.hash(&mut state); + let exported = match item { + TransItem::Fn(ref instance) => { + let node_id = scx.tcx().map.as_local_node_id(instance.def); + node_id.map(|node_id| exported_symbols.contains(&node_id)) + .unwrap_or(false) + } + TransItem::Static(node_id) => { + exported_symbols.contains(&node_id) + } + TransItem::DropGlue(..) => false, + }; + exported.hash(&mut state); } - state.finish() + state.finish().to_smaller_hash() } pub fn items_in_deterministic_order(&self, From 90f0de8244c6d25eab841b0e24caff842ec90539 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 9 Dec 2016 17:46:31 -0500 Subject: [PATCH 288/293] incr.comp.: Add test case for symbol visibility changes --- .../change_symbol_export_status.rs | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/test/incremental/change_symbol_export_status.rs diff --git a/src/test/incremental/change_symbol_export_status.rs b/src/test/incremental/change_symbol_export_status.rs new file mode 100644 index 00000000000..71f46c641bf --- /dev/null +++ b/src/test/incremental/change_symbol_export_status.rs @@ -0,0 +1,42 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// revisions: rpass1 rpass2 + +#![feature(rustc_attrs)] +#![allow(private_no_mangle_fns)] + +#![rustc_partition_reused(module="change_symbol_export_status", cfg="rpass2")] +#![rustc_partition_translated(module="change_symbol_export_status-mod1", cfg="rpass2")] + + +// This test case makes sure that a change in symbol visibility is detected by +// our dependency tracking. We do this by changing a module's visibility to +// `private` in rpass2, causing the contained function to go from `default` to +// `hidden` visibility. +// The function is marked with #[no_mangle] so it is considered for exporting +// even from an executable. Plain Rust functions are only exported from Rust +// libraries, which our test infrastructure does not support. + +#[cfg(rpass1)] +pub mod mod1 { + #[no_mangle] + pub fn foo() {} +} + +#[cfg(rpass2)] +mod mod1 { + #[no_mangle] + pub fn foo() {} +} + +fn main() { + mod1::foo(); +} From d24028b5a83f9bbad6eca2d276ad7c0f625f6f01 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Fri, 9 Dec 2016 13:28:16 -0800 Subject: [PATCH 289/293] Add UI test for missing type parameter --- .../ui/missing-items/missing-type-parameter.rs | 15 +++++++++++++++ .../missing-items/missing-type-parameter.stderr | 10 ++++++++++ 2 files changed, 25 insertions(+) create mode 100644 src/test/ui/missing-items/missing-type-parameter.rs create mode 100644 src/test/ui/missing-items/missing-type-parameter.stderr diff --git a/src/test/ui/missing-items/missing-type-parameter.rs b/src/test/ui/missing-items/missing-type-parameter.rs new file mode 100644 index 00000000000..3671abd6624 --- /dev/null +++ b/src/test/ui/missing-items/missing-type-parameter.rs @@ -0,0 +1,15 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn foo() { } + +fn main() { + foo(); +} diff --git a/src/test/ui/missing-items/missing-type-parameter.stderr b/src/test/ui/missing-items/missing-type-parameter.stderr new file mode 100644 index 00000000000..2d007af4980 --- /dev/null +++ b/src/test/ui/missing-items/missing-type-parameter.stderr @@ -0,0 +1,10 @@ +error[E0282]: unable to infer enough type information about `X` + --> $DIR/missing-type-parameter.rs:14:5 + | +14 | foo(); + | ^^^ cannot infer type for `X` + | + = note: type annotations or generic parameter binding required + +error: aborting due to previous error + From 5e3be09b58e5ef96573db8d412a8ed5146a47ff1 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 10 Dec 2016 23:27:42 +0000 Subject: [PATCH 290/293] Check the license of vendored deps --- src/tools/tidy/src/deps.rs | 73 ++++++++++++++++++++++++++++++++++++++ src/tools/tidy/src/main.rs | 2 ++ 2 files changed, 75 insertions(+) create mode 100644 src/tools/tidy/src/deps.rs diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs new file mode 100644 index 00000000000..7592c09a913 --- /dev/null +++ b/src/tools/tidy/src/deps.rs @@ -0,0 +1,73 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Check license of third-party deps by inspecting src/vendor + +use std::fs::File; +use std::io::Read; +use std::path::Path; + +static LICENSES: &'static [&'static str] = &[ + "MIT/Apache-2.0" +]; + +pub fn check(path: &Path, bad: &mut bool) { + let path = path.join("vendor"); + assert!(path.exists(), "vendor directory missing"); + let mut saw_dir = false; + for dir in t!(path.read_dir()) { + saw_dir = true; + let dir = t!(dir); + let toml = dir.path().join("Cargo.toml"); + if !check_license(&toml) { + *bad = true; + } + } + assert!(saw_dir, "no vendored source"); +} + +fn check_license(path: &Path) -> bool { + if !path.exists() { + panic!("{} does not exist", path.display()); + } + let mut contents = String::new(); + t!(t!(File::open(path)).read_to_string(&mut contents)); + + let mut found_license = false; + for line in contents.lines() { + if !line.starts_with("license") { + continue; + } + let license = extract_license(line); + if !LICENSES.contains(&&*license) { + println!("invalid license {} in {}", license, path.display()); + return false; + } + found_license = true; + break; + } + if !found_license { + println!("no license in {}", path.display()); + return false; + } + + true +} + +fn extract_license(line: &str) -> String { + let first_quote = line.find('"'); + let last_quote = line.rfind('"'); + if let (Some(f), Some(l)) = (first_quote, last_quote) { + let license = &line[f + 1 .. l]; + license.into() + } else { + "bad-license-parse".into() + } +} diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index cb11fe261c4..7566580b1a5 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -36,6 +36,7 @@ mod errors; mod features; mod cargo; mod pal; +mod deps; fn main() { let path = env::args_os().skip(1).next().expect("need an argument"); @@ -48,6 +49,7 @@ fn main() { cargo::check(&path, &mut bad); features::check(&path, &mut bad); pal::check(&path, &mut bad); + deps::check(&path, &mut bad); if bad { panic!("some tidy checks failed"); From 6222de3ce4fcb59aeb0516305767f0043cc88f1e Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Sun, 11 Dec 2016 22:42:32 +1300 Subject: [PATCH 291/293] [LLVM 4.0] Explicitly call constructor of 'llvm::Error' The implicit constructor has been deleted. We should use Error::success() instead. The constructor in the LLVM headers mentions that "success" should be used instead of the deleted constructor for clarity. --- src/rustllvm/ArchiveWrapper.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/rustllvm/ArchiveWrapper.cpp b/src/rustllvm/ArchiveWrapper.cpp index 5adb05d6089..c7f426fbfa3 100644 --- a/src/rustllvm/ArchiveWrapper.cpp +++ b/src/rustllvm/ArchiveWrapper.cpp @@ -37,6 +37,8 @@ struct RustArchiveIterator { Archive::child_iterator end; #if LLVM_VERSION_GE(3, 9) Error err; + + RustArchiveIterator() : err(Error::success()) { } #endif }; From 6d46a21cb3fd6d9c238fb979b5f071285f23e919 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Sun, 11 Dec 2016 21:16:01 +0100 Subject: [PATCH 292/293] Simplify use of mir_opt_level Remove the unused top level option by the same name, and retain the debug option. Use -Zmir-opt-level=1 as default. One pass is enabled by default but wants to be optional: - Instcombine requires mir_opt_level > 0 Copy propagation is not used by default, but used to be activated by explicit -Zmir-opt-level=1. It must move one higher to be off by default: - CopyPropagation requires mir_opt_level > 1 Deaggregate is not used by default, and used to be on a different level than CopyPropagation: - Deaggreate requires mir_opt_level > 2 --- src/librustc/session/config.rs | 11 +++-------- src/librustc_mir/transform/copy_prop.rs | 9 ++++----- src/librustc_mir/transform/deaggregator.rs | 11 ++++------- src/librustc_mir/transform/instcombine.rs | 2 +- 4 files changed, 12 insertions(+), 21 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 17b572e7f9e..e500c08ce6e 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -269,7 +269,6 @@ top_level_options!( test: bool [TRACKED], error_format: ErrorOutputType [UNTRACKED], - mir_opt_level: usize [TRACKED], // if Some, enable incremental compilation, using the given // directory to store intermediate results @@ -435,7 +434,6 @@ pub fn basic_options() -> Options { maybe_sysroot: None, target_triple: host_triple().to_string(), test: false, - mir_opt_level: 1, incremental: None, debugging_opts: basic_debugging_options(), prints: Vec::new(), @@ -916,8 +914,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "print layout information for each type encountered"), print_trans_items: Option = (None, parse_opt_string, [UNTRACKED], "print the result of the translation item collection pass"), - mir_opt_level: Option = (None, parse_opt_uint, [TRACKED], - "set the MIR optimization level (0-3)"), + mir_opt_level: usize = (1, parse_uint, [TRACKED], + "set the MIR optimization level (0-3, default: 1)"), dump_mir: Option = (None, parse_opt_string, [UNTRACKED], "dump MIR state at various points in translation"), dump_mir_dir: Option = (None, parse_opt_string, [UNTRACKED], @@ -1322,8 +1320,6 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) let debugging_opts = build_debugging_options(matches, error_format); - let mir_opt_level = debugging_opts.mir_opt_level.unwrap_or(1); - let mut output_types = BTreeMap::new(); if !debugging_opts.parse_only { for list in matches.opt_strs("emit") { @@ -1532,7 +1528,6 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) maybe_sysroot: sysroot_opt, target_triple: target, test: test, - mir_opt_level: mir_opt_level, incremental: incremental, debugging_opts: debugging_opts, prints: prints, @@ -2475,7 +2470,7 @@ mod tests { assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); opts = reference.clone(); - opts.debugging_opts.mir_opt_level = Some(1); + opts.debugging_opts.mir_opt_level = 3; assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); } } diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs index 8c8c42a1c76..d16b51adbaf 100644 --- a/src/librustc_mir/transform/copy_prop.rs +++ b/src/librustc_mir/transform/copy_prop.rs @@ -65,11 +65,10 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation { } } - // We only run when the MIR optimization level is at least 1. This avoids messing up debug - // info. - match tcx.sess.opts.debugging_opts.mir_opt_level { - Some(0) | None => return, - _ => {} + // We only run when the MIR optimization level is > 1. + // This avoids a slow pass, and messing up debug info. + if tcx.sess.opts.debugging_opts.mir_opt_level <= 1 { + return; } loop { diff --git a/src/librustc_mir/transform/deaggregator.rs b/src/librustc_mir/transform/deaggregator.rs index fcdeae6d6c0..ccb5c36c617 100644 --- a/src/librustc_mir/transform/deaggregator.rs +++ b/src/librustc_mir/transform/deaggregator.rs @@ -23,13 +23,10 @@ impl<'tcx> MirPass<'tcx> for Deaggregator { let node_id = source.item_id(); let node_path = tcx.item_path_str(tcx.map.local_def_id(node_id)); debug!("running on: {:?}", node_path); - // we only run when mir_opt_level > 1 - match tcx.sess.opts.debugging_opts.mir_opt_level { - Some(0) | - Some(1) | - None => { return; }, - _ => {} - }; + // we only run when mir_opt_level > 2 + if tcx.sess.opts.debugging_opts.mir_opt_level <= 2 { + return; + } // Do not trigger on constants. Could be revised in future if let MirSource::Fn(_) = source {} else { return; } diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index c4a8d34bda0..3f6abb31fe9 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -38,7 +38,7 @@ impl<'tcx> MirPass<'tcx> for InstCombine { _: MirSource, mir: &mut Mir<'tcx>) { // We only run when optimizing MIR (at any level). - if tcx.sess.opts.debugging_opts.mir_opt_level == Some(0) { + if tcx.sess.opts.debugging_opts.mir_opt_level == 0 { return } From 271fb2292449848ba0259d52314d821f028cf374 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 8 Dec 2016 12:47:35 -0500 Subject: [PATCH 293/293] incr.comp.: Avoid creating an edge to DepNode::Krate when generating debuginfo namespaces. --- src/librustc/hir/map/mod.rs | 7 ++-- src/librustc_incremental/calculate_svh/mod.rs | 5 ++- .../calculate_svh/svh_visitor.rs | 22 +++++++++- src/test/incremental/issue-38222.rs | 40 +++++++++++++++++++ 4 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 src/test/incremental/issue-38222.rs diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 6ce6f6896df..117edcf14a1 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -310,8 +310,9 @@ impl<'ast> Map<'ast> { id = p; } - RootCrate => - return DepNode::Krate, + RootCrate => { + return DepNode::Hir(DefId::local(CRATE_DEF_INDEX)); + } RootInlinedParent(_) => bug!("node {} has inlined ancestor but is not inlined", id0), @@ -782,7 +783,7 @@ impl<'ast> Map<'ast> { Some(EntryVisibility(_, &Visibility::Restricted { ref path, .. })) => path.span, Some(EntryVisibility(_, v)) => bug!("unexpected Visibility {:?}", v), - Some(RootCrate) => self.krate().span, + Some(RootCrate) => self.forest.krate.span, Some(RootInlinedParent(parent)) => parent.body.span, Some(NotPresent) | None => { bug!("hir::map::Map::span: id not in map: {:?}", id) diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index 4595a940f10..df65c4d2794 100644 --- a/src/librustc_incremental/calculate_svh/mod.rs +++ b/src/librustc_incremental/calculate_svh/mod.rs @@ -112,8 +112,9 @@ pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) hash_spans: hash_spans, }; record_time(&tcx.sess.perf_stats.incr_comp_hashes_time, || { - visitor.calculate_def_id(DefId::local(CRATE_DEF_INDEX), - |v| visit::walk_crate(v, krate)); + visitor.calculate_def_id(DefId::local(CRATE_DEF_INDEX), |v| { + v.hash_crate_root_module(krate); + }); krate.visit_all_item_likes(&mut visitor.as_deep_visitor()); for macro_def in krate.exported_macros.iter() { diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 681ad2efa0c..de52b70f1ec 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -619,9 +619,10 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has visit::walk_item(self, i) } - fn visit_mod(&mut self, m: &'tcx Mod, _s: Span, n: NodeId) { + fn visit_mod(&mut self, m: &'tcx Mod, span: Span, n: NodeId) { debug!("visit_mod: st={:?}", self.st); SawMod.hash(self.st); + hash_span!(self, span); visit::walk_mod(self, m, n) } @@ -1085,4 +1086,23 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { token::Token::Shebang(val) => val.as_str().hash(self.st), } } + + pub fn hash_crate_root_module(&mut self, krate: &'tcx Crate) { + let hir::Crate { + ref module, + ref attrs, + span, + + // These fields are handled separately: + exported_macros: _, + items: _, + impl_items: _, + exprs: _, + } = *krate; + + visit::Visitor::visit_mod(self, module, span, ast::CRATE_NODE_ID); + // Crate attributes are not copied over to the root `Mod`, so hash them + // explicitly here. + hash_attrs!(self, attrs); + } } diff --git a/src/test/incremental/issue-38222.rs b/src/test/incremental/issue-38222.rs new file mode 100644 index 00000000000..d14b1cfd6c9 --- /dev/null +++ b/src/test/incremental/issue-38222.rs @@ -0,0 +1,40 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that debuginfo does not introduce a dependency edge to the Krate +// dep-node. + +// revisions:rpass1 rpass2 + +#![feature(rustc_attrs)] + + +#![rustc_partition_translated(module="issue_38222-mod1", cfg="rpass2")] + +// If trans had added a dependency edge to the Krate dep-node, nothing would +// be re-used, so checking that this module was re-used is sufficient. +#![rustc_partition_reused(module="issue_38222", cfg="rpass2")] + +//[rpass1] compile-flags: -C debuginfo=1 +//[rpass2] compile-flags: -C debuginfo=1 + +pub fn main() { + mod1::some_fn(); +} + +mod mod1 { + pub fn some_fn() { + let _ = 1; + } + + #[cfg(rpass2)] + fn _some_other_fn() { + } +}