From 06e4ff4d61f44d7e239e02256829ecf1e5598657 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Fri, 27 Sep 2019 17:15:17 -0400 Subject: [PATCH 01/10] Scope format! temporaries This places the temporaries that `format!` generates to refer to its arguments (through `&dyn Trait`) in a short-lived scope surrounding just the invocation of `format!`. This enables `format!` to be used in generators without the temporaries preventing the generator from being `Send` (due to `dyn Trait` not being `Sync`). See rust-lang/rust#64477 for details. --- src/liballoc/macros.rs | 5 ++++- src/test/ui/fmt/issue-64477.rs | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/fmt/issue-64477.rs diff --git a/src/liballoc/macros.rs b/src/liballoc/macros.rs index 2f2cdc39c633d..422d3486f92b2 100644 --- a/src/liballoc/macros.rs +++ b/src/liballoc/macros.rs @@ -98,5 +98,8 @@ macro_rules! vec { #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] macro_rules! format { - ($($arg:tt)*) => ($crate::fmt::format($crate::__export::format_args!($($arg)*))) + ($($arg:tt)*) => {{ + let res = $crate::fmt::format($crate::__export::format_args!($($arg)*)); + res + }} } diff --git a/src/test/ui/fmt/issue-64477.rs b/src/test/ui/fmt/issue-64477.rs new file mode 100644 index 0000000000000..b7c8cf17c3148 --- /dev/null +++ b/src/test/ui/fmt/issue-64477.rs @@ -0,0 +1,16 @@ +// In the past, the code generated by `format!` produced temporaries in the surrounding scope that +// borrowed the arguments through `&dyn Trait`. These temporaries do not implement `Send`, which +// meant that when `format!` was used in an async block, the resulting generator was not `Send`. +// See https://github.com/rust-lang/rust/issues/64477#issuecomment-534669068 for details +// and https://github.com/rust-lang/rust/issues/64477#issuecomment-531882958 for an example. +async fn foo(_: String) {} + +fn bar() -> impl Send { + async move { + foo(format!("{}:{}", 1, 2)).await; + } +} + +fn main() { + let _ = bar(); +} From 4d34ce2c2515a429bea325b93aea332ac8d6a7b9 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Fri, 27 Sep 2019 23:19:37 -0400 Subject: [PATCH 02/10] Place test with async-await and use 2018 edition --- .../issue-64477.rs => async-await/issues/issue-64477-2.rs} | 6 ++++++ 1 file changed, 6 insertions(+) rename src/test/ui/{fmt/issue-64477.rs => async-await/issues/issue-64477-2.rs} (89%) diff --git a/src/test/ui/fmt/issue-64477.rs b/src/test/ui/async-await/issues/issue-64477-2.rs similarity index 89% rename from src/test/ui/fmt/issue-64477.rs rename to src/test/ui/async-await/issues/issue-64477-2.rs index b7c8cf17c3148..2360b57cc4544 100644 --- a/src/test/ui/fmt/issue-64477.rs +++ b/src/test/ui/async-await/issues/issue-64477-2.rs @@ -1,8 +1,14 @@ +// Another regression test for #64477. +// // In the past, the code generated by `format!` produced temporaries in the surrounding scope that // borrowed the arguments through `&dyn Trait`. These temporaries do not implement `Send`, which // meant that when `format!` was used in an async block, the resulting generator was not `Send`. // See https://github.com/rust-lang/rust/issues/64477#issuecomment-534669068 for details // and https://github.com/rust-lang/rust/issues/64477#issuecomment-531882958 for an example. +// +// check-pass +// edition:2018 + async fn foo(_: String) {} fn bar() -> impl Send { From 8990f7d627525db934831cc29d5805172d80e156 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Sat, 28 Sep 2019 09:55:22 -0400 Subject: [PATCH 03/10] Update pretty-print test with new format! impl --- src/test/pretty/issue-4264.pp | 56 +++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index 4cf2e90e635fd..0f71dbe486b97 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -29,33 +29,37 @@ - ((::alloc::fmt::format as - for<'r> fn(std::fmt::Arguments<'r>) -> std::string::String {std::fmt::format})(((<::core::fmt::Arguments>::new_v1 - as - fn(&[&str], &[std::fmt::ArgumentV1<'_>]) -> std::fmt::Arguments<'_> {std::fmt::Arguments::<'_>::new_v1})((&([("test" - as - &'static str)] - as - [&str; 1]) - as - &[&str; 1]), - (&(match (() + ({ + let res = + ((::alloc::fmt::format as + for<'r> fn(std::fmt::Arguments<'r>) -> std::string::String {std::fmt::format})(((<::core::fmt::Arguments>::new_v1 + as + fn(&[&str], &[std::fmt::ArgumentV1<'_>]) -> std::fmt::Arguments<'_> {std::fmt::Arguments::<'_>::new_v1})((&([("test" + as + &'static str)] + as + [&str; 1]) as - ()) - { - () - => - ([] - as - [std::fmt::ArgumentV1<'_>; 0]), - } - as - [std::fmt::ArgumentV1<'_>; 0]) - as - &[std::fmt::ArgumentV1<'_>; 0])) - as - std::fmt::Arguments<'_>)) - as std::string::String); + &[&str; 1]), + (&(match (() + as + ()) + { + () + => + ([] + as + [std::fmt::ArgumentV1<'_>; 0]), + } + as + [std::fmt::ArgumentV1<'_>; 0]) + as + &[std::fmt::ArgumentV1<'_>; 0])) + as + std::fmt::Arguments<'_>)) + as std::string::String); + (res as std::string::String) + } as std::string::String); } as ()) pub type Foo = [i32; (3 as usize)]; pub struct Bar { From 7009e6d001ebc807eca04c5b9f07779db02eca99 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 Nov 2019 12:13:16 +0100 Subject: [PATCH 04/10] mem::forget docs: mention ManuallyDrop --- src/libcore/mem/mod.rs | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs index dc7c36ff03c4e..5ba2a3aa5996c 100644 --- a/src/libcore/mem/mod.rs +++ b/src/libcore/mem/mod.rs @@ -45,8 +45,9 @@ pub use crate::intrinsics::transmute; /// `mem::forget` from safe code does not fundamentally change Rust's safety /// guarantees. /// -/// That said, leaking resources such as memory or I/O objects is usually undesirable, -/// so `forget` is only recommended for specialized use cases like those shown below. +/// That said, leaking resources such as memory or I/O objects is usually undesirable. +/// The need comes up in some specialized use cases for FFI or unsafe code, but even +/// then, [`ManuallyDrop`] is typically preferred. /// /// Because forgetting a value is allowed, any `unsafe` code you write must /// allow for this possibility. You cannot return a value and expect that the @@ -68,7 +69,35 @@ pub use crate::intrinsics::transmute; /// ``` /// /// The practical use cases for `forget` are rather specialized and mainly come -/// up in unsafe or FFI code. +/// up in unsafe or FFI code. However, [`ManuallyDrop`] is usually preferred +/// for such cases, e.g.: +/// +/// ``` +/// use std::mem::ManuallyDrop; +/// +/// let v = vec![65, 122]; +/// // Before we disassemble `v` into its raw parts, make sure it +/// // does not get dropped! +/// let mut v = ManuallyDrop::new(v); +/// // Now disassemble `v`. These operations cannot panic, so there cannot be a leak. +/// let ptr = v.as_mut_ptr(); +/// let cap = v.capacity(); +/// // Finally, build a `String`. +/// let s = unsafe { String::from_raw_parts(ptr, 2, cap) }; +/// assert_eq!(s, "Az"); +/// // `s` is implicitly dropped and its memory deallocated. +/// ``` +/// +/// Using `ManuallyDrop` here has two advantages: +/// +/// * We do not "touch" `v` after disassembling it. For some types, operations +/// such as passing ownership (to a funcion like `mem::forget`) requires them to actually +/// be fully owned right now; that is a promise we do not want to make here as we are +/// in the process of transferring ownership to the new `String` we are building. +/// * In case of an unexpected panic, `ManuallyDrop` is not dropped, but if the panic +/// occurs before `mem::forget` was called we might end up dropping invalid data, +/// or double-dropping. In other words, `ManuallyDrop` errs on the side of leaking +/// instead of erring on the side of dropping. /// /// [drop]: fn.drop.html /// [uninit]: fn.uninitialized.html @@ -78,6 +107,7 @@ pub use crate::intrinsics::transmute; /// [leak]: ../../std/boxed/struct.Box.html#method.leak /// [into_raw]: ../../std/boxed/struct.Box.html#method.into_raw /// [ub]: ../../reference/behavior-considered-undefined.html +/// [`ManuallyDrop`]: struct.ManuallyDrop.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn forget(t: T) { From bc7b17c4779f09778e014b6c4c8198ac1f9a8ffa Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 20 Nov 2019 19:24:44 -0500 Subject: [PATCH 05/10] Fix cycle when debug-printing opaque types Fixes #61577 When printing an opaque type in non-verbose mode, we use the `tcx.predicates_of` query to retrieve the opaque type's bounds for pretty-printing. However, the pervasiveness of logging within librustc means that we may already be executing `tcx.predicates_of` for the opaque type we're trying to print, leading to a cycle error. This commit adds a new 'no queries' thread-local flag to the pretty printer. This flag is enabled during the computation of `predicates_of` for opaque types, and causes us to print the opaque type in 'verbose' mode (which does not require computing any additinal queries). This should only affect debug logging for highly nested log messages, not any user-visible output. --- src/librustc/ty/print/pretty.rs | 103 ++++++++++++++++++++------------ src/librustc_typeck/collect.rs | 56 +++++++++-------- 2 files changed, 95 insertions(+), 64 deletions(-) diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index 594550dd967ac..ee05d57d23910 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -49,6 +49,24 @@ macro_rules! define_scoped_cx { thread_local! { static FORCE_IMPL_FILENAME_LINE: Cell = Cell::new(false); static SHOULD_PREFIX_WITH_CRATE: Cell = Cell::new(false); + static NO_QUERIES: Cell = Cell::new(false); +} + +/// Avoids running any queries during any prints that occur +/// during the closure. This may alter the apperance of some +/// types (e.g. forcing verbose printing for opaque types). +/// This method is used during some queries (e.g. `predicates_of` +/// for opaque types), to ensure that any debug printing that +/// occurs during the query computation does not end up recursively +/// calling the same query. +pub fn with_no_queries R, R>(f: F) -> R { + NO_QUERIES.with(|no_queries| { + let old = no_queries.get(); + no_queries.set(true); + let result = f(); + no_queries.set(old); + result + }) } /// Force us to name impls with just the filename/line number. We @@ -556,52 +574,61 @@ pub trait PrettyPrinter<'tcx>: } ty::Opaque(def_id, substs) => { // FIXME(eddyb) print this with `print_def_path`. - if self.tcx().sess.verbose() { + // We use verbose printing in 'NO_QUERIES' mode, to + // avoid needing to call `predicates_of`. This should + // only affect certain debug messages (e.g. messages printed + // from `rustc::ty` during the computation of `tcx.predicates_of`), + // and should have no effect on any compiler output. + if self.tcx().sess.verbose() || NO_QUERIES.with(|q| q.get()) { p!(write("Opaque({:?}, {:?})", def_id, substs)); return Ok(self); } - let def_key = self.tcx().def_key(def_id); - if let Some(name) = def_key.disambiguated_data.data.get_opt_name() { - p!(write("{}", name)); - let mut substs = substs.iter(); - // FIXME(eddyb) print this with `print_def_path`. - if let Some(first) = substs.next() { - p!(write("::<")); - p!(print(first)); - for subst in substs { - p!(write(", "), print(subst)); + return Ok(with_no_queries(|| { + + let def_key = self.tcx().def_key(def_id); + if let Some(name) = def_key.disambiguated_data.data.get_opt_name() { + p!(write("{}", name)); + let mut substs = substs.iter(); + // FIXME(eddyb) print this with `print_def_path`. + if let Some(first) = substs.next() { + p!(write("::<")); + p!(print(first)); + for subst in substs { + p!(write(", "), print(subst)); + } + p!(write(">")); } - p!(write(">")); + return Ok(self); } - return Ok(self); - } - // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, - // by looking up the projections associated with the def_id. - let bounds = self.tcx().predicates_of(def_id).instantiate(self.tcx(), substs); - - let mut first = true; - let mut is_sized = false; - p!(write("impl")); - for predicate in bounds.predicates { - if let Some(trait_ref) = predicate.to_opt_poly_trait_ref() { - // Don't print +Sized, but rather +?Sized if absent. - if Some(trait_ref.def_id()) == self.tcx().lang_items().sized_trait() { - is_sized = true; - continue; - } + // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, + // by looking up the projections associated with the def_id. + let bounds = self.tcx().predicates_of(def_id).instantiate(self.tcx(), substs); + + let mut first = true; + let mut is_sized = false; + p!(write("impl")); + for predicate in bounds.predicates { + if let Some(trait_ref) = predicate.to_opt_poly_trait_ref() { + // Don't print +Sized, but rather +?Sized if absent. + if Some(trait_ref.def_id()) == self.tcx().lang_items().sized_trait() { + is_sized = true; + continue; + } - p!( - write("{}", if first { " " } else { "+" }), - print(trait_ref)); - first = false; + p!( + write("{}", if first { " " } else { "+" }), + print(trait_ref)); + first = false; + } } - } - if !is_sized { - p!(write("{}?Sized", if first { " " } else { "+" })); - } else if first { - p!(write(" Sized")); - } + if !is_sized { + p!(write("{}?Sized", if first { " " } else { "+" })); + } else if first { + p!(write(" Sized")); + } + Ok(self) + })?); } ty::Str => p!(write("str")), ty::Generator(did, substs, movability) => { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index d9f6d79f218f9..f4c8763f87910 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -2056,20 +2056,22 @@ fn explicit_predicates_of( Node::ImplItem(item) => match item.kind { ImplItemKind::OpaqueTy(ref bounds) => { - let substs = InternalSubsts::identity_for_item(tcx, def_id); - let opaque_ty = tcx.mk_opaque(def_id, substs); - - // Collect the bounds, i.e., the `A + B + 'c` in `impl A + B + 'c`. - let bounds = AstConv::compute_bounds( - &icx, - opaque_ty, - bounds, - SizedByDefault::Yes, - tcx.def_span(def_id), - ); + ty::print::with_no_queries(|| { + let substs = InternalSubsts::identity_for_item(tcx, def_id); + let opaque_ty = tcx.mk_opaque(def_id, substs); + + // Collect the bounds, i.e., the `A + B + 'c` in `impl A + B + 'c`. + let bounds = AstConv::compute_bounds( + &icx, + opaque_ty, + bounds, + SizedByDefault::Yes, + tcx.def_span(def_id), + ); - predicates.extend(bounds.predicates(tcx, opaque_ty)); - &item.generics + predicates.extend(bounds.predicates(tcx, opaque_ty)); + &item.generics + }) } _ => &item.generics, }, @@ -2102,19 +2104,21 @@ fn explicit_predicates_of( ref generics, origin: _, }) => { - let substs = InternalSubsts::identity_for_item(tcx, def_id); - let opaque_ty = tcx.mk_opaque(def_id, substs); - - // Collect the bounds, i.e., the `A + B + 'c` in `impl A + B + 'c`. - let bounds = AstConv::compute_bounds( - &icx, - opaque_ty, - bounds, - SizedByDefault::Yes, - tcx.def_span(def_id), - ); + let bounds_predicates = ty::print::with_no_queries(|| { + let substs = InternalSubsts::identity_for_item(tcx, def_id); + let opaque_ty = tcx.mk_opaque(def_id, substs); + + // Collect the bounds, i.e., the `A + B + 'c` in `impl A + B + 'c`. + let bounds = AstConv::compute_bounds( + &icx, + opaque_ty, + bounds, + SizedByDefault::Yes, + tcx.def_span(def_id), + ); - let bounds_predicates = bounds.predicates(tcx, opaque_ty); + bounds.predicates(tcx, opaque_ty) + }); if impl_trait_fn.is_some() { // opaque types return ty::GenericPredicates { @@ -2124,7 +2128,7 @@ fn explicit_predicates_of( } else { // named opaque types predicates.extend(bounds_predicates); - generics + generics.clone() } } From 0e660d8a79062ba3c664822a72ae782cb8c38da7 Mon Sep 17 00:00:00 2001 From: Janusz Marcinkiewicz Date: Sat, 23 Nov 2019 03:41:12 +0100 Subject: [PATCH 06/10] Add error reporting on nested keywords inside 'enum' definition --- src/librustc_parse/parser/item.rs | 37 ++++++++++++++++++++++++++++- src/test/ui/enum/nested-enum.rs | 8 +++++++ src/test/ui/enum/nested-enum.stderr | 26 ++++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/enum/nested-enum.rs create mode 100644 src/test/ui/enum/nested-enum.stderr diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 13645e7144a9b..712715705e1ed 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -9,6 +9,7 @@ use syntax::ast::{PathSegment, IsAuto, Constness, IsAsync, Unsafety, Defaultness use syntax::ast::{Visibility, VisibilityKind, Mutability, FnHeader, ForeignItem, ForeignItemKind}; use syntax::ast::{Ty, TyKind, Generics, TraitRef, EnumDef, VariantData, StructField}; use syntax::ast::{Mac, MacDelimiter, Block, BindingMode, FnDecl, FnSig, SelfKind, Param}; +use syntax::print::pprust; use syntax::ptr::P; use syntax::ThinVec; use syntax::token; @@ -16,7 +17,7 @@ use syntax::tokenstream::{TokenTree, TokenStream}; use syntax::source_map::{self, respan, Span}; use syntax::struct_span_err; use syntax_pos::BytePos; -use syntax_pos::symbol::{kw, sym}; +use syntax_pos::symbol::{kw, sym, Symbol}; use rustc_error_codes::*; @@ -1341,6 +1342,10 @@ impl<'a> Parser<'a> { let vlo = self.token.span; let vis = self.parse_visibility(FollowedByType::No)?; + if !self.recover_nested_adt_item(kw::Enum)? { + // Item already parsed, we need to skip this variant. + continue + } let ident = self.parse_ident()?; let struct_def = if self.check(&token::OpenDelim(token::Brace)) { @@ -1742,6 +1747,36 @@ impl<'a> Parser<'a> { ).emit(); } + /// Checks if current token is one of tokens which cannot be nested like `kw::Enum`. In case + /// it is, we try to parse the item and report error about nested types. + fn recover_nested_adt_item(&mut self, keyword: Symbol) -> PResult<'a, bool> { + if self.token.is_keyword(kw::Enum) || + self.token.is_keyword(kw::Struct) || + self.token.is_keyword(kw::Union) { + + let prev_token = self.token.clone(); + let item = self.parse_item()?; + if self.token == token::Comma { + self.bump(); + } + + let mut err = self.struct_span_err( + prev_token.span, + &format!("`{}` definition cannot be nested inside `{}`", pprust::token_to_string(&prev_token), keyword), + ); + err.span_suggestion( + item.unwrap().span, + &format!("consider creating a new `{}` definition instead of nesting", pprust::token_to_string(&prev_token)), + String::new(), + Applicability::MaybeIncorrect, + ); + err.emit(); + // We successfully parsed the item but we must inform the caller about nested problem. + return Ok(false) + } + Ok(true) + } + fn mk_item(&self, span: Span, ident: Ident, kind: ItemKind, vis: Visibility, attrs: Vec) -> P { P(Item { diff --git a/src/test/ui/enum/nested-enum.rs b/src/test/ui/enum/nested-enum.rs new file mode 100644 index 0000000000000..80957b8a14c23 --- /dev/null +++ b/src/test/ui/enum/nested-enum.rs @@ -0,0 +1,8 @@ +enum Foo { + enum Bar { Baz }, //~ ERROR `enum` definition cannot be nested inside `enum` + struct Quux { field: u8 }, //~ ERROR `struct` definition cannot be nested inside `enum` + union Wibble { field: u8 }, //~ ERROR `union` definition cannot be nested inside `enum` + Bat, +} + +fn main() { } diff --git a/src/test/ui/enum/nested-enum.stderr b/src/test/ui/enum/nested-enum.stderr new file mode 100644 index 0000000000000..7d6f57e88a826 --- /dev/null +++ b/src/test/ui/enum/nested-enum.stderr @@ -0,0 +1,26 @@ +error: `enum` definition cannot be nested inside `enum` + --> $DIR/nested-enum.rs:2:5 + | +LL | enum Bar { Baz }, + | ^^^^------------ + | | + | help: consider creating a new `enum` definition instead of nesting + +error: `struct` definition cannot be nested inside `enum` + --> $DIR/nested-enum.rs:3:5 + | +LL | struct Quux { field: u8 }, + | ^^^^^^------------------- + | | + | help: consider creating a new `struct` definition instead of nesting + +error: `union` definition cannot be nested inside `enum` + --> $DIR/nested-enum.rs:4:5 + | +LL | union Wibble { field: u8 }, + | ^^^^^--------------------- + | | + | help: consider creating a new `union` definition instead of nesting + +error: aborting due to 3 previous errors + From bbd0d9bea03ae1fdee31e7b94b27b38631b0cfe9 Mon Sep 17 00:00:00 2001 From: Janusz Marcinkiewicz Date: Sat, 23 Nov 2019 04:01:14 +0100 Subject: [PATCH 07/10] Cleanup code after review fixes --- src/librustc_parse/parser/item.rs | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 712715705e1ed..4b783c6c2bedc 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -1752,25 +1752,22 @@ impl<'a> Parser<'a> { fn recover_nested_adt_item(&mut self, keyword: Symbol) -> PResult<'a, bool> { if self.token.is_keyword(kw::Enum) || self.token.is_keyword(kw::Struct) || - self.token.is_keyword(kw::Union) { - - let prev_token = self.token.clone(); + self.token.is_keyword(kw::Union) + { + let kw_token = self.token.clone(); + let kw_str = pprust::token_to_string(&kw_token); let item = self.parse_item()?; - if self.token == token::Comma { - self.bump(); - } + self.eat(&token::Comma); - let mut err = self.struct_span_err( - prev_token.span, - &format!("`{}` definition cannot be nested inside `{}`", pprust::token_to_string(&prev_token), keyword), - ); - err.span_suggestion( + self.struct_span_err( + kw_token.span, + &format!("`{}` definition cannot be nested inside `{}`", kw_str, keyword), + ).span_suggestion( item.unwrap().span, - &format!("consider creating a new `{}` definition instead of nesting", pprust::token_to_string(&prev_token)), + &format!("consider creating a new `{}` definition instead of nesting", kw_str), String::new(), Applicability::MaybeIncorrect, - ); - err.emit(); + ).emit(); // We successfully parsed the item but we must inform the caller about nested problem. return Ok(false) } From 59257e6e88cc09697642cce889445d0fd6572ec1 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 23 Nov 2019 07:06:27 +0100 Subject: [PATCH 08/10] make `./x.py bench` again --- src/libcore/benches/num/mod.rs | 4 +- src/librustc/benches/dispatch.rs | 34 ----------- src/librustc/benches/lib.rs | 61 +++++++++++++++++++- src/librustc/benches/pattern.rs | 25 -------- src/librustc_codegen_ssa/back/rpath/tests.rs | 4 +- 5 files changed, 63 insertions(+), 65 deletions(-) delete mode 100644 src/librustc/benches/dispatch.rs delete mode 100644 src/librustc/benches/pattern.rs diff --git a/src/libcore/benches/num/mod.rs b/src/libcore/benches/num/mod.rs index f5c49ea5bf0d5..2dcdf2b6fe9f7 100644 --- a/src/libcore/benches/num/mod.rs +++ b/src/libcore/benches/num/mod.rs @@ -35,7 +35,7 @@ macro_rules! from_str_bench { .iter() .cycle() .take(5_000) - .filter_map(|s| <($t)>::from_str(s).ok()) + .filter_map(|s| <$t>::from_str(s).ok()) .max() }) } @@ -51,7 +51,7 @@ macro_rules! from_str_radix_bench { .iter() .cycle() .take(5_000) - .filter_map(|s| <($t)>::from_str_radix(s, $radix).ok()) + .filter_map(|s| <$t>::from_str_radix(s, $radix).ok()) .max() }) } diff --git a/src/librustc/benches/dispatch.rs b/src/librustc/benches/dispatch.rs deleted file mode 100644 index e3b36be5696b3..0000000000000 --- a/src/librustc/benches/dispatch.rs +++ /dev/null @@ -1,34 +0,0 @@ -use test::Bencher; - -// Static/dynamic method dispatch - -struct Struct { - field: isize -} - -trait Trait { - fn method(&self) -> isize; -} - -impl Trait for Struct { - fn method(&self) -> isize { - self.field - } -} - -#[bench] -fn trait_vtable_method_call(b: &mut Bencher) { - let s = Struct { field: 10 }; - let t = &s as &Trait; - b.iter(|| { - t.method() - }); -} - -#[bench] -fn trait_static_method_call(b: &mut Bencher) { - let s = Struct { field: 10 }; - b.iter(|| { - s.method() - }); -} diff --git a/src/librustc/benches/lib.rs b/src/librustc/benches/lib.rs index 0f81586d3bdd9..6b624028896ac 100644 --- a/src/librustc/benches/lib.rs +++ b/src/librustc/benches/lib.rs @@ -1,6 +1,63 @@ +#![feature(slice_patterns)] #![feature(test)] extern crate test; -mod dispatch; -mod pattern; +use test::Bencher; + +// Static/dynamic method dispatch + +struct Struct { + field: isize +} + +trait Trait { + fn method(&self) -> isize; +} + +impl Trait for Struct { + fn method(&self) -> isize { + self.field + } +} + +#[bench] +fn trait_vtable_method_call(b: &mut Bencher) { + let s = Struct { field: 10 }; + let t = &s as &dyn Trait; + b.iter(|| { + t.method() + }); +} + +#[bench] +fn trait_static_method_call(b: &mut Bencher) { + let s = Struct { field: 10 }; + b.iter(|| { + s.method() + }); +} + +// Overhead of various match forms + +#[bench] +fn option_some(b: &mut Bencher) { + let x = Some(10); + b.iter(|| { + match x { + Some(y) => y, + None => 11 + } + }); +} + +#[bench] +fn vec_pattern(b: &mut Bencher) { + let x = [1,2,3,4,5,6]; + b.iter(|| { + match x { + [1,2,3,..] => 10, + _ => 11, + } + }); +} diff --git a/src/librustc/benches/pattern.rs b/src/librustc/benches/pattern.rs deleted file mode 100644 index fd8cc5b83fd5a..0000000000000 --- a/src/librustc/benches/pattern.rs +++ /dev/null @@ -1,25 +0,0 @@ -use test::Bencher; - -// Overhead of various match forms - -#[bench] -fn option_some(b: &mut Bencher) { - let x = Some(10); - b.iter(|| { - match x { - Some(y) => y, - None => 11 - } - }); -} - -#[bench] -fn vec_pattern(b: &mut Bencher) { - let x = [1,2,3,4,5,6]; - b.iter(|| { - match x { - [1,2,3,..] => 10, - _ => 11, - } - }); -} diff --git a/src/librustc_codegen_ssa/back/rpath/tests.rs b/src/librustc_codegen_ssa/back/rpath/tests.rs index e42a878d7e45e..e8457fe0e19ea 100644 --- a/src/librustc_codegen_ssa/back/rpath/tests.rs +++ b/src/librustc_codegen_ssa/back/rpath/tests.rs @@ -52,7 +52,7 @@ fn test_minimize2() { fn test_rpath_relative() { if cfg!(target_os = "macos") { let config = &mut RPathConfig { - used_crates: Vec::new(), + used_crates: &[], has_rpath: true, is_like_osx: true, linker_is_gnu: false, @@ -64,7 +64,7 @@ fn test_rpath_relative() { assert_eq!(res, "@loader_path/../lib"); } else { let config = &mut RPathConfig { - used_crates: Vec::new(), + used_crates: &[], out_filename: PathBuf::from("bin/rustc"), get_install_prefix_lib_path: &mut || panic!(), has_rpath: true, From 2ba982d0e5ad87581e3685cba9207ffaf61a866e Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 23 Nov 2019 10:23:12 -0500 Subject: [PATCH 09/10] Remove unnecessary clone --- src/librustc_typeck/collect.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index f4c8763f87910..8dced83b987ea 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -2128,7 +2128,7 @@ fn explicit_predicates_of( } else { // named opaque types predicates.extend(bounds_predicates); - generics.clone() + generics } } From 9300c3b6ad296bdf08c867be269c0a8959a4cb3d Mon Sep 17 00:00:00 2001 From: Janusz Marcinkiewicz Date: Sat, 23 Nov 2019 04:21:21 +0100 Subject: [PATCH 10/10] Add FIXME for using 'parse_delim_comma_seq' when parsing enum variants --- src/librustc_parse/parser/item.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 4b783c6c2bedc..2c9d4004226c7 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -1337,6 +1337,8 @@ impl<'a> Parser<'a> { /// Parses the part of an enum declaration following the `{`. fn parse_enum_def(&mut self, _generics: &Generics) -> PResult<'a, EnumDef> { let mut variants = Vec::new(); + // FIXME: Consider using `parse_delim_comma_seq`. + // We could then remove eating comma in `recover_nested_adt_item`. while self.token != token::CloseDelim(token::Brace) { let variant_attrs = self.parse_outer_attributes()?; let vlo = self.token.span;