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/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/libcore/mem/mod.rs b/src/libcore/mem/mod.rs index fff010385c302..bba441464ff35 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) { 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/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_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, diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 13645e7144a9b..2c9d4004226c7 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::*; @@ -1336,11 +1337,17 @@ 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; 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 +1749,33 @@ 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 kw_token = self.token.clone(); + let kw_str = pprust::token_to_string(&kw_token); + let item = self.parse_item()?; + self.eat(&token::Comma); + + 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", kw_str), + String::new(), + Applicability::MaybeIncorrect, + ).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/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index d9f6d79f218f9..8dced83b987ea 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 { diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index b545146c9646e..8aa4cdeb5394e 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 { diff --git a/src/test/ui/async-await/issues/issue-64477-2.rs b/src/test/ui/async-await/issues/issue-64477-2.rs new file mode 100644 index 0000000000000..2360b57cc4544 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-64477-2.rs @@ -0,0 +1,22 @@ +// 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 { + async move { + foo(format!("{}:{}", 1, 2)).await; + } +} + +fn main() { + let _ = bar(); +} 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 +