about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-01-01 03:41:31 +0000
committerbors <bors@rust-lang.org>2021-01-01 03:41:31 +0000
commitf8ab56bf3201b0638e44caf5a484041f22e32d65 (patch)
tree2db271db195f182297ed2c2858426c43ec578f86
parent99ad5a1a2824fea1ecf60068fd3636beae7ea2da (diff)
parent3cbdbe8dcd6a61154b7b5a74707e9e4274df5ed8 (diff)
downloadrust-f8ab56bf3201b0638e44caf5a484041f22e32d65.tar.gz
rust-f8ab56bf3201b0638e44caf5a484041f22e32d65.zip
Auto merge of #79576 - m-ou-se:2021, r=Mark-Simulacrum
Add edition 2021.

:fireworks: Happy new ~~year~~ Rust. :champagne:

This adds --edition=2021, and updates suggestions about 2018 to say "2018 *or later*".

Related Cargo PR: https://github.com/rust-lang/cargo/pull/8922

---

Edit: This adds the new edition as *unstable*. Without `-Z unstable-options`, `--edition=2021` results in:
```
$ rustc --edition=2021
error: edition 2021 is unstable and only available with -Z unstable-options.
```
-rw-r--r--compiler/rustc_ast/src/token.rs3
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs5
-rw-r--r--compiler/rustc_parse/src/parser/item.rs8
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs4
-rw-r--r--compiler/rustc_session/src/config.rs5
-rw-r--r--compiler/rustc_session/src/session.rs5
-rw-r--r--compiler/rustc_span/src/edition.rs14
-rw-r--r--compiler/rustc_span/src/lib.rs5
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs5
-rw-r--r--src/test/ui/async-await/edition-deny-async-fns-2015.rs18
-rw-r--r--src/test/ui/async-await/edition-deny-async-fns-2015.stderr36
-rw-r--r--src/test/ui/async-await/suggest-switching-edition-on-await.stderr8
-rw-r--r--src/test/ui/editions/async-block-2015.rs10
-rw-r--r--src/test/ui/editions/async-block-2015.stderr10
-rw-r--r--src/test/ui/hello2021.rs7
-rw-r--r--src/test/ui/try-block/try-block-in-edition2015.stderr2
17 files changed, 87 insertions, 59 deletions
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index 6dde304e8cf..b311f9fdcb9 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -726,8 +726,7 @@ impl NonterminalKind {
                 Edition::Edition2015 | Edition::Edition2018 => {
                     NonterminalKind::Pat2018 { inferred: true }
                 }
-                // FIXME(mark-i-m): uncomment when 2021 machinery is available.
-                //Edition::Edition2021 => NonterminalKind::Pat2021{inferred:true},
+                Edition::Edition2021 => NonterminalKind::Pat2021 { inferred: true },
             },
             sym::pat2018 => NonterminalKind::Pat2018 { inferred: false },
             sym::pat2021 => NonterminalKind::Pat2021 { inferred: false },
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index b147f42fada..d11db74a3bd 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -15,6 +15,7 @@ use rustc_ast::{AnonConst, BinOp, BinOpKind, FnDecl, FnRetTy, MacCall, Param, Ty
 use rustc_ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits};
 use rustc_ast_pretty::pprust;
 use rustc_errors::{Applicability, DiagnosticBuilder, PResult};
+use rustc_span::edition::LATEST_STABLE_EDITION;
 use rustc_span::source_map::{self, Span, Spanned};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, Pos};
