about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--src/etc/natvis/liballoc.natvis12
-rw-r--r--src/etc/natvis/libcore.natvis8
-rw-r--r--src/librustc/hir/lowering.rs17
-rw-r--r--src/librustc_codegen_ssa/mir/analyze.rs5
-rw-r--r--src/libstd/Cargo.toml2
-rw-r--r--src/libstd/collections/hash/set.rs56
-rw-r--r--src/libsyntax/parse/diagnostics.rs304
-rw-r--r--src/libsyntax/parse/parser.rs296
-rw-r--r--src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.rs4
-rw-r--r--src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.stderr10
-rw-r--r--src/test/ui/await-keyword/2018-edition-error.rs4
-rw-r--r--src/test/ui/await-keyword/2018-edition-error.stderr10
-rw-r--r--src/test/ui/await-keyword/incorrect-syntax-suggestions.rs111
-rw-r--r--src/test/ui/await-keyword/incorrect-syntax-suggestions.stderr207
-rw-r--r--src/test/ui/await-keyword/post_expansion_error.stderr4
-rw-r--r--src/test/ui/issues/issue-51719.rs2
-rw-r--r--src/test/ui/issues/issue-51719.stderr4
-rw-r--r--src/test/ui/issues/issue-51751.stderr5
-rw-r--r--src/tools/compiletest/Cargo.toml1
-rw-r--r--src/tools/compiletest/src/main.rs27
-rw-r--r--src/tools/compiletest/src/runtest.rs3
-rw-r--r--src/tools/rustbook/Cargo.toml2
-rw-r--r--src/tools/rustc-std-workspace-alloc/Cargo.toml2
-rw-r--r--src/tools/rustc-std-workspace-core/Cargo.toml2
-rw-r--r--src/tools/rustc-workspace-hack/Cargo.toml2
-rw-r--r--src/tools/unstable-book-gen/Cargo.toml2
27 files changed, 781 insertions, 322 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 369c6c8ae47..a4f30d1ebcf 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -475,7 +475,6 @@ version = "0.0.0"
 dependencies = [
  "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/src/etc/natvis/liballoc.natvis b/src/etc/natvis/liballoc.natvis
index e3d99e34b35..de30b58526a 100644
--- a/src/etc/natvis/liballoc.natvis
+++ b/src/etc/natvis/liballoc.natvis
@@ -7,11 +7,11 @@
       <Item Name="[capacity]" ExcludeView="simple">buf.cap</Item>
       <ArrayItems>
         <Size>len</Size>
-        <ValuePointer>buf.ptr.pointer.__0</ValuePointer>
+        <ValuePointer>buf.ptr.pointer</ValuePointer>
       </ArrayItems>
     </Expand>
   </Type>
-  <Type Name="alloc::vec_deque::VecDeque&lt;*&gt;">
+  <Type Name="alloc::collections::vec_deque::VecDeque&lt;*&gt;">
     <DisplayString>{{ size={tail &lt;= head ? head - tail : buf.cap - tail + head} }}</DisplayString>
     <Expand>
       <Item Name="[size]" ExcludeView="simple">tail &lt;= head ? head - tail : buf.cap - tail + head</Item>
@@ -24,19 +24,19 @@
           <If Condition="i == head">
             <Break/>
           </If>
-          <Item>buf.ptr.pointer.__0 + i</Item>
+          <Item>buf.ptr.pointer[i]</Item>
           <Exec>i = (i + 1 == buf.cap ? 0 : i + 1)</Exec>
         </Loop>
       </CustomListItems>
     </Expand>
   </Type>
-  <Type Name="alloc::linked_list::LinkedList&lt;*&gt;">
+  <Type Name="alloc::collections::linked_list::LinkedList&lt;*&gt;">
     <DisplayString>{{ size={len} }}</DisplayString>
     <Expand>
       <LinkedListItems>
         <Size>len</Size>
-        <HeadPointer>*(alloc::linked_list::Node&lt;$T1&gt; **)&amp;head</HeadPointer>
-        <NextPointer>*(alloc::linked_list::Node&lt;$T1&gt; **)&amp;next</NextPointer>
+        <HeadPointer>*(alloc::collections::linked_list::Node&lt;$T1&gt; **)&amp;head</HeadPointer>
+        <NextPointer>*(alloc::collections::linked_list::Node&lt;$T1&gt; **)&amp;next</NextPointer>
         <ValueNode>element</ValueNode>
       </LinkedListItems>
     </Expand>
diff --git a/src/etc/natvis/libcore.natvis b/src/etc/natvis/libcore.natvis
index 37d64be1ce9..0e703b3b950 100644
--- a/src/etc/natvis/libcore.natvis
+++ b/src/etc/natvis/libcore.natvis
@@ -1,15 +1,15 @@
 <?xml version="1.0" encoding="utf-8"?>
 <AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
   <Type Name="core::ptr::Unique&lt;*&gt;">
-    <DisplayString>{{ Unique {*pointer.__0} }}</DisplayString>
+    <DisplayString>{{ Unique {pointer} }}</DisplayString>
     <Expand>
-      <Item Name="[ptr]">pointer.__0</Item>
+      <Item Name="[ptr]">pointer</Item>
     </Expand>
   </Type>
   <Type Name="core::ptr::Shared&lt;*&gt;">
-    <DisplayString>{{ Shared {*pointer.__0} }}</DisplayString>
+    <DisplayString>{{ Shared {pointer} }}</DisplayString>
     <Expand>
-      <Item Name="[ptr]">pointer.__0</Item>
+      <Item Name="[ptr]">pointer</Item>
     </Expand>
   </Type>
   <Type Name="core::option::Option&lt;*&gt;">
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index dd0d13d8f5a..3a8b139236c 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -97,6 +97,10 @@ pub struct LoweringContext<'a> {
     is_generator: bool,
     is_async_body: bool,
 
+    /// Used to get the current `fn`'s def span to point to when using `await`
+    /// outside of an `async fn`.
+    current_item: Option<Span>,
+
     catch_scopes: Vec<NodeId>,
     loop_scopes: Vec<NodeId>,
     is_in_loop_condition: bool,
@@ -250,6 +254,7 @@ pub fn lower_crate(
         node_id_to_hir_id: IndexVec::new(),
         is_generator: false,
         is_async_body: false,
+        current_item: None,
         is_in_trait_impl: false,
         lifetimes_to_define: Vec::new(),
         is_collecting_in_band_lifetimes: false,
@@ -3116,6 +3121,7 @@ impl<'a> LoweringContext<'a> {
             ItemKind::Fn(ref decl, ref header, ref generics, ref body) => {
                 let fn_def_id = self.resolver.definitions().local_def_id(id);
                 self.with_new_scopes(|this| {
+                    this.current_item = Some(ident.span);
                     let mut lower_fn = |decl: &FnDecl| {
                         // Note: we don't need to change the return type from `T` to
                         // `impl Future<Output = T>` here because lower_body
@@ -3654,6 +3660,7 @@ impl<'a> LoweringContext<'a> {
                 } else {
                     lower_method(sig)
                 };
+                self.current_item = Some(i.span);
 
                 (generics, hir::ImplItemKind::Method(sig, body_id))
             }
@@ -4270,6 +4277,7 @@ impl<'a> LoweringContext<'a> {
                     let fn_decl = self.lower_fn_decl(decl, None, false, None);
 
                     self.with_new_scopes(|this| {
+                        this.current_item = Some(fn_decl_span);
                         let mut is_generator = false;
                         let body_id = this.lower_body(Some(decl), |this| {
                             let e = this.lower_expr(body);
@@ -5551,13 +5559,18 @@ impl<'a> LoweringContext<'a> {
         //     }
         // }
         if !self.is_async_body {
-            span_err!(
+            let mut err = struct_span_err!(
                 self.sess,
                 await_span,
                 E0728,
                 "`await` is only allowed inside `async` functions and blocks"
             );
-            self.sess.abort_if_errors();
+            err.span_label(await_span, "only allowed inside `async` functions and blocks");
+            if let Some(item_sp) = self.current_item {
+                err.span_label(item_sp, "this is not `async`");
+            }
+            err.emit();
+            return hir::ExprKind::Err;
         }
         let span = self.sess.source_map().mark_span_with_reason(
             CompilerDesugaringKind::Await,
diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs
index 8021d4b11d0..06d7b6c78f1 100644
--- a/src/librustc_codegen_ssa/mir/analyze.rs
+++ b/src/librustc_codegen_ssa/mir/analyze.rs
@@ -243,9 +243,8 @@ impl<'mir, 'a: 'mir, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
             }
 
             PlaceContext::MutatingUse(MutatingUseContext::Drop) => {
-                let ty = mir::Place::Base(mir::PlaceBase::Local(local)).ty(self.fx.mir,
-                                                                           self.fx.cx.tcx());
-                let ty = self.fx.monomorphize(&ty.ty);
+                let ty = self.fx.mir.local_decls[local].ty;
+                let ty = self.fx.monomorphize(&ty);
 
                 // Only need the place if we're actually dropping it.
                 if self.fx.cx.type_needs_drop(ty) {
diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml
index ad5d62f667a..5d797b75621 100644
--- a/src/libstd/Cargo.toml
+++ b/src/libstd/Cargo.toml
@@ -3,7 +3,7 @@ authors = ["The Rust Project Developers"]
 name = "std"
 version = "0.0.0"
 build = "build.rs"
-license = "MIT/Apache-2.0"
+license = "MIT OR Apache-2.0"
 repository = "https://github.com/rust-lang/rust.git"
 description = "The Rust Standard Library"
 edition = "2018"
diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs
index b56a27c80bc..403914c0707 100644
--- a/src/libstd/collections/hash/set.rs
+++ b/src/libstd/collections/hash/set.rs
@@ -618,6 +618,62 @@ impl<T, S> HashSet<T, S>
         self.map.get_key_value(value).map(|(k, _)| k)
     }
 
+    /// Inserts the given `value` into the set if it is not present, then
+    /// returns a reference to the value in the set.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(hash_set_entry)]
+    ///
+    /// use std::collections::HashSet;
+    ///
+    /// let mut set: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+    /// assert_eq!(set.len(), 3);
+    /// assert_eq!(set.get_or_insert(2), &2);
+    /// assert_eq!(set.get_or_insert(100), &100);
+    /// assert_eq!(set.len(), 4); // 100 was inserted
+    /// ```
+    #[inline]
+    #[unstable(feature = "hash_set_entry", issue = "60896")]
+    pub fn get_or_insert(&mut self, value: T) -> &T {
+        // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with
+        // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`.
+        self.map.raw_entry_mut().from_key(&value).or_insert(value, ()).0
+    }
+
+    /// Inserts a value computed from `f` into the set if the given `value` is
+    /// not present, then returns a reference to the value in the set.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(hash_set_entry)]
+    ///
+    /// use std::collections::HashSet;
+    ///
+    /// let mut set: HashSet<String> = ["cat", "dog", "horse"]
+    ///     .iter().map(|&pet| pet.to_owned()).collect();
+    ///
+    /// assert_eq!(set.len(), 3);
+    /// for &pet in &["cat", "dog", "fish"] {
+    ///     let value = set.get_or_insert_with(pet, str::to_owned);
+    ///     assert_eq!(value, pet);
+    /// }
+    /// assert_eq!(set.len(), 4); // a new "fish" was inserted
+    /// ```
+    #[inline]
+    #[unstable(feature = "hash_set_entry", issue = "60896")]
+    pub fn get_or_insert_with<Q: ?Sized, F>(&mut self, value: &Q, f: F) -> &T
+        where T: Borrow<Q>,
+              Q: Hash + Eq,
+              F: FnOnce(&Q) -> T
+    {
+        // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with
+        // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`.
+        self.map.raw_entry_mut().from_key(value).or_insert_with(|| (f(value), ())).0
+    }
+
     /// Returns `true` if `self` has no elements in common with `other`.
     /// This is equivalent to checking for an empty intersection.
     ///
diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs
index 32e1ee94f0d..1a2393be806 100644
--- a/src/libsyntax/parse/diagnostics.rs
+++ b/src/libsyntax/parse/diagnostics.rs
@@ -1,14 +1,16 @@
 use crate::ast;
-use crate::ast::{Expr, ExprKind, Item, ItemKind, Pat, PatKind, QSelf, Ty, TyKind};
-use crate::parse::parser::PathStyle;
+use crate::ast::{BlockCheckMode, Expr, ExprKind, Item, ItemKind, Pat, PatKind, QSelf, Ty, TyKind};
+use crate::parse::parser::{BlockMode, PathStyle, TokenType, SemiColonMode};
 use crate::parse::token;
 use crate::parse::PResult;
 use crate::parse::Parser;
 use crate::print::pprust;
 use crate::ptr::P;
+use crate::symbol::keywords;
 use crate::ThinVec;
-use errors::Applicability;
+use errors::{Applicability, DiagnosticBuilder};
 use syntax_pos::Span;
+use log::debug;
 
 pub trait RecoverQPath: Sized + 'static {
     const PATH_STYLE: PathStyle = PathStyle::Expr;
@@ -223,4 +225,300 @@ impl<'a> Parser<'a> {
             false
         }
     }
+
+    /// Consume alternative await syntaxes like `await <expr>`, `await? <expr>`, `await(<expr>)`
+    /// and `await { <expr> }`.
+    crate fn parse_incorrect_await_syntax(
+        &mut self,
+        lo: Span,
+        await_sp: Span,
+    ) -> PResult<'a, (Span, ExprKind)> {
+        let is_question = self.eat(&token::Question); // Handle `await? <expr>`.
+        let expr = if self.token == token::OpenDelim(token::Brace) {
+            // Handle `await { <expr> }`.
+            // This needs to be handled separatedly from the next arm to avoid
+            // interpreting `await { <expr> }?` as `<expr>?.await`.
+            self.parse_block_expr(
+                None,
+                self.span,
+                BlockCheckMode::Default,
+                ThinVec::new(),
+            )
+        } else {
+            self.parse_expr()
+        }.map_err(|mut err| {
+            err.span_label(await_sp, "while parsing this incorrect await expression");
+            err
+        })?;
+        let expr_str = self.sess.source_map().span_to_snippet(expr.span)
+            .unwrap_or_else(|_| pprust::expr_to_string(&expr));
+        let suggestion = format!("{}.await{}", expr_str, if is_question { "?" } else { "" });
+        let sp = lo.to(expr.span);
+        let app = match expr.node {
+            ExprKind::Try(_) => Applicability::MaybeIncorrect, // `await <expr>?`
+            _ => Applicability::MachineApplicable,
+        };
+        self.struct_span_err(sp, "incorrect use of `await`")
+            .span_suggestion(sp, "`await` is a postfix operation", suggestion, app)
+            .emit();
+        Ok((sp, ExprKind::Await(ast::AwaitOrigin::FieldLike, expr)))
+    }
+
+    /// If encountering `future.await()`, consume and emit error.
+    crate fn recover_from_await_method_call(&mut self) {
+        if self.token == token::OpenDelim(token::Paren) &&
+            self.look_ahead(1, |t| t == &token::CloseDelim(token::Paren))
+        {
+            // future.await()
+            let lo = self.span;
+            self.bump(); // (
+            let sp = lo.to(self.span);
+            self.bump(); // )
+            self.struct_span_err(sp, "incorrect use of `await`")
+                .span_suggestion(
+                    sp,
+                    "`await` is not a method call, remove the parentheses",
+                    String::new(),
+                    Applicability::MachineApplicable,
+                ).emit()
+        }
+    }
+
+    crate fn could_ascription_be_path(&self, node: &ast::ExprKind) -> bool {
+        self.token.is_ident() &&
+            if let ast::ExprKind::Path(..) = node { true } else { false } &&
+            !self.token.is_reserved_ident() &&           // v `foo:bar(baz)`
+            self.look_ahead(1, |t| t == &token::OpenDelim(token::Paren)) ||
+            self.look_ahead(1, |t| t == &token::Lt) &&     // `foo:bar<baz`
+            self.look_ahead(2, |t| t.is_ident()) ||
+            self.look_ahead(1, |t| t == &token::Colon) &&  // `foo:bar:baz`
+            self.look_ahead(2, |t| t.is_ident()) ||
+            self.look_ahead(1, |t| t == &token::ModSep) &&  // `foo:bar::baz`
+            self.look_ahead(2, |t| t.is_ident())
+    }
+
+    crate fn bad_type_ascription(
+        &self,
+        err: &mut DiagnosticBuilder<'a>,
+        lhs_span: Span,
+        cur_op_span: Span,
+        next_sp: Span,
+        maybe_path: bool,
+    ) {
+        err.span_label(self.span, "expecting a type here because of type ascription");
+        let cm = self.sess.source_map();
+        let next_pos = cm.lookup_char_pos(next_sp.lo());
+        let op_pos = cm.lookup_char_pos(cur_op_span.hi());
+        if op_pos.line != next_pos.line {
+            err.span_suggestion(
+                cur_op_span,
+                "try using a semicolon",
+                ";".to_string(),
+                Applicability::MaybeIncorrect,
+            );
+        } else {
+            if maybe_path {
+                err.span_suggestion(
+                    cur_op_span,
+                    "maybe you meant to write a path separator here",
+                    "::".to_string(),
+                    Applicability::MaybeIncorrect,
+                );
+            } else {
+                err.note("type ascription is a nightly-only feature that lets \
+                          you annotate an expression with a type: `<expr>: <type>`")
+                    .span_note(
+                        lhs_span,
+                        "this expression expects an ascribed type after the colon",
+                    )
+                    .help("this might be indicative of a syntax error elsewhere");
+            }
+        }
+    }
+
+    crate fn recover_seq_parse_error(
+        &mut self,
+        delim: token::DelimToken,
+        lo: Span,
+        result: PResult<'a, P<Expr>>,
+    ) -> P<Expr> {
+        match result {
+            Ok(x) => x,
+            Err(mut err) => {
+                err.emit();
+                // recover from parse error
+                self.consume_block(delim);
+                self.mk_expr(lo.to(self.prev_span), ExprKind::Err, ThinVec::new())
+            }
+        }
+    }
+
+    crate fn recover_closing_delimiter(
+        &mut self,
+        tokens: &[token::Token],
+        mut err: DiagnosticBuilder<'a>,
+    ) -> PResult<'a, bool> {
+        let mut pos = None;
+        // we want to use the last closing delim that would apply
+        for (i, unmatched) in self.unclosed_delims.iter().enumerate().rev() {
+            if tokens.contains(&token::CloseDelim(unmatched.expected_delim))
+                && Some(self.span) > unmatched.unclosed_span
+            {
+                pos = Some(i);
+            }
+        }
+        match pos {
+            Some(pos) => {
+                // Recover and assume that the detected unclosed delimiter was meant for
+                // this location. Emit the diagnostic and act as if the delimiter was
+                // present for the parser's sake.
+
+                 // Don't attempt to recover from this unclosed delimiter more than once.
+                let unmatched = self.unclosed_delims.remove(pos);
+                let delim = TokenType::Token(token::CloseDelim(unmatched.expected_delim));
+
+                 // We want to suggest the inclusion of the closing delimiter where it makes
+                // the most sense, which is immediately after the last token:
+                //
+                //  {foo(bar {}}
+                //      -      ^
+                //      |      |
+                //      |      help: `)` may belong here (FIXME: #58270)
+                //      |
+                //      unclosed delimiter
+                if let Some(sp) = unmatched.unclosed_span {
+                    err.span_label(sp, "unclosed delimiter");
+                }
+                err.span_suggestion_short(
+                    self.sess.source_map().next_point(self.prev_span),
+                    &format!("{} may belong here", delim.to_string()),
+                    delim.to_string(),
+                    Applicability::MaybeIncorrect,
+                );
+                err.emit();
+                self.expected_tokens.clear();  // reduce errors
+                Ok(true)
+            }
+            _ => Err(err),
+        }
+    }
+
+    /// Recover from `pub` keyword in places where it seems _reasonable_ but isn't valid.
+    crate fn eat_bad_pub(&mut self) {
+        if self.token.is_keyword(keywords::Pub) {
+            match self.parse_visibility(false) {
+                Ok(vis) => {
+                    self.diagnostic()
+                        .struct_span_err(vis.span, "unnecessary visibility qualifier")
+                        .span_label(vis.span, "`pub` not permitted here")
+                        .emit();
+                }
+                Err(mut err) => err.emit(),
+            }
+        }
+    }
+
+    // Eat tokens until we can be relatively sure we reached the end of the
+    // statement. This is something of a best-effort heuristic.
+    //
+    // We terminate when we find an unmatched `}` (without consuming it).
+    crate fn recover_stmt(&mut self) {
+        self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore)
+    }
+
+    // If `break_on_semi` is `Break`, then we will stop consuming tokens after
+    // finding (and consuming) a `;` outside of `{}` or `[]` (note that this is
+    // approximate - it can mean we break too early due to macros, but that
+    // should only lead to sub-optimal recovery, not inaccurate parsing).
+    //
+    // If `break_on_block` is `Break`, then we will stop consuming tokens
+    // after finding (and consuming) a brace-delimited block.
+    crate fn recover_stmt_(&mut self, break_on_semi: SemiColonMode, break_on_block: BlockMode) {
+        let mut brace_depth = 0;
+        let mut bracket_depth = 0;
+        let mut in_block = false;
+        debug!("recover_stmt_ enter loop (semi={:?}, block={:?})",
+               break_on_semi, break_on_block);
+        loop {
+            debug!("recover_stmt_ loop {:?}", self.token);
+            match self.token {
+                token::OpenDelim(token::DelimToken::Brace) => {
+                    brace_depth += 1;
+                    self.bump();
+                    if break_on_block == BlockMode::Break &&
+                       brace_depth == 1 &&
+                       bracket_depth == 0 {
+                        in_block = true;
+                    }
+                }
+                token::OpenDelim(token::DelimToken::Bracket) => {
+                    bracket_depth += 1;
+                    self.bump();
+                }
+                token::CloseDelim(token::DelimToken::Brace) => {
+                    if brace_depth == 0 {
+                        debug!("recover_stmt_ return - close delim {:?}", self.token);
+                        break;
+                    }
+                    brace_depth -= 1;
+                    self.bump();
+                    if in_block && bracket_depth == 0 && brace_depth == 0 {
+                        debug!("recover_stmt_ return - block end {:?}", self.token);
+                        break;
+                    }
+                }
+                token::CloseDelim(token::DelimToken::Bracket) => {
+                    bracket_depth -= 1;
+                    if bracket_depth < 0 {
+                        bracket_depth = 0;
+                    }
+                    self.bump();
+                }
+                token::Eof => {
+                    debug!("recover_stmt_ return - Eof");
+                    break;
+                }
+                token::Semi => {
+                    self.bump();
+                    if break_on_semi == SemiColonMode::Break &&
+                       brace_depth == 0 &&
+                       bracket_depth == 0 {
+                        debug!("recover_stmt_ return - Semi");
+                        break;
+                    }
+                }
+                token::Comma if break_on_semi == SemiColonMode::Comma &&
+                       brace_depth == 0 &&
+                       bracket_depth == 0 =>
+                {
+                    debug!("recover_stmt_ return - Semi");
+                    break;
+                }
+                _ => {
+                    self.bump()
+                }
+            }
+        }
+    }
+
+    crate fn consume_block(&mut self, delim: token::DelimToken) {
+        let mut brace_depth = 0;
+        loop {
+            if self.eat(&token::OpenDelim(delim)) {
+                brace_depth += 1;
+            } else if self.eat(&token::CloseDelim(delim)) {
+                if brace_depth == 0 {
+                    return;
+                } else {
+                    brace_depth -= 1;
+                    continue;
+                }
+            } else if self.token == token::Eof || self.eat(&token::CloseDelim(token::NoDelim)) {
+                return;
+            } else {
+                self.bump();
+            }
+        }
+    }
+
 }
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 99e8db9d8e6..b1c3e46adc0 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -104,14 +104,14 @@ pub enum PathStyle {
 }
 
 #[derive(Clone, Copy, PartialEq, Debug)]
-enum SemiColonMode {
+crate enum SemiColonMode {
     Break,
     Ignore,
     Comma,
 }
 
 #[derive(Clone, Copy, PartialEq, Debug)]
-enum BlockMode {
+crate enum BlockMode {
     Break,
     Ignore,
 }
@@ -389,7 +389,7 @@ crate enum TokenType {
 }
 
 impl TokenType {
-    fn to_string(&self) -> String {
+    crate fn to_string(&self) -> String {
         match *self {
             TokenType::Token(ref t) => format!("`{}`", pprust::token_to_string(t)),
             TokenType::Keyword(kw) => format!("`{}`", kw.name()),
@@ -673,56 +673,6 @@ impl<'a> Parser<'a> {
         }
     }
 
-    fn recover_closing_delimiter(
-        &mut self,
-        tokens: &[token::Token],
-        mut err: DiagnosticBuilder<'a>,
-    ) -> PResult<'a, bool> {
-        let mut pos = None;
-        // we want to use the last closing delim that would apply
-        for (i, unmatched) in self.unclosed_delims.iter().enumerate().rev() {
-            if tokens.contains(&token::CloseDelim(unmatched.expected_delim))
-                && Some(self.span) > unmatched.unclosed_span
-            {
-                pos = Some(i);
-            }
-        }
-        match pos {
-            Some(pos) => {
-                // Recover and assume that the detected unclosed delimiter was meant for
-                // this location. Emit the diagnostic and act as if the delimiter was
-                // present for the parser's sake.
-
-                 // Don't attempt to recover from this unclosed delimiter more than once.
-                let unmatched = self.unclosed_delims.remove(pos);
-                let delim = TokenType::Token(token::CloseDelim(unmatched.expected_delim));
-
-                 // We want to suggest the inclusion of the closing delimiter where it makes
-                // the most sense, which is immediately after the last token:
-                //
-                //  {foo(bar {}}
-                //      -      ^
-                //      |      |
-                //      |      help: `)` may belong here (FIXME: #58270)
-                //      |
-                //      unclosed delimiter
-                if let Some(sp) = unmatched.unclosed_span {
-                    err.span_label(sp, "unclosed delimiter");
-                }
-                err.span_suggestion_short(
-                    self.sess.source_map().next_point(self.prev_span),
-                    &format!("{} may belong here", delim.to_string()),
-                    delim.to_string(),
-                    Applicability::MaybeIncorrect,
-                );
-                err.emit();
-                self.expected_tokens.clear();  // reduce errors
-                Ok(true)
-            }
-            _ => Err(err),
-        }
-    }
-
     /// Expect next token to be edible or inedible token.  If edible,
     /// then consume it; if inedible, then return without consuming
     /// anything.  Signal a fatal error if next token is unexpected.
@@ -2343,7 +2293,7 @@ impl<'a> Parser<'a> {
         })
     }
 
-    fn mk_expr(&self, span: Span, node: ExprKind, attrs: ThinVec<Attribute>) -> P<Expr> {
+    crate fn mk_expr(&self, span: Span, node: ExprKind, attrs: ThinVec<Attribute>) -> P<Expr> {
         P(Expr { node, span, attrs, id: ast::DUMMY_NODE_ID })
     }
 
@@ -2629,14 +2579,9 @@ impl<'a> Parser<'a> {
                     db.note("variable declaration using `let` is a statement");
                     return Err(db);
                 } else if self.span.rust_2018() && self.eat_keyword(keywords::Await) {
-                    // FIXME: remove this branch when `await!` is no longer supported
-                    // https://github.com/rust-lang/rust/issues/60610
-                    self.expect(&token::Not)?;
-                    self.expect(&token::OpenDelim(token::Paren))?;
-                    let expr = self.parse_expr()?;
-                    self.expect(&token::CloseDelim(token::Paren))?;
-                    hi = self.prev_span;
-                    ex = ExprKind::Await(ast::AwaitOrigin::MacroLike, expr);
+                    let (await_hi, e_kind) = self.parse_await_macro_or_alt(lo, self.prev_span)?;
+                    hi = await_hi;
+                    ex = e_kind;
                 } else if self.token.is_path_start() {
                     let path = self.parse_path(PathStyle::Expr)?;
 
@@ -2701,6 +2646,31 @@ impl<'a> Parser<'a> {
         self.maybe_recover_from_bad_qpath(expr, true)
     }
 
+    /// Parse `await!(<expr>)` calls, or alternatively recover from incorrect but reasonable
+    /// alternative syntaxes `await <expr>`, `await? <expr>`, `await(<expr>)` and
+    /// `await { <expr> }`.
+    fn parse_await_macro_or_alt(
+        &mut self,
+        lo: Span,
+        await_sp: Span,
+    ) -> PResult<'a, (Span, ExprKind)> {
+        if self.token == token::Not {
+            // Handle correct `await!(<expr>)`.
+            // FIXME: make this an error when `await!` is no longer supported
+            // https://github.com/rust-lang/rust/issues/60610
+            self.expect(&token::Not)?;
+            self.expect(&token::OpenDelim(token::Paren))?;
+            let expr = self.parse_expr().map_err(|mut err| {
+                err.span_label(await_sp, "while parsing this await macro call");
+                err
+            })?;
+            self.expect(&token::CloseDelim(token::Paren))?;
+            Ok((self.prev_span, ExprKind::Await(ast::AwaitOrigin::MacroLike, expr)))
+        } else { // Handle `await <expr>`.
+            self.parse_incorrect_await_syntax(lo, await_sp)
+        }
+    }
+
     fn maybe_parse_struct_expr(
         &mut self,
         lo: Span,
@@ -2849,10 +2819,13 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses a block or unsafe block.
-    fn parse_block_expr(&mut self, opt_label: Option<Label>,
-                            lo: Span, blk_mode: BlockCheckMode,
-                            outer_attrs: ThinVec<Attribute>)
-                            -> PResult<'a, P<Expr>> {
+    crate fn parse_block_expr(
+        &mut self,
+        opt_label: Option<Label>,
+        lo: Span,
+        blk_mode: BlockCheckMode,
+        outer_attrs: ThinVec<Attribute>,
+    ) -> PResult<'a, P<Expr>> {
         self.expect(&token::OpenDelim(token::Brace))?;
 
         let mut attrs = outer_attrs;
@@ -2913,6 +2886,7 @@ impl<'a> Parser<'a> {
                 ExprKind::Await(ast::AwaitOrigin::FieldLike, self_arg),
                 ThinVec::new(),
             );
+            self.recover_from_await_method_call();
             return Ok(await_expr);
         }
         let segment = self.parse_path_segment(PathStyle::Expr)?;
@@ -3151,23 +3125,6 @@ impl<'a> Parser<'a> {
         return Ok(e);
     }
 
-    fn recover_seq_parse_error(
-        &mut self,
-        delim: token::DelimToken,
-        lo: Span,
-        result: PResult<'a, P<Expr>>,
-    ) -> P<Expr> {
-        match result {
-            Ok(x) => x,
-            Err(mut err) => {
-                err.emit();
-                // recover from parse error
-                self.consume_block(delim);
-                self.mk_expr(lo.to(self.prev_span), ExprKind::Err, ThinVec::new())
-            }
-        }
-    }
-
     crate fn process_potential_macro_variable(&mut self) {
         let (token, span) = match self.token {
             token::Dollar if self.span.ctxt() != syntax_pos::hygiene::SyntaxContext::empty() &&
@@ -3570,58 +3527,6 @@ impl<'a> Parser<'a> {
         Ok(lhs)
     }
 
-    fn could_ascription_be_path(&self, node: &ast::ExprKind) -> bool {
-        self.token.is_ident() &&
-            if let ast::ExprKind::Path(..) = node { true } else { false } &&
-            !self.token.is_reserved_ident() &&           // v `foo:bar(baz)`
-            self.look_ahead(1, |t| t == &token::OpenDelim(token::Paren)) ||
-            self.look_ahead(1, |t| t == &token::Lt) &&     // `foo:bar<baz`
-            self.look_ahead(2, |t| t.is_ident()) ||
-            self.look_ahead(1, |t| t == &token::Colon) &&  // `foo:bar:baz`
-            self.look_ahead(2, |t| t.is_ident()) ||
-            self.look_ahead(1, |t| t == &token::ModSep) &&  // `foo:bar::baz`
-            self.look_ahead(2, |t| t.is_ident())
-    }
-
-    fn bad_type_ascription(
-        &self,
-        err: &mut DiagnosticBuilder<'a>,
-        lhs_span: Span,
-        cur_op_span: Span,
-        next_sp: Span,
-        maybe_path: bool,
-    ) {
-        err.span_label(self.span, "expecting a type here because of type ascription");
-        let cm = self.sess.source_map();
-        let next_pos = cm.lookup_char_pos(next_sp.lo());
-        let op_pos = cm.lookup_char_pos(cur_op_span.hi());
-        if op_pos.line != next_pos.line {
-            err.span_suggestion(
-                cur_op_span,
-                "try using a semicolon",
-                ";".to_string(),
-                Applicability::MaybeIncorrect,
-            );
-        } else {
-            if maybe_path {
-                err.span_suggestion(
-                    cur_op_span,
-                    "maybe you meant to write a path separator here",
-                    "::".to_string(),
-                    Applicability::MaybeIncorrect,
-                );
-            } else {
-                err.note("type ascription is a nightly-only feature that lets \
-                          you annotate an expression with a type: `<expr>: <type>`");
-                err.span_note(
-                    lhs_span,
-                    "this expression expects an ascribed type after the colon",
-                );
-                err.help("this might be indicative of a syntax error elsewhere");
-            }
-        }
-    }
-
     fn parse_assoc_op_cast(&mut self, lhs: P<Expr>, lhs_span: Span,
                            expr_kind: fn(P<Expr>, P<Ty>) -> ExprKind)
                            -> PResult<'a, P<Expr>> {
@@ -4903,92 +4808,6 @@ impl<'a> Parser<'a> {
         Ok(self.parse_stmt_(true))
     }
 
-    // Eat tokens until we can be relatively sure we reached the end of the
-    // statement. This is something of a best-effort heuristic.
-    //
-    // We terminate when we find an unmatched `}` (without consuming it).
-    fn recover_stmt(&mut self) {
-        self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore)
-    }
-
-    // If `break_on_semi` is `Break`, then we will stop consuming tokens after
-    // finding (and consuming) a `;` outside of `{}` or `[]` (note that this is
-    // approximate - it can mean we break too early due to macros, but that
-    // should only lead to sub-optimal recovery, not inaccurate parsing).
-    //
-    // If `break_on_block` is `Break`, then we will stop consuming tokens
-    // after finding (and consuming) a brace-delimited block.
-    fn recover_stmt_(&mut self, break_on_semi: SemiColonMode, break_on_block: BlockMode) {
-        let mut brace_depth = 0;
-        let mut bracket_depth = 0;
-        let mut in_block = false;
-        debug!("recover_stmt_ enter loop (semi={:?}, block={:?})",
-               break_on_semi, break_on_block);
-        loop {
-            debug!("recover_stmt_ loop {:?}", self.token);
-            match self.token {
-                token::OpenDelim(token::DelimToken::Brace) => {
-                    brace_depth += 1;
-                    self.bump();
-                    if break_on_block == BlockMode::Break &&
-                       brace_depth == 1 &&
-                       bracket_depth == 0 {
-                        in_block = true;
-                    }
-                }
-                token::OpenDelim(token::DelimToken::Bracket) => {
-                    bracket_depth += 1;
-                    self.bump();
-                }
-                token::CloseDelim(token::DelimToken::Brace) => {
-                    if brace_depth == 0 {
-                        debug!("recover_stmt_ return - close delim {:?}", self.token);
-                        break;
-                    }
-                    brace_depth -= 1;
-                    self.bump();
-                    if in_block && bracket_depth == 0 && brace_depth == 0 {
-                        debug!("recover_stmt_ return - block end {:?}", self.token);
-                        break;
-                    }
-                }
-                token::CloseDelim(token::DelimToken::Bracket) => {
-                    bracket_depth -= 1;
-                    if bracket_depth < 0 {
-                        bracket_depth = 0;
-                    }
-                    self.bump();
-                }
-                token::Eof => {
-                    debug!("recover_stmt_ return - Eof");
-                    break;
-                }
-                token::Semi => {
-                    self.bump();
-                    if break_on_semi == SemiColonMode::Break &&
-                       brace_depth == 0 &&
-                       bracket_depth == 0 {
-                        debug!("recover_stmt_ return - Semi");
-                        break;
-                    }
-                }
-                token::Comma => {
-                    if break_on_semi == SemiColonMode::Comma &&
-                       brace_depth == 0 &&
-                       bracket_depth == 0 {
-                        debug!("recover_stmt_ return - Semi");
-                        break;
-                    } else {
-                        self.bump();
-                    }
-                }
-                _ => {
-                    self.bump()
-                }
-            }
-        }
-    }
-
     fn parse_stmt_(&mut self, macro_legacy_warnings: bool) -> Option<Stmt> {
         self.parse_stmt_without_recovery(macro_legacy_warnings).unwrap_or_else(|mut e| {
             e.emit();
@@ -6892,26 +6711,6 @@ impl<'a> Parser<'a> {
         Ok((class_name, ItemKind::Union(vdata, generics), None))
     }
 
-    fn consume_block(&mut self, delim: token::DelimToken) {
-        let mut brace_depth = 0;
-        loop {
-            if self.eat(&token::OpenDelim(delim)) {
-                brace_depth += 1;
-            } else if self.eat(&token::CloseDelim(delim)) {
-                if brace_depth == 0 {
-                    return;
-                } else {
-                    brace_depth -= 1;
-                    continue;
-                }
-            } else if self.token == token::Eof || self.eat(&token::CloseDelim(token::NoDelim)) {
-                return;
-            } else {
-                self.bump();
-            }
-        }
-    }
-
     fn parse_record_struct_body(
         &mut self,
     ) -> PResult<'a, (Vec<StructField>, /* recovered */ bool)> {
@@ -8609,21 +8408,6 @@ impl<'a> Parser<'a> {
         ).emit();
     }
 
-    /// Recover from `pub` keyword in places where it seems _reasonable_ but isn't valid.
-    fn eat_bad_pub(&mut self) {
-        if self.token.is_keyword(keywords::Pub) {
-            match self.parse_visibility(false) {
-                Ok(vis) => {
-                    let mut err = self.diagnostic()
-                        .struct_span_err(vis.span, "unnecessary visibility qualifier");
-                    err.span_label(vis.span, "`pub` not permitted here");
-                    err.emit();
-                }
-                Err(mut err) => err.emit(),
-            }
-        }
-    }
-
     /// When lowering a `async fn` to the HIR, we need to move all of the arguments of the function
     /// into the generated closure so that they are dropped when the future is polled and not when
     /// it is created.
diff --git a/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.rs b/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.rs
index b2e8e4be172..f59f1160e70 100644
--- a/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.rs
+++ b/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.rs
@@ -22,6 +22,4 @@ macro_rules! await {
     () => {}
 }
 
-fn main() {
-    match await { await => () } //~ ERROR expected `!`, found `{`
-}
+fn main() {}
diff --git a/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.stderr b/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.stderr
index 076a31bd9ce..c4b82b29f02 100644
--- a/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.stderr
+++ b/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.stderr
@@ -68,13 +68,5 @@ help: you can escape reserved keywords to use them as identifiers
 LL | macro_rules! r#await {
    |              ^^^^^^^
 
-error: expected `!`, found `{`
-  --> $DIR/2018-edition-error-in-non-macro-position.rs:26:17
-   |
-LL |     match await { await => () }
-   |     -----       ^ expected `!`
-   |     |
-   |     while parsing this match expression
-
-error: aborting due to 8 previous errors
+error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/await-keyword/2018-edition-error.rs b/src/test/ui/await-keyword/2018-edition-error.rs
index e0b2962ce97..d8568696842 100644
--- a/src/test/ui/await-keyword/2018-edition-error.rs
+++ b/src/test/ui/await-keyword/2018-edition-error.rs
@@ -9,6 +9,4 @@ mod outer_mod {
 use self::outer_mod::await::await; //~ ERROR expected identifier
     //~^ ERROR expected identifier, found reserved keyword `await`
 
-fn main() {
-    match await { await => () } //~ ERROR expected `!`, found `{`
-}
+fn main() {}
diff --git a/src/test/ui/await-keyword/2018-edition-error.stderr b/src/test/ui/await-keyword/2018-edition-error.stderr
index c8bf9b42ca5..8afe5c1a36b 100644
--- a/src/test/ui/await-keyword/2018-edition-error.stderr
+++ b/src/test/ui/await-keyword/2018-edition-error.stderr
@@ -38,13 +38,5 @@ help: you can escape reserved keywords to use them as identifiers
 LL | use self::outer_mod::await::r#await;
    |                             ^^^^^^^
 
-error: expected `!`, found `{`
-  --> $DIR/2018-edition-error.rs:13:17
-   |
-LL |     match await { await => () }
-   |     -----       ^ expected `!`
-   |     |
-   |     while parsing this match expression
-
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/await-keyword/incorrect-syntax-suggestions.rs b/src/test/ui/await-keyword/incorrect-syntax-suggestions.rs
new file mode 100644
index 00000000000..e1e5bdd3d1b
--- /dev/null
+++ b/src/test/ui/await-keyword/incorrect-syntax-suggestions.rs
@@ -0,0 +1,111 @@
+// edition:2018
+
+#![feature(async_await)]
+
+async fn bar() -> Result<(), ()> {
+    Ok(())
+}
+
+async fn foo1() -> Result<(), ()> {
+    let _ = await bar(); //~ ERROR incorrect use of `await`
+    Ok(())
+}
+async fn foo2() -> Result<(), ()> {
+    let _ = await? bar(); //~ ERROR incorrect use of `await`
+    Ok(())
+}
+async fn foo3() -> Result<(), ()> {
+    let _ = await bar()?; //~ ERROR incorrect use of `await`
+    //~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try`
+    Ok(())
+}
+async fn foo21() -> Result<(), ()> {
+    let _ = await { bar() }; //~ ERROR incorrect use of `await`
+    Ok(())
+}
+async fn foo22() -> Result<(), ()> {
+    let _ = await(bar()); //~ ERROR incorrect use of `await`
+    Ok(())
+}
+async fn foo23() -> Result<(), ()> {
+    let _ = await { bar() }?; //~ ERROR incorrect use of `await`
+    Ok(())
+}
+async fn foo4() -> Result<(), ()> {
+    let _ = (await bar())?; //~ ERROR incorrect use of `await`
+    Ok(())
+}
+async fn foo5() -> Result<(), ()> {
+    let _ = bar().await(); //~ ERROR incorrect use of `await`
+    Ok(())
+}
+async fn foo6() -> Result<(), ()> {
+    let _ = bar().await()?; //~ ERROR incorrect use of `await`
+    Ok(())
+}
+async fn foo7() -> Result<(), ()> {
+    let _ = bar().await; // OK
+    Ok(())
+}
+async fn foo8() -> Result<(), ()> {
+    let _ = bar().await?; // OK
+    Ok(())
+}
+fn foo9() -> Result<(), ()> {
+    let _ = await bar(); //~ ERROR `await` is only allowed inside `async` functions and blocks
+    //~^ ERROR incorrect use of `await`
+    Ok(())
+}
+fn foo10() -> Result<(), ()> {
+    let _ = await? bar(); //~ ERROR `await` is only allowed inside `async` functions and blocks
+    //~^ ERROR incorrect use of `await`
+    Ok(())
+}
+fn foo11() -> Result<(), ()> {
+    let _ = await bar()?; //~ ERROR `await` is only allowed inside `async` functions and blocks
+    //~^ ERROR incorrect use of `await`
+    Ok(())
+}
+fn foo12() -> Result<(), ()> {
+    let _ = (await bar())?; //~ ERROR `await` is only allowed inside `async` functions and blocks
+    //~^ ERROR incorrect use of `await`
+    Ok(())
+}
+fn foo13() -> Result<(), ()> {
+    let _ = bar().await(); //~ ERROR `await` is only allowed inside `async` functions and blocks
+    //~^ ERROR incorrect use of `await`
+    Ok(())
+}
+fn foo14() -> Result<(), ()> {
+    let _ = bar().await()?; //~ ERROR `await` is only allowed inside `async` functions and blocks
+    //~^ ERROR incorrect use of `await`
+    Ok(())
+}
+fn foo15() -> Result<(), ()> {
+    let _ = bar().await; //~ ERROR `await` is only allowed inside `async` functions and blocks
+    Ok(())
+}
+fn foo16() -> Result<(), ()> {
+    let _ = bar().await?; //~ ERROR `await` is only allowed inside `async` functions and blocks
+    Ok(())
+}
+fn foo24() -> Result<(), ()> {
+    fn foo() -> Result<(), ()> {
+        let _ = bar().await?; //~ ERROR `await` is only allowed inside `async` functions and blocks
+        Ok(())
+    }
+    foo()
+}
+fn foo25() -> Result<(), ()> {
+    let foo = || {
+        let _ = bar().await?; //~ ERROR `await` is only allowed inside `async` functions and blocks
+        Ok(())
+    };
+    foo()
+}
+
+fn main() {
+    match await { await => () }
+    //~^ ERROR expected expression, found `=>`
+    //~| ERROR incorrect use of `await`
+} //~ ERROR expected one of `.`, `?`, `{`, or an operator, found `}`
diff --git a/src/test/ui/await-keyword/incorrect-syntax-suggestions.stderr b/src/test/ui/await-keyword/incorrect-syntax-suggestions.stderr
new file mode 100644
index 00000000000..380da4448ad
--- /dev/null
+++ b/src/test/ui/await-keyword/incorrect-syntax-suggestions.stderr
@@ -0,0 +1,207 @@
+error: incorrect use of `await`
+  --> $DIR/incorrect-syntax-suggestions.rs:10:13
+   |
+LL |     let _ = await bar();
+   |             ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
+
+error: incorrect use of `await`
+  --> $DIR/incorrect-syntax-suggestions.rs:14:13
+   |
+LL |     let _ = await? bar();
+   |             ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await?`
+
+error: incorrect use of `await`
+  --> $DIR/incorrect-syntax-suggestions.rs:18:13
+   |
+LL |     let _ = await bar()?;
+   |             ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar()?.await`
+
+error: incorrect use of `await`
+  --> $DIR/incorrect-syntax-suggestions.rs:23:13
+   |
+LL |     let _ = await { bar() };
+   |             ^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ bar() }.await`
+
+error: incorrect use of `await`
+  --> $DIR/incorrect-syntax-suggestions.rs:27:13
+   |
+LL |     let _ = await(bar());
+   |             ^^^^^^^^^^^^ help: `await` is a postfix operation: `(bar()).await`
+
+error: incorrect use of `await`
+  --> $DIR/incorrect-syntax-suggestions.rs:31:13
+   |
+LL |     let _ = await { bar() }?;
+   |             ^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ bar() }.await`
+
+error: incorrect use of `await`
+  --> $DIR/incorrect-syntax-suggestions.rs:35:14
+   |
+LL |     let _ = (await bar())?;
+   |              ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
+
+error: incorrect use of `await`
+  --> $DIR/incorrect-syntax-suggestions.rs:39:24
+   |
+LL |     let _ = bar().await();
+   |                        ^^ help: `await` is not a method call, remove the parentheses
+
+error: incorrect use of `await`
+  --> $DIR/incorrect-syntax-suggestions.rs:43:24
+   |
+LL |     let _ = bar().await()?;
+   |                        ^^ help: `await` is not a method call, remove the parentheses
+
+error: incorrect use of `await`
+  --> $DIR/incorrect-syntax-suggestions.rs:55:13
+   |
+LL |     let _ = await bar();
+   |             ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
+
+error: incorrect use of `await`
+  --> $DIR/incorrect-syntax-suggestions.rs:60:13
+   |
+LL |     let _ = await? bar();
+   |             ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await?`
+
+error: incorrect use of `await`
+  --> $DIR/incorrect-syntax-suggestions.rs:65:13
+   |
+LL |     let _ = await bar()?;
+   |             ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar()?.await`
+
+error: incorrect use of `await`
+  --> $DIR/incorrect-syntax-suggestions.rs:70:14
+   |
+LL |     let _ = (await bar())?;
+   |              ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
+
+error: incorrect use of `await`
+  --> $DIR/incorrect-syntax-suggestions.rs:75:24
+   |
+LL |     let _ = bar().await();
+   |                        ^^ help: `await` is not a method call, remove the parentheses
+
+error: incorrect use of `await`
+  --> $DIR/incorrect-syntax-suggestions.rs:80:24
+   |
+LL |     let _ = bar().await()?;
+   |                        ^^ help: `await` is not a method call, remove the parentheses
+
+error: expected expression, found `=>`
+  --> $DIR/incorrect-syntax-suggestions.rs:108:25
+   |
+LL |     match await { await => () }
+   |                   ----- ^^ expected expression
+   |                   |
+   |                   while parsing this incorrect await expression
+
+error: incorrect use of `await`
+  --> $DIR/incorrect-syntax-suggestions.rs:108:11
+   |
+LL |     match await { await => () }
+   |           ^^^^^^^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ await => () }.await`
+
+error: expected one of `.`, `?`, `{`, or an operator, found `}`
+  --> $DIR/incorrect-syntax-suggestions.rs:111:1
+   |
+LL |     match await { await => () }
+   |     -----                      - expected one of `.`, `?`, `{`, or an operator here
+   |     |
+   |     while parsing this match expression
+...
+LL | }
+   | ^ unexpected token
+
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+  --> $DIR/incorrect-syntax-suggestions.rs:55:13
+   |
+LL | fn foo9() -> Result<(), ()> {
+   |    ---- this is not `async`
+LL |     let _ = await bar();
+   |             ^^^^^^^^^^^ only allowed inside `async` functions and blocks
+
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+  --> $DIR/incorrect-syntax-suggestions.rs:60:13
+   |
+LL | fn foo10() -> Result<(), ()> {
+   |    ----- this is not `async`
+LL |     let _ = await? bar();
+   |             ^^^^^^^^^^^^ only allowed inside `async` functions and blocks
+
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+  --> $DIR/incorrect-syntax-suggestions.rs:65:13
+   |
+LL | fn foo11() -> Result<(), ()> {
+   |    ----- this is not `async`
+LL |     let _ = await bar()?;
+   |             ^^^^^^^^^^^^ only allowed inside `async` functions and blocks
+
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+  --> $DIR/incorrect-syntax-suggestions.rs:70:14
+   |
+LL | fn foo12() -> Result<(), ()> {
+   |    ----- this is not `async`
+LL |     let _ = (await bar())?;
+   |              ^^^^^^^^^^^ only allowed inside `async` functions and blocks
+
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+  --> $DIR/incorrect-syntax-suggestions.rs:75:13
+   |
+LL | fn foo13() -> Result<(), ()> {
+   |    ----- this is not `async`
+LL |     let _ = bar().await();
+   |             ^^^^^^^^^^^ only allowed inside `async` functions and blocks
+
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+  --> $DIR/incorrect-syntax-suggestions.rs:80:13
+   |
+LL | fn foo14() -> Result<(), ()> {
+   |    ----- this is not `async`
+LL |     let _ = bar().await()?;
+   |             ^^^^^^^^^^^ only allowed inside `async` functions and blocks
+
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+  --> $DIR/incorrect-syntax-suggestions.rs:85:13
+   |
+LL | fn foo15() -> Result<(), ()> {
+   |    ----- this is not `async`
+LL |     let _ = bar().await;
+   |             ^^^^^^^^^^^ only allowed inside `async` functions and blocks
+
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+  --> $DIR/incorrect-syntax-suggestions.rs:89:13
+   |
+LL | fn foo16() -> Result<(), ()> {
+   |    ----- this is not `async`
+LL |     let _ = bar().await?;
+   |             ^^^^^^^^^^^ only allowed inside `async` functions and blocks
+
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+  --> $DIR/incorrect-syntax-suggestions.rs:94:17
+   |
+LL |     fn foo() -> Result<(), ()> {
+   |        --- this is not `async`
+LL |         let _ = bar().await?;
+   |                 ^^^^^^^^^^^ only allowed inside `async` functions and blocks
+
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+  --> $DIR/incorrect-syntax-suggestions.rs:101:17
+   |
+LL |     let foo = || {
+   |               -- this is not `async`
+LL |         let _ = bar().await?;
+   |                 ^^^^^^^^^^^ only allowed inside `async` functions and blocks
+
+error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
+  --> $DIR/incorrect-syntax-suggestions.rs:18:19
+   |
+LL |     let _ = await bar()?;
+   |                   ^^^^^^ the `?` operator cannot be applied to type `impl std::future::Future`
+   |
+   = help: the trait `std::ops::Try` is not implemented for `impl std::future::Future`
+   = note: required by `std::ops::Try::into_result`
+
+error: aborting due to 29 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/await-keyword/post_expansion_error.stderr b/src/test/ui/await-keyword/post_expansion_error.stderr
index 0996c38b3b6..4e525974c2c 100644
--- a/src/test/ui/await-keyword/post_expansion_error.stderr
+++ b/src/test/ui/await-keyword/post_expansion_error.stderr
@@ -2,7 +2,9 @@ error: expected expression, found `)`
   --> $DIR/post_expansion_error.rs:8:12
    |
 LL |     await!()
-   |            ^ expected expression
+   |     -----  ^ expected expression
+   |     |
+   |     while parsing this await macro call
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-51719.rs b/src/test/ui/issues/issue-51719.rs
index 2c02ac01142..5966edd0bf0 100644
--- a/src/test/ui/issues/issue-51719.rs
+++ b/src/test/ui/issues/issue-51719.rs
@@ -9,3 +9,5 @@ async fn foo() {}
 fn make_generator() {
     let _gen = || foo.await; //~ ERROR `await` is only allowed inside `async` functions and blocks
 }
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-51719.stderr b/src/test/ui/issues/issue-51719.stderr
index 768909b66ec..c06165b2446 100644
--- a/src/test/ui/issues/issue-51719.stderr
+++ b/src/test/ui/issues/issue-51719.stderr
@@ -2,7 +2,9 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks
   --> $DIR/issue-51719.rs:10:19
    |
 LL |     let _gen = || foo.await;
-   |                   ^^^^^^^^^
+   |                -- ^^^^^^^^^ only allowed inside `async` functions and blocks
+   |                |
+   |                this is not `async`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-51751.stderr b/src/test/ui/issues/issue-51751.stderr
index 0c4cb034a93..97b63d1590e 100644
--- a/src/test/ui/issues/issue-51751.stderr
+++ b/src/test/ui/issues/issue-51751.stderr
@@ -1,8 +1,11 @@
 error[E0728]: `await` is only allowed inside `async` functions and blocks
   --> $DIR/issue-51751.rs:11:20
    |
+LL | fn main() {
+   |    ---- this is not `async`
+LL |     let result = inc(10000);
 LL |     let finished = result.await;
-   |                    ^^^^^^^^^^^^
+   |                    ^^^^^^^^^^^^ only allowed inside `async` functions and blocks
 
 error: aborting due to previous error
 
diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml
index 336d7e32024..e759ad1f35d 100644
--- a/src/tools/compiletest/Cargo.toml
+++ b/src/tools/compiletest/Cargo.toml
@@ -7,7 +7,6 @@ edition = "2018"
 [dependencies]
 diff = "0.1.10"
 env_logger = { version = "0.5", default-features = false }
-filetime = "0.2"
 getopts = "0.2"
 log = "0.4"
 regex = "1.0"
diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs
index e253934e566..442e58bfd74 100644
--- a/src/tools/compiletest/src/main.rs
+++ b/src/tools/compiletest/src/main.rs
@@ -9,7 +9,6 @@ use crate::common::CompareMode;
 use crate::common::{expected_output_path, output_base_dir, output_relative_path, UI_EXTENSIONS};
 use crate::common::{Config, TestPaths};
 use crate::common::{DebugInfoBoth, DebugInfoGdb, DebugInfoLldb, Mode, Pretty};
-use filetime::FileTime;
 use getopts::Options;
 use std::env;
 use std::ffi::OsString;
@@ -17,6 +16,7 @@ use std::fs;
 use std::io::{self, ErrorKind};
 use std::path::{Path, PathBuf};
 use std::process::Command;
+use std::time::SystemTime;
 use test::ColorConfig;
 use crate::util::logv;
 use walkdir::WalkDir;
@@ -752,31 +752,36 @@ fn up_to_date(
 
 #[derive(Debug, PartialEq, PartialOrd, Ord, Eq)]
 struct Stamp {
-    time: FileTime,
+    time: SystemTime,
     file: PathBuf,
 }
 
 impl Stamp {
     fn from_path(p: &Path) -> Self {
+        let time = fs::metadata(p)
+            .and_then(|metadata| metadata.modified())
+            .unwrap_or(SystemTime::UNIX_EPOCH);
+
         Stamp {
-            time: mtime(&p),
+            time,
             file: p.into(),
         }
     }
 
-    fn from_dir(path: &Path) -> impl Iterator<Item=Stamp> {
+    fn from_dir(path: &Path) -> impl Iterator<Item = Stamp> {
         WalkDir::new(path)
             .into_iter()
             .map(|entry| entry.unwrap())
             .filter(|entry| entry.file_type().is_file())
-            .map(|entry| Stamp::from_path(entry.path()))
-    }
-}
+            .map(|entry| {
+                let time = (|| -> io::Result<_> { entry.metadata()?.modified() })();
 
-fn mtime(path: &Path) -> FileTime {
-    fs::metadata(path)
-        .map(|f| FileTime::from_last_modification_time(&f))
-        .unwrap_or_else(|_| FileTime::zero())
+                Stamp {
+                    time: time.unwrap_or(SystemTime::UNIX_EPOCH),
+                    file: entry.path().into(),
+                }
+            })
+    }
 }
 
 fn make_test_name(
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index b335fe3ae18..1e4deee6bf1 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -9,7 +9,6 @@ use crate::common::{Config, TestPaths};
 use crate::common::{Incremental, MirOpt, RunMake, Ui, JsDocTest, Assembly};
 use diff;
 use crate::errors::{self, Error, ErrorKind};
-use filetime::FileTime;
 use crate::header::TestProps;
 use crate::json;
 use regex::{Captures, Regex};
@@ -3029,7 +3028,7 @@ impl<'test> TestCx<'test> {
     }
 
     fn check_mir_test_timestamp(&self, test_name: &str, output_file: &Path) {
-        let t = |file| FileTime::from_last_modification_time(&fs::metadata(file).unwrap());
+        let t = |file| fs::metadata(file).unwrap().modified().unwrap();
         let source_file = &self.testpaths.file;
         let output_time = t(output_file);
         let source_time = t(source_file);
diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml
index 5bf1553b227..d2b1a7bac60 100644
--- a/src/tools/rustbook/Cargo.toml
+++ b/src/tools/rustbook/Cargo.toml
@@ -2,7 +2,7 @@
 authors = ["The Rust Project Developers"]
 name = "rustbook"
 version = "0.1.0"
-license = "MIT/Apache-2.0"
+license = "MIT OR Apache-2.0"
 edition = "2018"
 
 [dependencies]
diff --git a/src/tools/rustc-std-workspace-alloc/Cargo.toml b/src/tools/rustc-std-workspace-alloc/Cargo.toml
index 98578914963..05df1fddc7f 100644
--- a/src/tools/rustc-std-workspace-alloc/Cargo.toml
+++ b/src/tools/rustc-std-workspace-alloc/Cargo.toml
@@ -2,7 +2,7 @@
 name = "rustc-std-workspace-alloc"
 version = "1.0.0"
 authors = ["Alex Crichton <alex@alexcrichton.com>"]
-license = 'MIT/Apache-2.0'
+license = 'MIT OR Apache-2.0'
 description = """
 Hack for the compiler's own build system
 """
diff --git a/src/tools/rustc-std-workspace-core/Cargo.toml b/src/tools/rustc-std-workspace-core/Cargo.toml
index d527ce12bc3..38ca56a557b 100644
--- a/src/tools/rustc-std-workspace-core/Cargo.toml
+++ b/src/tools/rustc-std-workspace-core/Cargo.toml
@@ -2,7 +2,7 @@
 name = "rustc-std-workspace-core"
 version = "1.0.0"
 authors = ["Alex Crichton <alex@alexcrichton.com>"]
-license = 'MIT/Apache-2.0'
+license = 'MIT OR Apache-2.0'
 description = """
 Hack for the compiler's own build system
 """
diff --git a/src/tools/rustc-workspace-hack/Cargo.toml b/src/tools/rustc-workspace-hack/Cargo.toml
index d51841cd650..290c4481c00 100644
--- a/src/tools/rustc-workspace-hack/Cargo.toml
+++ b/src/tools/rustc-workspace-hack/Cargo.toml
@@ -2,7 +2,7 @@
 name = "rustc-workspace-hack"
 version = "1.0.0"
 authors = ["Alex Crichton <alex@alexcrichton.com>"]
-license = 'MIT/Apache-2.0'
+license = 'MIT OR Apache-2.0'
 description = """
 Hack for the compiler's own build system
 """
diff --git a/src/tools/unstable-book-gen/Cargo.toml b/src/tools/unstable-book-gen/Cargo.toml
index 3209de09aeb..e43e4e6c7cb 100644
--- a/src/tools/unstable-book-gen/Cargo.toml
+++ b/src/tools/unstable-book-gen/Cargo.toml
@@ -3,7 +3,7 @@ authors = ["est31 <MTest31@outlook.com>",
            "The Rust Project Developers"]
 name = "unstable-book-gen"
 version = "0.1.0"
-license = "MIT/Apache-2.0"
+license = "MIT OR Apache-2.0"
 edition = "2018"
 
 [dependencies]