diff --git a/Cargo.lock b/Cargo.lock
index 8bd1e5f3308b4..74578084a72c8 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -74,7 +74,7 @@ name = "arena"
 version = "0.0.0"
 dependencies = [
  "rustc_data_structures",
- "smallvec 1.0.0",
+ "smallvec 1.4.0",
 ]
 
 [[package]]
@@ -492,7 +492,7 @@ dependencies = [
  "regex-syntax",
  "semver",
  "serde",
- "smallvec 1.0.0",
+ "smallvec 1.4.0",
  "toml",
  "unicode-normalization",
  "url 2.1.0",
@@ -2428,7 +2428,7 @@ dependencies = [
  "cloudabi",
  "libc",
  "redox_syscall",
- "smallvec 1.0.0",
+ "smallvec 1.4.0",
  "winapi 0.3.8",
 ]
 
@@ -3151,7 +3151,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "81dfcfbb0ddfd533abf8c076e3b49d1e5042d1962526a12ce2c66d514b24cca3"
 dependencies = [
  "rustc-ap-rustc_data_structures",
- "smallvec 1.0.0",
+ "smallvec 1.4.0",
 ]
 
 [[package]]
@@ -3174,7 +3174,7 @@ dependencies = [
  "rustc-ap-rustc_span",
  "rustc-ap-serialize",
  "scoped-tls",
- "smallvec 1.0.0",
+ "smallvec 1.4.0",
 ]
 
 [[package]]
@@ -3223,7 +3223,7 @@ dependencies = [
  "rustc-ap-rustc_session",
  "rustc-ap-rustc_span",
  "rustc-ap-serialize",
- "smallvec 1.0.0",
+ "smallvec 1.4.0",
 ]
 
 [[package]]
@@ -3249,7 +3249,7 @@ dependencies = [
  "rustc-hash",
  "rustc-rayon",
  "rustc-rayon-core",
- "smallvec 1.0.0",
+ "smallvec 1.4.0",
  "stable_deref_trait",
  "winapi 0.3.8",
 ]
@@ -3291,7 +3291,7 @@ dependencies = [
  "rustc-ap-rustc_session",
  "rustc-ap-rustc_span",
  "rustc-ap-serialize",
- "smallvec 1.0.0",
+ "smallvec 1.4.0",
 ]
 
 [[package]]
@@ -3318,7 +3318,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "32220c3e6cdf226f38e4474b747dca15f3106bb680c74f10b299af3f6cdb1663"
 dependencies = [
  "rustc-ap-serialize",
- "smallvec 1.0.0",
+ "smallvec 1.4.0",
 ]
 
 [[package]]
@@ -3358,7 +3358,7 @@ dependencies = [
  "rustc-ap-rustc_lexer",
  "rustc-ap-rustc_session",
  "rustc-ap-rustc_span",
- "smallvec 1.0.0",
+ "smallvec 1.4.0",
  "unicode-normalization",
 ]
 
@@ -3423,7 +3423,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "756e8f526ec7906e132188bf25e3c10a6ee42ab77294ecb3b3602647f0508eef"
 dependencies = [
  "indexmap",
- "smallvec 1.0.0",
+ "smallvec 1.4.0",
 ]
 
 [[package]]
@@ -3507,7 +3507,7 @@ dependencies = [
  "serde",
  "serde_json",
  "smallvec 0.6.10",
- "smallvec 1.0.0",
+ "smallvec 1.4.0",
  "syn 0.15.35",
  "url 2.1.0",
  "winapi 0.3.8",
@@ -3518,7 +3518,7 @@ name = "rustc_apfloat"
 version = "0.0.0"
 dependencies = [
  "bitflags",
- "smallvec 1.0.0",
+ "smallvec 1.4.0",
 ]
 
 [[package]]
@@ -3533,7 +3533,7 @@ dependencies = [
  "rustc_span",
  "scoped-tls",
  "serialize",
- "smallvec 1.0.0",
+ "smallvec 1.4.0",
 ]
 
 [[package]]
@@ -3551,7 +3551,7 @@ dependencies = [
  "rustc_session",
  "rustc_span",
  "rustc_target",
- "smallvec 1.0.0",
+ "smallvec 1.4.0",
 ]
 
 [[package]]
@@ -3593,6 +3593,7 @@ dependencies = [
  "rustc_session",
  "rustc_span",
  "serialize",
+ "version_check",
 ]
 
 [[package]]
@@ -3612,7 +3613,7 @@ dependencies = [
  "rustc_session",
  "rustc_span",
  "rustc_target",
- "smallvec 1.0.0",
+ "smallvec 1.4.0",
 ]
 
 [[package]]
@@ -3641,7 +3642,7 @@ dependencies = [
  "rustc_span",
  "rustc_target",
  "serialize",
- "smallvec 1.0.0",
+ "smallvec 1.4.0",
 ]
 
 [[package]]
@@ -3694,7 +3695,7 @@ dependencies = [
  "rustc-rayon-core",
  "rustc_index",
  "serialize",
- "smallvec 1.0.0",
+ "smallvec 1.4.0",
  "stable_deref_trait",
  "winapi 0.3.8",
 ]
@@ -3768,7 +3769,7 @@ dependencies = [
  "rustc_session",
  "rustc_span",
  "serialize",
- "smallvec 1.0.0",
+ "smallvec 1.4.0",
 ]
 
 [[package]]
@@ -3797,7 +3798,7 @@ dependencies = [
  "rustc_span",
  "rustc_target",
  "serialize",
- "smallvec 1.0.0",
+ "smallvec 1.4.0",
 ]
 
 [[package]]
@@ -3833,7 +3834,7 @@ name = "rustc_index"
 version = "0.0.0"
 dependencies = [
  "serialize",
- "smallvec 1.0.0",
+ "smallvec 1.4.0",
 ]
 
 [[package]]
@@ -3853,7 +3854,7 @@ dependencies = [
  "rustc_span",
  "rustc_target",
  "serialize",
- "smallvec 1.0.0",
+ "smallvec 1.4.0",
 ]
 
 [[package]]
@@ -3895,7 +3896,7 @@ dependencies = [
  "rustc_ty",
  "rustc_typeck",
  "serialize",
- "smallvec 1.0.0",
+ "smallvec 1.4.0",
  "tempfile",
  "winapi 0.3.8",
 ]
@@ -3968,7 +3969,7 @@ dependencies = [
  "rustc_span",
  "rustc_target",
  "serialize",
- "smallvec 1.0.0",
+ "smallvec 1.4.0",
  "stable_deref_trait",
  "winapi 0.3.8",
 ]
@@ -4000,7 +4001,7 @@ dependencies = [
  "rustc_target",
  "scoped-tls",
  "serialize",
- "smallvec 1.0.0",
+ "smallvec 1.4.0",
 ]
 
 [[package]]
@@ -4029,7 +4030,7 @@ dependencies = [
  "rustc_target",
  "rustc_trait_selection",
  "serialize",
- "smallvec 1.0.0",
+ "smallvec 1.4.0",
 ]
 
 [[package]]
@@ -4053,7 +4054,7 @@ dependencies = [
  "rustc_target",
  "rustc_trait_selection",
  "serialize",
- "smallvec 1.0.0",
+ "smallvec 1.4.0",
 ]
 
 [[package]]
@@ -4134,7 +4135,7 @@ dependencies = [
  "rustc_index",
  "rustc_span",
  "serialize",
- "smallvec 1.0.0",
+ "smallvec 1.4.0",
 ]
 
 [[package]]
@@ -4157,7 +4158,7 @@ dependencies = [
  "rustc_middle",
  "rustc_session",
  "rustc_span",
- "smallvec 1.0.0",
+ "smallvec 1.4.0",
 ]
 
 [[package]]
@@ -4272,7 +4273,7 @@ dependencies = [
  "rustc_session",
  "rustc_span",
  "rustc_target",
- "smallvec 1.0.0",
+ "smallvec 1.4.0",
 ]
 
 [[package]]
@@ -4287,7 +4288,7 @@ dependencies = [
  "rustc_middle",
  "rustc_span",
  "rustc_trait_selection",
- "smallvec 1.0.0",
+ "smallvec 1.4.0",
 ]
 
 [[package]]
@@ -4324,7 +4325,7 @@ dependencies = [
  "rustc_span",
  "rustc_target",
  "rustc_trait_selection",
- "smallvec 1.0.0",
+ "smallvec 1.4.0",
 ]
 
 [[package]]
@@ -4568,7 +4569,7 @@ name = "serialize"
 version = "0.0.0"
 dependencies = [
  "indexmap",
- "smallvec 1.0.0",
+ "smallvec 1.4.0",
 ]
 
 [[package]]
@@ -4635,9 +4636,9 @@ checksum = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7"
 
 [[package]]
 name = "smallvec"
-version = "1.0.0"
+version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ecf3b85f68e8abaa7555aa5abdb1153079387e60b718283d732f03897fcfc86"
+checksum = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4"
 
 [[package]]
 name = "socket2"
@@ -5359,11 +5360,11 @@ dependencies = [
 
 [[package]]
 name = "unicode-normalization"
-version = "0.1.11"
+version = "0.1.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b561e267b2326bb4cebfc0ef9e68355c7abe6c6f522aeac2f5bf95d56c59bdcf"
+checksum = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4"
 dependencies = [
- "smallvec 1.0.0",
+ "smallvec 1.4.0",
 ]
 
 [[package]]
@@ -5374,10 +5375,11 @@ checksum = "5b2c5c29e805da6817f5af6a627d65adb045cebf05cccd5a3493d6109454391c"
 
 [[package]]
 name = "unicode-security"
-version = "0.0.2"
+version = "0.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c49d35967fa037b881acc34ef717c38c4b5560eba10e3685271b3f530bb19634"
+checksum = "a5f9011bbed9c13372bc8df618b55a38138445199caf3b61d432c6859c36dee0"
 dependencies = [
+ "unicode-normalization",
  "unicode-script",
 ]
 
diff --git a/src/doc/unstable-book/src/language-features/cfg-version.md b/src/doc/unstable-book/src/language-features/cfg-version.md
new file mode 100644
index 0000000000000..2b1e50835b767
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/cfg-version.md
@@ -0,0 +1,34 @@
+# `cfg_version`
+
+The tracking issue for this feature is: [#64796]
+
+[#64796]: https://github.com/rust-lang/rust/issues/64796
+
+------------------------
+
+The `cfg_version` feature makes it possible to execute different code
+depending on the compiler version.
+
+## Examples
+
+```rust
+#![feature(cfg_version)]
+
+#[cfg(version("1.42"))]
+fn a() {
+    // ...
+}
+
+#[cfg(not(version("1.42")))]
+fn a() {
+    // ...
+}
+
+fn b() {
+    if cfg!(version("1.42")) {
+        // ...
+    } else {
+        // ...
+    }
+}
+```
diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs
index 7b357bb487a0a..f74c6862006c1 100644
--- a/src/libcore/slice/mod.rs
+++ b/src/libcore/slice/mod.rs
@@ -23,7 +23,6 @@
 // * The `raw` and `bytes` submodules.
 // * Boilerplate trait implementations.
 
-use crate::borrow::Borrow;
 use crate::cmp;
 use crate::cmp::Ordering::{self, Equal, Greater, Less};
 use crate::fmt;
@@ -2157,14 +2156,16 @@ impl<T> [T] {
     /// assert_eq!(buf, vec![1; 10]);
     /// ```
     #[unstable(feature = "slice_fill", issue = "70758")]
-    pub fn fill<V>(&mut self, value: V)
+    pub fn fill(&mut self, value: T)
     where
-        V: Borrow<T>,
         T: Clone,
     {
-        let value = value.borrow();
-        for el in self {
-            el.clone_from(value)
+        if let Some((last, elems)) = self.split_last_mut() {
+            for el in elems {
+                el.clone_from(&value);
+            }
+
+            *last = value
         }
     }
 
diff --git a/src/librustc_attr/Cargo.toml b/src/librustc_attr/Cargo.toml
index a7a7e3dcc5f02..d7af7fe6143e5 100644
--- a/src/librustc_attr/Cargo.toml
+++ b/src/librustc_attr/Cargo.toml
@@ -3,6 +3,7 @@ authors = ["The Rust Project Developers"]
 name = "rustc_attr"
 version = "0.0.0"
 edition = "2018"
+build = "build.rs"
 
 [lib]
 name = "rustc_attr"
@@ -19,3 +20,4 @@ rustc_feature = { path = "../librustc_feature" }
 rustc_macros = { path = "../librustc_macros" }
 rustc_session = { path = "../librustc_session" }
 rustc_ast = { path = "../librustc_ast" }
+version_check = "0.9"
diff --git a/src/librustc_attr/build.rs b/src/librustc_attr/build.rs
new file mode 100644
index 0000000000000..d230ba91039ad
--- /dev/null
+++ b/src/librustc_attr/build.rs
@@ -0,0 +1,4 @@
+fn main() {
+    println!("cargo:rerun-if-changed=build.rs");
+    println!("cargo:rerun-if-env-changed=CFG_VERSION");
+}
diff --git a/src/librustc_attr/builtin.rs b/src/librustc_attr/builtin.rs
index 0a6a4821e278e..ce38e3f5f4e4e 100644
--- a/src/librustc_attr/builtin.rs
+++ b/src/librustc_attr/builtin.rs
@@ -2,7 +2,7 @@
 
 use super::{find_by_name, mark_used};
 
-use rustc_ast::ast::{self, Attribute, MetaItem, MetaItemKind, NestedMetaItem};
+use rustc_ast::ast::{self, Attribute, Lit, LitKind, MetaItem, MetaItemKind, NestedMetaItem};
 use rustc_ast_pretty::pprust;
 use rustc_errors::{struct_span_err, Applicability, Handler};
 use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg};
@@ -11,6 +11,7 @@ use rustc_session::parse::{feature_err, ParseSess};
 use rustc_span::hygiene::Transparency;
 use rustc_span::{symbol::sym, symbol::Symbol, Span};
 use std::num::NonZeroU32;
+use version_check::Version;
 
 pub fn is_builtin_attr(attr: &Attribute) -> bool {
     attr.is_doc_comment() || attr.ident().filter(|ident| is_builtin_attr_name(ident.name)).is_some()
@@ -568,11 +569,8 @@ pub fn find_crate_name(attrs: &[Attribute]) -> Option<Symbol> {
 
 /// Tests if a cfg-pattern matches the cfg set
 pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Features>) -> bool {
-    eval_condition(cfg, sess, &mut |cfg| {
-        let gate = find_gated_cfg(|sym| cfg.check_name(sym));
-        if let (Some(feats), Some(gated_cfg)) = (features, gate) {
-            gate_cfg(&gated_cfg, cfg.span, sess, feats);
-        }
+    eval_condition(cfg, sess, features, &mut |cfg| {
+        try_gate_cfg(cfg, sess, features);
         let error = |span, msg| {
             sess.span_diagnostic.span_err(span, msg);
             true
@@ -603,6 +601,13 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat
     })
 }
 
+fn try_gate_cfg(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Features>) {
+    let gate = find_gated_cfg(|sym| cfg.check_name(sym));
+    if let (Some(feats), Some(gated_cfg)) = (features, gate) {
+        gate_cfg(&gated_cfg, cfg.span, sess, feats);
+    }
+}
+
 fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &ParseSess, features: &Features) {
     let (cfg, feature, has_feature) = gated_cfg;
     if !has_feature(features) && !cfg_span.allows_unstable(*feature) {
@@ -616,9 +621,41 @@ fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &ParseSess, features: &F
 pub fn eval_condition(
     cfg: &ast::MetaItem,
     sess: &ParseSess,
+    features: Option<&Features>,
     eval: &mut impl FnMut(&ast::MetaItem) -> bool,
 ) -> bool {
     match cfg.kind {
+        ast::MetaItemKind::List(ref mis) if cfg.name_or_empty() == sym::version => {
+            try_gate_cfg(cfg, sess, features);
+            let (min_version, span) = match &mis[..] {
+                [NestedMetaItem::Literal(Lit { kind: LitKind::Str(sym, ..), span, .. })] => {
+                    (sym, span)
+                }
+                [NestedMetaItem::Literal(Lit { span, .. })
+                | NestedMetaItem::MetaItem(MetaItem { span, .. })] => {
+                    sess.span_diagnostic
+                        .struct_span_err(*span, &*format!("expected a version literal"))
+                        .emit();
+                    return false;
+                }
+                [..] => {
+                    sess.span_diagnostic
+                        .struct_span_err(cfg.span, "expected single version literal")
+                        .emit();
+                    return false;
+                }
+            };
+            let min_version = match Version::parse(&min_version.as_str()) {
+                Some(ver) => ver,
+                None => {
+                    sess.span_diagnostic.struct_span_err(*span, "invalid version literal").emit();
+                    return false;
+                }
+            };
+            let version = Version::parse(env!("CFG_VERSION")).unwrap();
+
+            version >= min_version
+        }
         ast::MetaItemKind::List(ref mis) => {
             for mi in mis.iter() {
                 if !mi.is_meta_item() {
@@ -634,12 +671,12 @@ pub fn eval_condition(
             // The unwraps below may look dangerous, but we've already asserted
             // that they won't fail with the loop above.
             match cfg.name_or_empty() {
-                sym::any => {
-                    mis.iter().any(|mi| eval_condition(mi.meta_item().unwrap(), sess, eval))
-                }
-                sym::all => {
-                    mis.iter().all(|mi| eval_condition(mi.meta_item().unwrap(), sess, eval))
-                }
+                sym::any => mis
+                    .iter()
+                    .any(|mi| eval_condition(mi.meta_item().unwrap(), sess, features, eval)),
+                sym::all => mis
+                    .iter()
+                    .all(|mi| eval_condition(mi.meta_item().unwrap(), sess, features, eval)),
                 sym::not => {
                     if mis.len() != 1 {
                         struct_span_err!(
@@ -652,7 +689,7 @@ pub fn eval_condition(
                         return false;
                     }
 
-                    !eval_condition(mis[0].meta_item().unwrap(), sess, eval)
+                    !eval_condition(mis[0].meta_item().unwrap(), sess, features, eval)
                 }
                 _ => {
                     struct_span_err!(
diff --git a/src/librustc_attr/lib.rs b/src/librustc_attr/lib.rs
index 9803501fb96c2..66c4495c5afc8 100644
--- a/src/librustc_attr/lib.rs
+++ b/src/librustc_attr/lib.rs
@@ -4,6 +4,8 @@
 //! The goal is to move the definition of `MetaItem` and things that don't need to be in `syntax`
 //! to this crate.
 
+#![feature(or_patterns)]
+
 mod builtin;
 
 pub use builtin::*;
diff --git a/src/librustc_expand/proc_macro_server.rs b/src/librustc_expand/proc_macro_server.rs
index 5f21ff503d59e..10baffb28ac2d 100644
--- a/src/librustc_expand/proc_macro_server.rs
+++ b/src/librustc_expand/proc_macro_server.rs
@@ -141,10 +141,10 @@ impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec<Self>)>
             SingleQuote => op!('\''),
 
             Ident(name, false) if name == kw::DollarCrate => tt!(Ident::dollar_crate()),
-            Ident(name, is_raw) => tt!(Ident::new(name, is_raw)),
+            Ident(name, is_raw) => tt!(Ident::new(sess, name, is_raw)),
             Lifetime(name) => {
                 let ident = ast::Ident::new(name, span).without_first_quote();
-                stack.push(tt!(Ident::new(ident.name, false)));
+                stack.push(tt!(Ident::new(sess, ident.name, false)));
                 tt!(Punct::new('\'', true))
             }
             Literal(lit) => tt!(Literal { lit }),
@@ -322,7 +322,7 @@ impl Ident {
             false
         }
     }
-    fn new(sym: Symbol, is_raw: bool, span: Span) -> Ident {
+    fn new(sess: &ParseSess, sym: Symbol, is_raw: bool, span: Span) -> Ident {
         let sym = nfc_normalize(&sym.as_str());
         let string = sym.as_str();
         if !Self::is_valid(&string) {
@@ -331,6 +331,7 @@ impl Ident {
         if is_raw && !sym.can_be_raw() {
             panic!("`{}` cannot be a raw identifier", string);
         }
+        sess.symbol_gallery.insert(sym, span);
         Ident { sym, is_raw, span }
     }
     fn dollar_crate(span: Span) -> Ident {
@@ -495,7 +496,7 @@ impl server::Punct for Rustc<'_> {
 
 impl server::Ident for Rustc<'_> {
     fn new(&mut self, string: &str, span: Self::Span, is_raw: bool) -> Self::Ident {
-        Ident::new(Symbol::intern(string), is_raw, span)
+        Ident::new(self.sess, Symbol::intern(string), is_raw, span)
     }
     fn span(&mut self, ident: Self::Ident) -> Self::Span {
         ident.span
diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs
index cec9e0ce3af71..a1dd7a5ca5225 100644
--- a/src/librustc_feature/active.rs
+++ b/src/librustc_feature/active.rs
@@ -562,6 +562,9 @@ declare_features! (
     /// Allows the use of `#[target_feature]` on safe functions.
     (active, target_feature_11, "1.45.0", Some(69098), None),
 
+    /// Allow conditional compilation depending on rust version
+    (active, cfg_version, "1.45.0", Some(64796), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
diff --git a/src/librustc_feature/builtin_attrs.rs b/src/librustc_feature/builtin_attrs.rs
index e4975aae6b983..466b318bca730 100644
--- a/src/librustc_feature/builtin_attrs.rs
+++ b/src/librustc_feature/builtin_attrs.rs
@@ -26,6 +26,7 @@ const GATED_CFGS: &[GatedCfg] = &[
     (sym::target_has_atomic, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)),
     (sym::target_has_atomic_load_store, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)),
     (sym::sanitize, sym::cfg_sanitize, cfg_fn!(cfg_sanitize)),
+    (sym::version, sym::cfg_version, cfg_fn!(cfg_version)),
 ];
 
 /// Find a gated cfg determined by the `pred`icate which is given the cfg's name.
diff --git a/src/librustc_infer/infer/nll_relate/mod.rs b/src/librustc_infer/infer/nll_relate/mod.rs
index 0fb926d94166a..a2907e6e373b8 100644
--- a/src/librustc_infer/infer/nll_relate/mod.rs
+++ b/src/librustc_infer/infer/nll_relate/mod.rs
@@ -657,7 +657,7 @@ where
             // Reset the ambient variance to covariant. This is needed
             // to correctly handle cases like
             //
-            //     for<'a> fn(&'a u32, &'a u3) == for<'b, 'c> fn(&'b u32, &'c u32)
+            //     for<'a> fn(&'a u32, &'a u32) == for<'b, 'c> fn(&'b u32, &'c u32)
             //
             // Somewhat surprisingly, these two types are actually
             // **equal**, even though the one on the right looks more
diff --git a/src/librustc_lint/Cargo.toml b/src/librustc_lint/Cargo.toml
index b238a3156fae5..ada6f2a9381dc 100644
--- a/src/librustc_lint/Cargo.toml
+++ b/src/librustc_lint/Cargo.toml
@@ -10,7 +10,7 @@ path = "lib.rs"
 
 [dependencies]
 log = "0.4"
-unicode-security = "0.0.2"
+unicode-security = "0.0.3"
 rustc_middle = { path = "../librustc_middle" }
 rustc_ast_pretty = { path = "../librustc_ast_pretty" }
 rustc_attr = { path = "../librustc_attr" }
diff --git a/src/librustc_lint/levels.rs b/src/librustc_lint/levels.rs
index 12f4cd33689e6..274e57ae64cac 100644
--- a/src/librustc_lint/levels.rs
+++ b/src/librustc_lint/levels.rs
@@ -388,6 +388,11 @@ impl<'s> LintLevelsBuilder<'s> {
         self.cur = push.prev;
     }
 
+    /// Find the lint level for a lint.
+    pub fn lint_level(&self, lint: &'static Lint) -> (Level, LintSource) {
+        self.sets.get_lint_level(lint, self.cur, None, self.sess)
+    }
+
     /// Used to emit a lint-related diagnostic based on the current state of
     /// this lint context.
     pub fn struct_lint(
@@ -396,7 +401,7 @@ impl<'s> LintLevelsBuilder<'s> {
         span: Option<MultiSpan>,
         decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a>),
     ) {
-        let (level, src) = self.sets.get_lint_level(lint, self.cur, None, self.sess);
+        let (level, src) = self.lint_level(lint);
         struct_lint_level(self.sess, lint, level, src, span, decorate)
     }
 
diff --git a/src/librustc_lint/non_ascii_idents.rs b/src/librustc_lint/non_ascii_idents.rs
index 470fac2675bac..94fc1a228df03 100644
--- a/src/librustc_lint/non_ascii_idents.rs
+++ b/src/librustc_lint/non_ascii_idents.rs
@@ -1,5 +1,9 @@
 use crate::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_ast::ast;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_span::symbol::SymbolStr;
+use std::hash::{Hash, Hasher};
+use std::ops::Deref;
 
 declare_lint! {
     pub NON_ASCII_IDENTS,
@@ -13,9 +17,144 @@ declare_lint! {
     "detects uncommon Unicode codepoints in identifiers"
 }
 
-declare_lint_pass!(NonAsciiIdents => [NON_ASCII_IDENTS, UNCOMMON_CODEPOINTS]);
+// FIXME: Change this to warn.
+declare_lint! {
+    pub CONFUSABLE_IDENTS,
+    Allow,
+    "detects visually confusable pairs between identifiers"
+}
+
+declare_lint_pass!(NonAsciiIdents => [NON_ASCII_IDENTS, UNCOMMON_CODEPOINTS, CONFUSABLE_IDENTS]);
+
+enum CowBoxSymStr {
+    Interned(SymbolStr),
+    Owned(Box<str>),
+}
+
+impl Deref for CowBoxSymStr {
+    type Target = str;
+
+    fn deref(&self) -> &str {
+        match self {
+            CowBoxSymStr::Interned(interned) => interned,
+            CowBoxSymStr::Owned(ref owned) => owned,
+        }
+    }
+}
+
+impl Hash for CowBoxSymStr {
+    #[inline]
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        Hash::hash(&**self, state)
+    }
+}
+
+impl PartialEq<CowBoxSymStr> for CowBoxSymStr {
+    #[inline]
+    fn eq(&self, other: &CowBoxSymStr) -> bool {
+        PartialEq::eq(&**self, &**other)
+    }
+}
+
+impl Eq for CowBoxSymStr {}
+
+fn calc_skeleton(symbol_str: SymbolStr, buffer: &'_ mut String) -> CowBoxSymStr {
+    use std::mem::swap;
+    use unicode_security::confusable_detection::skeleton;
+    buffer.clear();
+    buffer.extend(skeleton(&symbol_str));
+    if symbol_str == *buffer {
+        CowBoxSymStr::Interned(symbol_str)
+    } else {
+        let mut owned = String::new();
+        swap(buffer, &mut owned);
+        CowBoxSymStr::Owned(owned.into_boxed_str())
+    }
+}
+
+fn is_in_ascii_confusable_closure(c: char) -> bool {
+    // FIXME: move this table to `unicode_security` crate.
+    // data here corresponds to Unicode 13.
+    const ASCII_CONFUSABLE_CLOSURE: &[(u64, u64)] = &[(0x00, 0x7f), (0xba, 0xba), (0x2080, 0x2080)];
+    let c = c as u64;
+    for &(range_start, range_end) in ASCII_CONFUSABLE_CLOSURE {
+        if c >= range_start && c <= range_end {
+            return true;
+        }
+    }
+    false
+}
+
+fn is_in_ascii_confusable_closure_relevant_list(c: char) -> bool {
+    // FIXME: move this table to `unicode_security` crate.
+    // data here corresponds to Unicode 13.
+    const ASCII_CONFUSABLE_CLOSURE_RELEVANT_LIST: &[u64] = &[
+        0x22, 0x25, 0x27, 0x2f, 0x30, 0x31, 0x49, 0x4f, 0x60, 0x6c, 0x6d, 0x6e, 0x72, 0x7c, 0xba,
+        0x2080,
+    ];
+    let c = c as u64;
+    for &item in ASCII_CONFUSABLE_CLOSURE_RELEVANT_LIST {
+        if c == item {
+            return true;
+        }
+    }
+    false
+}
 
 impl EarlyLintPass for NonAsciiIdents {
+    fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
+        use rustc_session::lint::Level;
+        if cx.builder.lint_level(CONFUSABLE_IDENTS).0 == Level::Allow {
+            return;
+        }
+        let symbols = cx.sess.parse_sess.symbol_gallery.symbols.lock();
+        let mut symbol_strs_and_spans = Vec::with_capacity(symbols.len());
+        let mut in_fast_path = true;
+        for (symbol, sp) in symbols.iter() {
+            // fast path
+            let symbol_str = symbol.as_str();
+            if !symbol_str.chars().all(is_in_ascii_confusable_closure) {
+                // fallback to slow path.
+                symbol_strs_and_spans.clear();
+                in_fast_path = false;
+                break;
+            }
+            if symbol_str.chars().any(is_in_ascii_confusable_closure_relevant_list) {
+                symbol_strs_and_spans.push((symbol_str, *sp));
+            }
+        }
+        if !in_fast_path {
+            // slow path
+            for (symbol, sp) in symbols.iter() {
+                let symbol_str = symbol.as_str();
+                symbol_strs_and_spans.push((symbol_str, *sp));
+            }
+        }
+        drop(symbols);
+        symbol_strs_and_spans.sort_by_key(|x| x.0.clone());
+        let mut skeleton_map =
+            FxHashMap::with_capacity_and_hasher(symbol_strs_and_spans.len(), Default::default());
+        let mut str_buf = String::new();
+        for (symbol_str, sp) in symbol_strs_and_spans {
+            let skeleton = calc_skeleton(symbol_str.clone(), &mut str_buf);
+            skeleton_map
+                .entry(skeleton)
+                .and_modify(|(existing_symbolstr, existing_span)| {
+                    cx.struct_span_lint(CONFUSABLE_IDENTS, sp, |lint| {
+                        lint.build(&format!(
+                            "identifier pair considered confusable between `{}` and `{}`",
+                            existing_symbolstr, symbol_str
+                        ))
+                        .span_label(
+                            *existing_span,
+                            "this is where the previous identifier occurred",
+                        )
+                        .emit();
+                    });
+                })
+                .or_insert((symbol_str, sp));
+        }
+    }
     fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: ast::Ident) {
         use unicode_security::GeneralSecurityProfile;
         let name_str = ident.name.as_str();
diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs
index 6a4b35ed3d7fa..04f17230717d9 100644
--- a/src/librustc_metadata/rmeta/decoder.rs
+++ b/src/librustc_metadata/rmeta/decoder.rs
@@ -1123,11 +1123,13 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         match self.kind(id) {
             EntryKind::Const(qualif, _)
             | EntryKind::AssocConst(
-                AssocContainer::ImplDefault | AssocContainer::ImplFinal,
+                AssocContainer::ImplDefault
+                | AssocContainer::ImplFinal
+                | AssocContainer::TraitWithDefault,
                 qualif,
                 _,
             ) => qualif,
-            _ => bug!(),
+            _ => bug!("mir_const_qualif: unexpected kind"),
         }
     }
 
diff --git a/src/librustc_parse/lexer/mod.rs b/src/librustc_parse/lexer/mod.rs
index 96321ef2145e5..f676a34a1d12b 100644
--- a/src/librustc_parse/lexer/mod.rs
+++ b/src/librustc_parse/lexer/mod.rs
@@ -222,8 +222,9 @@ impl<'a> StringReader<'a> {
                     ident_start = ident_start + BytePos(2);
                 }
                 let sym = nfc_normalize(self.str_from(ident_start));
+                let span = self.mk_sp(start, self.pos);
+                self.sess.symbol_gallery.insert(sym, span);
                 if is_raw_ident {
-                    let span = self.mk_sp(start, self.pos);
                     if !sym.can_be_raw() {
                         self.err_span(span, &format!("`{}` cannot be a raw identifier", sym));
                     }
diff --git a/src/librustc_session/parse.rs b/src/librustc_session/parse.rs
index 387d35422c43e..69d3e99b7458e 100644
--- a/src/librustc_session/parse.rs
+++ b/src/librustc_session/parse.rs
@@ -60,6 +60,20 @@ impl GatedSpans {
     }
 }
 
+#[derive(Default)]
+pub struct SymbolGallery {
+    /// All symbols occurred and their first occurrance span.
+    pub symbols: Lock<FxHashMap<Symbol, Span>>,
+}
+
+impl SymbolGallery {
+    /// Insert a symbol and its span into symbol gallery.
+    /// If the symbol has occurred before, ignore the new occurance.
+    pub fn insert(&self, symbol: Symbol, span: Span) {
+        self.symbols.lock().entry(symbol).or_insert(span);
+    }
+}
+
 /// Construct a diagnostic for a language feature error due to the given `span`.
 /// The `feature`'s `Symbol` is the one you used in `active.rs` and `rustc_span::symbols`.
 pub fn feature_err<'a>(
@@ -118,6 +132,7 @@ pub struct ParseSess {
     pub ambiguous_block_expr_parse: Lock<FxHashMap<Span, Span>>,
     pub injected_crate_name: Once<Symbol>,
     pub gated_spans: GatedSpans,
+    pub symbol_gallery: SymbolGallery,
     /// The parser has reached `Eof` due to an unclosed brace. Used to silence unnecessary errors.
     pub reached_eof: Lock<bool>,
 }
@@ -143,6 +158,7 @@ impl ParseSess {
             ambiguous_block_expr_parse: Lock::new(FxHashMap::default()),
             injected_crate_name: Once::new(),
             gated_spans: GatedSpans::default(),
+            symbol_gallery: SymbolGallery::default(),
             reached_eof: Lock::new(false),
         }
     }
diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs
index 74d73404acd8e..f194506e66069 100644
--- a/src/librustc_span/symbol.rs
+++ b/src/librustc_span/symbol.rs
@@ -192,6 +192,7 @@ symbols! {
         cfg_target_has_atomic,
         cfg_target_thread_local,
         cfg_target_vendor,
+        cfg_version,
         char,
         clippy,
         clone,
@@ -805,6 +806,7 @@ symbols! {
         var,
         vec,
         Vec,
+        version,
         vis,
         visible_private_types,
         volatile,
diff --git a/src/librustc_trait_selection/traits/on_unimplemented.rs b/src/librustc_trait_selection/traits/on_unimplemented.rs
index cf29c4249c019..3fbc0b7f08e5f 100644
--- a/src/librustc_trait_selection/traits/on_unimplemented.rs
+++ b/src/librustc_trait_selection/traits/on_unimplemented.rs
@@ -81,7 +81,7 @@ impl<'tcx> OnUnimplementedDirective {
                         None,
                     )
                 })?;
-            attr::eval_condition(cond, &tcx.sess.parse_sess, &mut |_| true);
+            attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |_| true);
             Some(cond.clone())
         };
 
@@ -208,11 +208,16 @@ impl<'tcx> OnUnimplementedDirective {
 
         for command in self.subcommands.iter().chain(Some(self)).rev() {
             if let Some(ref condition) = command.condition {
-                if !attr::eval_condition(condition, &tcx.sess.parse_sess, &mut |c| {
-                    c.ident().map_or(false, |ident| {
-                        options.contains(&(ident.name, c.value_str().map(|s| s.to_string())))
-                    })
-                }) {
+                if !attr::eval_condition(
+                    condition,
+                    &tcx.sess.parse_sess,
+                    Some(tcx.features()),
+                    &mut |c| {
+                        c.ident().map_or(false, |ident| {
+                            options.contains(&(ident.name, c.value_str().map(|s| s.to_string())))
+                        })
+                    },
+                ) {
                     debug!("evaluate: skipping {:?} due to condition", command);
                     continue;
                 }
diff --git a/src/test/ui/consts/const_in_pattern/auxiliary/consts.rs b/src/test/ui/consts/const_in_pattern/auxiliary/consts.rs
index 303c2f12bbce9..b438bcd9fb5eb 100644
--- a/src/test/ui/consts/const_in_pattern/auxiliary/consts.rs
+++ b/src/test/ui/consts/const_in_pattern/auxiliary/consts.rs
@@ -9,3 +9,8 @@ impl PartialEq for CustomEq {
 
 pub const NONE: Option<CustomEq> = None;
 pub const SOME: Option<CustomEq> = Some(CustomEq);
+
+pub trait AssocConst {
+    const NONE: Option<CustomEq> = None;
+    const SOME: Option<CustomEq> = Some(CustomEq);
+}
diff --git a/src/test/ui/consts/const_in_pattern/cross-crate-fail.rs b/src/test/ui/consts/const_in_pattern/cross-crate-fail.rs
index c9e6050fdc508..05c53e5edccc5 100644
--- a/src/test/ui/consts/const_in_pattern/cross-crate-fail.rs
+++ b/src/test/ui/consts/const_in_pattern/cross-crate-fail.rs
@@ -4,7 +4,11 @@
 
 extern crate consts;
 
+struct Defaulted;
+impl consts::AssocConst for Defaulted {}
+
 fn main() {
+    let _ = Defaulted;
     match None {
         consts::SOME => panic!(),
         //~^ must be annotated with `#[derive(PartialEq, Eq)]`
@@ -12,4 +16,12 @@ fn main() {
 
         _ => {}
     }
+
+    match None {
+        <Defaulted as consts::AssocConst>::SOME  => panic!(),
+        //~^ must be annotated with `#[derive(PartialEq, Eq)]`
+        //~| must be annotated with `#[derive(PartialEq, Eq)]`
+
+        _ => {}
+    }
 }
diff --git a/src/test/ui/consts/const_in_pattern/cross-crate-fail.stderr b/src/test/ui/consts/const_in_pattern/cross-crate-fail.stderr
index c97298f66e677..5d147e32f5a86 100644
--- a/src/test/ui/consts/const_in_pattern/cross-crate-fail.stderr
+++ b/src/test/ui/consts/const_in_pattern/cross-crate-fail.stderr
@@ -1,14 +1,26 @@
 error: to use a constant of type `consts::CustomEq` in a pattern, `consts::CustomEq` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/cross-crate-fail.rs:9:9
+  --> $DIR/cross-crate-fail.rs:13:9
    |
 LL |         consts::SOME => panic!(),
    |         ^^^^^^^^^^^^
 
 error: to use a constant of type `consts::CustomEq` in a pattern, `consts::CustomEq` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/cross-crate-fail.rs:9:9
+  --> $DIR/cross-crate-fail.rs:21:9
+   |
+LL |         <Defaulted as consts::AssocConst>::SOME  => panic!(),
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: to use a constant of type `consts::CustomEq` in a pattern, `consts::CustomEq` must be annotated with `#[derive(PartialEq, Eq)]`
+  --> $DIR/cross-crate-fail.rs:13:9
    |
 LL |         consts::SOME => panic!(),
    |         ^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: to use a constant of type `consts::CustomEq` in a pattern, `consts::CustomEq` must be annotated with `#[derive(PartialEq, Eq)]`
+  --> $DIR/cross-crate-fail.rs:21:9
+   |
+LL |         <Defaulted as consts::AssocConst>::SOME  => panic!(),
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/consts/const_in_pattern/cross-crate-pass.rs b/src/test/ui/consts/const_in_pattern/cross-crate-pass.rs
index ccf655c11cf8a..1d8ecf8ae6640 100644
--- a/src/test/ui/consts/const_in_pattern/cross-crate-pass.rs
+++ b/src/test/ui/consts/const_in_pattern/cross-crate-pass.rs
@@ -6,9 +6,18 @@
 extern crate consts;
 use consts::CustomEq;
 
+struct Defaulted;
+impl consts::AssocConst for Defaulted {}
+
 fn main() {
+    let _ = Defaulted;
     match Some(CustomEq) {
         consts::NONE => panic!(),
         _ => {}
     }
+
+    match Some(CustomEq) {
+        <Defaulted as consts::AssocConst>::NONE  => panic!(),
+        _ => {}
+    }
 }
diff --git a/src/test/ui/feature-gates/feature-gate-cfg-version.rs b/src/test/ui/feature-gates/feature-gate-cfg-version.rs
new file mode 100644
index 0000000000000..c29ef99945e71
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-cfg-version.rs
@@ -0,0 +1,41 @@
+#[cfg(version("1.44"))]
+//~^ ERROR `cfg(version)` is experimental and subject to change
+fn foo() -> bool { true }
+#[cfg(not(version("1.44")))]
+//~^ ERROR `cfg(version)` is experimental and subject to change
+fn foo() -> bool { false }
+
+#[cfg(version("1.43", "1.44", "1.45"))] //~ ERROR: expected single version literal
+//~^ ERROR `cfg(version)` is experimental and subject to change
+fn bar() -> bool  { false }
+#[cfg(version(false))] //~ ERROR: expected a version literal
+//~^ ERROR `cfg(version)` is experimental and subject to change
+fn bar() -> bool  { false }
+#[cfg(version("foo"))] //~ ERROR: invalid version literal
+//~^ ERROR `cfg(version)` is experimental and subject to change
+fn bar() -> bool  { false }
+#[cfg(version("999"))]
+//~^ ERROR `cfg(version)` is experimental and subject to change
+fn bar() -> bool  { false }
+#[cfg(version("-1"))] //~ ERROR: invalid version literal
+//~^ ERROR `cfg(version)` is experimental and subject to change
+fn bar() -> bool  { false }
+#[cfg(version("65536"))] //~ ERROR: invalid version literal
+//~^ ERROR `cfg(version)` is experimental and subject to change
+fn bar() -> bool  { false }
+#[cfg(version("0"))]
+//~^ ERROR `cfg(version)` is experimental and subject to change
+fn bar() -> bool { true }
+
+#[cfg(version("1.65536.2"))]
+//~^ ERROR `cfg(version)` is experimental and subject to change
+fn version_check_bug() {}
+
+fn main() {
+    // This should fail but due to a bug in version_check `1.65536.2` is interpreted as `1.2`.
+    // See https://github.com/SergioBenitez/version_check/issues/11
+    version_check_bug();
+    assert!(foo());
+    assert!(bar());
+    assert!(cfg!(version("1.42"))); //~ ERROR `cfg(version)` is experimental and subject to change
+}
diff --git a/src/test/ui/feature-gates/feature-gate-cfg-version.stderr b/src/test/ui/feature-gates/feature-gate-cfg-version.stderr
new file mode 100644
index 0000000000000..bdf160b5a0270
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-cfg-version.stderr
@@ -0,0 +1,132 @@
+error[E0658]: `cfg(version)` is experimental and subject to change
+  --> $DIR/feature-gate-cfg-version.rs:1:7
+   |
+LL | #[cfg(version("1.44"))]
+   |       ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information
+   = help: add `#![feature(cfg_version)]` to the crate attributes to enable
+
+error[E0658]: `cfg(version)` is experimental and subject to change
+  --> $DIR/feature-gate-cfg-version.rs:4:11
+   |
+LL | #[cfg(not(version("1.44")))]
+   |           ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information
+   = help: add `#![feature(cfg_version)]` to the crate attributes to enable
+
+error[E0658]: `cfg(version)` is experimental and subject to change
+  --> $DIR/feature-gate-cfg-version.rs:8:7
+   |
+LL | #[cfg(version("1.43", "1.44", "1.45"))]
+   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information
+   = help: add `#![feature(cfg_version)]` to the crate attributes to enable
+
+error: expected single version literal
+  --> $DIR/feature-gate-cfg-version.rs:8:7
+   |
+LL | #[cfg(version("1.43", "1.44", "1.45"))]
+   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0658]: `cfg(version)` is experimental and subject to change
+  --> $DIR/feature-gate-cfg-version.rs:11:7
+   |
+LL | #[cfg(version(false))]
+   |       ^^^^^^^^^^^^^^
+   |
+   = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information
+   = help: add `#![feature(cfg_version)]` to the crate attributes to enable
+
+error: expected a version literal
+  --> $DIR/feature-gate-cfg-version.rs:11:15
+   |
+LL | #[cfg(version(false))]
+   |               ^^^^^
+
+error[E0658]: `cfg(version)` is experimental and subject to change
+  --> $DIR/feature-gate-cfg-version.rs:14:7
+   |
+LL | #[cfg(version("foo"))]
+   |       ^^^^^^^^^^^^^^
+   |
+   = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information
+   = help: add `#![feature(cfg_version)]` to the crate attributes to enable
+
+error: invalid version literal
+  --> $DIR/feature-gate-cfg-version.rs:14:15
+   |
+LL | #[cfg(version("foo"))]
+   |               ^^^^^
+
+error[E0658]: `cfg(version)` is experimental and subject to change
+  --> $DIR/feature-gate-cfg-version.rs:17:7
+   |
+LL | #[cfg(version("999"))]
+   |       ^^^^^^^^^^^^^^
+   |
+   = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information
+   = help: add `#![feature(cfg_version)]` to the crate attributes to enable
+
+error[E0658]: `cfg(version)` is experimental and subject to change
+  --> $DIR/feature-gate-cfg-version.rs:20:7
+   |
+LL | #[cfg(version("-1"))]
+   |       ^^^^^^^^^^^^^
+   |
+   = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information
+   = help: add `#![feature(cfg_version)]` to the crate attributes to enable
+
+error: invalid version literal
+  --> $DIR/feature-gate-cfg-version.rs:20:15
+   |
+LL | #[cfg(version("-1"))]
+   |               ^^^^
+
+error[E0658]: `cfg(version)` is experimental and subject to change
+  --> $DIR/feature-gate-cfg-version.rs:23:7
+   |
+LL | #[cfg(version("65536"))]
+   |       ^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information
+   = help: add `#![feature(cfg_version)]` to the crate attributes to enable
+
+error: invalid version literal
+  --> $DIR/feature-gate-cfg-version.rs:23:15
+   |
+LL | #[cfg(version("65536"))]
+   |               ^^^^^^^
+
+error[E0658]: `cfg(version)` is experimental and subject to change
+  --> $DIR/feature-gate-cfg-version.rs:26:7
+   |
+LL | #[cfg(version("0"))]
+   |       ^^^^^^^^^^^^
+   |
+   = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information
+   = help: add `#![feature(cfg_version)]` to the crate attributes to enable
+
+error[E0658]: `cfg(version)` is experimental and subject to change
+  --> $DIR/feature-gate-cfg-version.rs:30:7
+   |
+LL | #[cfg(version("1.65536.2"))]
+   |       ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information
+   = help: add `#![feature(cfg_version)]` to the crate attributes to enable
+
+error[E0658]: `cfg(version)` is experimental and subject to change
+  --> $DIR/feature-gate-cfg-version.rs:40:18
+   |
+LL |     assert!(cfg!(version("1.42")));
+   |                  ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information
+   = help: add `#![feature(cfg_version)]` to the crate attributes to enable
+
+error: aborting due to 16 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.rs b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.rs
new file mode 100644
index 0000000000000..12093837d2630
--- /dev/null
+++ b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.rs
@@ -0,0 +1,9 @@
+#![feature(non_ascii_idents)]
+#![deny(confusable_idents)]
+#![allow(uncommon_codepoints, non_upper_case_globals)]
+
+const s: usize = 42; //~ ERROR identifier pair considered confusable
+
+fn main() {
+    let s = "rust";
+}
diff --git a/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.stderr b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.stderr
new file mode 100644
index 0000000000000..40ee18acb3cd4
--- /dev/null
+++ b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.stderr
@@ -0,0 +1,17 @@
+error: identifier pair considered confusable between `s` and `s`
+  --> $DIR/lint-confusable-idents.rs:5:7
+   |
+LL | const s: usize = 42;
+   |       ^^
+...
+LL |     let s = "rust";
+   |         - this is where the previous identifier occurred
+   |
+note: the lint level is defined here
+  --> $DIR/lint-confusable-idents.rs:2:9
+   |
+LL | #![deny(confusable_idents)]
+   |         ^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+