@@ -2108,8 +2109,8 @@ impl<'a> Parser<'a> {
 
         let mut async_block_err = |e: &mut DiagnosticBuilder<'_>, span: Span| {
             recover_async = true;
-            e.span_label(span, "`async` blocks are only allowed in the 2018 edition");
-            e.help("set `edition = \"2018\"` in `Cargo.toml`");
+            e.span_label(span, "`async` blocks are only allowed in Rust 2018 or later");
+            e.help(&format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION));
             e.note("for more on editions, read https://doc.rust-lang.org/edition-guide");
         };
 
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index c6669f04682..e49b1a54e9b 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -16,7 +16,7 @@ use rustc_ast::{FnHeader, ForeignItem, Path, PathSegment, Visibility, Visibility
 use rustc_ast::{MacArgs, MacCall, MacDelimiter};
 use rustc_ast_pretty::pprust;
 use rustc_errors::{struct_span_err, Applicability, PResult, StashKey};
-use rustc_span::edition::Edition;
+use rustc_span::edition::{Edition, LATEST_STABLE_EDITION};
 use rustc_span::source_map::{self, Span};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 
@@ -1667,9 +1667,9 @@ impl<'a> Parser<'a> {
     fn ban_async_in_2015(&self, span: Span) {
         if span.rust_2015() {
             let diag = self.diagnostic();
-            struct_span_err!(diag, span, E0670, "`async fn` is not permitted in the 2015 edition")
-                .span_label(span, "to use `async fn`, switch to Rust 2018")
-                .help("set `edition = \"2018\"` in `Cargo.toml`")
+            struct_span_err!(diag, span, E0670, "`async fn` is not permitted in Rust 2015")
+                .span_label(span, "to use `async fn`, switch to Rust 2018 or later")
+                .help(&format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION))
                 .note("for more on editions, read https://doc.rust-lang.org/edition-guide")
                 .emit();
         }
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 7d8f112af8a..55623c9bd9c 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -180,7 +180,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
             (
                 format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str),
                 if path_str == "async" && expected.starts_with("struct") {
-                    "`async` blocks are only allowed in the 2018 edition".to_string()
+                    "`async` blocks are only allowed in Rust 2018 or later".to_string()
                 } else {
                     format!("not found in {}", mod_str)
                 },
@@ -904,7 +904,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                     Applicability::MaybeIncorrect,
                 );
                 if path_str == "try" && span.rust_2015() {
-                    err.note("if you want the `try` keyword, you need to be in the 2018 edition");
+                    err.note("if you want the `try` keyword, you need Rust 2018 or later");
                 }
             }
             (Res::Def(DefKind::TyAlias, def_id), PathSource::Trait(_)) => {
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index c9ddcbdb5f5..62859f4bef4 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -1308,12 +1308,11 @@ fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
         None => DEFAULT_EDITION,
     };
 
-    if !edition.is_stable() && !nightly_options::match_is_nightly_build(matches) {
+    if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
         early_error(
             ErrorOutputType::default(),
             &format!(
-                "edition {} is unstable and only \
-                     available for nightly builds of rustc.",
+                "edition {} is unstable and only available with -Z unstable-options.",
                 edition,
             ),
         )
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 75faab12e3e..3a420f5f9de 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -1076,6 +1076,11 @@ impl Session {
         self.opts.edition >= Edition::Edition2018
     }
 
+    /// Are we allowed to use features from the Rust 2021 edition?
+    pub fn rust_2021(&self) -> bool {
+        self.opts.edition >= Edition::Edition2021
+    }
+
     pub fn edition(&self) -> Edition {
         self.opts.edition
     }
diff --git a/compiler/rustc_span/src/edition.rs b/compiler/rustc_span/src/edition.rs
index efbb0a23a6f..a9200dd7dfd 100644
--- a/compiler/rustc_span/src/edition.rs
+++ b/compiler/rustc_span/src/edition.rs
@@ -20,20 +20,26 @@ pub enum Edition {
     Edition2015,
     /// The 2018 edition
     Edition2018,
+    /// The 2021 ediiton
+    Edition2021,
 }
 
 // Must be in order from oldest to newest.
-pub const ALL_EDITIONS: &[Edition] = &[Edition::Edition2015, Edition::Edition2018];
+pub const ALL_EDITIONS: &[Edition] =
+    &[Edition::Edition2015, Edition::Edition2018, Edition::Edition2021];
 
-pub const EDITION_NAME_LIST: &str = "2015|2018";
+pub const EDITION_NAME_LIST: &str = "2015|2018|2021";
 
 pub const DEFAULT_EDITION: Edition = Edition::Edition2015;
 
+pub const LATEST_STABLE_EDITION: Edition = Edition::Edition2018;
+
 impl fmt::Display for Edition {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let s = match *self {
             Edition::Edition2015 => "2015",
             Edition::Edition2018 => "2018",
+            Edition::Edition2021 => "2021",
         };
         write!(f, "{}", s)
     }
@@ -44,6 +50,7 @@ impl Edition {
         match *self {
             Edition::Edition2015 => "rust_2015_compatibility",
             Edition::Edition2018 => "rust_2018_compatibility",
+            Edition::Edition2021 => "rust_2021_compatibility",
         }
     }
 
@@ -51,6 +58,7 @@ impl Edition {
         match *self {
             Edition::Edition2015 => sym::rust_2015_preview,
             Edition::Edition2018 => sym::rust_2018_preview,
+            Edition::Edition2021 => sym::rust_2021_preview,
         }
     }
 
@@ -58,6 +66,7 @@ impl Edition {
         match *self {
             Edition::Edition2015 => true,
             Edition::Edition2018 => true,
+            Edition::Edition2021 => false,
         }
     }
 }
