From f89ba5da4a7f9a6446b91cb621ed000d28529d82 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Tue, 18 Oct 2016 10:56:12 -0700 Subject: [PATCH 01/18] Fix some mistakes in HRTB docs The example code for higher-ranked trait bounds on closures had an unnecessary `mut` which was confusing, and the text referred to an mutable reference which does not exist in the code (and isn't needed). Removed the `mut`s and fixed the text to better describe the actual error for the failing example. --- src/doc/book/closures.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/doc/book/closures.md b/src/doc/book/closures.md index 3ed85c1a90b69..60b99c08825ee 100644 --- a/src/doc/book/closures.md +++ b/src/doc/book/closures.md @@ -327,7 +327,7 @@ that takes a reference like so: fn call_with_ref(some_closure:F) -> i32 where F: Fn(&i32) -> i32 { - let mut value = 0; + let value = 0; some_closure(&value) } ``` @@ -340,14 +340,15 @@ fn call_with_ref<'a, F>(some_closure:F) -> i32 where F: Fn(&'a i32) -> i32 { ``` -However this presents a problem in our case. When you specify the explicit -lifetime on a function it binds that lifetime to the *entire* scope of the function -instead of just the invocation scope of our closure. This means that the borrow checker -will see a mutable reference in the same lifetime as our immutable reference and fail -to compile. +However, this presents a problem in our case. When a function has an explicit +lifetime parameter, that lifetime must be at least as long as the *entire* +call to that function. The borrow checker will complain that `value` doesn't +live long enough, because it is only in scope after its declaration inside the +function body. -In order to say that we only need the lifetime to be valid for the invocation scope -of the closure we can use Higher-Ranked Trait Bounds with the `for<...>` syntax: +What we need is a closure that can borrow its argument only for its own +invocation scope, not for the outer function's scope. In order to say that, +we can use Higher-Ranked Trait Bounds with the `for<...>` syntax: ```ignore fn call_with_ref(some_closure:F) -> i32 @@ -362,7 +363,7 @@ expect. fn call_with_ref(some_closure:F) -> i32 where F: for<'a> Fn(&'a i32) -> i32 { - let mut value = 0; + let value = 0; some_closure(&value) } ``` From 942f909c1f6d2d203661831366e828ef030588c6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 2 Nov 2016 19:08:10 +0100 Subject: [PATCH 02/18] Add missing urls for ErrorKind's variants --- src/libstd/io/error.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index ddf0030858eda..54372d91c893e 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -124,23 +124,28 @@ pub enum ErrorKind { InvalidInput, /// Data not valid for the operation were encountered. /// - /// Unlike `InvalidInput`, this typically means that the operation + /// Unlike [`InvalidInput`], this typically means that the operation /// parameters were valid, however the error was caused by malformed /// input data. /// /// For example, a function that reads a file into a string will error with /// `InvalidData` if the file's contents are not valid UTF-8. + /// + /// [`InvalidInput`]: #variant.InvalidInput #[stable(feature = "io_invalid_data", since = "1.2.0")] InvalidData, /// The I/O operation's timeout expired, causing it to be canceled. #[stable(feature = "rust1", since = "1.0.0")] TimedOut, /// An error returned when an operation could not be completed because a - /// call to `write` returned `Ok(0)`. + /// call to [`write()`] returned [`Ok(0)`]. /// /// This typically means that an operation could only succeed if it wrote a /// particular number of bytes but only a smaller number of bytes could be /// written. + /// + /// [`write()`]: ../../std/io/trait.Write.html#tymethod.write + /// [`Ok(0)`]: ../../std/io/type.Result.html #[stable(feature = "rust1", since = "1.0.0")] WriteZero, /// This operation was interrupted. From 50ecee241008a17a3d296f0a0d2a4ff9080a5c57 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 15 Sep 2016 00:51:46 +0300 Subject: [PATCH 03/18] Add feature gate for Self and associated types in struct expressions and patterns --- src/librustc_typeck/check/mod.rs | 10 +++++++ src/libsyntax/feature_gate.rs | 3 ++ .../struct-path-associated-type.rs | 2 ++ .../struct-path-self-feature-gate.rs | 29 +++++++++++++++++++ .../struct-path-self-type-mismatch.rs | 2 ++ src/test/compile-fail/struct-path-self.rs | 2 ++ .../run-pass/struct-path-associated-type.rs | 2 ++ src/test/run-pass/struct-path-self.rs | 2 ++ 8 files changed, 52 insertions(+) create mode 100644 src/test/compile-fail/struct-path-self-feature-gate.rs diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 75a14bb3db922..9a40cbb824a04 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3235,6 +3235,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } Def::Struct(..) | Def::Union(..) | Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => { + match def { + 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, + "`Self` and associated types in struct \ + expressions and patterns are unstable"); + } + _ => {} + } match ty.sty { ty::TyAdt(adt, substs) if !adt.is_enum() => { Some((adt.struct_variant(), adt.did, substs)) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 129e4a8233803..69dfe8e862095 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -309,6 +309,9 @@ declare_features! ( // Allows field shorthands (`x` meaning `x: x`) in struct literal expressions. (active, field_init_shorthand, "1.14.0", Some(37340)), + + // Allows using `Self` and associated types in struct expressions and patterns. + (active, more_struct_aliases, "1.14.0", Some(37544)), ); declare_features! ( diff --git a/src/test/compile-fail/struct-path-associated-type.rs b/src/test/compile-fail/struct-path-associated-type.rs index 660ac44ce0b53..ecaf269fcb1ae 100644 --- a/src/test/compile-fail/struct-path-associated-type.rs +++ b/src/test/compile-fail/struct-path-associated-type.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(more_struct_aliases)] + struct S; trait Tr { diff --git a/src/test/compile-fail/struct-path-self-feature-gate.rs b/src/test/compile-fail/struct-path-self-feature-gate.rs new file mode 100644 index 0000000000000..a2050182a7e30 --- /dev/null +++ b/src/test/compile-fail/struct-path-self-feature-gate.rs @@ -0,0 +1,29 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct S; + +trait Tr { + type A; +} + +fn f>() { + let _ = T::A {}; + //~^ ERROR `Self` and associated types in struct expressions and patterns are unstable +} + +impl S { + fn f() { + let _ = Self {}; + //~^ ERROR `Self` and associated types in struct expressions and patterns are unstable + } +} + +fn main() {} diff --git a/src/test/compile-fail/struct-path-self-type-mismatch.rs b/src/test/compile-fail/struct-path-self-type-mismatch.rs index f694e7d277c7f..8352bd6751f50 100644 --- a/src/test/compile-fail/struct-path-self-type-mismatch.rs +++ b/src/test/compile-fail/struct-path-self-type-mismatch.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(more_struct_aliases)] + struct Foo { inner: A } trait Bar { fn bar(); } diff --git a/src/test/compile-fail/struct-path-self.rs b/src/test/compile-fail/struct-path-self.rs index 067d6ac22dc6f..aeac199227b75 100644 --- a/src/test/compile-fail/struct-path-self.rs +++ b/src/test/compile-fail/struct-path-self.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(more_struct_aliases)] + struct S; trait Tr { diff --git a/src/test/run-pass/struct-path-associated-type.rs b/src/test/run-pass/struct-path-associated-type.rs index b033ed5c80210..292761dfd005f 100644 --- a/src/test/run-pass/struct-path-associated-type.rs +++ b/src/test/run-pass/struct-path-associated-type.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(more_struct_aliases)] + struct S { a: T, b: U, diff --git a/src/test/run-pass/struct-path-self.rs b/src/test/run-pass/struct-path-self.rs index c7a282c2a2fa0..b569ab62c1bfa 100644 --- a/src/test/run-pass/struct-path-self.rs +++ b/src/test/run-pass/struct-path-self.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(more_struct_aliases)] + use std::ops::Add; struct S { From 7d06bdd4a148ccb924cd6628a94ca8bc0d3611fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Inf=C3=BChr?= Date: Thu, 3 Nov 2016 10:53:13 +0100 Subject: [PATCH 04/18] set frame pointer elimination attribute for main The rustc-generated function `main` should respect the same config for frame pointer elimination as the rest of code. --- src/librustc_trans/base.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 977ababbf5688..47b6fdc740a34 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1196,6 +1196,9 @@ pub fn maybe_create_entry_wrapper(ccx: &CrateContext) { } let llfn = declare::declare_cfn(ccx, "main", llfty); + // `main` should respect same config for frame pointer elimination as rest of code + attributes::set_frame_pointer_elimination(ccx, llfn); + let llbb = unsafe { llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llfn, "top\0".as_ptr() as *const _) }; From dc138b3156677f81f9be2afbf80465a0be8179c8 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Thu, 3 Nov 2016 11:51:11 +0100 Subject: [PATCH 05/18] use DefId's in const eval for cross-crate const fn's --- src/librustc_const_eval/eval.rs | 13 ++++++------- src/test/run-pass/auxiliary/issue-36954.rs | 18 ++++++++++++++++++ src/test/run-pass/issue-36954.rs | 17 +++++++++++++++++ 3 files changed, 41 insertions(+), 7 deletions(-) create mode 100644 src/test/run-pass/auxiliary/issue-36954.rs create mode 100644 src/test/run-pass/issue-36954.rs diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index c02cca0da7225..41baa1080b1fb 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -27,7 +27,7 @@ use rustc::ty::util::IntTypeExt; use rustc::ty::subst::Substs; use rustc::traits::Reveal; use rustc::util::common::ErrorReported; -use rustc::util::nodemap::NodeMap; +use rustc::util::nodemap::DefIdMap; use rustc::lint; use graphviz::IntoCow; @@ -413,7 +413,7 @@ pub fn eval_const_expr_checked<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, eval_const_expr_partial(tcx, e, ExprTypeChecked, None) } -pub type FnArgMap<'a> = Option<&'a NodeMap>; +pub type FnArgMap<'a> = Option<&'a DefIdMap>; #[derive(Clone, Debug)] pub struct ConstEvalErr { @@ -835,9 +835,8 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ConstVal::Struct(e.id) } Def::Local(def_id) => { - let id = tcx.map.as_local_node_id(def_id).unwrap(); - debug!("Def::Local({:?}): {:?}", id, fn_args); - if let Some(val) = fn_args.and_then(|args| args.get(&id)) { + debug!("Def::Local({:?}): {:?}", def_id, fn_args); + if let Some(val) = fn_args.and_then(|args| args.get(&def_id)) { val.clone() } else { signal!(e, NonConstPath); @@ -863,7 +862,7 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let result = result.as_ref().expect("const fn has no result expression"); assert_eq!(decl.inputs.len(), args.len()); - let mut call_args = NodeMap(); + let mut call_args = DefIdMap(); for (arg, arg_expr) in decl.inputs.iter().zip(args.iter()) { let arg_hint = ty_hint.erase_hint(); let arg_val = eval_const_expr_partial( @@ -873,7 +872,7 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn_args )?; debug!("const call arg: {:?}", arg); - let old = call_args.insert(arg.pat.id, arg_val); + let old = call_args.insert(tcx.expect_def(arg.pat.id).def_id(), arg_val); assert!(old.is_none()); } debug!("const call({:?})", call_args); diff --git a/src/test/run-pass/auxiliary/issue-36954.rs b/src/test/run-pass/auxiliary/issue-36954.rs new file mode 100644 index 0000000000000..832ee1d7c1b45 --- /dev/null +++ b/src/test/run-pass/auxiliary/issue-36954.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. + +#![feature(const_fn)] +#![crate_type = "lib"] + +const fn foo(i: i32) -> i32 { + i +} + +pub const FOO: i32 = foo(1); diff --git a/src/test/run-pass/issue-36954.rs b/src/test/run-pass/issue-36954.rs new file mode 100644 index 0000000000000..f8330ba99b7ae --- /dev/null +++ b/src/test/run-pass/issue-36954.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. + +// aux-build:issue-36954.rs + +extern crate issue_36954 as lib; + +fn main() { + let _ = lib::FOO; +} From ed0230ee568ca9325a1fb5ffeca2ee9b34233ce1 Mon Sep 17 00:00:00 2001 From: Martin Glagla Date: Thu, 3 Nov 2016 22:22:27 +0100 Subject: [PATCH 06/18] Peekable::peek(): Use Option::as_ref() --- src/libcore/iter/mod.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index df4f5e5c57643..97a232de6718e 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -1341,10 +1341,7 @@ impl Peekable { if self.peeked.is_none() { self.peeked = self.iter.next(); } - match self.peeked { - Some(ref value) => Some(value), - None => None, - } + self.peeked.as_ref() } } From d5f72d21afffcda4cc71945f12477136774aa604 Mon Sep 17 00:00:00 2001 From: Mark-Simulacrum Date: Thu, 3 Nov 2016 14:55:35 -0600 Subject: [PATCH 07/18] Fix ICE when querying DefId on Def::Err. --- src/librustc_typeck/collect.rs | 7 +++---- src/test/compile-fail/issue-37534.rs | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 src/test/compile-fail/issue-37534.rs diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 202e176df0dbc..0e0f5cb1a7e15 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1724,16 +1724,15 @@ fn add_unsized_bound<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, match unbound { Some(ref tpb) => { // FIXME(#8559) currently requires the unbound to be built-in. - let trait_def_id = tcx.expect_def(tpb.ref_id).def_id(); - match kind_id { - Ok(kind_id) if trait_def_id != kind_id => { + if let Ok(kind_id) = kind_id { + let trait_def = tcx.expect_def(tpb.ref_id); + if trait_def != Def::Trait(kind_id) { tcx.sess.span_warn(span, "default bound relaxed for a type parameter, but \ this does nothing because the given bound is not \ a default. Only `?Sized` is supported"); tcx.try_add_builtin_trait(kind_id, bounds); } - _ => {} } } _ if kind_id.is_ok() => { diff --git a/src/test/compile-fail/issue-37534.rs b/src/test/compile-fail/issue-37534.rs new file mode 100644 index 0000000000000..eb676601e89ce --- /dev/null +++ b/src/test/compile-fail/issue-37534.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. + +struct Foo { } +//~^ ERROR trait `Hash` is not in scope [E0405] +//~^^ ERROR parameter `T` is never used [E0392] +//~^^^ WARN default bound relaxed for a type parameter, but this does nothing + +fn main() { } From 6a34feb034407cfcc82ccd951c13fb654689f130 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 3 Nov 2016 22:15:43 +0000 Subject: [PATCH 08/18] Set RUSTC_BOOTSTRAP to some value. Environment variables on windows can't be empty. --- mk/main.mk | 2 +- src/bootstrap/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mk/main.mk b/mk/main.mk index a5e3764122003..2fa8ccf3621e0 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -372,7 +372,7 @@ 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 +export RUSTC_BOOTSTRAP=1 endif ifdef CFG_MUSL_ROOT export CFG_MUSL_ROOT diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 7c5a0c7373f88..fdd7a1ec57df9 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -873,7 +873,7 @@ impl Build { /// Adds the compiler's bootstrap key to the environment of `cmd`. fn add_bootstrap_key(&self, cmd: &mut Command) { - cmd.env("RUSTC_BOOTSTRAP", ""); + 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"); From 1e40c80cf527c3b18baaf443f0fc553f35424499 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Fri, 4 Nov 2016 01:07:00 +0000 Subject: [PATCH 09/18] Fix issues with the Add/AddAssign impls for Cow * Correct the stability attributes. * Make Add and AddAssign actually behave the same. * Use String::with_capacity when allocating a new string. * Fix the tests. --- src/libcollections/borrow.rs | 61 ++++++++------ src/libcollectionstest/cow_str.rs | 134 +++++++++++++++++++++++------- src/libcollectionstest/lib.rs | 1 + 3 files changed, 143 insertions(+), 53 deletions(-) diff --git a/src/libcollections/borrow.rs b/src/libcollections/borrow.rs index 8f9c357833791..3bc2a3f8f68b7 100644 --- a/src/libcollections/borrow.rs +++ b/src/libcollections/borrow.rs @@ -17,6 +17,7 @@ use core::hash::{Hash, Hasher}; use core::ops::{Add, AddAssign, Deref}; use fmt; +use string::String; use self::Cow::*; @@ -284,48 +285,60 @@ impl<'a, T: ?Sized + ToOwned> AsRef for Cow<'a, T> { } } -#[stable(feature = "cow_add", since = "1.13.0")] +#[stable(feature = "cow_add", since = "1.14.0")] impl<'a> Add<&'a str> for Cow<'a, str> { type Output = Cow<'a, str>; - fn add(self, rhs: &'a str) -> Self { - if self == "" { - Cow::Borrowed(rhs) - } else if rhs == "" { - self - } else { - Cow::Owned(self.into_owned() + rhs) - } + #[inline] + fn add(mut self, rhs: &'a str) -> Self::Output { + self += rhs; + self } } -#[stable(feature = "cow_add", since = "1.13.0")] +#[stable(feature = "cow_add", since = "1.14.0")] impl<'a> Add> for Cow<'a, str> { type Output = Cow<'a, str>; - fn add(self, rhs: Cow<'a, str>) -> Self { - if self == "" { - rhs - } else if rhs == "" { - self - } else { - Cow::Owned(self.into_owned() + rhs.borrow()) - } + #[inline] + fn add(mut self, rhs: Cow<'a, str>) -> Self::Output { + self += rhs; + self } } -#[stable(feature = "cow_add", since = "1.13.0")] +#[stable(feature = "cow_add", since = "1.14.0")] impl<'a> AddAssign<&'a str> for Cow<'a, str> { fn add_assign(&mut self, rhs: &'a str) { - if rhs == "" { return; } - self.to_mut().push_str(rhs); + if self.is_empty() { + *self = Cow::Borrowed(rhs) + } else if rhs.is_empty() { + return; + } else { + if let Cow::Borrowed(lhs) = *self { + let mut s = String::with_capacity(lhs.len() + rhs.len()); + s.push_str(lhs); + *self = Cow::Owned(s); + } + self.to_mut().push_str(rhs); + } } } -#[stable(feature = "cow_add", since = "1.13.0")] +#[stable(feature = "cow_add", since = "1.14.0")] impl<'a> AddAssign> for Cow<'a, str> { fn add_assign(&mut self, rhs: Cow<'a, str>) { - if rhs == "" { return; } - self.to_mut().push_str(rhs.borrow()); + if self.is_empty() { + *self = rhs + } else if rhs.is_empty() { + return; + } else { + if let Cow::Borrowed(lhs) = *self { + let mut s = String::with_capacity(lhs.len() + rhs.len()); + s.push_str(lhs); + *self = Cow::Owned(s); + } + self.to_mut().push_str(&rhs); + } } } diff --git a/src/libcollectionstest/cow_str.rs b/src/libcollectionstest/cow_str.rs index 82533ba077541..b29245121daad 100644 --- a/src/libcollectionstest/cow_str.rs +++ b/src/libcollectionstest/cow_str.rs @@ -1,4 +1,4 @@ -// Copyright 2012-2013-2014 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. // @@ -12,54 +12,130 @@ use std::borrow::Cow; // check that Cow<'a, str> implements addition #[test] -fn check_cow_add() { - borrowed1 = Cow::Borrowed("Hello, "); - borrowed2 = Cow::Borrowed("World!"); - borrow_empty = Cow::Borrowed(""); +fn check_cow_add_cow() { + let borrowed1 = Cow::Borrowed("Hello, "); + let borrowed2 = Cow::Borrowed("World!"); + let borrow_empty = Cow::Borrowed(""); - owned1 = Cow::Owned("Hi, ".into()); - owned2 = Cow::Owned("Rustaceans!".into()); - owned_empty = Cow::Owned("".into()); + let owned1: Cow = Cow::Owned(String::from("Hi, ")); + let owned2: Cow = Cow::Owned(String::from("Rustaceans!")); + let owned_empty: Cow = Cow::Owned(String::new()); - assert_eq!("Hello, World!", borrowed1 + borrowed2); - assert_eq!("Hello, Rustaceans!", borrowed1 + owned2); + assert_eq!("Hello, World!", borrowed1.clone() + borrowed2.clone()); + assert_eq!("Hello, Rustaceans!", borrowed1.clone() + owned2.clone()); - assert_eq!("Hello, World!", owned1 + borrowed2); - assert_eq!("Hello, Rustaceans!", owned1 + owned2); + assert_eq!("Hi, World!", owned1.clone() + borrowed2.clone()); + assert_eq!("Hi, Rustaceans!", owned1.clone() + owned2.clone()); - if let Cow::Owned(_) = borrowed1 + borrow_empty { + if let Cow::Owned(_) = borrowed1.clone() + borrow_empty.clone() { panic!("Adding empty strings to a borrow should note allocate"); } - if let Cow::Owned(_) = borrow_empty + borrowed1 { + if let Cow::Owned(_) = borrow_empty.clone() + borrowed1.clone() { panic!("Adding empty strings to a borrow should note allocate"); } - if let Cow::Owned(_) = borrowed1 + owned_empty { + if let Cow::Owned(_) = borrowed1.clone() + owned_empty.clone() { panic!("Adding empty strings to a borrow should note allocate"); } - if let Cow::Owned(_) = owned_empty + borrowed1 { + if let Cow::Owned(_) = owned_empty.clone() + borrowed1.clone() { panic!("Adding empty strings to a borrow should note allocate"); } } -fn check_cow_add_assign() { - borrowed1 = Cow::Borrowed("Hello, "); - borrowed2 = Cow::Borrowed("World!"); - borrow_empty = Cow::Borrowed(""); +#[test] +fn check_cow_add_str() { + let borrowed = Cow::Borrowed("Hello, "); + let borrow_empty = Cow::Borrowed(""); + + let owned: Cow = Cow::Owned(String::from("Hi, ")); + let owned_empty: Cow = Cow::Owned(String::new()); - owned1 = Cow::Owned("Hi, ".into()); - owned2 = Cow::Owned("Rustaceans!".into()); - owned_empty = Cow::Owned("".into()); + assert_eq!("Hello, World!", borrowed.clone() + "World!"); - let borrowed1clone = borrowed1.clone(); - borrowed1clone += borrow_empty; - assert_eq!((&borrowed1clone).as_ptr(), (&borrowed1).as_ptr()); + assert_eq!("Hi, World!", owned.clone() + "World!"); - borrowed1clone += owned_empty; - assert_eq!((&borrowed1clone).as_ptr(), (&borrowed1).as_ptr()); + if let Cow::Owned(_) = borrowed.clone() + "" { + panic!("Adding empty strings to a borrow should note allocate"); + } + if let Cow::Owned(_) = borrow_empty.clone() + "Hello, " { + panic!("Adding empty strings to a borrow should note allocate"); + } + if let Cow::Owned(_) = owned_empty.clone() + "Hello, " { + panic!("Adding empty strings to a borrow should note allocate"); + } +} + +#[test] +fn check_cow_add_assign_cow() { + let mut borrowed1 = Cow::Borrowed("Hello, "); + let borrowed2 = Cow::Borrowed("World!"); + let borrow_empty = Cow::Borrowed(""); + + let mut owned1: Cow = Cow::Owned(String::from("Hi, ")); + let owned2: Cow = Cow::Owned(String::from("Rustaceans!")); + let owned_empty: Cow = Cow::Owned(String::new()); + + let mut s = borrowed1.clone(); + s += borrow_empty.clone(); + assert_eq!("Hello, ", s); + if let Cow::Owned(_) = s { + panic!("Adding empty strings to a borrow should note allocate"); + } + let mut s = borrow_empty.clone(); + s += borrowed1.clone(); + assert_eq!("Hello, ", s); + if let Cow::Owned(_) = s { + panic!("Adding empty strings to a borrow should note allocate"); + } + let mut s = borrowed1.clone(); + s += owned_empty.clone(); + assert_eq!("Hello, ", s); + if let Cow::Owned(_) = s { + panic!("Adding empty strings to a borrow should note allocate"); + } + let mut s = owned_empty.clone(); + s += borrowed1.clone(); + assert_eq!("Hello, ", s); + if let Cow::Owned(_) = s { + panic!("Adding empty strings to a borrow should note allocate"); + } owned1 += borrowed2; borrowed1 += owned2; - assert_eq!("Hello, World!", owned1); + assert_eq!("Hi, World!", owned1); assert_eq!("Hello, Rustaceans!", borrowed1); } + +#[test] +fn check_cow_add_assign_str() { + let mut borrowed = Cow::Borrowed("Hello, "); + let borrow_empty = Cow::Borrowed(""); + + let mut owned: Cow = Cow::Owned(String::from("Hi, ")); + let owned_empty: Cow = Cow::Owned(String::new()); + + let mut s = borrowed.clone(); + s += ""; + assert_eq!("Hello, ", s); + if let Cow::Owned(_) = s { + panic!("Adding empty strings to a borrow should note allocate"); + } + let mut s = borrow_empty.clone(); + s += "World!"; + assert_eq!("World!", s); + if let Cow::Owned(_) = s { + panic!("Adding empty strings to a borrow should note allocate"); + } + let mut s = owned_empty.clone(); + s += "World!"; + assert_eq!("World!", s); + if let Cow::Owned(_) = s { + panic!("Adding empty strings to a borrow should note allocate"); + } + + owned += "World!"; + borrowed += "World!"; + + assert_eq!("Hi, World!", owned); + assert_eq!("Hello, World!", borrowed); +} diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs index 5d3e03c2dee36..14ec8d58bef61 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollectionstest/lib.rs @@ -42,6 +42,7 @@ mod bench; mod binary_heap; mod btree; +mod cow_str; mod enum_set; mod fmt; mod linked_list; From 9366ba31668af3575ecadb3b35d2b67e138c3605 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 3 Nov 2016 14:58:32 +1100 Subject: [PATCH 10/18] Reorder `hir::Expr` fields. On 64-bit platforms this reduces the size of `Expr` from 96 bytes to 88 bytes. --- src/librustc/hir/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index c451a789193aa..5ff69a789ed59 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -840,8 +840,8 @@ pub enum UnsafeSource { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)] pub struct Expr { pub id: NodeId, - pub node: Expr_, pub span: Span, + pub node: Expr_, pub attrs: ThinVec, } From 43452a36efae22492ffef157ce44f05346bde1b0 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 4 Nov 2016 15:04:16 +1100 Subject: [PATCH 11/18] Shrink `Expr_::ExprStruct`. On 64-bit platforms this reduces the size of `Expr_` from 64 bytes to 56 bytes, and reduces the size of `Expr` from 88 bytes to 80 bytes. --- src/librustc/hir/lowering.rs | 4 ++-- src/librustc/hir/mod.rs | 2 +- src/librustc_const_eval/eval.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 620ee30c95628..7567c405bcaec 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1239,7 +1239,7 @@ impl<'a> LoweringContext<'a> { }), outputs.iter().map(|out| self.lower_expr(&out.expr)).collect(), inputs.iter().map(|&(_, ref input)| self.lower_expr(input)).collect()), ExprKind::Struct(ref path, ref fields, ref maybe_expr) => { - hir::ExprStruct(self.lower_path(path), + hir::ExprStruct(P(self.lower_path(path)), fields.iter().map(|x| self.lower_field(x)).collect(), maybe_expr.as_ref().map(|x| self.lower_expr(x))) } @@ -1743,7 +1743,7 @@ impl<'a> LoweringContext<'a> { e: Option>, attrs: ThinVec) -> P { let def = self.resolver.resolve_generated_global_path(&path, false); - let expr = self.expr(sp, hir::ExprStruct(path, fields, e), attrs); + let expr = self.expr(sp, hir::ExprStruct(P(path), fields, e), attrs); self.resolver.record_resolution(expr.id, def); expr } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 5ff69a789ed59..5f57ceac353cc 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -946,7 +946,7 @@ pub enum Expr_ { /// /// For example, `Foo {x: 1, y: 2}`, or /// `Foo {x: 1, .. base}`, where `base` is the `Option`. - ExprStruct(Path, HirVec, Option>), + ExprStruct(P, HirVec, Option>), /// An array literal constructed from one repeated element. /// diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index c02cca0da7225..ad9e718617a52 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -314,7 +314,7 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }, })) .collect::>()?; - PatKind::Struct(path.clone(), field_pats, false) + PatKind::Struct((**path).clone(), field_pats, false) } hir::ExprArray(ref exprs) => { From a5f6aa1c14a4af1637170565dd0646cc7642a7c0 Mon Sep 17 00:00:00 2001 From: Liigo Zhuang Date: Fri, 4 Nov 2016 15:43:42 +0800 Subject: [PATCH 12/18] reference full path `DefaultHasher` --- src/libcore/hash/sip.rs | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/libcore/hash/sip.rs b/src/libcore/hash/sip.rs index 6b3ab64dfd88c..5f5d07b668237 100644 --- a/src/libcore/hash/sip.rs +++ b/src/libcore/hash/sip.rs @@ -24,7 +24,8 @@ use mem; /// /// See: https://131002.net/siphash/ #[unstable(feature = "sip_hash_13", issue = "34767")] -#[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")] +#[rustc_deprecated(since = "1.13.0", + reason = "use `std::collections::hash_map::DefaultHasher` instead")] #[derive(Debug, Clone, Default)] pub struct SipHasher13 { hasher: Hasher, @@ -34,7 +35,8 @@ pub struct SipHasher13 { /// /// See: https://131002.net/siphash/ #[unstable(feature = "sip_hash_13", issue = "34767")] -#[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")] +#[rustc_deprecated(since = "1.13.0", + reason = "use `std::collections::hash_map::DefaultHasher` instead")] #[derive(Debug, Clone, Default)] pub struct SipHasher24 { hasher: Hasher, @@ -53,7 +55,8 @@ pub struct SipHasher24 { /// it is not intended for cryptographic purposes. As such, all /// cryptographic uses of this implementation are _strongly discouraged_. #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")] +#[rustc_deprecated(since = "1.13.0", + reason = "use `std::collections::hash_map::DefaultHasher` instead")] #[derive(Debug, Clone, Default)] pub struct SipHasher(SipHasher24); @@ -140,7 +143,8 @@ impl SipHasher { /// Creates a new `SipHasher` with the two initial keys set to 0. #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")] + #[rustc_deprecated(since = "1.13.0", + reason = "use `std::collections::hash_map::DefaultHasher` instead")] pub fn new() -> SipHasher { SipHasher::new_with_keys(0, 0) } @@ -148,7 +152,8 @@ impl SipHasher { /// Creates a `SipHasher` that is keyed off the provided keys. #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")] + #[rustc_deprecated(since = "1.13.0", + reason = "use `std::collections::hash_map::DefaultHasher` instead")] pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher { SipHasher(SipHasher24::new_with_keys(key0, key1)) } @@ -158,7 +163,8 @@ impl SipHasher13 { /// Creates a new `SipHasher13` with the two initial keys set to 0. #[inline] #[unstable(feature = "sip_hash_13", issue = "34767")] - #[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")] + #[rustc_deprecated(since = "1.13.0", + reason = "use `std::collections::hash_map::DefaultHasher` instead")] pub fn new() -> SipHasher13 { SipHasher13::new_with_keys(0, 0) } @@ -166,7 +172,8 @@ impl SipHasher13 { /// Creates a `SipHasher13` that is keyed off the provided keys. #[inline] #[unstable(feature = "sip_hash_13", issue = "34767")] - #[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")] + #[rustc_deprecated(since = "1.13.0", + reason = "use `std::collections::hash_map::DefaultHasher` instead")] pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 { SipHasher13 { hasher: Hasher::new_with_keys(key0, key1) @@ -178,7 +185,8 @@ impl SipHasher24 { /// Creates a new `SipHasher24` with the two initial keys set to 0. #[inline] #[unstable(feature = "sip_hash_13", issue = "34767")] - #[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")] + #[rustc_deprecated(since = "1.13.0", + reason = "use `std::collections::hash_map::DefaultHasher` instead")] pub fn new() -> SipHasher24 { SipHasher24::new_with_keys(0, 0) } @@ -186,7 +194,8 @@ impl SipHasher24 { /// Creates a `SipHasher24` that is keyed off the provided keys. #[inline] #[unstable(feature = "sip_hash_13", issue = "34767")] - #[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")] + #[rustc_deprecated(since = "1.13.0", + reason = "use `std::collections::hash_map::DefaultHasher` instead")] pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher24 { SipHasher24 { hasher: Hasher::new_with_keys(key0, key1) From 94e655eca6909fdca6f346e04abdcec8b8cc6e25 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 4 Nov 2016 11:37:39 -0400 Subject: [PATCH 13/18] Add -Zhir-stats for collecting statistics on HIR and AST --- src/librustc/session/config.rs | 2 + src/librustc/util/common.rs | 34 +++ src/librustc_driver/driver.rs | 19 +- src/librustc_passes/hir_stats.rs | 374 +++++++++++++++++++++++++++++++ src/librustc_passes/lib.rs | 1 + 5 files changed, 428 insertions(+), 2 deletions(-) create mode 100644 src/librustc_passes/hir_stats.rs diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 87a5c6410a841..63eabd5212fd0 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -918,6 +918,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "the directory the MIR is dumped into"), perf_stats: bool = (false, parse_bool, [UNTRACKED], "print some performance-related statistics"), + hir_stats: bool = (false, parse_bool, [UNTRACKED], + "print some statistics about AST and HIR"), } pub fn default_lib_output() -> CrateType { diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 78f20b77f3185..7cd5fd78df528 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -75,6 +75,26 @@ pub fn duration_to_secs_str(dur: Duration) -> String { format!("{:.3}", secs) } +pub fn to_readable_str(mut val: usize) -> String { + let mut groups = vec![]; + loop { + let group = val % 1000; + + val /= 1000; + + if val == 0 { + groups.push(format!("{}", group)); + break + } else { + groups.push(format!("{:03}", group)); + } + } + + groups.reverse(); + + groups.join("_") +} + pub fn record_time(accu: &Cell, f: F) -> T where F: FnOnce() -> T, { @@ -264,3 +284,17 @@ pub fn path2cstr(p: &Path) -> CString { pub fn path2cstr(p: &Path) -> CString { CString::new(p.to_str().unwrap()).unwrap() } + + +#[test] +fn test_to_readable_str() { + assert_eq!("0", to_readable_str(0)); + assert_eq!("1", to_readable_str(1)); + assert_eq!("99", to_readable_str(99)); + assert_eq!("999", to_readable_str(999)); + assert_eq!("1_000", to_readable_str(1_000)); + assert_eq!("1_001", to_readable_str(1_001)); + assert_eq!("999_999", to_readable_str(999_999)); + assert_eq!("1_000_000", to_readable_str(1_000_000)); + assert_eq!("1_234_567", to_readable_str(1_234_567)); +} diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index da1d5ad2c4a9b..77d2eb0cbce3a 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -37,7 +37,8 @@ use rustc_typeck as typeck; 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}; +use rustc_passes::{ast_validation, no_asm, loops, consts, rvalues, + static_recursion, hir_stats}; use rustc_const_eval::check_match; use super::Compilation; @@ -513,6 +514,10 @@ pub fn phase_1_parse_input<'a>(sess: &'a Session, input: &Input) -> PResult<'a, syntax::show_span::run(sess.diagnostic(), s, &krate); } + if sess.opts.debugging_opts.hir_stats { + hir_stats::print_ast_stats(&krate, "PRE EXPANSION AST STATS"); + } + Ok(krate) } @@ -718,6 +723,10 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, println!("Post-expansion node count: {}", count_nodes(&krate)); } + if sess.opts.debugging_opts.hir_stats { + hir_stats::print_ast_stats(&krate, "POST EXPANSION AST STATS"); + } + if sess.opts.debugging_opts.ast_json { println!("{}", json::as_json(&krate)); } @@ -758,7 +767,13 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, // Lower ast -> hir. let hir_forest = time(sess.time_passes(), "lowering ast -> hir", || { - hir_map::Forest::new(lower_crate(sess, &krate, &mut resolver), &sess.dep_graph) + let hir_crate = lower_crate(sess, &krate, &mut resolver); + + if sess.opts.debugging_opts.hir_stats { + hir_stats::print_hir_stats(&hir_crate); + } + + hir_map::Forest::new(hir_crate, &sess.dep_graph) }); // Discard hygiene data, which isn't required past lowering to HIR. diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs new file mode 100644 index 0000000000000..18586715894f5 --- /dev/null +++ b/src/librustc_passes/hir_stats.rs @@ -0,0 +1,374 @@ +// 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 AST and HIR. The resulting numbers are good approximations but not +// completely accurate (some things might be counted twice, others missed). + +use rustc::hir; +use rustc::hir::intravisit as hir_visit; +use rustc::util::common::to_readable_str; +use rustc::util::nodemap::{FnvHashMap, FnvHashSet}; +use syntax::ast::{self, NodeId, AttrId}; +use syntax::visit as ast_visit; +use syntax_pos::Span; + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +enum Id { + Node(NodeId), + Attr(AttrId), + None, +} + +struct NodeData { + count: usize, + size: usize, +} + +struct StatCollector<'k> { + krate: Option<&'k hir::Crate>, + data: FnvHashMap<&'static str, NodeData>, + seen: FnvHashSet, +} + +pub fn print_hir_stats(krate: &hir::Crate) { + let mut collector = StatCollector { + krate: Some(krate), + data: FnvHashMap(), + seen: FnvHashSet(), + }; + hir_visit::walk_crate(&mut collector, krate); + collector.print("HIR STATS"); +} + +pub fn print_ast_stats(krate: &ast::Crate, title: &str) { + let mut collector = StatCollector { + krate: None, + data: FnvHashMap(), + seen: FnvHashSet(), + }; + ast_visit::walk_crate(&mut collector, krate); + collector.print(title); +} + +impl<'k> StatCollector<'k> { + + fn record(&mut self, label: &'static str, id: Id, node: &T) { + if id != Id::None { + if !self.seen.insert(id) { + return + } + } + + let entry = self.data.entry(label).or_insert(NodeData { + count: 0, + size: 0, + }); + + entry.count += 1; + entry.size = ::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); + + let mut total_size = 0; + + println!("\n{}\n", title); + + println!("{:<18}{:>18}{:>14}{:>14}", + "Name", "Accumulated Size", "Count", "Item Size"); + println!("----------------------------------------------------------------"); + + for (label, data) in stats { + println!("{:<18}{:>18}{:>14}{:>14}", + label, + to_readable_str(data.count * data.size), + to_readable_str(data.count), + to_readable_str(data.size)); + + total_size += data.count * data.size; + } + println!("----------------------------------------------------------------"); + println!("{:<18}{:>18}\n", + "Total", + to_readable_str(total_size)); + } +} + +impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { + + fn visit_nested_item(&mut self, id: hir::ItemId) { + let nested_item = self.krate.unwrap().item(id.id); + self.visit_item(nested_item) + } + + fn visit_item(&mut self, i: &'v hir::Item) { + self.record("Item", Id::Node(i.id), i); + hir_visit::walk_item(self, i) + } + + /////////////////////////////////////////////////////////////////////////// + + fn visit_mod(&mut self, m: &'v hir::Mod, _s: Span, n: NodeId) { + self.record("Mod", Id::None, m); + hir_visit::walk_mod(self, m, n) + } + fn visit_foreign_item(&mut self, i: &'v hir::ForeignItem) { + self.record("ForeignItem", Id::Node(i.id), i); + hir_visit::walk_foreign_item(self, i) + } + fn visit_local(&mut self, l: &'v hir::Local) { + self.record("Local", Id::Node(l.id), l); + hir_visit::walk_local(self, l) + } + fn visit_block(&mut self, b: &'v hir::Block) { + self.record("Block", Id::Node(b.id), b); + hir_visit::walk_block(self, b) + } + fn visit_stmt(&mut self, s: &'v hir::Stmt) { + self.record("Stmt", Id::Node(s.node.id()), s); + hir_visit::walk_stmt(self, s) + } + fn visit_arm(&mut self, a: &'v hir::Arm) { + self.record("Arm", Id::None, a); + hir_visit::walk_arm(self, a) + } + fn visit_pat(&mut self, p: &'v hir::Pat) { + self.record("Pat", Id::Node(p.id), p); + hir_visit::walk_pat(self, p) + } + fn visit_decl(&mut self, d: &'v hir::Decl) { + self.record("Decl", Id::None, d); + hir_visit::walk_decl(self, d) + } + fn visit_expr(&mut self, ex: &'v hir::Expr) { + self.record("Expr", Id::Node(ex.id), ex); + hir_visit::walk_expr(self, ex) + } + + fn visit_ty(&mut self, t: &'v hir::Ty) { + self.record("Ty", Id::Node(t.id), t); + hir_visit::walk_ty(self, t) + } + + fn visit_fn(&mut self, + fk: hir_visit::FnKind<'v>, + fd: &'v hir::FnDecl, + b: &'v hir::Block, + s: Span, + id: NodeId) { + self.record("FnDecl", Id::None, fd); + hir_visit::walk_fn(self, fk, fd, b, s, id) + } + + fn visit_where_predicate(&mut self, predicate: &'v hir::WherePredicate) { + self.record("WherePredicate", Id::None, predicate); + hir_visit::walk_where_predicate(self, predicate) + } + + fn visit_trait_item(&mut self, ti: &'v hir::TraitItem) { + self.record("TraitItem", Id::Node(ti.id), ti); + hir_visit::walk_trait_item(self, ti) + } + fn visit_impl_item(&mut self, ii: &'v hir::ImplItem) { + self.record("ImplItem", Id::Node(ii.id), ii); + hir_visit::walk_impl_item(self, ii) + } + + fn visit_ty_param_bound(&mut self, bounds: &'v hir::TyParamBound) { + self.record("TyParamBound", Id::None, bounds); + hir_visit::walk_ty_param_bound(self, bounds) + } + + fn visit_struct_field(&mut self, s: &'v hir::StructField) { + self.record("StructField", Id::Node(s.id), s); + hir_visit::walk_struct_field(self, s) + } + + fn visit_variant(&mut self, + v: &'v hir::Variant, + g: &'v hir::Generics, + item_id: NodeId) { + self.record("Variant", Id::None, v); + hir_visit::walk_variant(self, v, g, item_id) + } + fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) { + self.record("Lifetime", Id::Node(lifetime.id), lifetime); + hir_visit::walk_lifetime(self, lifetime) + } + fn visit_lifetime_def(&mut self, lifetime: &'v hir::LifetimeDef) { + self.record("LifetimeDef", Id::None, lifetime); + hir_visit::walk_lifetime_def(self, lifetime) + } + fn visit_path(&mut self, path: &'v hir::Path, _id: NodeId) { + 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) { + 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) + } + fn visit_attribute(&mut self, attr: &'v ast::Attribute) { + self.record("Attribute", Id::Attr(attr.node.id), attr); + } + fn visit_macro_def(&mut self, macro_def: &'v hir::MacroDef) { + self.record("MacroDef", Id::Node(macro_def.id), macro_def); + hir_visit::walk_macro_def(self, macro_def) + } +} + +impl<'v> ast_visit::Visitor for StatCollector<'v> { + + fn visit_mod(&mut self, m: &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) { + self.record("ForeignItem", Id::None, i); + ast_visit::walk_foreign_item(self, i) + } + + fn visit_item(&mut self, i: &ast::Item) { + self.record("Item", Id::None, i); + ast_visit::walk_item(self, i) + } + + fn visit_local(&mut self, l: &ast::Local) { + self.record("Local", Id::None, l); + ast_visit::walk_local(self, l) + } + + fn visit_block(&mut self, b: &ast::Block) { + self.record("Block", Id::None, b); + ast_visit::walk_block(self, b) + } + + fn visit_stmt(&mut self, s: &ast::Stmt) { + self.record("Stmt", Id::None, s); + ast_visit::walk_stmt(self, s) + } + + fn visit_arm(&mut self, a: &ast::Arm) { + self.record("Arm", Id::None, a); + ast_visit::walk_arm(self, a) + } + + fn visit_pat(&mut self, p: &ast::Pat) { + self.record("Pat", Id::None, p); + ast_visit::walk_pat(self, p) + } + + fn visit_expr(&mut self, ex: &ast::Expr) { + self.record("Expr", Id::None, ex); + ast_visit::walk_expr(self, ex) + } + + fn visit_ty(&mut self, t: &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, + b: &ast::Block, + s: Span, + _: NodeId) { + self.record("FnDecl", Id::None, fd); + ast_visit::walk_fn(self, fk, fd, b, s) + } + + fn visit_trait_item(&mut self, ti: &ast::TraitItem) { + self.record("TraitItem", Id::None, ti); + ast_visit::walk_trait_item(self, ti) + } + + fn visit_impl_item(&mut self, ii: &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) { + self.record("TyParamBound", Id::None, bounds); + ast_visit::walk_ty_param_bound(self, bounds) + } + + fn visit_struct_field(&mut self, s: &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, + 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) { + self.record("Lifetime", Id::None, lifetime); + ast_visit::walk_lifetime(self, lifetime) + } + + fn visit_lifetime_def(&mut self, lifetime: &ast::LifetimeDef) { + self.record("LifetimeDef", Id::None, lifetime); + ast_visit::walk_lifetime_def(self, lifetime) + } + + fn visit_mac(&mut self, mac: &ast::Mac) { + self.record("Mac", Id::None, mac); + } + + fn visit_path_list_item(&mut self, + prefix: &ast::Path, + item: &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) { + 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) { + self.record("TypeBinding", Id::None, type_binding); + ast_visit::walk_assoc_type_binding(self, type_binding) + } + + fn visit_attribute(&mut self, attr: &ast::Attribute) { + self.record("Attribute", Id::None, attr); + } + + fn visit_macro_def(&mut self, macro_def: &ast::MacroDef) { + self.record("MacroDef", Id::None, macro_def); + ast_visit::walk_macro_def(self, macro_def) + } +} diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs index a4657251c9ce2..94816594878cc 100644 --- a/src/librustc_passes/lib.rs +++ b/src/librustc_passes/lib.rs @@ -45,6 +45,7 @@ pub mod diagnostics; pub mod ast_validation; pub mod consts; +pub mod hir_stats; pub mod loops; pub mod no_asm; pub mod rvalues; From 3e4bd8843829284a62af22687ee415a66c8207cc Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Fri, 4 Nov 2016 15:54:08 -0200 Subject: [PATCH 14/18] Change Into> for String and Into for PathBuf to From impls --- src/libcollections/string.rs | 8 ++++---- src/libstd/path.rs | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 286f06b6fe32a..348eb6fb5ffa4 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1904,10 +1904,10 @@ impl<'a> FromIterator for Cow<'a, str> { } } -#[stable(feature = "rust1", since = "1.0.0")] -impl Into> for String { - fn into(self) -> Vec { - self.into_bytes() +#[stable(feature = "from_string_for_vec_u8", since = "1.14.0")] +impl From for Vec { + fn from(string : String) -> Vec { + string.into_bytes() } } diff --git a/src/libstd/path.rs b/src/libstd/path.rs index d6a5dfe551800..e8a7951d557b2 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1172,6 +1172,13 @@ impl From for PathBuf { } } +#[stable(feature = "from_path_buf_for_os_string", since = "1.14.0")] +impl From for OsString { + fn from(path_buf : PathBuf) -> OsString { + path_buf.inner + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl From for PathBuf { fn from(s: String) -> PathBuf { @@ -1282,13 +1289,6 @@ impl AsRef for PathBuf { } } -#[stable(feature = "rust1", since = "1.0.0")] -impl Into for PathBuf { - fn into(self) -> OsString { - self.inner - } -} - /// A slice of a path (akin to [`str`]). /// /// This type supports a number of operations for inspecting a path, including From a6cf77704f407f26a181af9cfd7c838ea6270312 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Fri, 4 Nov 2016 19:08:09 +0100 Subject: [PATCH 15/18] fix #37559: update compiler-rt --- src/compiler-rt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler-rt b/src/compiler-rt index f03ba5a4e8bf1..ecd2b1f6d689d 160000 --- a/src/compiler-rt +++ b/src/compiler-rt @@ -1 +1 @@ -Subproject commit f03ba5a4e8bf16dcf42dd742a4ce255c36321356 +Subproject commit ecd2b1f6d689d5afbf5debe8afb3739337323852 From 775d399da84776bfd8ae09af5f402874372e299c Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Fri, 4 Nov 2016 18:47:32 +0000 Subject: [PATCH 16/18] Remove recursive call from Cow::to_mut It seems to prevent it from being inlined. --- src/libcollections/borrow.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libcollections/borrow.rs b/src/libcollections/borrow.rs index 8f9c357833791..30286fb243c1d 100644 --- a/src/libcollections/borrow.rs +++ b/src/libcollections/borrow.rs @@ -159,7 +159,10 @@ impl<'a, B: ?Sized> Cow<'a, B> where B: ToOwned { match *self { Borrowed(borrowed) => { *self = Owned(borrowed.to_owned()); - self.to_mut() + match *self { + Borrowed(..) => unreachable!(), + Owned(ref mut owned) => owned, + } } Owned(ref mut owned) => owned, } From fe953dc16ee205ec27a946398f2d3350666962e3 Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Fri, 4 Nov 2016 13:01:15 -0700 Subject: [PATCH 17/18] std: Track change to cprng syscall signature (Fuchsia) The mx_cprng_draw syscall has changed signature to separate the status and size return values, rather than multiplexing them into a single value with errors interpreted as a negative value. This patch tracks that change. --- src/libstd/sys/unix/rand.rs | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/libstd/sys/unix/rand.rs b/src/libstd/sys/unix/rand.rs index 3aebb8c18ec86..9b1cf6ffd0e22 100644 --- a/src/libstd/sys/unix/rand.rs +++ b/src/libstd/sys/unix/rand.rs @@ -350,11 +350,19 @@ mod imp { #[link(name = "magenta")] extern { - fn mx_cprng_draw(buffer: *mut u8, len: usize) -> isize; + fn mx_cprng_draw(buffer: *mut u8, len: usize, actual: *mut usize) -> i32; } - fn getrandom(buf: &mut [u8]) -> isize { - unsafe { mx_cprng_draw(buf.as_mut_ptr(), buf.len()) } + fn getrandom(buf: &mut [u8]) -> Result { + unsafe { + let mut actual = 0; + let status = mx_cprng_draw(buf.as_mut_ptr(), buf.len(), &mut actual); + if status == 0 { + Ok(actual) + } else { + Err(status) + } + } } pub struct OsRng { @@ -381,12 +389,16 @@ mod imp { let mut buf = v; while !buf.is_empty() { let ret = getrandom(buf); - if ret < 0 { - panic!("kernel mx_cprng_draw call failed! (returned {}, buf.len() {})", - ret, buf.len()); + match ret { + Err(err) => { + panic!("kernel mx_cprng_draw call failed! (returned {}, buf.len() {})", + err, buf.len()) + } + Ok(actual) => { + let move_buf = buf; + buf = &mut move_buf[(actual as usize)..]; + } } - let move_buf = buf; - buf = &mut move_buf[(ret as usize)..]; } } } From ecd79a125b333e2e38fa1e0f6156438659c283db Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 4 Nov 2016 22:37:51 +0100 Subject: [PATCH 18/18] Add error when proc_macro_derive is used not on functions Fixes #37590 --- src/libsyntax_ext/proc_macro_registrar.rs | 11 +++++++++++ ...crate-type.rs => illegal-proc-macro-derive-use.rs} | 6 ++++++ 2 files changed, 17 insertions(+) rename src/test/compile-fail-fulldeps/proc-macro/{require-rustc-macro-crate-type.rs => illegal-proc-macro-derive-use.rs} (82%) diff --git a/src/libsyntax_ext/proc_macro_registrar.rs b/src/libsyntax_ext/proc_macro_registrar.rs index f49a5f0e0706e..a8accd63dcf0a 100644 --- a/src/libsyntax_ext/proc_macro_registrar.rs +++ b/src/libsyntax_ext/proc_macro_registrar.rs @@ -105,6 +105,17 @@ impl<'a> Visitor for CollectCustomDerives<'a> { match item.node { ast::ItemKind::Fn(..) => {} _ => { + // Check for invalid use of proc_macro_derive + let attr = item.attrs.iter() + .filter(|a| a.check_name("proc_macro_derive")) + .next(); + if let Some(attr) = attr { + self.handler.span_err(attr.span(), + "the `#[proc_macro_derive]` \ + attribute may only be used \ + on bare functions"); + return; + } self.check_not_pub_in_root(&item.vis, item.span); return visit::walk_item(self, item) } diff --git a/src/test/compile-fail-fulldeps/proc-macro/require-rustc-macro-crate-type.rs b/src/test/compile-fail-fulldeps/proc-macro/illegal-proc-macro-derive-use.rs similarity index 82% rename from src/test/compile-fail-fulldeps/proc-macro/require-rustc-macro-crate-type.rs rename to src/test/compile-fail-fulldeps/proc-macro/illegal-proc-macro-derive-use.rs index 44397cdde0c0a..405994b36e25e 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/require-rustc-macro-crate-type.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/illegal-proc-macro-derive-use.rs @@ -18,4 +18,10 @@ pub fn foo(a: proc_macro::TokenStream) -> proc_macro::TokenStream { a } +// Issue #37590 +#[proc_macro_derive(Foo)] +//~^ ERROR: the `#[proc_macro_derive]` attribute may only be used on bare functions +pub struct Foo { +} + fn main() {}