about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-11-24 02:17:29 +0000
committerbors <bors@rust-lang.org>2019-11-24 02:17:29 +0000
commite41ced3f8d8e2f3f377ef931458e612d5f3d1f3f (patch)
tree7d1fb15021ff6320393277ab0aeb5ce5ac5a566c
parentad808d95c4839caedc2be76d0ed059dc920ab4b6 (diff)
parentd22bf91320cf3ba08326ca644e39de35592ce394 (diff)
downloadrust-e41ced3f8d8e2f3f377ef931458e612d5f3d1f3f.tar.gz
rust-e41ced3f8d8e2f3f377ef931458e612d5f3d1f3f.zip
Auto merge of #66686 - Centril:rollup-07slyoo, r=Centril
Rollup of 5 pull requests

Successful merges:

 - #64856 (Scope format! temporaries)
 - #66411 (mem::forget docs: mention ManuallyDrop)
 - #66594 (Fix cycle when debug-printing opaque types)
 - #66641 (parser: recover on nested ADTs as enum variants)
 - #66659 (make `./x.py bench` again)

Failed merges:

r? @ghost
-rw-r--r--src/liballoc/macros.rs5
-rw-r--r--src/libcore/benches/num/mod.rs4
-rw-r--r--src/libcore/mem/mod.rs36
-rw-r--r--src/librustc/benches/dispatch.rs34
-rw-r--r--src/librustc/benches/lib.rs61
-rw-r--r--src/librustc/benches/pattern.rs25
-rw-r--r--src/librustc/ty/print/pretty.rs103
-rw-r--r--src/librustc_codegen_ssa/back/rpath/tests.rs4
-rw-r--r--src/librustc_parse/parser/item.rs36
-rw-r--r--src/librustc_typeck/collect.rs54
-rw-r--r--src/test/pretty/issue-4264.pp56
-rw-r--r--src/test/ui/async-await/issues/issue-64477-2.rs22
-rw-r--r--src/test/ui/enum/nested-enum.rs8
-rw-r--r--src/test/ui/enum/nested-enum.stderr26
14 files changed, 315 insertions, 159 deletions
diff --git a/src/liballoc/macros.rs b/src/liballoc/macros.rs
index 2f2cdc39c63..422d3486f92 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 f5c49ea5bf0..2dcdf2b6fe9 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 fff010385c3..bba441464ff 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: T) {
diff --git a/src/librustc/benches/dispatch.rs b/src/librustc/benches/dispatch.rs
deleted file mode 100644
index e3b36be5696..00000000000
--- 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 0f81586d3bd..6b624028896 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 fd8cc5b83fd..00000000000
--- 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 594550dd967..ee05d57d239 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<bool> = Cell::new(false);
     static SHOULD_PREFIX_WITH_CRATE: Cell<bool> = Cell::new(false);
+    static NO_QUERIES: Cell<bool> = 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<F: FnOnce() -> 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 e42a878d7e4..e8457fe0e19 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 13645e7144a..2c9d4004226 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<Attribute>) -> P<Item> {
         P(Item {
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index d9f6d79f218..8dced83b987 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 b545146c964..8aa4cdeb539 100644
--- a/src/test/pretty/issue-4264.pp
+++ b/src/test/pretty/issue-4264.pp
@@ -29,33 +29,37 @@ pub fn bar() ({
 
 
 
-                  ((::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 00000000000..2360b57cc45
--- /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 00000000000..80957b8a14c
--- /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 00000000000..7d6f57e88a8
--- /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
+