@@ -68,6 +77,7 @@ impl FromStr for Edition {
         match s {
             "2015" => Ok(Edition::Edition2015),
             "2018" => Ok(Edition::Edition2018),
+            "2021" => Ok(Edition::Edition2021),
             _ => Err(()),
         }
     }
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 80095307175..99f01062545 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -481,6 +481,11 @@ impl Span {
         self.edition() >= edition::Edition::Edition2018
     }
 
+    #[inline]
+    pub fn rust_2021(&self) -> bool {
+        self.edition() >= edition::Edition::Edition2021
+    }
+
     /// Returns the source callee.
     ///
     /// Returns `None` if the supplied span has no expansion trace,
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 382b7a4f2db..b040a70437d 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -923,6 +923,7 @@ symbols! {
         rust,
         rust_2015_preview,
         rust_2018_preview,
+        rust_2021_preview,
         rust_begin_unwind,
         rust_eh_catch_typeinfo,
         rust_eh_personality,
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 93eb2cfc72a..8197d02ec59 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -38,6 +38,7 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::TypeFoldable;
 use rustc_middle::ty::{AdtKind, Visibility};
+use rustc_span::edition::LATEST_STABLE_EDITION;
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::lev_distance::find_best_match_for_name;
 use rustc_span::source_map::Span;
@@ -1637,8 +1638,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         if field.name == kw::Await {
             // We know by construction that `<expr>.await` is either on Rust 2015
             // or results in `ExprKind::Await`. Suggest switching the edition to 2018.
-            err.note("to `.await` a `Future`, switch to Rust 2018");
-            err.help("set `edition = \"2018\"` in `Cargo.toml`");
+            err.note("to `.await` a `Future`, switch to Rust 2018 or later");
+            err.help(&format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION));
             err.note("for more on editions, read https://doc.rust-lang.org/edition-guide");
         }
 
diff --git a/src/test/ui/async-await/edition-deny-async-fns-2015.rs b/src/test/ui/async-await/edition-deny-async-fns-2015.rs
index 5d2d186137e..e5dc9c8a5fe 100644
--- a/src/test/ui/async-await/edition-deny-async-fns-2015.rs
+++ b/src/test/ui/async-await/edition-deny-async-fns-2015.rs
@@ -1,21 +1,21 @@
 // edition:2015
 
-async fn foo() {} //~ ERROR `async fn` is not permitted in the 2015 edition
+async fn foo() {} //~ ERROR `async fn` is not permitted in Rust 2015
 
-fn baz() { async fn foo() {} } //~ ERROR `async fn` is not permitted in the 2015 edition
+fn baz() { async fn foo() {} } //~ ERROR `async fn` is not permitted in Rust 2015
 
-async fn async_baz() { //~ ERROR `async fn` is not permitted in the 2015 edition
-    async fn bar() {} //~ ERROR `async fn` is not permitted in the 2015 edition
+async fn async_baz() { //~ ERROR `async fn` is not permitted in Rust 2015
+    async fn bar() {} //~ ERROR `async fn` is not permitted in Rust 2015
 }
 
 struct Foo {}
 
 impl Foo {
-    async fn foo() {} //~ ERROR `async fn` is not permitted in the 2015 edition
+    async fn foo() {} //~ ERROR `async fn` is not permitted in Rust 2015
 }
 
 trait Bar {
-    async fn foo() {} //~ ERROR `async fn` is not permitted in the 2015 edition
+    async fn foo() {} //~ ERROR `async fn` is not permitted in Rust 2015
                       //~^ ERROR functions in traits cannot be declared `async`
 }
 
@@ -23,16 +23,16 @@ fn main() {
     macro_rules! accept_item { ($x:item) => {} }
 
     accept_item! {
-        async fn foo() {} //~ ERROR `async fn` is not permitted in the 2015 edition
+        async fn foo() {} //~ ERROR `async fn` is not permitted in Rust 2015
     }
 
     accept_item! {
         impl Foo {
-            async fn bar() {} //~ ERROR `async fn` is not permitted in the 2015 edition
+            async fn bar() {} //~ ERROR `async fn` is not permitted in Rust 2015
         }
     }
 
     let inside_closure = || {
-        async fn bar() {} //~ ERROR `async fn` is not permitted in the 2015 edition
+        async fn bar() {} //~ ERROR `async fn` is not permitted in Rust 2015
     };
 }
diff --git a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr
index 8bffeb2131d..43364a8e858 100644
--- a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr
+++ b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr
@@ -1,80 +1,80 @@
-error[E0670]: `async fn` is not permitted in the 2015 edition
+error[E0670]: `async fn` is not permitted in Rust 2015
   --> $DIR/edition-deny-async-fns-2015.rs:3:1
    |
 LL | async fn foo() {}
-   | ^^^^^ to use `async fn`, switch to Rust 2018
+   | ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
    = help: set `edition = "2018"` in `Cargo.toml`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
-error[E0670]: `async fn` is not permitted in the 2015 edition
+error[E0670]: `async fn` is not permitted in Rust 2015
   --> $DIR/edition-deny-async-fns-2015.rs:5:12
    |
 LL | fn baz() { async fn foo() {} }
-   |            ^^^^^ to use `async fn`, switch to Rust 2018
+   |            ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
    = help: set `edition = "2018"` in `Cargo.toml`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
-error[E0670]: `async fn` is not permitted in the 2015 edition
+error[E0670]: `async fn` is not permitted in Rust 2015
   --> $DIR/edition-deny-async-fns-2015.rs:7:1
    |
 LL | async fn async_baz() {
-   | ^^^^^ to use `async fn`, switch to Rust 2018
+   | ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
    = help: set `edition = "2018"` in `Cargo.toml`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
-error[E0670]: `async fn` is not permitted in the 2015 edition
+error[E0670]: `async fn` is not permitted in Rust 2015
   --> $DIR/edition-deny-async-fns-2015.rs:8:5
    |
 LL |     async fn bar() {}
-   |     ^^^^^ to use `async fn`, switch to Rust 2018
+   |     ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
    = help: set `edition = "2018"` in `Cargo.toml`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
-error[E0670]: `async fn` is not permitted in the 2015 edition
+error[E0670]: `async fn` is not permitted in Rust 2015
   --> $DIR/edition-deny-async-fns-2015.rs:14:5
    |
 LL |     async fn foo() {}
-   |     ^^^^^ to use `async fn`, switch to Rust 2018
+   |     ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
    = help: set `edition = "2018"` in `Cargo.toml`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
-error[E0670]: `async fn` is not permitted in the 2015 edition
+error[E0670]: `async fn` is not permitted in Rust 2015
   --> $DIR/edition-deny-async-fns-2015.rs:18:5
    |
 LL |     async fn foo() {}
-   |     ^^^^^ to use `async fn`, switch to Rust 2018
+   |     ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
    = help: set `edition = "2018"` in `Cargo.toml`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
-error[E0670]: `async fn` is not permitted in the 2015 edition
+error[E0670]: `async fn` is not permitted in Rust 2015
   --> $DIR/edition-deny-async-fns-2015.rs:36:9
    |
 LL |         async fn bar() {}
-   |         ^^^^^ to use `async fn`, switch to Rust 2018
+   |         ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
    = help: set `edition = "2018"` in `Cargo.toml`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
-error[E0670]: `async fn` is not permitted in the 2015 edition
+error[E0670]: `async fn` is not permitted in Rust 2015
   --> $DIR/edition-deny-async-fns-2015.rs:26:9
    |
 LL |         async fn foo() {}
-   |         ^^^^^ to use `async fn`, switch to Rust 2018
+   |         ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
    = help: set `edition = "2018"` in `Cargo.toml`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
-error[E0670]: `async fn` is not permitted in the 2015 edition
+error[E0670]: `async fn` is not permitted in Rust 2015
   --> $DIR/edition-deny-async-fns-2015.rs:31:13
    |
 LL |             async fn bar() {}
-   |             ^^^^^ to use `async fn`, switch to Rust 2018
+   |             ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
    = help: set `edition = "2018"` in `Cargo.toml`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
diff --git a/src/test/ui/async-await/suggest-switching-edition-on-await.stderr b/src/test/ui/async-await/suggest-switching-edition-on-await.stderr
index 695d7dd59fb..9ac2bc5cc89 100644
--- a/src/test/ui/async-await/suggest-switching-edition-on-await.stderr
+++ b/src/test/ui/async-await/suggest-switching-edition-on-await.stderr
@@ -4,7 +4,7 @@ error[E0609]: no field `await` on type `await_on_struct_missing::S`
 LL |     x.await;
    |       ^^^^^ unknown field
    |
-   = note: to `.await` a `Future`, switch to Rust 2018
+   = note: to `.await` a `Future`, switch to Rust 2018 or later
    = help: set `edition = "2018"` in `Cargo.toml`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
@@ -14,7 +14,7 @@ error[E0609]: no field `await` on type `await_on_struct_similar::S`
 LL |     x.await;
    |       ^^^^^ help: a field with a similar name exists: `awai`
    |
-   = note: to `.await` a `Future`, switch to Rust 2018
+   = note: to `.await` a `Future`, switch to Rust 2018 or later
    = help: set `edition = "2018"` in `Cargo.toml`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
@@ -24,7 +24,7 @@ error[E0609]: no field `await` on type `Pin<&mut dyn Future<Output = ()>>`
 LL |     x.await;
    |       ^^^^^ unknown field
    |
-   = note: to `.await` a `Future`, switch to Rust 2018
+   = note: to `.await` a `Future`, switch to Rust 2018 or later
    = help: set `edition = "2018"` in `Cargo.toml`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
@@ -34,7 +34,7 @@ error[E0609]: no field `await` on type `impl Future<Output = ()>`
 LL |     x.await;
    |       ^^^^^
    |
-   = note: to `.await` a `Future`, switch to Rust 2018
+   = note: to `.await` a `Future`, switch to Rust 2018 or later
    = help: set `edition = "2018"` in `Cargo.toml`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
diff --git a/src/test/ui/editions/async-block-2015.rs b/src/test/ui/editions/async-block-2015.rs
index 985606a6f25..92eae9e3c14 100644
--- a/src/test/ui/editions/async-block-2015.rs
+++ b/src/test/ui/editions/async-block-2015.rs
@@ -1,13 +1,13 @@
 async fn foo() {
-//~^ ERROR `async fn` is not permitted in the 2015 edition
-//~| NOTE to use `async fn`, switch to Rust 2018
+//~^ ERROR `async fn` is not permitted in Rust 2015
+//~| NOTE to use `async fn`, switch to Rust 2018 or later
 //~| HELP set `edition = "2018"` in `Cargo.toml`
 //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
 
     let x = async {};
     //~^ ERROR cannot find struct, variant or union type `async` in this scope
-    //~| NOTE `async` blocks are only allowed in the 2018 edition
-    let y = async { //~ NOTE `async` blocks are only allowed in the 2018 edition
+    //~| NOTE `async` blocks are only allowed in Rust 2018 or later
+    let y = async { //~ NOTE `async` blocks are only allowed in Rust 2018 or later
         let x = 42;
         //~^ ERROR expected identifier, found keyword `let`
         //~| NOTE expected identifier, found keyword
@@ -15,7 +15,7 @@ async fn foo() {
         //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
         42
     };
-    let z = async { //~ NOTE `async` blocks are only allowed in the 2018 edition
+    let z = async { //~ NOTE `async` blocks are only allowed in Rust 2018 or later
         42
         //~^ ERROR expected identifier, found `42`
         //~| NOTE expected identifier
diff --git a/src/test/ui/editions/async-block-2015.stderr b/src/test/ui/editions/async-block-2015.stderr
index 8e5e5d8bfab..e42747c804c 100644
--- a/src/test/ui/editions/async-block-2015.stderr
+++ b/src/test/ui/editions/async-block-2015.stderr
@@ -1,8 +1,8 @@
-error[E0670]: `async fn` is not permitted in the 2015 edition
+error[E0670]: `async fn` is not permitted in Rust 2015
   --> $DIR/async-block-2015.rs:1:1
    |
 LL | async fn foo() {
-   | ^^^^^ to use `async fn`, switch to Rust 2018
+   | ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
    = help: set `edition = "2018"` in `Cargo.toml`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
@@ -11,7 +11,7 @@ error: expected identifier, found keyword `let`
   --> $DIR/async-block-2015.rs:11:9
    |
 LL |     let y = async {
-   |             ----- `async` blocks are only allowed in the 2018 edition
+   |             ----- `async` blocks are only allowed in Rust 2018 or later
 LL |         let x = 42;
    |         ^^^ expected identifier, found keyword
    |
@@ -22,7 +22,7 @@ error: expected identifier, found `42`
   --> $DIR/async-block-2015.rs:19:9
    |
 LL |     let z = async {
-   |             ----- `async` blocks are only allowed in the 2018 edition
+   |             ----- `async` blocks are only allowed in Rust 2018 or later
 LL |         42
    |         ^^ expected identifier
    |
@@ -33,7 +33,7 @@ error[E0422]: cannot find struct, variant or union type `async` in this scope
   --> $DIR/async-block-2015.rs:7:13
    |
 LL |     let x = async {};
-   |             ^^^^^ `async` blocks are only allowed in the 2018 edition
+   |             ^^^^^ `async` blocks are only allowed in Rust 2018 or later
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/hello2021.rs b/src/test/ui/hello2021.rs
new file mode 100644
index 00000000000..738f151b0f6
--- /dev/null
+++ b/src/test/ui/hello2021.rs
@@ -0,0 +1,7 @@
+// run-pass
+// edition:2021
+// compile-flags: -Zunstable-options
+
+fn main() {
+    println!("hello, 2021");
+}
diff --git a/src/test/ui/try-block/try-block-in-edition2015.stderr b/src/test/ui/try-block/try-block-in-edition2015.stderr
index 78cdfb2cc7f..0f3c14b1386 100644
--- a/src/test/ui/try-block/try-block-in-edition2015.stderr
+++ b/src/test/ui/try-block/try-block-in-edition2015.stderr
@@ -13,7 +13,7 @@ error[E0574]: expected struct, variant or union type, found macro `try`
 LL |     let try_result: Option<_> = try {
    |                                 ^^^ not a struct, variant or union type
    |
-   = note: if you want the `try` keyword, you need to be in the 2018 edition
+   = note: if you want the `try` keyword, you need Rust 2018 or later
 help: use `!` to invoke the macro
    |
 LL |     let try_result: Option<_> = try! {